数值误差计算交叉点

时间:2014-11-22 22:09:11

标签: java geometry intersection numeric

我想计算光线和线段之间的交叉点。为此,我形成线性方程并寻找交叉点。现在我遇到一个例子的数值问题。我的代码的缩写:

public class Test {
    public static void main(String[] args) {
        double rayAX = 443.19661703858895d;
        double rayAY = 666.3485960845833d;

        double rayBX = 443.196744279195d;
        double rayBY = 103.21654864924565d;

        double segAX = 450.0d;
        double segAY = 114.42801992127828d;

        double segBX = 443.196744279195d;
        double segBY = 103.21654864924565d;


        double a1 = (rayBY - rayAY) / (rayBX - rayAX);
        double t1 = rayAY - rayAX * a1;

        double a2 = (segBY - segAY) / (segBX - segAX);
        double t2 = segAY - segAX * a2;

        double x = (t2 - t1) / (a1 - a2);
        double y = a1 * x + t1;

        System.out.println(x);
        System.out.println(y);
    }
}

显然,返回应为(443.196744279195,103.21654864924565),因为此点在光线和线段上都相同。 但实际回报是在我的情况下(443.19674427919506,103.21654844284058)

在第二个数字中,小数点后第六位出现错误。 我猜错误是因为值rayAX和rayBX彼此非常接近。我的问题是:在计算交叉点时,我能获得更精确的结果吗?

2 个答案:

答案 0 :(得分:3)

这里是一种更加数字稳定的交叉方式(注意它实际上是两条线的交叉点......看起来你原来的代码并没有检查交叉点是否在细分市场):

double rX = rayBX - rayAX;                                                                                                                                           
double rY = rayBY - rayAY;                                                                                                                                           

double sAX = segAX - rayAX;                                                                                                                                          
double sAY = segAY - rayAY;                                                                                                                                          
double areaA = sAX * rY - sAY * rX;                                                                                                                                  

double sBX = segBX - rayAX;                                                                                                                                          
double sBY = segBY - rayAY;                                                                                                                                          
double areaB = sBX * rY - sBY * rX;                                                                                                                                  

double t = areaA / (areaA - areaB);
// if t is not between 0 and 1, intersection is not in segment                                                                                                 
double x = (1 - t) * segAX + t * segBX;                                                                                                                              
double y = (1 - t) * segAY + t * segBY;

粗略解释:让AB成为光线的端点,让XY成为细分的端点。让P成为我们正在寻找的交叉点。然后,PXPY的比率等于ABX的面积与ABY的面积之比。您可以使用交叉产品计算面积,这是上面的代码所做的。请注意此过程如何仅使用一个除法,这有助于最小化数值不稳定性。

答案 1 :(得分:0)

据我所知,通过高斯旋转的Gauss或Gauss-Jordan方法可以获得最佳的数值稳定性。

您需要为RS解决此线性2x2系统。

(Brx - Arx).R - (Bsx - Asx).S = Asx - Arx
(Bxy - Ary).R - (Bsx - Asx).S = Asy - Ary

Total pivoting告诉您选择具有最大模块的LHS系数。有四种可能的选择,因此您必须实现四种算法版本。

例如,假设左上系数在系统中占主导地位

A.X + B.Y = C
D.X + E.Y = F

然后

  X + (B/A).Y = (C/A)
D.X + E    .Y = F

(E - D.(B/A)) Y = F - D.(C/A)

Y = (F - D.(C/A)) / (E - D.(B/A))
X = (C/A) - (B/A).Y

使用精确算术这确实等同于克莱默的规则,但从数字的角度来看可能更好。

其他案例是对称处理的。