from pathlib import Path import xml.etree.ElementTree as E,trimesh,coacd,json R=Path(__file__).resolve().parents[1];O=R/'output/collision_fix_20260915/hand_collision';O.mkdir(exist_ok=True) r=E.parse(R/'output/foundationpose_spider_20260915/datasets/processed/current/l20/bimanual/boxes/scene_act.xml').getroot();report={};coacd.set_log_level('warn') for x in r.findall('asset/mesh'): n=x.get('name') if not any(n==s+'_'+part+'_mesh_0' for s in ['right','left'] for part in ['hand_base_link','thumb_metacarpals']):continue m=trimesh.load(x.get('file'));parts=coacd.run_coacd(coacd.Mesh(m.vertices,m.faces),threshold=.015,max_convex_hull=16,preprocess_mode='auto',preprocess_resolution=60,resolution=1000,mcts_nodes=10,mcts_iterations=40,mcts_max_depth=3,merge=True,seed=0) for i,(v,f) in enumerate(parts):trimesh.Trimesh(v,f,process=False).export(O/f'{n}_{i:03d}.obj') report[n]={'parts':len(parts),'original_hull_volume':float(m.convex_hull.volume),'parts_volume_sum':float(sum(trimesh.Trimesh(v,f,process=False).volume for v,f in parts)),'nonwatertight_source':not m.is_watertight} (O/'manifest.json').write_text(json.dumps(report,indent=2));print(n,report[n],flush=True)