Files
wheel/scripts/build_70_m4_drill.FCMacro

47 lines
3.5 KiB
Plaintext

from pathlib import Path
import os, json, math, traceback
import FreeCAD as App
import FreeCADGui as Gui
import Import, Part
root = Path(r'C:\projects\wheel')
out = root / 'models' / '70_m4_drill_quote'
out.mkdir(parents=True, exist_ok=True)
try:
os.chdir(str(root))
base = (root / 'scripts' / 'build_70.py').read_text(encoding='utf-8')
base = base.replace("target = os.path.join(root, 'models', '\\u0037\\u0030\\u8f6c\\u63a5\\u677f_\\u53c2\\u6570\\u5316.FCStd')", "target = str(out / '70_M4_drill.FCStd')")
base = base.replace("('HoleDiameter', '4.234 mm', 'Through hole diameter (all 24 holes)')", "('HoleDiameter', '3.3 mm', 'M4 tapping pilot diameter for all 24 holes')")
base = base.replace("print('OUTPUT', target)", "Import.export([final], str(out / '70_M4_drill.step'))\nGui.activeDocument().activeView().saveImage(str(out / '70_M4_drill.png'), 1600, 1200, 'White')\nprint('OUTPUT', target)")
if "target = str(out / '70_M4_drill.FCStd')" not in base or "'3.3 mm'" not in base:
raise RuntimeError('Failed to patch baseline; original file not modified')
exec(compile(base, str(root/'scripts'/'build_70.py'), 'exec'), {'out':out, '__name__':'__main__'})
for name in list(App.listDocuments()): App.closeDocument(name)
f=App.openDocument(str(out/'70_M4_drill.FCStd')); f.recompute()
plate=f.getObject('FinishedPlate'); shape=plate.Shape
assert shape.isValid() and len(shape.Solids)==1
assert abs(f.getObject('Hole42_0').Radius.Value-1.65)<1e-8
assert abs(f.getObject('Countersink0').Height.Value-1.75)<1e-8
step=App.newDocument('VerifyExport'); Import.insert(str(out/'70_M4_drill.step'), step.Name); step.recompute()
stepShapes=[o.Shape for o in step.Objects if hasattr(o,'Shape') and not o.Shape.isNull()]
assert len(stepShapes)==1 and stepShapes[0].isValid() and len(stepShapes[0].Solids)==1
cylinder_faces=[]
for face in stepShapes[0].Faces:
surf=face.Surface
if isinstance(surf,Part.Cylinder) and abs(surf.Radius-1.65)<1e-6 and abs(abs(surf.Axis.z)-1)<1e-7:
center=surf.Center
cylinder_faces.append({'x':round(center.x,6),'y':round(center.y,6),'z_min':round(face.BoundBox.ZMin,6),'z_max':round(face.BoundBox.ZMax,6),'r':surf.Radius})
assert len(cylinder_faces)==24, 'Expected 24 pilot cylinders, found '+str(len(cylinder_faces))
radii=sorted(round(math.hypot(c['x'],c['y']),4) for c in cylinder_faces)
assert radii == [21.0]*6+[24.0]*6+[25.4]*6+[35.0]*6, str(radii)
pcd42=[c for c in cylinder_faces if abs(math.hypot(c['x'],c['y'])-21)<0.001]
assert all(abs(c['z_min']-1.75)<1e-6 and abs(c['z_max']-8)<1e-6 for c in pcd42)
assert all(abs(c['z_min'])<1e-6 and abs(c['z_max']-8)<1e-6 for c in cylinder_faces if c not in pcd42)
result={'fcstd_valid':True,'fcstd_solids':1,'step_valid':True,'step_solids':1,'step_volume':stepShapes[0].Volume,'pilot_diameter_mm':3.3,'number_pilot_cylinders':len(cylinder_faces),'positions_and_extents':cylinder_faces,'countersink_diameter_mm':6.8,'countersink_angle_deg':90,'countersink_depth_mm':1.75,'pcd42_straight_segment_mm':6.25,'other_straight_segment_mm':8.0,'interpretation':'These are smooth pilot holes, not semantic or geometric threads. Automatic quotation recognition untested.'}
(out/'validation.json').write_text(json.dumps(result,ensure_ascii=False,indent=2),encoding='utf-8')
(out/'status.txt').write_text('OK',encoding='utf-8')
except:
(out/'status.txt').write_text(traceback.format_exc(),encoding='utf-8')
for name in list(App.listDocuments()): App.closeDocument(name)
Gui.getMainWindow().close()