structure saas with tools
This commit is contained in:
@@ -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