"""Door robot arm: every link of the arm as surface points in its own frame (origin on its joint, unscaled), for the fit (2026-10-18, scale-up). Reads this model's file; writes build/arm_points.npz (per link: points, joint, parent). blender -b --factory-startup --python build/dra_arm_points.py -- """ import os import sys import math import random import numpy as np import bpy HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, HERE) args = sys.argv[sys.argv.index("--") + 1:] bpy.ops.wm.open_mainfile(filepath=args[0], load_ui=False) import dra_rigdata as rd # noqa: E402 STEP = 0.035 rng = random.Random(5) out = {} for spec in rd.LINKS: me = bpy.data.meshes.get(rd.mesh_name(spec["name"])) if me is None: continue me.calc_loop_triangles() V = [v.co.copy() for v in me.vertices] lay = me.attributes.get('part') dec = list(me.get("decals", [])) pts = [tuple(v) for v in V] for lt in me.loop_triangles: if lay is not None and dec: pv = lay.data[lt.polygon_index].value if 0 <= pv < len(dec) and dec[pv]: continue a, b, c = (V[i] for i in lt.vertices) area = (b - a).cross(c - a).length / 2 n = int(area / (STEP * STEP)) for _ in range(n): r1, r2 = rng.random(), rng.random() if r1 + r2 > 1: r1, r2 = 1 - r1, 1 - r2 p = a + (b - a) * r1 + (c - a) * r2 pts.append((p.x, p.y, p.z)) P = np.array(pts, np.float32) key = spec["name"].replace(" ", "_") out["pts__" + key] = P out["joint__" + key] = np.array(spec["joint"], np.float64) out["parent__" + key] = np.array(spec["parent"] or "") print("[ap] %-26s %6d points" % (spec["name"], len(P)), flush=True) np.savez_compressed(os.path.join(HERE, "arm_points.npz"), **out) print("[ap] written", flush=True)