diff --git a/CHANGELOG.md b/CHANGELOG.md index 117796a..44d2972 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -71,6 +71,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. without a geometry. - Writing no longer fails for a date property with the same value for all features, the value is stored as an ISO 8601 date in the collection. +- Fix: `create-stac-collection` takes the bbox from the geometries in EPSG:4326. It + transformed the corners of the source bbox, which in a projected CRS reach beyond + the data. ## [v0.3.1] - 2026-09-24 diff --git a/tests/test_create_stac.py b/tests/test_create_stac.py index 42d4909..2254ea8 100644 --- a/tests/test_create_stac.py +++ b/tests/test_create_stac.py @@ -55,3 +55,28 @@ def test_create_stac_collection(tmp_folder: Path, file: str, expected_file: str) del expected["assets"]["data"]["processing:software"]["vecorel-cli"] assert created_file == expected + + +def test_bbox_is_the_extent_of_the_geometries(): + """In a projected CRS, the corners of the source bbox reach beyond the data.""" + import geopandas as gpd + import pytest as _pytest + from shapely.geometry import Polygon + + from vecorel_cli.vecorel.collection import Collection + + # a parcel in Saxony, in ETRS89 / UTM zone 33N + field = Polygon([(300000, 5600000), (500000, 5650000), (450000, 5700000), (320000, 5680000)]) + gdf = gpd.GeoDataFrame({"id": ["1"]}, geometry=[field], crs="EPSG:25833") + collection = Collection( + { + "schemas": {"c": ["https://vecorel.org/specification/v0.1.0/schema.yaml"]}, + "title": "t", + "description": "d", + } + ) + + stac = CreateStacCollection().create(collection, gdf, "x.parquet") + + expected = gdf.to_crs(epsg=4326).total_bounds + assert stac["extent"]["spatial"]["bbox"][0] == _pytest.approx(list(expected)) diff --git a/vecorel_cli/create_stac.py b/vecorel_cli/create_stac.py index 970a596..d6a4a04 100644 --- a/vecorel_cli/create_stac.py +++ b/vecorel_cli/create_stac.py @@ -4,8 +4,7 @@ import click import pandas as pd -from geopandas import GeoDataFrame, GeoSeries -from shapely.geometry import box +from geopandas import GeoDataFrame from yarl import URL from .basecommand import BaseCommand, runnable @@ -142,7 +141,13 @@ def create( if len(description) == 0: raise Exception("Description is not found in collection.") - bbox = list(GeoSeries([box(*gdf.total_bounds)], crs=gdf.crs).to_crs(epsg=4326).total_bounds) + # the extent of the geometries themselves: in a projected CRS the corners of its bbox reach beyond the data + geometry = ( + gdf.geometry + if gdf.crs and gdf.crs.to_epsg() == 4326 + else gdf.geometry.to_crs(epsg=4326) + ) + bbox = list(geometry.total_bounds) if isinstance(data_url, Path): href = "file://" + str(data_url.resolve()).replace("\\", "/")