Pangolin
Header-only C++20 plane computational geometry library
Loading...
Searching...
No Matches
interiorcontains.hpp
Go to the documentation of this file.
1#pragma once
2
4
9
10#include <limits>
12
13
14namespace pgl {
15
21
22template <class Number, class Label>
23template<PointConcept OtherPoint>
24constexpr bool Point<Number, Label>::interiorContains(const OtherPoint& other) const {
25 return contains(other);
26}
27
28template <class Number, class Label>
29template<SegmentConcept OtherSegment>
30constexpr bool Point<Number, Label>::interiorContains(const OtherSegment& other) const {
31 return contains(other);
32}
33
34template <class Number, class Label>
35template<OrientedSegmentConcept OtherOrientedSegment>
36constexpr bool Point<Number, Label>::interiorContains(const OtherOrientedSegment& other) const {
37 return contains(other);
38}
39
40template <class Number, class Label>
41template<LineConcept OtherLine>
42constexpr bool Point<Number, Label>::interiorContains(const OtherLine& other) const {
43 return contains(other);
44}
45
46template <class Number, class Label>
47template<OrientedLineConcept OtherOrientedLine>
48constexpr bool Point<Number, Label>::interiorContains(const OtherOrientedLine& other) const {
49 return contains(other);
50}
51
52template <class Number, class Label>
53template<RayConcept OtherRay>
54constexpr bool Point<Number, Label>::interiorContains(const OtherRay& other) const {
55 return contains(other);
56}
57
58template <class Number, class Label>
59template<HalfplaneConcept OtherHalfplane>
60constexpr bool Point<Number, Label>::interiorContains(const OtherHalfplane& other) const {
61 return contains(other);
62}
63
64template <class Number, class Label>
65template<RectangleConcept OtherRectangle>
66constexpr bool Point<Number, Label>::interiorContains(const OtherRectangle& other) const {
67 if (other.empty()) {
68 // The empty set is a subset of every shape, its boundary and its
69 // interior alike.
70 return true;
71 }
72 return contains(other);
73}
74
75template <class Number, class Label>
76template<TriangleConcept OtherTriangle>
77constexpr bool Point<Number, Label>::interiorContains(const OtherTriangle& other) const {
78 return contains(other);
79}
80
81template <class Number, class Label>
82template<ConvexConcept OtherConvex>
83constexpr bool Point<Number, Label>::interiorContains(const OtherConvex& other) const {
84 return contains(other);
85}
86
87template <class Number, class Label>
88template<PolygonConcept OtherPolygon>
89constexpr bool Point<Number, Label>::interiorContains(const OtherPolygon& other) const {
90 return contains(other);
91}
92
93template <class Number, class Label>
94template<DiskConcept OtherDisk>
95constexpr bool Point<Number, Label>::interiorContains(const OtherDisk& other) const {
96 // The interior of a point is the point itself, so this matches contains:
97 // it holds only for a disk that degenerates to this very point.
98 return other.a() == other.b() && other.b() == other.c() && contains(other.a());
99}
100
107
108template <class PointType, class LabelType>
109template<PointConcept OtherPoint>
110constexpr bool Segment<PointType, LabelType>::interiorContains(const OtherPoint& point) const {
111 return !boundaryContains(point) && contains(point);
112}
113
114template <class PointType, class LabelType>
115template<SegmentConcept OtherSegment>
116constexpr bool Segment<PointType, LabelType>::interiorContains(const OtherSegment& other) const {
117 return interiorContains(other.min()) && interiorContains(other.max());
118}
119
120template <class PointType, class LabelType>
121template<OrientedSegmentConcept OtherOrientedSegment>
122constexpr bool Segment<PointType, LabelType>::interiorContains(const OtherOrientedSegment& other) const {
123 return interiorContains(other.source()) && interiorContains(other.target());
124}
125
126template <class PointType, class LabelType>
127template<TriangleConcept OtherTriangle>
128constexpr bool Segment<PointType, LabelType>::interiorContains(const OtherTriangle& other) const {
129 return interiorContains(other.a()) && interiorContains(other.b()) && interiorContains(other.c());
130}
131
132template <class PointType, class LabelType>
133template<PointConcept OtherPoint>
135 return std::visit(
136 [this](const auto& value) {
137 return interiorContains(value);
138 },
139 other.variant());
140}
141
147
148template <class PointType, class LabelType>
149template<PointConcept OtherPoint>
150constexpr bool Triangle<PointType, LabelType>::interiorContains(const OtherPoint& point) const {
151 return !isDegenerate() && contains(point) && !boundaryContains(point);
152}
153
154template <class PointType, class LabelType>
155template<SegmentConcept OtherSegment>
156constexpr bool Triangle<PointType, LabelType>::interiorContains(const OtherSegment& other) const {
157 return interiorContains(other.min()) && interiorContains(other.max());
158}
159
160template <class PointType, class LabelType>
161template<OrientedSegmentConcept OtherOrientedSegment>
162constexpr bool Triangle<PointType, LabelType>::interiorContains(const OtherOrientedSegment& other) const {
163 return interiorContains(other.source()) && interiorContains(other.target());
164}
165
166template <class PointType, class LabelType>
167template<LineConcept OtherLine>
168constexpr bool Triangle<PointType, LabelType>::interiorContains(const OtherLine& other) const {
169 return other.isDegenerate() && interiorContains(other.min());
170}
171
172template <class PointType, class LabelType>
173template<OrientedLineConcept OtherOrientedLine>
174constexpr bool Triangle<PointType, LabelType>::interiorContains(const OtherOrientedLine& other) const {
175 return other.isDegenerate() && interiorContains(other.source());
176}
177
178template <class PointType, class LabelType>
179template<RayConcept OtherRay>
180constexpr bool Triangle<PointType, LabelType>::interiorContains(const OtherRay& other) const {
181 return other.isDegenerate() && interiorContains(other.source());
182}
183
184template <class PointType, class LabelType>
185template<HalfplaneConcept OtherHalfplane>
186constexpr bool Triangle<PointType, LabelType>::interiorContains(const OtherHalfplane& other) const {
187 return other.isDegenerate() && interiorContains(other.source());
188}
189
190template <class PointType, class LabelType>
191template<RectangleConcept OtherRectangle>
192constexpr bool Triangle<PointType, LabelType>::interiorContains(const OtherRectangle& other) const {
193 if (other.empty()) {
194 // The empty set is a subset of every shape, its boundary and its
195 // interior alike.
196 return true;
197 }
198 const auto vertices = other.vertices();
199 for (const auto& vertex : vertices) {
200 if (!interiorContains(vertex)) {
201 return false;
202 }
203 }
204 return true;
205}
206
207template <class PointType, class LabelType>
208template<TriangleConcept OtherTriangle>
209constexpr bool Triangle<PointType, LabelType>::interiorContains(const OtherTriangle& other) const {
210 return interiorContains(other.a()) && interiorContains(other.b()) && interiorContains(other.c());
211}
212
213template <class PointType, class LabelType>
214template<ConvexConcept OtherConvex>
215constexpr bool Triangle<PointType, LabelType>::interiorContains(const OtherConvex& other) const {
216 if (other.size() == 0) {
217 return true;
218 }
219 if (!bbox().interiorContains(other.bbox())) {
220 return false;
221 }
222 // The triangle is convex, so it interior-contains the convex iff it
223 // interior-contains every vertex.
224 for (std::size_t i = 0; i < other.size(); ++i) {
225 if (!interiorContains(other[i])) {
226 return false;
227 }
228 }
229 return true;
230}
231
237
238template <class PointType, class LabelType>
239template<PointConcept OtherPoint>
240constexpr bool OrientedSegment<PointType, LabelType>::interiorContains(const OtherPoint& point) const {
241 return !boundaryContains(point) && contains(point);
242}
243
244template <class PointType, class LabelType>
245template<SegmentConcept OtherSegment>
246constexpr bool OrientedSegment<PointType, LabelType>::interiorContains(const OtherSegment& other) const {
247 return interiorContains(other.min()) && interiorContains(other.max());
248}
249
250template <class PointType, class LabelType>
251template<OrientedSegmentConcept OtherOrientedSegment>
252constexpr bool OrientedSegment<PointType, LabelType>::interiorContains(const OtherOrientedSegment& other) const {
253 return interiorContains(other.source()) && interiorContains(other.target());
254}
255
256template <class PointType, class LabelType>
257template<LineConcept OtherLine>
258constexpr bool OrientedSegment<PointType, LabelType>::interiorContains(const OtherLine& other) const {
259 return other.isDegenerate() && interiorContains(other.min());
260}
261
262template <class PointType, class LabelType>
263template<OrientedLineConcept OtherOrientedLine>
264constexpr bool OrientedSegment<PointType, LabelType>::interiorContains(const OtherOrientedLine& other) const {
265 return other.isDegenerate() && interiorContains(other.source());
266}
267
268template <class PointType, class LabelType>
269template<RayConcept OtherRay>
270constexpr bool OrientedSegment<PointType, LabelType>::interiorContains(const OtherRay& other) const {
271 return other.isDegenerate() && interiorContains(other.source());
272}
273
274template <class PointType, class LabelType>
275template<HalfplaneConcept OtherHalfplane>
276constexpr bool OrientedSegment<PointType, LabelType>::interiorContains(const OtherHalfplane& other) const {
277 return other.isDegenerate() && interiorContains(other.source());
278}
279
280template <class PointType, class LabelType>
281template<RectangleConcept OtherRectangle>
282constexpr bool OrientedSegment<PointType, LabelType>::interiorContains(const OtherRectangle& other) const {
283 if (other.empty()) {
284 // The empty set is a subset of every shape, its boundary and its
285 // interior alike.
286 return true;
287 }
288 // min/max alone would miss the other two corners; defer to the convex view.
289 return interiorContains(other.asConvex());
290}
291
292template <class PointType, class LabelType>
293template<TriangleConcept OtherTriangle>
294constexpr bool OrientedSegment<PointType, LabelType>::interiorContains(const OtherTriangle& other) const {
295 return interiorContains(other.a()) && interiorContains(other.b()) && interiorContains(other.c());
296}
297
298template <class PointType, class LabelType>
299template<ConvexConcept OtherConvex>
300constexpr bool OrientedSegment<PointType, LabelType>::interiorContains(const OtherConvex& other) const {
301 // A convex with area (more than two vertices) cannot fit in a 1D interior.
302 // Otherwise the segment is convex, so it interior-contains the convex iff it
303 // interior-contains every vertex.
304 if (other.size() > 2) {
305 return false;
306 }
307 for (std::size_t i = 0; i < other.size(); ++i) {
308 if (!interiorContains(other[i])) {
309 return false;
310 }
311 }
312 return true;
313}
314
320
321template <class PointType, class LabelType>
322template<PointConcept OtherPoint>
323constexpr bool Line<PointType, LabelType>::interiorContains(const OtherPoint& point) const {
324 return contains(point);
325}
326
327template <class PointType, class LabelType>
328template<LineConcept OtherLine>
329constexpr bool Line<PointType, LabelType>::interiorContains(const OtherLine& other) const {
330 return contains(other);
331}
332
333template <class PointType, class LabelType>
334template<SegmentConcept OtherSegment>
335constexpr bool Line<PointType, LabelType>::interiorContains(const OtherSegment& other) const {
336 return contains(other);
337}
338
339template <class PointType, class LabelType>
340template<OrientedSegmentConcept OtherOrientedSegment>
341constexpr bool Line<PointType, LabelType>::interiorContains(const OtherOrientedSegment& other) const {
342 return contains(other);
343}
344
345template <class PointType, class LabelType>
346template<OrientedLineConcept OtherOrientedLine>
347constexpr bool Line<PointType, LabelType>::interiorContains(const OtherOrientedLine& other) const {
348 return contains(other);
349}
350
351template <class PointType, class LabelType>
352template<RayConcept OtherRay>
353constexpr bool Line<PointType, LabelType>::interiorContains(const OtherRay& other) const {
354 return contains(other);
355}
356
357template <class PointType, class LabelType>
358template<HalfplaneConcept OtherHalfplane>
359constexpr bool Line<PointType, LabelType>::interiorContains(const OtherHalfplane& other) const {
360 return contains(other);
361}
362
363template <class PointType, class LabelType>
364template<RectangleConcept OtherRectangle>
365constexpr bool Line<PointType, LabelType>::interiorContains(const OtherRectangle& other) const {
366 if (other.empty()) {
367 // The empty set is a subset of every shape, its boundary and its
368 // interior alike.
369 return true;
370 }
371 return contains(other);
372}
373
374template <class PointType, class LabelType>
375template<TriangleConcept OtherTriangle>
376constexpr bool Line<PointType, LabelType>::interiorContains(const OtherTriangle& other) const {
377 return contains(other);
378}
379
380template <class PointType, class LabelType>
381template<ConvexConcept OtherConvex>
382constexpr bool Line<PointType, LabelType>::interiorContains(const OtherConvex& other) const {
383 // A line has no boundary, so its interior is the whole line.
384 return contains(other);
385}
386
392
393template <class PointType, class LabelType>
394template<PointConcept OtherPoint>
395constexpr bool OrientedLine<PointType, LabelType>::interiorContains(const OtherPoint& point) const {
396 return contains(point);
397}
398
399template <class PointType, class LabelType>
400template<LineConcept OtherLine>
401constexpr bool OrientedLine<PointType, LabelType>::interiorContains(const OtherLine& other) const {
402 return contains(other);
403}
404
405template <class PointType, class LabelType>
406template<OrientedLineConcept OtherOrientedLine>
407constexpr bool OrientedLine<PointType, LabelType>::interiorContains(const OtherOrientedLine& other) const {
408 return contains(other);
409}
410
411template <class PointType, class LabelType>
412template<SegmentConcept OtherSegment>
413constexpr bool OrientedLine<PointType, LabelType>::interiorContains(const OtherSegment& other) const {
414 return contains(other);
415}
416
417template <class PointType, class LabelType>
418template<OrientedSegmentConcept OtherOrientedSegment>
419constexpr bool OrientedLine<PointType, LabelType>::interiorContains(const OtherOrientedSegment& other) const {
420 return contains(other);
421}
422
423template <class PointType, class LabelType>
424template<RayConcept OtherRay>
425constexpr bool OrientedLine<PointType, LabelType>::interiorContains(const OtherRay& other) const {
426 return contains(other);
427}
428
429template <class PointType, class LabelType>
430template<HalfplaneConcept OtherHalfplane>
431constexpr bool OrientedLine<PointType, LabelType>::interiorContains(const OtherHalfplane& other) const {
432 return contains(other);
433}
434
435template <class PointType, class LabelType>
436template<RectangleConcept OtherRectangle>
437constexpr bool OrientedLine<PointType, LabelType>::interiorContains(const OtherRectangle& other) const {
438 if (other.empty()) {
439 // The empty set is a subset of every shape, its boundary and its
440 // interior alike.
441 return true;
442 }
443 return contains(other);
444}
445
446template <class PointType, class LabelType>
447template<TriangleConcept OtherTriangle>
448constexpr bool OrientedLine<PointType, LabelType>::interiorContains(const OtherTriangle& other) const {
449 return contains(other);
450}
451
452template <class PointType, class LabelType>
453template<ConvexConcept OtherConvex>
454constexpr bool OrientedLine<PointType, LabelType>::interiorContains(const OtherConvex& other) const {
455 // A line has no boundary, so its interior is the whole line.
456 return contains(other);
457}
458
464
465template <class PointType, class LabelType>
466template<PointConcept OtherPoint>
467constexpr bool Ray<PointType, LabelType>::interiorContains(const OtherPoint& point) const {
468 return contains(point) && !boundaryContains(point);
469}
470
471template <class PointType, class LabelType>
472template<LineConcept OtherLine>
473constexpr bool Ray<PointType, LabelType>::interiorContains(const OtherLine& other) const {
474 return other.isDegenerate() && interiorContains(other.min());
475}
476
477template <class PointType, class LabelType>
478template<OrientedLineConcept OtherOrientedLine>
479constexpr bool Ray<PointType, LabelType>::interiorContains(const OtherOrientedLine& other) const {
480 return other.isDegenerate() && interiorContains(other.source());
481}
482
483template <class PointType, class LabelType>
484template<SegmentConcept OtherSegment>
485constexpr bool Ray<PointType, LabelType>::interiorContains(const OtherSegment& other) const {
486 return interiorContains(other.min()) && interiorContains(other.max());
487}
488
489template <class PointType, class LabelType>
490template<OrientedSegmentConcept OtherOrientedSegment>
491constexpr bool Ray<PointType, LabelType>::interiorContains(const OtherOrientedSegment& other) const {
492 return interiorContains(other.source()) && interiorContains(other.target());
493}
494
495template <class PointType, class LabelType>
496template<RayConcept OtherRay>
497constexpr bool Ray<PointType, LabelType>::interiorContains(const OtherRay& other) const {
498 return interiorContains(other.source()) && contains(other.target());
499}
500
501template <class PointType, class LabelType>
502template<HalfplaneConcept OtherHalfplane>
503constexpr bool Ray<PointType, LabelType>::interiorContains(const OtherHalfplane& other) const {
504 return other.isDegenerate() && interiorContains(other.source());
505}
506
507template <class PointType, class LabelType>
508template<RectangleConcept OtherRectangle>
509constexpr bool Ray<PointType, LabelType>::interiorContains(const OtherRectangle& other) const {
510 if (other.empty()) {
511 // The empty set is a subset of every shape, its boundary and its
512 // interior alike.
513 return true;
514 }
515 // min/max alone would miss the other two corners; defer to the convex view.
516 return interiorContains(other.asConvex());
517}
518
519template <class PointType, class LabelType>
520template<TriangleConcept OtherTriangle>
521constexpr bool Ray<PointType, LabelType>::interiorContains(const OtherTriangle& other) const {
522 return interiorContains(other.a()) &&
523 interiorContains(other.b()) &&
524 interiorContains(other.c());
525}
526
527template <class PointType, class LabelType>
528template<ConvexConcept OtherConvex>
529constexpr bool Ray<PointType, LabelType>::interiorContains(const OtherConvex& other) const {
530 // A convex with area (more than two vertices) cannot fit in a 1D interior.
531 // Otherwise the ray is convex, so it interior-contains the convex iff it
532 // interior-contains every vertex.
533 if (other.size() > 2) {
534 return false;
535 }
536 for (std::size_t i = 0; i < other.size(); ++i) {
537 if (!interiorContains(other[i])) {
538 return false;
539 }
540 }
541 return true;
542}
543
549
550
551template <class PointType, class LabelType>
552template<PointConcept OtherPoint>
553constexpr bool Rectangle<PointType, LabelType>::interiorContains(const OtherPoint& point) const {
554 // The empty set has no interior, and it needs no case of its own: it
555 // contains no point, so the test below is already false for it.
556 return contains(point) && !boundaryContains(point);
557}
558
559template <class PointType, class LabelType>
560template<LineConcept OtherLine>
561constexpr bool Rectangle<PointType, LabelType>::interiorContains(const OtherLine& other) const {
562 if (empty()) {
563 // The empty set is a subset of itself and of nothing else.
564 return detail::coversNoPoint(other);
565 }
566 return other.isDegenerate() && interiorContains(other.min());
567}
568
569template <class PointType, class LabelType>
570template<OrientedLineConcept OtherOrientedLine>
571constexpr bool Rectangle<PointType, LabelType>::interiorContains(const OtherOrientedLine& other) const {
572 if (empty()) {
573 // The empty set is a subset of itself and of nothing else.
574 return detail::coversNoPoint(other);
575 }
576 return other.isDegenerate() && interiorContains(other.source());
577}
578
579template <class PointType, class LabelType>
580template<SegmentConcept OtherSegment>
581constexpr bool Rectangle<PointType, LabelType>::interiorContains(const OtherSegment& other) const {
582 if (empty()) {
583 // The empty set is a subset of itself and of nothing else.
584 return detail::coversNoPoint(other);
585 }
586 return interiorContains(other.min()) && interiorContains(other.max());
587}
588
589template <class PointType, class LabelType>
590template<OrientedSegmentConcept OtherOrientedSegment>
591constexpr bool Rectangle<PointType, LabelType>::interiorContains(const OtherOrientedSegment& other) const {
592 if (empty()) {
593 // The empty set is a subset of itself and of nothing else.
594 return detail::coversNoPoint(other);
595 }
596 return interiorContains(other.source()) && interiorContains(other.target());
597}
598
599template <class PointType, class LabelType>
600template<RayConcept OtherRay>
601constexpr bool Rectangle<PointType, LabelType>::interiorContains(const OtherRay& other) const {
602 if (empty()) {
603 // The empty set is a subset of itself and of nothing else.
604 return detail::coversNoPoint(other);
605 }
606 return other.isDegenerate() && interiorContains(other.source());
607}
608
609template <class PointType, class LabelType>
610template<HalfplaneConcept OtherHalfplane>
611constexpr bool Rectangle<PointType, LabelType>::interiorContains(const OtherHalfplane& other) const {
612 if (empty()) {
613 // The empty set is a subset of itself and of nothing else.
614 return detail::coversNoPoint(other);
615 }
616 return other.isDegenerate() && interiorContains(other.source());
617}
618
619template <class PointType, class LabelType>
620template<RectangleConcept OtherRectangle>
621constexpr bool Rectangle<PointType, LabelType>::interiorContains(const OtherRectangle& other) const {
622 // The empty set is a subset of every interior, so an empty operand is
623 // contained whatever its inverted corners do to the tests below. An empty
624 // *this needs no case of its own: it covers no point, so the corner tests
625 // already answer false, which is the right answer for every non-empty
626 // operand. The emptiness test trails the geometry because containment is
627 // usually decided without it.
628 return (interiorContains(other.min()) && interiorContains(other.max())) || other.empty();
629}
630
631template <class PointType, class LabelType>
632template<TriangleConcept OtherTriangle>
633constexpr bool Rectangle<PointType, LabelType>::interiorContains(const OtherTriangle& other) const {
634 if (empty()) {
635 // The empty set is a subset of itself and of nothing else.
636 return detail::coversNoPoint(other);
637 }
638 return interiorContains(other.a()) && interiorContains(other.b()) && interiorContains(other.c());
639}
640
641template <class PointType, class LabelType>
642template<ConvexConcept OtherConvex>
643constexpr bool Rectangle<PointType, LabelType>::interiorContains(const OtherConvex& other) const {
644 if (empty()) {
645 // The empty set is a subset of itself and of nothing else.
646 return detail::coversNoPoint(other);
647 }
648 // For an axis-aligned rectangle, containing the convex strictly is equivalent
649 // to containing its (axis-aligned) bounding box strictly.
650 return other.size() == 0 || interiorContains(other.bbox());
651}
652
658
659template <class PointType, class LabelType>
660template<PointConcept OtherPoint>
661constexpr bool Halfplane<PointType, LabelType>::interiorContains(const OtherPoint& point) const {
662 return contains(point) && !boundaryContains(point);
663}
664
665template <class PointType, class LabelType>
666template<LineConcept OtherLine>
667constexpr bool Halfplane<PointType, LabelType>::interiorContains(const OtherLine& other) const {
668 if (isDegenerate() || other.isDegenerate()) {
669 return other.isDegenerate() && interiorContains(other.min());
670 }
671 // Parallel to the boundary, i.e. the two endpoint determinants agree; the
672 // sign of their difference is one cross product of the two directions.
673 return crossSign(source(), target(), other.min(), other.max()) == 0 &&
674 interiorContains(other.min());
675}
676
677template <class PointType, class LabelType>
678template<OrientedLineConcept OtherOrientedLine>
679constexpr bool Halfplane<PointType, LabelType>::interiorContains(const OtherOrientedLine& other) const {
680 if (isDegenerate() || other.isDegenerate()) {
681 return other.isDegenerate() && interiorContains(other.source());
682 }
683 return crossSign(source(), target(), other.source(), other.target()) == 0 &&
684 interiorContains(other.source());
685}
686
687template <class PointType, class LabelType>
688template<SegmentConcept OtherSegment>
689constexpr bool Halfplane<PointType, LabelType>::interiorContains(const OtherSegment& other) const {
690 if (isDegenerate()) {
691 return false;
692 }
693 return interiorContains(other.min()) && interiorContains(other.max());
694}
695
696template <class PointType, class LabelType>
697template<OrientedSegmentConcept OtherOrientedSegment>
698constexpr bool Halfplane<PointType, LabelType>::interiorContains(const OtherOrientedSegment& other) const {
699 if (isDegenerate()) {
700 return false;
701 }
702 return interiorContains(other.source()) && interiorContains(other.target());
703}
704
705template <class PointType, class LabelType>
706template<RayConcept OtherRay>
707constexpr bool Halfplane<PointType, LabelType>::interiorContains(const OtherRay& other) const {
708 if (isDegenerate() || other.isDegenerate()) {
709 return false;
710 }
711 return orientationSign(source(), target(), other.source()) > 0 &&
712 !(crossSign(source(), target(), other.source(), other.target()) < 0);
713}
714
715template <class PointType, class LabelType>
716template<RectangleConcept OtherRectangle>
717constexpr bool Halfplane<PointType, LabelType>::interiorContains(const OtherRectangle& other) const {
718 if (other.empty()) {
719 // The empty set is a subset of every shape, its boundary and its
720 // interior alike.
721 return true;
722 }
723 if (isDegenerate()) {
724 return false;
725 }
726 const auto vertices = other.vertices();
727 for (const auto& vertex : vertices) {
728 if (!interiorContains(vertex)) {
729 return false;
730 }
731 }
732 return true;
733}
734
735template <class PointType, class LabelType>
736template<ConvexConcept OtherConvex>
737constexpr bool Halfplane<PointType, LabelType>::interiorContains(const OtherConvex& other) const {
738 if (other.size() == 0) {
739 return true;
740 }
741
742 return interiorContains(other[0]) && !static_cast<Line<PointType>>(*this).intersects(other);
743}
744
745template <class PointType, class LabelType>
746template<DiskConcept OtherDisk>
747constexpr bool Halfplane<PointType, LabelType>::interiorContains(const OtherDisk& other) const {
748 if (const auto center = other.getIfPoint()) {
749 // A radius-zero disk is its center; it has no interior point for the
750 // witness test below to find.
751 return interiorContains(*center);
752 }
753 // The closed disk lies in the open half-plane iff the boundary line does not
754 // touch the closed disk at all (so the disk is strictly off the boundary) and
755 // the disk is on the interior side (a point strictly inside the disk is in
756 // the open half-plane). Both tests are exact and division-free, avoiding the
757 // disk's rational center and radius; this is the strict version of
758 // contains(Disk), which only excludes the boundary line piercing the open
759 // disk.
760 return !asLine().intersects(other) && other.pointInsideInteriorContainedIn(*this);
761}
762
763template <class PointType, class LabelType>
764template<HalfplaneConcept OtherHalfplane>
765constexpr bool Halfplane<PointType, LabelType>::interiorContains(const OtherHalfplane& other) const {
766 if (isDegenerate() || other.isDegenerate()) {
767 return false;
768 }
769 // Mirrors contains(other): the boundaries must be parallel and face the
770 // same side, and then the whole parallel boundary line of `other` must lie
771 // strictly inside, which interiorContains(other.source()) tests exactly.
772 if (!asLine().parallel(other.asLine()) ||
773 dotSign(target() - source(), other.target() - other.source()) !=
774 std::partial_ordering::greater) {
775 return false;
776 }
777 return interiorContains(other.source());
778}
779
780template <class PointType, class LabelType>
781template<TriangleConcept OtherTriangle>
782constexpr bool Halfplane<PointType, LabelType>::interiorContains(const OtherTriangle& other) const {
783 return interiorContains(other.a()) && interiorContains(other.b()) && interiorContains(other.c());
784}
785
786
787// ---------------------------------------------------------------------------
788// Convex
789
790template <class PointType, class LabelType>
791template<PointConcept OtherPoint>
792constexpr bool Convex<PointType, LabelType>::interiorContains(const OtherPoint& point) const {
793 // A point is in the strict interior iff it is contained but not on
794 // the boundary. Both predicates are O(log n) and together they handle
795 // every edge case (including points on vertical edges at extreme x,
796 // where edgesAtX returns the horizontal extent rather than the
797 // vertical edge itself).
798 return contains(point) && !boundaryContains(point);
799}
800
801template <class PointType, class LabelType>
802template<SegmentConcept OtherSegment>
803constexpr bool Convex<PointType, LabelType>::interiorContains(const OtherSegment& other) const {
804 return interiorContains(other[0]) && interiorContains(other[1]);
805}
806
807template <class PointType, class LabelType>
808template<OrientedSegmentConcept OtherOrientedSegment>
809constexpr bool Convex<PointType, LabelType>::interiorContains(const OtherOrientedSegment& other) const {
810 return interiorContains(other[0]) && interiorContains(other[1]);
811}
812
813template <class PointType, class LabelType>
814template<LineConcept OtherLine>
815constexpr bool Convex<PointType, LabelType>::interiorContains(const OtherLine&) const {
816 return false;
817}
818
819template <class PointType, class LabelType>
820template<OrientedLineConcept OtherOrientedLine>
821constexpr bool Convex<PointType, LabelType>::interiorContains(const OtherOrientedLine&) const {
822 return false;
823}
824
825template <class PointType, class LabelType>
826template<RayConcept OtherRay>
827constexpr bool Convex<PointType, LabelType>::interiorContains(const OtherRay&) const {
828 return false;
829}
830
831template <class PointType, class LabelType>
832template<HalfplaneConcept OtherHalfplane>
833constexpr bool Convex<PointType, LabelType>::interiorContains(const OtherHalfplane&) const {
834 return false;
835}
836
837template <class PointType, class LabelType>
838template<RectangleConcept OtherRectangle>
839constexpr bool Convex<PointType, LabelType>::interiorContains(const OtherRectangle& other) const {
840 if (other.empty()) {
841 // The empty set is a subset of every shape, its boundary and its
842 // interior alike.
843 return true;
844 }
845 if (!bbox().interiorContains(other)) {
846 return false;
847 }
848 for (size_t i = 0; i < 4; ++i) {
849 if (!interiorContains(other[i])) {
850 return false;
851 }
852 }
853 return true;
854}
855
856template <class PointType, class LabelType>
857template<TriangleConcept OtherTriangle>
858constexpr bool Convex<PointType, LabelType>::interiorContains(const OtherTriangle& other) const {
859 if (!bbox().interiorContains(other)) {
860 return false;
861 }
862 for (size_t i = 0; i < 3; ++i) {
863 if (!interiorContains(other[i])) {
864 return false;
865 }
866 }
867 return true;
868}
869
870template <class PointType, class LabelType>
871template<ConvexConcept OtherConvex>
872constexpr bool Convex<PointType, LabelType>::interiorContains(const OtherConvex& other) const {
873 if (size() <= 2) {
874 return false;
875 }
876 if (other.size() == 0) {
877 return true;
878 }
879 if (!bbox().interiorContains(other.bbox())) {
880 return false;
881 }
882 if (other.size() == 1) {
883 return interiorContains(other[0]);
884 }
885 if (other.size() == 2) {
887 }
888
889 if (other.size() <= 2*size()) {
890 for (size_t i = 0; i < other.size(); ++i) {
891 if (!interiorContains(other[i])) {
892 return false;
893 }
894 }
895 } else {
896 for (const auto& edge : orientedEdgesView()) {
897 if (!edge.leftHalfplane().interiorContains(other)) {
898 return false;
899 }
900 }
901 }
902 return true;
903}
904
905template <class PointType, class LabelType>
906template<DiskConcept OtherDisk>
907constexpr bool Convex<PointType, LabelType>::interiorContains(const OtherDisk& other) const {
908 for (const auto& edge : orientedEdgesView()) {
909 if (!edge.leftHalfplane().interiorContains(other)) {
910 return false;
911 }
912 }
913 return true;
914}
915
916template <class PointType, class LabelType>
917template <PointConcept OtherPoint>
919 return std::visit(
920 [this](const auto& value) {
921 return this->interiorContains(value);
922 },
923 other.variant());
924}
925
926// ---------------------------------------------------------------------------
927// Polygon
928
929template <class PointType, class LabelType>
930template<PointConcept OtherPoint>
931constexpr bool Polygon<PointType, LabelType>::interiorContains(const OtherPoint& point) const {
932 // Strictly interior iff contained but not on the boundary (mirrors
933 // Convex::interiorContains). A polygon with fewer than three vertices has
934 // every contained point on its boundary, so this yields false there.
935 return contains(point) && !boundaryContains(point);
936}
937
938template <class PointType, class LabelType>
939template<SegmentConcept OtherSegment>
940constexpr bool Polygon<PointType, LabelType>::interiorContains(const OtherSegment& other) const {
941 if (size() < 3) {
942 return false;
943 }
944 // Both endpoints strictly inside, plus no boundary contact anywhere: a
945 // segment that grazes or crosses the boundary (e.g. through a reflex notch)
946 // is rejected even when both endpoints are interior.
947 if (!interiorContains(other.min()) || !interiorContains(other.max())) {
948 return false;
949 }
950 for (const auto& edge : edgesView()) {
951 if (other.intersects(edge)) {
952 return false;
953 }
954 }
955 return true;
956}
957
958template <class PointType, class LabelType>
959template<SegmentConcept OtherSegment>
960constexpr bool Polygon<PointType, LabelType>::interiorContainsInterior(const OtherSegment& other) const {
961 // The endpoint exception still requires the closed segment to be contained:
962 // endpoints may be on the boundary, never outside it. It also gives the
963 // intended point-containment answer for a degenerate segment.
964 if (!contains(other)) {
965 return false;
966 }
967 if (other.isDegenerate()) {
968 return true;
969 }
970
971 // Reject precisely the contacts between the polygon boundary and the open
972 // segment. Segment::interiorsIntersect catches crossings and positive-length
973 // overlaps in edge interiors; the vertex test catches a boundary contact at
974 // an edge endpoint. Both are exact orientation/order predicates and do not
975 // construct intersection coordinates.
976 for (const auto& edge : edgesView()) {
977 if (edge.interiorsIntersect(other) || other.interiorContains(edge.min())) {
978 return false;
979 }
980 }
981 return true;
982}
983
984template <class PointType, class LabelType>
985template<OrientedSegmentConcept OtherOrientedSegment>
986constexpr bool Polygon<PointType, LabelType>::interiorContains(const OtherOrientedSegment& other) const {
987 return interiorContains(Segment<typename OtherOrientedSegment::PointType>(other.source(), other.target()));
988}
989
990template <class PointType, class LabelType>
991template<LineConcept OtherLine>
992constexpr bool Polygon<PointType, LabelType>::interiorContains(const OtherLine& other) const {
993 return other.isDegenerate() && interiorContains(other.min());
994}
995
996template <class PointType, class LabelType>
997template<OrientedLineConcept OtherOrientedLine>
998constexpr bool Polygon<PointType, LabelType>::interiorContains(const OtherOrientedLine& other) const {
999 return other.isDegenerate() && interiorContains(other.source());
1000}
1001
1002template <class PointType, class LabelType>
1003template<RayConcept OtherRay>
1004constexpr bool Polygon<PointType, LabelType>::interiorContains(const OtherRay& other) const {
1005 return other.isDegenerate() && interiorContains(other.source());
1006}
1007
1008template <class PointType, class LabelType>
1009template<HalfplaneConcept OtherHalfplane>
1010constexpr bool Polygon<PointType, LabelType>::interiorContains(const OtherHalfplane& other) const {
1011 return other.isDegenerate() && interiorContains(other.source());
1012}
1013
1014// For a simple polygon (no holes) the region overloads reduce to an
1015// edge-by-edge interior check, mirroring the contains() overloads.
1016template <class PointType, class LabelType>
1017template<RectangleConcept OtherRectangle>
1018constexpr bool Polygon<PointType, LabelType>::interiorContains(const OtherRectangle& other) const {
1019 if (other.empty()) {
1020 // The empty set is a subset of every shape, its boundary and its
1021 // interior alike.
1022 return true;
1023 }
1024 for (std::size_t i = 0; i < other.size(); ++i) {
1025 if (!interiorContains(Segment<typename OtherRectangle::PointType>(other[i], other[(i + 1) % other.size()]))) {
1026 return false;
1027 }
1028 }
1029 return true;
1030}
1031
1032template <class PointType, class LabelType>
1033template<TriangleConcept OtherTriangle>
1034constexpr bool Polygon<PointType, LabelType>::interiorContains(const OtherTriangle& other) const {
1035 for (std::size_t i = 0; i < other.size(); ++i) {
1036 if (!interiorContains(Segment<typename OtherTriangle::PointType>(other[i], other[(i + 1) % other.size()]))) {
1037 return false;
1038 }
1039 }
1040 return true;
1041}
1042
1043// A convex polygon's boundary is exactly two lex-monotone chains — its lower and
1044// upper hull — so we can run the interiorContains(Polygon) criterion (one vertex
1045// strictly inside and the boundaries fully disjoint) without building a
1046// BoundaryChains decomposition (or an asPolygon copy) of the convex: just test
1047// this polygon's chains against those two known hull chains for any shared point.
1048template <class PointType, class LabelType>
1049template<ConvexConcept OtherConvex>
1050constexpr bool Polygon<PointType, LabelType>::interiorContains(const OtherConvex& other) const {
1051 using OtherPoint = typename OtherConvex::PointType;
1052 if (other.size() == 0) {
1053 return true;
1054 }
1055 if (!bbox().interiorContains(other.bbox())) {
1056 return false;
1057 }
1058 if (other.size() == 1) {
1059 return interiorContains(other[0]);
1060 }
1061
1062 if (!interiorContains(other[0])) {
1063 return false;
1064 }
1065
1066 const MonotoneChain<OtherPoint> lower = other.lowerHull();
1067 const MonotoneChain<OtherPoint> upper = other.upperHull();
1068
1069 BoundaryChains<Polygon> mine(*this);
1070 while (!mine.exhausted()) {
1071 const auto& chain = mine.produceNext();
1072 for (const MonotoneChain<OtherPoint>* their : {&lower, &upper}) {
1073 if (chain.intersects(*their)) {
1074 return false;
1075 }
1076 }
1077 }
1078
1079 return true;
1080}
1081
1082template <class PointType, class LabelType>
1083template<PolygonConcept OtherPolygon>
1084constexpr bool Polygon<PointType, LabelType>::interiorContains(const OtherPolygon& other) const {
1085 if (other.size() == 0) {
1086 return true;
1087 }
1088 if (!bbox().interiorContains(other.bbox())) {
1089 return false;
1090 }
1091 if (other.size() == 1) {
1092 return interiorContains(other[0]);
1093 }
1094
1095 if (!interiorContains(other[0])) {
1096 return false;
1097 }
1098
1099 return !boundariesIntersect(other);
1100}
1101
1102// ---------------------------------------------------------------------------
1103// Disk
1104
1105template <class PointType, class LabelType>
1106template<PointConcept OtherPoint>
1107constexpr bool Disk<PointType, LabelType>::interiorContains(const OtherPoint& point) const {
1108 return inCircleSign(a(), b(), c(), point) == std::partial_ordering::greater;
1109}
1110
1111template <class PointType, class LabelType>
1112template<SegmentConcept OtherSegment>
1113constexpr bool Disk<PointType, LabelType>::interiorContains(const OtherSegment& other) const {
1114 return interiorContains(other.min()) && interiorContains(other.max());
1115}
1116
1117template <class PointType, class LabelType>
1118template<OrientedSegmentConcept OtherOrientedSegment>
1119constexpr bool Disk<PointType, LabelType>::interiorContains(const OtherOrientedSegment& other) const {
1120 return interiorContains(other.source()) && interiorContains(other.target());
1121}
1122
1123template <class PointType, class LabelType>
1124template<LineConcept OtherLine>
1125constexpr bool Disk<PointType, LabelType>::interiorContains(const OtherLine&) const {
1126 return false;
1127}
1128
1129template <class PointType, class LabelType>
1130template<OrientedLineConcept OtherOrientedLine>
1131constexpr bool Disk<PointType, LabelType>::interiorContains(const OtherOrientedLine&) const {
1132 return false;
1133}
1134
1135template <class PointType, class LabelType>
1136template<RayConcept OtherRay>
1137constexpr bool Disk<PointType, LabelType>::interiorContains(const OtherRay&) const {
1138 return false;
1139}
1140
1141template <class PointType, class LabelType>
1142template<HalfplaneConcept OtherHalfplane>
1143constexpr bool Disk<PointType, LabelType>::interiorContains(const OtherHalfplane&) const {
1144 return false;
1145}
1146
1147template <class PointType, class LabelType>
1148template<TriangleConcept OtherTriangle>
1149constexpr bool Disk<PointType, LabelType>::interiorContains(const OtherTriangle& other) const {
1150 return interiorContains(other.a()) && interiorContains(other.b()) && interiorContains(other.c());
1151}
1152
1153template <class PointType, class LabelType>
1154template<RectangleConcept OtherRectangle>
1155constexpr bool Disk<PointType, LabelType>::interiorContains(const OtherRectangle& other) const {
1156 if (other.empty()) {
1157 // The empty set is a subset of every shape, its boundary and its
1158 // interior alike.
1159 return true;
1160 }
1161 const auto vertices = other.vertices();
1162 return interiorContains(vertices[0]) && interiorContains(vertices[1]) &&
1163 interiorContains(vertices[2]) && interiorContains(vertices[3]);
1164}
1165
1166template <class PointType, class LabelType>
1167template<ConvexConcept OtherConvex>
1168constexpr bool Disk<PointType, LabelType>::interiorContains(const OtherConvex& other) const {
1169 for (const auto& point : other) {
1170 if (!interiorContains(point)) {
1171 return false;
1172 }
1173 }
1174 return true;
1175}
1176
1177template <class PointType, class LabelType>
1178template<DiskConcept OtherDisk>
1179constexpr bool Disk<PointType, LabelType>::interiorContains(const OtherDisk& other) const {
1180 // The circumcenter and squared circumradius are generally rational, so they
1181 // must be evaluated exactly (truncating to an integer type gives wrong
1182 // answers for three-point disks); mirror intersects(Disk) and contains(Disk).
1183 using R = std::conditional_t<
1184 std::is_floating_point_v<NumberType> ||
1185 std::is_floating_point_v<typename OtherDisk::NumberType>,
1186 long double,
1188
1189 const R r1_sq = squaredRadius<R>();
1190 const R r2_sq = other.template squaredRadius<R>();
1191 if (r1_sq <= r2_sq) {
1192 return false;
1193 }
1194
1195 const R d2 = center<R>().template squaredDistance<R>(other.template center<R>());
1196 const R A = d2 - r1_sq - r2_sq;
1197 return A < R{} && A * A > R{4} * r1_sq * r2_sq;
1198}
1199
1200template <class PointType, class LabelType>
1201template<PolygonConcept OtherPolygon>
1202constexpr bool Convex<PointType, LabelType>::interiorContains(const OtherPolygon& other) const {
1203 if (size() <= 2) {
1204 return false;
1205 }
1206 for (const auto& vertex : other) {
1207 if (!interiorContains(vertex)) {
1208 return false;
1209 }
1210 }
1211 return true;
1212}
1213
1214
1215// --- asymmetric Disk/Polygon containment ---
1216//
1217// Oriented 1D shapes forward to their unoriented view. The remaining 1D shapes
1218// can only interior-contain a disk that has degenerated to a single point, or a
1219// polygon whose vertices all lie on the (relative) interior. The 2D convex
1220// shapes (Triangle, Rectangle, Disk, Halfplane) reuse the convex containment
1221// logic: a convex set interior-contains a polygon iff it interior-contains
1222// every vertex, and Triangle/Rectangle defer the disk case to their Convex view.
1223
1224template <class PointType, class LabelType>
1225template<DiskConcept OtherDisk>
1226constexpr bool OrientedSegment<PointType, LabelType>::interiorContains(const OtherDisk& other) const {
1227 return asSegment().interiorContains(other);
1228}
1229
1230template <class PointType, class LabelType>
1231template<PolygonConcept OtherPolygon>
1232constexpr bool OrientedSegment<PointType, LabelType>::interiorContains(const OtherPolygon& other) const {
1233 return asSegment().interiorContains(other);
1234}
1235
1236template <class PointType, class LabelType>
1237template<DiskConcept OtherDisk>
1238constexpr bool Line<PointType, LabelType>::interiorContains(const OtherDisk& other) const {
1239 // A line is 1D, so it interior-contains a disk only when the disk
1240 // degenerates to a single point lying on the line.
1241 return other.a() == other.b() && other.b() == other.c() && contains(other.a());
1242}
1243
1244template <class PointType, class LabelType>
1245template<PolygonConcept OtherPolygon>
1246constexpr bool Line<PointType, LabelType>::interiorContains(const OtherPolygon& other) const {
1247 // A line has no boundary, so its interior is the whole line.
1248 return contains(other);
1249}
1250
1251template <class PointType, class LabelType>
1252template<DiskConcept OtherDisk>
1253constexpr bool OrientedLine<PointType, LabelType>::interiorContains(const OtherDisk& other) const {
1254 return asLine().interiorContains(other);
1255}
1256
1257template <class PointType, class LabelType>
1258template<PolygonConcept OtherPolygon>
1259constexpr bool OrientedLine<PointType, LabelType>::interiorContains(const OtherPolygon& other) const {
1260 return asLine().interiorContains(other);
1261}
1262
1263template <class PointType, class LabelType>
1264template<DiskConcept OtherDisk>
1265constexpr bool Ray<PointType, LabelType>::interiorContains(const OtherDisk& other) const {
1266 // A ray is 1D, so it interior-contains a disk only when the disk
1267 // degenerates to a single point in the ray's interior.
1268 return other.a() == other.b() && other.b() == other.c() && interiorContains(other.a());
1269}
1270
1271template <class PointType, class LabelType>
1272template<PolygonConcept OtherPolygon>
1273constexpr bool Ray<PointType, LabelType>::interiorContains(const OtherPolygon& other) const {
1274 // A ray is 1D: a polygon fits in its interior only when degenerate (all
1275 // vertices collinear on the ray), which the per-vertex test captures.
1276 for (const auto& vertex : other) {
1277 if (!interiorContains(vertex)) {
1278 return false;
1279 }
1280 }
1281 return true;
1282}
1283
1284template <class PointType, class LabelType>
1285template<PolygonConcept OtherPolygon>
1286constexpr bool Halfplane<PointType, LabelType>::interiorContains(const OtherPolygon& other) const {
1287 if (isDegenerate()) {
1288 return false;
1289 }
1290 // The half-plane is convex, so it interior-contains the polygon iff it
1291 // interior-contains every vertex.
1292 for (const auto& vertex : other) {
1293 if (!interiorContains(vertex)) {
1294 return false;
1295 }
1296 }
1297 return true;
1298}
1299
1300template <class PointType, class LabelType>
1301template<DiskConcept OtherDisk>
1302constexpr bool Rectangle<PointType, LabelType>::interiorContains(const OtherDisk& other) const {
1303 if (empty()) {
1304 // The empty set is a subset of itself and of nothing else.
1305 return detail::coversNoPoint(other);
1306 }
1307 return asConvex().interiorContains(other);
1308}
1309
1310template <class PointType, class LabelType>
1311template<PolygonConcept OtherPolygon>
1312constexpr bool Rectangle<PointType, LabelType>::interiorContains(const OtherPolygon& other) const {
1313 if (empty()) {
1314 // The empty set is a subset of itself and of nothing else.
1315 return detail::coversNoPoint(other);
1316 }
1317 return asConvex().interiorContains(other);
1318}
1319
1320template <class PointType, class LabelType>
1321template<DiskConcept OtherDisk>
1322constexpr bool Triangle<PointType, LabelType>::interiorContains(const OtherDisk& other) const {
1323 return asConvex().interiorContains(other);
1324}
1325
1326template <class PointType, class LabelType>
1327template<PolygonConcept OtherPolygon>
1328constexpr bool Triangle<PointType, LabelType>::interiorContains(const OtherPolygon& other) const {
1329 return asConvex().interiorContains(other);
1330}
1331
1332template <class PointType, class LabelType>
1333template<PolygonConcept OtherPolygon>
1334constexpr bool Disk<PointType, LabelType>::interiorContains(const OtherPolygon& other) const {
1335 // The disk is convex, so it interior-contains the polygon iff it
1336 // interior-contains every vertex.
1337 for (const auto& vertex : other) {
1338 if (!interiorContains(vertex)) {
1339 return false;
1340 }
1341 }
1342 return true;
1343}
1344
1345template <class PointType, class LabelType>
1346template<DiskConcept OtherDisk>
1347constexpr bool Polygon<PointType, LabelType>::interiorContains(const OtherDisk& other) const {
1348 if (other.isDegenerate()) {
1349 return interiorContains(other.a());
1350 }
1351
1352 if (!interiorContains(other.a())) {
1353 return false;
1354 }
1355 for (const auto& edge : edgesView()) {
1356 if (other.intersects(edge)) {
1357 return false;
1358 }
1359 }
1360 return true;
1361}
1362
1368
1369template <class PointType, class LabelType, class Storage>
1370template<PointConcept OtherPoint>
1371constexpr bool MonotoneChain<PointType, LabelType, Storage>::interiorContains(const OtherPoint& point) const {
1372 return !boundaryContains(point) && contains(point);
1373}
1374
1375template <class PointType, class LabelType, class Storage>
1376template<SegmentConcept OtherSegment>
1377constexpr bool MonotoneChain<PointType, LabelType, Storage>::interiorContains(const OtherSegment& other) const {
1378 // Containment already puts every point of the segment on the chain; the
1379 // extreme chain vertices have degree one, so a contained segment avoids
1380 // the chain's boundary iff its endpoints do.
1381 return contains(other) && !boundaryContains(other.min()) && !boundaryContains(other.max());
1382}
1383
1384template <class PointType, class LabelType, class Storage>
1385template<OrientedSegmentConcept OtherOrientedSegment>
1386constexpr bool MonotoneChain<PointType, LabelType, Storage>::interiorContains(const OtherOrientedSegment& other) const {
1388}
1389
1390template <class PointType, class LabelType, class Storage>
1391template<LineConcept OtherLine>
1392constexpr bool MonotoneChain<PointType, LabelType, Storage>::interiorContains(const OtherLine& other) const {
1393 return other.isDegenerate() && interiorContains(other.min());
1394}
1395
1396template <class PointType, class LabelType, class Storage>
1397template<OrientedLineConcept OtherOrientedLine>
1398constexpr bool MonotoneChain<PointType, LabelType, Storage>::interiorContains(const OtherOrientedLine& other) const {
1399 return other.isDegenerate() && interiorContains(other.source());
1400}
1401
1402template <class PointType, class LabelType, class Storage>
1403template<RayConcept OtherRay>
1404constexpr bool MonotoneChain<PointType, LabelType, Storage>::interiorContains(const OtherRay& other) const {
1405 return other.isDegenerate() && interiorContains(other.source());
1406}
1407
1408template <class PointType, class LabelType, class Storage>
1409template<HalfplaneConcept OtherHalfplane>
1410constexpr bool MonotoneChain<PointType, LabelType, Storage>::interiorContains(const OtherHalfplane& other) const {
1411 return other.isDegenerate() && interiorContains(other.source());
1412}
1413
1414template <class PointType, class LabelType, class Storage>
1415template<TriangleConcept OtherTriangle>
1416constexpr bool MonotoneChain<PointType, LabelType, Storage>::interiorContains(const OtherTriangle& other) const {
1417 if (!other.isDegenerate()) {
1418 return false;
1419 }
1420 if (other.a() == other.c()) {
1421 return interiorContains(other.a());
1422 }
1424}
1425
1426template <class PointType, class LabelType, class Storage>
1427template<MonotoneChainConcept OtherChain>
1428constexpr bool MonotoneChain<PointType, LabelType, Storage>::interiorContains(const OtherChain& other) const {
1429 if (other.empty()) {
1430 return true;
1431 }
1432 // A contained chain is a connected subset of this chain, so it can only
1433 // reach this chain's extreme vertices through its own extremes.
1434 return contains(other) && !boundaryContains(other[0]) &&
1435 !boundaryContains(other[other.size() - 1]);
1436}
1437
1438template <class PointType, class LabelType, class Storage>
1439template<PointConcept OtherPoint>
1441 return std::visit(
1442 [this](const auto& value) {
1443 return this->interiorContains(value);
1444 },
1445 other.variant());
1446}
1447
1448template <class Number, class Label>
1449template<MonotoneChainConcept OtherChain>
1450constexpr bool Point<Number, Label>::interiorContains(const OtherChain& other) const {
1451 return contains(other);
1452}
1453
1454// The interiors below are convex sets, so they contain the chain iff they
1455// contain all of its vertices.
1456
1457template <class PointType, class LabelType>
1458template<MonotoneChainConcept OtherChain>
1459constexpr bool Segment<PointType, LabelType>::interiorContains(const OtherChain& other) const {
1460 for (const auto& vertex : other) {
1461 if (!interiorContains(vertex)) {
1462 return false;
1463 }
1464 }
1465 return true;
1466}
1467
1468template <class PointType, class LabelType>
1469template<MonotoneChainConcept OtherChain>
1470constexpr bool OrientedSegment<PointType, LabelType>::interiorContains(const OtherChain& other) const {
1471 return asSegment().interiorContains(other);
1472}
1473
1474template <class PointType, class LabelType>
1475template<MonotoneChainConcept OtherChain>
1476constexpr bool Line<PointType, LabelType>::interiorContains(const OtherChain& other) const {
1477 return contains(other);
1478}
1479
1480template <class PointType, class LabelType>
1481template<MonotoneChainConcept OtherChain>
1482constexpr bool OrientedLine<PointType, LabelType>::interiorContains(const OtherChain& other) const {
1483 return asLine().interiorContains(other);
1484}
1485
1486template <class PointType, class LabelType>
1487template<MonotoneChainConcept OtherChain>
1488constexpr bool Ray<PointType, LabelType>::interiorContains(const OtherChain& other) const {
1489 for (const auto& vertex : other) {
1490 if (!interiorContains(vertex)) {
1491 return false;
1492 }
1493 }
1494 return true;
1495}
1496
1497template <class PointType, class LabelType>
1498template<MonotoneChainConcept OtherChain>
1499constexpr bool Halfplane<PointType, LabelType>::interiorContains(const OtherChain& other) const {
1500 if (isDegenerate()) {
1501 return false;
1502 }
1503 for (const auto& vertex : other) {
1504 if (!interiorContains(vertex)) {
1505 return false;
1506 }
1507 }
1508 return true;
1509}
1510
1511template <class PointType, class LabelType>
1512template<MonotoneChainConcept OtherChain>
1513constexpr bool Rectangle<PointType, LabelType>::interiorContains(const OtherChain& other) const {
1514 if (empty()) {
1515 // The empty set is a subset of itself and of nothing else.
1516 return detail::coversNoPoint(other);
1517 }
1518 return asConvex().interiorContains(other);
1519}
1520
1521template <class PointType, class LabelType>
1522template<MonotoneChainConcept OtherChain>
1523constexpr bool Triangle<PointType, LabelType>::interiorContains(const OtherChain& other) const {
1524 return asConvex().interiorContains(other);
1525}
1526
1527template <class PointType, class LabelType>
1528template<MonotoneChainConcept OtherChain>
1529constexpr bool Disk<PointType, LabelType>::interiorContains(const OtherChain& other) const {
1530 for (const auto& vertex : other) {
1531 if (!interiorContains(vertex)) {
1532 return false;
1533 }
1534 }
1535 return true;
1536}
1537
1538template <class PointType, class LabelType>
1539template<MonotoneChainConcept OtherChain>
1540constexpr bool Convex<PointType, LabelType>::interiorContains(const OtherChain& other) const {
1541 if (size() <= 2) {
1542 return false;
1543 }
1544 for (const auto& vertex : other) {
1545 if (!interiorContains(vertex)) {
1546 return false;
1547 }
1548 }
1549 return true;
1550}
1551
1552// A polygon's interior is generally not convex, so it must interior-contain
1553// every chain edge.
1554template <class PointType, class LabelType>
1555template<MonotoneChainConcept OtherChain>
1556constexpr bool Polygon<PointType, LabelType>::interiorContains(const OtherChain& other) const {
1557 if (other.empty()) {
1558 return true;
1559 }
1560 if (other.size() == 1) {
1561 return interiorContains(other[0]);
1562 }
1563 for (std::size_t i = 0; i + 1 < other.size(); ++i) {
1564 if (!interiorContains(Segment<typename OtherChain::PointType>(other[i], other[i + 1]))) {
1565 return false;
1566 }
1567 }
1568 return true;
1569}
1570
1578
1579template <class PointType, class LabelType>
1580template<PointConcept OtherPoint>
1581constexpr bool Polyline<PointType, LabelType>::interiorContains(const OtherPoint& point) const {
1582 return !boundaryContains(point) && contains(point);
1583}
1584
1585template <class PointType, class LabelType>
1586template<SegmentConcept OtherSegment>
1587constexpr bool Polyline<PointType, LabelType>::interiorContains(const OtherSegment& other) const {
1588 // The interior is the polyline minus the two extreme points, so a
1589 // contained segment lies in it iff the segment avoids those points
1590 // entirely -- not just with its endpoints: the polyline may revisit an
1591 // extreme vertex in the middle of the segment.
1592 return contains(other) && !other.contains((*this)[0]) &&
1593 !other.contains((*this)[size() - 1]);
1594}
1595
1596template <class PointType, class LabelType>
1597template<OrientedSegmentConcept OtherOrientedSegment>
1598constexpr bool Polyline<PointType, LabelType>::interiorContains(const OtherOrientedSegment& other) const {
1600}
1601
1602template <class PointType, class LabelType>
1603template<LineConcept OtherLine>
1604constexpr bool Polyline<PointType, LabelType>::interiorContains(const OtherLine& other) const {
1605 return other.isDegenerate() && interiorContains(other.min());
1606}
1607
1608template <class PointType, class LabelType>
1609template<OrientedLineConcept OtherOrientedLine>
1610constexpr bool Polyline<PointType, LabelType>::interiorContains(const OtherOrientedLine& other) const {
1611 return other.isDegenerate() && interiorContains(other.source());
1612}
1613
1614template <class PointType, class LabelType>
1615template<RayConcept OtherRay>
1616constexpr bool Polyline<PointType, LabelType>::interiorContains(const OtherRay& other) const {
1617 return other.isDegenerate() && interiorContains(other.source());
1618}
1619
1620template <class PointType, class LabelType>
1621template<HalfplaneConcept OtherHalfplane>
1622constexpr bool Polyline<PointType, LabelType>::interiorContains(const OtherHalfplane& other) const {
1623 return other.isDegenerate() && interiorContains(other.source());
1624}
1625
1626template <class PointType, class LabelType>
1627template<TriangleConcept OtherTriangle>
1628constexpr bool Polyline<PointType, LabelType>::interiorContains(const OtherTriangle& other) const {
1629 if (!other.isDegenerate()) {
1630 return false;
1631 }
1632 if (other.a() == other.c()) {
1633 return interiorContains(other.a());
1634 }
1636}
1637
1638template <class PointType, class LabelType>
1639template<MonotoneChainConcept OtherChain>
1640constexpr bool Polyline<PointType, LabelType>::interiorContains(const OtherChain& other) const {
1641 if (other.empty()) {
1642 return true;
1643 }
1644 // Same set subtraction as the segment overload: the contained chain must
1645 // avoid both extreme points of this polyline entirely.
1646 return contains(other) && !other.contains((*this)[0]) &&
1647 !other.contains((*this)[size() - 1]);
1648}
1649
1650template <class PointType, class LabelType>
1651template<PolylineConcept OtherPolyline>
1652constexpr bool Polyline<PointType, LabelType>::interiorContains(const OtherPolyline& other) const {
1653 if (other.empty()) {
1654 return true;
1655 }
1656 // Same set subtraction as the segment overload: the contained polyline
1657 // must avoid both extreme points of this polyline entirely.
1658 return contains(other) && !other.contains((*this)[0]) &&
1659 !other.contains((*this)[size() - 1]);
1660}
1661
1662template <class PointType, class LabelType>
1663template<PointConcept OtherPoint>
1665 return std::visit(
1666 [this](const auto& value) {
1667 return this->interiorContains(value);
1668 },
1669 other.variant());
1670}
1671
1672template <class Number, class Label>
1673template<PolylineConcept OtherPolyline>
1674constexpr bool Point<Number, Label>::interiorContains(const OtherPolyline& other) const {
1675 return contains(other);
1676}
1677
1678// A segment's relative interior is convex, so it contains the polyline iff it
1679// contains all of its vertices.
1680template <class PointType, class LabelType>
1681template<PolylineConcept OtherPolyline>
1682constexpr bool Segment<PointType, LabelType>::interiorContains(const OtherPolyline& other) const {
1683 for (const auto& vertex : other) {
1684 if (!interiorContains(vertex)) {
1685 return false;
1686 }
1687 }
1688 return true;
1689}
1690
1691template <class PointType, class LabelType>
1692template<PolylineConcept OtherPolyline>
1693constexpr bool OrientedSegment<PointType, LabelType>::interiorContains(const OtherPolyline& other) const {
1694 return asSegment().interiorContains(other);
1695}
1696
1697template <class PointType, class LabelType>
1698template<PolylineConcept OtherPolyline>
1699constexpr bool Line<PointType, LabelType>::interiorContains(const OtherPolyline& other) const {
1700 return contains(other);
1701}
1702
1703template <class PointType, class LabelType>
1704template<PolylineConcept OtherPolyline>
1705constexpr bool OrientedLine<PointType, LabelType>::interiorContains(const OtherPolyline& other) const {
1706 return asLine().interiorContains(other);
1707}
1708
1709// The interiors below are convex sets, so they contain the polyline iff they
1710// contain all of its vertices.
1711
1712template <class PointType, class LabelType>
1713template<PolylineConcept OtherPolyline>
1714constexpr bool Ray<PointType, LabelType>::interiorContains(const OtherPolyline& other) const {
1715 for (const auto& vertex : other) {
1716 if (!interiorContains(vertex)) {
1717 return false;
1718 }
1719 }
1720 return true;
1721}
1722
1723template <class PointType, class LabelType>
1724template<PolylineConcept OtherPolyline>
1725constexpr bool Halfplane<PointType, LabelType>::interiorContains(const OtherPolyline& other) const {
1726 if (isDegenerate()) {
1727 return false;
1728 }
1729 for (const auto& vertex : other) {
1730 if (!interiorContains(vertex)) {
1731 return false;
1732 }
1733 }
1734 return true;
1735}
1736
1737template <class PointType, class LabelType>
1738template<PolylineConcept OtherPolyline>
1739constexpr bool Rectangle<PointType, LabelType>::interiorContains(const OtherPolyline& other) const {
1740 if (empty()) {
1741 // The empty set is a subset of itself and of nothing else.
1742 return detail::coversNoPoint(other);
1743 }
1744 return asConvex().interiorContains(other);
1745}
1746
1747template <class PointType, class LabelType>
1748template<PolylineConcept OtherPolyline>
1749constexpr bool Triangle<PointType, LabelType>::interiorContains(const OtherPolyline& other) const {
1750 return asConvex().interiorContains(other);
1751}
1752
1753template <class PointType, class LabelType>
1754template<PolylineConcept OtherPolyline>
1755constexpr bool Disk<PointType, LabelType>::interiorContains(const OtherPolyline& other) const {
1756 for (const auto& vertex : other) {
1757 if (!interiorContains(vertex)) {
1758 return false;
1759 }
1760 }
1761 return true;
1762}
1763
1764template <class PointType, class LabelType>
1765template<PolylineConcept OtherPolyline>
1766constexpr bool Convex<PointType, LabelType>::interiorContains(const OtherPolyline& other) const {
1767 if (size() <= 2) {
1768 return false;
1769 }
1770 for (const auto& vertex : other) {
1771 if (!interiorContains(vertex)) {
1772 return false;
1773 }
1774 }
1775 return true;
1776}
1777
1778// A contained polyline is a subset of the chain, so it can only reach the
1779// chain's extreme vertices as a point set; subtract them explicitly (the
1780// polyline may revisit such a point mid-sequence).
1781template <class PointType, class LabelType, class Storage>
1782template<PolylineConcept OtherPolyline>
1783constexpr bool MonotoneChain<PointType, LabelType, Storage>::interiorContains(const OtherPolyline& other) const {
1784 if (other.empty()) {
1785 return true;
1786 }
1787 return contains(other) && !other.contains((*this)[0]) &&
1788 !other.contains((*this)[size() - 1]);
1789}
1790
1791// A polygon's interior is generally not convex, so it must interior-contain
1792// every polyline edge.
1793template <class PointType, class LabelType>
1794template<PolylineConcept OtherPolyline>
1795constexpr bool Polygon<PointType, LabelType>::interiorContains(const OtherPolyline& other) const {
1796 if (other.empty()) {
1797 return true;
1798 }
1799 if (other.size() == 1) {
1800 return interiorContains(other[0]);
1801 }
1802 for (std::size_t i = 0; i + 1 < other.size(); ++i) {
1803 if (!interiorContains(Segment<typename OtherPolyline::PointType>(other[i], other[i + 1]))) {
1804 return false;
1805 }
1806 }
1807 return true;
1808}
1809
1810
1811// ---------------------------------------------------------------------------
1812// HalfplaneIntersection
1813
1814template <class PointType, class LabelType>
1815template <PointConcept OtherPoint>
1816constexpr bool HalfplaneIntersection<PointType, LabelType>::interiorContains(const OtherPoint& point) const {
1817 // A degenerate region has empty interior, and then no point tests
1818 // strictly inside all constraints, so no special handling is needed.
1819 return pointStatus(point) > 0;
1820}
1821
1822template <class PointType, class LabelType>
1823template <SegmentConcept OtherSegment>
1824constexpr bool HalfplaneIntersection<PointType, LabelType>::interiorContains(const OtherSegment& other) const {
1825 // The interior of the region is convex, so containing both endpoints
1826 // contains the segment.
1827 return interiorContains(other[0]) && interiorContains(other[1]);
1828}
1829
1830template <class PointType, class LabelType>
1831template <OrientedSegmentConcept OtherOrientedSegment>
1832constexpr bool HalfplaneIntersection<PointType, LabelType>::interiorContains(const OtherOrientedSegment& other) const {
1833 return interiorContains(other[0]) && interiorContains(other[1]);
1834}
1835
1836template <class PointType, class LabelType>
1837template <LineConcept OtherLine>
1838constexpr bool HalfplaneIntersection<PointType, LabelType>::interiorContains(const OtherLine& other) const {
1839 // Only constraints parallel to the line can strictly contain it, and the
1840 // canonical form stores at most one constraint per direction.
1841 if (empty() || size() > 2) {
1842 return false;
1843 }
1844 for (const auto& halfplane : halfplanes_) {
1845 if (!halfplane.interiorContains(other)) {
1846 return false;
1847 }
1848 }
1849 return true;
1850}
1851
1852template <class PointType, class LabelType>
1853template <OrientedLineConcept OtherOrientedLine>
1854constexpr bool HalfplaneIntersection<PointType, LabelType>::interiorContains(const OtherOrientedLine& other) const {
1855 return interiorContains(other.asLine());
1856}
1857
1858template <class PointType, class LabelType>
1859template <RayConcept OtherRay>
1860constexpr bool HalfplaneIntersection<PointType, LabelType>::interiorContains(const OtherRay& other) const {
1861 // Starting strictly inside and pointing into the recession cone keeps the
1862 // ray strictly inside: the distance to each boundary line is affine and
1863 // nonincreasing distances would eventually leave the region, so along a
1864 // recession direction each distance is nondecreasing.
1865 if (empty()) {
1866 return false;
1867 }
1868 if (!interiorContains(other.source())) {
1869 return false;
1870 }
1871 const Halfplane<typename OtherRay::PointType> forward(other.source(), other.target());
1872 return recessionContains(forward);
1873}
1874
1875template <class PointType, class LabelType>
1876template <HalfplaneConcept OtherHalfplane>
1877constexpr bool HalfplaneIntersection<PointType, LabelType>::interiorContains(const OtherHalfplane& other) const {
1878 // As with contains: only a same-direction constraint can contain a
1879 // half-plane, so at most one constraint may be stored.
1880 if (empty() || size() > 1) {
1881 return false;
1882 }
1883 return halfplanes_.empty() || halfplanes_[0].interiorContains(other);
1884}
1885
1886template <class PointType, class LabelType>
1887template <RectangleConcept OtherRectangle>
1888constexpr bool HalfplaneIntersection<PointType, LabelType>::interiorContains(const OtherRectangle& other) const {
1889 if (other.empty()) {
1890 // The empty set is a subset of every shape, its boundary and its
1891 // interior alike.
1892 return true;
1893 }
1894 // The interior of the region is convex, so containing the vertices
1895 // contains the rectangle.
1896 const auto vertices = other.vertices();
1897 for (const auto& vertex : vertices) {
1898 if (!interiorContains(vertex)) {
1899 return false;
1900 }
1901 }
1902 return true;
1903}
1904
1905template <class PointType, class LabelType>
1906template <TriangleConcept OtherTriangle>
1907constexpr bool HalfplaneIntersection<PointType, LabelType>::interiorContains(const OtherTriangle& other) const {
1908 return interiorContains(other.a()) && interiorContains(other.b()) && interiorContains(other.c());
1909}
1910
1911template <class PointType, class LabelType>
1912template <DiskConcept OtherDisk>
1913constexpr bool HalfplaneIntersection<PointType, LabelType>::interiorContains(const OtherDisk& other) const {
1914 // The interior of the region is the intersection of the constraints'
1915 // open interiors.
1916 if (empty()) {
1917 return false;
1918 }
1919 for (const auto& halfplane : halfplanes_) {
1920 if (!halfplane.interiorContains(other)) {
1921 return false;
1922 }
1923 }
1924 return true;
1925}
1926
1927template <class PointType, class LabelType>
1928template <ConvexConcept OtherConvex>
1929constexpr bool HalfplaneIntersection<PointType, LabelType>::interiorContains(const OtherConvex& other) const {
1930 for (std::size_t i = 0; i < other.size(); ++i) {
1931 if (!interiorContains(other[i])) {
1932 return false;
1933 }
1934 }
1935 return true;
1936}
1937
1938template <class PointType, class LabelType>
1939template <MonotoneChainConcept OtherChain>
1940constexpr bool HalfplaneIntersection<PointType, LabelType>::interiorContains(const OtherChain& other) const {
1941 for (std::size_t i = 0; i < other.size(); ++i) {
1942 if (!interiorContains(other[i])) {
1943 return false;
1944 }
1945 }
1946 return true;
1947}
1948
1949template <class PointType, class LabelType>
1950template <PolylineConcept OtherPolyline>
1951constexpr bool HalfplaneIntersection<PointType, LabelType>::interiorContains(const OtherPolyline& other) const {
1952 for (std::size_t i = 0; i < other.size(); ++i) {
1953 if (!interiorContains(other[i])) {
1954 return false;
1955 }
1956 }
1957 return true;
1958}
1959
1960template <class PointType, class LabelType>
1961template <PolygonConcept OtherPolygon>
1962constexpr bool HalfplaneIntersection<PointType, LabelType>::interiorContains(const OtherPolygon& other) const {
1963 // The interior of the region is convex, so containing the vertices
1964 // contains the polygon.
1965 for (std::size_t i = 0; i < other.size(); ++i) {
1966 if (!interiorContains(other[i])) {
1967 return false;
1968 }
1969 }
1970 return true;
1971}
1972
1973template <class PointType, class LabelType>
1974template <HalfplaneIntersectionConcept OtherRegion>
1975constexpr bool HalfplaneIntersection<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
1976 // The interior of the region is the intersection of the constraints' open
1977 // half-planes, so it contains the other region exactly when every
1978 // constraint's interior does. A degenerate region has two antiparallel
1979 // constraints with disjoint interiors, so it correctly contains only the
1980 // empty region.
1981 if (other.empty()) {
1982 return true;
1983 }
1984 if (empty()) {
1985 return false;
1986 }
1987 for (const auto& halfplane : halfplanes_) {
1988 if (!halfplane.interiorContains(other)) {
1989 return false;
1990 }
1991 }
1992 return true;
1993}
1994
1995template <class PointType, class LabelType>
1996template <PointConcept OtherPoint>
1998 return std::visit(
1999 [this](const auto& value) {
2000 return this->interiorContains(value);
2001 },
2002 other.variant());
2003}
2004
2005
2006// ---------------------------------------------------------------------------
2007// Reverse direction: lower-ranked shapes' interiors containing a
2008// HalfplaneIntersection.
2009//
2010// The empty region is a subset of every interior. A degenerate region reduces
2011// to its carrier shape; a full-dimensional region can only be inside the
2012// interior of a two-dimensional shape, where it reduces to strict half-plane
2013// containment tests or the region's convex-polygon form.
2014
2015namespace detail {
2016
2017// Dispatches interiorContains(carrier) over the degenerate region's carrier,
2018// treating alternatives without a matching overload as geometrically
2019// impossible.
2020template <class Shape2, class Region>
2021constexpr bool interiorContainsDegenerateRegion(const Shape2& shape, const Region& region) {
2022 return std::visit(
2023 [&shape](const auto& carrier) {
2024 if constexpr (requires { shape.interiorContains(carrier); }) {
2025 return shape.interiorContains(carrier);
2026 } else {
2027 (void)carrier;
2028 return false;
2029 }
2030 },
2031 degenerateRegionCarrier(region));
2032}
2033
2034} // namespace detail
2035
2036template <class Number, class Label>
2037template <HalfplaneIntersectionConcept OtherRegion>
2038constexpr bool Point<Number, Label>::interiorContains(const OtherRegion& other) const {
2039 // The interior of a point is the point itself.
2040 return contains(other);
2041}
2042
2043template <class PointType, class LabelType>
2044template <HalfplaneIntersectionConcept OtherRegion>
2045constexpr bool Segment<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2046 if (other.empty()) {
2047 return true;
2048 }
2049 if (!other.isDegenerate()) {
2050 return false;
2051 }
2052 return detail::interiorContainsDegenerateRegion(*this, other);
2053}
2054
2055template <class PointType, class LabelType>
2056template <HalfplaneIntersectionConcept OtherRegion>
2057constexpr bool OrientedSegment<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2058 return asSegment().interiorContains(other);
2059}
2060
2061template <class PointType, class LabelType>
2062template <HalfplaneIntersectionConcept OtherRegion>
2063constexpr bool Line<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2064 // The interior of a line is the line itself.
2065 return contains(other);
2066}
2067
2068template <class PointType, class LabelType>
2069template <HalfplaneIntersectionConcept OtherRegion>
2070constexpr bool OrientedLine<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2071 return asLine().interiorContains(other);
2072}
2073
2074template <class PointType, class LabelType>
2075template <HalfplaneIntersectionConcept OtherRegion>
2076constexpr bool Ray<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2077 if (other.empty()) {
2078 return true;
2079 }
2080 if (!other.isDegenerate()) {
2081 return false;
2082 }
2083 return detail::interiorContainsDegenerateRegion(*this, other);
2084}
2085
2086template <class PointType, class LabelType>
2087template <HalfplaneIntersectionConcept OtherRegion>
2088constexpr bool Halfplane<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2089 return detail::regionInsideHalfplaneInterior(other, *this);
2090}
2091
2092template <class PointType, class LabelType>
2093template <HalfplaneIntersectionConcept OtherRegion>
2094constexpr bool Rectangle<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2095 if (empty()) {
2096 // The empty set is a subset of itself and of nothing else.
2097 return detail::coversNoPoint(other);
2098 }
2099 if (other.empty()) {
2100 return true;
2101 }
2102 if (isDegenerate()) {
2103 return false; // a degenerate rectangle has empty interior
2104 }
2105 const PointType lo(min());
2106 const PointType hi(max());
2107 const PointType lohi(lo.x(), hi.y());
2108 const PointType hilo(hi.x(), lo.y());
2109 return detail::regionInsideHalfplaneInterior(other, Halfplane<PointType>(lo, hilo)) &&
2110 detail::regionInsideHalfplaneInterior(other, Halfplane<PointType>(hilo, hi)) &&
2111 detail::regionInsideHalfplaneInterior(other, Halfplane<PointType>(hi, lohi)) &&
2112 detail::regionInsideHalfplaneInterior(other, Halfplane<PointType>(lohi, lo));
2113}
2114
2115template <class PointType, class LabelType>
2116template <HalfplaneIntersectionConcept OtherRegion>
2117constexpr bool Triangle<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2118 if (other.empty()) {
2119 return true;
2120 }
2121 if (isDegenerate()) {
2122 return false;
2123 }
2124 return detail::regionInsideHalfplaneInterior(other, Halfplane<PointType>(a(), b())) &&
2125 detail::regionInsideHalfplaneInterior(other, Halfplane<PointType>(b(), c())) &&
2126 detail::regionInsideHalfplaneInterior(other, Halfplane<PointType>(c(), a()));
2127}
2128
2129template <class PointType, class LabelType>
2130template <HalfplaneIntersectionConcept OtherRegion>
2131constexpr bool Disk<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2132 if (other.empty()) {
2133 return true;
2134 }
2135 if (!other.isBounded() || isDegenerate()) {
2136 return false;
2137 }
2138 // The open disk is convex and the bounded region is the hull of its
2139 // vertices.
2140 using E = detail::region_exact_number_t<typename OtherRegion::NumberType>;
2141 const auto vertices = other.template vertices<E>();
2142 for (const auto& vertex : vertices) {
2143 if (!interiorContains(vertex)) {
2144 return false;
2145 }
2146 }
2147 return true;
2148}
2149
2150template <class PointType, class LabelType>
2151template <HalfplaneIntersectionConcept OtherRegion>
2152constexpr bool Convex<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2153 if (other.empty()) {
2154 return true;
2155 }
2156 if (isDegenerate()) {
2157 return false; // a degenerate polygon has empty interior
2158 }
2159 for (std::size_t i = 0; i < size(); ++i) {
2160 if (!detail::regionInsideHalfplaneInterior(
2161 other, Halfplane<PointType>((*this)[i], get(static_cast<std::ptrdiff_t>(i) + 1)))) {
2162 return false;
2163 }
2164 }
2165 return true;
2166}
2167
2168template <class PointType, class LabelType, class Storage>
2169template <HalfplaneIntersectionConcept OtherRegion>
2170constexpr bool MonotoneChain<PointType, LabelType, Storage>::interiorContains(const OtherRegion& other) const {
2171 if (other.empty()) {
2172 return true;
2173 }
2174 if (!other.isDegenerate()) {
2175 return false;
2176 }
2177 return detail::interiorContainsDegenerateRegion(*this, other);
2178}
2179
2180template <class PointType, class LabelType>
2181template <HalfplaneIntersectionConcept OtherRegion>
2182constexpr bool Polyline<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2183 if (other.empty()) {
2184 return true;
2185 }
2186 if (!other.isDegenerate()) {
2187 return false;
2188 }
2189 return detail::interiorContainsDegenerateRegion(*this, other);
2190}
2191
2192template <class PointType, class LabelType>
2193template <HalfplaneIntersectionConcept OtherRegion>
2194constexpr bool Polygon<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2195 if (other.empty()) {
2196 return true;
2197 }
2198 if (!other.isBounded()) {
2199 return false;
2200 }
2201 using E = detail::region_exact_number_t<typename OtherRegion::NumberType>;
2202 if (other.isDegenerate()) {
2203 return std::visit(
2204 [this](const auto& carrier) {
2205 if constexpr (requires { this->interiorContains(carrier); }) {
2206 return this->interiorContains(carrier);
2207 } else {
2208 (void)carrier;
2209 return false;
2210 }
2211 },
2212 detail::degenerateRegionCarrier(other));
2213 }
2214 return interiorContains(other.template asConvex<E>());
2215}
2216
2217
2218// ---------------------------------------------------------------------------
2219// PolygonWithHoles
2220
2221template <class PointType, class LabelType>
2222template <PointConcept OtherPoint>
2223constexpr bool PolygonWithHoles<PointType, LabelType>::interiorContains(const OtherPoint& point) const {
2224 if (!outer_.interiorContains(point)) {
2225 return false;
2226 }
2227 // The whole closed hole is out of the region's interior: its boundary is
2228 // part of the region's boundary, not of its interior.
2229 for (const auto& hole : holes_) {
2230 if (hole.contains(point)) {
2231 return false;
2232 }
2233 }
2234 return true;
2235}
2236
2237template <class PointType, class LabelType>
2238template <SegmentConcept OtherSegment>
2239constexpr bool PolygonWithHoles<PointType, LabelType>::interiorContains(const OtherSegment& other) const {
2240 if (other.isDegenerate()) {
2241 return interiorContains(other.min());
2242 }
2243 if (!outer_.interiorContains(other)) {
2244 return false;
2245 }
2246 // Unlike contains, no part of a hole survives here — the hole boundary is
2247 // region boundary — so any contact at all disqualifies the segment.
2248 for (const auto& hole : holes_) {
2249 if (hole.intersects(other)) {
2250 return false;
2251 }
2252 }
2253 return true;
2254}
2255
2256template <class PointType, class LabelType>
2257template <SegmentConcept OtherSegment>
2258constexpr bool PolygonWithHoles<PointType, LabelType>::interiorContainsInterior(const OtherSegment& other) const {
2259 if (!contains(other)) {
2260 return false;
2261 }
2262 if (other.isDegenerate()) {
2263 return true;
2264 }
2265 if (!outer_.interiorContainsInterior(other)) {
2266 return false;
2267 }
2268 for (const auto& hole : holes_) {
2269 for (const auto& edge : hole.edgesView()) {
2270 if (edge.interiorsIntersect(other) || other.interiorContains(edge.min())) {
2271 return false;
2272 }
2273 }
2274 }
2275 return true;
2276}
2277
2278template <class PointType, class LabelType>
2279template <OrientedSegmentConcept OtherOrientedSegment>
2280constexpr bool PolygonWithHoles<PointType, LabelType>::interiorContains(const OtherOrientedSegment& other) const {
2281 return interiorContains(other.asSegment());
2282}
2283
2284// Unbounded operands again: only a degenerate one fits inside a bounded region.
2285template <class PointType, class LabelType>
2286template <LineConcept OtherLine>
2287constexpr bool PolygonWithHoles<PointType, LabelType>::interiorContains(const OtherLine& other) const {
2288 return other.isDegenerate() && interiorContains(other.min());
2289}
2290
2291template <class PointType, class LabelType>
2292template <OrientedLineConcept OtherOrientedLine>
2293constexpr bool PolygonWithHoles<PointType, LabelType>::interiorContains(const OtherOrientedLine& other) const {
2294 return other.isDegenerate() && interiorContains(other.source());
2295}
2296
2297template <class PointType, class LabelType>
2298template <RayConcept OtherRay>
2299constexpr bool PolygonWithHoles<PointType, LabelType>::interiorContains(const OtherRay& other) const {
2300 return other.isDegenerate() && interiorContains(other.source());
2301}
2302
2303template <class PointType, class LabelType>
2304template <HalfplaneConcept OtherHalfplane>
2305constexpr bool PolygonWithHoles<PointType, LabelType>::interiorContains(const OtherHalfplane& other) const {
2306 return other.isDegenerate() && interiorContains(other.source());
2307}
2308
2309// Same argument as outerContains, applied to the open outer polygon: its
2310// complement — the outer boundary together with the exterior — is closed,
2311// connected and unbounded, so a bounded shape whose boundary is strictly inside
2312// is strictly inside.
2313template <class PointType, class LabelType>
2314template <class OtherArea>
2315constexpr bool PolygonWithHoles<PointType, LabelType>::outerInteriorContains(const OtherArea& other) const {
2316 if constexpr (PolygonWithHolesConcept<OtherArea>) {
2317 for (const auto& edge : other.edges()) {
2318 if (!outer_.interiorContains(edge)) {
2319 return false;
2320 }
2321 }
2322 return true;
2323 } else {
2324 return outer_.interiorContains(other);
2325 }
2326}
2327
2328// A° = outer° ∖ ⋃ hole, with the *closed* holes removed: a point of outer° off
2329// every closed hole has a ball around it inside outer° and clear of the finitely
2330// many closed holes, so it is interior to the region, and conversely a hole
2331// boundary point is region boundary. That identity is about point sets, so
2332// unlike contains it needs no case for a collapsed operand.
2333template <class PointType, class LabelType>
2334template <class OtherArea>
2335constexpr bool PolygonWithHoles<PointType, LabelType>::areaInteriorContains(const OtherArea& other) const {
2336 if (!outerInteriorContains(other)) {
2337 return false;
2338 }
2339 for (const auto& hole : holes_) {
2340 if (other.intersects(hole)) {
2341 return false;
2342 }
2343 }
2344 return true;
2345}
2346
2347template <class PointType, class LabelType>
2348template <RectangleConcept OtherRectangle>
2349constexpr bool PolygonWithHoles<PointType, LabelType>::interiorContains(const OtherRectangle& other) const {
2350 if (other.empty()) {
2351 // The empty set is a subset of every shape, its boundary and its
2352 // interior alike.
2353 return true;
2354 }
2355 return areaInteriorContains(other);
2356}
2357
2358template <class PointType, class LabelType>
2359template <TriangleConcept OtherTriangle>
2360constexpr bool PolygonWithHoles<PointType, LabelType>::interiorContains(const OtherTriangle& other) const {
2361 return areaInteriorContains(other);
2362}
2363
2364template <class PointType, class LabelType>
2365template <ConvexConcept OtherConvex>
2366constexpr bool PolygonWithHoles<PointType, LabelType>::interiorContains(const OtherConvex& other) const {
2367 return areaInteriorContains(other);
2368}
2369
2370template <class PointType, class LabelType>
2371template <PolygonConcept OtherPolygon>
2372constexpr bool PolygonWithHoles<PointType, LabelType>::interiorContains(const OtherPolygon& other) const {
2373 return areaInteriorContains(other);
2374}
2375
2376template <class PointType, class LabelType>
2377template <PolygonWithHolesConcept OtherRegion>
2378constexpr bool PolygonWithHoles<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2379 return areaInteriorContains(other);
2380}
2381
2382// A chain is the union of its edges, so the open region holds it exactly when
2383// it holds every edge (see @ref chainRelation).
2384template <class PointType, class LabelType>
2385template <MonotoneChainConcept OtherChain>
2386constexpr bool PolygonWithHoles<PointType, LabelType>::interiorContains(const OtherChain& other) const {
2387 return chainRelation(other, true,
2388 [this](const auto& edge) { return this->interiorContains(edge); });
2389}
2390
2391template <class PointType, class LabelType>
2392template <PolylineConcept OtherPolyline>
2393constexpr bool PolygonWithHoles<PointType, LabelType>::interiorContains(const OtherPolyline& other) const {
2394 return chainRelation(other, true,
2395 [this](const auto& edge) { return this->interiorContains(edge); });
2396}
2397
2398// A° = outer° ∖ ⋃ hole, with the holes removed closed. That is an identity
2399// between point sets, so — unlike contains — it asks nothing of the operand and
2400// applies to the disk as it stands.
2401template <class PointType, class LabelType>
2402template <DiskConcept OtherDisk>
2403constexpr bool PolygonWithHoles<PointType, LabelType>::interiorContains(const OtherDisk& other) const {
2404 if (other.isDegenerate()) {
2405 return interiorContains(other.a()); // radius zero, or undefined
2406 }
2407 if (!outer_.interiorContains(other)) {
2408 return false;
2409 }
2410 for (const auto& hole : holes_) {
2411 if (other.intersects(hole)) {
2412 return false;
2413 }
2414 }
2415 return true;
2416}
2417
2418template <class PointType, class LabelType>
2419template <HalfplaneIntersectionConcept OtherIntersection>
2420constexpr bool PolygonWithHoles<PointType, LabelType>::interiorContains(const OtherIntersection& other) const {
2421 if (other.empty()) {
2422 return true;
2423 }
2424 if (other.isDegenerate()) {
2425 return degenerateIntersectionRelation(
2426 other, [this](const auto& carrier) { return this->interiorContains(carrier); });
2427 }
2428 if (!other.isBounded()) {
2429 return false;
2430 }
2431 return areaInteriorContains(asConvexOperand(other));
2432}
2433
2434
2435// ---------------------------------------------------------------------------
2436// Reverse direction: lower-ranked shapes' interiors containing a
2437// PolygonWithHoles.
2438//
2439// The argument of the forward block in contains.hpp carries over verbatim with
2440// B replaced by B°, so again every shape but a Polyline answers the region as
2441// it answers the region's outer polygon:
2442//
2443// B° ⊇ A ⟺ B° ⊇ outer.
2444//
2445// A ⊆ outer gives (⇐). For (⇒), A ⊇ ∂outer; a zero-area outer polygon *is*
2446// ∂outer and carries no hole, so the two questions coincide; and otherwise
2447// ∂outer is a Jordan curve, which an at most one-dimensional interior cannot
2448// hold (both sides false) and a two-dimensional one holds together with
2449// everything inside it, since the complement of B° is closed and connected for
2450// every shape here.
2451//
2452// A Polyline is the exception for the same reason as there — it can close a
2453// loop — and takes the same zero-area rewriting, edge by edge against its own
2454// relative interior.
2455
2456template <class Number, class Label>
2457template <PolygonWithHolesConcept OtherRegion>
2458constexpr bool Point<Number, Label>::interiorContains(const OtherRegion& other) const {
2459 // The interior of a point is the point itself.
2460 return contains(other);
2461}
2462
2463template <class PointType, class LabelType>
2464template <PolygonWithHolesConcept OtherRegion>
2465constexpr bool Segment<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2466 return interiorContains(other.outer());
2467}
2468
2469template <class PointType, class LabelType>
2470template <PolygonWithHolesConcept OtherRegion>
2471constexpr bool OrientedSegment<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2472 return asSegment().interiorContains(other);
2473}
2474
2475template <class PointType, class LabelType>
2476template <PolygonWithHolesConcept OtherRegion>
2477constexpr bool Line<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2478 // The interior of a line is the line itself.
2479 return contains(other);
2480}
2481
2482template <class PointType, class LabelType>
2483template <PolygonWithHolesConcept OtherRegion>
2484constexpr bool OrientedLine<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2485 return asLine().interiorContains(other);
2486}
2487
2488template <class PointType, class LabelType>
2489template <PolygonWithHolesConcept OtherRegion>
2490constexpr bool Ray<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2491 return interiorContains(other.outer());
2492}
2493
2494template <class PointType, class LabelType>
2495template <PolygonWithHolesConcept OtherRegion>
2496constexpr bool Halfplane<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2497 return interiorContains(other.outer());
2498}
2499
2500template <class PointType, class LabelType>
2501template <PolygonWithHolesConcept OtherRegion>
2502constexpr bool Rectangle<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2503 if (empty()) {
2504 // The empty set is a subset of itself and of nothing else.
2505 return detail::coversNoPoint(other);
2506 }
2507 return interiorContains(other.outer());
2508}
2509
2510template <class PointType, class LabelType>
2511template <PolygonWithHolesConcept OtherRegion>
2512constexpr bool Triangle<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2513 return interiorContains(other.outer());
2514}
2515
2516template <class PointType, class LabelType>
2517template <PolygonWithHolesConcept OtherRegion>
2518constexpr bool Disk<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2519 return interiorContains(other.outer());
2520}
2521
2522template <class PointType, class LabelType>
2523template <PolygonWithHolesConcept OtherRegion>
2524constexpr bool Convex<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2525 return interiorContains(other.outer());
2526}
2527
2528template <class PointType, class LabelType, class Storage>
2529template <PolygonWithHolesConcept OtherRegion>
2530constexpr bool MonotoneChain<PointType, LabelType, Storage>::interiorContains(const OtherRegion& other) const {
2531 return interiorContains(other.outer());
2532}
2533
2534// The exception; see the note above.
2535template <class PointType, class LabelType>
2536template <PolygonWithHolesConcept OtherRegion>
2537constexpr bool Polyline<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2538 if (!other.isDegenerate()) {
2539 return false; // the region has area; the polyline has none
2540 }
2541 return detail::everyHoledRegionEdge(
2542 other, [this](const auto& edge) { return this->interiorContains(edge); });
2543}
2544
2545template <class PointType, class LabelType>
2546template <PolygonWithHolesConcept OtherRegion>
2547constexpr bool Polygon<PointType, LabelType>::interiorContains(const OtherRegion& other) const {
2548 return interiorContains(other.outer());
2549}
2550
2551template <class PointType, class LabelType>
2552template <PolygonWithHolesConcept OtherHoledRegion>
2553constexpr bool HalfplaneIntersection<PointType, LabelType>::interiorContains(const OtherHoledRegion& other) const {
2554 return interiorContains(other.outer());
2555}
2556
2557// ---------------------------------------------------------------------------
2558// Runtime Shape argument: unwrap the stored alternative and re-dispatch. Every
2559// alternative has a per-shape overload above, so no fallback is needed.
2560
2561template <class PointType, class LabelType>
2562template <PointConcept OtherPoint>
2564 return std::visit(
2565 [this](const auto& value) {
2566 return this->interiorContains(value);
2567 },
2568 other.variant());
2569}
2570
2571
2572// ---------------------------------------------------------------------------
2573// PolygonSet
2574//
2575// The component interiors are open and pairwise disjoint, so their union — the
2576// set's interior, by the no-shared-edge clause of PolygonSet::isValid — holds a
2577// connected shape only by holding it in one of them. Every operand but another
2578// set is connected, so this is exact componentwise throughout, with none of the
2579// one-dimensional trouble PolygonSet::contains has.
2580
2581template <class PointType, class LabelType>
2582template <detail::SetOperandConcept OtherShape>
2583bool PolygonSet<PointType, LabelType>::interiorContains(const OtherShape& other) const {
2584 return anyComponent([&](const ComponentType& component) {
2585 return component.interiorContains(other);
2586 });
2587}
2588
2589template <class PointType, class LabelType>
2590template <SegmentConcept OtherSegment>
2592 return anyComponent([&](const ComponentType& component) {
2593 return component.interiorContainsInterior(other);
2594 });
2595}
2596
2597template <class PointType, class LabelType>
2598template <PolygonSetConcept OtherSet>
2600 for (const auto& component : other) {
2602 return false;
2603 }
2604 }
2605 return true;
2606}
2607
2608template <class PointType, class LabelType>
2609template <PointConcept OtherPoint>
2611 return std::visit([this](const auto& value) { return this->interiorContains(value); },
2612 other.variant());
2613}
2614
2615} // namespace pgl
Exact rational number class template.
Definition rational.hpp:106
Definition forward.hpp:317
Implementations of the 'crosses' predicate.
Definition arrangement.hpp:67
constexpr std::partial_ordering inCircleSign(const Point< ANumber, ALabel > &a, const Point< BNumber, BLabel > &b, const Point< CNumber, CLabel > &c, const Point< DNumber, DLabel > &d)
Classifies a point with respect to the circumcircle of three others.
Definition orientation.hpp:894
@ edge
Definition bitmatrix.hpp:37
@ vertex
Definition bitmatrix.hpp:37
constexpr std::partial_ordering dotSign(const Point< ANumber, ALabel > &a, const Point< BNumber, BLabel > &b)
Tells if the angle between two vectors is acute, right, or obtuse.
Definition orientation.hpp:688
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 std::partial_ordering crossSign(const Point< UNumber, ULabel > &u, const Point< VNumber, VLabel > &v)
Classifies the turn from one vector to another.
Definition orientation.hpp:583
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 PointType get(std::ptrdiff_t index) const
Cyclic access: same as operator[] but index is taken modulo size(); negative indices wrap from the en...
Definition convex.hpp:289
constexpr bool isDegenerate() const
Checks if the convex polygon is degenerate (has zero area).
Definition predicates.hpp:982
constexpr bool interiorContains(const EmptyShape< EmptyPoint > &) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition convex.hpp:1340
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:1135
constexpr auto orientedEdgesView() const
Lazy view counterpart of orientedEdges(); see edgesView().
Definition convex.hpp:583
size_t size() const
Returns the number of vertices in the convex polygon.
Definition convex.hpp:840
constexpr bool boundaryContains(const OtherPoint &point) const
Tests whether this shape's boundary contains the other shape (∂A ⊇ B).
Definition boundarycontains.hpp:652
constexpr ResultNumber squaredRadius() const
Returns the squared radius in an explicitly chosen result type.
Definition disk.hpp:402
constexpr Point< ResultNumber, PointLabelType > center() const
Returns the center (circumcenter of the three boundary points) in an explicitly chosen coordinate typ...
Definition disk.hpp:284
constexpr bool isDegenerate() const
Returns whether the three boundary points are collinear.
Definition disk.hpp:348
constexpr const PointType & c() const
Returns the third boundary point in canonical order.
Definition disk.hpp:244
constexpr bool interiorContains(const EmptyShape< EmptyPoint > &) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition disk.hpp:909
detail::floating_result_t< ResultNumber > squaredDistance(const OtherPoint &point) const
Returns the squared Euclidean distance from this disk to a point.
Definition distance.hpp:1194
constexpr const PointType & a() const
Returns the first boundary point (lexicographically smallest).
Definition disk.hpp:228
constexpr const PointType & b() const
Returns the second boundary point in canonical order.
Definition disk.hpp:235
constexpr bool empty() const
Returns whether the region is the empty set.
Definition halfplaneintersection.hpp:649
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 interiorContains(const OtherPoint &point) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition interiorcontains.hpp:1816
constexpr std::size_t size() const
Returns the number of stored (non-redundant) half-planes.
Definition halfplaneintersection.hpp:596
constexpr Point< ResultNumber, typename PointType::LabelType > vertex(std::size_t i) const
Returns the vertex between half-planes i and i+1 (cyclically).
Definition halfplaneintersection.hpp:875
Closed half-plane defined by an oriented boundary line.
Definition halfplane.hpp:51
constexpr bool interiorContains(const EmptyShape< EmptyPoint > &) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition halfplane.hpp:562
constexpr const PointType & target() const
Returns the target boundary point.
Definition halfplane.hpp:193
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:872
constexpr bool boundaryContains(const OtherPoint &point) const
Tests whether this shape's boundary contains the other shape (∂A ⊇ B).
Definition boundarycontains.hpp:405
constexpr Line< PointType > asLine() const
Returns the boundary line without orientation.
Definition halfplane.hpp:318
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
Unoriented infinite line.
Definition line.hpp:52
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:428
constexpr bool intersects(const OtherPoint &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:312
constexpr bool interiorContains(const EmptyShape< EmptyPoint > &) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition line.hpp:574
Weakly x-monotone polyline stored by lexicographically sorted vertices.
Definition monotonechain.hpp:146
constexpr bool boundaryContains(const OtherPoint &point) const
Tests whether this shape's boundary contains the other shape (∂A ⊇ B).
Definition boundarycontains.hpp:1159
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:1822
constexpr std::size_t size() const
Returns the number of vertices in the chain.
Definition monotonechain.hpp:393
constexpr bool interiorContains(const OtherPoint &point) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition interiorcontains.hpp:1371
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:531
constexpr bool interiorContains(const EmptyShape< EmptyPoint > &) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition orientedline.hpp:683
constexpr Line< PointType > asLine() const
Returns the line without orientation.
Definition orientedline.hpp:321
constexpr bool boundaryContains(const OtherPoint &point) const
Tests whether this shape's boundary contains the other shape (∂A ⊇ B).
Definition boundarycontains.hpp:216
constexpr Segment< PointType > asSegment() const
Returns the segment without orientation.
Definition orientedsegment.hpp:322
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:346
constexpr bool interiorContains(const EmptyShape< EmptyPoint > &) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition orientedsegment.hpp:720
constexpr bool contains(const OtherPoint &other) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:25
constexpr bool interiorContains(const EmptyShape< EmptyPoint > &) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition point.hpp:471
bool interiorContains(const OtherShape &other) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition interiorcontains.hpp:2583
bool interiorContainsInterior(const OtherSegment &other) const
Tests whether this shape's interior contains the segment's interior.
Definition interiorcontains.hpp:2591
constexpr const ComponentType & component(std::size_t index) const
Accesses a component by index.
Definition polygonset.hpp:271
PolygonWithHoles< PointType > ComponentType
Definition polygonset.hpp:169
constexpr bool interiorContainsInterior(const OtherSegment &other) const
Tests whether this shape's interior contains the segment's interior.
Definition interiorcontains.hpp:2258
constexpr const PolygonType & hole(std::size_t index) const
Accesses a hole by index.
Definition polygonwithholes.hpp:196
constexpr bool interiorContains(const OtherPoint &point) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition interiorcontains.hpp:2223
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:2945
constexpr const Rectangle< PointType > & bbox() const
Computes the bounding box of the polygon.
Definition bounding.hpp:449
constexpr bool boundaryContains(const EmptyShape< EmptyPoint > &) const
Tests whether this shape's boundary contains the other shape (∂A ⊇ B).
Definition polygon.hpp:1532
constexpr bool interiorContains(const EmptyShape< EmptyPoint > &) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition polygon.hpp:1537
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:1296
constexpr auto edgesView() const
Returns a lazy view over the edges, materializing each Segment on the fly instead of allocating a vec...
Definition polygon.hpp:782
constexpr bool boundariesIntersect(const OtherPolygon &other) const
Tests whether the two polygon boundaries share at least one point (∂A ∩ ∂B ≠ ∅).
Definition interiorsintersect.hpp:1197
constexpr std::size_t size() const
Returns the number of vertices in the polygon.
Definition polygon.hpp:259
constexpr bool interiorContainsInterior(const OtherSegment &other) const
Tests whether this shape's interior contains the segment's interior.
Definition interiorcontains.hpp:960
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:2134
constexpr bool boundaryContains(const OtherPoint &point) const
Tests whether this shape's boundary contains the other shape (∂A ⊇ B).
Definition boundarycontains.hpp:1268
constexpr std::size_t size() const
Returns the number of vertices in the polyline.
Definition polyline.hpp:388
constexpr bool interiorContains(const OtherPoint &point) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition interiorcontains.hpp:1581
constexpr bool interiorContains(const EmptyShape< EmptyPoint > &) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition ray.hpp:589
constexpr bool boundaryContains(const OtherPoint &point) const
Tests whether this shape's boundary contains the other shape (∂A ⊇ B).
Definition boundarycontains.hpp:254
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:625
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 interiorContains(const EmptyShape< EmptyPoint > &) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition rectangle.hpp:862
constexpr Convex< PointType > asConvex() const
Returns the rectangle as a convex polygon.
Definition rectangle.hpp:690
PointType_ PointType
Definition rectangle.hpp:76
constexpr bool boundaryContains(const Shape< PointType > &other) const
Tests whether this shape's boundary contains the other shape (∂A ⊇ B).
Definition boundarycontains.hpp:1134
constexpr const PointType & max() const
Returns the maximum corner (max x, max y).
Definition rectangle.hpp:359
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:728
Unoriented closed segment between two endpoints plus optional segment label.
Definition segment.hpp:58
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:119
constexpr bool boundaryContains(const OtherPoint &point) const
Tests whether this shape's boundary contains the other shape (∂A ⊇ B).
Definition boundarycontains.hpp:110
constexpr bool interiorContains(const EmptyShape< EmptyPoint > &) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition segment.hpp:736
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 contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:223
constexpr const PointType & b() const
Returns the second vertex.
Definition triangle.hpp:217
constexpr std::array< PointType, 3 > vertices() const
Returns the vertices in canonical order.
Definition bounding.hpp:235
constexpr const PointType & a() const
Returns the first vertex.
Definition triangle.hpp:208
constexpr bool boundaryContains(const OtherPoint &point) const
Tests whether this shape's boundary contains the other shape (∂A ⊇ B).
Definition boundarycontains.hpp:123
constexpr Rectangle< PointType > bbox() const
Returns the axis-aligned bounding box of the vertices.
Definition bounding.hpp:224
constexpr Convex< PointType > asConvex() const
Returns the triangle as a convex polygon.
Definition triangle.hpp:490
constexpr bool isDegenerate() const
Tests whether the three vertices are collinear.
Definition predicates.hpp:223
constexpr const PointType & c() const
Returns the third vertex.
Definition triangle.hpp:226
constexpr bool interiorContains(const EmptyShape< EmptyPoint > &) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition triangle.hpp:806