Как я могу определить, находится ли 2D точка внутри многоугольника? - PullRequest
459 голосов
/ 20 октября 2008

Я пытаюсь создать быструю 2D точку внутри алгоритма многоугольника для использования при тестировании попаданий (например, Polygon.contains(p:Point)). Буду признателен за эффективные методы.

Ответы [ 32 ]

1 голос
/ 07 апреля 2016

VBA VERSION:

Примечание. Помните, что если ваш многоугольник является областью на карте, то широта / долгота являются значениями Y / X, а не X / Y (широта = Y, долгота = X) из-за того, что я понимаю, из назад, когда Долгота не была измерением.

МОДУЛЬ КЛАССА: CPoint

Private pXValue As Double
Private pYValue As Double

'''''X Value Property'''''

Public Property Get X() As Double
    X = pXValue
End Property

Public Property Let X(Value As Double)
    pXValue = Value
End Property

'''''Y Value Property'''''

Public Property Get Y() As Double
    Y = pYValue
End Property

Public Property Let Y(Value As Double)
    pYValue = Value
End Property

МОДУЛЬ:

Public Function isPointInPolygon(p As CPoint, polygon() As CPoint) As Boolean

    Dim i As Integer
    Dim j As Integer
    Dim q As Object
    Dim minX As Double
    Dim maxX As Double
    Dim minY As Double
    Dim maxY As Double
    minX = polygon(0).X
    maxX = polygon(0).X
    minY = polygon(0).Y
    maxY = polygon(0).Y

    For i = 1 To UBound(polygon)
        Set q = polygon(i)
        minX = vbMin(q.X, minX)
        maxX = vbMax(q.X, maxX)
        minY = vbMin(q.Y, minY)
        maxY = vbMax(q.Y, maxY)
    Next i

    If p.X < minX Or p.X > maxX Or p.Y < minY Or p.Y > maxY Then
        isPointInPolygon = False
        Exit Function
    End If


    ' SOURCE: http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html

    isPointInPolygon = False
    i = 0
    j = UBound(polygon)

    Do While i < UBound(polygon) + 1
        If (polygon(i).Y > p.Y) Then
            If (polygon(j).Y < p.Y) Then
                If p.X < (polygon(j).X - polygon(i).X) * (p.Y - polygon(i).Y) / (polygon(j).Y - polygon(i).Y) + polygon(i).X Then
                    isPointInPolygon = True
                    Exit Function
                End If
            End If
        ElseIf (polygon(i).Y < p.Y) Then
            If (polygon(j).Y > p.Y) Then
                If p.X < (polygon(j).X - polygon(i).X) * (p.Y - polygon(i).Y) / (polygon(j).Y - polygon(i).Y) + polygon(i).X Then
                    isPointInPolygon = True
                    Exit Function
                End If
            End If
        End If
        j = i
        i = i + 1
    Loop   
End Function

Function vbMax(n1, n2) As Double
    vbMax = IIf(n1 > n2, n1, n2)
End Function

Function vbMin(n1, n2) As Double
    vbMin = IIf(n1 > n2, n2, n1)
End Function


Sub TestPointInPolygon()

    Dim i As Integer
    Dim InPolygon As Boolean

'   MARKER Object
    Dim p As CPoint
    Set p = New CPoint
    p.X = <ENTER X VALUE HERE>
    p.Y = <ENTER Y VALUE HERE>

'   POLYGON OBJECT
    Dim polygon() As CPoint
    ReDim polygon(<ENTER VALUE HERE>) 'Amount of vertices in polygon - 1
    For i = 0 To <ENTER VALUE HERE> 'Same value as above
       Set polygon(i) = New CPoint
       polygon(i).X = <ASSIGN X VALUE HERE> 'Source a list of values that can be looped through
       polgyon(i).Y = <ASSIGN Y VALUE HERE> 'Source a list of values that can be looped through
    Next i

    InPolygon = isPointInPolygon(p, polygon)
    MsgBox InPolygon

End Sub
0 голосов
/ 19 декабря 2018

Удивлен никто раньше, но для прагматиков, которым требуется база данных: MongoDB имеет отличную поддержку запросов Geo, включая этот.

То, что вы ищете:

db.neighborhoods.findOne ({geometry: {$ geoIntersects: {$ geometry: { тип: "Точка", координаты: ["долгота", "широта"]}}} })

Neighborhoods - это коллекция, в которой хранится один или несколько полигонов в стандартном формате GeoJson. Если запрос возвращает ноль, он не пересекается, в противном случае это так.

Очень хорошо задокументировано здесь: https://docs.mongodb.com/manual/tutorial/geospatial-tutorial/

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

0 голосов
/ 30 октября 2018

Вот вариант ответа @nirg на golang (на основе кода C # @@ m-katz)

func isPointInPolygon(polygon []point, testp point) bool {
    minX := polygon[0].X
    maxX := polygon[0].X
    minY := polygon[0].Y
    maxY := polygon[0].Y

    for _, p := range polygon {
        minX = min(p.X, minX)
        maxX = max(p.X, maxX)
        minY = min(p.Y, minY)
        maxY = max(p.Y, maxY)
    }

    if testp.X < minX || testp.X > maxX || testp.Y < minY || testp.Y > maxY {
        return false
    }

    inside := false
    j := len(polygon) - 1
    for i := 0; i < len(polygon); i++ {
        if (polygon[i].Y > testp.Y) != (polygon[j].Y > testp.Y) && testp.X < (polygon[j].X-polygon[i].X)*(testp.Y-polygon[i].Y)/(polygon[j].Y-polygon[i].Y)+polygon[i].X {
            inside = !inside
        }
        j = i
    }

    return inside
}
0 голосов
/ 15 февраля 2018

Scala-версия решения по nirg (предполагается, что предварительная проверка ограничивающего прямоугольника выполняется отдельно):

def inside(p: Point, polygon: Array[Point], bounds: Bounds): Boolean = {

  val length = polygon.length

  @tailrec
  def oddIntersections(i: Int, j: Int, tracker: Boolean): Boolean = {
    if (i == length)
      tracker
    else {
      val intersects = (polygon(i).y > p.y) != (polygon(j).y > p.y) && p.x < (polygon(j).x - polygon(i).x) * (p.y - polygon(i).y) / (polygon(j).y - polygon(i).y) + polygon(i).x
      oddIntersections(i + 1, i, if (intersects) !tracker else tracker)
    }
  }

  oddIntersections(0, length - 1, tracker = false)
}
0 голосов
/ 19 октября 2016

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

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

Вот отличная статья с реализацией C обоих алгоритмов. Я попробовал их, и они хорошо работают.

http://geomalgorithms.com/a03-_inclusion.html

0 голосов
/ 11 февраля 2016

Если вы ищете библиотеку java-script, есть расширение javascript google maps v3 для класса Polygon, чтобы определить, находится ли точка внутри него.

var polygon = new google.maps.Polygon([], "#000000", 1, 1, "#336699", 0.3);
var isWithinPolygon = polygon.containsLatLng(40, -90);

Google Extention Github

0 голосов
/ 18 марта 2016

При использовании (Qt 4.3+), можно использовать функцию QPolygon containsPoint

0 голосов
/ 22 ноября 2015

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

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

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

Вы также можете опубликовать вопрос в математическом сообществе. Могу поспорить, у них есть миллион способов сделать это

0 голосов
/ 20 ноября 2015

Для решения следующих особых случаев в Алгоритм приведения лучей :

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

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

0 голосов
/ 19 ноября 2015

Для обнаружения попадания в полигон нам нужно проверить две вещи:

  1. Если точка находится внутри области многоугольника. (может быть выполнено алгоритмом преобразования лучей)
  2. Если точка находится на границе многоугольника (может быть выполнен по тому же алгоритму, который используется для обнаружения точки на полилинии (линии)).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...