"""Convert irregular change polygons into product-friendly rectangles."""
|
|
from __future__ import annotations
|
|
import json
|
from pathlib import Path
|
|
from shapely.geometry import box, mapping, shape
|
|
|
def rectangularize_vector(source: Path, destination: Path, wgs84_destination: Path | None = None) -> int:
|
# geoai.masks_to_vector may omit the file when a threshold produces no
|
# features. Keep the artifact contract stable by materializing an empty
|
# GeoJSON collection so downstream promotion and downloads still work.
|
if source.is_file():
|
payload = json.loads(source.read_text(encoding="utf-8"))
|
else:
|
payload = {"type": "FeatureCollection", "features": []}
|
source.parent.mkdir(parents=True, exist_ok=True)
|
source.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")
|
rectangles = []
|
for feature in payload.get("features", []):
|
geometry = feature.get("geometry")
|
if not geometry:
|
continue
|
source_shape = shape(geometry)
|
if source_shape.is_empty:
|
continue
|
rectangle = box(*source_shape.bounds)
|
properties = dict(feature.get("properties") or {})
|
properties["geometry_mode"] = "axis_aligned_rectangle"
|
properties["source_geometry_type"] = source_shape.geom_type
|
rectangles.append({"type": "Feature", "properties": properties, "geometry": mapping(rectangle)})
|
output = {"type": "FeatureCollection", "features": rectangles}
|
if payload.get("crs"):
|
output["crs"] = payload["crs"]
|
destination.parent.mkdir(parents=True, exist_ok=True)
|
destination.write_text(json.dumps(output, ensure_ascii=False, indent=2), encoding="utf-8")
|
if wgs84_destination is not None and payload.get("crs") and rectangles:
|
import geopandas as gpd
|
|
frame = gpd.GeoDataFrame.from_features(output["features"], crs=payload["crs"].get("properties", {}).get("name"))
|
if frame.crs:
|
frame.to_crs("EPSG:4326").to_file(wgs84_destination, driver="GeoJSON")
|
return len(rectangles)
|