Найти, находится ли точка внутри прямоугольника или нет


Я хочу найти, лежит ли точка внутри прямоугольника или нет. Прямоугольник может быть ориентирован любым способом и не должен быть выровнен по оси.

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

вышеуказанный метод требует вращения и, следовательно, операций с плавающей запятой. Есть ли другие эффективный способ сделать это?

9 66

9 ответов:

как представлен прямоугольник? Три очка? Четыре очка? Точка, стороны и угол? Два очка и одна сторона? Что-то еще? Не зная этого, любые попытки ответить на ваш вопрос будут иметь только чисто академическую ценность.

в любом случае, для любого выпуклой полигон (включая прямоугольник) тест очень прост: проверьте каждый край полигона, предполагая, что каждый край ориентирован против часовой стрелки, и проверьте, лежит ли точка к слева края (в левой полуплоскости). Если все ребра проходят тест-точка находится внутри. Если кто - то терпит неудачу-точка находится снаружи.

для того чтобы проверить, является ли точка (xp, yp) лежит на левой стороне края (x1, y1) - (x2, y2), вам нужно построить линейное уравнение для линии, содержащей ребро. Уравнение выглядит следующим образом

A * x + B * y + C = 0

здесь

A = -(y2 - y1)
B = x2 - x1
C = -(A * x1 + B * y1)

теперь все, что вам нужно сделать, это вычислить

D = A * xp + B * yp + C

если D > 0, точка находится на левой стороне. Если D < 0, точка находится на правой стороне. Если D = 0 точка находится на линии.

однако этот тест, опять же, работает для любого выпуклого многоугольника, что означает, что он может быть слишком общим для прямоугольника. Прямоугольник может позволить более простой тест... Например, в прямоугольнике (или в любом другом параллелограмме) значения A и B имеют одинаковую величину, но разные знаки на противоположные (т. е. параллельные) ребра, которые могут быть эксплуатируется для упрощения теста.

предполагая, что прямоугольник представлен тремя точками A, B, C, с перпендикуляром AB и BC, вам нужно только проверить проекции точки запроса M на AB и BC:

0 <= dot(AB,AM) <= dot(AB,AB) &&
0 <= dot(BC,BM) <= dot(BC,BC)

AB - это вектор AB, с координатами (Bx-Ax, By-Ay), и dot(U,V) является скалярным произведением векторов U и V: Ux*Vx+Uy*Vy.

обновление. Давайте возьмем пример, чтобы проиллюстрировать это: A(5,0) B(0,2) C(1,5) и D(6,3). Из координат точек получаем AB=(-5,2), BC=(1,3), точка(АВ,АВ)=29, точка(до нашей эры,до н. э.)=10.

для точки запроса M(4,2) мы имеем AM=(-1,2), BM=(4,0), dot(AB, AM)=9,dot (BC, BM)=4. М находится внутри прямоугольника.

для точки запроса P(6,1) мы имеем AP=(1,1), BP=(6, -1), dot(AB, AP)=-3,dot (BC, BP)=3. P не находится внутри прямоугольника, потому что его проекция на сторону AB не находится внутри сегмента AB.

# Pseudo code
# Corners in ax,ay,bx,by,dx,dy
# Point in x, y

bax = bx - ax
bay = by - ay
dax = dx - ax
day = dy - ay

if ((x - ax) * bax + (y - ay) * bay < 0.0) return false
if ((x - bx) * bax + (y - by) * bay > 0.0) return false
if ((x - ax) * dax + (y - ay) * day < 0.0) return false
if ((x - dx) * dax + (y - dy) * day > 0.0) return false

return true

Я взял из ответа Эрик Bainville-это:

0 <= dot(AB,AM) <= dot(AB,AB) && 0 <= dot(BC,BM) <= dot(BC,BC)

который в javascript выглядит так:

function pointInRectangle(m, r) {
    var AB = vector(r.A, r.B);
    var AM = vector(r.A, m);
    var BC = vector(r.B, r.C);
    var BM = vector(r.B, m);
    var dotABAM = dot(AB, AM);
    var dotABAB = dot(AB, AB);
    var dotBCBM = dot(BC, BM);
    var dotBCBC = dot(BC, BC);
    return 0 <= dotABAM && dotABAM <= dotABAB && 0 <= dotBCBM && dotBCBM <= dotBCBC;
}

function vector(p1, p2) {
    return {
            x: (p2.x - p1.x),
            y: (p2.y - p1.y)
    };
}

function dot(u, v) {
    return u.x * v.x + u.y * v.y; 
}

например:

var r = {
    A: {x: 50, y: 0},
    B: {x: 0, y: 20},
    C: {x: 10, y: 50},
    D: {x: 60, y: 30}
};

var m = {x: 40, y: 20};

затем:

pointInRectangle(m, r); // returns true.

вот codepen, чтобы нарисовать вывод в виде визуального теста :) http://codepen.io/mattburns/pen/jrrprN

enter image description here

Я понимаю, что это старый поток, но для тех, кто заинтересован в том, чтобы смотреть на это с чисто математической точки зрения, есть отличный поток на математическом стеке exchange, здесь:

https://math.stackexchange.com/questions/190111/how-to-check-if-a-point-is-inside-a-rectangle

Edit: вдохновленный этой нитью, я собрал простой векторный метод для быстрого определения того, где находится ваша точка.

предположим, что у вас есть прямоугольник с точками на p1 = (x1, y1), p2 = (x2, y2), p3 = (x3, y3) и p4 = (x4, y4), идущий по часовой стрелке. Если точка p = (x, y) лежит внутри прямоугольника, то точечное произведение (p - p1).(p2 - p1) будет лежать между 0 и |p2 - p1|^2, и (p-p1).(p4 - p1) будет лежать между 0 и |p4-p1|^2. Это эквивалентно взятию проекции вектора p-p1 вдоль длины и ширины прямоугольника, с P1 в качестве начала координат.

Это может иметь больше смысла, если я покажу эквивалент код:

p21 = (x2 - x1, y2 - y1)
p41 = (x4 - x1, y4 - y1)

p21magnitude_squared = p21[0]^2 + p21[1]^2
p41magnitude_squared = p41[0]^2 + p41[1]^2

for x, y in list_of_points_to_test:

    p = (x - x1, y - y1)

    if 0 <= p[0] * p21[0] + p[1] * p21[1] <= p21magnitude_squared:
        if 0 <= p[0] * p41[0] + p[1] * p41[1]) <= p41magnitude_squared:
            return "Inside"
        else:
            return "Outside"
    else:
        return "Outside"

и это все. Он также будет работать для параллелограммов.

Если вы не можете решить проблему для прямоугольника, попробуйте разделить проблему на более простые проблемы. Разделите прямоугольник на 2 треугольника и проверьте, находится ли точка внутри любого из них, как они объясняют в здесь

по существу, вы проходите через ребра на каждые две пары линий от точки. Затем с помощью перекрестного продукта, чтобы проверить, если точка находится между двумя линиями с помощью перекрестного продукта. Если это проверено для всех 3 точек, то точка находится внутри треугольник. Хорошая вещь об этом методе заключается в том, что он не создает никаких ошибок с плавающей точкой, которые происходят, если вы проверяете углы.

bool pointInRectangle(Point A, Point B, Point C, Point D, Point m ) {
    Point AB = vect2d(A, B);  float C1 = -1 * (AB.y*A.x + AB.x*A.y); float  D1 = (AB.y*m.x + AB.x*m.y) + C1;
    Point AD = vect2d(A, D);  float C2 = -1 * (AD.y*A.x + AD.x*A.y); float D2 = (AD.y*m.x + AD.x*m.y) + C2;
    Point BC = vect2d(B, C);  float C3 = -1 * (BC.y*B.x + BC.x*B.y); float D3 = (BC.y*m.x + BC.x*m.y) + C3;
    Point CD = vect2d(C, D);  float C4 = -1 * (CD.y*C.x + CD.x*C.y); float D4 = (CD.y*m.x + CD.x*m.y) + C4;
    return     0 >= D1 && 0 >= D4 && 0 <= D2 && 0 >= D3;}





Point vect2d(Point p1, Point p2) {
    Point temp;
    temp.x = (p2.x - p1.x);
    temp.y = -1 * (p2.y - p1.y);
    return temp;}

Points inside polygon

Я только что реализовал ответ AnT с помощью c++. Я использовал этот код,чтобы проверить, лежит ли координация пикселя(X, Y) внутри формы или нет.

Если точка находится внутри прямоугольника. На плоскости. Для математика или геодезии (GPS) координаты

  • пусть прямоугольник задается вершинами A, B, C, D. точка-P. координаты прямоугольные: x, y.
  • позволяет продлить стороны прямоугольника. Итак, у нас есть 4 прямые линии l AB, lBC, lCD, lда, или, для краткости, l1, l2, l3, l4.
  • составьте уравнение для каждого lЯ. Уравнение вроде:

    fЯ(P)=0.

P-это точка. Для точек, принадлежащих lЯ уравнение верно.

  • нам нужны функции в левой части уравнений. Они f1, f2, f3, f4.
  • уведомления, это для каждой точки с одной стороны lЯ функция fЯ больше 0, для точек с другой стороны fЯ меньше 0.
  • Итак, если мы проверяем, что P находится в прямоугольнике, нам нужно только, чтобы p был на правильных сторонах всех четырех линий. Итак, мы должны проверить четыре функции на их признаки.
  • но какая сторона линии правильная, к которой принадлежит прямоугольник? Это та сторона, где лежат вершины прямоугольник, который не принадлежит к линии. Для проверки мы можем выбрать любую из двух не принадлежащих вершин.
  • Итак, мы должны проверить это:

    f AB(P) f AB(C) > = 0

    fBC(P) fBC(D) > = 0

    fCD(P) fCD(A) > = 0

    fда(P) fда(B) > = 0

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

  • для точки, которая находится в прямоугольнике, все четыре неравенства истинны. Обратите внимание, что он работает также для каждого выпуклого многоугольника, только количество линий/уравнений будет отличаться.
  • только осталось получить уравнение линии, проходящей через две точки. Это хорошо известное линейное уравнение. Напишем его для строки AB и точки P:

    f AB(P) ≡   (xA - xB) (yP - yB) - (yA - yB) (xP - xB)

проверка может быть упрощена-пойдем по прямоугольнику по часовой стрелке - A, B, C, Д, А. Тогда все правильно будет справа от линии. Таким образом, нам не нужно сравнивать с той стороной, где находится другая вершина. И нам нужно проверить набор более коротких неравенств:

f AB(P) > = 0

fBC(P) > = 0

fCD(P) > = 0

fда(P) > = 0

но это правильно для нормального, математик (из школьной математики) набор координат, где X находится справа и Y к вершине. И для геодезия координаты, как используются в GPS, где X-сверху, а Y-справа, мы должны повернуть неравенства:

f AB(P)

fBC(P)

fCD(P)

fда(P)

если вы не уверены с направлениями осей, будьте осторожны с этим упрощенная проверка-проверка на одну точку с известным размещением, если вы выбрали правильные неравенства.

самый простой способ, о котором я думал, это просто проецировать точку на ось прямоугольника. Позвольте мне объяснить:

Если вы можете получить вектор от центра прямоугольника до верхнего или нижнего края и левого или правого края. И у вас также есть вектор от центра прямоугольника до вашей точки, вы можете проецировать эту точку на свои векторы ширины и высоты.

P = вектор точки, H = вектор высоты, W = вектор ширины

получить единичный вектор W', H ' по деление векторов на их величину

proj_P, H = P - (P. H')H' proj_P, W = P- (P. W') W'

Если я не ошибаюсь, чего я не думаю... (Поправьте меня, если я ошибаюсь) но если величина проекции вашей точки на вектор высоты меньше, чем величина вектора высоты (которая составляет половину высоты прямоугольника) и величина проекции вашей точки на вектор ширины, то у вас есть точка внутри вашего вектора высоты. прямоугольник.

Если у вас есть универсальная система координат, вам может потребоваться вычислить векторы высоты/ширины/точки с помощью векторного вычитания. Векторные проекции удивительны! помнить это.