Швидкий перехід прямокутника до прямокутника


81

Який швидкий спосіб перевірити, чи перетинаються 2 прямокутники?


Під час пошуку в Інтернеті з’явився цей однокласний вкладиш (WOOT!), Але я не розумію, як писати його в Javascript, здається, він написаний у давній формі C ++.

struct
{
    LONG    left;
    LONG    top;
    LONG    right;
    LONG    bottom;
} RECT; 

bool IntersectRect(const RECT * r1, const RECT * r2)
{
    return ! ( r2->left > r1->right
        || r2->right < r1->left
        || r2->top > r1->bottom
        || r2->bottom < r1->top
        );
}

5
Думаю, ви зробили друкарську помилку у своїй копії / вставці
fmark

5
Оригінальна стаття має друкарську помилку. r2->right leftне має сенсу. Це може бути пошкоджено через проблеми з HTML-екраном.
Марсело Кантос,

42
Мені цікаво, як ви вважаєте, що наведений вище код відрізнявся б у "сучасній" формі С ++.
jamesdlin

3
Я впевнений, що відсутні символи є <символами через HTML-екран.
devios1,

1
@jamesdlin ви б зробили функцію функцією-членом структури, взявши один параметр. По-друге, ви зазвичай використовуєте const & замість const *. Ви можете використовувати шаблони для версій int, long і double, замість того, щоб використовувати якийсь макрос Win32 ... (Він також не компілюється, оскільки RECT в кінцевому підсумку є екземпляром неназваної структури, а не імені типу.) Приклад : ideone.com/bnzwl3
Себастьян Вал,

Відповіді:


142

Ось як цей код можна перекласти в JavaScript. Зверніть увагу, що у вашому коді та в статті, як передбачається у коментарях, є помилка. Зокрема, r2->right leftмає бути r2->right < r1->leftі r2->bottom topповинно бути, r2->bottom < r1->topщоб функція працювала.

function intersectRect(r1, r2) {
  return !(r2.left > r1.right || 
           r2.right < r1.left || 
           r2.top > r1.bottom ||
           r2.bottom < r1.top);
}

Тестовий приклад:

var rectA = {
  left:   10,
  top:    10,
  right:  30,
  bottom: 30
};

var rectB = {
  left:   20,
  top:    20,
  right:  50,
  bottom: 50
};

var rectC = {
  left:   70,
  top:    70,
  right:  90,
  bottom: 90
};

intersectRect(rectA, rectB);  // returns true
intersectRect(rectA, rectC);  // returns false

Просто для додавання / підтвердження - це тестування трьох ящиків розміром 20px x 20px, за винятком rectB, який становить 30px x 30px
verenion 20.03.13

6
якщо r1 і r2 ідентичні, функція intersectRect поверне false
zumalifeguard

Фантастична красномовна реалізація. Любіть це! +1, чудово спрацював для моєї гри.
Unome

1
@zumalifeguard Чому ти так думаєш?
Minix

Ця функція така геніальна. Я б ніколи про це не думав, натомість спробував би зробити так, щоб ці дві коробки перетиналися.
nikk wong

69
function intersect(a, b) {
  return (a.left <= b.right &&
          b.left <= a.right &&
          a.top <= b.bottom &&
          b.top <= a.bottom)
}

Це передбачає, що topзазвичай менше ніж bottom(тобто, що yкоординати збільшуються вниз).


Хороше та робоче рішення, але повинно бути трохи повільнішим, оскільки всі умови повинні бути оцінені. Інше рішення виконується, як тільки одна з умов оцінюється як істинна.
Гіго

21
Це також робиться, як тільки одна з умов оцінюється як помилкова. Тобто в тих самих випадках, що й інший.
DS.

3
Це краще, оскільки воно усуває негативну дію.
Discipol

4
+1, набагато акуратніше прийнятої відповіді. якщо використовується напіввідкритий діапазон (тобто прямокутник включає верхній і лівий, але не включає нижній і правий, як це поширено у багатьох графічних системах), зміна <=на <має працювати.
Жуль

Мені подобається це рішення, тому що я можу видалити =для кожної умови, і це дозволяє прямокутникам "торкатися" меж.
програхаммер

20

Ось як .NET Framework реалізує Rectangle.Intersect

public bool IntersectsWith(Rectangle rect)
{
  if (rect.X < this.X + this.Width && this.X < rect.X + rect.Width && rect.Y < this.Y + this.Height)
    return this.Y < rect.Y + rect.Height;
  else
    return false;
}

Або статична версія:

public static Rectangle Intersect(Rectangle a, Rectangle b)
{
  int x = Math.Max(a.X, b.X);
  int num1 = Math.Min(a.X + a.Width, b.X + b.Width);
  int y = Math.Max(a.Y, b.Y);
  int num2 = Math.Min(a.Y + a.Height, b.Y + b.Height);
  if (num1 >= x && num2 >= y)
    return new Rectangle(x, y, num1 - x, num2 - y);
  else
    return Rectangle.Empty;
}

6

Ще один більш простий спосіб. (Це передбачає збільшення осі y вниз).

function intersect(a, b) {
  return Math.max(a.left, b.left) < Math.min(a.right, b.right) &&
          Math.max(a.top, b.top) < Math.min(a.bottom, b.bottom);
}

4 числа (макс. Та мін.) У наведеному вище стані також дають точки перетину.


1

Це тип Rect, який ви можете використовувати. Це вже JavaScript.

https://dxr.mozilla.org/mozilla-beta/source/toolkit/modules/Geometry.jsm


Цей код поверне значення false для виправлень A (0,0 100 100) і B (100 100 100 100 100). Я думаю, що там має бути <= замість <
Станіслав С.

<= дає прямокутник висотою 0. Не корисно для моїх цілей.
englebart

0

Я використав суміш методів, щоб виявити менший прямокутник всередині великого прямокутника. Це метод nodejs, який використовує ширину / висоту, але може бути легко адаптований.

            isIntersectingRect: function (r1, r2) {
              var quickCheck = (r1.x <= r2.x + r2.w &&
                      r2.x <= r1.x + r1.w &&
                      r1.y <= r2.y + r2.h &&
                      r2.y <= r1.y + r1.h)
              if (quickCheck) return true;
              var x_overlap = Math.max(0, Math.min(r1.x + r1.w, r2.x + r2.w) - Math.max(r1.x, r2.x));
              var y_overlap = Math.max(0, Math.min(r1.y + r1.h, r2.y + r2.h) - Math.max(r1.y, r2.y));
              var overlapArea = x_overlap * y_overlap;
              return overlapArea == 0;
            }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.