"""Thin the camera bracket tower (shared gnode_v2_cam_conn): mid-span slimmed to a 22x22 strut,
FULL section kept at the root band (holder attach) and top band (mount bond + wedge). Camera position
untouched — identical to the UMI wand viewpoint. Run AFTER any cam_conn re-pose (rigid_cam)."""
import numpy as np, trimesh, trimesh.repair
def LR(f):
    m = trimesh.load(f, force="mesh")
    if not m.is_volume:
        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()
    return m
def box(x0, x1, y0, y1, z0, z1):
    b = trimesh.creation.box(extents=[x1-x0, y1-y0, z1-z0])
    b.apply_translation([(x0+x1)/2, (y0+y1)/2, (z0+z1)/2]); return b
import shutil, os
if not os.path.exists("gnode_v2_cam_conn_full.stl"):
    shutil.copy("gnode_v2_cam_conn.stl", "gnode_v2_cam_conn_full.stl")
br = LR("gnode_v2_cam_conn_full.stl")
TOP_BAND, ROOT_BAND = -88.0, -16.0            # protect y <= TOP_BAND and y >= ROOT_BAND
STRUT = (20.0, 44.0, 3.0, 25.0)               # slim strut routed through space clear of the arm yoke (z>17 at the root)
cut = trimesh.boolean.difference(
    [box(0.0, 50.0, TOP_BAND, ROOT_BAND, -25.0, 35.0),
     box(STRUT[0], STRUT[1], TOP_BAND - 1, ROOT_BAND + 1, STRUT[2], STRUT[3])], engine="manifold")
thin = trimesh.boolean.difference([br, cut], engine="manifold")
keep = [b for b in thin.split(only_watertight=False) if b.volume > 100.0]
thin = keep[0] if len(keep) == 1 else trimesh.util.concatenate(keep)
thin.export("gnode_v2_cam_conn.stl")
print(f"thin bracket: wt={thin.is_watertight} bodies={len(thin.split(only_watertight=False))} vol={thin.volume/1000:.1f}cm3 (was {br.volume/1000:.1f})")
mount = LR("gnode_v2_camera_mount.stl")
bond = trimesh.boolean.intersection([mount, thin], engine="manifold").volume / 1000.0
print(f"mount bond: {bond:.2f}cm3 (unchanged = top band protected)")
