|
21 | 21 | import pyproj |
22 | 22 | from pyproj import Transformer |
23 | 23 | from pyproj.exceptions import ProjError |
| 24 | +import shapely |
24 | 25 | import shapely.geometry as sgeom |
25 | 26 | from shapely.prepared import prep |
26 | 27 |
|
@@ -1214,34 +1215,52 @@ def _rings_to_multi_polygon(self, rings, is_ccw): |
1214 | 1215 | y3 -= by |
1215 | 1216 | x4 += bx |
1216 | 1217 | y4 += by |
| 1218 | + |
| 1219 | + interior_polys = [] |
| 1220 | + |
1217 | 1221 | for ring in interior_rings: |
1218 | | - # Use shapely buffer in an attempt to fix invalid geometries |
1219 | | - polygon = sgeom.Polygon(ring).buffer(0) |
1220 | | - if not polygon.is_empty and polygon.is_valid: |
| 1222 | + polygon = shapely.make_valid(sgeom.Polygon(ring)) |
| 1223 | + if not polygon.is_empty: |
| 1224 | + if isinstance(polygon, sgeom.Polygon): |
| 1225 | + interior_polys.append(polygon) |
| 1226 | + elif isinstance(polygon, sgeom.MultiPolygon): |
| 1227 | + interior_polys.extend(polygon.geoms) |
| 1228 | + elif isinstance(polygon, sgeom.GeometryCollection): |
| 1229 | + for geom in polygon.geoms: |
| 1230 | + if isinstance(geom, sgeom.Polygon): |
| 1231 | + interior_polys.append(geom) |
| 1232 | + else: |
| 1233 | + # make_valid may produce some linestrings. Ignore these |
| 1234 | + continue |
| 1235 | + |
1221 | 1236 | x1, y1, x2, y2 = polygon.bounds |
1222 | 1237 | bx = (x2 - x1) * 0.1 |
1223 | 1238 | by = (y2 - y1) * 0.1 |
1224 | 1239 | x1 -= bx |
1225 | 1240 | y1 -= by |
1226 | 1241 | x2 += bx |
1227 | 1242 | y2 += by |
1228 | | - box = sgeom.box(min(x1, x3), min(y1, y3), |
1229 | | - max(x2, x4), max(y2, y4)) |
1230 | 1243 |
|
1231 | | - # Invert the polygon |
1232 | | - polygon = box.difference(polygon) |
| 1244 | + x3 = min(x1, x3) |
| 1245 | + x4 = max(x2, x4) |
| 1246 | + y3 = min(y1, y3) |
| 1247 | + y4 = max(y2, y4) |
1233 | 1248 |
|
1234 | | - # Intersect the inverted polygon with the boundary |
1235 | | - polygon = boundary_poly.intersection(polygon) |
| 1249 | + box = sgeom.box(x3, y3, x4, y4, ccw=is_ccw) |
1236 | 1250 |
|
1237 | | - if not polygon.is_empty: |
1238 | | - polygon_bits.append(polygon) |
| 1251 | + # Invert the polygons |
| 1252 | + polygon = box.difference(sgeom.MultiPolygon(interior_polys)) |
1239 | 1253 |
|
1240 | | - if polygon_bits: |
1241 | | - multi_poly = sgeom.MultiPolygon(polygon_bits) |
1242 | | - else: |
1243 | | - multi_poly = sgeom.MultiPolygon() |
1244 | | - return multi_poly |
| 1254 | + # Intersect the inverted polygon with the boundary |
| 1255 | + polygon = boundary_poly.intersection(polygon) |
| 1256 | + |
| 1257 | + if not polygon.is_empty: |
| 1258 | + if isinstance(polygon, sgeom.MultiPolygon): |
| 1259 | + polygon_bits.extend(polygon.geoms) |
| 1260 | + else: |
| 1261 | + polygon_bits.append(polygon) |
| 1262 | + |
| 1263 | + return sgeom.MultiPolygon(polygon_bits) |
1245 | 1264 |
|
1246 | 1265 | def quick_vertices_transform(self, vertices, src_crs): |
1247 | 1266 | """ |
|
0 commit comments