72 lines
4.5 KiB
Python
72 lines
4.5 KiB
Python
from pathlib import Path
|
|
import os, time, traceback
|
|
import FreeCAD as A, FreeCADGui as G, Part, Import
|
|
from pivy import coin
|
|
V=A.Vector
|
|
R=Path(r'C:\projects\wheel'); O=R/'models'/'kfl_3030_motor_corner_concept'; O.mkdir(parents=True,exist_ok=True)
|
|
def box(x,y,z,dx,dy,dz): return Part.makeBox(dx,dy,dz,V(x,y,z))
|
|
def cy(r,h,x,y,z,d=V(0,0,1)): return Part.makeCylinder(r,h,V(x,y,z),d)
|
|
def add(d,n,s,c):
|
|
o=d.addObject('PartDesign::Feature',n);o.Shape=s.removeSplitter();o.Label=n;o.ViewObject.ShapeColor=c;o.ViewObject.LineColor=(.15,.15,.15);return o
|
|
ok=False
|
|
try:
|
|
d=A.openDocument(str(R/'models'/'kfl_3030_concept'/'Assembly.FCStd'));d.Label='3030 base, motor rail corner joints - concept'
|
|
d.recompute()
|
|
corners=[]; extensions=[]
|
|
for i,x in enumerate((-50.6200577,50.6200577)):
|
|
rail=d.getObject('NewRail%d'%i);rail.Shape=box(x-15,-85,-215,30,30,255);rail.Label='3030 longitudinal base rail, extended 20 mm'
|
|
ext=box(x-15,-85,20,30,30,20);extensions.append(ext)
|
|
# Outer size 20 x 20, width 18, thickness 3. Short slot overall 9.5mm, 4mm from tip.
|
|
upright=box(x-9,-55,20,18,20,3)
|
|
slot=box(x-2.75,-45.75,19.98,5.5,4,3.04).fuse(cy(2.75,3.04,x,-45.75,19.98)).fuse(cy(2.75,3.04,x,-41.75,19.98))
|
|
upright=upright.cut(slot)
|
|
foot=box(x-9,-55,20,18,3,20).cut(cy(2.75,3.04,x,-55.02,30,V(0,1,0)))
|
|
corners.append(add(d,'MotorBaseCorner%d'%i,upright.fuse(foot),(.86,.12,.14)))
|
|
d.recompute()
|
|
# Only check new angles and the newly added portions of rails against existing visible geometry.
|
|
visible=[o for o in d.Objects if hasattr(o,'Shape') and not o.Shape.isNull() and o.ViewObject.Visibility and o not in corners]
|
|
lines=[]; bad=[]
|
|
for i,a in enumerate(corners):
|
|
for b in visible + corners[i+1:]:
|
|
v=a.Shape.common(b.Shape).Volume if a.Shape.BoundBox.intersect(b.Shape.BoundBox) else 0.
|
|
dist=a.Shape.distToShape(b.Shape)[0]
|
|
lines.append('%s / %s: overlap=%.6f mm3, distance=%.4f mm'%(a.Name,b.Name,v,dist))
|
|
if v>0.001:bad.append((a.Name,b.Name,v))
|
|
for i,ext in enumerate(extensions):
|
|
for b in visible:
|
|
if b.Name=='NewRail%d'%i: continue
|
|
v=ext.common(b.Shape).Volume if ext.BoundBox.intersect(b.Shape.BoundBox) else 0.
|
|
if v>0.001:bad.append(('rail extension %d'%i,b.Name,v))
|
|
if v>0.001:lines.append('rail extension %d / %s: overlap=%.6f mm3'%(i,b.Name,v))
|
|
(O/'interference_report.txt').write_text('\n'.join(lines)+'\n',encoding='utf8')
|
|
(O/'positive_intersections.txt').write_text('\n'.join('%s / %s = %.6f mm3'%x for x in bad) or 'none',encoding='utf8')
|
|
d.saveAs(str(O/'Assembly.FCStd'));Import.export([o for o in d.Objects if hasattr(o,'Shape')],str(O/'Assembly.step'))
|
|
view=G.activeDocument().activeView();G.activateWorkbench('PartWorkbench')
|
|
def save(name,mode):
|
|
if mode=='front':view.viewFront()
|
|
elif 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')
|
|
save('assembly.png','axon')
|
|
vis={o.Name:o.ViewObject.Visibility for o in d.Objects if hasattr(o,'Shape')}
|
|
# Hide the broad framing/shaft only to make the actual motor connections legible.
|
|
names={'Motor','OpenPillarBracket','Holder','Magnet','PCB','Chip','Rail0','Rail1','NewRail0','NewRail1','Corner0','Corner1','Corner2','Corner3','MotorBaseCorner0','MotorBaseCorner1'}
|
|
for o in d.Objects:
|
|
if hasattr(o,'Shape'):o.ViewObject.Visibility=o.Name in names
|
|
save('motor_corner_detail.png','axon');save('motor_corner_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)
|
|
# Reopen FCStd and separately import STEP to confirm persistence/nonempty shape.
|
|
d=A.openDocument(str(O/'Assembly.FCStd'))
|
|
valid=[(n,not d.getObject(n).Shape.isNull(),d.getObject(n).Shape.isValid()) for n in ['MotorBaseCorner0','MotorBaseCorner1','NewRail0','NewRail1']]
|
|
A.closeDocument(d.Name)
|
|
stepdoc=A.newDocument('StepVerify');Import.insert(str(O/'Assembly.step'),stepdoc.Name);stepdoc.recompute()
|
|
stepcount=sum(1 for o in stepdoc.Objects if hasattr(o,'Shape') and not o.Shape.isNull())
|
|
A.closeDocument(stepdoc.Name)
|
|
(O/'validation.txt').write_text('FCStd reopen: '+str(valid)+'\nSTEP nonempty shapes: '+str(stepcount)+'\n',encoding='utf8')
|
|
(O/'DONE.txt').write_text('ok',encoding='utf8');ok=True
|
|
except Exception:
|
|
(O/'ERROR.txt').write_text(traceback.format_exc(),encoding='utf8')
|
|
finally:os._exit(0 if ok else 1)
|