"""Split one collinear T-junction; preserve all original vertices and surface geometry.""" from pathlib import Path import json,trimesh,numpy as np root=Path(__file__).resolve().parents[1];out=root/'output/depth_ablation_red_20260916';m=trimesh.load(root/'docs/上半.stl');old=m.copy() c=np.bincount(m.edges_unique_inverse);boundary=m.edges_unique[c==1];edge=max(boundary,key=lambda e:np.linalg.norm(m.vertices[e[0]]-m.vertices[e[1]]));a,b=edge v=m.vertices;ab=v[b]-v[a];t=(v-v[a])@ab/(ab@ab);dist=np.linalg.norm(v-(v[a]+t[:,None]*ab),axis=1);inside=np.flatnonzero((t>1e-7)&(t<1-1e-7)&(dist<1e-9));assert len(inside)==2 faces=m.faces.tolist();hit=[i for i,f in enumerate(faces) if a in f and b in f];assert len(hit)==1 face=faces.pop(hit[0]);k=next(k for k in range(3) if face[k] in edge and face[(k+1)%3] in edge);a,b,third=face[k],face[(k+1)%3],face[(k+2)%3] inside=sorted(inside,key=lambda q:np.linalg.norm(v[q]-v[a]));chain=[a,*inside,b];faces.extend([[int(x),int(y),int(third)] for x,y in zip(chain[:-1],chain[1:])]);m=trimesh.Trimesh(vertices=v.copy(),faces=faces,process=False) assert m.is_watertight and m.is_winding_consistent and m.volume>0 assert np.array_equal(m.vertices,old.vertices) and abs(m.area-old.area)<1e-10 and abs(m.volume-old.volume)<1e-10 m.export(out/'red_box_closed.ply') (out/'mesh_repair.json').write_text(json.dumps({'method':'Split original long boundary edge at two existing collinear vertices (T-junction); no added vertices or geometric hole filling','before_faces':len(old.faces),'after_faces':len(m.faces),'watertight':m.is_watertight,'winding_consistent':m.is_winding_consistent,'area_change_m2':m.area-old.area,'volume_change_m3':m.volume-old.volume},indent=2)) print('Topology repaired with unchanged geometry',m.is_watertight)