_geometry.py 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027
  1. import warnings
  2. from enum import IntEnum
  3. import numpy as np
  4. from shapely import _geometry_helpers, geos_version, lib
  5. from shapely._enum import ParamEnum
  6. from shapely.decorators import (
  7. deprecate_positional,
  8. multithreading_enabled,
  9. requires_geos,
  10. )
  11. __all__ = [
  12. "GeometryType",
  13. "force_2d",
  14. "force_3d",
  15. "get_coordinate_dimension",
  16. "get_dimensions",
  17. "get_exterior_ring",
  18. "get_geometry",
  19. "get_interior_ring",
  20. "get_m",
  21. "get_num_coordinates",
  22. "get_num_geometries",
  23. "get_num_interior_rings",
  24. "get_num_points",
  25. "get_parts",
  26. "get_point",
  27. "get_precision",
  28. "get_rings",
  29. "get_srid",
  30. "get_type_id",
  31. "get_x",
  32. "get_y",
  33. "get_z",
  34. "set_precision",
  35. "set_srid",
  36. ]
  37. class GeometryType(IntEnum):
  38. """The enumeration of GEOS geometry types."""
  39. MISSING = -1
  40. POINT = 0
  41. LINESTRING = 1
  42. LINEARRING = 2
  43. POLYGON = 3
  44. MULTIPOINT = 4
  45. MULTILINESTRING = 5
  46. MULTIPOLYGON = 6
  47. GEOMETRYCOLLECTION = 7
  48. # generic
  49. @multithreading_enabled
  50. def get_type_id(geometry, **kwargs):
  51. """Return the type ID of a geometry.
  52. Possible values are:
  53. - None (missing) is -1
  54. - POINT is 0
  55. - LINESTRING is 1
  56. - LINEARRING is 2
  57. - POLYGON is 3
  58. - MULTIPOINT is 4
  59. - MULTILINESTRING is 5
  60. - MULTIPOLYGON is 6
  61. - GEOMETRYCOLLECTION is 7
  62. Parameters
  63. ----------
  64. geometry : Geometry or array_like
  65. Geometry or geometries to get the type ID of.
  66. **kwargs
  67. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  68. See Also
  69. --------
  70. GeometryType
  71. Examples
  72. --------
  73. >>> import shapely
  74. >>> from shapely import LineString, Point
  75. >>> shapely.get_type_id(LineString([(0, 0), (1, 1), (2, 2), (3, 3)]))
  76. 1
  77. >>> shapely.get_type_id([Point(1, 2), Point(2, 3)]).tolist()
  78. [0, 0]
  79. """
  80. return lib.get_type_id(geometry, **kwargs)
  81. @multithreading_enabled
  82. def get_dimensions(geometry, **kwargs):
  83. """Return the inherent dimensionality of a geometry.
  84. The inherent dimension is 0 for points, 1 for linestrings and linearrings,
  85. and 2 for polygons. For geometrycollections it is the max of the containing
  86. elements. Empty collections and None values return -1.
  87. Parameters
  88. ----------
  89. geometry : Geometry or array_like
  90. Geometry or geometries to get the dimensionality of.
  91. **kwargs
  92. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  93. Examples
  94. --------
  95. >>> import shapely
  96. >>> from shapely import GeometryCollection, Point, Polygon
  97. >>> point = Point(0, 0)
  98. >>> shapely.get_dimensions(point)
  99. 0
  100. >>> polygon = Polygon([(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)])
  101. >>> shapely.get_dimensions(polygon)
  102. 2
  103. >>> shapely.get_dimensions(GeometryCollection([point, polygon]))
  104. 2
  105. >>> shapely.get_dimensions(GeometryCollection([]))
  106. -1
  107. >>> shapely.get_dimensions(None)
  108. -1
  109. """
  110. return lib.get_dimensions(geometry, **kwargs)
  111. @multithreading_enabled
  112. def get_coordinate_dimension(geometry, **kwargs):
  113. """Return the dimensionality of the coordinates in a geometry (2, 3 or 4).
  114. The return value can be one of the following:
  115. * Return 2 for geometries with XY coordinate types,
  116. * Return 3 for XYZ or XYM coordinate types
  117. (distinguished by :meth:`has_z` or :meth:`has_m`),
  118. * Return 4 for XYZM coordinate types,
  119. * Return -1 for missing geometries (``None`` values).
  120. Note that with GEOS < 3.12, if the first Z coordinate equals ``nan``, this function
  121. will return ``2``. Geometries with M coordinates are supported with GEOS >= 3.12.
  122. Parameters
  123. ----------
  124. geometry : Geometry or array_like
  125. Geometry or geometries to get the coordinate dimension of.
  126. **kwargs
  127. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  128. Examples
  129. --------
  130. >>> import shapely
  131. >>> from shapely import Point
  132. >>> shapely.get_coordinate_dimension(Point(0, 0))
  133. 2
  134. >>> shapely.get_coordinate_dimension(Point(0, 0, 1))
  135. 3
  136. >>> shapely.get_coordinate_dimension(None)
  137. -1
  138. """
  139. return lib.get_coordinate_dimension(geometry, **kwargs)
  140. @multithreading_enabled
  141. def get_num_coordinates(geometry, **kwargs):
  142. """Return the total number of coordinates in a geometry.
  143. Returns 0 for not-a-geometry values.
  144. Parameters
  145. ----------
  146. geometry : Geometry or array_like
  147. Geometry or geometries to get the number of coordinates of.
  148. **kwargs
  149. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  150. Examples
  151. --------
  152. >>> import shapely
  153. >>> from shapely import GeometryCollection, LineString, Point
  154. >>> point = Point(0, 0)
  155. >>> shapely.get_num_coordinates(point)
  156. 1
  157. >>> shapely.get_num_coordinates(Point(0, 0, 0))
  158. 1
  159. >>> line = LineString([(0, 0), (1, 1)])
  160. >>> shapely.get_num_coordinates(line)
  161. 2
  162. >>> shapely.get_num_coordinates(GeometryCollection([point, line]))
  163. 3
  164. >>> shapely.get_num_coordinates(None)
  165. 0
  166. """
  167. return lib.get_num_coordinates(geometry, **kwargs)
  168. @multithreading_enabled
  169. def get_srid(geometry, **kwargs):
  170. """Return the SRID of a geometry.
  171. Returns -1 for not-a-geometry values.
  172. Parameters
  173. ----------
  174. geometry : Geometry or array_like
  175. Geometry or geometries to get the SRID of.
  176. **kwargs
  177. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  178. See Also
  179. --------
  180. set_srid
  181. Examples
  182. --------
  183. >>> import shapely
  184. >>> from shapely import Point
  185. >>> point = Point(0, 0)
  186. >>> shapely.get_srid(point)
  187. 0
  188. >>> with_srid = shapely.set_srid(point, 4326)
  189. >>> shapely.get_srid(with_srid)
  190. 4326
  191. """
  192. return lib.get_srid(geometry, **kwargs)
  193. @multithreading_enabled
  194. def set_srid(geometry, srid, **kwargs):
  195. """Return a geometry with its SRID set.
  196. Parameters
  197. ----------
  198. geometry : Geometry or array_like
  199. Geometry or geometries to set the SRID of.
  200. srid : int
  201. The SRID to set on the geometry.
  202. **kwargs
  203. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  204. See Also
  205. --------
  206. get_srid
  207. Examples
  208. --------
  209. >>> import shapely
  210. >>> from shapely import Point
  211. >>> point = Point(0, 0)
  212. >>> shapely.get_srid(point)
  213. 0
  214. >>> with_srid = shapely.set_srid(point, 4326)
  215. >>> shapely.get_srid(with_srid)
  216. 4326
  217. """
  218. return lib.set_srid(geometry, np.intc(srid), **kwargs)
  219. # points
  220. @multithreading_enabled
  221. def get_x(point, **kwargs):
  222. """Return the x-coordinate of a point.
  223. Parameters
  224. ----------
  225. point : Geometry or array_like
  226. Non-point geometries will result in NaN being returned.
  227. **kwargs
  228. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  229. See Also
  230. --------
  231. get_y, get_z, get_m
  232. Examples
  233. --------
  234. >>> import shapely
  235. >>> from shapely import MultiPoint, Point
  236. >>> shapely.get_x(Point(1, 2))
  237. 1.0
  238. >>> shapely.get_x(MultiPoint([(1, 1), (1, 2)]))
  239. nan
  240. """
  241. return lib.get_x(point, **kwargs)
  242. @multithreading_enabled
  243. def get_y(point, **kwargs):
  244. """Return the y-coordinate of a point.
  245. Parameters
  246. ----------
  247. point : Geometry or array_like
  248. Non-point geometries will result in NaN being returned.
  249. **kwargs
  250. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  251. See Also
  252. --------
  253. get_x, get_z, get_m
  254. Examples
  255. --------
  256. >>> import shapely
  257. >>> from shapely import MultiPoint, Point
  258. >>> shapely.get_y(Point(1, 2))
  259. 2.0
  260. >>> shapely.get_y(MultiPoint([(1, 1), (1, 2)]))
  261. nan
  262. """
  263. return lib.get_y(point, **kwargs)
  264. @multithreading_enabled
  265. def get_z(point, **kwargs):
  266. """Return the z-coordinate of a point.
  267. Parameters
  268. ----------
  269. point : Geometry or array_like
  270. Non-point geometries or geometries without Z dimension will result
  271. in NaN being returned.
  272. **kwargs
  273. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  274. See Also
  275. --------
  276. get_x, get_y, get_m
  277. Examples
  278. --------
  279. >>> import shapely
  280. >>> from shapely import MultiPoint, Point
  281. >>> shapely.get_z(Point(1, 2, 3))
  282. 3.0
  283. >>> shapely.get_z(Point(1, 2))
  284. nan
  285. >>> shapely.get_z(MultiPoint([(1, 1, 1), (2, 2, 2)]))
  286. nan
  287. """
  288. return lib.get_z(point, **kwargs)
  289. @multithreading_enabled
  290. @requires_geos("3.12.0")
  291. def get_m(point, **kwargs):
  292. """Return the m-coordinate of a point.
  293. .. versionadded:: 2.1.0
  294. Parameters
  295. ----------
  296. point : Geometry or array_like
  297. Non-point geometries or geometries without M dimension will result
  298. in NaN being returned.
  299. **kwargs
  300. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  301. See Also
  302. --------
  303. get_x, get_y, get_z
  304. Examples
  305. --------
  306. >>> import shapely
  307. >>> from shapely import Point, from_wkt
  308. >>> shapely.get_m(from_wkt("POINT ZM (1 2 3 4)"))
  309. 4.0
  310. >>> shapely.get_m(from_wkt("POINT M (1 2 4)"))
  311. 4.0
  312. >>> shapely.get_m(Point(1, 2, 3))
  313. nan
  314. >>> shapely.get_m(from_wkt("MULTIPOINT M ((1 1 1), (2 2 2))"))
  315. nan
  316. """
  317. return lib.get_m(point, **kwargs)
  318. # linestrings
  319. @multithreading_enabled
  320. def get_point(geometry, index, **kwargs):
  321. """Return the nth point of a linestring or linearring.
  322. Parameters
  323. ----------
  324. geometry : Geometry or array_like
  325. Geometry or geometries to get the point of.
  326. index : int or array_like
  327. Negative values count from the end of the linestring backwards.
  328. **kwargs
  329. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  330. See Also
  331. --------
  332. get_num_points
  333. Examples
  334. --------
  335. >>> import shapely
  336. >>> from shapely import LinearRing, LineString, MultiPoint, Point
  337. >>> line = LineString([(0, 0), (1, 1), (2, 2), (3, 3)])
  338. >>> shapely.get_point(line, 1)
  339. <POINT (1 1)>
  340. >>> shapely.get_point(line, -2)
  341. <POINT (2 2)>
  342. >>> shapely.get_point(line, [0, 3]).tolist()
  343. [<POINT (0 0)>, <POINT (3 3)>]
  344. The function works the same for LinearRing input:
  345. >>> shapely.get_point(LinearRing([(0, 0), (1, 1), (2, 2), (0, 0)]), 1)
  346. <POINT (1 1)>
  347. For non-linear geometries it returns None:
  348. >>> shapely.get_point(MultiPoint([(0, 0), (1, 1), (2, 2), (3, 3)]), 1) is None
  349. True
  350. >>> shapely.get_point(Point(1, 1), 0) is None
  351. True
  352. """
  353. return lib.get_point(geometry, np.intc(index), **kwargs)
  354. @multithreading_enabled
  355. def get_num_points(geometry, **kwargs):
  356. """Return the number of points in a linestring or linearring.
  357. Returns 0 for not-a-geometry values. The number of points in geometries
  358. other than linestring or linearring equals zero.
  359. Parameters
  360. ----------
  361. geometry : Geometry or array_like
  362. Geometry or geometries to get the number of points of.
  363. **kwargs
  364. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  365. See Also
  366. --------
  367. get_point
  368. get_num_geometries
  369. Examples
  370. --------
  371. >>> import shapely
  372. >>> from shapely import LineString, MultiPoint
  373. >>> shapely.get_num_points(LineString([(0, 0), (1, 1), (2, 2), (3, 3)]))
  374. 4
  375. >>> shapely.get_num_points(MultiPoint([(0, 0), (1, 1), (2, 2), (3, 3)]))
  376. 0
  377. >>> shapely.get_num_points(None)
  378. 0
  379. """
  380. return lib.get_num_points(geometry, **kwargs)
  381. # polygons
  382. @multithreading_enabled
  383. def get_exterior_ring(geometry, **kwargs):
  384. """Return the exterior ring of a polygon.
  385. Parameters
  386. ----------
  387. geometry : Geometry or array_like
  388. Geometry or geometries to get the exterior ring of.
  389. **kwargs
  390. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  391. See Also
  392. --------
  393. get_interior_ring
  394. Examples
  395. --------
  396. >>> import shapely
  397. >>> from shapely import Point, Polygon
  398. >>> shapely.get_exterior_ring(Polygon([(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)]))
  399. <LINEARRING (0 0, 0 10, 10 10, 10 0, 0 0)>
  400. >>> shapely.get_exterior_ring(Point(1, 1)) is None
  401. True
  402. """
  403. return lib.get_exterior_ring(geometry, **kwargs)
  404. @multithreading_enabled
  405. def get_interior_ring(geometry, index, **kwargs):
  406. """Return the nth interior ring of a polygon.
  407. The number of interior rings in non-polygons equals zero.
  408. Parameters
  409. ----------
  410. geometry : Geometry or array_like
  411. Geometry or geometries to get the interior ring of.
  412. index : int or array_like
  413. Negative values count from the end of the interior rings backwards.
  414. **kwargs
  415. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  416. See Also
  417. --------
  418. get_exterior_ring
  419. get_num_interior_rings
  420. Examples
  421. --------
  422. >>> import shapely
  423. >>> from shapely import Point, Polygon
  424. >>> polygon_with_hole = Polygon(
  425. ... [(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)],
  426. ... holes=[[(2, 2), (2, 4), (4, 4), (4, 2), (2, 2)]]
  427. ... )
  428. >>> shapely.get_interior_ring(polygon_with_hole, 0)
  429. <LINEARRING (2 2, 2 4, 4 4, 4 2, 2 2)>
  430. >>> shapely.get_interior_ring(polygon_with_hole, 1) is None
  431. True
  432. >>> polygon = Polygon([(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)])
  433. >>> shapely.get_interior_ring(polygon, 0) is None
  434. True
  435. >>> shapely.get_interior_ring(Point(0, 0), 0) is None
  436. True
  437. """
  438. return lib.get_interior_ring(geometry, np.intc(index), **kwargs)
  439. @multithreading_enabled
  440. def get_num_interior_rings(geometry, **kwargs):
  441. """Return number of internal rings in a polygon.
  442. Returns 0 for not-a-geometry values.
  443. Parameters
  444. ----------
  445. geometry : Geometry or array_like
  446. Geometry or geometries to get the number of interior rings of.
  447. **kwargs
  448. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  449. See Also
  450. --------
  451. get_exterior_ring
  452. get_interior_ring
  453. Examples
  454. --------
  455. >>> import shapely
  456. >>> from shapely import Point, Polygon
  457. >>> polygon = Polygon([(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)])
  458. >>> shapely.get_num_interior_rings(polygon)
  459. 0
  460. >>> polygon_with_hole = Polygon(
  461. ... [(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)],
  462. ... holes=[[(2, 2), (2, 4), (4, 4), (4, 2), (2, 2)]]
  463. ... )
  464. >>> shapely.get_num_interior_rings(polygon_with_hole)
  465. 1
  466. >>> shapely.get_num_interior_rings(Point(0, 0))
  467. 0
  468. >>> shapely.get_num_interior_rings(None)
  469. 0
  470. """
  471. return lib.get_num_interior_rings(geometry, **kwargs)
  472. # collections
  473. @multithreading_enabled
  474. def get_geometry(geometry, index, **kwargs):
  475. """Return the nth geometry from a collection of geometries.
  476. Parameters
  477. ----------
  478. geometry : Geometry or array_like
  479. Geometry or geometries to get the nth geometry of.
  480. index : int or array_like
  481. Negative values count from the end of the collection backwards.
  482. **kwargs
  483. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  484. Notes
  485. -----
  486. - simple geometries act as length-1 collections
  487. - out-of-range values return None
  488. See Also
  489. --------
  490. get_num_geometries, get_parts
  491. Examples
  492. --------
  493. >>> import shapely
  494. >>> from shapely import Point, MultiPoint
  495. >>> multipoint = MultiPoint([(0, 0), (1, 1), (2, 2), (3, 3)])
  496. >>> shapely.get_geometry(multipoint, 1)
  497. <POINT (1 1)>
  498. >>> shapely.get_geometry(multipoint, -1)
  499. <POINT (3 3)>
  500. >>> shapely.get_geometry(multipoint, 5) is None
  501. True
  502. >>> shapely.get_geometry(Point(1, 1), 0)
  503. <POINT (1 1)>
  504. >>> shapely.get_geometry(Point(1, 1), 1) is None
  505. True
  506. """
  507. return lib.get_geometry(geometry, np.intc(index), **kwargs)
  508. # Note: future plan is to change this signature over a few releases:
  509. # shapely 2.0:
  510. # get_parts(geometry, return_index=False)
  511. # shapely 2.1: shows deprecation warning about positional 'return_index'
  512. # same signature as 2.0
  513. # shapely 2.2(?): enforce keyword-only arguments after 'geometry'
  514. # get_parts(geometry, *, return_index=False)
  515. @deprecate_positional(["return_index"])
  516. def get_parts(geometry, return_index=False):
  517. """Get parts of each GeometryCollection or Multi* geometry object.
  518. A copy of each geometry in the GeometryCollection or Multi* geometry object
  519. is returned.
  520. Note: This does not return the individual parts of Multi* geometry objects
  521. in a GeometryCollection. You may need to call this function multiple times
  522. to return individual parts of Multi* geometry objects in a
  523. GeometryCollection.
  524. Parameters
  525. ----------
  526. geometry : Geometry or array_like
  527. Geometry or geometries to get the parts of.
  528. return_index : bool, default False
  529. If True, will return a tuple of ndarrays of (parts, indexes), where
  530. indexes are the indexes of the original geometries in the source array.
  531. Notes
  532. -----
  533. .. deprecated:: 2.1.0
  534. A deprecation warning is shown if ``return_index`` is specified as
  535. a positional argument. This will need to be specified as a keyword
  536. argument in a future release.
  537. Returns
  538. -------
  539. ndarray of parts or tuple of (parts, indexes)
  540. See Also
  541. --------
  542. get_geometry, get_rings
  543. Examples
  544. --------
  545. >>> import shapely
  546. >>> from shapely import MultiPoint
  547. >>> shapely.get_parts(MultiPoint([(0, 1), (2, 3)])).tolist()
  548. [<POINT (0 1)>, <POINT (2 3)>]
  549. >>> parts, index = shapely.get_parts([MultiPoint([(0, 1)]), \
  550. MultiPoint([(4, 5), (6, 7)])], return_index=True)
  551. >>> parts.tolist()
  552. [<POINT (0 1)>, <POINT (4 5)>, <POINT (6 7)>]
  553. >>> index.tolist()
  554. [0, 1, 1]
  555. """
  556. geometry = np.asarray(geometry, dtype=np.object_)
  557. geometry = np.atleast_1d(geometry)
  558. if geometry.ndim != 1:
  559. raise ValueError("Array should be one dimensional")
  560. if return_index:
  561. return _geometry_helpers.get_parts(geometry)
  562. return _geometry_helpers.get_parts(geometry)[0]
  563. # Note: future plan is to change this signature over a few releases:
  564. # shapely 2.0:
  565. # get_rings(geometry, return_index=False)
  566. # shapely 2.1: shows deprecation warning about positional 'return_index'
  567. # same signature as 2.0
  568. # shapely 2.2(?): enforce keyword-only arguments after 'geometry'
  569. # get_rings(geometry, *, return_index=False)
  570. @deprecate_positional(["return_index"])
  571. def get_rings(geometry, return_index=False):
  572. """Get rings of Polygon geometry object.
  573. For each Polygon, the first returned ring is always the exterior ring
  574. and potential subsequent rings are interior rings.
  575. If the geometry is not a Polygon, nothing is returned (empty array for
  576. scalar geometry input or no element in output array for array input).
  577. Parameters
  578. ----------
  579. geometry : Geometry or array_like
  580. Geometry or geometries to get the rings of.
  581. return_index : bool, default False
  582. If True, will return a tuple of ndarrays of (rings, indexes), where
  583. indexes are the indexes of the original geometries in the source array.
  584. Notes
  585. -----
  586. .. deprecated:: 2.1.0
  587. A deprecation warning is shown if ``return_index`` is specified as
  588. a positional argument. This will need to be specified as a keyword
  589. argument in a future release.
  590. Returns
  591. -------
  592. ndarray of rings or tuple of (rings, indexes)
  593. See Also
  594. --------
  595. get_exterior_ring, get_interior_ring, get_parts
  596. Examples
  597. --------
  598. >>> import shapely
  599. >>> from shapely import Polygon
  600. >>> polygon_with_hole = Polygon(
  601. ... [(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)],
  602. ... holes=[[(2, 2), (2, 4), (4, 4), (4, 2), (2, 2)]]
  603. ... )
  604. >>> shapely.get_rings(polygon_with_hole).tolist()
  605. [<LINEARRING (0 0, 0 10, 10 10, 10 0, 0 0)>,
  606. <LINEARRING (2 2, 2 4, 4 4, 4 2, 2 2)>]
  607. With ``return_index=True``:
  608. >>> polygon = Polygon([(0, 0), (2, 0), (2, 2), (0, 2), (0, 0)])
  609. >>> rings, index = shapely.get_rings(
  610. ... [polygon, polygon_with_hole],
  611. ... return_index=True
  612. ... )
  613. >>> rings.tolist()
  614. [<LINEARRING (0 0, 2 0, 2 2, 0 2, 0 0)>,
  615. <LINEARRING (0 0, 0 10, 10 10, 10 0, 0 0)>,
  616. <LINEARRING (2 2, 2 4, 4 4, 4 2, 2 2)>]
  617. >>> index.tolist()
  618. [0, 1, 1]
  619. """
  620. geometry = np.asarray(geometry, dtype=np.object_)
  621. geometry = np.atleast_1d(geometry)
  622. if geometry.ndim != 1:
  623. raise ValueError("Array should be one dimensional")
  624. if return_index:
  625. return _geometry_helpers.get_parts(geometry, extract_rings=True)
  626. return _geometry_helpers.get_parts(geometry, extract_rings=True)[0]
  627. @multithreading_enabled
  628. def get_num_geometries(geometry, **kwargs):
  629. """Return number of geometries in a collection.
  630. Returns 0 for not-a-geometry values. The number of geometries in points,
  631. linestrings, linearrings and polygons equals one.
  632. Parameters
  633. ----------
  634. geometry : Geometry or array_like
  635. Geometry or geometries to get the number of geometries of.
  636. **kwargs
  637. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  638. See Also
  639. --------
  640. get_num_points
  641. get_geometry
  642. Examples
  643. --------
  644. >>> import shapely
  645. >>> from shapely import MultiPoint, Point
  646. >>> shapely.get_num_geometries(MultiPoint([(0, 0), (1, 1), (2, 2), (3, 3)]))
  647. 4
  648. >>> shapely.get_num_geometries(Point(1, 1))
  649. 1
  650. >>> shapely.get_num_geometries(None)
  651. 0
  652. """
  653. return lib.get_num_geometries(geometry, **kwargs)
  654. @multithreading_enabled
  655. def get_precision(geometry, **kwargs):
  656. """Get the precision of a geometry.
  657. If a precision has not been previously set, it will be 0 (double
  658. precision). Otherwise, it will return the precision grid size that was
  659. set on a geometry.
  660. Returns NaN for not-a-geometry values.
  661. Parameters
  662. ----------
  663. geometry : Geometry or array_like
  664. Geometry or geometries to get the precision of.
  665. **kwargs
  666. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  667. See Also
  668. --------
  669. set_precision
  670. Examples
  671. --------
  672. >>> import shapely
  673. >>> from shapely import Point
  674. >>> point = Point(1, 1)
  675. >>> shapely.get_precision(point)
  676. 0.0
  677. >>> geometry = shapely.set_precision(point, 1.0)
  678. >>> shapely.get_precision(geometry)
  679. 1.0
  680. >>> shapely.get_precision(None)
  681. nan
  682. """
  683. return lib.get_precision(geometry, **kwargs)
  684. class SetPrecisionMode(ParamEnum):
  685. valid_output = 0
  686. pointwise = 1
  687. keep_collapsed = 2
  688. @multithreading_enabled
  689. def set_precision(geometry, grid_size, mode="valid_output", **kwargs):
  690. """Return geometry with the precision set to a precision grid size.
  691. By default, geometries use double precision coordinates (grid_size = 0).
  692. Coordinates will be rounded if the precision grid specified is less precise
  693. than the input geometry. Duplicated vertices will be dropped from lines and
  694. polygons for grid sizes greater than 0. Line and polygon geometries may
  695. collapse to empty geometries if all vertices are closer together than
  696. ``grid_size`` or if a polygon becomes significantly narrower than
  697. ``grid_size``. Spikes or sections in polygons narrower than ``grid_size``
  698. after rounding the vertices will be removed, which can lead to multipolygons
  699. or empty geometries. Z values, if present, will not be modified.
  700. Notes
  701. -----
  702. * subsequent operations will always be performed in the precision of the
  703. geometry with higher precision (smaller "grid_size"). That same precision
  704. will be attached to the operation outputs.
  705. * input geometries should be geometrically valid; unexpected results may
  706. occur if input geometries are not.
  707. * the geometry returned will be in
  708. :ref:`mild canonical form <canonical-form>`, and the order of vertices can
  709. change and should not be relied upon.
  710. * returns None if geometry is None.
  711. Parameters
  712. ----------
  713. geometry : Geometry or array_like
  714. Geometry or geometries to set the precision of.
  715. grid_size : float
  716. Precision grid size. If 0, will use double precision (will not modify
  717. geometry if precision grid size was not previously set). If this
  718. value is more precise than input geometry, the input geometry will
  719. not be modified.
  720. mode : {'valid_output', 'pointwise', 'keep_collapsed'}, default 'valid_output'
  721. This parameter determines the way a precision reduction is applied on
  722. the geometry. There are three modes:
  723. 1. `'valid_output'` (default): The output is always valid. Collapsed
  724. geometry elements (including both polygons and lines) are removed.
  725. Duplicate vertices are removed.
  726. 2. `'pointwise'`: Precision reduction is performed pointwise. Output
  727. geometry may be invalid due to collapse or self-intersection.
  728. Duplicate vertices are not removed. In GEOS this option is called
  729. NO_TOPO.
  730. .. note::
  731. 'pointwise' mode requires at least GEOS 3.10. It is accepted in
  732. earlier versions, but the results may be unexpected.
  733. 3. `'keep_collapsed'`: Like the default mode, except that collapsed
  734. linear geometry elements are preserved. Collapsed polygonal input
  735. elements are removed. Duplicate vertices are removed.
  736. **kwargs
  737. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  738. See Also
  739. --------
  740. get_precision
  741. Examples
  742. --------
  743. >>> import shapely
  744. >>> from shapely import LineString, Point
  745. >>> shapely.set_precision(Point(0.9, 0.9), 1.0)
  746. <POINT (1 1)>
  747. >>> shapely.set_precision(Point(0.9, 0.9, 0.9), 1.0)
  748. <POINT Z (1 1 0.9)>
  749. >>> shapely.set_precision(LineString([(0, 0), (0, 0.1), (0, 1), (1, 1)]), 1.0)
  750. <LINESTRING (0 0, 0 1, 1 1)>
  751. >>> shapely.set_precision(LineString([(0, 0), (0, 0.1), (0.1, 0.1)]), 1.0, mode="valid_output")
  752. <LINESTRING EMPTY>
  753. >>> shapely.set_precision(LineString([(0, 0), (0, 0.1), (0.1, 0.1)]), 1.0, mode="pointwise")
  754. <LINESTRING (0 0, 0 0, 0 0)>
  755. >>> shapely.set_precision(LineString([(0, 0), (0, 0.1), (0.1, 0.1)]), 1.0, mode="keep_collapsed")
  756. <LINESTRING (0 0, 0 0)>
  757. >>> shapely.set_precision(None, 1.0) is None
  758. True
  759. """ # noqa: E501
  760. if isinstance(mode, str):
  761. mode = SetPrecisionMode.get_value(mode)
  762. elif not np.isscalar(mode):
  763. raise TypeError("mode only accepts scalar values")
  764. if mode == SetPrecisionMode.pointwise and geos_version < (3, 10, 0):
  765. warnings.warn(
  766. "'pointwise' is only supported for GEOS 3.10",
  767. UserWarning,
  768. stacklevel=2,
  769. )
  770. return lib.set_precision(geometry, grid_size, np.intc(mode), **kwargs)
  771. @multithreading_enabled
  772. def force_2d(geometry, **kwargs):
  773. """Force the dimensionality of a geometry to 2D.
  774. Parameters
  775. ----------
  776. geometry : Geometry or array_like
  777. Geometry or geometries to force to 2D.
  778. **kwargs
  779. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  780. Examples
  781. --------
  782. >>> import shapely
  783. >>> from shapely import LineString, Point, Polygon, from_wkt
  784. >>> shapely.force_2d(Point(0, 0, 1))
  785. <POINT (0 0)>
  786. >>> shapely.force_2d(Point(0, 0))
  787. <POINT (0 0)>
  788. >>> shapely.force_2d(LineString([(0, 0, 0), (0, 1, 1), (1, 1, 2)]))
  789. <LINESTRING (0 0, 0 1, 1 1)>
  790. >>> shapely.force_2d(from_wkt("POLYGON Z EMPTY"))
  791. <POLYGON EMPTY>
  792. >>> shapely.force_2d(None) is None
  793. True
  794. """
  795. return lib.force_2d(geometry, **kwargs)
  796. @multithreading_enabled
  797. def force_3d(geometry, z=0.0, **kwargs):
  798. """Force the dimensionality of a geometry to 3D.
  799. 2D geometries will get the provided Z coordinate; Z coordinates of 3D geometries
  800. are unchanged (unless they are nan).
  801. Note that for empty geometries, 3D is only supported since GEOS 3.9 and then
  802. still only for simple geometries (non-collections).
  803. Parameters
  804. ----------
  805. geometry : Geometry or array_like
  806. Geometry or geometries to force to 3D.
  807. z : float or array_like, default 0.0
  808. The Z coordinate value to set on the geometry.
  809. **kwargs
  810. See :ref:`NumPy ufunc docs <ufuncs.kwargs>` for other keyword arguments.
  811. Examples
  812. --------
  813. >>> import shapely
  814. >>> from shapely import LineString, Point
  815. >>> shapely.force_3d(Point(0, 0), z=3)
  816. <POINT Z (0 0 3)>
  817. >>> shapely.force_3d(Point(0, 0, 0), z=3)
  818. <POINT Z (0 0 0)>
  819. >>> shapely.force_3d(LineString([(0, 0), (0, 1), (1, 1)]))
  820. <LINESTRING Z (0 0 0, 0 1 0, 1 1 0)>
  821. >>> shapely.force_3d(None) is None
  822. True
  823. """
  824. if np.isnan(z).any():
  825. raise ValueError("It is not allowed to set the Z coordinate to NaN.")
  826. return lib.force_3d(geometry, z, **kwargs)