constructive.py 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552
  1. """Methods that yield new objects not derived from set-theoretic analysis."""
  2. import numpy as np
  3. from shapely import lib
  4. from shapely._enum import ParamEnum
  5. from shapely.algorithms._oriented_envelope import _oriented_envelope_min_area_vectorized
  6. from shapely.algorithms.cga import _orient_polygons_vectorized
  7. from shapely.decorators import (
  8. deprecate_positional,
  9. multithreading_enabled,
  10. requires_geos,
  11. )
  12. from shapely.errors import UnsupportedGEOSVersionError
  13. __all__ = [
  14. "BufferCapStyle",
  15. "BufferJoinStyle",
  16. "boundary",
  17. "buffer",
  18. "build_area",
  19. "centroid",
  20. "clip_by_rect",
  21. "concave_hull",
  22. "constrained_delaunay_triangles",
  23. "convex_hull",
  24. "delaunay_triangles",
  25. "envelope",
  26. "extract_unique_points",
  27. "make_valid",
  28. "maximum_inscribed_circle",
  29. "minimum_bounding_circle",
  30. "minimum_clearance_line",
  31. "minimum_rotated_rectangle",
  32. "node",
  33. "normalize",
  34. "offset_curve",
  35. "orient_polygons",
  36. "oriented_envelope",
  37. "point_on_surface",
  38. "polygonize",
  39. "polygonize_full",
  40. "remove_repeated_points",
  41. "reverse",
  42. "segmentize",
  43. "simplify",
  44. "snap",
  45. "voronoi_polygons",
  46. ]
  47. class BufferCapStyle(ParamEnum):
  48. """Enumeration of buffer cap styles.
  49. Attributes
  50. ----------
  51. round : int
  52. Represents a round cap style.
  53. flat : int
  54. Represents a flat cap style.
  55. square : int
  56. Represents a square cap style.
  57. """
  58. round = 1
  59. flat = 2
  60. square = 3
  61. class BufferJoinStyle(ParamEnum):
  62. """Enumeration of buffer join styles.
  63. Attributes
  64. ----------
  65. round : int
  66. Specifies a round join style.
  67. mitre : int
  68. Specifies a mitre join style.
  69. bevel : int
  70. Specifies a bevel join style.
  71. """
  72. round = 1
  73. mitre = 2
  74. bevel = 3
  75. @multithreading_enabled
  76. def boundary(geometry, **kwargs):
  77. """Return the topological boundary of a geometry.
  78. This function will return None for geometrycollections.
  79. Parameters
  80. ----------
  81. geometry : Geometry or array_like
  82. Geometry for which to return the boundary.
  83. **kwargs
  84. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  85. Examples
  86. --------
  87. >>> import shapely
  88. >>> from shapely import GeometryCollection, LinearRing, LineString, \
  89. MultiLineString, MultiPoint, Point, Polygon
  90. >>> shapely.boundary(Point(0, 0))
  91. <GEOMETRYCOLLECTION EMPTY>
  92. >>> shapely.boundary(LineString([(0, 0), (1, 1), (1, 2)]))
  93. <MULTIPOINT ((0 0), (1 2))>
  94. >>> shapely.boundary(LinearRing([(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)]))
  95. <MULTIPOINT EMPTY>
  96. >>> shapely.boundary(Polygon([(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)]))
  97. <LINESTRING (0 0, 1 0, 1 1, 0 1, 0 0)>
  98. >>> shapely.boundary(MultiPoint([(0, 0), (1, 2)]))
  99. <GEOMETRYCOLLECTION EMPTY>
  100. >>> shapely.boundary(MultiLineString([[(0, 0), (1, 1)], [(0, 1), (1, 0)]]))
  101. <MULTIPOINT ((0 0), (0 1), (1 0), (1 1))>
  102. >>> shapely.boundary(GeometryCollection([Point(0, 0)])) is None
  103. True
  104. """
  105. return lib.boundary(geometry, **kwargs)
  106. # Note: future plan is to change this signature over a few releases:
  107. # shapely 2.0:
  108. # buffer(geometry, distance, quad_segs=8, ...)
  109. # shapely 2.1: shows deprecation warning about positional 'quad_segs', etc.
  110. # same signature as 2.0
  111. # shapely 2.2(?): enforce keyword-only arguments after 'distance'
  112. # buffer(geometry, distance, *, quad_segs=8, ...)
  113. @deprecate_positional(
  114. ["quad_segs", "cap_style", "join_style", "mitre_limit", "single_sided"],
  115. category=DeprecationWarning,
  116. )
  117. @multithreading_enabled
  118. def buffer(
  119. geometry,
  120. distance,
  121. quad_segs=8,
  122. cap_style="round",
  123. join_style="round",
  124. mitre_limit=5.0,
  125. single_sided=False,
  126. **kwargs,
  127. ):
  128. """Compute the buffer of a geometry for positive and negative buffer distance.
  129. The buffer of a geometry is defined as the Minkowski sum (or difference,
  130. for negative distance) of the geometry with a circle with radius equal
  131. to the absolute value of the buffer distance.
  132. The buffer operation always returns a polygonal result. The negative
  133. or zero-distance buffer of lines and points is always empty.
  134. Parameters
  135. ----------
  136. geometry : Geometry or array_like
  137. Geometry or geometries for which to compute the buffer.
  138. distance : float or array_like
  139. Specifies the circle radius in the Minkowski sum (or difference).
  140. quad_segs : int, default 8
  141. Specifies the number of linear segments in a quarter circle in the
  142. approximation of circular arcs.
  143. cap_style : shapely.BufferCapStyle or {'round', 'square', 'flat'}, default 'round'
  144. Specifies the shape of buffered line endings. BufferCapStyle.round ('round')
  145. results in circular line endings (see ``quad_segs``). Both BufferCapStyle.square
  146. ('square') and BufferCapStyle.flat ('flat') result in rectangular line endings,
  147. only BufferCapStyle.flat ('flat') will end at the original vertex,
  148. while BufferCapStyle.square ('square') involves adding the buffer width.
  149. join_style : shapely.BufferJoinStyle or {'round', 'mitre', 'bevel'}, default 'round'
  150. Specifies the shape of buffered line midpoints. BufferJoinStyle.round ('round')
  151. results in rounded shapes. BufferJoinStyle.bevel ('bevel') results in a beveled
  152. edge that touches the original vertex. BufferJoinStyle.mitre ('mitre') results
  153. in a single vertex that is beveled depending on the ``mitre_limit`` parameter.
  154. mitre_limit : float, default 5.0
  155. Crops of 'mitre'-style joins if the point is displaced from the
  156. buffered vertex by more than this limit.
  157. single_sided : bool, default False
  158. Only buffer at one side of the geometry.
  159. **kwargs
  160. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  161. Notes
  162. -----
  163. .. deprecated:: 2.1.0
  164. A deprecation warning is shown if ``quad_segs``, ``cap_style``,
  165. ``join_style``, ``mitre_limit`` or ``single_sided`` are
  166. specified as positional arguments. In a future release, these will
  167. need to be specified as keyword arguments.
  168. Examples
  169. --------
  170. >>> import shapely
  171. >>> from shapely import LineString, Point, Polygon, BufferCapStyle, BufferJoinStyle
  172. >>> shapely.buffer(Point(10, 10), 2, quad_segs=1)
  173. <POLYGON ((12 10, 10 8, 8 10, 10 12, 12 10))>
  174. >>> shapely.buffer(Point(10, 10), 2, quad_segs=2)
  175. <POLYGON ((12 10, 11.414 8.586, 10 8, 8.586 8.586, 8 10, 8.5...>
  176. >>> shapely.buffer(Point(10, 10), -2, quad_segs=1)
  177. <POLYGON EMPTY>
  178. >>> line = LineString([(10, 10), (20, 10)])
  179. >>> shapely.buffer(line, 2, cap_style="square")
  180. <POLYGON ((20 12, 22 12, 22 8, 10 8, 8 8, 8 12, 20 12))>
  181. >>> shapely.buffer(line, 2, cap_style="flat")
  182. <POLYGON ((20 12, 20 8, 10 8, 10 12, 20 12))>
  183. >>> shapely.buffer(line, 2, single_sided=True, cap_style="flat")
  184. <POLYGON ((20 10, 10 10, 10 12, 20 12, 20 10))>
  185. >>> line2 = LineString([(10, 10), (20, 10), (20, 20)])
  186. >>> shapely.buffer(line2, 2, cap_style="flat", join_style="bevel")
  187. <POLYGON ((18 12, 18 20, 22 20, 22 10, 20 8, 10 8, 10 12, 18 12))>
  188. >>> shapely.buffer(line2, 2, cap_style="flat", join_style="mitre")
  189. <POLYGON ((18 12, 18 20, 22 20, 22 8, 10 8, 10 12, 18 12))>
  190. >>> shapely.buffer(line2, 2, cap_style="flat", join_style="mitre", mitre_limit=1)
  191. <POLYGON ((18 12, 18 20, 22 20, 22 9.172, 20.828 8, 10 8, 10 12, 18 12))>
  192. >>> square = Polygon([(0, 0), (10, 0), (10, 10), (0, 10), (0, 0)])
  193. >>> shapely.buffer(square, 2, join_style="mitre")
  194. <POLYGON ((-2 -2, -2 12, 12 12, 12 -2, -2 -2))>
  195. >>> shapely.buffer(square, -2, join_style="mitre")
  196. <POLYGON ((2 2, 2 8, 8 8, 8 2, 2 2))>
  197. >>> shapely.buffer(square, -5, join_style="mitre")
  198. <POLYGON EMPTY>
  199. >>> shapely.buffer(line, float("nan")) is None
  200. True
  201. """
  202. if isinstance(cap_style, str):
  203. cap_style = BufferCapStyle.get_value(cap_style)
  204. if isinstance(join_style, str):
  205. join_style = BufferJoinStyle.get_value(join_style)
  206. if not np.isscalar(quad_segs):
  207. raise TypeError("quad_segs only accepts scalar values")
  208. if not np.isscalar(cap_style):
  209. raise TypeError("cap_style only accepts scalar values")
  210. if not np.isscalar(join_style):
  211. raise TypeError("join_style only accepts scalar values")
  212. if not np.isscalar(mitre_limit):
  213. raise TypeError("mitre_limit only accepts scalar values")
  214. if not np.isscalar(single_sided):
  215. raise TypeError("single_sided only accepts scalar values")
  216. return lib.buffer(
  217. geometry,
  218. distance,
  219. np.intc(quad_segs),
  220. np.intc(cap_style),
  221. np.intc(join_style),
  222. mitre_limit,
  223. np.bool_(single_sided),
  224. **kwargs,
  225. )
  226. # Note: future plan is to change this signature over a few releases:
  227. # shapely 2.0:
  228. # offset_curve(geometry, distance, quad_segs=8, ...)
  229. # shapely 2.1: shows deprecation warning about positional 'quad_segs', etc.
  230. # same signature as 2.0
  231. # shapely 2.2(?): enforce keyword-only arguments after 'distance'
  232. # offset_curve(geometry, distance, *, quad_segs=8, ...)
  233. @deprecate_positional(
  234. ["quad_segs", "join_style", "mitre_limit"], category=DeprecationWarning
  235. )
  236. @multithreading_enabled
  237. def offset_curve(
  238. geometry, distance, quad_segs=8, join_style="round", mitre_limit=5.0, **kwargs
  239. ):
  240. """Return a (Multi)LineString at a distance from the object.
  241. For positive distance the offset will be at the left side of the input
  242. line. For a negative distance it will be at the right side. In general,
  243. this function tries to preserve the direction of the input.
  244. Note: the behaviour regarding orientation of the resulting line depends
  245. on the GEOS version. With GEOS < 3.11, the line retains the same
  246. direction for a left offset (positive distance) or has opposite direction
  247. for a right offset (negative distance), and this behaviour was documented
  248. as such in previous Shapely versions. Starting with GEOS 3.11, the
  249. function tries to preserve the orientation of the original line.
  250. Parameters
  251. ----------
  252. geometry : Geometry or array_like
  253. Geometry or geometries for which to compute the offset.
  254. distance : float or array_like
  255. Specifies the offset distance from the input geometry. Negative
  256. for right side offset, positive for left side offset.
  257. quad_segs : int, default 8
  258. Specifies the number of linear segments in a quarter circle in the
  259. approximation of circular arcs.
  260. join_style : {'round', 'bevel', 'mitre'}, default 'round'
  261. Specifies the shape of outside corners. 'round' results in
  262. rounded shapes. 'bevel' results in a beveled edge that touches the
  263. original vertex. 'mitre' results in a single vertex that is beveled
  264. depending on the ``mitre_limit`` parameter.
  265. mitre_limit : float, default 5.0
  266. Crops of 'mitre'-style joins if the point is displaced from the
  267. buffered vertex by more than this limit.
  268. **kwargs
  269. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  270. Notes
  271. -----
  272. .. deprecated:: 2.1.0
  273. A deprecation warning is shown if ``quad_segs``, ``join_style`` or
  274. ``mitre_limit`` are specified as positional arguments. In a future
  275. release, these will need to be specified as keyword arguments.
  276. Examples
  277. --------
  278. >>> import shapely
  279. >>> from shapely import LineString
  280. >>> line = LineString([(0, 0), (0, 2)])
  281. >>> shapely.offset_curve(line, 2)
  282. <LINESTRING (-2 0, -2 2)>
  283. >>> shapely.offset_curve(line, -2)
  284. <LINESTRING (2 0, 2 2)>
  285. """
  286. if isinstance(join_style, str):
  287. join_style = BufferJoinStyle.get_value(join_style)
  288. if not np.isscalar(quad_segs):
  289. raise TypeError("quad_segs only accepts scalar values")
  290. if not np.isscalar(join_style):
  291. raise TypeError("join_style only accepts scalar values")
  292. if not np.isscalar(mitre_limit):
  293. raise TypeError("mitre_limit only accepts scalar values")
  294. return lib.offset_curve(
  295. geometry,
  296. distance,
  297. np.intc(quad_segs),
  298. np.intc(join_style),
  299. np.double(mitre_limit),
  300. **kwargs,
  301. )
  302. @multithreading_enabled
  303. def centroid(geometry, **kwargs):
  304. """Compute the geometric center (center-of-mass) of a geometry.
  305. For multipoints this is computed as the mean of the input coordinates.
  306. For multilinestrings the centroid is weighted by the length of each
  307. line segment. For multipolygons the centroid is weighted by the area of
  308. each polygon.
  309. Parameters
  310. ----------
  311. geometry : Geometry or array_like
  312. Geometry or geometries for which to compute the centroid.
  313. **kwargs
  314. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  315. Examples
  316. --------
  317. >>> import shapely
  318. >>> from shapely import LineString, MultiPoint, Polygon
  319. >>> shapely.centroid(Polygon([(0, 0), (10, 0), (10, 10), (0, 10), (0, 0)]))
  320. <POINT (5 5)>
  321. >>> shapely.centroid(LineString([(0, 0), (2, 2), (10, 10)]))
  322. <POINT (5 5)>
  323. >>> shapely.centroid(MultiPoint([(0, 0), (10, 10)]))
  324. <POINT (5 5)>
  325. >>> shapely.centroid(Polygon())
  326. <POINT EMPTY>
  327. """
  328. return lib.centroid(geometry, **kwargs)
  329. @multithreading_enabled
  330. def clip_by_rect(geometry, xmin, ymin, xmax, ymax, **kwargs):
  331. """Return the portion of a geometry within a rectangle.
  332. The geometry is clipped in a fast but possibly dirty way. The output is
  333. not guaranteed to be valid. No exceptions will be raised for topological
  334. errors.
  335. Note: empty geometries or geometries that do not overlap with the
  336. specified bounds will result in GEOMETRYCOLLECTION EMPTY.
  337. Parameters
  338. ----------
  339. geometry : Geometry or array_like
  340. The geometry to be clipped.
  341. xmin : float
  342. Minimum x value of the rectangle.
  343. ymin : float
  344. Minimum y value of the rectangle.
  345. xmax : float
  346. Maximum x value of the rectangle.
  347. ymax : float
  348. Maximum y value of the rectangle.
  349. **kwargs
  350. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  351. Examples
  352. --------
  353. >>> import shapely
  354. >>> from shapely import LineString, Polygon
  355. >>> line = LineString([(0, 0), (10, 10)])
  356. >>> shapely.clip_by_rect(line, 0., 0., 1., 1.)
  357. <LINESTRING (0 0, 1 1)>
  358. >>> polygon = Polygon([(0, 0), (10, 0), (10, 10), (0, 10), (0, 0)])
  359. >>> shapely.clip_by_rect(polygon, 0., 0., 1., 1.)
  360. <POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))>
  361. """
  362. if not all(np.isscalar(val) for val in [xmin, ymin, xmax, ymax]):
  363. raise TypeError("xmin/ymin/xmax/ymax only accepts scalar values")
  364. return lib.clip_by_rect(
  365. geometry,
  366. np.double(xmin),
  367. np.double(ymin),
  368. np.double(xmax),
  369. np.double(ymax),
  370. **kwargs,
  371. )
  372. @requires_geos("3.11.0")
  373. @multithreading_enabled
  374. def concave_hull(geometry, ratio=0.0, allow_holes=False, **kwargs):
  375. """Compute a concave geometry that encloses an input geometry.
  376. Parameters
  377. ----------
  378. geometry : Geometry or array_like
  379. Geometry or geometries for which to compute the concave hull.
  380. ratio : float, default 0.0
  381. Number in the range [0, 1]. Higher numbers will include fewer vertices
  382. in the hull.
  383. allow_holes : bool, default False
  384. If set to True, the concave hull may have holes.
  385. **kwargs
  386. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  387. Examples
  388. --------
  389. >>> import shapely
  390. >>> from shapely import MultiPoint, Polygon
  391. >>> multi_point = MultiPoint([(0, 0), (0, 3), (1, 1), (3, 0), (3, 3)])
  392. >>> shapely.concave_hull(multi_point, ratio=0.1)
  393. <POLYGON ((0 0, 0 3, 1 1, 3 3, 3 0, 0 0))>
  394. >>> shapely.concave_hull(multi_point, ratio=1.0)
  395. <POLYGON ((0 0, 0 3, 3 3, 3 0, 0 0))>
  396. >>> shapely.concave_hull(Polygon())
  397. <POLYGON EMPTY>
  398. """
  399. if not np.isscalar(ratio):
  400. raise TypeError("ratio must be scalar")
  401. if not np.isscalar(allow_holes):
  402. raise TypeError("allow_holes must be scalar")
  403. return lib.concave_hull(geometry, np.double(ratio), np.bool_(allow_holes), **kwargs)
  404. @multithreading_enabled
  405. def convex_hull(geometry, **kwargs):
  406. """Compute the minimum convex geometry that encloses an input geometry.
  407. Parameters
  408. ----------
  409. geometry : Geometry or array_like
  410. Geometry or geometries for which to compute the convex hull.
  411. **kwargs
  412. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  413. Examples
  414. --------
  415. >>> import shapely
  416. >>> from shapely import MultiPoint, Polygon
  417. >>> shapely.convex_hull(MultiPoint([(0, 0), (10, 0), (10, 10)]))
  418. <POLYGON ((0 0, 10 10, 10 0, 0 0))>
  419. >>> shapely.convex_hull(Polygon())
  420. <GEOMETRYCOLLECTION EMPTY>
  421. """
  422. return lib.convex_hull(geometry, **kwargs)
  423. @multithreading_enabled
  424. def delaunay_triangles(geometry, tolerance=0.0, only_edges=False, **kwargs):
  425. """Compute a Delaunay triangulation around the vertices of an input geometry.
  426. The output is a geometrycollection containing polygons (default)
  427. or linestrings (see ``only_edges``). Returns an empty geometry for input
  428. geometries that contain less than 3 vertices.
  429. Parameters
  430. ----------
  431. geometry : Geometry or array_like
  432. Geometry or geometries for which to compute the Delaunay triangulation.
  433. tolerance : float or array_like, default 0.0
  434. Snap input vertices together if their distance is less than this value.
  435. only_edges : bool or array_like, default False
  436. If set to True, the triangulation will return a collection of
  437. linestrings instead of polygons.
  438. **kwargs
  439. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  440. Returns
  441. -------
  442. GeometryCollection or array of GeometryCollections
  443. See Also
  444. --------
  445. constrained_delaunay_triangles
  446. Examples
  447. --------
  448. >>> import shapely
  449. >>> from shapely import GeometryCollection, LineString, MultiPoint, Polygon
  450. >>> points = MultiPoint([(50, 30), (60, 30), (100, 100)])
  451. >>> shapely.delaunay_triangles(points).normalize()
  452. <GEOMETRYCOLLECTION (POLYGON ((50 30, 100 100, 60 30, 50 30)))>
  453. >>> shapely.delaunay_triangles(points, only_edges=True)
  454. <MULTILINESTRING ((50 30, 100 100), (50 30, 60 30), ...>
  455. >>> shapely.delaunay_triangles(
  456. ... MultiPoint([(50, 30), (51, 30), (60, 30), (100, 100)]),
  457. ... tolerance=2
  458. ... ).normalize()
  459. <GEOMETRYCOLLECTION (POLYGON ((50 30, 100 100, 60 30, 50 30)))>
  460. >>> shapely.delaunay_triangles(Polygon([(50, 30), (60, 30), (100, 100), (50, 30)]))\
  461. .normalize()
  462. <GEOMETRYCOLLECTION (POLYGON ((50 30, 100 100, 60 30, 50 30)))>
  463. >>> shapely.delaunay_triangles(LineString([(50, 30), (60, 30), (100, 100)]))\
  464. .normalize()
  465. <GEOMETRYCOLLECTION (POLYGON ((50 30, 100 100, 60 30, 50 30)))>
  466. >>> shapely.delaunay_triangles(GeometryCollection([]))
  467. <GEOMETRYCOLLECTION EMPTY>
  468. """
  469. return lib.delaunay_triangles(geometry, tolerance, only_edges, **kwargs)
  470. @requires_geos("3.10.0")
  471. @multithreading_enabled
  472. def constrained_delaunay_triangles(geometry, **kwargs):
  473. """Compute the constrained Delaunay triangulation of polygons.
  474. A constrained Delaunay triangulation requires the edges of the input
  475. polygon(s) to be in the set of resulting triangle edges. An unconstrained
  476. delaunay triangulation only triangulates based on the vertices, hence
  477. triangle edges could cross polygon boundaries.
  478. .. versionadded:: 2.1.0
  479. Parameters
  480. ----------
  481. geometry : Geometry or array_like
  482. **kwargs
  483. For other keyword-only arguments, see the
  484. `NumPy ufunc docs <https://numpy.org/doc/stable/reference/ufuncs.html#ufuncs-kwargs>`_.
  485. Returns
  486. -------
  487. GeometryCollection or array of GeometryCollections
  488. * GeometryCollection of polygons, given polygonal input
  489. * Empty GeometryCollection, given non-polygonal input
  490. See Also
  491. --------
  492. delaunay_triangles
  493. Examples
  494. --------
  495. >>> import shapely
  496. >>> from shapely import MultiPoint, MultiPolygon, Polygon
  497. >>> shapely.constrained_delaunay_triangles(Polygon([(10, 10), (20, 40), (90, 90), (90, 10), (10, 10)]))
  498. <GEOMETRYCOLLECTION (POLYGON ((90 10, 20 40, 90 90, 90 10)), POLYGON ((20 40...>
  499. >>> shapely.constrained_delaunay_triangles(Polygon())
  500. <GEOMETRYCOLLECTION EMPTY>
  501. >>> 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)))]))
  502. <GEOMETRYCOLLECTION (POLYGON ((50 30, 100 100, 60 30, 50 30)), POLYGON ((90 ...>
  503. >>> shapely.constrained_delaunay_triangles(MultiPolygon())
  504. <GEOMETRYCOLLECTION EMPTY>
  505. >>> shapely.constrained_delaunay_triangles(MultiPoint([(50, 30), (51, 30), (60, 30), (100, 100)]))
  506. <GEOMETRYCOLLECTION EMPTY>
  507. """ # noqa: E501
  508. return lib.constrained_delaunay_triangles(geometry, **kwargs)
  509. @multithreading_enabled
  510. def envelope(geometry, **kwargs):
  511. """Compute the minimum bounding box that encloses an input geometry.
  512. Parameters
  513. ----------
  514. geometry : Geometry or array_like
  515. Geometry or geometries for which to compute the envelope.
  516. **kwargs
  517. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  518. Examples
  519. --------
  520. >>> import shapely
  521. >>> from shapely import GeometryCollection, LineString, MultiPoint, Point
  522. >>> shapely.envelope(LineString([(0, 0), (10, 10)]))
  523. <POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))>
  524. >>> shapely.envelope(MultiPoint([(0, 0), (10, 10)]))
  525. <POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))>
  526. >>> shapely.envelope(Point(0, 0))
  527. <POINT (0 0)>
  528. >>> shapely.envelope(GeometryCollection([]))
  529. <POINT EMPTY>
  530. """
  531. return lib.envelope(geometry, **kwargs)
  532. @multithreading_enabled
  533. def extract_unique_points(geometry, **kwargs):
  534. """Return all distinct vertices of an input geometry as a multipoint.
  535. Note that only 2 dimensions of the vertices are considered when testing
  536. for equality.
  537. Parameters
  538. ----------
  539. geometry : Geometry or array_like
  540. Geometry or geometries for which to extract unique points.
  541. **kwargs
  542. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  543. Examples
  544. --------
  545. >>> import shapely
  546. >>> from shapely import LineString, MultiPoint, Point, Polygon
  547. >>> shapely.extract_unique_points(Point(0, 0))
  548. <MULTIPOINT ((0 0))>
  549. >>> shapely.extract_unique_points(LineString([(0, 0), (1, 1), (1, 1)]))
  550. <MULTIPOINT ((0 0), (1 1))>
  551. >>> shapely.extract_unique_points(Polygon([(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)]))
  552. <MULTIPOINT ((0 0), (1 0), (1 1), (0 1))>
  553. >>> shapely.extract_unique_points(MultiPoint([(0, 0), (1, 1), (0, 0)]))
  554. <MULTIPOINT ((0 0), (1 1))>
  555. >>> shapely.extract_unique_points(LineString())
  556. <MULTIPOINT EMPTY>
  557. """
  558. return lib.extract_unique_points(geometry, **kwargs)
  559. @multithreading_enabled
  560. def build_area(geometry, **kwargs):
  561. """Create an areal geometry formed by the constituent linework of given geometry.
  562. Equivalent of the PostGIS ST_BuildArea() function.
  563. Parameters
  564. ----------
  565. geometry : Geometry or array_like
  566. Geometry or geometries for which to build an area.
  567. **kwargs
  568. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  569. Examples
  570. --------
  571. >>> import shapely
  572. >>> from shapely import GeometryCollection, Polygon
  573. >>> polygon1 = Polygon([(0, 0), (3, 0), (3, 3), (0, 3), (0, 0)])
  574. >>> polygon2 = Polygon([(1, 1), (1, 2), (2, 2), (1, 1)])
  575. >>> shapely.build_area(GeometryCollection([polygon1, polygon2]))
  576. <POLYGON ((0 0, 0 3, 3 3, 3 0, 0 0), (1 1, 2 2, 1 2, 1 1))>
  577. """
  578. return lib.build_area(geometry, **kwargs)
  579. @multithreading_enabled
  580. def make_valid(geometry, *, method="linework", keep_collapsed=True, **kwargs):
  581. """Repair invalid geometries.
  582. Two ``methods`` are available:
  583. * the 'linework' algorithm tries to preserve every edge and vertex in the input. It
  584. combines all rings into a set of noded lines and then extracts valid polygons from
  585. that linework. An alternating even-odd strategy is used to assign areas as
  586. interior or exterior. A disadvantage is that for some relatively simple invalid
  587. geometries this produces rather complex results.
  588. * the 'structure' algorithm tries to reason from the structure of the input to find
  589. the 'correct' repair: exterior rings bound area, interior holes exclude area.
  590. It first makes all rings valid, then shells are merged and holes are subtracted
  591. from the shells to generate valid result. It assumes that holes and shells are
  592. correctly categorized in the input geometry.
  593. Example:
  594. .. plot:: code/make_valid_methods.py
  595. When using ``make_valid`` on a Polygon, the result can be a GeometryCollection. For
  596. this example this is the case when the 'linework' ``method`` is used. LineStrings in
  597. the result are drawn in red.
  598. Parameters
  599. ----------
  600. geometry : Geometry or array_like
  601. Geometry or geometries to repair.
  602. method : {'linework', 'structure'}, default 'linework'
  603. Algorithm to use when repairing geometry. 'structure'
  604. requires GEOS >= 3.10.
  605. .. versionadded:: 2.1.0
  606. keep_collapsed : bool, default True
  607. For the 'structure' method, True will keep components that have collapsed into a
  608. lower dimensionality. For example, a ring collapsing to a line, or a line
  609. collapsing to a point. Must be True for the 'linework' method.
  610. .. versionadded:: 2.1.0
  611. **kwargs
  612. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  613. Examples
  614. --------
  615. >>> import shapely
  616. >>> from shapely import Polygon
  617. >>> polygon = Polygon([(0, 0), (1, 1), (1, 2), (1, 1), (0, 0)])
  618. >>> shapely.is_valid(polygon)
  619. False
  620. >>> shapely.make_valid(polygon)
  621. <MULTILINESTRING ((0 0, 1 1), (1 1, 1 2))>
  622. >>> shapely.make_valid(polygon, method="structure", keep_collapsed=True)
  623. <LINESTRING (0 0, 1 1, 1 2, 1 1, 0 0)>
  624. >>> shapely.make_valid(polygon, method="structure", keep_collapsed=False)
  625. <POLYGON EMPTY>
  626. """
  627. if not np.isscalar(method):
  628. raise TypeError("method only accepts scalar values")
  629. if not np.isscalar(keep_collapsed):
  630. raise TypeError("keep_collapsed only accepts scalar values")
  631. if method == "linework":
  632. if keep_collapsed is False:
  633. raise ValueError(
  634. "The 'linework' method does not support 'keep_collapsed=False'"
  635. )
  636. # The make_valid code can be removed once support for GEOS < 3.10 is dropped.
  637. # In GEOS >= 3.10, make_valid just calls make_valid_with_params with
  638. # method="linework" and keep_collapsed=True, so there is no advantage to keep
  639. # both code paths in shapely on long term.
  640. return lib.make_valid(geometry, **kwargs)
  641. elif method == "structure":
  642. if lib.geos_version < (3, 10, 0):
  643. raise ValueError(
  644. "The 'structure' method is only available in GEOS >= 3.10.0"
  645. )
  646. return lib.make_valid_with_params(
  647. geometry, np.intc(1), np.bool_(keep_collapsed), **kwargs
  648. )
  649. else:
  650. raise ValueError(f"Unknown method: {method}")
  651. @multithreading_enabled
  652. def minimum_clearance_line(geometry, **kwargs):
  653. """Return a LineString whose endpoints define the minimum clearance.
  654. A geometry's "minimum clearance" is the smallest distance by which a vertex
  655. of the geometry could be moved to produce an invalid geometry.
  656. If the geometry has no minimum clearance, an empty LineString will be
  657. returned.
  658. .. versionadded:: 2.1.0
  659. Parameters
  660. ----------
  661. geometry : Geometry or array_like
  662. Geometry or geometries to determine the minimum clearance line for.
  663. **kwargs
  664. For other keyword-only arguments, see the
  665. `NumPy ufunc docs <https://numpy.org/doc/stable/reference/ufuncs.html#ufuncs-kwargs>`_.
  666. Examples
  667. --------
  668. >>> import shapely
  669. >>> from shapely import Polygon
  670. >>> poly = Polygon([(0, 0), (10, 0), (10, 10), (5, 5), (0, 10), (0, 0)])
  671. >>> shapely.minimum_clearance_line(poly)
  672. <LINESTRING (5 5, 5 0)>
  673. See Also
  674. --------
  675. minimum_clearance
  676. """
  677. return lib.minimum_clearance_line(geometry, **kwargs)
  678. @multithreading_enabled
  679. def normalize(geometry, **kwargs):
  680. """Convert Geometry to strict normal form (or canonical form).
  681. In :ref:`strict canonical form <canonical-form>`, the coordinates, rings of
  682. a polygon and parts of multi geometries are ordered consistently. Typically
  683. useful for testing purposes (for example in combination with
  684. ``equals_exact``).
  685. Parameters
  686. ----------
  687. geometry : Geometry or array_like
  688. Geometry or geometries to normalize.
  689. **kwargs
  690. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  691. Examples
  692. --------
  693. >>> import shapely
  694. >>> from shapely import MultiLineString
  695. >>> line = MultiLineString([[(0, 0), (1, 1)], [(2, 2), (3, 3)]])
  696. >>> shapely.normalize(line)
  697. <MULTILINESTRING ((2 2, 3 3), (0 0, 1 1))>
  698. """
  699. return lib.normalize(geometry, **kwargs)
  700. @multithreading_enabled
  701. def point_on_surface(geometry, **kwargs):
  702. """Return a point that intersects an input geometry.
  703. Parameters
  704. ----------
  705. geometry : Geometry or array_like
  706. Geometry or geometries for which to compute a point on the surface.
  707. **kwargs
  708. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  709. Examples
  710. --------
  711. >>> import shapely
  712. >>> from shapely import LineString, MultiPoint, Polygon
  713. >>> shapely.point_on_surface(Polygon([(0, 0), (10, 0), (10, 10), (0, 10), (0, 0)]))
  714. <POINT (5 5)>
  715. >>> shapely.point_on_surface(LineString([(0, 0), (2, 2), (10, 10)]))
  716. <POINT (2 2)>
  717. >>> shapely.point_on_surface(MultiPoint([(0, 0), (10, 10)]))
  718. <POINT (0 0)>
  719. >>> shapely.point_on_surface(Polygon())
  720. <POINT EMPTY>
  721. """
  722. return lib.point_on_surface(geometry, **kwargs)
  723. @multithreading_enabled
  724. def node(geometry, **kwargs):
  725. """Return the fully noded version of the linear input as MultiLineString.
  726. Given a linear input geometry, this function returns a new MultiLineString
  727. in which no lines cross each other but only touch at and points. To
  728. obtain this, all intersections between segments are computed and added
  729. to the segments, and duplicate segments are removed.
  730. Non-linear input (points) will result in an empty MultiLineString.
  731. This function can for example be used to create a fully-noded linework
  732. suitable to passed as input to ``polygonize``.
  733. Parameters
  734. ----------
  735. geometry : Geometry or array_like
  736. Geometry or geometries for which to compute the noded version.
  737. **kwargs
  738. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  739. Examples
  740. --------
  741. >>> import shapely
  742. >>> from shapely import LineString, Point
  743. >>> line = LineString([(0, 0), (1,1), (0, 1), (1, 0)])
  744. >>> shapely.node(line)
  745. <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))>
  746. >>> shapely.node(Point(1, 1))
  747. <MULTILINESTRING EMPTY>
  748. """
  749. return lib.node(geometry, **kwargs)
  750. def polygonize(geometries, **kwargs):
  751. """Create polygons formed from the linework of a set of Geometries.
  752. Polygonizes an array of Geometries that contain linework which
  753. represents the edges of a planar graph. Any type of Geometry may be
  754. provided as input; only the constituent lines and rings will be used to
  755. create the output polygons.
  756. Lines or rings that when combined do not completely close a polygon
  757. will result in an empty GeometryCollection. Duplicate segments are
  758. ignored.
  759. This function returns the polygons within a GeometryCollection.
  760. Individual Polygons can be obtained using ``get_geometry`` to get
  761. a single polygon or ``get_parts`` to get an array of polygons.
  762. MultiPolygons can be constructed from the output using
  763. ``shapely.multipolygons(shapely.get_parts(shapely.polygonize(geometries)))``.
  764. Parameters
  765. ----------
  766. geometries : array_like
  767. An array of geometries.
  768. axis : int
  769. Axis along which the geometries are polygonized.
  770. The default is to perform a reduction over the last dimension
  771. of the input array. A 1D array results in a scalar geometry.
  772. **kwargs
  773. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  774. Returns
  775. -------
  776. GeometryCollection or array of GeometryCollections
  777. See Also
  778. --------
  779. get_parts, get_geometry
  780. polygonize_full
  781. node
  782. Examples
  783. --------
  784. >>> import shapely
  785. >>> from shapely import LineString
  786. >>> lines = [
  787. ... LineString([(0, 0), (1, 1)]),
  788. ... LineString([(0, 0), (0, 1)]),
  789. ... LineString([(0, 1), (1, 1)])
  790. ... ]
  791. >>> shapely.polygonize(lines)
  792. <GEOMETRYCOLLECTION (POLYGON ((1 1, 0 0, 0 1, 1 1)))>
  793. """
  794. return lib.polygonize(geometries, **kwargs)
  795. def polygonize_full(geometries, **kwargs):
  796. """Create polygons formed from the linework of a set of Geometries.
  797. All extra outputs are returned as well.
  798. Polygonizes an array of Geometries that contain linework which
  799. represents the edges of a planar graph. Any type of Geometry may be
  800. provided as input; only the constituent lines and rings will be used to
  801. create the output polygons.
  802. This function performs the same polygonization as ``polygonize`` but does
  803. not only return the polygonal result but all extra outputs as well. The
  804. return value consists of 4 elements:
  805. * The polygonal valid output
  806. * **Cut edges**: edges connected on both ends but not part of polygonal output
  807. * **dangles**: edges connected on one end but not part of polygonal output
  808. * **invalid rings**: polygons formed but which are not valid
  809. This function returns the geometries within GeometryCollections.
  810. Individual geometries can be obtained using ``get_geometry`` to get
  811. a single geometry or ``get_parts`` to get an array of geometries.
  812. Parameters
  813. ----------
  814. geometries : array_like
  815. An array of geometries.
  816. axis : int
  817. Axis along which the geometries are polygonized.
  818. The default is to perform a reduction over the last dimension
  819. of the input array. A 1D array results in a scalar geometry.
  820. **kwargs
  821. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  822. Returns
  823. -------
  824. (polygons, cuts, dangles, invalid)
  825. tuple of 4 GeometryCollections or arrays of GeometryCollections
  826. See Also
  827. --------
  828. polygonize
  829. Examples
  830. --------
  831. >>> import shapely
  832. >>> from shapely import LineString
  833. >>> lines = [
  834. ... LineString([(0, 0), (1, 1)]),
  835. ... LineString([(0, 0), (0, 1), (1, 1)]),
  836. ... LineString([(0, 1), (1, 1)])
  837. ... ]
  838. >>> shapely.polygonize_full(lines)
  839. (<GEOMETRYCOLLECTION (POLYGON ((1 1, 0 0, 0 1, 1 1)))>,
  840. <GEOMETRYCOLLECTION EMPTY>,
  841. <GEOMETRYCOLLECTION (LINESTRING (0 1, 1 1))>,
  842. <GEOMETRYCOLLECTION EMPTY>)
  843. """
  844. return lib.polygonize_full(geometries, **kwargs)
  845. @requires_geos("3.11.0")
  846. @multithreading_enabled
  847. def remove_repeated_points(geometry, tolerance=0.0, **kwargs):
  848. """Return a copy of a Geometry with repeated points removed.
  849. From the start of the coordinate sequence, each next point within the
  850. tolerance is removed.
  851. Removing repeated points with a non-zero tolerance may result in an invalid
  852. geometry being returned.
  853. Parameters
  854. ----------
  855. geometry : Geometry or array_like
  856. Geometry or geometries to remove repeated points from.
  857. tolerance : float or array_like, default=0.0
  858. Use 0.0 to remove only exactly repeated points.
  859. **kwargs
  860. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  861. Examples
  862. --------
  863. >>> import shapely
  864. >>> from shapely import LineString, Polygon
  865. >>> shapely.remove_repeated_points(LineString([(0,0), (0,0), (1,0)]), tolerance=0)
  866. <LINESTRING (0 0, 1 0)>
  867. >>> shapely.remove_repeated_points(Polygon([(0, 0), (0, .5), (0, 1), (.5, 1), (0,0)]), tolerance=.5)
  868. <POLYGON ((0 0, 0 1, 0 0))>
  869. """ # noqa: E501
  870. return lib.remove_repeated_points(geometry, tolerance, **kwargs)
  871. @multithreading_enabled
  872. def reverse(geometry, **kwargs):
  873. """Return a copy of a Geometry with the order of coordinates reversed.
  874. If a Geometry is a polygon with interior rings, the interior rings are also
  875. reversed.
  876. Points are unchanged. None is returned where Geometry is None.
  877. Parameters
  878. ----------
  879. geometry : Geometry or array_like
  880. Geometry or geometries to reverse the coordinates of.
  881. **kwargs
  882. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  883. See Also
  884. --------
  885. is_ccw : Checks if a Geometry is clockwise.
  886. Examples
  887. --------
  888. >>> import shapely
  889. >>> from shapely import LineString, Polygon
  890. >>> shapely.reverse(LineString([(0, 0), (1, 2)]))
  891. <LINESTRING (1 2, 0 0)>
  892. >>> shapely.reverse(Polygon([(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)]))
  893. <POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))>
  894. >>> shapely.reverse(None) is None
  895. True
  896. """
  897. return lib.reverse(geometry, **kwargs)
  898. @requires_geos("3.10.0")
  899. @multithreading_enabled
  900. def segmentize(geometry, max_segment_length, **kwargs):
  901. """Add vertices to line segments based on maximum segment length.
  902. Additional vertices will be added to every line segment in an input geometry
  903. so that segments are no longer than the provided maximum segment length. New
  904. vertices will evenly subdivide each segment.
  905. Only linear components of input geometries are densified; other geometries
  906. are returned unmodified.
  907. Parameters
  908. ----------
  909. geometry : Geometry or array_like
  910. Geometry or geometries to segmentize.
  911. max_segment_length : float or array_like
  912. Additional vertices will be added so that all line segments are no
  913. longer than this value. Must be greater than 0.
  914. **kwargs
  915. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  916. Examples
  917. --------
  918. >>> import shapely
  919. >>> from shapely import LineString, Polygon
  920. >>> line = LineString([(0, 0), (0, 10)])
  921. >>> shapely.segmentize(line, max_segment_length=5)
  922. <LINESTRING (0 0, 0 5, 0 10)>
  923. >>> polygon = Polygon([(0, 0), (10, 0), (10, 10), (0, 10), (0, 0)])
  924. >>> shapely.segmentize(polygon, max_segment_length=5)
  925. <POLYGON ((0 0, 5 0, 10 0, 10 5, 10 10, 5 10, 0 10, 0 5, 0 0))>
  926. >>> shapely.segmentize(None, max_segment_length=5) is None
  927. True
  928. """
  929. return lib.segmentize(geometry, max_segment_length, **kwargs)
  930. # Note: future plan is to change this signature over a few releases:
  931. # shapely 2.0:
  932. # simplify(geometry, tolerance, preserve_topology=True, **kwargs)
  933. # shapely 2.1: shows deprecation warning about positional 'preserve_topology'
  934. # same signature as 2.0
  935. # shapely 2.2(?): enforce keyword-only arguments after 'tolerance'
  936. # simplify(geometry, tolerance, *, preserve_topology=True, **kwargs)
  937. @deprecate_positional(["preserve_topology"], category=DeprecationWarning)
  938. @multithreading_enabled
  939. def simplify(geometry, tolerance, preserve_topology=True, **kwargs):
  940. """Return a simplified version of an input geometry.
  941. The Douglas-Peucker algorithm is used to simplify the geometry.
  942. Parameters
  943. ----------
  944. geometry : Geometry or array_like
  945. Geometry or geometries to simplify.
  946. tolerance : float or array_like
  947. The maximum allowed geometry displacement. The higher this value, the
  948. smaller the number of vertices in the resulting geometry.
  949. preserve_topology : bool, default True
  950. By default (True), the operation will avoid creating invalid
  951. geometries (checking for collapses, ring-intersections, etc), but
  952. this is computationally more expensive.
  953. **kwargs
  954. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  955. Notes
  956. -----
  957. .. deprecated:: 2.1.0
  958. A deprecation warning is shown if ``preserve_topology`` is specified as
  959. a positional argument. This will need to be specified as a keyword
  960. argument in a future release.
  961. Examples
  962. --------
  963. >>> import shapely
  964. >>> from shapely import LineString, Polygon
  965. >>> line = LineString([(0, 0), (1, 10), (0, 20)])
  966. >>> shapely.simplify(line, tolerance=0.9)
  967. <LINESTRING (0 0, 1 10, 0 20)>
  968. >>> shapely.simplify(line, tolerance=1)
  969. <LINESTRING (0 0, 0 20)>
  970. >>> polygon_with_hole = Polygon(
  971. ... [(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)],
  972. ... holes=[[(2, 2), (2, 4), (4, 4), (4, 2), (2, 2)]]
  973. ... )
  974. >>> shapely.simplify(polygon_with_hole, tolerance=4, preserve_topology=True)
  975. <POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0), (4 2, 2 4, 4 4, 4 2))>
  976. >>> shapely.simplify(polygon_with_hole, tolerance=4, preserve_topology=False)
  977. <POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))>
  978. """
  979. if preserve_topology:
  980. return lib.simplify_preserve_topology(geometry, tolerance, **kwargs)
  981. else:
  982. return lib.simplify(geometry, tolerance, **kwargs)
  983. @multithreading_enabled
  984. def snap(geometry, reference, tolerance, **kwargs):
  985. """Snap the vertices and segments of the geometry to vertices of the reference.
  986. Vertices and segments of the input geometry are snapped to vertices of the
  987. reference geometry, returning a new geometry; the input geometries are not
  988. modified. The result geometry is the input geometry with the vertices and
  989. segments snapped. If no snapping occurs then the input geometry is returned
  990. unchanged. The tolerance is used to control where snapping is performed.
  991. Where possible, this operation tries to avoid creating invalid geometries;
  992. however, it does not guarantee that output geometries will be valid. It is
  993. the responsibility of the caller to check for and handle invalid geometries.
  994. Because too much snapping can result in invalid geometries being created,
  995. heuristics are used to determine the number and location of snapped
  996. vertices that are likely safe to snap. These heuristics may omit
  997. some potential snaps that are otherwise within the tolerance.
  998. Parameters
  999. ----------
  1000. geometry : Geometry or array_like
  1001. Geometry or geometries to snap.
  1002. reference : Geometry or array_like
  1003. Geometry or geometries to snap to.
  1004. tolerance : float or array_like
  1005. The maximum distance between the input and reference geometries for
  1006. snapping to occur. A value of 0 will snap only identical points.
  1007. **kwargs
  1008. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  1009. Examples
  1010. --------
  1011. >>> import shapely
  1012. >>> from shapely import LineString, Point, Polygon, MultiPoint
  1013. >>> point = Point(0.5, 2.5)
  1014. >>> target_point = Point(0, 2)
  1015. >>> shapely.snap(point, target_point, tolerance=1)
  1016. <POINT (0 2)>
  1017. >>> shapely.snap(point, target_point, tolerance=0.49)
  1018. <POINT (0.5 2.5)>
  1019. >>> polygon = Polygon([(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)])
  1020. >>> shapely.snap(polygon, Point(8, 10), tolerance=5)
  1021. <POLYGON ((0 0, 0 10, 8 10, 10 0, 0 0))>
  1022. >>> shapely.snap(polygon, LineString([(8, 10), (8, 0)]), tolerance=5)
  1023. <POLYGON ((0 0, 0 10, 8 10, 8 0, 0 0))>
  1024. You can snap one line to another, for example to clean imprecise coordinates:
  1025. >>> line1 = LineString([(0.1, 0.1), (0.49, 0.51), (1.01, 0.89)])
  1026. >>> line2 = LineString([(0, 0), (0.5, 0.5), (1.0, 1.0)])
  1027. >>> shapely.snap(line1, line2, 0.25)
  1028. <LINESTRING (0 0, 0.5 0.5, 1 1)>
  1029. Snapping also supports Z coordinates:
  1030. >>> point1 = Point(0.1, 0.1, 0.5)
  1031. >>> multipoint = MultiPoint([(0, 0, 1), (0, 0, 0)])
  1032. >>> shapely.snap(point1, multipoint, 1)
  1033. <POINT Z (0 0 1)>
  1034. Snapping to an empty geometry has no effect:
  1035. >>> shapely.snap(line1, LineString([]), 0.25)
  1036. <LINESTRING (0.1 0.1, 0.49 0.51, 1.01 0.89)>
  1037. Snapping to a non-geometry (None) will always return None:
  1038. >>> shapely.snap(line1, None, 0.25) is None
  1039. True
  1040. Only one vertex of a polygon is snapped to a target point,
  1041. even if all vertices are equidistant to it,
  1042. in order to prevent collapse of the polygon:
  1043. >>> poly = shapely.box(0, 0, 1, 1)
  1044. >>> poly
  1045. <POLYGON ((1 0, 1 1, 0 1, 0 0, 1 0))>
  1046. >>> shapely.snap(poly, Point(0.5, 0.5), 1)
  1047. <POLYGON ((0.5 0.5, 1 1, 0 1, 0 0, 0.5 0.5))>
  1048. """
  1049. return lib.snap(geometry, reference, tolerance, **kwargs)
  1050. # Note: future plan is to change this signature over a few releases:
  1051. # shapely 2.0:
  1052. # voronoi_polygons(geometry, tolerance=0.0, extend_to=None, ...)
  1053. # shapely 2.1: shows deprecation warning about positional 'extend_to'
  1054. # same signature as 2.0
  1055. # shapely 2.2(?): enforce keyword-only arguments after 'tolerance'
  1056. # voronoi_polygons(geometry, tolerance=0.0, extend_to=None, ...)
  1057. @deprecate_positional(
  1058. ["extend_to", "only_edges", "ordered"], category=DeprecationWarning
  1059. )
  1060. @multithreading_enabled
  1061. def voronoi_polygons(
  1062. geometry, tolerance=0.0, extend_to=None, only_edges=False, ordered=False, **kwargs
  1063. ):
  1064. """Compute a Voronoi diagram from the vertices of an input geometry.
  1065. The output is a geometrycollection containing polygons (default)
  1066. or linestrings (see only_edges). Returns empty if an input geometry
  1067. contains less than 2 vertices or if the provided extent has zero area.
  1068. Parameters
  1069. ----------
  1070. geometry : Geometry or array_like
  1071. Geometry or geometries for which to compute the Voronoi diagram.
  1072. tolerance : float or array_like, default 0.0
  1073. Snap input vertices together if their distance is less than this value.
  1074. extend_to : Geometry or array_like, optional
  1075. If provided, the diagram will be extended to cover the envelope of this
  1076. geometry (unless this envelope is smaller than the input geometry).
  1077. only_edges : bool or array_like, default False
  1078. If set to True, the triangulation will return a collection of
  1079. linestrings instead of polygons.
  1080. ordered : bool or array_like, default False
  1081. If set to True, polygons within the GeometryCollection will be ordered
  1082. according to the order of the input vertices. Note that this may slow
  1083. down the computation. Requires GEOS >= 3.12.0.
  1084. .. versionadded:: 2.1.0
  1085. **kwargs
  1086. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  1087. Notes
  1088. -----
  1089. .. deprecated:: 2.1.0
  1090. A deprecation warning is shown if ``extend_to``, ``only_edges`` or
  1091. ``ordered`` are specified as positional arguments. In a future
  1092. release, these will need to be specified as keyword arguments.
  1093. Examples
  1094. --------
  1095. >>> import shapely
  1096. >>> from shapely import LineString, MultiPoint, Point
  1097. >>> points = MultiPoint([(2, 2), (4, 2)])
  1098. >>> shapely.voronoi_polygons(points).normalize()
  1099. <GEOMETRYCOLLECTION (POLYGON ((3 0, 3 4, 6 4, 6 0, 3 0)), POLYGON ((0 0, 0 4...>
  1100. >>> shapely.voronoi_polygons(points, only_edges=True)
  1101. <MULTILINESTRING ((3 4, 3 0))>
  1102. >>> shapely.voronoi_polygons(MultiPoint([(2, 2), (4, 2), (4.2, 2)]), 0.5, only_edges=True)
  1103. <MULTILINESTRING ((3 4.2, 3 -0.2))>
  1104. >>> shapely.voronoi_polygons(points, extend_to=LineString([(0, 0), (10, 10)]), only_edges=True)
  1105. <MULTILINESTRING ((3 10, 3 0))>
  1106. >>> shapely.voronoi_polygons(LineString([(2, 2), (4, 2)]), only_edges=True)
  1107. <MULTILINESTRING ((3 4, 3 0))>
  1108. >>> shapely.voronoi_polygons(Point(2, 2))
  1109. <GEOMETRYCOLLECTION EMPTY>
  1110. >>> shapely.voronoi_polygons(points, ordered=True)
  1111. <GEOMETRYCOLLECTION (POLYGON ((0 0, 0 4, 3 4, 3 0, 0 0)), POLYGON ((6 4, 6 0...>
  1112. """ # noqa: E501
  1113. if ordered is not False and lib.geos_version < (3, 12, 0):
  1114. raise UnsupportedGEOSVersionError(
  1115. "Ordered Voronoi polygons require GEOS >= 3.12.0, "
  1116. f"found {lib.geos_version_string}"
  1117. )
  1118. return lib.voronoi_polygons(
  1119. geometry, tolerance, extend_to, only_edges, ordered, **kwargs
  1120. )
  1121. @multithreading_enabled
  1122. def _oriented_envelope_geos(geometry, **kwargs):
  1123. return lib.oriented_envelope(geometry, **kwargs)
  1124. def oriented_envelope(geometry, **kwargs):
  1125. """Compute the oriented envelope (minimum rotated rectangle) of the input geometry.
  1126. The oriented envelope encloses an input geometry, such that the resulting
  1127. rectangle has minimum area.
  1128. Unlike envelope this rectangle is not constrained to be parallel to the
  1129. coordinate axes. If the convex hull of the object is a degenerate (line
  1130. or point) this degenerate is returned.
  1131. The starting point of the rectangle is not fixed. You can use
  1132. :func:`~shapely.normalize` to reorganize the rectangle to
  1133. :ref:`strict canonical form <canonical-form>` so the starting point is
  1134. always the lower left point.
  1135. ``minimum_rotated_rectangle`` is an alias for ``oriented_envelope``.
  1136. Parameters
  1137. ----------
  1138. geometry : Geometry or array_like
  1139. Geometry or geometries for which to compute the oriented envelope.
  1140. **kwargs
  1141. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  1142. Examples
  1143. --------
  1144. >>> import shapely
  1145. >>> from shapely import GeometryCollection, LineString, MultiPoint, Point, Polygon
  1146. >>> shapely.oriented_envelope(MultiPoint([(0, 0), (10, 0), (10, 10)])).normalize()
  1147. <POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0))>
  1148. >>> shapely.oriented_envelope(LineString([(1, 1), (5, 1), (10, 10)])).normalize()
  1149. <POLYGON ((1 1, 10 10, 12 8, 3 -1, 1 1))>
  1150. >>> shapely.oriented_envelope(Polygon([(1, 1), (15, 1), (5, 10), (1, 1)]))\
  1151. .normalize()
  1152. <POLYGON ((1 1, 5 10, 16.691 4.804, 12.691 -4.196, 1 1))>
  1153. >>> shapely.oriented_envelope(LineString([(1, 1), (10, 1)])).normalize()
  1154. <LINESTRING (1 1, 10 1)>
  1155. >>> shapely.oriented_envelope(Point(2, 2))
  1156. <POINT (2 2)>
  1157. >>> shapely.oriented_envelope(GeometryCollection([]))
  1158. <POLYGON EMPTY>
  1159. """
  1160. if lib.geos_version < (3, 12, 0):
  1161. f = _oriented_envelope_min_area_vectorized
  1162. else:
  1163. f = _oriented_envelope_geos
  1164. return f(geometry, **kwargs)
  1165. minimum_rotated_rectangle = oriented_envelope
  1166. @multithreading_enabled
  1167. def minimum_bounding_circle(geometry, **kwargs):
  1168. """Compute the minimum bounding circle that encloses an input geometry.
  1169. Parameters
  1170. ----------
  1171. geometry : Geometry or array_like
  1172. Geometry or geometries for which to compute the minimum bounding circle.
  1173. **kwargs
  1174. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  1175. Examples
  1176. --------
  1177. >>> import shapely
  1178. >>> from shapely import GeometryCollection, LineString, MultiPoint, Point, Polygon
  1179. >>> shapely.minimum_bounding_circle(
  1180. ... Polygon([(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)])
  1181. ... )
  1182. <POLYGON ((12.071 5, 11.935 3.621, 11.533 2.294, 10.879 1.07...>
  1183. >>> shapely.minimum_bounding_circle(LineString([(1, 1), (10, 10)]))
  1184. <POLYGON ((11.864 5.5, 11.742 4.258, 11.38 3.065, 10.791 1.9...>
  1185. >>> shapely.minimum_bounding_circle(MultiPoint([(2, 2), (4, 2)]))
  1186. <POLYGON ((4 2, 3.981 1.805, 3.924 1.617, 3.831 1.444, 3.707...>
  1187. >>> shapely.minimum_bounding_circle(Point(0, 1))
  1188. <POINT (0 1)>
  1189. >>> shapely.minimum_bounding_circle(GeometryCollection([]))
  1190. <POLYGON EMPTY>
  1191. See Also
  1192. --------
  1193. minimum_bounding_radius, maximum_inscribed_circle
  1194. """
  1195. return lib.minimum_bounding_circle(geometry, **kwargs)
  1196. @multithreading_enabled
  1197. def maximum_inscribed_circle(geometry, tolerance=None, **kwargs):
  1198. """Find the largest circle that is fully contained within the input geometry.
  1199. Constructs the "maximum inscribed circle" (MIC) for a polygonal geometry,
  1200. up to a specified tolerance. The MIC is determined by a point in the
  1201. interior of the area which has the farthest distance from the area
  1202. boundary, along with a boundary point at that distance. In the context of
  1203. geography the center of the MIC is known as the "pole of inaccessibility".
  1204. A cartographic use case is to determine a suitable point to place a map
  1205. label within a polygon.
  1206. The radius length of the MIC is a measure of how "narrow" a polygon is.
  1207. It is the distance at which the negative buffer becomes empty.
  1208. The function supports polygons with holes and multipolygons.
  1209. Returns a two-point linestring, with the first point at the center of the
  1210. inscribed circle and the second on the boundary of the inscribed circle.
  1211. .. versionadded:: 2.1.0
  1212. Parameters
  1213. ----------
  1214. geometry : Geometry or array_like
  1215. tolerance : float or array_like, optional
  1216. Stop the algorithm when the search area is smaller than this tolerance.
  1217. When not specified, uses `max(width, height) / 1000` per geometry as
  1218. the default.
  1219. **kwargs
  1220. For other keyword-only arguments, see the
  1221. `NumPy ufunc docs <https://numpy.org/doc/stable/reference/ufuncs.html#ufuncs-kwargs>`_.
  1222. Examples
  1223. --------
  1224. >>> import shapely
  1225. >>> from shapely import Polygon
  1226. >>> poly = Polygon([(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)])
  1227. >>> shapely.maximum_inscribed_circle(poly)
  1228. <LINESTRING (5 5, 0 5)>
  1229. See Also
  1230. --------
  1231. minimum_bounding_circle
  1232. """
  1233. if tolerance is None:
  1234. tolerance = 0.0
  1235. elif np.isscalar(tolerance) and tolerance < 0:
  1236. raise ValueError("'tolerance' should be positive")
  1237. return lib.maximum_inscribed_circle(geometry, tolerance, **kwargs)
  1238. @multithreading_enabled
  1239. def _orient_polygons_geos(geometry, exterior_cw=False, **kwargs):
  1240. return lib.orient_polygons(geometry, exterior_cw, **kwargs)
  1241. @multithreading_enabled
  1242. def orient_polygons(geometry, *, exterior_cw=False, **kwargs):
  1243. """Enforce a ring orientation on all polygonal elements in the input geometry.
  1244. Forces (Multi)Polygons to use a counter-clockwise orientation for their
  1245. exterior ring, and a clockwise orientation for their interior rings (or
  1246. the oppposite if ``exterior_cw=True``).
  1247. Also processes geometries inside a GeometryCollection in the same way.
  1248. Other geometries are returned unchanged.
  1249. .. versionadded:: 2.1.0
  1250. Parameters
  1251. ----------
  1252. geometry : Geometry or array_like
  1253. Geometry or geometries to orient consistently.
  1254. exterior_cw : bool, default False
  1255. If True, exterior rings will be clockwise and interior rings
  1256. will be counter-clockwise.
  1257. **kwargs
  1258. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  1259. Examples
  1260. --------
  1261. A polygon with both shell and hole having clockwise orientation:
  1262. >>> from shapely import Polygon, orient_polygons
  1263. >>> polygon = Polygon(
  1264. ... [(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)],
  1265. ... holes=[[(2, 2), (2, 4), (4, 4), (4, 2), (2, 2)]],
  1266. ... )
  1267. >>> polygon
  1268. <POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 4, 4 4, 4 2, 2 2))>
  1269. By default, the exterior ring is oriented counter-clockwise and
  1270. the holes clockwise:
  1271. >>> orient_polygons(polygon)
  1272. <POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (2 2, 2 4, 4 4, 4 2, 2 2))>
  1273. Asking for the opposite orientation:
  1274. >>> orient_polygons(polygon, exterior_cw=True)
  1275. <POLYGON ((0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 4 2, 4 4, 2 4, 2 2))>
  1276. """
  1277. if lib.geos_version < (3, 12, 0):
  1278. f = _orient_polygons_vectorized
  1279. else:
  1280. f = _orient_polygons_geos
  1281. return f(geometry, exterior_cw, **kwargs)