169 lines
5.6 KiB
Python
169 lines
5.6 KiB
Python
import numpy as np
|
|
|
|
from shapely import Geometry, GeometryType, lib
|
|
from shapely._geometry import get_parts
|
|
from shapely.decorators import multithreading_enabled, requires_geos
|
|
|
|
__all__ = ["coverage_invalid_edges", "coverage_is_valid", "coverage_simplify"]
|
|
|
|
|
|
@requires_geos("3.12.0")
|
|
@multithreading_enabled
|
|
def coverage_is_valid(geometry, gap_width=0.0, **kwargs):
|
|
"""Verify if a coverage is valid.
|
|
|
|
The coverage is represented by an array of polygonal geometries with
|
|
exactly matching edges and no overlap.
|
|
|
|
A valid coverage may contain holes (regions of no coverage). However,
|
|
sometimes it might be desirable to detect narrow gaps as invalidities in
|
|
the coverage. The `gap_width` parameter allows to specify the maximum
|
|
width of gaps to detect. When gaps are detected, this function will
|
|
return False and the `coverage_invalid_edges` function can be used to
|
|
find the edges of those gaps.
|
|
|
|
Geometries that are not Polygon or MultiPolygon are ignored.
|
|
|
|
.. versionadded:: 2.1.0
|
|
|
|
Parameters
|
|
----------
|
|
geometry : array_like
|
|
Array of geometries to verify.
|
|
gap_width : float, default 0.0
|
|
The maximum width of gaps to detect.
|
|
**kwargs
|
|
See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
|
|
|
|
Returns
|
|
-------
|
|
bool
|
|
|
|
See Also
|
|
--------
|
|
coverage_invalid_edges, coverage_simplify
|
|
|
|
"""
|
|
geometries = np.asarray(geometry)
|
|
# we always consider the full array as a single coverage -> ravel the input
|
|
# to pass a 1D array
|
|
return lib.coverage_is_valid(geometries.ravel(order="K"), gap_width, **kwargs)
|
|
|
|
|
|
@requires_geos("3.12.0")
|
|
@multithreading_enabled
|
|
def coverage_invalid_edges(geometry, gap_width=0.0, **kwargs):
|
|
"""Verify if a coverage is valid and return invalid edges.
|
|
|
|
This functions returns linear indicators showing the location of invalid
|
|
edges (if any) in each polygon in the input array.
|
|
|
|
The coverage is represented by an array of polygonal geometries with
|
|
exactly matching edges and no overlap.
|
|
|
|
A valid coverage may contain holes (regions of no coverage). However,
|
|
sometimes it might be desirable to detect narrow gaps as invalidities in
|
|
the coverage. The `gap_width` parameter allows to specify the maximum
|
|
width of gaps to detect. When gaps are detected, the `coverage_is_valid`
|
|
function will return False and this function can be used to find the
|
|
edges of those gaps.
|
|
|
|
Geometries that are not Polygon or MultiPolygon are ignored.
|
|
|
|
.. versionadded:: 2.1.0
|
|
|
|
Parameters
|
|
----------
|
|
geometry : array_like
|
|
Array of geometries to verify.
|
|
gap_width : float, default 0.0
|
|
The maximum width of gaps to detect.
|
|
**kwargs
|
|
See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
|
|
|
|
Returns
|
|
-------
|
|
numpy.ndarray | shapely.Geometry
|
|
|
|
See Also
|
|
--------
|
|
coverage_is_valid, coverage_simplify
|
|
|
|
"""
|
|
geometries = np.asarray(geometry)
|
|
# we always consider the full array as a single coverage -> ravel the input
|
|
# to pass a 1D array
|
|
return lib.coverage_invalid_edges(geometries.ravel(order="K"), gap_width, **kwargs)
|
|
|
|
|
|
@requires_geos("3.12.0")
|
|
@multithreading_enabled
|
|
def coverage_simplify(geometry, tolerance, *, simplify_boundary=True):
|
|
"""Return a simplified version of an input geometry using coverage simplification.
|
|
|
|
Assumes that the geometry forms a polygonal coverage. Under this assumption, the
|
|
function simplifies the edges using the Visvalingam-Whyatt algorithm, while
|
|
preserving a valid coverage. In the most simplified case, polygons are reduced to
|
|
triangles.
|
|
|
|
A collection of valid polygons is considered a coverage if the polygons are:
|
|
|
|
* **Non-overlapping** - polygons do not overlap (their interiors do not intersect)
|
|
* **Edge-Matched** - vertices along shared edges are identical
|
|
|
|
The function allows simplification of all edges including the outer boundaries of
|
|
the coverage or simplification of only the inner (shared) edges.
|
|
|
|
If there are other geometry types than Polygons or MultiPolygons present,
|
|
the function will raise an error.
|
|
|
|
If the geometry is polygonal but does not form a valid coverage due to overlaps,
|
|
it will be simplified but it may result in invalid topology.
|
|
|
|
.. versionadded:: 2.1.0
|
|
|
|
Parameters
|
|
----------
|
|
geometry : Geometry or array_like
|
|
tolerance : float or array_like
|
|
The degree of simplification roughly equal to the square root of the area
|
|
of triangles that will be removed.
|
|
simplify_boundary : bool, optional
|
|
By default (True), simplifies both internal edges of the coverage as well
|
|
as its boundary. If set to False, only simplifies internal edges.
|
|
|
|
Returns
|
|
-------
|
|
numpy.ndarray | shapely.Geometry
|
|
|
|
See Also
|
|
--------
|
|
coverage_is_valid, coverage_invalid_edges
|
|
|
|
Examples
|
|
--------
|
|
>>> import shapely
|
|
>>> from shapely import Polygon
|
|
>>> poly = Polygon([(0, 0), (20, 0), (20, 10), (10, 5), (0, 10), (0, 0)])
|
|
>>> shapely.coverage_simplify(poly, tolerance=2)
|
|
<POLYGON ((0 0, 20 0, 20 10, 10 5, 0 10, 0 0))>
|
|
"""
|
|
scalar = False
|
|
if isinstance(geometry, Geometry):
|
|
scalar = True
|
|
|
|
geometries = np.asarray(geometry)
|
|
shape = geometries.shape
|
|
geometries = geometries.ravel()
|
|
|
|
# create_collection acts on the inner axis
|
|
collections = lib.create_collection(
|
|
geometries, np.intc(GeometryType.GEOMETRYCOLLECTION)
|
|
)
|
|
|
|
simplified = lib.coverage_simplify(collections, tolerance, simplify_boundary)
|
|
parts = get_parts(simplified).reshape(shape)
|
|
if scalar:
|
|
return parts.item()
|
|
return parts
|