| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344 |
- import numpy as np
- import pytest
- from numpy.testing import assert_allclose, assert_array_equal
- import shapely
- from shapely import GeometryCollection, LineString, MultiPoint, Point, Polygon
- from shapely.tests.common import (
- empty,
- geometry_collection,
- ignore_invalid,
- line_string,
- linear_ring,
- multi_line_string,
- multi_point,
- multi_polygon,
- point,
- point_polygon_testdata,
- polygon,
- polygon_with_hole,
- )
- @pytest.mark.parametrize(
- "geom",
- [
- point,
- line_string,
- linear_ring,
- multi_point,
- multi_line_string,
- geometry_collection,
- ],
- )
- def test_area_non_polygon(geom):
- assert shapely.area(geom) == 0.0
- def test_area():
- actual = shapely.area([polygon, polygon_with_hole, multi_polygon])
- assert actual.tolist() == [4.0, 96.0, 1.01]
- def test_distance():
- actual = shapely.distance(*point_polygon_testdata)
- expected = [2 * 2**0.5, 2**0.5, 0, 0, 0, 2**0.5]
- np.testing.assert_allclose(actual, expected)
- def test_distance_missing():
- actual = shapely.distance(point, None)
- assert np.isnan(actual)
- def test_distance_duplicated():
- a = Point(1, 2)
- b = LineString([(0, 0), (0, 0), (1, 1)])
- with ignore_invalid(shapely.geos_version < (3, 12, 0)):
- # https://github.com/shapely/shapely/issues/1552
- # GEOS < 3.12 raises "invalid" floating point errors
- actual = shapely.distance(a, b)
- assert actual == 1.0
- @pytest.mark.parametrize(
- "geom,expected",
- [
- (point, [2, 3, 2, 3]),
- ([point, multi_point], [[2, 3, 2, 3], [0, 0, 1, 2]]),
- (shapely.linestrings([[0, 0], [0, 1]]), [0, 0, 0, 1]),
- (shapely.linestrings([[0, 0], [1, 0]]), [0, 0, 1, 0]),
- (multi_point, [0, 0, 1, 2]),
- (multi_polygon, [0, 0, 2.2, 2.2]),
- (geometry_collection, [49, -1, 52, 2]),
- (empty, [np.nan, np.nan, np.nan, np.nan]),
- (None, [np.nan, np.nan, np.nan, np.nan]),
- ],
- )
- def test_bounds(geom, expected):
- assert_array_equal(shapely.bounds(geom), expected)
- @pytest.mark.parametrize(
- "geom,shape",
- [
- (point, (4,)),
- (None, (4,)),
- ([point, multi_point], (2, 4)),
- ([[point, multi_point], [polygon, point]], (2, 2, 4)),
- ([[[point, multi_point]], [[polygon, point]]], (2, 1, 2, 4)),
- ],
- )
- def test_bounds_dimensions(geom, shape):
- assert shapely.bounds(geom).shape == shape
- @pytest.mark.parametrize(
- "geom,expected",
- [
- (point, [2, 3, 2, 3]),
- (shapely.linestrings([[0, 0], [0, 1]]), [0, 0, 0, 1]),
- (shapely.linestrings([[0, 0], [1, 0]]), [0, 0, 1, 0]),
- (multi_point, [0, 0, 1, 2]),
- (multi_polygon, [0, 0, 2.2, 2.2]),
- (geometry_collection, [49, -1, 52, 2]),
- (empty, [np.nan, np.nan, np.nan, np.nan]),
- (None, [np.nan, np.nan, np.nan, np.nan]),
- ([empty, empty, None], [np.nan, np.nan, np.nan, np.nan]),
- # mixed missing and non-missing coordinates
- ([point, None], [2, 3, 2, 3]),
- ([point, empty], [2, 3, 2, 3]),
- ([point, empty, None], [2, 3, 2, 3]),
- ([point, empty, None, multi_point], [0, 0, 2, 3]),
- ],
- )
- def test_total_bounds(geom, expected):
- assert_array_equal(shapely.total_bounds(geom), expected)
- @pytest.mark.parametrize(
- "geom",
- [
- point,
- None,
- [point, multi_point],
- [[point, multi_point], [polygon, point]],
- [[[point, multi_point]], [[polygon, point]]],
- ],
- )
- def test_total_bounds_dimensions(geom):
- assert shapely.total_bounds(geom).shape == (4,)
- def test_length():
- actual = shapely.length(
- [
- point,
- line_string,
- linear_ring,
- polygon,
- polygon_with_hole,
- multi_point,
- multi_polygon,
- ]
- )
- assert actual.tolist() == [0.0, 2.0, 4.0, 8.0, 48.0, 0.0, 4.4]
- def test_length_missing():
- actual = shapely.length(None)
- assert np.isnan(actual)
- def test_hausdorff_distance():
- # example from GEOS docs
- a = shapely.linestrings([[0, 0], [100, 0], [10, 100], [10, 100]])
- b = shapely.linestrings([[0, 100], [0, 10], [80, 10]])
- with ignore_invalid(shapely.geos_version < (3, 12, 0)):
- # Hausdorff distance emits "invalid value encountered"
- # (see https://github.com/libgeos/geos/issues/515)
- actual = shapely.hausdorff_distance(a, b)
- assert actual == pytest.approx(22.360679775, abs=1e-7)
- def test_hausdorff_distance_densify():
- # example from GEOS docs
- a = shapely.linestrings([[0, 0], [100, 0], [10, 100], [10, 100]])
- b = shapely.linestrings([[0, 100], [0, 10], [80, 10]])
- with ignore_invalid(shapely.geos_version < (3, 12, 0)):
- # Hausdorff distance emits "invalid value encountered"
- # (see https://github.com/libgeos/geos/issues/515)
- actual = shapely.hausdorff_distance(a, b, densify=0.001)
- assert actual == pytest.approx(47.8, abs=0.1)
- def test_hausdorff_distance_missing():
- actual = shapely.hausdorff_distance(point, None)
- assert np.isnan(actual)
- actual = shapely.hausdorff_distance(point, None, densify=0.001)
- assert np.isnan(actual)
- def test_hausdorff_densify_nan():
- actual = shapely.hausdorff_distance(point, point, densify=np.nan)
- assert np.isnan(actual)
- def test_distance_empty():
- actual = shapely.distance(point, empty)
- assert np.isnan(actual)
- def test_hausdorff_distance_empty():
- actual = shapely.hausdorff_distance(point, empty)
- assert np.isnan(actual)
- def test_hausdorff_distance_densify_empty():
- actual = shapely.hausdorff_distance(point, empty, densify=0.2)
- assert np.isnan(actual)
- @pytest.mark.parametrize(
- "geom1, geom2, expected",
- [
- # identical geometries should have 0 distance
- (
- shapely.linestrings([[0, 0], [100, 0]]),
- shapely.linestrings([[0, 0], [100, 0]]),
- 0,
- ),
- # example from GEOS docs
- (
- shapely.linestrings([[0, 0], [50, 200], [100, 0], [150, 200], [200, 0]]),
- shapely.linestrings([[0, 200], [200, 150], [0, 100], [200, 50], [0, 0]]),
- 200,
- ),
- # same geometries but different curve direction results in maximum
- # distance between vertices on the lines.
- (
- shapely.linestrings([[0, 0], [50, 200], [100, 0], [150, 200], [200, 0]]),
- shapely.linestrings([[200, 0], [150, 200], [100, 0], [50, 200], [0, 0]]),
- 200,
- ),
- # another example from GEOS docs
- (
- shapely.linestrings([[0, 0], [50, 200], [100, 0], [150, 200], [200, 0]]),
- shapely.linestrings([[0, 0], [200, 50], [0, 100], [200, 150], [0, 200]]),
- 282.842712474619,
- ),
- # example from GEOS tests
- (
- shapely.linestrings([[0, 0], [100, 0]]),
- shapely.linestrings([[0, 0], [50, 50], [100, 0]]),
- 70.7106781186548,
- ),
- ],
- )
- def test_frechet_distance(geom1, geom2, expected):
- actual = shapely.frechet_distance(geom1, geom2)
- assert actual == pytest.approx(expected, abs=1e-12)
- @pytest.mark.parametrize(
- "geom1, geom2, densify, expected",
- [
- # example from GEOS tests
- (
- shapely.linestrings([[0, 0], [100, 0]]),
- shapely.linestrings([[0, 0], [50, 50], [100, 0]]),
- 0.002,
- 50,
- )
- ],
- )
- def test_frechet_distance_densify(geom1, geom2, densify, expected):
- actual = shapely.frechet_distance(geom1, geom2, densify=densify)
- assert actual == pytest.approx(expected, abs=1e-12)
- @pytest.mark.parametrize(
- "geom1, geom2",
- [
- (line_string, None),
- (None, line_string),
- (None, None),
- (line_string, empty),
- (empty, line_string),
- (empty, empty),
- ],
- )
- def test_frechet_distance_nan_for_invalid_geometry_inputs(geom1, geom2):
- actual = shapely.frechet_distance(geom1, geom2)
- assert np.isnan(actual)
- def test_frechet_densify_ndarray():
- actual = shapely.frechet_distance(
- shapely.linestrings([[0, 0], [100, 0]]),
- shapely.linestrings([[0, 0], [50, 50], [100, 0]]),
- densify=[0.1, 0.2, 1],
- )
- expected = np.array([50, 50.99019514, 70.7106781186548])
- np.testing.assert_array_almost_equal(actual, expected)
- def test_frechet_densify_nan():
- actual = shapely.frechet_distance(line_string, line_string, densify=np.nan)
- assert np.isnan(actual)
- @pytest.mark.parametrize("densify", [0, -1, 2])
- def test_frechet_densify_invalid_values(densify):
- with pytest.raises(shapely.GEOSException, match="Fraction is not in range"):
- shapely.frechet_distance(line_string, line_string, densify=densify)
- def test_frechet_distance_densify_empty():
- actual = shapely.frechet_distance(line_string, empty, densify=0.2)
- assert np.isnan(actual)
- def test_minimum_clearance():
- actual = shapely.minimum_clearance([polygon, polygon_with_hole, multi_polygon])
- assert_allclose(actual, [2.0, 2.0, 0.1])
- def test_minimum_clearance_nonexistent():
- actual = shapely.minimum_clearance([point, empty])
- assert np.isinf(actual).all()
- def test_minimum_clearance_missing():
- actual = shapely.minimum_clearance(None)
- assert np.isnan(actual)
- @pytest.mark.parametrize(
- "geometry, expected",
- [
- (
- Polygon([(0, 5), (5, 10), (10, 5), (5, 0), (0, 5)]),
- 5,
- ),
- (
- LineString([(1, 0), (1, 10)]),
- 5,
- ),
- (
- MultiPoint([(2, 2), (4, 2)]),
- 1,
- ),
- (
- Point(2, 2),
- 0,
- ),
- (
- GeometryCollection(),
- 0,
- ),
- ],
- )
- def test_minimum_bounding_radius(geometry, expected):
- actual = shapely.minimum_bounding_radius(geometry)
- assert actual == pytest.approx(expected, abs=1e-12)
|