def assert_shapes_mostly_equal(shape1: BaseGeometry, shape2: BaseGeometry, threshold: float): __tracebackhide__ = operator.methodcaller("errisinstance", AssertionError) # Check area first, as it's a nicer error message when they're wildly different. assert shape1.area == pytest.approx( shape2.area, abs=threshold), "Shapes have different areas" s1 = shape1.simplify(tolerance=threshold) s2 = shape2.simplify(tolerance=threshold) assert (s1 - s2).area < threshold, f"{s1} is not mostly equal to {s2}"
def decompose(self, geometry: BaseGeometry) -> List[LineString]: geometry = geometry.simplify(self._simplify_distance) if isinstance(geometry, Polygon): return self.decompose_polygon(polygon=geometry) elif isinstance(geometry, MultiPolygon): lines_list: List[List[LineString]] = [ self.decompose_polygon(polygon=sub_polygon) for sub_polygon in list(geometry) ] return list(chain.from_iterable(lines_list)) elif isinstance(geometry, LinearRing): return self.decompose_linearRing(ring=geometry) elif isinstance(geometry, LineString): return self.decompose_lineString(lineString=geometry) elif isinstance(geometry, MultiLineString): lines_list: List[List[LineString]] = [ self.decompose_lineString(lineString=sub_lineString) for sub_lineString in list(geometry) ] return list(chain.from_iterable(lines_list)) elif isinstance(geometry, GeometryCollection): lines_list: List[List[LineString]] = [ self.decompose(geometry=sub_geometry) for sub_geometry in list(geometry) ] return list(chain.from_iterable(lines_list)) else: return []
def interpolate(geometry: BaseGeometry, gap: float, simplify_distance: float = 1e-6) -> BaseGeometry: def interpolate_coords(coords): new_coords: List[Tuple[float, float]] = [] for i in range(len(coords) - 2): new_coords.extend( interpolate_coords_by_len(coords[i], coords[i + 1], gap, result_include_coord2=False)) new_coords.extend( interpolate_coords_by_len(coords[-2], coords[-1], gap, result_include_coord2=True)) return new_coords if isinstance(geometry, (Point, MultiPoint)): return geometry elif isinstance(geometry, (Polygon, LineString, LinearRing)): geometry_simplified = geometry.simplify(simplify_distance) if isinstance(geometry, Polygon): exterior_coords = list(geometry_simplified.exterior.coords) interior_coords_list = [ list(interior.coords) for interior in geometry_simplified.interiors ] interpolated_exterior = interpolate_coords(exterior_coords) interpolated_interiors = [ interpolate_coords(interior_coords) for interior_coords in interior_coords_list ] return Polygon(shell=interpolated_exterior, holes=interpolated_interiors) else: # LineString or LinearRing coords = list(geometry_simplified.coords) return type(geometry)(interpolate_coords(coords)) elif isinstance(geometry, (MultiPolygon, MultiLineString, GeometryCollection)): geoms = list(geometry) interpolated_geoms = [interpolate(geom, gap) for geom in geoms] return type(geometry)(interpolated_geoms) return geometry # return origin geometry if not match any type