线线碰撞检测场景下浮点数运算时如何判断两条直线平行
两条线段平行判断的浮点数实现方案
理论基础
你代码中的den本质是两条线段方向向量的叉乘结果:设第一条线段的方向向量为v1 = (x2-x1, y2-y1),第二条线段的方向向量为v2 = (x4-x3, y4-y3),叉乘计算公式为den = v1.x * v2.y - v1.y * v2.x,理论上当且仅当叉乘值为0时,两条线段的方向完全平行。
浮点数场景的核心问题
你遇到的长度差异较大时判断失效的本质原因是:叉乘的绝对值等于|v1| * |v2| * sinθ,其中θ是两个向量的夹角。当两条线段都很长时,哪怕θ极小(几乎平行),|v1|*|v2|的乘积也会把极小的sinθ放大,导致den的绝对值远大于常规固定阈值(比如1e-6),无法正确识别平行状态。如果用固定阈值判断,对长线段会漏判平行,对短线段又会误判平行。
正确实现步骤
要消除向量长度的影响,需要对叉乘结果做归一化处理,仅通过夹角大小判断平行:
- 第一步:提前过滤无效线段,避免后续除0风险
// 计算两个线段长度的平方,避免提前开方损耗性能 float len1_sq = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1); float len2_sq = (x4-x3)*(x4-x3) + (y4-y3)*(y4-y3); const float eps_len_sq = 1e-12; // 任意线段两个端点几乎重合,属于无效线段,可按业务需求返回false或单独处理 if (len1_sq < eps_len_sq || len2_sq < eps_len_sq) { return false; }
- 第二步:归一化判断平行
float den = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); const float eps_theta = 1e-6; // 可根据精度需求调整,1e-6对应夹角约0.00057度 // 不开根号的优化写法,精度完全一致,避免开方运算损耗 if (den*den < eps_theta * eps_theta * len1_sq * len2_sq) { // 已判定两线段平行,此处可补充共线、重叠判断逻辑 // 平行状态下原代码直接除以den会触发除0错误,必须单独分支处理 return false; // 平行线段无交点,可根据需求调整返回值 }
- 第三步:保留原有非平行场景的相交判断
确认非平行后再执行你原有代码的uA、uB计算逻辑,不会出现除0问题。
内容的提问来源于stack exchange,提问作者Stefan Nastase
相关产品推荐
相关产品推荐

