"""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)