web-dev-qa-db-ja.com

同じ平面内の円と他の円との交差を検出するにはどうすればよいですか?

円が同じ平面内の他の円と交差するかどうかを検出するアルゴリズムを探しています(平面内に複数の円がある場合)。

私が見つけた1つの方法は、分離軸テストを行うことです。それは言います:

2つのオブジェクトを分離する線、つまり、すべてのオブジェクトまたはオブジェクトのポイントが線の異なる側にある線を見つけることができる場合、2つのオブジェクトは交差しません。

ただし、この方法を私のケースに適用する方法がわかりません。

誰も私を助けることができますか?

34
Jean-Luc Godard

2つの円は、中心間の距離が半径の合計と差の間にある場合にのみ交差します。 2つの円(x0, y0, R0)および(x1, y1, R1)、式は次のとおりです。

ABS(R0 - R1) <= SQRT((x0 - x1)^2 + (y0 - y1)^2) <= (R0 + R1)

両側を二乗することで、遅いSQRTを回避し、入力が整数の場合はintのままにすることができます。

(R0 - R1)^2 <= (x0 - x1)^2 + (y0 - y1)^2 <= (R0 + R1)^2

Yes/noテストのみが必要なので、このチェックは正確な交差点を計算するよりも高速です。

上記の解決策は、「1つの円が他の円の中にある」場合でも機能するはずです。

66
dasblinkenlight

塗りつぶされた円の交差を想定します(つまり、1つの円が別の円の内側にあると交差します)。

どこ:

  • x0、y0、r0 =円0の中心と半径。
  • x1、y1、r1 =円1の中心と半径。

コード:

boolean intersects = Math.hypot(x0-x1, y0-y1) <= (r0 + r1);
7
Craigo

XNA/C#ソリューション

    class Circle
    {
        public Vector2 Center;
        public float Radius;

        public bool Intersects(Circle circle)
        {
            float distanceX = Center.X - circle.Center.X;
            float distanceY = Center.Y - circle.Center.Y;
            float radiusSum = circle.Radius + Radius;
            return distanceX * distanceX + distanceY * distanceY <= radiusSum * radiusSum;
        }
        public bool Contains(Circle circle)
        {
            if (circle.Radius > Radius)
                return false;
            float distanceX = Center.X - circle.Center.X;
            float distanceY = Center.Y - circle.Center.Y;
            float radiusD = Radius - circle.Radius;
            return distanceX * distanceX + distanceY * distanceY <= radiusD * radiusD;
        }
    }

Circle.Intersects()メソッドは、ある円が別の円の中にある場合でもtrueを返すことに注意してください(それらを「塗りつぶされた」円として扱います)。

4
Peter Gruden

2つの円の中心間の距離が最大で半径の合計であるが、少なくとも半径の差の絶対値である場合、円自体はある点で交差します。

「少なくとも違い」の部分は、円の内側の領域ではなく、円自体にのみ関心がある場合に適用されます。円またはそれらが囲む領域がポイントを共有するかどうか-つまり、ある円が他の円の内側に完全に「交差」している場合は、違い」チェック。

2
cHao

ここで与えられた答えであると思われる公式を試してみたところ、深刻な欠陥はあるものの、全員が賛成票を投じました。 JavaFXでプログラムを作成し、ユーザーが各円のcenterX、centerY、Radiusの値を変更することで2つの円が交差するかどうかをテストできるようにしました。サークル2をサークル1の近くに移動すると動作しますが、サークル1をサークル2の近くの反対側に移動すると動作しません..... ?????それは少し奇妙です...式も反対の方法でテストする必要があるため、試してみましたがうまくいきません

if (Math.abs(circle1Radius - circle2Radius) <=
            Math.sqrt(Math.pow((circle1X - circle2X), 2)
            + Math.pow((circle1Y - circle2Y), 2)) &&
            Math.sqrt(Math.pow((circle1X - circle2X), 2)
            + Math.pow((circle1X - circle2Y), 2)) <=
            (circle1Radius + circle2Radius)} {
    return true;
} else {
    return false;
}

これは動作します:

    // dx and dy are the vertical and horizontal distances
    double dx = circle2X - circle1X;
    double dy = circle2Y - circle1Y;

    // Determine the straight-line distance between centers.
    double d = Math.sqrt((dy * dy) + (dx * dx));

    // Check Intersections
    if (d > (circle1Radius + circle2Radius)) {
        // No Solution. Circles do not intersect
        return false;
    } else if (d < Math.abs(circle1Radius - circle2Radius)) {
        // No Solution. one circle is contained in the other
        return false;
    } else {
        return true;
    }

式はこちら 2つの円の交差点

使用されたフォーミュラは私のフォーミュラではなく、すべてのクレジットはポール・バークにあります(1997年4月)

 First calculate the distance d between the center of the circles. d = ||P1 - P0||.

    If d > r0 + r1 then there are no solutions, the circles are separate.

    If d < |r0 - r1| then there are no solutions because one circle is contained within the other.

    If d = 0 and r0 = r1 then the circles are coincident and there are an infinite number of solutions.

Considering the two triangles P0P2P3 and P1P2P3 we can write

a2 + h2 = r02 and b2 + h2 = r12

Using d = a + b we can solve for a,

a = (r02 - r12 + d2 ) / (2 d)

It can be readily shown that this reduces to r0 when the two circles touch at one point, ie: d = r0 + r1

Solve for h by substituting a into the first equation, h2 = r02 - a2
So

P2 = P0 + a ( P1 - P0 ) / d

And finally, P3 = (x3,y3) in terms of P0 = (x0,y0), P1 = (x1,y1) and P2 = (x2,y2), is

x3 = x2 +- h ( y1 - y0 ) / d

y3 = y2 -+ h ( x1 - x0 ) / d 
0
John Conner