"""Join the gripper into its two printable pieces (servo excluded):
- gripper_print_base.stl  = holder + connector1 + servo_to_finger plate + fixed_conn + finger_adj (static jaw)
- gripper_print_thumb.stl = yoke + yoke_conn + fin-ray finger (moving jaw, bolts to the servo output)"""
import trimesh, trimesh.repair
def load(n):
    m = trimesh.load(f"gnode_{n}.stl", force="mesh")
    if not m.is_volume:                       # repair tessellation cracks (e.g. build123d yoke export)
        m.merge_vertices(merge_tex=True, merge_norm=True)
        m.update_faces(m.nondegenerate_faces()); m.update_faces(m.unique_faces())
        trimesh.repair.fill_holes(m); m.fix_normals()
        print(f"repaired {n}: volume_ok={m.is_volume}")
    return m
def U(names):
    return trimesh.boolean.union([load(n) for n in names], engine="manifold")
base = U(["holder", "connector1", "servo_to_finger", "fixed_conn", "finger_adj"])
base.export("gripper_print_base.stl")
thumb = U(["yoke", "yoke_conn", "finger"])
thumb.export("gripper_print_thumb.stl")
for n, m in [("base", base), ("thumb", thumb)]:
    bodies = len(m.split(only_watertight=False))
    print(f"gripper_print_{n}: wt={m.is_watertight} bodies={bodies} vol={m.volume/1000:.1f}cm3 bbox={[round(v) for v in m.extents]}mm{'  <-- WARNING disjoint!' if bodies>1 else ''}")
