Geometry 线段交点代码的精度问题

Geometry 线段交点代码的精度问题,geometry,floating-point,precision,computational-geometry,Geometry,Floating Point,Precision,Computational Geometry,我正在调试我编写的一个算法,该算法通过识别所有交点并绕外围行走,将复杂的自相交多边形转换为简单多边形 我编写了一系列随机数据生成压力测试,在这一次中,我遇到了一个有趣的情况,导致我的算法在正确运行了数千次之后失败 double fRand(double fMin, double fMax) { double f = (double)rand() / RAND_MAX; // On my machine RAND_MAX = 2147483647 return fMin + f *

我正在调试我编写的一个算法,该算法通过识别所有交点并绕外围行走,将复杂的自相交多边形转换为简单多边形

我编写了一系列随机数据生成压力测试,在这一次中,我遇到了一个有趣的情况,导致我的算法在正确运行了数千次之后失败

double fRand(double fMin, double fMax)
{
    double f = (double)rand() / RAND_MAX; // On my machine RAND_MAX = 2147483647
    return fMin + f * (fMax - fMin);
}
// ... testing code below:  
srand(1);
for(int j=3;j<5000;j+=5) {
    std::vector<E_Point> geometry;
    for(int i=0;i<j;i++) {
        double radius = fRand(0.6,1.0);
        double angle = fRand(0,2*3.1415926535);
        E_Point pt(cos(angle),sin(angle));
        pt *= radius;
        geometry.push_back(pt); // sending in a pile of shit
    }
    // run algorithm on this geometry
输出:

Starting Test intersection_precision_test, at Polygon.cpp:1830
1: <0.3617803309457128,0.8888024564015979>
2: <0.3617803309457128,0.8888024564015979>
3: <0.3617803314022162,0.8888024239374175>
4: <0.3617803314022162,0.8888024239374175>
rev: <0.3617803635476076,0.8888024344185281>
revf1: <0.3617803313928456,0.8888024246235207>
revf2: <0.3617803635476076,0.8888024344185281>
revfboth: <0.3617803313928456,0.8888024246235207>
在多边形处开始测试交点\u精度\u测试。cpp:1830
1: 
2: 
三:
4: 
修订版:
revf1:
revf2:
revfboth:
我是否真的用完了尾数位,或者我可以用更智能的算法做得更好


这里的问题是,对于我来说,没有简单的方法来确定一个顶点何时被设置得非常靠近另一条直线。我不介意移动它,甚至完全用核武器,因为这两种东西都不会把我搞砸

如果您将浮点中间值(ua、ub、denom)更改为双精度,并打印ua值(除法后),您将得到以下结果:

0x1.f864ab6b36458p-1 in the first case
0x1.f864af01f2037p-1 in the second case
0.9999960389052315
5.904388076838819e-06
我已经用十六进制打印了它们,以便于查看位。这两个值在前22位一致(
1.f864a
加上
b
f
的高位)。浮点数只有23位有效位!毫不奇怪,如果你用浮点数计算中间值,它们会四舍五入得到相同的答案

在这种情况下,您可能可以通过使用double而不是float计算中间产物来解决这个问题。(我让我的point struct对x和y使用double。如果使用float,我不知道计算double中的中间值是否有帮助。)

但是,如果垂直段通过的距离更接近两个水平段的交点,则可能仍然需要比双精度更高的精度

如果垂直线段正好通过水平线段的共享端点,您会怎么做?我想你处理这个案子是对的

如果您查看ub值(除法后),使用双精度计算,您将得到以下结果:

0x1.f864ab6b36458p-1 in the first case
0x1.f864af01f2037p-1 in the second case
0.9999960389052315
5.904388076838819e-06
这意味着交点非常非常靠近水平线段的共享端点


这就是我认为你能做的。每次计算交点时,请查看ub。如果距离1足够近,请将端点移动到交点。然后,首先将交叉口视为一个完全通过的情况。您实际上不必更改数据,但必须将共享端点的两个线段的端点视为已移动,这意味着当前的交叉测试和下一条线段的测试。

我真是个傻瓜,因为我没有注意到该函数中的浮点变量。但正如我提到的,我不认为使用双精度是万能的。你说得对。没有任何东西可以阻止顶点非常靠近另一个线段,并再次产生相同的问题。但是在我修正它之后,在我的函数中没有更多的浮动,相交结果不再到处都是。如果这个问题真的再次出现,我将看看如何使用
ub
值。否则我还有更重要的事要做。