S02E04:点到线段的最近点坐标

234 阅读1分钟

说明

一般情况下,线段用两个点的方式定义,这种方式也可以很方便转换为点+向量的方式,类似于直线和射线。

//定义线段
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
}