web-dev-qa-db-ja.com

線分間の交点の計算

ここStackowerflowでのラインセグメント間の交差点については多くの質問があります。申し訳ありませんが、交差点の計算方法を理解する助けが必要です。私はここでいくつかの質問を読み、他のウェブサイトのいくつかの例を見てきましたが、私はまだ混乱しており、理解できません!私は、物事がどのように機能するかを除いてコードをコピーして貼り付けるのは好きではありません。

これまでのところ、Ax、Ay、Bx、By、Cx、Cy、Dx、Dyのような各ラインセグメントのポイントを比較することを知っています。誰かが私のために計算するものを説明してもらえますか、交差点がある場合、計算の結果はどうなりますか?

これは私が見たサンプルコードの1つです。線が交差するかどうかを知るためだけに、交差点は必要ないと思います。

   public static Point lineIntersect(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) {
  double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
  if (denom == 0.0) { // Lines are parallel.
     return null;
  }
  double ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3))/denom;
  double ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3))/denom;
    if (ua >= 0.0f && ua <= 1.0f && ub >= 0.0f && ub <= 1.0f) {
        // Get the intersection point.
        return new Point((int) (x1 + ua*(x2 - x1)), (int) (y1 + ua*(y2 - y1)));
    }

  return null;
  }

このコード例のように中央値を計算する必要もありますか?

For lines through points (x0,y0) and (x1,y1), let xm = (x0+x1)/2, ym = (y0+y1)/2 (median of line segment). 
Then a = (y1-y0) and b = (x0-x1). 
If you evaluate c = a(x-xm)+b(y-ym), c=0 for (x,y) on the line, and the sign(c) tells you which side a point is on
17
3D-kreativ

最初に表示するコードは、ここで説明したベクトル外積に基づいています 2つの線分が交差する場所をどのように検出しますか? 詳細に。

IMO、それを理解するより簡単な方法は、方程式系を解くことです。まず、一般的に線を見てから、それらからセグメントを切り取ります。以下では、特定のセグメント_((x1, x2), (y1, y2))_および_((x3, x4), (y3, y4))_に表記法を使用します。

  1. 行のいずれかが垂直(_x1 == x2_または_x3 == x4_)かどうかを確認します。

    a。両方が垂直で_x1 != x3_の場合、交差はありません。

    b。両方が垂直で_x1 == x3_の場合は、_(y1, y2)_と_(y3, y4)_が重複していないかどうかを確認します。

    c。 1つだけが垂直の場合(たとえば、最初のもの)、2行目の方程式を構築し(以下に概説するように)、2行が交差する点を見つけます(2行目の方程式に_x1_を代入して)この点が両方のセグメント内にあるかどうかを確認します(手順5と同様)。

    d。そうでない場合は、続行します。

  2. ポイント座標を使用して、_y = a*x + b_( here など)の形式で線の方程式を作成します。

    _a1 = (y2-y1)/(x2-x1)
    b1 = y1 - a1*x1 
    a2 = (y4-y3)/(x4-x3)
    b2 = y3 - a2*x3
    _
  3. ラインが平行かどうかを確認します(同じスロープa)。はいの場合、それらが同じインターセプトbを持っているかどうかを確認します。はいの場合、1Dセグメント_(x1, x2)_と_(x3, x4)_が重複しているかどうかを確認します。はいの場合、セグメントは重複しています。行が平行である場合はあいまいになる可能性があります。それらが重なる場合は、交差点(両端が接触している場合でも1つのポイントになることもあります)と見なすことができます。注:フロートを使用している場合は少し複雑になりますが、これは無視したいと思います。 _a1 = a2_が次と等しいかどうかを確認する整数のみがある場合:

    _if((y2-y1)*(x4-x3) == (x2-x1)*(y4-y3))
    _
  4. 線が平行でない場合。交点は、2本の線を表す連立方程式の解に相当します。本当に、_y = a1*x + b1_と_y = a2*x + b2_の交差は、基本的にこれらの式の両方が成り立つことを意味します。このシステムを解決するには、2つの右側を一致させると、交点が得られます。実際、必要なのは交差点のx座標だけです(描画すると、その理由がわかります)。

    _x0 = -(b1-b2)/(a1-a2)
    _
  5. 最後のステップは、交差点_x0_が両方のセグメント内にあるかどうかを確認することです。つまり、min(x1, x2) < x0 < max(x1, x2)およびmin(x3, x4) < x0 < max(x3, x4)です。はいの場合、ラインは交差します!

27
sashkello

私は本当に@sashkelloの答えであり、ベクターの実装よりも直感的で説明しやすいことがわかりました。特に、この種のコードをコードベースに追加する場合。

JavaのLine2Dヘルパーメソッドを利用できると言って、それを警告します。

Line2D.linesIntersect(double x1, double y1,
                      double x2, double y2,
                      double x3, double y3,
                      double x4, double y4)

唯一の欠点は、セグメントがちょうど接触している場合でも(エンドポイントとライン自体の両方で)セグメントが交差していることを考慮する必要があることです。

たとえば、次の線はポイント(1,1)を共有しているため、交差していると見なされます。

L1 = [(0,0),(1,1)]
L2 = [(1,1),(2,3)]

それが問題である場合、ポイントが等しいかどうかを確認するために4つのチェックを追加できます。

ポイントがライン内のポイントに該当するという懸念がある場合は、少し手間がかかります。アルゴリズム自体でチェックを実行できるように、自分で実装する方が良いでしょう。

これらのEdgeケースがどれもあなたに影響しない場合、Line2D.linesIntersectあなたのためです。 :)

4
Kenny Cason
public void fixData()
{
    slope = (p2.getY() - p1.getY()) / (p2.getX() - p1.getX());
    yInt = p1.getY() - slope * p1.getX();
    xInt = (-yInt) / slope;
}
1
user7127290