【问题标题】:Floating-point error when checking for coplanar 3D points检查共面 3D 点时出现浮点错误
【发布时间】:2014-12-14 16:17:27
【问题描述】:

我正在寻找一种算法来检查一个点是否与给定的 3D 平面共面,由三个顶点定义,同时最大限度地减少浮点错误。

我想尽量减少乘法和除法的数量以减少浮点错误。

我的实现使用floats,我不能去double

我无法使用外部库。


我当前的方法存在以下错误:

我有使用平面方程的一般形式定义平面的代码:

ax + by + cz + d = 0

我使用三个 3D 顶点 v0v1v2 计算这些系数,如下所示:

// 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.

【问题讨论】:

  • 在您的示例中,abs(res) > EPSILON,所以它应该返回 false,对吗?
  • 是的,代码无法找到 v2 在这种情况下是共面的,尽管 v2 用于定义平面。
  • 您是如何选择EPSILON 的值的?你有理由相信res 的值,如果用精确的数学计算(没有舍入误差),由于计算Nd 的错误,不会比EPSILON 更远离零?换句话说,如果在计算Nd 时出现的错误已经将它们描述的平面移动得足够远,那么v2 可能与平面不够接近,甚至无法精确计算@ 987654350@ 将小于 EPSILON
  • 嗯,你很幸运。如果 Nd 使用精确数学计算,然后四舍五入到最接近的 float 值,然后 res 使用精确数学从这些值和 v2 计算,则小于 1e-5,大约为 0.0000051611115。不幸的是,您为Nd 计算的值已经被破坏了。当res 是根据这些值精确计算时,它正好是 -0.000011984341398374454001896083354949951171875,超过 1e-5。因此,在计算res 时,没有最小化错误会产生小于 1e-5 的结果。
  • 因此,您必须修复Nd 的计算或接受EPSILON 的更高值。

标签: c++ 3d floating-point floating-point-precision


【解决方案1】:

这种几何谓词在很多方面都受到浮点错误的影响。唯一的工业强度解决方案是使用adaptable arithmetic filtering(前提是coplanar 测试的健壮实现不包括您)。

幸运的是,这样的implementations(这将需要相当长的时间来编写)已经可用。在上一个链接中,orient3d 谓词可以满足您的需要:给定 3 个平面形成点,确定第 4 个位于平面上方、下方还是平面上

如果这样的实现太过分了,请检查简单的实现。它总共提供 4 个:

orient3dfast() 近似 3D 方向测试。非鲁棒性。
orient3dexact() 精确的 3D 方向测试。强大。
orient3dslow() 另一个精确的 3D 方向测试。强大。
orient3d() 自适应精确 3D 方向测试。强大。

免责声明:代码清单是作为获得稳健解决方案所需的数学概念和编程技术的教程提供的。我既不建议也不暗示复制粘贴任何内容。

【讨论】:

  • 十年前的这篇论文让我成为了一个更好的程序员!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-05
  • 2023-03-31
  • 2021-10-20
  • 2012-12-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多