複雑な自己交差ポリゴンをすべての交差点を識別して外側の周りを歩くことによって単純なポリゴンに変換するアルゴリズムをデバッグしています。セグメントセグメントの交差点コードの精度問題
ストレステストを生成する一連のランダムデータを書きましたが、何千回も正しく作業した後、私のアルゴリズムが失敗するという面白い状況に遭遇しました。
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
これは、これがどのように関係しているか、私が今どこにいるかの概要です。私が放棄している詳細はたくさんあります。私は何をすることができたことは、私が使用しているセグメントのセグメントの交差点コードへのダウン狭い問題である
:起こっ
bool intersect(const E_Point& a0, const E_Point& a1,
const E_Point& b0, const E_Point& b1,
E_Point& intersectionPoint) {
if (a0 == b0 || a0 == b1 || a1 == b0 || a1 == b1) return false;
double x1 = a0.x; double y1 = a0.y;
double x2 = a1.x; double y2 = a1.y;
double x3 = b0.x; double y3 = b0.y;
double x4 = b1.x; double y4 = b1.y;
//AABB early exit
if (b2Max(x1,x2) < b2Min(x3,x4) || b2Max(x3,x4) < b2Min(x1,x2)) return false;
if (b2Max(y1,y2) < b2Min(y3,y4) || b2Max(y3,y4) < b2Min(y1,y2)) return false;
float ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3));
float ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3));
float denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
// check against epsilon (lowest normalized double value)
if (fabs(denom) < DBL_EPSILON) {
//Lines are too close to parallel to call
return false;
}
ua /= denom;
ub /= denom;
if ((0 < ua) && (ua < 1) && (0 < ub) && (ub < 1)) {
intersectionPoint.x = (x1 + ua * (x2 - x1));
intersectionPoint.y = (y1 + ua * (y2 - y1));
return true;
}
return false;
}
何が、私はこの機能はまったく同じ交差点を返す2つの交点を有することですのポイント値。垂直線は点 (0.3871953044519425, -0.91857980824611341), (0.36139704793723609, 0.91605957361605106)
緑色ほぼ水平ライン(0.8208980020500205, 0.52853407296583088), (0.36178501611208552, 0.88880385168617226)
とによって規定される
:ここに非常に関連するジオメトリを考慮してズームされます白い行by (0.36178501611208552, 0.88880385168617226), (-0.43211245441046209, 0.68034202227710472)
最後の2行は共通点を共有しています。
私の関数は、これらの交点の両方について(0.36178033094571277, 0.88880245640159794)
の解を与えます(そのうちの1つは赤い点として表示されます)。
これが大きな問題である理由は、私の周辺アルゴリズムは各エッジの交点をソートすることに依存するからです。これらの交点は両方とも同じ正確な値を持つように計算されていたため、ソートはそれらを間違った方向に置きました。周囲のパスは上から来て、緑の線が残っているのではなく、左の白い線に沿っています。これは、もはや私の多角形の外周をたどっていないことを意味します。
この問題を解決するには、できることは多分ありますが、交差点リストをすべて検索して、他の点と比較して位置が等しいかどうかを確認する必要はありません。よりよい解決策は、私の交差点機能の精度を上げることです。
私は何を求めているのですか。なぜソリューションポイントが不正確なのですか?それはラインの1つがほぼ垂直なのでですか?最初に何らかの変換を実行する必要がありますか?両方の場合において、ほぼ垂直な線はa0
およびa1
として渡された。
更新:ねえ、これを見て:
TEST(intersection_precision_test) {
E_Point problem[] = {
{0.3871953044519425, -0.91857980824611341}, // 1559
{0.36139704793723609, 0.91605957361605106}, // 1560
{-0.8208980020500205, 0.52853407296583088}, // 1798
{0.36178501611208552, 0.88880385168617226}, // 1799
{-0.43211245441046209, 0.6803420222771047} // 1800
};
std::cout.precision(16);
E_Point result;
intersect(problem[0],problem[1],problem[2],problem[3],result);
std::cout << "1: " << result << std::endl;
intersect(problem[0],problem[1],problem[3],problem[2],result);
std::cout << "2: " << result << std::endl;
intersect(problem[1],problem[0],problem[2],problem[3],result);
std::cout << "3: " << result << std::endl;
intersect(problem[1],problem[0],problem[3],problem[2],result);
std::cout << "4: " << result << std::endl;
intersect(problem[2],problem[3],problem[0],problem[1],result);
std::cout << "rev: " << result << std::endl;
intersect(problem[3],problem[2],problem[0],problem[1],result);
std::cout << "revf1: " << result << std::endl;
intersect(problem[2],problem[3],problem[1],problem[0],result);
std::cout << "revf2: " << result << std::endl;
intersect(problem[3],problem[2],problem[1],problem[0],result);
std::cout << "revfboth: " << result << std::endl;
}
出力:
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>
は、私が実際に仮数ビットのうち、実行しているか、私は賢くアルゴリズムで有意に優れて行うことができますか?
ここで問題となるのは、頂点が本当に本当に本当に別の線の近くに設定されているかを簡単に判断できないということです。私はそれを動かすことも、完全にそれを噛んだりすることもないでしょう。
私はその機能の中にフロートバールに気づかなかったので、馬鹿だ。 –
しかし私が言及したように、ダブルスの使用は万能薬だとは思わない。 –
あなたは正しいです。頂点が他のセグメントに極端に接近することを防ぎ、同じ問題を再度発生させるものはありません。しかし、私はそれを固定した後、私の機能には浮動小数点がなくなり、交差点の結果はもはや全面的にはなりません。この問題が実際に再びうまくいけば、私は 'ub'値を使うことを見ていきます。さもなければ、私は揚げるためにはるかに大きな魚を持っています。 –