fix: query persisted work area geometry
GeoIntel CI / docs-smoke (push) Canceled after 0s
GeoIntel CI / contract-smoke (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-14 19:38:41 +02:00
parent a879c74b12
commit 616424e2a2
9 changed files with 179 additions and 46 deletions
+31 -24
View File
@@ -124,25 +124,25 @@ class VectorFeatureService:
bbox: dict[str, Any],
limit: int = 100,
dataset: Dataset | None = None,
selection_geometry: Any | None = None,
selection_area_id: UUID | None = None,
) -> dict[str, Any]:
normalized_bbox = VectorFeatureService._normalize_selection_bbox(bbox)
safe_limit = max(1, min(int(limit), 1000))
selection_shape = selection_geometry
if selection_shape is None:
selection_shape = ST_MakeEnvelope(
normalized_bbox["min_x"],
normalized_bbox["min_y"],
normalized_bbox["max_x"],
normalized_bbox["max_y"],
4326,
)
query = (
db.query(VectorFeature)
.filter(VectorFeature.dataset_id == dataset_id)
.filter(
ST_Intersects(
VectorFeature.geometry,
ST_MakeEnvelope(
normalized_bbox["min_x"],
normalized_bbox["min_y"],
normalized_bbox["max_x"],
normalized_bbox["max_y"],
4326,
),
)
)
.filter(ST_Intersects(VectorFeature.geometry, selection_shape))
)
if hasattr(query, "count"):
total_feature_count = int(query.count())
@@ -164,9 +164,10 @@ class VectorFeatureService:
dataset=dataset,
bbox=normalized_bbox,
total_feature_count=total_feature_count,
selection_geometry=selection_geometry,
)
return {
result = {
"selection_bbox": normalized_bbox,
"feature_count": len(features),
"total_feature_count": total_feature_count,
@@ -178,6 +179,9 @@ class VectorFeatureService:
},
"summary": summary,
}
if selection_area_id is not None:
result["selection_area_id"] = str(selection_area_id)
return result
@staticmethod
def summarize_features_by_bbox(
@@ -186,18 +190,21 @@ class VectorFeatureService:
dataset: Dataset,
bbox: dict[str, Any],
total_feature_count: int | None = None,
selection_geometry: Any | None = None,
) -> dict[str, Any]:
normalized_bbox = VectorFeatureService._normalize_selection_bbox(bbox)
envelope = ST_MakeEnvelope(
normalized_bbox["min_x"],
normalized_bbox["min_y"],
normalized_bbox["max_x"],
normalized_bbox["max_y"],
4326,
)
selection_shape = selection_geometry
if selection_shape is None:
selection_shape = ST_MakeEnvelope(
normalized_bbox["min_x"],
normalized_bbox["min_y"],
normalized_bbox["max_x"],
normalized_bbox["max_y"],
4326,
)
selection_filter = (
VectorFeature.dataset_id == dataset.id,
ST_Intersects(VectorFeature.geometry, envelope),
ST_Intersects(VectorFeature.geometry, selection_shape),
)
feature_count = total_feature_count
if feature_count is None:
@@ -215,13 +222,13 @@ class VectorFeatureService:
metric_value = float(feature_count)
if method == "intersection_area":
intersection = func.ST_Intersection(VectorFeature.geometry, envelope)
intersection = func.ST_Intersection(VectorFeature.geometry, selection_shape)
area_expression = func.ST_Area(func.ST_Transform(intersection, 31370))
area_m2 = db.query(func.coalesce(func.sum(area_expression), 0.0)).filter(*selection_filter).scalar()
divisor = 10_000.0 if unit == "ha" else 1.0
metric_value = float(area_m2 or 0.0) / divisor
elif method == "intersection_length":
intersection = func.ST_Intersection(VectorFeature.geometry, envelope)
intersection = func.ST_Intersection(VectorFeature.geometry, selection_shape)
length_expression = func.ST_Length(func.ST_Transform(intersection, 31370))
length_m = db.query(func.coalesce(func.sum(length_expression), 0.0)).filter(*selection_filter).scalar()
divisor = 1_000.0 if unit == "km" else 1.0
@@ -240,7 +247,7 @@ class VectorFeatureService:
if method == "area_weighted_sum":
source_area = func.ST_Area(func.ST_Transform(VectorFeature.geometry, 31370))
intersection_area = func.ST_Area(
func.ST_Transform(func.ST_Intersection(VectorFeature.geometry, envelope), 31370)
func.ST_Transform(func.ST_Intersection(VectorFeature.geometry, selection_shape), 31370)
)
coverage_ratio = intersection_area / func.nullif(source_area, 0.0)
value_expression = numeric_value * coverage_ratio