18template <
class Number,
class Label>
23template <
class Number,
class Label>
24template<Po
intConcept OtherPo
int>
26 coords_[0] += detail::asNumber<Number>(other[0]);
27 coords_[1] += detail::asNumber<Number>(other[1]);
31template <
class Number,
class Label>
32template<Po
intConcept OtherPo
int>
34 coords_[0] -= detail::asNumber<Number>(other[0]);
35 coords_[1] -= detail::asNumber<Number>(other[1]);
39template <
class Number,
class Label>
40template <
class OtherNumber>
42 coords_[0] *= detail::asNumber<Number>(scalar);
43 coords_[1] *= detail::asNumber<Number>(scalar);
47template <
class Number,
class Label>
48template <
class OtherNumber>
50 coords_[0] /= detail::asNumber<Number>(scalar);
51 coords_[1] /= detail::asNumber<Number>(scalar);
55template <
class Number,
class Label>
60template <
class Number,
class Label>
62 switch (((k % 4) + 4) % 4) {
63 case 1:
return Point(-
y(),
x());
64 case 2:
return Point(-
x(), -
y());
65 case 3:
return Point(
y(), -
x());
66 default:
return Point(
x(),
y());
70template <
class Number,
class Label>
72 switch (((k % 4) + 4) % 4) {
73 case 1: {
auto tmp =
x();
x() = -
y();
y() = tmp;
break; }
74 case 2: {
x() = -
x();
y() = -
y();
break; }
75 case 3: {
auto tmp =
x();
x() =
y();
y() = -tmp;
break; }
79template <
class Number,
class Label>
80template <
class OtherNumber>
85template <
class Number,
class Label>
86template <
class OtherNumber>
88 coords_[0] *= detail::asNumber<Number>(scalar);
91template <
class Number,
class Label>
92template <
class OtherNumber>
97template <
class Number,
class Label>
98template <
class OtherNumber>
100 coords_[1] *= detail::asNumber<Number>(scalar);
103template <
class Number,
class Label>
104template <
class OtherNumber>
109template <
class Number,
class Label>
110template <
class OtherNumber>
112 coords_[0] /= detail::asNumber<Number>(scalar);
115template <
class Number,
class Label>
116template <
class OtherNumber>
121template <
class Number,
class Label>
122template <
class OtherNumber>
124 coords_[1] /= detail::asNumber<Number>(scalar);
129template <
class LeftNumber,
class LeftLabel,
class RightNumber,
class RightLabel>
131 using ResultNumber = std::common_type_t<LeftNumber, RightNumber>;
133 detail::asNumber<ResultNumber>(left.
x()) - detail::asNumber<ResultNumber>(right.
x()),
134 detail::asNumber<ResultNumber>(left.
y()) - detail::asNumber<ResultNumber>(right.
y()));
137template <
class Number,
class Label,
class Scalar>
138 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
140 using ResultNumber = std::common_type_t<Number, Scalar>;
142 detail::asNumber<ResultNumber>(point.
x()) * detail::asNumber<ResultNumber>(scalar),
143 detail::asNumber<ResultNumber>(point.
y()) * detail::asNumber<ResultNumber>(scalar));
146template <
class Scalar,
class Number,
class Label>
147 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
149 return point * scalar;
152template <
class Number,
class Label,
class Scalar>
153 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
155 using ResultNumber = std::common_type_t<Number, Scalar>;
157 detail::asNumber<ResultNumber>(point.
x()) / detail::asNumber<ResultNumber>(scalar),
158 detail::asNumber<ResultNumber>(point.
y()) / detail::asNumber<ResultNumber>(scalar));
164template <
class Po
intType,
class LabelType>
165template<Po
intConcept OtherPo
int>
167 points_[0] += translation;
168 points_[1] += translation;
172template <
class Po
intType,
class LabelType>
173template<Po
intConcept OtherPo
int>
175 points_[0] -= translation;
176 points_[1] -= translation;
180template <
class Po
intType,
class LabelType>
181template <
class Scalar>
184 points_[0] *= scalar;
185 points_[1] *= scalar;
186 if (points_[1] < points_[0]) std::swap(points_[0], points_[1]);
190template <
class Po
intType,
class LabelType>
191template <
class Scalar>
194 points_[0] /= scalar;
195 points_[1] /= scalar;
196 if (points_[1] < points_[0]) std::swap(points_[0], points_[1]);
200template <
class Po
intType,
class LabelType,
class TranslationNumber,
class TranslationLabel>
202 const auto first = segment.
min() - translation;
203 const auto second = segment.
max() - translation;
204 return Segment<std::decay_t<
decltype(first)>, LabelType>(first, second);
207template <
class Po
intType,
class LabelType,
class Scalar>
208 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
210 const auto first = segment.
min() * scalar;
211 const auto second = segment.
max() * scalar;
212 return Segment<std::decay_t<
decltype(first)>, LabelType>(first, second);
215template <
class Scalar,
class Po
intType,
class LabelType>
216 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
218 return segment * scalar;
221template <
class Po
intType,
class LabelType,
class Scalar>
222 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
224 const auto first = segment.
min() / scalar;
225 const auto second = segment.
max() / scalar;
226 return Segment<std::decay_t<
decltype(first)>, LabelType>(first, second);
229template <
class Po
intType,
class LabelType>
234template <
class Po
intType,
class LabelType>
236 points_[0].rotate90(k);
237 points_[1].rotate90(k);
238 if (points_[1] < points_[0]) std::swap(points_[0], points_[1]);
241template <
class Po
intType,
class LabelType>
242template <
class OtherNumber>
247template <
class Po
intType,
class LabelType>
248template <
class OtherNumber>
250 points_[0].scaleUpX(scalar);
251 points_[1].scaleUpX(scalar);
252 if (points_[1] < points_[0]) std::swap(points_[0], points_[1]);
255template <
class Po
intType,
class LabelType>
256template <
class OtherNumber>
261template <
class Po
intType,
class LabelType>
262template <
class OtherNumber>
264 points_[0].scaleUpY(scalar);
265 points_[1].scaleUpY(scalar);
266 if (points_[1] < points_[0]) std::swap(points_[0], points_[1]);
269template <
class Po
intType,
class LabelType>
270template <
class OtherNumber>
275template <
class Po
intType,
class LabelType>
276template <
class OtherNumber>
278 points_[0].scaleDownX(scalar);
279 points_[1].scaleDownX(scalar);
280 if (points_[1] < points_[0]) std::swap(points_[0], points_[1]);
283template <
class Po
intType,
class LabelType>
284template <
class OtherNumber>
289template <
class Po
intType,
class LabelType>
290template <
class OtherNumber>
292 points_[0].scaleDownY(scalar);
293 points_[1].scaleDownY(scalar);
294 if (points_[1] < points_[0]) std::swap(points_[0], points_[1]);
300template <
class Po
intType,
class LabelType>
301template<Po
intConcept OtherPo
int>
308template <
class Po
intType,
class LabelType>
309template<Po
intConcept OtherPo
int>
316template <
class Po
intType,
class LabelType>
317template <
class Scalar>
325template <
class Po
intType,
class LabelType>
326template <
class Scalar>
334template <
class Po
intType,
class LabelType,
class TranslationNumber,
class TranslationLabel>
336 const auto first = segment.
source() - translation;
337 const auto second = segment.
target() - translation;
338 return OrientedSegment<std::decay_t<
decltype(first)>, LabelType>(first, second);
341template <
class Po
intType,
class LabelType,
class Scalar>
342 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
344 const auto first = segment.
source() * scalar;
345 const auto second = segment.
target() * scalar;
346 return OrientedSegment<std::decay_t<
decltype(first)>, LabelType>(first, second);
349template <
class Scalar,
class Po
intType,
class LabelType>
350 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
352 return segment * scalar;
355template <
class Po
intType,
class LabelType,
class Scalar>
356 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
358 const auto first = segment.
source() / scalar;
359 const auto second = segment.
target() / scalar;
360 return OrientedSegment<std::decay_t<
decltype(first)>, LabelType>(first, second);
363template <
class Po
intType,
class LabelType>
368template <
class Po
intType,
class LabelType>
374template <
class Po
intType,
class LabelType>
375template <
class OtherNumber>
380template <
class Po
intType,
class LabelType>
381template <
class OtherNumber>
387template <
class Po
intType,
class LabelType>
388template <
class OtherNumber>
393template <
class Po
intType,
class LabelType>
394template <
class OtherNumber>
400template <
class Po
intType,
class LabelType>
401template <
class OtherNumber>
406template <
class Po
intType,
class LabelType>
407template <
class OtherNumber>
413template <
class Po
intType,
class LabelType>
414template <
class OtherNumber>
419template <
class Po
intType,
class LabelType>
420template <
class OtherNumber>
429template <
class Po
intType,
class LabelType>
430template<Po
intConcept OtherPo
int>
432 points_[0] += translation;
433 points_[1] += translation;
437template <
class Po
intType,
class LabelType>
438template<Po
intConcept OtherPo
int>
440 points_[0] -= translation;
441 points_[1] -= translation;
445template <
class Po
intType,
class LabelType>
446template <
class Scalar>
449 points_[0] *= scalar;
450 points_[1] *= scalar;
451 if (points_[1] < points_[0]) std::swap(points_[0], points_[1]);
455template <
class Po
intType,
class LabelType>
456template <
class Scalar>
459 points_[0] /= scalar;
460 points_[1] /= scalar;
461 if (points_[1] < points_[0]) std::swap(points_[0], points_[1]);
465template <
class Po
intType,
class LabelType,
class TranslationNumber,
class TranslationLabel>
467 const auto first = line.
min() - translation;
468 const auto second = line.
max() - translation;
469 return Line<std::decay_t<
decltype(first)>, LabelType>(first, second);
472template <
class Po
intType,
class LabelType,
class Scalar>
473 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
475 const auto first = line.
min() * scalar;
476 const auto second = line.
max() * scalar;
477 return Line<std::decay_t<
decltype(first)>, LabelType>(first, second);
480template <
class Scalar,
class Po
intType,
class LabelType>
481 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
483 return line * scalar;
486template <
class Po
intType,
class LabelType,
class Scalar>
487 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
489 const auto first = line.
min() / scalar;
490 const auto second = line.
max() / scalar;
491 return Line<std::decay_t<
decltype(first)>, LabelType>(first, second);
494template <
class Po
intType,
class LabelType>
499template <
class Po
intType,
class LabelType>
504template <
class Po
intType,
class LabelType>
509template <
class Po
intType,
class LabelType>
511 points_[0].rotate90(k);
512 points_[1].rotate90(k);
513 if (points_[1] < points_[0]) std::swap(points_[0], points_[1]);
516template <
class Po
intType,
class LabelType>
517template <
class OtherNumber>
522template <
class Po
intType,
class LabelType>
523template <
class OtherNumber>
525 points_[0].scaleUpX(scalar);
526 points_[1].scaleUpX(scalar);
527 if (points_[1] < points_[0]) std::swap(points_[0], points_[1]);
530template <
class Po
intType,
class LabelType>
531template <
class OtherNumber>
536template <
class Po
intType,
class LabelType>
537template <
class OtherNumber>
539 points_[0].scaleUpY(scalar);
540 points_[1].scaleUpY(scalar);
541 if (points_[1] < points_[0]) std::swap(points_[0], points_[1]);
544template <
class Po
intType,
class LabelType>
545template <
class OtherNumber>
550template <
class Po
intType,
class LabelType>
551template <
class OtherNumber>
553 points_[0].scaleDownX(scalar);
554 points_[1].scaleDownX(scalar);
555 if (points_[1] < points_[0]) std::swap(points_[0], points_[1]);
558template <
class Po
intType,
class LabelType>
559template <
class OtherNumber>
564template <
class Po
intType,
class LabelType>
565template <
class OtherNumber>
567 points_[0].scaleDownY(scalar);
568 points_[1].scaleDownY(scalar);
569 if (points_[1] < points_[0]) std::swap(points_[0], points_[1]);
575template <
class Po
intType,
class LabelType>
580template <
class Po
intType,
class LabelType>
581template<Po
intConcept OtherPo
int>
583 points_[0] += translation;
584 points_[1] += translation;
588template <
class Po
intType,
class LabelType>
589template<Po
intConcept OtherPo
int>
591 points_[0] -= translation;
592 points_[1] -= translation;
596template <
class Po
intType,
class LabelType>
597template <
class Scalar>
600 points_[0] *= scalar;
601 points_[1] *= scalar;
605template <
class Po
intType,
class LabelType>
606template <
class Scalar>
609 points_[0] /= scalar;
610 points_[1] /= scalar;
614template <
class Po
intType,
class LabelType,
class TranslationNumber,
class TranslationLabel>
616 const auto first = line.
source() - translation;
617 const auto second = line.
target() - translation;
618 return OrientedLine<std::decay_t<
decltype(first)>, LabelType>(first, second);
621template <
class Po
intType,
class LabelType,
class Scalar>
622 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
624 const auto first = line.
source() * scalar;
625 const auto second = line.
target() * scalar;
626 return OrientedLine<std::decay_t<
decltype(first)>, LabelType>(first, second);
629template <
class Scalar,
class Po
intType,
class LabelType>
630 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
632 return line * scalar;
635template <
class Po
intType,
class LabelType,
class Scalar>
636 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
638 const auto first = line.
source() / scalar;
639 const auto second = line.
target() / scalar;
640 return OrientedLine<std::decay_t<
decltype(first)>, LabelType>(first, second);
643template <
class Po
intType,
class LabelType>
648template <
class Po
intType,
class LabelType>
653template <
class Po
intType,
class LabelType>
658template <
class Po
intType,
class LabelType>
660 points_[0].rotate90(k);
661 points_[1].rotate90(k);
664template <
class Po
intType,
class LabelType>
665template <
class OtherNumber>
670template <
class Po
intType,
class LabelType>
671template <
class OtherNumber>
673 points_[0].scaleUpX(scalar);
674 points_[1].scaleUpX(scalar);
677template <
class Po
intType,
class LabelType>
678template <
class OtherNumber>
683template <
class Po
intType,
class LabelType>
684template <
class OtherNumber>
686 points_[0].scaleUpY(scalar);
687 points_[1].scaleUpY(scalar);
690template <
class Po
intType,
class LabelType>
691template <
class OtherNumber>
696template <
class Po
intType,
class LabelType>
697template <
class OtherNumber>
699 points_[0].scaleDownX(scalar);
700 points_[1].scaleDownX(scalar);
703template <
class Po
intType,
class LabelType>
704template <
class OtherNumber>
709template <
class Po
intType,
class LabelType>
710template <
class OtherNumber>
712 points_[0].scaleDownY(scalar);
713 points_[1].scaleDownY(scalar);
730inline constexpr int integralLinePartBits = 12;
743template <
class Working>
744std::optional<std::array<Working, 4>> integralLinePoints(
const std::array<Working, 8>& parts) {
745 const auto& [sourceXNum, sourceXDen, sourceYNum, sourceYDen,
746 targetXNum, targetXDen, targetYNum, targetYDen] = parts;
758 const Working deltaXNum = targetXNum * sourceXDen - sourceXNum * targetXDen;
759 const Working deltaXDen = targetXDen * sourceXDen;
760 const Working deltaYNum = targetYNum * sourceYDen - sourceYNum * targetYDen;
761 const Working deltaYDen = targetYDen * sourceYDen;
762 Working directionX = deltaXNum * deltaYDen;
763 Working directionY = deltaYNum * deltaXDen;
764 const Working scale = gcd(
abs(directionX),
abs(directionY));
765 if (scale == Working(0)) {
768 directionX = directionX / scale;
769 directionY = directionY / scale;
777 const Working offsetNum = directionY * sourceXNum * sourceYDen
778 - directionX * sourceYNum * sourceXDen;
779 const Working offsetDen = sourceXDen * sourceYDen;
780 if (offsetNum % offsetDen != Working(0)) {
783 const Working offset = offsetNum / offsetDen;
788 const auto bezout = extendedGcd(directionY, -directionX);
789 Working
x = bezout[1] * offset;
790 Working
y = bezout[2] * offset;
796 if (abs(directionX) >= abs(directionY)) {
798 y = (directionY *
x - offset) / directionX;
801 x = (directionX *
y + offset) / directionY;
807 const Working steps = nearestQuotient(
808 -(
x * directionX +
y * directionY),
809 directionX * directionX + directionY * directionY);
810 x =
x + steps * directionX;
811 y =
y + steps * directionY;
818 const Working previousX =
x - directionX;
819 const Working previousY =
y - directionY;
820 if (previousX * previousX + previousY * previousY ==
x *
x +
y *
y
821 && (previousX <
x || (previousX ==
x && previousY <
y))) {
826 return std::array<Working, 4>{
x,
y,
x + directionX,
y + directionY};
835template <
class Po
intType_,
class TLabel>
836template <
class ResultNumber>
838 && (detail::extended_integral<ResultNumber> || std::same_as<ResultNumber, BigInt>))
852 const std::array<Integer, 8> parts{sourceX.numerator(), sourceX.denominator(),
853 sourceY.numerator(), sourceY.denominator(),
854 targetX.numerator(), targetX.denominator(),
855 targetY.numerator(), targetY.denominator()};
860 const auto partsFitNarrow = [&] {
861 if constexpr (detail::numeric_limits<Integer>::digits <= detail::integralLinePartBits) {
864 const Integer bound = Integer(1) << detail::integralLinePartBits;
865 for (
const Integer& part : parts) {
866 if (part >= bound || part <= -bound) {
874 const auto widened = [&]<
class Working>(std::type_identity<Working>) {
875 std::array<Working, 8> result;
876 for (std::size_t i = 0; i < parts.size(); ++i) {
877 result[i] = Working(parts[i]);
886 const auto asLineOverResult = [&](
const auto& points) -> std::optional<Result> {
887 using Working =
typename std::remove_cvref_t<
decltype(points)>::value_type;
888 for (
const Working& coordinate : points) {
889 if (!detail::representableAs<ResultNumber>(coordinate)) {
893 Result line(ResultPoint(detail::narrowTo<ResultNumber>(points[0]),
894 detail::narrowTo<ResultNumber>(points[1])),
895 ResultPoint(detail::narrowTo<ResultNumber>(points[2]),
896 detail::narrowTo<ResultNumber>(points[3])));
897 if constexpr (detail::has_label_v<LabelType>) {
898 line.label() =
label();
908 if constexpr (detail::arbitraryPrecision<Integer>) {
909 const auto points = detail::integralLinePoints(parts);
910 return points ? asLineOverResult(*points) : std::nullopt;
912 if (partsFitNarrow()) {
913 const auto points = detail::integralLinePoints(widened(std::type_identity<pgl::int128>{}));
914 return points ? asLineOverResult(*points) : std::nullopt;
916 const auto points = detail::integralLinePoints(widened(std::type_identity<BigInt>{}));
917 return points ? asLineOverResult(*points) : std::nullopt;
924template <
class Po
intType,
class LabelType>
929template <
class Po
intType,
class LabelType>
934template <
class Po
intType,
class LabelType>
935template<Po
intConcept OtherPo
int>
937 points_[0] += translation;
938 points_[1] += translation;
942template <
class Po
intType,
class LabelType>
943template<Po
intConcept OtherPo
int>
945 points_[0] -= translation;
946 points_[1] -= translation;
950template <
class Po
intType,
class LabelType>
951template <
class Scalar>
954 points_[0] *= scalar;
955 points_[1] *= scalar;
959template <
class Po
intType,
class LabelType>
960template <
class Scalar>
963 points_[0] /= scalar;
964 points_[1] /= scalar;
968template <
class Po
intType,
class LabelType,
class TranslationNumber,
class TranslationLabel>
970 const auto first = ray.
source() - translation;
971 const auto second = ray.
target() - translation;
972 return Ray<std::decay_t<
decltype(first)>, LabelType>(first, second);
975template <
class Po
intType,
class LabelType,
class Scalar>
976 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
978 const auto first = ray.
source() * scalar;
979 const auto second = ray.
target() * scalar;
980 return Ray<std::decay_t<
decltype(first)>, LabelType>(first, second);
983template <
class Scalar,
class Po
intType,
class LabelType>
984 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
989template <
class Po
intType,
class LabelType,
class Scalar>
990 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
992 const auto first = ray.
source() / scalar;
993 const auto second = ray.
target() / scalar;
994 return Ray<std::decay_t<
decltype(first)>, LabelType>(first, second);
997template <
class Po
intType,
class LabelType>
1002template <
class Po
intType,
class LabelType>
1007template <
class Po
intType,
class LabelType>
1009 points_[0].rotate90(k);
1010 points_[1].rotate90(k);
1013template <
class Po
intType,
class LabelType>
1014template <
class OtherNumber>
1019template <
class Po
intType,
class LabelType>
1020template <
class OtherNumber>
1022 points_[0].scaleUpX(scalar);
1023 points_[1].scaleUpX(scalar);
1026template <
class Po
intType,
class LabelType>
1027template <
class OtherNumber>
1032template <
class Po
intType,
class LabelType>
1033template <
class OtherNumber>
1035 points_[0].scaleUpY(scalar);
1036 points_[1].scaleUpY(scalar);
1039template <
class Po
intType,
class LabelType>
1040template <
class OtherNumber>
1045template <
class Po
intType,
class LabelType>
1046template <
class OtherNumber>
1048 points_[0].scaleDownX(scalar);
1049 points_[1].scaleDownX(scalar);
1052template <
class Po
intType,
class LabelType>
1053template <
class OtherNumber>
1058template <
class Po
intType,
class LabelType>
1059template <
class OtherNumber>
1061 points_[0].scaleDownY(scalar);
1062 points_[1].scaleDownY(scalar);
1068template <
class Po
intType,
class LabelType>
1069template<Po
intConcept OtherPo
int>
1075 points_[0] += translation;
1076 points_[1] += translation;
1080template <
class Po
intType,
class LabelType>
1081template<Po
intConcept OtherPo
int>
1087 points_[0] -= translation;
1088 points_[1] -= translation;
1092template <
class Po
intType,
class LabelType>
1093template <
class Scalar>
1096 auto saved = label_;
1097 *
this = *
this * scalar;
1098 label_ = std::move(saved);
1102template <
class Po
intType,
class LabelType>
1103template <
class Scalar>
1106 auto saved = label_;
1107 *
this = *
this / scalar;
1108 label_ = std::move(saved);
1112template <
class Po
intType,
class LabelType,
class TranslationNumber,
class TranslationLabel>
1114 const auto first = rectangle.
min() - translation;
1115 using ResultRectangle =
Rectangle<std::decay_t<
decltype(first)>, LabelType>;
1116 if (rectangle.
empty()) {
1118 return ResultRectangle();
1120 const auto second = rectangle.
max() - translation;
1121 return ResultRectangle(first, second);
1124template <
class Po
intType,
class LabelType,
class Scalar>
1125 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
1127 const auto first = rectangle.
min() * scalar;
1128 using ResultRectangle =
Rectangle<std::decay_t<
decltype(first)>, LabelType>;
1129 if (rectangle.
empty()) {
1131 return ResultRectangle();
1133 const auto second = rectangle.
max() * scalar;
1134 return ResultRectangle(first, second);
1137template <
class Scalar,
class Po
intType,
class LabelType>
1138 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
1140 return rectangle * scalar;
1143template <
class Po
intType,
class LabelType,
class Scalar>
1144 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
1146 const auto first = rectangle.
min() / scalar;
1147 using ResultRectangle =
Rectangle<std::decay_t<
decltype(first)>, LabelType>;
1148 if (rectangle.
empty()) {
1150 return ResultRectangle();
1152 const auto second = rectangle.
max() / scalar;
1153 return ResultRectangle(first, second);
1156template <
class Po
intType,
class LabelType>
1165template <
class Po
intType,
class LabelType>
1167 auto saved = label_;
1169 label_ = std::move(saved);
1172template <
class Po
intType,
class LabelType>
1173template <
class OtherNumber>
1182template <
class Po
intType,
class LabelType>
1183template <
class OtherNumber>
1185 auto saved = label_;
1187 label_ = std::move(saved);
1190template <
class Po
intType,
class LabelType>
1191template <
class OtherNumber>
1200template <
class Po
intType,
class LabelType>
1201template <
class OtherNumber>
1203 auto saved = label_;
1205 label_ = std::move(saved);
1208template <
class Po
intType,
class LabelType>
1209template <
class OtherNumber>
1218template <
class Po
intType,
class LabelType>
1219template <
class OtherNumber>
1221 auto saved = label_;
1223 label_ = std::move(saved);
1226template <
class Po
intType,
class LabelType>
1227template <
class OtherNumber>
1236template <
class Po
intType,
class LabelType>
1237template <
class OtherNumber>
1239 auto saved = label_;
1241 label_ = std::move(saved);
1247template <
class Po
intType,
class LabelType>
1248template<Po
intConcept OtherPo
int>
1250 points_[0] += translation;
1251 points_[1] += translation;
1252 points_[2] += translation;
1257template <
class Po
intType,
class LabelType>
1258template<Po
intConcept OtherPo
int>
1260 points_[0] -= translation;
1261 points_[1] -= translation;
1262 points_[2] -= translation;
1267template <
class Po
intType,
class LabelType>
1268template <
class Scalar>
1271 points_[0] *= scalar;
1272 points_[1] *= scalar;
1273 points_[2] *= scalar;
1278template <
class Po
intType,
class LabelType>
1279template <
class Scalar>
1282 points_[0] /= scalar;
1283 points_[1] /= scalar;
1284 points_[2] /= scalar;
1289template <
class Po
intType,
class LabelType,
class TranslationNumber,
class TranslationLabel>
1291 const auto first = triangle.
a() - translation;
1292 const auto second = triangle.
b() - translation;
1293 const auto third = triangle.
c() - translation;
1294 return Triangle<std::decay_t<
decltype(first)>, LabelType>(first, second, third);
1297template <
class Po
intType,
class LabelType,
class Scalar>
1300 const auto first = triangle.
a() * scalar;
1301 const auto second = triangle.
b() * scalar;
1302 const auto third = triangle.
c() * scalar;
1303 return Triangle<std::decay_t<
decltype(first)>, LabelType>(first, second, third);
1306template <
class Scalar,
class Po
intType,
class LabelType>
1307 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
1309 return triangle * scalar;
1312template <
class Po
intType,
class LabelType,
class Scalar>
1313 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
1315 const auto first = triangle.
a() / scalar;
1316 const auto second = triangle.
b() / scalar;
1317 const auto third = triangle.
c() / scalar;
1318 return Triangle<std::decay_t<
decltype(first)>,
LabelType>(first, second, third);
1321template <
class Po
intType,
class LabelType>
1326template <
class Po
intType,
class LabelType>
1328 auto saved = label_;
1330 label_ = std::move(saved);
1333template <
class Po
intType,
class LabelType>
1334template <
class OtherNumber>
1339template <
class Po
intType,
class LabelType>
1340template <
class OtherNumber>
1342 auto saved = label_;
1344 label_ = std::move(saved);
1347template <
class Po
intType,
class LabelType>
1348template <
class OtherNumber>
1353template <
class Po
intType,
class LabelType>
1354template <
class OtherNumber>
1356 auto saved = label_;
1358 label_ = std::move(saved);
1361template <
class Po
intType,
class LabelType>
1362template <
class OtherNumber>
1367template <
class Po
intType,
class LabelType>
1368template <
class OtherNumber>
1370 auto saved = label_;
1372 label_ = std::move(saved);
1375template <
class Po
intType,
class LabelType>
1376template <
class OtherNumber>
1381template <
class Po
intType,
class LabelType>
1382template <
class OtherNumber>
1384 auto saved = label_;
1386 label_ = std::move(saved);
1392template <
class Po
intType,
class LabelType>
1393template<Po
intConcept OtherPo
int>
1395 points_[0] += translation;
1396 points_[1] += translation;
1400template <
class Po
intType,
class LabelType>
1401template<Po
intConcept OtherPo
int>
1403 points_[0] -= translation;
1404 points_[1] -= translation;
1408template <
class Po
intType,
class LabelType>
1409template <
class Scalar>
1412 points_[0] *= scalar;
1413 points_[1] *= scalar;
1417template <
class Po
intType,
class LabelType>
1418template <
class Scalar>
1421 points_[0] /= scalar;
1422 points_[1] /= scalar;
1426template <
class Po
intType,
class LabelType,
class TranslationNumber,
class TranslationLabel>
1428 const auto first = halfplane.
source() - translation;
1429 const auto second = halfplane.
target() - translation;
1430 return Halfplane<std::decay_t<
decltype(first)>, LabelType>(first, second);
1433template <
class Po
intType,
class LabelType,
class Scalar>
1434 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
1436 const auto first = halfplane.
source() * scalar;
1437 const auto second = halfplane.
target() * scalar;
1438 return Halfplane<std::decay_t<
decltype(first)>, LabelType>(first, second);
1441template <
class Scalar,
class Po
intType,
class LabelType>
1442 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
1444 return halfplane * scalar;
1447template <
class Po
intType,
class LabelType,
class Scalar>
1448 requires(!detail::is_point_v<Scalar> && !TransformationConcept<Scalar>)
1450 const auto first = halfplane.
source() / scalar;
1451 const auto second = halfplane.
target() / scalar;
1452 return Halfplane<std::decay_t<
decltype(first)>, LabelType>(first, second);
1456template <
class Po
intType,
class LabelType>
1461template <
class Po
intType,
class LabelType>
1463 auto saved = label_;
1465 label_ = std::move(saved);
1468template <
class Po
intType,
class LabelType>
1469template <
class OtherNumber>
1473 if (scalar < OtherNumber{})
1478template <
class Po
intType,
class LabelType>
1479template <
class OtherNumber>
1481 auto saved = label_;
1483 label_ = std::move(saved);
1486template <
class Po
intType,
class LabelType>
1487template <
class OtherNumber>
1491 if (scalar < OtherNumber{})
1496template <
class Po
intType,
class LabelType>
1497template <
class OtherNumber>
1499 auto saved = label_;
1501 label_ = std::move(saved);
1504template <
class Po
intType,
class LabelType>
1505template <
class OtherNumber>
1509 if (scalar < OtherNumber{})
1514template <
class Po
intType,
class LabelType>
1515template <
class OtherNumber>
1517 auto saved = label_;
1519 label_ = std::move(saved);
1522template <
class Po
intType,
class LabelType>
1523template <
class OtherNumber>
1527 if (scalar < OtherNumber{})
1532template <
class Po
intType,
class LabelType>
1533template <
class OtherNumber>
1535 auto saved = label_;
1537 label_ = std::move(saved);
1543template <
class Po
intType,
class LabelType>
1544template<Po
intConcept OtherPo
int>
1546 translation_ += translation;
1551 if (!bbox_.empty()) {
1552 bbox_ += translation;
1558template <
class Po
intType,
class LabelType>
1559template<Po
intConcept OtherPo
int>
1561 translation_ -= translation;
1562 if (!bbox_.empty()) {
1563 bbox_ -= translation;
1580template <
class Po
intType,
class LabelType>
1581template <
class Scalar>
1584 std::vector<PointType> scaled;
1585 scaled.reserve(
size());
1589 scaled.push_back(std::move(moved));
1591 auto saved = label_;
1592 *
this =
Convex(std::move(scaled));
1593 label_ = std::move(saved);
1600template <
class Po
intType,
class LabelType>
1601template <
class Scalar>
1604 std::vector<PointType> scaled;
1605 scaled.reserve(
size());
1609 scaled.push_back(std::move(moved));
1611 auto saved = label_;
1612 *
this =
Convex(std::move(scaled));
1613 label_ = std::move(saved);
1617template <
class Po
intType,
class LabelType>
1619 std::vector<PointType> pts;
1620 pts.reserve(
size());
1621 for (
const auto& p : *
this) {
1622 pts.push_back(p.rotated90(k));
1624 return Convex(std::move(pts));
1627template <
class Po
intType,
class LabelType>
1629 auto saved = label_;
1631 label_ = std::move(saved);
1634template <
class Po
intType,
class LabelType>
1635template <
class OtherNumber>
1637 std::vector<PointType> pts;
1638 pts.reserve(
size());
1639 for (
const auto& p : *
this) {
1640 pts.push_back(p.scaledUpX(scalar));
1642 return Convex(std::move(pts));
1645template <
class Po
intType,
class LabelType>
1646template <
class OtherNumber>
1648 auto saved = label_;
1650 label_ = std::move(saved);
1653template <
class Po
intType,
class LabelType>
1654template <
class OtherNumber>
1656 std::vector<PointType> pts;
1657 pts.reserve(
size());
1658 for (
const auto& p : *
this) {
1659 pts.push_back(p.scaledUpY(scalar));
1661 return Convex(std::move(pts));
1664template <
class Po
intType,
class LabelType>
1665template <
class OtherNumber>
1667 auto saved = label_;
1669 label_ = std::move(saved);
1672template <
class Po
intType,
class LabelType>
1673template <
class OtherNumber>
1675 std::vector<PointType> pts;
1676 pts.reserve(
size());
1677 for (
const auto& p : *
this) {
1678 pts.push_back(p.scaledDownX(scalar));
1680 return Convex(std::move(pts));
1683template <
class Po
intType,
class LabelType>
1684template <
class OtherNumber>
1686 auto saved = label_;
1688 label_ = std::move(saved);
1691template <
class Po
intType,
class LabelType>
1692template <
class OtherNumber>
1694 std::vector<PointType> pts;
1695 pts.reserve(
size());
1696 for (
const auto& p : *
this) {
1697 pts.push_back(p.scaledDownY(scalar));
1699 return Convex(std::move(pts));
1702template <
class Po
intType,
class LabelType>
1703template <
class OtherNumber>
1705 auto saved = label_;
1707 label_ = std::move(saved);
1713template <
class Po
intType,
class LabelType>
1715 std::vector<PointType> pts;
1716 pts.reserve(
size());
1717 for (
const auto& p : *
this) {
1718 pts.push_back(p.rotated90(k));
1720 return Polygon(std::move(pts));
1723template <
class Po
intType,
class LabelType>
1725 auto saved = label_;
1727 label_ = std::move(saved);
1730template <
class Po
intType,
class LabelType>
1732 if (!std::is_constant_evaluated()) {
1741 const auto edge = [
this](std::ptrdiff_t a) {
1742 const std::ptrdiff_t n =
static_cast<std::ptrdiff_t
>(points_.size());
1744 points_[
static_cast<std::size_t
>((a + 1) % n)]);
1747 while (points_.size() >= 3) {
1748 const std::ptrdiff_t n =
static_cast<std::ptrdiff_t
>(points_.size());
1753 bool flipped =
false;
1754 for (std::ptrdiff_t i = 0; i < n && !flipped; ++i) {
1755 for (std::ptrdiff_t j = i + 1; j < n; ++j) {
1756 const bool adjacent = (j == i + 1) || (i == 0 && j == n - 1);
1761 std::reverse(points_.begin() + (i + 1), points_.begin() + (j + 1));
1775 bool removed =
false;
1776 for (std::ptrdiff_t k = 0; k < n && !removed; ++k) {
1777 if (points_[
static_cast<std::size_t
>(k)] ==
1778 points_[
static_cast<std::size_t
>((k + 1) % n)]) {
1779 points_.erase(points_.begin() + k);
1783 for (std::ptrdiff_t e = 0; e < n; ++e) {
1784 if (e == k || e == (k - 1 + n) % n) {
1787 if (
edge(e).
contains(points_[
static_cast<std::size_t
>(k)])) {
1788 points_.erase(points_.begin() + k);
1803template <
class Po
intType,
class LabelType>
1804template <
class OtherNumber>
1806 std::vector<PointType> pts;
1807 pts.reserve(
size());
1808 for (
const auto& p : *
this) {
1809 pts.push_back(p.scaledUpX(scalar));
1811 return Polygon(std::move(pts));
1814template <
class Po
intType,
class LabelType>
1815template <
class OtherNumber>
1817 auto saved = label_;
1819 label_ = std::move(saved);
1822template <
class Po
intType,
class LabelType>
1823template <
class OtherNumber>
1825 std::vector<PointType> pts;
1826 pts.reserve(
size());
1827 for (
const auto& p : *
this) {
1828 pts.push_back(p.scaledUpY(scalar));
1830 return Polygon(std::move(pts));
1833template <
class Po
intType,
class LabelType>
1834template <
class OtherNumber>
1836 auto saved = label_;
1838 label_ = std::move(saved);
1841template <
class Po
intType,
class LabelType>
1842template <
class OtherNumber>
1844 std::vector<PointType> pts;
1845 pts.reserve(
size());
1846 for (
const auto& p : *
this) {
1847 pts.push_back(p.scaledDownX(scalar));
1849 return Polygon(std::move(pts));
1852template <
class Po
intType,
class LabelType>
1853template <
class OtherNumber>
1855 auto saved = label_;
1857 label_ = std::move(saved);
1860template <
class Po
intType,
class LabelType>
1861template <
class OtherNumber>
1863 std::vector<PointType> pts;
1864 pts.reserve(
size());
1865 for (
const auto& p : *
this) {
1866 pts.push_back(p.scaledDownY(scalar));
1868 return Polygon(std::move(pts));
1871template <
class Po
intType,
class LabelType>
1872template <
class OtherNumber>
1874 auto saved = label_;
1876 label_ = std::move(saved);
1887template <
class Po
intType,
class LabelType,
class Storage>
1889 std::vector<PointType> pts;
1890 pts.reserve(
size());
1891 for (
const auto& p : *
this) {
1892 pts.push_back(p.rotated90(k));
1897template <
class Po
intType,
class LabelType,
class Storage>
1899 requires detail::ownsChainStorage<Storage, PointType> {
1900 auto saved = label_;
1902 label_ = std::move(saved);
1905template <
class Po
intType,
class LabelType,
class Storage>
1906template <
class OtherNumber>
1908 std::vector<PointType> pts;
1909 pts.reserve(
size());
1910 for (
const auto& p : *
this) {
1911 pts.push_back(p.scaledUpX(scalar));
1916template <
class Po
intType,
class LabelType,
class Storage>
1917template <
class OtherNumber>
1919 requires detail::ownsChainStorage<Storage, PointType> {
1920 auto saved = label_;
1922 label_ = std::move(saved);
1925template <
class Po
intType,
class LabelType,
class Storage>
1926template <
class OtherNumber>
1928 std::vector<PointType> pts;
1929 pts.reserve(
size());
1930 for (
const auto& p : *
this) {
1931 pts.push_back(p.scaledUpY(scalar));
1936template <
class Po
intType,
class LabelType,
class Storage>
1937template <
class OtherNumber>
1939 requires detail::ownsChainStorage<Storage, PointType> {
1940 auto saved = label_;
1942 label_ = std::move(saved);
1945template <
class Po
intType,
class LabelType,
class Storage>
1946template <
class OtherNumber>
1948 std::vector<PointType> pts;
1949 pts.reserve(
size());
1950 for (
const auto& p : *
this) {
1951 pts.push_back(p.scaledDownX(scalar));
1956template <
class Po
intType,
class LabelType,
class Storage>
1957template <
class OtherNumber>
1959 requires detail::ownsChainStorage<Storage, PointType> {
1960 auto saved = label_;
1962 label_ = std::move(saved);
1965template <
class Po
intType,
class LabelType,
class Storage>
1966template <
class OtherNumber>
1968 std::vector<PointType> pts;
1969 pts.reserve(
size());
1970 for (
const auto& p : *
this) {
1971 pts.push_back(p.scaledDownY(scalar));
1976template <
class Po
intType,
class LabelType,
class Storage>
1977template <
class OtherNumber>
1979 requires detail::ownsChainStorage<Storage, PointType> {
1980 auto saved = label_;
1982 label_ = std::move(saved);
1993template <
class Po
intType,
class LabelType>
1995 std::vector<PointType> pts;
1996 pts.reserve(
size());
1997 for (
const auto& p : *
this) {
1998 pts.push_back(p.rotated90(k));
2003template <
class Po
intType,
class LabelType>
2005 auto saved = label_;
2007 label_ = std::move(saved);
2010template <
class Po
intType,
class LabelType>
2011template <
class OtherNumber>
2013 std::vector<PointType> pts;
2014 pts.reserve(
size());
2015 for (
const auto& p : *
this) {
2016 pts.push_back(p.scaledUpX(scalar));
2021template <
class Po
intType,
class LabelType>
2022template <
class OtherNumber>
2024 auto saved = label_;
2026 label_ = std::move(saved);
2029template <
class Po
intType,
class LabelType>
2030template <
class OtherNumber>
2032 std::vector<PointType> pts;
2033 pts.reserve(
size());
2034 for (
const auto& p : *
this) {
2035 pts.push_back(p.scaledUpY(scalar));
2040template <
class Po
intType,
class LabelType>
2041template <
class OtherNumber>
2043 auto saved = label_;
2045 label_ = std::move(saved);
2048template <
class Po
intType,
class LabelType>
2049template <
class OtherNumber>
2051 std::vector<PointType> pts;
2052 pts.reserve(
size());
2053 for (
const auto& p : *
this) {
2054 pts.push_back(p.scaledDownX(scalar));
2059template <
class Po
intType,
class LabelType>
2060template <
class OtherNumber>
2062 auto saved = label_;
2064 label_ = std::move(saved);
2067template <
class Po
intType,
class LabelType>
2068template <
class OtherNumber>
2070 std::vector<PointType> pts;
2071 pts.reserve(
size());
2072 for (
const auto& p : *
this) {
2073 pts.push_back(p.scaledDownY(scalar));
2078template <
class Po
intType,
class LabelType>
2079template <
class OtherNumber>
2081 auto saved = label_;
2083 label_ = std::move(saved);
2086template <
class Po
intType,
class LabelType>
2087template <SegmentConcept OldSegment, SegmentConcept NewSegment>
2088constexpr std::optional<std::vector<PointType>>
2089Polyline<PointType, LabelType>::flipVertices(
const OldSegment& oldEdge,
2090 const NewSegment& newEdge)
const {
2091 const std::size_t n = size();
2093 return std::nullopt;
2096 const PointType o0 = oldEdge[0];
2097 const PointType o1 = oldEdge[1];
2098 const PointType m0 = newEdge[0];
2099 const PointType m1 = newEdge[1];
2103 return std::nullopt;
2105 const auto sameSet = [](
const PointType& a,
const PointType& b,
const PointType& c,
2106 const PointType& d) {
2107 return (a == c && b == d) || (a == d && b == c);
2109 if (sameSet(o0, o1, m0, m1)) {
2110 return std::nullopt;
2113 const std::vector<PointType> v = vertices();
2114 for (std::size_t i = 0; i + 1 < n; ++i) {
2115 if (!sameSet(v[i], v[i + 1], o0, o1)) {
2119 std::vector<PointType> out;
2121 if (sameSet(m0, m1, v[i], v[n - 1])) {
2122 for (std::size_t k = 0; k <= i; ++k) {
2123 out.push_back(v[k]);
2125 for (std::size_t k = n; k-- > i + 1;) {
2126 out.push_back(v[k]);
2130 if (sameSet(m0, m1, v[0], v[i + 1])) {
2131 for (std::size_t k = i + 1; k-- > 0;) {
2132 out.push_back(v[k]);
2134 for (std::size_t k = i + 1; k < n; ++k) {
2135 out.push_back(v[k]);
2139 if (sameSet(m0, m1, v[0], v[n - 1])) {
2140 for (std::size_t k = i + 1; k-- > 0;) {
2141 out.push_back(v[k]);
2143 for (std::size_t k = n; k-- > i + 1;) {
2144 out.push_back(v[k]);
2151 return std::nullopt;
2154template <
class Po
intType,
class LabelType>
2155template <SegmentConcept OldSegment, SegmentConcept NewSegment>
2157 const NewSegment& newEdge)
const {
2158 return flipVertices(oldEdge, newEdge).has_value();
2161template <
class Po
intType,
class LabelType>
2162template <SegmentConcept OldSegment, SegmentConcept NewSegment>
2165 auto vertices = flipVertices(oldEdge, newEdge);
2170template <
class Po
intType,
class LabelType>
2171template <SegmentConcept OldSegment, SegmentConcept NewSegment>
2173 const NewSegment& newEdge) {
2174 auto saved = label_;
2175 *
this =
flipped(oldEdge, newEdge);
2176 label_ = std::move(saved);
2182template <
class Po
intType,
class LabelType>
2187template <
class Po
intType,
class LabelType>
2189 for (
auto& point : points_) {
2192 points_ = canonicalizePoints(points_[0], points_[1], points_[2]);
2198template <
class Number,
class ShapeT>
2203 const auto point = [&transformation](
const auto& p) {
2204 using PLabel =
typename std::decay_t<
decltype(p)>::LabelType;
2205 using PNumber =
typename std::decay_t<
decltype(p)>::NumberType;
2206 using ResultNumber = std::common_type_t<Number, PNumber>;
2208 transformation.
a() * p.x() + transformation.
b() * p.y() + transformation.
tx(),
2209 transformation.
c() * p.x() + transformation.
d() * p.y() + transformation.
ty());
2212 if constexpr (detail::is_empty_shape_v<ShapeT>) {
2213 using ResultNumber = std::common_type_t<Number, typename ShapeT::NumberType>;
2216 return point(shape);
2218 const auto first = point(shape.min());
2219 const auto second = point(shape.max());
2220 return Segment<std::decay_t<
decltype(first)>,
typename ShapeT::LabelType>(first, second);
2222 const auto first = point(shape.source());
2223 const auto second = point(shape.target());
2224 return OrientedSegment<std::decay_t<
decltype(first)>,
typename ShapeT::LabelType>(first, second);
2226 const auto first = point(shape.min());
2227 const auto second = point(shape.max());
2228 return Line<std::decay_t<
decltype(first)>,
typename ShapeT::LabelType>(first, second);
2234 const auto first = point(shape.source());
2235 const auto second = point(shape.target());
2236 return OrientedLine<std::decay_t<
decltype(first)>,
typename ShapeT::LabelType>(first, second);
2238 const auto first = point(shape.source());
2239 const auto second = point(shape.target());
2240 return Ray<std::decay_t<
decltype(first)>,
typename ShapeT::LabelType>(first, second);
2242 const auto first = point(shape.source());
2243 const auto second = point(shape.target());
2244 using ResultPoint = std::decay_t<
decltype(first)>;
2256 const auto pa = point(shape.a());
2257 const auto pb = point(shape.b());
2258 const auto pc = point(shape.c());
2259 return Triangle<std::decay_t<
decltype(pa)>,
typename ShapeT::LabelType>(pa, pb, pc);
2265 using ResultPoint =
decltype(point(std::declval<typename ShapeT::PointType>()));
2266 std::vector<ResultPoint> pts;
2267 pts.reserve(shape.size());
2268 for (
const auto& p : shape) {
2269 pts.push_back(point(p));
2275 using ResultPoint =
decltype(point(std::declval<typename ShapeT::PointType>()));
2276 std::vector<ResultPoint> pts;
2277 pts.reserve(shape.size());
2278 for (
const auto& p : shape) {
2279 pts.push_back(point(p));
2287 using ResultPoint =
decltype(point(std::declval<typename ShapeT::PointType>()));
2288 std::vector<ResultPoint> pts;
2289 pts.reserve(shape.size());
2290 for (
const auto& p : shape) {
2291 pts.push_back(point(p));
2298 using ResultPoint =
decltype(point(std::declval<typename ShapeT::PointType>()));
2299 std::vector<ResultPoint> pts;
2300 pts.reserve(shape.size());
2301 for (
const auto& p : shape) {
2302 pts.push_back(point(p));
2310 using ResultPoint =
decltype(point(std::declval<typename ShapeT::PointType>()));
2312 const auto ring = [&point](
const auto& source) {
2313 std::vector<ResultPoint> pts;
2314 pts.reserve(source.size());
2315 for (
const auto& p : source) {
2316 pts.push_back(point(p));
2318 return ResultPolygon(std::move(pts));
2321 std::vector<ResultPolygon> holes;
2322 holes.reserve(shape.holeCount());
2323 for (
const auto& hole : shape.holes()) {
2324 holes.push_back(ring(hole));
2327 ring(shape.outer()), std::move(holes));
2333 using ResultPoint =
decltype(point(std::declval<typename ShapeT::PointType>()));
2335 const auto ring = [&point](
const auto& source) {
2336 std::vector<ResultPoint> pts;
2337 pts.reserve(source.size());
2338 for (
const auto& p : source) {
2339 pts.push_back(point(p));
2344 std::vector<ResultRegion> components;
2345 components.reserve(shape.componentCount());
2346 for (
const auto& component : shape) {
2347 std::vector<Polygon<ResultPoint>> holes;
2348 holes.reserve(component.holeCount());
2349 for (
const auto& hole : component.holes()) {
2350 holes.push_back(ring(hole));
2352 components.emplace_back(ring(component.outer()), std::move(holes));
2361 using ResultPoint =
decltype(point(std::declval<typename ShapeT::PointType>()));
2363 using ResultHalfplane =
typename ResultRegion::HalfplaneType;
2364 if (shape.empty()) {
2365 ResultRegion result;
2366 result.insert(ResultHalfplane(ResultPoint(0, 0), ResultPoint(0, 1)));
2367 result.insert(ResultHalfplane(ResultPoint(1, 1), ResultPoint(1, 0)));
2370 const bool reflecting =
2372 std::vector<ResultHalfplane> mapped;
2373 mapped.reserve(shape.size());
2374 for (
const auto& halfplane : shape) {
2375 const auto first = point(halfplane.
source());
2376 const auto second = point(halfplane.
target());
2377 mapped.push_back(reflecting ? ResultHalfplane(second, first)
2378 : ResultHalfplane(first, second));
2380 return ResultRegion(mapped);
2384template <
class Number, ShapeConcept ShapeT>
2386 using PointType =
typename ShapeT::PointType_;
2387 using ResultNumber = std::common_type_t<Number, typename PointType::NumberType>;
2390 [&transformation](
const auto& value) -> ResultShape {
2391 if constexpr (
requires { transformation * value; }) {
2392 return ResultShape(transformation * value);
2394 throw std::logic_error(
2395 "Transformation::operator* is not defined for the Rectangle/Disk alternative");
2412template <
class Po
intType,
class LabelType>
2413template <Po
intConcept OtherPo
int>
2416 for (
auto& halfplane : halfplanes_) {
2417 halfplane += translation;
2423template <
class Po
intType,
class LabelType>
2424template <Po
intConcept OtherPo
int>
2427 for (
auto& halfplane : halfplanes_) {
2428 halfplane -= translation;
2434template <
class Po
intType,
class LabelType>
2435template <
class Scalar>
2439 for (
auto& halfplane : halfplanes_) {
2440 halfplane *= scalar;
2442 canonicalizeSorted();
2446template <
class Po
intType,
class LabelType>
2447template <
class Scalar>
2451 for (
auto& halfplane : halfplanes_) {
2452 halfplane /= scalar;
2454 canonicalizeSorted();
2458template <
class Po
intType,
class LabelType>
2466template <
class Po
intType,
class LabelType>
2468 for (
auto& halfplane : halfplanes_) {
2471 canonicalizeSorted();
2474template <
class Po
intType,
class LabelType>
2475template <
class OtherNumber>
2483template <
class Po
intType,
class LabelType>
2484template <
class OtherNumber>
2486 for (
auto& halfplane : halfplanes_) {
2489 canonicalizeSorted();
2492template <
class Po
intType,
class LabelType>
2493template <
class OtherNumber>
2501template <
class Po
intType,
class LabelType>
2502template <
class OtherNumber>
2504 for (
auto& halfplane : halfplanes_) {
2507 canonicalizeSorted();
2510template <
class Po
intType,
class LabelType>
2511template <
class OtherNumber>
2519template <
class Po
intType,
class LabelType>
2520template <
class OtherNumber>
2522 for (
auto& halfplane : halfplanes_) {
2525 canonicalizeSorted();
2528template <
class Po
intType,
class LabelType>
2529template <
class OtherNumber>
2537template <
class Po
intType,
class LabelType>
2538template <
class OtherNumber>
2540 for (
auto& halfplane : halfplanes_) {
2543 canonicalizeSorted();
Definition forward.hpp:315
Definition forward.hpp:322
Definition forward.hpp:312
Definition forward.hpp:319
Definition forward.hpp:309
Definition forward.hpp:320
Definition forward.hpp:310
Definition forward.hpp:308
Definition forward.hpp:306
Definition forward.hpp:316
Definition forward.hpp:318
Definition forward.hpp:317
Definition forward.hpp:321
Definition forward.hpp:311
Definition forward.hpp:313
Definition forward.hpp:307
Definition forward.hpp:314
Stream output helpers for Pangolin value types.
Definition arrangement.hpp:67
HalfplaneIntersection() -> HalfplaneIntersection< Point<>, NoLabel >
Definition halfplaneintersection.hpp:2308
@ y
Definition intervaltree.hpp:24
@ x
Definition intervaltree.hpp:24
BigInt abs(const BigInt &v)
Free-function absolute value, matching the integer helpers.
Definition bigint.hpp:948
Rectangle() -> Rectangle< Point<>, NoLabel >
Definition rectangle.hpp:2384
constexpr bool is_Rational_v
Definition rational.hpp:37
@ edge
Definition bitmatrix.hpp:37
@ vertex
Definition bitmatrix.hpp:37
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 >
typename rational_int< T >::type rational_int_t
Definition rational.hpp:61
MonotoneChain() -> MonotoneChain< Point<>, NoLabel >
Definition monotonechain.hpp:2439
PolygonWithHoles() -> PolygonWithHoles< Point<>, NoLabel >
Definition polygonwithholes.hpp:3093
Convex() -> Convex< Point<>, NoLabel >
Definition convex.hpp:3311
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 >
constexpr auto operator*(const Transformation< Number > &transformation, const ShapeT &shape)
Applies a transformation to any supported shape.
Definition transformations.hpp:2200
Triangle() -> Triangle< Point<>, NoLabel >
Definition triangle.hpp:2029
constexpr void scaleUpY(const OtherNumber scalar)
Multiplies the convex polygon's y-coordinates by a factor in place.
Definition transformations.hpp:1666
constexpr void scaleDownX(const OtherNumber scalar)
Divides the convex polygon's x-coordinates by a divisor in place.
Definition transformations.hpp:1685
constexpr Convex scaledDownX(const OtherNumber scalar) const
Returns the convex polygon with its x-coordinates divided by a divisor.
constexpr void scaleDownY(const OtherNumber scalar)
Divides the convex polygon's y-coordinates by a divisor in place.
Definition transformations.hpp:1704
constexpr void scaleUpX(const OtherNumber scalar)
Multiplies the convex polygon's x-coordinates by a factor in place.
Definition transformations.hpp:1647
constexpr Convex & operator+=(const OtherPoint &translation)
Translates the convex polygon by the given point in place.
constexpr Convex & operator-=(const OtherPoint &translation)
Translates the convex polygon by the negation of the given point.
constexpr Convex rotated90(int k=1) const
Returns the convex polygon rotated by 90k degrees around the origin.
Definition transformations.hpp:1618
constexpr Convex scaledUpX(const OtherNumber scalar) const
Returns the convex polygon with its x-coordinates multiplied by a factor.
constexpr Convex scaledUpY(const OtherNumber scalar) const
Returns the convex polygon with its y-coordinates multiplied by a factor.
constexpr Convex()=default
constexpr void rotate90(int k=1)
Rotates the convex polygon by 90k degrees around the origin in place.
Definition transformations.hpp:1628
size_t size() const
Definition convex.hpp:840
PointType PointType
Definition convex.hpp:171
constexpr Convex scaledDownY(const OtherNumber scalar) const
Returns the convex polygon with its y-coordinates divided by a divisor.
constexpr Disk rotated90(int k=1) const
Returns the disk rotated by 90k degrees around the origin.
Definition transformations.hpp:2183
constexpr const PointType & c() const
Returns the third boundary point in canonical order.
Definition disk.hpp:244
constexpr Disk()=default
Creates a disk with all three boundary points at the origin.
constexpr void rotate90(int k=1)
Rotates the disk by 90k degrees around the origin in place.
Definition transformations.hpp:2188
constexpr const PointType & a() const
Returns the first boundary point (lexicographically smallest).
Definition disk.hpp:228
constexpr const PointType & b() const
Returns the second boundary point in canonical order.
Definition disk.hpp:235
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
constexpr HalfplaneIntersection rotated90(int k=1) const
Returns the region rotated by 90k degrees around the origin.
Definition transformations.hpp:2460
constexpr void scaleDownX(const OtherNumber scalar)
Divides the region's x-coordinates by a divisor in place.
Definition transformations.hpp:2521
constexpr HalfplaneIntersection & operator-=(const OtherPoint &translation)
Translates the region by the negation of the given point in place.
constexpr HalfplaneIntersection scaledDownX(const OtherNumber scalar) const
Returns the region with its x-coordinates divided by a divisor.
constexpr void scaleDownY(const OtherNumber scalar)
Divides the region's y-coordinates by a divisor in place.
Definition transformations.hpp:2539
constexpr HalfplaneIntersection scaledDownY(const OtherNumber scalar) const
Returns the region with its y-coordinates divided by a divisor.
constexpr HalfplaneIntersection scaledUpX(const OtherNumber scalar) const
Returns the region with its x-coordinates multiplied by a factor.
constexpr void rotate90(int k=1)
Rotates the region by 90k degrees around the origin in place.
Definition transformations.hpp:2467
constexpr void scaleUpY(const OtherNumber scalar)
Multiplies the region's y-coordinates by a factor in place.
Definition transformations.hpp:2503
friend struct HalfplaneIntersection
Definition halfplaneintersection.hpp:2308
constexpr HalfplaneIntersection scaledUpY(const OtherNumber scalar) const
Returns the region with its y-coordinates multiplied by a factor.
constexpr HalfplaneIntersection & operator+=(const OtherPoint &translation)
Translates the region by the given point in place.
constexpr void scaleUpX(const OtherNumber scalar)
Multiplies the region's x-coordinates by a factor in place.
Definition transformations.hpp:2485
Closed half-plane defined by an oriented boundary line.
Definition halfplane.hpp:51
constexpr Halfplane rotated90(int k=1) const
Returns the half-plane rotated by 90k degrees around the origin.
Definition transformations.hpp:1457
constexpr Halfplane scaledDownY(const OtherNumber scalar) const
Returns the half-plane with its y-coordinates divided by a divisor.
constexpr void scaleDownX(const OtherNumber scalar)
Divides the half-plane's x-coordinates by a divisor in place.
Definition transformations.hpp:1516
constexpr Halfplane & operator+=(const OtherPoint &translation)
Translates the half-plane by the given point in place.
constexpr void scaleDownY(const OtherNumber scalar)
Divides the half-plane's y-coordinates by a divisor in place.
Definition transformations.hpp:1534
constexpr void rotate90(int k=1)
Rotates the half-plane by 90k degrees around the origin in place.
Definition transformations.hpp:1462
constexpr void scaleUpX(const OtherNumber scalar)
Multiplies the half-plane's x-coordinates by a factor in place.
Definition transformations.hpp:1480
constexpr Halfplane & operator-=(const OtherPoint &translation)
Translates the half-plane by the negation of the given point in place.
constexpr const PointType & target() const
Returns the target boundary point.
Definition halfplane.hpp:193
constexpr Halfplane scaledDownX(const OtherNumber scalar) const
Returns the half-plane with its x-coordinates divided by a divisor.
constexpr void scaleUpY(const OtherNumber scalar)
Multiplies the half-plane's y-coordinates by a factor in place.
Definition transformations.hpp:1498
constexpr Halfplane scaledUpX(const OtherNumber scalar) const
Returns the half-plane with its x-coordinates multiplied by a factor.
constexpr const PointType & source() const
Returns the source boundary point.
Definition halfplane.hpp:181
constexpr Halfplane()=default
Creates the degenerate half-plane (0,0)->(0,0).
constexpr Halfplane scaledUpY(const OtherNumber scalar) const
Returns the half-plane with its y-coordinates multiplied by a factor.
Unoriented infinite line.
Definition line.hpp:52
constexpr void rotate90(int k=1)
Rotates the line by 90k degrees around the origin in place.
Definition transformations.hpp:510
constexpr const PointType & max() const
Returns the largest stored defining point.
Definition line.hpp:189
constexpr Line scaledDownX(const OtherNumber scalar) const
Returns the line with its x-coordinates divided by a divisor.
constexpr const PointType & min() const
Returns the smallest stored defining point.
Definition line.hpp:180
constexpr Line scaledUpY(const OtherNumber scalar) const
Returns the line with its y-coordinates multiplied by a factor.
constexpr void scaleUpX(const OtherNumber scalar)
Multiplies the line's x-coordinates by a factor in place.
Definition transformations.hpp:524
constexpr Line rotated90(int k=1) const
Returns the line rotated by 90k degrees around the origin.
Definition transformations.hpp:505
constexpr void scaleDownY(const OtherNumber scalar)
Divides the line's y-coordinates by a divisor in place.
Definition transformations.hpp:566
constexpr void scaleDownX(const OtherNumber scalar)
Divides the line's x-coordinates by a divisor in place.
Definition transformations.hpp:552
constexpr Line & operator+=(const OtherPoint &translation)
Translates both defining points in place.
constexpr Line scaledUpX(const OtherNumber scalar) const
Returns the line with its x-coordinates multiplied by a factor.
constexpr void scaleUpY(const OtherNumber scalar)
Multiplies the line's y-coordinates by a factor in place.
Definition transformations.hpp:538
constexpr Line scaledDownY(const OtherNumber scalar) const
Returns the line with its y-coordinates divided by a divisor.
constexpr Line & operator-=(const OtherPoint &translation)
Translates both defining points by the opposite vector in place.
constexpr void scaleUpX(const OtherNumber scalar)
Multiplies the chain's x-coordinates by a factor in place.
Definition transformations.hpp:1918
constexpr void scaleDownX(const OtherNumber scalar)
Divides the chain's x-coordinates by a divisor in place.
Definition transformations.hpp:1958
constexpr std::size_t size() const
Returns the number of vertices in the chain.
Definition monotonechain.hpp:393
constexpr OwningChain scaledUpY(const OtherNumber scalar) const
Returns the chain with its y-coordinates multiplied by a factor.
constexpr void scaleDownY(const OtherNumber scalar)
Divides the chain's y-coordinates by a divisor in place.
Definition transformations.hpp:1978
constexpr OwningChain scaledDownX(const OtherNumber scalar) const
Returns the chain with its x-coordinates divided by a divisor.
constexpr OwningChain scaledDownY(const OtherNumber scalar) const
Returns the chain with its y-coordinates divided by a divisor.
constexpr MonotoneChain()=default
Creates a chain with no vertex.
constexpr void rotate90(int k=1)
Rotates the chain by 90k degrees around the origin in place.
Definition transformations.hpp:1898
constexpr OwningChain rotated90(int k=1) const
Returns the chain rotated by 90k degrees around the origin.
Definition transformations.hpp:1888
constexpr void scaleUpY(const OtherNumber scalar)
Multiplies the chain's y-coordinates by a factor in place.
Definition transformations.hpp:1938
constexpr OwningChain scaledUpX(const OtherNumber scalar) const
Returns the chain with its x-coordinates multiplied by a factor.
Directed infinite line with left/right side semantics plus optional line label.
Definition orientedline.hpp:53
constexpr OrientedLine scaledUpY(const OtherNumber scalar) const
Returns the line with its y-coordinates multiplied by a factor.
constexpr void scaleUpY(const OtherNumber scalar)
Multiplies the line's y-coordinates by a factor in place.
Definition transformations.hpp:685
constexpr OrientedLine & operator-=(const OtherPoint &translation)
Translates the oriented line by the negation of the given point in place.
constexpr const PointType & target() const
Returns the target defining point.
Definition orientedline.hpp:195
constexpr OrientedLine scaledDownX(const OtherNumber scalar) const
Returns the line with its x-coordinates divided by a divisor.
constexpr void rotate90(int k=1)
Rotates the oriented line by 90k degrees around the origin in place.
Definition transformations.hpp:659
constexpr A & label() const
Returns the line label.
Definition orientedline.hpp:305
std::optional< OrientedLine< Point< ResultNumber, typename PointType_::LabelType >, TLabel > > integralLine() const
Returns an equal oriented line whose defining points have integer coordinates, when one exists.
Definition transformations.hpp:840
constexpr OrientedLine scaledDownY(const OtherNumber scalar) const
Returns the line with its y-coordinates divided by a divisor.
constexpr OrientedLine & operator+=(const OtherPoint &translation)
Translates the oriented line by the given point in place.
constexpr OrientedLine scaledUpX(const OtherNumber scalar) const
Returns the line with its x-coordinates multiplied by a factor.
constexpr OrientedLine()=default
Creates the degenerate oriented line (0,0)--(0,0).
constexpr OrientedLine rotated90(int k=1) const
Returns the oriented line rotated by 90k degrees around the origin.
Definition transformations.hpp:654
constexpr void scaleDownX(const OtherNumber scalar)
Divides the line's x-coordinates by a divisor in place.
Definition transformations.hpp:698
constexpr void scaleDownY(const OtherNumber scalar)
Divides the line's y-coordinates by a divisor in place.
Definition transformations.hpp:711
PointType::NumberType NumberType
Definition orientedline.hpp:55
constexpr const PointType & source() const
Returns the source defining point.
Definition orientedline.hpp:183
constexpr void scaleUpX(const OtherNumber scalar)
Multiplies the line's x-coordinates by a factor in place.
Definition transformations.hpp:672
Directed segment preserving source-to-target order plus optional segment label.
Definition orientedsegment.hpp:44
constexpr void rotate90(int k=1)
Rotates the segment by 90k degrees around the origin in place.
Definition transformations.hpp:369
std::array< PointType, 2 > points_
Definition orientedsegment.hpp:1842
constexpr void scaleUpX(const OtherNumber scalar)
Multiplies the segment's x-coordinates by a factor in place.
Definition transformations.hpp:382
constexpr const PointType & source() const
Returns the source endpoint.
Definition orientedsegment.hpp:178
constexpr OrientedSegment rotated90(int k=1) const
Returns the segment rotated by 90k degrees around the origin.
Definition transformations.hpp:364
constexpr OrientedSegment scaledDownY(const OtherNumber scalar) const
Returns the segment with its y-coordinates divided by a divisor.
constexpr OrientedSegment & operator+=(const OtherPoint &translation)
Translates the oriented segment by the given point in place.
constexpr const PointType & target() const
Returns the target endpoint.
Definition orientedsegment.hpp:190
constexpr void scaleDownX(const OtherNumber scalar)
Divides the segment's x-coordinates by a divisor in place.
Definition transformations.hpp:408
constexpr OrientedSegment & operator-=(const OtherPoint &translation)
Translates the oriented segment by the negation of the given point in place.
constexpr OrientedSegment()=default
constexpr void scaleUpY(const OtherNumber scalar)
Multiplies the segment's y-coordinates by a factor in place.
Definition transformations.hpp:395
constexpr OrientedSegment scaledUpX(const OtherNumber scalar) const
Returns the segment with its x-coordinates multiplied by a factor.
constexpr OrientedSegment scaledDownX(const OtherNumber scalar) const
Returns the segment with its x-coordinates divided by a divisor.
constexpr void scaleDownY(const OtherNumber scalar)
Divides the segment's y-coordinates by a divisor in place.
Definition transformations.hpp:421
constexpr OrientedSegment scaledUpY(const OtherNumber scalar) const
Returns the segment with its y-coordinates multiplied by a factor.
Two-dimensional point with optional label payload.
Definition point.hpp:129
constexpr void scaleUpX(const OtherNumber scalar)
Multiplies the point's x-coordinate by a scalar in place.
Definition transformations.hpp:87
constexpr Point rotated90(int k=1) const
Returns the point rotated by 90k degrees around the origin.
Definition transformations.hpp:61
constexpr Point()=default
Creates the origin point (0, 0).
constexpr void scaleDownX(const OtherNumber scalar)
Divides the point's x-coordinate by a scalar in place.
Definition transformations.hpp:111
constexpr Point< Number, Label > scaledUpY(const OtherNumber scalar) const
Definition transformations.hpp:93
constexpr Point swapped() const
Returns the point with x and y swapped.
Definition transformations.hpp:56
constexpr Point operator-() const
Returns the point mirrored through the origin.
Definition transformations.hpp:19
constexpr void scaleDownY(const OtherNumber scalar)
Divides the point's y-coordinate by a scalar in place.
Definition transformations.hpp:123
constexpr Point scaledUpX(const OtherNumber scalar) const
Returns the point with its x-coordinate multiplied by a scalar.
constexpr Point scaledDownX(const OtherNumber scalar) const
Returns the point with its x-coordinate divided by a scalar.
constexpr Point & operator/=(const OtherNumber scalar)
Scales a point by a scalar division in place.
constexpr Point & operator-=(const OtherPoint &other)
Translates a point by the opposite of another point in place.
constexpr Point< Number, Label > scaledUpX(const OtherNumber scalar) const
Definition transformations.hpp:81
constexpr void scaleUpY(const OtherNumber scalar)
Multiplies the point's y-coordinate by a scalar in place.
Definition transformations.hpp:99
constexpr Point & operator*=(const OtherNumber scalar)
Scales a point by a scalar in place.
constexpr Point & operator+=(const OtherPoint &other)
Translates a point by another point in place.
constexpr void rotate90(int k=1)
Rotates the point by 90k degrees around the origin in place.
Definition transformations.hpp:71
TLabel LabelType
Definition point.hpp:133
constexpr const NumberType & x() const
Returns the x coordinate.
Definition point.hpp:193
constexpr const NumberType & y() const
Returns the y coordinate.
Definition point.hpp:205
constexpr Point scaledDownY(const OtherNumber scalar) const
Returns the point with its y-coordinate divided by a scalar.
constexpr Point scaledUpY(const OtherNumber scalar) const
Returns the point with its y-coordinate multiplied by a scalar.
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
constexpr bool crosses(const OtherChain &other) const
Tests whether the two shapes mutually separate each other (each disconnects the other).
Definition crosses.hpp:940
constexpr Polygon scaledUpY(const OtherNumber scalar) const
Returns the polygon with its y-coordinates multiplied by a factor.
constexpr bool contains(const OtherPoint &point) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:1296
constexpr void scaleUpX(const OtherNumber scalar)
Multiplies the polygon's x-coordinates by a factor in place.
Definition transformations.hpp:1816
constexpr Polygon scaledDownY(const OtherNumber scalar) const
Returns the polygon with its y-coordinates divided by a divisor.
constexpr Polygon()=default
Creates a polygon with no vertex.
constexpr void scaleDownY(const OtherNumber scalar)
Divides the polygon's y-coordinates by a divisor in place.
Definition transformations.hpp:1873
constexpr std::size_t size() const
Returns the number of vertices in the polygon.
Definition polygon.hpp:259
constexpr void untangle()
Makes the polygon simple in place by uncrossing its boundary.
Definition transformations.hpp:1731
constexpr void rotate90(int k=1)
Rotates the polygon by 90k degrees around the origin in place.
Definition transformations.hpp:1724
constexpr void scaleUpY(const OtherNumber scalar)
Multiplies the polygon's y-coordinates by a factor in place.
Definition transformations.hpp:1835
constexpr Polygon scaledUpX(const OtherNumber scalar) const
Returns the polygon with its x-coordinates multiplied by a factor.
constexpr Polygon rotated90(int k=1) const
Returns the polygon rotated by 90k degrees around the origin.
Definition transformations.hpp:1714
constexpr Polygon scaledDownX(const OtherNumber scalar) const
Returns the polygon with its x-coordinates divided by a divisor.
constexpr void scaleDownX(const OtherNumber scalar)
Divides the polygon's x-coordinates by a divisor in place.
Definition transformations.hpp:1854
Open polygonal chain stored in traversal order; may self-intersect.
Definition polyline.hpp:69
constexpr void scaleUpY(const OtherNumber scalar)
Multiplies the polyline's y-coordinates by a factor in place.
Definition transformations.hpp:2042
constexpr void rotate90(int k=1)
Rotates the polyline by 90k degrees around the origin in place.
Definition transformations.hpp:2004
constexpr Polyline()=default
Creates a polyline with no vertex.
constexpr Polyline flipped(const OldSegment &oldEdge, const NewSegment &newEdge) const
Returns the polyline with oldEdge flipped to newEdge.
constexpr bool flippable(const OldSegment &oldEdge, const NewSegment &newEdge) const
Tests whether oldEdge can be flipped to newEdge.
Definition transformations.hpp:2156
constexpr std::vector< PointType > vertices() const
Definition polyline.hpp:570
constexpr void scaleUpX(const OtherNumber scalar)
Multiplies the polyline's x-coordinates by a factor in place.
Definition transformations.hpp:2023
constexpr void flip(const OldSegment &oldEdge, const NewSegment &newEdge)
Flips oldEdge to newEdge in place.
Definition transformations.hpp:2172
constexpr void scaleDownX(const OtherNumber scalar)
Divides the polyline's x-coordinates by a divisor in place.
Definition transformations.hpp:2061
constexpr Polyline rotated90(int k=1) const
Returns the polyline rotated by 90k degrees around the origin.
Definition transformations.hpp:1994
constexpr Polyline scaledUpX(const OtherNumber scalar) const
Returns the polyline with its x-coordinates multiplied by a factor.
constexpr Polyline scaledDownX(const OtherNumber scalar) const
Returns the polyline with its x-coordinates divided by a divisor.
constexpr std::size_t size() const
Returns the number of vertices in the polyline.
Definition polyline.hpp:388
constexpr Polyline scaledUpY(const OtherNumber scalar) const
Returns the polyline with its y-coordinates multiplied by a factor.
constexpr Polyline scaledDownY(const OtherNumber scalar) const
Returns the polyline with its y-coordinates divided by a divisor.
constexpr void scaleDownY(const OtherNumber scalar)
Divides the polyline's y-coordinates by a divisor in place.
Definition transformations.hpp:2080
Half-infinite line starting from one source point plus optional ray label.
Definition ray.hpp:51
constexpr Ray scaledDownY(const OtherNumber scalar) const
Returns the ray with its y-coordinates divided by a divisor.
constexpr void scaleDownX(const OtherNumber scalar)
Divides the ray's x-coordinates by a divisor in place.
Definition transformations.hpp:1047
constexpr Ray & operator-=(const OtherPoint &translation)
Translates the ray by the negation of the given point in place.
constexpr Ray()=default
Creates the degenerate ray (0,0)--(0,0)->.
constexpr Ray scaledUpY(const OtherNumber scalar) const
Returns the ray with its y-coordinates multiplied by a factor.
constexpr void scaleDownY(const OtherNumber scalar)
Divides the ray's y-coordinates by a divisor in place.
Definition transformations.hpp:1060
constexpr Ray & operator+=(const OtherPoint &translation)
Translates the ray by the given point in place.
constexpr void scaleUpY(const OtherNumber scalar)
Multiplies the ray's y-coordinates by a factor in place.
Definition transformations.hpp:1034
constexpr const PointType & target() const
Returns the second stored point defining the direction.
Definition ray.hpp:193
constexpr void rotate90(int k=1)
Rotates the ray by 90k degrees around the origin in place.
Definition transformations.hpp:1008
constexpr void scaleUpX(const OtherNumber scalar)
Multiplies the ray's x-coordinates by a factor in place.
Definition transformations.hpp:1021
constexpr Ray scaledUpX(const OtherNumber scalar) const
Returns the ray with its x-coordinates multiplied by a factor.
constexpr Ray scaledDownX(const OtherNumber scalar) const
Returns the ray with its x-coordinates divided by a divisor.
constexpr const PointType & source() const
Returns the source point of the ray.
Definition ray.hpp:181
constexpr Ray rotated90(int k=1) const
Returns the ray rotated by 90k degrees around the origin.
Definition transformations.hpp:1003
Axis-aligned rectangle stored by minimum and maximum corners.
Definition rectangle.hpp:75
constexpr Rectangle rotated90(int k=1) const
Returns the rectangle rotated by 90k degrees around the origin.
Definition transformations.hpp:1157
constexpr void scaleUpY(const OtherNumber scalar)
Multiplies the rectangle's y-coordinates by a factor in place.
Definition transformations.hpp:1202
constexpr Rectangle & operator+=(const OtherPoint &translation)
Translates both stored corners in place.
constexpr Rectangle & operator-=(const OtherPoint &translation)
Translates both stored corners by the opposite vector in place.
constexpr Rectangle scaledDownX(const OtherNumber scalar) const
Returns the rectangle with its x-coordinates divided by a divisor.
constexpr const PointType & min() const
Returns the minimum corner (min x, min y).
Definition rectangle.hpp:347
constexpr bool empty() const
Definition rectangle.hpp:290
constexpr void rotate90(int k=1)
Rotates the rectangle by 90k degrees around the origin in place.
Definition transformations.hpp:1166
constexpr Rectangle scaledDownY(const OtherNumber scalar) const
Returns the rectangle with its y-coordinates divided by a divisor.
constexpr void scaleDownY(const OtherNumber scalar)
Divides the rectangle's y-coordinates by a divisor in place.
Definition transformations.hpp:1238
constexpr void scaleDownX(const OtherNumber scalar)
Divides the rectangle's x-coordinates by a divisor in place.
Definition transformations.hpp:1220
constexpr Rectangle scaledUpX(const OtherNumber scalar) const
Returns the rectangle with its x-coordinates multiplied by a factor.
constexpr void scaleUpX(const OtherNumber scalar)
Multiplies the rectangle's x-coordinates by a factor in place.
Definition transformations.hpp:1184
constexpr const PointType & max() const
Returns the maximum corner (max x, max y).
Definition rectangle.hpp:359
constexpr Rectangle()
Definition rectangle.hpp:120
constexpr Rectangle scaledUpY(const OtherNumber scalar) const
Returns the rectangle with its y-coordinates multiplied by a factor.
Unoriented closed segment between two endpoints plus optional segment label.
Definition segment.hpp:58
constexpr Segment scaledUpX(const OtherNumber scalar) const
Returns the segment with its x-coordinates multiplied by a factor.
constexpr void rotate90(int k=1)
Rotates the segment by 90k degrees around the origin in place.
Definition transformations.hpp:235
constexpr Segment & operator-=(const OtherPoint &translation)
Translates the segment by the negation of the given point in place.
constexpr void scaleDownY(const OtherNumber scalar)
Divides the segment's y-coordinates by a divisor in place.
Definition transformations.hpp:291
constexpr Segment scaledDownY(const OtherNumber scalar) const
Returns the segment with its y-coordinates divided by a divisor.
constexpr void scaleUpY(const OtherNumber scalar)
Multiplies the segment's y-coordinates by a factor in place.
Definition transformations.hpp:263
constexpr Segment scaledUpY(const OtherNumber scalar) const
Returns the segment with its y-coordinates multiplied by a factor.
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 rotated90(int k=1) const
Returns the segment rotated by 90k degrees around the origin.
Definition transformations.hpp:230
constexpr Segment & operator+=(const OtherPoint &translation)
Translates the segment by the given point in place.
constexpr void scaleUpX(const OtherNumber scalar)
Multiplies the segment's x-coordinates by a factor in place.
Definition transformations.hpp:249
constexpr Segment scaledDownX(const OtherNumber scalar) const
Returns the segment with its x-coordinates divided by a divisor.
constexpr Segment()=default
constexpr void scaleDownX(const OtherNumber scalar)
Divides the segment's x-coordinates by a divisor in place.
Definition transformations.hpp:277
Runtime variant wrapper over the supported primitive shapes.
Definition shape.hpp:160
Closed triangle stored by three vertices.
Definition triangle.hpp:53
constexpr Triangle & operator-=(const OtherPoint &translation)
Translates all vertices by the opposite of a point in place.
constexpr const PointType & b() const
Returns the second vertex.
Definition triangle.hpp:217
constexpr Triangle()=default
constexpr const PointType & a() const
Returns the first vertex.
Definition triangle.hpp:208
constexpr Triangle & operator+=(const OtherPoint &translation)
Translates all vertices by a point in place.
constexpr Triangle scaledDownX(const OtherNumber scalar) const
Returns the triangle with its x-coordinates divided by a divisor.
constexpr void scaleUpX(const OtherNumber scalar)
Multiplies the triangle's x-coordinates by a factor in place.
Definition transformations.hpp:1341
constexpr Triangle scaledUpX(const OtherNumber scalar) const
Returns the triangle with its x-coordinates multiplied by a factor.
constexpr void scaleUpY(const OtherNumber scalar)
Multiplies the triangle's y-coordinates by a factor in place.
Definition transformations.hpp:1355
constexpr Triangle scaledDownY(const OtherNumber scalar) const
Returns the triangle with its y-coordinates divided by a divisor.
constexpr void rotate90(int k=1)
Rotates the triangle by 90k degrees around the origin in place.
Definition transformations.hpp:1327
constexpr Triangle scaledUpY(const OtherNumber scalar) const
Returns the triangle with its y-coordinates multiplied by a factor.
constexpr void scaleDownY(const OtherNumber scalar)
Divides the triangle's y-coordinates by a divisor in place.
Definition transformations.hpp:1383
constexpr void scaleDownX(const OtherNumber scalar)
Divides the triangle's x-coordinates by a divisor in place.
Definition transformations.hpp:1369
constexpr Triangle rotated90(int k=1) const
Returns the triangle rotated by 90k degrees around the origin.
Definition transformations.hpp:1322
constexpr const PointType & c() const
Returns the third vertex.
Definition triangle.hpp:226