我正在寻找一种算法来检查一个点是否与三个顶点定义的给定3D平面共面,同时最小化浮点误差。
我想尽量减少乘法和除法的数量,以减轻浮点错误。
我的实施使用float
,我不能去double
。
我不能使用外部库。
我当前的方法存在以下错误:
我有使用平面方程的一般形式定义平面的代码:
ax + by + cz + d = 0
我使用三个3D顶点v0
,v1
和v2
来计算这些系数,如下所示:
// Pseudo-code to define a plane (with class Vector3 defining a vector in 3D)
Vector3 A = v1 - v0;
Vector3 B = v2 - v0;
Vector3 N = cross_product(A,B); // Normal vector
N.Normalize(); // Unit normal vector storing coefs. a, b, c
float d = dot_product(N,v0);
要检查另一个顶点p
是否是共面的,我将该点插入平面方程并检查结果是否为0
:
// Pseudo-code for coplanar test:
bool is_coplanar()
{
float res = N.x()*p.x() + N.y()*p.y() + N.z()*p.z() - d;
return true if res is "almost" null; // "almost" is: abs(res)<EPSILON
}
在这种情况下,我的代码失败了:
v0 = [-8.50001907, 0, 323]
v1 = [8.49998093, 0, 323]
v2 = [-8.50001907, 1.49999976, 322.598083]
然后平面系数为:
N = [-0, 0.258814692, 0.965926945]
d = 311.994415
当我插入点v2
时,我发现0
的结果“远”(虽然v2
用于定义平面):
res = -3.05175781e-05
我的EPSILON
目前为1e-5
。
在编译器qcc 4.4.2(QNX Momentics,类似于gcc)上测试。没有优化-O0
。
答案 0 :(得分:4)
这种几何谓词在很多方面都受到浮点错误的影响。唯一的工业强度解决方案是使用adaptable arithmetic filtering(前提是coplanar
测试的强大实现不会覆盖您)。
幸运的是,这样的implementations(需要相当长的一段时间才能写)已经可以使用了。在上一个链接中, orient3d 谓词可以满足您的需求:给定3个平面形成点,确定第4个位于平面上方,下方或平面上
如果这样的实现是一种矫枉过正,请检查简单的实现。它共提供4个:
orient3dfast()近似3D方向测试。 Nonrobust。
orient3dexact()精确的3D方向测试。强劲。
orient3dslow()另一个精确的3D方向测试。强劲。
orient3d()自适应精确三维方向测试。的鲁棒性。
免责声明:代码清单是作为获得强大解决方案所需的数学概念和编程技术的教程提供的。我既不暗示也不暗示复制粘贴任何东西。