Как вычислить положение точки относительно выпуклого четырехугольника Java?

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


Ответы (1 шт):

Автор решения: EzikBro

Так как многоугольник выпуклый, достаточно проверить, что точка лежит в каждом из углов многоугольника. То есть пусть у вас N вершин, тогда вы должны пройти по каждой из них и проверить, что точка X лежит в угле A[i - 1]_A[i]_A[i + 1], где A - массив координат вершин вашего многоугольника по порядку.

Чтобы проверить, что точка лежит в угле, можно использовать псевдоскалярное произведение векторов. Псевдоскалярное (косое) произведение векторов A и B - это число, равное |A| * |B| * sin(alpha), где alpha - угол вращения против часовой стрелки от A до B. То есть для нахождения alpha вы можете построить данные вам вектора от одной точки и найти ориентированный(!) угол от A до B.

Извиняюсь за такие великолепные рисунки, но что есть, то есть

Также это прекрасное произведение очень просто вычисляется и без всяких измерений углов с помощью одних лишь координат: A ^ B = Ax * By - Bx * Ay. Получается, теперь, зная координаты, мы можем узнать и кое-какие сведения об угле, а именно - точное значение его синуса.

В прочем, в нашем случае точное значение нам не пригодится, а важен будет лишь знак. Заметим, что:

  1. sin(x) > 0 => 0 < x < 180 (градусов).
  2. sin(x) = 0 => x = 0 или x = 180.
  3. sin(x) < 0 => 180 < x < 360.

При этом псевдоскалярное произведение по знаку полностью совпадает со знаком синуса, а значит, что:

  1. A ^ B > 0 => B левее A.
  2. A ^ B = 0 => B коллинеарен с A.
  3. A ^ B < 0 => B правее A.

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

Примерный код алгоритма выглядит так:

double vectorMultiple(Vector a, Vector b)
    return a.x * b.y - b.x * a.y;

bool pointInAngle(Vector a, Vector b, Vector p) 
    if (vectorMultiple(a, b) < 0)
        return (vectorMultiple(a, p) < 0) && (vectorMultiple(p, b) < 0);
    return (vectorMultiple(b, p) < 0) && (vectorMultiple(p, a) < 0);

bool pointInAngle(Point a, Point b, Point c, Point p) // Point P in angle ABC
    Vector ba = Vector(b, a); // Vector AB = {B.x - A.x, B.y - A.y}
    Vector bc = Vector(b, c);
    Vector bp = Vector(b, p);
    return pointInAngle(ba, bc, bp);

bool pointInPolygon(Point[] poly, Point p)
    for (int i = 0; i < poly.length; i++)
        if (!pointInAngle(p, poly[i], poly[(i + 1) % poly.length], poly[(i + 2) % poly.length])
            return false;
    return true;

Также стоит отметить, что существует более быстрый алгоритм, работающий за O(logN), прочитать о котором можно, например, тут: https://neerc.ifmo.ru/wiki/index.php?title=принадлежность_точки_выпуклому_и_невыпуклому_многоугольникам

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

→ Ссылка