Pangolin
Header-only C++20 plane computational geometry library
Loading...
Searching...
No Matches
crosses.hpp
Go to the documentation of this file.
1#pragma once
2
4
9
10#include <limits>
11#include <stdexcept>
13
14
15namespace pgl {
16
22
23template <class Number, class Label>
24template<PointConcept OtherPoint>
25constexpr bool Point<Number, Label>::crosses(const OtherPoint&) const {
26 return false;
27}
28
35
36template <class PointType, class LabelType>
37template<SegmentConcept OtherSegment>
38constexpr bool Segment<PointType, LabelType>::crosses(const OtherSegment& other) const {
39 using Coordinate = detail::sign_coordinate_t<NumberType, typename OtherSegment::NumberType>;
40
41 // Four orientation signs over four endpoints, each endpoint in three of
42 // them; see Segment::intersects for what the filtered wrappers buy.
43 const auto a = detail::filtered<Coordinate>(min());
44 const auto b = detail::filtered<Coordinate>(max());
45 const auto c = detail::filtered<Coordinate>(other.min());
46 const auto d = detail::filtered<Coordinate>(other.max());
47 const auto s1 = detail::orientationSignOf(a, b, c);
48 const auto s2 = detail::orientationSignOf(a, b, d);
49 const auto s3 = detail::orientationSignOf(c, d, a);
50 const auto s4 = detail::orientationSignOf(c, d, b);
51
52 if (detail::allDecided(s1, s2, s3, s4)) {
53 return s1.value() != s2.value() && s3.value() != s4.value();
54 }
55
57 const int cross = boundingBoxesCross(other);
58 if (cross == 0) {
59 return false;
60 }
61 if (cross == 2) {
62 return true;
63 }
64 }
65
66 const auto d1 = s1.value();
67 if (d1 == 0) {
68 return false;
69 }
70 const auto d2 = s2.value();
71 if (d1 == d2 || d2 == 0) {
72 return false;
73 }
74 const auto d3 = s3.value();
75 if (d3 == 0) {
76 return false;
77 }
78 const auto d4 = s4.value();
79 return d4 != 0 && d3 != d4;
80}
81
82template <class PointType, class LabelType>
83template<PointConcept OtherPoint>
84constexpr bool Segment<PointType, LabelType>::crosses(const OtherPoint&) const {
85 return false;
86}
87
88template <class PointType, class LabelType>
89constexpr bool Segment<PointType, LabelType>::crosses(const Shape<PointType>& other) const {
90 return std::visit(
91 [this](const auto& value) {
92 return this->crosses(value);
93 },
94 other.variant());
95}
96
102
103template <class PointType, class LabelType>
104template<SegmentConcept OtherSegment>
105constexpr bool Triangle<PointType, LabelType>::crosses(const OtherSegment& other) const {
106 return separates(other) && other.separates(*this);
107}
108
109template <class PointType, class LabelType>
110template<PointConcept OtherPoint>
111constexpr bool Triangle<PointType, LabelType>::crosses(const OtherPoint&) const {
112 return false;
113}
114
115template <class PointType, class LabelType>
116template<OrientedSegmentConcept OtherOrientedSegment>
117constexpr bool Triangle<PointType, LabelType>::crosses(const OtherOrientedSegment& other) const {
118 return separates(other) && other.separates(*this);
119}
120
121template <class PointType, class LabelType>
122template<LineConcept OtherLine>
123constexpr bool Triangle<PointType, LabelType>::crosses(const OtherLine& other) const {
124 return separates(other) && other.separates(*this);
125}
126
127template <class PointType, class LabelType>
128template<OrientedLineConcept OtherOrientedLine>
129constexpr bool Triangle<PointType, LabelType>::crosses(const OtherOrientedLine& other) const {
130 return separates(other) && other.separates(*this);
131}
132
133template <class PointType, class LabelType>
134template<RayConcept OtherRay>
135constexpr bool Triangle<PointType, LabelType>::crosses(const OtherRay& other) const {
136 return separates(other) && other.separates(*this);
137}
138
139template <class PointType, class LabelType>
140template<HalfplaneConcept OtherHalfplane>
141constexpr bool Triangle<PointType, LabelType>::crosses(const OtherHalfplane&) const {
142 return false;
143}
144
145template <class PointType, class LabelType>
146template<RectangleConcept OtherRectangle>
147constexpr bool Triangle<PointType, LabelType>::crosses(const OtherRectangle& other) const {
148 if (other.empty()) {
149 // The empty set meets nothing and disconnects nothing.
150 return false;
151 }
152 return separates(other) && other.separates(*this);
153}
154
155template <class PointType, class LabelType>
156template<TriangleConcept OtherTriangle>
157constexpr bool Triangle<PointType, LabelType>::crosses(const OtherTriangle& other) const {
158 return separates(other) && other.separates(*this);
159}
160
161template <class PointType, class LabelType>
163 return std::visit(
164 [this](const auto& value) {
165 return this->crosses(value);
166 },
167 other.variant());
168}
169
175
176template <class PointType, class LabelType>
177template<SegmentConcept OtherSegment>
178constexpr bool OrientedSegment<PointType, LabelType>::crosses(const OtherSegment& other) const {
179 return this->asSegment().crosses(other);
180}
181
182template <class PointType, class LabelType>
183template<OrientedSegmentConcept OtherOrientedSegment>
184constexpr bool OrientedSegment<PointType, LabelType>::crosses(const OtherOrientedSegment& other) const {
185 return this->asSegment().crosses(other.asSegment());
186}
187
188template <class PointType, class LabelType>
189template<PointConcept OtherPoint>
190constexpr bool OrientedSegment<PointType, LabelType>::crosses(const OtherPoint& other) const {
191 return this->asSegment().crosses(other);
192}
193
194template <class PointType, class LabelType>
196 return std::visit(
197 [this](const auto& value) {
198 return this->crosses(value);
199 },
200 other.variant());
201}
202
208
209template <class PointType, class LabelType>
210template<LineConcept OtherLine>
211constexpr bool Line<PointType, LabelType>::crosses(const OtherLine& other) const {
212 if (isDegenerate() || other.isDegenerate() || *this == other) {
213 return false;
214 }
215 return !parallel(other);
216}
217
218template <class PointType, class LabelType>
219template<PointConcept OtherPoint>
220constexpr bool Line<PointType, LabelType>::crosses(const OtherPoint&) const {
221 return false;
222}
223
224template <class PointType, class LabelType>
225template<SegmentConcept OtherSegment>
226constexpr bool Line<PointType, LabelType>::crosses(const OtherSegment& other) const {
227 return separates(other) && other.separates(*this);
228}
229
230template <class PointType, class LabelType>
231template<OrientedSegmentConcept OtherOrientedSegment>
232constexpr bool Line<PointType, LabelType>::crosses(const OtherOrientedSegment& other) const {
233 return crosses(other.asSegment());
234}
235
236template <class PointType, class LabelType>
237constexpr bool Line<PointType, LabelType>::crosses(const Shape<PointType>& other) const {
238 return std::visit(
239 [this](const auto& value) {
240 return this->crosses(value);
241 },
242 other.variant());
243}
244
250
251template <class PointType, class LabelType>
252template<LineConcept OtherLine>
253constexpr bool OrientedLine<PointType, LabelType>::crosses(const OtherLine& other) const {
254 return this->asLine().crosses(other);
255}
256
257template <class PointType, class LabelType>
258template<OrientedLineConcept OtherOrientedLine>
259constexpr bool OrientedLine<PointType, LabelType>::crosses(const OtherOrientedLine& other) const {
260 return this->asLine().crosses(other.asLine());
261}
262
263template <class PointType, class LabelType>
264template<PointConcept OtherPoint>
265constexpr bool OrientedLine<PointType, LabelType>::crosses(const OtherPoint& other) const {
266 return this->asLine().crosses(other);
267}
268
269template <class PointType, class LabelType>
270template<SegmentConcept OtherSegment>
271constexpr bool OrientedLine<PointType, LabelType>::crosses(const OtherSegment& other) const {
272 return this->asLine().crosses(other);
273}
274
275template <class PointType, class LabelType>
276template<OrientedSegmentConcept OtherOrientedSegment>
277constexpr bool OrientedLine<PointType, LabelType>::crosses(const OtherOrientedSegment& other) const {
278 return this->asLine().crosses(other);
279}
280
281template <class PointType, class LabelType>
283 return std::visit(
284 [this](const auto& value) {
285 return this->crosses(value);
286 },
287 other.variant());
288}
289
290template <class PointType, class LabelType>
291template <LineConcept OtherLine>
292constexpr std::partial_ordering
294 const OtherLine& second) const {
295 // A point source() + t*(target() - source()) lies on a line L = (P, Q) where
296 // the affine function orientationDeterminant(P, Q, .) = p + t*(q - p)
297 // vanishes, i.e. at parameter t = p / (p - q). The denominator p - q is the
298 // cross product of the two line directions and is zero exactly when L is
299 // parallel to this oriented line.
300 const auto crossing = [&](const OtherLine& line) {
301 const auto p = orientationDeterminant(line[0], line[1], source());
302 const auto q = orientationDeterminant(line[0], line[1], target());
303 return std::pair{p, p - q}; // crossing parameter is p / (p - q)
304 };
305 const auto [p1, d1] = crossing(first);
306 const auto [p2, d2] = crossing(second);
307 if (d1 == 0 || d2 == 0) {
308 return std::partial_ordering::unordered; // a line is parallel to this one
309 }
310
311 // Order p1/d1 against p2/d2 without forming the difference: compare the
312 // cross products, then undo the sign of the denominators d1*d2. The products
313 // are ~coordinate^4, so promote the operands first to widen the headroom.
314 using Wide = detail::promoted_number_t<std::remove_cvref_t<decltype(p1)>>;
315 const auto cross = detail::threeWay(detail::asNumber<Wide>(p1) * detail::asNumber<Wide>(d2),
316 detail::asNumber<Wide>(p2) * detail::asNumber<Wide>(d1));
317 if (cross == 0) {
318 return std::partial_ordering::equivalent; // both cross at the same point
319 }
320 const bool denominators_agree = (d1 < 0) == (d2 < 0);
321 const bool first_is_earlier = (cross < 0) == denominators_agree;
322 return first_is_earlier ? std::partial_ordering::less : std::partial_ordering::greater;
323}
324
330
331template <class PointType, class LabelType>
332template<LineConcept OtherLine>
333constexpr bool Ray<PointType, LabelType>::crosses(const OtherLine& other) const {
334 return separates(other) && other.separates(*this);
335}
336
337template <class PointType, class LabelType>
338template<OrientedLineConcept OtherOrientedLine>
339constexpr bool Ray<PointType, LabelType>::crosses(const OtherOrientedLine& other) const {
340 return separates(other) && other.separates(*this);
341}
342
343template <class PointType, class LabelType>
344template<SegmentConcept OtherSegment>
345constexpr bool Ray<PointType, LabelType>::crosses(const OtherSegment& other) const {
346 return separates(other) && other.separates(*this);
347}
348
349template <class PointType, class LabelType>
350template<OrientedSegmentConcept OtherOrientedSegment>
351constexpr bool Ray<PointType, LabelType>::crosses(const OtherOrientedSegment& other) const {
352 return separates(other) && other.separates(*this);
353}
354
355template <class PointType, class LabelType>
356template<RayConcept OtherRay>
357constexpr bool Ray<PointType, LabelType>::crosses(const OtherRay& other) const {
358 return separates(other) && other.separates(*this);
359}
360
361template <class PointType, class LabelType>
362template<PointConcept OtherPoint>
363constexpr bool Ray<PointType, LabelType>::crosses(const OtherPoint&) const {
364 return false;
365}
366
367template <class PointType, class LabelType>
368constexpr bool Ray<PointType, LabelType>::crosses(const Shape<PointType>& other) const {
369 return std::visit(
370 [this](const auto& value) {
371 return this->crosses(value);
372 },
373 other.variant());
374}
375
381
382template <class PointType, class LabelType>
383template<RectangleConcept OtherRectangle>
384constexpr bool Rectangle<PointType, LabelType>::crosses(const OtherRectangle& other) const {
385 // The empty set disconnects nothing and cannot be disconnected, and the
386 // inverted corners of an empty rectangle can pass the tests below, so both
387 // branches that reach true rule emptiness out. The check trails the
388 // geometry rather than guarding the function because false is the common
389 // answer, and that path then never pays for it.
390 const bool hor_ver =
391 min().x() < other.min().x() &&
392 other.max().x() < max().x() &&
393 other.min().y() < min().y() &&
394 max().y() < other.max().y();
395 if (hor_ver) {
396 return !empty() && !other.empty();
397 }
398 const bool ver_hor =
399 other.min().x() < min().x() &&
400 max().x() < other.max().x() &&
401 min().y() < other.min().y() &&
402 other.max().y() < max().y();
403 return ver_hor && !empty() && !other.empty();
404}
405
406template <class PointType, class LabelType>
407template<PointConcept OtherPoint>
408constexpr bool Rectangle<PointType, LabelType>::crosses(const OtherPoint&) const {
409 return false;
410}
411
412template <class PointType, class LabelType>
413template<LineConcept OtherLine>
414constexpr bool Rectangle<PointType, LabelType>::crosses(const OtherLine& other) const {
415 if (empty()) {
416 // The empty set meets nothing and disconnects nothing.
417 return false;
418 }
419 return separates(other) && other.separates(*this);
420}
421
422template <class PointType, class LabelType>
423template<OrientedLineConcept OtherOrientedLine>
424constexpr bool Rectangle<PointType, LabelType>::crosses(const OtherOrientedLine& other) const {
425 if (empty()) {
426 // The empty set meets nothing and disconnects nothing.
427 return false;
428 }
429 return separates(other) && other.separates(*this);
430}
431
432template <class PointType, class LabelType>
433template<SegmentConcept OtherSegment>
434constexpr bool Rectangle<PointType, LabelType>::crosses(const OtherSegment& other) const {
435 if (empty()) {
436 // The empty set meets nothing and disconnects nothing.
437 return false;
438 }
439 return separates(other) && other.separates(*this);
440}
441
442template <class PointType, class LabelType>
443template<OrientedSegmentConcept OtherOrientedSegment>
444constexpr bool Rectangle<PointType, LabelType>::crosses(const OtherOrientedSegment& other) const {
445 if (empty()) {
446 // The empty set meets nothing and disconnects nothing.
447 return false;
448 }
449 return separates(other) && other.separates(*this);
450}
451
452template <class PointType, class LabelType>
453template<RayConcept OtherRay>
454constexpr bool Rectangle<PointType, LabelType>::crosses(const OtherRay& other) const {
455 if (empty()) {
456 // The empty set meets nothing and disconnects nothing.
457 return false;
458 }
459 return separates(other) && other.separates(*this);
460}
461
462template <class PointType, class LabelType>
463template<HalfplaneConcept OtherHalfplane>
464constexpr bool Rectangle<PointType, LabelType>::crosses(const OtherHalfplane& other) const {
465 if (empty()) {
466 // The empty set meets nothing and disconnects nothing.
467 return false;
468 }
469 (void)other;
470 return false;
471}
472
473template <class PointType, class LabelType>
475 return std::visit(
476 [this](const auto& value) {
477 return this->crosses(value);
478 },
479 other.variant());
480}
481
487
488template <class PointType, class LabelType>
489template<PointConcept OtherPoint>
490constexpr bool Halfplane<PointType, LabelType>::crosses(const OtherPoint&) const {
491 return false;
492}
493
494template <class PointType, class LabelType>
495template<LineConcept OtherLine>
496constexpr bool Halfplane<PointType, LabelType>::crosses(const OtherLine& other) const {
497 (void)other;
498 return false;
499}
500
501template <class PointType, class LabelType>
502template<OrientedLineConcept OtherOrientedLine>
503constexpr bool Halfplane<PointType, LabelType>::crosses(const OtherOrientedLine& other) const {
504 (void)other;
505 return false;
506}
507
508template <class PointType, class LabelType>
509template<SegmentConcept OtherSegment>
510constexpr bool Halfplane<PointType, LabelType>::crosses(const OtherSegment& other) const {
511 (void)other;
512 return false;
513}
514
515template <class PointType, class LabelType>
516template<OrientedSegmentConcept OtherOrientedSegment>
517constexpr bool Halfplane<PointType, LabelType>::crosses(const OtherOrientedSegment& other) const {
518 (void)other;
519 return false;
520}
521
522template <class PointType, class LabelType>
523template<RayConcept OtherRay>
524constexpr bool Halfplane<PointType, LabelType>::crosses(const OtherRay& other) const {
525 (void)other;
526 return false;
527}
528
529template <class PointType, class LabelType>
530template<HalfplaneConcept OtherHalfplane>
531constexpr bool Halfplane<PointType, LabelType>::crosses(const OtherHalfplane& other) const {
532 (void)other;
533 return false;
534}
535
536template <class PointType, class LabelType>
538 return std::visit(
539 [this](const auto& value) {
540 return this->crosses(value);
541 },
542 other.variant());
543}
544
545
546// ---------------------------------------------------------------------------
547// Convex
548
549template <class PointType, class LabelType>
550template<PointConcept OtherPoint>
551constexpr bool Convex<PointType, LabelType>::crosses(const OtherPoint&) const {
552 return false;
553}
554
555template <class PointType, class LabelType>
556template<SegmentConcept OtherSegment>
557constexpr bool Convex<PointType, LabelType>::crosses(const OtherSegment& other) const {
558 return separates(other) && other.separates(*this);
559}
560
561template <class PointType, class LabelType>
562template<OrientedSegmentConcept OtherOrientedSegment>
563constexpr bool Convex<PointType, LabelType>::crosses(const OtherOrientedSegment& other) const {
565}
566
567template <class PointType, class LabelType>
568template<LineConcept OtherLine>
569constexpr bool Convex<PointType, LabelType>::crosses(const OtherLine& other) const {
570 return separates(other) && other.separates(*this);
571}
572
573template <class PointType, class LabelType>
574template<OrientedLineConcept OtherOrientedLine>
575constexpr bool Convex<PointType, LabelType>::crosses(const OtherOrientedLine& other) const {
576 return crosses(static_cast<Line<typename OtherOrientedLine::PointType>>(other));
577}
578
579template <class PointType, class LabelType>
580template<RayConcept OtherRay>
581constexpr bool Convex<PointType, LabelType>::crosses(const OtherRay& other) const {
582 return separates(other) && other.separates(*this);
583}
584
585template <class PointType, class LabelType>
586template<HalfplaneConcept OtherHalfplane>
587constexpr bool Convex<PointType, LabelType>::crosses(const OtherHalfplane&) const {
588 return false;
589}
590
591template <class PointType, class LabelType>
592template<RectangleConcept OtherRectangle>
593constexpr bool Convex<PointType, LabelType>::crosses(const OtherRectangle& other) const {
594 if (other.empty()) {
595 // The empty set meets nothing and disconnects nothing.
596 return false;
597 }
598 return crosses(other.asConvex());
599}
600
601template <class PointType, class LabelType>
602template<TriangleConcept OtherTriangle>
603constexpr bool Convex<PointType, LabelType>::crosses(const OtherTriangle& other) const {
604 return crosses(other.asConvex());
605}
606
607template <class PointType, class LabelType>
608template<ConvexConcept OtherConvex>
609constexpr bool Convex<PointType, LabelType>::crosses(const OtherConvex& other) const {
610 if (bbox().crosses(other.bbox())) {
611 return true;
612 }
613 return separates(other) && other.separates(*this);
614}
615
616template <class PointType, class LabelType>
617template<DiskConcept OtherDisk>
618constexpr bool Convex<PointType, LabelType>::crosses(const OtherDisk& other) const {
619 return (separates(other) && other.separates(*this));
620}
621
622template <class PointType, class LabelType>
623template <PointConcept OtherPoint>
625 return std::visit(
626 [this](const auto& value) {
627 return this->crosses(value);
628 },
629 other.variant());
630}
631
632template <class PointType, class LabelType>
633template<PointConcept OtherPoint>
634constexpr bool Polygon<PointType, LabelType>::crosses(const OtherPoint&) const {
635 return false;
636}
637
638template <class PointType, class LabelType>
639template<SegmentConcept OtherSegment>
640constexpr bool Polygon<PointType, LabelType>::crosses(const OtherSegment& other) const {
641 return separates(other) && other.separates(*this);
642}
643
644template <class PointType, class LabelType>
645template<OrientedSegmentConcept OtherOrientedSegment>
646constexpr bool Polygon<PointType, LabelType>::crosses(const OtherOrientedSegment& other) const {
647 return crosses(other.asSegment());
648}
649
650template <class PointType, class LabelType>
651template<RayConcept OtherRay>
652constexpr bool Polygon<PointType, LabelType>::crosses(const OtherRay& other) const {
653 return separates(other) && other.separates(*this);
654}
655
656template <class PointType, class LabelType>
657template<LineConcept OtherLine>
658constexpr bool Polygon<PointType, LabelType>::crosses(const OtherLine& other) const {
659 return separates(other) && other.separates(*this);
660}
661
662template <class PointType, class LabelType>
663template<OrientedLineConcept OtherOrientedLine>
664constexpr bool Polygon<PointType, LabelType>::crosses(const OtherOrientedLine& other) const {
665 return separates(other) && other.separates(*this);
666}
667
668template <class PointType, class LabelType>
669template<HalfplaneConcept OtherHalfplane>
670constexpr bool Polygon<PointType, LabelType>::crosses(const OtherHalfplane&) const {
671 return false;
672}
673
674template <class PointType, class LabelType>
675template<RectangleConcept OtherRectangle>
676constexpr bool Polygon<PointType, LabelType>::crosses(const OtherRectangle&other) const {
677 if (other.empty()) {
678 // The empty set meets nothing and disconnects nothing.
679 return false;
680 }
681 return separates(other) && other.separates(*this);
682}
683
684template <class PointType, class LabelType>
685template<TriangleConcept OtherTriangle>
686constexpr bool Polygon<PointType, LabelType>::crosses(const OtherTriangle& other) const {
687 return separates(other) && other.separates(*this);
688}
689
690template <class PointType, class LabelType>
691template<ConvexConcept OtherConvex>
692constexpr bool Polygon<PointType, LabelType>::crosses(const OtherConvex& other) const {
693 return separates(other) && other.separates(*this);
694}
695
696template <class PointType, class LabelType>
697template<DiskConcept OtherDisk>
698constexpr bool Polygon<PointType, LabelType>::crosses(const OtherDisk& other) const {
699 return separates(other) && other.separates(*this);
700}
701
702template <class PointType, class LabelType>
703template<PolygonConcept OtherPolygon>
704constexpr bool Polygon<PointType, LabelType>::crosses(const OtherPolygon& other) const {
705 return separates(other) && other.separates(*this);
706}
707
708template <class PointType, class LabelType>
709template<PointConcept OtherPoint>
711 return std::visit(
712 [this](const auto& value) {
713 return this->crosses(value);
714 },
715 other.variant());
716}
717
718template <class Number, class Label>
719constexpr bool Point<Number, Label>::crosses(const Shape<Point<Number, Label>>& other) const {
720 return std::visit(
721 [this](const auto& value) {
722 return this->crosses(value);
723 },
724 other.variant());
725}
726
727
728// --- Disk crosses overloads (via separates) + Shape dispatch ---
729
730template <class PointType, class LabelType>
731template<PointConcept OtherPoint>
732constexpr bool Disk<PointType, LabelType>::crosses(const OtherPoint&) const {
733 return false;
734}
735
736template <class PointType, class LabelType>
737template<SegmentConcept OtherSegment>
738constexpr bool Disk<PointType, LabelType>::crosses(const OtherSegment& other) const {
739 return separates(other) && other.separates(*this);
740}
741
742template <class PointType, class LabelType>
743template<OrientedSegmentConcept OtherOrientedSegment>
744constexpr bool Disk<PointType, LabelType>::crosses(const OtherOrientedSegment& other) const {
745 return crosses(other.asSegment());
746}
747
748template <class PointType, class LabelType>
749template<LineConcept OtherLine>
750constexpr bool Disk<PointType, LabelType>::crosses(const OtherLine& other) const {
751 return separates(other) && other.separates(*this);
752}
753
754template <class PointType, class LabelType>
755template<OrientedLineConcept OtherOrientedLine>
756constexpr bool Disk<PointType, LabelType>::crosses(const OtherOrientedLine& other) const {
757 return separates(other) && other.separates(*this);
758}
759
760template <class PointType, class LabelType>
761template<RayConcept OtherRay>
762constexpr bool Disk<PointType, LabelType>::crosses(const OtherRay& other) const {
763 return separates(other) && other.separates(*this);
764}
765
766template <class PointType, class LabelType>
767template<HalfplaneConcept OtherHalfplane>
768constexpr bool Disk<PointType, LabelType>::crosses(const OtherHalfplane& other) const {
769 return separates(other) && other.separates(*this);
770}
771
772template <class PointType, class LabelType>
773template<RectangleConcept OtherRectangle>
774constexpr bool Disk<PointType, LabelType>::crosses(const OtherRectangle& other) const {
775 if (other.empty()) {
776 // The empty set meets nothing and disconnects nothing.
777 return false;
778 }
779 return separates(other) && other.separates(*this);
780}
781
782template <class PointType, class LabelType>
783template<TriangleConcept OtherTriangle>
784constexpr bool Disk<PointType, LabelType>::crosses(const OtherTriangle& other) const {
785 return separates(other) && other.separates(*this);
786}
787
788template <class PointType, class LabelType>
789template<DiskConcept OtherDisk>
790constexpr bool Disk<PointType, LabelType>::crosses(const OtherDisk& other) const {
791 return separates(other) && other.separates(*this);
792}
793
794template <class PointType, class LabelType>
795template<PointConcept OtherPoint>
796constexpr bool Disk<PointType, LabelType>::crosses(const Shape<OtherPoint>& other) const {
797 return std::visit(
798 [this](const auto& value) {
799 return this->crosses(value);
800 },
801 other.variant());
802}
803
810
811template <class PointType, class LabelType, class Storage>
812template<SegmentConcept OtherSegment>
813constexpr bool MonotoneChain<PointType, LabelType, Storage>::crosses(const OtherSegment& other) const {
814 return separates(other) && other.separates(*this);
815}
817template <class PointType, class LabelType, class Storage>
818template<OrientedSegmentConcept OtherOrientedSegment>
819constexpr bool MonotoneChain<PointType, LabelType, Storage>::crosses(const OtherOrientedSegment& other) const {
820 return crosses(other.asSegment());
821}
822
823template <class PointType, class LabelType, class Storage>
824template<LineConcept OtherLine>
825constexpr bool MonotoneChain<PointType, LabelType, Storage>::crosses(const OtherLine& other) const {
826 return separates(other) && other.separates(*this);
827}
828
829template <class PointType, class LabelType, class Storage>
830template<OrientedLineConcept OtherOrientedLine>
831constexpr bool MonotoneChain<PointType, LabelType, Storage>::crosses(const OtherOrientedLine& other) const {
832 return separates(other) && other.separates(*this);
833}
834
835template <class PointType, class LabelType, class Storage>
836template<RayConcept OtherRay>
837constexpr bool MonotoneChain<PointType, LabelType, Storage>::crosses(const OtherRay& other) const {
838 return separates(other) && other.separates(*this);
839}
840
841template <class PointType, class LabelType, class Storage>
842template<HalfplaneConcept OtherHalfplane>
843constexpr bool MonotoneChain<PointType, LabelType, Storage>::crosses(const OtherHalfplane& other) const {
844 return separates(other) && other.separates(*this);
845}
846
847template <class PointType, class LabelType, class Storage>
848template<RectangleConcept OtherRectangle>
849constexpr bool MonotoneChain<PointType, LabelType, Storage>::crosses(const OtherRectangle& other) const {
850 if (other.empty()) {
851 // The empty set meets nothing and disconnects nothing.
852 return false;
853 }
854 return separates(other) && other.separates(*this);
855}
856
857template <class PointType, class LabelType, class Storage>
858template<TriangleConcept OtherTriangle>
859constexpr bool MonotoneChain<PointType, LabelType, Storage>::crosses(const OtherTriangle& other) const {
860 return separates(other) && other.separates(*this);
861}
862
863template <class PointType, class LabelType, class Storage>
864template<DiskConcept OtherDisk>
865constexpr bool MonotoneChain<PointType, LabelType, Storage>::crosses(const OtherDisk& other) const {
866 return separates(other) && other.separates(*this);
867}
868
869template <class PointType, class LabelType, class Storage>
870template<ConvexConcept OtherConvex>
871constexpr bool MonotoneChain<PointType, LabelType, Storage>::crosses(const OtherConvex& other) const {
872 return separates(other) && other.separates(*this);
873}
874
875template <class PointType, class LabelType, class Storage>
876template<MonotoneChainConcept OtherChain>
877constexpr bool MonotoneChain<PointType, LabelType, Storage>::crosses(const OtherChain& other) const {
878 return separates(other) && other.separates(*this);
879}
880
881template <class PointType, class LabelType, class Storage>
882template<PointConcept OtherPoint>
884 return std::visit(
885 [this](const auto& value) {
886 return this->crosses(value);
887 },
888 other.variant());
889}
890
891template <class PointType, class LabelType, class Storage>
892template<MonotoneChainConcept OtherChain>
893constexpr bool MonotoneChain<PointType, LabelType, Storage>::edgesCross(const OtherChain& other) const {
894 if (size() < 2 || other.size() < 2) {
895 return false;
896 }
897 // A strong (robust, transversal) crossing is exactly a properly crossing
898 // edge pair: two edges whose interiors meet with the chains passing to
899 // opposite sides (Segment::crosses). A mere touch, a collinear overlap, or a
900 // vertical edge that only brackets the other chain at a shared boundary x
901 // are not proper crossings, so they do not count -- unlike "some vertex
902 // above and some below", they cannot be slid apart into a non-crossing by an
903 // arbitrarily small perturbation. Both edge sequences are sorted by
904 // x-interval, so a merge sweep advancing the edge with the smaller right
905 // endpoint visits every pair whose x-ranges overlap in O(n + m).
906 const std::size_t iEnd = size() - 1;
907 const std::size_t jEnd = other.size() - 1;
908 // Seed past the leading edges left of the shared x-window (see the sweep in
909 // MonotoneChain::intersects): indexAtX locates the first candidate in
910 // O(log n); a disengaged result means the x-ranges are disjoint, so no pair
911 // can properly cross.
912 using XType = std::common_type_t<NumberType, typename OtherChain::PointType::NumberType>;
913 const XType xlo = std::max<XType>((*this)[0].x(), other[0].x());
914 const auto iSeed = indexAtX(xlo);
915 const auto jSeed = other.indexAtX(xlo);
916 // Back up one edge: the edge whose right endpoint sits exactly on xlo can
917 // still meet the other chain there, yet indexAtX returns the next edge.
918 std::size_t i = (iSeed && jSeed) ? (*iSeed > 0 ? *iSeed - 1 : 0) : iEnd;
919 std::size_t j = (iSeed && jSeed) ? (*jSeed > 0 ? *jSeed - 1 : 0) : jEnd;
920 while (i < iEnd && j < jEnd) {
921 const Segment<PointType> mine((*this)[i], (*this)[i + 1]);
922 const Segment<typename OtherChain::PointType> theirs(other[j], other[j + 1]);
923 if (!(mine.max().x() < theirs.min().x() || theirs.max().x() < mine.min().x()) &&
924 mine.crosses(theirs)) {
925 return true;
926 }
927 const auto order = mine.max() <=> theirs.max();
928 if (order <= 0) {
929 ++i;
930 }
931 if (order >= 0) {
932 ++j;
933 }
934 }
935 return false;
936}
937
938template <class PointType, class LabelType>
939template<MonotoneChainConcept OtherChain>
940constexpr bool Polygon<PointType, LabelType>::crosses(const OtherChain& other) const {
941 return separates(other) && other.separates(*this);
942}
943
949
950template <class PointType, class LabelType>
951template<SegmentConcept OtherSegment>
952constexpr bool Polyline<PointType, LabelType>::crosses(const OtherSegment& other) const {
953 return separates(other) && other.separates(*this);
954}
955
956template <class PointType, class LabelType>
957template<OrientedSegmentConcept OtherOrientedSegment>
958constexpr bool Polyline<PointType, LabelType>::crosses(const OtherOrientedSegment& other) const {
959 return crosses(other.asSegment());
960}
961
962template <class PointType, class LabelType>
963template<LineConcept OtherLine>
964constexpr bool Polyline<PointType, LabelType>::crosses(const OtherLine& other) const {
965 return separates(other) && other.separates(*this);
966}
967
968template <class PointType, class LabelType>
969template<OrientedLineConcept OtherOrientedLine>
970constexpr bool Polyline<PointType, LabelType>::crosses(const OtherOrientedLine& other) const {
971 return separates(other) && other.separates(*this);
972}
973
974template <class PointType, class LabelType>
975template<RayConcept OtherRay>
976constexpr bool Polyline<PointType, LabelType>::crosses(const OtherRay& other) const {
977 return separates(other) && other.separates(*this);
978}
979
980template <class PointType, class LabelType>
981template<HalfplaneConcept OtherHalfplane>
982constexpr bool Polyline<PointType, LabelType>::crosses(const OtherHalfplane& other) const {
983 return separates(other) && other.separates(*this);
984}
985
986template <class PointType, class LabelType>
987template<RectangleConcept OtherRectangle>
988constexpr bool Polyline<PointType, LabelType>::crosses(const OtherRectangle& other) const {
989 if (other.empty()) {
990 // The empty set meets nothing and disconnects nothing.
991 return false;
992 }
993 return separates(other) && other.separates(*this);
994}
995
996template <class PointType, class LabelType>
997template<TriangleConcept OtherTriangle>
998constexpr bool Polyline<PointType, LabelType>::crosses(const OtherTriangle& other) const {
999 return separates(other) && other.separates(*this);
1000}
1001
1002template <class PointType, class LabelType>
1003template<DiskConcept OtherDisk>
1004constexpr bool Polyline<PointType, LabelType>::crosses(const OtherDisk& other) const {
1005 return separates(other) && other.separates(*this);
1006}
1007
1008template <class PointType, class LabelType>
1009template<ConvexConcept OtherConvex>
1010constexpr bool Polyline<PointType, LabelType>::crosses(const OtherConvex& other) const {
1011 return separates(other) && other.separates(*this);
1012}
1013
1014template <class PointType, class LabelType>
1015template<MonotoneChainConcept OtherChain>
1016constexpr bool Polyline<PointType, LabelType>::crosses(const OtherChain& other) const {
1017 return separates(other) && other.separates(*this);
1018}
1019
1020template <class PointType, class LabelType>
1021template<PolylineConcept OtherPolyline>
1022constexpr bool Polyline<PointType, LabelType>::crosses(const OtherPolyline& other) const {
1023 return separates(other) && other.separates(*this);
1024}
1025
1026template <class PointType, class LabelType>
1027template<PointConcept OtherPoint>
1029 return std::visit(
1030 [this](const auto& value) {
1031 return this->crosses(value);
1032 },
1033 other.variant());
1034}
1035
1036template <class PointType, class LabelType>
1037template<PolylineConcept OtherPolyline>
1038constexpr bool Polygon<PointType, LabelType>::crosses(const OtherPolyline& other) const {
1039 return separates(other) && other.separates(*this);
1040}
1041
1042
1043// ---------------------------------------------------------------------------
1044// HalfplaneIntersection
1045//
1046// crosses(a, b) = a.separates(b) && b.separates(a). Both directions live in
1047// separates.hpp, including the reverse overloads against the region on the
1048// lower-ranked shapes.
1049
1050template <class PointType, class LabelType>
1051template <PointConcept OtherPoint>
1052constexpr bool HalfplaneIntersection<PointType, LabelType>::crosses(const OtherPoint&) const {
1053 // The region never separates a point, so the shapes never cross.
1054 return false;
1055}
1056
1057template <class PointType, class LabelType>
1058template <SegmentConcept OtherSegment>
1059constexpr bool HalfplaneIntersection<PointType, LabelType>::crosses(const OtherSegment& other) const {
1060 return separates(other) && other.separates(*this);
1061}
1062
1063template <class PointType, class LabelType>
1064template <OrientedSegmentConcept OtherOrientedSegment>
1065constexpr bool HalfplaneIntersection<PointType, LabelType>::crosses(const OtherOrientedSegment& other) const {
1067}
1068
1069template <class PointType, class LabelType>
1070template <LineConcept OtherLine>
1071constexpr bool HalfplaneIntersection<PointType, LabelType>::crosses(const OtherLine& other) const {
1072 return separates(other) && other.separates(*this);
1073}
1074
1075template <class PointType, class LabelType>
1076template <OrientedLineConcept OtherOrientedLine>
1077constexpr bool HalfplaneIntersection<PointType, LabelType>::crosses(const OtherOrientedLine& other) const {
1078 return crosses(other.asLine());
1079}
1080
1081template <class PointType, class LabelType>
1082template <RayConcept OtherRay>
1083constexpr bool HalfplaneIntersection<PointType, LabelType>::crosses(const OtherRay& other) const {
1084 return separates(other) && other.separates(*this);
1085}
1086
1087template <class PointType, class LabelType>
1088template <HalfplaneConcept OtherHalfplane>
1089constexpr bool HalfplaneIntersection<PointType, LabelType>::crosses(const OtherHalfplane&) const {
1090 // Removing a closed half-plane from the (convex) region leaves a convex
1091 // set, so the half-plane never separates the region and they never cross.
1092 return false;
1093}
1094
1095template <class PointType, class LabelType>
1096template <RectangleConcept OtherRectangle>
1097constexpr bool HalfplaneIntersection<PointType, LabelType>::crosses(const OtherRectangle& other) const {
1098 if (other.empty()) {
1099 // The empty set meets nothing and disconnects nothing.
1100 return false;
1101 }
1102 return separates(other) && other.separates(*this);
1103}
1104
1105template <class PointType, class LabelType>
1106template <TriangleConcept OtherTriangle>
1107constexpr bool HalfplaneIntersection<PointType, LabelType>::crosses(const OtherTriangle& other) const {
1108 return separates(other) && other.separates(*this);
1109}
1110
1111template <class PointType, class LabelType>
1112template <DiskConcept OtherDisk>
1113constexpr bool HalfplaneIntersection<PointType, LabelType>::crosses(const OtherDisk& other) const {
1114 return separates(other) && other.separates(*this);
1115}
1116
1117template <class PointType, class LabelType>
1118template <ConvexConcept OtherConvex>
1119constexpr bool HalfplaneIntersection<PointType, LabelType>::crosses(const OtherConvex& other) const {
1120 return separates(other) && other.separates(*this);
1121}
1122
1123template <class PointType, class LabelType>
1124template <MonotoneChainConcept OtherChain>
1125constexpr bool HalfplaneIntersection<PointType, LabelType>::crosses(const OtherChain& other) const {
1126 return separates(other) && other.separates(*this);
1127}
1128
1129template <class PointType, class LabelType>
1130template <PolylineConcept OtherPolyline>
1131constexpr bool HalfplaneIntersection<PointType, LabelType>::crosses(const OtherPolyline& other) const {
1132 return separates(other) && other.separates(*this);
1133}
1134
1135template <class PointType, class LabelType>
1136template <PolygonConcept OtherPolygon>
1137constexpr bool HalfplaneIntersection<PointType, LabelType>::crosses(const OtherPolygon& other) const {
1138 return separates(other) && other.separates(*this);
1139}
1140
1141template <class PointType, class LabelType>
1142template <HalfplaneIntersectionConcept OtherRegion>
1143constexpr bool HalfplaneIntersection<PointType, LabelType>::crosses(const OtherRegion& other) const {
1144 return separates(other) && other.separates(*this);
1145}
1146
1147template <class PointType, class LabelType>
1148template <PointConcept OtherPoint>
1150 return std::visit(
1151 [this](const auto& value) {
1152 return this->crosses(value);
1153 },
1154 other.variant());
1155}
1156
1157
1158// ---------------------------------------------------------------------------
1159// PolygonWithHoles
1160//
1161// crosses(a, b) = a.separates(b) && b.separates(a), with both directions
1162// defined in separates.hpp: unlike the half-plane intersection, whose reverse
1163// separations against the 1D shapes are spelled out here, a region needs the
1164// same engine either way round.
1165
1166template <class PointType, class LabelType>
1167template <PointConcept OtherPoint>
1169 return false; // a region never separates a point
1170}
1171
1172template <class PointType, class LabelType>
1173template <SegmentConcept OtherSegment>
1174bool PolygonWithHoles<PointType, LabelType>::crosses(const OtherSegment& other) const {
1175 return separates(other) && other.separates(*this);
1176}
1177
1178template <class PointType, class LabelType>
1179template <OrientedSegmentConcept OtherOrientedSegment>
1180bool PolygonWithHoles<PointType, LabelType>::crosses(const OtherOrientedSegment& other) const {
1181 return separates(other) && other.separates(*this);
1182}
1183
1184template <class PointType, class LabelType>
1185template <LineConcept OtherLine>
1186bool PolygonWithHoles<PointType, LabelType>::crosses(const OtherLine& other) const {
1187 return separates(other) && other.separates(*this);
1188}
1189
1190template <class PointType, class LabelType>
1191template <OrientedLineConcept OtherOrientedLine>
1192bool PolygonWithHoles<PointType, LabelType>::crosses(const OtherOrientedLine& other) const {
1193 return separates(other) && other.separates(*this);
1194}
1195
1196template <class PointType, class LabelType>
1197template <RayConcept OtherRay>
1198bool PolygonWithHoles<PointType, LabelType>::crosses(const OtherRay& other) const {
1199 return separates(other) && other.separates(*this);
1200}
1201
1202template <class PointType, class LabelType>
1203template <HalfplaneConcept OtherHalfplane>
1204bool PolygonWithHoles<PointType, LabelType>::crosses(const OtherHalfplane& other) const {
1205 return separates(other) && other.separates(*this);
1206}
1207
1208template <class PointType, class LabelType>
1209template <RectangleConcept OtherRectangle>
1210bool PolygonWithHoles<PointType, LabelType>::crosses(const OtherRectangle& other) const {
1211 if (other.empty()) {
1212 // The empty set meets nothing and disconnects nothing.
1213 return false;
1214 }
1215 return separates(other) && other.separates(*this);
1216}
1217
1218template <class PointType, class LabelType>
1219template <TriangleConcept OtherTriangle>
1220bool PolygonWithHoles<PointType, LabelType>::crosses(const OtherTriangle& other) const {
1221 return separates(other) && other.separates(*this);
1222}
1223
1224template <class PointType, class LabelType>
1225template <ConvexConcept OtherConvex>
1226bool PolygonWithHoles<PointType, LabelType>::crosses(const OtherConvex& other) const {
1227 return separates(other) && other.separates(*this);
1228}
1229
1230template <class PointType, class LabelType>
1231template <PolygonConcept OtherPolygon>
1232bool PolygonWithHoles<PointType, LabelType>::crosses(const OtherPolygon& other) const {
1233 return separates(other) && other.separates(*this);
1234}
1235
1236template <class PointType, class LabelType>
1237template <PolygonWithHolesConcept OtherRegion>
1238bool PolygonWithHoles<PointType, LabelType>::crosses(const OtherRegion& other) const {
1239 return separates(other) && other.separates(*this);
1240}
1241
1242template <class PointType, class LabelType>
1243template <MonotoneChainConcept OtherChain>
1244bool PolygonWithHoles<PointType, LabelType>::crosses(const OtherChain& other) const {
1245 return separates(other) && other.separates(*this);
1246}
1247
1248template <class PointType, class LabelType>
1249template <PolylineConcept OtherPolyline>
1250bool PolygonWithHoles<PointType, LabelType>::crosses(const OtherPolyline& other) const {
1251 return separates(other) && other.separates(*this);
1252}
1253
1254template <class PointType, class LabelType>
1255template <DiskConcept OtherDisk>
1256bool PolygonWithHoles<PointType, LabelType>::crosses(const OtherDisk& other) const {
1257 return separates(other) && other.separates(*this);
1258}
1259
1260template <class PointType, class LabelType>
1261template <HalfplaneIntersectionConcept OtherIntersection>
1262bool PolygonWithHoles<PointType, LabelType>::crosses(const OtherIntersection& other) const {
1263 return separates(other) && other.separates(*this);
1264}
1265
1266// ---------------------------------------------------------------------------
1267// Runtime Shape argument: unwrap the stored alternative and re-dispatch. Every
1268// alternative has a per-shape overload above, so no fallback is needed.
1269
1270template <class PointType, class LabelType>
1271template <PointConcept OtherPoint>
1273 return std::visit(
1274 [this](const auto& value) {
1275 return this->crosses(value);
1276 },
1277 other.variant());
1278}
1279
1280
1281// ---------------------------------------------------------------------------
1282// PolygonSet
1283
1284template <class PointType, class LabelType>
1285template <detail::SetOperandConcept OtherShape>
1286bool PolygonSet<PointType, LabelType>::crosses(const OtherShape& other) const {
1287 if constexpr (PointConcept<OtherShape>) {
1288 return false; // a set never separates a point
1289 } else {
1290 return separates(other) && other.separates(*this);
1291 }
1292}
1293
1294template <class PointType, class LabelType>
1295template <PolygonSetConcept OtherSet>
1296bool PolygonSet<PointType, LabelType>::crosses(const OtherSet& other) const {
1297 return separates(other) && other.separates(*this);
1298}
1299
1300template <class PointType, class LabelType>
1301template <PointConcept OtherPoint>
1303 return std::visit([this](const auto& value) { return this->crosses(value); }, other.variant());
1304}
1305
1306} // namespace pgl
Definition forward.hpp:306
Implementations of the 'contains' predicate.
Definition arrangement.hpp:67
@ x
Definition intervaltree.hpp:24
constexpr bool is_Rational_v
Definition rational.hpp:37
constexpr auto orientationDeterminant(const Point< ANumber, ALabel > &a, const Point< BNumber, BLabel > &b, const Point< CNumber, CLabel > &c)
Returns the signed orientation determinant of three points.
Definition orientation.hpp:518
Small dispatch traits and geometry helpers reused by the implementations.
constexpr const Rectangle< PointType > & bbox() const
Computes the bounding box of the convex polygon.
Definition bounding.hpp:374
constexpr bool crosses(const OtherPoint &) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:551
constexpr bool separates(const EmptyShape< EmptyPoint > &) const
Tests whether removing this shape disconnects the other shape (B∖A is disconnected).
Definition convex.hpp:1345
constexpr bool crosses(const OtherPoint &other) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:732
constexpr bool separates(const OtherPolygon &other) const
Tests whether removing this shape disconnects the other shape (B∖A is disconnected).
Definition separates.hpp:2294
constexpr bool crosses(const OtherPoint &other) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:1052
constexpr bool separates(const OtherPoint &other) const
Tests whether removing this shape disconnects the other shape (B∖A is disconnected).
Definition separates.hpp:4050
constexpr bool crosses(const OtherLine &other) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:496
Unoriented infinite line.
Definition line.hpp:52
constexpr bool separates(const EmptyShape< EmptyPoint > &) const
Tests whether removing this shape disconnects the other shape (B∖A is disconnected).
Definition line.hpp:579
constexpr bool parallel(const OtherLine &other) const
Returns whether another line is parallel to this line.
Definition predicates.hpp:508
constexpr bool crosses(const OtherLine &other) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:211
constexpr bool isDegenerate() const
Returns whether the defining points coincide.
Definition predicates.hpp:451
constexpr std::optional< std::size_t > indexAtX(const OtherNumber &x) const
Locates the vertex or edge of the chain at a given x-coordinate.
Definition atxy.hpp:346
constexpr bool edgesCross(const OtherChain &other) const
Tests whether the two chains have edges that cross.
Definition crosses.hpp:893
constexpr std::size_t size() const
Returns the number of vertices in the chain.
Definition monotonechain.hpp:393
constexpr bool separates(const OtherPoint &) const
Tests whether removing this shape disconnects the other shape (B∖A is disconnected).
Definition monotonechain.hpp:1374
constexpr bool crosses(const OtherPoint &) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition monotonechain.hpp:1584
constexpr bool crosses(const OtherLine &other) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:253
constexpr const PointType & target() const
Returns the target defining point.
Definition orientedline.hpp:195
constexpr std::partial_ordering crossingOrder(const OtherLine &first, const OtherLine &second) const
Orders two lines by where they cross this oriented line.
Definition crosses.hpp:293
constexpr Line< PointType > asLine() const
Returns the line without orientation.
Definition orientedline.hpp:321
constexpr const PointType & source() const
Returns the source defining point.
Definition orientedline.hpp:183
constexpr bool crosses(const OtherSegment &other) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:178
constexpr Segment< PointType > asSegment() const
Returns the segment without orientation.
Definition orientedsegment.hpp:322
Two-dimensional point with optional label payload.
Definition point.hpp:129
constexpr bool crosses(const OtherPoint &other) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:25
bool crosses(const OtherShape &other) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:1286
bool separates(const OtherShape &other) const
Tests whether removing this shape disconnects the other shape (B∖A is disconnected).
Definition separates.hpp:5849
bool crosses(const OtherPoint &other) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:1168
bool separates(const OtherPoint &other) const
Tests whether removing this shape disconnects the other shape (B∖A is disconnected).
Definition separates.hpp:5467
constexpr bool crosses(const OtherChain &other) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:940
constexpr bool separates(const OtherPoint &other) const
Tests whether removing this shape disconnects the other shape (B∖A is disconnected).
Definition separates.hpp:1864
constexpr bool separates(const OtherPoint &) const
Tests whether removing this shape disconnects the other shape (B∖A is disconnected).
Definition polyline.hpp:1176
constexpr bool crosses(const OtherPoint &) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition polyline.hpp:1362
constexpr bool crosses(const OtherLine &other) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:333
constexpr bool separates(const EmptyShape< EmptyPoint > &) const
Tests whether removing this shape disconnects the other shape (B∖A is disconnected).
Definition ray.hpp:594
constexpr const PointType & min() const
Returns the minimum corner (min x, min y).
Definition rectangle.hpp:347
constexpr bool empty() const
Returns whether the rectangle is the empty set of points.
Definition rectangle.hpp:290
constexpr const PointType & max() const
Returns the maximum corner (max x, max y).
Definition rectangle.hpp:359
constexpr bool crosses(const OtherRectangle &other) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:384
constexpr bool separates(const EmptyShape< EmptyPoint > &) const
Tests whether removing this shape disconnects the other shape (B∖A is disconnected).
Definition rectangle.hpp:867
Unoriented closed segment between two endpoints plus optional segment label.
Definition segment.hpp:58
constexpr bool crosses(const OtherSegment &other) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:38
constexpr const PointType & max() const
Returns the largest stored endpoint.
Definition segment.hpp:199
constexpr const PointType & min() const
Returns the smallest stored endpoint.
Definition segment.hpp:190
Runtime variant wrapper over the supported primitive shapes.
Definition shape.hpp:160
constexpr const Variant & variant() const
Returns the underlying variant.
Definition shape.hpp:264
constexpr bool crosses(const OtherSegment &other) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:105
constexpr bool separates(const EmptyShape< EmptyPoint > &) const
Tests whether removing this shape disconnects the other shape (B∖A is disconnected).
Definition triangle.hpp:811