def filterByViewport(self, geometry): try: return geometry.intersection(self.viewportRect) except shapely.geos.TopologicalError: return False
def mask_geometries_by_geometries( geometries: List[geometry.base.BaseGeometry], masking_geometries: List[geometry.base.BaseGeometry], ): masked_geometries = [] for geometry in geometries: for mask in masking_geometries: geometry = geometry.intersection(mask) if geometry.length > 0.0: masked_geometries.append(geometry) return masked_geometries
def _index_shapes(shapes, cell_key): """Spatially index other masks to cell mask. Parameters ---------- shapes : dict Dictionary of GeoDataFrames. Returns ------- indexed_shapes : GeoDataFrame Each column is """ cell_shapes = shapes[cell_key] indexed_shapes = cell_shapes.copy() for shape_name, shape in shapes.items(): # Don't index cell to itself if shape_name == "cell": continue # For each cell, get all overlapping shapes geometry = gpd.sjoin(shape, cell_shapes, how="left", op="intersects", rsuffix="cell").dropna() # Calculate fraction overlap for each pair SLOW geometry["fraction_overlap"] = (geometry.intersection( cell_shapes.loc[geometry["index_cell"]], align=False).area / geometry.area) # Keep shape that overlaps with cell_shapes the most geometry = (geometry.sort_values( "fraction_overlap", ascending=False).drop_duplicates("index_cell").set_index( "index_cell").reindex(cell_shapes.index)["geometry"]) geometry.name = f"{shape_name}_shape" # Add indexed shapes as new column in GeoDataFrame indexed_shapes[f"{shape_name}_shape"] = geometry # Cells are rows, intersecting shape sets are columns indexed_shapes = indexed_shapes.rename(columns={"geometry": "cell_shape"}) indexed_shapes.index = indexed_shapes.index.astype(str) return indexed_shapes
def tile(geometry, chunk_dim_meters=chunk_dim_meters): # NOTE: these are not aligned to tile coordinates minx, miny, maxx, maxy = geometry.bounds tiled_polys = [] y = miny while y < maxy: x = minx endy = y + chunk_dim_meters while x < maxx: endx = x + chunk_dim_meters tile_bounds = shapely.geometry.box(x, y, endx, endy) tiled_poly = geometry.intersection(tile_bounds) if not tiled_poly.is_empty: tiled_polys.append(tiled_poly) x += chunk_dim_meters y += chunk_dim_meters return tiled_polys
def _katana(geometry, threshold, count=0, maxcount=250): """ From https://snorfalorpagus.net/blog/2016/03/13/splitting-large-polygons-for-faster-intersections/ Split a Polygon into two parts across it's shortest dimension Copyright (c) 2016, Joshua Arnott All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ bounds = geometry.bounds width = bounds[2] - bounds[0] height = bounds[3] - bounds[1] if max(width, height) <= threshold or count == maxcount: # either the polygon is smaller than the threshold, or the maximum # number of recursions has been reached return [geometry] if height >= width: # split left to right a = box(bounds[0], bounds[1], bounds[2], bounds[1]+height/2) b = box(bounds[0], bounds[1]+height/2, bounds[2], bounds[3]) else: # split top to bottom a = box(bounds[0], bounds[1], bounds[0]+width/2, bounds[3]) b = box(bounds[0]+width/2, bounds[1], bounds[2], bounds[3]) result = [] for d in (a, b,): c = geometry.intersection(d) if not isinstance(c, GeometryCollection): c = [c] for e in c: if isinstance(e, (Polygon, MultiPolygon)): result.extend(_katana(e, threshold, count+1, maxcount)) if count > 0: return result # convert multipart into singlepart final_result = [] for g in result: if isinstance(g, MultiPolygon): final_result.extend(g) else: final_result.append(g) return final_result