1. 2D 隐式直线上的最近点
考虑 2D 中的直线 L , L 由所有满足 p⋅n=d 的点 p 组成。
其中 n 是单位向量,目标是对任意点 q ,找出直线 L 上距 q 距离最短的点 q′ ,它是 q 投影到 L 上的结果。

画一条经过 q 并平行于 L 的辅助线 M ,设 nM 和 dM 分别为直线方程的法向量和距离原点的距离。
由于 L 和 M 平行,所以他们法向量相等:nM=n 。
又 q 在 M 上,因此 dM=q⋅n 。
M 到 L 的 有符号距离 为:d−dM=d−q⋅n 。
- 这个距离显然等于 q 与 q′ 之间的距离(如果结果只需要距离而不是 q′ 的值,到这里就可以停止计算了)。
为了计算 q′ ,只需要将 q 沿着 n 的方向位移一定距离:
q′=q+(d−dM)n=q+(d−q⋅n)n
2. 参数射线上的最近点
在 2D 或 3D 中的参数射线 R:p(t)=porg+td
其中 d 是单位向量,参数 t 在 0 到 l 间变化, l 是 R 的长度。
对一给定点 q ,需要找出在 R 上离 q 最近的点 q′ 。
设 v 为 porg 到 q 的向量。我们希望得到 v 在 d 上的投影,或 v 平行于 d 的部分。

点乘 v⋅d 的结果就是满足 p(t)=q′ 的 t 值。
tq′=d⋅v=d⋅(q−porg)=p(t)=porg+td=porg+(d⋅(q−porg))d
等式 p(t) 求得了在包含 R 的直线上距 q 最近的点。
如果 t<0 或 t>l ,则 p(t) 不在 R 的范围内。
这种情况下, R 上距 q 最近的点是原点(如果 t<0 )或者终点(如果 t>l )。
如果射线的定义是 t 从 0 到 1 变化, d 不必是单位向量。那么在计算 t 值必须除以 d 的模:
t=∥d∥d⋅(q−porg)
3. 平面上的最近点
平面 p 的标准的隐式:p⋅n=d ;
其中 n 为单位向量。给定一点 q ,我们想要找到点 q′ ,它是 q 在 p 上的投影;
q′ 就是 p 上离 q 最近的点。

见 《05 - 平面类》 1.4 点到平面的距离:
a=q⋅n−d
计算 q′ ,只需要在 n 的方向上平移一段距离:
q′=q−a⋅n=q+(d−q⋅n)⋅n
4. 圆或球上的最近点
已知 2D 中的点 q 和圆心为 c 、半径为 r 的圆(也适用于 3D 中的球体)。
目标是找到一点 q′ ,它是圆上离 q 最近的点。
设 d 为从 q 指向 c 的向量。该向量和圆相较于 q′ 。设 b 为从 q 指向 q′ 的向量。

显然:
∥b∥=∥d∥−r
可得:
b=∥d∥∥d∥−rd
将此位移加至 q 上,则可将它投影到圆上:
q′=q+b=q+∥d∥∥d∥−rd
退化情况 :
- 若 ∥d∥<r,那么 q 在圆内部;
- 若 q=c ,那么 q 在圆心。
5. AABB 上的最近点
设 B 是由极值点 pmin 和 pmax 定义的 AABB 。
对任意点 q 均可计算出在 B 上距离 q 最近的点 q′ 。
主要思路是按一定顺序沿着每条轴将 q “推向” B 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
|
Vector3 AABB3::closestPointTo(const Vector3& p) const {
Vector3 r;
if (p.x < min.x) { r.x = min.x; } else if (p.x > max.x) { r.x = max.x; } else { r.x = p.x; }
if (p.y < min.y) { r.y = min.y; } else if (p.y > max.y) { r.y = max.y; } else { r.y = p.y; }
if (p.z < min.z) { r.z = min.z; } else if (p.z > max.z) { r.z = max.z; } else { r.z = p.z; }
return r; }
|