web-dev-qa-db-fra.com

Déterminer si deux rectangles se chevauchent?

J'essaie d'écrire un programme C++ qui utilise les entrées suivantes de l'utilisateur pour construire des rectangles (entre 2 et 5): hauteur, largeur, x-pos, y-pos. Tous ces rectangles existeront parallèlement aux axes x et y, c'est-à-dire que tous leurs bords auront des pentes de 0 ou de l'infini.

J'ai essayé de mettre en œuvre ce qui est mentionné dans cette question mais je n'ai pas beaucoup de chance.

Ma mise en œuvre actuelle fait ce qui suit:

// 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;  

Cependant, je ne suis pas tout à fait sûr si (a) j’ai correctement implémenté l’algorithme que j’ai lié, ou si j’ai fait exactement comment l’interpréter?

Aucune suggestion?

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

ou, en utilisant des coordonnées cartésiennes 

(X1 étant la coordonnée gauche, X2 la coordonnée droite, augmentant de gauche à droite et Y1 la coordonnée supérieure et Y2 la coordonnée inférieure, augmentant de bas en haut) ...

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

REMARQUE: TOUS LES SO UTILISATEURS AVEC AUTORITÉ DE MONTAGE. VEUILLEZ CESSER DE TROUVER AVEC CELA.

Disons que vous avez Rect A, et Rect B. La preuve est par contradiction. Chacune des quatre conditions garantit que aucun chevauchement ne peut exister :

  • Cond1. Si le bord gauche de A est à droite du bord droit du B, - alors A est totalement à droite de B
  • Cond2. Si le bord droit de A se trouve à gauche du bord gauche du B, - alors A est totalement à gauche de B
  • Cond3. Si le bord supérieur de A est inférieur au bord inférieur de B, - alors A est totalement inférieur à B
  • Cond4. Si le bord inférieur de A est supérieur au bord supérieur de B, - alors A est totalement supérieur à B

Donc, la condition de non-chevauchement est 

Cond1 ou Cond2 ou Cond3 ou Cond4

Par conséquent, une condition suffisante pour le chevauchement est le contraire. 

Not (Cond1 ou Cond2 ou Cond3 ou Cond4)

La loi de De Morgan dit
Not (A or B or C or D) est identique à Not A And Not B And Not C And Not D
donc en utilisant De Morgan, nous avons

Pas Cond1 Et Pas Cond2 Et Pas Cond3 Et Pas Cond4

Ceci est équivalent à:

  • Bord gauche de A à gauche du bord droit de B, [RectA.Left < RectB.Right], et
  • Bord droit de A à droite du bord gauche de B, [RectA.Right > RectB.Left], et
  • Le haut de A est supérieur au bas de B, [RectA.Top > RectB.Bottom], et
  • Bas de A en dessous de Haut de B [RectA.Bottom < RectB.Top]

Note 1 : Il est assez évident que ce même principe peut être étendu à un nombre quelconque de dimensions.
Note 2 : Il devrait également être assez évident de compter les chevauchements d’un pixel, de changer le < et/ou le > de cette limite en un <= ou un >=.
Note 3 : Cette réponse, lorsque vous utilisez les coordonnées cartésiennes (X, Y), est basée sur les coordonnées cartésiennes algébriques standard (x augmente de gauche à droite et Y augmente de bas en haut). Évidemment, lorsqu'un système informatique pourrait mécaniser différemment les coordonnées de l'écran (par exemple, augmenter Y de haut en bas ou X de droite à gauche), la syntaxe devra être ajustée en conséquence / 

639
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;
}
108
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

Il est plus facile de vérifier si un rectangle est complètement en dehors de l’autre, donc s’il est soit 

sur la gauche... 

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

ou à droite ... 

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

ou sur le dessus ... 

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

ou sur le fond ... 

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

du deuxième rectangle, il ne peut pas entrer en collision avec lui. Donc, pour avoir une fonction qui retourne un Booléen disant que les rectangles se rencontrent, nous combinons simplement les conditions par des OR logiques et nions le résultat:

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);
}

Pour recevoir déjà un résultat positif en touchant uniquement, nous pouvons modifier les "<" et ">" par "<=" et "> =".

21
Björn Kechel

Supposons que vous ayez défini les positions et les tailles des rectangles comme ceci:

enter image description here

Mon implémentation C++ ressemble à ceci:

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;
}

Un exemple d'appel de fonction selon la figure donnée ci-dessus:

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

Les comparaisons à l'intérieur du bloc if ressembleront à celles ci-dessous:

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

Posez-vous la question opposée: comment puis-je déterminer si deux rectangles ne se croisent pas du tout? Évidemment, un rectangle A situé complètement à gauche du rectangle B ne se croise pas. Aussi, si A est complètement à droite. Et de même si A est complètement supérieur à B ou complètement inférieur à B. Dans tous les autres cas, A et B se croisent.

Ce qui suit peut avoir des bugs, mais je suis assez confiant pour l’algorithme:

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

Voici comment cela se passe dans l'API Java:

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

Dans la question, vous établissez un lien avec les maths lorsque les rectangles présentent des angles de rotation arbitraires. Si je comprends toutefois le problème des angles dans la question, j’interprète que tous les rectangles sont perpendiculaires les uns aux autres.

Un général connaissant la formule de chevauchement est:

En utilisant l'exemple:

    1 2 3 4 5 6 

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

1) rassemblez toutes les coordonnées x (à gauche et à droite) dans une liste, puis triez-la et supprimez les doublons

1 3 4 5 6

2) rassemblez toutes les coordonnées y (haut et bas) dans une liste, puis triez-la et éliminez les doublons

1 2 3 4 6

3) créer un tableau 2D par nombre d'espaces entre les coordonnées x uniques * nombre d'espaces entre les coordonnées y uniques.

4 * 4

4) Peignez tous les rectangles dans cette grille, en incrémentant le nombre de cellules sur lesquelles elle apparaît.

 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) Lorsque vous peignez les rectangles, il est facile d’intercepter les chevauchements.

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

Disons que les deux rectangles sont le rectangle A et le rectangle B. Soit A1 et B1 les centres (les coordonnées de A1 et B1 sont faciles à trouver), les hauteurs sont Ha et Hb, la largeur est Wa et Wb, soit dx le largeur (x) distance entre A1 et B1 et dy est la hauteur (y) distance entre A1 et B1.

Maintenant, nous pouvons dire que nous pouvons dire A et B se chevauchent: quand

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

Le moyen le plus simple est

/**
 * 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);
}

tout d'abord, gardez à l'esprit que dans les ordinateurs, le système de coordonnées est à l'envers. L'axe des abscisses est identique à celui des mathématiques, mais l'axe des ordonnées augmente et décroît de manière ascendante .. si un rectangle est tracé à partir du centre . si les coordonnées x1 sont supérieures à x2 et à la moitié de sa largeur. alors cela signifie aller à moitié, ils vont se toucher. et de la même manière en descendant vers le bas + la moitié de sa hauteur. il va entrer en collision ..

1
Xar E Ahmer

Ne pensez pas que les coordonnées indiquent où sont les pixels. Pensez à eux comme étant entre les pixels. De cette façon, l'aire d'un rectangle 2x2 devrait être 4, pas 9.

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

Pour ceux d'entre vous qui utilisent des points centraux et des demi-tailles pour leurs données de rectangle, au lieu des x, y, w, h ou x0, y0, x1, x1, voici comment procéder:

#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 et B deux rectangle. C soit leur rectangle de couverture. 

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) 

Il prend en charge tous les cas possibles.

0
Anwit

Cette réponse devrait être la meilleure réponse:

Si les rectangles se chevauchent, la zone de chevauchement sera supérieure à zéro. Trouvons maintenant la zone de recouvrement:

S'ils se chevauchent, le bord gauche du chevauchement-rect sera le max(r1.x1, r2.x1) et le bord droit sera min(r1.x2, r2.x2). Donc, la longueur du chevauchement sera min(r1.x2, r2.x2) - max(r1.x1, r2.x1)

Donc le domaine sera:

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

Si area = 0 alors ils ne se chevauchent pas.

Simple n'est-ce pas?

0
anony

J'ai implémenté une version C #, elle est facilement convertie en 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

J'ai une solution très facile

soit x1, y1 x2, y2, l1, b1, l2, être les coordonnées et leurs longueurs et largeurs respectivement

considérer la condition ((x2

or, le rectangle ne se chevauchera plus que si le point diagonal à x1, y1 sera situé à l'intérieur de l'autre rectangle ou, de la même manière, le point diagonal à x2, y2 sera situé à l'intérieur de l'autre rectangle. ce qui est exactement la condition ci-dessus implique.

0
himanshu

Un coup d'oeil à la matière d'un autre site.

Le cas s'avère pour être assez simple si on regarde le problème (algorithme) de l'autre côté}.

Cela signifie qu'au lieu de répondre à la question: "Les rectangles se chevauchent-ils?", Nous répondrons à la question: "Les rectangles font-ils pas se chevauchent?".

En fin de compte, les deux questions résolvent le même problème mais la réponse à la deuxième question est plus simple à mettre en œuvre} parce que les rectangles ne se chevauchent pas seulement quand l'un est sous l'autre ou quand on est plus à gauche de l'autre (il suffit qu'un de ces cas se produise, mais bien entendu, il peut arriver que les deux se produisent simultanément - dans ce cas, une bonne compréhension de la condition logique "ou" est importante). Cela réduit le nombre de cas à prendre en compte pour la première question.

Le sujet entier est également simplifié par l’utilisation de noms de variables appropriés}:

#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;
}

Même si nous avons une représentation différente d'un rectangle, il est facile d'adapter la fonction ci-dessus en ne modifiant que la section où les modifications de variables sont définies. L'autre partie de la fonction reste inchangée (bien sûr , les commentaires ne sont pas vraiment nécessaires ici, mais je les ai ajoutés pour que tout le monde puisse comprendre rapidement cet algorithme simple).

Un équivalent mais peut-être un peu moins lisible forme de la fonction ci-dessus pourrait ressembler à ceci:

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

Ceci est tiré de l'exercice 3.28 de l'ouvrage Introduction à la programmation Java - Édition complète. Le code teste si les deux rectangles sont un indenticule, si l'un est à l'intérieur de l'autre et si l'un est à l'extérieur de l'autre. Si aucune de ces conditions n'est remplie, les deux se chevauchent.

** 3.28 (Géométrie: deux rectangles) Ecrivez un programme qui invite l'utilisateur à entrer les coordonnées x, y, centre, largeur et hauteur de Centre de deux rectangles et détermine si le deuxième rectangle est à l'intérieur du premier. ou chevauche le premier, comme indiqué dans la Figure 3.9. Testez votre programme pour couvrir tous les cas . Voici les exemples de tests:

Entrez le centre des coordonnées x, y, la largeur et la hauteur de r1: 2.5 4 2.5 43 Entrez le centre des coordonnées x, y, la largeur et la hauteur de r2: 1.5 5 0.5 3 R2 est à l'intérieur de r1 

Entrez le centre des coordonnées x, y, la largeur et la hauteur de r1: 1 2 3 5.5 Entrez le centre des coordonnées x, y, la largeur et la hauteur de r2: 3 4 4,5 5 R2 chevauche r1

Entrez le centre des coordonnées x, y, la largeur et la hauteur de r1: 1 2 3 3 Entrez le centre des coordonnées x, y, la largeur et la hauteur de r2: 40 45 3 2 R2 ne chevauche pas 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