简体   繁体   English

尝试检查点是否在线上的误差幅度

[英]margin of error trying to check if a point lays on line

Working with floating point values it is as easy as breathing to run on approximation errors by comparing quantities which should be the same. 使用浮点值,通过比较应该相同的数量,就可以轻松地逼近近似误差。 I want to know if there is a way built in some MSDN (or even external) library for c# to ignore the problem. 我想知道是否在C#的某些MSDN(甚至外部)库中构建了一种方法来忽略该问题。

An example could be: more than comparing 2 float values like this 一个例子可能是:不仅仅是比较2个float值,像这样

if(myVector3.X == anotherVector3.X)

I would appreciate something like this 我会喜欢这样的事情

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

This is not well-written, I know. 我知道这写得不好。 That is just to simplify the explaination. 那只是为了简化说明。 What I am exactly doing is checking if a point ( Vector3 ) lays on line segment. 我正在做的是检查点( Vector3 )是否位于线段上。 So basically the calculations I make are nothing more than 所以基本上我所做的只是计算

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

But these values won't be always the same, so I need to write down some code which includes a sort of tolerance a sort of Neighbourhood mathematical concept to accept values close enought to the line. 但是这些值并不总是相同的,因此我需要写下一些代码,其中包括一种公差和某种邻域数学概念,以接受足够接近该行的值。

Hope that I made myself clear. 希望我能说清楚。 Has anyone a solution for this? 有人对此有解决方案吗?

Check out the following related post: Floating point comparison functions for C# . 请查看以下相关文章: C#的浮点比较函数

Also, MSDN has some examples: http://msdn.microsoft.com/en-us/library/t24f0axa(v=vs.110).aspx . 此外,MSDN还提供了一些示例: http : //msdn.microsoft.com/zh-cn/library/t24f0axa(v=vs.110).aspx

I'm proposing the use of an exact predicate. 我建议使用一个确切的谓词。 This is an alternative approach to what you actually asked, but it might be worth considering. 这是您实际要求的替代方法,但可能值得考虑。

Suppose your three points really are at locations indicated by their respective double precision coordinates. 假设您的三个点确实在它们各自的双精度坐标所指示的位置。 A simple double precision computation like the one suggested in your question will likely still return a wrong result. 一个简单的双精度计算(如您的问题中建议的那种)可能仍会返回错误的结果。 However, there are techniques to obtain exact results to detect these cases. 但是,有一些技术可以获取准确的结果以检测这些情况。 One technique is by turning all numbers into arbitrary precision floating point (or integer) numbers and do most of the computation using integers under the hood. 一种技术是将所有数字转换为任意精度的浮点(或整数)数字,并在后台使用整数进行大多数计算。 Another, which should work faster on modern hardware, expresses intermediate results as sums of doubles. 另一个在现代硬件上应该能更快地工作,将中间结果表示为double的总和。 Eg when computing a+b , you obtain two resulting numbers, the first is the sum as you'd usually compute it, the other is a correction term to note down the error. 例如,当计算a+b ,您将获得两个结果数,第一个是通常计算所得的总和,另一个是记录误差的校正项。 In many cases, the bigger terms are sufficient to make a choice, which leads to the concept of adaptive precision. 在许多情况下,较大的术语足以做出选择,这导致了自适应精度的概念。

All of this, including the application to geometric predicates, has been outlined nicely by Jonathan Richard Shewchuk in his page Adaptive Precision Floating-Point Arithmetic and Fast Robust Predicates for Computational Geometry . 乔纳森·理查德·谢丘克(Jonathan Richard Shewchuk)在他的页面《 自适应精确浮点算术和计算几何的快速鲁棒谓词》中很好地概述了所有这一切,包括应用于几何谓词。 He has a paper on it , and some C code which should be possible to adapt to C#. 他上面有一篇论文 ,以及一些可能适合C#的C代码 Or perhaps to compile in C and link to C#, thus forming a mixed language project. 或者也许用C编译并链接到C#,从而形成一个混合语言项目。 Note however that it makes some assumptions on how the compiler treats floating point computations. 但是请注意,它对编译器如何处理浮点计算进行了一些假设。 In particular, you have to be careful that certain intermediate results don't have excess precision, like the 80-bit numbers stored in a 80387-style floating point unit . 特别是,您必须注意某些中间结果不会具有过高的精度,例如存储在80387样式浮点单元中 的80位数字 I've looked into this myself recently , and the easiest solution might be asking the compiler to use SSE instructions instead of x87 ones. 我最近亲自研究了这个问题 ,最简单的解决方案可能是要求编译器使用SSE指令而不是x87指令。

In your case, you are asking whether a point p lies on the segment connecting p1 and p2 . 在您的情况下,您要询问点p是否位于连接p1p2的线段上。 One predicate which would be very much in the spirit of that paper would be the position of a fourth point in relation to a plane spanned by three others: it is either above, below or within that plane, and the orient3d predicate can tell you which. 一个谓词非常符合本文的精神,它是第四个点相对于一个平面的位置,该平面由其他三个平面跨越:它位于该平面的上方,下方或内部, orient3d谓词可以告诉您哪个。 So one possible approach would be taking four arbitrary points q1 through q4 in general position, ie not all in a single plane, and no three on a single line. 因此,一种可能的方法是在一般位置上取四个任意点q1q4 ,即不是所有点都在一个平面上,在一个直线上不取三个点。 Then you could check whether p,p1,p2,qi are coplanar (sign is zero) for all i ∈ {1,2,3,4}. 然后,你可以检查P,P1,P2,齐是否是共面(标志是零)对所有的i∈{1,2,3,4}。 If they are, then p does at least lie on the line spanned by p1 and p2 . 如果是,则p至少位于p1p2所跨越的线上。 Next you could check the orientations of p,p1,qi,qj for different i,j until you find a non-zero sign, then you could see whether p,p2,qi,qj has a different sign. 接下来,您可以针对不同的i,j检查p,p1,qi,qj的方向直到找到一个非零符号,然后您才能查看p,p2,qi,qj是否具有不同的符号。 If it does, then p is indeed between p1 and p2 , hence on the same line. 如果是这样,则p确实在p1p2之间,因此在同一行上。 If you find no i,j such that p,p1,qi,qj is non-zero, then p=p1 . 如果没有找到i,j使得p,p1,qi,qj不为零,则p = p1 Likewise if you have found one non-zero sign, but the corresponding sign of p,p2,qi,qj is zero, then p=p2 . 同样,如果找到一个非零符号,但p,p2,qi,qj的对应符号为零,则p = p2 It is up to you whether you want to include the endpoints of your line segment. 是否要包含线段的端点取决于您。 This paragraph might not be the most elegant way to do this, but it leverages the existing orient3d implementation, so it might be easier to use than writing a new predicate from scratch. 本段可能不是执行此操作的最优雅的方法,但它利用了现有的orient3d实现,因此它比从头开始编写新谓词更容易使用。

Note that in most cases, a point will not exactly lie on a line segment, due to rounding of the point coordinates themselves. 请注意,在大多数情况下,由于点坐标本身的舍入,因此点不会精确地位于线段上。 The above will only help you to reliably detect those rare cases when it does, so you can deal with them. 上面的内容仅能帮助您可靠地检测到那些罕见的情况,因此您可以对其进行处理。 It may also allow you to make consistent choices for other predicates as well. 它还可能使您也可以为其他谓词做出一致的选择。 In the world of CGAL , this approach would be termed “ exact predicates, inexact constructions ”, since the predicates can be computed reliably, but the geometric objects on which they operate are still subject to approximation. CGAL的世界中,这种方法将被称为“ 精确谓词,不精确的构造 ”,因为可以可靠地计算谓词,但是对其进行操作的几何对象仍然是近似的。 If you really need points that reliably lie on the line segments, and not just close by, then an exact construction approach using some exact number type would be preferable. 如果确实需要可靠地位于线段上的点,而不仅仅是在线段附近,那么使用某种精确数字类型的精确构造方法将是可取的。 Or you go with the approaches the other answers suggest. 或者您采用其他答案建议的方法。

You need to calculate the distance of the point to the line. 您需要计算点到线的距离。 That's simple mathematics . 那是简单的数学 Then you decide how far of a distance "close enough" is in your case. 然后,确定您的情况下“足够近”的距离。

This problem is described as floating-point tolerance in this article and it points out the importance of measuring relative tolerance rather than absolute when comparing large values: http://realtimecollisiondetection.net/blog/?p=89 此问题在本文中被描述为浮点公差,并且指出比较大值时测量相对公差而不是绝对值的重要性: http : //realtimecollisiondetection.net/blog/?p=89

I've never had a situation where large floating point values are possible so I've always hard-coded a magic value into my comparisons. 我从来没有遇到过可能会有大浮点值的情况,因此我总是将魔术值硬编码到比较中。 Eg: 例如:

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

Which is "bad" but it works so long as value1 and value2 can't get too big. 这是“不好的”,但只要value1和value2不能太大就可以了。

In your case you really want to calculate the distance of the point from the line and then check that distance is small enough, rather than testing that the point is exactly on the line. 在您的情况下,您确实想计算点到直线的距离,然后检查距离是否足够小,而不是测试该点是否在直线上。 I am rubbish at math myself so don't understand this but let me copy someone else's answer for calculating the shortest distance between a 3D point and a 3D line: 我本人对数学很不了解,所以不明白这一点,但让我复制其他人的答案来计算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 从3D点开始在线的3D垂直点

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM