from pathlib import Path import os, time, traceback, math import FreeCAD as A, FreeCADGui as G, Part, Import from pivy import coin R=Path(r'C:\projects\wheel'); O=R/'models'/'switch_2020_direct_profiles';O.mkdir(parents=True,exist_ok=True) try: d=A.openDocument(str(R/'models'/'switch_2020_raise10_concept'/'Assembly.FCStd')) for n in ('Rail0','Rail1','MotorBaseCorner0','MotorBaseCorner1'): o=d.getObject(n);p=o.Placement;p.Base.y-=10;o.Placement=p for n in ('MotorShim0','MotorShim1'): if d.getObject(n):d.removeObject(n) d.Label='Switch crossbeam - raised shaft, direct profile contact' d.recompute() checks=[] def compare(a,b): aa=d.getObject(a).Shape;bb=d.getObject(b).Shape volume=aa.common(bb).Volume if aa.BoundBox.intersect(bb.BoundBox) else 0 distance=aa.distToShape(bb)[0] checks.append('%s / %s: overlap=%.9f distance=%.6f'%(a,b,volume,distance)) return volume,distance for i in range(2): compare('Rail%d'%i,'NewRail%d'%i) compare('Rail%d'%i,'MotorBaseCorner%d'%i) compare('NewRail%d'%i,'MotorBaseCorner%d'%i) for i in range(4): q=d.getObject('Corner%d'%i); rail=d.getObject('Rail%d'%(i//2));bb=q.Shape.BoundBox compare(q.Name,rail.Name); compare(q.Name,'Motor') centers=[] for face in q.Shape.Faces: s=face.Surface if hasattr(s,'Radius') and abs(s.Radius-2.75)<1e-5 and hasattr(s,'Axis') and abs(abs(s.Axis.x)-1)<1e-5: centers.append((s.Center.y,s.Center.z)) checks.append('%s side-hole cylinders %s bbox=%s rail_y=%s..%s'%(q.Name,str(centers),str(bb),rail.Shape.BoundBox.YMin,rail.Shape.BoundBox.YMax)) if not centers:raise Exception('Missing profile side hole in '+q.Name) for y,z in centers: if not (rail.Shape.BoundBox.YMin < y < rail.Shape.BoundBox.YMax and abs(z-10)<1e-5):raise Exception('Profile side hole outside rail slot: '+q.Name) checks.append('%s hole y=%.5f z=%.5f near_end=%.5f'%(q.Name,y,z,min(y-rail.Shape.BoundBox.YMin,rail.Shape.BoundBox.YMax-y))) for name in ('Rail0','Rail1','MotorBaseCorner0','MotorBaseCorner1'): x=d.getObject(name) for o in d.Objects: if o==x or not hasattr(o,'Shape') or o.Shape.isNull() or not o.ViewObject.Visibility:continue if o.Name in ('Rail0','Rail1','MotorBaseCorner0','MotorBaseCorner1'):continue if x.Shape.BoundBox.intersect(o.Shape.BoundBox): vol=x.Shape.common(o.Shape).Volume if vol>.001:checks.append('POSITIVE %s / %s volume=%.8f'%(name,o.Name,vol)) (O/'检查.txt').write_text('\n'.join(checks)+'\n',encoding='utf8') d.saveAs(str(O/'Assembly.FCStd')) Import.export([o for o in d.Objects if hasattr(o,'Shape') and not o.Shape.isNull() and o.ViewObject.Visibility],str(O/'Assembly.step')) G.activateWorkbench('PartWorkbench');view=G.activeDocument().activeView() def snap(name,mode): if mode=='top':view.viewTop() else: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/name),1800,1250,'White') snap('assembly.png','axon') vis={o.Name:o.ViewObject.Visibility for o in d.Objects if hasattr(o,'Shape')} show=set(['Motor','Rail0','Rail1','NewRail0','NewRail1','MotorBaseCorner0','MotorBaseCorner1','Corner0','Corner1','Corner2','Corner3','OpenPillarBracket','PCB','Holder','Magnet']) for o in d.Objects: if hasattr(o,'Shape'):o.ViewObject.Visibility=o.Name in show snap('motor_detail.png','axon');snap('motor_top.png','top') for o in d.Objects: if hasattr(o,'Shape'):o.ViewObject.Visibility=vis.get(o.Name,True) d.recompute();d.saveAs(str(O/'Assembly.FCStd'));A.closeDocument(d.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)