111 lines
3.1 KiB
Python
111 lines
3.1 KiB
Python
"""tests/test_geometry.py —— 几何运算单元测试。"""
|
|
|
|
import pytest
|
|
from shapely.geometry import LineString, Point, Polygon
|
|
|
|
import geo_tools
|
|
from geo_tools.core.geometry import (
|
|
buffer_geometry,
|
|
bounding_box,
|
|
centroid,
|
|
contains,
|
|
convex_hull,
|
|
difference,
|
|
distance_between,
|
|
fix_geometry,
|
|
intersect,
|
|
intersects,
|
|
is_valid_geometry,
|
|
unary_union,
|
|
union,
|
|
within,
|
|
)
|
|
|
|
|
|
class TestIsValidGeometry:
|
|
def test_valid_polygon(self):
|
|
poly = Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])
|
|
assert is_valid_geometry(poly) is True
|
|
|
|
def test_none_returns_false(self):
|
|
assert is_valid_geometry(None) is False
|
|
|
|
def test_invalid_self_intersecting(self):
|
|
# 蝴蝶形(自相交)
|
|
bowtie = Polygon([(0, 0), (1, 1), (1, 0), (0, 1)])
|
|
assert is_valid_geometry(bowtie) is False
|
|
|
|
|
|
class TestFixGeometry:
|
|
def test_fix_bowtie(self):
|
|
bowtie = Polygon([(0, 0), (1, 1), (1, 0), (0, 1)])
|
|
assert not bowtie.is_valid
|
|
fixed = fix_geometry(bowtie)
|
|
assert fixed is not None
|
|
assert fixed.is_valid
|
|
|
|
def test_valid_geometry_unchanged(self):
|
|
poly = Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])
|
|
fixed = fix_geometry(poly)
|
|
assert fixed.is_valid
|
|
assert fixed.area == pytest.approx(poly.area)
|
|
|
|
def test_none_returns_none(self):
|
|
assert fix_geometry(None) is None
|
|
|
|
|
|
class TestBufferGeometry:
|
|
def test_point_buffer(self):
|
|
pt = Point(0, 0)
|
|
buf = buffer_geometry(pt, 1.0)
|
|
assert buf.area > 3.0 # π * r² ≈ 3.14
|
|
|
|
def test_zero_distance_returns_point_like(self):
|
|
pt = Point(0, 0)
|
|
buf = buffer_geometry(pt, 0.0)
|
|
# buffer(0) on point may return empty or point
|
|
assert buf is not None
|
|
|
|
|
|
class TestSetOperations:
|
|
@pytest.fixture
|
|
def poly_a(self):
|
|
return Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])
|
|
|
|
@pytest.fixture
|
|
def poly_b(self):
|
|
return Polygon([(1, 0), (3, 0), (3, 2), (1, 2)])
|
|
|
|
def test_intersection(self, poly_a, poly_b):
|
|
result = intersect(poly_a, poly_b)
|
|
assert result.area == pytest.approx(2.0)
|
|
|
|
def test_union(self, poly_a, poly_b):
|
|
result = union(poly_a, poly_b)
|
|
assert result.area == pytest.approx(6.0)
|
|
|
|
def test_difference(self, poly_a, poly_b):
|
|
result = difference(poly_a, poly_b)
|
|
assert result.area == pytest.approx(2.0)
|
|
|
|
def test_unary_union(self, poly_a, poly_b):
|
|
result = unary_union([poly_a, poly_b])
|
|
assert result.area == pytest.approx(6.0)
|
|
|
|
|
|
class TestSpatialRelations:
|
|
def test_contains_true(self):
|
|
big = Polygon([(0, 0), (10, 0), (10, 10), (0, 10)])
|
|
small = Polygon([(1, 1), (2, 1), (2, 2), (1, 2)])
|
|
assert contains(big, small) is True
|
|
|
|
def test_within(self):
|
|
big = Polygon([(0, 0), (10, 0), (10, 10), (0, 10)])
|
|
small = Polygon([(1, 1), (2, 1), (2, 2), (1, 2)])
|
|
assert within(small, big) is True
|
|
|
|
def test_distance(self):
|
|
p1 = Point(0, 0)
|
|
p2 = Point(3, 4)
|
|
assert distance_between(p1, p2) == pytest.approx(5.0)
|