试图检查一个点是否在线的误差范围

时间:2014-01-02 11:11:42

标签: c# math

使用浮点值,通过比较应该相同的量,就可以像在呼吸一样容易。我想知道在某些MSDN(甚至是外部)库中是否有一种方法可以让c#忽略这个问题。

一个例子可能是:比比较像这样的2个浮点值

if(myVector3.X == anotherVector3.X)

我会很感激这样的事情

if(myVector3.X.isInTheNeighbourhood(anotherVector3.X))

我知道这不好写。这只是为了简化解释。我正在做的是检查一个点(Vector3)是否放在线段上。所以基本上我所做的计算只不过是

(x - x1)/(x2 - x1) = (y - y1)/(y2 - y1) = (z - z1)/(z2 - z1)

但是这些值并不总是一样的,所以我需要写下一些代码,其中包含一种容忍度,一种邻域数学概念,以接受接近该行的值。

希望我清楚自己。 有人有解决方案吗?

4 个答案:

答案 0 :(得分:3)

查看以下相关帖子:Floating point comparison functions for C#

此外,MSDN还有一些示例:http://msdn.microsoft.com/en-us/library/t24f0axa(v=vs.110).aspx

答案 1 :(得分:2)

我建议使用精确谓词。 这是您实际要求的替代方法,但可能值得考虑。

假设您的三个点确实位于各自双精度坐标所指示的位置。像您的问题中建议的简单双精度计算可能仍会返回错误的结果。但是,有一些技术可以获得精确的结果来检测这些情况。一种技术是将所有数字转换为任意精度浮点(或整数)数,并使用引擎下的整数进行大部分计算。另一个应该在现代硬件上运行得更快的另一个,表示作为双倍总和的中间结果。例如。在计算a+b时,您获得两个结果数字,第一个是您通常计算它的总和,另一个是用于记下错误的校正项。在许多情况下,较大的术语足以做出选择,这导致了自适应精度的概念。

Jonathan Richard Shewchuk在他的页面Adaptive Precision Floating-Point Arithmetic and Fast Robust Predicates for Computational Geometry中很好地概述了所有这些,包括对几何谓词的应用。他有a paper on itsome C code应该可以适应C#。或者也许用C编译并链接到C#,从而形成一个混合语言项目。但请注意,它会对编译器如何处理浮点计算做出一些假设。特别是,您必须注意某些中间结果没有过多的精度,例如存储在the 80-bit numbers中的80387-style floating point unit。我looked into this myself recently,最简单的解决方案可能是要求编译器使用SSE指令而不是x87指令。

在您的情况下,您要问的是 p 点是否位于连接 p1 p2 的段上。一个非常符合该论文精神的谓词将是与另外三个跨越的平面相关的第四个点的位置:它位于该平面的上方,下方或内部,以及orient3d谓词可以告诉你哪个。因此,一种可能的方法是在一般位置采用 q1 q4 四个任意点,即不是全部在一个平面上,而在一条线上没有三个。然后你可以检查所有 i ∈{1,2,3,4}的 p,p1,p2,qi 是否共面(符号为零)。如果是,那么 p 至少会位于 p1 p2 所跨越的行上。接下来,您可以检查 p,p1,qi,qj 的方向,以查找不同的 i,j ,直到找到非零符号,然后您可以看到 p,p2,qi,qj 有不同的符号。如果是,那么 p 确实在 p1 p2 之间,因此在同一行上。如果没有找到 i,j p,p1,qi,qj 非零,则 p = p1 。同样,如果您找到一个非零符号,但 p,p2,qi,qj 的相应符号为零,则 p = p2 。是否要包含线段的端点取决于您。这段可能不是最优雅的方式,但它利用了现有的orient3d实现,因此它可能比从头开始编写新谓词更容易使用。

请注意,在大多数情况下,由于点坐标本身的舍入,的点将完全位于线段上。以上内容只会帮助您可靠地检测到这些罕见的情况,因此您可以处理它们。它还可以允许您为其他谓词做出一致的选择。在CGAL的世界中,这种方法将被称为“exact predicates, inexact constructions”,因为谓词可以可靠地计算,但是它们运行的​​几何对象仍然需要近似。如果你真的需要可靠地位于线段上的点,而不仅仅是靠近,那么使用一些精确数字类型的精确构造方法将是更可取的。或者你选择其他答案建议的方法。

答案 2 :(得分:1)

您需要计算点到线的距离。 That's simple mathematics。然后你决定在你的情况下距离“足够近”的距离。

答案 3 :(得分:1)

本文将此问题描述为浮点容差,并指出在比较较大值时测量相对容差而非绝对值的重要性:http://realtimecollisiondetection.net/blog/?p=89

我从来没有可能出现大浮点值的情况,所以我总是将魔术值硬编码到我的比较中。例如:

if (Math.Abs(value1, value2) < 0.05f)
{
   ...
}

哪个“糟糕”,但只要value1和value2不能太大,它就会起作用。

在你的情况下,你真的想要计算点与线的距离,然后检查距离是否足够小,而不是测试点是否恰好在线上。我自己在数学上很垃圾,所以不理解这一点,但让我复制别人的答案来计算3D点和3D线之间的最短距离:

Vector3 u = new Vector3(x2 - x1, y2 - y1, z2 - z1);
Vector3 pq = new Vector3(x3 - x1, y3 - y1, z3 - z1);
float distance = Vector3.Cross(pq, u).Length / u.Length;

3D Perpendicular Point on Line From 3D point