# Extrait toute la géométrie utile du plan Rhino TRANSFO en mètres (JSON), une fois pour toutes. import sys, json, rhino3dm, math m = rhino3dm.File3dm.Read(sys.argv[1]) L = {i: l.Name for i, l in enumerate(m.Layers)} def pts(c, n=48): if isinstance(c, rhino3dm.PolylineCurve): return [(c.Point(i).X/100, c.Point(i).Y/100) for i in range(c.PointCount)] if isinstance(c, rhino3dm.LineCurve): return [(c.PointAtStart.X/100, c.PointAtStart.Y/100), (c.PointAtEnd.X/100, c.PointAtEnd.Y/100)] 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)] courbes = [] instances = [] defs = {str(d.Id): d.Name for d in m.InstanceDefinitions} for o in m.Objects: g = o.Geometry; ln = L.get(o.Attributes.LayerIndex, "") if isinstance(g, rhino3dm.InstanceReference): x = g.Xform px, py = x.M03/100, x.M13/100 sx = math.hypot(x.M00, x.M10); instances.append({"l": ln, "d": defs.get(str(g.ParentIdefId), "?"), "x": round(px, 3), "y": round(py, 3), "s": round(sx, 4)}) continue if not isinstance(g, rhino3dm.Curve): continue try: P = pts(g) except Exception: continue if len(P) < 2: continue courbes.append({"l": ln, "f": bool(g.IsClosed), "p": [[round(a, 3), round(b, 3)] for a, b in P]}) # boîte englobante de chaque définition de bloc (pour le rayon des arbres) bb = {} for d in m.InstanceDefinitions: xs, ys = [], [] for oid in d.GetObjectIds(): ob = m.Objects.FindId(oid) if ob is None: continue try: b = ob.Geometry.GetBoundingBox(); xs += [b.Min.X, b.Max.X]; ys += [b.Min.Y, b.Max.Y] except Exception: pass if xs: bb[d.Name] = [round((max(xs)-min(xs))/100, 3), round((max(ys)-min(ys))/100, 3)] json.dump({"courbes": courbes, "instances": instances, "defs_bbox": bb}, open(sys.argv[2], "w")) import collections print("courbes", len(courbes), "instances", len(instances)) print(collections.Counter(i["l"] for i in instances).most_common(12)) print("defs bbox (échantillon)", list(bb.items())[:8])