"""Read pinned STEP B-rep; write reproducible solid/face measurements beside it.""" import json import re from pathlib import Path from OCP.STEPControl import STEPControl_Reader from OCP.IFSelect import IFSelect_RetDone from OCP.TopExp import TopExp_Explorer from OCP.TopAbs import TopAbs_SOLID, TopAbs_FACE from OCP.TopoDS import TopoDS from OCP.Bnd import Bnd_Box from OCP.BRepBndLib import BRepBndLib from OCP.BRepAdaptor import BRepAdaptor_Surface from OCP.GeomAbs import GeomAbs_Cylinder, GeomAbs_Plane from OCP.BRepCheck import BRepCheck_Analyzer HERE = Path(__file__).resolve().parent def bounds(s): b = Bnd_Box() BRepBndLib.AddOptimal_s(s, b, False, False) return list(b.Get()) def xyz(p): return [p.X(), p.Y(), p.Z()] r = STEPControl_Reader() assert r.ReadFile(str(HERE / '5988 RS-232 Level Shifter.step')) == IFSelect_RetDone r.TransferRoots() entities = dict(re.findall(r'#(\d+)\s*=\s*(.*?);', (HERE / '5988 RS-232 Level Shifter.step').read_text(), re.S)) styles = {} for text in entities.values(): if text.startswith('STYLED_ITEM('): refs = re.findall(r'#(\d+)', text) styles[refs[-1]] = refs[:-1] def colors(refs, seen=None): seen = set() if seen is None else seen result = [] for ref in refs: if ref in seen: continue seen.add(ref) text = entities[ref] if text.startswith('COLOUR_RGB('): result.append(text.replace('\n', '')) else: result.extend(colors(re.findall(r'#(\d+)', text), seen)) return result e = TopExp_Explorer(r.OneShape(), TopAbs_SOLID) out = [] while e.More(): s = TopoDS.Solid_s(e.Current()) item = dict(id=len(out)+1, bounds=bounds(s), valid=BRepCheck_Analyzer(s).IsValid(), faces=[]) f = TopExp_Explorer(s, TopAbs_FACE) while f.More(): face = TopoDS.Face_s(f.Current()) a = BRepAdaptor_Surface(face) # These unique bodies retain CLOSED_SHELL face order on this pinned import. shell_id = {1: '14428', 12: '14431', 13: '14432', 14: '14433'}.get(item['id']) refs = re.findall(r'#(\d+)', entities[shell_id]) if shell_id else [] step_id = refs[len(item['faces'])] if refs else '0' if refs: surface_id = re.findall(r'#(\d+)', entities[step_id])[-1] surface = entities[surface_id] expected = str(a.GetType()).split('_')[-1].upper() assert surface.startswith({'PLANE': 'PLANE(', 'CYLINDER': 'CYLINDRICAL_SURFACE(', 'CONE': 'CONICAL_SURFACE(', 'TORUS': 'TOROIDAL_SURFACE('}[expected]) if a.GetType() == GeomAbs_Cylinder: assert abs(float(surface.rsplit(',', 1)[1].rstrip(')')) - a.Cylinder().Radius()) < 1e-8 row = dict(id=len(item['faces'])+1, bounds=bounds(face), type=str(a.GetType()), orientation=str(face.Orientation())) row.update(step_id=step_id, colors=colors(styles.get(step_id, []))) if a.GetType() == GeomAbs_Cylinder: c = a.Cylinder() row.update(radius=c.Radius(), location=xyz(c.Location()), axis=xyz(c.Axis().Direction())) elif a.GetType() == GeomAbs_Plane: p = a.Plane() row.update(location=xyz(p.Location()), normal=xyz(p.Axis().Direction())) item['faces'].append(row) f.Next() if shell_id: assert len(item['faces']) == len(refs) out.append(item) e.Next() (HERE / 'geometry.json').write_text(json.dumps(out, indent=2)+'\n') for s in out: print(s['id'], 'valid', s['valid'], 'bounds', [round(v,6) for v in s['bounds']], 'faces', len(s['faces']))