From 2ae460fc4a4c2419cf44329783d49a739e2a04ea Mon Sep 17 00:00:00 2001
From: shuishen <1109946754@qq.com>
Date: Wed, 19 Aug 2026 16:58:50 +0800
Subject: [PATCH] Merge branch 'master' of http://139.196.74.78:10010/r/geoai/geoai-workbench

---
 capabilities/00-change-detection/rectangularize_vectors.py |   45 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 45 insertions(+), 0 deletions(-)

diff --git a/capabilities/00-change-detection/rectangularize_vectors.py b/capabilities/00-change-detection/rectangularize_vectors.py
new file mode 100644
index 0000000..959ec41
--- /dev/null
+++ b/capabilities/00-change-detection/rectangularize_vectors.py
@@ -0,0 +1,45 @@
+"""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)

--
Gitblit v1.9.3