I am trying to insert a point from a projected line into a polygon (I need to do this a few times to 'cut' a section of the polygon exterior, but this the key issue).
There is close similarity with this question, but I find that answer does or doesn't work depending on the segment orientation. It works for simple vertical or horizontal projections, but in most other segment orientations results in a fail due to the projected point falling outside the polygon.exterior by ~ 1e-16 (numerical precision).
This question checks for a point being inside the polygon, and also fails when the point is on the polygon exterior.
I have tried extending the projected line (pline
below) by a tiny bit then intersection
, but that gives the exact same Point and numerical precision problem.
Avoiding the precision by adding a tiny .buffer(1e-15)
does intercept, but that results in adding a (tiny) rounded line segment from the buffer which introduces errors elsewhere.
Example:
import matplotlib.pyplot as plt
import shapely as sh
from shapely import ops
from shapely.geometry import *
def insert_projected_point(point, poly):
s = sh.normalize(Polygon(poly))
pline = sh.shortest_line(point,s)
p2 = sh.intersection(s, pline)
# Per https://gis.stackexchange.com/questions/188594/how-can-i-add-points-to-a-linestring-in-shapely
ring = LineString(list(s.exterior.coords))
union = ring.union(pline)
s2 = ops.polygonize(union)[0]
return p2, s2
def do_results(p, s, p1, s1):
print(f"s: {s}")
print(f"p out: {p1}")
print(f"s out: {s1}")
p = Point((3, 0.5))
# This works
poly1 = (0,0), (2,0), (2,2), (0,2), (0,0)
p1, s1 = insert_projected_point(p, poly1)
do_results(p, poly1, p1, s1)
# This doesn't work
poly2 = (0,0), (1,0), (2,2), (0,2), (0,0)
p2, s2 = insert_projected_point(p, poly2)
do_results(p, poly2, p2, s2)
Result:
s: ((0, 0), (2, 0), (2, 2), (0, 2), (0, 0))
p out: POINT (2 0.5)
sout: POLYGON ((0 0, 0 2, 2 2, 2 0.5, 2 0, 0 0))s: ((0, 0), (1, 0),(2, 2), (0, 2), (0, 0))
p out: LINESTRING Z EMPTY
s out: POLYGON((0 0, 0 2, 2 2, 1 0, 0 0))