web-dev-qa-db-ja.com

2つの長方形が互いに重なり合っているかどうかを確認しますか?

私はユーザーからの高さ、幅、x-pos、y-posの長方形を作るために次の入力を受け取るC++プログラムを書くことを試みています。これらの長方形はすべてx軸とy軸に平行に存在します。つまり、すべての長方形のエッジは0または無限大の傾きを持ちます。

this questionに記載されているものを実装しようとしましたが、あまり運がありません。

私の現在の実装は以下を行います。

// Gets all the vertices for Rectangle 1 and stores them in an array -> arrRect1
// point 1 x: arrRect1[0], point 1 y: arrRect1[1] and so on...
// Gets all the vertices for Rectangle 2 and stores them in an array -> arrRect2

// rotated Edge of point a, rect 1
int rot_x, rot_y;
rot_x = -arrRect1[3];
rot_y = arrRect1[2];
// point on rotated Edge
int pnt_x, pnt_y;
pnt_x = arrRect1[2]; 
pnt_y = arrRect1[3];
// test point, a from rect 2
int tst_x, tst_y;
tst_x = arrRect2[0];
tst_y = arrRect2[1];

int value;
value = (rot_x * (tst_x - pnt_x)) + (rot_y * (tst_y - pnt_y));
cout << "Value: " << value;  

しかし、(a)リンクしたアルゴリズムを正しく実装したのか、それともどうやってこれを解釈するのかを正確に判断できたのかどうか、よくわかりません。

助言がありますか?

310
Rob Burke
if (RectA.Left < RectB.Right && RectA.Right > RectB.Left &&
     RectA.Top > RectB.Bottom && RectA.Bottom < RectB.Top ) 

または、直交座標を使用して

(X1は左座標、X2は右座標、左から右へ、Y1は上座標で、Y2は下座標で、下から上へと増えていきます)...

if (RectA.X1 < RectB.X2 && RectA.X2 > RectB.X1 &&
    RectA.Y1 > RectB.Y2 && RectA.Y2 < RectB.Y1) 

注:編集権限を持つすべてのSOユーザーに。これで終わるのをやめてください。

あなたが四角形Aと四角形Bを持っているとしましょう。証明は矛盾しています。 4つの条件のいずれか1つでは、重複がないこと:を保証します。

  • 条件1 Aの左端がBの右端の右側にある場合、 - AはBの右側に完全に近い
  • Cond2。 Aの右端がBの左端の左側にある場合、 - Aは完全にBの左側になります
  • 条件3 Aの上端がBの下端の下にある場合、 - Aは完全にBの下にあります。
  • Cond4。 Aの下端がBの上端の上にある場合、 - Aは完全にBの上にあります。

したがって、非重複の条件は

Cond1またはCond2またはCond3またはCond4

したがって、重複のための十分な条件は反対です。

しない(Cond1またはCond2またはCond3またはCond4)

De Morganの法則は言う
Not (A or B or C or D)Not A And Not B And Not C And Not Dと同じです
だから、De Morganを使って、

Cond1ではなく、Cond2ではなく、Cond3ではなく、Cond4ではありません

これは以下と同等です。

  • Aの左端、Bの右端の左、[RectA.Left < RectB.Right]、
  • Aの右端からBの左端の右、[RectA.Right > RectB.Left]、
  • Aの上、Bの下、[RectA.Top > RectB.Bottom]、そして
  • AがBのトップより下にある[RectA.Bottom < RectB.Top]

注1:これと同じ原則を任意の次元に拡張できることは明らかです。
注2:たった1ピクセルの重なりを数えることも、その境界上の<および/または><=または>=に変更することはかなり明白であるはずです。
:デカルト座標(X、Y)を使用する場合のこの答えは、標準代数デカルト座標に基づいています(xは左から右に増加し、Yは下から上に増加します)。明らかに、コンピュータシステムが異なる方法でスクリーン座標を機械化する場合(例えば、Yを上から下へ、またはXを右から左へ増加させる)、それに応じて構文を調整する必要がある。

663
Charles Bretana
struct rect
{
    int x;
    int y;
    int width;
    int height;
};

bool valueInRange(int value, int min, int max)
{ return (value >= min) && (value <= max); }

bool rectOverlap(rect A, rect B)
{
    bool xOverlap = valueInRange(A.x, B.x, B.x + B.width) ||
                    valueInRange(B.x, A.x, A.x + A.width);

    bool yOverlap = valueInRange(A.y, B.y, B.y + B.height) ||
                    valueInRange(B.y, A.y, A.y + A.height);

    return xOverlap && yOverlap;
}
111
e.James
struct Rect
{
    Rect(int x1, int x2, int y1, int y2)
    : x1(x1), x2(x2), y1(y1), y2(y2)
    {
        assert(x1 < x2);
        assert(y1 < y2);
    }

    int x1, x2, y1, y2;
};

bool
overlap(const Rect &r1, const Rect &r2)
{
    // The rectangles don't overlap if
    // one rectangle's minimum in some dimension 
    // is greater than the other's maximum in
    // that dimension.

    bool noOverlap = r1.x1 > r2.x2 ||
                     r2.x1 > r1.x2 ||
                     r1.y1 > r2.y2 ||
                     r2.y1 > r1.y2;

    return !noOverlap;
}
26
David Norman

長方形が完全にもう一方の外側にあるかどうかを確認する方が簡単です。

左に...

(r1.x + r1.width < r2.x)

または右側に...

(r1.x > r2.x + r2.width)

または上に...

(r1.y + r1.height < r2.y)

または一番下に...

(r1.y > r2.y + r2.height)

2番目の長方形の、それはおそらくそれと衝突することはできません。四角形がぶつかるとブール値を返す関数を作成するために、条件を論理ORで結合して結果を否定します。

function checkOverlap(r1, r2) : Boolean
{ 
    return !(r1.x + r1.width < r2.x || r1.y + r1.height < r2.y || r1.x > r2.x + r2.width || r1.y > r2.y + r2.height);
}

タッチするだけで既に肯定的な結果が得られるように、 "<"と ">"を "<="と "> ="で変更できます。

21
Björn Kechel

四角形の位置とサイズを次のように定義したとします。

enter image description here

私のC++の実装はこのようなものです。

class Vector2D
{
    public:
        Vector2D(int x, int y) : x(x), y(y) {}
        ~Vector2D(){}
        int x, y;
};

bool DoRectanglesOverlap(   const Vector2D & Pos1,
                            const Vector2D & Size1,
                            const Vector2D & Pos2,
                            const Vector2D & Size2)
{
    if ((Pos1.x < Pos2.x + Size2.x) &&
        (Pos1.y < Pos2.y + Size2.y) &&
        (Pos2.x < Pos1.x + Size1.x) &&
        (Pos2.y < Pos1.y + Size1.y))
    {
        return true;
    }
    return false;
}

上記の図に従った関数呼び出しの例

DoRectanglesOverlap(Vector2D(3, 7),
                    Vector2D(8, 5),
                    Vector2D(6, 4),
                    Vector2D(9, 4));

ifブロック内の比較は以下のようになります。

if ((Pos1.x < Pos2.x + Size2.x) &&
    (Pos1.y < Pos2.y + Size2.y) &&
    (Pos2.x < Pos1.x + Size1.x) &&
    (Pos2.y < Pos1.y + Size1.y))
                 ↓  
if ((   3   <    6   +   9    ) &&
    (   7   <    4   +   4    ) &&
    (   6   <    3   +   8    ) &&
    (   4   <    7   +   5    ))
6
hkBattousai

反対の質問をしてください。2つの長方形がまったく交差していないかどうかをどうやって判断できますか?明らかに、長方形Bの完全に左側にある長方形Aは交差しません。もしAが完全に右側にあるならば。また、AがBより完全に上またはBより完全に下にある場合も同様です。その他の場合、AとBは交差します。

以下にバグがあるかもしれませんが、アルゴリズムについてはかなり自信があります。

struct Rectangle { int x; int y; int width; int height; };

bool is_left_of(Rectangle const & a, Rectangle const & b) {
   if (a.x + a.width <= b.x) return true;
   return false;
}
bool is_right_of(Rectangle const & a, Rectangle const & b) {
   return is_left_of(b, a);
}

bool not_intersect( Rectangle const & a, Rectangle const & b) {
   if (is_left_of(a, b)) return true;
   if (is_right_of(a, b)) return true;
   // Do the same for top/bottom...
 }

bool intersect(Rectangle const & a, Rectangle const & b) {
  return !not_intersect(a, b);
}
6
coryan

これがJava APIで行われる方法は次のとおりです。

public boolean intersects(Rectangle r) {
    int tw = this.width;
    int th = this.height;
    int rw = r.width;
    int rh = r.height;
    if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0) {
        return false;
    }
    int tx = this.x;
    int ty = this.y;
    int rx = r.x;
    int ry = r.y;
    rw += rx;
    rh += ry;
    tw += tx;
    th += ty;
    //      overflow || intersect
    return ((rw < rx || rw > tx) &&
            (rh < ry || rh > ty) &&
            (tw < tx || tw > rx) &&
            (th < ty || th > ry));
}
3
Lyle

質問では、長方形が任意の回転角にあるときの数学にリンクします。質問の角度について少し理解した場合、すべての長方形は互いに垂直であると解釈します。

オーバーラップの公式の一般的な知識は、次のとおりです。

例を使用して:

   1 2 3 4 5 6 
 
 1 + --- + --- + 
 | | 
 2 + A + --- + --- + 
 | | B | 
 3 + + + --- + --- + 
 | | | | | 
 4 + --- + --- + --- + --- + + 
 | | 
 5 + C + 
 | | 
 6 + --- + --- + 

1)全てのx座標(左右両方)をリストに集め、それからそれをソートして重複を取り除く

1 3 4 5 6

2)すべてのy座標(上と下の両方)をリストにまとめ、それをソートして重複を取り除く

1 2 3 4 6

3)固有のx座標間のギャップ数×固有のy座標間のギャップ数によって2D配列を作成する。

4×4

4)すべての長方形をこのグリッドにペイントし、それが発生する各セルの数を増やします。

 1 3 4 5 6 
 
 1 + --- + 
 | 1 | 0 0 0 
 2 + --- + --- + --- + 
 | 1 | 1 | 1 | 0 
 3 + --- + --- + --- + --- + 
 | 1 | 1 | 2 | 1 | 
 4 + --- + --- + --- + --- + 
 0 0 | 1 | 1 | 
 6 + --- + --- + 

5)あなたが長方形を描くように、重なりを傍受するのは簡単です。

2
Will
struct Rect
{
   Rect(int x1, int x2, int y1, int y2)
   : x1(x1), x2(x2), y1(y1), y2(y2)
   {
       assert(x1 < x2);
       assert(y1 < y2);
   }

   int x1, x2, y1, y2;
};

//some area of the r1 overlaps r2
bool overlap(const Rect &r1, const Rect &r2)
{
    return r1.x1 < r2.x2 && r2.x1 < r1.x2 &&
           r1.y1 < r2.y2 && r2.x1 < r1.y2;
}

//either the rectangles overlap or the edges touch
bool touch(const Rect &r1, const Rect &r2)
{
    return r1.x1 <= r2.x2 && r2.x1 <= r1.x2 &&
           r1.y1 <= r2.y2 && r2.x1 <= r1.y2;
}
2
Adam Tegen

2つの長方形が長方形Aと長方形Bであるとしましょう(中心はA1とB1です(A1とB1の座標は簡単に見つけられます))、高さはHaとHb、幅はWaとWb、dxはDとします。 A1とB1の間の幅(x)の距離とdyは、A1とB1の間の高さ(y)の距離になります。

これで、AとBが重なっていると言えます。

if(!(dx > Wa+Wb)||!(dy > Ha+Hb)) returns true
1
sachinr

最も簡単な方法は

/**
 * Check if two rectangles collide
 * x_1, y_1, width_1, and height_1 define the boundaries of the first rectangle
 * x_2, y_2, width_2, and height_2 define the boundaries of the second rectangle
 */
boolean rectangle_collision(float x_1, float y_1, float width_1, float height_1, float x_2, float y_2, float width_2, float height_2)
{
  return !(x_1 > x_2+width_2 || x_1+width_1 < x_2 || y_1 > y_2+height_2 || y_1+height_1 < y_2);
}

まず第一に、コンピュータでは座標系が逆さまになっていることを頭に入れておいてください。 x軸は数学と同じですが、長方形が中心から引かれる場合、y軸は下に向かって増加し、上に行くにつれて減少します。 x1座標がx2にその半分のwidhtを加えたものより大きい場合。それが半分になれば、彼らはお互いに触れ合うことになります。そして同じように、その高さの半分を下向きにして半分になります。それは衝突するでしょう..

1
Xar E Ahmer

座標はピクセルの位置を示すものとは考えないでください。それらをピクセルの間にあると考えてください。そのため、2×2の長方形の面積は9ではなく4になります。

bool bOverlap = !((A.Left >= B.Right || B.Left >= A.Right)
               && (A.Bottom >= B.Top || B.Bottom >= A.Top));
1
Mike Dunlavey

典型的なx、y、w、h、またはx0、y0、x1、x1の代わりに、中心点とその半分のサイズを四角形のデータに使用している場合は、次のようにします。

#include <cmath> // for fabsf(float)

struct Rectangle
{
    float centerX, centerY, halfWidth, halfHeight;
};

bool isRectangleOverlapping(const Rectangle &a, const Rectangle &b)
{
    return (fabsf(a.centerX - b.centerX) <= (a.halfWidth + b.halfWidth)) &&
           (fabsf(a.centerY - b.centerY) <= (a.halfHeight + b.halfHeight)); 
}
0
mchiasson

AとBは2つの長方形です。 Cをカバーする長方形にします。

four points of A be (xAleft,yAtop),(xAleft,yAbottom),(xAright,yAtop),(xAright,yAbottom)
four points of A be (xBleft,yBtop),(xBleft,yBbottom),(xBright,yBtop),(xBright,yBbottom)

A.width = abs(xAleft-xAright);
A.height = abs(yAleft-yAright);
B.width = abs(xBleft-xBright);
B.height = abs(yBleft-yBright);

C.width = max(xAleft,xAright,xBleft,xBright)-min(xAleft,xAright,xBleft,xBright);
C.height = max(yAtop,yAbottom,yBtop,yBbottom)-min(yAtop,yAbottom,yBtop,yBbottom);

A and B does not overlap if
(C.width >= A.width + B.width )
OR
(C.height >= A.height + B.height) 

それはすべての可能なケースを気にかけます。

0
Anwit

この答えはトップアンサーでなければなりません:

長方形が重なる場合、重なり領域はゼロより大きくなります。次に、重複領域を見つけましょう。

それらが重なる場合、overlap-rectの左端はmax(r1.x1, r2.x1)になり、右端はmin(r1.x2, r2.x2)になります。したがって、オーバーラップの長さはmin(r1.x2, r2.x2) - max(r1.x1, r2.x1)になります

したがって、エリアは次のようになります。

area = (max(r1.x1, r2.x1) - min(r1.x2, r2.x2)) * (max(r1.y1, r2.y1) - min(r1.y2, r2.y2))

area = 0の場合、それらは重複しません。

シンプルですね。

0
anony

私はC#バージョンを実装しました、それは簡単にC++に変換されます。

public bool Intersects ( Rectangle rect )
{
  float ulx = Math.Max ( x, rect.x );
  float uly = Math.Max ( y, rect.y );
  float lrx = Math.Min ( x + width, rect.x + rect.width );
  float lry = Math.Min ( y + height, rect.y + rect.height );

  return ulx <= lrx && uly <= lry;
}
0
baretta

非常に簡単な解決策があります

x1、y1、x2、y2、l1、b1、l2をそれぞれ座標とし、それぞれの長さと幅とする

条件を考えます((x 2

これらの長方形が重なる唯一の方法は、x 1、y 1の対角線上の点が他の長方形の内側にあるか、あるいはx 2、y 2の対角線上の点が他の長方形の内側にある場合です。これはまさに上記の条件が暗示していることです。

0
himanshu

別のサイトからの問題を見てください。

ケースは判明します問題(アルゴリズム)を反対側から見ると非常に簡単になります

これは、「長方形は重なっていますか?」という質問に答える代わりに、「長方形はnot重なっていますか?」という質問に答えることを意味します。

最終的に、両方の質問は同じ問題を解決しますが、2番目の質問に対する答えは実装が簡単です長方形は、一方が他方の下にあるとき、または1つがもっと他方の左(これらのケースのいずれかが発生するのに十分ですが、もちろん両方が同時に発生する可能性があります-ここでは論理条件「または」の十分な理解が重要です)。これにより、最初の質問で考慮する必要がある多くのケースが削減されます。

全体の問題も適切な変数名の使用により簡略化

#include<bits/stdc++.h> 

struct Rectangle
{ 
    // Coordinates of the top left corner of the rectangle and width and height
    float x, y, width, height; 
}; 

bool areRectanglesOverlap(Rectangle rect1, Rectangle rect2) 
{
  // Declaration and initialization of local variables

  // if x and y are the top left corner of the rectangle
  float left1, top1, right1, bottom1, left2, top2, right2, bottom2;
  left1 = rect1.x;
  top1 = rect1.y;
  right1 = rect1.x + rect1.width;
  bottom1 = rect1.y - rect1.height;
  left2 = rect2.x;
  top2 = rect2.y;
  right2 = rect2.x + rect2.width;
  bottom2 = rect2.y - rect2.height;

  // The main part of the algorithm

  // The first rectangle is under the second or vice versa
  if (top1 < bottom2 || top2 < bottom1)
  {
    return false;
  }
  // The first rectangle is to the left of the second or vice versa
  if (right1 < left2 || right2 < left1)
  {
    return false;
  }
  // Rectangles overlap
  return true;
}

長方形の別の表現がある場合、変数の変更が定義されているセクションのみを変更することにより、上記の関数を簡単に適応させることができます。関数のそれ以降の部分は変更されませんもちろん、ここではコメントは実際には必要ありませんが、この単純なアルゴリズムを誰もがすぐに理解できるようにコメントを追加しました。

同等ですが、少し読みにくいかもしれません上記の関数の形式は次のようになります:

bool areRectanglesOverlap(Rectangle rect1, Rectangle rect2) 
{
  float left1, top1, right1, bottom1, left2, top2, right2, bottom2;
  left1 = rect1.x;
  top1 = rect1.y;
  right1 = rect1.x + rect1.width;
  bottom1 = rect1.y - rect1.height;
  left2 = rect2.x;
  top2 = rect2.y;
  right2 = rect2.x + rect2.width;
  bottom2 = rect2.y - rect2.height;

  return !(top1 < bottom2 || top2 < bottom1 || right1 < left2 || right2 < left1);
}
0
simhumileco
bool Square::IsOverlappig(Square &other)
{
    bool result1 = other.x >= x && other.y >= y && other.x <= (x + width) && other.y <= (y + height); // other's top left falls within this area
    bool result2 = other.x >= x && other.y <= y && other.x <= (x + width) && (other.y + other.height) <= (y + height); // other's bottom left falls within this area
    bool result3 = other.x <= x && other.y >= y && (other.x + other.width) <= (x + width) && other.y <= (y + height); // other's top right falls within this area
    bool result4 = other.x <= x && other.y <= y && (other.x + other.width) >= x && (other.y + other.height) >= y; // other's bottom right falls within this area
    return result1 | result2 | result3 | result4;
}
0
Kok How Teh

これは、 『Introduction to Java Programming- Comprehensive Edition』のエクササイズ3.28からの引用です。このコードは、2つの長方形がインデントかどうか、一方が他方の内側にあるかどうか、一方が他方の外側にあるかどうかをテストします。これらの条件のどれもが満たされないならば、2つは重なります。

** 3.28(ジオメトリ:2つの長方形)2つの長方形の中心のx、y座標、幅、高さを入力し、2つ目の長方形が最初の長方形の内側にあるか最初の長方形と重なるかを決定するプログラム図3.9に示すように。すべてのケースを網羅するようにプログラムをテストしてください。サンプル実行はここにあります:

R1の中心のx、y座標、幅、および高さを入力:2.5 4 2.5 43 r2の中心のx、y座標、幅、および高さを入力:1.5 5 0.5 3 r2はr1の内側にあります

R1の中心のx、y座標、幅、および高さを入力:1 2 3 5.5 r2の中心のx、y座標、幅、および高さを入力:3 4 4.5 5 r2はr1と重なります

R1の中心のx、y座標、幅、および高さを入力します。1 2 3 3 r2の中心のx、y座標、幅、および高さを入力します。40 45 3 2 r2はr1と重なりません

import Java.util.Scanner;

public class ProgrammingEx3_28 {
public static void main(String[] args) {
    Scanner input = new Scanner(System.in);

    System.out
            .print("Enter r1's center x-, y-coordinates, width, and height:");
    double x1 = input.nextDouble();
    double y1 = input.nextDouble();
    double w1 = input.nextDouble();
    double h1 = input.nextDouble();
    w1 = w1 / 2;
    h1 = h1 / 2;
    System.out
            .print("Enter r2's center x-, y-coordinates, width, and height:");
    double x2 = input.nextDouble();
    double y2 = input.nextDouble();
    double w2 = input.nextDouble();
    double h2 = input.nextDouble();
    w2 = w2 / 2;
    h2 = h2 / 2;

    // Calculating range of r1 and r2
    double x1max = x1 + w1;
    double y1max = y1 + h1;
    double x1min = x1 - w1;
    double y1min = y1 - h1;
    double x2max = x2 + w2;
    double y2max = y2 + h2;
    double x2min = x2 - w2;
    double y2min = y2 - h2;

    if (x1max == x2max && x1min == x2min && y1max == y2max
            && y1min == y2min) {
        // Check if the two are identicle
        System.out.print("r1 and r2 are indentical");

    } else if (x1max <= x2max && x1min >= x2min && y1max <= y2max
            && y1min >= y2min) {
        // Check if r1 is in r2
        System.out.print("r1 is inside r2");
    } else if (x2max <= x1max && x2min >= x1min && y2max <= y1max
            && y2min >= y1min) {
        // Check if r2 is in r1
        System.out.print("r2 is inside r1");
    } else if (x1max < x2min || x1min > x2max || y1max < y2min
            || y2min > y1max) {
        // Check if the two overlap
        System.out.print("r2 does not overlaps r1");
    } else {
        System.out.print("r2 overlaps r1");
    }

}
}
0
anchan42