Files
wheel/scripts/build_kfl001_plate_draft.py

89 lines
6.2 KiB
Python

"""Editable KFL001 bearing mounting plate -- provisional concept only.
Run with rebuild_kfl001_plate_draft.FCMacro in a hidden FreeCAD instance.
Both assembly plates have the same geometry; flip the second when fitting.
The centre cut is an unverified placeholder and MUST NOT be used for CNC.
"""
from pathlib import Path
import os, time, traceback, json
import FreeCAD as A, FreeCADGui as G, Part, Import
R=Path(r'C:\projects\wheel')
O=R/'models'/'kfl001_plate_draft'
O.mkdir(parents=True, exist_ok=True)
try:
d=A.newDocument('KFL001_Plate_Draft')
d.Label='KFL001 8mm plate DRAFT - centre cut unverified'
s=d.addObject('Spreadsheet::Sheet','Parameters')
s.Label='Parameters - centre diameter UNVERIFIED'
rows=[('PlateWidth','76 mm','Overall width'),('PlateHeight','80 mm','Overall height'),
('Thickness','8 mm','Plate thickness'),('AxisFromBottom','51 mm','Axle height above lower edge'),
('CenterClearance','39 mm','TEMPORARY ONLY - verify real KFL back geometry'),
('BearingPitch','48 mm','Bolt centre spacing for KFL001'),
('BearingHole','7 mm','Bearing mount clearance diameter'),
('SlotPitch','47 mm','Centre spacing of lower mounting slots'),
('SlotBottom','9 mm','Mounting slot centre above plate lower edge'),
('SlotLength','9.5 mm','Horizontal slot overall length'),
('SlotWidth','5.5 mm','Horizontal slot width')]
for row,(name,val,note) in enumerate(rows,2):
s.set('A%d'%row,name);s.set('B%d'%row,val);s.set('C%d'%row,note);s.setAlias('B%d'%row,name)
def expr(o,p,v):o.setExpression(p,v)
plate=d.addObject('Part::Box','PlateBlank');plate.Label='76 x 80 x 8 plate blank'
expr(plate,'Length','Parameters.PlateWidth');expr(plate,'Width','Parameters.PlateHeight');expr(plate,'Height','Parameters.Thickness')
expr(plate,'Placement.Base.x','-Parameters.PlateWidth / 2')
def cyl(name,x,y,r):
o=d.addObject('Part::Cylinder',name);expr(o,'Radius',r);expr(o,'Height','Parameters.Thickness + 0.2 mm');expr(o,'Placement.Base.x',x);expr(o,'Placement.Base.y',y);o.Placement.Base.z=-.1;return o
tools=[]
tools.append(cyl('TEMP_CentreHole','0 mm','Parameters.AxisFromBottom','Parameters.CenterClearance / 2'))
for side in (-1,1):
sign='-' if side<0 else ''
tools.append(cyl('BearingHole_'+('L' if side<0 else 'R'),sign+'Parameters.BearingPitch / 2','Parameters.AxisFromBottom','Parameters.BearingHole / 2'))
cx=sign+'Parameters.SlotPitch / 2';tag='L' if side<0 else 'R'
tools.append(cyl('Slot'+tag+'End1','(%s) - (Parameters.SlotLength - Parameters.SlotWidth) / 2'%cx,'Parameters.SlotBottom','Parameters.SlotWidth / 2'))
tools.append(cyl('Slot'+tag+'End2','(%s) + (Parameters.SlotLength - Parameters.SlotWidth) / 2'%cx,'Parameters.SlotBottom','Parameters.SlotWidth / 2'))
b=d.addObject('Part::Box','Slot'+tag+'Middle')
expr(b,'Length','Parameters.SlotLength - Parameters.SlotWidth');expr(b,'Width','Parameters.SlotWidth');expr(b,'Height','Parameters.Thickness + 0.2 mm')
expr(b,'Placement.Base.x','(%s) - (Parameters.SlotLength - Parameters.SlotWidth) / 2'%cx)
expr(b,'Placement.Base.y','Parameters.SlotBottom - Parameters.SlotWidth / 2');b.Placement.Base.z=-.1
tools.append(b)
d.recompute()
cutters=d.addObject('Part::MultiFuse','Cutters');cutters.Shapes=tools;d.recompute()
final=d.addObject('Part::Cut','Plate_DRAFT');final.Label='DRAFT bearing plate - centre 39mm NOT verified';final.Base=plate;final.Tool=cutters
d.recompute()
assert not final.Shape.isNull() and final.Shape.isValid() and len(final.Shape.Solids)==1
for o in d.Objects:
if o.ViewObject:o.ViewObject.Visibility=False
final.ViewObject.Visibility=True;final.ViewObject.ShapeColor=(.71,.74,.77);final.ViewObject.LineColor=(.12,.12,.12)
G.activateWorkbench('PartWorkbench');view=G.activeDocument().activeView();view.viewAxonometric();G.updateGui();view.fitAll();time.sleep(.3);G.updateGui();view.saveImage(str(O/'plate_isometric.png'),1400,1100,'White')
view.viewTop();G.updateGui();view.fitAll();time.sleep(.3);G.updateGui();view.saveImage(str(O/'plate_top.png'),1400,1100,'White')
d.saveAs(str(O/'KFL001_plate_DRAFT.FCStd'));Import.export([final],str(O/'KFL001_plate_DRAFT.step'))
baseline=final.Shape.Volume
s.set('B6','38 mm');d.recompute()
assert final.Shape.isValid() and abs(final.Shape.Volume-baseline)>0.1
changed=final.Shape.Volume
s.set('B6','39 mm');d.recompute()
assert final.Shape.isValid() and abs(final.Shape.Volume-baseline)<1e-5
A.closeDocument(d.Name)
dd=A.openDocument(str(O/'KFL001_plate_DRAFT.FCStd'));dd.recompute();ff=dd.getObject('Plate_DRAFT')
assert ff.Shape.isValid() and len(ff.Shape.Solids)==1 and abs(ff.Shape.Volume-baseline)<1e-5
imported=Part.read(str(O/'KFL001_plate_DRAFT.step'))
assert imported.isValid() and len(imported.Solids)==1
# At the middle Z plane compare the STEP vs native shape by mutual differences.
stepdiff1=ff.Shape.cut(imported).Volume;stepdiff2=imported.cut(ff.Shape).Volume
assert stepdiff1<1e-4 and stepdiff2<1e-4
angles=[(3.5,24,51),(3.5,-24,51),(19.5,0,51)]
cylinders=[]
for f in imported.Faces:
surf=f.Surface
if hasattr(surf,'Radius') and hasattr(surf,'Center'):
cylinders.append({'radius':round(float(surf.Radius),5),'x':round(float(surf.Center.x),5),'y':round(float(surf.Center.y),5),'z_min':round(f.BoundBox.ZMin,5),'z_max':round(f.BoundBox.ZMax,5)})
for r,x,y in angles:
assert any(abs(c['radius']-r)<1e-4 and abs(c['x']-x)<1e-4 and abs(c['y']-y)<1e-4 and c['z_min']<=.001 and c['z_max']>=7.999 for c in cylinders), (r,x,y,cylinders)
info={'fcstd_valid':True,'step_valid':True,'solid_count':len(imported.Solids),'volume':baseline,'diameter_parameter_test_38':changed,'diameter_test_restored':True,'step_old_minus_new':stepdiff1,'step_new_minus_old':stepdiff2,'dimensions_mm':{'width':76,'height':80,'thickness':8,'axis_from_bottom':51,'center_diameter_provisional':39,'bearing_pitch':48,'bearing_hole':7,'slot_pitch':47,'slot_bottom':9,'slot_length':9.5,'slot_width':5.5},'cylinder_faces':cylinders,'nominal_m5_slot_range_mm':4.5,'quantity_identical_plates':2,'center_UNVERIFIED':True}
(O/'validation.json').write_text(json.dumps(info,ensure_ascii=False,indent=2),encoding='utf-8')
A.closeDocument(dd.Name)
(O/'DONE.txt').write_text('ok',encoding='utf-8')
os._exit(0)
except Exception:
(O/'ERROR.txt').write_text(traceback.format_exc(),encoding='utf-8');os._exit(1)