it-swarm.com.ru

Определить, перекрывают ли два прямоугольника друг друга?

Я пытаюсь написать программу на 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;  

Однако я не совсем уверен, что (а) я правильно реализовал алгоритм, к которому я привязан, или я сделал именно так, как это интерпретировать?

Какие-либо предложения?

295
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 ПОЛЬЗОВАТЕЛЕЙ С ПОЛНОМОЧИЯМИ РЕДАКТИРОВАНИЯ. ПОЖАЛУЙСТА, Хватит возиться с этим.

Скажем, у вас есть Rect A и Rect B. Доказательство противоречит. Любое из четырех условий гарантирует, что перекрытие не может существовать :

  • COND1. Если левый край А находится справа от правого края В, - тогда A находится полностью справа от B
  • Cond2. Если правый край А находится слева от левого края В, - тогда A находится полностью слева от B
  • Cond3. Если верхний край А находится ниже нижнего края В, - тогда А полностью ниже В
  • Cond4. Если нижний край А находится выше верхнего края В, - тогда А полностью выше В

Таким образом, условие не перекрытия 

Cond1 или Cond2 или Cond3 или Cond4

Поэтому достаточным условием перекрытия является обратное. 

Нет (Cond1 или Cond2 или Cond3 или Cond4)

Закон де Моргана гласит
Not (A or B or C or D) такая же, как Not A And Not B And Not C And Not D
Таким образом, используя Де Морган, мы имеем

Не Cond1 и не Cond2 и не Cond3 и не Cond4

Это эквивалентно:

  • Левый край А слева от правого края В, [RectA.Left < RectB.Right] и
  • Правый край A справа от левого края B, [RectA.Right > RectB.Left] и
  • Верхняя часть А над нижней частью В, [RectA.Top > RectB.Bottom] и
  • A снизу под B сверху [RectA.Bottom < RectB.Top]

Примечание 1 : Совершенно очевидно, что этот же принцип может быть распространен на любое количество измерений.
Примечание 2 : Также должно быть достаточно очевидно подсчитывать перекрытия только одного пикселя, изменять < и/или > на этой границе на <= или >=.
Примечание 3 : Этот ответ при использовании декартовых координат (X, Y) основан на стандартных алгебраических декартовых координатах (x увеличивается слева направо, а Y увеличивается снизу вверх). Очевидно, что если компьютерная система может механизировать координаты экрана по-разному (например, увеличивая Y сверху вниз или X справа налево), синтаксис необходимо будет соответствующим образом скорректировать / 

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

Проще проверить, находится ли прямоугольник полностью вне другого, поэтому, если он 

налево... 

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

или справа ... 

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

или сверху ... 

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

или на дне ... 

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

второго прямоугольника, он не может столкнуться с ним. Таким образом, чтобы получить функцию, которая возвращает логическое значение, говорящее о столкновении прямоугольников, мы просто объединяем условия с помощью логических ИЛИ и отменяем результат:

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

Задайте себе противоположный вопрос: как я могу определить, не пересекаются ли два прямоугольника вообще? Очевидно, что прямоугольник A полностью слева от прямоугольника B не пересекается. Кроме того, если А полностью вправо. И точно так же, если 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) собрать все координаты х (как левые, так и правые) в список, затем отсортировать и удалить дубликаты

1 3 4 5 6

2) собрать все координаты y (как верхнюю, так и нижнюю) в список, затем отсортировать и удалить дубликаты

1 2 3 4 6

3) создать двумерный массив по количеству промежутков между уникальными координатами x * числу промежутков между уникальными координатами y.

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

Допустим, два прямоугольника - это прямоугольник A и прямоугольник B. Пусть есть центры с A1 и B1 (координаты A1 и B1 могут быть легко найдены), пусть высоты - это Ha и Hb, ширина - это Wa и Wb, пусть dx - это width (x) расстояние между A1 и B1, а dy - расстояние по высоте (y) между A1 и B1.

Теперь мы можем сказать, что можем сказать, что А и В перекрываются: когда

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 плюс его половина видимости. тогда это означает, что половину они коснутся друг друга. и таким же образом идет вниз + половина его высоты. это столкнется ..

1
Xar E Ahmer

Не думайте, что координаты указывают, где находятся пиксели. Думайте о них как о пикселях. Таким образом, площадь прямоугольника 2х2 должна быть 4, а не 9.

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

А и В два прямоугольника. 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

Я реализовал версию 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, будут кординаты и их длины и ширины соответственно

рассмотрим условие ((x2

теперь единственный способ перекрытия этих прямоугольников - это если точка, диагональная x1, y1, будет находиться внутри другого прямоугольника или аналогично точке, диагональной x2, y2, будет находиться внутри другого прямоугольника. что именно из вышеуказанного условия подразумевает.

0
himanshu

Посмотрите на вопрос с другого сайта.

Случай оказывается довольно простым, если мы посмотрим на проблему (алгоритм) с другой стороны.

Это означает, что вместо ответа на вопрос: «Прямоугольники перекрываются?», Мы ответим на вопрос: «Прямоугольники не перекрываются?».

В конце оба вопроса решают одну и ту же проблему, но ответ на второй вопрос проще реализовать, потому что прямоугольники не перекрываются, только когда один находится под другим или когда один находится слева от другого. (достаточно, чтобы один из этих случаев имел место, но, конечно, может случиться, что оба произойдут одновременно - здесь важно хорошее понимание логического условия «или» важно). Это уменьшает многие случаи, которые необходимо рассмотреть по первому вопросу.

Весь вопрос также упрощается путем использования соответствующих имен переменных:

#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

Это из упражнения 3.28 из книги Введение в программирование на Java - полное издание. Код проверяет, являются ли два прямоугольника одинаковыми, находится ли один внутри другого и находится ли один за другим. Если ни одно из этих условий не выполнено, то два перекрываются.

** 3.28 (Геометрия: два прямоугольника) Напишите программу, которая предлагает пользователю ввести координаты X-, y-координат, ширину и высоту двух прямоугольников и определяет , Находится ли второй прямоугольник внутри первого или совпадает с первым, как показано на рисунке 3.9. Протестируйте вашу программу, чтобы охватить все случаи . Вот примеры прогонов:

Введите x-, y-координаты, ширину и высоту центра r1: 2.5 4 2.5 43 Введите x-, y-координаты, ширину и высоту центра r1: 1,5 5 0,5 3 R2 находится внутри r1 

Введите x-, y-координаты, ширину и высоту центра r1: 1 2 3 5.5 Введите x-, y-координаты, ширину и высоту центра r2: 3 4 4.5 5 R2 перекрывает r1

Введите x-, y-координаты, ширину и высоту центра r1: 1 2 3 3 Введите x-, y-координаты, ширину и высоту центра r2: 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