如何判定同一球面上的两条大圆弧段是否相交
球面上两条大圆弧段相交判定方法
判定同一球面上的两条大圆弧段是否相交,用三维向量运算实现效率最高、数值稳定性最好,不需要做球面坐标转平面投影的操作,避免投影带来的极点畸变误差,是地理信息、计算机图形学、球面导航场景下的通用工业实现方案,具体步骤如下:
- 第一步:坐标归一化预处理
先把球面平移到三维坐标系原点,将半径缩放为1,把两条弧段的端点都转为单位向量:记弧段a的两个端点为单位向量A1、A2,弧段b的两个端点为单位向量B1、B2。 - 第二步:计算两个完整大圆的交点
大圆弧所在的平面一定过球心,先算两个大圆的平面法向量:
弧a所在平面法向量Na = cross(A1, A2)(cross为三维向量叉乘)
弧b所在平面法向量Nb = cross(B1, B2)
两个大圆所在平面的交线过球心,交线方向向量为P = cross(Na, Nb)
这里先判断P的模长:如果模长小于预设的浮点数容差(比如1e-8),说明两个大圆共面(重合),走特殊共面判定逻辑即可。
如果模长正常,把P归一化为单位向量p,对应的对径交点就是-p,两个完整大圆的交点只有这两个。 - 第三步:判断交点是否落在两条弧段范围内
两个交点p和-p只要有一个同时落在弧a、弧b上,就说明两条弧段相交。
对于默认取两点间劣弧的大圆弧段,判断单位点X是否在弧段(X1, X2)上的逻辑非常简单,不需要计算角度:单位向量的点积等于向量夹角的余弦值,只要X和X1的点积、X和X2的点积都大于等于X1和X2的点积(计算时减去容差避免浮点误差),就说明X落在X1、X2之间的劣弧上。
这个判断逻辑成立的原因是:X1、X2劣弧上的任意点,和两个端点的夹角都不会超过两个端点本身的夹角,对应的余弦值自然更大。如果业务场景里大圆弧段可能是优弧,只需要提前给弧段加优/劣弧标记,把判断条件反向即可。 - 特殊场景处理
- 共面(大圆重合)场景:分别检查四个端点A1、A2、B1、B2是否落在对方弧段上,再判断两段弧的覆盖范围是否有重叠,有重叠/端点落段即判定相交。
- 端点相接场景:上述点积判断逻辑会自动识别端点刚好落在另一段弧上的情况,不需要额外写分支,只要浮点数比较时留好容差即可,不要直接做精确相等判断。
核心逻辑伪代码参考:
const EPS = 1e-8 func isGreatArcIntersect(A1, A2, B1, B2 Vec3) bool: // 所有传入点需提前归一化为单位向量 Na = cross(A1, A2) Nb = cross(B1, B2) P = cross(Na, Nb) pLen = norm(P) if pLen < EPS: // 共面场景单独判定:检查端点落段、弧段重叠 return isCoPlanarArcIntersect(A1, A2, B1, B2) p = P / pLen // 遍历两个对径交点检查 for _, point := range []Vec3{p, p.Mul(-1)}: onA := (dot(point, A1) >= dot(A1, A2) - EPS) && (dot(point, A2) >= dot(A1, A2) - EPS) onB := (dot(point, B1) >= dot(B1, B2) - EPS) && (dot(point, B2) >= dot(B1, B2) - EPS) if onA && onB: return true return false
内容的提问来源于stack exchange,提问作者史越洋
相关产品推荐
相关产品推荐

