from pathlib import Path import os, time, json, traceback import FreeCAD as A, FreeCADGui as G, Part, Import from pivy import coin R=Path(r'C:\projects\wheel'); O=R/'models'/'switch_2020_crossbar132'; O.mkdir(parents=True,exist_ok=True) try: d=A.openDocument(str(R/'models'/'switch_2020_direct_profiles'/'Assembly.FCStd')) beam=d.getObject('SwitchCross2020'); old=beam.Shape.copy() assert abs(old.BoundBox.XLength-160)<1e-5 beam.Shape=Part.makeBox(132,20,20,A.Vector(-66,-55,-142)) beam.Label='Switch crossbeam 2020 x 132 mm'; d.recompute() new=beam.Shape assert new.isValid() and abs(new.BoundBox.XLength-132)<1e-6 added=new.cut(old).Volume; removed=old.cut(new).Volume assert added<1e-7 and abs(removed-11200)<1e-5 result={'crossbar_length_mm':132,'profile_mm':[20,20],'crossbar_x_min_mm':-66,'crossbar_x_max_mm':66,'added_volume_mm3':added,'removed_volume_mm3':removed,'components':{}} # Replace the two old square bearing plates by the latest V3 machining model. # V3 coordinates have the same X origin, Y=0 at the plate bottom, and Z=0 at its front face. v3=Part.read(str(R/'models'/'kfl001_plate_v3_alt'/'KFL001_plate_V3.step')) result['bearing_plates_v3']={} for i,z in ((0,-84),(1,-187)): obj=d.getObject('CompactPlate%d'%i);before=obj.Shape.copy() revised=v3.copy();revised.translate(A.Vector(0,-41,z)) addedplate=revised.cut(before).Volume assert addedplate<1e-4,(i,addedplate) obj.Placement=A.Placement();obj.Shape=revised obj.Label='Bearing plate V3 %d (76 x 75 x 8)'%(i+1) result['bearing_plates_v3'][obj.Name]={'added_volume_mm3':addedplate,'removed_volume_mm3':before.cut(revised).Volume,'z_mm':z} d.recompute() for n in ['NewRail0','NewRail1','SwitchAngleA','SwitchAngleB','SwitchCrossJoint0','SwitchCrossJoint1','SwitchEnvelope']: obj=d.getObject(n);bb=obj.Shape.BoundBox overlap=new.common(obj.Shape).Volume if new.BoundBox.intersect(bb) else 0 distance=new.distToShape(obj.Shape)[0] result['components'][n]={'x_min_mm':bb.XMin,'x_max_mm':bb.XMax,'distance_mm':distance,'overlap_mm3':overlap} if n!='SwitchEnvelope': assert bb.XMin>=-66 and bb.XMax<=66,(n,bb.XMin,bb.XMax) assert overlap<0.001,(n,overlap) else: assert distance>4.99 for n in ['SwitchAngleA','SwitchAngleB','SwitchCrossJoint0','SwitchCrossJoint1']: assert result['components'][n]['distance_mm']<0.0001, n d.Label='Switch crossbar 2020 x 132 mm - layout' 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')) G.activateWorkbench('PartWorkbench');view=G.activeDocument().activeView() view.viewAxonometric();G.updateGui();view.getCameraNode().orientation.setValue(coin.SbRotation(.880476,.115917,-.279848,-.364705));G.updateGui();time.sleep(.3);view.fitAll();G.updateGui();time.sleep(.4);view.saveImage(str(O/'assembly.png'),1800,1250,'White') visibility={o.Name:o.ViewObject.Visibility for o in d.Objects if hasattr(o,'Shape')} show=set(['SwitchCross2020','SwitchAngleA','SwitchAngleB','SwitchHeadA','SwitchHeadB','SwitchRailHeadA','SwitchRailHeadB','SwitchCrossJoint0','SwitchCrossJoint1','SwitchEnvelope','AssumedEarA','AssumedEarB','NewRail0','NewRail1']) for o in d.Objects: if hasattr(o,'Shape'):o.ViewObject.Visibility=o.Name in show view.viewAxonometric();G.updateGui();time.sleep(.2);view.fitAll();G.updateGui();time.sleep(.4);view.saveImage(str(O/'crossbar_focus.png'),1800,1250,'White') view.viewTop();G.updateGui();time.sleep(.2);view.fitAll();G.updateGui();time.sleep(.4);view.saveImage(str(O/'crossbar_front.png'),1800,1250,'White') for o in d.Objects: if hasattr(o,'Shape'):o.ViewObject.Visibility=visibility.get(o.Name,True) d.recompute();d.saveAs(str(O/'Assembly.FCStd'));A.closeDocument(d.Name) dd=A.openDocument(str(O/'Assembly.FCStd'));dd.recompute();v=dd.getObject('SwitchCross2020').Shape assert v.isValid() and abs(v.BoundBox.XLength-132)<1e-6 step=Part.read(str(O/'Assembly.step'));assert step.isValid() and len(step.Solids)>0 result['fcstd_reopened']=True;result['step_valid']=True;result['step_solid_count']=len(step.Solids) (O/'validation.json').write_text(json.dumps(result,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)