[GIS] Creating Shapely Polygons with holes

pythonshapely

I believe I understand the shapely methodology fairly well at this point. However, I'm struggling with getting my holes to populate to the polygons. I've tried a number of approaches.

What I'm doing is taking a buffer feature that I then want to simplify the edges. So, I take the exterior and the individual interior LineStrings and split them by the points that were used to create the buffer.

All of this works fine. However, I then want to take that exterior and the separate interiors and create a single Polygon feature with the holes. Here's some of the various methods that I have tried:

polygonExterior = Polygon(self.SplitLinesByPoints(inputPolygon.exterior,...)) # returns a LinearRing
polygonInteriors = []
for i in range(len(inputPolygon.interiors)):
    polygonInteriors.append(self.SplitLinesByPoints(inputPolygon.interiors[i],...))

#when I check polygonInteriors, it has 3 valid LinearRings

#Trial 1
newPolygon = Polygon(polygonExteriors, polygonInteriors)
# returns a polygon with the correct exterior and no holes (should be 3 in my test dataset)

#Trial 2
interiorCoords = []
for interior in polygonInteriors:
    interiorCoords.append(list(interior.coords))
newPolygon = Polygon(polygonExteriors, interiorCoords)
# same result as Trial 1

#Trial 3
newPolygon = Polygon(polygonExterior)
for interior in polygonInteriors:
    newPolygon = newPolygon.difference(Polygon(interior))
#same result

#Trial 4 based on first received answer
newPolygon = Polygon(polygonExterior, [[pt for pt in inner.coords] for inner in polygonInteriors])
#same result

# testing output
print(str(len(newPolygon.interiors)))
# gives 0

I output the list of list of tuples that are passed in trial 4 and it looks like this:

[[(3149326.399938697, 13547034.20647637), (3149326.3938959567, 13547034.177421806),...,(3149326.399938697, 13547034.20647637)], [(3149339.754347628, 13546944.667812834), (3149339.6827200023, 13546944.533919774),...,(3149339.754347628, 13546944.667812834)], [(3149334.7216034834, 13547168.84576934), (3149334.729913973, 13547168.803259838),..., (3149334.7216034834, 13547168.84576934)]]

I also just wanted to confirm that the interiors were where they should be. So I created shapefiles for each of the interior circles as well. This is what I expect to get:
expectedOutput

As you can see, I have the actual output with the three holes as separate shapefiles.

But, what I get is this:

actual output

That's just the TestInterior2… file that should have the holes.

I'm just really at a loss as to what to try next.

Anyone have any ideas what I'm doing wrong or how to get the holes into the Polygon?

Best Answer

I think the only issue here is that you need to pass the coordinates to the Polygon constructor, not the list of coordinates. So in trial one, instead of

#Trial 1
newPolygon = Polygon(polygonExteriors, polygonInteriors)

do:

#Trial 1
newPolygon = Polygon(polygonExteriors, [[pt for pt in inner.coords] for inner in polygonInteriors])

As I don't have all of your code, here is an example to demonstrate the solution, which returns the same polygon as inputPolygon:

from shapely.geometry import Polygon

# Example polygon with two holes
inputPolygon = Polygon(((0,0),(10,0),(10,10),(0,10)), (((1,3),(5,3),(5,1),(1,1)), ((9,9),(9,8),(8,8),(8,9))))

polygonExterior = inputPolygon.exterior
polygonInteriors = []
for i in range(len(inputPolygon.interiors)):
    # do the stuff with your polygons
    polygonInteriors.append(inputPolygon.interiors[i])

newPolygon = Polygon(polygonExterior, [[pt for pt in inner.coords] for inner in polygonInteriors])