42template <
class Self,
class Other>
43using closestCompare_t =
53template <
class ShapeType>
54constexpr auto coveringSegments(
const ShapeType& shape) {
55 if constexpr (PointConcept<ShapeType>) {
58 auto result = shape.edges();
59 if constexpr (
requires(
decltype(result)& growable) { growable.emplace_back(); }) {
61 for (
const auto&
vertex : shape.vertices()) {
77template <
class Self,
class Other>
78constexpr auto closestNativeSegments(
const Self& self,
const Other& other) {
79 using Compare = closestCompare_t<Self, Other>;
80 const auto selfSegments = coveringSegments(self);
81 const auto otherSegments = coveringSegments(other);
82 using SelfSegment =
typename std::decay_t<
decltype(selfSegments)>::value_type;
83 using OtherSegment =
typename std::decay_t<
decltype(otherSegments)>::value_type;
84 using Result = std::optional<std::pair<SelfSegment, OtherSegment>>;
86 if (selfSegments.empty() || otherSegments.empty()) {
89 if (self.template squaredDistance<Compare>(other) == Compare{}) {
93 std::size_t bestSelf = 0;
94 std::size_t bestOther = 0;
95 Compare best = selfSegments[0].template squaredDistance<Compare>(otherSegments[0]);
96 for (std::size_t i = 0; i < selfSegments.size(); ++i) {
97 for (std::size_t j = 0; j < otherSegments.size(); ++j) {
98 const Compare candidate =
99 selfSegments[i].template squaredDistance<Compare>(otherSegments[j]);
100 if (candidate < best) {
107 return Result{std::pair<SelfSegment, OtherSegment>{selfSegments[bestSelf], otherSegments[bestOther]}};
111template <
class ResultNumber,
class LabelType,
class Self,
class Other>
112constexpr auto closestSegmentsOf(
const Self& self,
const Other& other) {
114 using Result = std::optional<std::array<ResultSegment, 2>>;
116 const auto native = closestNativeSegments(self, other);
120 return Result{std::array<ResultSegment, 2>{ResultSegment(native->first), ResultSegment(native->second)}};
130template <
class Piece>
131constexpr auto pieceEnds(
const Piece& piece) {
132 using PiecePoint =
typename Piece::PointType;
133 if constexpr (LineConcept<Piece>) {
134 return std::array<PiecePoint, 0>{};
135 }
else if constexpr (RayConcept<Piece>) {
136 return std::array<PiecePoint, 1>{piece.source()};
138 return std::array<PiecePoint, 2>{piece.min(), piece.max()};
148template <
class ResultNumber,
class LabelType,
class Piece,
class QueryPo
int>
151 constexpr bool stopsAtOrigin = !LineConcept<Piece>;
152 constexpr bool stopsAtHeading = !LineConcept<Piece> && !RayConcept<Piece>;
156 const auto& origin = [&piece]() ->
const auto& {
157 if constexpr (RayConcept<Piece>) {
158 return piece.source();
163 const auto& heading = [&piece]() ->
const auto& {
164 if constexpr (RayConcept<Piece>) {
165 return piece.target();
175 const auto along = second - first;
176 const auto toTarget = target - first;
177 const auto squaredLength = along * along;
179 if (squaredLength == ResultNumber{}) {
180 return ResultPoint(origin);
182 if constexpr (stopsAtOrigin) {
183 if (
dotSign(toTarget, along) <= 0) {
184 return ResultPoint(origin);
187 if constexpr (stopsAtHeading) {
188 if (
dotSign(target - second, along) >= 0) {
189 return ResultPoint(heading);
192 const ResultNumber ratio = (toTarget * along) / squaredLength;
193 return ResultPoint(first.x() + ratio * along.x(), first.y() + ratio * along.y());
197template <
class ResultNumber,
class LabelType>
198struct ClosestCandidate {
199 std::optional<std::array<Point<ResultNumber, LabelType>, 2>> pair{};
200 ResultNumber distance{};
208template <
class ResultNumber,
class LabelType,
class FirstPiece,
class SecondPiece>
209constexpr void offerPiecePair(
const FirstPiece& first,
const SecondPiece& second,
210 ClosestCandidate<ResultNumber, LabelType>& best) {
212 const auto offer = [&best](ResultPoint here, ResultPoint there) {
213 const ResultNumber distance = here.template squaredDistance<ResultNumber>(there);
214 if (!best.pair || distance < best.distance) {
215 best.distance = distance;
216 best.pair = std::array<ResultPoint, 2>{std::move(here), std::move(there)};
219 for (
const auto& end : pieceEnds(first)) {
220 offer(ResultPoint(end), closestPointOn<ResultNumber, LabelType>(second, end));
222 for (
const auto& end : pieceEnds(second)) {
223 offer(closestPointOn<ResultNumber, LabelType>(first, end), ResultPoint(end));
234template <
class ResultNumber,
class Unbounded,
class Visitor>
235constexpr void forEachBoundaryPiece(
const Unbounded& shape, Visitor&& visitor) {
236 if constexpr (HalfplaneIntersectionConcept<Unbounded>) {
240 for (std::size_t i = 0; i < shape.size(); ++i) {
241 std::visit([&visitor](
const auto& piece) { visitor(piece); },
244 }
else if constexpr (LineConcept<Unbounded>) {
246 }
else if constexpr (RayConcept<Unbounded>) {
251 visitor(shape.asLine());
256template <
class ResultNumber,
class LabelType,
class Self,
class Other>
257constexpr auto closestPointsOf(
const Self& self,
const Other& other) {
258 using Compare = closestCompare_t<Self, Other>;
260 using Result = std::optional<std::array<ResultPoint, 2>>;
262 ClosestCandidate<Compare, LabelType> best;
263 if constexpr (BoundedPolygonalConcept<Self> && BoundedPolygonalConcept<Other>) {
266 const auto native = closestNativeSegments(self, other);
270 offerPiecePair<Compare, LabelType>(native->first, native->second, best);
271 }
else if (self.template squaredDistance<Compare>(other) == Compare{}) {
273 }
else if constexpr (BoundedPolygonalConcept<Self>) {
274 const auto mine = coveringSegments(self);
275 forEachBoundaryPiece<Compare>(other, [&mine, &best](
const auto& piece) {
276 for (
const auto& element : mine) {
277 offerPiecePair<Compare, LabelType>(element, piece, best);
281 const auto theirs = coveringSegments(other);
282 forEachBoundaryPiece<Compare>(self, [&theirs, &best](
const auto& piece) {
283 for (
const auto& element : theirs) {
284 offerPiecePair<Compare, LabelType>(piece, element, best);
292 return Result{std::array<ResultPoint, 2>{ResultPoint((*best.pair)[0]), ResultPoint((*best.pair)[1])}};
297template <
class TNumber,
class TLabel>
298template <
class ResultNumber, BoundedPolygonalConcept OtherShape>
299 requires detail::ClosestPairConcept<Point<TNumber, TLabel>, OtherShape>
301 return detail::closestSegmentsOf<ResultNumber, TLabel>(*
this, other);
304template <
class TNumber,
class TLabel>
305template <
class ResultNumber,
class OtherShape>
306 requires detail::ClosestPointsPairConcept<Point<TNumber, TLabel>, OtherShape>
308 return detail::closestPointsOf<ResultNumber, TLabel>(*
this, other);
311template <
class TPo
int,
class TLabel>
312template <
class ResultNumber, BoundedPolygonalConcept OtherShape>
313 requires detail::ClosestPairConcept<Segment<TPoint, TLabel>, OtherShape>
315 return detail::closestSegmentsOf<ResultNumber, typename TPoint::LabelType>(*
this, other);
318template <
class TPo
int,
class TLabel>
319template <
class ResultNumber,
class OtherShape>
320 requires detail::ClosestPointsPairConcept<Segment<TPoint, TLabel>, OtherShape>
322 return detail::closestPointsOf<ResultNumber, typename TPoint::LabelType>(*
this, other);
325template <
class Po
intType_,
class TLabel>
326template <
class ResultNumber, BoundedPolygonalConcept OtherShape>
327 requires detail::ClosestPairConcept<OrientedSegment<PointType_, TLabel>, OtherShape>
329 return detail::closestSegmentsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
332template <
class Po
intType_,
class TLabel>
333template <
class ResultNumber,
class OtherShape>
334 requires detail::ClosestPointsPairConcept<OrientedSegment<PointType_, TLabel>, OtherShape>
336 return detail::closestPointsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
339template <
class Po
intType_,
class TLabel>
340template <
class ResultNumber, BoundedPolygonalConcept OtherShape>
341 requires detail::ClosestPairConcept<Rectangle<PointType_, TLabel>, OtherShape>
343 return detail::closestSegmentsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
346template <
class Po
intType_,
class TLabel>
347template <
class ResultNumber,
class OtherShape>
348 requires detail::ClosestPointsPairConcept<Rectangle<PointType_, TLabel>, OtherShape>
350 return detail::closestPointsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
353template <
class Po
intType_,
class TLabel>
354template <
class ResultNumber, BoundedPolygonalConcept OtherShape>
355 requires detail::ClosestPairConcept<Triangle<PointType_, TLabel>, OtherShape>
357 return detail::closestSegmentsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
360template <
class Po
intType_,
class TLabel>
361template <
class ResultNumber,
class OtherShape>
362 requires detail::ClosestPointsPairConcept<Triangle<PointType_, TLabel>, OtherShape>
364 return detail::closestPointsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
367template <
class Po
intType_,
class TLabel>
368template <
class ResultNumber, BoundedPolygonalConcept OtherShape>
369 requires detail::ClosestPairConcept<Convex<PointType_, TLabel>, OtherShape>
371 return detail::closestSegmentsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
374template <
class Po
intType_,
class TLabel>
375template <
class ResultNumber,
class OtherShape>
376 requires detail::ClosestPointsPairConcept<Convex<PointType_, TLabel>, OtherShape>
378 return detail::closestPointsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
381template <
class Po
intType_,
class TLabel,
class Storage>
382template <
class ResultNumber, BoundedPolygonalConcept OtherShape>
383 requires detail::ClosestPairConcept<MonotoneChain<PointType_, TLabel, Storage>, OtherShape>
385 return detail::closestSegmentsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
388template <
class Po
intType_,
class TLabel,
class Storage>
389template <
class ResultNumber,
class OtherShape>
390 requires detail::ClosestPointsPairConcept<MonotoneChain<PointType_, TLabel, Storage>, OtherShape>
392 return detail::closestPointsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
395template <
class Po
intType_,
class TLabel>
396template <
class ResultNumber, BoundedPolygonalConcept OtherShape>
397 requires detail::ClosestPairConcept<Polyline<PointType_, TLabel>, OtherShape>
399 return detail::closestSegmentsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
402template <
class Po
intType_,
class TLabel>
403template <
class ResultNumber,
class OtherShape>
404 requires detail::ClosestPointsPairConcept<Polyline<PointType_, TLabel>, OtherShape>
406 return detail::closestPointsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
409template <
class Po
intType_,
class TLabel>
410template <
class ResultNumber, BoundedPolygonalConcept OtherShape>
411 requires detail::ClosestPairConcept<Polygon<PointType_, TLabel>, OtherShape>
413 return detail::closestSegmentsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
416template <
class Po
intType_,
class TLabel>
417template <
class ResultNumber,
class OtherShape>
418 requires detail::ClosestPointsPairConcept<Polygon<PointType_, TLabel>, OtherShape>
420 return detail::closestPointsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
423template <
class Po
intType_,
class TLabel>
424template <
class ResultNumber, BoundedPolygonalConcept OtherShape>
425 requires detail::ClosestPairConcept<PolygonWithHoles<PointType_, TLabel>, OtherShape>
427 return detail::closestSegmentsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
430template <
class Po
intType_,
class TLabel>
431template <
class ResultNumber,
class OtherShape>
432 requires detail::ClosestPointsPairConcept<PolygonWithHoles<PointType_, TLabel>, OtherShape>
434 return detail::closestPointsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
437template <
class Po
intType_,
class TLabel>
438template <
class ResultNumber, BoundedPolygonalConcept OtherShape>
439 requires detail::ClosestPairConcept<PolygonSet<PointType_, TLabel>, OtherShape>
441 return detail::closestSegmentsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
444template <
class Po
intType_,
class TLabel>
445template <
class ResultNumber,
class OtherShape>
446 requires detail::ClosestPointsPairConcept<PolygonSet<PointType_, TLabel>, OtherShape>
448 return detail::closestPointsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
451template <
class Po
intType_,
class TLabel>
452template <
class ResultNumber,
class OtherShape>
453 requires detail::ClosestPointsPairConcept<Line<PointType_, TLabel>, OtherShape>
455 return detail::closestPointsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
458template <
class Po
intType_,
class TLabel>
459template <
class ResultNumber,
class OtherShape>
460 requires detail::ClosestPointsPairConcept<OrientedLine<PointType_, TLabel>, OtherShape>
462 return detail::closestPointsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
465template <
class Po
intType_,
class TLabel>
466template <
class ResultNumber,
class OtherShape>
467 requires detail::ClosestPointsPairConcept<Ray<PointType_, TLabel>, OtherShape>
469 return detail::closestPointsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
472template <
class Po
intType_,
class TLabel>
473template <
class ResultNumber,
class OtherShape>
474 requires detail::ClosestPointsPairConcept<Halfplane<PointType_, TLabel>, OtherShape>
476 return detail::closestPointsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
479template <
class Po
intType_,
class TLabel>
480template <
class ResultNumber,
class OtherShape>
481 requires detail::ClosestPointsPairConcept<HalfplaneIntersection<PointType_, TLabel>, OtherShape>
483 return detail::closestPointsOf<ResultNumber, typename PointType_::LabelType>(*
this, other);
Distance and Hausdorff-style measurements between shapes.
Definition arrangement.hpp:67
@ edge
Definition bitmatrix.hpp:37
@ vertex
Definition bitmatrix.hpp:37
typename DivisionResult< Number >::type division_result_t
Convenience alias for DivisionResult.
Definition rational.hpp:1175
constexpr std::partial_ordering dotSign(const Point< ANumber, ALabel > &a, const Point< BNumber, BLabel > &b)
Tells if the angle between two vectors is acute, right, or obtuse.
Definition orientation.hpp:688
Segment() -> Segment< Point<>, NoLabel >
constexpr auto closestPoints(const OtherShape &other) const
Returns the pair of points realizing the distance, nothing when the shapes meet.
Definition closest.hpp:377
constexpr auto closestSegments(const OtherShape &other) const
Returns the pair of elements realizing the distance, nothing when the shapes meet.
Definition closest.hpp:370
constexpr auto closestPoints(const OtherShape &other) const
Returns the pair of points realizing the distance, nothing when the shapes meet.
Definition closest.hpp:482
constexpr auto closestPoints(const OtherShape &other) const
Returns the pair of points realizing the distance, nothing when the shapes meet.
Definition closest.hpp:475
constexpr auto closestPoints(const OtherShape &other) const
Returns the pair of points realizing the distance, nothing when the shapes meet.
Definition closest.hpp:454
constexpr auto closestSegments(const OtherShape &other) const
Returns the pair of elements realizing the distance, nothing when the shapes meet.
Definition closest.hpp:384
constexpr auto closestPoints(const OtherShape &other) const
Returns the pair of points realizing the distance, nothing when the shapes meet.
Definition closest.hpp:391
constexpr auto closestPoints(const OtherShape &other) const
Returns the pair of points realizing the distance, nothing when the shapes meet.
Definition closest.hpp:461
constexpr auto closestSegments(const OtherShape &other) const
Returns the pair of elements realizing the distance, nothing when the shapes meet.
Definition closest.hpp:328
constexpr auto closestPoints(const OtherShape &other) const
Returns the pair of points realizing the distance, nothing when the shapes meet.
Definition closest.hpp:335
constexpr auto closestPoints(const OtherShape &other) const
Returns the pair of points realizing the distance, nothing when the shapes meet.
Definition closest.hpp:307
constexpr auto closestSegments(const OtherShape &other) const
Returns the pair of elements realizing the distance, nothing when the shapes meet.
Definition closest.hpp:300
auto closestSegments(const OtherShape &other) const
Returns the pair of elements realizing the distance, nothing when the shapes meet.
Definition closest.hpp:440
auto closestPoints(const OtherShape &other) const
Returns the pair of points realizing the distance, nothing when the shapes meet.
Definition closest.hpp:447
constexpr auto closestPoints(const OtherShape &other) const
Returns the pair of points realizing the distance, nothing when the shapes meet.
Definition closest.hpp:433
constexpr auto closestSegments(const OtherShape &other) const
Returns the pair of elements realizing the distance, nothing when the shapes meet.
Definition closest.hpp:426
constexpr auto closestPoints(const OtherShape &other) const
Returns the pair of points realizing the distance, nothing when the shapes meet.
Definition closest.hpp:419
constexpr auto closestSegments(const OtherShape &other) const
Returns the pair of elements realizing the distance, nothing when the shapes meet.
Definition closest.hpp:412
constexpr auto closestSegments(const OtherShape &other) const
Returns the pair of elements realizing the distance, nothing when the shapes meet.
Definition closest.hpp:398
constexpr auto closestPoints(const OtherShape &other) const
Returns the pair of points realizing the distance, nothing when the shapes meet.
Definition closest.hpp:405
constexpr auto closestPoints(const OtherShape &other) const
Returns the pair of points realizing the distance, nothing when the shapes meet.
Definition closest.hpp:468
constexpr auto closestSegments(const OtherShape &other) const
Returns the pair of elements realizing the distance, nothing when the shapes meet.
Definition closest.hpp:342
constexpr auto closestPoints(const OtherShape &other) const
Returns the pair of points realizing the distance, nothing when the shapes meet.
Definition closest.hpp:349
constexpr auto closestSegments(const OtherShape &other) const
Returns the pair of elements realizing the distance, nothing when the shapes meet.
Definition closest.hpp:314
constexpr auto closestPoints(const OtherShape &other) const
Returns the pair of points realizing the distance, nothing when the shapes meet.
Definition closest.hpp:321
constexpr auto closestPoints(const OtherShape &other) const
Returns the pair of points realizing the distance, nothing when the shapes meet.
Definition closest.hpp:363
constexpr auto closestSegments(const OtherShape &other) const
Returns the pair of elements realizing the distance, nothing when the shapes meet.
Definition closest.hpp:356