22template <
class Number,
class Label>
23template<Po
intConcept OtherPo
int>
37template <
class Po
intType,
class LabelType>
38template<Po
intConcept OtherPo
int>
44template <
class Po
intType,
class LabelType>
45template<SegmentConcept OtherSegment>
47 using Coordinate = detail::sign_coordinate_t<NumberType, typename OtherSegment::NumberType>;
49 const auto& a =
min();
50 const auto& b =
max();
51 const auto& c = other.min();
52 const auto& d = other.max();
56 const auto fa = detail::filtered<Coordinate>(a);
57 const auto fb = detail::filtered<Coordinate>(b);
58 const auto fc = detail::filtered<Coordinate>(c);
59 const auto fd = detail::filtered<Coordinate>(d);
60 const auto s1 = detail::orientationSignOf(fa, fb, fc);
61 const auto s2 = detail::orientationSignOf(fa, fb, fd);
62 const auto s3 = detail::orientationSignOf(fc, fd, fa);
63 const auto s4 = detail::orientationSignOf(fc, fd, fb);
67 if (detail::allDecided(s1, s2, s3, s4)) {
68 return s1.value() != s2.value() && s3.value() != s4.value();
72 const int cross = boundingBoxesCross(other);
80 else if (!boundingBoxesOverlap(other)) {
83 if (a == b || c == d) {
86 const auto d1 = s1.value();
87 const auto d2 = s2.value();
88 const auto d3 = s3.value();
89 const auto d4 = s4.value();
90 const bool no_endpoint_is_collinear = d1 != 0 && d2 != 0 && d3 != 0 && d4 != 0;
91 const bool this_segment_straddles_other = (d1 > 0) != (d2 > 0);
92 const bool other_segment_straddles_this = (d3 > 0) != (d4 > 0);
93 const bool proper_cross =
94 no_endpoint_is_collinear &&
95 this_segment_straddles_other &&
96 other_segment_straddles_this;
100 if (d1 != 0 || d2 != 0) {
110 other.interiorContains(a) ||
111 other.interiorContains(b) ||
115template <
class Po
intType,
class LabelType>
118 [
this](
const auto& value) {
130template <
class Po
intType,
class LabelType>
131template<Po
intConcept OtherPo
int>
137template <
class Po
intType,
class LabelType>
138template<LineConcept OtherLine>
143 if (other.isDegenerate()) {
146 bool has_positive =
false;
147 bool has_negative =
false;
148 const auto triangle_vertices =
vertices();
149 for (
const auto&
vertex : triangle_vertices) {
151 has_positive = has_positive || side == std::partial_ordering::greater;
152 has_negative = has_negative || side == std::partial_ordering::less;
153 if (has_positive && has_negative) {
160template <
class Po
intType,
class LabelType>
161template<OrientedLineConcept OtherOrientedLine>
166 if (other.isDegenerate()) {
169 bool has_positive =
false;
170 bool has_negative =
false;
171 const auto triangle_vertices =
vertices();
172 for (
const auto&
vertex : triangle_vertices) {
174 has_positive = has_positive || side == std::partial_ordering::greater;
175 has_negative = has_negative || side == std::partial_ordering::less;
176 if (has_positive && has_negative) {
183template <
class Po
intType,
class LabelType>
184template<SegmentConcept OtherSegment>
191 other.separates(*
this);
194template <
class Po
intType,
class LabelType>
195template<OrientedSegmentConcept OtherOrientedSegment>
200template <
class Po
intType,
class LabelType>
201template<RayConcept OtherRay>
209template <
class Po
intType,
class LabelType>
210template<HalfplaneConcept OtherHalfplane>
215 return other.interiorContains(
a()) || other.interiorContains(
b()) || other.interiorContains(
c());
218template <
class Po
intType,
class LabelType>
219template<RectangleConcept OtherRectangle>
228 if (other.interiorContains(
a()) || other.interiorContains(
b()) || other.interiorContains(
c())) {
231 const auto rectangle_vertices = other.vertices();
232 for (
const auto&
vertex : rectangle_vertices) {
237 const auto rectangle_edges = other.edges();
238 for (
const auto&
edge : rectangle_edges) {
239 if (
edge.separates(*
this)) {
243 const auto triangle_edges =
edges();
244 for (
const auto&
edge : triangle_edges) {
245 if (
edge.separates(other)) {
252template <
class Po
intType,
class LabelType>
253template<TriangleConcept OtherTriangle>
263 for (
const auto& thisEdge :
edges()) {
264 if (thisEdge.interiorsIntersect(other)) {
269 for (
const auto& otherEdge : other.edges()) {
270 if (otherEdge.interiorsIntersect(*
this)) {
275 return other == *
this;
278template <
class Po
intType,
class LabelType>
281 [
this](
const auto& value) {
293template <
class Po
intType,
class LabelType>
294template<Po
intConcept OtherPo
int>
296 return this->
asSegment().interiorsIntersect(other);
299template <
class Po
intType,
class LabelType>
300template<SegmentConcept OtherSegment>
302 return this->
asSegment().interiorsIntersect(other);
305template <
class Po
intType,
class LabelType>
306template<OrientedSegmentConcept OtherOrientedSegment>
308 return this->
asSegment().interiorsIntersect(other.asSegment());
311template <
class Po
intType,
class LabelType>
314 [
this](
const auto& value) {
326template <
class Po
intType,
class LabelType>
327template<Po
intConcept OtherPo
int>
333template <
class Po
intType,
class LabelType>
334template<LineConcept OtherLine>
339template <
class Po
intType,
class LabelType>
340template<SegmentConcept OtherSegment>
347 if (first_side == std::partial_ordering::equivalent &&
348 second_side == std::partial_ordering::equivalent) {
351 if (first_side == std::partial_ordering::equivalent ||
352 second_side == std::partial_ordering::equivalent) {
355 return first_side != second_side;
358template <
class Po
intType,
class LabelType>
359template<OrientedSegmentConcept OtherOrientedSegment>
364template <
class Po
intType,
class LabelType>
367 [
this](
const auto& value) {
379template <
class Po
intType,
class LabelType>
380template<Po
intConcept OtherPo
int>
382 return this->
asLine().interiorsIntersect(other);
385template <
class Po
intType,
class LabelType>
386template<LineConcept OtherLine>
391template <
class Po
intType,
class LabelType>
392template<OrientedLineConcept OtherOrientedLine>
397template <
class Po
intType,
class LabelType>
398template<SegmentConcept OtherSegment>
400 return this->
asLine().interiorsIntersect(other);
403template <
class Po
intType,
class LabelType>
404template<OrientedSegmentConcept OtherOrientedSegment>
406 return this->
asLine().interiorsIntersect(other);
409template <
class Po
intType,
class LabelType>
412 [
this](
const auto& value) {
424template <
class Po
intType,
class LabelType>
425template<Po
intConcept OtherPo
int>
431template <
class Po
intType,
class LabelType>
432template<LineConcept OtherLine>
439 if (source_side == 0) {
440 return other.contains(
target());
445 const auto direction_side =
447 return direction_side != 0 && direction_side != source_side;
450template <
class Po
intType,
class LabelType>
451template<OrientedLineConcept OtherOrientedLine>
456template <
class Po
intType,
class LabelType>
457template<SegmentConcept OtherSegment>
466 if (ray_min_side == std::partial_ordering::equivalent &&
467 ray_max_side == std::partial_ordering::equivalent) {
470 other.interiorContains(
source());
473 if (ray_min_side == std::partial_ordering::equivalent ||
474 ray_max_side == std::partial_ordering::equivalent ||
475 ray_min_side == ray_max_side) {
484 if (source_side == std::partial_ordering::equivalent) {
487 const auto direction_side =
489 return direction_side != std::partial_ordering::equivalent &&
490 direction_side != source_side;
493template <
class Po
intType,
class LabelType>
494template<OrientedSegmentConcept OtherOrientedSegment>
499template <
class Po
intType,
class LabelType>
500template<RayConcept OtherRay>
509 if (other_source_side == std::partial_ordering::equivalent &&
510 other_target_side == std::partial_ordering::equivalent) {
518 if (other_source_side == other_target_side &&
519 other_source_side != std::partial_ordering::equivalent) {
526 if (this_source_side == this_target_side &&
527 this_source_side != std::partial_ordering::equivalent) {
534template <
class Po
intType,
class LabelType>
537 [
this](
const auto& value) {
549template <
class Po
intType,
class LabelType>
550template<Po
intConcept OtherPo
int>
558template <
class Po
intType,
class LabelType>
559template<RectangleConcept OtherRectangle>
567 return intervalsOverlapStrict(
min().
x(),
max().
x(), other.min().x(), other.max().x()) &&
568 intervalsOverlapStrict(
min().
y(),
max().
y(), other.min().y(), other.max().y());
571template <
class Po
intType,
class LabelType>
572template<LineConcept OtherLine>
581 if (other.isDegenerate()) {
584 return detail::lineIntersectsRectangleInterior(*
this, other.min(), other.max());
587template <
class Po
intType,
class LabelType>
588template<OrientedLineConcept OtherOrientedLine>
597 if (other.isDegenerate()) {
600 return detail::lineIntersectsRectangleInterior(*
this, other.source(), other.target());
603template <
class Po
intType,
class LabelType>
604template<SegmentConcept OtherSegment>
613 return detail::segmentIntersectsRectangleInteriorExact(*
this, other.min(), other.max());
616template <
class Po
intType,
class LabelType>
617template<OrientedSegmentConcept OtherOrientedSegment>
626 return detail::segmentIntersectsRectangleInteriorExact(*
this, other.source(), other.target());
629template <
class Po
intType,
class LabelType>
630template<RayConcept OtherRay>
646template <
class Po
intType,
class LabelType>
647template<HalfplaneConcept OtherHalfplane>
656 const auto rectangle_vertices =
vertices();
657 for (
const auto&
vertex : rectangle_vertices) {
658 if (other.interiorContains(
vertex)) {
665template <
class Po
intType,
class LabelType>
668 [
this](
const auto& value) {
680template <
class Po
intType,
class LabelType>
681template<Po
intConcept OtherPo
int>
687template <
class Po
intType,
class LabelType>
688template<LineConcept OtherLine>
693 if (other.isDegenerate()) {
696 const auto direction_side =
699 return direction_side !=
decltype(direction_side){} ||
interiorContains(other.min());
702template <
class Po
intType,
class LabelType>
703template<OrientedLineConcept OtherOrientedLine>
708 if (other.isDegenerate()) {
711 const auto direction_side =
714 return direction_side !=
decltype(direction_side){} ||
interiorContains(other.source());
717template <
class Po
intType,
class LabelType>
718template<SegmentConcept OtherSegment>
726 const auto zero =
decltype(first_side){};
727 return zero < first_side || zero < second_side;
730template <
class Po
intType,
class LabelType>
731template<OrientedSegmentConcept OtherOrientedSegment>
739 const auto zero =
decltype(first_side){};
740 return zero < first_side || zero < second_side;
743template <
class Po
intType,
class LabelType>
744template<RayConcept OtherRay>
749 if (other.isDegenerate()) {
753 const auto direction_side =
756 const auto zero =
decltype(source_side){};
757 return zero < source_side || zero < direction_side;
760template <
class Po
intType,
class LabelType>
761template<HalfplaneConcept OtherHalfplane>
767 const auto this_boundary = this->
asLine();
768 const auto other_boundary = other.asLine();
769 if (!this_boundary.parallel(other_boundary)) {
774 const auto zero =
decltype(side_of_other_source){};
775 if (zero < side_of_other_source) {
780 if (zero < side_of_this_source) {
786 return this_oriented_boundary == other_oriented_boundary;
789template <
class Po
intType,
class LabelType>
792 [
this](
const auto& value) {
802template <
class Po
intType,
class LabelType>
803template<Po
intConcept OtherPo
int>
809template <
class Po
intType,
class LabelType>
810template<LineConcept OtherLine>
815 if (other.isDegenerate()) {
821 const auto max_it = detail::cyclicMax(points_.begin(), points_.end(),
823 return orientationDeterminant(other.min(), other.max(), a + translation_);
825 const auto min_it = detail::cyclicMax(points_.begin(), points_.end(),
827 return -orientationDeterminant(other.min(), other.max(), a + translation_);
831 return max_val > 0 && min_val < 0;
834template <
class Po
intType,
class LabelType>
835template<OrientedLineConcept OtherOrientedLine>
840template <
class Po
intType,
class LabelType>
841template<SegmentConcept OtherSegment>
849 auto translatedOther = other - translation_;
850 auto it1 = detail::cyclicMaxOrPositive(points_.begin(), points_.end(), [&translatedOther](
const PointType& a) {
851 return orientationDeterminant(translatedOther[0], translatedOther[1], a);
853 auto it2 = detail::cyclicMaxOrPositive(points_.begin(), points_.end(), [&translatedOther](
const PointType& a) {
854 return orientationDeterminant(translatedOther[1], translatedOther[0], a);
856 auto i3 = it1 - points_.begin() - 1;
857 i3 = i3 < 0 ? points_.size()-1 : i3;
858 if (points_[i3] == *it2) {
859 i3 = (i3+2) % points_.size();
866template <
class Po
intType,
class LabelType>
867template<OrientedSegmentConcept OtherOrientedSegment>
872template <
class Po
intType,
class LabelType>
873template<RayConcept OtherRay>
882 auto translatedOther = other - translation_;
883 auto it1 = detail::cyclicMaxOrPositive(points_.begin(), points_.end(), [&translatedOther](
const PointType& a) {
884 return orientationDeterminant(translatedOther[0], translatedOther[1], a);
886 auto it2 = detail::cyclicMaxOrPositive(points_.begin(), points_.end(), [&translatedOther](
const PointType& a) {
887 return orientationDeterminant(translatedOther[1], translatedOther[0], a);
889 auto i3 = it1 - points_.begin() - 1;
890 i3 = i3 < 0 ? points_.size()-1 : i3;
891 if (points_[i3] == *it2) {
892 i3 = (i3+2) % points_.size();
899template <
class Po
intType,
class LabelType>
900template<HalfplaneConcept OtherHalfplane>
907 const auto it = detail::cyclicMaxOrPositive(points_.begin(), points_.end(),
909 return orientationDeterminant(other.source(), other.target(), a + translation_);
911 return other.interiorContains(*it + translation_);
914template <
class Po
intType,
class LabelType>
915template<RectangleConcept OtherRectangle>
924template <
class Po
intType,
class LabelType>
925template<TriangleConcept OtherTriangle>
930template <
class Po
intType,
class LabelType>
931template<ConvexConcept OtherConvex>
939 if (
size() > other.size()) {
940 return other.interiorsIntersect(*
this);
954 if (other.interiorsIntersect(
edge)) {
962template <
class Po
intType,
class LabelType>
963template<DiskConcept OtherDisk>
974 if (
edge.interiorsIntersect(other)) {
978 return other.pointInsideInteriorContainedIn(*
this);
981template <
class Po
intType,
class LabelType>
982template <Po
intConcept OtherPo
int>
985 [
this](
const auto& value) {
995template <
class Po
intType,
class LabelType>
996template<Po
intConcept OtherPo
int>
1002template <
class Po
intType,
class LabelType>
1003template<LineConcept OtherLine>
1012 bool positive =
false, negative =
false;
1015 positive = positive || side > 0;
1016 negative = negative || side < 0;
1017 if (positive && negative) {
1024template <
class Po
intType,
class LabelType>
1025template<OrientedLineConcept OtherOrientedLine>
1030template <
class Po
intType,
class LabelType>
1031template<SegmentConcept OtherSegment>
1039 if (
edge.crosses(other)) {
1049 using C = std::common_type_t<NumberType, typename OtherSegment::NumberType>;
1051 std::vector<V> contacts{
static_cast<V
>(other.min()),
static_cast<V
>(other.max())};
1053 if (other.contains(
vertex)) {
1054 contacts.push_back(
static_cast<V
>(
vertex));
1060 std::sort(contacts.begin(), contacts.end(), [&](
const V& p,
const V& q) {
1061 return dotSign(p, q, other.min(), other.max()) > 0;
1063 const auto doubled = (*this) *
NumberType(2);
1064 for (std::size_t i = 1; i < contacts.size(); ++i) {
1065 if (contacts[i - 1] == contacts[i]) {
1068 if (doubled.interiorContains(contacts[i - 1] + contacts[i])) {
1075template <
class Po
intType,
class LabelType>
1076template<OrientedSegmentConcept OtherOrientedSegment>
1081template <
class Po
intType,
class LabelType>
1082template<RayConcept OtherRay>
1088 if (
edge.crosses(other)) {
1095 using C = std::common_type_t<NumberType, typename OtherRay::NumberType>;
1097 std::vector<V> contacts{
static_cast<V
>(other.source())};
1099 if (other.contains(
vertex)) {
1100 contacts.push_back(
static_cast<V
>(
vertex));
1103 std::sort(contacts.begin(), contacts.end(), [&](
const V& p,
const V& q) {
1104 return dotSign(p, q, other.source(), other.target()) > 0;
1106 const auto doubled = (*this) *
NumberType(2);
1107 for (std::size_t i = 1; i < contacts.size(); ++i) {
1108 if (contacts[i - 1] == contacts[i]) {
1111 if (doubled.interiorContains(contacts[i - 1] + contacts[i])) {
1118template <
class Po
intType,
class LabelType>
1119template<HalfplaneConcept OtherHalfplane>
1128 if (other.interiorContains(
vertex)) {
1147template <
class Poly,
class Area>
1148constexpr bool polygonAreaInteriorsIntersect(
const Poly& poly,
const Area& area) {
1149 if (area.isDegenerate() || poly.isDegenerate()) {
1152 auto abbox = area.bbox();
1153 if (!poly.bbox().interiorsIntersect(abbox)) {
1156 if (poly.bbox().separates(abbox) || abbox.separates(poly.bbox())) {
1160 for (
const auto&
edge : area.edges()) {
1161 if (
edge.interiorsIntersect(poly)) {
1168 return area.pointInsideInteriorContainedIn(poly) || poly.pointInsideInteriorContainedIn(area);
1173template <
class Po
intType,
class LabelType>
1174template<RectangleConcept OtherRectangle>
1176 if (other.empty()) {
1180 return detail::polygonAreaInteriorsIntersect(*
this, other);
1183template <
class Po
intType,
class LabelType>
1184template<TriangleConcept OtherTriangle>
1186 return detail::polygonAreaInteriorsIntersect(*
this, other);
1189template <
class Po
intType,
class LabelType>
1190template<ConvexConcept OtherConvex>
1192 return detail::polygonAreaInteriorsIntersect(*
this, other);
1195template <
class Po
intType,
class LabelType>
1196template<PolygonConcept OtherPolygon>
1202 return other.boundaryContains(*
vertex);
1204 if (
const auto vertex = other.getIfPoint()) {
1216 BoundaryChains<Polygon> mine(*
this);
1217 BoundaryChains<OtherPolygon> theirs(other);
1218 while (!mine.exhausted() || !theirs.exhausted()) {
1219 if (!mine.exhausted()) {
1220 const auto& chain = mine.produceNext();
1221 for (
const auto& their : theirs.produced()) {
1222 if (chain.intersects(their)) {
1227 if (!theirs.exhausted()) {
1228 const auto& chain = theirs.produceNext();
1229 for (
const auto& my : mine.produced()) {
1230 if (chain.intersects(my)) {
1239template <
class Po
intType,
class LabelType>
1240template<PolygonConcept OtherPolygon>
1244 if (
isPoint() || other.isPoint()) {
1253 BoundaryChains<Polygon> mine(*
this);
1254 BoundaryChains<OtherPolygon> theirs(other);
1255 while (!mine.exhausted() || !theirs.exhausted()) {
1256 if (!mine.exhausted()) {
1257 const auto& chain = mine.produceNext();
1258 for (
const auto& their : theirs.produced()) {
1259 if (chain.edgesCross(their)) {
1264 if (!theirs.exhausted()) {
1265 const auto& chain = theirs.produceNext();
1266 for (
const auto& my : mine.produced()) {
1267 if (chain.edgesCross(my)) {
1276template <
class Po
intType,
class LabelType>
1277template<PolygonConcept OtherPolygon>
1290 if (*
this == other) {
1311 bool boundaries_intersect =
false;
1318 boundaries_intersect = met;
1320 BoundaryChains<Polygon> mine(*
this);
1321 BoundaryChains<OtherPolygon> theirs(other);
1322 while (!mine.exhausted() || !theirs.exhausted()) {
1323 if (!mine.exhausted()) {
1324 const auto& chain = mine.produceNext();
1325 for (
const auto& their : theirs.produced()) {
1326 if (chain.intersects(their)) {
1327 boundaries_intersect =
true;
1328 if (chain.edgesCross(their)) {
1334 if (!theirs.exhausted()) {
1335 const auto& chain = theirs.produceNext();
1336 for (
const auto& my : mine.produced()) {
1337 if (chain.intersects(my)) {
1338 boundaries_intersect =
true;
1339 if (chain.edgesCross(my)) {
1348 if (!boundaries_intersect) {
1357 for (
const auto&
vertex : other.vertices()) {
1363 if (other.interiorContains(
vertex)) {
1368 if (
edge.separates(other)) {
1372 for (
const auto&
edge : other.edgesView()) {
1373 if (
edge.separates(*
this)) {
1381template <
class Po
intType,
class LabelType>
1382template<Po
intConcept OtherPo
int>
1385 [
this](
const auto& value) {
1391template <
class Number,
class Label>
1394 [
this](
const auto& value) {
1395 return this->interiorsIntersect(value);
1400template <
class Po
intType,
class LabelType>
1401template<Po
intConcept OtherPo
int>
1407template <
class Po
intType,
class LabelType>
1408template<SegmentConcept OtherSegment>
1437 using W = detail::promoted_number_t<
1444 const W m = squared_length * det;
1446 const W projection = (j0 - j1) * det;
1447 const W half_span = m * det;
1448 const W discriminant_base = j0 + j1 + m;
1450 const bool foot_on_segment = projection >= -half_span && projection <= half_span;
1451 const bool pierces_disk = discriminant_base * discriminant_base > W{4} * j0 * j1;
1453 return foot_on_segment && pierces_disk;
1456template <
class Po
intType,
class LabelType>
1457template<OrientedSegmentConcept OtherOrientedSegment>
1462template <
class Po
intType,
class LabelType>
1463template<LineConcept OtherLine>
1477 using W = detail::promoted_number_t<
1484 const W discriminant_base = j0 + j1 + squared_length * det;
1486 return discriminant_base * discriminant_base > W{4} * j0 * j1;
1489template <
class Po
intType,
class LabelType>
1490template<OrientedLineConcept OtherOrientedLine>
1495template <
class Po
intType,
class LabelType>
1496template<RayConcept OtherRay>
1516 using W = detail::promoted_number_t<
1523 const W m = squared_length * det;
1525 const W projection = (j0 - j1) * det;
1526 const W half_span = m * det;
1527 const W discriminant_base = j0 + j1 + m;
1529 const bool strict_secant = discriminant_base * discriminant_base > W{4} * j0 * j1;
1530 const bool contact_ahead = projection < half_span;
1532 return strict_secant && contact_ahead;
1535template <
class Po
intType,
class LabelType>
1536template<HalfplaneConcept OtherHalfplane>
1545template <
class Po
intType,
class LabelType>
1546template<RectangleConcept OtherRectangle>
1548 if (other.empty()) {
1559 for (
const auto&
edge : other.edges()) {
1567template <
class Po
intType,
class LabelType>
1568template<TriangleConcept OtherTriangle>
1577 for (
const auto&
edge : other.edges()) {
1585template <
class Po
intType,
class LabelType>
1586template<DiskConcept OtherDisk>
1596 using R = std::conditional_t<
1597 std::is_floating_point_v<NumberType> ||
1598 std::is_floating_point_v<typename OtherDisk::NumberType>,
1604 const R A = d2 - r1_sq - r2_sq;
1605 return A < R{} || A * A < R{4} * r1_sq * r2_sq;
1608template <
class Po
intType,
class LabelType>
1609template<Po
intConcept OtherPo
int>
1612 [
this](
const auto& value) {
1619template <
class Po
intType,
class LabelType>
1620template<DiskConcept OtherDisk>
1633 if (
edge.interiorsIntersect(other)) {
1637 return other.pointInsideInteriorContainedIn(*
this);
1647template <
class Po
intType,
class LabelType,
class Storage>
1648template<Po
intConcept OtherPo
int>
1654template <
class Po
intType,
class LabelType,
class Storage>
1655template<SegmentConcept OtherSegment>
1657 if (points_.size() < 2) {
1661 const auto window = edgeWindow(other.min().x(), other.max().x());
1665 for (std::size_t i = window->first; i <= window->second; ++i) {
1673 const std::size_t firstVertex = std::max<std::size_t>(window->first, 1);
1674 const std::size_t lastVertex = std::min(window->second + 1, points_.size() - 2);
1675 for (std::size_t v = firstVertex; v <= lastVertex; ++v) {
1676 if (other.interiorContains((*
this)[v])) {
1683template <
class Po
intType,
class LabelType,
class Storage>
1684template<OrientedSegmentConcept OtherOrientedSegment>
1695template <
class Chain,
class OtherShape>
1696constexpr bool chainInteriorsIntersect(
const Chain& chain,
const OtherShape& other) {
1697 const std::size_t n = chain.size();
1702 for (std::size_t i = 0; i + 1 < n; ++i) {
1707 for (std::size_t v = 1; v + 1 < n; ++v) {
1708 if (other.interiorContains(chain[v])) {
1717template <
class Po
intType,
class LabelType,
class Storage>
1718template<LineConcept OtherLine>
1720 return detail::chainInteriorsIntersect(*
this, other);
1723template <
class Po
intType,
class LabelType,
class Storage>
1724template<OrientedLineConcept OtherOrientedLine>
1726 return detail::chainInteriorsIntersect(*
this, other);
1729template <
class Po
intType,
class LabelType,
class Storage>
1730template<RayConcept OtherRay>
1732 return detail::chainInteriorsIntersect(*
this, other);
1735template <
class Po
intType,
class LabelType,
class Storage>
1736template<HalfplaneConcept OtherHalfplane>
1738 return detail::chainInteriorsIntersect(*
this, other);
1741template <
class Po
intType,
class LabelType,
class Storage>
1742template<RectangleConcept OtherRectangle>
1744 if (other.empty()) {
1748 return detail::chainInteriorsIntersect(*
this, other);
1751template <
class Po
intType,
class LabelType,
class Storage>
1752template<TriangleConcept OtherTriangle>
1754 return detail::chainInteriorsIntersect(*
this, other);
1757template <
class Po
intType,
class LabelType,
class Storage>
1758template<ConvexConcept OtherConvex>
1760 return detail::chainInteriorsIntersect(*
this, other);
1763template <
class Po
intType,
class LabelType,
class Storage>
1764template<DiskConcept OtherDisk>
1766 return detail::chainInteriorsIntersect(*
this, other);
1769template <
class Po
intType,
class LabelType,
class Storage>
1770template<MonotoneChainConcept OtherChain>
1772 if (
size() < 2 || other.size() < 2) {
1776 const std::size_t iEnd =
size() - 1;
1777 const std::size_t jEnd = other.size() - 1;
1783 using XType = std::common_type_t<NumberType, typename OtherChain::PointType::NumberType>;
1784 const XType xlo = std::max<XType>((*
this)[0].
x(), other[0].
x());
1786 const auto jSeed = other.indexAtX(xlo);
1789 std::size_t i = (iSeed && jSeed) ? (*iSeed > 0 ? *iSeed - 1 : 0) : iEnd;
1790 std::size_t j = (iSeed && jSeed) ? (*jSeed > 0 ? *jSeed - 1 : 0) : jEnd;
1791 while (i < iEnd && j < jEnd) {
1794 if (!(mine.
max().x() < theirs.
min().x() || theirs.
max().x() < mine.
min().x()) &&
1798 const auto order = mine.
max() <=> theirs.
max();
1808 for (std::size_t v = 1; v + 1 <
size(); ++v) {
1809 if (other.interiorContains((*
this)[v])) {
1813 for (std::size_t v = 1; v + 1 < other.size(); ++v) {
1821template <
class Po
intType,
class LabelType,
class Storage>
1822template<Po
intConcept OtherPo
int>
1825 [
this](
const auto& value) {
1831template <
class Po
intType,
class LabelType>
1832template<MonotoneChainConcept OtherChain>
1834 return detail::chainInteriorsIntersect(other, *
this);
1846template <
class Po
intType,
class LabelType>
1847template<Po
intConcept OtherPo
int>
1853template <
class Po
intType,
class LabelType>
1854template<SegmentConcept OtherSegment>
1869 if (!
edge.intersects(other)) {
1872 if (
edge.collinear(other) &&
edge.min() < other.max() && other.min() <
edge.max()) {
1878 const bool excluded = (
edge.contains(front) && other.contains(front)) ||
1879 (
edge.contains(back) && other.contains(back)) ||
1880 edge.contains(other.min()) ||
edge.contains(other.max());
1888template <
class Po
intType,
class LabelType>
1889template<OrientedSegmentConcept OtherOrientedSegment>
1894template <
class Po
intType,
class LabelType>
1895template<LineConcept OtherLine>
1907 if (!
edge.intersects(other)) {
1910 if (other.contains(
edge.min()) && other.contains(
edge.max()) &&
1917 const bool excluded = (
edge.contains(front) && other.contains(front)) ||
1918 (
edge.contains(back) && other.contains(back));
1926template <
class Po
intType,
class LabelType>
1927template<OrientedLineConcept OtherOrientedLine>
1932template <
class Po
intType,
class LabelType>
1933template<RayConcept OtherRay>
1942 const auto supporting = other.asLine();
1944 if (!
edge.intersects(other)) {
1947 if (supporting.contains(
edge.min()) && supporting.contains(
edge.max())) {
1950 const bool minOnRay = other.contains(
edge.min());
1951 const bool maxOnRay = other.contains(
edge.max());
1952 if (minOnRay && maxOnRay &&
edge.min() !=
edge.max()) {
1955 if (minOnRay != maxOnRay) {
1959 if (onRay != other.source()) {
1966 const bool excluded = (
edge.contains(front) && other.contains(front)) ||
1967 (
edge.contains(back) && other.contains(back)) ||
1968 edge.contains(other.source());
1982template <
class Po
intType,
class LabelType>
1983template<HalfplaneConcept OtherHalfplane>
1985 return detail::chainInteriorsIntersect(*
this, other);
1988template <
class Po
intType,
class LabelType>
1989template<RectangleConcept OtherRectangle>
1991 if (other.empty()) {
1995 return detail::chainInteriorsIntersect(*
this, other);
1998template <
class Po
intType,
class LabelType>
1999template<TriangleConcept OtherTriangle>
2001 return detail::chainInteriorsIntersect(*
this, other);
2004template <
class Po
intType,
class LabelType>
2005template<ConvexConcept OtherConvex>
2007 return detail::chainInteriorsIntersect(*
this, other);
2010template <
class Po
intType,
class LabelType>
2011template<DiskConcept OtherDisk>
2013 return detail::chainInteriorsIntersect(*
this, other);
2016template <
class Po
intType,
class LabelType>
2017template<MonotoneChainConcept OtherChain>
2019 if (
size() < 2 || other.size() < 2) {
2026 const auto otherFront = other[0];
2027 const auto otherBack = other[other.size() - 1];
2029 for (
const auto& theirs : other.edgesView()) {
2030 if (!mine.intersects(theirs)) {
2033 if (mine.collinear(theirs) && mine.min() < theirs.max() && theirs.min() < mine.max()) {
2036 const bool excluded =
2037 (mine.contains(front) && theirs.contains(front)) ||
2038 (mine.contains(back) && theirs.contains(back)) ||
2039 (mine.contains(otherFront) && theirs.contains(otherFront)) ||
2040 (mine.contains(otherBack) && theirs.contains(otherBack));
2049template <
class Po
intType,
class LabelType>
2050template<PolylineConcept OtherPolyline>
2052 if (
size() < 2 || other.size() < 2) {
2059 const auto otherFront = other[0];
2060 const auto otherBack = other[other.size() - 1];
2062 for (
const auto& theirs : other.edgesView()) {
2063 if (!mine.intersects(theirs)) {
2066 if (mine.collinear(theirs) && mine.min() < theirs.max() && theirs.min() < mine.max()) {
2069 const bool excluded =
2070 (mine.contains(front) && theirs.contains(front)) ||
2071 (mine.contains(back) && theirs.contains(back)) ||
2072 (mine.contains(otherFront) && theirs.contains(otherFront)) ||
2073 (mine.contains(otherBack) && theirs.contains(otherBack));
2082template <
class Po
intType,
class LabelType>
2083template<Po
intConcept OtherPo
int>
2086 [
this](
const auto& value) {
2094template <
class Po
intType,
class LabelType>
2095template<PolylineConcept OtherPolyline>
2097 return detail::chainInteriorsIntersect(other, *
this);
2109template <
class Po
intType,
class LabelType>
2110template <Po
intConcept OtherPo
int>
2116template <
class Po
intType,
class LabelType>
2117template <SegmentConcept OtherSegment>
2122 if (halfplanes_.empty()) {
2125 if (other.isDegenerate()) {
2130 const auto clip = clipLine(along);
2131 if (clip.empty || clip.onParallelBoundary || !clipHasLength(clip, along)) {
2134 if (clip.entry >= 0 && !(constraintSide(
static_cast<std::size_t
>(clip.entry), other.max()) > 0)) {
2137 if (clip.exit >= 0 && !(constraintSide(
static_cast<std::size_t
>(clip.exit), other.min()) > 0)) {
2143template <
class Po
intType,
class LabelType>
2144template <OrientedSegmentConcept OtherOrientedSegment>
2149template <
class Po
intType,
class LabelType>
2150template <LineConcept OtherLine>
2155 if (halfplanes_.empty()) {
2159 const auto clip = clipLine(along);
2160 return !clip.empty && !clip.onParallelBoundary && clipHasLength(clip, along);
2163template <
class Po
intType,
class LabelType>
2164template <OrientedLineConcept OtherOrientedLine>
2169template <
class Po
intType,
class LabelType>
2170template <RayConcept OtherRay>
2175 if (halfplanes_.empty()) {
2180 const auto clip = clipLine(along);
2181 if (clip.empty || clip.onParallelBoundary || !clipHasLength(clip, along)) {
2184 return clip.exit < 0 || constraintSide(
static_cast<std::size_t
>(clip.exit), other.source()) > 0;
2187template <
class Po
intType,
class LabelType>
2188template <HalfplaneConcept OtherHalfplane>
2193 if (halfplanes_.empty()) {
2199 const SupStatus infimum = supStatus(other.opposite());
2200 return infimum == SupStatus::unbounded || infimum == SupStatus::above;
2203template <
class Po
intType,
class LabelType>
2204template <RectangleConcept OtherRectangle>
2206 if (other.empty()) {
2218template <
class Po
intType,
class LabelType>
2219template <TriangleConcept OtherTriangle>
2227template <
class Po
intType,
class LabelType>
2228template <ConvexConcept OtherConvex>
2236template <
class Po
intType,
class LabelType>
2237template <DiskConcept OtherDisk>
2242 if (halfplanes_.empty()) {
2245 using E = detail::region_exact_number_t<NumberType>;
2246 const auto clipped = detail::regionClippedToBox(*
this, other.bbox());
2247 if (clipped.isDegenerate()) {
2250 return clipped.template
asConvex<E>().interiorsIntersect(other);
2253template <
class Po
intType,
class LabelType>
2254template <MonotoneChainConcept OtherChain>
2261 for (
const auto&
edge : other.edgesView()) {
2269template <
class Po
intType,
class LabelType>
2270template <PolylineConcept OtherPolyline>
2275 for (
const auto&
edge : other.edgesView()) {
2283template <
class Po
intType,
class LabelType>
2284template <PolygonConcept OtherPolygon>
2286 if (
isDegenerate() || other.isDegenerate() || other.size() < 3) {
2289 if (halfplanes_.empty()) {
2294 using E = detail::region_exact_number_t<NumberType>;
2295 const auto clipped = detail::regionClippedToBox(*
this, other.bbox());
2296 if (clipped.isDegenerate()) {
2299 return other.interiorsIntersect(clipped.template
asConvex<E>());
2302template <
class Po
intType,
class LabelType>
2303template <HalfplaneIntersectionConcept OtherRegion>
2314template <
class Po
intType,
class LabelType>
2315template <Po
intConcept OtherPo
int>
2318 [
this](
const auto& value) {
2328template <
class Po
intType,
class LabelType>
2329template <
class OtherLinear,
class ContactNumber>
2330constexpr bool PolygonWithHoles<PointType, LabelType>::linearInteriorsIntersect(
2331 const OtherLinear& other,
2341 const std::size_t firstRingVertex = contacts.
size();
2342 for (
const auto&
vertex : outer_) {
2343 if (other.contains(
vertex)) {
2344 contacts.push_back(
static_cast<V
>(
vertex));
2347 for (
const auto& hole : holes_) {
2348 for (
const auto&
vertex : hole) {
2349 if (other.contains(
vertex)) {
2350 contacts.push_back(
static_cast<V
>(
vertex));
2375 std::vector<EdgeType> crossed;
2376 anyBoundaryEdge([&](
const auto&
edge) {
2377 if (
edge.crosses(other)) {
2378 crossed.push_back(
edge);
2382 for (std::size_t i = 0; i < crossed.size(); ++i) {
2383 bool pinched =
false;
2384 for (std::size_t v = firstRingVertex; v < contacts.size() && !pinched; ++v) {
2385 pinched = crossed[i].contains(contacts[v]);
2387 for (std::size_t j = 0; j < crossed.size() && !pinched; ++j) {
2388 pinched = j != i && crossed[i].collinear(crossed[j]);
2402 std::sort(contacts.begin(), contacts.end(), [&](
const V& p,
const V& q) {
2403 return dotSign(p, q, tail, head) > 0;
2405 const auto doubled = (*this) * NumberType(2);
2406 for (std::size_t i = 1; i < contacts.size(); ++i) {
2407 if (contacts[i - 1] == contacts[i]) {
2410 if (doubled.interiorContains(contacts[i - 1] + contacts[i])) {
2417template <
class Po
intType,
class LabelType>
2418template <SegmentConcept OtherSegment>
2424 using C = std::common_type_t<NumberType, typename OtherSegment::NumberType>;
2426 const V
begin =
static_cast<V
>(other.min());
2427 const V
end =
static_cast<V
>(other.max());
2428 return linearInteriorsIntersect(other, std::vector<V>{
begin,
end},
begin,
end);
2431template <
class Po
intType,
class LabelType>
2432template <OrientedSegmentConcept OtherOrientedSegment>
2437template <
class Po
intType,
class LabelType>
2438template <LineConcept OtherLine>
2448 using C = std::common_type_t<NumberType, typename OtherLine::NumberType>;
2450 const V
begin =
static_cast<V
>(other.min());
2451 const V
end =
static_cast<V
>(other.max());
2452 return linearInteriorsIntersect(other, std::vector<V>{},
begin,
end);
2455template <
class Po
intType,
class LabelType>
2456template <OrientedLineConcept OtherOrientedLine>
2461template <
class Po
intType,
class LabelType>
2462template <RayConcept OtherRay>
2469 using C = std::common_type_t<NumberType, typename OtherRay::NumberType>;
2471 const V source =
static_cast<V
>(other.source());
2472 const V target =
static_cast<V
>(other.target());
2473 return linearInteriorsIntersect(other, std::vector<V>{source}, source, target);
2476template <
class Po
intType,
class LabelType>
2477template <HalfplaneConcept OtherHalfplane>
2500 for (
const auto&
vertex : outer_) {
2501 if (other.interiorContains(
vertex) && isSolidVertex(
vertex)) {
2505 for (
const auto&
hole : holes_) {
2507 if (other.interiorContains(
vertex) && isSolidVertex(
vertex)) {
2515template <
class Po
intType,
class LabelType>
2516constexpr bool PolygonWithHoles<PointType, LabelType>::isSolidVertex(
const PointType&
vertex)
const {
2517 if (holes_.empty()) {
2521 anyBoundaryEdge([&](
const auto&
edge) {
2525 for (
const auto& endpoint : {
edge.min(),
edge.max()}) {
2526 if (endpoint ==
vertex) {
2532 PointType beyond = endpoint;
2533 const auto shrink = [&](
const PointType& candidate) {
2534 if (candidate !=
vertex && EdgeType(
vertex, beyond).contains(candidate)) {
2538 for (
const auto& candidate : outer_) {
2541 for (
const auto& hole : holes_) {
2542 for (
const auto& candidate : hole) {
2549 const PointType doubledMidpoint =
vertex + beyond;
2550 std::size_t covers = 0;
2551 anyBoundaryEdge([&](
const auto& candidate) {
2552 if (EdgeType(candidate.min() + candidate.min(), candidate.max() + candidate.max())
2553 .contains(doubledMidpoint)) {
2597template <
class Po
intType,
class LabelType>
2598template <
class OtherArea>
2599bool PolygonWithHoles<PointType, LabelType>::areaInteriorsIntersect(
const OtherArea& other)
const {
2600 if (isDegenerate() || other.isDegenerate()) {
2603 if (!bbox().interiorsIntersect(other.bbox())) {
2610 if (!other.hasHoles()) {
2611 return areaInteriorsIntersect(other.outer());
2613 if (holes_.empty()) {
2614 return other.interiorsIntersect(outer_);
2616 const auto mine = triangulation();
2617 const auto theirs = other.triangulation();
2618 return mine.visitTriangles([&theirs](
const auto& t) {
2619 return theirs.visitTriangles([&t](
const auto& u) {
return t.interiorsIntersect(u); });
2624 if (holes_.empty()) {
2625 return other.interiorsIntersect(outer_);
2627 for (
const auto&
edge : other.edges()) {
2628 if (interiorsIntersect(
edge)) {
2632 return triangulation().visitTriangles(
2633 [&other](
const auto& triangle) {
return other.interiorsIntersect(triangle); });
2637template <
class Po
intType,
class LabelType>
2638template <RectangleConcept OtherRectangle>
2640 if (other.empty()) {
2644 return areaInteriorsIntersect(other);
2647template <
class Po
intType,
class LabelType>
2648template <TriangleConcept OtherTriangle>
2650 return areaInteriorsIntersect(other);
2653template <
class Po
intType,
class LabelType>
2654template <ConvexConcept OtherConvex>
2656 return areaInteriorsIntersect(other);
2659template <
class Po
intType,
class LabelType>
2660template <PolygonConcept OtherPolygon>
2662 return areaInteriorsIntersect(other);
2665template <
class Po
intType,
class LabelType>
2666template <PolygonWithHolesConcept OtherRegion>
2668 return areaInteriorsIntersect(other);
2677template <
class Po
intType,
class LabelType>
2678template <MonotoneChainConcept OtherChain>
2680 return detail::chainInteriorsIntersect(other, *
this);
2683template <
class Po
intType,
class LabelType>
2684template <PolylineConcept OtherPolyline>
2686 return detail::chainInteriorsIntersect(other, *
this);
2699template <
class Po
intType,
class LabelType>
2700template <DiskConcept OtherDisk>
2705 if (holes_.empty()) {
2706 return other.interiorsIntersect(outer_);
2711 if (other.pointInsideInteriorContainedIn(*
this)) {
2715 [&other](
const auto& triangle) {
return other.interiorsIntersect(triangle); });
2722template <
class Po
intType,
class LabelType>
2723template <HalfplaneIntersectionConcept OtherIntersection>
2728 const auto clipped = detail::regionClippedToBox(other,
bbox());
2729 if (clipped.isDegenerate()) {
2732 return areaInteriorsIntersect(asConvexOperand(clipped));
2745template <
class Po
intType,
class LabelType>
2746template <Po
intConcept OtherPo
int>
2749 [
this](
const auto& value) {
2762template <
class Po
intType,
class LabelType>
2763template <detail::SetOperandConcept OtherShape>
2765 return anyComponent(
2769template <
class Po
intType,
class LabelType>
2770template <PolygonSetConcept OtherSet>
2780template <
class Po
intType,
class LabelType>
2781template <Po
intConcept OtherPo
int>
2783 return std::visit([
this](
const auto& value) {
return this->
interiorsIntersect(value); },
Exact rational number class template.
Definition rational.hpp:106
Definition forward.hpp:317
constexpr bool preferSweep(const RedShape &red, const BlueShape &blue)
Whether red against blue is a job for redBlueSweep rather than for a pairwise test of their monotone ...
Definition redbluesweep.hpp:673
Implementations of the 'interiorContains' predicate.
Definition arrangement.hpp:67
@ y
Definition intervaltree.hpp:24
@ x
Definition intervaltree.hpp:24
constexpr auto inCircleDeterminant(const Point< ANumber, ALabel > &a, const Point< BNumber, BLabel > &b, const Point< CNumber, CLabel > &c, const Point< DNumber, DLabel > &d)
Returns the signed in-circle determinant of a query point.
Definition orientation.hpp:857
constexpr bool is_Rational_v
Definition rational.hpp:37
@ edge
Definition bitmatrix.hpp:37
@ vertex
Definition bitmatrix.hpp:37
bool boundariesCross(const RedRange &red, const BlueRange &blue)
True exactly when some red edge properly crosses some blue edge.
Definition redbluesweep.hpp:482
bool boundariesMeet(const RedRange &red, const BlueRange &blue)
True exactly when some red edge meets some blue edge, crossing or not.
Definition redbluesweep.hpp:494
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
Segment() -> Segment< Point<>, NoLabel >
SweepContact boundaryContactBits(const RedRange &red, const BlueRange &blue)
Definition redbluesweep.hpp:515
constexpr auto orientationDeterminant(const Point< ANumber, ALabel > &a, const Point< BNumber, BLabel > &b, const Point< CNumber, CLabel > &c)
Returns the signed orientation determinant of three points.
Definition orientation.hpp:518
OrientedLine() -> OrientedLine< Point<>, NoLabel >
Small dispatch traits and geometry helpers reused by the implementations.
constexpr const Rectangle< PointType > & bbox() const
Computes the bounding box of the convex polygon.
Definition bounding.hpp:374
constexpr bool intersects(const OtherSegment &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:716
constexpr auto edgesView() const
Returns a lazy view over the edges, materializing each Segment on the fly instead of allocating a vec...
Definition convex.hpp:575
constexpr bool isDegenerate() const
Checks if the convex polygon is degenerate (has zero area).
Definition predicates.hpp:982
constexpr bool interiorsIntersect(const OtherPoint &other) const
Tests whether the interiors of the two shapes intersect ((A∖∂A) ∩ (B∖∂B) ≠ ∅).
Definition interiorsintersect.hpp:804
constexpr bool crosses(const OtherPoint &) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:551
constexpr bool 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
size_t size() const
Returns the number of vertices in the convex polygon.
Definition convex.hpp:840
PointType_ PointType
Definition convex.hpp:171
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 pointInsideInteriorContainedIn(const OtherShape &shape) const
Tests whether some point strictly inside this disk lies in the strict interior of shape.
Definition disk.hpp:1714
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 bool interiorsIntersect(const OtherPoint &other) const
Tests whether the interiors of the two shapes intersect ((A∖∂A) ∩ (B∖∂B) ≠ ∅).
Definition interiorsintersect.hpp:1402
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 EmptyShape< EmptyPoint > intersection(const EmptyShape< EmptyPoint > &) const
Returns the intersection of the two shapes (A ∩ B), empty when they are disjoint.
Definition halfplaneintersection.hpp:1762
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 bool isDegenerate() const
Returns whether the region has empty interior (it is empty or lower-dimensional: a line,...
Definition halfplaneintersection.hpp:664
constexpr bool interiorsIntersect(const OtherPoint &other) const
Tests whether the interiors of the two shapes intersect ((A∖∂A) ∩ (B∖∂B) ≠ ∅).
Definition interiorsintersect.hpp:2111
constexpr Convex< Point< ResultNumber, typename PointType::LabelType > > asConvex() const
Returns the region as a convex polygon.
Definition halfplaneintersection.hpp:955
constexpr std::variant< Segment< Point< ResultNumber, typename PointType::LabelType > >, Ray< Point< ResultNumber, typename PointType::LabelType > >, Line< Point< ResultNumber, typename PointType::LabelType > > > edge(std::size_t i) const
Returns the boundary contribution of half-plane i as a typed one-dimensional shape.
Definition halfplaneintersection.hpp:919
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 bool interiorsIntersect(const OtherPoint &other) const
Tests whether the interiors of the two shapes intersect ((A∖∂A) ∩ (B∖∂B) ≠ ∅).
Definition interiorsintersect.hpp:682
constexpr const PointType & target() const
Returns the target boundary point.
Definition halfplane.hpp:193
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 const PointType & max() const
Returns the largest stored defining point.
Definition line.hpp:189
constexpr const PointType & min() const
Returns the smallest stored defining point.
Definition line.hpp:180
constexpr bool intersects(const OtherPoint &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:312
constexpr bool interiorsIntersect(const OtherPoint &other) const
Tests whether the interiors of the two shapes intersect ((A∖∂A) ∩ (B∖∂B) ≠ ∅).
Definition interiorsintersect.hpp:328
constexpr bool interiorContains(const EmptyShape< EmptyPoint > &) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition line.hpp:574
constexpr bool isDegenerate() const
Returns whether the defining points coincide.
Definition predicates.hpp:451
constexpr std::optional< std::size_t > indexAtX(const OtherNumber &x) const
Locates the vertex or edge of the chain at a given x-coordinate.
Definition atxy.hpp:346
constexpr bool interiorsIntersect(const OtherPoint &other) const
Tests whether the interiors of the shapes intersect (A° ∩ B° ≠ ∅).
Definition interiorsintersect.hpp:1649
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 Line< PointType > asLine() const
Returns the line without orientation.
Definition orientedline.hpp:321
constexpr bool interiorsIntersect(const OtherPoint &other) const
Tests whether the interiors of the two shapes intersect ((A∖∂A) ∩ (B∖∂B) ≠ ∅).
Definition interiorsintersect.hpp:381
constexpr bool intersects(const OtherPoint &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:364
constexpr bool interiorsIntersect(const OtherPoint &other) const
Tests whether the interiors of the two shapes intersect ((A∖∂A) ∩ (B∖∂B) ≠ ∅).
Definition interiorsintersect.hpp:295
constexpr Segment< PointType > asSegment() const
Returns the segment without orientation.
Definition orientedsegment.hpp:322
Two-dimensional point with optional label payload.
Definition point.hpp:129
constexpr bool interiorsIntersect(const OtherPoint &other) const
Tests whether the interiors of the two shapes intersect ((A∖∂A) ∩ (B∖∂B) ≠ ∅).
Definition interiorsintersect.hpp:24
static constexpr std::size_t size()
Returns the number of coordinates (always 2).
Definition point.hpp:246
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 interiorsIntersect(const OtherShape &other) const
Tests whether the interiors of the shapes intersect (A° ∩ B° ≠ ∅).
Definition interiorsintersect.hpp:2764
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 const Rectangle< PointType > & bbox() const
Computes the bounding box of the region.
Definition polygonwithholes.hpp:1571
constexpr bool interiorsIntersect(const OtherPoint &) const
Tests whether the interiors of the shapes intersect (A° ∩ B° ≠ ∅).
Definition polygonwithholes.hpp:1660
constexpr bool isDegenerate() const
Tests whether the region has zero area.
Definition polygonwithholes.hpp:441
constexpr const PolygonType & hole(std::size_t index) const
Accesses a hole by index.
Definition polygonwithholes.hpp:196
constexpr bool intersects(const OtherPoint &point) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition polygonwithholes.hpp:1649
constexpr auto end() const
Returns a constant iterator past the last hole.
Definition polygonwithholes.hpp:213
constexpr auto begin() const
Returns a constant iterator to the first hole.
Definition polygonwithholes.hpp:207
auto triangulation() const
Builds the constrained Delaunay triangulation of this region.
Definition triangulation.hpp:6930
constexpr std::optional< PointType > getIfPoint() const
Returns the point the polygon collapses to, if it does.
Definition polygon.hpp:341
PointType::NumberType NumberType
Definition polygon.hpp:61
constexpr bool intersects(const OtherChain &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:1596
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 crosses(const OtherChain &other) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:940
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 isPoint() const
Checks whether the polygon covers exactly one point.
Definition polygon.hpp:330
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 boundariesStrongCross(const OtherPolygon &other) const
Tests whether the two polygon boundaries have mononotone chains that strong cross.
Definition interiorsintersect.hpp:1241
constexpr bool interiorsIntersect(const OtherChain &other) const
Tests whether the interiors of the shapes intersect (A° ∩ B° ≠ ∅).
Definition interiorsintersect.hpp:1833
constexpr std::vector< PointType > vertices() const
Returns the vertices of the polygon (translation applied).
Definition polygon.hpp:587
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 polygon.hpp:169
constexpr bool isDegenerate() const
Checks if the polygon is degenerate (has zero area).
Definition polygon.hpp:319
PointType_ PointType
Definition polyline.hpp:70
constexpr bool interiorsIntersect(const OtherPoint &other) const
Tests whether the interiors of the shapes intersect (A° ∩ B° ≠ ∅).
Definition interiorsintersect.hpp:1848
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 auto edgesView() const
Returns a lazy view over the edges, materializing each Segment on the fly instead of allocating a vec...
Definition polyline.hpp:627
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 isDegenerate() const
Returns whether the defining points coincide.
Definition predicates.hpp:727
constexpr const PointType & target() const
Returns the second stored point defining the direction.
Definition ray.hpp:193
constexpr bool interiorsIntersect(const OtherPoint &other) const
Tests whether the interiors of the two shapes intersect ((A∖∂A) ∩ (B∖∂B) ≠ ∅).
Definition interiorsintersect.hpp:426
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 const PointType & source() const
Returns the source point of the ray.
Definition ray.hpp:181
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 interiorsIntersect(const OtherPoint &other) const
Tests whether the interiors of the two shapes intersect ((A∖∂A) ∩ (B∖∂B) ≠ ∅).
Definition interiorsintersect.hpp:551
constexpr std::array< PointType, 4 > vertices() const
Returns the four vertices in counterclockwise order.
Definition bounding.hpp:188
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 const PointType & max() const
Returns the maximum corner (max x, max y).
Definition rectangle.hpp:359
Unoriented closed segment between two endpoints plus optional segment label.
Definition segment.hpp:58
constexpr const PointType & max() const
Returns the largest stored endpoint.
Definition segment.hpp:199
constexpr const PointType & min() const
Returns the smallest stored endpoint.
Definition segment.hpp:190
constexpr bool interiorsIntersect(const OtherPoint &other) const
Tests whether the interiors of the two shapes intersect ((A∖∂A) ∩ (B∖∂B) ≠ ∅).
Definition interiorsintersect.hpp:39
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
Closed triangle stored by three vertices.
Definition triangle.hpp:53
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 interiorsIntersect(const OtherPoint &other) const
Tests whether the interiors of the two shapes intersect ((A∖∂A) ∩ (B∖∂B) ≠ ∅).
Definition interiorsintersect.hpp:132
constexpr bool intersects(const OtherPoint &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:134
constexpr Rectangle< PointType > bbox() const
Returns the axis-aligned bounding box of the vertices.
Definition bounding.hpp:224
constexpr bool isDegenerate() const
Tests whether the three vertices are collinear.
Definition predicates.hpp:223
constexpr std::array< Segment< PointType >, 3 > edges() const
Returns the three unoriented boundary edges.
Definition bounding.hpp:240
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