def flatten_geometry(geometry: BaseGeometry) -> BaseGeometry: """ :param geometry: Shapely geometry object :return: geometry with Z values removed """ geometry_type = type(geometry) # strip 3rd dimension if 'POLYGON Z' in geometry.wkt: polygons = ([polygon for polygon in geometry] if geometry_type is MultiPolygon else [geometry]) for polygon_index, polygon in enumerate(polygons): exterior_2d = LinearRing( [vertex[:2] for vertex in polygon.exterior.coords]) interiors_2d = [ LinearRing([vertex[:2] for vertex in interior.coords]) for interior in polygon.interiors ] polygons[polygon_index] = Polygon(exterior_2d, interiors_2d) geometry = (MultiPolygon(polygons) if geometry_type is MultiPolygon else Polygon(polygons[0])) if not geometry.is_valid: geometry = geometry.buffer(0) return geometry
def stretch_contour(geom: BaseGeometry, width: float = 1) -> BaseGeometry: """ Stretch geometry (expected to be a geometry contour) to given width scale. """ if width > 1 and geom: buf = 1 + (width - 1) / 10 return geom.buffer(buf) return geom
def is_similar(geom1: BaseGeometry, geom2: BaseGeometry, eps: float = 1e-6) -> bool: if type(geom1) is not type(geom2): return False if isinstance(geom1, (LineString, MultiLineString, Point, MultiPoint)): return (geom1.buffer(eps).contains(geom2) and geom2.buffer(eps).contains(geom1)) if isinstance(geom1, (Polygon, MultiPolygon)): return geom1.symmetric_difference(geom2).area < eps if isinstance(geom1, GeometryCollection): polygons1, non_polygons1 = separate(geom1, lambda geom: isinstance(geom, Polygon)) polygons2, non_polygons2 = separate(geom2, lambda geom: isinstance(geom, Polygon)) polygon_union1 = unary_union(polygons1) non_polygon_union1 = unary_union(non_polygons1) polygon_union2 = unary_union(polygons2) non_polygon_union2 = unary_union(non_polygons2) return (polygon_union1.symmetric_difference(polygon_union2).area < eps and non_polygon_union1.buffer(eps).contains(non_polygon_union2) and non_polygon_union2.buffer(eps).contains(non_polygon_union1))
def _valid_shape(shape: BaseGeometry) -> BaseGeometry: if shape.is_valid: return shape return shape.buffer(0)