Pangolin
Header-only C++20 plane computational geometry library
Loading...
Searching...
No Matches
polygonset.hpp
Go to the documentation of this file.
1#pragma once
2
4
5#include <algorithm>
6#include <cassert>
7#include <compare>
8#include <concepts>
9#include <cstddef>
10#include <iterator>
11#include <optional>
12#include <ostream>
13#include <ranges>
14#include <type_traits>
15#include <utility>
16#include <variant>
17#include <vector>
18
19
20namespace pgl {
21
22namespace detail {
23
38template <class T>
39concept SetOperandConcept =
40 shapeRank<std::remove_cvref_t<T>> >= 0 &&
41 shapeRank<std::remove_cvref_t<T>> < shapeRank<PolygonSet<Point<>, NoLabel>> &&
42 !is_empty_shape_v<T>;
43
53template <class T>
54concept SetBooleanOperandConcept = PolygonalRegionConcept<T>;
55
67template <class T>
68concept SetMinkowskiOperandConcept =
69 SetBooleanOperandConcept<T> || is_segment_v<T> || is_oriented_segment_v<T> ||
70 is_polyline_v<T> || is_monotone_chain_v<T>;
71
82template <class ResultNumber, class Component, class Operand>
83concept ComponentDistanceL1Concept =
84 requires(const Component& component, const Operand& operand) {
85 component.template distanceL1<ResultNumber>(operand);
86 };
87
89template <class ResultNumber, class Component, class Operand>
90concept ComponentDistanceLInfConcept =
91 requires(const Component& component, const Operand& operand) {
92 component.template distanceLInf<ResultNumber>(operand);
93 };
94
95} // namespace detail
96
97template <class PointType = Point<>, class Label>
98struct PolygonSet;
99
100// Explicit deduction guides, rather than the implicit ones the constrained
101// constructors below would otherwise synthesize: clang 18 mishandles the
102// constraints on such a guide, and CI compiles with it.
104
105template <PolygonWithHolesConcept Component>
107
108template <std::ranges::input_range ComponentRange>
109 requires detail::is_polygon_with_holes_v<std::ranges::range_value_t<ComponentRange>>
110PolygonSet(ComponentRange&&)
112
113template <std::ranges::input_range ComponentRange>
114 requires detail::is_polygon_with_holes_v<std::ranges::range_value_t<ComponentRange>>
115PolygonSet(ComponentRange&&, bool)
117
118
164template <class PointType_, class TLabel>
166 using PointType = PointType_;
167 using NumberType = typename PointType::NumberType;
168 using LabelType = TLabel;
170
171 class VertexIterator;
174 static_assert(detail::is_point_v<PointType>, "PolygonSet requires pgl::Point vertices");
175
179 constexpr PolygonSet() = default;
180
188 constexpr explicit PolygonSet(ComponentType component) {
189 if (!component.isDegenerate()) {
190 components_.push_back(std::move(component));
191 }
192 }
193
209 template <std::ranges::input_range ComponentRange>
210 requires detail::is_polygon_with_holes_v<std::ranges::range_value_t<ComponentRange>>
211 constexpr PolygonSet(ComponentRange&& components, bool trusted = false) {
212 for (const auto& component : components) {
213 components_.emplace_back(component);
214 }
215 if (!trusted) {
216 normalize();
217 }
218 }
219
231 template <PointConcept OtherPointType, class OtherLabelType>
232 requires(std::constructible_from<PointType, const OtherPointType&>)
234 components_.reserve(other.componentCount());
235 for (const auto& component : other.components()) {
236 components_.emplace_back(component);
237 }
238 }
239
248 template <class A = LabelType>
249 requires(detail::has_label_v<A>)
250 constexpr A& label() const {
251 return label_;
252 }
253
254 // -------------------------------------------------------------------------
255 // Component access
256 //
257 // Deliberately not `size()` / `operator[]`: `size()` counts defining points
258 // on Polygon, Convex, Polyline and MonotoneChain, and a name whose meaning
259 // differs per shape is a trap in generic code. @ref PolygonWithHoles made
260 // the same call for its holes.
261
263 [[nodiscard]] constexpr std::size_t componentCount() const {
264 return components_.size();
265 }
266
271 [[nodiscard]] constexpr const ComponentType& component(std::size_t index) const {
272 assert(index < components_.size());
273 return components_[index];
274 }
275
277 [[nodiscard]] constexpr const std::vector<ComponentType>& components() const {
278 return components_;
279 }
280
282 [[nodiscard]] constexpr auto begin() const { return components_.begin(); }
283
285 [[nodiscard]] constexpr auto cbegin() const { return components_.cbegin(); }
286
288 [[nodiscard]] constexpr auto end() const { return components_.end(); }
289
291 [[nodiscard]] constexpr auto cend() const { return components_.cend(); }
292
304 if (component.isDegenerate()) {
305 return;
306 }
307 const auto position = std::lower_bound(components_.begin(), components_.end(), component);
308 if (position != components_.end() && *position == component) {
309 return;
310 }
311 components_.insert(position, std::move(component));
312 resetCache();
313 }
314
325 constexpr void eraseComponent(std::size_t index) {
326 assert(index < components_.size());
327 components_.erase(components_.begin() + static_cast<std::ptrdiff_t>(index));
328 resetCache();
329 }
330
341 constexpr bool eraseComponent(const ComponentType& component) {
342 const auto position = std::lower_bound(components_.begin(), components_.end(), component);
343 if (position == components_.end() || !(*position == component)) {
344 return false;
345 }
346 components_.erase(position);
347 resetCache();
348 return true;
349 }
350
352 [[nodiscard]] constexpr std::size_t holeCount() const {
353 std::size_t total = 0;
354 for (const auto& component : components_) {
355 total += component.holeCount();
356 }
357 return total;
358 }
359
361 [[nodiscard]] constexpr bool hasHoles() const {
362 for (const auto& component : components_) {
363 if (component.hasHoles()) {
364 return true;
365 }
366 }
367 return false;
368 }
369
377 [[nodiscard]] constexpr std::size_t vertexCount() const {
378 std::size_t total = 0;
379 for (const auto& component : components_) {
380 total += component.vertexCount();
381 }
382 return total;
383 }
384
386 [[nodiscard]] constexpr std::vector<PointType> vertices() const {
387 std::vector<PointType> result;
388 result.reserve(vertexCount());
389 for (const auto& component : components_) {
390 for (const auto& vertex : component.vertices()) {
391 result.push_back(vertex);
392 }
393 }
394 return result;
395 }
396
405 [[nodiscard]] constexpr auto verticesView() const {
406 return std::ranges::subrange(verticesBegin(), verticesEnd());
407 }
408
410 [[nodiscard]] constexpr VertexIterator verticesBegin() const {
411 return VertexIterator(this, 0);
412 }
413
415 [[nodiscard]] constexpr VertexIterator verticesEnd() const {
416 return VertexIterator(this, components_.size());
417 }
418
420 [[nodiscard]] constexpr std::vector<EdgeType> edges() const {
421 std::vector<EdgeType> result;
422 result.reserve(vertexCount());
423 for (const auto& component : components_) {
424 for (const auto& edge : component.edges()) {
425 result.push_back(edge);
426 }
427 }
428 return result;
429 }
430
437 [[nodiscard]] constexpr std::vector<OrientedSegment<PointType>> orientedEdges() const {
438 std::vector<OrientedSegment<PointType>> result;
439 result.reserve(vertexCount());
440 for (const auto& component : components_) {
441 for (const auto& edge : component.orientedEdges()) {
442 result.push_back(edge);
443 }
444 }
445 return result;
446 }
447
448 // -------------------------------------------------------------------------
449 // Value semantics
450
452 [[nodiscard]] constexpr auto operator<=>(const PolygonSet& other) const {
453 if (auto cmp = components_.size() <=> other.components_.size(); cmp != 0) {
454 return cmp;
455 }
456 for (std::size_t i = 0; i < components_.size(); ++i) {
457 if (auto cmp = components_[i] <=> other.components_[i]; cmp != 0) {
458 return cmp;
459 }
460 }
461 return std::strong_ordering::equal;
462 }
463
465 [[nodiscard]] constexpr bool operator==(const PolygonSet& other) const {
466 if (components_.size() != other.components_.size()) {
467 return false;
468 }
469 for (std::size_t i = 0; i < components_.size(); ++i) {
470 if (!(components_[i] == other.components_[i])) {
471 return false;
472 }
473 }
474 return true;
475 }
476
478 template<AnyShapeConcept OtherShape>
479 [[nodiscard]] constexpr bool samePointSet(const OtherShape& other) const;
480
481 // -------------------------------------------------------------------------
482 // State queries
483
485 [[nodiscard]] constexpr bool empty() const {
486 return components_.empty();
487 }
488
499 [[nodiscard]] constexpr bool isDegenerate() const {
500 using Exact = detail::promoted_number_t<NumberType>;
501 return twiceArea<Exact>() == Exact(0);
502 }
503
510 [[nodiscard]] constexpr bool isPoint() const {
511 return components_.size() == 1 && components_[0].isPoint();
512 }
513
515 [[nodiscard]] constexpr bool isSegment() const {
516 return components_.size() == 1 && components_[0].isSegment();
517 }
518
523 [[nodiscard]] constexpr bool isUndefined() const {
524 return !isPoint() && !isSegment() && isDegenerate();
525 }
526
536 template <class Rational = pgl::Rational<pgl::BigInt>>
537 [[nodiscard]] bool isSimple() const {
538 for (const auto& component : components_) {
539 if (!component.template isSimple<Rational>()) {
540 return false;
541 }
542 }
543 return true;
544 }
545
565 template <class Rational = pgl::Rational<pgl::BigInt>>
566 [[nodiscard]] bool isValid() const;
567
583 [[nodiscard]] bool isRegular() const {
584 for (const auto& component : components_) {
585 if (!component.isRegular()) {
586 return false;
587 }
588 }
589 return true;
590 }
591
607 template <class ResultNumber = division_result_t<NumberType>>
609
610 // -------------------------------------------------------------------------
611 // Measures
612
624 template <class ResultNumber = NumberType>
625 [[nodiscard]] constexpr ResultNumber twiceArea() const {
626 ResultNumber total{};
627 for (const auto& component : components_) {
628 total += component.template twiceArea<ResultNumber>();
629 }
630 return total;
631 }
632
637 template <class ResultNumber = division_result_t<NumberType>>
638 [[nodiscard]] constexpr auto area() const {
639 ResultNumber result = static_cast<ResultNumber>(twiceArea());
640 return result / ResultNumber(2);
641 }
642
654 template <class ResultNumber = division_result_t<NumberType>>
655 [[nodiscard]] constexpr Point<ResultNumber> centroid() const;
656
658 template <class ResultNumber = division_result_t<NumberType>>
659 [[nodiscard]] constexpr Point<ResultNumber> verticesCentroid() const;
660
673 template <class ResultNumber = division_result_t<NumberType>>
674 [[nodiscard]] Point<ResultNumber> pointInside() const;
675
685 [[nodiscard]] constexpr Segment<PointType> diameter() const {
686 std::vector<PointType> hullPoints;
687 hullPoints.reserve(vertexCount());
688 for (const auto& component : components_) {
689 for (const auto& vertex : component.outer()) {
690 hullPoints.push_back(vertex);
691 }
692 }
693 return Convex<PointType>(std::move(hullPoints)).diameter();
694 }
695
702 [[nodiscard]] constexpr Convex<PointType> convexHull() const {
703 std::vector<PointType> hullPoints;
704 hullPoints.reserve(vertexCount());
705 for (const auto& component : components_) {
706 for (const auto& vertex : component.outer()) {
707 hullPoints.push_back(vertex);
708 }
709 }
710 return Convex<PointType>(std::move(hullPoints));
711 }
712
719 [[nodiscard]] constexpr const Rectangle<PointType>& bbox() const;
720
739 template <class ResultNumber = grid_number_t<typename PointType_::NumberType>>
740 requires(detail::extended_integral<ResultNumber> || std::same_as<ResultNumber, BigInt>)
743
745 template <std::floating_point ResultNumber = double>
746 [[nodiscard]] constexpr Rectangle<Point<ResultNumber>> fbox() const;
747
748 // -------------------------------------------------------------------------
749 // Decompositions
750
762 auto triangulation() const;
763
773 template <class SegmentRange>
774 auto triangulation(const SegmentRange& segments) const;
775
787 [[nodiscard]] std::vector<Convex<PointType>> convexPartition() const;
788
800 [[nodiscard]] std::vector<Convex<PointType>> convexCovering() const;
801
827 template <class ResultNumber = grid_number_t<typename PointType_::NumberType>>
828 requires(std::signed_integral<ResultNumber>)
829 [[nodiscard]] auto asBitMatrix() const;
830
831 // -------------------------------------------------------------------------
832 // Boolean operations
833 //
834 // This is what the shape is for. `Polygon` and `PolygonWithHoles` already
835 // produce a set of regions from a difference, a union or a symmetric
836 // difference, and now say so in their return type; a set does the same and
837 // takes one back, so the four operations are **closed** and a result can be
838 // fed straight into the next one.
839 //
840 // The engine does not care that a receiver is a set: it is the arrangement
841 // of both operands' boundaries with one witness test per cell, and a set
842 // contributes its components' rings the way a region contributes its own.
843 // In particular the operands go in together rather than being folded over
844 // one component at a time, so one arrangement settles the whole answer.
845
856 template <class ResultNumber = division_result_t<NumberType>, detail::SetBooleanOperandConcept OtherShape>
858 difference(const OtherShape& other) const;
859
869 template <class ResultNumber = division_result_t<NumberType>, HalfplaneIntersectionConcept OtherIntersection>
871 difference(const OtherIntersection& other) const;
872
879 template <class ResultNumber = division_result_t<NumberType>, HalfplaneConcept OtherHalfplane>
881 difference(const OtherHalfplane& other) const;
882
891 template <class ResultNumber = division_result_t<NumberType>, detail::SetBooleanOperandConcept OtherShape>
893 regularizedUnion(const OtherShape& other) const;
894
903 template <class ResultNumber = division_result_t<NumberType>, detail::SetBooleanOperandConcept OtherShape>
905 regularizedIntersection(const OtherShape& other) const;
906
913 template <class ResultNumber = division_result_t<NumberType>, detail::SetBooleanOperandConcept OtherShape>
915 symmetricDifference(const OtherShape& other) const;
916
926 template <class ResultNumber = division_result_t<NumberType>, HalfplaneIntersectionConcept OtherIntersection>
928 regularizedIntersection(const OtherIntersection& other) const;
929
931 template <class ResultNumber = division_result_t<NumberType>, HalfplaneConcept OtherHalfplane>
933 regularizedIntersection(const OtherHalfplane& other) const;
934
951 template <class ResultNumber = division_result_t<NumberType>, detail::SetBooleanOperandConcept OtherShape>
952 [[nodiscard]] std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
955 intersection(const OtherShape& other) const;
956
969 template <class ResultNumber = division_result_t<NumberType>, HalfplaneIntersectionConcept OtherIntersection>
970 [[nodiscard]] std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
973 intersection(const OtherIntersection& other) const;
974
976 template <class ResultNumber = division_result_t<NumberType>, HalfplaneConcept OtherHalfplane>
977 [[nodiscard]] std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
980 intersection(const OtherHalfplane& other) const;
981
983 template <class ResultNumber = NumberType, class EmptyPoint>
984 [[nodiscard]] constexpr EmptyShape<EmptyPoint> intersection(const EmptyShape<EmptyPoint>&) const {
985 return {};
986 }
987
988 // -------------------------------------------------------------------------
989 // Predicates
990 //
991 // With `A = ⋃ Aᵢ`, interiors pairwise disjoint and contacts finite, four of
992 // the five relations fold over the components outright:
993 //
994 // intersects(x) ∃i Aᵢ.intersects(x) — A is the union
995 // interiorsIntersect(x) ∃i Aᵢ.interiorsIntersect(x) — A° = ⋃ Aᵢ°
996 // interiorContains(x) ∃i Aᵢ.interiorContains(x) — see below
997 // contains(point) ∃i Aᵢ.contains(point)
998 //
999 // `A° = ⋃ Aᵢ°` is what the no-shared-edge clause of @ref isValid buys, and
1000 // it settles `interiorContains` for every operand: the `Aᵢ°` are open and
1001 // pairwise disjoint, so a connected operand inside their union is inside one
1002 // of them, and every shape but another set is connected.
1003 //
1004 // `contains` and `boundaryContains` are the two that do not fold, and they
1005 // fail for exactly one kind of operand. `∃i` is still necessary and
1006 // sufficient whenever the operand stays connected after finitely many points
1007 // are removed — every operand with area, and every point — because the
1008 // components meet at finitely many points at most. A **one-dimensional**
1009 // operand does not: two unit squares meeting corner to corner at the origin
1010 // contain the segment from (-1,-1) to (1,1) between them and neither
1011 // contains it alone. Those operands are settled by splitting them at every
1012 // component-boundary contact and classifying each piece, which is exact and
1013 // costs nothing when the components do not touch at all (@ref isPinched).
1014
1021 template <detail::SetOperandConcept OtherShape>
1022 [[nodiscard]] bool intersects(const OtherShape& other) const;
1023
1029 template <detail::SetOperandConcept OtherShape>
1030 [[nodiscard]] bool interiorsIntersect(const OtherShape& other) const;
1031
1043 template <detail::SetOperandConcept OtherShape>
1044 [[nodiscard]] bool contains(const OtherShape& other) const;
1045
1053 template <detail::SetOperandConcept OtherShape>
1054 [[nodiscard]] bool interiorContains(const OtherShape& other) const;
1055
1063 template <SegmentConcept OtherSegment>
1064 [[nodiscard]] bool interiorContainsInterior(const OtherSegment& other) const;
1065
1073 template <detail::SetOperandConcept OtherShape>
1074 [[nodiscard]] bool boundaryContains(const OtherShape& other) const;
1075
1086 template <detail::SetOperandConcept OtherShape>
1087 [[nodiscard]] bool separates(const OtherShape& other) const;
1088
1090 template <detail::SetOperandConcept OtherShape>
1091 [[nodiscard]] bool crosses(const OtherShape& other) const;
1092
1093 // -------------------------------------------------------------------------
1094 // The self pair. A set operand is the one operand that need not be
1095 // connected, so the relations that lean on the operand's connectedness fold
1096 // over *its* components instead of assuming it lies in one piece.
1097
1099 template <PolygonSetConcept OtherSet>
1100 [[nodiscard]] bool intersects(const OtherSet& other) const;
1101
1103 template <PolygonSetConcept OtherSet>
1104 [[nodiscard]] bool interiorsIntersect(const OtherSet& other) const;
1105
1107 template <PolygonSetConcept OtherSet>
1108 [[nodiscard]] bool contains(const OtherSet& other) const;
1109
1111 template <PolygonSetConcept OtherSet>
1112 [[nodiscard]] bool interiorContains(const OtherSet& other) const;
1113
1115 template <PolygonSetConcept OtherSet>
1116 [[nodiscard]] bool boundaryContains(const OtherSet& other) const;
1117
1119 template <PolygonSetConcept OtherSet>
1120 [[nodiscard]] bool separates(const OtherSet& other) const;
1121
1123 template <PolygonSetConcept OtherSet>
1124 [[nodiscard]] bool crosses(const OtherSet& other) const;
1125
1126 // -------------------------------------------------------------------------
1127 // The empty set is a subset of every shape, so its containment relations are
1128 // true and its intersection relations are false.
1129
1131 template <class EmptyPoint>
1132 [[nodiscard]] constexpr bool contains(const EmptyShape<EmptyPoint>&) const {
1133 return true;
1134 }
1135
1137 template <class EmptyPoint>
1138 [[nodiscard]] constexpr bool interiorContains(const EmptyShape<EmptyPoint>&) const {
1139 return true;
1140 }
1141
1143 template <class EmptyPoint>
1144 [[nodiscard]] constexpr bool boundaryContains(const EmptyShape<EmptyPoint>&) const {
1145 return true;
1146 }
1147
1149 template <class EmptyPoint>
1150 [[nodiscard]] constexpr bool intersects(const EmptyShape<EmptyPoint>&) const {
1151 return false;
1152 }
1153
1155 template <class EmptyPoint>
1156 [[nodiscard]] constexpr bool interiorsIntersect(const EmptyShape<EmptyPoint>&) const {
1157 return false;
1158 }
1159
1161 template <class EmptyPoint>
1162 [[nodiscard]] constexpr bool separates(const EmptyShape<EmptyPoint>&) const {
1163 return false;
1164 }
1165
1167 template <class EmptyPoint>
1168 [[nodiscard]] constexpr bool crosses(const EmptyShape<EmptyPoint>&) const {
1169 return false;
1170 }
1171
1172 // -------------------------------------------------------------------------
1173 // Runtime Shape argument: visit the wrapped alternative and re-dispatch to
1174 // the matching per-shape overload (defined in the implementation layer).
1175
1177 template <PointConcept OtherPoint>
1178 [[nodiscard]] bool contains(const Shape<OtherPoint>& other) const;
1179
1181 template <PointConcept OtherPoint>
1182 [[nodiscard]] bool interiorContains(const Shape<OtherPoint>& other) const;
1183
1185 template <PointConcept OtherPoint>
1186 [[nodiscard]] bool boundaryContains(const Shape<OtherPoint>& other) const;
1187
1189 template <PointConcept OtherPoint>
1190 [[nodiscard]] bool intersects(const Shape<OtherPoint>& other) const;
1191
1193 template <PointConcept OtherPoint>
1194 [[nodiscard]] bool interiorsIntersect(const Shape<OtherPoint>& other) const;
1195
1197 template <PointConcept OtherPoint>
1198 [[nodiscard]] bool separates(const Shape<OtherPoint>& other) const;
1199
1201 template <PointConcept OtherPoint>
1202 [[nodiscard]] bool crosses(const Shape<OtherPoint>& other) const;
1203
1204 // -------------------------------------------------------------------------
1205 // Distances
1206 //
1207 // The distance to a union is the minimum of the distances, with no caveat at
1208 // all: every one of these is exactly the minimum over the components.
1209
1225 template <class ResultNumber = division_result_t<NumberType>, detail::SetOperandConcept OtherShape>
1226 [[nodiscard]] auto squaredDistance(const OtherShape& other) const;
1227
1229 template <class ResultNumber = division_result_t<NumberType>, PolygonSetConcept OtherSet>
1230 [[nodiscard]] auto squaredDistance(const OtherSet& other) const;
1231
1244 template <class ResultNumber = NumberType, BoundedPolygonalConcept OtherShape>
1245 requires detail::ClosestPairConcept<PolygonSet<PointType_, TLabel>, OtherShape>
1246 [[nodiscard]] auto closestSegments(const OtherShape& other) const;
1247
1264 template <class ResultNumber = division_result_t<NumberType>, class OtherShape>
1265 requires detail::ClosestPointsPairConcept<PolygonSet<PointType_, TLabel>, OtherShape>
1266 [[nodiscard]] auto closestPoints(const OtherShape& other) const;
1267
1275 template <class ResultNumber = division_result_t<NumberType>, detail::SetOperandConcept OtherShape>
1276 requires detail::ComponentDistanceL1Concept<ResultNumber, PolygonWithHoles<PointType_>, OtherShape>
1277 [[nodiscard]] auto distanceL1(const OtherShape& other) const;
1278
1280 template <class ResultNumber = division_result_t<NumberType>, PolygonSetConcept OtherSet>
1281 [[nodiscard]] auto distanceL1(const OtherSet& other) const;
1282
1284 template <class ResultNumber = division_result_t<NumberType>, detail::SetOperandConcept OtherShape>
1285 requires detail::ComponentDistanceLInfConcept<ResultNumber, PolygonWithHoles<PointType_>, OtherShape>
1286 [[nodiscard]] auto distanceLInf(const OtherShape& other) const;
1287
1289 template <class ResultNumber = division_result_t<NumberType>, PolygonSetConcept OtherSet>
1290 [[nodiscard]] auto distanceLInf(const OtherSet& other) const;
1291
1307 template <class ResultNumber = division_result_t<NumberType>, PointConcept OtherPoint>
1308 [[nodiscard]] constexpr auto intersection(const Shape<OtherPoint>& other) const {
1309 return other.template intersection<ResultNumber>(*this);
1310 }
1311
1313 template <class ResultNumber = division_result_t<NumberType>, PointConcept OtherPoint>
1314 [[nodiscard]] auto regularizedIntersection(const Shape<OtherPoint>& other) const {
1315 return other.template regularizedIntersection<ResultNumber>(*this);
1316 }
1317
1330 template <class ResultNumber = division_result_t<NumberType>, PointConcept OtherPoint>
1331 [[nodiscard]] auto regularizedUnion(const Shape<OtherPoint>& other) const {
1332 return other.template regularizedUnion<ResultNumber>(*this);
1333 }
1334
1349 template <class ResultNumber = division_result_t<NumberType>, PointConcept OtherPoint>
1350 [[nodiscard]] auto difference(const Shape<OtherPoint>& other) const {
1351 return Shape<OtherPoint>(*this).template difference<ResultNumber>(other);
1352 }
1353
1366 template <class ResultNumber = division_result_t<NumberType>, PointConcept OtherPoint>
1367 [[nodiscard]] auto symmetricDifference(const Shape<OtherPoint>& other) const {
1368 return other.template symmetricDifference<ResultNumber>(*this);
1369 }
1370
1375 template <class ResultNumber = double, PointConcept OtherPoint>
1376 [[nodiscard]] constexpr auto distanceL1(const Shape<OtherPoint>& other) const {
1377 return other.template distanceL1<ResultNumber>(*this);
1378 }
1379
1384 template <class ResultNumber = double, PointConcept OtherPoint>
1385 [[nodiscard]] constexpr auto distanceLInf(const Shape<OtherPoint>& other) const {
1386 return other.template distanceLInf<ResultNumber>(*this);
1387 }
1388
1401 [[nodiscard]] bool isPinched() const;
1402
1418 [[nodiscard]] bool isConnected() const;
1419
1434 template <class OtherShape>
1436 [[nodiscard]] constexpr auto minkowskiSum(const OtherShape& other) const;
1437
1460 template <class OtherShape>
1462 [[nodiscard]] constexpr auto minkowskiErosion(const OtherShape& other) const;
1463
1495 template <class ResultNumber = division_result_t<NumberType>, class OtherShape>
1499 minkowskiErosion(const OtherShape& other) const;
1500
1531 template <class ResultNumber = division_result_t<NumberType>,
1532 detail::SetMinkowskiOperandConcept OtherShape>
1534 minkowskiSum(const OtherShape& other) const;
1535
1536 // -------------------------------------------------------------------------
1537 // Transformations
1538
1540 template <class TranslationNumber, class TranslationLabel>
1542 for (auto& component : components_) {
1543 component += translation;
1544 }
1545 resetCache();
1546 return *this;
1547 }
1548
1550 template <class TranslationNumber, class TranslationLabel>
1552 return *this += (-translation);
1553 }
1554
1562 template <class Scalar>
1563 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
1564 constexpr PolygonSet& operator*=(const Scalar& scalar) {
1565 for (auto& component : components_) {
1566 component *= scalar;
1567 }
1568 normalize();
1569 return *this;
1570 }
1571
1573 template <class Scalar>
1574 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
1575 constexpr PolygonSet& operator/=(const Scalar& scalar) {
1576 for (auto& component : components_) {
1577 component /= scalar;
1578 }
1579 normalize();
1580 return *this;
1581 }
1582
1584 [[nodiscard]] constexpr PolygonSet rotated90(int k) const {
1585 return mappedComponents([k](const ComponentType& component) { return component.rotated90(k); });
1586 }
1587
1589 constexpr void rotate90(int k) {
1590 auto saved = label_;
1591 *this = rotated90(k);
1592 label_ = std::move(saved);
1593 }
1594
1602 template <class OtherNumber>
1603 [[nodiscard]] constexpr PolygonSet scaledUpX(const OtherNumber scalar) const {
1604 return mappedComponents(
1605 [scalar](const ComponentType& component) { return component.scaledUpX(scalar); });
1606 }
1607
1609 template <class OtherNumber>
1610 constexpr void scaleUpX(const OtherNumber scalar) {
1611 auto saved = label_;
1612 *this = scaledUpX(scalar);
1613 label_ = std::move(saved);
1614 }
1615
1617 template <class OtherNumber>
1618 [[nodiscard]] constexpr PolygonSet scaledUpY(const OtherNumber scalar) const {
1619 return mappedComponents(
1620 [scalar](const ComponentType& component) { return component.scaledUpY(scalar); });
1621 }
1622
1624 template <class OtherNumber>
1625 constexpr void scaleUpY(const OtherNumber scalar) {
1626 auto saved = label_;
1627 *this = scaledUpY(scalar);
1628 label_ = std::move(saved);
1629 }
1630
1632 template <class OtherNumber>
1633 [[nodiscard]] constexpr PolygonSet scaledDownX(const OtherNumber scalar) const {
1634 return mappedComponents(
1635 [scalar](const ComponentType& component) { return component.scaledDownX(scalar); });
1636 }
1637
1639 template <class OtherNumber>
1640 constexpr void scaleDownX(const OtherNumber scalar) {
1641 auto saved = label_;
1642 *this = scaledDownX(scalar);
1643 label_ = std::move(saved);
1644 }
1645
1647 template <class OtherNumber>
1648 [[nodiscard]] constexpr PolygonSet scaledDownY(const OtherNumber scalar) const {
1649 return mappedComponents(
1650 [scalar](const ComponentType& component) { return component.scaledDownY(scalar); });
1651 }
1652
1654 template <class OtherNumber>
1655 constexpr void scaleDownY(const OtherNumber scalar) {
1656 auto saved = label_;
1657 *this = scaledDownY(scalar);
1658 label_ = std::move(saved);
1659 }
1660
1670 public:
1671 using iterator_category = std::forward_iterator_tag;
1672 using iterator_concept = std::forward_iterator_tag;
1674 using difference_type = std::ptrdiff_t;
1676
1677 constexpr VertexIterator() = default;
1678
1679 constexpr value_type operator*() const {
1680 assert(set != nullptr);
1681 return *inner;
1682 }
1683
1685 ++inner;
1686 skipExhausted();
1687 return *this;
1688 }
1689
1691 VertexIterator copy(*this);
1692 ++(*this);
1693 return copy;
1694 }
1695
1696 constexpr bool operator==(const VertexIterator& other) const = default;
1697
1698 private:
1699 friend struct PolygonSet;
1700
1701 constexpr VertexIterator(const PolygonSet* set_arg, std::size_t component_arg)
1702 : set(set_arg), component(component_arg) {
1703 enterComponent();
1704 skipExhausted();
1705 }
1706
1707 // Seeds `inner` from the current component, or clears it at the end so
1708 // that a walked-to-the-end iterator compares equal to verticesEnd().
1709 constexpr void enterComponent() {
1710 const std::size_t count = set == nullptr ? 0 : set->components_.size();
1711 inner = component < count ? set->components_[component].verticesBegin()
1712 : typename ComponentType::VertexIterator{};
1713 }
1714
1715 // Steps over components holding no vertices. A canonical set has none —
1716 // addComponent() drops the ones without area — but this keeps the end
1717 // state reachable by increment alone for a set built any other way.
1718 constexpr void skipExhausted() {
1719 const std::size_t count = set == nullptr ? 0 : set->components_.size();
1720 while (component < count && inner == set->components_[component].verticesEnd()) {
1721 ++component;
1722 enterComponent();
1723 }
1724 }
1725
1726 const PolygonSet* set = nullptr;
1727 std::size_t component = 0;
1728 typename ComponentType::VertexIterator inner{};
1729 };
1730
1731 private:
1738 template <class ComponentRelation>
1739 constexpr bool anyComponent(ComponentRelation&& relation) const {
1740 for (const auto& component : components_) {
1741 if (relation(component)) {
1742 return true;
1743 }
1744 }
1745 return false;
1746 }
1747
1763 template <class OtherSegment>
1764 bool segmentIn(const OtherSegment& segment, bool boundaryOnly) const;
1765
1770 template <class OtherChain>
1771 bool chainIn(const OtherChain& chain, bool boundaryOnly) const;
1772
1806 template <class OtherRegion>
1807 bool regionIn(const OtherRegion& region) const;
1808
1818 template <class ComponentDistance>
1819 auto minOverComponents(ComponentDistance&& distance) const {
1820 using ResultNumber = std::decay_t<decltype(distance(std::declval<const ComponentType&>()))>;
1821 ResultNumber best{};
1822 bool seeded = false;
1823 for (const auto& component : components_) {
1824 const ResultNumber current = distance(component);
1825 if (!seeded || current < best) {
1826 best = current;
1827 seeded = true;
1828 }
1829 }
1830 return best;
1831 }
1832
1841 template <class ComponentTransform>
1842 constexpr PolygonSet mappedComponents(ComponentTransform&& transform) const {
1843 PolygonSet result;
1844 result.components_.reserve(components_.size());
1845 for (const auto& component : components_) {
1846 result.components_.push_back(transform(component));
1847 }
1848 result.normalize();
1849 return result;
1850 }
1851
1852 std::vector<ComponentType> components_{};
1853 [[no_unique_address]] mutable LabelType label_{};
1854
1855 // Cached bounding box. A region reads its own off its outer ring, which
1856 // caches one already; a set has no single ring to ask, so it caches the
1857 // union of the components' boxes itself.
1858 mutable Rectangle<PointType> bbox_{};
1859
1860 // Tri-state cache for @ref isPinched: -1 not yet computed, 0 no two
1861 // components touch, 1 some two do.
1862 mutable signed char pinched_ = -1;
1863
1864 // Memoized hash, computed lazily by std::hash<PolygonSet>, with the same
1865 // sentinel scheme as Polygon and PolygonWithHoles: hashUnset_ means "not yet
1866 // computed", and the one true hash colliding with it is remapped so the
1867 // sentinel is never stored as a real value.
1868 static constexpr std::size_t hashUnset_ = pgl::detail::numeric_limits<std::size_t>::max();
1869 mutable std::size_t hash_ = hashUnset_;
1870 friend struct std::hash<PolygonSet>;
1871
1872 template <class OtherPointType, class OtherLabelType>
1873 friend struct PolygonSet;
1874
1875 constexpr void resetCache() const {
1876 hash_ = hashUnset_;
1877 bbox_ = {};
1878 pinched_ = -1;
1879 }
1880
1890 constexpr void normalize() {
1891 std::erase_if(components_,
1892 [](const ComponentType& component) { return component.isDegenerate(); });
1893 std::sort(components_.begin(), components_.end());
1894 components_.erase(std::unique(components_.begin(), components_.end()), components_.end());
1895 resetCache();
1896 }
1897};
1898
1899// `set + point` is the translating Minkowski sum, spelled by the generic
1900// operator+ in implementation/minkowski.hpp like every other shape's: writing a
1901// second one here would shadow it and, holding the set's own point type, would
1902// silently truncate a translation that does not fit it.
1903
1905template <class PointType, class LabelType, class TranslationNumber, class TranslationLabel>
1907 const Point<TranslationNumber, TranslationLabel>& translation) {
1908 return set + (-translation);
1909}
1910
1911template <class PointType, class LabelType, class Scalar>
1912 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
1913constexpr auto operator*(const PolygonSet<PointType, LabelType>& set, const Scalar& scalar) {
1914 using ResultPointType = Point<decltype(std::declval<PointType>().x() * scalar), typename PointType::LabelType>;
1916 result *= scalar;
1917 if constexpr (detail::has_label_v<LabelType>) {
1918 result.label() = LabelType{};
1919 }
1920 return result;
1921}
1922
1923template <class Scalar, class PointType, class LabelType>
1924 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
1925constexpr auto operator*(const Scalar& scalar, const PolygonSet<PointType, LabelType>& set) {
1926 return set * scalar;
1927}
1928
1929template <class PointType, class LabelType, class Scalar>
1930 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
1931constexpr auto operator/(const PolygonSet<PointType, LabelType>& set, const Scalar& scalar) {
1932 using ResultPointType = Point<decltype(std::declval<PointType>().x() / scalar), typename PointType::LabelType>;
1934 result /= scalar;
1935 if constexpr (detail::has_label_v<LabelType>) {
1936 result.label() = LabelType{};
1937 }
1938 return result;
1939}
1940
1941template <class PointType, class LabelType>
1942std::ostream& operator<<(std::ostream& stream, const PolygonSet<PointType, LabelType>& set);
1943
1944} // namespace pgl
friend struct PolygonSet
Definition polygonset.hpp:1699
constexpr VertexIterator()=default
PointType value_type
Definition polygonset.hpp:1673
value_type reference
Definition polygonset.hpp:1675
constexpr value_type operator*() const
Definition polygonset.hpp:1679
std::ptrdiff_t difference_type
Definition polygonset.hpp:1674
constexpr VertexIterator operator++(int)
Definition polygonset.hpp:1690
std::forward_iterator_tag iterator_category
Definition polygonset.hpp:1671
constexpr VertexIterator & operator++()
Definition polygonset.hpp:1684
constexpr bool operator==(const VertexIterator &other) const =default
std::forward_iterator_tag iterator_concept
Definition polygonset.hpp:1672
Bounded polygonal primitives, convex or not.
Definition forward.hpp:373
Shape pairs whose Minkowski sum Pangolin can represent.
Definition forward.hpp:476
Definition forward.hpp:324
Definition arrangement.hpp:67
@ edge
Definition bitmatrix.hpp:37
@ vertex
Definition bitmatrix.hpp:37
Point() -> Point< int >
constexpr auto operator-(const Point< LeftNumber, LeftLabel > &left, const Point< RightNumber, RightLabel > &right)
Translates a point by the opposite of another point.
Definition transformations.hpp:130
PolygonSet() -> PolygonSet< Point<>, NoLabel >
Definition polygonset.hpp:1699
Shape(const std::variant< T, Ts... > &) -> Shape< detail::shape_point_type_t< T > >
std::ostream & operator<<(std::ostream &stream, const Point< Number, Label > &point)
Streams a point as (x,y) or label:(x,y).
Definition io.hpp:27
Closed convex polygon stored by its vertices.
Definition convex.hpp:170
constexpr Segment< PointType > diameter() const
Returns a segment realizing the diameter (the farthest vertex pair).
Definition measures.hpp:696
The empty set of points in the plane.
Definition emptyshape.hpp:33
Sentinel type used when a point carries no extra label.
Definition point.hpp:31
Two-dimensional point with optional label payload.
Definition point.hpp:129
Set of closed regions with pairwise disjoint interiors.
Definition polygonset.hpp:165
bool isSimple() const
Tests whether every ring of every component is simple.
Definition polygonset.hpp:537
std::vector< Convex< PointType > > convexCovering() const
Covers this set with a greedily selected set of convex polygons.
Definition triangulation.hpp:6967
constexpr Point< ResultNumber > centroid() const
Computes the area-weighted centroid of the set.
Definition measures.hpp:1184
friend struct PolygonSet
Definition polygonset.hpp:1873
bool contains(const Shape< OtherPoint > &other) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:3660
constexpr bool intersects(const EmptyShape< EmptyPoint > &) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition polygonset.hpp:1150
auto triangulation() const
Builds the constrained Delaunay triangulation of this set.
Definition triangulation.hpp:6951
constexpr auto cbegin() const
Returns a constant iterator to the first component.
Definition polygonset.hpp:285
PolygonSet< Point< ResultNumber, typename PointType::LabelType > > regularizedIntersection(const OtherHalfplane &other) const
Returns the regularized intersection of the two shapes (A ∩ B).
constexpr EmptyShape< EmptyPoint > intersection(const EmptyShape< EmptyPoint > &) const
Returns the intersection of the two shapes (A ∩ B), empty when they are disjoint.
Definition polygonset.hpp:984
constexpr std::vector< EdgeType > edges() const
Returns the boundary edges of every ring of every component.
Definition polygonset.hpp:420
constexpr ResultNumber twiceArea() const
Computes twice the area of the set.
Definition polygonset.hpp:625
constexpr Rectangle< Point< ResultNumber > > fbox() const
Computes the floating-point bounding box of the set.
Definition bounding.hpp:487
PolygonSet< Point< ResultNumber, typename PointType::LabelType > > symmetricDifference(const OtherShape &other) const
Returns the regularized symmetric difference of the two shapes (A △ B).
constexpr bool operator==(const PolygonSet &other) const
Checks equality of two sets.
Definition polygonset.hpp:465
typename PointType::NumberType NumberType
Definition polygonset.hpp:167
constexpr bool eraseComponent(const ComponentType &component)
Erases the component equal to the given region, if the set has one.
Definition polygonset.hpp:341
bool contains(const OtherSet &other) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:3647
auto squaredDistance(const OtherShape &other) const
Computes the squared Euclidean distance to the other shape.
Definition distance.hpp:2025
constexpr PolygonSet(const PolygonSet< OtherPointType, OtherLabelType > &other)
Converts a set with compatible vertex type.
Definition polygonset.hpp:233
constexpr void addComponent(ComponentType component)
Adds a component, keeping the canonical order.
Definition polygonset.hpp:303
PolygonSet< Point< ResultNumber, typename PointType::LabelType > > difference(const OtherHalfplane &other) const
Returns the regularized set difference of the two shapes (A ∖ B).
PolygonSet< Point< ResultNumber, typename PointType::LabelType > > difference(const OtherShape &other) const
Returns the regularized set difference of the two shapes (A ∖ B).
auto regularizedIntersection(const Shape< OtherPoint > &other) const
Re-dispatches a regularized intersection through a runtime shape.
Definition polygonset.hpp:1314
constexpr bool interiorContains(const EmptyShape< EmptyPoint > &) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition polygonset.hpp:1138
constexpr Point< ResultNumber > verticesCentroid() const
Computes the centroid of the vertex set over every ring of every component.
Definition measures.hpp:1166
constexpr Segment< PointType > diameter() const
Returns a segment realizing the diameter (the farthest vertex pair).
Definition polygonset.hpp:685
constexpr PolygonSet()=default
Creates the empty set (no components).
constexpr PolygonSet scaledDownX(const OtherNumber scalar) const
Returns the set with its x-coordinates multiplied by scalar.
Definition polygonset.hpp:1633
bool boundaryContains(const Shape< OtherPoint > &other) const
Tests whether this shape's boundary contains the other shape (∂A ⊇ B).
Definition boundarycontains.hpp:2155
constexpr Convex< PointType > convexHull() const
Returns the convex hull of the set's vertices.
Definition polygonset.hpp:702
PolygonSet< Point< ResultNumber, typename PointType::LabelType > > minkowskiSum(const OtherShape &other) const
Returns the regularized Minkowski sum of the two shapes (A ⊕ B), as a set of regions.
constexpr PolygonSet(ComponentType component)
Creates a set with a single component.
Definition polygonset.hpp:188
bool interiorsIntersect(const Shape< OtherPoint > &other) const
Tests whether the interiors of the shapes intersect (A° ∩ B° ≠ ∅).
Definition interiorsintersect.hpp:2782
bool intersects(const Shape< OtherPoint > &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:2251
Polygon< PointType > PolygonType
Definition polygonset.hpp:172
std::vector< std::variant< Point< ResultNumber, typename PointType::LabelType >, Polyline< Point< ResultNumber, typename PointType::LabelType > >, PolygonWithHoles< Point< ResultNumber, typename PointType::LabelType > > > > intersection(const OtherShape &other) const
Returns the intersection of the two shapes (A ∩ B), empty when they are disjoint.
bool isConnected() const
Tests whether the set is connected as a point set.
Definition separates.hpp:5799
constexpr bool isSegment() const
Tests whether the set covers exactly one segment of positive length.
Definition polygonset.hpp:515
bool isRegular() const
Tests whether the set is the closure of its own interior (A = closure(A°)).
Definition polygonset.hpp:583
constexpr auto begin() const
Returns a constant iterator to the first component.
Definition polygonset.hpp:282
bool interiorsIntersect(const OtherShape &other) const
Tests whether the interiors of the shapes intersect (A° ∩ B° ≠ ∅).
Definition interiorsintersect.hpp:2764
Segment< PointType > EdgeType
Definition polygonset.hpp:173
constexpr bool crosses(const EmptyShape< EmptyPoint > &) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition polygonset.hpp:1168
constexpr auto minkowskiErosion(const OtherShape &other) const
Returns the Minkowski erosion of this shape by another (A ⊖ B).
Definition minkowskierosion.hpp:640
auto squaredDistance(const OtherSet &other) const
Computes the squared Euclidean distance to the other shape.
Definition distance.hpp:2033
constexpr auto minkowskiSum(const OtherShape &other) const
Returns the Minkowski sum of this shape and another (A ⊕ B).
Definition minkowski.hpp:807
constexpr bool hasHoles() const
Tests whether any component has a hole.
Definition polygonset.hpp:361
std::vector< Point< ResultNumber, typename PointType::LabelType > > latticePoints() const
Returns the integer points the set contains.
Definition lattice.hpp:703
PolygonSet< Point< ResultNumber, typename PointType::LabelType > > regularizedUnion(const OtherShape &other) const
Returns the regularized union of the two shapes (A ∪ B).
auto closestSegments(const OtherShape &other) const
Returns the pair of elements realizing the distance, nothing when the shapes meet.
Definition closest.hpp:440
constexpr auto operator<=>(const PolygonSet &other) const
Compares two sets by component count, then lexicographically.
Definition polygonset.hpp:452
bool interiorContains(const OtherShape &other) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition interiorcontains.hpp:2583
bool separates(const OtherSet &other) const
Tests whether removing this shape disconnects the other shape (B∖A is disconnected).
Definition separates.hpp:5892
auto difference(const Shape< OtherPoint > &other) const
Returns the regularized set difference of the two shapes (A ∖ B), re-dispatching through the wrapper'...
Definition polygonset.hpp:1350
constexpr void eraseComponent(std::size_t index)
Erases the component at the given index.
Definition polygonset.hpp:325
PolygonSet< Point< ResultNumber, typename PointType::LabelType > > regularizedIntersection(const OtherShape &other) const
Returns the regularized intersection of the two shapes (A ∩ B).
constexpr PolygonSet(ComponentRange &&components, bool trusted=false)
Creates a set from a range of components.
Definition polygonset.hpp:211
constexpr std::size_t vertexCount() const
Returns the total number of vertices over every ring of every component.
Definition polygonset.hpp:377
constexpr auto distanceL1(const Shape< OtherPoint > &other) const
Returns the Manhattan (L1) distance to the given shape, using symmetry to re-dispatch through the wra...
Definition polygonset.hpp:1376
PolygonSet< Point< ResultNumber, typename PointType_::LabelType > > minkowskiErosion(const OtherShape &other) const
Returns the regularized Minkowski erosion of this shape by a bounded polygonal one (A ⊖ B),...
Definition minkowskierosion.hpp:724
constexpr bool empty() const
Tests whether the set has no components at all.
Definition polygonset.hpp:485
constexpr void scaleUpX(const OtherNumber scalar)
Scales the set's x-coordinates up in place.
Definition polygonset.hpp:1610
auto distanceLInf(const OtherShape &other) const
Computes the squared Euclidean distance to the other shape.
Definition distancelinf.hpp:1620
constexpr bool isPoint() const
Tests whether the set covers exactly one point.
Definition polygonset.hpp:510
bool crosses(const Shape< OtherPoint > &other) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:1302
auto regularizedUnion(const Shape< OtherPoint > &other) const
Returns the regularized union of the two shapes (A ∪ B), re-dispatching through the wrapper's own reg...
Definition polygonset.hpp:1331
constexpr bool isUndefined() const
Tests whether the set is degenerate without covering a point or a segment (which includes the empty s...
Definition polygonset.hpp:523
bool intersects(const OtherSet &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:2240
constexpr void rotate90(int k)
Rotates the set by 90k degrees around the origin in place.
Definition polygonset.hpp:1589
auto triangulation(const SegmentRange &segments) const
Builds the constrained Delaunay triangulation of this set with the given interior constraint segments...
Definition triangulation.hpp:6957
constexpr PolygonSet & operator-=(const Point< TranslationNumber, TranslationLabel > &translation)
Translates the set in place by the opposite vector.
Definition polygonset.hpp:1551
constexpr PolygonSet & operator+=(const Point< TranslationNumber, TranslationLabel > &translation)
Translates the set in place.
Definition polygonset.hpp:1541
constexpr void scaleDownY(const OtherNumber scalar)
Scales the set's y-coordinates down in place.
Definition polygonset.hpp:1655
bool interiorContainsInterior(const OtherSegment &other) const
Tests whether this shape's interior contains the segment's interior.
Definition interiorcontains.hpp:2591
PointType PointType
Definition polygonset.hpp:166
constexpr const std::vector< ComponentType > & components() const
Definition polygonset.hpp:277
constexpr A & label() const
Returns the set label.
Definition polygonset.hpp:250
std::vector< Convex< PointType > > convexPartition() const
Cuts this set into convex pieces with disjoint interiors.
Definition triangulation.hpp:6962
bool intersects(const OtherShape &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:2234
bool crosses(const OtherShape &other) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:1286
std::vector< std::variant< Point< ResultNumber, typename PointType::LabelType >, Polyline< Point< ResultNumber, typename PointType::LabelType > >, PolygonWithHoles< Point< ResultNumber, typename PointType::LabelType > > > > intersection(const OtherIntersection &other) const
Returns the intersection of the two shapes (A ∩ B), empty when they are disjoint.
PolygonSet< Point< ResultNumber, typename PointType::LabelType > > difference(const OtherIntersection &other) const
Returns the regularized set difference of the two shapes (A ∖ B).
auto closestPoints(const OtherShape &other) const
Returns the pair of points realizing the distance, nothing when the shapes meet.
Definition closest.hpp:447
constexpr const ComponentType & component(std::size_t index) const
Definition polygonset.hpp:271
constexpr bool samePointSet(const OtherShape &other) const
Tests whether another shape defines exactly the same point set.
Definition samepointset.hpp:2037
constexpr bool interiorsIntersect(const EmptyShape< EmptyPoint > &) const
Tests whether the interiors of the shapes intersect (A° ∩ B° ≠ ∅).
Definition polygonset.hpp:1156
constexpr PolygonSet scaledUpY(const OtherNumber scalar) const
Returns the set with its x-coordinates multiplied by scalar.
Definition polygonset.hpp:1618
constexpr VertexIterator verticesEnd() const
Returns an iterator past the last vertex of the last component.
Definition polygonset.hpp:415
bool crosses(const OtherSet &other) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:1296
bool interiorContains(const OtherSet &other) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition interiorcontains.hpp:2599
constexpr bool boundaryContains(const EmptyShape< EmptyPoint > &) const
Tests whether this shape's boundary contains the other shape (∂A ⊇ B).
Definition polygonset.hpp:1144
constexpr bool separates(const EmptyShape< EmptyPoint > &) const
Tests whether removing this shape disconnects the other shape (B∖A is disconnected).
Definition polygonset.hpp:1162
constexpr void scaleDownX(const OtherNumber scalar)
Scales the set's x-coordinates down in place.
Definition polygonset.hpp:1640
bool contains(const OtherShape &other) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:3564
auto distanceLInf(const OtherSet &other) const
Computes the squared Euclidean distance to the other shape.
Definition distancelinf.hpp:1628
bool separates(const Shape< OtherPoint > &other) const
Tests whether removing this shape disconnects the other shape (B∖A is disconnected).
Definition separates.hpp:5898
constexpr bool isDegenerate() const
Tests whether the set has zero area.
Definition polygonset.hpp:499
constexpr bool contains(const EmptyShape< EmptyPoint > &) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition polygonset.hpp:1132
PolygonSet< Point< ResultNumber, typename PointType::LabelType > > regularized() const
Returns the set without its slits (closure(A°)).
auto asBitMatrix() const
Rasterizes this set into a BitMatrix, one bit per covered cell.
Definition bitmatrix.hpp:2712
constexpr auto area() const
Computes the area of the set.
Definition polygonset.hpp:638
constexpr std::vector< PointType > vertices() const
Returns the vertices of every ring of every component.
Definition polygonset.hpp:386
constexpr void scaleUpY(const OtherNumber scalar)
Scales the set's y-coordinates up in place.
Definition polygonset.hpp:1625
constexpr auto cend() const
Returns a constant iterator past the last component.
Definition polygonset.hpp:291
bool interiorsIntersect(const OtherSet &other) const
Tests whether the interiors of the shapes intersect (A° ∩ B° ≠ ∅).
Definition interiorsintersect.hpp:2771
bool isPinched() const
Tests whether two components touch each other anywhere.
Definition contains.hpp:3368
constexpr std::size_t componentCount() const
Returns the number of components.
Definition polygonset.hpp:263
constexpr auto verticesView() const
Returns a lazy view over the vertices of every ring of every component, without allocating a vector.
Definition polygonset.hpp:405
bool interiorContains(const Shape< OtherPoint > &other) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition interiorcontains.hpp:2610
constexpr std::size_t holeCount() const
Returns the total number of holes over all components.
Definition polygonset.hpp:352
bool isValid() const
Tests the structural contract: every component valid, component interiors pairwise disjoint,...
Definition intersections.hpp:1248
PolygonWithHoles< PointType > ComponentType
Definition polygonset.hpp:169
constexpr PolygonSet scaledUpX(const OtherNumber scalar) const
Returns the set with its x-coordinates multiplied by scalar.
Definition polygonset.hpp:1603
constexpr auto distanceLInf(const Shape< OtherPoint > &other) const
Returns the Chebyshev (L∞) distance to the given shape, using symmetry to re-dispatch through the wra...
Definition polygonset.hpp:1385
Point< ResultNumber > pointInside() const
Returns a point strictly inside the set.
Definition triangulation.hpp:6975
bool boundaryContains(const OtherSet &other) const
Tests whether this shape's boundary contains the other shape (∂A ⊇ B).
Definition boundarycontains.hpp:2144
PolygonSet< Point< ResultNumber, typename PointType::LabelType > > regularizedIntersection(const OtherIntersection &other) const
Returns the regularized intersection of the two shapes (A ∩ B).
auto distanceL1(const OtherSet &other) const
Computes the squared Euclidean distance to the other shape.
Definition distancel1.hpp:1639
constexpr auto intersection(const Shape< OtherPoint > &other) const
Returns the intersection of the two shapes (A ∩ B), re-dispatching through the wrapper's own intersec...
Definition polygonset.hpp:1308
auto symmetricDifference(const Shape< OtherPoint > &other) const
Returns the regularized symmetric difference of the two shapes (A △ B), re-dispatching through the wr...
Definition polygonset.hpp:1367
constexpr auto end() const
Returns a constant iterator past the last component.
Definition polygonset.hpp:288
constexpr std::vector< OrientedSegment< PointType > > orientedEdges() const
Returns the boundary edges directed so the set lies to the left.
Definition polygonset.hpp:437
TLabel LabelType
Definition polygonset.hpp:168
constexpr PolygonSet scaledDownY(const OtherNumber scalar) const
Returns the set with its x-coordinates multiplied by scalar.
Definition polygonset.hpp:1648
std::vector< std::variant< Point< ResultNumber, typename PointType::LabelType >, Polyline< Point< ResultNumber, typename PointType::LabelType > >, PolygonWithHoles< Point< ResultNumber, typename PointType::LabelType > > > > intersection(const OtherHalfplane &other) const
Returns the intersection of the two shapes (A ∩ B), empty when they are disjoint.
constexpr VertexIterator verticesBegin() const
Returns an iterator to the first vertex of the first component.
Definition polygonset.hpp:410
auto distanceL1(const OtherShape &other) const
Computes the squared Euclidean distance to the other shape.
Definition distancel1.hpp:1631
constexpr const Rectangle< PointType > & bbox() const
Computes the bounding box of the set.
Definition bounding.hpp:469
constexpr PolygonSet rotated90(int k) const
Returns the set rotated by 90k degrees around the origin.
Definition polygonset.hpp:1584
bool boundaryContains(const OtherShape &other) const
Tests whether this shape's boundary contains the other shape (∂A ⊇ B).
Definition boundarycontains.hpp:2104
bool separates(const OtherShape &other) const
Tests whether removing this shape disconnects the other shape (B∖A is disconnected).
Definition separates.hpp:5849
Closed region bounded by one outer simple polygon minus disjoint polygonal holes.
Definition polygonwithholes.hpp:89
constexpr bool isDegenerate() const
Tests whether the region has zero area.
Definition polygonwithholes.hpp:441
Closed simple polygon stored by its vertices.
Definition polygon.hpp:59
Open polygonal chain stored in traversal order; may self-intersect.
Definition polyline.hpp:69
Axis-aligned rectangle stored by minimum and maximum corners.
Definition rectangle.hpp:75
Unoriented closed segment between two endpoints plus optional segment label.
Definition segment.hpp:58
Runtime variant wrapper over the supported primitive shapes.
Definition shape.hpp:160