29template <
class Po
intType,
class T>
30struct is_shape_alternative : std::false_type {};
32template <
class Po
intType>
33struct is_shape_alternative<PointType, EmptyShape<PointType>> : std::true_type {};
35template <
class Po
intType,
class Number,
class Label>
36struct is_shape_alternative<PointType,
Point<Number, Label>> : std::bool_constant<std::same_as<PointType, Point<Number, Label>>> {};
38template <
class Po
intType,
class Label>
39struct is_shape_alternative<PointType,
Segment<PointType, Label>> : std::true_type {};
41template <
class Po
intType>
42struct is_shape_alternative<PointType,
OrientedSegment<PointType>> : std::true_type {};
44template <
class Po
intType>
45struct is_shape_alternative<PointType,
Line<PointType>> : std::true_type {};
47template <
class Po
intType>
48struct is_shape_alternative<PointType,
OrientedLine<PointType>> : std::true_type {};
50template <
class Po
intType>
51struct is_shape_alternative<PointType,
Ray<PointType>> : std::true_type {};
53template <
class Po
intType>
54struct is_shape_alternative<PointType,
Halfplane<PointType>> : std::true_type {};
56template <
class Po
intType>
57struct is_shape_alternative<PointType,
Rectangle<PointType>> : std::true_type {};
59template <
class Po
intType>
60struct is_shape_alternative<PointType,
Triangle<PointType>> : std::true_type {};
62template <
class Po
intType>
63struct is_shape_alternative<PointType,
Convex<PointType>> : std::true_type {};
65template <
class Po
intType,
class Label>
66struct is_shape_alternative<PointType,
Disk<PointType, Label>> : std::true_type {};
68template <
class Po
intType>
69struct is_shape_alternative<PointType,
MonotoneChain<PointType>> : std::true_type {};
71template <
class Po
intType>
72struct is_shape_alternative<PointType,
Polyline<PointType>> : std::true_type {};
74template <
class Po
intType>
75struct is_shape_alternative<PointType,
Polygon<PointType>> : std::true_type {};
77template <
class Po
intType,
class Label>
80template <
class Po
intType,
class Label>
81struct is_shape_alternative<PointType,
PolygonWithHoles<PointType, Label>> : std::true_type {};
83template <
class Po
intType,
class Label>
84struct is_shape_alternative<PointType,
PolygonSet<PointType, Label>> : std::true_type {};
86template <
class Po
intType,
class T>
87inline constexpr bool is_shape_alternative_v = is_shape_alternative<PointType, std::remove_cvref_t<T>>::value;
89template <
class Po
intType,
class T>
90concept ShapeAlternative = is_shape_alternative_v<PointType, T>;
94struct is_std_optional : std::false_type {};
96struct is_std_optional<std::optional<T>> : std::true_type {};
99struct is_std_vector : std::false_type {};
100template <
class T,
class A>
101struct is_std_vector<std::vector<T, A>> : std::true_type {};
104struct is_std_variant : std::false_type {};
105template <
class... Ts>
106struct is_std_variant<std::variant<Ts...>> : std::true_type {};
111template <
class Po
intType,
class T>
112struct is_shape_variant : std::false_type {};
114template <
class PointType,
class... Ts>
115struct is_shape_variant<PointType, std::variant<Ts...>>
116 : std::bool_constant<(is_shape_alternative_v<PointType, Ts> && ...)> {};
118template <
class Po
intType,
class T>
119inline constexpr bool is_shape_variant_v = is_shape_variant<PointType, std::remove_cvref_t<T>>::value;
122template <
class Po
intType,
class T>
123struct is_shape_optional_variant : std::false_type {};
125template <
class Po
intType,
class V>
126struct is_shape_optional_variant<PointType, std::optional<V>>
127 : std::bool_constant<is_shape_variant_v<PointType, V>> {};
129template <
class Po
intType,
class T>
130inline constexpr bool is_shape_optional_variant_v =
131 is_shape_optional_variant<PointType, std::remove_cvref_t<T>>::value;
137struct shape_point_type {
138 using type =
typename T::PointType;
141template <
class Number,
class Label>
142struct shape_point_type<
Point<Number, Label>> {
143 using type = Point<Number, Label>;
147using shape_point_type_t =
typename shape_point_type<T>::type;
159template <
class Po
intType = Po
int<>>
201 requires(detail::ShapeAlternative<PointType, T>)
203 : value_(std::forward<T>(value)) {}
217 template <
class Result>
218 requires(detail::is_shape_variant_v<PointType, Result> ||
219 detail::is_shape_optional_variant_v<PointType, Result>)
220 constexpr Shape(
const Result& result) {
221 if constexpr (detail::is_shape_optional_variant_v<PointType, Result>) {
223 *
this =
Shape(*result);
227 [
this](
const auto& alternative) { *
this =
Shape(alternative); }, result);
239 requires(detail::ShapeAlternative<PointType, T>)
240 constexpr Shape&
operator=(T&& value) {
241 value_ = std::forward<T>(value);
251 template<AnyShapeConcept OtherShape>
252 [[nodiscard]]
constexpr bool samePointSet(
const OtherShape& other)
const;
293 [[nodiscard]]
constexpr bool empty()
const {
294 return std::visit([](
const auto& value) {
return detail::coversNoPoint(value); },
305 [](
const auto& value) {
306 if constexpr (
requires { value.isDegenerate(); }) {
307 return value.isDegenerate();
330 }
else if constexpr (
requires { value.bbox(); }) {
333 throw std::logic_error(
"Shape::bbox is not defined for this unbounded alternative");
352 [[nodiscard]]
constexpr std::size_t
size()
const {
354 [](
const auto& value) -> std::size_t {
355 using S = std::decay_t<
decltype(value)>;
356 if constexpr (detail::is_polygon_with_holes_v<S>) {
357 throw std::logic_error(
"Shape::size is not defined for the PolygonWithHoles alternative");
358 }
else if constexpr (detail::is_polygon_set_v<S>) {
359 throw std::logic_error(
"Shape::size is not defined for the PolygonSet alternative");
381 using S = std::decay_t<
decltype(value)>;
382 if constexpr (std::same_as<S, PointType_>) {
383 throw std::logic_error(
"Shape::get is not defined for the Point alternative");
384 }
else if constexpr (detail::is_halfplane_intersection_v<S>) {
385 throw std::logic_error(
"Shape::get is not defined for the HalfplaneIntersection alternative");
386 }
else if constexpr (detail::is_polygon_with_holes_v<S>) {
387 throw std::logic_error(
"Shape::get is not defined for the PolygonWithHoles alternative");
388 }
else if constexpr (detail::is_polygon_set_v<S>) {
389 throw std::logic_error(
"Shape::get is not defined for the PolygonSet alternative");
391 return value.get(
index);
411 using S = std::decay_t<
decltype(value)>;
412 if constexpr (std::same_as<S, PointType_>) {
413 throw std::logic_error(
"Shape::operator[] is not defined for the Point alternative");
414 }
else if constexpr (detail::is_halfplane_intersection_v<S>) {
415 throw std::logic_error(
"Shape::operator[] is not defined for the HalfplaneIntersection alternative");
416 }
else if constexpr (detail::is_polygon_with_holes_v<S>) {
417 throw std::logic_error(
"Shape::operator[] is not defined for the PolygonWithHoles alternative");
418 }
else if constexpr (detail::is_polygon_set_v<S>) {
419 throw std::logic_error(
"Shape::operator[] is not defined for the PolygonSet alternative");
441 [&point](
const auto& value) -> std::ptrdiff_t {
442 using S = std::decay_t<
decltype(value)>;
443 if constexpr (std::same_as<S, PointType_>) {
444 throw std::logic_error(
"Shape::index(Point) is not defined for the Point alternative");
445 }
else if constexpr (detail::is_halfplane_intersection_v<S>) {
446 throw std::logic_error(
"Shape::index(Point) is not defined for the HalfplaneIntersection alternative");
447 }
else if constexpr (detail::is_polygon_with_holes_v<S>) {
448 throw std::logic_error(
"Shape::index(Point) is not defined for the PolygonWithHoles alternative");
449 }
else if constexpr (detail::is_polygon_set_v<S>) {
450 throw std::logic_error(
"Shape::index(Point) is not defined for the PolygonSet alternative");
452 return value.index(point);
470 [&value](
const auto& shape) -> std::ptrdiff_t {
471 using S = std::decay_t<
decltype(shape)>;
472 if constexpr (std::same_as<S, PointType_>) {
473 return shape.index(value);
475 throw std::logic_error(
"Shape::index(NumberType) is only defined for the Point alternative");
488 requires(detail::ShapeAlternative<PointType, T>)
490 return std::holds_alternative<std::remove_cvref_t<T>>(value_);
500 requires(detail::ShapeAlternative<PointType, T>)
501 constexpr const std::remove_cvref_t<T>*
getIf()
const {
502 return std::get_if<std::remove_cvref_t<T>>(&value_);
512 requires(detail::ShapeAlternative<PointType, T>)
513 constexpr std::remove_cvref_t<T>*
getIf() {
514 return std::get_if<std::remove_cvref_t<T>>(&value_);
541#define PGL_SHAPE_ALTERNATIVE(Name, Type) \
543 [[nodiscard]] constexpr bool is##Name() const { \
544 return std::holds_alternative<Type>(value_); \
548 [[nodiscard]] constexpr const Type* getIf##Name() const { \
549 return std::get_if<Type>(&value_); \
553 [[nodiscard]] constexpr Type* getIf##Name() { \
554 return std::get_if<Type>(&value_); \
575#undef PGL_SHAPE_ALTERNATIVE
589 requires(detail::ShapeAlternative<PointType, T>)
590 constexpr explicit operator T()
const {
591 return std::get<std::remove_cvref_t<T>>(value_);
601 template <
class Other>
602 requires(std::same_as<std::remove_cvref_t<Other>,
Shape> || detail::ShapeAlternative<PointType, Other>)
603 constexpr bool contains(
const Other& other)
const {
604 return applyPredicate(
605 [](
const auto& left,
const auto& right) {
606 if constexpr (
requires { left.contains(right); }) {
607 return left.contains(right);
622 template <
class Other>
623 requires(std::same_as<std::remove_cvref_t<Other>,
Shape> || detail::ShapeAlternative<PointType, Other>)
625 return applyPredicate(
626 [](
const auto& left,
const auto& right) {
627 if constexpr (
requires { left.boundaryContains(right); }) {
628 return left.boundaryContains(right);
643 template <
class Other>
644 requires(std::same_as<std::remove_cvref_t<Other>,
Shape> || detail::ShapeAlternative<PointType, Other>)
646 return applyPredicate(
647 [](
const auto& left,
const auto& right) {
648 if constexpr (
requires { left.interiorContains(right); }) {
649 return left.interiorContains(right);
664 template <
class Other>
665 requires(std::same_as<std::remove_cvref_t<Other>,
Shape> || detail::ShapeAlternative<PointType, Other>)
666 constexpr bool intersects(
const Other& other)
const {
667 return applyPredicate(
668 [](
const auto& left,
const auto& right) {
669 if constexpr (
requires { left.intersects(right); }) {
670 return left.intersects(right);
685 template <
class Other>
686 requires(std::same_as<std::remove_cvref_t<Other>,
Shape> || detail::ShapeAlternative<PointType, Other>)
688 return applyPredicate(
689 [](
const auto& left,
const auto& right) {
690 if constexpr (
requires { left.interiorsIntersect(right); }) {
691 return left.interiorsIntersect(right);
706 template <
class Other>
707 requires(std::same_as<std::remove_cvref_t<Other>,
Shape> || detail::ShapeAlternative<PointType, Other>)
708 constexpr bool separates(
const Other& other)
const {
709 return applyPredicate(
710 [](
const auto& left,
const auto& right) {
711 if constexpr (
requires { left.separates(right); }) {
712 return left.separates(right);
727 template <
class Other>
728 requires(std::same_as<std::remove_cvref_t<Other>,
Shape> || detail::ShapeAlternative<PointType, Other>)
729 constexpr bool crosses(
const Other& other)
const {
730 return applyPredicate(
731 [](
const auto& left,
const auto& right) {
732 if constexpr (
requires { left.crosses(right); }) {
733 return left.crosses(right);
783 template <
class ResultNumber = division_result_t<NumberType>,
class Other>
784 requires(std::same_as<std::remove_cvref_t<Other>,
Shape> || detail::ShapeAlternative<PointType, Other>)
786 if constexpr (detail::is_shape_v<Other>) {
788 [](
const auto& left,
const auto& right) {
789 return intersectionOf<ResultNumber>(left, right);
795 [&other](
const auto& left) {
796 return intersectionOf<ResultNumber>(left, other);
825 template <
class ResultNumber = division_result_t<NumberType>,
class Other>
826 requires(std::same_as<std::remove_cvref_t<Other>,
Shape> || detail::ShapeAlternative<PointType, Other>)
828 if constexpr (detail::is_shape_v<Other>) {
830 [](
const auto& left,
const auto& right) {
831 return regularizedIntersectionOf<ResultNumber>(left, right);
837 [&other](
const auto& left) {
838 return regularizedIntersectionOf<ResultNumber>(left, other);
874 template <
class ResultNumber = division_result_t<NumberType>,
class Other>
875 requires(std::same_as<std::remove_cvref_t<Other>,
Shape> || detail::ShapeAlternative<PointType, Other>)
877 if constexpr (detail::is_shape_v<Other>) {
879 [](
const auto& left,
const auto& right) {
880 return regularizedUnionOf<ResultNumber>(left, right);
886 [&other](
const auto& left) {
887 return regularizedUnionOf<ResultNumber>(left, other);
924 template <
class ResultNumber = division_result_t<NumberType>,
class Other>
925 requires(std::same_as<std::remove_cvref_t<Other>,
Shape> || detail::ShapeAlternative<PointType, Other>)
927 if constexpr (detail::is_shape_v<Other>) {
929 [](
const auto& left,
const auto& right) {
930 return differenceOf<ResultNumber>(left, right);
936 [&other](
const auto& left) {
937 return differenceOf<ResultNumber>(left, other);
962 template <
class ResultNumber = division_result_t<NumberType>,
class Other>
963 requires(std::same_as<std::remove_cvref_t<Other>,
Shape> || detail::ShapeAlternative<PointType, Other>)
965 if constexpr (detail::is_shape_v<Other>) {
967 [](
const auto& left,
const auto& right) {
968 return symmetricDifferenceOf<ResultNumber>(left, right);
974 [&other](
const auto& left) {
975 return symmetricDifferenceOf<ResultNumber>(left, other);
1004 template <
class ResultNumber =
double,
class Other>
1005 requires(std::same_as<std::remove_cvref_t<Other>,
Shape> || detail::ShapeAlternative<PointType, Other>)
1007 if constexpr (detail::is_shape_v<Other>) {
1009 [](
const auto& left,
const auto& right) {
1010 return squaredDistanceOf<ResultNumber>(left, right);
1016 [&other](
const auto& left) {
1017 return squaredDistanceOf<ResultNumber>(left, other);
1048 template <
class ResultNumber = division_result_t<NumberType>,
class Other>
1049 requires(std::same_as<std::remove_cvref_t<Other>,
Shape> || detail::ShapeAlternative<PointType, Other>)
1051 if constexpr (detail::is_shape_v<Other>) {
1053 [](
const auto& left,
const auto& right) {
1054 return squaredHausdorffDistanceOf<ResultNumber>(left, right);
1060 [&other](
const auto& left) {
1061 return squaredHausdorffDistanceOf<ResultNumber>(left, other);
1093 template <
class ResultNumber =
double,
class Other>
1094 requires(std::same_as<std::remove_cvref_t<Other>,
Shape> || detail::ShapeAlternative<PointType, Other>)
1095 constexpr ResultNumber
distanceL1(
const Other& other)
const {
1096 if constexpr (detail::is_shape_v<Other>) {
1098 [](
const auto& left,
const auto& right) {
1099 return distanceL1Of<ResultNumber>(left, right);
1105 [&other](
const auto& left) {
1106 return distanceL1Of<ResultNumber>(left, other);
1117 template <
class ResultNumber =
double,
class Other>
1118 requires(std::same_as<std::remove_cvref_t<Other>,
Shape> || detail::ShapeAlternative<PointType, Other>)
1119 constexpr ResultNumber
distanceLInf(
const Other& other)
const {
1120 if constexpr (detail::is_shape_v<Other>) {
1122 [](
const auto& left,
const auto& right) {
1123 return distanceLInfOf<ResultNumber>(left, right);
1129 [&other](
const auto& left) {
1130 return distanceLInfOf<ResultNumber>(left, other);
1159 template <
class ResultNumber = division_result_t<NumberType>,
class Other>
1160 requires(std::same_as<std::remove_cvref_t<Other>,
Shape> || detail::ShapeAlternative<PointType, Other>)
1162 if constexpr (detail::is_shape_v<Other>) {
1164 [](
const auto& left,
const auto& right) {
1165 return hausdorffDistanceL1Of<ResultNumber>(left, right);
1171 [&other](
const auto& left) {
1172 return hausdorffDistanceL1Of<ResultNumber>(left, other);
1183 template <
class ResultNumber = division_result_t<NumberType>,
class Other>
1184 requires(std::same_as<std::remove_cvref_t<Other>,
Shape> || detail::ShapeAlternative<PointType, Other>)
1186 if constexpr (detail::is_shape_v<Other>) {
1188 [](
const auto& left,
const auto& right) {
1189 return hausdorffDistanceLInfOf<ResultNumber>(left, right);
1195 [&other](
const auto& left) {
1196 return hausdorffDistanceLInfOf<ResultNumber>(left, other);
1215 template <
class OtherShape>
1217 [[nodiscard]]
constexpr auto minkowskiSum(
const OtherShape& other)
const;
1241 template <
class OtherShape>
1243 [[nodiscard]]
constexpr auto minkowskiErosion(
const OtherShape& other)
const;
1255 template <Po
intConcept OtherPo
int>
1257 std::visit([&translation](
auto& alternative) { alternative += translation; }, value_);
1271 template <Po
intConcept OtherPo
int>
1273 std::visit([&translation](
auto& alternative) { alternative -= translation; }, value_);
1287 template <
class Scalar>
1289 constexpr Shape&
operator*=(
const Scalar& scalar) {
1290 std::visit([&scalar](
auto& alternative) { alternative *= scalar; }, value_);
1304 template <
class Scalar>
1306 constexpr Shape&
operator/=(
const Scalar& scalar) {
1307 std::visit([&scalar](
auto& alternative) { alternative /= scalar; }, value_);
1319 [k](
const auto& value) ->
Shape {
return Shape(value.rotated90(k)); },
1328 constexpr void rotate90(
int k = 1) {
1329 std::visit([k](
auto& value) { value.rotate90(k); }, value_);
1338 template <
class OtherNumber>
1339 [[nodiscard]]
constexpr Shape scaledUpX(
const OtherNumber scalar)
const {
1341 [scalar](
const auto& value) ->
Shape {
1342 if constexpr (
requires { value.scaledUpX(scalar); }) {
1343 return Shape(value.scaledUpX(scalar));
1345 throw std::logic_error(
"Shape::scaledUpX is not defined for the Disk alternative");
1357 template <
class OtherNumber>
1358 constexpr void scaleUpX(
const OtherNumber scalar) {
1360 [scalar](
auto& value) {
1361 if constexpr (
requires { value.scaleUpX(scalar); }) {
1362 value.scaleUpX(scalar);
1364 throw std::logic_error(
"Shape::scaleUpX is not defined for the Disk alternative");
1376 template <
class OtherNumber>
1377 [[nodiscard]]
constexpr Shape scaledUpY(
const OtherNumber scalar)
const {
1379 [scalar](
const auto& value) ->
Shape {
1380 if constexpr (
requires { value.scaledUpY(scalar); }) {
1381 return Shape(value.scaledUpY(scalar));
1383 throw std::logic_error(
"Shape::scaledUpY is not defined for the Disk alternative");
1395 template <
class OtherNumber>
1396 constexpr void scaleUpY(
const OtherNumber scalar) {
1398 [scalar](
auto& value) {
1399 if constexpr (
requires { value.scaleUpY(scalar); }) {
1400 value.scaleUpY(scalar);
1402 throw std::logic_error(
"Shape::scaleUpY is not defined for the Disk alternative");
1414 template <
class OtherNumber>
1415 [[nodiscard]]
constexpr Shape scaledDownX(
const OtherNumber scalar)
const {
1417 [scalar](
const auto& value) ->
Shape {
1418 if constexpr (
requires { value.scaledDownX(scalar); }) {
1419 return Shape(value.scaledDownX(scalar));
1421 throw std::logic_error(
"Shape::scaledDownX is not defined for the Disk alternative");
1433 template <
class OtherNumber>
1434 constexpr void scaleDownX(
const OtherNumber scalar) {
1436 [scalar](
auto& value) {
1437 if constexpr (
requires { value.scaleDownX(scalar); }) {
1438 value.scaleDownX(scalar);
1440 throw std::logic_error(
"Shape::scaleDownX is not defined for the Disk alternative");
1452 template <
class OtherNumber>
1453 [[nodiscard]]
constexpr Shape scaledDownY(
const OtherNumber scalar)
const {
1455 [scalar](
const auto& value) ->
Shape {
1456 if constexpr (
requires { value.scaledDownY(scalar); }) {
1457 return Shape(value.scaledDownY(scalar));
1459 throw std::logic_error(
"Shape::scaledDownY is not defined for the Disk alternative");
1471 template <
class OtherNumber>
1472 constexpr void scaleDownY(
const OtherNumber scalar) {
1474 [scalar](
auto& value) {
1475 if constexpr (
requires { value.scaleDownY(scalar); }) {
1476 value.scaleDownY(scalar);
1478 throw std::logic_error(
"Shape::scaleDownY is not defined for the Disk alternative");
1496 template <
class Dispatch,
class Other>
1497 constexpr bool applyPredicate(Dispatch dispatch,
const Other& other)
const {
1498 if constexpr (detail::is_shape_v<Other>) {
1500 [&dispatch](
const auto& left,
const auto& right) {
1501 return dispatch(left, right);
1507 [&dispatch, &other](
const auto& self) {
1508 return dispatch(self, other);
1520 template <
class ResultNumber,
class Left,
class Right>
1523 if constexpr (std::same_as<Left, EmptyShape<PointType>> ||
1524 std::same_as<Right, EmptyShape<PointType>>) {
1529 throw std::logic_error(
"Shape::intersection is not defined for this shape pair");
1536 template <
class ResultNumber,
class Left,
class Right>
1538 const Left& left,
const Right& right) {
1542 throw std::logic_error(
1543 "Shape::regularizedIntersection is not defined for this shape pair");
1559 template <
class ResultNumber,
class Left,
class Right>
1564 throw std::logic_error(
"Shape::regularizedUnion is not defined for this shape pair");
1578 template <
class ResultNumber,
class Left,
class Right>
1583 throw std::logic_error(
"Shape::difference is not defined for this shape pair");
1588 template <
class ResultNumber,
class Left,
class Right>
1590 const Right& right) {
1594 throw std::logic_error(
"Shape::symmetricDifference is not defined for this shape pair");
1610 template <
class ResultNumber,
class Left,
class Right>
1611 static constexpr ResultNumber squaredDistanceOf(
const Left& left,
const Right& right) {
1614 }
else if constexpr (
requires { left.squaredDistance(right); }) {
1615 return static_cast<ResultNumber
>(left.squaredDistance(right));
1617 throw std::logic_error(
"Shape::squaredDistance is not defined for this shape pair");
1628 template <
class ResultNumber,
class Left,
class Right>
1629 static constexpr ResultNumber squaredHausdorffDistanceOf(
const Left& left,
const Right& right) {
1633 throw std::logic_error(
"Shape::squaredHausdorffDistance is not defined for this shape pair");
1642 template <
class ResultNumber,
class Left,
class Right>
1643 static constexpr ResultNumber distanceL1Of(
const Left& left,
const Right& right) {
1647 throw std::logic_error(
"Shape::distanceL1 is not defined for this shape pair");
1652 template <
class ResultNumber,
class Left,
class Right>
1653 static constexpr ResultNumber distanceLInfOf(
const Left& left,
const Right& right) {
1657 throw std::logic_error(
"Shape::distanceLInf is not defined for this shape pair");
1665 template <
class ResultNumber,
class Left,
class Right>
1666 static constexpr ResultNumber hausdorffDistanceL1Of(
const Left& left,
const Right& right) {
1670 throw std::logic_error(
"Shape::hausdorffDistanceL1 is not defined for this shape pair");
1675 template <
class ResultNumber,
class Left,
class Right>
1676 static constexpr ResultNumber hausdorffDistanceLInfOf(
const Left& left,
const Right& right) {
1680 throw std::logic_error(
"Shape::hausdorffDistanceLInf is not defined for this shape pair");
1689 template <
class ResultNumber,
class Result>
1692 if constexpr (detail::is_std_optional<Result>::value) {
1693 return result ? ResultShape(*result) : ResultShape{};
1694 }
else if constexpr (detail::is_std_vector<Result>::value) {
1695 if (result.size() > 1) {
1696 throw std::logic_error(
1697 "Shape::intersection: disconnected result cannot be a single Shape");
1699 return result.empty() ? ResultShape{} : ResultShape(result.front());
1700 }
else if constexpr (detail::is_polygon_set_v<Result>) {
1706 if (result.empty()) {
1707 return ResultShape{};
1709 return result.componentCount() == 1 ? ResultShape(result.component(0))
1710 : ResultShape(result);
1712 return ResultShape(result);
1723template <
class T,
class... Ts>
1726template <
class T,
class... Ts>
1740template <
class Po
intType,
class TranslationNumber,
class TranslationLabel>
1743 using ResultPoint = std::decay_t<decltype(std::declval<const PointType&>() - translation)>;
1745 [&translation](
const auto& alternative) {
1762template <
class Po
intType,
class Scalar>
1764constexpr auto operator*(
const Shape<PointType>& shape,
const Scalar& scalar) {
1765 using ResultPoint = std::decay_t<decltype(std::declval<const PointType&>() * scalar)>;
1767 [&scalar](
const auto& alternative) {
1774template <
class Scalar,
class Po
intType>
1776constexpr auto operator*(
const Scalar& scalar,
const Shape<PointType>& shape) {
1777 return shape * scalar;
1791template <
class Po
intType,
class Scalar>
1793constexpr auto operator/(
const Shape<PointType>& shape,
const Scalar& scalar) {
1794 using ResultPoint = std::decay_t<decltype(std::declval<const PointType&>() / scalar)>;
1796 [&scalar](
const auto& alternative) {
1810template <
class Po
intType>
1813 [&stream](
const auto& value) {
Shape pairs whose Minkowski sum Pangolin can represent.
Definition forward.hpp:476
Definition arrangement.hpp:67
HalfplaneIntersection() -> HalfplaneIntersection< Point<>, NoLabel >
Definition halfplaneintersection.hpp:2308
Rectangle() -> Rectangle< Point<>, NoLabel >
Definition rectangle.hpp:2384
Line() -> Line< Point<>, NoLabel >
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
OrientedSegment() -> OrientedSegment< Point<>, NoLabel >
MonotoneChain() -> MonotoneChain< Point<>, NoLabel >
Definition monotonechain.hpp:2439
Shape(const std::variant< T, Ts... > &) -> Shape< detail::shape_point_type_t< T > >
PolygonWithHoles() -> PolygonWithHoles< Point<>, NoLabel >
Definition polygonwithholes.hpp:3093
Convex() -> Convex< Point<>, NoLabel >
Definition convex.hpp:3311
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
Segment() -> Segment< Point<>, NoLabel >
Halfplane() -> Halfplane< Point<>, NoLabel >
Polyline() -> Polyline< Point<>, NoLabel >
Definition polyline.hpp:2369
Ray() -> Ray< Point<>, NoLabel >
Polygon() -> Polygon< Point<>, NoLabel >
Definition polygon.hpp:3200
Disk() -> Disk< Point<>, NoLabel >
Deduces a default disk with Point<> boundary points and no label.
Definition disk.hpp:1691
OrientedLine() -> OrientedLine< Point<>, NoLabel >
Triangle() -> Triangle< Point<>, NoLabel >
Definition triangle.hpp:2029
#define PGL_SHAPE_ALTERNATIVE(Name, Type)
Definition shape.hpp:541
Closed convex polygon stored by its vertices.
Definition convex.hpp:170
Closed Euclidean disk stored by boundary points plus optional disk label.
Definition disk.hpp:66
The empty set of points in the plane.
Definition emptyshape.hpp:33
Intersection of closed half-planes; convex but possibly unbounded or empty.
Definition halfplaneintersection.hpp:244
Closed half-plane defined by an oriented boundary line.
Definition halfplane.hpp:51
Unoriented infinite line.
Definition line.hpp:52
Weakly x-monotone polyline stored by lexicographically sorted vertices.
Definition monotonechain.hpp:146
Directed infinite line with left/right side semantics plus optional line label.
Definition orientedline.hpp:53
Directed segment preserving source-to-target order plus optional segment label.
Definition orientedsegment.hpp:44
Two-dimensional point with optional label payload.
Definition point.hpp:129
Set of closed regions with pairwise disjoint interiors.
Definition polygonset.hpp:165
Closed region bounded by one outer simple polygon minus disjoint polygonal holes.
Definition polygonwithholes.hpp:89
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
Half-infinite line starting from one source point plus optional ray label.
Definition ray.hpp:51
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
constexpr Shape scaledDownX(const OtherNumber scalar) const
Returns the wrapped shape with its x-coordinates scaled down.
Definition shape.hpp:1413
constexpr const Variant & variant() const
Returns the underlying variant.
Definition shape.hpp:264
constexpr bool holdsAlternative() const
Tests whether the wrapper currently stores a given alternative.
Definition shape.hpp:489
EPoint::NumberType NumberType
Definition shape.hpp:164
constexpr auto operator<=>(const Shape &) const =default
Orders wrapped values by the underlying variant ordering.
constexpr Shape scaledUpY(const OtherNumber scalar) const
Returns the wrapped shape with its y-coordinates scaled up.
Definition shape.hpp:1375
constexpr Shape & operator+=(const OtherPoint &translation)
Translates the stored shape in place.
Definition shape.hpp:1254
constexpr ResultNumber distanceL1(const Other &other) const
Returns the Manhattan (L1) distance to the given shape.
Definition shape.hpp:1093
constexpr Variant & variant()
Returns the underlying variant.
Definition shape.hpp:273
constexpr PointType_ operator[](std::size_t index) const
Returns the vertex at index of the wrapped shape.
Definition shape.hpp:408
constexpr bool boundaryContains(const Other &other) const
Tests whether this shape's boundary contains the other shape (∂A ⊇ B).
Definition shape.hpp:622
constexpr void scaleUpX(const OtherNumber scalar)
Scales the wrapped shape's x-coordinates up in place.
Definition shape.hpp:1356
constexpr bool intersects(const Other &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition shape.hpp:664
constexpr Shape()=default
Creates a point-valued default shape.
constexpr Shape rotated90(int k=1) const
Returns the wrapped shape rotated by 90k degrees around the origin.
Definition shape.hpp:1315
constexpr Shape(T &&value)
Constructs a shape from one supported alternative.
Definition shape.hpp:202
constexpr bool isDegenerate() const
Tests whether the wrapped shape is degenerate.
Definition shape.hpp:303
constexpr std::ptrdiff_t index(const PointType_ &point) const
Definition shape.hpp:439
PolygonSet< Point< ResultNumber, LabelType > > regularizedIntersection(const Other &other) const
Returns the regularized intersection of two region-valued shapes.
Definition shape.hpp:825
constexpr PointType_ get(std::ptrdiff_t index) const
Returns the i-th vertex (modulo size()) of the wrapped shape.
Definition shape.hpp:378
constexpr void scaleDownX(const OtherNumber scalar)
Scales the wrapped shape's x-coordinates down in place.
Definition shape.hpp:1432
constexpr bool contains(const Other &other) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition shape.hpp:601
constexpr Rectangle< PointType > bbox() const
Returns the wrapped shape's axis-aligned bounding box.
Definition shape.hpp:325
PolygonSet< Point< ResultNumber, LabelType > > regularizedUnion(const Other &other) const
Returns the regularized union closure(A° ∪ B°).
Definition shape.hpp:874
constexpr bool separates(const Other &other) const
Tests whether removing this shape disconnects the other shape (B∖A is disconnected).
Definition shape.hpp:706
constexpr bool interiorsIntersect(const Other &other) const
Tests whether the interiors of the two shapes intersect ((A∖∂A) ∩ (B∖∂B) ≠ ∅).
Definition shape.hpp:685
constexpr ResultNumber hausdorffDistanceLInf(const Other &other) const
Returns the Chebyshev (LInf) Hausdorff distance to the given shape.
Definition shape.hpp:1183
constexpr std::size_t size() const
Returns the number of indexable elements of the wrapped shape.
Definition shape.hpp:352
constexpr bool interiorContains(const Other &other) const
Tests whether this shape's interior contains the other shape (A∖∂A ⊇ B).
Definition shape.hpp:643
constexpr bool empty() const
Tests whether the wrapped shape covers no point at all.
Definition shape.hpp:293
constexpr void scaleDownY(const OtherNumber scalar)
Scales the wrapped shape's y-coordinates down in place.
Definition shape.hpp:1470
constexpr bool crosses(const Other &other) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition shape.hpp:727
constexpr ResultNumber squaredHausdorffDistance(const Other &other) const
Returns the squared Euclidean Hausdorff distance to the given shape.
Definition shape.hpp:1048
constexpr ResultNumber hausdorffDistanceL1(const Other &other) const
Returns the Manhattan (L1) Hausdorff distance to the given shape.
Definition shape.hpp:1159
constexpr Shape scaledDownY(const OtherNumber scalar) const
Returns the wrapped shape with its y-coordinates scaled down.
Definition shape.hpp:1451
PolygonSet< Point< ResultNumber, LabelType > > difference(const Other &other) const
Returns the regularized set difference of the two shapes (A ∖ B).
Definition shape.hpp:924
EPoint::LabelType LabelType
Definition shape.hpp:166
constexpr auto minkowskiErosion(const OtherShape &other) const
Returns the Minkowski erosion of this shape by another (A ⊖ B).
Definition minkowskierosion.hpp:670
constexpr Shape< Point< ResultNumber, LabelType > > intersection(const Other &other) const
Returns the intersection of the two shapes (A ∩ B), empty when they are disjoint.
Definition shape.hpp:783
std::variant< EmptyShape< EPoint >, EPoint, Segment< EPoint >, OrientedSegment< EPoint >, Line< EPoint >, OrientedLine< EPoint >, Ray< EPoint >, Halfplane< EPoint >, Rectangle< EPoint >, Triangle< EPoint >, Disk< EPoint >, Convex< EPoint >, MonotoneChain< EPoint >, Polyline< EPoint >, Polygon< EPoint >, HalfplaneIntersection< EPoint >, PolygonWithHoles< EPoint >, PolygonSet< EPoint > > Variant
Definition shape.hpp:169
constexpr std::remove_cvref_t< T > * getIf()
Returns a mutable pointer to the stored alternative when it matches T.
Definition shape.hpp:513
constexpr ResultNumber distanceLInf(const Other &other) const
Returns the Chebyshev (LInf) distance to the given shape.
Definition shape.hpp:1117
constexpr auto minkowskiSum(const OtherShape &other) const
Returns the Minkowski sum of this shape and another (A ⊕ B).
Definition minkowski.hpp:895
PolygonSet< Point< ResultNumber, LabelType > > symmetricDifference(const Other &other) const
Returns the regularized symmetric difference of the two shapes (A △ B).
Definition shape.hpp:962
constexpr Shape(const Result &result)
Constructs a shape from a variant over supported alternatives.
Definition shape.hpp:220
EPoint PointType_
Definition shape.hpp:162
constexpr bool operator==(const Shape &) const =default
Compares wrapped values.
constexpr bool samePointSet(const OtherShape &other) const
Tests whether another shape defines exactly the same point set.
Definition samepointset.hpp:2043
constexpr void scaleUpY(const OtherNumber scalar)
Scales the wrapped shape's y-coordinates up in place.
Definition shape.hpp:1394
constexpr std::ptrdiff_t index(const NumberType &value) const
Returns the smallest index i with (*this)[i] == value, or -1 if no coordinate equals value.
Definition shape.hpp:468
constexpr Shape scaledUpX(const OtherNumber scalar) const
Returns the wrapped shape with its x-coordinates scaled up.
Definition shape.hpp:1337
constexpr ResultNumber squaredDistance(const Other &other) const
Returns the squared Euclidean distance to the given shape.
Definition shape.hpp:1004
constexpr Shape & operator-=(const OtherPoint &translation)
Translates the stored shape in place by a negated point.
Definition shape.hpp:1270
constexpr void rotate90(int k=1)
Rotates the wrapped shape by 90k degrees around the origin in place.
Definition shape.hpp:1326
constexpr const std::remove_cvref_t< T > * getIf() const
Returns a pointer to the stored alternative when it matches T.
Definition shape.hpp:501
Closed triangle stored by three vertices.
Definition triangle.hpp:53