test_geometry.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. import warnings
  2. import numpy as np
  3. import pytest
  4. import shapely
  5. from shapely import LinearRing, LineString, MultiPolygon, Point, Polygon
  6. from shapely.testing import assert_geometries_equal
  7. from shapely.tests.common import (
  8. all_types,
  9. empty as empty_geometry_collection,
  10. empty_line_string,
  11. empty_line_string_z,
  12. empty_point,
  13. empty_point_z,
  14. empty_polygon,
  15. equal_geometries_abnormally_yield_unequal,
  16. geometry_collection,
  17. geometry_collection_z,
  18. ignore_invalid,
  19. ignore_warnings,
  20. line_string,
  21. line_string_nan,
  22. line_string_z,
  23. linear_ring,
  24. multi_line_string,
  25. multi_line_string_z,
  26. multi_point,
  27. multi_point_z,
  28. multi_polygon,
  29. multi_polygon_z,
  30. point,
  31. point_m,
  32. point_z,
  33. point_zm,
  34. polygon,
  35. polygon_with_hole,
  36. polygon_with_hole_z,
  37. polygon_z,
  38. )
  39. def test_get_num_points():
  40. actual = shapely.get_num_points(all_types + (None,)).tolist()
  41. assert actual == [0, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  42. def test_get_num_interior_rings():
  43. actual = shapely.get_num_interior_rings(all_types + (None,)).tolist()
  44. assert actual == [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  45. def test_get_num_geometries():
  46. actual = shapely.get_num_geometries(all_types + (None,)).tolist()
  47. assert actual == [1, 1, 1, 1, 1, 2, 1, 2, 2, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0]
  48. @pytest.mark.parametrize(
  49. "geom",
  50. [
  51. point,
  52. polygon,
  53. multi_point,
  54. multi_line_string,
  55. multi_polygon,
  56. geometry_collection,
  57. ],
  58. )
  59. def test_get_point_non_linestring(geom):
  60. actual = shapely.get_point(geom, [0, 2, -1])
  61. assert shapely.is_missing(actual).all()
  62. @pytest.mark.parametrize("geom", [line_string, linear_ring])
  63. def test_get_point(geom):
  64. n = shapely.get_num_points(geom)
  65. actual = shapely.get_point(geom, [0, -n, n, -(n + 1)])
  66. assert_geometries_equal(actual[0], actual[1])
  67. assert shapely.is_missing(actual[2:4]).all()
  68. @pytest.mark.parametrize(
  69. "geom",
  70. [
  71. point,
  72. line_string,
  73. linear_ring,
  74. multi_point,
  75. multi_line_string,
  76. multi_polygon,
  77. geometry_collection,
  78. ],
  79. )
  80. def test_get_exterior_ring_non_polygon(geom):
  81. actual = shapely.get_exterior_ring(geom)
  82. assert shapely.is_missing(actual).all()
  83. def test_get_exterior_ring():
  84. actual = shapely.get_exterior_ring([polygon, polygon_with_hole])
  85. assert (shapely.get_type_id(actual) == shapely.GeometryType.LINEARRING).all()
  86. @pytest.mark.parametrize(
  87. "geom",
  88. [
  89. point,
  90. line_string,
  91. linear_ring,
  92. multi_point,
  93. multi_line_string,
  94. multi_polygon,
  95. geometry_collection,
  96. ],
  97. )
  98. def test_get_interior_ring_non_polygon(geom):
  99. actual = shapely.get_interior_ring(geom, [0, 2, -1])
  100. assert shapely.is_missing(actual).all()
  101. def test_get_interior_ring():
  102. actual = shapely.get_interior_ring(polygon_with_hole, [0, -1, 1, -2])
  103. assert_geometries_equal(actual[0], actual[1])
  104. assert shapely.is_missing(actual[2:4]).all()
  105. @pytest.mark.parametrize("geom", [point, line_string, linear_ring, polygon])
  106. def test_get_geometry_simple(geom):
  107. actual = shapely.get_geometry(geom, [0, -1, 1, -2])
  108. assert_geometries_equal(actual[0], actual[1])
  109. assert shapely.is_missing(actual[2:4]).all()
  110. @pytest.mark.parametrize(
  111. "geom", [multi_point, multi_line_string, multi_polygon, geometry_collection]
  112. )
  113. def test_get_geometry_collection(geom):
  114. n = shapely.get_num_geometries(geom)
  115. actual = shapely.get_geometry(geom, [0, -n, n, -(n + 1)])
  116. assert_geometries_equal(actual[0], actual[1])
  117. assert shapely.is_missing(actual[2:4]).all()
  118. def test_get_type_id():
  119. actual = shapely.get_type_id(all_types + (None,)).tolist()
  120. assert actual == [0, 1, 2, 3, 3, 4, 5, 6, 7, 7, 0, 1, 3, 4, 5, 6, 4, 5, 6, 7, -1]
  121. def test_get_dimensions():
  122. actual = shapely.get_dimensions(all_types + (None,)).tolist()
  123. assert actual == [0, 1, 1, 2, 2, 0, 1, 2, 1, -1, 0, 1, 2, 0, 1, 2, 0, 1, 2, 1, -1]
  124. def test_get_coordinate_dimension():
  125. actual = shapely.get_coordinate_dimension([point, point_z, None]).tolist()
  126. assert actual == [2, 3, -1]
  127. def test_get_num_coordinates():
  128. actual = shapely.get_num_coordinates(all_types + (None,)).tolist()
  129. assert actual == [1, 3, 5, 5, 10, 2, 2, 10, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  130. def test_get_srid():
  131. """All geometry types have no SRID by default; None returns -1"""
  132. actual = shapely.get_srid(all_types + (None,)).tolist()
  133. assert actual == [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1]
  134. def test_get_set_srid():
  135. actual = shapely.set_srid(point, 4326)
  136. assert shapely.get_srid(point) == 0
  137. assert shapely.get_srid(actual) == 4326
  138. @pytest.mark.parametrize(
  139. "func",
  140. [
  141. shapely.get_x,
  142. shapely.get_y,
  143. shapely.get_z,
  144. pytest.param(
  145. shapely.get_m,
  146. marks=pytest.mark.skipif(
  147. shapely.geos_version < (3, 12, 0), reason="GEOS < 3.12"
  148. ),
  149. ),
  150. ],
  151. )
  152. @pytest.mark.parametrize(
  153. "geom",
  154. np.array(all_types)[shapely.get_type_id(all_types) != shapely.GeometryType.POINT],
  155. )
  156. def test_get_xyz_no_point(func, geom):
  157. assert np.isnan(func(geom))
  158. def test_get_x():
  159. assert shapely.get_x([point, point_z]).tolist() == [2.0, 2.0]
  160. def test_get_y():
  161. assert shapely.get_y([point, point_z]).tolist() == [3.0, 3.0]
  162. def test_get_z():
  163. assert shapely.get_z([point_z]).tolist() == [4.0]
  164. def test_get_z_2d():
  165. assert np.isnan(shapely.get_z(point))
  166. @pytest.mark.skipif(
  167. shapely.geos_version < (3, 12, 0),
  168. reason="M coordinates not supported with GEOS < 3.12",
  169. )
  170. def test_get_m():
  171. assert shapely.get_m([point_m, point_zm]).tolist() == [5.0, 5.0]
  172. assert np.isnan(shapely.get_m(point))
  173. assert np.isnan(shapely.get_m(point_z))
  174. @pytest.mark.parametrize("geom", all_types)
  175. def test_new_from_wkt(geom):
  176. actual = shapely.from_wkt(str(geom))
  177. if equal_geometries_abnormally_yield_unequal(geom):
  178. # abnormal test
  179. with pytest.raises(AssertionError):
  180. assert_geometries_equal(actual, geom)
  181. else:
  182. # normal test
  183. assert_geometries_equal(actual, geom)
  184. def test_adapt_ptr_raises():
  185. point = Point(2, 2)
  186. with pytest.raises(AttributeError):
  187. point._geom += 1
  188. @pytest.mark.parametrize("geom", all_types)
  189. def test_set_unique(geom):
  190. a = {geom, shapely.transform(geom, lambda x: x)}
  191. assert len(a) == 1
  192. def test_set_nan():
  193. # Although NaN != NaN, you cannot have multiple "NaN" points in a set
  194. # This is because "NaN" coordinates in a geometry are considered as equal.
  195. with ignore_invalid():
  196. a = set(shapely.linestrings([[[np.nan, np.nan], [np.nan, np.nan]]] * 10))
  197. assert len(a) == 1 # same objects: NaN == NaN (as geometry coordinates)
  198. def test_set_nan_same_objects():
  199. # You can't put identical objects in a set.
  200. # x = float("nan"); set([x, x]) also returns a set with 1 element
  201. a = set([line_string_nan] * 10)
  202. assert len(a) == 1
  203. @pytest.mark.parametrize(
  204. "geom",
  205. [
  206. point,
  207. multi_point,
  208. line_string,
  209. multi_line_string,
  210. polygon,
  211. multi_polygon,
  212. geometry_collection,
  213. empty_point,
  214. empty_line_string,
  215. empty_polygon,
  216. empty_geometry_collection,
  217. np.array([None]),
  218. np.empty_like(np.array([None])),
  219. ],
  220. )
  221. def test_get_parts(geom):
  222. expected_num_parts = shapely.get_num_geometries(geom)
  223. if expected_num_parts == 0:
  224. expected_parts = []
  225. else:
  226. expected_parts = shapely.get_geometry(geom, range(expected_num_parts))
  227. parts = shapely.get_parts(geom)
  228. assert len(parts) == expected_num_parts
  229. assert_geometries_equal(parts, expected_parts)
  230. def test_get_parts_array():
  231. # note: this also verifies that None is handled correctly
  232. # in the mix; internally it returns -1 for count of geometries
  233. geom = np.array([None, empty_line_string, multi_point, point, multi_polygon])
  234. expected_parts = []
  235. for g in geom:
  236. for i in range(shapely.get_num_geometries(g)):
  237. expected_parts.append(shapely.get_geometry(g, i))
  238. parts = shapely.get_parts(geom)
  239. assert len(parts) == len(expected_parts)
  240. assert_geometries_equal(parts, expected_parts)
  241. def test_get_parts_geometry_collection_multi():
  242. """On the first pass, the individual Multi* geometry objects are returned
  243. from the collection. On the second pass, the individual singular geometry
  244. objects within those are returned.
  245. """
  246. geom = shapely.geometrycollections([multi_point, multi_line_string, multi_polygon])
  247. expected_num_parts = shapely.get_num_geometries(geom)
  248. expected_parts = shapely.get_geometry(geom, range(expected_num_parts))
  249. parts = shapely.get_parts(geom)
  250. assert len(parts) == expected_num_parts
  251. assert_geometries_equal(parts, expected_parts)
  252. expected_subparts = []
  253. for g in np.asarray(expected_parts):
  254. for i in range(shapely.get_num_geometries(g)):
  255. expected_subparts.append(shapely.get_geometry(g, i))
  256. subparts = shapely.get_parts(parts)
  257. assert len(subparts) == len(expected_subparts)
  258. assert_geometries_equal(subparts, expected_subparts)
  259. def test_get_parts_return_index():
  260. geom = np.array([multi_point, point, multi_polygon])
  261. expected_parts = []
  262. expected_index = []
  263. for i, g in enumerate(geom):
  264. for j in range(shapely.get_num_geometries(g)):
  265. expected_parts.append(shapely.get_geometry(g, j))
  266. expected_index.append(i)
  267. parts, index = shapely.get_parts(geom, return_index=True)
  268. assert len(parts) == len(expected_parts)
  269. assert_geometries_equal(parts, expected_parts)
  270. assert np.array_equal(index, expected_index)
  271. @pytest.mark.parametrize(
  272. "geom",
  273. ([[None]], [[empty_point]], [[multi_point]], [[multi_point, multi_line_string]]),
  274. )
  275. def test_get_parts_invalid_dimensions(geom):
  276. """Only 1D inputs are supported"""
  277. with pytest.raises(ValueError, match="Array should be one dimensional"):
  278. shapely.get_parts(geom)
  279. @pytest.mark.parametrize("geom", [point, line_string, polygon])
  280. def test_get_parts_non_multi(geom):
  281. """Non-multipart geometries should be returned identical to inputs"""
  282. assert_geometries_equal(geom, shapely.get_parts(geom))
  283. @pytest.mark.parametrize("geom", [None, [None], []])
  284. def test_get_parts_None(geom):
  285. assert len(shapely.get_parts(geom)) == 0
  286. @pytest.mark.parametrize("geom", ["foo", ["foo"], 42])
  287. def test_get_parts_invalid_geometry(geom):
  288. with pytest.raises(TypeError, match="One of the arguments is of incorrect type."):
  289. shapely.get_parts(geom)
  290. def test_get_parts_deprecate_positional():
  291. with pytest.deprecated_call(
  292. match="positional argument `return_index` for `get_parts` is deprecated"
  293. ):
  294. shapely.get_parts(multi_point, False)
  295. @pytest.mark.parametrize(
  296. "geom",
  297. [
  298. point,
  299. multi_point,
  300. line_string,
  301. multi_line_string,
  302. polygon,
  303. multi_polygon,
  304. geometry_collection,
  305. empty_point,
  306. empty_line_string,
  307. empty_polygon,
  308. empty_geometry_collection,
  309. None,
  310. ],
  311. )
  312. def test_get_rings(geom):
  313. if (shapely.get_type_id(geom) != shapely.GeometryType.POLYGON) or shapely.is_empty(
  314. geom
  315. ):
  316. rings = shapely.get_rings(geom)
  317. assert len(rings) == 0
  318. else:
  319. rings = shapely.get_rings(geom)
  320. assert len(rings) == 1
  321. assert rings[0] == shapely.get_exterior_ring(geom)
  322. def test_get_rings_holes():
  323. rings = shapely.get_rings(polygon_with_hole)
  324. assert len(rings) == 2
  325. assert rings[0] == shapely.get_exterior_ring(polygon_with_hole)
  326. assert rings[1] == shapely.get_interior_ring(polygon_with_hole, 0)
  327. def test_get_rings_return_index():
  328. geom = np.array([polygon, None, empty_polygon, polygon_with_hole])
  329. expected_parts = []
  330. expected_index = []
  331. for i, g in enumerate(geom):
  332. if g is None or shapely.is_empty(g):
  333. continue
  334. expected_parts.append(shapely.get_exterior_ring(g))
  335. expected_index.append(i)
  336. for j in range(shapely.get_num_interior_rings(g)):
  337. expected_parts.append(shapely.get_interior_ring(g, j))
  338. expected_index.append(i)
  339. parts, index = shapely.get_rings(geom, return_index=True)
  340. assert len(parts) == len(expected_parts)
  341. assert_geometries_equal(parts, expected_parts)
  342. assert np.array_equal(index, expected_index)
  343. @pytest.mark.parametrize("geom", [[[None]], [[polygon]]])
  344. def test_get_rings_invalid_dimensions(geom):
  345. """Only 1D inputs are supported"""
  346. with pytest.raises(ValueError, match="Array should be one dimensional"):
  347. shapely.get_parts(geom)
  348. def test_get_rings_deprecate_positional():
  349. with pytest.deprecated_call(
  350. match="positional argument `return_index` for `get_rings` is deprecated"
  351. ):
  352. shapely.get_rings(polygon, False)
  353. def test_get_precision():
  354. geometries = all_types + (point_z, empty_point, empty_line_string, empty_polygon)
  355. # default is 0
  356. actual = shapely.get_precision(geometries).tolist()
  357. assert actual == [0] * len(geometries)
  358. geometry = shapely.set_precision(geometries, 1)
  359. actual = shapely.get_precision(geometry).tolist()
  360. assert actual == [1] * len(geometries)
  361. def test_get_precision_none():
  362. assert np.all(np.isnan(shapely.get_precision([None])))
  363. @pytest.mark.parametrize("mode", ("valid_output", "pointwise", "keep_collapsed"))
  364. def test_set_precision(mode):
  365. initial_geometry = Point(0.9, 0.9)
  366. assert shapely.get_precision(initial_geometry) == 0
  367. with ignore_warnings((3, 10, 0), UserWarning):
  368. # GEOS < 3.10 emits warning for 'pointwise'
  369. geometry = shapely.set_precision(initial_geometry, 0, mode=mode)
  370. assert shapely.get_precision(geometry) == 0
  371. assert_geometries_equal(geometry, initial_geometry)
  372. with ignore_warnings((3, 10, 0), UserWarning):
  373. geometry = shapely.set_precision(initial_geometry, 1, mode=mode)
  374. assert shapely.get_precision(geometry) == 1
  375. assert_geometries_equal(geometry, Point(1, 1))
  376. # original should remain unchanged
  377. assert_geometries_equal(initial_geometry, Point(0.9, 0.9))
  378. def test_set_precision_drop_coords():
  379. # setting precision of 0 will not drop duplicated points in original
  380. geometry = shapely.set_precision(LineString([(0, 0), (0, 0), (0, 1), (1, 1)]), 0)
  381. assert_geometries_equal(geometry, LineString([(0, 0), (0, 0), (0, 1), (1, 1)]))
  382. # setting precision will remove duplicated points
  383. geometry = shapely.set_precision(geometry, 1)
  384. assert_geometries_equal(geometry, LineString([(0, 0), (0, 1), (1, 1)]))
  385. @pytest.mark.parametrize("mode", ("valid_output", "pointwise", "keep_collapsed"))
  386. def test_set_precision_z(mode):
  387. with ignore_warnings((3, 10, 0), UserWarning):
  388. # GEOS < 3.10 emits warning for 'pointwise'
  389. geometry = shapely.set_precision(Point(0.9, 0.9, 0.9), 1, mode=mode)
  390. assert shapely.get_precision(geometry) == 1
  391. assert_geometries_equal(geometry, Point(1, 1, 0.9))
  392. @pytest.mark.parametrize("mode", ("valid_output", "pointwise", "keep_collapsed"))
  393. def test_set_precision_nan(mode):
  394. with warnings.catch_warnings():
  395. warnings.simplefilter("ignore") # GEOS emits warnings
  396. actual = shapely.set_precision(line_string_nan, 1, mode=mode)
  397. assert_geometries_equal(actual, line_string_nan)
  398. def test_set_precision_none():
  399. assert shapely.set_precision(None, 0) is None
  400. def test_set_precision_grid_size_nan():
  401. assert shapely.set_precision(Point(0.9, 0.9), np.nan) is None
  402. @pytest.mark.parametrize(
  403. "geometry,mode,expected",
  404. [
  405. (
  406. Polygon([(2, 2), (4, 2), (3.2, 3), (4, 4), (2, 4), (2.8, 3), (2, 2)]),
  407. "valid_output",
  408. MultiPolygon(
  409. [
  410. Polygon([(4, 2), (2, 2), (3, 3), (4, 2)]),
  411. Polygon([(2, 4), (4, 4), (3, 3), (2, 4)]),
  412. ]
  413. ),
  414. ),
  415. pytest.param(
  416. Polygon([(2, 2), (4, 2), (3.2, 3), (4, 4), (2, 4), (2.8, 3), (2, 2)]),
  417. "pointwise",
  418. Polygon([(2, 2), (4, 2), (3, 3), (4, 4), (2, 4), (3, 3), (2, 2)]),
  419. marks=pytest.mark.skipif(
  420. shapely.geos_version < (3, 10, 0),
  421. reason="pointwise does not work pre-GEOS 3.10",
  422. ),
  423. ),
  424. (
  425. Polygon([(2, 2), (4, 2), (3.2, 3), (4, 4), (2, 4), (2.8, 3), (2, 2)]),
  426. "keep_collapsed",
  427. MultiPolygon(
  428. [
  429. Polygon([(4, 2), (2, 2), (3, 3), (4, 2)]),
  430. Polygon([(2, 4), (4, 4), (3, 3), (2, 4)]),
  431. ]
  432. ),
  433. ),
  434. (LineString([(0, 0), (0.1, 0.1)]), "valid_output", LineString()),
  435. pytest.param(
  436. LineString([(0, 0), (0.1, 0.1)]),
  437. "pointwise",
  438. LineString([(0, 0), (0, 0)]),
  439. marks=pytest.mark.skipif(
  440. shapely.geos_version < (3, 10, 0),
  441. reason="pointwise does not work pre-GEOS 3.10",
  442. ),
  443. ),
  444. (
  445. LineString([(0, 0), (0.1, 0.1)]),
  446. "keep_collapsed",
  447. LineString([(0, 0), (0, 0)]),
  448. ),
  449. pytest.param(
  450. LinearRing([(0, 0), (0.1, 0), (0.1, 0.1), (0, 0.1), (0, 0)]),
  451. "valid_output",
  452. LinearRing(),
  453. marks=pytest.mark.skipif(
  454. shapely.geos_version == (3, 10, 0), reason="Segfaults on GEOS 3.10.0"
  455. ),
  456. ),
  457. pytest.param(
  458. LinearRing([(0, 0), (0.1, 0), (0.1, 0.1), (0, 0.1), (0, 0)]),
  459. "pointwise",
  460. LinearRing([(0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]),
  461. marks=pytest.mark.skipif(
  462. shapely.geos_version < (3, 10, 0),
  463. reason="pointwise does not work pre-GEOS 3.10",
  464. ),
  465. ),
  466. pytest.param(
  467. LinearRing([(0, 0), (0.1, 0), (0.1, 0.1), (0, 0.1), (0, 0)]),
  468. "keep_collapsed",
  469. # See https://trac.osgeo.org/geos/ticket/1135#comment:5
  470. LineString([(0, 0), (0, 0), (0, 0)]),
  471. marks=pytest.mark.skipif(
  472. shapely.geos_version < (3, 10, 0),
  473. reason="this collapsed into an invalid linearring pre-GEOS 3.10",
  474. ),
  475. ),
  476. (
  477. Polygon([(0, 0), (0.1, 0), (0.1, 0.1), (0, 0.1), (0, 0)]),
  478. "valid_output",
  479. Polygon(),
  480. ),
  481. pytest.param(
  482. Polygon([(0, 0), (0.1, 0), (0.1, 0.1), (0, 0.1), (0, 0)]),
  483. "pointwise",
  484. Polygon([(0, 0), (0, 0), (0, 0), (0, 0), (0, 0)]),
  485. marks=pytest.mark.skipif(
  486. shapely.geos_version < (3, 10, 0),
  487. reason="pointwise does not work pre-GEOS 3.10",
  488. ),
  489. ),
  490. (
  491. Polygon([(0, 0), (0.1, 0), (0.1, 0.1), (0, 0.1), (0, 0)]),
  492. "keep_collapsed",
  493. Polygon(),
  494. ),
  495. ],
  496. )
  497. def test_set_precision_collapse(geometry, mode, expected):
  498. """Lines and polygons collapse to empty geometries if vertices are too close"""
  499. actual = shapely.set_precision(geometry, 1, mode=mode)
  500. assert_geometries_equal(
  501. # force to 2D because of various dimension issues; GEOS GH-1152
  502. shapely.force_2d(actual),
  503. expected,
  504. normalize=shapely.geos_version == (3, 9, 0),
  505. )
  506. def test_set_precision_intersection():
  507. """Operations should use the most precise precision grid size of the inputs"""
  508. box1 = shapely.normalize(shapely.box(0, 0, 0.9, 0.9))
  509. box2 = shapely.normalize(shapely.box(0.75, 0, 1.75, 0.75))
  510. assert shapely.get_precision(shapely.intersection(box1, box2)) == 0
  511. # GEOS will use and keep the most precise precision grid size
  512. box1 = shapely.set_precision(box1, 0.5)
  513. box2 = shapely.set_precision(box2, 1)
  514. out = shapely.intersection(box1, box2)
  515. assert shapely.get_precision(out) == 0.5
  516. assert_geometries_equal(out, LineString([(1, 1), (1, 0)]))
  517. @pytest.mark.parametrize("preserve_topology", [False, True])
  518. def set_precision_preserve_topology(preserve_topology):
  519. # the preserve_topology kwarg is deprecated (ignored)
  520. with pytest.warns(UserWarning):
  521. actual = shapely.set_precision(
  522. LineString([(0, 0), (0.1, 0.1)]),
  523. 1.0,
  524. preserve_topology=preserve_topology,
  525. )
  526. assert_geometries_equal(shapely.force_2d(actual), LineString())
  527. @pytest.mark.skipif(shapely.geos_version >= (3, 10, 0), reason="GEOS >= 3.10")
  528. def set_precision_pointwise_pre_310():
  529. # using 'pointwise' emits a warning
  530. with pytest.warns(UserWarning):
  531. actual = shapely.set_precision(
  532. LineString([(0, 0), (0.1, 0.1)]),
  533. 1.0,
  534. mode="pointwise",
  535. )
  536. assert_geometries_equal(shapely.force_2d(actual), LineString())
  537. @pytest.mark.parametrize("flags", [np.array([0, 1]), 4, "foo"])
  538. def set_precision_illegal_flags(flags):
  539. # the preserve_topology kwarg is deprecated (ignored)
  540. with pytest.raises((ValueError, TypeError)):
  541. shapely.lib.set_precision(line_string, 1.0, flags)
  542. def test_empty():
  543. """Compatibility with empty_like, see GH373"""
  544. g = np.empty_like(np.array([None, None]))
  545. assert shapely.is_missing(g).all()
  546. # corresponding to geometry_collection_z:
  547. geometry_collection_2 = shapely.geometrycollections([point, line_string])
  548. @pytest.mark.parametrize(
  549. "geom,expected",
  550. [
  551. (point, point),
  552. (point_z, point),
  553. (empty_point, empty_point),
  554. (empty_point_z, empty_point),
  555. (line_string, line_string),
  556. (line_string_z, line_string),
  557. (empty_line_string, empty_line_string),
  558. (empty_line_string_z, empty_line_string),
  559. (polygon, polygon),
  560. (polygon_z, polygon),
  561. (polygon_with_hole, polygon_with_hole),
  562. (polygon_with_hole_z, polygon_with_hole),
  563. (multi_point, multi_point),
  564. (multi_point_z, multi_point),
  565. (multi_line_string, multi_line_string),
  566. (multi_line_string_z, multi_line_string),
  567. (multi_polygon, multi_polygon),
  568. (multi_polygon_z, multi_polygon),
  569. (geometry_collection_2, geometry_collection_2),
  570. (geometry_collection_z, geometry_collection_2),
  571. ],
  572. )
  573. def test_force_2d(geom, expected):
  574. actual = shapely.force_2d(geom)
  575. assert shapely.get_coordinate_dimension(actual) == 2
  576. assert_geometries_equal(actual, expected)
  577. @pytest.mark.parametrize(
  578. "geom,expected",
  579. [
  580. (point, point_z),
  581. (point_z, point_z),
  582. (empty_point, empty_point_z),
  583. (empty_point_z, empty_point_z),
  584. (line_string, line_string_z),
  585. (line_string_z, line_string_z),
  586. (empty_line_string, empty_line_string_z),
  587. (empty_line_string_z, empty_line_string_z),
  588. (polygon, polygon_z),
  589. (polygon_z, polygon_z),
  590. (polygon_with_hole, polygon_with_hole_z),
  591. (polygon_with_hole_z, polygon_with_hole_z),
  592. (multi_point, multi_point_z),
  593. (multi_point_z, multi_point_z),
  594. (multi_line_string, multi_line_string_z),
  595. (multi_line_string_z, multi_line_string_z),
  596. (multi_polygon, multi_polygon_z),
  597. (multi_polygon_z, multi_polygon_z),
  598. (geometry_collection_2, geometry_collection_z),
  599. (geometry_collection_z, geometry_collection_z),
  600. ],
  601. )
  602. def test_force_3d(geom, expected):
  603. actual = shapely.force_3d(geom, z=4)
  604. assert shapely.get_coordinate_dimension(actual) == 3
  605. assert_geometries_equal(actual, expected)