fix(map): make area analysis scale-aware
GeoIntel release gates / Compile, test, contracts and builds (push) Canceled after 0s
GeoIntel release gates / Python and npm vulnerability policy (push) Canceled after 0s
GeoIntel release gates / GIS image, SBOM and container scan (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-21 21:59:56 +02:00
parent 80631607f7
commit 20829f1a24
20 changed files with 619 additions and 56 deletions
+12 -3
View File
@@ -11,7 +11,7 @@ from geoalchemy2.shape import to_shape
from shapely.geometry import box, mapping, shape
from shapely.ops import transform as transform_geometry
from shapely.validation import make_valid
from sqlalchemy import Float, cast, func
from sqlalchemy import Float, String, cast, func
from app.core.errors import AppError
from app.models import Dataset, VectorFeature
@@ -548,6 +548,8 @@ class VectorFeatureService:
selection_area_id: UUID | None = None,
full_dataset_area: bool = False,
preclipped_partition_filter: tuple[str, str] | None = None,
dataset_ids: list[UUID] | None = None,
deduplicate_source_features: bool = False,
) -> dict[str, Any]:
normalized_bbox = VectorFeatureService._normalize_selection_bbox(bbox)
safe_limit = max(1, min(int(limit), 1000))
@@ -561,13 +563,19 @@ class VectorFeatureService:
4326,
)
query = db.query(VectorFeature).filter(VectorFeature.dataset_id == dataset_id)
selected_dataset_ids = dataset_ids or [dataset_id]
query = db.query(VectorFeature).filter(VectorFeature.dataset_id.in_(selected_dataset_ids))
if preclipped_partition_filter is not None:
partition_property, partition_value = preclipped_partition_filter
query = query.filter(VectorFeature.properties_json.op("->>")(partition_property) == partition_value)
if not full_dataset_area:
query = query.filter(ST_Intersects(VectorFeature.geometry, selection_shape))
if hasattr(query, "count"):
if deduplicate_source_features:
identity = func.coalesce(VectorFeature.source_feature_id, cast(VectorFeature.id, String))
total_feature_count = int(
query.with_entities(func.count(func.distinct(identity))).scalar() or 0
)
elif hasattr(query, "count"):
total_feature_count = int(query.count())
else: # Lightweight unit-test sessions do not always implement Query.count().
total_feature_count = len(query.all())
@@ -585,6 +593,7 @@ class VectorFeatureService:
summary = VectorFeatureService.summarize_features_by_bbox(
db,
dataset=dataset,
dataset_ids=selected_dataset_ids,
bbox=normalized_bbox,
total_feature_count=total_feature_count,
selection_geometry=selection_geometry,