// David Eberly, Geometric Tools, Redmond WA 98052 // Copyright (c) 1998-2026 // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt // File Version: 8.0.2025.05.10 #pragma once // Compute the distance between a point and a segment in nD. // // The segment is P0 + t * (P1 - P0) for 0 <= t <= 1. The direction D = P1-P0 // is generally not unit length. // // The input point is stored in closest[0]. The closest point on the segment // is stored in closest[1]. When there are infinitely many choices for the // pair of closest points, only one of them is returned. #include #include #include #include #include namespace gte { template class DCPQuery, Segment> { public: struct Result { Result() : distance(static_cast(0)), sqrDistance(static_cast(0)), parameter(static_cast(0)), closest{ Vector::Zero(), Vector::Zero() } { } T distance, sqrDistance; T parameter; std::array, 2> closest; }; Result operator()(Vector const& point, Segment const& segment) { Result result{}; // The direction vector is not unit length. The normalization is // deferred until it is needed. T const zero = static_cast(0); T const one = static_cast(1); Vector direction = segment.p[1] - segment.p[0]; Vector diff = point - segment.p[1]; T t = Dot(direction, diff); if (t >= zero) { result.parameter = one; result.closest[1] = segment.p[1]; } else { diff = point - segment.p[0]; t = Dot(direction, diff); if (t <= zero) { result.parameter = zero; result.closest[1] = segment.p[0]; } else { T sqrLength = Dot(direction, direction); if (sqrLength > zero) { t /= sqrLength; result.parameter = t; result.closest[1] = segment.p[0] + t * direction; } else { result.parameter = zero; result.closest[1] = segment.p[0]; } } } result.closest[0] = point; diff = result.closest[0] - result.closest[1]; result.sqrDistance = Dot(diff, diff); result.distance = std::sqrt(result.sqrDistance); return result; } }; // Template aliases for convenience. template using DCPPointSegment = DCPQuery, Segment>; template using DCPPoint2Segment2 = DCPPointSegment<2, T>; template using DCPPoint3Segment3 = DCPPointSegment<3, T>; }