from pathlib import Path import os, time, json, traceback import FreeCAD as A, FreeCADGui as G, Part, Import R=Path(r'C:\projects\wheel') O=R/'models'/'integer_profiles';O.mkdir(parents=True,exist_ok=True) try: d=A.openDocument(str(R/'models'/'switch_2020_crossbar132'/'Assembly.FCStd')) d.Label='Wheel assembly - integer profile lengths' check={}; baselines={} for i in range(2): o=d.getObject('Crossbeam%d'%i);b=o.Shape.BoundBox old=o.Shape.copy() cutbox=Part.makeBox(71, b.YLength, b.ZLength,A.Vector(-35.5,b.YMin,b.ZMin)) new=old.common(cutbox) assert new.isValid() and len(new.Solids)==1 and abs(new.BoundBox.XLength-71)<1e-6 assert new.cut(old).Volume <1e-5 o.Shape=new;o.Label='3030 crossbeam %d - 71 mm'%i baselines[o.Name]={'removed_mm3':old.cut(new).Volume,'added_mm3':new.cut(old).Volume} d.recompute() for n,dimensions in [('NewRail0',(30,30,255)),('NewRail1',(30,30,255)),('Crossbeam0',(71,30,30)),('Crossbeam1',(71,30,30)),('Rail0',(20,110,20)),('Rail1',(20,110,20)),('SwitchCross2020',(132,20,20))]: o=d.getObject(n);b=o.Shape.BoundBox dims=(b.XLength,b.YLength,b.ZLength) assert all(abs(a-b)<1e-6 for a,b in zip(dims,dimensions)),(n,dims) check[n]={'dimensions_xyz_mm':dims} for i in range(2): for j in range(2): cross=d.getObject('Crossbeam%d'%i).Shape rail=d.getObject('NewRail%d'%j).Shape angle=d.getObject('BaseJoint%d%d'%(i,j)).Shape pd=d.getObject('PurchasedAngle%d%d'%(i,j)).Shape check['beam%d_rail%d'%(i,j)]={'distance_mm':cross.distToShape(rail)[0],'intersection_mm3':cross.common(rail).Volume} check['beam%d_angle%d'%(i,j)]={'distance_mm':cross.distToShape(angle)[0],'intersection_mm3':cross.common(angle).Volume} check['rail%d_angle%d%d'%(j,i,j)]={'distance_mm':rail.distToShape(angle)[0],'intersection_mm3':rail.common(angle).Volume} check['beam%d_longangle%d'%(i,j)]={'distance_mm':cross.distToShape(pd)[0],'intersection_mm3':cross.common(pd).Volume} assert cross.distToShape(angle)[0]<1e-6 and cross.common(angle).Volume<1e-6 assert rail.distToShape(angle)[0]<1e-6 and rail.common(angle).Volume<1e-6 assert cross.distToShape(pd)[0]<1e-6 and cross.common(pd).Volume<1e-6 assert abs(cross.distToShape(rail)[0]-.1200577)<1e-5 assert cross.common(rail).Volume<1e-6 d.recompute() d.saveAs(str(O/'Assembly.FCStd')) visible=[o for o in d.Objects if hasattr(o,'Shape') and not o.Shape.isNull() and o.ViewObject.Visibility] Import.export(visible,str(O/'Assembly.step')) v=G.activeDocument().activeView();v.viewAxonometric();G.updateGui();v.fitAll();time.sleep(.5);G.updateGui();v.saveImage(str(O/'assembly.png'),1800,1250,'White') source=O/'Assembly.FCStd';A.closeDocument(d.Name) dd=A.openDocument(str(source));dd.recompute() for i in range(2): assert abs(dd.getObject('Crossbeam%d'%i).Shape.BoundBox.XLength-71)<1e-6 s=Part.read(str(O/'Assembly.step'));assert s.isValid() and len(s.Solids)>0 check['baselines']=baselines;check['fcstd_reopened']=True;check['step_valid']=True;check['step_solid_count']=len(s.Solids) (O/'validation.json').write_text(json.dumps(check,indent=2),encoding='utf8') A.closeDocument(dd.Name) (O/'DONE.txt').write_text('OK',encoding='utf8') os._exit(0) except Exception: (O/'ERROR.txt').write_text(traceback.format_exc(),encoding='utf8');os._exit(1)