Pangolin
Header-only C++20 plane computational geometry library
Loading...
Searching...
No Matches
predicates.hpp
Go to the documentation of this file.
1#pragma once
2
4
9
10#include <limits>
12#include "boundarycontains.hpp"
13#include "contains.hpp"
14#include "crosses.hpp"
15#include "interiorcontains.hpp"
17#include "intersects.hpp"
18#include "separates.hpp"
19
20namespace pgl {
21
27
28template <class Number, class Label>
29template<PointConcept OtherPoint>
30constexpr bool Point<Number, Label>::operator==(const OtherPoint& other) const {
31 using Compare = std::common_type_t<Number, typename OtherPoint::NumberType>;
32 return detail::asNumber<Compare>(x()) == detail::asNumber<Compare>(other.x()) &&
33 detail::asNumber<Compare>(y()) == detail::asNumber<Compare>(other.y());
34}
35
36template <class Number, class Label>
37template<PointConcept OtherPoint>
38constexpr std::strong_ordering Point<Number, Label>::operator<=>(const OtherPoint& other) const {
39 using Compare = std::common_type_t<Number, typename OtherPoint::NumberType>;
40 if (auto cmp = detail::strongOrder(detail::asNumber<Compare>(x()), detail::asNumber<Compare>(other.x())); cmp != 0) {
41 return cmp;
42 }
43 return detail::strongOrder(detail::asNumber<Compare>(y()), detail::asNumber<Compare>(other.y()));
44}
45
52
53template <class PointType, class LabelType>
55 return min() == max();
56}
57
58template <class PointType, class LabelType>
60 return min() == max();
61}
62
63template <class PointType, class LabelType>
64constexpr std::optional<PointType> Segment<PointType, LabelType>::getIfPoint() const {
65 if (!isPoint()) {
66 return std::nullopt;
67 }
68 return min();
69}
70
71template <class PointType, class LabelType>
73 return false;
74}
75
76template <class PointType, class LabelType>
78 return min().x() == max().x();
79}
80
81template <class PointType, class LabelType>
83 return min().y() == max().y();
84}
85
86template <class PointType, class LabelType>
87template<SegmentConcept OtherSegment>
88constexpr bool Segment<PointType, LabelType>::boundingBoxesOverlap(const OtherSegment& other) const {
89 using Compare = std::common_type_t<NumberType, typename OtherSegment::NumberType>;
90 const auto& a = min();
91 const auto& b = max();
92 const auto& c = other.min();
93 const auto& d = other.max();
94 const Compare thisMinX = static_cast<Compare>(a.x());
95 const Compare thisMaxX = static_cast<Compare>(b.x());
96 const Compare otherMinX = static_cast<Compare>(c.x());
97 const Compare otherMaxX = static_cast<Compare>(d.x());
98 if (thisMaxX < otherMinX || otherMaxX < thisMinX) {
99 return false;
100 }
101 const Compare thisY1 = static_cast<Compare>(a.y());
102 const Compare thisY2 = static_cast<Compare>(b.y());
103 const Compare otherY1 = static_cast<Compare>(c.y());
104 const Compare otherY2 = static_cast<Compare>(d.y());
105 const Compare thisMinY = thisY1 < thisY2 ? thisY1 : thisY2;
106 const Compare thisMaxY = thisY1 < thisY2 ? thisY2 : thisY1;
107 const Compare otherMinY = otherY1 < otherY2 ? otherY1 : otherY2;
108 const Compare otherMaxY = otherY1 < otherY2 ? otherY2 : otherY1;
109 return !(thisMaxY < otherMinY || otherMaxY < thisMinY);
110}
111
112template <class PointType, class LabelType>
113template<SegmentConcept OtherSegment>
114constexpr int Segment<PointType, LabelType>::boundingBoxesCross(const OtherSegment& other) const {
115 using Compare = std::common_type_t<NumberType, typename OtherSegment::NumberType>;
116 const auto& a = min();
117 const auto& b = max();
118 const auto& c = other.min();
119 const auto& d = other.max();
120 const Compare thisMinX = static_cast<Compare>(a.x());
121 const Compare thisMaxX = static_cast<Compare>(b.x());
122 const Compare otherMinX = static_cast<Compare>(c.x());
123 const Compare otherMaxX = static_cast<Compare>(d.x());
124 if (thisMaxX < otherMinX || otherMaxX < thisMinX) {
125 return 0;
126 }
127 const Compare thisY1 = static_cast<Compare>(a.y());
128 const Compare thisY2 = static_cast<Compare>(b.y());
129 const Compare otherY1 = static_cast<Compare>(c.y());
130 const Compare otherY2 = static_cast<Compare>(d.y());
131 const Compare thisMinY = thisY1 < thisY2 ? thisY1 : thisY2;
132 const Compare thisMaxY = thisY1 < thisY2 ? thisY2 : thisY1;
133 const Compare otherMinY = otherY1 < otherY2 ? otherY1 : otherY2;
134 const Compare otherMaxY = otherY1 < otherY2 ? otherY2 : otherY1;
135 if (thisMaxY < otherMinY || otherMaxY < thisMinY) {
136 return 0;
137 }
138 if (thisMinX < otherMinX && otherMaxX < thisMaxX && otherMinY < thisMinY && thisMaxY < otherMaxY ) {
139 return 2;
140 }
141 if (otherMinX < thisMinX && thisMaxX < otherMaxX && thisMinY < otherMinY && otherMaxY < thisMaxY ) {
142 return 2;
143 }
144 return 1;
145}
146
147template <class PointType, class LabelType>
148template<PointConcept OtherPoint>
149constexpr bool Segment<PointType, LabelType>::verticesContain(const OtherPoint& point) const {
150 return point == min() || point == max();
151}
152
153template <class PointType, class LabelType>
154template<PointConcept OtherPoint>
155constexpr bool Segment<PointType, LabelType>::containsEndpoint(const OtherPoint& point) const {
156 return verticesContain(point);
157}
158
159template <class PointType, class LabelType>
160template<PointConcept OtherPoint>
161constexpr bool Segment<PointType, LabelType>::containsCollinear(const OtherPoint& point) const {
162 return !(point < min() || max() < point);
163}
164
165template <class PointType, class LabelType>
166template<PointConcept OtherPoint>
167constexpr bool Segment<PointType, LabelType>::collinear(const OtherPoint& point) const {
168 if (isDegenerate()) {
169 return point == min();
170 }
171 return pgl::collinear(min(), max(), point);
172}
173
174template <class PointType, class LabelType>
175template<SegmentConcept OtherSegment>
176constexpr bool Segment<PointType, LabelType>::collinear(const OtherSegment& other) const {
177 return collinear(other.min()) && collinear(other.max());
178}
179
180template <class PointType, class LabelType>
181template<SegmentConcept OtherSegment>
182constexpr bool Segment<PointType, LabelType>::parallel(const OtherSegment& other) const {
183 return sameDirection(min(), max(), other.min(), other.max());
184}
185
186template <class PointType, class LabelType>
187template<OrientedSegmentConcept OtherOrientedSegment>
188constexpr bool Segment<PointType, LabelType>::collinear(const OtherOrientedSegment& other) const {
189 return collinear(other.source()) && collinear(other.target());
190}
191
192template <class PointType, class LabelType>
193template<LineConcept OtherLine>
194constexpr bool Segment<PointType, LabelType>::collinear(const OtherLine& other) const {
195 return collinear(other.min()) && collinear(other.max());
196}
197
198template <class PointType, class LabelType>
199template<OrientedLineConcept OtherOrientedLine>
200constexpr bool Segment<PointType, LabelType>::collinear(const OtherOrientedLine& other) const {
201 return collinear(other.source()) && collinear(other.target());
202}
203
204template <class PointType, class LabelType>
205template<RayConcept OtherRay>
206constexpr bool Segment<PointType, LabelType>::collinear(const OtherRay& other) const {
207 return collinear(other.source()) && collinear(other.target());
208}
209
210template <class PointType, class LabelType>
211template<OrientedSegmentConcept OtherOrientedSegment>
212constexpr bool Segment<PointType, LabelType>::parallel(const OtherOrientedSegment& other) const {
213 return sameDirection(min(), max(), other.source(), other.target());
214}
215
221
222template <class PointType, class LabelType>
224 // The orientation sign rather than `twiceArea() == 0`: twiceArea() narrows
225 // the promoted determinant back to NumberType, so a determinant that is a
226 // nonzero multiple of the coordinate type's range wraps to zero and reports
227 // a perfectly good triangle as degenerate — (0,0), (65536,0), (0,65536) on
228 // `int` coordinates is such a triangle, and everything keyed off this
229 // predicate (isSegment, getIfSegment, the Convex and Polygon conversions)
230 // followed it. The sign predicate stays in the promoted type and drops the
231 // absolute value the area needs and this does not.
232 return orientationSign(a(), b(), c()) == 0;
233}
234
235template <class PointType, class LabelType>
237 return a() == b() && b() == c();
238}
239
240template <class PointType, class LabelType>
241constexpr std::optional<PointType> Triangle<PointType, LabelType>::getIfPoint() const {
242 if (!isPoint()) {
243 return std::nullopt;
244 }
245 return a();
246}
247
248template <class PointType, class LabelType>
250 return isDegenerate() && !isPoint();
251}
252
253template <class PointType, class LabelType>
254constexpr std::optional<typename Triangle<PointType, LabelType>::template BoundaryType<false>>
256 if (!isSegment()) {
257 return std::nullopt;
258 }
259 // The vertices are collinear, so the lexicographic extremes span them all.
260 return BoundaryType<false>(std::min({a(), b(), c()}), std::max({a(), b(), c()}));
261}
262
263template <class PointType, class LabelType>
265 return false;
266}
267
268template <class PointType, class LabelType>
269template<PointConcept OtherPoint>
270constexpr bool Triangle<PointType, LabelType>::verticesContain(const OtherPoint& point) const {
271 return a().contains(point) || b().contains(point) || c().contains(point);
272}
273
279
280template <class PointType, class LabelType>
282 return source() == target();
283}
284
285template <class PointType, class LabelType>
287 return source() == target();
288}
289
290template <class PointType, class LabelType>
291constexpr std::optional<PointType> OrientedSegment<PointType, LabelType>::getIfPoint() const {
292 if (!isPoint()) {
293 return std::nullopt;
294 }
295 return source();
296}
297
298template <class PointType, class LabelType>
300 return false;
301}
302
303template <class PointType, class LabelType>
305 return source().x() == target().x();
306}
307
308template <class PointType, class LabelType>
310 return source().y() == target().y();
311}
312
313template <class PointType, class LabelType>
314template<PointConcept OtherPoint>
315constexpr bool OrientedSegment<PointType, LabelType>::verticesContain(const OtherPoint& point) const {
316 return point == source() || point == target();
317}
318
319template <class PointType, class LabelType>
320template<PointConcept OtherPoint>
321constexpr bool OrientedSegment<PointType, LabelType>::containsEndpoint(const OtherPoint& point) const {
322 return verticesContain(point);
323}
324
325template <class PointType, class LabelType>
326template<PointConcept OtherPoint>
327constexpr bool OrientedSegment<PointType, LabelType>::containsCollinear(const OtherPoint& point) const {
328 return !(point < min() || max() < point);
329}
330
331template <class PointType, class LabelType>
332template<PointConcept OtherPoint>
333constexpr bool OrientedSegment<PointType, LabelType>::collinear(const OtherPoint& point) const {
334 if (isDegenerate()) {
335 return point == source();
336 }
337 return pgl::collinear(source(), target(), point);
338}
339
340template <class PointType, class LabelType>
341template<SegmentConcept OtherSegment>
342constexpr bool OrientedSegment<PointType, LabelType>::collinear(const OtherSegment& other) const {
343 return collinear(other.min()) && collinear(other.max());
344}
346template <class PointType, class LabelType>
347template<OrientedSegmentConcept OtherOrientedSegment>
348constexpr bool OrientedSegment<PointType, LabelType>::collinear(const OtherOrientedSegment& other) const {
349 return collinear(other.source()) && collinear(other.target());
350}
351
352template <class PointType, class LabelType>
353template<LineConcept OtherLine>
354constexpr bool OrientedSegment<PointType, LabelType>::collinear(const OtherLine& other) const {
355 return collinear(other.min()) && collinear(other.max());
356}
357
358template <class PointType, class LabelType>
359template<OrientedLineConcept OtherOrientedLine>
360constexpr bool OrientedSegment<PointType, LabelType>::collinear(const OtherOrientedLine& other) const {
361 return collinear(other.source()) && collinear(other.target());
362}
363
364template <class PointType, class LabelType>
365template<RayConcept OtherRay>
366constexpr bool OrientedSegment<PointType, LabelType>::collinear(const OtherRay& other) const {
367 return collinear(other.source()) && collinear(other.target());
368}
369
370template <class PointType, class LabelType>
371template<PointConcept OtherPoint>
372constexpr std::partial_ordering OrientedSegment<PointType, LabelType>::orientation(const OtherPoint& point) const {
373 return orientationSign(source(), target(), point);
374}
375
376template <class PointType, class LabelType>
377template<SegmentConcept OtherSegment>
378constexpr bool OrientedSegment<PointType, LabelType>::parallel(const OtherSegment& other) const {
379 return static_cast<Segment<PointType>>(*this).parallel(other);
380}
381
382template <class PointType, class LabelType>
383template<OrientedSegmentConcept OtherOrientedSegment>
384constexpr bool OrientedSegment<PointType, LabelType>::parallel(const OtherOrientedSegment& other) const {
385 return static_cast<Segment<PointType>>(*this).parallel(static_cast<Segment<typename OtherOrientedSegment::PointType>>(other));
386}
387
388template <class PointType, class LabelType>
389template<LineConcept OtherLine>
390constexpr bool OrientedSegment<PointType, LabelType>::parallel(const OtherLine& other) const {
391 return other.parallel(*this);
392}
393
394template <class PointType, class LabelType>
395template<OrientedLineConcept OtherOrientedLine>
396constexpr bool OrientedSegment<PointType, LabelType>::parallel(const OtherOrientedLine& other) const {
397 return other.parallel(*this);
398}
399
400template <class PointType, class LabelType>
401template<RayConcept OtherRay>
402constexpr bool OrientedSegment<PointType, LabelType>::parallel(const OtherRay& other) const {
403 return other.parallel(*this);
404}
405
406template <class PointType, class LabelType>
410
411template <class PointType, class LabelType>
415
421
422template <class PointType, class LabelType>
423constexpr bool Line<PointType, LabelType>::operator==(const Line& other) const {
424 return contains(other);
425}
426
427template <class PointType, class LabelType>
428constexpr auto Line<PointType, LabelType>::operator<=>(const Line& other) const {
429 // Vertical lines have no dual point, so they sort before every
430 // non-vertical line and among themselves by their x-coordinate.
431 if (isVertical() || other.isVertical()) {
432 if (!other.isVertical()) {
433 return std::strong_ordering::less;
434 }
435 if (!isVertical()) {
436 return std::strong_ordering::greater;
437 }
438 return detail::strongOrder(min().x(), other.min().x());
439 }
440 using otherNumber = std::remove_cvref_t<decltype(other.min().x())>;
441 using Coordinate = detail::promoted_number_t<std::common_type_t<NumberType, otherNumber>>;
442 const auto [anum, bnum, den] = dualCoordinates<Coordinate>();
443 const auto [other_anum, other_bnum, other_den] = other.template dualCoordinates<Coordinate>();
444 if (auto cmp = detail::strongOrder(anum * other_den, other_anum * den); cmp != 0) {
445 return cmp;
446 }
447 return detail::strongOrder(bnum * other_den, other_bnum * den);
448}
449
450template <class PointType, class LabelType>
452 return min() == max();
453}
454
455template <class PointType, class LabelType>
457 return isDegenerate();
458}
459
460template <class PointType, class LabelType>
462 return min().x() == max().x();
463}
464
465template <class PointType, class LabelType>
467 return min().y() == max().y();
468}
469
470template <class PointType, class LabelType>
471template<LineConcept OtherLine>
472constexpr bool Segment<PointType, LabelType>::parallel(const OtherLine& other) const {
473 return other.parallel(*this);
474}
475
476template <class PointType, class LabelType>
477template<PointConcept OtherPoint>
478constexpr bool Line<PointType, LabelType>::verticesContain(const OtherPoint& point) const {
479 return point == min() || point == max();
480}
481
482template <class PointType, class LabelType>
483template<PointConcept OtherPoint>
484constexpr bool Line<PointType, LabelType>::collinear(const OtherPoint& point) const {
485 return contains(point);
486}
487
488template <class PointType, class LabelType>
489template<SegmentConcept OtherSegment>
490constexpr bool Line<PointType, LabelType>::collinear(const OtherSegment& other) const {
491 return contains(other);
492}
493
494template <class PointType, class LabelType>
495template<OrientedSegmentConcept OtherOrientedSegment>
496constexpr bool Line<PointType, LabelType>::collinear(const OtherOrientedSegment& other) const {
497 return contains(other);
498}
499
500template <class PointType, class LabelType>
501template<LineConcept OtherLine>
502constexpr bool Line<PointType, LabelType>::collinear(const OtherLine& other) const {
503 return contains(other);
504}
505
506template <class PointType, class LabelType>
507template<LineConcept OtherLine>
508constexpr bool Line<PointType, LabelType>::parallel(const OtherLine& other) const {
509 return sameDirection(min(), max(), other.min(), other.max());
510}
511
512template <class PointType, class LabelType>
513template<SegmentConcept OtherSegment>
514constexpr bool Line<PointType, LabelType>::parallel(const OtherSegment& other) const {
515 return sameDirection(min(), max(), other.min(), other.max());
516}
517
518template <class PointType, class LabelType>
519template<OrientedSegmentConcept OtherOrientedSegment>
520constexpr bool Line<PointType, LabelType>::parallel(const OtherOrientedSegment& other) const {
521 return sameDirection(min(), max(), other.source(), other.target());
522}
523
524template <class PointType, class LabelType>
525template<OrientedLineConcept OtherOrientedLine>
526constexpr bool Line<PointType, LabelType>::parallel(const OtherOrientedLine& other) const {
527 return parallel(other.asLine());
528}
529
530template <class PointType, class LabelType>
531template<RayConcept OtherRay>
532constexpr bool Line<PointType, LabelType>::parallel(const OtherRay& other) const {
533 return parallel(other.asLine());
534}
535
536template <class PointType, class LabelType>
537template<OrientedLineConcept OtherOrientedLine>
538constexpr bool Line<PointType, LabelType>::collinear(const OtherOrientedLine& other) const {
539 return collinear(other.asLine());
540}
541
542template <class PointType, class LabelType>
543template<RayConcept OtherRay>
544constexpr bool Line<PointType, LabelType>::collinear(const OtherRay& other) const {
545 return collinear(other.asLine());
546}
547
548template <class PointType, class LabelType>
552
553template <class PointType, class LabelType>
557
563
564template <class PointType, class LabelType>
566 return contains(other) && ((source() <=> target()) == (other.source() <=> other.target()));
567}
568
569template <class PointType, class LabelType>
571 // Order by orientation first (ascending before descending), then by the
572 // underlying line, so opposite orientations of the same line are ordered
573 // consistently from both sides.
574 const bool ascending = source() < target();
575 const bool otherAscending = other.source() < other.target();
576 if (ascending != otherAscending) {
577 return ascending ? std::strong_ordering::less : std::strong_ordering::greater;
578 }
579 return this->asLine() <=> other.asLine();
580}
581
582template <class PointType, class LabelType>
584 return source() == target();
585}
586
587template <class PointType, class LabelType>
589 return isDegenerate();
590}
591
592template <class PointType, class LabelType>
594 return source().x() == target().x();
595}
596
597template <class PointType, class LabelType>
599 return source().y() == target().y();
600}
601
602template <class PointType, class LabelType>
603template<OrientedLineConcept OtherOrientedLine>
604constexpr bool Segment<PointType, LabelType>::parallel(const OtherOrientedLine& other) const {
605 return other.parallel(*this);
606}
607
608template <class PointType, class LabelType>
609template<PointConcept OtherPoint>
610constexpr bool OrientedLine<PointType, LabelType>::verticesContain(const OtherPoint& point) const {
611 return point == source() || point == target();
612}
613
614template <class PointType, class LabelType>
615template<PointConcept OtherPoint>
616constexpr bool OrientedLine<PointType, LabelType>::collinear(const OtherPoint& point) const {
617 return contains(point);
618}
619
620template <class PointType, class LabelType>
621template<LineConcept OtherLine>
622constexpr bool OrientedLine<PointType, LabelType>::collinear(const OtherLine& other) const {
623 return contains(other);
624}
625
626template <class PointType, class LabelType>
627template<OrientedLineConcept OtherOrientedLine>
628constexpr bool OrientedLine<PointType, LabelType>::collinear(const OtherOrientedLine& other) const {
629 return contains(other);
630}
631
632template <class PointType, class LabelType>
633template<SegmentConcept OtherSegment>
634constexpr bool OrientedLine<PointType, LabelType>::collinear(const OtherSegment& other) const {
635 return contains(other);
636}
637
638template <class PointType, class LabelType>
639template<OrientedSegmentConcept OtherOrientedSegment>
640constexpr bool OrientedLine<PointType, LabelType>::collinear(const OtherOrientedSegment& other) const {
641 return contains(other);
642}
643
644template <class PointType, class LabelType>
645template<RayConcept OtherRay>
646constexpr bool OrientedLine<PointType, LabelType>::collinear(const OtherRay& other) const {
647 return collinear(other.asLine());
648}
649
650template <class PointType, class LabelType>
651template<PointConcept OtherPoint>
652constexpr std::partial_ordering OrientedLine<PointType, LabelType>::orientation(const OtherPoint& point) const {
653 return orientationSign(source(), target(), point);
654}
655
656template <class PointType, class LabelType>
657template<LineConcept OtherLine>
658constexpr bool OrientedLine<PointType, LabelType>::parallel(const OtherLine& other) const {
659 return sameDirection(source(), target(), other.min(), other.max());
660}
661
662template <class PointType, class LabelType>
663template<OrientedLineConcept OtherOrientedLine>
664constexpr bool OrientedLine<PointType, LabelType>::parallel(const OtherOrientedLine& other) const {
665 return sameDirection(source(), target(), other.source(), other.target());
666}
667
668template <class PointType, class LabelType>
669template<SegmentConcept OtherSegment>
670constexpr bool OrientedLine<PointType, LabelType>::parallel(const OtherSegment& other) const {
671 return sameDirection(source(), target(), other.min(), other.max());
672}
673
674template <class PointType, class LabelType>
675template<OrientedSegmentConcept OtherOrientedSegment>
676constexpr bool OrientedLine<PointType, LabelType>::parallel(const OtherOrientedSegment& other) const {
677 return sameDirection(source(), target(), other.source(), other.target());
678}
679
680template <class PointType, class LabelType>
681template<RayConcept OtherRay>
682constexpr bool OrientedLine<PointType, LabelType>::parallel(const OtherRay& other) const {
683 return other.parallel(*this);
684}
685
686template <class PointType, class LabelType>
690
691template <class PointType, class LabelType>
695
696template <class PointType, class LabelType>
700
701template <class PointType, class LabelType>
705
711
712template <class PointType, class LabelType>
713constexpr bool Ray<PointType, LabelType>::operator==(const Ray& other) const {
714 return source() == other.source() && contains(other);
715}
716
717template <class PointType, class LabelType>
718constexpr auto Ray<PointType, LabelType>::operator<=>(const Ray& other) const {
719 if (source() != other.source()) {
720 return source() <=> other.source();
721 }
722 using otherPointType = std::remove_cvref_t<decltype(other.source())>;
723 return static_cast<OrientedLine<PointType>>(*this) <=> static_cast<OrientedLine<otherPointType>>(other);
724}
725
726template <class PointType, class LabelType>
728 return source() == target();
729}
730
731template <class PointType, class LabelType>
733 return isDegenerate();
734}
735
736template <class PointType, class LabelType>
738 return source().x() == target().x();
739}
740
741template <class PointType, class LabelType>
743 return source().y() == target().y();
744}
745
746template <class PointType, class LabelType>
747template<PointConcept OtherPoint>
748constexpr bool Ray<PointType, LabelType>::verticesContain(const OtherPoint& point) const {
749 return point == source() || point == target();
750}
751
752template <class PointType, class LabelType>
753template<PointConcept OtherPoint>
754constexpr bool Ray<PointType, LabelType>::containsCollinear(const OtherPoint& point) const {
755 if (isDegenerate()) {
756 return point == source();
757 }
758 if (source() < target()) {
759 return !(point < source());
760 }
761 return !(source() < point);
762}
763
764template <class PointType, class LabelType>
765template<PointConcept OtherPoint>
766constexpr bool Ray<PointType, LabelType>::collinear(const OtherPoint& point) const {
767 return this->asLine().contains(point);
768}
769
770template <class PointType, class LabelType>
771template<LineConcept OtherLine>
772constexpr bool Ray<PointType, LabelType>::collinear(const OtherLine& other) const {
773 return this->asLine().contains(other);
774}
775
776template <class PointType, class LabelType>
777template<OrientedLineConcept OtherOrientedLine>
778constexpr bool Ray<PointType, LabelType>::collinear(const OtherOrientedLine& other) const {
779 return this->asLine().contains(other.asLine());
780}
781
782template <class PointType, class LabelType>
783template<SegmentConcept OtherSegment>
784constexpr bool Ray<PointType, LabelType>::collinear(const OtherSegment& other) const {
785 return this->asLine().contains(other);
786}
787
788template <class PointType, class LabelType>
789template<OrientedSegmentConcept OtherOrientedSegment>
790constexpr bool Ray<PointType, LabelType>::collinear(const OtherOrientedSegment& other) const {
791 return this->asLine().contains(other);
792}
793
794template <class PointType, class LabelType>
795template<RayConcept OtherRay>
796constexpr bool Ray<PointType, LabelType>::collinear(const OtherRay& other) const {
797 return this->asLine().contains(other.asLine());
798}
799
800template <class PointType, class LabelType>
801template<PointConcept OtherPoint>
802constexpr std::partial_ordering Ray<PointType, LabelType>::orientation(const OtherPoint& point) const {
803 return orientationSign(source(), target(), point);
804}
805
806template <class PointType, class LabelType>
807template<LineConcept OtherLine>
808constexpr bool Ray<PointType, LabelType>::parallel(const OtherLine& other) const {
809 return sameDirection(source(), target(), other.min(), other.max());
810}
811
812template <class PointType, class LabelType>
813template<OrientedLineConcept OtherOrientedLine>
814constexpr bool Ray<PointType, LabelType>::parallel(const OtherOrientedLine& other) const {
815 return sameDirection(source(), target(), other.source(), other.target());
816}
817
818template <class PointType, class LabelType>
819template<SegmentConcept OtherSegment>
820constexpr bool Ray<PointType, LabelType>::parallel(const OtherSegment& other) const {
821 return sameDirection(source(), target(), other.min(), other.max());
822}
823
824template <class PointType, class LabelType>
825template<OrientedSegmentConcept OtherOrientedSegment>
826constexpr bool Ray<PointType, LabelType>::parallel(const OtherOrientedSegment& other) const {
827 return sameDirection(source(), target(), other.source(), other.target());
828}
829
830template <class PointType, class LabelType>
831template<RayConcept OtherRay>
832constexpr bool Ray<PointType, LabelType>::parallel(const OtherRay& other) const {
833 return sameDirection(source(), target(), other.source(), other.target());
834}
835
836template <class PointType, class LabelType>
837template<RayConcept OtherRay>
838constexpr bool Segment<PointType, LabelType>::parallel(const OtherRay& other) const {
839 return other.parallel(*this);
840}
841
842template <class PointType, class LabelType>
846
847template <class PointType, class LabelType>
851
852template <class PointType, class LabelType>
856
857template <class PointType, class LabelType>
861
867
868template <class PointType, class LabelType>
870 // The inverted corners of an empty rectangle already fail both tests, so
871 // the empty set is reported as degenerate without a separate check.
872 return !(min().x() < max().x()) || !(min().y() < max().y());
873}
874
875template <class PointType, class LabelType>
877 return min() == max();
878}
879
880template <class PointType, class LabelType>
881constexpr std::optional<PointType> Rectangle<PointType, LabelType>::getIfPoint() const {
882 if (!isPoint()) {
883 return std::nullopt;
884 }
885 return min();
886}
887
888template <class PointType, class LabelType>
890 return !empty() && isDegenerate() && !isPoint();
891}
892
893template <class PointType, class LabelType>
894constexpr std::optional<typename Rectangle<PointType, LabelType>::template BoundaryType<false>>
896 if (!isSegment()) {
897 return std::nullopt;
898 }
899 return BoundaryType<false>(min(), max());
900}
901
902template <class PointType, class LabelType>
904 return *this != Rectangle<PointType, LabelType>() && points_[1] < points_[0];
905}
906
907template <class PointType, class LabelType>
908template <class Left, class Right>
909constexpr bool Rectangle<PointType, LabelType>::intervalsOverlap(const Left& first_min, const Left& first_max, const Right& second_min, const Right& second_max) {
910 return !(first_max < second_min) && !(second_max < first_min);
911}
912
913template <class PointType, class LabelType>
914template <class Left, class Right>
915constexpr bool Rectangle<PointType, LabelType>::intervalsOverlapStrict(const Left& first_min, const Left& first_max, const Right& second_min, const Right& second_max) {
916 return first_min < second_max && second_min < first_max;
917}
918
919template <class PointType, class LabelType>
920template<PointConcept OtherPoint>
921constexpr bool Rectangle<PointType, LabelType>::verticesContain(const OtherPoint& point) const {
922 // The one case here that does need an emptiness test: the corners of the
923 // empty rectangle are points like any other, and `(0,0)` is one of them, so
924 // a match has to be rejected afterwards rather than trusted. Only a match
925 // pays for it, and most calls do not match.
926 return (point == min() ||
927 point == bottomRight() ||
928 point == max() ||
929 point == topLeft()) && !empty();
930}
931
937
938
939template <class PointType, class LabelType>
940constexpr bool Halfplane<PointType, LabelType>::operator==(const Halfplane& other) const {
941 using otherPointType = std::remove_cvref_t<decltype(other.source())>;
942 return static_cast<OrientedLine<PointType>>(*this) == static_cast<OrientedLine<otherPointType>>(other);
943}
944
945template <class PointType, class LabelType>
946constexpr auto Halfplane<PointType, LabelType>::operator<=>(const Halfplane& other) const {
947 using otherPointType = std::remove_cvref_t<decltype(other.source())>;
948 return static_cast<OrientedLine<PointType>>(*this) <=> static_cast<OrientedLine<otherPointType>>(other);
949}
950
951template <class PointType, class LabelType>
953 return source() == target();
954}
955
956template <class PointType, class LabelType>
958 return isDegenerate();
959}
960
961template <class PointType, class LabelType>
963 return source().x() == target().x();
964}
965
966template <class PointType, class LabelType>
968 return source().y() == target().y();
969}
970
971template <class PointType, class LabelType>
972template<PointConcept OtherPoint>
973constexpr bool Halfplane<PointType, LabelType>::verticesContain(const OtherPoint& point) const {
974 return point == source() || point == target();
975}
976
977
978// ---------------------------------------------------------------------------
979// Convex
980
981template <class PointType, class LabelType>
983 return size() < 3;
984}
985
986template <class PointType, class LabelType>
988 // grahamScan drops duplicates, so size() == 2 implies distinct vertices;
989 // the equality test only matters for a `trusted` polygon built by hand.
990 return size() == 1 || (size() == 2 && (*this)[0] == (*this)[1]);
991}
992
993template <class PointType, class LabelType>
994constexpr std::optional<PointType> Convex<PointType, LabelType>::getIfPoint() const {
995 if (!isPoint()) {
996 return std::nullopt;
997 }
998 return (*this)[0];
999}
1000
1001template <class PointType, class LabelType>
1003 return size() == 2 && (*this)[0] != (*this)[1];
1004}
1005
1006template <class PointType, class LabelType>
1007constexpr std::optional<typename Convex<PointType, LabelType>::template BoundaryType<false>>
1009 if (!isSegment()) {
1010 return std::nullopt;
1011 }
1012 return BoundaryType<false>((*this)[0], (*this)[1]);
1013}
1014
1015template <class PointType, class LabelType>
1017 // The vertex-free polygon is the empty set, which is defined; see empty.
1018 return false;
1019}
1020
1021template <class PointType, class LabelType>
1023 assert(size() != 0);
1024 if (maxIndex_ >= 0) {
1025 return static_cast<size_t>(maxIndex_);
1026 }
1027
1028 const size_t n = size();
1029 size_t lo = 0;
1030 size_t hi = n - 1;
1031
1032 while (lo < hi) {
1033 size_t mid = lo + (hi - lo) / 2;
1034
1035 // Compare consecutive x values.
1036 // If increasing, maximum is to the right.
1037 if (points_[mid] < points_[mid + 1]) {
1038 lo = mid + 1;
1039 }
1040 else {
1041 hi = mid;
1042 }
1043 }
1044
1045 maxIndex_ = static_cast<std::ptrdiff_t>(lo);
1046 return lo;
1047}
1048
1049template <class PointType, class LabelType>
1050template<PointConcept OtherPoint>
1051constexpr bool Convex<PointType, LabelType>::verticesContain(const OtherPoint& point) const {
1052 if (points_.empty()) {
1053 return false;
1054 }
1055 using CommonNumberType = std::common_type_t<NumberType, typename OtherPoint::NumberType>;
1056 Point<CommonNumberType> translatedPoint = static_cast<Point<CommonNumberType>>(point) -
1057 static_cast<Point<CommonNumberType>>(translation_);
1058
1059 if (points_.size() == 1) {
1060 return translatedPoint == points_[0];
1061 }
1062 if (points_.size() == 2) {
1063 return translatedPoint == points_[0] || translatedPoint == points_[1];
1064 }
1065 if (points_.size() == 3) {
1066 return translatedPoint == points_[0] || translatedPoint == points_[1] || translatedPoint == points_[2];
1067 }
1068
1069 const size_t max_i = maxIndex();
1070
1071 auto o = orientationSign(points_[0], points_[max_i], translatedPoint);
1072 if (o < 0) {
1073 return std::binary_search(points_.begin(), points_.begin() + max_i + 1, translatedPoint, lexLessCrossType);
1074 }
1075 if (o > 0) {
1076 return std::binary_search(std::make_reverse_iterator(points_.end()),
1077 std::make_reverse_iterator(points_.begin() + max_i),
1078 translatedPoint, lexLessCrossType);
1079 }
1080
1081 return translatedPoint == points_[0] || translatedPoint == points_[max_i];
1082}
1083
1084template <class PointType, class LabelType>
1085constexpr std::ptrdiff_t Convex<PointType, LabelType>::index(const PointType& point) const {
1086 const std::ptrdiff_t n = static_cast<std::ptrdiff_t>(points_.size());
1087 if (n == 0) {
1088 return -1;
1089 }
1090
1091 const PointType translatedPoint = point - translation_;
1092
1093 // For few vertices a linear scan already runs in O(1) and naturally yields
1094 // the smallest matching index.
1095 if (n <= 3) {
1096 for (std::ptrdiff_t i = 0; i < n; ++i) {
1097 if (points_[static_cast<std::size_t>(i)] == translatedPoint) {
1098 return i;
1099 }
1100 }
1101 return -1;
1102 }
1103
1104 const std::size_t max_i = maxIndex();
1105
1106 // The boundary splits at the lex-min vertex (index 0) and the lex-max
1107 // vertex (index max_i) into two chains, each monotone in lexicographic
1108 // order. The orientation of the query point relative to the line through
1109 // those two vertices selects the chain to binary-search.
1110 const auto o = orientationSign(points_[0], points_[max_i], translatedPoint);
1111 if (o < 0) {
1112 // Lower chain: points_[0 .. max_i], ascending lexicographically.
1113 const auto first = points_.begin();
1114 const auto last = points_.begin() + max_i + 1;
1115 const auto it = std::lower_bound(first, last, translatedPoint, lexLessCrossType);
1116 if (it != last && *it == translatedPoint) {
1117 return it - points_.begin();
1118 }
1119 return -1;
1120 }
1121 if (o > 0) {
1122 // Upper chain: points_[max_i .. n-1] viewed in reverse, which is
1123 // ascending lexicographically.
1124 const auto rfirst = std::make_reverse_iterator(points_.end());
1125 const auto rlast = std::make_reverse_iterator(points_.begin() + max_i);
1126 const auto rit = std::lower_bound(rfirst, rlast, translatedPoint, lexLessCrossType);
1127 if (rit != rlast && *rit == translatedPoint) {
1128 return (rit.base() - 1) - points_.begin();
1129 }
1130 return -1;
1131 }
1132
1133 // o == 0: the point lies on the supporting line, so it can only be one of
1134 // the two shared chain endpoints. Return the smaller matching index.
1135 if (translatedPoint == points_[0]) {
1136 return 0;
1137 }
1138 if (translatedPoint == points_[max_i]) {
1139 return static_cast<std::ptrdiff_t>(max_i);
1140 }
1141 return -1;
1142}
1143
1150
1151template <class PointType, class LabelType>
1153 return !empty() && size() == 1;
1154}
1155
1156template <class PointType, class LabelType>
1157constexpr std::optional<typename HalfplaneIntersection<PointType, LabelType>::HalfplaneType>
1159 if (!isHalfplane()) {
1160 return std::nullopt;
1161 }
1162 return (*this)[0];
1163}
1164
1165template <class PointType, class LabelType>
1167 // Among the degenerate regions only a line has no vertex: a point and a
1168 // segment are bounded (so every consecutive pair turns), and a ray turns at
1169 // its source.
1170 return !empty() && isDegenerate() && vertexCount() == 0;
1171}
1172
1173template <class PointType, class LabelType>
1174constexpr std::optional<Line<PointType>> HalfplaneIntersection<PointType, LabelType>::getIfLine() const {
1175 if (!isLine()) {
1176 return std::nullopt;
1177 }
1178 // Every stored constraint of a line region is bounded by that line: one
1179 // whose boundary differed would cut it and leave a ray or less.
1180 return (*this)[0].asLine();
1181}
1182
1183template <class PointType, class LabelType>
1185 // The unbounded degenerate regions are the ray and the line, and only the
1186 // ray has a vertex; the bounded ones (point, segment) are excluded by
1187 // isBounded.
1188 return !empty() && isDegenerate() && !isBounded() && vertexCount() > 0;
1189}
1190
1191template <class PointType, class LabelType>
1192template <class ResultNumber>
1193constexpr std::optional<Ray<Point<ResultNumber, typename PointType::LabelType>>>
1195 if (!isRay()) {
1196 return std::nullopt;
1197 }
1198 // The region has empty interior, so the constraints bounded by its
1199 // supporting line have the whole region as their edge. `edge` orients the
1200 // ray by which end carries the vertex, so either of them answers.
1202 for (std::size_t i = 0; i < size(); ++i) {
1203 const auto e = this->template edge<ResultNumber>(i);
1204 if (const auto* ray = std::get_if<Ray<ResultPoint>>(&e)) {
1205 return *ray;
1206 }
1207 }
1208 return std::nullopt; // Unreachable for a ray region.
1209}
1210
1211template <class PointType, class LabelType>
1213 if (empty() || !isDegenerate()) {
1214 return false;
1215 }
1216 using ExactPoint = Point<detail::region_exact_number_t<NumberType>, typename PointType::LabelType>;
1217 return std::holds_alternative<ExactPoint>(detail::degenerateRegionCarrier(*this));
1218}
1219
1220template <class PointType, class LabelType>
1221template <class ResultNumber>
1222constexpr std::optional<Point<ResultNumber, typename PointType::LabelType>>
1224 if (!isPoint()) {
1225 return std::nullopt;
1226 }
1227 // Every vertex of a point region is that point.
1228 return this->template vertices<ResultNumber>().front();
1229}
1230
1231template <class PointType, class LabelType>
1233 if (empty() || !isDegenerate()) {
1234 return false;
1235 }
1236 using ExactPoint = Point<detail::region_exact_number_t<NumberType>, typename PointType::LabelType>;
1237 return std::holds_alternative<Segment<ExactPoint>>(detail::degenerateRegionCarrier(*this));
1238}
1239
1240template <class PointType, class LabelType>
1241template <class ResultNumber>
1242constexpr std::optional<Segment<Point<ResultNumber, typename PointType::LabelType>>>
1244 if (!isSegment()) {
1245 return std::nullopt;
1246 }
1247 // The vertices are the (partly coincident) endpoints; the segment spans the
1248 // lexicographic extremes among them.
1250 const auto verts = this->template vertices<ResultNumber>();
1251 const auto [low, high] = std::ranges::minmax_element(verts);
1252 return Segment<ResultPoint>(*low, *high);
1253}
1254
1255} // namespace pgl
Implementations of the 'boundaryContains' predicate.
Implementations of the 'contains' predicate.
Implementations of the 'crosses' predicate.
Implementations of the 'interiorContains' predicate.
Implementations of the 'interiorsIntersect' predicate.
Implementations of the 'intersects' predicate.
Definition arrangement.hpp:67
@ y
Definition intervaltree.hpp:24
@ x
Definition intervaltree.hpp:24
Rectangle() -> Rectangle< Point<>, NoLabel >
Definition rectangle.hpp:2384
@ edge
Definition bitmatrix.hpp:37
constexpr bool sameDirection(const Point< ANumber, ALabel > &a1, const Point< ANumber, ALabel > &a2, const Point< BNumber, BLabel > &b1, const Point< BNumber, BLabel > &b2)
Tests whether the directions a1 -> a2 and b1 -> b2 are parallel.
Definition orientation.hpp:673
constexpr std::partial_ordering orientationSign(const Point< ANumber, ALabel > &a, const Point< BNumber, BLabel > &b, const Point< CNumber, CLabel > &c)
Classifies the orientation of three points.
Definition orientation.hpp:544
constexpr bool collinear(const Point< ANumber, ALabel > &a, const Point< BNumber, BLabel > &b, const Point< CNumber, CLabel > &c)
Tests whether three points are collinear.
Definition orientation.hpp:651
Segment() -> Segment< Point<>, NoLabel >
Small dispatch traits and geometry helpers reused by the implementations.
Implementations of the 'separates' predicate.
std::conditional_t< Oriented, OrientedSegment< PointType >, Segment< PointType > > BoundaryType
Definition convex.hpp:177
constexpr std::optional< PointType > getIfPoint() const
Returns the point the convex polygon collapses to, if it does.
Definition predicates.hpp:994
constexpr bool isDegenerate() const
Checks if the convex polygon is degenerate (has zero area).
Definition predicates.hpp:982
constexpr std::ptrdiff_t index(const PointType &point) const
Returns the smallest index i with (*this)[i] == point, or -1 if point is not a vertex.
Definition predicates.hpp:1085
constexpr size_t maxIndex() const
Returns the index of the maximum vertex (rightmost and highest in case of ties).
Definition predicates.hpp:1022
constexpr bool verticesContain(const OtherPoint &point) const
Checks if the vertices list contains the given point.
Definition predicates.hpp:1051
constexpr bool isSegment() const
Returns whether the convex polygon collapses to a non-degenerate segment.
Definition predicates.hpp:1002
constexpr std::optional< BoundaryType< false > > getIfSegment() const
Returns the segment the convex polygon collapses to, if it does.
Definition predicates.hpp:1008
constexpr bool isPoint() const
Returns whether the convex polygon collapses to a single point.
Definition predicates.hpp:987
constexpr bool isUndefined() const
Returns whether the convex polygon is degenerate without collapsing to a point or to a segment.
Definition predicates.hpp:1016
size_t size() const
Returns the number of vertices in the convex polygon.
Definition convex.hpp:840
PointType_ PointType
Definition convex.hpp:171
constexpr std::optional< Segment< Point< ResultNumber, typename PointType::LabelType > > > getIfSegment() const
Returns the segment the region collapses to, if it is one.
Definition predicates.hpp:1243
constexpr bool empty() const
Returns whether the region is the empty set.
Definition halfplaneintersection.hpp:649
constexpr bool isHalfplane() const
Returns whether the region is exactly one closed half-plane.
Definition predicates.hpp:1152
constexpr std::vector< Point< ResultNumber, typename PointType::LabelType > > vertices() const
Returns every vertex of the region, in pair-index order (for a bounded region: counterclockwise).
Definition halfplaneintersection.hpp:890
constexpr bool isSegment() const
Returns whether the region is a segment of positive length.
Definition predicates.hpp:1232
constexpr bool isBounded() const
Returns whether the region is bounded.
Definition halfplaneintersection.hpp:811
constexpr bool isDegenerate() const
Returns whether the region has empty interior (it is empty or lower-dimensional: a line,...
Definition halfplaneintersection.hpp:664
constexpr std::optional< Ray< Point< ResultNumber, typename PointType::LabelType > > > getIfRay() const
Returns the ray the region equals, if it is one.
Definition predicates.hpp:1194
constexpr std::size_t size() const
Returns the number of stored (non-redundant) half-planes.
Definition halfplaneintersection.hpp:596
constexpr std::size_t vertexCount() const
Returns the number of vertices of the region.
Definition halfplaneintersection.hpp:833
constexpr bool isPoint() const
Returns whether the region is a single point.
Definition predicates.hpp:1212
constexpr std::optional< HalfplaneType > getIfHalfplane() const
Returns the half-plane the region equals, if it is one.
Definition predicates.hpp:1158
constexpr bool isRay() const
Returns whether the region is exactly one ray.
Definition predicates.hpp:1184
constexpr bool isLine() const
Returns whether the region is exactly one line.
Definition predicates.hpp:1166
constexpr std::optional< Line< PointType > > getIfLine() const
Returns the line the region equals, if it is one.
Definition predicates.hpp:1174
constexpr std::optional< Point< ResultNumber, typename PointType::LabelType > > getIfPoint() const
Returns the point the region collapses to, if it is one.
Definition predicates.hpp:1223
Closed half-plane defined by an oriented boundary line.
Definition halfplane.hpp:51
constexpr auto operator<=>(const Halfplane &other) const
Provides an ordering compatible with half-plane equality.
Definition predicates.hpp:946
constexpr bool verticesContain(const OtherPoint &point) const
Returns whether the given point is one of the stored defining points.
Definition predicates.hpp:973
constexpr bool isVertical() const
Returns whether the boundary line is vertical.
Definition predicates.hpp:962
constexpr bool operator==(const Halfplane &other) const
Tests equality of the represented half-plane.
Definition predicates.hpp:940
constexpr const PointType & target() const
Returns the target boundary point.
Definition halfplane.hpp:193
constexpr bool isUndefined() const
Returns whether the half-plane is degenerate without collapsing to a point or to a segment.
Definition predicates.hpp:957
constexpr bool isHorizontal() const
Returns whether the boundary line is horizontal.
Definition predicates.hpp:967
constexpr const PointType & source() const
Returns the source boundary point.
Definition halfplane.hpp:181
constexpr bool isDegenerate() const
Returns whether the defining points coincide.
Definition predicates.hpp:952
constexpr Halfplane()=default
Creates the degenerate half-plane (0,0)->(0,0).
constexpr bool isHorizontal() const
Returns whether the line is horizontal.
Definition predicates.hpp:466
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:428
constexpr auto dualCoordinates() const
Returns normalized dual-line coordinates for the supporting line.
Definition duality.hpp:69
constexpr const PointType & max() const
Returns the largest stored defining point.
Definition line.hpp:189
constexpr bool isUndefined() const
Returns whether the line is degenerate without collapsing to a point or to a segment.
Definition predicates.hpp:456
constexpr bool isVertical() const
Returns whether the line is vertical.
Definition predicates.hpp:461
constexpr bool collinear(const OtherPoint &point) const
Returns whether the line interior contains the given point.
Definition predicates.hpp:484
constexpr bool parallel(const OtherLine &other) const
Returns whether another line is parallel to this line.
Definition predicates.hpp:508
constexpr const PointType & min() const
Returns the smallest stored defining point.
Definition line.hpp:180
constexpr Halfplane< PointType > halfplaneAbove() const
Returns the half-plane geometrically above this line.
Definition predicates.hpp:549
constexpr bool verticesContain(const OtherPoint &point) const
Returns whether the given point is one of the stored defining points.
Definition predicates.hpp:478
constexpr Line()=default
Creates the degenerate line (0,0)--(0,0).
constexpr bool isDegenerate() const
Returns whether the defining points coincide.
Definition predicates.hpp:451
constexpr Halfplane< PointType > halfplaneBelow() const
Returns the half-plane geometrically below this line.
Definition predicates.hpp:554
constexpr auto operator<=>(const Line &other) const
Provides an ordering compatible with geometric equality.
Definition predicates.hpp:428
constexpr bool operator==(const Line &other) const
Tests geometric equality of two lines.
Definition predicates.hpp:423
Directed infinite line with left/right side semantics plus optional line label.
Definition orientedline.hpp:53
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:531
constexpr bool operator==(const OrientedLine &other) const
Tests equality of the represented oriented line.
Definition predicates.hpp:565
constexpr Halfplane< PointType > leftHalfplane() const
Returns the half-plane on the left of the oriented line.
Definition predicates.hpp:702
constexpr const PointType & target() const
Returns the target defining point.
Definition orientedline.hpp:195
constexpr Halfplane< PointType > rightHalfplane() const
Returns the half-plane on the right of the oriented line.
Definition predicates.hpp:697
constexpr auto operator<=>(const OrientedLine &other) const
Provides an ordering compatible with oriented-line equality.
Definition predicates.hpp:570
constexpr bool collinear(const OtherPoint &point) const
Returns whether the given point is collinear with the oriented line.
Definition predicates.hpp:616
constexpr bool verticesContain(const OtherPoint &point) const
Returns whether the given point is one of the stored defining points.
Definition predicates.hpp:610
constexpr const PointType & max() const
Returns the lexicographically largest defining point.
Definition orientedline.hpp:216
constexpr OrientedLine()=default
Creates the degenerate oriented line (0,0)--(0,0).
constexpr std::partial_ordering orientation(const OtherPoint &point) const
Returns the orientation sign of a point with respect to the line.
Definition predicates.hpp:652
constexpr bool isDegenerate() const
Returns whether the defining points coincide.
Definition predicates.hpp:583
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 Halfplane< PointType > halfplaneBelow() const
Returns the half-plane geometrically below the supporting line.
Definition predicates.hpp:692
constexpr bool isUndefined() const
Returns whether the line is degenerate without collapsing to a point or to a segment.
Definition predicates.hpp:588
constexpr bool isVertical() const
Returns whether the line is vertical.
Definition predicates.hpp:593
constexpr const PointType & min() const
Returns the lexicographically smallest defining point.
Definition orientedline.hpp:207
constexpr bool isHorizontal() const
Returns whether the line is horizontal.
Definition predicates.hpp:598
constexpr Halfplane< PointType > halfplaneAbove() const
Returns the half-plane geometrically above the supporting line.
Definition predicates.hpp:687
constexpr bool parallel(const OtherLine &other) const
Returns whether the given line is parallel to the oriented line.
Definition predicates.hpp:658
constexpr Halfplane< PointType > rightHalfplane() const
Returns the half-plane on the right of the segment direction.
Definition predicates.hpp:407
constexpr const PointType & min() const
Returns the lexicographically smallest endpoint.
Definition orientedsegment.hpp:202
constexpr bool verticesContain(const OtherPoint &point) const
Returns whether one endpoint equals the given point.
Definition predicates.hpp:315
constexpr bool containsEndpoint(const OtherPoint &point) const
Returns whether the given point is one endpoint.
Definition predicates.hpp:321
constexpr const PointType & source() const
Returns the source endpoint.
Definition orientedsegment.hpp:178
constexpr bool isUndefined() const
Returns whether the segment is degenerate without collapsing to a point or to a segment.
Definition predicates.hpp:299
constexpr bool isDegenerate() const
Returns whether both endpoints coincide.
Definition predicates.hpp:281
constexpr const PointType & max() const
Returns the lexicographically largest endpoint.
Definition orientedsegment.hpp:211
constexpr std::partial_ordering orientation(const OtherPoint &point) const
Returns the orientation sign of a point with respect to the segment.
Definition predicates.hpp:372
constexpr std::optional< PointType > getIfPoint() const
Returns the point the segment collapses to, if it does.
Definition predicates.hpp:291
constexpr bool isPoint() const
Returns whether the segment collapses to a single point.
Definition predicates.hpp:286
constexpr const PointType & target() const
Returns the target endpoint.
Definition orientedsegment.hpp:190
constexpr bool isVertical() const
Returns whether the segment is vertical.
Definition predicates.hpp:304
constexpr Halfplane< PointType > leftHalfplane() const
Returns the half-plane on the left of the segment direction.
Definition predicates.hpp:412
constexpr bool containsCollinear(const OtherPoint &point) const
Returns whether the segment contains the given point that is collinear with the segment.
Definition predicates.hpp:327
constexpr bool isHorizontal() const
Returns whether the segment is horizontal.
Definition predicates.hpp:309
constexpr bool collinear(const OtherPoint &point) const
Returns whether the given point is collinear with the oriented segment.
Definition predicates.hpp:333
constexpr bool parallel(const OtherSegment &other) const
Returns whether the given segment is parallel to the oriented segment.
Definition predicates.hpp:378
Two-dimensional point with optional label payload.
Definition point.hpp:129
constexpr bool operator==(const OtherPoint &other) const
Tests coordinate equality.
Definition predicates.hpp:30
constexpr std::strong_ordering operator<=>(const OtherPoint &other) const
Provides lexicographic ordering on (x, y).
Definition predicates.hpp:38
Half-infinite line starting from one source point plus optional ray label.
Definition ray.hpp:51
constexpr Halfplane< PointType > halfplaneAbove() const
Returns the half-plane geometrically above the supporting line.
Definition predicates.hpp:843
constexpr Halfplane< PointType > leftHalfplane() const
Returns the half-plane on the left of the ray direction.
Definition predicates.hpp:858
constexpr bool isVertical() const
Returns whether the ray is vertical.
Definition predicates.hpp:737
constexpr Halfplane< PointType > rightHalfplane() const
Returns the half-plane on the right of the ray direction.
Definition predicates.hpp:853
constexpr std::partial_ordering orientation(const OtherPoint &point) const
Returns the orientation sign of a point with respect to the ray.
Definition predicates.hpp:802
constexpr bool collinear(const OtherPoint &point) const
Returns whether the given point is collinear with the ray.
Definition predicates.hpp:766
constexpr bool operator==(const Ray &other) const
Tests equality of the represented ray.
Definition predicates.hpp:713
constexpr bool parallel(const OtherLine &other) const
Returns whether the given line is parallel to the ray.
Definition predicates.hpp:808
constexpr bool containsCollinear(const OtherPoint &point) const
Returns whether the ray contains the given point that is collinear with the ray.
Definition predicates.hpp:754
constexpr Ray()=default
Creates the degenerate ray (0,0)--(0,0)->.
constexpr auto operator<=>(const Ray &other) const
Provides an ordering compatible with ray equality.
Definition predicates.hpp:718
constexpr bool isDegenerate() const
Returns whether the defining points coincide.
Definition predicates.hpp:727
constexpr const PointType & max() const
Returns the lexicographically largest stored defining point.
Definition ray.hpp:214
constexpr const PointType & target() const
Returns the second stored point defining the direction.
Definition ray.hpp:193
constexpr bool verticesContain(const OtherPoint &point) const
Returns whether the given point is one of the stored defining points.
Definition predicates.hpp:748
constexpr bool isHorizontal() const
Returns whether the ray is horizontal.
Definition predicates.hpp:742
constexpr Halfplane< PointType > halfplaneBelow() const
Returns the half-plane geometrically below the supporting line.
Definition predicates.hpp:848
constexpr const PointType & min() const
Returns the lexicographically smallest stored defining point.
Definition ray.hpp:205
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:625
constexpr Line< PointType > asLine() const
Returns the supporting line without orientation.
Definition ray.hpp:319
constexpr bool isUndefined() const
Returns whether the ray is degenerate without collapsing to a point or to a segment.
Definition predicates.hpp:732
constexpr const PointType & source() const
Returns the source point of the ray.
Definition ray.hpp:181
constexpr std::optional< PointType > getIfPoint() const
Returns the point the rectangle collapses to, if it does.
Definition predicates.hpp:881
constexpr bool verticesContain(const OtherPoint &point) const
Returns whether a point is one of the rectangle vertices.
Definition predicates.hpp:921
std::conditional_t< Oriented, OrientedSegment< PointType >, Segment< PointType > > BoundaryType
Selects unordered or oriented boundary segments.
Definition rectangle.hpp:88
constexpr bool isPoint() const
Returns whether the rectangle collapses to a single point.
Definition predicates.hpp:876
constexpr bool isDegenerate() const
Returns whether the rectangle has empty interior.
Definition predicates.hpp:869
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 bool isSegment() const
Returns whether the rectangle collapses to a non-degenerate segment.
Definition predicates.hpp:889
constexpr bool isUndefined() const
Returns whether the rectangle is degenerate without collapsing to a point or to a segment.
Definition predicates.hpp:903
constexpr const PointType & max() const
Returns the maximum corner (max x, max y).
Definition rectangle.hpp:359
constexpr std::optional< BoundaryType< false > > getIfSegment() const
Returns the segment the rectangle collapses to, if it does.
Definition predicates.hpp:895
Unoriented closed segment between two endpoints plus optional segment label.
Definition segment.hpp:58
constexpr bool verticesContain(const OtherPoint &point) const
Returns whether one endpoint equals the given point.
Definition predicates.hpp:149
constexpr bool isDegenerate() const
Returns whether both endpoints coincide.
Definition predicates.hpp:54
constexpr bool isUndefined() const
Returns whether the segment is degenerate without collapsing to a point or to a segment.
Definition predicates.hpp:72
constexpr bool containsCollinear(const OtherPoint &point) const
Returns whether the segment contains the given point that is collinear with the segment.
Definition predicates.hpp:161
constexpr bool isHorizontal() const
Returns whether the segment is horizontal.
Definition predicates.hpp:82
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
constexpr bool isPoint() const
Returns whether the segment collapses to a single point.
Definition predicates.hpp:59
constexpr bool containsEndpoint(const OtherPoint &point) const
Returns whether the given point is one endpoint.
Definition predicates.hpp:155
constexpr bool collinear(const OtherPoint &point) const
Returns whether the given point lies on the supporting line.
Definition predicates.hpp:167
constexpr bool isVertical() const
Returns whether the segment is vertical.
Definition predicates.hpp:77
constexpr bool parallel(const OtherSegment &other) const
Returns whether another segment is parallel to this one.
Definition predicates.hpp:182
constexpr std::optional< PointType > getIfPoint() const
Returns the point the segment collapses to, if it does.
Definition predicates.hpp:64
constexpr bool verticesContain(const OtherPoint &point) const
Tests whether a point equals one of the vertices.
Definition predicates.hpp:270
constexpr bool isUndefined() const
Returns whether the triangle is degenerate without collapsing to a point or to a segment.
Definition predicates.hpp:264
constexpr const PointType & b() const
Returns the second vertex.
Definition triangle.hpp:217
constexpr bool isPoint() const
Returns whether the triangle collapses to a single point.
Definition predicates.hpp:236
constexpr const PointType & a() const
Returns the first vertex.
Definition triangle.hpp:208
constexpr bool isSegment() const
Returns whether the triangle collapses to a non-degenerate segment.
Definition predicates.hpp:249
constexpr std::optional< BoundaryType< false > > getIfSegment() const
Returns the segment the triangle collapses to, if it does.
Definition predicates.hpp:255
constexpr bool isDegenerate() const
Tests whether the three vertices are collinear.
Definition predicates.hpp:223
constexpr std::optional< PointType > getIfPoint() const
Returns the point the triangle collapses to, if it does.
Definition predicates.hpp:241
std::conditional_t< Oriented, OrientedSegment< PointType >, Segment< PointType > > BoundaryType
Definition triangle.hpp:71
constexpr const PointType & c() const
Returns the third vertex.
Definition triangle.hpp:226