Files
quartier/pipeline/extract_quartier.py
T
Jules NényandClaude Fable 5.1 2e249f1027 LOT Q0 : socle du démonstrateur Quelque part en 2035
Scaffold Vite + TypeScript + Three.js (scène vide : sol + boîte, marqueur de build),
store et encodage de l'état dans l'URL (5 tests), lint de frontières entre modules,
pipeline d'extraction Rhino (graine du 26/09) et première géométrie v0,
deploy.sh statique (releases + lien symbolique + smoke), AGENTS.md, RUNBOOK, licences MIT + CC BY-SA 4.0.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-27 15:21:40 +02:00

35 lines
1.8 KiB
Python

import sys, json, math, rhino3dm
from shapely.geometry import Polygon
p = sys.argv[1]; m = rhino3dm.File3dm.Read(p)
L = {i: l.Name for i, l in enumerate(m.Layers)}
def pts(c):
n = 64 if not isinstance(c,(rhino3dm.PolylineCurve,)) else c.PointCount
if isinstance(c, rhino3dm.PolylineCurve):
return [(c.Point(i).X/100, c.Point(i).Y/100) for i in range(c.PointCount)]
pl = c.ToPolyline(0.0,0.0,0.1,5.0,0.0,0.0,0.0,0.0,True) if hasattr(c,'ToPolyline') else None
if pl is None:
d=c.Domain; return [(c.PointAt(d.T0+(d.T1-d.T0)*i/n).X/100, c.PointAt(d.T0+(d.T1-d.T0)*i/n).Y/100) for i in range(n+1)]
return [(pl[i].X/100, pl[i].Y/100) for i in range(pl.Count)]
out = {"parcelles":[], "noues":[], "sentiers":[], "topo":[], "plante":[], "maisons_candidates":[], "autres_fermes":[]}
for o in m.Objects:
g=o.Geometry; ln=L.get(o.Attributes.LayerIndex,"")
if not isinstance(g, rhino3dm.Curve): continue
try: P=pts(g)
except Exception: continue
if len(P)<2: continue
if ln=="7_TOPO": out["topo"].append(P); continue
if not g.IsClosed: continue
try: poly=Polygon(P); a=poly.area
except Exception: continue
if ln=="PARCELLES": out["parcelles"].append(P)
elif ln=="B_EAU noues": out["noues"].append(P)
elif ln=="C_SENTIER": out["sentiers"].append(P)
elif ln=="planté": out["plante"].append(P)
elif ln in ("0","caché","3_ TRAITS VUS","4_ TRAITS VUS FIINS","traits cachés","Défaut","ombres portées") and 40<=a<=400:
# maison candidate : quadrilatère-ish compact
mrr=poly.minimum_rotated_rectangle;
if mrr.area>0 and a/mrr.area>0.7: out["maisons_candidates"].append({"layer":ln,"area":round(a,1),"pts":P})
json.dump(out, open(sys.argv[2],"w"))
print({k:len(v) for k,v in out.items()})
import collections; print(collections.Counter(c["layer"] for c in out["maisons_candidates"]))