Як обчислити відстань між точкою та прямокутником, орієнтованим на вісь?


29

У мене є 2D прямокутник з x, y положенням, висотою та шириною та випадково розташованою точкою поруч.

Чи є спосіб перевірити, чи може ця точка стикатися з прямокутником, якщо вона ближче певної відстані? Уявіть невидимий радіус поза цією точкою, що стикається з вказаним прямокутником. У мене проблеми з цим просто тому, що це не квадрат!

Відповіді:


26

Якщо (x,y)центр прямокутника, відстань у квадраті від точки (px,py)до межі прямокутника може бути обчислена таким чином:

dx = max(abs(px - x) - width / 2, 0);
dy = max(abs(py - y) - height / 2, 0);
return dx * dx + dy * dy;

Якщо відстань у квадраті дорівнює нулю, це означає, що точка торкається або знаходиться всередині прямокутника.


6
Для всіх, хто цікавиться, (x, y) - це центр прямокутника, а не кут
Грег Розмарновіц

2
Вибачте за старий коментар, але чи вважає це рівняння, що прямокутник вирівняний по осі?
BitNinja

1
@BitNinja так, ось що передбачає питання. Якщо він не вирівняний по осі, найшвидший / найпростіший алгоритм буде залежати від того, як зберігається інформація прямокутника.
sam hocevar

скажімо, точка (4: 4), прямокутник знаходиться на (5: 5) з шириною / висотою (5: 5). Ваш код стверджує, що точка торкається або знаходиться всередині прямокутника, але, очевидно, зовні
LRN

@LRN прямокутник із центром у (5: 5) із шириною / висотою (5: 5) прольотами від (2,5: 2,5) до (7,5: 7,5). Точка (4: 4) знаходиться всередині цього прямокутника.
sam hocevar

11

Я припускаю, що ваш прямокутник вирівняний по осі.

Вам просто потрібно «затиснути» точку в прямокутнику, а потім обчислити відстань від затиснутої точки.

Point = (px, py), прямокутник = (rx, ry, rwidth, rheight) // (лівий верхній кут, розміри)

function pointRectDist (px, py, rx, ry, rwidth, rheight)
{
    var cx = Math.max(Math.min(px, rx+rwidth ), rx);
    var cy = Math.max(Math.min(py, ry+rheight), ry);
    return Math.sqrt( (px-cx)*(px-cx) + (py-cy)*(py-cy) );
}

3

Для цього потрібно використовувати колізії прямокутника кола. Там є аналогічний питання на переповнення стека.

Центр вашого кола був би точкою, про яку йдеться, а радіус - це відстань, яку ви хочете перевірити.


3

Якщо ви намагаєтеся визначити відстань від точки до краю прямокутника, робота з кожною з дев'яти областей, створених прямокутником, може бути найшвидшим способом:

function pointRectangleDistance(x, y, x1, y1, x2, y2) {
    var dx, dy;
    if (x < x1) {
        dx = x1 - x;
        if (y < y1) {
            dy = y1 - y;
            return Math.sqrt(dx * dx + dy * dy);
        }
        else if (y > y2) {
            dy = y - y2;
            return Math.sqrt(dx * dx + dy * dy);
        }
        else {
            return dx;
        }
    }
    else if (x > x2) {
        dx = x - x2;
        if (y < y1) {
            dy = y1 - y;
            return Math.sqrt(dx * dx + dy * dy);
        }
        else if (y > y2) {
            dy = y - y2;
            return Math.sqrt(dx * dx + dy * dy);
        }
        else {
            return dx;
        }
    }
    else {
        if (y < y1) {
            return y1 - y;
        }
        else if (y > y2) {
            return y - y2;
        }
        else {
            return 0.0; // inside the rectangle or on the edge
        }
    }
}

2

[Змінена відповідь на основі коментарів]

Якщо ви хочете побачити, чи точка знаходиться в межах, скажімо, 10 одиниць, якщо сірий прямокутник на зображенні нижче, ви перевірте, чи є точка в якомусь із

  1. червоний прямокутник
  2. Синій прямокутник
  3. будь-яке зелене коло (радіус 10)

введіть тут опис зображення

inside=false;

bluerect.x=oldrect.x-10;
bluerect.y=oldrect.y;
bluerect.width=oldrect.width;
bluerect.height=oldrect.height+20;

if(  point.x >=bluerect && point.x <=redrect.x+bluerect.width &&
     point.y >=bluerect && point.y <=redrect.y+bluerect.height){
         //now point is side the blue rectangle
         inside=true;
}

redrect.x=oldrect.x;
redrect.y=oldrect.y-10;
redrect.width=oldrect.width+20;
redrect.height=oldrect.height;

if(  point.x >=redrect&& point.x <=redrect.x+redrect.width &&
     point.y >=redrect&& point.y <=redrect.y+redrect.height){
         //now point is side the redrectangle
         inside=true;
}


d1= distance(point, new point(oldrect.x, oldrect.y)) //calculate distance between point and (oldrect.x, oldrect.y)
d2= distance(point, new point(oldrect.x+10, oldrect.y))
d3= distance(point, new point(oldrect.x, oldrect.y+10))
d4= distance(point, new point(oldrect.x+10, oldrect.y+10))
if (d1 < 10 || d2 <10 || d3 < 10 || d4 <10){
    inside=true;
}

//inside is now true if the point is within 10 units of rectangle

Цей підхід трохи неелегантний. Аналогічний метод, який дозволяє уникнути тестування всіх 4 кутів за допомогою симетрії прямокутника, задокументований тут на стартовому потоці


У діагональному напрямку це дасть помилковий позитив точкам, які є, наприклад. 11 одиниць.
Ерік Б

Оновлена ​​картина очевидно неправильна, адже вона насправді ілюструє випадок помилки та робить її правильною. Ця зелена точка може легко знаходитися на відстані більше ніж 10 одиниць і знаходитися всередині цього зовнішнього прямокутника.
Ерік Б

Привіт @EricB, я виправив помилку, яку ти вказав, як щодо скасування вашої суботи?
Кен

Ваша відповідь більше не дасть суворо неправильних результатів, тому я видалив знижку, але це теж не найкращий спосіб. Чому б не просто перевірити, чи є центр у прямокутнику, і якщо чотири лінійки перетинаються з колом? Побудова цих нових прямокутників і кіл просто не потрібна. Ваша відповідь також не передбачає фактичної відстані від точки до прямокутника.
Ерік Б

Ця відповідь чесно жахлива. 12 доповнень, 4 конструкції об'єкта, 12 тестів, 4 квадратних кореня для завдання, яке фактично вимагає 3 рядка коду?
sam hocevar

-2

Ви можете використовувати щось подібне: введіть тут опис зображення


Цей метод видається зайвим складним. Пошук x1 і y1 не є необхідним для вирішення цієї проблеми.
Ерік Б

Насправді це навіть не задовольняє вимогу знайти зіткнення на заданій відстані. Це просто поганий спосіб виявити, якщо точка знаходиться у прямокутнику.
Ерік Б

Міра відстані вже неявно є. якщо (d2 <10 * 10) {/ * в межах 10 одиниць виміру * /}
ОлександрБревіг
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.