Pangolin
Header-only C++20 plane computational geometry library
Loading...
Searching...
No Matches
distancel1.hpp
Go to the documentation of this file.
1#pragma once
2
4
21
22#include <cmath>
23#include <numbers>
24
25namespace pgl {
26
27namespace detail {
28
47template <class ResultNumber>
48constexpr ResultNumber segmentLikeDistanceL1(const Point<ResultNumber>& a, const Point<ResultNumber>& b,
49 const Point<ResultNumber>& q, bool boundedLow, bool boundedHigh) {
50 const ResultNumber dx = b.x() - a.x();
51 const ResultNumber dy = b.y() - a.y();
52 const ResultNumber px = q.x() - a.x();
53 const ResultNumber py = q.y() - a.y();
54
55 if (dx == 0 && dy == 0) {
56 return pgl::detail::abs(px) + pgl::detail::abs(py);
57 }
58
59 bool haveBest = false;
60 ResultNumber best{};
61 const auto consider = [&](const ResultNumber& value) {
62 if (!haveBest || value < best) {
63 best = value;
64 haveBest = true;
65 }
66 };
67
68 if (boundedLow) {
69 consider(pgl::detail::abs(px) + pgl::detail::abs(py));
70 }
71 if (boundedHigh) {
72 consider(pgl::detail::abs(px - dx) + pgl::detail::abs(py - dy));
73 }
74
75 const ResultNumber cross = dx * py - dy * px;
76 const auto considerCrossing = [&](const ResultNumber& n, const ResultNumber& d) {
77 if (d == 0) {
78 return;
79 }
80 // The low bound rejects t = n/d < 0, i.e. n and d of opposite signs.
81 // Read off the two signs rather than forming n*d: for an exact rational
82 // the product is a multiplication plus a normalization, while comparing
83 // against the literal 0 is the sign of a numerator. d is nonzero here,
84 // so d > 0 splits the cases exhaustively, and n == 0 correctly fails
85 // both branches.
86 if (boundedLow && (d > 0 ? n < 0 : n > 0)) {
87 return;
88 }
89 if (boundedHigh && n * d > d * d) {
90 return;
91 }
92 consider(pgl::detail::abs(cross) / pgl::detail::abs(d));
93 };
94 considerCrossing(px, dx);
95 considerCrossing(py, dy);
96
97 return best;
98}
99
112template <class ResultNumber, class Self, class OtherShape>
113constexpr ResultNumber maxVertexDistanceL1(const Self& self, const OtherShape& other) {
114 const auto self_vertices = self.vertices();
115 const auto distanceToVertex = [&other](const auto& vertex) -> ResultNumber {
116 return other.template distanceL1<ResultNumber>(vertex);
117 };
118 ResultNumber worst = distanceToVertex(self_vertices[0]);
119 for (std::size_t index = 1; index < self_vertices.size(); ++index) {
120 const ResultNumber current = distanceToVertex(self_vertices[index]);
121 if (worst < current) {
122 worst = current;
123 }
124 }
125 return worst;
126}
127
142template <class Float = double>
143Float diskPointDistanceL1(Float a, Float b, Float r) {
144 const auto h = [&](Float theta) {
145 return std::abs(a + r * std::cos(theta)) + std::abs(b + r * std::sin(theta));
146 };
147
148 constexpr int coarseSteps = 720;
149 Float bestTheta{0};
150 Float bestValue = h(Float{0});
151 for (int i = 1; i < coarseSteps; ++i) {
152 const Float theta = Float{2} * std::numbers::pi_v<Float> * i / coarseSteps;
153 const Float value = h(theta);
154 if (value < bestValue) {
155 bestValue = value;
156 bestTheta = theta;
157 }
158 }
159
160 const Float step = Float{2} * std::numbers::pi_v<Float> / coarseSteps;
161 Float lo = bestTheta - step;
162 Float hi = bestTheta + step;
163 constexpr Float invPhi = 0.6180339887498949;
164 Float c1 = hi - invPhi * (hi - lo);
165 Float c2 = lo + invPhi * (hi - lo);
166 Float hc1 = h(c1);
167 Float hc2 = h(c2);
168 for (int i = 0; i < 100; ++i) {
169 if (hc1 < hc2) {
170 hi = c2;
171 c2 = c1;
172 hc2 = hc1;
173 c1 = hi - invPhi * (hi - lo);
174 hc1 = h(c1);
175 } else {
176 lo = c1;
177 c1 = c2;
178 hc1 = hc2;
179 c2 = lo + invPhi * (hi - lo);
180 hc2 = h(c2);
181 }
182 }
183
184 return std::min({bestValue, hc1, hc2});
185}
186
187} // namespace detail
188
189// -----------------------------------------------------------------------------
190// Point
191
192template <class Number, class Label>
193template <class ResultNumber, PointConcept OtherPoint>
194constexpr auto Point<Number, Label>::hausdorffDistanceL1(const OtherPoint& other) const {
195 return this->template distanceL1<ResultNumber>(other);
196}
197
198// -----------------------------------------------------------------------------
199// Disk
200
201template <class PointType_, class TLabel>
202template <class ResultNumber, PointConcept OtherPoint>
203detail::floating_result_t<ResultNumber> Disk<PointType_, TLabel>::distanceL1(
204 const OtherPoint& point) const {
205 using Float = detail::floating_result_t<ResultNumber>;
206 if (contains(point)) {
207 return Float{0};
208 }
209 const Float a = center<Float>().x() - static_cast<Float>(point.x());
210 const Float b = center<Float>().y() - static_cast<Float>(point.y());
211 return detail::diskPointDistanceL1(a, b, radius<Float>());
212}
213
214// -----------------------------------------------------------------------------
215// Segment
216
217template <class PointType, class LabelType>
218template <class ResultNumber, PointConcept OtherPoint>
219constexpr auto Segment<PointType, LabelType>::distanceL1(const OtherPoint& point) const {
220 return detail::segmentLikeDistanceL1<ResultNumber>(
222}
223
224template <class PointType, class LabelType>
225template <class ResultNumber, SegmentConcept OtherSegment>
226constexpr auto Segment<PointType, LabelType>::distanceL1(const OtherSegment& other) const {
227 if (intersects(other)) {
228 return ResultNumber{};
229 }
230
231 const auto this_min_to_other = other.template distanceL1<ResultNumber>(min());
232 const auto this_max_to_other = other.template distanceL1<ResultNumber>(max());
233 const auto other_min_to_this = this->template distanceL1<ResultNumber>(other.min());
234 const auto other_max_to_this = this->template distanceL1<ResultNumber>(other.max());
235
236 const auto best_from_this = this_min_to_other < this_max_to_other ? this_min_to_other : this_max_to_other;
237 const auto best_from_other = other_min_to_this < other_max_to_this ? other_min_to_this : other_max_to_this;
238
239 return best_from_this < best_from_other ? best_from_this : best_from_other;
240}
241
242// -----------------------------------------------------------------------------
243// OrientedSegment
244
245template <class PointType, class LabelType>
246template <class ResultNumber, PointConcept OtherPoint>
247constexpr auto OrientedSegment<PointType, LabelType>::distanceL1(const OtherPoint& point) const {
248 return static_cast<Segment<PointType>>(*this).template distanceL1<ResultNumber>(point);
249}
250
251template <class PointType, class LabelType>
252template <class ResultNumber, SegmentConcept OtherSegment>
253constexpr auto OrientedSegment<PointType, LabelType>::distanceL1(const OtherSegment& other) const {
254 return static_cast<Segment<PointType>>(*this).template distanceL1<ResultNumber>(other);
255}
256
257template <class PointType, class LabelType>
258template <class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
259constexpr auto OrientedSegment<PointType, LabelType>::distanceL1(const OtherOrientedSegment& other) const {
260 return static_cast<Segment<PointType>>(*this).template distanceL1<ResultNumber>(
262}
263
264// -----------------------------------------------------------------------------
265// Line
266
267template <class PointType, class LabelType>
268template <class ResultNumber, PointConcept OtherPoint>
269constexpr auto Line<PointType, LabelType>::distanceL1(const OtherPoint& point) const {
270 return detail::segmentLikeDistanceL1<ResultNumber>(
272}
273
274template <class PointType, class LabelType>
275template <class ResultNumber, LineConcept OtherLine>
276constexpr auto Line<PointType, LabelType>::distanceL1(const OtherLine& other) const {
277 if (intersects(other)) {
278 return ResultNumber{};
279 }
280 return other.template distanceL1<ResultNumber>(min());
281}
282
283template <class PointType, class LabelType>
284template <class ResultNumber, SegmentConcept OtherSegment>
285constexpr auto Line<PointType, LabelType>::distanceL1(const OtherSegment& other) const {
286 if (intersects(other)) {
287 return ResultNumber{};
288 }
289
290 const auto source_distance = this->template distanceL1<ResultNumber>(other.min());
291 const auto target_distance = this->template distanceL1<ResultNumber>(other.max());
292 return source_distance < target_distance ? source_distance : target_distance;
293}
294
295template <class PointType, class LabelType>
296template <class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
297constexpr auto Line<PointType, LabelType>::distanceL1(const OtherOrientedSegment& other) const {
298 return this->template distanceL1<ResultNumber>(static_cast<Segment<typename OtherOrientedSegment::PointType>>(other));
299}
300
301// -----------------------------------------------------------------------------
302// OrientedLine
303
304template <class PointType, class LabelType>
305template <class ResultNumber, PointConcept OtherPoint>
306constexpr auto OrientedLine<PointType, LabelType>::distanceL1(const OtherPoint& point) const {
307 return this->asLine().template distanceL1<ResultNumber>(point);
308}
309
310template <class PointType, class LabelType>
311template <class ResultNumber, LineConcept OtherLine>
312constexpr auto OrientedLine<PointType, LabelType>::distanceL1(const OtherLine& other) const {
313 return this->asLine().template distanceL1<ResultNumber>(other);
314}
315
316template <class PointType, class LabelType>
317template <class ResultNumber, OrientedLineConcept OtherOrientedLine>
318constexpr auto OrientedLine<PointType, LabelType>::distanceL1(const OtherOrientedLine& other) const {
319 return this->asLine().template distanceL1<ResultNumber>(other.asLine());
320}
321
322template <class PointType, class LabelType>
323template <class ResultNumber, SegmentConcept OtherSegment>
324constexpr auto OrientedLine<PointType, LabelType>::distanceL1(const OtherSegment& other) const {
325 return this->asLine().template distanceL1<ResultNumber>(other);
326}
327
328template <class PointType, class LabelType>
329template <class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
330constexpr auto OrientedLine<PointType, LabelType>::distanceL1(const OtherOrientedSegment& other) const {
331 return this->asLine().template distanceL1<ResultNumber>(other);
332}
333
334// -----------------------------------------------------------------------------
335// Ray
336
337template <class PointType, class LabelType>
338template <class ResultNumber, PointConcept OtherPoint>
339constexpr auto Ray<PointType, LabelType>::distanceL1(const OtherPoint& point) const {
340 return detail::segmentLikeDistanceL1<ResultNumber>(
342}
343
344template <class PointType, class LabelType>
345template <class ResultNumber, LineConcept OtherLine>
346constexpr auto Ray<PointType, LabelType>::distanceL1(const OtherLine& other) const {
347 if (intersects(other)) {
348 return ResultNumber{};
349 }
350 return other.template distanceL1<ResultNumber>(source());
351}
352
353template <class PointType, class LabelType>
354template <class ResultNumber, OrientedLineConcept OtherOrientedLine>
355constexpr auto Ray<PointType, LabelType>::distanceL1(const OtherOrientedLine& other) const {
356 if (intersects(other)) {
357 return ResultNumber{};
358 }
359 return other.template distanceL1<ResultNumber>(source());
360}
361
362template <class PointType, class LabelType>
363template <class ResultNumber, SegmentConcept OtherSegment>
364constexpr auto Ray<PointType, LabelType>::distanceL1(const OtherSegment& other) const {
365 if (intersects(other)) {
366 return ResultNumber{};
367 }
368
369 const auto source_to_other = other.template distanceL1<ResultNumber>(source());
370 const auto other_min_to_this = this->template distanceL1<ResultNumber>(other.min());
371 const auto other_max_to_this = this->template distanceL1<ResultNumber>(other.max());
372 const auto best_from_segment = other_min_to_this < other_max_to_this ? other_min_to_this : other_max_to_this;
373 return source_to_other < best_from_segment ? source_to_other : best_from_segment;
374}
375
376template <class PointType, class LabelType>
377template <class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
378constexpr auto Ray<PointType, LabelType>::distanceL1(const OtherOrientedSegment& other) const {
379 if (intersects(other)) {
380 return ResultNumber{};
381 }
382
383 const auto source_to_other = other.template distanceL1<ResultNumber>(source());
384 const auto other_source_to_this = this->template distanceL1<ResultNumber>(other.source());
385 const auto other_target_to_this = this->template distanceL1<ResultNumber>(other.target());
386 const auto best_from_segment = other_source_to_this < other_target_to_this ? other_source_to_this : other_target_to_this;
387 return source_to_other < best_from_segment ? source_to_other : best_from_segment;
388}
389
390template <class PointType, class LabelType>
391template <class ResultNumber, RayConcept OtherRay>
392constexpr auto Ray<PointType, LabelType>::distanceL1(const OtherRay& other) const {
393 if (intersects(other)) {
394 return ResultNumber{};
395 }
396
397 const auto this_source_to_other = other.template distanceL1<ResultNumber>(source());
398 const auto other_source_to_this = this->template distanceL1<ResultNumber>(other.source());
399 return this_source_to_other < other_source_to_this ? this_source_to_other : other_source_to_this;
400}
401
402// -----------------------------------------------------------------------------
403// Halfplane
404
405template <class PointType, class LabelType>
406template <class ResultNumber, PointConcept OtherPoint>
407constexpr auto Halfplane<PointType, LabelType>::distanceL1(const OtherPoint& point) const {
408 if (intersects(point)) {
409 return ResultNumber{};
410 }
411 return asLine().template distanceL1<ResultNumber>(point);
412}
413
414template <class PointType, class LabelType>
415template <class ResultNumber, SegmentConcept OtherSegment>
416constexpr auto Halfplane<PointType, LabelType>::distanceL1(const OtherSegment& other) const {
417 if (intersects(other)) {
418 return ResultNumber{};
419 }
420 return asLine().template distanceL1<ResultNumber>(other);
421}
422
423template <class PointType, class LabelType>
424template <class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
425constexpr auto Halfplane<PointType, LabelType>::distanceL1(const OtherOrientedSegment& other) const {
426 if (intersects(other)) {
427 return ResultNumber{};
428 }
429 return asLine().template distanceL1<ResultNumber>(other);
430}
431
432template <class PointType, class LabelType>
433template <class ResultNumber, LineConcept OtherLine>
434constexpr auto Halfplane<PointType, LabelType>::distanceL1(const OtherLine& other) const {
435 if (intersects(other)) {
436 return ResultNumber{};
437 }
438 return asLine().template distanceL1<ResultNumber>(other);
439}
440
441template <class PointType, class LabelType>
442template <class ResultNumber, OrientedLineConcept OtherOrientedLine>
443constexpr auto Halfplane<PointType, LabelType>::distanceL1(const OtherOrientedLine& other) const {
444 if (intersects(other)) {
445 return ResultNumber{};
446 }
447 return asLine().template distanceL1<ResultNumber>(other);
448}
449
450template <class PointType, class LabelType>
451template <class ResultNumber, RayConcept OtherRay>
452constexpr auto Halfplane<PointType, LabelType>::distanceL1(const OtherRay& other) const {
453 if (intersects(other)) {
454 return ResultNumber{};
455 }
456 return asLine().template distanceL1<ResultNumber>(other);
457}
458
459template <class PointType, class LabelType>
460template <class ResultNumber, HalfplaneConcept OtherHalfplane>
461constexpr auto Halfplane<PointType, LabelType>::distanceL1(const OtherHalfplane& other) const {
462 if (intersects(other)) {
463 return ResultNumber{};
464 }
465 return asLine().template distanceL1<ResultNumber>(other.asLine());
466}
467
468// -----------------------------------------------------------------------------
469// Rectangle
470
471template <class PointType, class LabelType>
472template <class ResultNumber, PointConcept OtherPoint>
473constexpr auto Rectangle<PointType, LabelType>::distanceL1(const OtherPoint& point) const {
474 // There is no nearest point of the empty set, so it has no distance to
475 // anything; asking for one is a precondition violation.
476 assert(!empty());
477 const ResultNumber dx = static_cast<ResultNumber>(axisDistance(min().x(), max().x(), point.x(), point.x()));
478 const ResultNumber dy = static_cast<ResultNumber>(axisDistance(min().y(), max().y(), point.y(), point.y()));
479 return dx + dy;
480}
481
482template <class PointType, class LabelType>
483template <class ResultNumber, LineConcept OtherLine>
484constexpr auto Rectangle<PointType, LabelType>::distanceL1(const OtherLine& other) const {
485 // There is no nearest point of the empty set, so it has no distance to
486 // anything; asking for one is a precondition violation.
487 assert(!empty());
488 if (intersects(other)) {
489 return ResultNumber{};
490 }
491
492 const auto rectangle_vertices = vertices();
493 auto best_distance = other.template distanceL1<ResultNumber>(rectangle_vertices[0]);
494 for (std::size_t index = 1; index < rectangle_vertices.size(); ++index) {
495 const auto current_distance = other.template distanceL1<ResultNumber>(rectangle_vertices[index]);
496 if (current_distance < best_distance) {
497 best_distance = current_distance;
498 }
499 }
500
501 return best_distance;
502}
503
504template <class PointType, class LabelType>
505template <class ResultNumber, OrientedLineConcept OtherOrientedLine>
506constexpr auto Rectangle<PointType, LabelType>::distanceL1(const OtherOrientedLine& other) const {
507 // There is no nearest point of the empty set, so it has no distance to
508 // anything; asking for one is a precondition violation.
509 assert(!empty());
510 return this->template distanceL1<ResultNumber>(other.asLine());
511}
512
513template <class PointType, class LabelType>
514template <class ResultNumber, SegmentConcept OtherSegment>
515constexpr auto Rectangle<PointType, LabelType>::distanceL1(const OtherSegment& other) const {
516 // There is no nearest point of the empty set, so it has no distance to
517 // anything; asking for one is a precondition violation.
518 assert(!empty());
519 if (intersects(other)) {
520 return ResultNumber{};
521 }
522
523 auto best_distance = this->template distanceL1<ResultNumber>(other.min());
524 const auto other_max_distance = this->template distanceL1<ResultNumber>(other.max());
525 if (other_max_distance < best_distance) {
526 best_distance = other_max_distance;
527 }
528
529 const auto rectangle_edges = edges();
530 for (const auto& edge : rectangle_edges) {
531 const auto current_distance = edge.template distanceL1<ResultNumber>(other);
532 if (current_distance < best_distance) {
533 best_distance = current_distance;
534 }
535 }
536
537 return best_distance;
538}
539
540template <class PointType, class LabelType>
541template <class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
542constexpr auto Rectangle<PointType, LabelType>::distanceL1(const OtherOrientedSegment& other) const {
543 // There is no nearest point of the empty set, so it has no distance to
544 // anything; asking for one is a precondition violation.
545 assert(!empty());
546 return this->template distanceL1<ResultNumber>(static_cast<Segment<typename OtherOrientedSegment::PointType>>(other));
547}
548
549template <class PointType, class LabelType>
550template <class ResultNumber, RayConcept OtherRay>
551constexpr auto Rectangle<PointType, LabelType>::distanceL1(const OtherRay& other) const {
552 // There is no nearest point of the empty set, so it has no distance to
553 // anything; asking for one is a precondition violation.
554 assert(!empty());
555 if (intersects(other)) {
556 return ResultNumber{};
557 }
558
559 auto best_distance = this->template distanceL1<ResultNumber>(other.source());
560 const auto rectangle_edges = edges();
561 for (const auto& edge : rectangle_edges) {
562 const auto current_distance = other.template distanceL1<ResultNumber>(edge);
563 if (current_distance < best_distance) {
564 best_distance = current_distance;
565 }
566 }
567
568 return best_distance;
569}
570
571template <class PointType, class LabelType>
572template <class ResultNumber, HalfplaneConcept OtherHalfplane>
573constexpr auto Rectangle<PointType, LabelType>::distanceL1(const OtherHalfplane& other) const {
574 // There is no nearest point of the empty set, so it has no distance to
575 // anything; asking for one is a precondition violation.
576 assert(!empty());
577 if (intersects(other)) {
578 return ResultNumber{};
579 }
580 return this->template distanceL1<ResultNumber>(other.asLine());
581}
582
583template <class PointType, class LabelType>
584template <class ResultNumber, RectangleConcept OtherRectangle>
585constexpr auto Rectangle<PointType, LabelType>::distanceL1(const OtherRectangle& other) const {
586 // There is no nearest point of the empty set, so it has no distance to
587 // anything; asking for one is a precondition violation.
588 assert(!empty());
589 const ResultNumber dx = static_cast<ResultNumber>(axisDistance(min().x(), max().x(), other.min().x(), other.max().x()));
590 const ResultNumber dy = static_cast<ResultNumber>(axisDistance(min().y(), max().y(), other.min().y(), other.max().y()));
591 return dx + dy;
592}
593
594// -----------------------------------------------------------------------------
595// Triangle
596
597template <class PointType, class LabelType>
598template <class ResultNumber, class OtherShape>
599constexpr ResultNumber Triangle<PointType, LabelType>::edgeMinDistanceL1(const OtherShape& other) const {
600 const auto triangle_edges = edges();
601 auto best = triangle_edges[0].template distanceL1<ResultNumber>(other);
602 for (std::size_t index = 1; index < triangle_edges.size(); ++index) {
603 const auto current = triangle_edges[index].template distanceL1<ResultNumber>(other);
604 if (current < best) {
605 best = current;
606 }
607 }
608 return best;
609}
610
611template <class PointType, class LabelType>
612template <class ResultNumber, class OtherShape>
613constexpr ResultNumber Triangle<PointType, LabelType>::vertexMinDistanceL1(const OtherShape& other) const {
614 const auto triangle_vertices = vertices();
615 auto best = other.template distanceL1<ResultNumber>(triangle_vertices[0]);
616 for (std::size_t index = 1; index < triangle_vertices.size(); ++index) {
617 const auto current = other.template distanceL1<ResultNumber>(triangle_vertices[index]);
618 if (current < best) {
619 best = current;
620 }
621 }
622 return best;
623}
624
625template <class PointType, class LabelType>
626template <class ResultNumber, PointConcept OtherPoint>
627constexpr auto Triangle<PointType, LabelType>::distanceL1(const OtherPoint& point) const {
628 if (intersects(point)) {
629 return ResultNumber{};
630 }
631 return this->template edgeMinDistanceL1<ResultNumber>(point);
632}
633
634template <class PointType, class LabelType>
635template <class ResultNumber, SegmentConcept OtherSegment>
636constexpr auto Triangle<PointType, LabelType>::distanceL1(const OtherSegment& other) const {
637 if (intersects(other)) {
638 return ResultNumber{};
639 }
640 return this->template edgeMinDistanceL1<ResultNumber>(other);
641}
642
643template <class PointType, class LabelType>
644template <class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
645constexpr auto Triangle<PointType, LabelType>::distanceL1(const OtherOrientedSegment& other) const {
646 if (intersects(other)) {
647 return ResultNumber{};
648 }
649 return this->template edgeMinDistanceL1<ResultNumber>(other);
650}
651
652template <class PointType, class LabelType>
653template <class ResultNumber, LineConcept OtherLine>
654constexpr auto Triangle<PointType, LabelType>::distanceL1(const OtherLine& other) const {
655 if (intersects(other)) {
656 return ResultNumber{};
657 }
658 return this->template vertexMinDistanceL1<ResultNumber>(other);
659}
660
661template <class PointType, class LabelType>
662template <class ResultNumber, OrientedLineConcept OtherOrientedLine>
663constexpr auto Triangle<PointType, LabelType>::distanceL1(const OtherOrientedLine& other) const {
664 if (intersects(other)) {
665 return ResultNumber{};
666 }
667 return this->template vertexMinDistanceL1<ResultNumber>(other);
668}
669
670template <class PointType, class LabelType>
671template <class ResultNumber, RayConcept OtherRay>
672constexpr auto Triangle<PointType, LabelType>::distanceL1(const OtherRay& other) const {
673 if (intersects(other)) {
674 return ResultNumber{};
675 }
676 return this->template edgeMinDistanceL1<ResultNumber>(other);
677}
678
679template <class PointType, class LabelType>
680template <class ResultNumber, HalfplaneConcept OtherHalfplane>
681constexpr auto Triangle<PointType, LabelType>::distanceL1(const OtherHalfplane& other) const {
682 if (intersects(other)) {
683 return ResultNumber{};
684 }
685 return this->template distanceL1<ResultNumber>(other.asLine());
686}
687
688template <class PointType, class LabelType>
689template <class ResultNumber, RectangleConcept OtherRectangle>
690constexpr auto Triangle<PointType, LabelType>::distanceL1(const OtherRectangle& other) const {
691 if (intersects(other)) {
692 return ResultNumber{};
693 }
694 return this->template edgeMinDistanceL1<ResultNumber>(other);
695}
696
697template <class PointType, class LabelType>
698template <class ResultNumber, TriangleConcept OtherTriangle>
699constexpr auto Triangle<PointType, LabelType>::distanceL1(const OtherTriangle& other) const {
700 if (intersects(other)) {
701 return ResultNumber{};
702 }
703 return this->template edgeMinDistanceL1<ResultNumber>(other);
704}
705
706// -----------------------------------------------------------------------------
707// Convex
708//
709// Always uses the O(n) edge scan below (no cyclic support-function fast path):
710// see the distanceL1 declarations in convex.hpp for why the Euclidean fast
711// path's search functional does not carry over to the L1 gauge.
712
713template <class PointType_, class LabelType>
714template <class ResultNumber, PointConcept OtherPoint>
715constexpr auto Convex<PointType_, LabelType>::distanceL1(const OtherPoint& point) const {
716 if (contains(point)) {
717 return ResultNumber{};
718 }
719 auto edgeVector = edges();
720 ResultNumber best = edgeVector[0].template distanceL1<ResultNumber>(point);
721 for (auto& e : edgeVector) {
722 const ResultNumber current = e.template distanceL1<ResultNumber>(point);
723 if (current < best) {
724 best = current;
725 }
726 }
727 return best;
728}
729
730template <class PointType_, class LabelType>
731template <class ResultNumber, SegmentConcept OtherSegment>
732constexpr auto Convex<PointType_, LabelType>::distanceL1(const OtherSegment& other) const {
733 if (intersects(other)) {
734 return ResultNumber{};
735 }
736 auto edgeVector = edges();
737 ResultNumber best = edgeVector[0].template distanceL1<ResultNumber>(other);
738 for (auto& e : edgeVector) {
739 const ResultNumber current = e.template distanceL1<ResultNumber>(other);
740 if (current < best) {
741 best = current;
742 }
743 }
744 return best;
745}
746
747template <class PointType_, class LabelType>
748template <class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
749constexpr auto Convex<PointType_, LabelType>::distanceL1(const OtherOrientedSegment& other) const {
750 return this->template distanceL1<ResultNumber>(
752}
753
754template <class PointType_, class LabelType>
755template <class ResultNumber, ConvexConcept OtherConvex>
756constexpr auto Convex<PointType_, LabelType>::distanceL1(const OtherConvex& other) const {
757 if (intersects(other)) {
758 return ResultNumber{};
759 }
760
761 const auto minOverEdges = [](const auto& source, const auto& target) {
762 const auto edgeVector = source.edges();
763 ResultNumber best = target.template distanceL1<ResultNumber>(edgeVector[0]);
764 for (const auto& edge : edgeVector) {
765 const ResultNumber current = target.template distanceL1<ResultNumber>(edge);
766 if (current < best) {
767 best = current;
768 }
769 }
770 return best;
771 };
772
773 if (size() <= other.size()) {
774 return minOverEdges(*this, other);
775 }
776 return minOverEdges(other, *this);
777}
778
779template <class PointType_, class LabelType>
780template <class ResultNumber, TriangleConcept OtherTriangle>
781constexpr auto Convex<PointType_, LabelType>::distanceL1(const OtherTriangle& other) const {
782 return this->template distanceL1<ResultNumber>(other.asConvex());
783}
784
785template <class PointType_, class LabelType>
786template <class ResultNumber, RectangleConcept OtherRectangle>
787constexpr auto Convex<PointType_, LabelType>::distanceL1(const OtherRectangle& other) const {
788 return this->template distanceL1<ResultNumber>(other.asConvex());
789}
790
791template <class PointType_, class LabelType>
792template <class ResultNumber, LineConcept OtherLine>
793constexpr auto Convex<PointType_, LabelType>::distanceL1(const OtherLine& other) const {
794 if (intersects(other)) {
795 return ResultNumber{};
796 }
797 ResultNumber best = other.template distanceL1<ResultNumber>(get(0));
798 for (std::ptrdiff_t i = 1; i < static_cast<std::ptrdiff_t>(size()); ++i) {
799 const ResultNumber current = other.template distanceL1<ResultNumber>(get(i));
800 if (current < best) {
801 best = current;
802 }
803 }
804 return best;
805}
806
807template <class PointType_, class LabelType>
808template <class ResultNumber, OrientedLineConcept OtherOrientedLine>
809constexpr auto Convex<PointType_, LabelType>::distanceL1(const OtherOrientedLine& other) const {
810 return this->template distanceL1<ResultNumber>(other.asLine());
811}
812
813template <class PointType_, class LabelType>
814template <class ResultNumber, RayConcept OtherRay>
815constexpr auto Convex<PointType_, LabelType>::distanceL1(const OtherRay& other) const {
816 if (intersects(other)) {
817 return ResultNumber{};
818 }
819 auto edgeVector = edges();
820 ResultNumber best = other.template distanceL1<ResultNumber>(edgeVector[0]);
821 for (const auto& e : edgeVector) {
822 const ResultNumber current = other.template distanceL1<ResultNumber>(e);
823 if (current < best) {
824 best = current;
825 }
826 }
827 return best;
828}
829
830template <class PointType_, class LabelType>
831template <class ResultNumber, HalfplaneConcept OtherHalfplane>
832constexpr auto Convex<PointType_, LabelType>::distanceL1(const OtherHalfplane& other) const {
833 if (intersects(other)) {
834 return ResultNumber{};
835 }
836 return this->template distanceL1<ResultNumber>(other.asLine());
837}
838
839// -----------------------------------------------------------------------------
840// Polygon
841
842template <class PointType_, class TLabel>
843template <class ResultNumber, class OtherShape>
844constexpr ResultNumber Polygon<PointType_, TLabel>::edgeMinDistanceL1(const OtherShape& other) const {
845 const auto boundaryEdges = edges();
846 ResultNumber best = boundaryEdges[0].template distanceL1<ResultNumber>(other);
847 for (std::size_t index = 1; index < boundaryEdges.size(); ++index) {
848 const ResultNumber current = boundaryEdges[index].template distanceL1<ResultNumber>(other);
849 if (current < best) {
850 best = current;
851 }
852 }
853 return best;
854}
855
856template <class PointType_, class TLabel>
857template <class ResultNumber, PointConcept OtherPoint>
858constexpr auto Polygon<PointType_, TLabel>::distanceL1(const OtherPoint& point) const {
859 if (intersects(point)) {
860 return ResultNumber{};
861 }
862 return this->template edgeMinDistanceL1<ResultNumber>(point);
863}
864
865template <class PointType_, class TLabel>
866template <class ResultNumber, SegmentConcept OtherSegment>
867constexpr auto Polygon<PointType_, TLabel>::distanceL1(const OtherSegment& other) const {
868 if (intersects(other)) {
869 return ResultNumber{};
870 }
871 return this->template edgeMinDistanceL1<ResultNumber>(other);
872}
873
874template <class PointType_, class TLabel>
875template <class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
876constexpr auto Polygon<PointType_, TLabel>::distanceL1(const OtherOrientedSegment& other) const {
877 if (intersects(other)) {
878 return ResultNumber{};
879 }
880 return this->template edgeMinDistanceL1<ResultNumber>(other);
881}
882
883template <class PointType_, class TLabel>
884template <class ResultNumber, LineConcept OtherLine>
885constexpr auto Polygon<PointType_, TLabel>::distanceL1(const OtherLine& other) const {
886 if (intersects(other)) {
887 return ResultNumber{};
888 }
889 return this->template edgeMinDistanceL1<ResultNumber>(other);
890}
891
892template <class PointType_, class TLabel>
893template <class ResultNumber, OrientedLineConcept OtherOrientedLine>
894constexpr auto Polygon<PointType_, TLabel>::distanceL1(const OtherOrientedLine& other) const {
895 if (intersects(other)) {
896 return ResultNumber{};
897 }
898 return this->template edgeMinDistanceL1<ResultNumber>(other);
899}
900
901template <class PointType_, class TLabel>
902template <class ResultNumber, RayConcept OtherRay>
903constexpr auto Polygon<PointType_, TLabel>::distanceL1(const OtherRay& other) const {
904 if (intersects(other)) {
905 return ResultNumber{};
906 }
907 return this->template edgeMinDistanceL1<ResultNumber>(other);
908}
909
910template <class PointType_, class TLabel>
911template <class ResultNumber, HalfplaneConcept OtherHalfplane>
912constexpr auto Polygon<PointType_, TLabel>::distanceL1(const OtherHalfplane& other) const {
913 if (intersects(other)) {
914 return ResultNumber{};
915 }
916 return this->template edgeMinDistanceL1<ResultNumber>(other);
917}
918
919template <class PointType_, class TLabel>
920template <class ResultNumber, RectangleConcept OtherRectangle>
921constexpr auto Polygon<PointType_, TLabel>::distanceL1(const OtherRectangle& other) const {
922 if (intersects(other)) {
923 return ResultNumber{};
924 }
925 return this->template edgeMinDistanceL1<ResultNumber>(other);
926}
927
928template <class PointType_, class TLabel>
929template <class ResultNumber, TriangleConcept OtherTriangle>
930constexpr auto Polygon<PointType_, TLabel>::distanceL1(const OtherTriangle& other) const {
931 if (intersects(other)) {
932 return ResultNumber{};
933 }
934 return this->template edgeMinDistanceL1<ResultNumber>(other);
935}
936
937template <class PointType_, class TLabel>
938template <class ResultNumber, ConvexConcept OtherConvex>
939constexpr auto Polygon<PointType_, TLabel>::distanceL1(const OtherConvex& other) const {
940 if (intersects(other)) {
941 return ResultNumber{};
942 }
943 return this->template edgeMinDistanceL1<ResultNumber>(other);
944}
945
946template <class PointType_, class TLabel>
947template <class ResultNumber, PolygonConcept OtherPolygon>
948constexpr auto Polygon<PointType_, TLabel>::distanceL1(const OtherPolygon& other) const {
949 if (intersects(other)) {
950 return ResultNumber{};
951 }
952 return this->template edgeMinDistanceL1<ResultNumber>(other);
953}
954
955// -----------------------------------------------------------------------------
956// Hausdorff distance (added only where a Euclidean squaredHausdorffDistance
957// overload already exists; Polygon has none today, so it gets none here).
958
959template <class PointType, class LabelType>
960template <class ResultNumber, SegmentConcept OtherSegment>
961constexpr auto Segment<PointType, LabelType>::hausdorffDistanceL1(const OtherSegment& other) const {
962 const auto worst_from_this = detail::maxVertexDistanceL1<ResultNumber>(*this, other);
963 const auto worst_from_other = detail::maxVertexDistanceL1<ResultNumber>(other, *this);
964 return worst_from_this > worst_from_other ? worst_from_this : worst_from_other;
965}
966
967template <class PointType, class LabelType>
968template <class ResultNumber, PointConcept OtherPoint>
969constexpr auto Segment<PointType, LabelType>::hausdorffDistanceL1(const OtherPoint& point) const {
970 return detail::maxVertexDistanceL1<ResultNumber>(*this, point);
971}
972
973template <class PointType, class LabelType>
974template <class ResultNumber, SegmentConcept OtherSegment>
975constexpr auto OrientedSegment<PointType, LabelType>::hausdorffDistanceL1(const OtherSegment& other) const {
976 return static_cast<Segment<PointType>>(*this).template hausdorffDistanceL1<ResultNumber>(other);
977}
978
979template <class PointType, class LabelType>
980template <class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
981constexpr auto OrientedSegment<PointType, LabelType>::hausdorffDistanceL1(const OtherOrientedSegment& other) const {
982 return static_cast<Segment<PointType>>(*this).template hausdorffDistanceL1<ResultNumber>(
984}
985
986template <class PointType, class LabelType>
987template <class ResultNumber, PointConcept OtherPoint>
988constexpr auto OrientedSegment<PointType, LabelType>::hausdorffDistanceL1(const OtherPoint& point) const {
989 return static_cast<Segment<PointType>>(*this).template hausdorffDistanceL1<ResultNumber>(point);
990}
991
992template <class PointType, class LabelType>
993template <class ResultNumber, RectangleConcept OtherRectangle>
994constexpr auto Rectangle<PointType, LabelType>::hausdorffDistanceL1(const OtherRectangle& other) const {
995 // There is no nearest point of the empty set, so it has no distance to
996 // anything; asking for one is a precondition violation.
997 assert(!empty());
998 const auto worst_from_this = detail::maxVertexDistanceL1<ResultNumber>(*this, other);
999 const auto worst_from_other = detail::maxVertexDistanceL1<ResultNumber>(other, *this);
1000 return worst_from_this > worst_from_other ? worst_from_this : worst_from_other;
1001}
1002
1003template <class PointType, class LabelType>
1004template <class ResultNumber, PointConcept OtherPoint>
1005constexpr auto Rectangle<PointType, LabelType>::hausdorffDistanceL1(const OtherPoint& point) const {
1006 // There is no nearest point of the empty set, so it has no distance to
1007 // anything; asking for one is a precondition violation.
1008 assert(!empty());
1009 return detail::maxVertexDistanceL1<ResultNumber>(*this, point);
1010}
1011
1012template <class PointType, class LabelType>
1013template <class ResultNumber, SegmentConcept OtherSegment>
1014constexpr auto Rectangle<PointType, LabelType>::hausdorffDistanceL1(const OtherSegment& other) const {
1015 // There is no nearest point of the empty set, so it has no distance to
1016 // anything; asking for one is a precondition violation.
1017 assert(!empty());
1018 const auto worst_from_this = detail::maxVertexDistanceL1<ResultNumber>(*this, other);
1019 const auto worst_from_other = detail::maxVertexDistanceL1<ResultNumber>(other, *this);
1020 return worst_from_this > worst_from_other ? worst_from_this : worst_from_other;
1021}
1022
1023template <class PointType, class LabelType>
1024template <class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
1025constexpr auto Rectangle<PointType, LabelType>::hausdorffDistanceL1(const OtherOrientedSegment& other) const {
1026 // There is no nearest point of the empty set, so it has no distance to
1027 // anything; asking for one is a precondition violation.
1028 assert(!empty());
1029 const auto worst_from_this = detail::maxVertexDistanceL1<ResultNumber>(*this, other);
1030 const auto worst_from_other = detail::maxVertexDistanceL1<ResultNumber>(other, *this);
1031 return worst_from_this > worst_from_other ? worst_from_this : worst_from_other;
1032}
1033
1034template <class PointType, class LabelType>
1035template <class ResultNumber, PointConcept OtherPoint>
1036constexpr auto Triangle<PointType, LabelType>::hausdorffDistanceL1(const OtherPoint& point) const {
1037 return detail::maxVertexDistanceL1<ResultNumber>(*this, point);
1038}
1039
1040template <class PointType, class LabelType>
1041template <class ResultNumber, SegmentConcept OtherSegment>
1042constexpr auto Triangle<PointType, LabelType>::hausdorffDistanceL1(const OtherSegment& other) const {
1043 const auto worst_from_this = detail::maxVertexDistanceL1<ResultNumber>(*this, other);
1044 const auto worst_from_other = detail::maxVertexDistanceL1<ResultNumber>(other, *this);
1045 return worst_from_this > worst_from_other ? worst_from_this : worst_from_other;
1046}
1047
1048template <class PointType, class LabelType>
1049template <class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
1050constexpr auto Triangle<PointType, LabelType>::hausdorffDistanceL1(const OtherOrientedSegment& other) const {
1051 const auto worst_from_this = detail::maxVertexDistanceL1<ResultNumber>(*this, other);
1052 const auto worst_from_other = detail::maxVertexDistanceL1<ResultNumber>(other, *this);
1053 return worst_from_this > worst_from_other ? worst_from_this : worst_from_other;
1054}
1055
1056template <class PointType, class LabelType>
1057template <class ResultNumber, RectangleConcept OtherRectangle>
1058constexpr auto Triangle<PointType, LabelType>::hausdorffDistanceL1(const OtherRectangle& other) const {
1059 const auto worst_from_this = detail::maxVertexDistanceL1<ResultNumber>(*this, other);
1060 const auto worst_from_other = detail::maxVertexDistanceL1<ResultNumber>(other, *this);
1061 return worst_from_this > worst_from_other ? worst_from_this : worst_from_other;
1062}
1063
1064template <class PointType, class LabelType>
1065template <class ResultNumber, TriangleConcept OtherTriangle>
1066constexpr auto Triangle<PointType, LabelType>::hausdorffDistanceL1(const OtherTriangle& other) const {
1067 const auto worst_from_this = detail::maxVertexDistanceL1<ResultNumber>(*this, other);
1068 const auto worst_from_other = detail::maxVertexDistanceL1<ResultNumber>(other, *this);
1069 return worst_from_this > worst_from_other ? worst_from_this : worst_from_other;
1070}
1071
1072template <class PointType_, class LabelType>
1073template <class ResultNumber, PointConcept OtherPoint>
1074constexpr auto Convex<PointType_, LabelType>::hausdorffDistanceL1(const OtherPoint& point) const {
1075 return detail::maxVertexDistanceL1<ResultNumber>(*this, point);
1076}
1077
1078template <class PointType_, class LabelType>
1079template <class ResultNumber, SegmentConcept OtherSegment>
1080constexpr auto Convex<PointType_, LabelType>::hausdorffDistanceL1(const OtherSegment& other) const {
1081 const auto worst_from_this = detail::maxVertexDistanceL1<ResultNumber>(*this, other);
1082 const auto worst_from_other = detail::maxVertexDistanceL1<ResultNumber>(other, *this);
1083 return worst_from_this > worst_from_other ? worst_from_this : worst_from_other;
1084}
1085
1086template <class PointType_, class LabelType>
1087template <class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
1088constexpr auto Convex<PointType_, LabelType>::hausdorffDistanceL1(const OtherOrientedSegment& other) const {
1089 const auto worst_from_this = detail::maxVertexDistanceL1<ResultNumber>(*this, other);
1090 const auto worst_from_other = detail::maxVertexDistanceL1<ResultNumber>(other, *this);
1091 return worst_from_this > worst_from_other ? worst_from_this : worst_from_other;
1092}
1093
1094template <class PointType_, class LabelType>
1095template <class ResultNumber, RectangleConcept OtherRectangle>
1096constexpr auto Convex<PointType_, LabelType>::hausdorffDistanceL1(const OtherRectangle& other) const {
1097 const auto worst_from_this = detail::maxVertexDistanceL1<ResultNumber>(*this, other);
1098 const auto worst_from_other = detail::maxVertexDistanceL1<ResultNumber>(other, *this);
1099 return worst_from_this > worst_from_other ? worst_from_this : worst_from_other;
1100}
1101
1102template <class PointType_, class LabelType>
1103template <class ResultNumber, TriangleConcept OtherTriangle>
1104constexpr auto Convex<PointType_, LabelType>::hausdorffDistanceL1(const OtherTriangle& other) const {
1105 const auto worst_from_this = detail::maxVertexDistanceL1<ResultNumber>(*this, other);
1106 const auto worst_from_other = detail::maxVertexDistanceL1<ResultNumber>(other, *this);
1107 return worst_from_this > worst_from_other ? worst_from_this : worst_from_other;
1108}
1109
1110template <class PointType_, class LabelType>
1111template <class ResultNumber, ConvexConcept OtherConvex>
1112constexpr auto Convex<PointType_, LabelType>::hausdorffDistanceL1(const OtherConvex& other) const {
1113 const auto worst_from_this = detail::maxVertexDistanceL1<ResultNumber>(*this, other);
1114 const auto worst_from_other = detail::maxVertexDistanceL1<ResultNumber>(other, *this);
1115 return worst_from_this > worst_from_other ? worst_from_this : worst_from_other;
1116}
1117
1118
1119template <class PointType_, class TLabel>
1120template <class ResultNumber, MonotoneChainConcept OtherChain>
1121constexpr auto Polygon<PointType_, TLabel>::distanceL1(const OtherChain& other) const {
1122 if (intersects(other)) {
1123 return ResultNumber{};
1124 }
1125 return this->template edgeMinDistanceL1<ResultNumber>(other);
1126}
1127
1128// -----------------------------------------------------------------------------
1129// MonotoneChain
1130
1131template <class PointType, class LabelType, class Storage>
1132template <class ResultNumber, class OtherShape>
1133constexpr ResultNumber MonotoneChain<PointType, LabelType, Storage>::edgeMinDistanceL1(const OtherShape& other) const {
1134 assert(size() >= 1);
1135 if (size() == 1) {
1136 // A chain collapsed to a single vertex has no edge to measure from;
1137 // its distance is the distance from that vertex.
1138 return (*this)[0].template distanceL1<ResultNumber>(other);
1139 }
1140 ResultNumber best = this->template boundaryAt<false>(0).template distanceL1<ResultNumber>(other);
1141 for (std::size_t index = 1; index + 1 < size(); ++index) {
1142 const ResultNumber current =
1143 this->template boundaryAt<false>(index).template distanceL1<ResultNumber>(other);
1144 if (current < best) {
1145 best = current;
1146 }
1147 }
1148 return best;
1149}
1150
1151template <class PointType, class LabelType, class Storage>
1152template <class ResultNumber, PointConcept OtherPoint>
1153constexpr auto MonotoneChain<PointType, LabelType, Storage>::distanceL1(const OtherPoint& point) const {
1154 if (intersects(point)) {
1155 return ResultNumber{};
1156 }
1157 return this->template edgeMinDistanceL1<ResultNumber>(point);
1158}
1159
1160template <class PointType, class LabelType, class Storage>
1161template <class ResultNumber, SegmentConcept OtherSegment>
1162constexpr auto MonotoneChain<PointType, LabelType, Storage>::distanceL1(const OtherSegment& other) const {
1163 if (intersects(other)) {
1164 return ResultNumber{};
1165 }
1166 return this->template edgeMinDistanceL1<ResultNumber>(other);
1167}
1168
1169template <class PointType, class LabelType, class Storage>
1170template <class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
1171constexpr auto MonotoneChain<PointType, LabelType, Storage>::distanceL1(const OtherOrientedSegment& other) const {
1172 if (intersects(other)) {
1173 return ResultNumber{};
1174 }
1175 return this->template edgeMinDistanceL1<ResultNumber>(other);
1176}
1177
1178template <class PointType, class LabelType, class Storage>
1179template <class ResultNumber, LineConcept OtherLine>
1180constexpr auto MonotoneChain<PointType, LabelType, Storage>::distanceL1(const OtherLine& other) const {
1181 if (intersects(other)) {
1182 return ResultNumber{};
1183 }
1184 return this->template edgeMinDistanceL1<ResultNumber>(other);
1185}
1186
1187template <class PointType, class LabelType, class Storage>
1188template <class ResultNumber, OrientedLineConcept OtherOrientedLine>
1189constexpr auto MonotoneChain<PointType, LabelType, Storage>::distanceL1(const OtherOrientedLine& other) const {
1190 if (intersects(other)) {
1191 return ResultNumber{};
1192 }
1193 return this->template edgeMinDistanceL1<ResultNumber>(other);
1194}
1195
1196template <class PointType, class LabelType, class Storage>
1197template <class ResultNumber, RayConcept OtherRay>
1198constexpr auto MonotoneChain<PointType, LabelType, Storage>::distanceL1(const OtherRay& other) const {
1199 if (intersects(other)) {
1200 return ResultNumber{};
1201 }
1202 return this->template edgeMinDistanceL1<ResultNumber>(other);
1203}
1204
1205template <class PointType, class LabelType, class Storage>
1206template <class ResultNumber, HalfplaneConcept OtherHalfplane>
1207constexpr auto MonotoneChain<PointType, LabelType, Storage>::distanceL1(const OtherHalfplane& other) const {
1208 if (intersects(other)) {
1209 return ResultNumber{};
1210 }
1211 return this->template edgeMinDistanceL1<ResultNumber>(other);
1212}
1213
1214template <class PointType, class LabelType, class Storage>
1215template <class ResultNumber, RectangleConcept OtherRectangle>
1216constexpr auto MonotoneChain<PointType, LabelType, Storage>::distanceL1(const OtherRectangle& other) const {
1217 if (intersects(other)) {
1218 return ResultNumber{};
1219 }
1220 return this->template edgeMinDistanceL1<ResultNumber>(other);
1221}
1222
1223template <class PointType, class LabelType, class Storage>
1224template <class ResultNumber, TriangleConcept OtherTriangle>
1225constexpr auto MonotoneChain<PointType, LabelType, Storage>::distanceL1(const OtherTriangle& other) const {
1226 if (intersects(other)) {
1227 return ResultNumber{};
1228 }
1229 return this->template edgeMinDistanceL1<ResultNumber>(other);
1230}
1231
1232template <class PointType, class LabelType, class Storage>
1233template <class ResultNumber, ConvexConcept OtherConvex>
1234constexpr auto MonotoneChain<PointType, LabelType, Storage>::distanceL1(const OtherConvex& other) const {
1235 if (intersects(other)) {
1236 return ResultNumber{};
1237 }
1238 return this->template edgeMinDistanceL1<ResultNumber>(other);
1239}
1240
1241template <class PointType, class LabelType, class Storage>
1242template <class ResultNumber, MonotoneChainConcept OtherChain>
1243constexpr auto MonotoneChain<PointType, LabelType, Storage>::distanceL1(const OtherChain& other) const {
1244 if (intersects(other)) {
1245 return ResultNumber{};
1246 }
1247 return this->template edgeMinDistanceL1<ResultNumber>(other);
1248}
1249
1250// -----------------------------------------------------------------------------
1251// Polyline
1252
1253template <class PointType, class LabelType>
1254template <class ResultNumber, class OtherShape>
1255constexpr ResultNumber Polyline<PointType, LabelType>::edgeMinDistanceL1(const OtherShape& other) const {
1256 assert(size() >= 1);
1257 if (size() == 1) {
1258 // A polyline collapsed to a single vertex has no edge to measure from;
1259 // its distance is the distance from that vertex.
1260 return (*this)[0].template distanceL1<ResultNumber>(other);
1261 }
1262 ResultNumber best = this->template boundaryAt<false>(0).template distanceL1<ResultNumber>(other);
1263 for (std::size_t index = 1; index + 1 < size(); ++index) {
1264 const ResultNumber current =
1265 this->template boundaryAt<false>(index).template distanceL1<ResultNumber>(other);
1266 if (current < best) {
1267 best = current;
1268 }
1269 }
1270 return best;
1271}
1272
1273template <class PointType, class LabelType>
1274template <class ResultNumber, PointConcept OtherPoint>
1275constexpr auto Polyline<PointType, LabelType>::distanceL1(const OtherPoint& point) const {
1276 if (intersects(point)) {
1277 return ResultNumber{};
1278 }
1279 return this->template edgeMinDistanceL1<ResultNumber>(point);
1280}
1281
1282template <class PointType, class LabelType>
1283template <class ResultNumber, SegmentConcept OtherSegment>
1284constexpr auto Polyline<PointType, LabelType>::distanceL1(const OtherSegment& other) const {
1285 if (intersects(other)) {
1286 return ResultNumber{};
1287 }
1288 return this->template edgeMinDistanceL1<ResultNumber>(other);
1289}
1290
1291template <class PointType, class LabelType>
1292template <class ResultNumber, PolylineConcept OtherPolyline>
1293constexpr auto Polyline<PointType, LabelType>::distanceL1(const OtherPolyline& other) const {
1294 if (intersects(other)) {
1295 return ResultNumber{};
1296 }
1297 return this->template edgeMinDistanceL1<ResultNumber>(other);
1298}
1299
1300
1301template <class PointType, class LabelType>
1302template <class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
1303constexpr auto Polyline<PointType, LabelType>::distanceL1(const OtherOrientedSegment& other) const {
1304 if (intersects(other)) {
1305 return ResultNumber{};
1306 }
1307 return this->template edgeMinDistanceL1<ResultNumber>(other);
1308}
1309
1310template <class PointType, class LabelType>
1311template <class ResultNumber, LineConcept OtherLine>
1312constexpr auto Polyline<PointType, LabelType>::distanceL1(const OtherLine& other) const {
1313 if (intersects(other)) {
1314 return ResultNumber{};
1315 }
1316 return this->template edgeMinDistanceL1<ResultNumber>(other);
1317}
1318
1319template <class PointType, class LabelType>
1320template <class ResultNumber, OrientedLineConcept OtherOrientedLine>
1321constexpr auto Polyline<PointType, LabelType>::distanceL1(const OtherOrientedLine& other) const {
1322 if (intersects(other)) {
1323 return ResultNumber{};
1324 }
1325 return this->template edgeMinDistanceL1<ResultNumber>(other);
1326}
1327
1328template <class PointType, class LabelType>
1329template <class ResultNumber, RayConcept OtherRay>
1330constexpr auto Polyline<PointType, LabelType>::distanceL1(const OtherRay& other) const {
1331 if (intersects(other)) {
1332 return ResultNumber{};
1333 }
1334 return this->template edgeMinDistanceL1<ResultNumber>(other);
1335}
1336
1337template <class PointType, class LabelType>
1338template <class ResultNumber, HalfplaneConcept OtherHalfplane>
1339constexpr auto Polyline<PointType, LabelType>::distanceL1(const OtherHalfplane& other) const {
1340 if (intersects(other)) {
1341 return ResultNumber{};
1342 }
1343 return this->template edgeMinDistanceL1<ResultNumber>(other);
1344}
1345
1346template <class PointType, class LabelType>
1347template <class ResultNumber, RectangleConcept OtherRectangle>
1348constexpr auto Polyline<PointType, LabelType>::distanceL1(const OtherRectangle& other) const {
1349 if (intersects(other)) {
1350 return ResultNumber{};
1351 }
1352 return this->template edgeMinDistanceL1<ResultNumber>(other);
1353}
1354
1355template <class PointType, class LabelType>
1356template <class ResultNumber, TriangleConcept OtherTriangle>
1357constexpr auto Polyline<PointType, LabelType>::distanceL1(const OtherTriangle& other) const {
1358 if (intersects(other)) {
1359 return ResultNumber{};
1360 }
1361 return this->template edgeMinDistanceL1<ResultNumber>(other);
1362}
1363
1364template <class PointType, class LabelType>
1365template <class ResultNumber, ConvexConcept OtherConvex>
1366constexpr auto Polyline<PointType, LabelType>::distanceL1(const OtherConvex& other) const {
1367 if (intersects(other)) {
1368 return ResultNumber{};
1369 }
1370 return this->template edgeMinDistanceL1<ResultNumber>(other);
1371}
1372
1373template <class PointType, class LabelType>
1374template <class ResultNumber, MonotoneChainConcept OtherChain>
1375constexpr auto Polyline<PointType, LabelType>::distanceL1(const OtherChain& other) const {
1376 if (intersects(other)) {
1377 return ResultNumber{};
1378 }
1379 return this->template edgeMinDistanceL1<ResultNumber>(other);
1380}
1381
1382template <class PointType_, class TLabel>
1383template <class ResultNumber, PolylineConcept OtherPolyline>
1384constexpr auto Polygon<PointType_, TLabel>::distanceL1(const OtherPolyline& other) const {
1385 if (intersects(other)) {
1386 return ResultNumber{};
1387 }
1388 return this->template edgeMinDistanceL1<ResultNumber>(other);
1389}
1390
1391
1392// -----------------------------------------------------------------------------
1393// HalfplaneIntersection
1394//
1395// Minimum over the region's boundary edges of the edge-to-shape L1 distance,
1396// mirroring squaredDistance. Disk is excluded (the library defines L1/LInf to
1397// a disk only from a point). Querying the empty region is undefined behavior.
1398
1399namespace detail {
1400
1401template <class ResultNumber, class Region, class Other>
1402constexpr ResultNumber regionEdgesDistanceL1(const Region& region, const Other& other) {
1403 ResultNumber best{};
1404 bool has = false;
1405 for (std::size_t i = 0; i < region.size(); ++i) {
1406 const ResultNumber current = std::visit(
1407 [&other](const auto& piece) {
1408 return static_cast<ResultNumber>(piece.template distanceL1<ResultNumber>(other));
1409 },
1410 region.template edge<ResultNumber>(i));
1411 if (!has || current < best) {
1412 best = current;
1413 has = true;
1414 }
1415 }
1416 return best;
1417}
1418
1419} // namespace detail
1420
1421#define PGL_HPI_DISTANCE_L1(ConceptName, ArgType) \
1422 template <class PointType, class LabelType> \
1423 template <class ResultNumber, ConceptName ArgType> \
1424 constexpr auto HalfplaneIntersection<PointType, LabelType>::distanceL1( \
1425 const ArgType& other) const { \
1426 if (intersects(other)) { \
1427 return ResultNumber{}; \
1428 } \
1429 return detail::regionEdgesDistanceL1<ResultNumber>(*this, other); \
1430 }
1431
1445
1446#undef PGL_HPI_DISTANCE_L1
1447
1448template <class PointType, class LabelType>
1449template <class ResultNumber, HalfplaneIntersectionConcept OtherRegion>
1450constexpr auto HalfplaneIntersection<PointType, LabelType>::distanceL1(const OtherRegion& other) const {
1451 // Disjoint convex regions realize their distance on this region's
1452 // boundary; each edge re-dispatches into the other region's own edge scan.
1453 if (intersects(other)) {
1454 return ResultNumber{};
1455 }
1456 return detail::regionEdgesDistanceL1<ResultNumber>(*this, other);
1457}
1458
1459
1460// -----------------------------------------------------------------------------
1461// PolygonWithHoles
1462//
1463// See distance.hpp: a shape the closed region misses is nearest to a point of
1464// ∂A, so one scan over the edges of every ring answers all three metrics.
1465
1466template <class PointType, class LabelType>
1467template <class ResultNumber, class OtherShape>
1468constexpr ResultNumber PolygonWithHoles<PointType, LabelType>::edgeMinDistanceL1(const OtherShape& other) const {
1469 ResultNumber best{};
1470 bool seeded = false;
1471 anyBoundaryEdge([&](const auto& edge) {
1472 const ResultNumber current = edge.template distanceL1<ResultNumber>(other);
1473 if (!seeded || current < best) {
1474 best = current;
1475 seeded = true;
1476 }
1477 return false;
1478 });
1479 return best;
1480}
1481
1482template <class PointType, class LabelType>
1483template <class ResultNumber, PointConcept OtherPoint>
1484constexpr auto PolygonWithHoles<PointType, LabelType>::distanceL1(const OtherPoint& point) const {
1485 if (intersects(point)) {
1486 return ResultNumber{};
1487 }
1488 return this->template edgeMinDistanceL1<ResultNumber>(point);
1489}
1490
1491template <class PointType, class LabelType>
1492template <class ResultNumber, SegmentConcept OtherSegment>
1493constexpr auto PolygonWithHoles<PointType, LabelType>::distanceL1(const OtherSegment& other) const {
1494 if (intersects(other)) {
1495 return ResultNumber{};
1496 }
1497 return this->template edgeMinDistanceL1<ResultNumber>(other);
1498}
1499
1500template <class PointType, class LabelType>
1501template <class ResultNumber, OrientedSegmentConcept OtherOrientedSegment>
1502constexpr auto PolygonWithHoles<PointType, LabelType>::distanceL1(const OtherOrientedSegment& other) const {
1503 if (intersects(other)) {
1504 return ResultNumber{};
1505 }
1506 return this->template edgeMinDistanceL1<ResultNumber>(other);
1507}
1508
1509template <class PointType, class LabelType>
1510template <class ResultNumber, LineConcept OtherLine>
1511constexpr auto PolygonWithHoles<PointType, LabelType>::distanceL1(const OtherLine& other) const {
1512 if (intersects(other)) {
1513 return ResultNumber{};
1514 }
1515 return this->template edgeMinDistanceL1<ResultNumber>(other);
1516}
1517
1518template <class PointType, class LabelType>
1519template <class ResultNumber, OrientedLineConcept OtherOrientedLine>
1520constexpr auto PolygonWithHoles<PointType, LabelType>::distanceL1(const OtherOrientedLine& other) const {
1521 if (intersects(other)) {
1522 return ResultNumber{};
1523 }
1524 return this->template edgeMinDistanceL1<ResultNumber>(other);
1525}
1526
1527template <class PointType, class LabelType>
1528template <class ResultNumber, RayConcept OtherRay>
1529constexpr auto PolygonWithHoles<PointType, LabelType>::distanceL1(const OtherRay& other) const {
1530 if (intersects(other)) {
1531 return ResultNumber{};
1532 }
1533 return this->template edgeMinDistanceL1<ResultNumber>(other);
1534}
1535
1536template <class PointType, class LabelType>
1537template <class ResultNumber, HalfplaneConcept OtherHalfplane>
1538constexpr auto PolygonWithHoles<PointType, LabelType>::distanceL1(const OtherHalfplane& other) const {
1539 if (intersects(other)) {
1540 return ResultNumber{};
1541 }
1542 return this->template edgeMinDistanceL1<ResultNumber>(other);
1543}
1544
1545template <class PointType, class LabelType>
1546template <class ResultNumber, RectangleConcept OtherRectangle>
1547constexpr auto PolygonWithHoles<PointType, LabelType>::distanceL1(const OtherRectangle& other) const {
1548 if (intersects(other)) {
1549 return ResultNumber{};
1550 }
1551 return this->template edgeMinDistanceL1<ResultNumber>(other);
1552}
1553
1554template <class PointType, class LabelType>
1555template <class ResultNumber, TriangleConcept OtherTriangle>
1556constexpr auto PolygonWithHoles<PointType, LabelType>::distanceL1(const OtherTriangle& other) const {
1557 if (intersects(other)) {
1558 return ResultNumber{};
1559 }
1560 return this->template edgeMinDistanceL1<ResultNumber>(other);
1561}
1562
1563template <class PointType, class LabelType>
1564template <class ResultNumber, ConvexConcept OtherConvex>
1565constexpr auto PolygonWithHoles<PointType, LabelType>::distanceL1(const OtherConvex& other) const {
1566 if (intersects(other)) {
1567 return ResultNumber{};
1568 }
1569 return this->template edgeMinDistanceL1<ResultNumber>(other);
1570}
1571
1572template <class PointType, class LabelType>
1573template <class ResultNumber, PolygonConcept OtherPolygon>
1574constexpr auto PolygonWithHoles<PointType, LabelType>::distanceL1(const OtherPolygon& other) const {
1575 if (intersects(other)) {
1576 return ResultNumber{};
1577 }
1578 return this->template edgeMinDistanceL1<ResultNumber>(other);
1579}
1580
1581template <class PointType, class LabelType>
1582template <class ResultNumber, PolygonWithHolesConcept OtherRegion>
1583constexpr auto PolygonWithHoles<PointType, LabelType>::distanceL1(const OtherRegion& other) const {
1584 if (intersects(other)) {
1585 return ResultNumber{};
1586 }
1587 return this->template edgeMinDistanceL1<ResultNumber>(other);
1588}
1589
1590template <class PointType, class LabelType>
1591template <class ResultNumber, MonotoneChainConcept OtherChain>
1592constexpr auto PolygonWithHoles<PointType, LabelType>::distanceL1(const OtherChain& other) const {
1593 if (intersects(other)) {
1594 return ResultNumber{};
1595 }
1596 return this->template edgeMinDistanceL1<ResultNumber>(other);
1597}
1598
1599template <class PointType, class LabelType>
1600template <class ResultNumber, PolylineConcept OtherPolyline>
1601constexpr auto PolygonWithHoles<PointType, LabelType>::distanceL1(const OtherPolyline& other) const {
1602 if (intersects(other)) {
1603 return ResultNumber{};
1604 }
1605 return this->template edgeMinDistanceL1<ResultNumber>(other);
1606}
1607
1608template <class PointType, class LabelType>
1609template <class ResultNumber, HalfplaneIntersectionConcept OtherIntersection>
1610constexpr auto PolygonWithHoles<PointType, LabelType>::distanceL1(const OtherIntersection& other) const {
1611 if (intersects(other)) {
1612 return ResultNumber{};
1613 }
1614 return this->template edgeMinDistanceL1<ResultNumber>(other);
1615}
1616
1617// No Disk overload: the library defines the L1 and LInf distances to a disk
1618// only from a point.
1619
1620
1621// ---------------------------------------------------------------------------
1622// PolygonSet
1623//
1624// The distance to a union is the minimum of the distances, with no caveat and
1625// no operand it fails for. An empty set has no component to measure from and
1626// reports zero.
1627
1628template <class PointType, class LabelType>
1629template <class ResultNumber, detail::SetOperandConcept OtherShape>
1630 requires detail::ComponentDistanceL1Concept<ResultNumber, PolygonWithHoles<PointType>, OtherShape>
1631auto PolygonSet<PointType, LabelType>::distanceL1(const OtherShape& other) const {
1632 return minOverComponents([&other](const ComponentType& component) {
1633 return component.template distanceL1<ResultNumber>(other);
1634 });
1635}
1636
1637template <class PointType, class LabelType>
1638template <class ResultNumber, PolygonSetConcept OtherSet>
1639auto PolygonSet<PointType, LabelType>::distanceL1(const OtherSet& other) const {
1640 ResultNumber best{};
1641 bool seeded = false;
1642 for (const auto& component : other) {
1643 const ResultNumber current = this->template distanceL1<ResultNumber>(component);
1644 if (!seeded || current < best) {
1645 best = current;
1646 seeded = true;
1647 }
1648 }
1649 return best;
1650}
1651
1652} // namespace pgl
Definition forward.hpp:315
Definition forward.hpp:312
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:321
Definition forward.hpp:311
Definition forward.hpp:313
Definition forward.hpp:307
Definition forward.hpp:314
Distance and Hausdorff-style measurements between shapes.
#define PGL_HPI_DISTANCE_L1(ConceptName, ArgType)
Definition distancel1.hpp:1421
Definition arrangement.hpp:67
@ y
Definition intervaltree.hpp:24
@ x
Definition intervaltree.hpp:24
@ edge
Definition bitmatrix.hpp:37
@ vertex
Definition bitmatrix.hpp:37
Point() -> Point< int >
constexpr auto hausdorffDistanceL1(const OtherPoint &point) const
Returns the Manhattan (L1) Hausdorff distance to the given shape.
Definition distancel1.hpp:1074
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::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 auto distanceL1(const OtherPoint &point) const
Returns the Manhattan (L1) distance to the given shape.
Definition distancel1.hpp:715
size_t size() const
Returns the number of vertices in the convex polygon.
Definition convex.hpp:840
constexpr Point< ResultNumber, PointLabelType > center() const
Returns the center (circumcenter of the three boundary points) in an explicitly chosen coordinate typ...
Definition disk.hpp:284
constexpr bool contains(const OtherPoint &other) const
Tests whether this shape contains the other shape (A ⊇ B).
Definition contains.hpp:1015
constexpr ResultNumber radius() const
Returns the radius.
Definition disk.hpp:333
detail::floating_result_t< ResultNumber > distanceL1(const OtherPoint &point) const
Returns the Manhattan (L1) distance from this disk to a point.
Definition distancel1.hpp:203
constexpr const PointType & a() const
Returns the first boundary point (lexicographically smallest).
Definition disk.hpp:228
constexpr const PointType & b() const
Returns the second boundary point in canonical order.
Definition disk.hpp:235
constexpr bool intersects(const OtherPoint &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:1808
constexpr auto distanceL1(const OtherPoint &other) const
Returns the Manhattan (L1) distance to the given shape.
Definition distancel1.hpp:1432
constexpr auto distanceL1(const OtherPoint &point) const
Returns the Manhattan (L1) distance to the given shape.
Definition distancel1.hpp:407
constexpr bool intersects(const OtherPoint &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:622
constexpr Line< PointType > asLine() const
Returns the boundary line without orientation.
Definition halfplane.hpp:318
constexpr auto distanceL1(const OtherPoint &point) const
Returns the Manhattan (L1) distance to the given shape.
Definition distancel1.hpp:269
constexpr const PointType & max() const
Returns the largest stored defining point.
Definition line.hpp:189
constexpr const PointType & min() const
Returns the smallest stored defining point.
Definition line.hpp:180
constexpr bool intersects(const OtherPoint &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:312
constexpr bool intersects(const OtherPoint &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:1353
constexpr auto distanceL1(const OtherPoint &point) const
Returns the Manhattan (L1) distance to the given shape.
Definition distancel1.hpp:1153
constexpr Line< PointType > asLine() const
Returns the line without orientation.
Definition orientedline.hpp:321
constexpr auto distanceL1(const OtherPoint &point) const
Returns the Manhattan (L1) distance to the given shape.
Definition distancel1.hpp:306
constexpr auto hausdorffDistanceL1(const OtherSegment &other) const
Returns the Manhattan (L1) Hausdorff distance to the given shape.
Definition distancel1.hpp:975
constexpr auto distanceL1(const OtherPoint &point) const
Returns the Manhattan (L1) distance to the given shape.
Definition distancel1.hpp:247
Two-dimensional point with optional label payload.
Definition point.hpp:129
constexpr auto hausdorffDistanceL1(const OtherPoint &other) const
Returns the Manhattan (L1) Hausdorff distance to another point.
Definition distancel1.hpp:194
constexpr auto distanceL1(const OtherPoint &other) const
Returns the Manhattan distance to another point.
Definition distance.hpp:75
constexpr const ComponentType & component(std::size_t index) const
Accesses a component by index.
Definition polygonset.hpp:271
PolygonWithHoles< PointType > ComponentType
Definition polygonset.hpp:169
auto distanceL1(const OtherShape &other) const
Computes the squared Euclidean distance to the other shape.
Definition distancel1.hpp:1631
constexpr bool intersects(const OtherPoint &point) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition polygonwithholes.hpp:1649
constexpr auto distanceL1(const OtherPoint &point) const
Computes the squared Euclidean distance to the other shape.
Definition distancel1.hpp:1484
constexpr bool intersects(const OtherChain &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:1596
constexpr auto distanceL1(const OtherChain &other) const
Returns the Manhattan (L1) distance to the given shape.
Definition distancel1.hpp:1121
constexpr bool intersects(const OtherPoint &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:1620
constexpr auto distanceL1(const OtherPoint &point) const
Returns the Manhattan (L1) distance to the given shape.
Definition distancel1.hpp:1275
constexpr const PointType & target() const
Returns the second stored point defining the direction.
Definition ray.hpp:193
constexpr bool intersects(const OtherPoint &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:409
constexpr auto distanceL1(const OtherPoint &point) const
Returns the Manhattan (L1) distance to the given shape.
Definition distancel1.hpp:339
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< Segment< PointType >, 4 > edges() const
Returns the four edges as unordered segments.
Definition bounding.hpp:199
constexpr std::array< PointType, 4 > vertices() const
Returns the four vertices in counterclockwise order.
Definition bounding.hpp:188
constexpr std::ptrdiff_t index(const PointType &point) const
Returns the smallest index i with (*this)[i] == point, or -1 if no corner equals point.
Definition rectangle.hpp:330
constexpr auto distanceL1(const OtherPoint &point) const
Returns the Manhattan (L1) distance to the given shape.
Definition distancel1.hpp:473
constexpr const PointType & max() const
Returns the maximum corner (max x, max y).
Definition rectangle.hpp:359
constexpr auto hausdorffDistanceL1(const OtherRectangle &other) const
Returns the Manhattan (L1) Hausdorff distance to the given shape.
Definition distancel1.hpp:994
Unoriented closed segment between two endpoints plus optional segment label.
Definition segment.hpp:58
constexpr bool intersects(const OtherPoint &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:48
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 auto hausdorffDistanceL1(const OtherSegment &other) const
Returns the Manhattan (L1) Hausdorff distance to the given shape.
Definition distancel1.hpp:961
constexpr auto distanceL1(const OtherPoint &point) const
Returns the Manhattan (L1) distance to the given shape.
Definition distancel1.hpp:219
constexpr auto distanceL1(const OtherPoint &point) const
Returns the Manhattan (L1) distance to the given shape.
Definition distancel1.hpp:627
constexpr bool intersects(const OtherPoint &other) const
Tests whether this shape and the other shape intersect (A ∩ B ≠ ∅).
Definition intersects.hpp:134
constexpr auto hausdorffDistanceL1(const OtherPoint &point) const
Returns the Manhattan (L1) Hausdorff distance to the given shape.
Definition distancel1.hpp:1036