两平面求交算法中的除零问题解决方案咨询
你当前实现的两平面交线算法,在大多数场景下能正常运行,但碰到某些特殊平面(比如垂直于坐标轴的平面)时,会因为$P1->A * $P2->B - $P2->A * $P1->B这个分母为0触发除零错误——但这种情况其实是有交线的,比如你举的例子:
Plane1: A = 0 B = 0 C = 100 D = 0
Plane2: A = 50 B = 0 C = 0 D = -250
这两个平面的交线是明确存在的(x=5,z=0,y可取任意值),问题出在你当前的公式只适配了xy平面投影不平行的情况,当分母为0时,咱们得换个思路计算。
核心思路调整
两平面的交线方向向量,本质是两个平面法向量的叉乘(因为交线同时垂直于两个平面的法向量),而交线上的点只需要找到同时满足两个平面方程的任意一点即可——不用死磕固定的xy平面投影求解,而是根据方向向量的分量灵活选择求解方式:
计算方向向量:
两个平面的法向量分别是(P1->A, P1->B, P1->C)和(P2->A, P2->B, P2->C),它们的叉乘结果就是交线的方向向量(a,b,c):$a = $P1->B * $P2->C - $P2->B * $P1->C; $b = $P1->C * $P2->A - $P2->C * $P1->A; $c = $P1->A * $P2->B - $P2->A * $P1->B;(注:如果
a,b,c全为0,说明两个平面平行,无交线,这时候可以直接返回null或者抛出异常)寻找交线上的一点:
我们需要找任意一个满足两个平面方程的点(x0,y0,z0),这时候根据方向向量的分量是否为0来选择固定哪个坐标:- 如果
c != 0(z分量不为0):固定z0=0,解x和y(就是你原来的计算方式) - 如果
c == 0但b != 0(y分量不为0):固定y0=0,代入两个平面方程解x和z - 如果
c == 0且b == 0:那a肯定不为0,固定x0=0,代入两个平面方程解y和z
- 如果
修改后的代码实现
public static function getIntersectOf2Planes(self $P1, self $P2) { // 计算方向向量(法向量叉乘) $a = $P1->B * $P2->C - $P2->B * $P1->C; $b = $P1->C * $P2->A - $P2->C * $P1->A; $c = $P1->A * $P2->B - $P2->A * $P1->B; // 方向向量全为0,说明两平面平行,无交线 if (abs($a) < 1e-9 && abs($b) < 1e-9 && abs($c) < 1e-9) { return null; // 或者根据需求抛出异常 } $x0 = 0; $y0 = 0; $z0 = 0; // 根据方向向量分量选择求解方式,用微小值判断避免浮点精度问题 if (abs($c) > 1e-9) { // 固定z=0,解x和y $denominator = $P1->A * $P2->B - $P2->A * $P1->B; $x0 = ($P1->B * $P2->D - $P2->B * $P1->D) / $denominator; $y0 = ($P2->A * $P1->D - $P1->A * $P2->D) / $denominator; } elseif (abs($b) > 1e-9) { // 固定y=0,解x和z $denominator = $P1->A * $P2->C - $P2->A * $P1->C; $x0 = ($P1->C * $P2->D - $P2->C * $P1->D) / $denominator; $z0 = ($P2->A * $P1->D - $P1->A * $P2->D) / $denominator; } else { // 固定x=0,解y和z $denominator = $P1->B * $P2->C - $P2->B * $P1->C; $y0 = ($P1->C * $P2->D - $P2->C * $P1->D) / $denominator; $z0 = ($P2->B * $P1->D - $P1->B * $P2->D) / $denominator; } return new Line3D($x0, $a, $y0, $b, $z0, $c); }
针对你示例的验证
你给出的Plane1法向量是(0,0,100),Plane2是(50,0,0),叉乘得到方向向量(0, 5000, 0),也就是b分量不为0。这时候代码会进入abs($b) > 1e-9的分支,固定y0=0,代入方程求解:
- Plane1方程:
0*x + 0*y +100*z +0=0→ z0=0 - Plane2方程:
50*x +0*y +0*z -250=0→ x0=5
最终得到的交线是x=5+0*t,y=0+5000*t,z=0+0*t,和实际交线完全一致,也不会触发除零错误。
内容的提问来源于stack exchange,提问作者Przemysław Niemiec

