"""Does the Season 1 furniture stand clear of what the Season 2 rooms already hold? (bounding boxes, world space) blender -b --factory-startup models/M_Ship_v2_interior_season2.blend --python build/check_furniture.py """ import json import bpy import numpy as np TOL = 0.03 # furniture stands on the floor: touching by this much is not a clash FLOORS = ("SM_Floor_A", "SM_GlassFloor", "SM_FloorPipes") def box(ob): me = ob.data co = np.empty(len(me.vertices) * 3) me.vertices.foreach_get("co", co) m = np.array(ob.matrix_world) v = co.reshape(-1, 3) @ m[:3, :3].T + m[:3, 3] return v.min(0), v.max(0) out = [] for zname in ("10.4 | Fore main deck", "10.5 | Command deck"): col = bpy.data.collections[zname] objs = [o for o in col.objects if o.type == "MESH" and o.get("ue_mesh")] furn = [o for o in objs if "/ModularScifiProps/" in o["ue_mesh"]] rest = [o for o in objs if o["ue_mesh"].startswith("/Game/ModSci")] rb = [(o, box(o)) for o in rest if not o.data.name.split("_", 1)[1].startswith(FLOORS)] for f in furn: lo, hi = box(f) for o, (l2, h2) in rb: ov = np.minimum(hi, h2) - np.maximum(lo, l2) if (ov > TOL).all(): out.append({"zone": zname, "furniture": f.data.name, "at": [round(float(c), 2) for c in (lo + hi) / 2], "clashes_with": o.data.name, "overlap_m": [round(float(c), 2) for c in ov]}) print("FURNITURE " + json.dumps({"clashes": len(out), "pairs": out[:40]}))