ラインコリジョンで2Dラインを検出する方法


13

私は数学が少し後戻りしているFlash ActionScriptゲーム開発者ですが、物理学は面白くてクールです。

参考のために、これは私が作っているものと類似したゲームである:Untangledフラッシュゲーム

私はこのもつれのないゲームをほぼ完全に論理的に完成させました。しかし、2本の線が交差する場合、異なる色を表示するために、交差または「もつれた」線が必要です。赤。

線分衝突を検出するためのアルゴリズムを提案できれば、本当に親切な人になります。私は基本的に「算術的」よりも「視覚的に」考えるのが好きな人です:)

編集:アイデアをより明確に伝えるために、いくつかの図を追加したい

交差点なし 交差点なし 交差点 交差点なし

PS私は次のような関数を作成しようとしています

private function isIntersecting(A:Point, B:Point, C:Point, D:Point):Boolean

前もって感謝します。


6
これは、問題のがっかり非視覚的な説明であるが、それはアルゴリズムであり、あなたが彼らの数学を読むために自分自身をもたらすことができるならば、それはメイクセンスを行いますlocal.wasp.uwa.edu.au/~pbourke/geometry/lineline2dそれはかもしれませんあなたのベクトルの数学が弱い場合は重い。わかりました-視覚的な説明も好みます。後でこれを落書きする時間を見つけようとしますが、芸術的に傾倒している人がこのリンクを見て、私がやる前に時間があれば、それを見つけてください!
アンコ

回答:


18

私はかなりの単なる実装で、次の方法を使用このアルゴリズムを。C#ですが、ActionScriptに翻訳するのは簡単です。

bool IsIntersecting(Point a, Point b, Point c, Point d)
{
    float denominator = ((b.X - a.X) * (d.Y - c.Y)) - ((b.Y - a.Y) * (d.X - c.X));
    float numerator1 = ((a.Y - c.Y) * (d.X - c.X)) - ((a.X - c.X) * (d.Y - c.Y));
    float numerator2 = ((a.Y - c.Y) * (b.X - a.X)) - ((a.X - c.X) * (b.Y - a.Y));

    // Detect coincident lines (has a problem, read below)
    if (denominator == 0) return numerator1 == 0 && numerator2 == 0;

    float r = numerator1 / denominator;
    float s = numerator2 / denominator;

    return (r >= 0 && r <= 1) && (s >= 0 && s <= 1);
}

ただし、アルゴリズムには微妙な問題があります。これは、2行が一致しているが重複していない場合です。その場合、アルゴリズムは依然として交差を返します。その場合は、stackoverflowでのこの回答には、それを解決するより複雑なバージョンがあると思います。

編集

このアルゴリズムから結果が得られませんでした、ごめんなさい!

それは奇妙です、私はそれをテストしました、そして、それは私が上で説明したその単一のケースを除いて私のために働いています。上記で投稿したものとまったく同じバージョンを使用して、テストドライブに使用したときにこれらの結果が得られました。

ここに画像の説明を入力してください


このアルゴリズムから結果が得られませんでした、ごめんなさい!
ヴィシュヌ

4
@Vishどのような問題がありましたか?投稿する前に、このアルゴリズムの正確なコピーをテストしましたが、説明した単一のケースを除き、問題なく動作しました。
デヴィッドゴーベイア

それから、もう一度試してみましょう、いくつかの数学を混同したかもしれません。すぐにお知らせします。どうもありがとう、とにかく:)
ヴィシュヌ

1
@DavidGouveiaに感謝します。
ヴィシュヌ

1
さて、しかし今私は別の問題を抱えています:)!赤と緑の交差線を作成する必要があります。交差点は正常に機能します。しかし、私が理解したように、(数学的にではありませんが)単純なif-elseは、交差した線と交差していない線に赤と緑の線を置くことに関しては機能しません。ドラッグしているノードには、左右の線があります。そのため、交差していない線の色を緑に戻すときに、どこかで問題が発生しました。別の条件も必要だと思います。うーん、とにかくトンのおかげで、私はこれを正しい答えとしてマークしています。
ヴィシュヌ

4

部門なし!したがって、精度やゼロ除算に問題はありません。

ラインセグメント1はAからBラインセグメント2はCからD

線は終わりのない線であり、線分はその線の定義された部分です。

2つの境界ボックスが交差するかどうかを確認します。交差がない場合->クロスなし!(計算完了、falseを返します)

ラインセグメント1がラインセグメント2にまたがっているかどうか、ラインセグメント2がラインセグメント1にまたがっているかどうかを確認します(つまり、ラインセグメント1はラインセグメント2で定義されたラインの両側にあります)。

これは、すべてのポイントを-Aで変換することで作成できます(つまり、Aがorigo(0,0)にあるように2行を移動します)

次に、ポイントCとDが0,0からBで定義される線の両側にあるかどうかを確認します

//Cross Product (hope I got it right here)
float fC= (B.x*C.y) - (B.y*C.x); //<0 == to the left, >0 == to the right
float fD= (B.x*D.y) - (B.y*D.x);

if( (fc<0) && (fd<0)) //both to the left  -> No Cross!
if( (fc>0) && (fd>0)) //both to the right -> No Cross!

まだ「No Cross」を取得していない場合は、A、B対C、DではなくC、D対A、Bを使用し続けます(同じ計算、AとC、BとDを入れ替える)。 「ノークロス!」交差点があります!

クロス積の正確な計算を検索し、このブログ投稿で方法を説明しています。


1
申し訳ありませんが、ベクトル演算はあまり得意ではありません。このアルゴリズムをそのまま実装しましたが、結果は得られませんでした、申し訳ありません!
ヴィシュヌ

1
うまくいくはずなので、もしあなたがあなたのコードを見せてくれれば、私たちはあなたを助けることができますか?
ヴァルモンド

いいね!ただし、リンクが壊れています
clabe45

これに追加して交差点を取得できるものはありますか?
SeanRamey

1

言いたいのは、Gamemaker Studioゲームに必要で、うまく機能していることです。

///scr_line_collision(x1,y1,x2,y2,x3,y3,x4,y4)

var denominator= ((argument2 - argument0) * (argument7 - argument5)) - ((argument3 - argument1) * (argument6 - argument4));
var numerator1 = ((argument1 - argument5) * (argument6 - argument4)) - ((argument0 - argument4) * (argument7 - argument5));
var numerator2 = ((argument1 - argument5) * (argument2 - argument0)) - ((argument0 - argument4) * (argument3 - argument1));

// Detect coincident lines
if (denominator == 0) {return (numerator1 == 0 && numerator2 == 0)}

var r = numerator1 / denominator;
var s = numerator2 / denominator;

return ((r >= 0 && r <= 1) && (s >= 0 && s <= 1));

コードが何をするのかを説明すれば、この答えは本当に改善されると思います。
-TomTsagk

1

この場合、受け入れられた答えは間違った答えを与えました。

x1 = 0;
y1 = 0;
x2 = 10;
y2 = 10;

x3 = 10.1;
y3 = 10.1;
x4 = 15;
y4 = 15;

これらの線は明らかに交差していませんが、「正解」の機能によると、線は交差しています。

これは私が使用するものです:

function do_lines_intersect(px1,py1,px2,py2,px3,py3,px4,py4) {
  var ua = 0.0;
  var ub = 0.0;
  var ud = (py4 - py3) * (px2 - px1) - (px4 - px3) * (py2 - py1);


  if (ud != 0) {
    ua = ((px4 - px3) * (py1 - py3) - (py4 - py3) * (px1 - px3)) / ud;
    ub = ((px2 - px1) * (py1 - py3) - (py2 - py1) * (px1 - px3)) / ud;
        if (ua < 0.0 || ua > 1.0 || ub < 0.0 || ub > 1.0) ua = 0.0;
  }

  return ua;
}

0を返します=ラインは交差しません

> 0 =線が交差する


質問に答えるために更新:

私はこのコードを自分で作成しませんでした。それは5年以上前のもので、元のソースが何なのかわかりません。だが..

戻り値は、それらが交差する最初の行の相対的な位置だと思います(説明が間違っています)。交差点を計算するには、おそらく次のようなlerpを使用できます。

l = do_lines_intersect(...)
if (l > 0) {
    intersect_pos_x = l * (px2-px1);
    intersect_pos_y = l * (py2-py1);
} else {
    // lines do not cross
}

(私はこれをテストしませんでした)


交差点を返すこのバージョンはありますか?
SeanRamey
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.