Является ли точка внутри правильного шестиугольника

Я ищу совет по наилучшему пути. Я пытаюсь найти, находится ли заданная точка A: (a, b) внутри правильного шестиугольника, определенного с центром O: (x, y) и диаметром окружности.

Кажется, что излишний метод использования Ray-casting, или Winding-number, для такого простого случая, и сейчас я рассматриваю возможность поиска угла (от горизонтали) линии OA и "нормализуя" (возможно, не правильное слово) в один из шести равносторонних треугольников и видя, находится ли эта новая точка внутри этого треугольника.

У меня такое ощущение, что я пропустил что-то простое, и там простой способ (или, если мне повезет, Java API) сделать это просто и эффективно.

Спасибо за вашу помощь.

Изменить. Шестиугольник ориентирован так, что одна из сторон плоская с горизонтальной.

Ответ 1

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

Например, верхняя правая сторона имеет уравнение:

-sqrt(3)x - y + sqrt(3)/2 = 0

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

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

Ответ 2

Если вы уменьшите проблему до проверки {x = 0, y = 0, d = 1} в одном квадранте, вы можете сделать очень просто.

public boolean IsInsideHexagon(float x0, float y0, float d, float x, float y) {
    float dx = Math.abs(x - x0)/d;
    float dy = Math.abs(y - y0)/d;
    float a = 0.25 * Math.sqrt(3.0);
    return (dy <= a) && (a*dx + 0.25*dy <= 0.5*a);
}
  • dy <= a проверяет, что точка находится ниже горизонтального края.
  • a*dx + 0.25*dy <= 0.5*a проверяет, что точка находится слева от наклонного правого края.

Для {x0 = 0, y0 = 0, d = 1} угловые точки будут (±0.25, ±0.43) и (±0.5, 0.0).

Ответ 3

Похоже, вы знаете общее решение: "Похоже, что излишнее использование...". Итак, вот моя идея:

Вычислить расстояние от точки к центру и называть его l.

Затем вы можете сравнить его с inradius (r) и circumradius (r). если l < r, то точка находится внутри шестиугольника, если l > R затем снаружи. Если r < l < R, то вам нужно будет проверять каждую сторону соответственно, но поскольку R - r очень мала (13% от длины стороны гекса), вероятность того, что вам придется выполнять сложные вычисления, крошечная.

Формулы можно найти здесь: http://mathworld.wolfram.com/Hexagon.html

Ответ 4

Это то, что я использовал:

public bool InsideHexagon(float x, float y)
{
    // Check length (squared) against inner and outer radius
    float l2 = x * x + y * y;
    if (l2 > 1.0f) return false;
    if (l2 < 0.75f) return true; // (sqrt(3)/2)^2 = 3/4

    // Check against borders
    float px = x * 1.15470053838f; // 2/sqrt(3)
    if (px > 1.0f || px < -1.0f) return false;

    float py = 0.5f * px + y;
    if (py > 1.0f || py < -1.0f) return false;

    if (px - py > 1.0f || px - py < -1.0f) return false;

    return true;
}

px и py - координаты x и y, проецируемые на систему координат, где гораздо легче проверить границы.

enter image description here

Ответ 5

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

Первое означает, что точка находится, последняя означает ее.

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

Для наихудшего сценария (точка находится между вписанными и описанными кругами), я думаю, вы можете найти две вершины, которые ближе всего к точке, а затем увидеть на какой стороне отрезка V1V2 точка (внутренняя или внешний, относительно О-центра). Особый случай: точка равна одной из вершин = > it in.

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

Ответ 6

Вычтите положение центра шестиугольника из точки P, чтобы получить вектор V. Затем возьмем точечный продукт V со следующими векторами, которые соответствуют трем парам противоположных шестигранных ребер:

[0,1] ; the edges that are flat with the horizontal
[cos(30),sin(30)] ; the upper-right and lower-left edges
[cos(-30),sin(-30)] ; the lower-right and upper-left edges

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

Для справки, точечное произведение векторов [a, b] и [c, d] является a * c + b * d.

Угол "30" выше находится в градусах;)

Ответ 7

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

Вот хороший ответ: fooobar.com/info/253594/...

Я изменил эту функцию для моего использования, я нашел свою версию более ясной. Это typescript (вы просто косоглазие и это javascript):

function vectorX(v: Vector): number {
    return v[1].x - v[0].x;
}

function vectorY(v: Vector): number {
    return v[1].y - v[0].y;
}

function crossProduct(v1: Vector, v2: Vector): number {
    return vectorX(v1)*vectorY(v2) - vectorY(v1)*vectorX(v2);
}

function isInConvexPolygon(testPoint: Point, polygon: Polygon): boolean {
    // /info/253594/how-to-test-if-a-point-is-inside-of-a-convex-polygon-in-2d-integer-coordinates/1301164#1301164
    if (polygon.length < 3) {
        throw "Only supporting polygons of length at least 3";
    }
    // going through all the edges around the polygon. compute the
    // vector cross-product http://allenchou.net/2013/07/cross-product-of-2d-vectors/
    // to find out for each edge on which side of the edge is the point.
    // if the point is on the same side for all the edges, it inside
    let initCrossIsPositive = undefined;
    for (var i=0;i<polygon.length;i++) {
        if (polygon[i].x === testPoint.x &&
            polygon[i].y === testPoint.y) {
            // testPoint is an edge of the polygon
            return true;
        }
        const curPointOnEdge = polygon[i];
        const nextPointOnEdge = polygon[(i+1)%polygon.length];
        const vector1 = <[Point,Point]>[curPointOnEdge, nextPointOnEdge];
        const vector2 = <[Point,Point]>[curPointOnEdge, testPoint];
        const cross = crossProduct(vector1, vector2);
        if (initCrossIsPositive === undefined) {
            initCrossIsPositive = cross > 0;
        } else {
            if (initCrossIsPositive !== (cross > 0)) {
                return false;
            }
        }
    }
    // all the cross-products have the same sign: we're inside
    return true;
}