bound change detection to the operator's selection
Change detection was the one analysis that ignored the selection entirely. It compared two datasets in full, loaded every feature of both into Python with no spatial predicate, and — with include_unchanged defaulting to true — returned a FeatureCollection holding both datasets. For a regional building layer that is the wrong answer to "what changed here" and a response no browser should be asked to hold. It now accepts bbox and area_id, resolved the way every other analysis resolves them, and loads through an indexed ST_Intersects predicate. Features are deliberately not clipped to the selection. A change class describes a whole object: comparing a clipped earlier footprint against an unclipped later one would report the selection edge itself as a change. Objects the edge crosses are compared in full and counted in a warning. The returned geometry is capped by preview_limit, spending that budget on modified, added and removed before unchanged, while every count still describes the whole selection. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,12 +5,22 @@ from uuid import UUID
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from app.schemas.operations import VectorSelectionBBox
|
||||
|
||||
|
||||
class ChangeDetectionRequest(BaseModel):
|
||||
source_dataset_id: UUID
|
||||
target_dataset_id: UUID
|
||||
iou_threshold: float = Field(default=0.8, ge=0.0, le=1.0)
|
||||
# Below this the two footprints are separate objects rather than one that
|
||||
# was redrawn; between the two thresholds the change class is "modified".
|
||||
modified_threshold: float = Field(default=0.3, ge=0.0, le=1.0)
|
||||
include_unchanged: bool = True
|
||||
# Without a selection the comparison covers both datasets in full, which is
|
||||
# rarely the question and never a response a map can draw.
|
||||
bbox: VectorSelectionBBox | None = None
|
||||
area_id: UUID | None = None
|
||||
preview_limit: int = Field(default=2_000, ge=1, le=20_000)
|
||||
|
||||
|
||||
class ChangeDetectionSummary(BaseModel):
|
||||
@@ -26,6 +36,11 @@ class ChangeDetectionSummary(BaseModel):
|
||||
unchanged_count: int
|
||||
iou_threshold: float
|
||||
modified_iou_threshold: float | None = None
|
||||
selection_area_id: UUID | None = None
|
||||
# Counts describe the whole selection; the GeoJSON is capped so a regional
|
||||
# comparison does not return both datasets in one response.
|
||||
preview_limit: int | None = None
|
||||
preview_truncated: bool = False
|
||||
warnings: list[str] = Field(default_factory=list)
|
||||
generated_at: datetime
|
||||
geojson: dict
|
||||
|
||||
Reference in New Issue
Block a user