る場合は二つの矩形が重なのだろうか。
-
08-07-2019 - |
質問
って書はC++のプログラムは次の入力をユーザーから構築矩形(2、5):高さ、幅、x-pos,y-posです。これらすべての長方形が平行にx、y軸はすべてのエッジにおいてゲレンデは0または無限大になる
たって行かれました この 問題がないともできます。
私の現在の実装は、次の操作を実行します:
// 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;
しかしいくだもんのアルゴリズムかつ正確に、またいつどのように解釈する。
ご意見募集
解決
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)
注:編集権限を持つすべてのユーザーに。これでフィドリングを停止してください。
Rect AとRect Bがあるとします。 証明は矛盾によるものです。 4つの条件のいずれか1つにより、重複が存在しないことが保証されます。
- 条件1。 Aの左端がBの右端の右側にある場合、 -その後、Aは完全にBの右側になります
- 条件2。 Aの右端がBの左端の左側にある場合、 -その後、Aは完全にBの左側になります
- 条件3。 Aの上端がBの下端より下にある場合、 -その後、Aは完全にBを下回ります
- 条件4。 Aの下端がBの上端より上にある場合、 -その後、Aは完全にBの上になります
つまり、非オーバーラップの条件は
ですCond1 Or Cond2 Or Cond3 Or Cond4
したがって、オーバーラップの十分条件は反対です。
Not (Cond1 Or Cond2 Or Cond3 Or Cond4)
デモーガンの法則は言う
Not (A or B or C or D)
はNot A And Not B And Not C And Not D
と同じです
De Morganを使用して、
Not Cond1 And Not Cond2 And Not Cond3 And Not 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つのピクセルのオーバーラップをカウントし、その境界上の<
および/または>
を<=
または>=
に変更することもかなり明白です。
注3 :この回答は、デカルト座標(X、Y)を使用する場合、標準代数デカルト座標に基づいています(xは左から右に増加し、Yは下から上に増加します)。明らかに、コンピューターシステムがスクリーン座標を異なる方法で機械化する場合(たとえば、Yを上から下に、またはXを右から左に増やす)、それに応じて構文を調整する必要があります/
他のヒント
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;
}
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;
}
長方形が完全に他の長方形の外側にあるかどうかを確認する方が簡単です。
左側...
(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);
}
タッチのみのときにすでに肯定的な結果を得るために、<!> quot; <!> lt; <!> quot;および<!> quot; <!> gt; <!> quot; <!> quot; <!> lt; = <!> quot;および<!> quot; <!> gt; = <!> quot;。
反対の質問を自問してください: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);
}
次のように長方形の位置とサイズを定義したとします:
私の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 ))
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));
}
質問では、長方形が任意の回転角度にあるときの数学にリンクします。ただし、質問の角度について少し理解したら、すべての長方形が互いに垂直であると解釈します。
重複領域の式を知っている一般的なことは次のとおりです。
例を使用:
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)四角形をペイントすると、重複を簡単に傍受できます。
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;
}
座標は、ピクセルの位置を示すものと考えないでください。それらはピクセルの間にあると考えてください。そうすれば、2x2の長方形の面積は9ではなく4になります。
bool bOverlap = !((A.Left >= B.Right || B.Left >= A.Right)
&& (A.Bottom >= B.Top || B.Bottom >= A.Top));
最も簡単な方法は
/**
* 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とその半分の幅よりも大きい場合。それは彼らがお互いに触れる半分になることを意味します。そして、同じ方法で下方向に+高さの半分になります。衝突します。
2つの長方形が長方形Aと長方形Bであるとしましょう。中心をA1とB1(A1とB1の座標は簡単に見つけられます)、高さをHaとHb、幅をWaとWbとしましょう。 dxはA1とB1の間のwidth(x)距離、dyはA1とB1の間のheight(y)距離です。
これで、AとBが重複すると言うことができます:when
if(!(dx > Wa+Wb)||!(dy > Ha+Hb)) returns true
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;
}
非常に簡単な解決策があります
それぞれx1、y1 x2、y2、l1、b1、l2、letの座標、長さ、幅にする
条件を検討する((x2
これらの長方形が重なる唯一の方法は、x1、y1の対角点が他の長方形の内側にあるか、同様にx2、y2の対角点が他の長方形の内側にある場合です。これはまさに上記の条件が暗示しています。
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)
考えられるすべてのケースを処理します。
これは、Javaプログラミング入門編入門の本の演習3.28からのものです。このコードは、2つの長方形がインデンティクルであるかどうか、一方が他方の内側にあるか、一方が他方の外側にあるかをテストします。これらの条件のいずれも満たされない場合、2つは重複します。
** 3.28(ジオメトリ:2つの四角形)ユーザーに入力を促すプログラムを作成します 2つの長方形の中心のx、y座標、幅、高さを決定します 図に示すように、2番目の長方形が最初の長方形の内側にあるか、最初の長方形と重なるか 図<!> nbsp; 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");
}
}
}
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;
}
典型的な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));
}
この答えはトップアンサーでなければなりません:
長方形がオーバーラップする場合、オーバーラップ領域はゼロより大きくなります。オーバーラップ領域を見つけましょう:
それらが重なる場合、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
の場合、重複しません。
シンプルではありませんか?
別のサイトの問題をご覧ください。
問題は、反対側から問題(アルゴリズム)を見ると非常に単純であることが判明しました。
これは、質問に答える代わりに:<!> quot;長方形が重なっていますか?<!> quot ;、質問に答えます:<!> quot;長方形はしない重複しますか?<!> quot;。
最後に、両方の質問が同じ問題を解決しますが、 2番目の質問の答えは実装が簡単ですもう一方の左側に追加します(これらのケースのいずれかが発生するのに十分ですが、もちろん両方が同時に発生する可能性があります-ここでは論理条件の十分な理解<!> quot;または<!> quot;は重要です)。これにより、最初の質問で考慮する必要がある多くのケースが削減されます。
問題全体は、適切な変数名を使用することで簡略化されています:
#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);
}
"を実行した場合の差分xまたはy座標に対応する頂点の向矩形の場合、結果は同じ符号の二つの矩形重なり合うわけではない軸は"申し訳ございませんが、私に私の翻訳が正しい)
ソース: http://www.ieev.org/2009/05/kiem-tra-hai-hinh-chu-nhat-chong-nhau.html
長方形が互いに接触しているか、重なり合っているかを判断するJavaコード
...
for ( int i = 0; i < n; i++ ) {
for ( int j = 0; j < n; j++ ) {
if ( i != j ) {
Rectangle rectangle1 = rectangles.get(i);
Rectangle rectangle2 = rectangles.get(j);
int l1 = rectangle1.l; //left
int r1 = rectangle1.r; //right
int b1 = rectangle1.b; //bottom
int t1 = rectangle1.t; //top
int l2 = rectangle2.l;
int r2 = rectangle2.r;
int b2 = rectangle2.b;
int t2 = rectangle2.t;
boolean topOnBottom = t2 == b1;
boolean bottomOnTop = b2 == t1;
boolean topOrBottomContact = topOnBottom || bottomOnTop;
boolean rightOnLeft = r2 == l1;
boolean leftOnRight = l2 == r1;
boolean rightOrLeftContact = leftOnRight || rightOnLeft;
boolean leftPoll = l2 <= l1 && r2 >= l1;
boolean rightPoll = l2 <= r1 && r2 >= r1;
boolean leftRightInside = l2 >= l1 && r2 <= r1;
boolean leftRightPossiblePlaces = leftPoll || rightPoll || leftRightInside;
boolean bottomPoll = t2 >= b1 && b2 <= b1;
boolean topPoll = b2 <= b1 && t2 >= b1;
boolean topBottomInside = b2 >= b1 && t2 <= t1;
boolean topBottomPossiblePlaces = bottomPoll || topPoll || topBottomInside;
boolean topInBetween = t2 > b1 && t2 < t1;
boolean bottomInBetween = b2 > b1 && b2 < t1;
boolean topBottomInBetween = topInBetween || bottomInBetween;
boolean leftInBetween = l2 > l1 && l2 < r1;
boolean rightInBetween = r2 > l1 && r2 < r1;
boolean leftRightInBetween = leftInBetween || rightInBetween;
if ( (topOrBottomContact && leftRightPossiblePlaces) || (rightOrLeftContact && topBottomPossiblePlaces) ) {
path[i][j] = true;
}
}
}
}
...