给定线段 s→e 与点 p,返回点到线段的最短距离;并给出“线段-线段”最近距离的典型扩展思路与边界处理。
Returns the shortest distance between point p and the line segment from point s to e. Usage: Point
a, b(2,2), p(1,1); bool onSegment = segDist(a,b,p) < 1e-10; Status: tested
展开阐述
-
定义与背景
- 对象:二维点/向量 P(常用 double/long long,见 039-几何-点),线段由端点 s,e 表示。
- 目标:最短距离 d = min_{t∈[0,1]} | s + t(e−s) − p |,对应“投影裁剪”的标准模型。
- 适用:最近点查询、点在段上判定的几何阈值(与 038-几何-点在线段上 协同)、碰撞检测的最短分离向量求解。
-
接口/数据结构(据实现)
- 函数签名:template
double segDist(P& s, P& e, P& p) - s,e:线段端点;p:查询点
- 返回:最短距离(double)
- 类型注意:当 P=Point
时,内部涉及点积/模长平方等“三坐标乘积/平方和”,大坐标可能溢出;建议以 long double 计算中间量。
- 函数签名:template
-
核心流程/要点(向量投影 + 区间裁剪)
- 退化判定
- 若 s==e:线段退化为点,直接返回 |p−s|
- 投影参数
- 设 v = e−s,d = |v|²
- 原始参数 τ = (p−s)·v
- 裁剪 t = clamp(τ, 0, d)
- 最近点与距离
- 最近点 q = s + v·(t/d)
- 返回 |p−q|
- 与“点在线段上”关系
- 若 segDist(s,e,p) ≤ eps,则可视为 p 落在 s–e 段内(见 038-几何-点在线段上 的阈值策略)
- 退化判定
-
复杂度与边界条件
- 时间复杂度:O(1)
- 边界/退化:
- s==e:直接点距
- 极短线段:|v|²≈0 时需以 eps 判零避免数值爆炸
- 数值与溢出:
- 整型:dot(v, w) 与 |v|² 可能超 64 位;可改用 128 位中间值或切换到长浮点
- 浮点:统一 eps(如 1e−9)用于“在段上/端点吸附”的阈值判断
-
扩展:线段-线段最近距离(典型方案)
- 思路:设两段 s1–e1、s2–e2
- 若两段相交(见 048-几何-线段相交),距离为 0
- 否则,取四种候选:
- 点 s1 到段 s2–e2 的 segDist
- 点 e1 到段 s2–e2 的 segDist
- 点 s2 到段 s1–e1 的 segDist
- 点 e2 到段 s1–e1 的 segDist
- 取四者最小值即为段段最近距离
- 说明:该模式内隐地完成了“对端点投影后落段内则取垂距,否则取端点距”的全覆盖分类
- 思路:设两段 s1–e1、s2–e2
-
变体/协同
- 点到射线距离:将 t 裁剪到 [0, +∞)
- 与 032-几何-点线距离 协同:共享“分子/分母”(有向面积与 |v|),可缓存以降常数
- 与 035-几何-线的投影与反射 协同:若还需最近点坐标 q,可直接返回投影点作为下游输入
-
正确性要点与不变式
- 投影裁剪:在仿射参数域 [0,1] 上取最优,保证覆盖“端点-垂足-端点”的三类情形且彼此无遗漏
- 方向一致性:所有向量以差向量构造,避免坐标原点依赖
-
与相邻技术的对比与取舍
- 与枚举端点距离相比:加入投影裁剪后可在线段内部得到垂距(更短)
- 与显式解二次函数相比:向量法更短且稳定,与其他几何原语可复用