Как проверить, находится ли точка внутри выпуклого многоугольника в 2D целочисленными координатами?

полигон задается как список объектов Vector2I (2-мерные, целочисленные координаты). Как я могу проверить, находится ли данная точка внутри? Все реализации, которые я нашел в интернете, терпят неудачу для некоторого тривиального контрпримера. Кажется, действительно трудно написать правильную реализацию. Язык не имеет значения, так как я сам буду его переносить.

7 ответов


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

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

вот код в Python:

RIGHT = "RIGHT"
LEFT = "LEFT"

def inside_convex_polygon(point, vertices):
    previous_side = None
    n_vertices = len(vertices)
    for n in xrange(n_vertices):
        a, b = vertices[n], vertices[(n+1)%n_vertices]
        affine_segment = v_sub(b, a)
        affine_point = v_sub(point, a)
        current_side = get_side(affine_segment, affine_point)
        if current_side is None:
            return False #outside or over an edge
        elif previous_side is None: #first segment
            previous_side = current_side
        elif previous_side != current_side:
            return False
    return True

def get_side(a, b):
    x = x_product(a, b)
    if x < 0:
        return LEFT
    elif x > 0: 
        return RIGHT
    else:
        return None

def v_sub(a, b):
    return (a[0]-b[0], a[1]-b[1])

def x_product(a, b):
    return a[0]*b[1]-a[1]*b[0]

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

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


если многоугольник выпуклый, то в C# следующее реализует "


функция pointPolygonTest в openCV " определяет, находится ли точка внутри контура, снаружи или лежит на краю": http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=pointpolygontest#pointpolygontest


ответ fortran почти сработал для меня, но я обнаружил, что мне пришлось перевести многоугольник так, чтобы точка, которую вы тестируете, была такой же, как и начало координат. Вот JavaScript, который я написал для этого:

function Vec2(x, y) {
  return [x, y]
}
Vec2.nsub = function (v1, v2) {
  return Vec2(v1[0]-v2[0], v1[1]-v2[1])
}
// aka the "scalar cross product"
Vec2.perpdot = function (v1, v2) {
  return v1[0]*v2[1] - v1[1]*v2[0]
}

// Determine if a point is inside a polygon.
//
// point     - A Vec2 (2-element Array).
// polyVerts - Array of Vec2's (2-element Arrays). The vertices that make
//             up the polygon, in clockwise order around the polygon.
//
function coordsAreInside(point, polyVerts) {
  var i, len, v1, v2, edge, x
  // First translate the polygon so that `point` is the origin. Then, for each
  // edge, get the angle between two vectors: 1) the edge vector and 2) the
  // vector of the first vertex of the edge. If all of the angles are the same
  // sign (which is negative since they will be counter-clockwise) then the
  // point is inside the polygon; otherwise, the point is outside.
  for (i = 0, len = polyVerts.length; i < len; i++) {
    v1 = Vec2.nsub(polyVerts[i], point)
    v2 = Vec2.nsub(polyVerts[i+1 > len-1 ? 0 : i+1], point)
    edge = Vec2.nsub(v1, v2)
    // Note that we could also do this by using the normal + dot product
    x = Vec2.perpdot(edge, v1)
    // If the point lies directly on an edge then count it as in the polygon
    if (x < 0) { return false }
  }
  return true
}

то, как я знаю, что-то вроде этого.

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

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

их сумма количества пересекающихся линий дает вам это внутри или нет.

Если это странно : внутри

Если это даже : за пределами


или от человека, который написал книгу вижу - страница геометрия

конкретно на этой странице, он обсуждает, почему правило намотки обычно лучше, чем пересечение лучей.

edit-извините, это не Джозеф О'Рурк кто написал отличную книгу вычислительная геометрия В C, Это Пол Бурк, но все же очень хороший источник алгоритмов геометрии.