Skip to content

Commit a29d2dc

Browse files
committed
#334 compute geometry bbox in target crs if possible
1 parent f41d9fd commit a29d2dc

2 files changed

Lines changed: 78 additions & 6 deletions

File tree

openeo_driver/dry_run.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
import numpy
4141
import shapely.geometry.base
42+
from pyproj import CRS
4243
from shapely.geometry import Point, Polygon, MultiPolygon, GeometryCollection
4344
from shapely.geometry.base import BaseGeometry
4445

@@ -53,7 +54,7 @@
5354
AggregatePolygonResult,
5455
AggregatePolygonSpatialResult,
5556
)
56-
from openeo_driver.util.geometry import geojson_to_geometry, GeometryBufferer
57+
from openeo_driver.util.geometry import geojson_to_geometry, GeometryBufferer, BoundingBox
5758
from openeo_driver.utils import to_hashable, EvalEnv
5859

5960
_log = logging.getLogger(__name__)
@@ -519,7 +520,11 @@ def filter_bbox(
519520
"crs": (crs or "EPSG:4326")})
520521

521522
def filter_spatial(self, geometries):
522-
geometries, bbox = self._normalize_geometry(geometries)
523+
crs = None
524+
if (len(self.metadata.spatial_dimensions) > 0):
525+
spatial_dim = self.metadata.spatial_dimensions[0]
526+
crs = spatial_dim.crs
527+
geometries, bbox = self._normalize_geometry(geometries,target_crs= crs)
523528
cube = self.filter_bbox(**bbox, operation="weak_spatial_extent")
524529
return cube._process(operation="filter_spatial", arguments={"geometries": geometries})
525530

@@ -570,11 +575,15 @@ def aggregate_spatial(
570575
geoms_is_empty = isinstance(geometries, DriverVectorCube) and len(geometries.get_geometries()) == 0
571576
cube = self
572577
if not geoms_is_empty:
573-
geometries, bbox = self._normalize_geometry(geometries)
578+
crs = None
579+
if(len(self.metadata.spatial_dimensions)>0):
580+
spatial_dim = self.metadata.spatial_dimensions[0]
581+
crs = spatial_dim.crs
582+
geometries, bbox = self._normalize_geometry(geometries,target_crs=crs)
574583
cube = self.filter_bbox(**bbox, operation="weak_spatial_extent")
575584
return cube._process(operation="aggregate_spatial", arguments={"geometries": geometries})
576585

577-
def _normalize_geometry(self, geometries) -> Tuple[Union[DriverVectorCube, DelayedVector, BaseGeometry], dict]:
586+
def _normalize_geometry(self, geometries, target_crs=None) -> Tuple[Union[DriverVectorCube, DelayedVector, BaseGeometry], dict]:
578587
"""
579588
Helper to preprocess geometries (as used in aggregate_spatial and mask_polygon)
580589
and extract bbox (e.g. for filter_bbox)
@@ -586,8 +595,17 @@ def _normalize_geometry(self, geometries) -> Tuple[Union[DriverVectorCube, Delay
586595
# TODO: buffer distance of 10m assumes certain resolution (e.g. sentinel2 pixels)
587596
# TODO: use proper distance for collection resolution instead of using a default distance?
588597
# TODO: or eliminate need for buffering in the first place? https://github.com/Open-EO/openeo-python-driver/issues/148
589-
bbox = geometries.buffer_points(distance=10).get_bounding_box()
590-
crs = geometries.get_crs_str()
598+
if target_crs is not None:
599+
is_utm = crs == "AUTO:42001" or "Auto42001" in str(target_crs)
600+
if is_utm:
601+
target_crs = BoundingBox.from_wsen_tuple(geometries.get_bounding_box(),crs=geometries.get_crs()).best_utm()
602+
else:
603+
target_crs = BoundingBox.normalize_crs(target_crs)
604+
bbox = geometries.buffer_points(distance=10).reproject(CRS.from_user_input( target_crs )).get_bounding_box()
605+
crs = target_crs
606+
else:
607+
bbox = geometries.buffer_points(distance=10).get_bounding_box()
608+
crs = geometries.get_crs_str()
591609
elif isinstance(geometries, dict):
592610
return self._normalize_geometry(geojson_to_geometry(geometries))
593611
elif isinstance(geometries, str):

tests/test_dry_run.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2185,3 +2185,57 @@ def test_complex_extract_load_stac(dry_run_env,dry_run_tracer):
21852185
assert (loadparams.global_extent == expected_extent)
21862186
assert (loadparams.target_resolution == [10,10])
21872187

2188+
def test_normalize_geometries(dry_run_env,dry_run_tracer):
2189+
geometry_path = str(get_path("geojson/points.geojson"))
2190+
pg = {
2191+
"lc": {"process_id": "load_collection", "arguments": {"id": "S2_FOOBAR"}},
2192+
"vector": {"process_id": "read_vector", "arguments": {"filename": geometry_path}},
2193+
"agg": {
2194+
"process_id": "aggregate_spatial",
2195+
"arguments": {
2196+
"data": {"from_node": "lc"},
2197+
"geometries": {"from_node": "vector"},
2198+
"reducer": {
2199+
"process_graph": {
2200+
"mean": {
2201+
"process_id": "mean",
2202+
"arguments": {"data": {"from_parameter": "data"}},
2203+
"result": True,
2204+
}
2205+
}
2206+
},
2207+
},
2208+
},
2209+
"raster": {
2210+
"process_id": "vector_to_raster",
2211+
"arguments": {"data": {"from_node": "agg"}, "target_data_cube": {"from_node": "lc"}},
2212+
},
2213+
"rename": {
2214+
"process_id": "rename_labels",
2215+
"arguments": {"data": {"from_node": "raster"}, "dimension": "bands", "target": ["score"]},
2216+
"result": True,
2217+
},
2218+
}
2219+
save_result = evaluate(pg, env=dry_run_env)
2220+
source_constraints = dry_run_tracer.get_source_constraints(merge=True)
2221+
print(source_constraints)
2222+
2223+
dry_run_env = dry_run_env.push({ENV_SOURCE_CONSTRAINTS: source_constraints})
2224+
params = [_extract_load_parameters(dry_run_env,source_id) for source_id, _ in source_constraints]
2225+
extents = [BoundingBox.from_dict(param.spatial_extent).as_polygon() for param in params]
2226+
2227+
from shapely.geometry import mapping
2228+
from shapely.ops import transform
2229+
import json
2230+
import pyproj
2231+
t = pyproj.Transformer.from_crs(pyproj.CRS.from_user_input(32632), pyproj.CRS.from_user_input(4326), always_xy=True)
2232+
extents += [transform(t.transform,BoundingBox.from_dict(param.global_extent).as_polygon().segmentize(1000)) for param in params]
2233+
2234+
#print(json.dumps(dict(type="FeatureCollection",features=[dict(type="Feature",geometry=mapping(e),properties={}) for e in extents])))
2235+
2236+
2237+
assert params[0].global_extent == {'crs': 'EPSG:32632',
2238+
'east': 636980,
2239+
'north': 5729350,
2240+
'south': 5654910,
2241+
'west': 89920}

0 commit comments

Comments
 (0)