Как расширить многоугольник, пока одна из границ не достигнет точки - PullRequest
0 голосов
/ 30 июня 2018

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

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

import numpy as np
import itertools as IT
import copy
from shapely.geometry import LineString, Point

def getPolyCenter(points):
    """
    http://stackoverflow.com/a/14115494/190597 (mgamba)
    """
    area = area_of_polygon(*zip(*points))
    result_x = 0
    result_y = 0
    N = len(points)
    points = IT.cycle(points)
    x1, y1 = next(points)
    for i in range(N):
        x0, y0 = x1, y1
        x1, y1 = next(points)
        cross = (x0 * y1) - (x1 * y0)
        result_x += (x0 + x1) * cross
        result_y += (y0 + y1) * cross
    result_x /= (area * 6.0)
    result_y /= (area * 6.0)
    return (result_x, result_y)

def expandPoly(points, factor):
    points = np.array(points, dtype=np.float64)
    expandedPoly = points*factor
    expandedPoly -= getPolyCenter(expandedPoly)
    expandedPoly += getPolyCenter(points)
    return np.array(expandedPoly, dtype=np.int64)

def distanceLine2Point(points, point):
    points = np.array(points, dtype=np.float64)
    point = np.array(point, dtype=np.float64)

    points = LineString(points)
    point = Point(point)
    return points.distance(point)

def distancePolygon2Point(points, point):
    distances = []
    for i in range(len(points)):
        if i==len(points)-1:
            j = 0
        else:
            j = i+1
        line = [points[i], points[j]]
        distances.append(distanceLine2Point(line, point))

    minDistance = np.min(distances)
    #index = np.where(distances==minDistance)[0][0]

    return minDistance 

"""
    Returns the distance from a point to the nearest line of the polygon,
    AND the distance from where the normal to the line (to reach the point)
    intersets the line to the center of the polygon.
"""
def distancePolygon2PointAndCenter(points, point):
    distances = []
    for i in range(len(points)):
        if i==len(points)-1:
            j = 0
        else:
            j = i+1
        line = [points[i], points[j]]
        distances.append(distanceLine2Point(line, point))

    minDistance = np.min(distances)
    i = np.where(distances==minDistance)[0][0]
    if i==len(points)-1:
        j = 0
    else:
        j = i+1
    line = copy.deepcopy([points[i], points[j]])

    centerDistance = distanceLine2Point(line, getPolyCenter(points))

    return minDistance, centerDistance

minDistance, centerDistance = distancePolygon2PointAndCenter(points, point)
expandedPoly = expandPoly(points, 1+minDistance/centerDistance)

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

Ответы [ 2 ]

0 голосов
/ 30 июня 2018

Определите, что такое «центр многоугольника» как центральная точка C расширения. Возможно, это центроид (или какая-то точка с другими свойствами?).

Сделайте отрезок от вашей точки P до C. Найдите точку пересечения I между ПК и ребрами многоугольника. Если полигон вогнутый и есть несколько точек пересечения, выберите ближайший к P.

Рассчитайте коэффициент расширения:

 E = Length(PC) / Length(CI)

Рассчитать новые координаты вершины. Для i-й вершины многоугольника:

 V'[i].X = C.X + (V[i].X - C.X) * E
 V'[i].Y = C.Y + (V[i].Y - C.Y) * E
0 голосов
/ 30 июня 2018

Измените свой метод distancePolygon2PointAndCenter вместо

Возвращает расстояние от точки до ближайшей линии многоугольника

Для возврата расстояния от точки до отрезка, пересекаемого лучом от центра к точке . Это линия, которая будет пересекать точку после полного раскрытия многоугольника. Чтобы получить этот сегмент, возьмите обе конечные точки каждого сегмента вашего многоугольника и включите их в уравнение для прямой, параллельной и пересекающей луч, упомянутый ранее. Это y = ((centerY-pointY)/(centerX-pointX)) * (x - centerX) + centerY. Вы хотите найти конечные точки, где либо одна из них пересекает линию, либо две находятся на противоположных сторонах линии.

Тогда остается только убедиться, что мы выбрали отрезок, пересекающий правую «сторону» линии. Для этого есть несколько вариантов. Отказоустойчивый метод будет использовать формулу cos(theta) = sqrt((centerX**2 + centerY**2)*(pointX**2 + pointY**2)) / (centerX * pointX + centerY * pointY), однако вы можете использовать такие методы, как сравнение значений x и y, взятие arctan2() и такие, чтобы выяснить, какой сегмент находится на правильной «стороне» центра , У вас будет много краевых случаев. После того, как все это сказано и сделано, ваши две конечные точки (если только они не выпуклые, в этом случае берут отрезок, самый дальний от вашего центра), расширяют отрезок.

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