web-dev-qa-db-ja.com

2つの長方形間の距離を計算する方法は? (コンテキスト:Luaでのゲーム。)

X、y、幅、高さ(ピクセル)、回転値(度)の2つの長方形がある場合、それらの輪郭の相互の最も近い距離を計算するにはどうすればよいですか?

背景:Luaで書かれたゲームでは、ランダムにマップを生成していますが、特定の長方形が互いに近すぎないようにしたいのですが、長方形が特定の近距離位置に入るとマップが解決できなくなるため、これが必要です。ボールはそれらの間を通過する必要があります。長方形があまりなく、マップはレベルごとに1回だけ生成されるため、速度は大きな問題ではありません。 StackOverflowで見つけた以前のリンクは thisthis です

よろしくお願いします!

20
Philipp Lenssen

Luaにはありませんが、M Katzの提案に基づくPythonコード:

def rect_distance((x1, y1, x1b, y1b), (x2, y2, x2b, y2b)):
    left = x2b < x1
    right = x1b < x2
    bottom = y2b < y1
    top = y1b < y2
    if top and left:
        return dist((x1, y1b), (x2b, y2))
    Elif left and bottom:
        return dist((x1, y1), (x2b, y2b))
    Elif bottom and right:
        return dist((x1b, y1), (x2, y2b))
    Elif right and top:
        return dist((x1b, y1b), (x2, y2))
    Elif left:
        return x1 - x2b
    Elif right:
        return x2 - x1b
    Elif bottom:
        return y1 - y2b
    Elif top:
        return y2 - y1b
    else:             # rectangles intersect
        return 0.

どこ

  • distは、点間のユークリッド距離です。
  • 長方形。 1は点によって形成されます(x1, y1)および(x1b, y1b)
  • 長方形。 2は点によって形成されます(x2, y2)および(x2b, y2b)
23
Maxim

編集:OKが指摘しているように、このソリューションはすべての長方形が直立していることを前提としています。 OPが要求するように回転した長方形で機能させるには、各長方形の角から他の長方形の最も近い辺までの距離も計算する必要があります。ただし、ポイントがラインセグメントの両方のエンドポイントの上または下にあり、両方のラインセグメントの左または右にある場合(電話の位置1、3、7、または9)、ほとんどの場合、この計算を回避できます。線分)。

Agniusの答えは、DistanceBetweenLineSegments()関数に依存しています。これは、以下を行わないケース分析です。

(1) Check if the rects intersect. If so, the distance between them is 0.
(2) If not, think of r2 as the center of a telephone key pad, #5.
(3) r1 may be fully in one of the extreme quadrants (#1, #3, #7, or #9). If so
    the distance is the distance from one rect corner to another (e.g., if r1 is
    in quadrant #1, the distance is the distance from the lower-right corner of
    r1 to the upper-left corner of r2).
(4) Otherwise r1 is to the left, right, above, or below r2 and the distance is
    the distance between the relevant sides (e.g., if r1 is above, the distance
    is the distance between r1's low y and r2's high y).
12
M Katz

擬似コード:

distance_between_rectangles = some_scary_big_number;
Rectangle1の各Edge1について:
Rectangle2の各Edge2について:
距離=最短を計算 Edge1とEdge2の間の距離
if(distance <distance_between_rectangles)
distance_between_rectangles =距離

3

実際には、高速な数学的解決策があります。

_Length(Max((0, 0), Abs(Center - otherCenter) - (Extent + otherExtent)))
_

ここで、Center = ((Maximum - Minimum) / 2) + MinimumおよびExtent = (Maximum - Minimum) / 2。基本的に、ゼロの軸より上のコードはオーバーラップしているため、距離は常に正しいです。

多くの状況で望ましいので、長方形をこの形式のままにしておくことをお勧めします(つまり、回転がはるかに簡単です)。

1
Felix K.

これを解決するための多くのアルゴリズムがあり、Agniusアルゴリズムは正常に機能します。ただし、以下の方が直感的であり(1枚の紙で行うことができます)、線の間の最小距離を見つけることに依存せず、点と線の間の距離を見つけることに依存しているため、以下の方が好きです。

難しいのは、数学関数を実装して、線と点の間の距離を見つけ、点が線に面しているかどうかを見つけることです。ただし、単純な三角法でこれらすべてを解決できます。これを行うための方法論を以下に示します。

任意の角度のポリゴン(三角形、長方形、六角形など)の場合

  1. ポリゴンが重なっている場合は、0を返します
  2. 2つのポリゴンの中心の間に線を引きます。
  3. 各ポリゴンから交差するエッジを選択します。 (ここで問題を減らします)
  4. これらの2つのエッジからの最小距離を見つけます。 (各4点をループして、他の形状のエッジまでの最小距離を探すことができます)。

これらのアルゴリズムは、形状の任意の2つのエッジが180度を超える角度を作成しない限り機能します。その理由は、何かが180度を超える場合、それは星のようにいくつかの角が内側で膨らんでいることを意味するからです。

エッジとポイントの間の最小距離

  1. ポイントが面を向いていない場合は、ポイントとエッジコーナーの間の2つの距離のうち最小のものを返します。
  2. 3つのポイント(エッジのポイントとソロポイント)から三角形を描きます。
  3. ピタゴラス定理 を使用すると、3本の線の間の距離を簡単に取得できます。
  4. ヘロンの公式 で三角形の面積を取得します。
  5. Area = 12⋅base⋅heightを使用して高さを計算します。baseはエッジの長さです。

ポイントがエッジに面しているかどうかを確認します

前と同じように、エッジとポイントから三角形を作成します。 余弦定理 を使用すると、エッジ距離を知るだけですべての角度を見つけることができます。エッジからポイントまでの各角度が90度未満である限り、ポイントはエッジに面しています。

興味があれば、Python for all this here に実装しています。

1
Pithikos

Javaの場合はこれを確認してください。すべての長方形が平行であるという制約があり、交差するすべての長方形に対して0を返します。

   public static double findClosest(Rectangle rec1, Rectangle rec2) {
      double x1, x2, y1, y2;
      double w, h;
      if (rec1.x > rec2.x) {
         x1 = rec2.x; w = rec2.width; x2 = rec1.x;
      } else {
         x1 = rec1.x; w = rec1.width; x2 = rec2.x;
      }
      if (rec1.y > rec2.y) {
         y1 = rec2.y; h = rec2.height; y2 = rec1.y;
      } else {
         y1 = rec1.y; h = rec1.height; y2 = rec2.y;
      }
      double a = Math.max(0, x2 - x1 - w);
      double b = Math.max(0, y2 - y1 - h);
      return Math.sqrt(a*a+b*b);
   }
0
Thomas

この質問は、どのような距離に依存します。中心の距離、エッジの距離、または最も近いコーナーの距離が必要ですか?

私はあなたが最後のものを意味すると思います。 X値とY値が長方形の中心を示している場合は、このトリックを適用することで各コーナーを見つけることができます

//Pseudo code
Vector2 BottomLeftCorner = new Vector2(width / 2, heigth / 2);
BottomLeftCorner = BottomLeftCorner * Matrix.CreateRotation(MathHelper.ToRadians(degrees));
//If LUA has no built in Vector/Matrix calculus search for "rotate Vector" on the web.
//this helps: http://www.kirupa.com/forum/archive/index.php/t-12181.html

BottomLeftCorner += new Vector2(X, Y); //add the Origin so that we have to world position.

すべての長方形のすべての角に対してこれを行い、次にすべての角をループして距離を計算します(abs(v1-v2)のみ)。

これがお役に立てば幸いです

0
Roy T.