说明
一般情况下,线段用两个点的方式定义,这种方式也可以很方便转换为点+向量的方式,类似于直线和射线。
//定义线段
struct Segment {
let point1:simd_float3
let point2:simd_float3
}
几何
点到线段的最近点,其实本质上和点到射线是一样的,我们把线段 AB 当成两条射线:射线 AB 和射线 BA,分别计算就可以了:
可以看到,点 C 到射线 AB 的最近点是 D,但点 C 到射线 BA 的最近点是点 B。
所以,点 C 到线段 AB 的最近点,是点 B。计算过程与射线最近点是一样的,只是射线方向的归一化可以只做一次,因为 AB 和 BA 方向相反。
代码
///点到线段的最近点坐标
static func nearestPointOnSegment(from point:simd_float3, to segment:Segment) -> simd_float3 {
let direction = segment.point2 - segment.point1
let vector1 = point - segment.point1
let normalizedDirection = normalize(direction)
let dotValue1 = dot(vector1, normalizedDirection)
if dotValue1 <= 0 {
return segment.point1
}
let vector2 = point - segment.point2
let dotValue2 = dot(vector2, -normalizedDirection)
if dotValue2 <= 0 {
return segment.point2
}
let tarPoint = segment.point1 + dotValue1 * normalizedDirection
return tarPoint
}