(
    primary_barriers,
    limit=None,
    additional_barriers=None,
    enclosure_id="eID",
    clip=False,
)
return final_enclosures
Generate enclosures based on passed barriers.

    Enclosures are areas enclosed from all sides by at least one type of
    a barrier. Barriers are typically roads, railways, natural features
    like rivers and other water bodies or coastline. Enclosures are a
    result of polygonization of the  ``primary_barrier`` and ``limit`` and its
    subdivision based on additional_barriers.

    Parameters
    ----------
    primary_barriers : GeoDataFrame, GeoSeries
        GeoDataFrame or GeoSeries containing primary barriers.
        (Multi)LineString geometry is expected.
    limit : GeoDataFrame, GeoSeries, shapely geometry (default None)
        GeoDataFrame, GeoSeries or shapely geometry containing external limit
        of enclosures,
        i.e. the area which gets partitioned. If None is passed,
        the internal area of ``primary_barriers`` will be used.
    additional_barriers : GeoDataFrame
        GeoDataFrame or GeoSeries containing additional barriers.
        (Multi)LineString geometry is expected.
    enclosure_id : str (default 'eID')
        name of the enclosure_id (to be created).
    clip : bool (default False)
        if True, returns enclosures with representative point within the limit
        (if given). Requires ``limit`` composed of Polygon or MultiPolygon geometries.

    Returns
    -------
    enclosures : GeoDataFrame
       GeoDataFrame containing enclosure geometries and enclosure_id

    Examples
    --------
    >>> enclosures = mm.enclosures(streets, admin_boundary, [railway, rivers])
Generate enclosures based on passed barriers.
Generate enclosures based on passed barriers .
def enclosures(
    primary_barriers,
    limit=None,
    additional_barriers=None,
    enclosure_id="eID",
    clip=False,
):
    """
    Generate enclosures based on passed barriers.

    Enclosures are areas enclosed from all sides by at least one type of
    a barrier. Barriers are typically roads, railways, natural features
    like rivers and other water bodies or coastline. Enclosures are a
    result of polygonization of the  ``primary_barrier`` and ``limit`` and its
    subdivision based on additional_barriers.

    Parameters
    ----------
    primary_barriers : GeoDataFrame, GeoSeries
        GeoDataFrame or GeoSeries containing primary barriers.
        (Multi)LineString geometry is expected.
    limit : GeoDataFrame, GeoSeries, shapely geometry (default None)
        GeoDataFrame, GeoSeries or shapely geometry containing external limit
        of enclosures,
        i.e. the area which gets partitioned. If None is passed,
        the internal area of ``primary_barriers`` will be used.
    additional_barriers : GeoDataFrame
        GeoDataFrame or GeoSeries containing additional barriers.
        (Multi)LineString geometry is expected.
    enclosure_id : str (default 'eID')
        name of the enclosure_id (to be created).
    clip : bool (default False)
        if True, returns enclosures with representative point within the limit
        (if given). Requires ``limit`` composed of Polygon or MultiPolygon geometries.

    Returns
    -------
    enclosures : GeoDataFrame
       GeoDataFrame containing enclosure geometries and enclosure_id

    Examples
    --------
    >>> enclosures = mm.enclosures(streets, admin_boundary, [railway, rivers])

    """
    if limit is not None:
        if isinstance(limit, BaseGeometry):
            limit = gpd.GeoSeries([limit])
        if limit.geom_type.isin(["Polygon", "MultiPolygon"]).any():
            limit_b = limit.boundary
        else:
            limit_b = limit
        barriers = pd.concat([primary_barriers.geometry, limit_b.geometry])
    else:
        barriers = primary_barriers
    unioned = barriers.unary_union
    polygons = polygonize(unioned)
    enclosures = gpd.GeoSeries(list(polygons), crs=primary_barriers.crs)

    if additional_barriers is not None:
        if not isinstance(additional_barriers, list):
            raise TypeError(
                "`additional_barriers` expects a list of GeoDataFrames or GeoSeries."
                f"Got {type(additional_barriers)}."
            )
        additional = pd.concat([gdf.geometry for gdf in additional_barriers])

        inp, res = enclosures.sindex.query_bulk(
            additional.geometry, predicate="intersects"
        )
        unique = np.unique(res)

        new = []

        for i in unique:
            poly = enclosures.values.data[i]  # get enclosure polygon
            crossing = inp[res == i]  # get relevant additional barriers
            buf = pygeos.buffer(poly, 0.01)  # to avoid floating point errors
            crossing_ins = pygeos.intersection(
                buf, additional.values.data[crossing]
            )  # keeping only parts of additional barriers within polygon
            union = pygeos.union_all(
                np.append(crossing_ins, pygeos.boundary(poly))
            )  # union
            polygons = pygeos.get_parts(pygeos.polygonize([union]))  # polygonize
            within = pygeos.covered_by(
                polygons, buf
            )  # keep only those within original polygon
            new += list(polygons[within])

        final_enclosures = (
            gpd.GeoSeries(enclosures)
            .drop(unique)
            .append(gpd.GeoSeries(new))
            .reset_index(drop=True)
        ).set_crs(primary_barriers.crs)

        final_enclosures = gpd.GeoDataFrame(
            {enclosure_id: range(len(final_enclosures))}, geometry=final_enclosures
        )

    else:
        final_enclosures = gpd.GeoDataFrame(
            {enclosure_id: range(len(enclosures))}, geometry=enclosures
        )

    if clip and limit is not None:
        if not limit.geom_type.isin(["Polygon", "MultiPolygon"]).all():
            raise TypeError(
                "`limit` requires a GeoDataFrame or GeoSeries with Polygon or "
                "MultiPolygon geometry to be used with clip=True."
            )
        _, encl_index = final_enclosures.representative_point().sindex.query_bulk(
            limit.geometry, predicate="contains"
        )
        keep = np.unique(encl_index)
        return final_enclosures.iloc[keep]

    return final_enclosures
def enclosures ( primary_barriers , limit = None , additional_barriers = None , enclosure_id = "eID" , clip = False , ) : if limit is not None : if isinstance ( limit , BaseGeometry ) : limit = gpd . GeoSeries ( [ limit ] ) if limit . geom_type . isin ( [ "Polygon" , "MultiPolygon" ] ) . any ( ) : limit_b = limit . boundary else : limit_b = limit barriers = pd . concat ( [ primary_barriers . geometry , limit_b . geometry ] ) else : barriers = primary_barriers unioned = barriers . unary_union polygons = polygonize ( unioned ) enclosures = gpd . GeoSeries ( list ( polygons ) , crs = primary_barriers . crs ) if additional_barriers is not None : if not isinstance ( additional_barriers , list ) : raise TypeError ( "`additional_barriers` expects a list of GeoDataFrames or GeoSeries." f"Got {type(additional_barriers)}." ) additional = pd . concat ( [ gdf . geometry for gdf in additional_barriers ] ) inp , res = enclosures . sindex . query_bulk ( additional . geometry , predicate = "intersects" ) unique = np . unique ( res ) new = [ ] for i in unique : poly = enclosures . values . data [ i ] # get enclosure polygon crossing = inp [ res == i ] # get relevant additional barriers buf = pygeos . buffer ( poly , 0.01 ) # to avoid floating point errors crossing_ins = pygeos . intersection ( buf , additional . values . data [ crossing ] ) # keeping only parts of additional barriers within polygon union = pygeos . union_all ( np . append ( crossing_ins , pygeos . boundary ( poly ) ) ) # union polygons = pygeos . get_parts ( pygeos . polygonize ( [ union ] ) ) # polygonize within = pygeos . covered_by ( polygons , buf ) # keep only those within original polygon new += list ( polygons [ within ] ) final_enclosures = ( gpd . GeoSeries ( enclosures ) . drop ( unique ) . append ( gpd . GeoSeries ( new ) ) . reset_index ( drop = True ) ) . set_crs ( primary_barriers . crs ) final_enclosures = gpd . GeoDataFrame ( { enclosure_id : range ( len ( final_enclosures ) ) } , geometry = final_enclosures ) else : final_enclosures = gpd . GeoDataFrame ( { enclosure_id : range ( len ( enclosures ) ) } , geometry = enclosures ) if clip and limit is not None : if not limit . geom_type . isin ( [ "Polygon" , "MultiPolygon" ] ) . all ( ) : raise TypeError ( "`limit` requires a GeoDataFrame or GeoSeries with Polygon or " "MultiPolygon geometry to be used with clip=True." ) _ , encl_index = final_enclosures . representative_point ( ) . sindex . query_bulk ( limit . geometry , predicate = "contains" ) keep = np . unique ( encl_index ) return final_enclosures . iloc [ keep ] return final_enclosures