40template <
class ResultNumber,
class ResultLabel, Po
intConcept APo
int, Po
intConcept BPo
int>
42 const APoint& a1,
const APoint& a2,
const BPoint& b1,
const BPoint& b2) {
43 using InputNumber = std::common_type_t<
typename APoint::NumberType,
44 typename BPoint::NumberType>;
46 std::conditional_t<std::floating_point<InputNumber>, ResultNumber,
47 promoted_number_t<promoted_number_t<InputNumber>>>;
49 const auto wide = [](
const auto& value) ->
decltype(
auto) {
50 return detail::asNumber<Coordinate>(value);
52 const Coordinate rx = wide(a2.x()) - wide(a1.x());
53 const Coordinate ry = wide(a2.y()) - wide(a1.y());
54 const Coordinate sx = wide(b2.x()) - wide(b1.x());
55 const Coordinate sy = wide(b2.y()) - wide(b1.y());
56 const Coordinate ox = wide(b1.x()) - wide(a1.x());
57 const Coordinate oy = wide(b1.y()) - wide(a1.y());
59 const Coordinate determinant = rx * sy - ry * sx;
60 const Coordinate along = ox * sy - oy * sx;
65 const auto ratio = [&determinant](
const Coordinate& numerator) {
66 if constexpr (std::integral<ResultNumber>) {
67 return static_cast<ResultNumber
>(numerator / determinant);
69 return detail::asNumber<ResultNumber>(numerator) /
70 detail::asNumber<ResultNumber>(determinant);
75 detail::asNumber<ResultNumber>(a1.x()) + ratio(along * rx),
76 detail::asNumber<ResultNumber>(a1.y()) + ratio(along * ry));
84template <
class Number,
class Label>
85template <
class ResultNumber, Po
intConcept OtherPo
int>
86constexpr std::optional<Point<ResultNumber, Label>>
97template <
class Po
intType,
class LabelType>
98template <
class ResultNumber, Po
intConcept OtherPo
int>
99constexpr std::optional<Point<ResultNumber, typename PointType::LabelType>>
107template <
class Po
intType,
class LabelType>
108template <
class ResultNumber, SegmentConcept OtherSegment>
114 if (!boundingBoxesOverlap(other)) {
121 if (d1 == 0 && d2 == 0) {
126 const ResultPoint a_min(
min());
127 const ResultPoint a_max(
max());
128 const ResultPoint b_min(other.min());
129 const ResultPoint b_max(other.max());
130 const ResultPoint pminmax = a_max < b_max ? a_max : b_max;
131 const ResultPoint pmaxmin = a_min < b_min ? b_min : a_min;
133 if (pminmax < pmaxmin) {
136 if (pminmax == pmaxmin) {
140 return ResultSegment(pminmax, pmaxmin);
151 if (d3 == 0 && other.containsCollinear(
min())) {
156 if (d4 == 0 && other.containsCollinear(
max())) {
160 if (d1 == 0 || d2 == 0 || d3 == 0 || d4 == 0) {
164 if (d1 != d2 && d3 != d4) {
167 return detail::carrierCrossing<ResultNumber, typename PointType::LabelType>(
168 min(),
max(), other.min(), other.max());
177template <
class Po
intType,
class LabelType>
178template <
class ResultNumber, Po
intConcept OtherPo
int>
179constexpr std::optional<Point<ResultNumber, typename PointType::LabelType>>
184template <
class Po
intType,
class LabelType>
185template <
class ResultNumber, SegmentConcept OtherSegment>
190template <
class Po
intType,
class LabelType>
191template <
class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
200template <
class Po
intType,
class LabelType>
201template <
class ResultNumber, Po
intConcept OtherPo
int>
202constexpr std::optional<Point<ResultNumber, typename PointType::LabelType>>
210template <
class Po
intType,
class LabelType>
211template <
class ResultNumber, LineConcept OtherLine>
212constexpr std::optional<
221 if (other.contains(
min())) {
222 return ResultPoint(
min());
227 if (other.isDegenerate()) {
229 return ResultPoint(other.min());
235 return ResultLine(ResultPoint(
min()), ResultPoint(
max()));
243 return detail::carrierCrossing<ResultNumber, typename PointType::LabelType>(
244 min(),
max(), other.min(), other.max());
247template <
class Po
intType,
class LabelType>
248template <
class ResultNumber, SegmentConcept OtherSegment>
252 using ResultType = std::optional<std::variant<ResultPoint, ResultSegment>>;
255 if (!line_intersection) {
258 if (std::holds_alternative<ResultPoint>(*line_intersection)) {
259 const auto& point = std::get<ResultPoint>(*line_intersection);
260 if (other.contains(point)) {
261 return ResultType(point);
265 return ResultType(ResultSegment(ResultPoint(other.min()), ResultPoint(other.max())));
268template <
class Po
intType,
class LabelType>
269template <
class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
277template <
class Po
intType,
class LabelType>
278template <
class ResultNumber, Po
intConcept OtherPo
int>
279constexpr std::optional<Point<ResultNumber, typename PointType::LabelType>>
284template <
class Po
intType,
class LabelType>
285template <
class ResultNumber, LineConcept OtherLine>
286constexpr std::optional<
294template <
class Po
intType,
class LabelType>
295template <
class ResultNumber, OrientedLineConcept OtherOrientedLine>
296constexpr std::optional<
305template <
class Po
intType,
class LabelType>
306template <
class ResultNumber, SegmentConcept OtherSegment>
311template <
class Po
intType,
class LabelType>
312template <
class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
320template <
class Po
intType,
class LabelType>
321template <
class ResultNumber, Po
intConcept OtherPo
int>
322constexpr std::optional<Point<ResultNumber, typename PointType::LabelType>>
330template <
class Po
intType,
class LabelType>
331template <
class ResultNumber, LineConcept OtherLine>
332constexpr std::optional<
339 if (other.contains(
source())) {
340 return ResultPoint(
source());
346 if (!line_intersection) {
354 const auto& point = std::get<ResultPoint>(*line_intersection);
362template <
class Po
intType,
class LabelType>
363template <
class ResultNumber, OrientedLineConcept OtherOrientedLine>
364constexpr std::optional<
372template <
class Po
intType,
class LabelType>
373template <
class ResultNumber, SegmentConcept OtherSegment>
374constexpr std::optional<
382 if (other.contains(
source())) {
383 return ResultPoint(
source());
388 const auto line_intersection =
391 if (!line_intersection) {
395 if (std::holds_alternative<ResultPoint>(*line_intersection)) {
396 const auto& point = std::get<ResultPoint>(*line_intersection);
397 if (
contains(point) && other.contains(point)) {
403 const ResultPoint ray_source(
source());
404 const bool min_on_ray =
contains(other.min());
405 const bool max_on_ray =
contains(other.max());
407 if (min_on_ray && max_on_ray) {
408 return ResultSegment(ResultPoint(other.min()), ResultPoint(other.max()));
412 const auto point = ResultPoint(other.min());
413 if (other.contains(ray_source) && point != ray_source) {
414 return ResultSegment(point, ray_source);
420 const auto point = ResultPoint(other.max());
421 if (other.contains(ray_source) && point != ray_source) {
422 return ResultSegment(point, ray_source);
427 if (other.contains(ray_source)) {
434template <
class Po
intType,
class LabelType>
435template <
class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
436constexpr std::optional<
444template <
class Po
intType,
class LabelType>
445template <
class ResultNumber, RayConcept OtherRay>
446constexpr std::optional<
456 if (other.contains(
source())) {
457 return ResultPoint(
source());
462 if (other.isDegenerate()) {
464 return ResultPoint(other.source());
469 const auto line_intersection =
472 if (!line_intersection) {
476 if (std::holds_alternative<ResultPoint>(*line_intersection)) {
477 const auto& point = std::get<ResultPoint>(*line_intersection);
478 if (
contains(point) && other.contains(point)) {
484 if (
source() == other.source()) {
486 return ResultRay(ResultPoint(
source()), ResultPoint(
target()));
488 return ResultPoint(
source());
491 const bool this_contains_other_source =
contains(other.source());
492 const bool other_contains_this_source = other.contains(
source());
494 if (this_contains_other_source && other_contains_this_source) {
495 return ResultSegment(ResultPoint(
source()), ResultPoint(other.source()));
498 if (this_contains_other_source) {
499 return ResultRay(ResultPoint(other.source()), ResultPoint(other.target()));
502 if (other_contains_this_source) {
503 return ResultRay(ResultPoint(
source()), ResultPoint(
target()));
514template <
class ResultPo
int>
515constexpr ResultPoint extendRayAlongLine(
const ResultPoint& intersection,
const ResultPoint& first,
const ResultPoint& second) {
516 return intersection + (second - first);
521template <
class Po
intType,
class LabelType>
522template <
class ResultNumber, Po
intConcept OtherPo
int>
523constexpr std::optional<Point<ResultNumber, typename PointType::LabelType>>
531template <
class Po
intType,
class LabelType>
532template <
class ResultNumber, LineConcept OtherLine>
533constexpr std::optional<
544 if (other.contains(
source())) {
545 return ResultPoint(
source());
550 if (other.isDegenerate()) {
552 return ResultPoint(other.min());
557 const auto boundary_intersection =
560 if (!boundary_intersection) {
562 return ResultLine(ResultPoint(other.min()), ResultPoint(other.max()));
567 if (std::holds_alternative<ResultPoint>(*boundary_intersection)) {
568 const auto& point = std::get<ResultPoint>(*boundary_intersection);
569 const ResultPoint first(other.min());
570 const ResultPoint second(other.max());
571 const auto direction_side =
574 const auto zero =
decltype(direction_side){};
576 if (zero < direction_side) {
577 return ResultRay(point, detail::extendRayAlongLine(point, first, second));
580 return ResultRay(point, detail::extendRayAlongLine(point, second, first));
583 return ResultLine(ResultPoint(other.min()), ResultPoint(other.max()));
586template <
class Po
intType,
class LabelType>
587template <
class ResultNumber, OrientedLineConcept OtherOrientedLine>
588constexpr std::optional<
597template <
class Po
intType,
class LabelType>
598template <
class ResultNumber, SegmentConcept OtherSegment>
599constexpr std::optional<
610 if (other.contains(
source())) {
611 return ResultPoint(
source());
616 if (other.isDegenerate()) {
618 return ResultPoint(other.min());
623 const auto supporting_intersection =
625 if (!supporting_intersection) {
629 if (std::holds_alternative<ResultPoint>(*supporting_intersection)) {
630 const auto& point = std::get<ResultPoint>(*supporting_intersection);
631 if (other.contains(point)) {
637 if (std::holds_alternative<ResultLine>(*supporting_intersection)) {
638 return ResultSegment(ResultPoint(other.min()), ResultPoint(other.max()));
644template <
class Po
intType,
class LabelType>
645template <
class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
646constexpr std::optional<
654template <
class Po
intType,
class LabelType>
655template <
class ResultNumber, RayConcept OtherRay>
656constexpr std::optional<
666 if (other.contains(
source())) {
667 return ResultPoint(
source());
672 if (other.isDegenerate()) {
674 return ResultPoint(other.source());
679 const auto supporting_intersection =
681 if (!supporting_intersection) {
685 if (std::holds_alternative<ResultPoint>(*supporting_intersection)) {
686 const auto& point = std::get<ResultPoint>(*supporting_intersection);
687 if (other.contains(point)) {
694 return ResultRay(ResultPoint(other.source()), ResultPoint(other.target()));
700template <
class Po
intType,
class LabelType>
701template <
class ResultNumber, HalfplaneConcept OtherHalfplane>
717template <
class Po
intType, std::
size_t Capacity>
718struct UniqueIntersectionPoints {
719 constexpr void add(
const PointType& point) {
720 for (std::size_t index = 0; index < size; ++index) {
721 if (points[index] == point) {
726 points[size] = point;
730 constexpr const PointType& operator[](std::size_t index)
const {
731 return points[index];
734 constexpr PointType minPoint()
const {
735 PointType result = points[0];
736 for (std::size_t index = 1; index < size; ++index) {
737 if (points[index] < result) {
738 result = points[index];
744 constexpr PointType maxPoint()
const {
745 PointType result = points[0];
746 for (std::size_t index = 1; index < size; ++index) {
747 if (result < points[index]) {
748 result = points[index];
754 std::array<PointType, Capacity> points{};
755 std::size_t size = 0;
758template <
class SegmentType,
class Po
intSet>
759constexpr void addSegmentEndpoints(
const SegmentType& segment, PointSet& points) {
760 points.add(segment.min());
761 points.add(segment.max());
764template <
class Po
intSet>
765constexpr auto pointsToSegmentIntersection(
const PointSet& points) {
766 using PointType = std::remove_cvref_t<
decltype(points[0])>;
767 using SegmentType = Segment<PointType>;
768 using ResultType = std::optional<std::variant<PointType, SegmentType>>;
770 if (points.size == 0) {
774 if (points.size == 1) {
775 return ResultType(points[0]);
778 const auto first = points.minPoint();
779 const auto second = points.maxPoint();
780 if (first == second) {
781 return ResultType(first);
784 return ResultType(SegmentType(first, second));
787template <
class ResultNumber,
class LabelType,
class RectangleType,
class LineType>
788constexpr auto rectangleLineIntersection(
const RectangleType& rectangle,
const LineType& line) {
790 UniqueIntersectionPoints<ResultPoint, 8> points;
792 if (line.isDegenerate()) {
793 if (rectangle.contains(line.min())) {
794 points.add(ResultPoint(line.min()));
796 return pointsToSegmentIntersection(points);
799 const auto rectangle_edges = rectangle.edges();
800 for (
const auto&
edge : rectangle_edges) {
802 const auto intersection = edge_line.template intersection<ResultNumber>(line);
807 if (std::holds_alternative<ResultPoint>(*intersection)) {
808 const auto& point = std::get<ResultPoint>(*intersection);
809 if (
edge.contains(point)) {
813 const auto& overlap = std::get<Line<ResultPoint>>(*intersection);
814 static_cast<void>(overlap);
819 return pointsToSegmentIntersection(points);
822template <
class ResultNumber,
class LabelType,
class RectangleType,
class SegmentType>
823constexpr auto rectangleSegmentIntersection(
const RectangleType& rectangle,
const SegmentType& segment) {
825 UniqueIntersectionPoints<ResultPoint, 10> points;
827 if (rectangle.contains(segment.min())) {
828 points.add(ResultPoint(segment.min()));
830 if (rectangle.contains(segment.max())) {
831 points.add(ResultPoint(segment.max()));
834 const auto rectangle_edges = rectangle.edges();
835 for (
const auto&
edge : rectangle_edges) {
836 const auto intersection =
edge.template intersection<ResultNumber>(segment);
841 if (std::holds_alternative<ResultPoint>(*intersection)) {
842 points.add(std::get<ResultPoint>(*intersection));
848 return pointsToSegmentIntersection(points);
851template <
class ResultNumber,
class LabelType,
class RectangleType,
class RayType>
852constexpr auto rectangleRayIntersection(
const RectangleType& rectangle,
const RayType& ray) {
854 UniqueIntersectionPoints<ResultPoint, 10> points;
856 if (rectangle.contains(ray.source())) {
857 points.add(ResultPoint(ray.source()));
860 if (ray.isDegenerate()) {
861 return pointsToSegmentIntersection(points);
865 const auto rectangle_edges = rectangle.edges();
866 for (
const auto&
edge : rectangle_edges) {
868 const auto intersection = edge_line.template intersection<ResultNumber>(ray_line);
873 if (std::holds_alternative<ResultPoint>(*intersection)) {
874 const auto& point = std::get<ResultPoint>(*intersection);
875 if (
edge.contains(point) && ray.contains(point)) {
879 if (ray.contains(
edge.min())) {
880 points.add(ResultPoint(
edge.min()));
882 if (ray.contains(
edge.max())) {
883 points.add(ResultPoint(
edge.max()));
888 return pointsToSegmentIntersection(points);
891template <
class ResultNumber,
class LabelType,
class TriangleType,
class LineType>
892constexpr auto triangleLineIntersection(
const TriangleType& triangle,
const LineType& line) {
894 UniqueIntersectionPoints<ResultPoint, 8> points;
896 if (line.isDegenerate()) {
897 if (triangle.contains(line.min())) {
898 points.add(ResultPoint(line.min()));
900 return pointsToSegmentIntersection(points);
903 const auto triangle_edges = triangle.edges();
904 for (
const auto&
edge : triangle_edges) {
906 const auto intersection = edge_line.template intersection<ResultNumber>(line);
911 if (std::holds_alternative<ResultPoint>(*intersection)) {
912 const auto& point = std::get<ResultPoint>(*intersection);
913 if (
edge.contains(point)) {
921 return pointsToSegmentIntersection(points);
924template <
class ResultNumber,
class LabelType,
class TriangleType,
class SegmentType>
925constexpr auto triangleSegmentIntersection(
const TriangleType& triangle,
const SegmentType& segment) {
927 UniqueIntersectionPoints<ResultPoint, 10> points;
929 if (triangle.contains(segment.min())) {
930 points.add(ResultPoint(segment.min()));
932 if (triangle.contains(segment.max())) {
933 points.add(ResultPoint(segment.max()));
936 const auto triangle_edges = triangle.edges();
937 for (
const auto&
edge : triangle_edges) {
938 const auto intersection =
edge.template intersection<ResultNumber>(segment);
943 if (std::holds_alternative<ResultPoint>(*intersection)) {
944 points.add(std::get<ResultPoint>(*intersection));
950 return pointsToSegmentIntersection(points);
953template <
class ResultNumber,
class LabelType,
class TriangleType,
class RayType>
954constexpr auto triangleRayIntersection(
const TriangleType& triangle,
const RayType& ray) {
956 UniqueIntersectionPoints<ResultPoint, 10> points;
958 if (triangle.contains(ray.source())) {
959 points.add(ResultPoint(ray.source()));
962 if (ray.isDegenerate()) {
963 return pointsToSegmentIntersection(points);
967 const auto triangle_edges = triangle.edges();
968 for (
const auto&
edge : triangle_edges) {
970 const auto intersection = edge_line.template intersection<ResultNumber>(ray_line);
975 if (std::holds_alternative<ResultPoint>(*intersection)) {
976 const auto& point = std::get<ResultPoint>(*intersection);
977 if (
edge.contains(point) && ray.contains(point)) {
981 if (ray.contains(
edge.min())) {
982 points.add(ResultPoint(
edge.min()));
984 if (ray.contains(
edge.max())) {
985 points.add(ResultPoint(
edge.max()));
990 return pointsToSegmentIntersection(points);
995template <
class Po
intType,
class LabelType>
996template <
class ResultNumber, Po
intConcept OtherPo
int>
997constexpr std::optional<Point<ResultNumber, typename PointType::LabelType>>
1005template <
class Po
intType,
class LabelType>
1006template <
class ResultNumber, RectangleConcept OtherRectangle>
1007constexpr std::optional<Rectangle<Point<ResultNumber, typename PointType::LabelType>>>
1016 const auto min_x =
min().x() < other.min().x() ? other.min().x() :
min().x();
1017 const auto min_y =
min().y() < other.min().y() ? other.min().y() :
min().y();
1018 const auto max_x =
max().x() < other.max().x() ?
max().x() : other.max().x();
1019 const auto max_y =
max().y() < other.max().y() ?
max().y() : other.max().y();
1021 return ResultRectangle(
1022 ResultPoint(detail::asNumber<ResultNumber>(min_x), detail::asNumber<ResultNumber>(min_y)),
1023 ResultPoint(detail::asNumber<ResultNumber>(max_x), detail::asNumber<ResultNumber>(max_y)));
1026template <
class Po
intType,
class LabelType>
1027template <
class ResultNumber, LineConcept OtherLine>
1034 return detail::rectangleLineIntersection<ResultNumber, typename PointType::LabelType>(*
this, other);
1037template <
class Po
intType,
class LabelType>
1038template <
class ResultNumber, OrientedLineConcept OtherOrientedLine>
1044template <
class Po
intType,
class LabelType>
1045template <
class ResultNumber, SegmentConcept OtherSegment>
1052 return detail::rectangleSegmentIntersection<ResultNumber, typename PointType::LabelType>(*
this, other);
1055template <
class Po
intType,
class LabelType>
1056template <
class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
1062template <
class Po
intType,
class LabelType>
1063template <
class ResultNumber, RayConcept OtherRay>
1070 return detail::rectangleRayIntersection<ResultNumber, typename PointType::LabelType>(*
this, other);
1078template <
class Po
intType,
class LabelType>
1079template <
class ResultNumber, HalfplaneConcept OtherHalfplane>
1084 using ResultType = std::optional<std::variant<ResultPoint, ResultSegment, ResultConvex>>;
1088 return ResultType{};
1093 using ResultType = std::optional<std::variant<ResultPoint, ResultSegment, ResultConvex>>;
1095 const std::array<PointType, 4> corners{
min(), bottomRight(),
max(), topLeft()};
1097 std::array<Determinant, 4> sides{};
1098 for (std::size_t i = 0; i < 4; ++i) {
1105 std::array<ResultPoint, 6> clipped{};
1106 std::size_t count = 0;
1107 const auto keep = [&clipped, &count](
const ResultPoint& point) {
1108 if (count == 0 || clipped[count - 1] != point) {
1109 clipped[count++] = point;
1113 const auto boundary = other.asLine();
1114 for (std::size_t i = 0; i < 4; ++i) {
1115 const std::size_t next = (i + 1) % 4;
1116 if (sides[i] >= 0) {
1117 keep(ResultPoint(corners[i]));
1119 if (!((sides[i] > 0 && sides[next] < 0) || (sides[i] < 0 && sides[next] > 0))) {
1126 keep(ResultPoint(*boundary.template xAtY<ResultNumber>(corners[i].y()),
1127 detail::asNumber<ResultNumber>(corners[i].y())));
1129 keep(ResultPoint(detail::asNumber<ResultNumber>(corners[i].
x()),
1130 *boundary.template yAtX<ResultNumber>(corners[i].x())));
1133 while (count > 1 && clipped[count - 1] == clipped[0]) {
1138 return ResultType{};
1141 return ResultType(clipped[0]);
1144 return ResultType(ResultSegment(clipped[0], clipped[1]));
1150 std::size_t first = 0;
1151 for (std::size_t i = 1; i < count; ++i) {
1152 if (clipped[i] < clipped[first]) {
1158 for (std::size_t i = 0; i < count; ++i) {
1159 vertices.push_back(clipped[(first + i) % count]);
1161 return ResultType(ResultConvex(std::move(
vertices),
true));
1167template <
class Po
intType,
class LabelType>
1168template <
class ResultNumber, Po
intConcept OtherPo
int>
1169constexpr std::optional<Point<ResultNumber, typename PointType::LabelType>>
1177template <
class Po
intType,
class LabelType>
1178template <
class ResultNumber, LineConcept OtherLine>
1181 return detail::triangleLineIntersection<ResultNumber, typename PointType::LabelType>(*
this, other);
1184template <
class Po
intType,
class LabelType>
1185template <
class ResultNumber, OrientedLineConcept OtherOrientedLine>
1191template <
class Po
intType,
class LabelType>
1192template <
class ResultNumber, SegmentConcept OtherSegment>
1195 return detail::triangleSegmentIntersection<ResultNumber, typename PointType::LabelType>(*
this, other);
1198template <
class Po
intType,
class LabelType>
1199template <
class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
1205template <
class Po
intType,
class LabelType>
1206template <
class ResultNumber, RayConcept OtherRay>
1209 return detail::triangleRayIntersection<ResultNumber, typename PointType::LabelType>(*
this, other);
1215template <
class Po
intType,
class LabelType>
1216template <
class ResultNumber, HalfplaneConcept OtherHalfplane>
1221template <
class Po
intType,
class LabelType>
1222template <
class ResultNumber, RectangleConcept OtherRectangle>
1231template <
class Po
intType,
class LabelType>
1232template <
class ResultNumber, TriangleConcept OtherTriangle>
1241template <
class Po
intType,
class LabelType>
1242template <
class ResultNumber, Po
intConcept OtherPo
int>
1243constexpr std::optional<Point<ResultNumber, typename PointType::LabelType>>
1251template <
class Po
intType,
class LabelType>
1252template <
class ResultNumber, SegmentConcept OtherSegment>
1258 size_t index = isec->index();
1260 const auto& p = std::get<0>(*isec);
1261 if (other.containsCollinear(p)) {
1266 const auto& seg = std::get<1>(*isec);
1270template <
class Po
intType,
class LabelType>
1271template <
class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
1276template <
class Po
intType,
class LabelType>
1277template <
class ResultNumber, LineConcept OtherLine>
1279 if (points_.empty()) {
1283 using CommonNumberType = std::common_type_t<NumberType, typename OtherLine::NumberType>;
1286 const CommonPoint local_p0(detail::asNumber<CommonNumberType>(other[0].
x()) - detail::asNumber<CommonNumberType>(translation_.x()),
1287 detail::asNumber<CommonNumberType>(other[0].y()) - detail::asNumber<CommonNumberType>(translation_.y()));
1288 const CommonPoint local_p1(detail::asNumber<CommonNumberType>(other[1].
x()) - detail::asNumber<CommonNumberType>(translation_.x()),
1289 detail::asNumber<CommonNumberType>(other[1].y()) - detail::asNumber<CommonNumberType>(translation_.y()));
1291 if (local_p0 == local_p1) {
1297 auto orientationValue = [&](
size_t index) {
1301 if (points_.size() == 1) {
1302 if (orientationValue(0) == CommonNumberType(0)) {
1310 if (points_.size() == 2) {
1318 return std::get<Point<ResultNumber, typename PointType::LabelType>>(*isec) + shift;
1320 auto seg = std::get<Segment<Point<ResultNumber, typename PointType::LabelType>>>(*isec);
1324 auto max_it = detail::cyclicMax(points_.begin(), points_.end(),
1326 return orientationDeterminant(localLine[0], localLine[1], a);
1328 auto min_it = detail::cyclicMax(points_.begin(), points_.end(),
1330 return orientationDeterminant(localLine[1], localLine[0], a);
1333 const size_t n = points_.size();
1334 const size_t i_max =
static_cast<size_t>(std::distance(points_.begin(), max_it));
1335 const size_t i_min =
static_cast<size_t>(std::distance(points_.begin(), min_it));
1337 const CommonNumberType max_value = orientationValue(i_max);
1338 const CommonNumberType min_value = orientationValue(i_min);
1340 if (max_value < CommonNumberType(0) || min_value > CommonNumberType(0)) {
1350 translatePoint(segment[0]), translatePoint(segment[1]));
1353 if (max_value == CommonNumberType(0) && min_value == CommonNumberType(0)) {
1354 const CommonPoint direction(localLine[1].
x() - localLine[0].
x(),
1355 localLine[1].
y() - localLine[0].
y());
1357 auto extremal_high = detail::cyclicMax(points_.begin(), points_.end(),
1359 return detail::asNumber<CommonNumberType>(a.x()) * direction.x() +
1360 detail::asNumber<CommonNumberType>(a.y()) * direction.y();
1363 auto extremal_low = detail::cyclicMax(points_.begin(), points_.end(),
1365 return -(detail::asNumber<CommonNumberType>(a.x()) * direction.x() +
1366 detail::asNumber<CommonNumberType>(a.y()) * direction.y());
1380 auto forwardDist = [&](
size_t from,
size_t to) {
1381 return (to + n - from) % n;
1384 auto findBoundaryForward = [&](
size_t start,
size_t length) ->
size_t {
1387 size_t result = length + 1;
1389 size_t mid = lo + (hi - lo) / 2;
1390 if (orientationValue((start + mid) % n) <= CommonNumberType(0)) {
1400 auto findBoundaryBackward = [&](
size_t start,
size_t length) ->
size_t {
1403 size_t result = length + 1;
1405 size_t mid = lo + (hi - lo) / 2;
1406 size_t index = (start + n - mid) % n;
1407 if (orientationValue(
index) <= CommonNumberType(0)) {
1417 const size_t forward_len = forwardDist(i_max, i_min);
1418 const size_t backward_len = forwardDist(i_min, i_max);
1420 const size_t boundary_forward = findBoundaryForward(i_max, forward_len);
1421 const size_t boundary_backward = findBoundaryBackward(i_max, backward_len);
1423 if (boundary_forward > forward_len || boundary_backward > backward_len) {
1427 const size_t b1 = (i_max + boundary_forward) % n;
1428 const size_t b1_prev = (b1 + n - 1) % n;
1429 const size_t b2 = (i_max + n - boundary_backward) % n;
1430 const size_t b2_next = (b2 + 1) % n;
1433 std::vector<Point<ResultNumber, typename PointType::LabelType>>& points) {
1441 auto seg = std::get<Segment<Point<ResultNumber, typename PointType::LabelType>>>(*edge_isec);
1442 points.push_back(seg[0]);
1443 points.push_back(seg[1]);
1447 std::vector<Point<ResultNumber, typename PointType::LabelType>> points;
1452 if (points.empty()) {
1456 const CommonPoint direction(localLine[1].
x() - localLine[0].
x(),
1457 localLine[1].
y() - localLine[0].
y());
1460 return (detail::asNumber<CommonNumberType>(point.x()) - localLine[0].x()) * direction.x() +
1461 (detail::asNumber<CommonNumberType>(point.y()) - localLine[0].y()) * direction.y();
1464 std::sort(points.begin(), points.end(), [&](
auto const& a,
auto const& b) {
1465 return project(a) < project(b);
1467 points.erase(std::unique(points.begin(), points.end()), points.end());
1469 if (points.empty()) {
1472 if (points.size() == 1) {
1473 return translatePoint(points[0]);
1477 translatePoint(points.back()));
1480template <
class Po
intType,
class LabelType>
1481template <
class ResultNumber, OrientedLineConcept OtherOrientedLine>
1486template <
class Po
intType,
class LabelType>
1487template <
class ResultNumber, RayConcept OtherRay>
1493 size_t index = line_isec->index();
1495 if (other.containsCollinear(std::get<0>(*line_isec))) {
1496 return std::get<0>(*line_isec);
1501 auto seg = std::get<1>(*line_isec);
1509template <
class Po
intType,
class LabelType>
1510template <
class ResultNumber, HalfplaneConcept OtherHalfplane>
1516 const std::ptrdiff_t n =
static_cast<std::ptrdiff_t
>(points_.size());
1523 const auto it = detail::cyclicMaxOrPositive(points_.begin(), points_.end(),
1525 return orientationDeterminant(other.source(), other.target(), a + translation_);
1527 const std::ptrdiff_t start = it - points_.begin();
1529 if (!other.contains(
get(start))) {
1535 std::ptrdiff_t f = start, fSteps = 0;
1536 while (fSteps + 1 < n && other.contains(
get(f + 1))) {
1540 if (fSteps + 1 == n) {
1542 ResultConvex whole(*
this,
true);
1543 if (whole.size() == 1)
return whole[0];
1544 if (whole.size() == 2)
return ResultSegment(whole[0], whole[1]);
1549 std::ptrdiff_t b = start, bSteps = 0;
1550 while (bSteps + fSteps + 1 < n && other.contains(
get(b - 1))) {
1558 auto crossing = [&](std::ptrdiff_t insideIdx, std::ptrdiff_t outsideIdx) {
1559 const ResultSegment
edge(
static_cast<ResultPoint
>(
get(insideIdx)),
1560 static_cast<ResultPoint
>(
get(outsideIdx)));
1564 std::vector<ResultPoint> result;
1565 result.reserve(
static_cast<std::size_t
>(fSteps + bSteps + 3));
1566 result.push_back(crossing(b, b - 1));
1567 for (std::ptrdiff_t i = b; ; ++i) {
1568 result.push_back(
static_cast<ResultPoint
>(
get(i)));
1571 result.push_back(crossing(f, f + 1));
1573 ResultConvex convex(std::move(result));
1574 if (convex.size() == 1)
return convex[0];
1575 if (convex.size() == 2)
return ResultSegment(convex[0], convex[1]);
1579template <
class Po
intType,
class LabelType>
1580template <
class ResultNumber, RectangleConcept OtherRectangle>
1585template <
class Po
intType,
class LabelType>
1586template <
class ResultNumber, TriangleConcept OtherTriangle>
1591template <
class Po
intType,
class LabelType>
1592template <
class ResultNumber, ConvexConcept OtherConvex>
1601 ResultPointType point =
static_cast<ResultPointType
>(points_[0] + translation_);
1602 if (other.contains(point)) {
1608 if (other.size() == 1) {
1609 ResultPointType point =
static_cast<ResultPointType
>(other[0]);
1616 std::vector<ResultPointType> isecPoints;
1618 for (
auto &
edge : other.edges()) {
1624 auto seg = std::get<Segment<Point<ResultNumber, typename PointType::LabelType>>>(*isec);
1625 isecPoints.push_back(seg[0]);
1626 isecPoints.push_back(seg[1]);
1633 if (std::holds_alternative<ResultPointType>(*isec)) {
1634 isecPoints.push_back(std::get<ResultPointType>(*isec));
1636 auto seg = std::get<Segment<ResultPointType>>(*isec);
1637 isecPoints.push_back(seg[0]);
1638 isecPoints.push_back(seg[1]);
1643 if (isecPoints.empty()) {
1649 if (convex.
size() == 1) {
1652 if (convex.
size() == 2) {
1672template <
class ResultPo
int>
1673using LinePieces = std::vector<std::variant<ResultPoint, Segment<ResultPoint>>>;
1681template <
class ResultNumber,
class ResultPo
int>
1683 ResultNumber lo, hi;
1684 ResultPoint plo, phi;
1704template <
class ResultNumber,
class ResultPo
int,
class EdgeRange>
1705constexpr std::vector<LineSpan<ResultNumber, ResultPoint>>
1706lineAreaSpans(
const ResultPoint& a,
const ResultPoint& b,
const EdgeRange& edges) {
1707 using Span = LineSpan<ResultNumber, ResultPoint>;
1709 const ResultPoint direction = b - a;
1711 auto tOf = [&](
const ResultPoint& p) -> ResultNumber {
return (p - a) * direction; };
1714 auto sideOf = [&](
const ResultPoint& v) ->
int {
1716 if (o > 0)
return 1;
1717 if (o < 0)
return -1;
1721 auto makeSpan = [](ResultNumber t1, ResultNumber t2,
const ResultPoint& p1,
const ResultPoint& p2) -> Span {
1722 return (t1 <= t2) ? Span{t1, t2, p1, p2} : Span{t2, t1, p2, p1};
1724 std::vector<Span> spans;
1733 std::vector<std::pair<ResultNumber, ResultPoint>> crossings;
1735 for (
const auto&
edge : edges) {
1736 using EdgePoint =
typename std::remove_cvref_t<
decltype(
edge)>::PointType;
1737 const ResultPoint u =
static_cast<ResultPoint
>(
edge.source());
1738 const ResultPoint w =
static_cast<ResultPoint
>(
edge.target());
1739 const int su = sideOf(u);
1740 const int sw = sideOf(w);
1742 if (su == 0 && sw == 0) {
1744 spans.push_back(makeSpan(tOf(u), tOf(w), u, w));
1750 spans.push_back({tOf(u), tOf(u), u, u});
1753 if (su != 0 && sw != 0 && su != sw) {
1755 const auto isec = line.template intersection<ResultNumber>(
1757 if (isec && std::holds_alternative<ResultPoint>(*isec)) {
1758 const ResultPoint c = std::get<ResultPoint>(*isec);
1759 spans.push_back({tOf(c), tOf(c), c, c});
1760 crossings.emplace_back(tOf(c), c);
1764 const int eu = (su != 0) ? su : -1;
1765 const int ew = (sw != 0) ? sw : -1;
1767 const ResultPoint& onLine = (su == 0) ? u : w;
1768 crossings.emplace_back(tOf(onLine), onLine);
1777 std::sort(crossings.begin(), crossings.end(),
1778 [](
const auto&
x,
const auto&
y) { return x.first < y.first; });
1779 std::size_t idx = 0;
1781 while (idx < crossings.size()) {
1782 const ResultNumber tcur = crossings[idx].first;
1783 const ResultPoint pcur = crossings[idx].second;
1784 std::size_t next = idx;
1785 while (next < crossings.size() && crossings[next].first == tcur) {
1788 parity +=
static_cast<int>(next - idx);
1789 if ((parity & 1) && next < crossings.size()) {
1790 spans.push_back({tcur, crossings[next].first, pcur, crossings[next].second});
1796 std::sort(spans.begin(), spans.end(),
1797 [](
const Span&
x,
const Span&
y) { return x.lo != y.lo ? x.lo < y.lo : x.hi < y.hi; });
1798 std::vector<Span> merged;
1799 for (
const Span& s : spans) {
1800 if (merged.empty() || s.lo > merged.back().hi) {
1801 merged.push_back(s);
1802 }
else if (s.hi > merged.back().hi) {
1803 merged.back().hi = s.hi;
1804 merged.back().phi = s.phi;
1819template <
class ResultPo
int,
class Area,
class EdgeRange,
class OtherSegment>
1820constexpr LinePieces<ResultPoint>
1821areaSegmentIntersection(
const Area& area,
const EdgeRange& edges,
const OtherSegment& other) {
1822 using ResultNumber =
typename ResultPoint::NumberType;
1825 LinePieces<ResultPoint> result;
1826 const ResultPoint a(other.min());
1827 const ResultPoint b(other.max());
1830 if (other.isDegenerate()) {
1831 if (area.contains(a)) {
1832 result.emplace_back(a);
1838 const ResultNumber T = (b - a) * (b - a);
1839 for (
const auto& span : lineAreaSpans<ResultNumber>(a, b, edges)) {
1840 if (span.hi < ResultNumber(0) || span.lo > T) {
1843 const ResultPoint lo = (span.lo < ResultNumber(0)) ? a : span.plo;
1844 const ResultPoint hi = (span.hi > T) ? b : span.phi;
1846 result.emplace_back(lo);
1848 result.emplace_back(ResultSegment(lo, hi));
1863template <
class ResultPo
int,
class Area,
class EdgeRange,
class OtherLine>
1864constexpr LinePieces<ResultPoint>
1865areaLineIntersection(
const Area& area,
const EdgeRange& edges,
const OtherLine& other) {
1866 using ResultNumber =
typename ResultPoint::NumberType;
1869 LinePieces<ResultPoint> result;
1870 const ResultPoint a(other.min());
1871 const ResultPoint b(other.max());
1874 if (other.isDegenerate()) {
1875 if (area.contains(a)) {
1876 result.emplace_back(a);
1882 for (
const auto& span : lineAreaSpans<ResultNumber>(a, b, edges)) {
1883 if (span.lo == span.hi) {
1884 result.emplace_back(span.plo);
1886 result.emplace_back(ResultSegment(span.plo, span.phi));
1901template <
class ResultPo
int,
class Area,
class EdgeRange,
class OtherRay>
1902constexpr LinePieces<ResultPoint>
1903areaRayIntersection(
const Area& area,
const EdgeRange& edges,
const OtherRay& other) {
1904 using ResultNumber =
typename ResultPoint::NumberType;
1907 LinePieces<ResultPoint> result;
1908 const ResultPoint a(other.source());
1909 const ResultPoint b(other.target());
1912 if (other.isDegenerate()) {
1913 if (area.contains(a)) {
1914 result.emplace_back(a);
1920 for (
const auto& span : lineAreaSpans<ResultNumber>(a, b, edges)) {
1921 if (span.hi < ResultNumber(0)) {
1924 const ResultPoint lo = (span.lo < ResultNumber(0)) ? a : span.plo;
1925 if (lo == span.phi) {
1926 result.emplace_back(lo);
1928 result.emplace_back(ResultSegment(lo, span.phi));
1939template <
class Po
intType,
class LabelType>
1940template <
class ResultNumber, Po
intConcept OtherPo
int>
1941constexpr std::optional<Point<ResultNumber, typename PointType::LabelType>>
1949template <
class Po
intType,
class LabelType>
1950template <
class ResultNumber, SegmentConcept OtherSegment>
1954 return detail::areaSegmentIntersection<ResultPoint>(*
this,
orientedEdgesView(), other);
1957template <
class Po
intType,
class LabelType>
1958template <
class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
1964template <
class Po
intType,
class LabelType>
1965template <
class ResultNumber, LineConcept OtherLine>
1969 return detail::areaLineIntersection<ResultPoint>(*
this,
orientedEdgesView(), other);
1972template <
class Po
intType,
class LabelType>
1973template <
class ResultNumber, OrientedLineConcept OtherOrientedLine>
1979template <
class Po
intType,
class LabelType>
1980template <
class ResultNumber, RayConcept OtherRay>
1984 return detail::areaRayIntersection<ResultPoint>(*
this,
orientedEdgesView(), other);
1987template <
class Po
intType,
class LabelType>
1988template <
class ResultNumber, PolygonConcept OtherPolygon>
1995 using Piece = std::variant<ResultPoint, ResultPolyline, ResultPolygon>;
2000 std::set<ResultSegment> segments;
2001 std::set<ResultPoint> touchPoints;
2003 auto clipEdgesAgainst = [&](
const auto& edgePolygon,
const auto& clipPolygon) {
2004 for (
const auto&
edge : edgePolygon.edges()) {
2006 if (std::holds_alternative<ResultPoint>(piece)) {
2007 touchPoints.insert(std::get<ResultPoint>(piece));
2009 segments.insert(std::get<ResultSegment>(piece));
2014 clipEdgesAgainst(*
this, other);
2015 clipEdgesAgainst(other, *
this);
2021 auto planarize = [](
const std::set<ResultSegment>& input) {
2023 for (
const auto& s : input) {
2030 std::set<ResultSegment> out;
2031 for (
const auto& s : input) {
2032 const ResultPoint a = s.min();
2033 const ResultPoint b = s.max();
2034 std::vector<ResultPoint> cut{a, b};
2036 if (v == a || v == b || !
collinear(a, b, v)) {
2039 if (v.x() < std::min(a.x(), b.x()) || v.x() > std::max(a.x(), b.x()) ||
2040 v.y() < std::min(a.y(), b.y()) || v.y() > std::max(a.y(), b.y())) {
2045 std::sort(cut.begin(), cut.end());
2046 cut.erase(std::unique(cut.begin(), cut.end()), cut.end());
2047 for (std::size_t i = 0; i + 1 < cut.size(); ++i) {
2048 out.insert(ResultSegment(cut[i], cut[i + 1]));
2053 segments = planarize(segments);
2056 std::map<ResultPoint, std::vector<ResultPoint>> adjacency;
2057 for (
const auto& segment : segments) {
2058 adjacency[segment.min()].push_back(segment.max());
2059 adjacency[segment.max()].push_back(segment.min());
2062 std::vector<Piece> result;
2065 for (
const auto& point : touchPoints) {
2066 if (adjacency.find(point) == adjacency.end()) {
2067 result.emplace_back(point);
2071 using Number = ResultNumber;
2072 auto degree = [&adjacency](
const ResultPoint& p) {
2073 const auto it = adjacency.find(p);
2074 return it == adjacency.end() ? std::size_t(0) : it->second.size();
2076 auto removeEdge = [&adjacency](
const ResultPoint& u,
const ResultPoint& v) {
2077 auto& au = adjacency[u];
2078 au.erase(std::find(au.begin(), au.end(), v));
2079 auto& av = adjacency[v];
2080 av.erase(std::find(av.begin(), av.end(), u));
2087 const ResultPoint* leaf =
nullptr;
2088 for (
const auto& [p, neighbors] : adjacency) {
2089 if (neighbors.size() == 1) {
2097 std::vector<ResultPoint> path;
2098 ResultPoint current = *leaf;
2099 path.push_back(current);
2100 while (degree(current) == 1) {
2101 const ResultPoint next = adjacency.at(current)[0];
2102 removeEdge(current, next);
2103 path.push_back(next);
2106 result.emplace_back(ResultPolyline(std::move(path)));
2114 auto rotationalNext = [&adjacency](
const ResultPoint& at,
const ResultPoint& from) {
2115 const auto& neighbors = adjacency.at(at);
2116 auto dx = [&](
const ResultPoint& p) {
return p.x() - at.x(); };
2117 auto dy = [&](
const ResultPoint& p) {
return p.y() - at.y(); };
2119 auto half = [&](
const ResultPoint& p) {
2120 const Number
y = dy(p);
2121 if (
y > Number(0))
return 0;
2122 if (
y < Number(0))
return 1;
2123 return dx(p) >= Number(0) ? 0 : 1;
2125 auto ccwBefore = [&](
const ResultPoint& u,
const ResultPoint& w) {
2126 const int hu = half(u), hw = half(w);
2130 return dx(u) * dy(w) - dy(u) * dx(w) > Number(0);
2134 const ResultPoint* best =
nullptr;
2135 for (
const auto& n : neighbors) {
2136 if (n == from || !ccwBefore(n, from)) {
2139 if (!best || ccwBefore(*best, n)) {
2144 for (
const auto& n : neighbors) {
2145 if (n != from && (!best || ccwBefore(*best, n))) {
2153 std::set<std::pair<ResultPoint, ResultPoint>> usedDart;
2154 for (
const auto& [u, neighbors] : adjacency) {
2155 for (
const auto& v : neighbors) {
2156 if (usedDart.count({u, v})) {
2159 std::vector<ResultPoint> cycle;
2163 usedDart.insert({a, b});
2165 const ResultPoint c = rotationalNext(b, a);
2168 }
while (a != u || b != v);
2172 for (std::size_t i = 0; i < cycle.size(); ++i) {
2173 const ResultPoint& p = cycle[i];
2174 const ResultPoint& q = cycle[(i + 1) % cycle.size()];
2175 twiceArea += p.x() * q.y() - q.x() * p.y();
2178 result.emplace_back(ResultPolygon(cycle));
2186template <
class Po
intType,
class LabelType>
2187template <
class ResultNumber, ConvexConcept OtherConvex>
2193template <
class Po
intType,
class LabelType>
2194template <
class ResultNumber, TriangleConcept OtherTriangle>
2200template <
class Po
intType,
class LabelType>
2201template <
class ResultNumber, RectangleConcept OtherRectangle>
2207template <
class Po
intType,
class LabelType>
2208template <
class ResultNumber, HalfplaneConcept OtherHalfplane>
2214 using Piece = std::variant<ResultPoint, ResultSegment, ResultPolygon>;
2216 std::vector<Piece> result;
2222 if (other.isDegenerate()) {
2223 const ResultPoint p(other.source());
2225 result.emplace_back(p);
2233 std::set<ResultSegment> segments;
2234 std::set<ResultPoint> touchPoints;
2236 auto collect = [&](
const std::optional<std::variant<ResultPoint, ResultSegment>>& piece) {
2240 if (std::holds_alternative<ResultPoint>(*piece)) {
2241 touchPoints.insert(std::get<ResultPoint>(*piece));
2243 segments.insert(std::get<ResultSegment>(*piece));
2251 if (std::holds_alternative<ResultPoint>(piece)) {
2252 touchPoints.insert(std::get<ResultPoint>(piece));
2254 segments.insert(std::get<ResultSegment>(piece));
2261 auto planarize = [](
const std::set<ResultSegment>& input) {
2263 for (
const auto& s : input) {
2270 std::set<ResultSegment> out;
2271 for (
const auto& s : input) {
2272 const ResultPoint a = s.min();
2273 const ResultPoint b = s.max();
2274 std::vector<ResultPoint> cut{a, b};
2276 if (v == a || v == b || !
collinear(a, b, v)) {
2279 if (v.x() < std::min(a.x(), b.x()) || v.x() > std::max(a.x(), b.x()) ||
2280 v.y() < std::min(a.y(), b.y()) || v.y() > std::max(a.y(), b.y())) {
2285 std::sort(cut.begin(), cut.end());
2286 cut.erase(std::unique(cut.begin(), cut.end()), cut.end());
2287 for (std::size_t i = 0; i + 1 < cut.size(); ++i) {
2288 out.insert(ResultSegment(cut[i], cut[i + 1]));
2293 segments = planarize(segments);
2296 std::map<ResultPoint, std::vector<ResultPoint>> adjacency;
2297 for (
const auto& segment : segments) {
2298 adjacency[segment.min()].push_back(segment.max());
2299 adjacency[segment.max()].push_back(segment.min());
2303 for (
const auto& point : touchPoints) {
2304 if (adjacency.find(point) == adjacency.end()) {
2305 result.emplace_back(point);
2309 using Number = ResultNumber;
2310 auto degree = [&adjacency](
const ResultPoint& p) {
2311 const auto it = adjacency.find(p);
2312 return it == adjacency.end() ? std::size_t(0) : it->second.size();
2314 auto removeEdge = [&adjacency](
const ResultPoint& u,
const ResultPoint& v) {
2315 auto& au = adjacency[u];
2316 au.erase(std::find(au.begin(), au.end(), v));
2317 auto& av = adjacency[v];
2318 av.erase(std::find(av.begin(), av.end(), u));
2325 const ResultPoint* leaf =
nullptr;
2326 for (
const auto& [p, neighbors] : adjacency) {
2327 if (neighbors.size() == 1) {
2335 const ResultPoint start = *leaf;
2336 ResultPoint current = start;
2337 while (degree(current) == 1) {
2338 const ResultPoint next = adjacency.at(current)[0];
2339 removeEdge(current, next);
2342 result.emplace_back(ResultSegment(start, current));
2347 auto rotationalNext = [&adjacency](
const ResultPoint& at,
const ResultPoint& from) {
2348 const auto& neighbors = adjacency.at(at);
2349 auto dx = [&](
const ResultPoint& p) {
return p.x() - at.x(); };
2350 auto dy = [&](
const ResultPoint& p) {
return p.y() - at.y(); };
2351 auto half = [&](
const ResultPoint& p) {
2352 const Number
y = dy(p);
2353 if (
y > Number(0))
return 0;
2354 if (
y < Number(0))
return 1;
2355 return dx(p) >= Number(0) ? 0 : 1;
2357 auto ccwBefore = [&](
const ResultPoint& u,
const ResultPoint& w) {
2358 const int hu = half(u), hw = half(w);
2362 return dx(u) * dy(w) - dy(u) * dx(w) > Number(0);
2364 const ResultPoint* best =
nullptr;
2365 for (
const auto& n : neighbors) {
2366 if (n == from || !ccwBefore(n, from)) {
2369 if (!best || ccwBefore(*best, n)) {
2374 for (
const auto& n : neighbors) {
2375 if (n != from && (!best || ccwBefore(*best, n))) {
2383 std::set<std::pair<ResultPoint, ResultPoint>> usedDart;
2384 for (
const auto& [u, neighbors] : adjacency) {
2385 for (
const auto& v : neighbors) {
2386 if (usedDart.count({u, v})) {
2389 std::vector<ResultPoint> cycle;
2393 usedDart.insert({a, b});
2395 const ResultPoint c = rotationalNext(b, a);
2398 }
while (a != u || b != v);
2401 for (std::size_t i = 0; i < cycle.size(); ++i) {
2402 const ResultPoint& p = cycle[i];
2403 const ResultPoint& q = cycle[(i + 1) % cycle.size()];
2404 twiceArea += p.x() * q.y() - q.x() * p.y();
2407 result.emplace_back(ResultPolygon(cycle));
2418template <
class Po
intType,
class LabelType>
2419template <
class ResultNumber, Po
intConcept OtherPo
int>
2420constexpr std::optional<Point<ResultNumber, typename PointType::LabelType>>
2431template <
class Po
intType,
class LabelType,
class Storage>
2432template <
class ResultNumber, MonotoneChainConcept OtherChain>
2433constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2438 using Piece = std::variant<ResultPoint, ResultSegment>;
2440 std::vector<Piece> pieces;
2441 if (
empty() || other.empty()) {
2445 if (other.contains((*
this)[0])) {
2446 pieces.emplace_back(ResultPoint((*
this)[0]));
2450 if (other.size() == 1) {
2452 pieces.emplace_back(ResultPoint(other[0]));
2463 const std::size_t iEnd =
size() - 1;
2464 const std::size_t jEnd = other.size() - 1;
2465 while (i < iEnd && j < jEnd) {
2468 if (!(mine.
max().x() < theirs.
min().x() || theirs.
max().x() < mine.
min().x())) {
2470 pieces.push_back(std::move(*piece));
2473 const auto order = mine.
max() <=> theirs.
max();
2482 return coalescePieces<ResultNumber>(std::move(pieces));
2485template <
class Po
intType,
class LabelType,
class Storage>
2486template <
class ResultNumber>
2487constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2489MonotoneChain<PointType, LabelType, Storage>::coalescePieces(
2494 using Piece = std::variant<ResultPoint, ResultSegment>;
2501 std::sort(pieces.begin(), pieces.end(), [](
const Piece& lhs,
const Piece& rhs) {
2502 const auto pieceMin = [](const Piece& piece) -> ResultPoint {
2503 if (const auto* point = std::get_if<ResultPoint>(&piece)) {
2506 return std::get<ResultSegment>(piece).min();
2508 const ResultPoint leftMin = pieceMin(lhs);
2509 const ResultPoint rightMin = pieceMin(rhs);
2510 if (leftMin != rightMin) {
2511 return leftMin < rightMin;
2513 const bool leftIsPoint = std::holds_alternative<ResultPoint>(lhs);
2514 const bool rightIsPoint = std::holds_alternative<ResultPoint>(rhs);
2515 if (leftIsPoint != rightIsPoint) {
2516 return !leftIsPoint;
2521 return std::get<ResultSegment>(lhs).max() < std::get<ResultSegment>(rhs).max();
2524 std::vector<Piece> result;
2525 for (
const Piece& piece : pieces) {
2526 if (
const auto* point = std::get_if<ResultPoint>(&piece)) {
2527 if (!result.empty()) {
2531 const Piece& last = result.back();
2532 if (
const auto* lastPoint = std::get_if<ResultPoint>(&last)) {
2533 if (*lastPoint == *point) {
2536 }
else if (std::get<ResultSegment>(last).contains(*point)) {
2540 result.push_back(piece);
2543 const auto& segment = std::get<ResultSegment>(piece);
2544 if (!result.empty()) {
2545 if (
auto* lastSegment = std::get_if<ResultSegment>(&result.back());
2546 lastSegment !=
nullptr && !(segment.min() < lastSegment->min()) &&
2547 !(lastSegment->max() < segment.min()) &&
2548 collinear(lastSegment->min(), lastSegment->max(), segment.min()) &&
2549 collinear(lastSegment->min(), lastSegment->max(), segment.max())) {
2552 if (lastSegment->max() < segment.max()) {
2553 *lastSegment = ResultSegment(lastSegment->min(), segment.max());
2558 result.push_back(piece);
2563template <
class Po
intType,
class LabelType,
class Storage>
2564template <
class ResultNumber, Po
intConcept OtherPo
int>
2565constexpr std::optional<Point<ResultNumber, typename PointType::LabelType>>
2573template <
class Po
intType,
class LabelType,
class Storage>
2574template <
class ResultNumber,
class OtherShape>
2575constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2577MonotoneChain<PointType, LabelType, Storage>::edgeFoldIntersection(
const OtherShape& other)
const {
2580 using Piece = std::variant<ResultPoint, ResultSegment>;
2582 std::vector<Piece> pieces;
2587 if (other.contains((*
this)[0])) {
2588 pieces.emplace_back(ResultPoint((*
this)[0]));
2592 for (std::size_t i = 0; i + 1 < size(); ++i) {
2594 this->
template boundaryAt<false>(i).template intersection<ResultNumber>(other);
2598 pieces.push_back(std::visit(
2599 [](
const auto& value) -> Piece {
2600 if constexpr (detail::is_point_v<std::remove_cvref_t<
decltype(value)>>) {
2601 return Piece(ResultPoint(value));
2603 return Piece(ResultSegment(value));
2609 return coalescePieces<ResultNumber>(std::move(pieces));
2612template <
class Po
intType,
class LabelType,
class Storage>
2613template <
class ResultNumber, SegmentConcept OtherSegment>
2614constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2615 Segment<Point<ResultNumber, typename PointType::LabelType>>>>
2617 return this->
template edgeFoldIntersection<ResultNumber>(other);
2620template <
class Po
intType,
class LabelType,
class Storage>
2621template <
class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
2622constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2625 return this->
template edgeFoldIntersection<ResultNumber>(other);
2628template <
class Po
intType,
class LabelType,
class Storage>
2629template <
class ResultNumber, LineConcept OtherLine>
2630constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2633 return this->
template edgeFoldIntersection<ResultNumber>(other);
2636template <
class Po
intType,
class LabelType,
class Storage>
2637template <
class ResultNumber, OrientedLineConcept OtherOrientedLine>
2638constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2641 return this->
template edgeFoldIntersection<ResultNumber>(other);
2644template <
class Po
intType,
class LabelType,
class Storage>
2645template <
class ResultNumber, RayConcept OtherRay>
2646constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2649 return this->
template edgeFoldIntersection<ResultNumber>(other);
2652template <
class Po
intType,
class LabelType,
class Storage>
2653template <
class ResultNumber, HalfplaneConcept OtherHalfplane>
2654constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2657 return this->
template edgeFoldIntersection<ResultNumber>(other);
2660template <
class Po
intType,
class LabelType,
class Storage>
2661template <
class ResultNumber, RectangleConcept OtherRectangle>
2662constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2665 return this->
template edgeFoldIntersection<ResultNumber>(other);
2668template <
class Po
intType,
class LabelType,
class Storage>
2669template <
class ResultNumber, TriangleConcept OtherTriangle>
2670constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2673 return this->
template edgeFoldIntersection<ResultNumber>(other);
2676template <
class Po
intType,
class LabelType,
class Storage>
2677template <
class ResultNumber, ConvexConcept OtherConvex>
2678constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2681 return this->
template edgeFoldIntersection<ResultNumber>(other);
2687template <
class Po
intType,
class LabelType>
2688template <
class ResultNumber, Po
intConcept OtherPo
int>
2689constexpr std::optional<Point<ResultNumber, typename PointType::LabelType>>
2697template <
class Po
intType,
class LabelType>
2698template <
class ResultNumber>
2699constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2701Polyline<PointType, LabelType>::coalescePieces(
2706 using Piece = std::variant<ResultPoint, ResultSegment>;
2713 std::vector<ResultSegment> segments;
2714 for (
const Piece& piece : pieces) {
2715 const auto* segment = std::get_if<ResultSegment>(&piece);
2716 if (segment ==
nullptr) {
2719 ResultSegment merged = *segment;
2720 for (std::size_t i = segments.size(); i-- > 0;) {
2721 const ResultSegment& kept = segments[i];
2722 if (collinear(merged.min(), merged.max(), kept.min()) &&
2723 collinear(merged.min(), merged.max(), kept.max()) &&
2724 merged.intersects(kept)) {
2727 merged = ResultSegment(std::min(merged.min(), kept.min()),
2728 std::max(merged.max(), kept.max()));
2729 segments.erase(segments.begin() +
static_cast<std::ptrdiff_t
>(i));
2732 segments.push_back(std::move(merged));
2737 std::vector<ResultPoint> points;
2738 for (
const Piece& piece : pieces) {
2739 if (
const auto* point = std::get_if<ResultPoint>(&piece)) {
2740 points.push_back(*point);
2743 std::sort(points.begin(), points.end());
2744 points.erase(std::unique(points.begin(), points.end()), points.end());
2746 std::vector<Piece> result;
2747 result.reserve(segments.size() + points.size());
2748 for (
const ResultPoint& point : points) {
2749 if (std::none_of(segments.begin(), segments.end(),
2750 [&point](
const ResultSegment& segment) { return segment.contains(point); })) {
2751 result.emplace_back(point);
2754 for (ResultSegment& segment : segments) {
2755 result.emplace_back(std::move(segment));
2760 std::sort(result.begin(), result.end(), [](
const Piece& lhs,
const Piece& rhs) {
2761 const auto pieceMin = [](const Piece& piece) -> ResultPoint {
2762 if (const auto* point = std::get_if<ResultPoint>(&piece)) {
2765 return std::get<ResultSegment>(piece).min();
2767 const ResultPoint leftMin = pieceMin(lhs);
2768 const ResultPoint rightMin = pieceMin(rhs);
2769 if (leftMin != rightMin) {
2770 return leftMin < rightMin;
2772 const bool leftIsPoint = std::holds_alternative<ResultPoint>(lhs);
2773 const bool rightIsPoint = std::holds_alternative<ResultPoint>(rhs);
2774 if (leftIsPoint != rightIsPoint) {
2775 return !leftIsPoint;
2780 return std::get<ResultSegment>(lhs).max() < std::get<ResultSegment>(rhs).max();
2785template <
class Po
intType,
class LabelType>
2786template <
class ResultNumber,
class OtherShape>
2787constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2788 Segment<Point<ResultNumber, typename PointType::LabelType>>>>
2789Polyline<PointType, LabelType>::edgeFoldIntersection(
const OtherShape& other)
const {
2790 using ResultPoint = Point<ResultNumber, typename PointType::LabelType>;
2791 using ResultSegment = Segment<ResultPoint>;
2792 using Piece = std::variant<ResultPoint, ResultSegment>;
2794 std::vector<Piece> pieces;
2799 if (other.contains((*
this)[0])) {
2800 pieces.emplace_back(ResultPoint((*
this)[0]));
2804 for (std::size_t i = 0; i + 1 < size(); ++i) {
2806 this->
template boundaryAt<false>(i).template intersection<ResultNumber>(other);
2810 pieces.push_back(std::visit(
2811 [](
const auto& value) -> Piece {
2812 if constexpr (detail::is_point_v<std::remove_cvref_t<
decltype(value)>>) {
2813 return Piece(ResultPoint(value));
2815 return Piece(ResultSegment(value));
2821 return coalescePieces<ResultNumber>(std::move(pieces));
2824template <
class Po
intType,
class LabelType>
2825template <
class ResultNumber, SegmentConcept OtherSegment>
2826constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2827 Segment<Point<ResultNumber, typename PointType::LabelType>>>>
2829 return this->
template edgeFoldIntersection<ResultNumber>(other);
2832template <
class Po
intType,
class LabelType>
2833template <
class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
2834constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2837 return this->
template edgeFoldIntersection<ResultNumber>(other);
2840template <
class Po
intType,
class LabelType>
2841template <
class ResultNumber, LineConcept OtherLine>
2842constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2845 return this->
template edgeFoldIntersection<ResultNumber>(other);
2848template <
class Po
intType,
class LabelType>
2849template <
class ResultNumber, OrientedLineConcept OtherOrientedLine>
2850constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2853 return this->
template edgeFoldIntersection<ResultNumber>(other);
2856template <
class Po
intType,
class LabelType>
2857template <
class ResultNumber, RayConcept OtherRay>
2858constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2861 return this->
template edgeFoldIntersection<ResultNumber>(other);
2864template <
class Po
intType,
class LabelType>
2865template <
class ResultNumber, HalfplaneConcept OtherHalfplane>
2866constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2869 return this->
template edgeFoldIntersection<ResultNumber>(other);
2872template <
class Po
intType,
class LabelType>
2873template <
class ResultNumber, RectangleConcept OtherRectangle>
2874constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2877 return this->
template edgeFoldIntersection<ResultNumber>(other);
2880template <
class Po
intType,
class LabelType>
2881template <
class ResultNumber, TriangleConcept OtherTriangle>
2882constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2885 return this->
template edgeFoldIntersection<ResultNumber>(other);
2888template <
class Po
intType,
class LabelType>
2889template <
class ResultNumber, ConvexConcept OtherConvex>
2890constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2893 return this->
template edgeFoldIntersection<ResultNumber>(other);
2896template <
class Po
intType,
class LabelType>
2897template <
class ResultNumber, MonotoneChainConcept OtherChain>
2898constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2903 using Piece = std::variant<ResultPoint, ResultSegment>;
2905 std::vector<Piece> pieces;
2906 if (
empty() || other.empty()) {
2910 if (other.contains((*
this)[0])) {
2911 pieces.emplace_back(ResultPoint((*
this)[0]));
2915 if (other.size() == 1) {
2917 pieces.emplace_back(ResultPoint(other[0]));
2927 for (std::size_t i = 0; i + 1 <
size(); ++i) {
2929 for (std::size_t j = 0; j + 1 < other.size(); ++j) {
2932 pieces.push_back(std::move(*piece));
2936 return coalescePieces<ResultNumber>(std::move(pieces));
2939template <
class Po
intType,
class LabelType>
2940template <
class ResultNumber, PolylineConcept OtherPolyline>
2941constexpr std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
2946 using Piece = std::variant<ResultPoint, ResultSegment>;
2948 std::vector<Piece> pieces;
2949 if (
empty() || other.empty()) {
2953 if (other.contains((*
this)[0])) {
2954 pieces.emplace_back(ResultPoint((*
this)[0]));
2958 if (other.size() == 1) {
2960 pieces.emplace_back(ResultPoint(other[0]));
2970 for (std::size_t i = 0; i + 1 <
size(); ++i) {
2972 for (std::size_t j = 0; j + 1 < other.size(); ++j) {
2975 pieces.push_back(std::move(*piece));
2979 return coalescePieces<ResultNumber>(std::move(pieces));
2982template <
class Po
intType,
class LabelType>
2983template <
class ResultNumber,
class OtherArea>
2990 using Piece = std::variant<ResultPoint, ResultSegment>;
2992 std::vector<Piece> pieces;
2997 if (other.contains((*
this)[0])) {
2998 pieces.emplace_back(ResultPoint((*
this)[0]));
3004 for (std::size_t i = 0; i + 1 <
size(); ++i) {
3005 const auto edgePieces =
3007 for (
const auto& piece : edgePieces) {
3010 pieces.push_back(std::visit(
3011 [](
const auto& value) -> Piece {
3012 if constexpr (detail::is_point_v<std::remove_cvref_t<
decltype(value)>>) {
3013 return Piece(ResultPoint(value));
3015 return Piece(ResultSegment(value));
3021 return coalescePieces<ResultNumber>(std::move(pieces));
3028template <
class Po
intType,
class LabelType>
3029template <
class ResultNumber, PolylineConcept OtherPolyline>
3031 return other.template polygonIntersection<ResultNumber>(*
this);
3034template <
class Po
intType,
class LabelType>
3035template <
class ResultNumber, MonotoneChainConcept OtherChain>
3037 return other.asPolyline().template polygonIntersection<ResultNumber>(*
this);
3050template <
class Po
intType_,
class TLabel>
3051template <
class ResultNumber, Po
intConcept OtherPo
int>
3052constexpr std::optional<Point<ResultNumber, typename PointType_::LabelType>>
3060template <
class Po
intType_,
class TLabel>
3061template <
class ResultNumber, SegmentConcept OtherSegment>
3062constexpr std::vector<std::variant<Point<ResultNumber, typename PointType_::LabelType>,
3066 return detail::areaSegmentIntersection<ResultPoint>(*
this,
orientedEdges(), other);
3069template <
class Po
intType_,
class TLabel>
3070template <
class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
3071constexpr std::vector<std::variant<Point<ResultNumber, typename PointType_::LabelType>,
3078template <
class Po
intType_,
class TLabel>
3079template <
class ResultNumber, LineConcept OtherLine>
3080constexpr std::vector<std::variant<Point<ResultNumber, typename PointType_::LabelType>,
3084 return detail::areaLineIntersection<ResultPoint>(*
this,
orientedEdges(), other);
3087template <
class Po
intType_,
class TLabel>
3088template <
class ResultNumber, OrientedLineConcept OtherOrientedLine>
3089constexpr std::vector<std::variant<Point<ResultNumber, typename PointType_::LabelType>,
3095template <
class Po
intType_,
class TLabel>
3096template <
class ResultNumber, RayConcept OtherRay>
3097constexpr std::vector<std::variant<Point<ResultNumber, typename PointType_::LabelType>,
3101 return detail::areaRayIntersection<ResultPoint>(*
this,
orientedEdges(), other);
3107template <
class Po
intType_,
class TLabel>
3108template <
class ResultNumber, PolylineConcept OtherPolyline>
3110 return other.template polygonIntersection<ResultNumber>(*
this);
3113template <
class Po
intType_,
class TLabel>
3114template <
class ResultNumber, MonotoneChainConcept OtherChain>
3116 return other.asPolyline().template polygonIntersection<ResultNumber>(*
this);
3123template <
class Po
intType,
class LabelType>
3124template <
class ResultNumber, Po
intConcept OtherPo
int>
3125constexpr std::optional<Point<ResultNumber, typename PointType::LabelType>>
3133template <
class Po
intType,
class LabelType>
3134template <
class ResultNumber, LineConcept OtherLine>
3135constexpr std::optional<std::variant<Point<ResultNumber, typename PointType::LabelType>,
3144 if (other.isDegenerate()) {
3146 return ResultPoint(other[0]);
3150 if (halfplanes_.empty()) {
3154 const auto clip = clipLine(along);
3159 const auto crossing = [&](std::ptrdiff_t idx) {
3160 const auto isec = halfplanes_[
static_cast<std::size_t
>(idx)].asLine()
3162 assert(isec && isec->index() == 0);
3163 return std::get<0>(*isec);
3165 if (clip.entry < 0 && clip.exit < 0) {
3168 const ResultPoint source(other[0]);
3169 const ResultPoint target(other[1]);
3170 const ResultNumber dx = target.x() - source.x();
3171 const ResultNumber dy = target.y() - source.y();
3172 if (clip.entry < 0) {
3173 const ResultPoint finish = crossing(clip.exit);
3174 return Ray<ResultPoint>(finish, ResultPoint(finish.x() - dx, finish.y() - dy));
3176 if (clip.exit < 0) {
3177 const ResultPoint start = crossing(clip.entry);
3178 return Ray<ResultPoint>(start, ResultPoint(start.x() + dx, start.y() + dy));
3180 const auto det = detail::boundaryLinesDeterminant(
3181 halfplanes_[
static_cast<std::size_t
>(clip.entry)],
3182 halfplanes_[
static_cast<std::size_t
>(clip.exit)], along);
3183 if (det ==
decltype(det){}) {
3184 return crossing(clip.entry);
3189template <
class Po
intType,
class LabelType>
3190template <
class ResultNumber, OrientedLineConcept OtherOrientedLine>
3191constexpr std::optional<std::variant<Point<ResultNumber, typename PointType::LabelType>,
3199template <
class Po
intType,
class LabelType>
3200template <
class ResultNumber, SegmentConcept OtherSegment>
3201constexpr std::optional<std::variant<Point<ResultNumber, typename PointType::LabelType>,
3208 if (other.isDegenerate()) {
3210 return ResultPoint(other.min());
3214 if (halfplanes_.empty()) {
3218 const auto clip = clipLine(along);
3223 const auto crossing = [&](std::ptrdiff_t idx) {
3224 const auto isec = halfplanes_[
static_cast<std::size_t
>(idx)].asLine()
3226 assert(isec && isec->index() == 0);
3227 return std::get<0>(*isec);
3231 const bool startsAtMin = clip.entry < 0 ||
3232 constraintSide(
static_cast<std::size_t
>(clip.entry), other.min()) >= 0;
3233 if (!startsAtMin && constraintSide(
static_cast<std::size_t
>(clip.entry), other.max()) < 0) {
3236 const bool endsAtMax = clip.exit < 0 ||
3237 constraintSide(
static_cast<std::size_t
>(clip.exit), other.max()) >= 0;
3238 if (!endsAtMax && constraintSide(
static_cast<std::size_t
>(clip.exit), other.min()) < 0) {
3241 if (startsAtMin && endsAtMax) {
3245 if (constraintSide(
static_cast<std::size_t
>(clip.exit), other.min()) == 0) {
3246 return ResultPoint(other.min());
3251 if (constraintSide(
static_cast<std::size_t
>(clip.entry), other.max()) == 0) {
3252 return ResultPoint(other.max());
3256 const auto det = detail::boundaryLinesDeterminant(
3257 halfplanes_[
static_cast<std::size_t
>(clip.entry)],
3258 halfplanes_[
static_cast<std::size_t
>(clip.exit)], along);
3259 if (det ==
decltype(det){}) {
3260 return crossing(clip.entry);
3265template <
class Po
intType,
class LabelType>
3266template <
class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
3267constexpr std::optional<std::variant<Point<ResultNumber, typename PointType::LabelType>,
3273template <
class Po
intType,
class LabelType>
3274template <
class ResultNumber, RayConcept OtherRay>
3275constexpr std::optional<std::variant<Point<ResultNumber, typename PointType::LabelType>,
3283 if (halfplanes_.empty()) {
3284 return Ray<ResultPoint>(ResultPoint(other.source()), ResultPoint(other.target()));
3287 const auto clip = clipLine(along);
3292 const auto crossing = [&](std::ptrdiff_t idx) {
3293 const auto isec = halfplanes_[
static_cast<std::size_t
>(idx)].asLine()
3295 assert(isec && isec->index() == 0);
3296 return std::get<0>(*isec);
3299 const bool startsAtSource = clip.entry < 0 ||
3300 constraintSide(
static_cast<std::size_t
>(clip.entry), other.source()) >= 0;
3301 if (clip.exit < 0) {
3302 if (startsAtSource) {
3303 return Ray<ResultPoint>(ResultPoint(other.source()), ResultPoint(other.target()));
3305 const ResultPoint start = crossing(clip.entry);
3306 const ResultPoint source(other.source());
3307 const ResultPoint target(other.target());
3308 return Ray<ResultPoint>(start, ResultPoint(start.x() + (target.x() - source.x()),
3309 start.y() + (target.y() - source.y())));
3311 const auto exitSide = constraintSide(
static_cast<std::size_t
>(clip.exit), other.source());
3315 if (startsAtSource) {
3316 if (exitSide == 0) {
3317 return ResultPoint(other.source());
3321 const auto det = detail::boundaryLinesDeterminant(
3322 halfplanes_[
static_cast<std::size_t
>(clip.entry)],
3323 halfplanes_[
static_cast<std::size_t
>(clip.exit)], along);
3324 if (det ==
decltype(det){}) {
3325 return crossing(clip.entry);
3330template <
class Po
intType,
class LabelType>
3331template <
class ResultNumber, HalfplaneConcept OtherHalfplane>
3342template <
class Po
intType,
class LabelType>
3343template <
class ResultNumber, RectangleConcept OtherRectangle>
3352 if (other.empty()) {
3358 result.
insert(ResultHalfplane(ResultPoint(0, 0), ResultPoint(0, 1)));
3359 result.
insert(ResultHalfplane(ResultPoint(1, 1), ResultPoint(1, 0)));
3363 result.
insert(halfplane);
3368template <
class Po
intType,
class LabelType>
3369template <
class ResultNumber, TriangleConcept OtherTriangle>
3375 result.
insert(halfplane);
3380template <
class Po
intType,
class LabelType>
3381template <
class ResultNumber, ConvexConcept OtherConvex>
3387 if (other.size() == 0) {
3390 result.
insert(ResultHalfplane(ResultPoint(0, 0), ResultPoint(0, 1)));
3391 result.
insert(ResultHalfplane(ResultPoint(1, 1), ResultPoint(1, 0)));
3395 result.
insert(halfplane);
3400template <
class Po
intType,
class LabelType>
3401template <
class ResultNumber, HalfplaneIntersectionConcept OtherRegion>
3410 if (other.empty()) {
3413 result.
insert(ResultHalfplane(ResultPoint(0, 0), ResultPoint(0, 1)));
3414 result.
insert(ResultHalfplane(ResultPoint(1, 1), ResultPoint(1, 0)));
3417 for (
const auto& halfplane : other) {
3418 result.
insert(ResultHalfplane(halfplane));
3435template <
class Po
intType,
class LabelType>
3436template <
class ResultNumber, PolygonConcept OtherPolygon>
3437std::vector<std::variant<Point<ResultNumber, typename PointType::LabelType>,
3445 using Piece = std::variant<ResultPoint, ResultPolyline, ResultPolygon>;
3446 using ExactNumber = detail::region_exact_number_t<NumberType>;
3450 std::vector<Piece> result;
3451 if (
empty() || other.size() == 0) {
3461 const auto carrierPieces = [&exact, &result](
const auto& region) {
3463 [&exact, &result](
const auto& carrier) {
3464 using Carrier = std::remove_cvref_t<
decltype(carrier)>;
3467 result.emplace_back(ResultPoint(carrier));
3471 if (
const auto* point = std::get_if<ResultPoint>(&piece)) {
3472 result.emplace_back(*point);
3474 const ResultSegment& chord = std::get<ResultSegment>(piece);
3475 result.emplace_back(
3476 ResultPolyline(std::vector<ResultPoint>{chord.min(), chord.max()}));
3481 detail::degenerateRegionCarrier(region));
3485 carrierPieces(*
this);
3489 ExactRegion clipped(*
this);
3490 for (
const auto& halfplane : ExactRegion(exact.
bbox())) {
3491 clipped.insert(halfplane);
3493 if (clipped.empty()) {
3498 if (clipped.isDegenerate()) {
3499 carrierPieces(clipped);
Coordinate-evaluation helpers for linear primitives.
Definition forward.hpp:306
Definition forward.hpp:316
Definition forward.hpp:317
Definition arrangement.hpp:67
@ y
Definition intervaltree.hpp:24
@ x
Definition intervaltree.hpp:24
@ edge
Definition bitmatrix.hpp:37
Line() -> Line< Point<>, NoLabel >
constexpr std::partial_ordering orientationSign(const Point< ANumber, ALabel > &a, const Point< BNumber, BLabel > &b, const Point< CNumber, CLabel > &c)
Classifies the orientation of three points.
Definition orientation.hpp:544
constexpr bool collinear(const Point< ANumber, ALabel > &a, const Point< BNumber, BLabel > &b, const Point< CNumber, CLabel > &c)
Tests whether three points are collinear.
Definition orientation.hpp:651
Segment() -> Segment< Point<>, NoLabel >
constexpr auto orientationDeterminant(const Point< ANumber, ALabel > &a, const Point< BNumber, BLabel > &b, const Point< CNumber, CLabel > &c)
Returns the signed orientation determinant of three points.
Definition orientation.hpp:518
Ray() -> Ray< Point<>, NoLabel >
Closed convex polygon stored by its vertices.
Definition convex.hpp:170
constexpr bool intersects(const OtherSegment &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:716
constexpr PointType get(std::ptrdiff_t index) const
Cyclic access: same as operator[] but index is taken modulo size(); negative indices wrap from the en...
Definition convex.hpp:289
constexpr std::ptrdiff_t index(const PointType &point) const
Returns the smallest index i with (*this)[i] == point, or -1 if point is not a vertex.
Definition predicates.hpp:1085
constexpr 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 convex.hpp:2496
constexpr std::vector< Segment< PointType > > edges() const
Returns the edges of the convex polygon.
Definition convex.hpp:529
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:1135
constexpr Convex()=default
Creates a convex with no vertex.
size_t size() const
Returns the number of vertices in the convex polygon.
Definition convex.hpp:840
PointType_ PointType
Definition convex.hpp:171
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 disk.hpp:787
constexpr bool contains(const OtherPoint &other) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:1015
Intersection of closed half-planes; convex but possibly unbounded or empty.
Definition halfplaneintersection.hpp:244
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:2511
Halfplane< PointType > HalfplaneType
Definition halfplaneintersection.hpp:248
constexpr bool empty() const
Returns whether the region is the empty set.
Definition halfplaneintersection.hpp:649
constexpr EmptyShape< EmptyPoint > intersection(const EmptyShape< EmptyPoint > &) const
Returns the intersection of the two shapes (A ∩ B), empty when they are disjoint.
Definition halfplaneintersection.hpp:1762
constexpr bool isDegenerate() const
Returns whether the region has empty interior (it is empty or lower-dimensional: a line,...
Definition halfplaneintersection.hpp:664
constexpr Convex< Point< ResultNumber, typename PointType::LabelType > > asConvex() const
Returns the region as a convex polygon.
Definition halfplaneintersection.hpp:955
friend struct HalfplaneIntersection
Definition halfplaneintersection.hpp:2308
constexpr bool insert(const OtherHalfplane &other)
Intersects the region with one more half-plane.
Definition halfplaneintersection.hpp:509
Closed half-plane defined by an oriented boundary line.
Definition halfplane.hpp:51
constexpr std::optional< Point< ResultNumber, typename PointType::LabelType > > intersection(const OtherPoint &other) const
Returns the intersection of the two shapes (A ∩ B), empty when they are disjoint.
Definition intersection.hpp:524
constexpr const PointType & target() const
Returns the target boundary point.
Definition halfplane.hpp:193
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:872
constexpr Line< PointType > asLine() const
Returns the boundary line without orientation.
Definition halfplane.hpp:318
constexpr const PointType & source() const
Returns the source boundary point.
Definition halfplane.hpp:181
constexpr bool isDegenerate() const
Returns whether the defining points coincide.
Definition predicates.hpp:952
Unoriented infinite line.
Definition line.hpp:52
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:428
constexpr const PointType & max() const
Returns the largest stored defining point.
Definition line.hpp:189
constexpr bool parallel(const OtherLine &other) const
Returns whether another line is parallel to this line.
Definition predicates.hpp:508
constexpr const PointType & min() const
Returns the smallest stored defining point.
Definition line.hpp:180
constexpr Line()=default
Creates the degenerate line (0,0)--(0,0).
constexpr std::optional< Point< ResultNumber, typename PointType::LabelType > > intersection(const OtherPoint &other) const
Returns the intersection of the two shapes (A ∩ B), empty when they are disjoint.
Definition intersection.hpp:203
constexpr bool isDegenerate() const
Returns whether the defining points coincide.
Definition predicates.hpp:451
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:1822
constexpr std::size_t size() const
Returns the number of vertices in the chain.
Definition monotonechain.hpp:393
constexpr bool empty() const
Checks whether the chain has no vertex.
Definition monotonechain.hpp:400
constexpr std::optional< Point< ResultNumber, typename PointType::LabelType > > intersection(const OtherPoint &other) const
Returns the intersection of the two shapes (A ∩ B), empty when they are disjoint.
Definition intersection.hpp:2566
constexpr std::optional< Point< ResultNumber, typename PointType::LabelType > > intersection(const OtherPoint &other) const
Returns the intersection of the two shapes (A ∩ B), empty when they are disjoint.
Definition intersection.hpp:280
constexpr Line< PointType > asLine() const
Returns the line without orientation.
Definition orientedline.hpp:321
constexpr std::optional< Point< ResultNumber, typename PointType::LabelType > > intersection(const OtherPoint &other) const
Returns the intersection of the two shapes (A ∩ B), empty when they are disjoint.
Definition intersection.hpp:180
Two-dimensional point with optional label payload.
Definition point.hpp:129
constexpr std::optional< Point< ResultNumber, LabelType > > intersection(const OtherPoint &other) const
Returns the intersection of the two shapes (A ∩ B), empty when they are disjoint.
constexpr bool contains(const OtherPoint &other) const
constexpr std::vector< OrientedSegment< PointType > > orientedEdges() const
Definition polygonwithholes.hpp:364
constexpr std::optional< Point< ResultNumber, typename PointType::LabelType > > intersection(const OtherPoint &other) const
Returns the intersection of the two shapes (A ∩ B), empty when they are disjoint.
constexpr bool contains(const OtherPoint &point) const
Closed simple polygon stored by its vertices.
Definition polygon.hpp:59
constexpr const Rectangle< PointType > & bbox() const
Computes the bounding box of the polygon.
Definition bounding.hpp:449
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:1296
constexpr auto orientedEdgesView() const
Lazy view counterpart of orientedEdges(); see edgesView().
Definition polygon.hpp:790
constexpr Polygon()=default
Creates a polygon with no vertex.
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 polygon.hpp:2510
constexpr std::size_t size() const
Returns the number of vertices in the polygon.
Definition polygon.hpp:259
constexpr ResultNumber twiceArea() const
Computes twice the (unsigned) area of the polygon via the shoelace formula.
Definition polygon.hpp:273
constexpr std::vector< PointType > vertices() const
Returns the vertices of the polygon (translation applied).
Definition polygon.hpp:587
constexpr std::vector< Segment< PointType > > edges() const
Returns the edges of the polygon.
Definition polygon.hpp:598
Open polygonal chain stored in traversal order; may self-intersect.
Definition polyline.hpp:69
constexpr const Rectangle< PointType > & bbox() const
Computes the bounding box of the polyline.
Definition bounding.hpp:515
constexpr std::vector< std::variant< Point< ResultNumber, typename PointType::LabelType >, Segment< Point< ResultNumber, typename PointType::LabelType > > > > polygonIntersection(const OtherArea &other) const
Returns the intersection with a polygon or a region (A ∩ B), a sequence of points and segments sorted...
Definition intersection.hpp:2987
constexpr std::optional< Point< ResultNumber, typename PointType::LabelType > > intersection(const OtherPoint &other) const
Returns the intersection of the two shapes (A ∩ B), empty when they are disjoint.
Definition intersection.hpp:2690
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:2134
constexpr bool intersects(const OtherPoint &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:1620
constexpr bool empty() const
Checks whether the polyline has no vertex.
Definition polyline.hpp:395
constexpr std::size_t size() const
Returns the number of vertices in the polyline.
Definition polyline.hpp:388
Half-infinite line starting from one source point plus optional ray label.
Definition ray.hpp:51
constexpr Ray()=default
Creates the degenerate ray (0,0)--(0,0)->.
constexpr std::optional< Point< ResultNumber, typename PointType::LabelType > > intersection(const OtherPoint &other) const
Returns the intersection of the two shapes (A ∩ B), empty when they are disjoint.
Definition intersection.hpp:323
constexpr bool isDegenerate() const
Returns whether the defining points coincide.
Definition predicates.hpp:727
constexpr const PointType & target() const
Returns the second stored point defining the direction.
Definition ray.hpp:193
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:625
constexpr Line< PointType > asLine() const
Returns the supporting line without orientation.
Definition ray.hpp:319
constexpr const PointType & source() const
Returns the source point of the ray.
Definition ray.hpp:181
constexpr bool intersects(const OtherPoint &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:502
constexpr const PointType & min() const
Returns the minimum corner (min x, min y).
Definition rectangle.hpp:347
constexpr bool empty() const
Returns whether the rectangle is the empty set of points.
Definition rectangle.hpp:290
constexpr std::array< PointType, 4 > vertices() const
Returns the four vertices in counterclockwise order.
Definition bounding.hpp:188
constexpr const PointType & max() const
Returns the maximum corner (max x, max y).
Definition rectangle.hpp:359
constexpr Rectangle()
Creates the empty rectangle [(0,0),(-1,-1)].
Definition rectangle.hpp:120
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:728
constexpr std::optional< Point< ResultNumber, typename PointType::LabelType > > intersection(const OtherPoint &other) const
Returns the intersection of the two shapes (A ∩ B), empty when they are disjoint.
Definition intersection.hpp:998
Unoriented closed segment between two endpoints plus optional segment label.
Definition segment.hpp:58
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:119
constexpr std::optional< Point< ResultNumber, typename PointType::LabelType > > intersection(const OtherPoint &other) const
Returns the intersection of the two shapes (A ∩ B), empty when they are disjoint.
Definition intersection.hpp:100
constexpr bool containsCollinear(const OtherPoint &point) const
Returns whether the segment contains the given point that is collinear with the segment.
Definition predicates.hpp:161
constexpr const PointType & max() const
Returns the largest stored endpoint.
Definition segment.hpp:199
constexpr const PointType & min() const
Returns the smallest stored endpoint.
Definition segment.hpp:190
constexpr Segment()=default
Creates the degenerate segment (0,0)--(0,0).
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:223
constexpr Convex< PointType > asConvex() const
Returns the triangle as a convex polygon.
Definition triangle.hpp:490
constexpr std::optional< Point< ResultNumber, typename PointType::LabelType > > intersection(const OtherPoint &other) const
Returns the intersection of the two shapes (A ∩ B), empty when they are disjoint.
Definition intersection.hpp:1170