예제 #1
0
    def filterByViewport(self, geometry):

        try:

            return geometry.intersection(self.viewportRect)

        except shapely.geos.TopologicalError:

            return False
예제 #2
0
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
예제 #3
0
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
예제 #4
0
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
예제 #5
0
 def filterByViewport(self, geometry):
   try:
     return geometry.intersection(self.viewportRect)
   except shapely.geos.TopologicalError:
     return False
예제 #6
0
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