I am trying to implement a polygon smoothing operation with shapely. I am doing this with the combination of erode and dilate (polygon.buffer function with positive and negative numbers). The specification of my smooth function goes something like this:
- The operation must be conservative. There must not be any part of the original shape that is not covered by the smoothed shape
- any protrusion must be preserved
- any concavity must be smoothed out
- Topology must be preserved
dilate followed by erode solves this with shapely in cases where the topology does not change with the operation. See example code below.
from shapely.geometry import Polygon
import numpy as np
from descartes import PolygonPatch
from matplotlib import pyplot as plt
# create a large square
x = np.array([-5,-5,5,5])
y = np.array([5,-5,-5,5])
poly1 = Polygon(zip(x,y))
# smaller square to cut away from first
x = np.array([-4,-4,4,4])
y = np.array([4,-4,-4,4])
poly2 = Polygon(zip(x,y))
# small shape to cut away from left side
x = np.array([-11,-11,0,0])
y = np.array([1,-1,0,0])
poly3 = Polygon(zip(x,y))
poly_t=poly1.difference(poly2)
poly4 = poly_t.difference(poly3)
poly5= poly4.buffer(0.45)
poly5= poly5.buffer(-0.45)
fig = plt.figure()
ax = fig.add_subplot(121)
plt.axis([-5.5, 5.5, -5.5, 5.5])
patch = PolygonPatch(poly5)
ax.add_patch(patch)
plt.show()
Visualized below is the before and after smoothing operation applied. the change of topology of the dilate operation is the cause of the unintended behaviour. Shapely polygons can be in a state where they are self intersecting, where they are "invalid" in some sence. I would like this to be the case for the intermediate polygon (the one where dilate has been applied, awaiting the erode). However, it seems the buffer function in shapely has no such feature.
Do you have a suggestion on how to solve this problem with Shapely still being the geometry engine? worst case, a solution with another framework.