0

I have code to expand the polygon, it works by multiplying the xs and ys by a factor then re centering the resultant polyon at the center of the original.

I also have code to find the value for the expansion factor, given a point that the polygon needs to reach:

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)

This code only works when the point is directly opposing one of the polygons lines.

user1581390
  • 1,900
  • 5
  • 25
  • 38
  • If I understand your description (not your code) correctly, you're growing a polygon by moving the polygon vertices away from the center of the polygon. According to your title, you want to do that _until_ one (or more) border(s) hit a specific point, but your text description then says you multiply all points by a factor. Can you explain why you think that implementation would do what your title suggests you want it to do? – Mike 'Pomax' Kamermans Jun 30 '18 at 02:04
  • 1
    Are we assuming that the polygon is convex? If so, then this is just a geometry problem. – user3386109 Jun 30 '18 at 02:16
  • 1
    @Mike'Pomax'Kamermans I was confused at first too, but now I think I understand. Imagine a polygon on a grid. To increase the size, multiply each point by a factor, but envision this instead as increasing the granularity of the grid, keeping everything in place. The polygon has effectively grown, but with the new coordinates, it may need translating (for whatever reason). – Dillon Davis Jun 30 '18 at 02:50

3 Answers3

4

Modify your method distancePolygon2PointAndCenter to instead of

Returns the distance from a point to the nearest line of the polygon

To return the distance from a point to the segment intersected by a ray from the center to the point. This is the line that will intersect the point once the polygon is fully expanded. To get this segment, take both endpoints of each segment of your polygon, and plug them into the equation for the line parallel & intersecting the ray mentioned earlier. That is y = ((centerY-pointY)/(centerX-pointX)) * (x - centerX) + centerY. You want to want to find endpoints where either one of them intersect the line, or the two are on opposite sides of the line.

Then, the only thing left to do is make sure that we pick the segment intersecting the right "side" of the line. To do this, there are a few options. The fail-safe method would be to use the formula cos(theta) = sqrt((centerX**2 + centerY**2)*(pointX**2 + pointY**2)) / (centerX * pointX + centerY * pointY) however, you could use methods such as comparing x and y values, taking the arctan2(), and such to figure out which segment is on the correct "side" of center. You'll just have lots of edge cases to cover. After all this is said and done, your two (unless its not convex, in which case take the segment farthest from you center) endpoints makeup the segment to expand off of.

Dillon Davis
  • 6,679
  • 2
  • 15
  • 37
  • Okay I have done as you said and it helps (I just used shapely functions to find the intersection, plotted to make sure then found the distance). There is an additional problem: the expansion function doesn't expand "from the center", when you multiply all the points by 2 it does expand the polygon but the factor to expand in all directions from the center is different. – user1581390 Jun 30 '18 at 18:35
  • Translate the polygon and the point (together) so that the center of the polygon is at the origin (0, 0), then calculate your expansion factor. Then expand the original polygon and translate as necessary. – Dillon Davis Jun 30 '18 at 18:46
  • Okay no my last comment is not true, expanding from the center by factor == multiplying (x,y) by factor. I had a bug where I translate from shapely Point to np.array() point. It now works perfectly! – user1581390 Jun 30 '18 at 19:11
1

Determine what is "polygon center" as central point C of expanding. Perhaps it is centroid (or some point with another properties?).

Make a segment from your point P to C. Find intersection point I between PC and polygon edges. If polygon is concave and there are some intersection points, choose the closest one to P.

Calculate coefficient of expanding:

 E = Length(PC) / Length(CI)

Calculate new vertex coordinates. For i-th vertex of polygon:

 V'[i].X = C.X + (V[i].X - C.X) * E
 V'[i].Y = C.Y + (V[i].Y - C.Y) * E
MBo
  • 77,366
  • 5
  • 53
  • 86
0

Decide which point you want to reach, then calculate how much % your polygon needs to expand to reach that point and use the shapely.affinity.scale function. For example, in my case I just needed to make the polygon 5% bigger:

region = shapely.affinity.scale(myPolygon, 
                            xfact=1.05, yfact=1.05 )
Ricardo Guerreiro
  • 497
  • 1
  • 4
  • 17