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
值。否则我还有更重要的事要做。