268 lines
8.8 KiB
Python
268 lines
8.8 KiB
Python
import numpy as np
|
|
import pytest
|
|
from numpy.testing import assert_allclose, assert_equal
|
|
|
|
import shapely
|
|
from shapely import count_coordinates, get_coordinates, set_coordinates, transform
|
|
|
|
from .common import (
|
|
empty,
|
|
empty_line_string_z,
|
|
empty_point,
|
|
empty_point_z,
|
|
geometry_collection,
|
|
geometry_collection_z,
|
|
line_string,
|
|
line_string_z,
|
|
linear_ring,
|
|
multi_line_string,
|
|
multi_point,
|
|
multi_polygon,
|
|
point,
|
|
point_z,
|
|
polygon,
|
|
polygon_with_hole,
|
|
polygon_z,
|
|
)
|
|
|
|
nested_2 = shapely.geometrycollections([geometry_collection, point])
|
|
nested_3 = shapely.geometrycollections([nested_2, point])
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"geoms,count",
|
|
[
|
|
([], 0),
|
|
([empty], 0),
|
|
([point, empty], 1),
|
|
([empty, point, empty], 1),
|
|
([point, None], 1),
|
|
([None, point, None], 1),
|
|
([point, point], 2),
|
|
([point, point_z], 2),
|
|
([line_string, linear_ring], 8),
|
|
([polygon], 5),
|
|
([polygon_with_hole], 10),
|
|
([multi_point, multi_line_string], 4),
|
|
([multi_polygon], 10),
|
|
([geometry_collection], 3),
|
|
([nested_2], 4),
|
|
([nested_3], 5),
|
|
],
|
|
)
|
|
def test_count_coords(geoms, count):
|
|
actual = count_coordinates(np.array(geoms, np.object_))
|
|
assert actual == count
|
|
|
|
|
|
# fmt: off
|
|
@pytest.mark.parametrize("include_z", [True, False])
|
|
@pytest.mark.parametrize(
|
|
"geoms,x,y",
|
|
[
|
|
([], [], []),
|
|
([empty], [], []),
|
|
([point, empty], [2], [3]),
|
|
([empty, point, empty], [2], [3]),
|
|
([point, None], [2], [3]),
|
|
([None, point, None], [2], [3]),
|
|
([point, point], [2, 2], [3, 3]),
|
|
([line_string, linear_ring], [0, 1, 1, 0, 1, 1, 0, 0], [0, 0, 1, 0, 0, 1, 1, 0]),
|
|
([polygon], [0, 2, 2, 0, 0], [0, 0, 2, 2, 0]),
|
|
([polygon_with_hole], [0, 0, 10, 10, 0, 2, 2, 4, 4, 2], [0, 10, 10, 0, 0, 2, 4, 4, 2, 2]),
|
|
([multi_point, multi_line_string], [0, 1, 0, 1], [0, 2, 0, 2]),
|
|
([multi_polygon], [0, 1, 1, 0, 0, 2.1, 2.2, 2.2, 2.1, 2.1], [0, 0, 1, 1, 0, 2.1, 2.1, 2.2, 2.2, 2.1]),
|
|
([geometry_collection], [51, 52, 49], [-1, -1, 2]),
|
|
([nested_2], [51, 52, 49, 2], [-1, -1, 2, 3]),
|
|
([nested_3], [51, 52, 49, 2, 2], [-1, -1, 2, 3, 3]),
|
|
],
|
|
) # fmt: on
|
|
def test_get_coords(geoms, x, y, include_z):
|
|
actual = get_coordinates(np.array(geoms, np.object_), include_z=include_z)
|
|
if not include_z:
|
|
expected = np.array([x, y], np.float64).T
|
|
else:
|
|
expected = np.array([x, y, [np.nan] * len(x)], np.float64).T
|
|
assert_equal(actual, expected)
|
|
|
|
|
|
# fmt: off
|
|
@pytest.mark.parametrize(
|
|
"geoms,index",
|
|
[
|
|
([], []),
|
|
([empty], []),
|
|
([point, empty], [0]),
|
|
([empty, point, empty], [1]),
|
|
([point, None], [0]),
|
|
([None, point, None], [1]),
|
|
([point, point], [0, 1]),
|
|
([point, line_string], [0, 1, 1, 1]),
|
|
([line_string, point], [0, 0, 0, 1]),
|
|
([line_string, linear_ring], [0, 0, 0, 1, 1, 1, 1, 1]),
|
|
],
|
|
) # fmt: on
|
|
def test_get_coords_index(geoms, index):
|
|
_, actual = get_coordinates(np.array(geoms, np.object_), return_index=True)
|
|
expected = np.array(index, dtype=np.intp)
|
|
assert_equal(actual, expected)
|
|
|
|
|
|
@pytest.mark.parametrize("order", ["C", "F"])
|
|
def test_get_coords_index_multidim(order):
|
|
geometry = np.array([[point, line_string], [empty, empty]], order=order)
|
|
expected = [0, 1, 1, 1] # would be [0, 2, 2, 2] with fortran order
|
|
_, actual = get_coordinates(geometry, return_index=True)
|
|
assert_equal(actual, expected)
|
|
|
|
|
|
# fmt: off
|
|
@pytest.mark.parametrize("include_z", [True, False])
|
|
@pytest.mark.parametrize(
|
|
"geoms,x,y,z",
|
|
[
|
|
([point, point_z], [2, 2], [3, 3], [np.nan, 4]),
|
|
([line_string_z], [0, 1, 1], [0, 0, 1], [4, 4, 4]),
|
|
([polygon_z], [0, 2, 2, 0, 0], [0, 0, 2, 2, 0], [4, 4, 4, 4, 4]),
|
|
([geometry_collection_z], [2, 0, 1, 1], [3, 0, 0, 1], [4, 4, 4, 4]),
|
|
([point, empty_point], [2], [3], [np.nan]),
|
|
],
|
|
) # fmt: on
|
|
def test_get_coords_3d(geoms, x, y, z, include_z):
|
|
actual = get_coordinates(np.array(geoms, np.object_), include_z=include_z)
|
|
if include_z:
|
|
expected = np.array([x, y, z], np.float64).T
|
|
else:
|
|
expected = np.array([x, y], np.float64).T
|
|
assert_equal(actual, expected)
|
|
|
|
|
|
@pytest.mark.parametrize("include_z", [True, False])
|
|
@pytest.mark.parametrize(
|
|
"geoms,count,has_ring",
|
|
[
|
|
([], 0, False),
|
|
([empty], 0, False),
|
|
([empty_point], 0, False),
|
|
([point, empty], 1, False),
|
|
([empty, point, empty], 1, False),
|
|
([point, None], 1, False),
|
|
([None, point, None], 1, False),
|
|
([point, point], 2, False),
|
|
([point, point_z], 2, False),
|
|
([line_string, linear_ring], 8, True),
|
|
([line_string_z], 3, True),
|
|
([polygon], 5, True),
|
|
([polygon_z], 5, True),
|
|
([polygon_with_hole], 10, True),
|
|
([multi_point, multi_line_string], 4, False),
|
|
([multi_polygon], 10, True),
|
|
([geometry_collection], 3, False),
|
|
([geometry_collection_z], 3, False),
|
|
([nested_2], 4, False),
|
|
([nested_3], 5, False),
|
|
],
|
|
)
|
|
def test_set_coords(geoms, count, has_ring, include_z):
|
|
arr_geoms = np.array(geoms, np.object_)
|
|
n = 3 if include_z else 2
|
|
coords = get_coordinates(arr_geoms, include_z=include_z) + np.random.random((1, n))
|
|
new_geoms = set_coordinates(arr_geoms, coords)
|
|
assert_equal(coords, get_coordinates(new_geoms, include_z=include_z))
|
|
|
|
|
|
def test_set_coords_nan():
|
|
geoms = np.array([point])
|
|
coords = np.array([[np.nan, np.inf]])
|
|
new_geoms = set_coordinates(geoms, coords)
|
|
assert_equal(coords, get_coordinates(new_geoms))
|
|
|
|
|
|
def test_set_coords_breaks_ring():
|
|
with pytest.raises(shapely.GEOSException):
|
|
set_coordinates(linear_ring, np.random.random((5, 2)))
|
|
|
|
|
|
def test_set_coords_0dim():
|
|
# a geometry input returns a geometry
|
|
actual = set_coordinates(point, [[1, 1]])
|
|
assert isinstance(actual, shapely.Geometry)
|
|
# a 0-dim array input returns a 0-dim array
|
|
actual = set_coordinates(np.asarray(point), [[1, 1]])
|
|
assert isinstance(actual, np.ndarray)
|
|
assert actual.ndim == 0
|
|
|
|
|
|
@pytest.mark.parametrize("include_z", [True, False])
|
|
def test_set_coords_mixed_dimension(include_z):
|
|
geoms = np.array([point, point_z], dtype=object)
|
|
coords = get_coordinates(geoms, include_z=include_z)
|
|
new_geoms = set_coordinates(geoms, coords * 2)
|
|
if include_z:
|
|
# preserve original dimensionality
|
|
assert not shapely.has_z(new_geoms[0])
|
|
assert shapely.has_z(new_geoms[1])
|
|
else:
|
|
# all 2D
|
|
assert not shapely.has_z(new_geoms).any()
|
|
|
|
|
|
@pytest.mark.parametrize("include_z", [True, False])
|
|
@pytest.mark.parametrize(
|
|
"geoms",
|
|
[[], [empty], [None, point, None], [nested_3], [point, point_z], [line_string_z]],
|
|
)
|
|
def test_transform(geoms, include_z):
|
|
geoms = np.array(geoms, np.object_)
|
|
coordinates_before = get_coordinates(geoms, include_z=include_z)
|
|
new_geoms = transform(geoms, lambda x: x + 1, include_z=include_z)
|
|
assert new_geoms is not geoms
|
|
coordinates_after = get_coordinates(new_geoms, include_z=include_z)
|
|
assert_allclose(coordinates_before + 1, coordinates_after, equal_nan=True)
|
|
|
|
|
|
def test_transform_0dim():
|
|
# a geometry input returns a geometry
|
|
actual = transform(point, lambda x: x + 1)
|
|
assert isinstance(actual, shapely.Geometry)
|
|
# a 0-dim array input returns a 0-dim array
|
|
actual = transform(np.asarray(point), lambda x: x + 1)
|
|
assert isinstance(actual, np.ndarray)
|
|
assert actual.ndim == 0
|
|
|
|
|
|
def test_transform_check_shape():
|
|
def remove_coord(arr):
|
|
return arr[:-1]
|
|
|
|
with pytest.raises(ValueError):
|
|
transform(linear_ring, remove_coord)
|
|
|
|
|
|
def test_transform_correct_coordinate_dimension():
|
|
# ensure that new geometry is 2D with include_z=False
|
|
geom = line_string_z
|
|
assert shapely.get_coordinate_dimension(geom) == 3
|
|
new_geom = transform(geom, lambda x: x + 1, include_z=False)
|
|
assert shapely.get_coordinate_dimension(new_geom) == 2
|
|
|
|
|
|
@pytest.mark.parametrize("geom", [
|
|
pytest.param(empty_point_z, marks=pytest.mark.skipif(shapely.geos_version < (3, 9, 0), reason="Empty points don't have a dimensionality before GEOS 3.9")),
|
|
empty_line_string_z,
|
|
])
|
|
def test_transform_empty_preserve_z(geom):
|
|
assert shapely.get_coordinate_dimension(geom) == 3
|
|
new_geom = transform(geom, lambda x: x + 1, include_z=True)
|
|
assert shapely.get_coordinate_dimension(new_geom) == 3
|
|
|
|
|
|
@pytest.mark.parametrize("geom", [
|
|
pytest.param(empty_point_z, marks=pytest.mark.skipif(shapely.geos_version < (3, 9, 0), reason="Empty points don't have a dimensionality before GEOS 3.9")),
|
|
empty_line_string_z,
|
|
])
|
|
def test_transform_remove_z(geom):
|
|
assert shapely.get_coordinate_dimension(geom) == 3
|
|
new_geom = transform(geom, lambda x: x + 1, include_z=False)
|
|
assert shapely.get_coordinate_dimension(new_geom) == 2
|