diff --git a/gdal_boots/gdal.py b/gdal_boots/gdal.py index fe5b200..654b1eb 100644 --- a/gdal_boots/gdal.py +++ b/gdal_boots/gdal.py @@ -936,7 +936,7 @@ def size(self): return len(self) def __getitem__(self, idx) -> Feature: - return Feature(self.ref_df, self.ref_layer.GetFeature(idx)) + return Feature(self.ref_ds, self.ref_layer.GetFeature(idx)) class Layer: diff --git a/tests/test_geometry.py b/tests/test_geometry.py index 0310716..16f746d 100644 --- a/tests/test_geometry.py +++ b/tests/test_geometry.py @@ -1,11 +1,54 @@ import json import pytest +from shapely.geometry import Polygon, shape from gdal_boots import gdal_version, geos_version from gdal_boots.geometry import GeometryBuilder, make_valid_geojson, to_geojson, transform, transform_geojson +def normalize_polygon(polygon): + """ + Normalize a polygon so that its exterior and interior rings start at the minimum coordinate. + """ + ext = list(polygon.exterior.coords) + min_pt = min(ext) + min_index = ext.index(min_pt) + norm_ext = ext[min_index:] + ext[:min_index] + + norm_ints = [] + for interior in polygon.interiors: + int_coords = list(interior.coords) + min_pt = min(int_coords) + min_index = int_coords.index(min_pt) + norm_ints.append(int_coords[min_index:] + int_coords[:min_index]) + + return Polygon(shell=norm_ext, holes=norm_ints) + + +def compare_geojson(geojson1, geojson2): + geom1 = shape(geojson1) + geom2 = shape(geojson2) + + if geom1.geom_type != geom2.geom_type: + return False + + if geom1.geom_type == "Polygon": + norm_geom1 = normalize_polygon(geom1) + norm_geom2 = normalize_polygon(geom2) + return norm_geom1.equals(norm_geom2) + + elif geom1.geom_type == "MultiPolygon": + # Using 'geoms' property to avoid ShapelyDeprecationWarning + sorted1 = sorted([normalize_polygon(p) for p in geom1.geoms], key=lambda p: p.wkt) + sorted2 = sorted([normalize_polygon(p) for p in geom2.geoms], key=lambda p: p.wkt) + + return all(p1.equals(p2) for p1, p2 in zip(sorted1, sorted2)) + + else: + raise ValueError("Unsupported geometry type. Only Polygon and MultiPolygon are supported.") + + @pytest.fixture def geometry_geojson_4326(): return { @@ -154,13 +197,16 @@ def test_make_valid(): result = make_valid_geojson(self_intersection, precision=6) - assert result == { - "type": "MultiPolygon", - "coordinates": [ - [[[27.582652, 53.893235], [26.768188, 53.504384], [26.845092, 54.226707], [27.582652, 53.893235]]], - [[[27.582652, 53.893235], [28.388671, 54.278054], [28.377685, 53.533778], [27.582652, 53.893235]]], - ], - } + assert compare_geojson( + result, + { + "type": "MultiPolygon", + "coordinates": [ + [[[27.582652, 53.893235], [26.768188, 53.504384], [26.845092, 54.226707], [27.582652, 53.893235]]], + [[[27.582652, 53.893235], [28.388671, 54.278054], [28.377685, 53.533778], [27.582652, 53.893235]]], + ], + }, + ) self_intersection_hole = { "type": "Polygon", @@ -180,22 +226,25 @@ def test_make_valid(): result = make_valid_geojson(self_intersection_hole, precision=6) - assert result == { - "type": "Polygon", - "coordinates": [ - [ - [27.443987, 53.655377], - [26.740722, 53.855766], - [26.531982, 54.204223], - [28.943481, 54.188155], - [28.883056, 53.176411], - [26.779174, 53.402982], - [27.443987, 53.655377], + assert compare_geojson( + result, + { + "type": "Polygon", + "coordinates": [ + [ + [27.443987, 53.655377], + [26.740722, 53.855766], + [26.531982, 54.204223], + [28.943481, 54.188155], + [28.883056, 53.176411], + [26.779174, 53.402982], + [27.443987, 53.655377], + ], + # hole + [[27.443987, 53.655377], [28.168945, 53.448806], [28.372192, 54.007768], [27.443987, 53.655377]], ], - # hole - [[27.443987, 53.655377], [28.168945, 53.448806], [28.372192, 54.007768], [27.443987, 53.655377]], - ], - } + }, + ) invalid = { "type": "Polygon", @@ -228,41 +277,11 @@ def test_make_valid(): result = make_valid_geojson(invalid, precision=6) - assert result == { - "type": "Polygon", - "coordinates": [ - [ - [123.912279, -9.94963], - [124.808856, -9.945983], - [124.658416, -10.631109], - [124.419945, -10.627865], - [124.417387, -10.633294], - [124.384578, -10.780016], - [124.378588, -10.807525], - [124.380593, -10.810794], - [124.598579, -10.901209], - [124.590119, -10.939784], - [123.915179, -10.942552], - [123.912279, -9.94963], - ], - [ - [124.107187, -10.547924], - [123.983748, -10.516936], - [123.94459, -10.689683], - [123.959686, -10.6948], - [124.149828, -10.743025], - [124.155046, -10.743006], - [124.16208, -10.716425], - [124.195546, -10.570105], - [124.107187, -10.547924], - ], - ], - } - - invalid = { - "type": "MultiPolygon", - "coordinates": [ - [ + assert compare_geojson( + result, + { + "type": "Polygon", + "coordinates": [ [ [123.912279, -9.94963], [124.808856, -9.945983], @@ -276,23 +295,23 @@ def test_make_valid(): [124.590119, -10.939784], [123.915179, -10.942552], [123.912279, -9.94963], - [124.16208, -10.716425], - [124.195546, -10.570105], + ], + [ + [124.107187, -10.547924], [123.983748, -10.516936], [123.94459, -10.689683], [123.959686, -10.6948], [124.149828, -10.743025], [124.155046, -10.743006], [124.16208, -10.716425], - [123.912279, -9.94963], - ] - ] - ], - } - - result = make_valid_geojson(invalid, precision=6) + [124.195546, -10.570105], + [124.107187, -10.547924], + ], + ], + }, + ) - assert result == { + invalid = { "type": "MultiPolygon", "coordinates": [ [ @@ -309,22 +328,58 @@ def test_make_valid(): [124.590119, -10.939784], [123.915179, -10.942552], [123.912279, -9.94963], - ], - [ - [124.107187, -10.547924], + [124.16208, -10.716425], + [124.195546, -10.570105], [123.983748, -10.516936], [123.94459, -10.689683], [123.959686, -10.6948], [124.149828, -10.743025], [124.155046, -10.743006], [124.16208, -10.716425], - [124.195546, -10.570105], - [124.107187, -10.547924], - ], + [123.912279, -9.94963], + ] ] ], } + result = make_valid_geojson(invalid, precision=6) + + assert compare_geojson( + result, + { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [123.912279, -9.94963], + [124.808856, -9.945983], + [124.658416, -10.631109], + [124.419945, -10.627865], + [124.417387, -10.633294], + [124.384578, -10.780016], + [124.378588, -10.807525], + [124.380593, -10.810794], + [124.598579, -10.901209], + [124.590119, -10.939784], + [123.915179, -10.942552], + [123.912279, -9.94963], + ], + [ + [124.107187, -10.547924], + [123.983748, -10.516936], + [123.94459, -10.689683], + [123.959686, -10.6948], + [124.149828, -10.743025], + [124.155046, -10.743006], + [124.16208, -10.716425], + [124.195546, -10.570105], + [124.107187, -10.547924], + ], + ] + ], + }, + ) + # invalid = { @@ -385,99 +440,102 @@ def test_make_valid(): result = make_valid_geojson(invalid, precision=6) - assert result == { - "type": "MultiPolygon", - "coordinates": [ - [ + assert compare_geojson( + result, + { + "type": "MultiPolygon", + "coordinates": [ [ - [124.496008, -10.6289], - [124.484578, -10.680016], - [124.478588, -10.707525], - [124.480593, -10.710794], - [124.698579, -10.801209], - [124.690119, -10.839784], - [124.452833, -10.840757], - [124.380593, -10.810794], - [124.378588, -10.807525], - [124.384578, -10.780016], - [124.417387, -10.633294], - [124.419945, -10.627865], - [124.496008, -10.6289], - ] - ], - [ + [ + [124.496008, -10.6289], + [124.484578, -10.680016], + [124.478588, -10.707525], + [124.480593, -10.710794], + [124.698579, -10.801209], + [124.690119, -10.839784], + [124.452833, -10.840757], + [124.380593, -10.810794], + [124.378588, -10.807525], + [124.384578, -10.780016], + [124.417387, -10.633294], + [124.419945, -10.627865], + [124.496008, -10.6289], + ] + ], [ - [124.452833, -10.840757], - [124.598579, -10.901209], - [124.590119, -10.939784], - [123.915179, -10.942552], - [123.912279, -9.94963], - [124.01257, -9.949222], - [124.013478, -10.260274], - [124.01425, -10.524593], - [123.983748, -10.516936], - [123.94459, -10.689683], - [123.959686, -10.6948], - [124.014788, -10.708775], - [124.015179, -10.842552], - [124.452833, -10.840757], - ] - ], - [ + [ + [124.452833, -10.840757], + [124.598579, -10.901209], + [124.590119, -10.939784], + [123.915179, -10.942552], + [123.912279, -9.94963], + [124.01257, -9.949222], + [124.013478, -10.260274], + [124.01425, -10.524593], + [123.983748, -10.516936], + [123.94459, -10.689683], + [123.959686, -10.6948], + [124.014788, -10.708775], + [124.015179, -10.842552], + [124.452833, -10.840757], + ] + ], [ - [124.01257, -9.949222], - [124.012279, -9.84963], - [124.908856, -9.845983], - [124.758416, -10.531109], - [124.680606, -10.530051], - [124.808856, -9.945983], - [124.044681, -9.949091], - [124.01257, -9.949222], - ] - ], - [ + [ + [124.01257, -9.949222], + [124.012279, -9.84963], + [124.908856, -9.845983], + [124.758416, -10.531109], + [124.680606, -10.530051], + [124.808856, -9.945983], + [124.044681, -9.949091], + [124.01257, -9.949222], + ] + ], [ - [124.680606, -10.530051], - [124.658416, -10.631109], - [124.496008, -10.6289], - [124.517387, -10.533294], - [124.519945, -10.527865], - [124.680606, -10.530051], - ] - ], - [ + [ + [124.680606, -10.530051], + [124.658416, -10.631109], + [124.496008, -10.6289], + [124.517387, -10.533294], + [124.519945, -10.527865], + [124.680606, -10.530051], + ] + ], [ - [124.182759, -10.626014], - [124.16208, -10.716425], - [124.155046, -10.743006], - [124.149828, -10.743025], - [124.014788, -10.708775], - [124.01425, -10.524593], - [124.056917, -10.535304], - [124.04459, -10.589683], - [124.059686, -10.5948], - [124.128112, -10.612155], - [124.182759, -10.626014], - ] - ], - [ + [ + [124.182759, -10.626014], + [124.16208, -10.716425], + [124.155046, -10.743006], + [124.149828, -10.743025], + [124.014788, -10.708775], + [124.01425, -10.524593], + [124.056917, -10.535304], + [124.04459, -10.589683], + [124.059686, -10.5948], + [124.128112, -10.612155], + [124.182759, -10.626014], + ] + ], [ - [124.056917, -10.535304], - [124.075856, -10.451751], - [124.083748, -10.416936], - [124.207187, -10.447924], - [124.295546, -10.470105], - [124.26208, -10.616425], - [124.255046, -10.643006], - [124.249828, -10.643025], - [124.182759, -10.626014], - [124.195546, -10.570105], - [124.107187, -10.547924], - [124.056917, -10.535304], - ] + [ + [124.056917, -10.535304], + [124.075856, -10.451751], + [124.083748, -10.416936], + [124.207187, -10.447924], + [124.295546, -10.470105], + [124.26208, -10.616425], + [124.255046, -10.643006], + [124.249828, -10.643025], + [124.182759, -10.626014], + [124.195546, -10.570105], + [124.107187, -10.547924], + [124.056917, -10.535304], + ] + ], ], - ], - } + }, + ) invalid = { "type": "MultiPolygon",