structure saas with tools
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,95 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
import shapely
|
||||
from shapely import GeometryCollection, LineString, Point, wkt
|
||||
from shapely.geometry import shape
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def geometrycollection_geojson():
|
||||
return {
|
||||
"type": "GeometryCollection",
|
||||
"geometries": [
|
||||
{"type": "Point", "coordinates": (0, 3, 0)},
|
||||
{"type": "LineString", "coordinates": ((2, 0), (1, 0))},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"geom",
|
||||
[
|
||||
GeometryCollection(),
|
||||
GeometryCollection([]),
|
||||
shape({"type": "GeometryCollection", "geometries": []}),
|
||||
wkt.loads("GEOMETRYCOLLECTION EMPTY"),
|
||||
],
|
||||
)
|
||||
def test_empty(geom):
|
||||
assert geom.geom_type == "GeometryCollection"
|
||||
assert geom.is_empty
|
||||
assert len(geom.geoms) == 0
|
||||
assert list(geom.geoms) == []
|
||||
|
||||
|
||||
def test_empty_subgeoms():
|
||||
geom = GeometryCollection([Point(), LineString()])
|
||||
assert geom.geom_type == "GeometryCollection"
|
||||
assert geom.is_empty
|
||||
assert len(geom.geoms) == 2
|
||||
parts = list(geom.geoms)
|
||||
if shapely.geos_version < (3, 9, 0):
|
||||
# the accessed empty 2D point has a 3D coordseq on GEOS 3.8
|
||||
parts[0] = shapely.force_2d(parts[0])
|
||||
assert parts == [Point(), LineString()]
|
||||
|
||||
|
||||
def test_child_with_deleted_parent():
|
||||
# test that we can remove a collection while keeping
|
||||
# children around
|
||||
a = LineString([(0, 0), (1, 1), (1, 2), (2, 2)])
|
||||
b = LineString([(0, 0), (1, 1), (2, 1), (2, 2)])
|
||||
collection = a.intersection(b)
|
||||
|
||||
child = collection.geoms[0]
|
||||
# delete parent of child
|
||||
del collection
|
||||
|
||||
# access geometry, this should not seg fault as 1.2.15 did
|
||||
assert child.wkt is not None
|
||||
|
||||
|
||||
def test_from_numpy_array():
|
||||
geoms = np.array([Point(0, 0), LineString([(1, 1), (2, 2)])])
|
||||
geom = GeometryCollection(geoms)
|
||||
assert len(geom.geoms) == 2
|
||||
np.testing.assert_array_equal(geoms, geom.geoms)
|
||||
|
||||
|
||||
def test_from_geojson(geometrycollection_geojson):
|
||||
geom = shape(geometrycollection_geojson)
|
||||
assert geom.geom_type == "GeometryCollection"
|
||||
assert len(geom.geoms) == 2
|
||||
|
||||
geom_types = [g.geom_type for g in geom.geoms]
|
||||
assert "Point" in geom_types
|
||||
assert "LineString" in geom_types
|
||||
|
||||
|
||||
def test_geointerface(geometrycollection_geojson):
|
||||
geom = shape(geometrycollection_geojson)
|
||||
assert geom.__geo_interface__ == geometrycollection_geojson
|
||||
|
||||
|
||||
def test_len_raises(geometrycollection_geojson):
|
||||
geom = shape(geometrycollection_geojson)
|
||||
with pytest.raises(TypeError):
|
||||
len(geom)
|
||||
|
||||
|
||||
def test_numpy_object_array():
|
||||
geom = GeometryCollection([LineString([(0, 0), (1, 1)])])
|
||||
ar = np.empty(1, object)
|
||||
ar[:] = [geom]
|
||||
assert ar[0] == geom
|
||||
@@ -0,0 +1,127 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from shapely import LineString, geos_version
|
||||
from shapely.tests.common import (
|
||||
line_string,
|
||||
line_string_m,
|
||||
line_string_z,
|
||||
line_string_zm,
|
||||
point,
|
||||
point_m,
|
||||
point_z,
|
||||
point_zm,
|
||||
)
|
||||
|
||||
|
||||
class TestCoords:
|
||||
"""
|
||||
Shapely assumes contiguous C-order float64 data for internal ops.
|
||||
Data should be converted to contiguous float64 if numpy exists.
|
||||
c9a0707 broke this a little bit.
|
||||
"""
|
||||
|
||||
def test_data_promotion(self):
|
||||
coords = np.array([[12, 34], [56, 78]], dtype=np.float32)
|
||||
processed_coords = np.array(LineString(coords).coords)
|
||||
|
||||
assert coords.tolist() == processed_coords.tolist()
|
||||
|
||||
def test_data_destriding(self):
|
||||
coords = np.array([[12, 34], [56, 78]], dtype=np.float32)
|
||||
|
||||
# Easy way to introduce striding: reverse list order
|
||||
processed_coords = np.array(LineString(coords[::-1]).coords)
|
||||
|
||||
assert coords[::-1].tolist() == processed_coords.tolist()
|
||||
|
||||
|
||||
class TestCoordsGetItem:
|
||||
def test_index_coords(self):
|
||||
c = [(float(x), float(-x)) for x in range(4)]
|
||||
g = LineString(c)
|
||||
for i in range(-4, 4):
|
||||
assert g.coords[i] == c[i]
|
||||
with pytest.raises(IndexError):
|
||||
g.coords[4]
|
||||
with pytest.raises(IndexError):
|
||||
g.coords[-5]
|
||||
|
||||
def test_index_coords_z(self):
|
||||
c = [(float(x), float(-x), float(x * 2)) for x in range(4)]
|
||||
g = LineString(c)
|
||||
for i in range(-4, 4):
|
||||
assert g.coords[i] == c[i]
|
||||
with pytest.raises(IndexError):
|
||||
g.coords[4]
|
||||
with pytest.raises(IndexError):
|
||||
g.coords[-5]
|
||||
|
||||
def test_index_coords_misc(self):
|
||||
g = LineString() # empty
|
||||
with pytest.raises(IndexError):
|
||||
g.coords[0]
|
||||
with pytest.raises(TypeError):
|
||||
g.coords[0.0]
|
||||
|
||||
def test_slice_coords(self):
|
||||
c = [(float(x), float(-x)) for x in range(4)]
|
||||
g = LineString(c)
|
||||
assert g.coords[1:] == c[1:]
|
||||
assert g.coords[:-1] == c[:-1]
|
||||
assert g.coords[::-1] == c[::-1]
|
||||
assert g.coords[::2] == c[::2]
|
||||
assert g.coords[:4] == c[:4]
|
||||
assert g.coords[4:] == c[4:] == []
|
||||
|
||||
def test_slice_coords_z(self):
|
||||
c = [(float(x), float(-x), float(x * 2)) for x in range(4)]
|
||||
g = LineString(c)
|
||||
assert g.coords[1:] == c[1:]
|
||||
assert g.coords[:-1] == c[:-1]
|
||||
assert g.coords[::-1] == c[::-1]
|
||||
assert g.coords[::2] == c[::2]
|
||||
assert g.coords[:4] == c[:4]
|
||||
assert g.coords[4:] == c[4:] == []
|
||||
|
||||
|
||||
class TestXY:
|
||||
"""New geometry/coordseq method 'xy' makes numpy interop easier"""
|
||||
|
||||
def test_arrays(self):
|
||||
x, y = LineString([(0, 0), (1, 1)]).xy
|
||||
assert len(x) == 2
|
||||
assert list(x) == [0.0, 1.0]
|
||||
assert len(y) == 2
|
||||
assert list(y) == [0.0, 1.0]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("geom", [point, point_z, line_string, line_string_z])
|
||||
def test_coords_array_copy(geom):
|
||||
"""Test CoordinateSequence.__array__ method."""
|
||||
coord_seq = geom.coords
|
||||
assert np.array(coord_seq) is not np.array(coord_seq)
|
||||
assert np.array(coord_seq, copy=True) is not np.array(coord_seq, copy=True)
|
||||
|
||||
# Behaviour of copy=False is different between NumPy 1.x and 2.x
|
||||
if int(np.version.short_version.split(".", 1)[0]) >= 2:
|
||||
with pytest.raises(ValueError, match="A copy is always created"):
|
||||
np.array(coord_seq, copy=False)
|
||||
else:
|
||||
assert np.array(coord_seq, copy=False) is np.array(coord_seq, copy=False)
|
||||
|
||||
|
||||
@pytest.mark.skipif(geos_version < (3, 12, 0), reason="GEOS < 3.12")
|
||||
def test_coords_with_m():
|
||||
assert point_m.coords[:] == [(2.0, 3.0, 5.0)]
|
||||
assert point_zm.coords[:] == [(2.0, 3.0, 4.0, 5.0)]
|
||||
assert line_string_m.coords[:] == [
|
||||
(0.0, 0.0, 1.0),
|
||||
(1.0, 0.0, 2.0),
|
||||
(1.0, 1.0, 3.0),
|
||||
]
|
||||
assert line_string_zm.coords[:] == [
|
||||
(0.0, 0.0, 4.0, 1.0),
|
||||
(1.0, 0.0, 4.0, 2.0),
|
||||
(1.0, 1.0, 4.0, 3.0),
|
||||
]
|
||||
@@ -0,0 +1,117 @@
|
||||
from decimal import Decimal
|
||||
|
||||
import pytest
|
||||
|
||||
from shapely import (
|
||||
GeometryCollection,
|
||||
LinearRing,
|
||||
LineString,
|
||||
MultiLineString,
|
||||
MultiPoint,
|
||||
MultiPolygon,
|
||||
Point,
|
||||
Polygon,
|
||||
)
|
||||
|
||||
items2d = [
|
||||
[(0.0, 0.0), (70.0, 120.0), (140.0, 0.0), (0.0, 0.0)],
|
||||
[(60.0, 80.0), (80.0, 80.0), (70.0, 60.0), (60.0, 80.0)],
|
||||
]
|
||||
|
||||
items2d_mixed = [
|
||||
[
|
||||
(Decimal("0.0"), Decimal("0.0")),
|
||||
(Decimal("70.0"), 120.0),
|
||||
(140.0, Decimal("0.0")),
|
||||
(0.0, 0.0),
|
||||
],
|
||||
[
|
||||
(Decimal("60.0"), Decimal("80.0")),
|
||||
(Decimal("80.0"), 80.0),
|
||||
(70.0, Decimal("60.0")),
|
||||
(60.0, 80.0),
|
||||
],
|
||||
]
|
||||
|
||||
items2d_decimal = [
|
||||
[
|
||||
(Decimal("0.0"), Decimal("0.0")),
|
||||
(Decimal("70.0"), Decimal("120.0")),
|
||||
(Decimal("140.0"), Decimal("0.0")),
|
||||
(Decimal("0.0"), Decimal("0.0")),
|
||||
],
|
||||
[
|
||||
(Decimal("60.0"), Decimal("80.0")),
|
||||
(Decimal("80.0"), Decimal("80.0")),
|
||||
(Decimal("70.0"), Decimal("60.0")),
|
||||
(Decimal("60.0"), Decimal("80.0")),
|
||||
],
|
||||
]
|
||||
|
||||
items3d = [
|
||||
[(0.0, 0.0, 1), (70.0, 120.0, 2), (140.0, 0.0, 3), (0.0, 0.0, 1)],
|
||||
[(60.0, 80.0, 1), (80.0, 80.0, 2), (70.0, 60.0, 3), (60.0, 80.0, 1)],
|
||||
]
|
||||
|
||||
items3d_mixed = [
|
||||
[
|
||||
(Decimal("0.0"), Decimal("0.0"), Decimal(1)),
|
||||
(Decimal("70.0"), 120.0, Decimal(2)),
|
||||
(140.0, Decimal("0.0"), 3),
|
||||
(0.0, 0.0, 1),
|
||||
],
|
||||
[
|
||||
(Decimal("60.0"), Decimal("80.0"), Decimal(1)),
|
||||
(Decimal("80.0"), 80.0, 2),
|
||||
(70.0, Decimal("60.0"), Decimal(3)),
|
||||
(60.0, 80.0, 1),
|
||||
],
|
||||
]
|
||||
|
||||
items3d_decimal = [
|
||||
[
|
||||
(Decimal("0.0"), Decimal("0.0"), Decimal(1)),
|
||||
(Decimal("70.0"), Decimal("120.0"), Decimal(2)),
|
||||
(Decimal("140.0"), Decimal("0.0"), Decimal(3)),
|
||||
(Decimal("0.0"), Decimal("0.0"), Decimal(1)),
|
||||
],
|
||||
[
|
||||
(Decimal("60.0"), Decimal("80.0"), Decimal(1)),
|
||||
(Decimal("80.0"), Decimal("80.0"), Decimal(2)),
|
||||
(Decimal("70.0"), Decimal("60.0"), Decimal(3)),
|
||||
(Decimal("60.0"), Decimal("80.0"), Decimal(1)),
|
||||
],
|
||||
]
|
||||
|
||||
all_geoms = [
|
||||
[
|
||||
Point(items[0][0]),
|
||||
Point(*items[0][0]),
|
||||
MultiPoint(items[0]),
|
||||
LinearRing(items[0]),
|
||||
LineString(items[0]),
|
||||
MultiLineString(items),
|
||||
Polygon(items[0]),
|
||||
MultiPolygon(
|
||||
[
|
||||
Polygon(items[1]),
|
||||
Polygon(items[0], holes=items[1:]),
|
||||
]
|
||||
),
|
||||
GeometryCollection([Point(items[0][0]), Polygon(items[0])]),
|
||||
]
|
||||
for items in [
|
||||
items2d,
|
||||
items2d_mixed,
|
||||
items2d_decimal,
|
||||
items3d,
|
||||
items3d_mixed,
|
||||
items3d_decimal,
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("geoms", list(zip(*all_geoms)))
|
||||
def test_decimal(geoms):
|
||||
assert geoms[0] == geoms[1] == geoms[2]
|
||||
assert geoms[3] == geoms[4] == geoms[5]
|
||||
@@ -0,0 +1,98 @@
|
||||
import math
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from shapely import (
|
||||
GeometryCollection,
|
||||
LinearRing,
|
||||
LineString,
|
||||
MultiLineString,
|
||||
MultiPoint,
|
||||
MultiPolygon,
|
||||
Point,
|
||||
Polygon,
|
||||
)
|
||||
from shapely.geometry import mapping, shape
|
||||
from shapely.geometry.base import BaseGeometry, EmptyGeometry
|
||||
|
||||
|
||||
def empty_generator():
|
||||
return iter([])
|
||||
|
||||
|
||||
class TestEmptiness:
|
||||
def test_empty_class(self):
|
||||
with pytest.warns(FutureWarning):
|
||||
g = EmptyGeometry()
|
||||
assert g.is_empty
|
||||
|
||||
def test_empty_base(self):
|
||||
with pytest.warns(FutureWarning):
|
||||
g = BaseGeometry()
|
||||
assert g.is_empty
|
||||
|
||||
def test_empty_point(self):
|
||||
assert Point().is_empty
|
||||
|
||||
def test_empty_multipoint(self):
|
||||
assert MultiPoint().is_empty
|
||||
|
||||
def test_empty_geometry_collection(self):
|
||||
assert GeometryCollection().is_empty
|
||||
|
||||
def test_empty_linestring(self):
|
||||
assert LineString().is_empty
|
||||
assert LineString(None).is_empty
|
||||
assert LineString([]).is_empty
|
||||
assert LineString(empty_generator()).is_empty
|
||||
|
||||
def test_empty_multilinestring(self):
|
||||
assert MultiLineString([]).is_empty
|
||||
|
||||
def test_empty_polygon(self):
|
||||
assert Polygon().is_empty
|
||||
assert Polygon(None).is_empty
|
||||
assert Polygon([]).is_empty
|
||||
assert Polygon(empty_generator()).is_empty
|
||||
|
||||
def test_empty_multipolygon(self):
|
||||
assert MultiPolygon([]).is_empty
|
||||
|
||||
def test_empty_linear_ring(self):
|
||||
assert LinearRing().is_empty
|
||||
assert LinearRing(None).is_empty
|
||||
assert LinearRing([]).is_empty
|
||||
assert LinearRing(empty_generator()).is_empty
|
||||
|
||||
|
||||
def test_numpy_object_array():
|
||||
geoms = [Point(), GeometryCollection()]
|
||||
arr = np.empty(2, object)
|
||||
arr[:] = geoms
|
||||
|
||||
|
||||
def test_shape_empty():
|
||||
empty_mp = MultiPolygon()
|
||||
empty_json = mapping(empty_mp)
|
||||
empty_shape = shape(empty_json)
|
||||
assert empty_shape.is_empty
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"geom",
|
||||
[
|
||||
Point(),
|
||||
LineString(),
|
||||
Polygon(),
|
||||
MultiPoint(),
|
||||
MultiLineString(),
|
||||
MultiPolygon(),
|
||||
GeometryCollection(),
|
||||
LinearRing(),
|
||||
],
|
||||
)
|
||||
def test_empty_geometry_bounds(geom):
|
||||
"""The bounds of an empty geometry is a tuple of NaNs"""
|
||||
assert len(geom.bounds) == 4
|
||||
assert all(math.isnan(v) for v in geom.bounds)
|
||||
@@ -0,0 +1,284 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
import shapely
|
||||
from shapely import LinearRing, LineString, MultiLineString, Point, Polygon
|
||||
from shapely.tests.common import all_types, all_types_z, empty_point, ignore_invalid
|
||||
|
||||
all_non_empty_types = np.array(all_types + all_types_z)[
|
||||
~shapely.is_empty(all_types + all_types_z)
|
||||
]
|
||||
|
||||
|
||||
# TODO add all_types_m and all_types_zm once tranform supports M coordinates
|
||||
@pytest.mark.parametrize("geom", all_types + all_types_z)
|
||||
def test_equality(geom):
|
||||
assert geom == geom # noqa: PLR0124
|
||||
transformed = shapely.transform(geom, lambda x: x, include_z=True)
|
||||
if (
|
||||
shapely.geos_version < (3, 9, 0)
|
||||
and isinstance(geom, Point)
|
||||
and geom.is_empty
|
||||
and not geom.has_z
|
||||
):
|
||||
# the transformed empty 2D point has become 3D on GEOS 3.8
|
||||
transformed = shapely.force_2d(geom)
|
||||
assert geom == transformed
|
||||
assert not (geom != transformed)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"left, right",
|
||||
# automated test cases with transformed coordinate values
|
||||
[(geom, shapely.transform(geom, lambda x: x + 1)) for geom in all_non_empty_types]
|
||||
+ [
|
||||
# (slightly) different coordinate values
|
||||
(LineString([(0, 0), (1, 1)]), LineString([(0, 0), (1, 2)])),
|
||||
(LineString([(0, 0), (1, 1)]), LineString([(0, 0), (1, 1 + 1e-12)])),
|
||||
# different coordinate order
|
||||
(LineString([(0, 0), (1, 1)]), LineString([(1, 1), (0, 0)])),
|
||||
# different number of coordinates (but spatially equal)
|
||||
(LineString([(0, 0), (1, 1)]), LineString([(0, 0), (1, 1), (1, 1)])),
|
||||
(LineString([(0, 0), (1, 1)]), LineString([(0, 0), (0.5, 0.5), (1, 1)])),
|
||||
# different order of sub-geometries
|
||||
(
|
||||
MultiLineString([[(1, 1), (2, 2)], [(2, 2), (3, 3)]]),
|
||||
MultiLineString([[(2, 2), (3, 3)], [(1, 1), (2, 2)]]),
|
||||
),
|
||||
# M coordinates (don't work yet with automated cases)
|
||||
pytest.param(
|
||||
shapely.from_wkt("POINT M (0 0 0)"),
|
||||
shapely.from_wkt("POINT M (0 0 1)"),
|
||||
marks=pytest.mark.skipif(
|
||||
shapely.geos_version < (3, 12, 0), reason="GEOS < 3.12"
|
||||
),
|
||||
),
|
||||
pytest.param(
|
||||
shapely.from_wkt("POINT ZM (0 0 0 0)"),
|
||||
shapely.from_wkt("POINT ZM (0 0 0 1)"),
|
||||
marks=pytest.mark.skipif(
|
||||
shapely.geos_version < (3, 12, 0), reason="GEOS < 3.12"
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_equality_false(left, right):
|
||||
assert left != right
|
||||
assert not (left == right)
|
||||
|
||||
|
||||
with ignore_invalid():
|
||||
cases1 = [
|
||||
(LineString([(0, 1), (2, np.nan)]), LineString([(0, 1), (2, np.nan)])),
|
||||
(
|
||||
LineString([(0, 1), (np.nan, np.nan)]),
|
||||
LineString([(0, 1), (np.nan, np.nan)]),
|
||||
),
|
||||
(LineString([(np.nan, 1), (2, 3)]), LineString([(np.nan, 1), (2, 3)])),
|
||||
(LineString([(0, np.nan), (2, 3)]), LineString([(0, np.nan), (2, 3)])),
|
||||
(
|
||||
LineString([(np.nan, np.nan), (np.nan, np.nan)]),
|
||||
LineString([(np.nan, np.nan), (np.nan, np.nan)]),
|
||||
),
|
||||
# NaN as explicit Z coordinate
|
||||
# TODO: if first z is NaN -> considered as 2D -> tested below explicitly
|
||||
# (
|
||||
# LineString([(0, 1, np.nan), (2, 3, np.nan)]),
|
||||
# LineString([(0, 1, np.nan), (2, 3, np.nan)]),
|
||||
# ),
|
||||
(
|
||||
LineString([(0, 1, 2), (2, 3, np.nan)]),
|
||||
LineString([(0, 1, 2), (2, 3, np.nan)]),
|
||||
),
|
||||
# (
|
||||
# LineString([(0, 1, np.nan), (2, 3, 4)]),
|
||||
# LineString([(0, 1, np.nan), (2, 3, 4)]),
|
||||
# ),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("left, right", cases1)
|
||||
def test_equality_with_nan(left, right):
|
||||
assert left == right
|
||||
assert not (left != right)
|
||||
|
||||
|
||||
with ignore_invalid():
|
||||
cases2 = [
|
||||
(
|
||||
LineString([(0, 1, np.nan), (2, 3, np.nan)]),
|
||||
LineString([(0, 1, np.nan), (2, 3, np.nan)]),
|
||||
),
|
||||
(
|
||||
LineString([(0, 1, np.nan), (2, 3, 4)]),
|
||||
LineString([(0, 1, np.nan), (2, 3, 4)]),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("left, right", cases2)
|
||||
def test_equality_with_nan_z(left, right):
|
||||
assert left == right
|
||||
assert not (left != right)
|
||||
|
||||
|
||||
with ignore_invalid():
|
||||
cases3 = [
|
||||
(LineString([(0, np.nan), (2, 3)]), LineString([(0, 1), (2, 3)])),
|
||||
(LineString([(0, 1), (2, np.nan)]), LineString([(0, 1), (2, 3)])),
|
||||
(LineString([(0, 1, np.nan), (2, 3, 4)]), LineString([(0, 1, 2), (2, 3, 4)])),
|
||||
(LineString([(0, 1, 2), (2, 3, np.nan)]), LineString([(0, 1, 2), (2, 3, 4)])),
|
||||
pytest.param(
|
||||
shapely.from_wkt("POINT M (0 0 0)"),
|
||||
shapely.from_wkt("POINT M (0 0 NaN)"),
|
||||
marks=pytest.mark.skipif(
|
||||
shapely.geos_version < (3, 12, 0), reason="GEOS < 3.12"
|
||||
),
|
||||
),
|
||||
pytest.param(
|
||||
shapely.from_wkt("POINT ZM (0 0 0 0)"),
|
||||
shapely.from_wkt("POINT ZM (0 0 0 NaN)"),
|
||||
marks=pytest.mark.skipif(
|
||||
shapely.geos_version < (3, 12, 0), reason="GEOS < 3.12"
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("left, right", cases3)
|
||||
def test_equality_with_nan_false(left, right):
|
||||
assert left != right
|
||||
|
||||
|
||||
def test_equality_with_nan_z_false():
|
||||
with ignore_invalid():
|
||||
left = LineString([(0, 1, np.nan), (2, 3, np.nan)])
|
||||
right = LineString([(0, 1, np.nan), (2, 3, 4)])
|
||||
|
||||
if shapely.geos_version < (3, 10, 0):
|
||||
# GEOS <= 3.9 fill the NaN with 0, so the z dimension is different
|
||||
assert left != right
|
||||
elif shapely.geos_version < (3, 12, 0):
|
||||
# GEOS 3.10-3.11 ignore NaN for Z also when explicitly created with 3D
|
||||
# and so the geometries are considered as 2D (and thus z dimension is ignored)
|
||||
assert left == right
|
||||
else:
|
||||
assert left != right
|
||||
|
||||
|
||||
def test_equality_z():
|
||||
# different dimensionality
|
||||
geom1 = Point(0, 1)
|
||||
geom2 = Point(0, 1, 0)
|
||||
assert geom1 != geom2
|
||||
|
||||
# different dimensionality with NaN z
|
||||
geom2 = Point(0, 1, np.nan)
|
||||
if shapely.geos_version < (3, 12, 0):
|
||||
# GEOS 3.10-3.11 ignore NaN for Z also when explicitly created with 3D
|
||||
# and so the geometries are considered as 2D (and thus z dimension is ignored)
|
||||
assert geom1 == geom2
|
||||
else:
|
||||
assert geom1 != geom2
|
||||
|
||||
|
||||
def test_equality_exact_type():
|
||||
# geometries with different type but same coord seq are not equal
|
||||
geom1 = LineString([(0, 0), (1, 1), (0, 1), (0, 0)])
|
||||
geom2 = LinearRing([(0, 0), (1, 1), (0, 1), (0, 0)])
|
||||
geom3 = Polygon([(0, 0), (1, 1), (0, 1), (0, 0)])
|
||||
assert geom1 != geom2
|
||||
assert geom1 != geom3
|
||||
assert geom2 != geom3
|
||||
|
||||
# empty with different type
|
||||
geom1 = shapely.from_wkt("POINT EMPTY")
|
||||
geom2 = shapely.from_wkt("LINESTRING EMPTY")
|
||||
assert geom1 != geom2
|
||||
|
||||
|
||||
def test_equality_polygon():
|
||||
# different exterior rings
|
||||
geom1 = shapely.from_wkt("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))")
|
||||
geom2 = shapely.from_wkt("POLYGON ((0 0, 10 0, 10 10, 0 15, 0 0))")
|
||||
assert geom1 != geom2
|
||||
|
||||
# different number of holes
|
||||
geom1 = shapely.from_wkt(
|
||||
"POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (1 1, 2 1, 2 2, 1 1))"
|
||||
)
|
||||
geom2 = shapely.from_wkt(
|
||||
"POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (1 1, 2 1, 2 2, 1 1), "
|
||||
"(3 3, 4 3, 4 4, 3 3))"
|
||||
)
|
||||
assert geom1 != geom2
|
||||
|
||||
# different order of holes
|
||||
geom1 = shapely.from_wkt(
|
||||
"POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (3 3, 4 3, 4 4, 3 3), "
|
||||
"(1 1, 2 1, 2 2, 1 1))"
|
||||
)
|
||||
geom2 = shapely.from_wkt(
|
||||
"POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0), (1 1, 2 1, 2 2, 1 1), "
|
||||
"(3 3, 4 3, 4 4, 3 3))"
|
||||
)
|
||||
assert geom1 != geom2
|
||||
|
||||
|
||||
@pytest.mark.parametrize("geom", all_types)
|
||||
def test_comparison_notimplemented(geom):
|
||||
# comparing to a non-geometry class should return NotImplemented in __eq__
|
||||
# to ensure proper delegation to other (eg to ensure comparison of scalar
|
||||
# with array works)
|
||||
# https://github.com/shapely/shapely/issues/1056
|
||||
assert geom.__eq__(1) is NotImplemented
|
||||
|
||||
# with array
|
||||
arr = np.array([geom, geom], dtype=object)
|
||||
|
||||
result = arr == geom
|
||||
assert isinstance(result, np.ndarray)
|
||||
assert result.all()
|
||||
|
||||
result = geom == arr
|
||||
assert isinstance(result, np.ndarray)
|
||||
assert result.all()
|
||||
|
||||
result = arr != geom
|
||||
assert isinstance(result, np.ndarray)
|
||||
assert not result.any()
|
||||
|
||||
result = geom != arr
|
||||
assert isinstance(result, np.ndarray)
|
||||
assert not result.any()
|
||||
|
||||
|
||||
def test_comparison_not_supported():
|
||||
geom1 = Point(1, 1)
|
||||
geom2 = Point(2, 2)
|
||||
|
||||
with pytest.raises(TypeError, match="not supported between instances"):
|
||||
assert geom1 > geom2
|
||||
|
||||
with pytest.raises(TypeError, match="not supported between instances"):
|
||||
assert geom1 < geom2
|
||||
|
||||
with pytest.raises(TypeError, match="not supported between instances"):
|
||||
assert geom1 >= geom2
|
||||
|
||||
with pytest.raises(TypeError, match="not supported between instances"):
|
||||
assert geom1 <= geom2
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"geom", all_types + (shapely.points(np.nan, np.nan), empty_point)
|
||||
)
|
||||
def test_hash_same_equal(geom):
|
||||
hash1 = hash(geom)
|
||||
hash2 = hash(shapely.transform(geom, lambda x: x))
|
||||
assert hash1 == hash2, geom
|
||||
|
||||
|
||||
@pytest.mark.parametrize("geom", all_non_empty_types)
|
||||
def test_hash_same_not_equal(geom):
|
||||
assert hash(geom) != hash(shapely.transform(geom, lambda x: x + 1))
|
||||
@@ -0,0 +1,118 @@
|
||||
import pytest
|
||||
|
||||
from shapely import Point, Polygon, geos_version
|
||||
|
||||
|
||||
def test_format_invalid():
|
||||
# check invalid spec formats
|
||||
pt = Point(1, 2)
|
||||
test_list = [
|
||||
("5G", ValueError, "invalid format specifier"),
|
||||
(".f", ValueError, "invalid format specifier"),
|
||||
("0.2e", ValueError, "invalid format specifier"),
|
||||
(".1x", ValueError, "hex representation does not specify precision"),
|
||||
]
|
||||
for format_spec, err, match in test_list:
|
||||
with pytest.raises(err, match=match):
|
||||
format(pt, format_spec)
|
||||
|
||||
|
||||
def get_tst_format_point_params():
|
||||
xy1 = (0.12345678901234567, 1.2345678901234567e10)
|
||||
xy2 = (-169.910918, -18.997564)
|
||||
xyz3 = (630084, 4833438, 76)
|
||||
test_list = [
|
||||
(".0f", xy1, "POINT (0 12345678901)", True),
|
||||
(".1f", xy1, "POINT (0.1 12345678901.2)", True),
|
||||
("0.2f", xy2, "POINT (-169.91 -19.00)", True),
|
||||
(".3F", (float("inf"), -float("inf")), "POINT (INF -INF)", True),
|
||||
]
|
||||
if geos_version < (3, 10, 0):
|
||||
# 'g' format varies depending on GEOS version
|
||||
test_list += [
|
||||
(".1g", xy1, "POINT (0.1 1e+10)", True),
|
||||
(".6G", xy1, "POINT (0.123457 1.23457E+10)", True),
|
||||
("0.12g", xy1, "POINT (0.123456789012 12345678901.2)", True),
|
||||
("0.4g", xy2, "POINT (-169.9 -19)", True),
|
||||
]
|
||||
else:
|
||||
test_list += [
|
||||
(".1g", xy1, "POINT (0.1 12345678901.2)", False),
|
||||
(".6G", xy1, "POINT (0.123457 12345678901.234568)", False),
|
||||
("0.12g", xy1, "POINT (0.123456789012 12345678901.234568)", False),
|
||||
("g", xy2, "POINT (-169.910918 -18.997564)", False),
|
||||
("0.2g", xy2, "POINT (-169.91 -19)", False),
|
||||
]
|
||||
# without precisions test GEOS rounding_precision=-1; different than Python
|
||||
test_list += [
|
||||
("f", (1, 2), f"POINT ({1:.16f} {2:.16f})", False),
|
||||
("F", xyz3, "POINT Z ({:.16f} {:.16f} {:.16f})".format(*xyz3), False),
|
||||
("g", xyz3, "POINT Z (630084 4833438 76)", False),
|
||||
]
|
||||
return test_list
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"format_spec, coords, expt_wkt, same_python_float", get_tst_format_point_params()
|
||||
)
|
||||
def test_format_point(format_spec, coords, expt_wkt, same_python_float):
|
||||
pt = Point(*coords)
|
||||
# basic checks
|
||||
assert f"{pt}" == pt.wkt
|
||||
assert format(pt, "") == pt.wkt
|
||||
assert format(pt, "x") == pt.wkb_hex.lower()
|
||||
assert format(pt, "X") == pt.wkb_hex
|
||||
# check formatted WKT to expected
|
||||
assert format(pt, format_spec) == expt_wkt, format_spec
|
||||
# check Python's format consistency
|
||||
text_coords = expt_wkt[expt_wkt.index("(") + 1 : expt_wkt.index(")")]
|
||||
is_same = []
|
||||
for coord, expt_coord in zip(coords, text_coords.split()):
|
||||
py_fmt_float = format(float(coord), format_spec)
|
||||
if same_python_float:
|
||||
assert py_fmt_float == expt_coord, format_spec
|
||||
else:
|
||||
is_same.append(py_fmt_float == expt_coord)
|
||||
if not same_python_float:
|
||||
assert not all(is_same), f"{format_spec!r} with {expt_wkt}"
|
||||
|
||||
|
||||
def test_format_polygon():
|
||||
# check basic cases
|
||||
poly = Point(0, 0).buffer(10, quad_segs=2)
|
||||
assert f"{poly}" == poly.wkt
|
||||
assert format(poly, "") == poly.wkt
|
||||
assert format(poly, "x") == poly.wkb_hex.lower()
|
||||
assert format(poly, "X") == poly.wkb_hex
|
||||
|
||||
# Use f-strings with extra characters and rounding precision
|
||||
if geos_version < (3, 13, 0):
|
||||
assert f"<{poly:.2f}>" == (
|
||||
"<POLYGON ((10.00 0.00, 7.07 -7.07, 0.00 -10.00, -7.07 -7.07, "
|
||||
"-10.00 -0.00, -7.07 7.07, -0.00 10.00, 7.07 7.07, 10.00 0.00))>"
|
||||
)
|
||||
else:
|
||||
assert f"<{poly:.2f}>" == (
|
||||
"<POLYGON ((10.00 0.00, 7.07 -7.07, 0.00 -10.00, -7.07 -7.07, "
|
||||
"-10.00 0.00, -7.07 7.07, 0.00 10.00, 7.07 7.07, 10.00 0.00))>"
|
||||
)
|
||||
|
||||
# 'g' format varies depending on GEOS version
|
||||
if geos_version < (3, 10, 0):
|
||||
assert f"{poly:.2G}" == (
|
||||
"POLYGON ((10 0, 7.1 -7.1, 1.6E-14 -10, -7.1 -7.1, "
|
||||
"-10 -3.2E-14, -7.1 7.1, -4.6E-14 10, 7.1 7.1, 10 0))"
|
||||
)
|
||||
else:
|
||||
assert f"{poly:.2G}" == (
|
||||
"POLYGON ((10 0, 7.07 -7.07, 0 -10, -7.07 -7.07, "
|
||||
"-10 0, -7.07 7.07, 0 10, 7.07 7.07, 10 0))"
|
||||
)
|
||||
|
||||
# check empty
|
||||
empty = Polygon()
|
||||
assert f"{empty}" == "POLYGON EMPTY"
|
||||
assert format(empty, "") == empty.wkt
|
||||
assert format(empty, ".2G") == empty.wkt
|
||||
assert format(empty, "x") == empty.wkb_hex.lower()
|
||||
assert format(empty, "X") == empty.wkb_hex
|
||||
@@ -0,0 +1,369 @@
|
||||
import platform
|
||||
import weakref
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
import shapely
|
||||
from shapely import (
|
||||
GeometryCollection,
|
||||
LinearRing,
|
||||
LineString,
|
||||
MultiLineString,
|
||||
MultiPoint,
|
||||
MultiPolygon,
|
||||
Point,
|
||||
Polygon,
|
||||
)
|
||||
from shapely.errors import ShapelyDeprecationWarning
|
||||
from shapely.testing import assert_geometries_equal
|
||||
|
||||
|
||||
def test_polygon():
|
||||
assert bool(Polygon()) is False
|
||||
|
||||
|
||||
def test_linestring():
|
||||
assert bool(LineString()) is False
|
||||
|
||||
|
||||
def test_point():
|
||||
assert bool(Point()) is False
|
||||
|
||||
|
||||
def test_geometry_collection():
|
||||
assert bool(GeometryCollection()) is False
|
||||
|
||||
|
||||
geometries_all_types = [
|
||||
Point(1, 1),
|
||||
LinearRing([(0, 0), (1, 1), (0, 1), (0, 0)]),
|
||||
LineString([(0, 0), (1, 1), (0, 1), (0, 0)]),
|
||||
Polygon([(0, 0), (1, 1), (0, 1), (0, 0)]),
|
||||
MultiPoint([(1, 1)]),
|
||||
MultiLineString([[(0, 0), (1, 1), (0, 1), (0, 0)]]),
|
||||
MultiPolygon([Polygon([(0, 0), (1, 1), (0, 1), (0, 0)])]),
|
||||
GeometryCollection([Point(1, 1)]),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
platform.python_implementation() == "PyPy",
|
||||
reason="Setting custom attributes doesn't fail on PyPy",
|
||||
)
|
||||
@pytest.mark.parametrize("geom", geometries_all_types)
|
||||
def test_setattr_disallowed(geom):
|
||||
with pytest.raises(AttributeError):
|
||||
geom.name = "test"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("geom", geometries_all_types)
|
||||
def test_weakrefable(geom):
|
||||
_ = weakref.ref(geom)
|
||||
|
||||
|
||||
def test_base_class_not_callable():
|
||||
with pytest.raises(TypeError):
|
||||
shapely.Geometry("POINT (1 1)")
|
||||
|
||||
|
||||
def test_GeometryType_deprecated():
|
||||
geom = Point(1, 1)
|
||||
|
||||
with pytest.warns(ShapelyDeprecationWarning):
|
||||
geom_type = geom.geometryType()
|
||||
|
||||
assert geom_type == geom.geom_type
|
||||
|
||||
|
||||
def test_type_deprecated():
|
||||
geom = Point(1, 1)
|
||||
|
||||
with pytest.warns(ShapelyDeprecationWarning):
|
||||
geom_type = geom.type
|
||||
|
||||
assert geom_type == geom.geom_type
|
||||
|
||||
|
||||
@pytest.mark.skipif(shapely.geos_version < (3, 10, 0), reason="GEOS < 3.10")
|
||||
def test_segmentize():
|
||||
line = LineString([(0, 0), (0, 10)])
|
||||
result = line.segmentize(max_segment_length=5)
|
||||
assert result.equals(LineString([(0, 0), (0, 5), (0, 10)]))
|
||||
|
||||
|
||||
def test_reverse():
|
||||
coords = [(0, 0), (1, 2)]
|
||||
line = LineString(coords)
|
||||
result = line.reverse()
|
||||
assert result.coords[:] == coords[::-1]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"op", ["union", "intersection", "difference", "symmetric_difference"]
|
||||
)
|
||||
@pytest.mark.parametrize("grid_size", [0, 1, 2])
|
||||
def test_binary_op_grid_size(op, grid_size):
|
||||
geom1 = shapely.box(0, 0, 2.5, 2.5)
|
||||
geom2 = shapely.box(2, 2, 3, 3)
|
||||
|
||||
result = getattr(geom1, op)(geom2, grid_size=grid_size)
|
||||
expected = getattr(shapely, op)(geom1, geom2, grid_size=grid_size)
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.skipif(shapely.geos_version < (3, 10, 0), reason="GEOS < 3.10")
|
||||
def test_dwithin():
|
||||
point = Point(1, 1)
|
||||
line = LineString([(0, 0), (0, 10)])
|
||||
assert point.dwithin(line, 0.5) is False
|
||||
assert point.dwithin(line, 1.5) is True
|
||||
|
||||
|
||||
def test_contains_properly():
|
||||
polygon = Polygon([(0, 0), (10, 10), (10, -10)])
|
||||
line = LineString([(0, 0), (10, 0)])
|
||||
assert polygon.contains_properly(line) is False
|
||||
assert polygon.contains(line) is True
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"op", ["convex_hull", "envelope", "oriented_envelope", "minimum_rotated_rectangle"]
|
||||
)
|
||||
def test_constructive_properties(op):
|
||||
geom = LineString([(0, 0), (0, 10), (10, 10)])
|
||||
result = getattr(geom, op)
|
||||
expected = getattr(shapely, op)(geom)
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"op",
|
||||
[
|
||||
"crosses",
|
||||
"contains",
|
||||
"contains_properly",
|
||||
"covered_by",
|
||||
"covers",
|
||||
"disjoint",
|
||||
"equals",
|
||||
"intersects",
|
||||
"overlaps",
|
||||
"touches",
|
||||
"within",
|
||||
],
|
||||
)
|
||||
def test_array_argument_binary_predicates(op):
|
||||
polygon = Polygon([(0, 0), (0, 1), (1, 1), (1, 0), (0, 0)])
|
||||
points = shapely.points([(0, 0), (0.5, 0.5), (1, 1)])
|
||||
|
||||
result = getattr(polygon, op)(points)
|
||||
assert isinstance(result, np.ndarray)
|
||||
expected = np.array([getattr(polygon, op)(p) for p in points], dtype=bool)
|
||||
np.testing.assert_array_equal(result, expected)
|
||||
|
||||
# check scalar
|
||||
result = getattr(polygon, op)(points[0])
|
||||
assert type(result) is bool
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"op, kwargs",
|
||||
[
|
||||
pytest.param(
|
||||
"dwithin",
|
||||
dict(distance=0.5),
|
||||
marks=pytest.mark.skipif(
|
||||
shapely.geos_version < (3, 10, 0), reason="GEOS < 3.10"
|
||||
),
|
||||
),
|
||||
("equals_exact", dict(tolerance=0.01)),
|
||||
("relate_pattern", dict(pattern="T*F**F***")),
|
||||
],
|
||||
)
|
||||
def test_array_argument_binary_predicates2(op, kwargs):
|
||||
polygon = Polygon([(0, 0), (0, 1), (1, 1), (1, 0), (0, 0)])
|
||||
points = shapely.points([(0, 0), (0.5, 0.5), (1, 1)])
|
||||
|
||||
result = getattr(polygon, op)(points, **kwargs)
|
||||
assert isinstance(result, np.ndarray)
|
||||
expected = np.array([getattr(polygon, op)(p, **kwargs) for p in points], dtype=bool)
|
||||
np.testing.assert_array_equal(result, expected)
|
||||
|
||||
# check scalar
|
||||
result = getattr(polygon, op)(points[0], **kwargs)
|
||||
assert type(result) is bool
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"op",
|
||||
[
|
||||
"difference",
|
||||
"intersection",
|
||||
"symmetric_difference",
|
||||
"union",
|
||||
],
|
||||
)
|
||||
def test_array_argument_binary_geo(op):
|
||||
box = Polygon([(0, 0), (0, 1), (1, 1), (1, 0), (0, 0)])
|
||||
polygons = shapely.buffer(shapely.points([(0, 0), (0.5, 0.5), (1, 1)]), 0.5)
|
||||
|
||||
result = getattr(box, op)(polygons)
|
||||
assert isinstance(result, np.ndarray)
|
||||
expected = np.array([getattr(box, op)(g) for g in polygons], dtype=object)
|
||||
assert_geometries_equal(result, expected)
|
||||
|
||||
# check scalar
|
||||
result = getattr(box, op)(polygons[0])
|
||||
assert isinstance(result, (Polygon, MultiPolygon))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("op", ["distance", "hausdorff_distance"])
|
||||
def test_array_argument_float(op):
|
||||
polygon = Polygon([(0, 0), (0, 1), (1, 1), (1, 0), (0, 0)])
|
||||
points = shapely.points([(0, 0), (0.5, 0.5), (1, 1)])
|
||||
|
||||
result = getattr(polygon, op)(points)
|
||||
assert isinstance(result, np.ndarray)
|
||||
expected = np.array([getattr(polygon, op)(p) for p in points], dtype="float64")
|
||||
np.testing.assert_array_equal(result, expected)
|
||||
|
||||
# check scalar
|
||||
result = getattr(polygon, op)(points[0])
|
||||
assert type(result) is float
|
||||
|
||||
|
||||
@pytest.mark.parametrize("op", ["line_interpolate_point", "interpolate"])
|
||||
def test_array_argument_linear_point(op):
|
||||
line = LineString([(0, 0), (0, 1), (1, 1)])
|
||||
distances = np.array([0, 0.5, 1])
|
||||
|
||||
result = getattr(line, op)(distances)
|
||||
assert isinstance(result, np.ndarray)
|
||||
expected = np.array(
|
||||
[line.line_interpolate_point(d) for d in distances], dtype=object
|
||||
)
|
||||
assert_geometries_equal(result, expected)
|
||||
|
||||
# check scalar
|
||||
result = getattr(line, op)(distances[0])
|
||||
assert isinstance(result, Point)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("op", ["line_locate_point", "project"])
|
||||
def test_array_argument_linear_float(op):
|
||||
line = LineString([(0, 0), (0, 1), (1, 1)])
|
||||
points = shapely.points([(0, 0), (0.5, 0.5), (1, 1)])
|
||||
|
||||
result = getattr(line, op)(points)
|
||||
assert isinstance(result, np.ndarray)
|
||||
expected = np.array([line.line_locate_point(p) for p in points], dtype="float64")
|
||||
np.testing.assert_array_equal(result, expected)
|
||||
|
||||
# check scalar
|
||||
result = getattr(line, op)(points[0])
|
||||
assert type(result) is float
|
||||
|
||||
|
||||
def test_array_argument_buffer():
|
||||
point = Point(1, 1)
|
||||
distances = np.array([0, 0.5, 1])
|
||||
|
||||
result = point.buffer(distances)
|
||||
assert isinstance(result, np.ndarray)
|
||||
expected = np.array([point.buffer(d) for d in distances], dtype=object)
|
||||
assert_geometries_equal(result, expected)
|
||||
|
||||
# check scalar
|
||||
result = point.buffer(distances[0])
|
||||
assert isinstance(result, Polygon)
|
||||
|
||||
|
||||
def test_buffer_deprecate_positional():
|
||||
point = Point(1, 1)
|
||||
with pytest.deprecated_call(
|
||||
match="positional argument `cap_style` for `buffer` is deprecated"
|
||||
):
|
||||
point.buffer(1.0, 8, "round")
|
||||
with pytest.deprecated_call(
|
||||
match="positional arguments `cap_style` and `join_style` "
|
||||
"for `buffer` are deprecated"
|
||||
):
|
||||
point.buffer(1.0, 8, "round", "round")
|
||||
with pytest.deprecated_call():
|
||||
point.buffer(1.0, 8, "round", "round", 5.0)
|
||||
with pytest.deprecated_call():
|
||||
point.buffer(1.0, 8, "round", "round", 5.0, False)
|
||||
|
||||
|
||||
def test_simplify_deprecate_positional():
|
||||
linestring = LineString([(0, 0), (1, 1)])
|
||||
with pytest.deprecated_call(
|
||||
match="positional argument `preserve_topology` for `simplify` is deprecated"
|
||||
):
|
||||
linestring.simplify(1.0, True)
|
||||
|
||||
|
||||
def test_difference_deprecate_positional():
|
||||
point = Point(1, 1)
|
||||
with pytest.deprecated_call(
|
||||
match="positional argument `grid_size` for `difference` is deprecated"
|
||||
):
|
||||
point.difference(point, None)
|
||||
|
||||
|
||||
def test_intersection_deprecate_positional():
|
||||
point = Point(1, 1)
|
||||
with pytest.deprecated_call(
|
||||
match="positional argument `grid_size` for `intersection` is deprecated"
|
||||
):
|
||||
point.intersection(point, None)
|
||||
|
||||
|
||||
def test_symmetric_difference_deprecate_positional():
|
||||
point = Point(1, 1)
|
||||
with pytest.deprecated_call(
|
||||
match="positional argument `grid_size` for `symmetric_difference` is deprecated"
|
||||
):
|
||||
point.symmetric_difference(point, None)
|
||||
|
||||
|
||||
def test_union_deprecate_positional():
|
||||
point = Point(1, 1)
|
||||
with pytest.deprecated_call(
|
||||
match="positional argument `grid_size` for `union` is deprecated"
|
||||
):
|
||||
point.union(point, None)
|
||||
|
||||
|
||||
def test_line_locate_point_deprecate_positional():
|
||||
line_string = LineString([(1.0, 2.0), (3.0, 4.0)])
|
||||
with pytest.deprecated_call(
|
||||
match="positional argument `normalized` for `line_locate_point` is deprecated"
|
||||
):
|
||||
line_string.line_locate_point(Point(1, 1), False)
|
||||
|
||||
|
||||
def test_project_deprecate_positional():
|
||||
line_string = LineString([(1.0, 2.0), (3.0, 4.0)])
|
||||
with pytest.deprecated_call(
|
||||
match="positional argument `normalized` for `project` is deprecated"
|
||||
):
|
||||
line_string.project(Point(1, 1), False)
|
||||
|
||||
|
||||
def test_line_interpolate_point_deprecate_positional():
|
||||
line_string = LineString([(1.0, 2.0), (3.0, 4.0)])
|
||||
with pytest.deprecated_call(
|
||||
match="positional argument `normalized` for `line_interpolate_point` "
|
||||
"is deprecated"
|
||||
):
|
||||
line_string.line_interpolate_point(0, False)
|
||||
|
||||
|
||||
def test_interpolate_deprecate_positional():
|
||||
line_string = LineString([(1.0, 2.0), (3.0, 4.0)])
|
||||
with pytest.deprecated_call(
|
||||
match="positional argument `normalized` for `interpolate` is deprecated"
|
||||
):
|
||||
line_string.interpolate(0, False)
|
||||
@@ -0,0 +1,28 @@
|
||||
import pytest
|
||||
|
||||
import shapely
|
||||
from shapely.affinity import translate
|
||||
from shapely.geometry import GeometryCollection, LineString, MultiPoint, Point
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"geom",
|
||||
[
|
||||
Point(1, 2),
|
||||
MultiPoint([(1, 2), (3, 4)]),
|
||||
LineString([(1, 2), (3, 4)]),
|
||||
Point(0, 0).buffer(1.0),
|
||||
GeometryCollection([Point(1, 2), LineString([(1, 2), (3, 4)])]),
|
||||
],
|
||||
ids=[
|
||||
"Point",
|
||||
"MultiPoint",
|
||||
"LineString",
|
||||
"Polygon",
|
||||
"GeometryCollection",
|
||||
],
|
||||
)
|
||||
def test_hash(geom):
|
||||
h1 = hash(geom)
|
||||
assert h1 == hash(shapely.from_wkb(geom.wkb))
|
||||
assert h1 != hash(translate(geom, 1.0, 2.0))
|
||||
@@ -0,0 +1,232 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
import shapely
|
||||
from shapely import LinearRing, LineString, Point
|
||||
from shapely.coords import CoordinateSequence
|
||||
|
||||
|
||||
def test_from_coordinate_sequence():
|
||||
# From coordinate tuples
|
||||
line = LineString([(1.0, 2.0), (3.0, 4.0)])
|
||||
assert len(line.coords) == 2
|
||||
assert line.coords[:] == [(1.0, 2.0), (3.0, 4.0)]
|
||||
|
||||
line = LineString([(1.0, 2.0), (3.0, 4.0)])
|
||||
assert line.coords[:] == [(1.0, 2.0), (3.0, 4.0)]
|
||||
|
||||
|
||||
def test_from_coordinate_sequence_z():
|
||||
line = LineString([(1.0, 2.0, 3.0), (3.0, 4.0, 5.0)])
|
||||
assert line.has_z
|
||||
assert line.coords[:] == [(1.0, 2.0, 3.0), (3.0, 4.0, 5.0)]
|
||||
|
||||
|
||||
def test_from_points():
|
||||
# From Points
|
||||
line = LineString([Point(1.0, 2.0), Point(3.0, 4.0)])
|
||||
assert line.coords[:] == [(1.0, 2.0), (3.0, 4.0)]
|
||||
|
||||
line = LineString([Point(1.0, 2.0), Point(3.0, 4.0)])
|
||||
assert line.coords[:] == [(1.0, 2.0), (3.0, 4.0)]
|
||||
|
||||
|
||||
def test_from_mix():
|
||||
# From mix of tuples and Points
|
||||
line = LineString([Point(1.0, 2.0), (2.0, 3.0), Point(3.0, 4.0)])
|
||||
assert line.coords[:] == [(1.0, 2.0), (2.0, 3.0), (3.0, 4.0)]
|
||||
|
||||
|
||||
def test_from_linestring():
|
||||
# From another linestring
|
||||
line = LineString([(1.0, 2.0), (3.0, 4.0)])
|
||||
copy = LineString(line)
|
||||
assert copy.coords[:] == [(1.0, 2.0), (3.0, 4.0)]
|
||||
assert copy.geom_type == "LineString"
|
||||
|
||||
|
||||
def test_from_linearring():
|
||||
coords = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]
|
||||
ring = LinearRing(coords)
|
||||
copy = LineString(ring)
|
||||
assert copy.coords[:] == coords
|
||||
assert copy.geom_type == "LineString"
|
||||
|
||||
|
||||
def test_from_linestring_z():
|
||||
coords = [(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)]
|
||||
line = LineString(coords)
|
||||
copy = LineString(line)
|
||||
assert copy.coords[:] == coords
|
||||
assert copy.geom_type == "LineString"
|
||||
|
||||
|
||||
def test_from_generator():
|
||||
gen = (coord for coord in [(1.0, 2.0), (3.0, 4.0)])
|
||||
line = LineString(gen)
|
||||
assert line.coords[:] == [(1.0, 2.0), (3.0, 4.0)]
|
||||
|
||||
|
||||
def test_from_empty():
|
||||
line = LineString()
|
||||
assert line.is_empty
|
||||
assert isinstance(line.coords, CoordinateSequence)
|
||||
assert line.coords[:] == []
|
||||
|
||||
line = LineString([])
|
||||
assert line.is_empty
|
||||
assert isinstance(line.coords, CoordinateSequence)
|
||||
assert line.coords[:] == []
|
||||
|
||||
|
||||
def test_from_numpy():
|
||||
# Construct from a numpy array
|
||||
line = LineString(np.array([[1.0, 2.0], [3.0, 4.0]]))
|
||||
assert line.coords[:] == [(1.0, 2.0), (3.0, 4.0)]
|
||||
|
||||
|
||||
def test_numpy_empty_linestring_coords():
|
||||
# Check empty
|
||||
line = LineString([])
|
||||
la = np.asarray(line.coords)
|
||||
|
||||
assert la.shape == (0, 2)
|
||||
|
||||
|
||||
def test_numpy_object_array():
|
||||
geom = LineString([(0.0, 0.0), (0.0, 1.0)])
|
||||
ar = np.empty(1, object)
|
||||
ar[:] = [geom]
|
||||
assert ar[0] == geom
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("ignore:Creating an ndarray from ragged nested sequences:")
|
||||
def test_from_invalid_dim():
|
||||
# TODO(shapely-2.0) better error message?
|
||||
# pytest.raises(
|
||||
# ValueError, match="at least 2 coordinate tuples|at least 2 coordinates"
|
||||
# ):
|
||||
with pytest.raises(shapely.GEOSException):
|
||||
LineString([(1, 2)])
|
||||
|
||||
# exact error depends on numpy version
|
||||
with pytest.raises((ValueError, TypeError)):
|
||||
LineString([(1, 2, 3), (4, 5)])
|
||||
|
||||
with pytest.raises((ValueError, TypeError)):
|
||||
LineString([(1, 2), (3, 4, 5)])
|
||||
|
||||
msg = r"The ordinate \(last\) dimension should be 2 or 3, got {}"
|
||||
with pytest.raises(ValueError, match=msg.format(4)):
|
||||
LineString([(1, 2, 3, 4), (4, 5, 6, 7)])
|
||||
|
||||
with pytest.raises(ValueError, match=msg.format(1)):
|
||||
LineString([(1,), (4,)])
|
||||
|
||||
|
||||
def test_from_single_coordinate():
|
||||
"""Test for issue #486"""
|
||||
coords = [[-122.185933073564, 37.3629353839073]]
|
||||
with pytest.raises(shapely.GEOSException):
|
||||
ls = LineString(coords)
|
||||
ls.geom_type # caused segfault before fix
|
||||
|
||||
|
||||
class TestLineString:
|
||||
def test_linestring(self):
|
||||
# From coordinate tuples
|
||||
line = LineString([(1.0, 2.0), (3.0, 4.0)])
|
||||
assert len(line.coords) == 2
|
||||
assert line.coords[:] == [(1.0, 2.0), (3.0, 4.0)]
|
||||
|
||||
# Bounds
|
||||
assert line.bounds == (1.0, 2.0, 3.0, 4.0)
|
||||
|
||||
# Coordinate access
|
||||
assert tuple(line.coords) == ((1.0, 2.0), (3.0, 4.0))
|
||||
assert line.coords[0] == (1.0, 2.0)
|
||||
assert line.coords[1] == (3.0, 4.0)
|
||||
with pytest.raises(IndexError):
|
||||
line.coords[2] # index out of range
|
||||
|
||||
# Geo interface
|
||||
assert line.__geo_interface__ == {
|
||||
"type": "LineString",
|
||||
"coordinates": ((1.0, 2.0), (3.0, 4.0)),
|
||||
}
|
||||
|
||||
def test_linestring_empty(self):
|
||||
# Test Non-operability of Null geometry
|
||||
l_null = LineString()
|
||||
assert l_null.wkt == "LINESTRING EMPTY"
|
||||
assert l_null.length == 0.0
|
||||
|
||||
def test_equals_argument_order(self):
|
||||
"""
|
||||
Test equals predicate functions correctly regardless of the order
|
||||
of the inputs. See issue #317.
|
||||
"""
|
||||
coords = ((0, 0), (1, 0), (1, 1), (0, 0))
|
||||
ls = LineString(coords)
|
||||
lr = LinearRing(coords)
|
||||
|
||||
assert ls.__eq__(lr) is False # previously incorrectly returned True
|
||||
assert lr.__eq__(ls) is False
|
||||
assert (ls == lr) is False
|
||||
assert (lr == ls) is False
|
||||
|
||||
ls_clone = LineString(coords)
|
||||
lr_clone = LinearRing(coords)
|
||||
|
||||
assert ls.__eq__(ls_clone) is True
|
||||
assert lr.__eq__(lr_clone) is True
|
||||
assert (ls == ls_clone) is True
|
||||
assert (lr == lr_clone) is True
|
||||
|
||||
def test_numpy_linestring_coords(self):
|
||||
from numpy.testing import assert_array_equal
|
||||
|
||||
line = LineString([(1.0, 2.0), (3.0, 4.0)])
|
||||
expected = np.array([[1.0, 2.0], [3.0, 4.0]])
|
||||
|
||||
# Coordinate sequences can be adapted as well
|
||||
la = np.asarray(line.coords)
|
||||
assert_array_equal(la, expected)
|
||||
|
||||
|
||||
def test_linestring_immutable():
|
||||
line = LineString([(1.0, 2.0), (3.0, 4.0)])
|
||||
|
||||
with pytest.raises(AttributeError):
|
||||
line.coords = [(-1.0, -1.0), (1.0, 1.0)]
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
line.coords[0] = (-1.0, -1.0)
|
||||
|
||||
|
||||
def test_linestring_array_coercion():
|
||||
# don't convert to array of coordinates, keep objects
|
||||
line = LineString([(1.0, 2.0), (3.0, 4.0)])
|
||||
arr = np.array(line)
|
||||
assert arr.ndim == 0
|
||||
assert arr.size == 1
|
||||
assert arr.dtype == np.dtype("object")
|
||||
assert arr.item() == line
|
||||
|
||||
|
||||
def test_offset_curve_deprecate_positional():
|
||||
line_string = LineString([(1.0, 2.0), (3.0, 4.0)])
|
||||
with pytest.deprecated_call(
|
||||
match="positional argument `quad_segs` for `offset_curve` is deprecated"
|
||||
):
|
||||
line_string.offset_curve(1.0, 8)
|
||||
with pytest.deprecated_call(
|
||||
match="positional arguments `quad_segs` and `join_style` "
|
||||
"for `offset_curve` are deprecated"
|
||||
):
|
||||
line_string.offset_curve(1.0, 8, "round")
|
||||
with pytest.deprecated_call(
|
||||
match="positional arguments `quad_segs`, `join_style`, and `mitre_limit` "
|
||||
"for `offset_curve` are deprecated"
|
||||
):
|
||||
line_string.offset_curve(1.0, 8, "round", 5.0)
|
||||
@@ -0,0 +1,11 @@
|
||||
import numpy as np
|
||||
|
||||
test_int_types = [int, np.int16, np.int32, np.int64]
|
||||
|
||||
|
||||
class MultiGeometryTestCase:
|
||||
def subgeom_access_test(self, cls, geoms):
|
||||
geom = cls(geoms)
|
||||
for t in test_int_types:
|
||||
for i, g in enumerate(geoms):
|
||||
assert geom.geoms[t(i)] == g
|
||||
@@ -0,0 +1,77 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from shapely import LineString, MultiLineString
|
||||
from shapely.errors import EmptyPartError
|
||||
from shapely.geometry.base import dump_coords
|
||||
from shapely.tests.geometry.test_multi import MultiGeometryTestCase
|
||||
|
||||
|
||||
class TestMultiLineString(MultiGeometryTestCase):
|
||||
def test_multilinestring(self):
|
||||
# From coordinate tuples
|
||||
geom = MultiLineString([[(1.0, 2.0), (3.0, 4.0)]])
|
||||
assert isinstance(geom, MultiLineString)
|
||||
assert len(geom.geoms) == 1
|
||||
assert dump_coords(geom) == [[(1.0, 2.0), (3.0, 4.0)]]
|
||||
|
||||
# From lines
|
||||
a = LineString([(1.0, 2.0), (3.0, 4.0)])
|
||||
ml = MultiLineString([a])
|
||||
assert len(ml.geoms) == 1
|
||||
assert dump_coords(ml) == [[(1.0, 2.0), (3.0, 4.0)]]
|
||||
|
||||
# From another multi-line
|
||||
ml2 = MultiLineString(ml)
|
||||
assert len(ml2.geoms) == 1
|
||||
assert dump_coords(ml2) == [[(1.0, 2.0), (3.0, 4.0)]]
|
||||
|
||||
# Sub-geometry Access
|
||||
geom = MultiLineString([(((0.0, 0.0), (1.0, 2.0)))])
|
||||
assert isinstance(geom.geoms[0], LineString)
|
||||
assert dump_coords(geom.geoms[0]) == [(0.0, 0.0), (1.0, 2.0)]
|
||||
with pytest.raises(IndexError): # index out of range
|
||||
geom.geoms[1]
|
||||
|
||||
# Geo interface
|
||||
assert geom.__geo_interface__ == {
|
||||
"type": "MultiLineString",
|
||||
"coordinates": (((0.0, 0.0), (1.0, 2.0)),),
|
||||
}
|
||||
|
||||
def test_from_multilinestring_z(self):
|
||||
coords1 = [(0.0, 1.0, 2.0), (3.0, 4.0, 5.0)]
|
||||
coords2 = [(6.0, 7.0, 8.0), (9.0, 10.0, 11.0)]
|
||||
|
||||
# From coordinate tuples
|
||||
ml = MultiLineString([coords1, coords2])
|
||||
copy = MultiLineString(ml)
|
||||
assert isinstance(copy, MultiLineString)
|
||||
assert copy.geom_type == "MultiLineString"
|
||||
assert len(copy.geoms) == 2
|
||||
assert dump_coords(copy.geoms[0]) == coords1
|
||||
assert dump_coords(copy.geoms[1]) == coords2
|
||||
|
||||
def test_numpy(self):
|
||||
# Construct from a numpy array
|
||||
geom = MultiLineString([np.array(((0.0, 0.0), (1.0, 2.0)))])
|
||||
assert isinstance(geom, MultiLineString)
|
||||
assert len(geom.geoms) == 1
|
||||
assert dump_coords(geom) == [[(0.0, 0.0), (1.0, 2.0)]]
|
||||
|
||||
def test_subgeom_access(self):
|
||||
line0 = LineString([(0.0, 1.0), (2.0, 3.0)])
|
||||
line1 = LineString([(4.0, 5.0), (6.0, 7.0)])
|
||||
self.subgeom_access_test(MultiLineString, [line0, line1])
|
||||
|
||||
def test_create_multi_with_empty_component(self):
|
||||
msg = "Can't create MultiLineString with empty component"
|
||||
with pytest.raises(EmptyPartError, match=msg):
|
||||
MultiLineString([LineString([(0, 0), (1, 1), (2, 2)]), LineString()]).wkt
|
||||
|
||||
|
||||
def test_numpy_object_array():
|
||||
geom = MultiLineString([[[5.0, 6.0], [7.0, 8.0]]])
|
||||
ar = np.empty(1, object)
|
||||
ar[:] = [geom]
|
||||
assert ar[0] == geom
|
||||
@@ -0,0 +1,93 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
import shapely
|
||||
from shapely import MultiPoint, Point
|
||||
from shapely.errors import EmptyPartError
|
||||
from shapely.geometry.base import dump_coords
|
||||
from shapely.tests.geometry.test_multi import MultiGeometryTestCase
|
||||
|
||||
|
||||
class TestMultiPoint(MultiGeometryTestCase):
|
||||
def test_multipoint(self):
|
||||
# From coordinate tuples
|
||||
geom = MultiPoint([(1.0, 2.0), (3.0, 4.0)])
|
||||
assert len(geom.geoms) == 2
|
||||
assert dump_coords(geom) == [[(1.0, 2.0)], [(3.0, 4.0)]]
|
||||
|
||||
# From points
|
||||
geom = MultiPoint([Point(1.0, 2.0), Point(3.0, 4.0)])
|
||||
assert len(geom.geoms) == 2
|
||||
assert dump_coords(geom) == [[(1.0, 2.0)], [(3.0, 4.0)]]
|
||||
|
||||
# From another multi-point
|
||||
geom2 = MultiPoint(geom)
|
||||
assert len(geom2.geoms) == 2
|
||||
assert dump_coords(geom2) == [[(1.0, 2.0)], [(3.0, 4.0)]]
|
||||
|
||||
# Sub-geometry Access
|
||||
assert isinstance(geom.geoms[0], Point)
|
||||
assert geom.geoms[0].x == 1.0
|
||||
assert geom.geoms[0].y == 2.0
|
||||
with pytest.raises(IndexError): # index out of range
|
||||
geom.geoms[2]
|
||||
|
||||
# Geo interface
|
||||
assert geom.__geo_interface__ == {
|
||||
"type": "MultiPoint",
|
||||
"coordinates": ((1.0, 2.0), (3.0, 4.0)),
|
||||
}
|
||||
|
||||
def test_multipoint_from_numpy(self):
|
||||
# Construct from a numpy array
|
||||
geom = MultiPoint(np.array([[0.0, 0.0], [1.0, 2.0]]))
|
||||
assert isinstance(geom, MultiPoint)
|
||||
assert len(geom.geoms) == 2
|
||||
assert dump_coords(geom) == [[(0.0, 0.0)], [(1.0, 2.0)]]
|
||||
|
||||
def test_subgeom_access(self):
|
||||
p0 = Point(1.0, 2.0)
|
||||
p1 = Point(3.0, 4.0)
|
||||
self.subgeom_access_test(MultiPoint, [p0, p1])
|
||||
|
||||
def test_create_multi_with_empty_component(self):
|
||||
msg = "Can't create MultiPoint with empty component"
|
||||
with pytest.raises(EmptyPartError, match=msg):
|
||||
MultiPoint([Point(0, 0), Point()])
|
||||
|
||||
if shapely.geos_version < (3, 13, 0):
|
||||
# for older GEOS, Point(NaN, NaN) is considered empty
|
||||
with pytest.raises(EmptyPartError, match=msg):
|
||||
MultiPoint([(0, 0), (np.nan, np.nan)])
|
||||
|
||||
with pytest.raises(EmptyPartError, match=msg):
|
||||
MultiPoint(np.array([(0, 0), (np.nan, np.nan)]))
|
||||
|
||||
else:
|
||||
result = MultiPoint([(0, 0), (np.nan, np.nan)])
|
||||
expected = shapely.multipoints(
|
||||
shapely.points([(0, 0), (np.nan, np.nan)], handle_nan="allow")
|
||||
)
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_multipoint_array_coercion():
|
||||
geom = MultiPoint([(1.0, 2.0), (3.0, 4.0)])
|
||||
arr = np.array(geom)
|
||||
assert arr.ndim == 0
|
||||
assert arr.size == 1
|
||||
assert arr.dtype == np.dtype("object")
|
||||
assert arr.item() == geom
|
||||
|
||||
|
||||
def test_numpy_object_array():
|
||||
geom = MultiPoint([(1.0, 2.0), (3.0, 4.0)])
|
||||
ar = np.empty(1, object)
|
||||
ar[:] = [geom]
|
||||
assert ar[0] == geom
|
||||
|
||||
|
||||
def test_len_raises():
|
||||
geom = MultiPoint([[5.0, 6.0], [7.0, 8.0]])
|
||||
with pytest.raises(TypeError):
|
||||
len(geom)
|
||||
@@ -0,0 +1,156 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from shapely import MultiPolygon, Polygon
|
||||
from shapely.geometry.base import dump_coords
|
||||
from shapely.tests.geometry.test_multi import MultiGeometryTestCase
|
||||
|
||||
|
||||
class TestMultiPolygon(MultiGeometryTestCase):
|
||||
def test_multipolygon(self):
|
||||
# Empty
|
||||
geom = MultiPolygon([])
|
||||
assert geom.is_empty
|
||||
assert len(geom.geoms) == 0
|
||||
|
||||
# From coordinate tuples
|
||||
coords = [
|
||||
(
|
||||
((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)),
|
||||
[((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))],
|
||||
)
|
||||
]
|
||||
geom = MultiPolygon(coords)
|
||||
assert isinstance(geom, MultiPolygon)
|
||||
assert len(geom.geoms) == 1
|
||||
assert dump_coords(geom) == [
|
||||
[
|
||||
(0.0, 0.0),
|
||||
(0.0, 1.0),
|
||||
(1.0, 1.0),
|
||||
(1.0, 0.0),
|
||||
(0.0, 0.0),
|
||||
[(0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)],
|
||||
]
|
||||
]
|
||||
|
||||
# Or without holes
|
||||
coords2 = [(((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)),)]
|
||||
geom = MultiPolygon(coords2)
|
||||
assert isinstance(geom, MultiPolygon)
|
||||
assert len(geom.geoms) == 1
|
||||
assert dump_coords(geom) == [
|
||||
[
|
||||
(0.0, 0.0),
|
||||
(0.0, 1.0),
|
||||
(1.0, 1.0),
|
||||
(1.0, 0.0),
|
||||
(0.0, 0.0),
|
||||
]
|
||||
]
|
||||
|
||||
# Or from polygons
|
||||
p = Polygon(
|
||||
((0, 0), (0, 1), (1, 1), (1, 0)),
|
||||
[((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))],
|
||||
)
|
||||
geom = MultiPolygon([p])
|
||||
assert len(geom.geoms) == 1
|
||||
assert dump_coords(geom) == [
|
||||
[
|
||||
(0.0, 0.0),
|
||||
(0.0, 1.0),
|
||||
(1.0, 1.0),
|
||||
(1.0, 0.0),
|
||||
(0.0, 0.0),
|
||||
[(0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)],
|
||||
]
|
||||
]
|
||||
|
||||
# None and empty polygons are dropped
|
||||
geom_from_list_with_empty = MultiPolygon([p, None, Polygon()])
|
||||
assert geom_from_list_with_empty == geom
|
||||
|
||||
# Or from a list of multiple polygons
|
||||
geom_multiple_from_list = MultiPolygon([p, p])
|
||||
assert len(geom_multiple_from_list.geoms) == 2
|
||||
assert all(p == geom.geoms[0] for p in geom_multiple_from_list.geoms)
|
||||
|
||||
# Or from a np.array of polygons
|
||||
geom_multiple_from_array = MultiPolygon(np.array([p, p]))
|
||||
assert geom_multiple_from_array == geom_multiple_from_list
|
||||
|
||||
# Or from another multi-polygon
|
||||
geom2 = MultiPolygon(geom)
|
||||
assert len(geom2.geoms) == 1
|
||||
assert dump_coords(geom2) == [
|
||||
[
|
||||
(0.0, 0.0),
|
||||
(0.0, 1.0),
|
||||
(1.0, 1.0),
|
||||
(1.0, 0.0),
|
||||
(0.0, 0.0),
|
||||
[(0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)],
|
||||
]
|
||||
]
|
||||
|
||||
# Sub-geometry Access
|
||||
assert isinstance(geom.geoms[0], Polygon)
|
||||
assert dump_coords(geom.geoms[0]) == [
|
||||
(0.0, 0.0),
|
||||
(0.0, 1.0),
|
||||
(1.0, 1.0),
|
||||
(1.0, 0.0),
|
||||
(0.0, 0.0),
|
||||
[(0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)],
|
||||
]
|
||||
with pytest.raises(IndexError): # index out of range
|
||||
geom.geoms[1]
|
||||
|
||||
# Geo interface
|
||||
assert geom.__geo_interface__ == {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
(
|
||||
((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)),
|
||||
((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)),
|
||||
)
|
||||
],
|
||||
}
|
||||
|
||||
def test_subgeom_access(self):
|
||||
poly0 = Polygon([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)])
|
||||
poly1 = Polygon([(0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25)])
|
||||
self.subgeom_access_test(MultiPolygon, [poly0, poly1])
|
||||
|
||||
|
||||
def test_fail_list_of_multipolygons():
|
||||
"""A list of multipolygons is not a valid multipolygon ctor argument"""
|
||||
poly = Polygon([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)])
|
||||
multi = MultiPolygon(
|
||||
[
|
||||
(
|
||||
((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)),
|
||||
[((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))],
|
||||
)
|
||||
]
|
||||
)
|
||||
with pytest.raises(ValueError):
|
||||
MultiPolygon([multi])
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
MultiPolygon([poly, multi])
|
||||
|
||||
|
||||
def test_numpy_object_array():
|
||||
geom = MultiPolygon(
|
||||
[
|
||||
(
|
||||
((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)),
|
||||
[((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))],
|
||||
)
|
||||
]
|
||||
)
|
||||
ar = np.empty(1, object)
|
||||
ar[:] = [geom]
|
||||
assert ar[0] == geom
|
||||
@@ -0,0 +1,201 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from shapely import Point, geos_version
|
||||
from shapely.coords import CoordinateSequence
|
||||
from shapely.errors import DimensionError, UnsupportedGEOSVersionError
|
||||
|
||||
|
||||
def test_from_coordinates():
|
||||
# Point
|
||||
p = Point(1.0, 2.0)
|
||||
assert p.coords[:] == [(1.0, 2.0)]
|
||||
assert p.has_z is False
|
||||
|
||||
# PointZ
|
||||
p = Point(1.0, 2.0, 3.0)
|
||||
assert p.coords[:] == [(1.0, 2.0, 3.0)]
|
||||
assert p.has_z
|
||||
|
||||
# empty
|
||||
p = Point()
|
||||
assert p.is_empty
|
||||
assert isinstance(p.coords, CoordinateSequence)
|
||||
assert p.coords[:] == []
|
||||
|
||||
|
||||
def test_from_sequence():
|
||||
# From single coordinate pair
|
||||
p = Point((3.0, 4.0))
|
||||
assert p.coords[:] == [(3.0, 4.0)]
|
||||
p = Point([3.0, 4.0])
|
||||
assert p.coords[:] == [(3.0, 4.0)]
|
||||
|
||||
# From coordinate sequence
|
||||
p = Point([(3.0, 4.0)])
|
||||
assert p.coords[:] == [(3.0, 4.0)]
|
||||
p = Point([[3.0, 4.0]])
|
||||
assert p.coords[:] == [(3.0, 4.0)]
|
||||
|
||||
# PointZ
|
||||
p = Point((3.0, 4.0, 5.0))
|
||||
assert p.coords[:] == [(3.0, 4.0, 5.0)]
|
||||
p = Point([3.0, 4.0, 5.0])
|
||||
assert p.coords[:] == [(3.0, 4.0, 5.0)]
|
||||
p = Point([(3.0, 4.0, 5.0)])
|
||||
assert p.coords[:] == [(3.0, 4.0, 5.0)]
|
||||
|
||||
|
||||
def test_from_numpy():
|
||||
# Construct from a numpy array
|
||||
p = Point(np.array([1.0, 2.0]))
|
||||
assert p.coords[:] == [(1.0, 2.0)]
|
||||
|
||||
p = Point(np.array([1.0, 2.0, 3.0]))
|
||||
assert p.coords[:] == [(1.0, 2.0, 3.0)]
|
||||
|
||||
|
||||
def test_from_numpy_xy():
|
||||
# Construct from separate x, y numpy arrays - if those are length 1,
|
||||
# this is allowed for compat with shapely 1.8
|
||||
# (https://github.com/shapely/shapely/issues/1587)
|
||||
p = Point(np.array([1.0]), np.array([2.0]))
|
||||
assert p.coords[:] == [(1.0, 2.0)]
|
||||
|
||||
p = Point(np.array([1.0]), np.array([2.0]), np.array([3.0]))
|
||||
assert p.coords[:] == [(1.0, 2.0, 3.0)]
|
||||
|
||||
|
||||
def test_from_point():
|
||||
# From another point
|
||||
p = Point(3.0, 4.0)
|
||||
q = Point(p)
|
||||
assert q.coords[:] == [(3.0, 4.0)]
|
||||
|
||||
p = Point(3.0, 4.0, 5.0)
|
||||
q = Point(p)
|
||||
assert q.coords[:] == [(3.0, 4.0, 5.0)]
|
||||
|
||||
|
||||
def test_from_generator():
|
||||
gen = (coord for coord in [(1.0, 2.0)])
|
||||
p = Point(gen)
|
||||
assert p.coords[:] == [(1.0, 2.0)]
|
||||
|
||||
|
||||
def test_from_invalid():
|
||||
with pytest.raises(TypeError, match="takes at most 3 arguments"):
|
||||
Point(1, 2, 3, 4)
|
||||
|
||||
# this worked in shapely 1.x, just ignoring the other coords
|
||||
with pytest.raises(
|
||||
ValueError, match="takes only scalar or 1-size vector arguments"
|
||||
):
|
||||
Point([(2, 3), (11, 4)])
|
||||
|
||||
|
||||
class TestPoint:
|
||||
def test_point(self):
|
||||
# Test XY point
|
||||
p = Point(1.0, 2.0)
|
||||
assert p.x == 1.0
|
||||
assert type(p.x) is float
|
||||
assert p.y == 2.0
|
||||
assert type(p.y) is float
|
||||
assert p.coords[:] == [(1.0, 2.0)]
|
||||
assert str(p) == p.wkt
|
||||
assert p.has_z is False
|
||||
with pytest.raises(DimensionError):
|
||||
p.z
|
||||
if geos_version >= (3, 12, 0):
|
||||
assert p.has_m is False
|
||||
with pytest.raises(DimensionError):
|
||||
p.m
|
||||
else:
|
||||
with pytest.raises(UnsupportedGEOSVersionError):
|
||||
p.m
|
||||
|
||||
# Check XYZ point
|
||||
p = Point(1.0, 2.0, 3.0)
|
||||
assert p.coords[:] == [(1.0, 2.0, 3.0)]
|
||||
assert str(p) == p.wkt
|
||||
assert p.has_z is True
|
||||
assert p.z == 3.0
|
||||
assert type(p.z) is float
|
||||
if geos_version >= (3, 12, 0):
|
||||
assert p.has_m is False
|
||||
with pytest.raises(DimensionError):
|
||||
p.m
|
||||
|
||||
# TODO: Check XYM and XYZM points
|
||||
|
||||
# Coordinate access
|
||||
p = Point((3.0, 4.0))
|
||||
assert p.x == 3.0
|
||||
assert p.y == 4.0
|
||||
assert tuple(p.coords) == ((3.0, 4.0),)
|
||||
assert p.coords[0] == (3.0, 4.0)
|
||||
with pytest.raises(IndexError): # index out of range
|
||||
p.coords[1]
|
||||
|
||||
# Bounds
|
||||
assert p.bounds == (3.0, 4.0, 3.0, 4.0)
|
||||
|
||||
# Geo interface
|
||||
assert p.__geo_interface__ == {"type": "Point", "coordinates": (3.0, 4.0)}
|
||||
|
||||
def test_point_empty(self):
|
||||
# Test Non-operability of Null geometry
|
||||
p_null = Point()
|
||||
assert p_null.wkt == "POINT EMPTY"
|
||||
assert p_null.coords[:] == []
|
||||
assert p_null.area == 0.0
|
||||
|
||||
assert p_null.__geo_interface__ == {"type": "Point", "coordinates": ()}
|
||||
|
||||
def test_coords(self):
|
||||
# From Array.txt
|
||||
p = Point(0.0, 0.0, 1.0)
|
||||
coords = p.coords[0]
|
||||
assert coords == (0.0, 0.0, 1.0)
|
||||
|
||||
# Convert to Numpy array, passing through Python sequence
|
||||
a = np.asarray(coords)
|
||||
assert a.ndim == 1
|
||||
assert a.size == 3
|
||||
assert a.shape == (3,)
|
||||
|
||||
|
||||
def test_point_immutable():
|
||||
p = Point(3.0, 4.0)
|
||||
|
||||
with pytest.raises(AttributeError):
|
||||
p.coords = (2.0, 1.0)
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
p.coords[0] = (2.0, 1.0)
|
||||
|
||||
|
||||
def test_point_array_coercion():
|
||||
# don't convert to array of coordinates, keep objects
|
||||
p = Point(3.0, 4.0)
|
||||
arr = np.array(p)
|
||||
assert arr.ndim == 0
|
||||
assert arr.size == 1
|
||||
assert arr.dtype == np.dtype("object")
|
||||
assert arr.item() == p
|
||||
|
||||
|
||||
def test_numpy_empty_point_coords():
|
||||
pe = Point()
|
||||
|
||||
# Access the coords
|
||||
a = np.asarray(pe.coords)
|
||||
assert a.shape == (0, 2)
|
||||
|
||||
|
||||
def test_numpy_object_array():
|
||||
geom = Point(3.0, 4.0)
|
||||
ar = np.empty(1, object)
|
||||
ar[:] = [geom]
|
||||
assert ar[0] == geom
|
||||
@@ -0,0 +1,460 @@
|
||||
"""Polygons and Linear Rings"""
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from shapely import LinearRing, LineString, Point, Polygon
|
||||
from shapely.coords import CoordinateSequence
|
||||
from shapely.errors import TopologicalError
|
||||
from shapely.wkb import loads as load_wkb
|
||||
|
||||
|
||||
def test_empty_linearring_coords():
|
||||
assert LinearRing().coords[:] == []
|
||||
|
||||
|
||||
def test_linearring_from_coordinate_sequence():
|
||||
expected_coords = [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (0.0, 0.0)]
|
||||
|
||||
ring = LinearRing([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0)])
|
||||
assert ring.coords[:] == expected_coords
|
||||
|
||||
ring = LinearRing([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0)])
|
||||
assert ring.coords[:] == expected_coords
|
||||
|
||||
|
||||
def test_linearring_from_points():
|
||||
# From Points
|
||||
expected_coords = [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (0.0, 0.0)]
|
||||
|
||||
ring = LinearRing([Point(0.0, 0.0), Point(0.0, 1.0), Point(1.0, 1.0)])
|
||||
assert ring.coords[:] == expected_coords
|
||||
|
||||
|
||||
def test_linearring_from_closed_linestring():
|
||||
coords = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]
|
||||
line = LineString(coords)
|
||||
ring = LinearRing(line)
|
||||
assert len(ring.coords) == 4
|
||||
assert ring.coords[:] == coords
|
||||
assert ring.geom_type == "LinearRing"
|
||||
|
||||
|
||||
def test_linearring_from_unclosed_linestring():
|
||||
coords = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]
|
||||
line = LineString(coords[:-1]) # Pass in unclosed line
|
||||
ring = LinearRing(line)
|
||||
assert len(ring.coords) == 4
|
||||
assert ring.coords[:] == coords
|
||||
assert ring.geom_type == "LinearRing"
|
||||
|
||||
|
||||
def test_linearring_from_invalid():
|
||||
coords = [(0.0, 0.0), (0.0, 0.0), (0.0, 0.0)]
|
||||
line = LineString(coords)
|
||||
assert not line.is_valid
|
||||
with pytest.raises(TopologicalError):
|
||||
LinearRing(line)
|
||||
|
||||
|
||||
def test_linearring_from_too_short_linestring():
|
||||
# Creation of LinearRing request at least 3 coordinates (unclosed) or
|
||||
# 4 coordinates (closed)
|
||||
coords = [(0.0, 0.0), (1.0, 1.0)]
|
||||
line = LineString(coords)
|
||||
with pytest.raises(ValueError, match="requires at least 4 coordinates"):
|
||||
LinearRing(line)
|
||||
|
||||
|
||||
def test_linearring_from_linearring():
|
||||
coords = [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (0.0, 0.0)]
|
||||
ring = LinearRing(coords)
|
||||
assert ring.coords[:] == coords
|
||||
|
||||
|
||||
def test_linearring_from_generator():
|
||||
coords = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]
|
||||
gen = (coord for coord in coords)
|
||||
ring = LinearRing(gen)
|
||||
assert ring.coords[:] == coords
|
||||
|
||||
|
||||
def test_linearring_from_empty():
|
||||
ring = LinearRing()
|
||||
assert ring.is_empty
|
||||
assert isinstance(ring.coords, CoordinateSequence)
|
||||
assert ring.coords[:] == []
|
||||
|
||||
ring = LinearRing([])
|
||||
assert ring.is_empty
|
||||
assert isinstance(ring.coords, CoordinateSequence)
|
||||
assert ring.coords[:] == []
|
||||
|
||||
|
||||
def test_linearring_from_numpy():
|
||||
# Construct from a numpy array
|
||||
coords = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]
|
||||
|
||||
ring = LinearRing(np.array(coords))
|
||||
assert ring.coords[:] == [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]
|
||||
|
||||
|
||||
def test_numpy_linearring_coords():
|
||||
from numpy.testing import assert_array_equal
|
||||
|
||||
ring = LinearRing([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0)])
|
||||
ra = np.asarray(ring.coords)
|
||||
expected = np.asarray([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (0.0, 0.0)])
|
||||
assert_array_equal(ra, expected)
|
||||
|
||||
|
||||
def test_numpy_empty_linearring_coords():
|
||||
ring = LinearRing()
|
||||
assert np.asarray(ring.coords).shape == (0, 2)
|
||||
|
||||
|
||||
def test_numpy_object_array():
|
||||
geom = Polygon([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0)])
|
||||
ar = np.empty(1, object)
|
||||
ar[:] = [geom]
|
||||
assert ar[0] == geom
|
||||
|
||||
|
||||
def test_polygon_from_coordinate_sequence():
|
||||
coords = [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (0.0, 0.0)]
|
||||
|
||||
# Construct a polygon, exterior ring only
|
||||
polygon = Polygon([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0)])
|
||||
assert polygon.exterior.coords[:] == coords
|
||||
assert len(polygon.interiors) == 0
|
||||
|
||||
polygon = Polygon([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0)])
|
||||
assert polygon.exterior.coords[:] == coords
|
||||
assert len(polygon.interiors) == 0
|
||||
|
||||
|
||||
def test_polygon_from_coordinate_sequence_with_holes():
|
||||
coords = [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (0.0, 0.0)]
|
||||
|
||||
# Interior rings (holes)
|
||||
polygon = Polygon(coords, [[(0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25)]])
|
||||
assert polygon.exterior.coords[:] == coords
|
||||
assert len(polygon.interiors) == 1
|
||||
assert len(polygon.interiors[0].coords) == 5
|
||||
|
||||
# Multiple interior rings with different length
|
||||
coords = [(0, 0), (0, 10), (10, 10), (10, 0), (0, 0)]
|
||||
holes = [
|
||||
[(1, 1), (2, 1), (2, 2), (1, 2), (1, 1)],
|
||||
[(3, 3), (3, 4), (4, 5), (5, 4), (5, 3), (3, 3)],
|
||||
]
|
||||
polygon = Polygon(coords, holes)
|
||||
assert polygon.exterior.coords[:] == coords
|
||||
assert len(polygon.interiors) == 2
|
||||
assert len(polygon.interiors[0].coords) == 5
|
||||
assert len(polygon.interiors[1].coords) == 6
|
||||
|
||||
|
||||
def test_polygon_from_linearring():
|
||||
coords = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]
|
||||
ring = LinearRing(coords)
|
||||
|
||||
polygon = Polygon(ring)
|
||||
assert polygon.exterior.coords[:] == coords
|
||||
assert len(polygon.interiors) == 0
|
||||
|
||||
# from shell and holes linearrings
|
||||
shell = LinearRing([(0.0, 0.0), (70.0, 120.0), (140.0, 0.0), (0.0, 0.0)])
|
||||
holes = [
|
||||
LinearRing([(60.0, 80.0), (80.0, 80.0), (70.0, 60.0), (60.0, 80.0)]),
|
||||
LinearRing([(30.0, 10.0), (50.0, 10.0), (40.0, 30.0), (30.0, 10.0)]),
|
||||
LinearRing([(90.0, 10), (110.0, 10.0), (100.0, 30.0), (90.0, 10.0)]),
|
||||
]
|
||||
polygon = Polygon(shell, holes)
|
||||
assert polygon.exterior.coords[:] == shell.coords[:]
|
||||
assert len(polygon.interiors) == 3
|
||||
for i in range(3):
|
||||
assert polygon.interiors[i].coords[:] == holes[i].coords[:]
|
||||
|
||||
|
||||
def test_polygon_from_linestring():
|
||||
coords = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]
|
||||
line = LineString(coords)
|
||||
polygon = Polygon(line)
|
||||
assert polygon.exterior.coords[:] == coords
|
||||
|
||||
# from unclosed linestring
|
||||
line = LineString(coords[:-1])
|
||||
polygon = Polygon(line)
|
||||
assert polygon.exterior.coords[:] == coords
|
||||
|
||||
|
||||
def test_polygon_from_points():
|
||||
polygon = Polygon([Point(0.0, 0.0), Point(0.0, 1.0), Point(1.0, 1.0)])
|
||||
expected_coords = [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (0.0, 0.0)]
|
||||
assert polygon.exterior.coords[:] == expected_coords
|
||||
|
||||
|
||||
def test_polygon_from_polygon():
|
||||
coords = [(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)]
|
||||
polygon = Polygon(coords, [[(0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25)]])
|
||||
|
||||
# Test from another Polygon
|
||||
copy = Polygon(polygon)
|
||||
assert len(copy.exterior.coords) == 5
|
||||
assert len(copy.interiors) == 1
|
||||
assert len(copy.interiors[0].coords) == 5
|
||||
|
||||
|
||||
def test_polygon_from_invalid():
|
||||
# Error handling
|
||||
with pytest.raises(ValueError):
|
||||
# A LinearRing must have at least 3 coordinate tuples
|
||||
Polygon([[1, 2], [2, 3]])
|
||||
|
||||
|
||||
def test_polygon_from_empty():
|
||||
polygon = Polygon()
|
||||
assert polygon.is_empty
|
||||
assert polygon.exterior.coords[:] == []
|
||||
|
||||
polygon = Polygon([])
|
||||
assert polygon.is_empty
|
||||
assert polygon.exterior.coords[:] == []
|
||||
|
||||
|
||||
def test_polygon_from_numpy():
|
||||
a = np.array(((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)))
|
||||
polygon = Polygon(a)
|
||||
assert len(polygon.exterior.coords) == 5
|
||||
assert polygon.exterior.coords[:] == [
|
||||
(0.0, 0.0),
|
||||
(0.0, 1.0),
|
||||
(1.0, 1.0),
|
||||
(1.0, 0.0),
|
||||
(0.0, 0.0),
|
||||
]
|
||||
assert len(polygon.interiors) == 0
|
||||
|
||||
|
||||
def test_polygon_from_generator():
|
||||
coords = [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]
|
||||
gen = (coord for coord in coords)
|
||||
polygon = Polygon(gen)
|
||||
assert polygon.exterior.coords[:] == coords
|
||||
|
||||
|
||||
class TestPolygon:
|
||||
def test_linearring(self):
|
||||
# Initialization
|
||||
# Linear rings won't usually be created by users, but by polygons
|
||||
coords = ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0))
|
||||
ring = LinearRing(coords)
|
||||
assert len(ring.coords) == 5
|
||||
assert ring.coords[0] == ring.coords[4]
|
||||
assert ring.coords[0] == ring.coords[-1]
|
||||
assert ring.is_ring is True
|
||||
|
||||
def test_polygon(self):
|
||||
coords = ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0))
|
||||
|
||||
# Construct a polygon, exterior ring only
|
||||
polygon = Polygon(coords)
|
||||
assert len(polygon.exterior.coords) == 5
|
||||
|
||||
# Ring Access
|
||||
assert isinstance(polygon.exterior, LinearRing)
|
||||
ring = polygon.exterior
|
||||
assert len(ring.coords) == 5
|
||||
assert ring.coords[0] == ring.coords[4]
|
||||
assert ring.coords[0] == (0.0, 0.0)
|
||||
assert ring.is_ring is True
|
||||
assert len(polygon.interiors) == 0
|
||||
|
||||
# Create a new polygon from WKB
|
||||
data = polygon.wkb
|
||||
polygon = None
|
||||
ring = None
|
||||
polygon = load_wkb(data)
|
||||
ring = polygon.exterior
|
||||
assert len(ring.coords) == 5
|
||||
assert ring.coords[0] == ring.coords[4]
|
||||
assert ring.coords[0] == (0.0, 0.0)
|
||||
assert ring.is_ring is True
|
||||
polygon = None
|
||||
|
||||
# Interior rings (holes)
|
||||
polygon = Polygon(
|
||||
coords, [((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25))]
|
||||
)
|
||||
assert len(polygon.exterior.coords) == 5
|
||||
assert len(polygon.interiors[0].coords) == 5
|
||||
with pytest.raises(IndexError): # index out of range
|
||||
polygon.interiors[1]
|
||||
|
||||
# Coordinate getter raises exceptions
|
||||
with pytest.raises(NotImplementedError):
|
||||
polygon.coords
|
||||
|
||||
# Geo interface
|
||||
assert polygon.__geo_interface__ == {
|
||||
"type": "Polygon",
|
||||
"coordinates": (
|
||||
((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)),
|
||||
((0.25, 0.25), (0.25, 0.5), (0.5, 0.5), (0.5, 0.25), (0.25, 0.25)),
|
||||
),
|
||||
}
|
||||
|
||||
def test_linearring_empty(self):
|
||||
# Test Non-operability of Null rings
|
||||
r_null = LinearRing()
|
||||
assert r_null.wkt == "LINEARRING EMPTY"
|
||||
assert r_null.length == 0.0
|
||||
|
||||
def test_dimensions(self):
|
||||
# Background: see http://trac.gispython.org/lab/ticket/168
|
||||
# http://lists.gispython.org/pipermail/community/2008-August/001859.html
|
||||
|
||||
coords = ((0.0, 0.0, 0.0), (0.0, 1.0, 0.0), (1.0, 1.0, 0.0), (1.0, 0.0, 0.0))
|
||||
polygon = Polygon(coords)
|
||||
assert polygon._ndim == 3
|
||||
gi = polygon.__geo_interface__
|
||||
assert gi["coordinates"] == (
|
||||
(
|
||||
(0.0, 0.0, 0.0),
|
||||
(0.0, 1.0, 0.0),
|
||||
(1.0, 1.0, 0.0),
|
||||
(1.0, 0.0, 0.0),
|
||||
(0.0, 0.0, 0.0),
|
||||
),
|
||||
)
|
||||
|
||||
e = polygon.exterior
|
||||
assert e._ndim == 3
|
||||
gi = e.__geo_interface__
|
||||
assert gi["coordinates"] == (
|
||||
(0.0, 0.0, 0.0),
|
||||
(0.0, 1.0, 0.0),
|
||||
(1.0, 1.0, 0.0),
|
||||
(1.0, 0.0, 0.0),
|
||||
(0.0, 0.0, 0.0),
|
||||
)
|
||||
|
||||
def test_attribute_chains(self):
|
||||
# Attribute Chaining
|
||||
# See also ticket #151.
|
||||
p = Polygon([(0.0, 0.0), (0.0, 1.0), (-1.0, 1.0), (-1.0, 0.0)])
|
||||
assert list(p.boundary.coords) == [
|
||||
(0.0, 0.0),
|
||||
(0.0, 1.0),
|
||||
(-1.0, 1.0),
|
||||
(-1.0, 0.0),
|
||||
(0.0, 0.0),
|
||||
]
|
||||
|
||||
ec = list(Point(0.0, 0.0).buffer(1.0, quad_segs=1).exterior.coords)
|
||||
assert isinstance(ec, list) # TODO: this is a poor test
|
||||
|
||||
# Test chained access to interiors
|
||||
p = Polygon(
|
||||
[(0.0, 0.0), (0.0, 1.0), (-1.0, 1.0), (-1.0, 0.0)],
|
||||
[[(-0.25, 0.25), (-0.25, 0.75), (-0.75, 0.75), (-0.75, 0.25)]],
|
||||
)
|
||||
assert p.area == 0.75
|
||||
|
||||
"""Not so much testing the exact values here, which are the
|
||||
responsibility of the geometry engine (GEOS), but that we can get
|
||||
chain functions and properties using anonymous references.
|
||||
"""
|
||||
assert list(p.interiors[0].coords) == [
|
||||
(-0.25, 0.25),
|
||||
(-0.25, 0.75),
|
||||
(-0.75, 0.75),
|
||||
(-0.75, 0.25),
|
||||
(-0.25, 0.25),
|
||||
]
|
||||
xy = next(iter(p.interiors[0].buffer(1).exterior.coords))
|
||||
assert len(xy) == 2
|
||||
|
||||
# Test multiple operators, boundary of a buffer
|
||||
ec = list(p.buffer(1).boundary.coords)
|
||||
assert isinstance(ec, list) # TODO: this is a poor test
|
||||
|
||||
def test_empty_equality(self):
|
||||
# Test equals operator, including empty geometries
|
||||
# see issue #338
|
||||
|
||||
point1 = Point(0, 0)
|
||||
polygon1 = Polygon([(0.0, 0.0), (0.0, 1.0), (-1.0, 1.0), (-1.0, 0.0)])
|
||||
polygon2 = Polygon([(0.0, 0.0), (0.0, 1.0), (-1.0, 1.0), (-1.0, 0.0)])
|
||||
polygon_empty1 = Polygon()
|
||||
polygon_empty2 = Polygon()
|
||||
|
||||
assert point1 != polygon1
|
||||
assert polygon_empty1 == polygon_empty2
|
||||
assert polygon1 != polygon_empty1
|
||||
assert polygon1 == polygon2
|
||||
assert polygon_empty1 is not None
|
||||
|
||||
def test_from_bounds(self):
|
||||
xmin, ymin, xmax, ymax = -180, -90, 180, 90
|
||||
coords = [(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)]
|
||||
assert Polygon(coords) == Polygon.from_bounds(xmin, ymin, xmax, ymax)
|
||||
|
||||
def test_empty_polygon_exterior(self):
|
||||
p = Polygon()
|
||||
assert p.exterior == LinearRing()
|
||||
|
||||
|
||||
def test_linearring_immutable():
|
||||
ring = LinearRing([(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)])
|
||||
|
||||
with pytest.raises(AttributeError):
|
||||
ring.coords = [(1.0, 1.0), (2.0, 2.0), (1.0, 2.0)]
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
ring.coords[0] = (1.0, 1.0)
|
||||
|
||||
|
||||
class TestLinearRingGetItem:
|
||||
def test_index_linearring(self):
|
||||
shell = LinearRing([(0.0, 0.0), (70.0, 120.0), (140.0, 0.0), (0.0, 0.0)])
|
||||
holes = [
|
||||
LinearRing([(60.0, 80.0), (80.0, 80.0), (70.0, 60.0), (60.0, 80.0)]),
|
||||
LinearRing([(30.0, 10.0), (50.0, 10.0), (40.0, 30.0), (30.0, 10.0)]),
|
||||
LinearRing([(90.0, 10), (110.0, 10.0), (100.0, 30.0), (90.0, 10.0)]),
|
||||
]
|
||||
g = Polygon(shell, holes)
|
||||
for i in range(-3, 3):
|
||||
assert g.interiors[i].equals(holes[i])
|
||||
with pytest.raises(IndexError):
|
||||
g.interiors[3]
|
||||
with pytest.raises(IndexError):
|
||||
g.interiors[-4]
|
||||
|
||||
def test_index_linearring_misc(self):
|
||||
g = Polygon() # empty
|
||||
with pytest.raises(IndexError):
|
||||
g.interiors[0]
|
||||
with pytest.raises(TypeError):
|
||||
g.interiors[0.0]
|
||||
|
||||
def test_slice_linearring(self):
|
||||
shell = LinearRing([(0.0, 0.0), (70.0, 120.0), (140.0, 0.0), (0.0, 0.0)])
|
||||
holes = [
|
||||
LinearRing([(60.0, 80.0), (80.0, 80.0), (70.0, 60.0), (60.0, 80.0)]),
|
||||
LinearRing([(30.0, 10.0), (50.0, 10.0), (40.0, 30.0), (30.0, 10.0)]),
|
||||
LinearRing([(90.0, 10), (110.0, 10.0), (100.0, 30.0), (90.0, 10.0)]),
|
||||
]
|
||||
g = Polygon(shell, holes)
|
||||
t = [a.equals(b) for (a, b) in zip(g.interiors[1:], holes[1:])]
|
||||
assert all(t)
|
||||
t = [a.equals(b) for (a, b) in zip(g.interiors[:-1], holes[:-1])]
|
||||
assert all(t)
|
||||
t = [a.equals(b) for (a, b) in zip(g.interiors[::-1], holes[::-1])]
|
||||
assert all(t)
|
||||
t = [a.equals(b) for (a, b) in zip(g.interiors[::2], holes[::2])]
|
||||
assert all(t)
|
||||
t = [a.equals(b) for (a, b) in zip(g.interiors[:3], holes[:3])]
|
||||
assert all(t)
|
||||
assert g.interiors[3:] == holes[3:] == []
|
||||
Reference in New Issue
Block a user