| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552 |
- """Methods that yield new objects not derived from set-theoretic analysis."""
- import numpy as np
- from shapely import lib
- from shapely._enum import ParamEnum
- from shapely.algorithms._oriented_envelope import _oriented_envelope_min_area_vectorized
- from shapely.algorithms.cga import _orient_polygons_vectorized
- from shapely.decorators import (
- deprecate_positional,
- multithreading_enabled,
- requires_geos,
- )
- from shapely.errors import UnsupportedGEOSVersionError
- __all__ = [
- "BufferCapStyle",
- "BufferJoinStyle",
- "boundary",
- "buffer",
- "build_area",
- "centroid",
- "clip_by_rect",
- "concave_hull",
- "constrained_delaunay_triangles",
- "convex_hull",
- "delaunay_triangles",
- "envelope",
- "extract_unique_points",
- "make_valid",
- "maximum_inscribed_circle",
- "minimum_bounding_circle",
- "minimum_clearance_line",
- "minimum_rotated_rectangle",
- "node",
- "normalize",
- "offset_curve",
- "orient_polygons",
- "oriented_envelope",
- "point_on_surface",
- "polygonize",
- "polygonize_full",
- "remove_repeated_points",
- "reverse",
- "segmentize",
- "simplify",
- "snap",
- "voronoi_polygons",
- ]
- class BufferCapStyle(ParamEnum):
- """Enumeration of buffer cap styles.
- Attributes
- ----------
- round : int
- Represents a round cap style.
- flat : int
- Represents a flat cap style.
- square : int
- Represents a square cap style.
- """
- round = 1
- flat = 2
- square = 3
- class BufferJoinStyle(ParamEnum):
- """Enumeration of buffer join styles.
- Attributes
- ----------
- round : int
- Specifies a round join style.
- mitre : int
- Specifies a mitre join style.
- bevel : int
- Specifies a bevel join style.
- """
- round = 1
- mitre = 2
- bevel = 3
- @multithreading_enabled
- def boundary(geometry, **kwargs):
- """Return the topological boundary of a geometry.
- This function will return None for geometrycollections.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry for which to return the boundary.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Examples
- --------
- >>> import shapely
- >>> from shapely import GeometryCollection, LinearRing, LineString, \
- MultiLineString, MultiPoint, Point, Polygon
- >>> shapely.boundary(Point(0, 0))
- <GEOMETRYCOLLECTION EMPTY>
- >>> shapely.boundary(LineString([(0, 0), (1, 1), (1, 2)]))
- <MULTIPOINT ((0 0), (1 2))>
- >>> shapely.boundary(LinearRing([(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)]))
- <MULTIPOINT EMPTY>
- >>> shapely.boundary(Polygon([(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)]))
- <LINESTRING (0 0, 1 0, 1 1, 0 1, 0 0)>
- >>> shapely.boundary(MultiPoint([(0, 0), (1, 2)]))
- <GEOMETRYCOLLECTION EMPTY>
- >>> shapely.boundary(MultiLineString([[(0, 0), (1, 1)], [(0, 1), (1, 0)]]))
- <MULTIPOINT ((0 0), (0 1), (1 0), (1 1))>
- >>> shapely.boundary(GeometryCollection([Point(0, 0)])) is None
- True
- """
- return lib.boundary(geometry, **kwargs)
- # Note: future plan is to change this signature over a few releases:
- # shapely 2.0:
- # buffer(geometry, distance, quad_segs=8, ...)
- # shapely 2.1: shows deprecation warning about positional 'quad_segs', etc.
- # same signature as 2.0
- # shapely 2.2(?): enforce keyword-only arguments after 'distance'
- # buffer(geometry, distance, *, quad_segs=8, ...)
- @deprecate_positional(
- ["quad_segs", "cap_style", "join_style", "mitre_limit", "single_sided"],
- category=DeprecationWarning,
- )
- @multithreading_enabled
- def buffer(
- geometry,
- distance,
- quad_segs=8,
- cap_style="round",
- join_style="round",
- mitre_limit=5.0,
- single_sided=False,
- **kwargs,
- ):
- """Compute the buffer of a geometry for positive and negative buffer distance.
- The buffer of a geometry is defined as the Minkowski sum (or difference,
- for negative distance) of the geometry with a circle with radius equal
- to the absolute value of the buffer distance.
- The buffer operation always returns a polygonal result. The negative
- or zero-distance buffer of lines and points is always empty.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries for which to compute the buffer.
- distance : float or array_like
- Specifies the circle radius in the Minkowski sum (or difference).
- quad_segs : int, default 8
- Specifies the number of linear segments in a quarter circle in the
- approximation of circular arcs.
- cap_style : shapely.BufferCapStyle or {'round', 'square', 'flat'}, default 'round'
- Specifies the shape of buffered line endings. BufferCapStyle.round ('round')
- results in circular line endings (see ``quad_segs``). Both BufferCapStyle.square
- ('square') and BufferCapStyle.flat ('flat') result in rectangular line endings,
- only BufferCapStyle.flat ('flat') will end at the original vertex,
- while BufferCapStyle.square ('square') involves adding the buffer width.
- join_style : shapely.BufferJoinStyle or {'round', 'mitre', 'bevel'}, default 'round'
- Specifies the shape of buffered line midpoints. BufferJoinStyle.round ('round')
- results in rounded shapes. BufferJoinStyle.bevel ('bevel') results in a beveled
- edge that touches the original vertex. BufferJoinStyle.mitre ('mitre') results
- in a single vertex that is beveled depending on the ``mitre_limit`` parameter.
- mitre_limit : float, default 5.0
- Crops of 'mitre'-style joins if the point is displaced from the
- buffered vertex by more than this limit.
- single_sided : bool, default False
- Only buffer at one side of the geometry.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Notes
- -----
- .. deprecated:: 2.1.0
- A deprecation warning is shown if ``quad_segs``, ``cap_style``,
- ``join_style``, ``mitre_limit`` or ``single_sided`` are
- specified as positional arguments. In a future release, these will
- need to be specified as keyword arguments.
- Examples
- --------
- >>> import shapely
- >>> from shapely import LineString, Point, Polygon, BufferCapStyle, BufferJoinStyle
- >>> shapely.buffer(Point(10, 10), 2, quad_segs=1)
- <POLYGON ((12 10, 10 8, 8 10, 10 12, 12 10))>
- >>> shapely.buffer(Point(10, 10), 2, quad_segs=2)
- <POLYGON ((12 10, 11.414 8.586, 10 8, 8.586 8.586, 8 10, 8.5...>
- >>> shapely.buffer(Point(10, 10), -2, quad_segs=1)
- <POLYGON EMPTY>
- >>> line = LineString([(10, 10), (20, 10)])
- >>> shapely.buffer(line, 2, cap_style="square")
- <POLYGON ((20 12, 22 12, 22 8, 10 8, 8 8, 8 12, 20 12))>
- >>> shapely.buffer(line, 2, cap_style="flat")
- <POLYGON ((20 12, 20 8, 10 8, 10 12, 20 12))>
- >>> shapely.buffer(line, 2, single_sided=True, cap_style="flat")
- <POLYGON ((20 10, 10 10, 10 12, 20 12, 20 10))>
- >>> line2 = LineString([(10, 10), (20, 10), (20, 20)])
- >>> shapely.buffer(line2, 2, cap_style="flat", join_style="bevel")
- <POLYGON ((18 12, 18 20, 22 20, 22 10, 20 8, 10 8, 10 12, 18 12))>
- >>> shapely.buffer(line2, 2, cap_style="flat", join_style="mitre")
- <POLYGON ((18 12, 18 20, 22 20, 22 8, 10 8, 10 12, 18 12))>
- >>> shapely.buffer(line2, 2, cap_style="flat", join_style="mitre", mitre_limit=1)
- <POLYGON ((18 12, 18 20, 22 20, 22 9.172, 20.828 8, 10 8, 10 12, 18 12))>
- >>> square = Polygon([(0, 0), (10, 0), (10, 10), (0, 10), (0, 0)])
- >>> shapely.buffer(square, 2, join_style="mitre")
- <POLYGON ((-2 -2, -2 12, 12 12, 12 -2, -2 -2))>
- >>> shapely.buffer(square, -2, join_style="mitre")
- <POLYGON ((2 2, 2 8, 8 8, 8 2, 2 2))>
- >>> shapely.buffer(square, -5, join_style="mitre")
- <POLYGON EMPTY>
- >>> shapely.buffer(line, float("nan")) is None
- True
- """
- if isinstance(cap_style, str):
- cap_style = BufferCapStyle.get_value(cap_style)
- if isinstance(join_style, str):
- join_style = BufferJoinStyle.get_value(join_style)
- if not np.isscalar(quad_segs):
- raise TypeError("quad_segs only accepts scalar values")
- if not np.isscalar(cap_style):
- raise TypeError("cap_style only accepts scalar values")
- if not np.isscalar(join_style):
- raise TypeError("join_style only accepts scalar values")
- if not np.isscalar(mitre_limit):
- raise TypeError("mitre_limit only accepts scalar values")
- if not np.isscalar(single_sided):
- raise TypeError("single_sided only accepts scalar values")
- return lib.buffer(
- geometry,
- distance,
- np.intc(quad_segs),
- np.intc(cap_style),
- np.intc(join_style),
- mitre_limit,
- np.bool_(single_sided),
- **kwargs,
- )
- # Note: future plan is to change this signature over a few releases:
- # shapely 2.0:
- # offset_curve(geometry, distance, quad_segs=8, ...)
- # shapely 2.1: shows deprecation warning about positional 'quad_segs', etc.
- # same signature as 2.0
- # shapely 2.2(?): enforce keyword-only arguments after 'distance'
- # offset_curve(geometry, distance, *, quad_segs=8, ...)
- @deprecate_positional(
- ["quad_segs", "join_style", "mitre_limit"], category=DeprecationWarning
- )
- @multithreading_enabled
- def offset_curve(
- geometry, distance, quad_segs=8, join_style="round", mitre_limit=5.0, **kwargs
- ):
- """Return a (Multi)LineString at a distance from the object.
- For positive distance the offset will be at the left side of the input
- line. For a negative distance it will be at the right side. In general,
- this function tries to preserve the direction of the input.
- Note: the behaviour regarding orientation of the resulting line depends
- on the GEOS version. With GEOS < 3.11, the line retains the same
- direction for a left offset (positive distance) or has opposite direction
- for a right offset (negative distance), and this behaviour was documented
- as such in previous Shapely versions. Starting with GEOS 3.11, the
- function tries to preserve the orientation of the original line.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries for which to compute the offset.
- distance : float or array_like
- Specifies the offset distance from the input geometry. Negative
- for right side offset, positive for left side offset.
- quad_segs : int, default 8
- Specifies the number of linear segments in a quarter circle in the
- approximation of circular arcs.
- join_style : {'round', 'bevel', 'mitre'}, default 'round'
- Specifies the shape of outside corners. 'round' results in
- rounded shapes. 'bevel' results in a beveled edge that touches the
- original vertex. 'mitre' results in a single vertex that is beveled
- depending on the ``mitre_limit`` parameter.
- mitre_limit : float, default 5.0
- Crops of 'mitre'-style joins if the point is displaced from the
- buffered vertex by more than this limit.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Notes
- -----
- .. deprecated:: 2.1.0
- A deprecation warning is shown if ``quad_segs``, ``join_style`` or
- ``mitre_limit`` are specified as positional arguments. In a future
- release, these will need to be specified as keyword arguments.
- Examples
- --------
- >>> import shapely
- >>> from shapely import LineString
- >>> line = LineString([(0, 0), (0, 2)])
- >>> shapely.offset_curve(line, 2)
- <LINESTRING (-2 0, -2 2)>
- >>> shapely.offset_curve(line, -2)
- <LINESTRING (2 0, 2 2)>
- """
- if isinstance(join_style, str):
- join_style = BufferJoinStyle.get_value(join_style)
- if not np.isscalar(quad_segs):
- raise TypeError("quad_segs only accepts scalar values")
- if not np.isscalar(join_style):
- raise TypeError("join_style only accepts scalar values")
- if not np.isscalar(mitre_limit):
- raise TypeError("mitre_limit only accepts scalar values")
- return lib.offset_curve(
- geometry,
- distance,
- np.intc(quad_segs),
- np.intc(join_style),
- np.double(mitre_limit),
- **kwargs,
- )
- @multithreading_enabled
- def centroid(geometry, **kwargs):
- """Compute the geometric center (center-of-mass) of a geometry.
- For multipoints this is computed as the mean of the input coordinates.
- For multilinestrings the centroid is weighted by the length of each
- line segment. For multipolygons the centroid is weighted by the area of
- each polygon.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries for which to compute the centroid.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Examples
- --------
- >>> import shapely
- >>> from shapely import LineString, MultiPoint, Polygon
- >>> shapely.centroid(Polygon([(0, 0), (10, 0), (10, 10), (0, 10), (0, 0)]))
- <POINT (5 5)>
- >>> shapely.centroid(LineString([(0, 0), (2, 2), (10, 10)]))
- <POINT (5 5)>
- >>> shapely.centroid(MultiPoint([(0, 0), (10, 10)]))
- <POINT (5 5)>
- >>> shapely.centroid(Polygon())
- <POINT EMPTY>
- """
- return lib.centroid(geometry, **kwargs)
- @multithreading_enabled
- def clip_by_rect(geometry, xmin, ymin, xmax, ymax, **kwargs):
- """Return the portion of a geometry within a rectangle.
- The geometry is clipped in a fast but possibly dirty way. The output is
- not guaranteed to be valid. No exceptions will be raised for topological
- errors.
- Note: empty geometries or geometries that do not overlap with the
- specified bounds will result in GEOMETRYCOLLECTION EMPTY.
- Parameters
- ----------
- geometry : Geometry or array_like
- The geometry to be clipped.
- xmin : float
- Minimum x value of the rectangle.
- ymin : float
- Minimum y value of the rectangle.
- xmax : float
- Maximum x value of the rectangle.
- ymax : float
- Maximum y value of the rectangle.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Examples
- --------
- >>> import shapely
- >>> from shapely import LineString, Polygon
- >>> line = LineString([(0, 0), (10, 10)])
- >>> shapely.clip_by_rect(line, 0., 0., 1., 1.)
- <LINESTRING (0 0, 1 1)>
- >>> polygon = Polygon([(0, 0), (10, 0), (10, 10), (0, 10), (0, 0)])
- >>> shapely.clip_by_rect(polygon, 0., 0., 1., 1.)
- <POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))>
- """
- if not all(np.isscalar(val) for val in [xmin, ymin, xmax, ymax]):
- raise TypeError("xmin/ymin/xmax/ymax only accepts scalar values")
- return lib.clip_by_rect(
- geometry,
- np.double(xmin),
- np.double(ymin),
- np.double(xmax),
- np.double(ymax),
- **kwargs,
- )
- @requires_geos("3.11.0")
- @multithreading_enabled
- def concave_hull(geometry, ratio=0.0, allow_holes=False, **kwargs):
- """Compute a concave geometry that encloses an input geometry.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries for which to compute the concave hull.
- ratio : float, default 0.0
- Number in the range [0, 1]. Higher numbers will include fewer vertices
- in the hull.
- allow_holes : bool, default False
- If set to True, the concave hull may have holes.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Examples
- --------
- >>> import shapely
- >>> from shapely import MultiPoint, Polygon
- >>> multi_point = MultiPoint([(0, 0), (0, 3), (1, 1), (3, 0), (3, 3)])
- >>> shapely.concave_hull(multi_point, ratio=0.1)
- <POLYGON ((0 0, 0 3, 1 1, 3 3, 3 0, 0 0))>
- >>> shapely.concave_hull(multi_point, ratio=1.0)
- <POLYGON ((0 0, 0 3, 3 3, 3 0, 0 0))>
- >>> shapely.concave_hull(Polygon())
- <POLYGON EMPTY>
- """
- if not np.isscalar(ratio):
- raise TypeError("ratio must be scalar")
- if not np.isscalar(allow_holes):
- raise TypeError("allow_holes must be scalar")
- return lib.concave_hull(geometry, np.double(ratio), np.bool_(allow_holes), **kwargs)
- @multithreading_enabled
- def convex_hull(geometry, **kwargs):
- """Compute the minimum convex geometry that encloses an input geometry.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries for which to compute the convex hull.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Examples
- --------
- >>> import shapely
- >>> from shapely import MultiPoint, Polygon
- >>> shapely.convex_hull(MultiPoint([(0, 0), (10, 0), (10, 10)]))
- <POLYGON ((0 0, 10 10, 10 0, 0 0))>
- >>> shapely.convex_hull(Polygon())
- <GEOMETRYCOLLECTION EMPTY>
- """
- return lib.convex_hull(geometry, **kwargs)
- @multithreading_enabled
- def delaunay_triangles(geometry, tolerance=0.0, only_edges=False, **kwargs):
- """Compute a Delaunay triangulation around the vertices of an input geometry.
- The output is a geometrycollection containing polygons (default)
- or linestrings (see ``only_edges``). Returns an empty geometry for input
- geometries that contain less than 3 vertices.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries for which to compute the Delaunay triangulation.
- tolerance : float or array_like, default 0.0
- Snap input vertices together if their distance is less than this value.
- only_edges : bool or array_like, default False
- If set to True, the triangulation will return a collection of
- linestrings instead of polygons.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Returns
- -------
- GeometryCollection or array of GeometryCollections
- See Also
- --------
- constrained_delaunay_triangles
- Examples
- --------
- >>> import shapely
- >>> from shapely import GeometryCollection, LineString, MultiPoint, Polygon
- >>> points = MultiPoint([(50, 30), (60, 30), (100, 100)])
- >>> shapely.delaunay_triangles(points).normalize()
- <GEOMETRYCOLLECTION (POLYGON ((50 30, 100 100, 60 30, 50 30)))>
- >>> shapely.delaunay_triangles(points, only_edges=True)
- <MULTILINESTRING ((50 30, 100 100), (50 30, 60 30), ...>
- >>> shapely.delaunay_triangles(
- ... MultiPoint([(50, 30), (51, 30), (60, 30), (100, 100)]),
- ... tolerance=2
- ... ).normalize()
- <GEOMETRYCOLLECTION (POLYGON ((50 30, 100 100, 60 30, 50 30)))>
- >>> shapely.delaunay_triangles(Polygon([(50, 30), (60, 30), (100, 100), (50, 30)]))\
- .normalize()
- <GEOMETRYCOLLECTION (POLYGON ((50 30, 100 100, 60 30, 50 30)))>
- >>> shapely.delaunay_triangles(LineString([(50, 30), (60, 30), (100, 100)]))\
- .normalize()
- <GEOMETRYCOLLECTION (POLYGON ((50 30, 100 100, 60 30, 50 30)))>
- >>> shapely.delaunay_triangles(GeometryCollection([]))
- <GEOMETRYCOLLECTION EMPTY>
- """
- return lib.delaunay_triangles(geometry, tolerance, only_edges, **kwargs)
- @requires_geos("3.10.0")
- @multithreading_enabled
- def constrained_delaunay_triangles(geometry, **kwargs):
- """Compute the constrained Delaunay triangulation of polygons.
- A constrained Delaunay triangulation requires the edges of the input
- polygon(s) to be in the set of resulting triangle edges. An unconstrained
- delaunay triangulation only triangulates based on the vertices, hence
- triangle edges could cross polygon boundaries.
- .. versionadded:: 2.1.0
- Parameters
- ----------
- geometry : Geometry or array_like
- **kwargs
- For other keyword-only arguments, see the
- `NumPy ufunc docs <https://numpy.org/doc/stable/reference/ufuncs.html#ufuncs-kwargs>`_.
- Returns
- -------
- GeometryCollection or array of GeometryCollections
- * GeometryCollection of polygons, given polygonal input
- * Empty GeometryCollection, given non-polygonal input
- See Also
- --------
- delaunay_triangles
- Examples
- --------
- >>> import shapely
- >>> from shapely import MultiPoint, MultiPolygon, Polygon
- >>> shapely.constrained_delaunay_triangles(Polygon([(10, 10), (20, 40), (90, 90), (90, 10), (10, 10)]))
- <GEOMETRYCOLLECTION (POLYGON ((90 10, 20 40, 90 90, 90 10)), POLYGON ((20 40...>
- >>> shapely.constrained_delaunay_triangles(Polygon())
- <GEOMETRYCOLLECTION EMPTY>
- >>> shapely.constrained_delaunay_triangles(MultiPolygon([Polygon(((50, 30), (60, 30), (100, 100), (50, 30))), Polygon(((10, 10), (20, 40), (90, 90), (90, 10), (10, 10)))]))
- <GEOMETRYCOLLECTION (POLYGON ((50 30, 100 100, 60 30, 50 30)), POLYGON ((90 ...>
- >>> shapely.constrained_delaunay_triangles(MultiPolygon())
- <GEOMETRYCOLLECTION EMPTY>
- >>> shapely.constrained_delaunay_triangles(MultiPoint([(50, 30), (51, 30), (60, 30), (100, 100)]))
- <GEOMETRYCOLLECTION EMPTY>
- """ # noqa: E501
- return lib.constrained_delaunay_triangles(geometry, **kwargs)
- @multithreading_enabled
- def envelope(geometry, **kwargs):
- """Compute the minimum bounding box that encloses an input geometry.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries for which to compute the envelope.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Examples
- --------
- >>> import shapely
- >>> from shapely import GeometryCollection, LineString, MultiPoint, Point
- >>> shapely.envelope(LineString([(0, 0), (10, 10)]))
- <POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))>
- >>> shapely.envelope(MultiPoint([(0, 0), (10, 10)]))
- <POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))>
- >>> shapely.envelope(Point(0, 0))
- <POINT (0 0)>
- >>> shapely.envelope(GeometryCollection([]))
- <POINT EMPTY>
- """
- return lib.envelope(geometry, **kwargs)
- @multithreading_enabled
- def extract_unique_points(geometry, **kwargs):
- """Return all distinct vertices of an input geometry as a multipoint.
- Note that only 2 dimensions of the vertices are considered when testing
- for equality.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries for which to extract unique points.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Examples
- --------
- >>> import shapely
- >>> from shapely import LineString, MultiPoint, Point, Polygon
- >>> shapely.extract_unique_points(Point(0, 0))
- <MULTIPOINT ((0 0))>
- >>> shapely.extract_unique_points(LineString([(0, 0), (1, 1), (1, 1)]))
- <MULTIPOINT ((0 0), (1 1))>
- >>> shapely.extract_unique_points(Polygon([(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)]))
- <MULTIPOINT ((0 0), (1 0), (1 1), (0 1))>
- >>> shapely.extract_unique_points(MultiPoint([(0, 0), (1, 1), (0, 0)]))
- <MULTIPOINT ((0 0), (1 1))>
- >>> shapely.extract_unique_points(LineString())
- <MULTIPOINT EMPTY>
- """
- return lib.extract_unique_points(geometry, **kwargs)
- @multithreading_enabled
- def build_area(geometry, **kwargs):
- """Create an areal geometry formed by the constituent linework of given geometry.
- Equivalent of the PostGIS ST_BuildArea() function.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries for which to build an area.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Examples
- --------
- >>> import shapely
- >>> from shapely import GeometryCollection, Polygon
- >>> polygon1 = Polygon([(0, 0), (3, 0), (3, 3), (0, 3), (0, 0)])
- >>> polygon2 = Polygon([(1, 1), (1, 2), (2, 2), (1, 1)])
- >>> shapely.build_area(GeometryCollection([polygon1, polygon2]))
- <POLYGON ((0 0, 0 3, 3 3, 3 0, 0 0), (1 1, 2 2, 1 2, 1 1))>
- """
- return lib.build_area(geometry, **kwargs)
- @multithreading_enabled
- def make_valid(geometry, *, method="linework", keep_collapsed=True, **kwargs):
- """Repair invalid geometries.
- Two ``methods`` are available:
- * the 'linework' algorithm tries to preserve every edge and vertex in the input. It
- combines all rings into a set of noded lines and then extracts valid polygons from
- that linework. An alternating even-odd strategy is used to assign areas as
- interior or exterior. A disadvantage is that for some relatively simple invalid
- geometries this produces rather complex results.
- * the 'structure' algorithm tries to reason from the structure of the input to find
- the 'correct' repair: exterior rings bound area, interior holes exclude area.
- It first makes all rings valid, then shells are merged and holes are subtracted
- from the shells to generate valid result. It assumes that holes and shells are
- correctly categorized in the input geometry.
- Example:
- .. plot:: code/make_valid_methods.py
- When using ``make_valid`` on a Polygon, the result can be a GeometryCollection. For
- this example this is the case when the 'linework' ``method`` is used. LineStrings in
- the result are drawn in red.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries to repair.
- method : {'linework', 'structure'}, default 'linework'
- Algorithm to use when repairing geometry. 'structure'
- requires GEOS >= 3.10.
- .. versionadded:: 2.1.0
- keep_collapsed : bool, default True
- For the 'structure' method, True will keep components that have collapsed into a
- lower dimensionality. For example, a ring collapsing to a line, or a line
- collapsing to a point. Must be True for the 'linework' method.
- .. versionadded:: 2.1.0
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Examples
- --------
- >>> import shapely
- >>> from shapely import Polygon
- >>> polygon = Polygon([(0, 0), (1, 1), (1, 2), (1, 1), (0, 0)])
- >>> shapely.is_valid(polygon)
- False
- >>> shapely.make_valid(polygon)
- <MULTILINESTRING ((0 0, 1 1), (1 1, 1 2))>
- >>> shapely.make_valid(polygon, method="structure", keep_collapsed=True)
- <LINESTRING (0 0, 1 1, 1 2, 1 1, 0 0)>
- >>> shapely.make_valid(polygon, method="structure", keep_collapsed=False)
- <POLYGON EMPTY>
- """
- if not np.isscalar(method):
- raise TypeError("method only accepts scalar values")
- if not np.isscalar(keep_collapsed):
- raise TypeError("keep_collapsed only accepts scalar values")
- if method == "linework":
- if keep_collapsed is False:
- raise ValueError(
- "The 'linework' method does not support 'keep_collapsed=False'"
- )
- # The make_valid code can be removed once support for GEOS < 3.10 is dropped.
- # In GEOS >= 3.10, make_valid just calls make_valid_with_params with
- # method="linework" and keep_collapsed=True, so there is no advantage to keep
- # both code paths in shapely on long term.
- return lib.make_valid(geometry, **kwargs)
- elif method == "structure":
- if lib.geos_version < (3, 10, 0):
- raise ValueError(
- "The 'structure' method is only available in GEOS >= 3.10.0"
- )
- return lib.make_valid_with_params(
- geometry, np.intc(1), np.bool_(keep_collapsed), **kwargs
- )
- else:
- raise ValueError(f"Unknown method: {method}")
- @multithreading_enabled
- def minimum_clearance_line(geometry, **kwargs):
- """Return a LineString whose endpoints define the minimum clearance.
- A geometry's "minimum clearance" is the smallest distance by which a vertex
- of the geometry could be moved to produce an invalid geometry.
- If the geometry has no minimum clearance, an empty LineString will be
- returned.
- .. versionadded:: 2.1.0
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries to determine the minimum clearance line for.
- **kwargs
- For other keyword-only arguments, see the
- `NumPy ufunc docs <https://numpy.org/doc/stable/reference/ufuncs.html#ufuncs-kwargs>`_.
- Examples
- --------
- >>> import shapely
- >>> from shapely import Polygon
- >>> poly = Polygon([(0, 0), (10, 0), (10, 10), (5, 5), (0, 10), (0, 0)])
- >>> shapely.minimum_clearance_line(poly)
- <LINESTRING (5 5, 5 0)>
- See Also
- --------
- minimum_clearance
- """
- return lib.minimum_clearance_line(geometry, **kwargs)
- @multithreading_enabled
- def normalize(geometry, **kwargs):
- """Convert Geometry to strict normal form (or canonical form).
- In :ref:`strict canonical form <canonical-form>`, the coordinates, rings of
- a polygon and parts of multi geometries are ordered consistently. Typically
- useful for testing purposes (for example in combination with
- ``equals_exact``).
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries to normalize.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Examples
- --------
- >>> import shapely
- >>> from shapely import MultiLineString
- >>> line = MultiLineString([[(0, 0), (1, 1)], [(2, 2), (3, 3)]])
- >>> shapely.normalize(line)
- <MULTILINESTRING ((2 2, 3 3), (0 0, 1 1))>
- """
- return lib.normalize(geometry, **kwargs)
- @multithreading_enabled
- def point_on_surface(geometry, **kwargs):
- """Return a point that intersects an input geometry.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries for which to compute a point on the surface.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Examples
- --------
- >>> import shapely
- >>> from shapely import LineString, MultiPoint, Polygon
- >>> shapely.point_on_surface(Polygon([(0, 0), (10, 0), (10, 10), (0, 10), (0, 0)]))
- <POINT (5 5)>
- >>> shapely.point_on_surface(LineString([(0, 0), (2, 2), (10, 10)]))
- <POINT (2 2)>
- >>> shapely.point_on_surface(MultiPoint([(0, 0), (10, 10)]))
- <POINT (0 0)>
- >>> shapely.point_on_surface(Polygon())
- <POINT EMPTY>
- """
- return lib.point_on_surface(geometry, **kwargs)
- @multithreading_enabled
- def node(geometry, **kwargs):
- """Return the fully noded version of the linear input as MultiLineString.
- Given a linear input geometry, this function returns a new MultiLineString
- in which no lines cross each other but only touch at and points. To
- obtain this, all intersections between segments are computed and added
- to the segments, and duplicate segments are removed.
- Non-linear input (points) will result in an empty MultiLineString.
- This function can for example be used to create a fully-noded linework
- suitable to passed as input to ``polygonize``.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries for which to compute the noded version.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Examples
- --------
- >>> import shapely
- >>> from shapely import LineString, Point
- >>> line = LineString([(0, 0), (1,1), (0, 1), (1, 0)])
- >>> shapely.node(line)
- <MULTILINESTRING ((0 0, 0.5 0.5), (0.5 0.5, 1 1, 0 1, 0.5 0.5), (0.5 0.5, 1 0))>
- >>> shapely.node(Point(1, 1))
- <MULTILINESTRING EMPTY>
- """
- return lib.node(geometry, **kwargs)
- def polygonize(geometries, **kwargs):
- """Create polygons formed from the linework of a set of Geometries.
- Polygonizes an array of Geometries that contain linework which
- represents the edges of a planar graph. Any type of Geometry may be
- provided as input; only the constituent lines and rings will be used to
- create the output polygons.
- Lines or rings that when combined do not completely close a polygon
- will result in an empty GeometryCollection. Duplicate segments are
- ignored.
- This function returns the polygons within a GeometryCollection.
- Individual Polygons can be obtained using ``get_geometry`` to get
- a single polygon or ``get_parts`` to get an array of polygons.
- MultiPolygons can be constructed from the output using
- ``shapely.multipolygons(shapely.get_parts(shapely.polygonize(geometries)))``.
- Parameters
- ----------
- geometries : array_like
- An array of geometries.
- axis : int
- Axis along which the geometries are polygonized.
- The default is to perform a reduction over the last dimension
- of the input array. A 1D array results in a scalar geometry.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Returns
- -------
- GeometryCollection or array of GeometryCollections
- See Also
- --------
- get_parts, get_geometry
- polygonize_full
- node
- Examples
- --------
- >>> import shapely
- >>> from shapely import LineString
- >>> lines = [
- ... LineString([(0, 0), (1, 1)]),
- ... LineString([(0, 0), (0, 1)]),
- ... LineString([(0, 1), (1, 1)])
- ... ]
- >>> shapely.polygonize(lines)
- <GEOMETRYCOLLECTION (POLYGON ((1 1, 0 0, 0 1, 1 1)))>
- """
- return lib.polygonize(geometries, **kwargs)
- def polygonize_full(geometries, **kwargs):
- """Create polygons formed from the linework of a set of Geometries.
- All extra outputs are returned as well.
- Polygonizes an array of Geometries that contain linework which
- represents the edges of a planar graph. Any type of Geometry may be
- provided as input; only the constituent lines and rings will be used to
- create the output polygons.
- This function performs the same polygonization as ``polygonize`` but does
- not only return the polygonal result but all extra outputs as well. The
- return value consists of 4 elements:
- * The polygonal valid output
- * **Cut edges**: edges connected on both ends but not part of polygonal output
- * **dangles**: edges connected on one end but not part of polygonal output
- * **invalid rings**: polygons formed but which are not valid
- This function returns the geometries within GeometryCollections.
- Individual geometries can be obtained using ``get_geometry`` to get
- a single geometry or ``get_parts`` to get an array of geometries.
- Parameters
- ----------
- geometries : array_like
- An array of geometries.
- axis : int
- Axis along which the geometries are polygonized.
- The default is to perform a reduction over the last dimension
- of the input array. A 1D array results in a scalar geometry.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Returns
- -------
- (polygons, cuts, dangles, invalid)
- tuple of 4 GeometryCollections or arrays of GeometryCollections
- See Also
- --------
- polygonize
- Examples
- --------
- >>> import shapely
- >>> from shapely import LineString
- >>> lines = [
- ... LineString([(0, 0), (1, 1)]),
- ... LineString([(0, 0), (0, 1), (1, 1)]),
- ... LineString([(0, 1), (1, 1)])
- ... ]
- >>> shapely.polygonize_full(lines)
- (<GEOMETRYCOLLECTION (POLYGON ((1 1, 0 0, 0 1, 1 1)))>,
- <GEOMETRYCOLLECTION EMPTY>,
- <GEOMETRYCOLLECTION (LINESTRING (0 1, 1 1))>,
- <GEOMETRYCOLLECTION EMPTY>)
- """
- return lib.polygonize_full(geometries, **kwargs)
- @requires_geos("3.11.0")
- @multithreading_enabled
- def remove_repeated_points(geometry, tolerance=0.0, **kwargs):
- """Return a copy of a Geometry with repeated points removed.
- From the start of the coordinate sequence, each next point within the
- tolerance is removed.
- Removing repeated points with a non-zero tolerance may result in an invalid
- geometry being returned.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries to remove repeated points from.
- tolerance : float or array_like, default=0.0
- Use 0.0 to remove only exactly repeated points.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Examples
- --------
- >>> import shapely
- >>> from shapely import LineString, Polygon
- >>> shapely.remove_repeated_points(LineString([(0,0), (0,0), (1,0)]), tolerance=0)
- <LINESTRING (0 0, 1 0)>
- >>> shapely.remove_repeated_points(Polygon([(0, 0), (0, .5), (0, 1), (.5, 1), (0,0)]), tolerance=.5)
- <POLYGON ((0 0, 0 1, 0 0))>
- """ # noqa: E501
- return lib.remove_repeated_points(geometry, tolerance, **kwargs)
- @multithreading_enabled
- def reverse(geometry, **kwargs):
- """Return a copy of a Geometry with the order of coordinates reversed.
- If a Geometry is a polygon with interior rings, the interior rings are also
- reversed.
- Points are unchanged. None is returned where Geometry is None.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries to reverse the coordinates of.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- See Also
- --------
- is_ccw : Checks if a Geometry is clockwise.
- Examples
- --------
- >>> import shapely
- >>> from shapely import LineString, Polygon
- >>> shapely.reverse(LineString([(0, 0), (1, 2)]))
- <LINESTRING (1 2, 0 0)>
- >>> shapely.reverse(Polygon([(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)]))
- <POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))>
- >>> shapely.reverse(None) is None
- True
- """
- return lib.reverse(geometry, **kwargs)
- @requires_geos("3.10.0")
- @multithreading_enabled
- def segmentize(geometry, max_segment_length, **kwargs):
- """Add vertices to line segments based on maximum segment length.
- Additional vertices will be added to every line segment in an input geometry
- so that segments are no longer than the provided maximum segment length. New
- vertices will evenly subdivide each segment.
- Only linear components of input geometries are densified; other geometries
- are returned unmodified.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries to segmentize.
- max_segment_length : float or array_like
- Additional vertices will be added so that all line segments are no
- longer than this value. Must be greater than 0.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Examples
- --------
- >>> import shapely
- >>> from shapely import LineString, Polygon
- >>> line = LineString([(0, 0), (0, 10)])
- >>> shapely.segmentize(line, max_segment_length=5)
- <LINESTRING (0 0, 0 5, 0 10)>
- >>> polygon = Polygon([(0, 0), (10, 0), (10, 10), (0, 10), (0, 0)])
- >>> shapely.segmentize(polygon, max_segment_length=5)
- <POLYGON ((0 0, 5 0, 10 0, 10 5, 10 10, 5 10, 0 10, 0 5, 0 0))>
- >>> shapely.segmentize(None, max_segment_length=5) is None
- True
- """
- return lib.segmentize(geometry, max_segment_length, **kwargs)
- # Note: future plan is to change this signature over a few releases:
- # shapely 2.0:
- # simplify(geometry, tolerance, preserve_topology=True, **kwargs)
- # shapely 2.1: shows deprecation warning about positional 'preserve_topology'
- # same signature as 2.0
- # shapely 2.2(?): enforce keyword-only arguments after 'tolerance'
- # simplify(geometry, tolerance, *, preserve_topology=True, **kwargs)
- @deprecate_positional(["preserve_topology"], category=DeprecationWarning)
- @multithreading_enabled
- def simplify(geometry, tolerance, preserve_topology=True, **kwargs):
- """Return a simplified version of an input geometry.
- The Douglas-Peucker algorithm is used to simplify the geometry.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries to simplify.
- tolerance : float or array_like
- The maximum allowed geometry displacement. The higher this value, the
- smaller the number of vertices in the resulting geometry.
- preserve_topology : bool, default True
- By default (True), the operation will avoid creating invalid
- geometries (checking for collapses, ring-intersections, etc), but
- this is computationally more expensive.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Notes
- -----
- .. deprecated:: 2.1.0
- A deprecation warning is shown if ``preserve_topology`` is specified as
- a positional argument. This will need to be specified as a keyword
- argument in a future release.
- Examples
- --------
- >>> import shapely
- >>> from shapely import LineString, Polygon
- >>> line = LineString([(0, 0), (1, 10), (0, 20)])
- >>> shapely.simplify(line, tolerance=0.9)
- <LINESTRING (0 0, 1 10, 0 20)>
- >>> shapely.simplify(line, tolerance=1)
- <LINESTRING (0 0, 0 20)>
- >>> polygon_with_hole = Polygon(
- ... [(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)],
- ... holes=[[(2, 2), (2, 4), (4, 4), (4, 2), (2, 2)]]
- ... )
- >>> shapely.simplify(polygon_with_hole, tolerance=4, preserve_topology=True)
- <POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0), (4 2, 2 4, 4 4, 4 2))>
- >>> shapely.simplify(polygon_with_hole, tolerance=4, preserve_topology=False)
- <POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))>
- """
- if preserve_topology:
- return lib.simplify_preserve_topology(geometry, tolerance, **kwargs)
- else:
- return lib.simplify(geometry, tolerance, **kwargs)
- @multithreading_enabled
- def snap(geometry, reference, tolerance, **kwargs):
- """Snap the vertices and segments of the geometry to vertices of the reference.
- Vertices and segments of the input geometry are snapped to vertices of the
- reference geometry, returning a new geometry; the input geometries are not
- modified. The result geometry is the input geometry with the vertices and
- segments snapped. If no snapping occurs then the input geometry is returned
- unchanged. The tolerance is used to control where snapping is performed.
- Where possible, this operation tries to avoid creating invalid geometries;
- however, it does not guarantee that output geometries will be valid. It is
- the responsibility of the caller to check for and handle invalid geometries.
- Because too much snapping can result in invalid geometries being created,
- heuristics are used to determine the number and location of snapped
- vertices that are likely safe to snap. These heuristics may omit
- some potential snaps that are otherwise within the tolerance.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries to snap.
- reference : Geometry or array_like
- Geometry or geometries to snap to.
- tolerance : float or array_like
- The maximum distance between the input and reference geometries for
- snapping to occur. A value of 0 will snap only identical points.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Examples
- --------
- >>> import shapely
- >>> from shapely import LineString, Point, Polygon, MultiPoint
- >>> point = Point(0.5, 2.5)
- >>> target_point = Point(0, 2)
- >>> shapely.snap(point, target_point, tolerance=1)
- <POINT (0 2)>
- >>> shapely.snap(point, target_point, tolerance=0.49)
- <POINT (0.5 2.5)>
- >>> polygon = Polygon([(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)])
- >>> shapely.snap(polygon, Point(8, 10), tolerance=5)
- <POLYGON ((0 0, 0 10, 8 10, 10 0, 0 0))>
- >>> shapely.snap(polygon, LineString([(8, 10), (8, 0)]), tolerance=5)
- <POLYGON ((0 0, 0 10, 8 10, 8 0, 0 0))>
- You can snap one line to another, for example to clean imprecise coordinates:
- >>> line1 = LineString([(0.1, 0.1), (0.49, 0.51), (1.01, 0.89)])
- >>> line2 = LineString([(0, 0), (0.5, 0.5), (1.0, 1.0)])
- >>> shapely.snap(line1, line2, 0.25)
- <LINESTRING (0 0, 0.5 0.5, 1 1)>
- Snapping also supports Z coordinates:
- >>> point1 = Point(0.1, 0.1, 0.5)
- >>> multipoint = MultiPoint([(0, 0, 1), (0, 0, 0)])
- >>> shapely.snap(point1, multipoint, 1)
- <POINT Z (0 0 1)>
- Snapping to an empty geometry has no effect:
- >>> shapely.snap(line1, LineString([]), 0.25)
- <LINESTRING (0.1 0.1, 0.49 0.51, 1.01 0.89)>
- Snapping to a non-geometry (None) will always return None:
- >>> shapely.snap(line1, None, 0.25) is None
- True
- Only one vertex of a polygon is snapped to a target point,
- even if all vertices are equidistant to it,
- in order to prevent collapse of the polygon:
- >>> poly = shapely.box(0, 0, 1, 1)
- >>> poly
- <POLYGON ((1 0, 1 1, 0 1, 0 0, 1 0))>
- >>> shapely.snap(poly, Point(0.5, 0.5), 1)
- <POLYGON ((0.5 0.5, 1 1, 0 1, 0 0, 0.5 0.5))>
- """
- return lib.snap(geometry, reference, tolerance, **kwargs)
- # Note: future plan is to change this signature over a few releases:
- # shapely 2.0:
- # voronoi_polygons(geometry, tolerance=0.0, extend_to=None, ...)
- # shapely 2.1: shows deprecation warning about positional 'extend_to'
- # same signature as 2.0
- # shapely 2.2(?): enforce keyword-only arguments after 'tolerance'
- # voronoi_polygons(geometry, tolerance=0.0, extend_to=None, ...)
- @deprecate_positional(
- ["extend_to", "only_edges", "ordered"], category=DeprecationWarning
- )
- @multithreading_enabled
- def voronoi_polygons(
- geometry, tolerance=0.0, extend_to=None, only_edges=False, ordered=False, **kwargs
- ):
- """Compute a Voronoi diagram from the vertices of an input geometry.
- The output is a geometrycollection containing polygons (default)
- or linestrings (see only_edges). Returns empty if an input geometry
- contains less than 2 vertices or if the provided extent has zero area.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries for which to compute the Voronoi diagram.
- tolerance : float or array_like, default 0.0
- Snap input vertices together if their distance is less than this value.
- extend_to : Geometry or array_like, optional
- If provided, the diagram will be extended to cover the envelope of this
- geometry (unless this envelope is smaller than the input geometry).
- only_edges : bool or array_like, default False
- If set to True, the triangulation will return a collection of
- linestrings instead of polygons.
- ordered : bool or array_like, default False
- If set to True, polygons within the GeometryCollection will be ordered
- according to the order of the input vertices. Note that this may slow
- down the computation. Requires GEOS >= 3.12.0.
- .. versionadded:: 2.1.0
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Notes
- -----
- .. deprecated:: 2.1.0
- A deprecation warning is shown if ``extend_to``, ``only_edges`` or
- ``ordered`` are specified as positional arguments. In a future
- release, these will need to be specified as keyword arguments.
- Examples
- --------
- >>> import shapely
- >>> from shapely import LineString, MultiPoint, Point
- >>> points = MultiPoint([(2, 2), (4, 2)])
- >>> shapely.voronoi_polygons(points).normalize()
- <GEOMETRYCOLLECTION (POLYGON ((3 0, 3 4, 6 4, 6 0, 3 0)), POLYGON ((0 0, 0 4...>
- >>> shapely.voronoi_polygons(points, only_edges=True)
- <MULTILINESTRING ((3 4, 3 0))>
- >>> shapely.voronoi_polygons(MultiPoint([(2, 2), (4, 2), (4.2, 2)]), 0.5, only_edges=True)
- <MULTILINESTRING ((3 4.2, 3 -0.2))>
- >>> shapely.voronoi_polygons(points, extend_to=LineString([(0, 0), (10, 10)]), only_edges=True)
- <MULTILINESTRING ((3 10, 3 0))>
- >>> shapely.voronoi_polygons(LineString([(2, 2), (4, 2)]), only_edges=True)
- <MULTILINESTRING ((3 4, 3 0))>
- >>> shapely.voronoi_polygons(Point(2, 2))
- <GEOMETRYCOLLECTION EMPTY>
- >>> shapely.voronoi_polygons(points, ordered=True)
- <GEOMETRYCOLLECTION (POLYGON ((0 0, 0 4, 3 4, 3 0, 0 0)), POLYGON ((6 4, 6 0...>
- """ # noqa: E501
- if ordered is not False and lib.geos_version < (3, 12, 0):
- raise UnsupportedGEOSVersionError(
- "Ordered Voronoi polygons require GEOS >= 3.12.0, "
- f"found {lib.geos_version_string}"
- )
- return lib.voronoi_polygons(
- geometry, tolerance, extend_to, only_edges, ordered, **kwargs
- )
- @multithreading_enabled
- def _oriented_envelope_geos(geometry, **kwargs):
- return lib.oriented_envelope(geometry, **kwargs)
- def oriented_envelope(geometry, **kwargs):
- """Compute the oriented envelope (minimum rotated rectangle) of the input geometry.
- The oriented envelope encloses an input geometry, such that the resulting
- rectangle has minimum area.
- Unlike envelope this rectangle is not constrained to be parallel to the
- coordinate axes. If the convex hull of the object is a degenerate (line
- or point) this degenerate is returned.
- The starting point of the rectangle is not fixed. You can use
- :func:`~shapely.normalize` to reorganize the rectangle to
- :ref:`strict canonical form <canonical-form>` so the starting point is
- always the lower left point.
- ``minimum_rotated_rectangle`` is an alias for ``oriented_envelope``.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries for which to compute the oriented envelope.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Examples
- --------
- >>> import shapely
- >>> from shapely import GeometryCollection, LineString, MultiPoint, Point, Polygon
- >>> shapely.oriented_envelope(MultiPoint([(0, 0), (10, 0), (10, 10)])).normalize()
- <POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))>
- >>> shapely.oriented_envelope(LineString([(1, 1), (5, 1), (10, 10)])).normalize()
- <POLYGON ((1 1, 10 10, 12 8, 3 -1, 1 1))>
- >>> shapely.oriented_envelope(Polygon([(1, 1), (15, 1), (5, 10), (1, 1)]))\
- .normalize()
- <POLYGON ((1 1, 5 10, 16.691 4.804, 12.691 -4.196, 1 1))>
- >>> shapely.oriented_envelope(LineString([(1, 1), (10, 1)])).normalize()
- <LINESTRING (1 1, 10 1)>
- >>> shapely.oriented_envelope(Point(2, 2))
- <POINT (2 2)>
- >>> shapely.oriented_envelope(GeometryCollection([]))
- <POLYGON EMPTY>
- """
- if lib.geos_version < (3, 12, 0):
- f = _oriented_envelope_min_area_vectorized
- else:
- f = _oriented_envelope_geos
- return f(geometry, **kwargs)
- minimum_rotated_rectangle = oriented_envelope
- @multithreading_enabled
- def minimum_bounding_circle(geometry, **kwargs):
- """Compute the minimum bounding circle that encloses an input geometry.
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries for which to compute the minimum bounding circle.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Examples
- --------
- >>> import shapely
- >>> from shapely import GeometryCollection, LineString, MultiPoint, Point, Polygon
- >>> shapely.minimum_bounding_circle(
- ... Polygon([(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)])
- ... )
- <POLYGON ((12.071 5, 11.935 3.621, 11.533 2.294, 10.879 1.07...>
- >>> shapely.minimum_bounding_circle(LineString([(1, 1), (10, 10)]))
- <POLYGON ((11.864 5.5, 11.742 4.258, 11.38 3.065, 10.791 1.9...>
- >>> shapely.minimum_bounding_circle(MultiPoint([(2, 2), (4, 2)]))
- <POLYGON ((4 2, 3.981 1.805, 3.924 1.617, 3.831 1.444, 3.707...>
- >>> shapely.minimum_bounding_circle(Point(0, 1))
- <POINT (0 1)>
- >>> shapely.minimum_bounding_circle(GeometryCollection([]))
- <POLYGON EMPTY>
- See Also
- --------
- minimum_bounding_radius, maximum_inscribed_circle
- """
- return lib.minimum_bounding_circle(geometry, **kwargs)
- @multithreading_enabled
- def maximum_inscribed_circle(geometry, tolerance=None, **kwargs):
- """Find the largest circle that is fully contained within the input geometry.
- Constructs the "maximum inscribed circle" (MIC) for a polygonal geometry,
- up to a specified tolerance. The MIC is determined by a point in the
- interior of the area which has the farthest distance from the area
- boundary, along with a boundary point at that distance. In the context of
- geography the center of the MIC is known as the "pole of inaccessibility".
- A cartographic use case is to determine a suitable point to place a map
- label within a polygon.
- The radius length of the MIC is a measure of how "narrow" a polygon is.
- It is the distance at which the negative buffer becomes empty.
- The function supports polygons with holes and multipolygons.
- Returns a two-point linestring, with the first point at the center of the
- inscribed circle and the second on the boundary of the inscribed circle.
- .. versionadded:: 2.1.0
- Parameters
- ----------
- geometry : Geometry or array_like
- tolerance : float or array_like, optional
- Stop the algorithm when the search area is smaller than this tolerance.
- When not specified, uses `max(width, height) / 1000` per geometry as
- the default.
- **kwargs
- For other keyword-only arguments, see the
- `NumPy ufunc docs <https://numpy.org/doc/stable/reference/ufuncs.html#ufuncs-kwargs>`_.
- Examples
- --------
- >>> import shapely
- >>> from shapely import Polygon
- >>> poly = Polygon([(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)])
- >>> shapely.maximum_inscribed_circle(poly)
- <LINESTRING (5 5, 0 5)>
- See Also
- --------
- minimum_bounding_circle
- """
- if tolerance is None:
- tolerance = 0.0
- elif np.isscalar(tolerance) and tolerance < 0:
- raise ValueError("'tolerance' should be positive")
- return lib.maximum_inscribed_circle(geometry, tolerance, **kwargs)
- @multithreading_enabled
- def _orient_polygons_geos(geometry, exterior_cw=False, **kwargs):
- return lib.orient_polygons(geometry, exterior_cw, **kwargs)
- @multithreading_enabled
- def orient_polygons(geometry, *, exterior_cw=False, **kwargs):
- """Enforce a ring orientation on all polygonal elements in the input geometry.
- Forces (Multi)Polygons to use a counter-clockwise orientation for their
- exterior ring, and a clockwise orientation for their interior rings (or
- the oppposite if ``exterior_cw=True``).
- Also processes geometries inside a GeometryCollection in the same way.
- Other geometries are returned unchanged.
- .. versionadded:: 2.1.0
- Parameters
- ----------
- geometry : Geometry or array_like
- Geometry or geometries to orient consistently.
- exterior_cw : bool, default False
- If True, exterior rings will be clockwise and interior rings
- will be counter-clockwise.
- **kwargs
- See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
- Examples
- --------
- A polygon with both shell and hole having clockwise orientation:
- >>> from shapely import Polygon, orient_polygons
- >>> polygon = Polygon(
- ... [(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)],
- ... holes=[[(2, 2), (2, 4), (4, 4), (4, 2), (2, 2)]],
- ... )
- >>> polygon
- <POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 4, 4 4, 4 2, 2 2))>
- By default, the exterior ring is oriented counter-clockwise and
- the holes clockwise:
- >>> orient_polygons(polygon)
- <POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (2 2, 2 4, 4 4, 4 2, 2 2))>
- Asking for the opposite orientation:
- >>> orient_polygons(polygon, exterior_cw=True)
- <POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 4 2, 4 4, 2 4, 2 2))>
- """
- if lib.geos_version < (3, 12, 0):
- f = _orient_polygons_vectorized
- else:
- f = _orient_polygons_geos
- return f(geometry, exterior_cw, **kwargs)
|