"""Design probe (headless): numbers of the ship context the arm has to fit. Run: blender -b --factory-startup source/ship_context_2026-10-16.blend --python build/design_probe.py -- Reads only. Writes one JSON.""" import bpy, json, sys, math from mathutils import Vector OUT = sys.argv[sys.argv.index("--") + 1] scn = bpy.context.scene for o in bpy.data.objects: if not o.users_scene: scn.collection.objects.link(o) scn.frame_start, scn.frame_end = 1, 120 bpy.context.view_layer.update() rep = {"objects": {}, "door_track": {}, "sections": {}} def wverts(o, dg): ev = o.evaluated_get(dg) me = ev.to_mesh() mw = ev.matrix_world.copy() vs = [mw @ v.co for v in me.vertices] polys = [list(p.vertices) for p in me.polygons] ev.to_mesh_clear() return vs, polys def bbox(vs): return [[round(min(v[i] for v in vs), 4) for i in range(3)], [round(max(v[i] for v in vs), 4) for i in range(3)]] def section(vs, polys, x0): segs = [] for p in polys: pts = [] for i in range(len(p)): a, b = vs[p[i]], vs[p[(i + 1) % len(p)]] if (a.x - x0) * (b.x - x0) < 0: t = (x0 - a.x) / (b.x - a.x) q = a.lerp(b, t) pts.append([round(q.y, 4), round(q.z, 4)]) if len(pts) >= 2: segs.append(pts[:2]) return segs scn.frame_set(1) dg = bpy.context.evaluated_depsgraph_get() for o in bpy.data.objects: d = {"type": o.type, "loc": [round(x, 4) for x in o.location], "rot": [round(x, 5) for x in o.rotation_euler], "scale": [round(x, 4) for x in o.scale], "parent": o.parent.name if o.parent else None} if o.type == 'MESH': vs, polys = wverts(o, dg) d["bbox_f1"] = bbox(vs) d["nverts"] = len(vs) d["npolys"] = len(polys) lv = [v.co for v in o.data.vertices] d["bbox_local"] = bbox(lv) rep["objects"][o.name] = d # door tracks for dn in ("Moonpool_Door_Aft", "Moonpool_Door_Fore"): tr = [] for f in range(1, 121): scn.frame_set(f) o = bpy.data.objects[dn] tr.append([f] + [round(x, 5) for x in o.matrix_world.translation] + [round(x, 6) for x in o.matrix_world.to_euler()]) rep["door_track"][dn] = tr # door section in LOCAL coordinates (same section along x): at local x = 0 and near both ends scn.frame_set(1) dg = bpy.context.evaluated_depsgraph_get() for dn in ("Moonpool_Door_Aft", "Moonpool_Door_Fore"): o = bpy.data.objects[dn] lv = [v.co.copy() for v in o.data.vertices] polys = [list(p.vertices) for p in o.data.polygons] rep["sections"][dn + " | local"] = {str(x0): section(lv, polys, x0) for x0 in (-2.9, -2.0, 0.0, 2.0, 2.7)} # static meshes: world sections at a few x through the pocket statics = ["Moonpool | hull lining", "Moonpool | curved dry basin channel", "Moonpool | deck around open well", "Moonpool | titanium aperture rim", "Pocket AFT | upper rail", "Pocket FORE | upper rail", "Pocket AFT | conformal closed end", "Pocket FORE | conformal closed end"] for sn in statics: o = bpy.data.objects[sn] vs, polys = wverts(o, dg) xs = (-9.0, -8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.6, -2.0, 0.0, 3.0, 6.0, 8.0, 8.7, 10.0, 12.0, 14.0, 15.1) rep["sections"][sn] = {str(x0): section(vs, polys, x0) for x0 in xs} with open(OUT, "w") as fh: json.dump(rep, fh) print("PROBE DONE", OUT)