"""Prepare an uploaded single-solid STEP for the casting prediction sandbox.""" import sys,json,time from pathlib import Path import numpy as np import inspect_step_parts as geo from OCC.Core.BRepCheck import BRepCheck_Analyzer from OCC.Core.BRepClass3d import BRepClass3d_SolidClassifier from OCC.Core.TopAbs import TopAbs_IN from OCC.Core.gp import gp_Pnt from OCC.Core.ShapeFix import ShapeFix_Shape from OCC.Core.BRepGProp import brepgprop from OCC.Core.GProp import GProp_GProps folder=Path(sys.argv[1]); shape=geo.read(folder/'input.step') def volume(s): p=GProp_GProps();brepgprop.VolumeProperties(s,p);return p.Mass() original=volume(shape);repaired=False if not BRepCheck_Analyzer(shape).IsValid(): fix=ShapeFix_Shape(shape);fix.Perform();shape=fix.Shape();repaired=True if not BRepCheck_Analyzer(shape).IsValid():raise ValueError('STEP solid is invalid after repair. Please heal it in CAD.') ss=geo.solids(shape) if len(ss)!=1:raise ValueError(f'This pilot supports one closed solid; file contains {len(ss)} solids.') if original<=0 or abs(volume(shape)-original)/original>.001:raise ValueError('Invalid volume or repair changed volume by more than 0.1%.') mesh,_=geo.mesh_shape(shape,.2);v=np.asarray(mesh.vertices);f=np.asarray(mesh.faces) if len(f)>150000:raise ValueError('Tessellation exceeds pilot limit of 150,000 triangles.') lo=v.min(0);hi=v.max(0);rng=np.random.default_rng(1742026);classifier=BRepClass3d_SolidClassifier(ss[0]);points=[];start=time.monotonic() for batch in range(150): for p in rng.uniform(lo,hi,(2048,3)): classifier.Perform(gp_Pnt(*p),1e-7) if classifier.State()==TopAbs_IN:points.append(p) if len(points)==2048:break if len(points)==2048:break if time.monotonic()-start>100:break if len(points)<2048:raise ValueError('Part is too thin or sparse for this pilot sampler; could not obtain 2,048 interior points.') n=np.cross(v[f[:,1]]-v[f[:,0]],v[f[:,2]]-v[f[:,0]]);areas=np.linalg.norm(n,axis=1);n/=np.maximum(areas[:,None],1e-12);cent=v[f].mean(1) ix=rng.choice(len(f),1024,p=areas/areas.sum(),replace=True) np.savez_compressed(folder/'geometry.npz',vertices=v,triangles=f,centers=cent,normals=n,areas=areas,points=np.array(points),surface=cent[ix],encoder_normals=n[ix]) (folder/'geometry.json').write_text(json.dumps({'dimensions_mm':(hi-lo).tolist(),'volume_mm3':volume(shape),'repair_applied':repaired,'repair_relative_volume_change':abs(volume(shape)-original)/original,'units':'mm (STEP reader conversion)','solid_count':1}))