FreeCAD Python API 实战指南:5 类脚本让建模效率翻倍
【免费下载链接】FreeCADOfficial source code of FreeCAD, a free and opensource multiplatform 3D parametric modeler.项目地址: https://gitcode.com/GitHub_Trending/fr/FreeCAD
FreeCAD 是一款开源的 3D 参数化建模工具,内置完整的 Python API,可以把重复的建模动作压缩成几行脚本。读完后,你将掌握基础几何建体、参数化特征、自动出图、几何体检与批量导出的写法,把机械劳动交给脚本,把时间留给设计本身。
环境与前置准备
这一步解决"脚本在哪里跑、依赖装了什么"的问题。
- 运行位置:FreeCAD 菜单 工具 → 宏 → 宏编辑器 或 控制台(Python Console),两者都运行在 FreeCAD 进程内,能直接使用
FreeCAD、Part、Draft等模块,无需额外安装。 - 版本:建议使用 1.0 及以上,文中
PartDesign草图约束 API 与TechDraw出图功能在该版本上行为最稳定。 - 第三方库:核心场景只用标准库(
csv、os)。若要生成数学曲面或做矩阵运算,再安装 NumPy。 - 获取源码:如需阅读实现,执行
git clone https://gitcode.com/GitHub_Trending/fr/freecad freecad,核心 API 都在src/目录下。
一个习惯建议:所有脚本第一行写import FreeCAD as App,第二行写doc = App.newDocument("名字"),文档句柄全程传递,不依赖"活动文档"。
阶段一|基础几何的脚本化创建
用 Part 模块 30 秒建出盒体、圆柱与球体
需要"不进入任何工作台、直接生成实体"时,用Part模块最稳,它不依赖 GUI。
import FreeCAD as App import Part doc = App.newDocument("基础几何") # makeBox 参数依次为长、宽、高,单位毫米 box = Part.makeBox(20, 15, 10) # makeCylinder 参数为半径、高度,第三参数是轴线起点 cyl = Part.makeCylinder(5, 20, App.Vector(30, 0, 0)) # 球体放在 (60, 0, 5) sph = Part.makeSphere(8, App.Vector(60, 0, 5)) # 把裸 Shape 挂到文档对象上,才能在 3D 视图里看到 doc.addObject("Part::Feature", "盒体").Shape = box doc.addObject("Part::Feature", "圆柱").Shape = cyl doc.addObject("Part::Feature", "球体").Shape = sph doc.recompute()核心 API 是Part.makeBox / makeCylinder / makeSphere,注意它们返回的是Shape而非文档对象,必须再addObject挂进文档才可见。
用 Draft 的极坐标阵列与正交阵列批量复制
需要"一个零件复制成一组"时,Draft 的阵列对象比手写循环更省代码,且后续可随参数联动。
import FreeCAD as App import Draft doc = App.newDocument("阵列示例") # 阵列源:一个圆柱 src = Draft.make_cylinder(2, 15) src.Placement.Base = App.Vector(10, 0, 0) # 极坐标阵列:绕 Z 轴均布 8 份 polar = Draft.make_polar_array(src, number=8, angle=360) # 正交阵列:3 行 × 4 列 rect = Draft.make_rect_array(src, 3, 4) doc.recompute()核心 API 是Draft.make_polar_array与Draft.make_rect_array,注意angle=360表示均布满圈、number控制份数,阵列对象会引用源对象,删掉源会连带失效。函数实现可看 src/Mod/Draft/draftmake/。
阶段二|参数化建模与特征批量操作
一键生成参数化六角螺栓头
需要"改一个数字、模型整体跟着变"时,走 PartDesign 的 Body + Sketch + Pad 链路。
import FreeCAD as App import Part import PartDesign doc = App.newDocument("螺栓") body = doc.addObject("PartDesign::Body", "Body") # 草图挂到 Body 自带的 XY 基准面上,保证后续可重建 sk = body.newObject("Sketcher::SketchObject", "HexSketch") sk.Support = (body.Origin.OriginFeatures[3], [""]) # XY_Plane sk.MapMode = "FlatFace" # 六边形:外接圆半径 5,6 条线段依次闭合 import math pts = [App.Vector(5 * math.cos(math.pi * i / 3), 5 * math.sin(math.pi * i / 3), 0) for i in range(6)] for i in range(6): sk.addGeometry(Part.LineSegment(pts[i], pts[(i + 1) % 6]), False) sk.addConstraint([Sketcher.Constraint("Equal", i, i + 1) for i in range(5)] + [Sketcher.Constraint("Equal", 5, 0)]) pad = body.newObject("PartDesign::Pad", "Head") pad.Profile = sk pad.Length = 6 # 拉伸长度 doc.recompute()核心 API 是body.newObject,注意草图必须绑定Support+MapMode="FlatFace"才能跟随基准面,否则重算后草图会"飞走"。Body 的内置基准面在body.Origin.OriginFeatures里按 ZY_XY_YZ_XZ 顺序排列,PartDesign 完整实现见 src/Mod/PartDesign/。
从 CSV 读孔表,批量挖出所有工艺孔
需要"参数在 Excel 里维护、模型自动生成"时,用csv标准库读表建体最直观。
import FreeCAD as App import Part import csv doc = App.newDocument("数据驱动") base = Part.makeBox(60, 40, 10) doc.addObject("Part::Feature", "底板").Shape = base # 孔表列:X, Y, 半径, 深度 with open("holes.csv", encoding="utf-8") as f: for row in csv.DictReader(f): r = float(row["半径"]) d = float(row["深度"]) hole = Part.makeCylinder(r, d, App.Vector(float(row["X"]), float(row["Y"]), 10)) # 用底板减孔,得到带孔实体 base = base.cut(hole) doc.getObject("底板").Shape = base doc.recompute()核心 API 是布尔运算Shape.cut,注意 CSV 数值一律先float()再使用,表头缺失会直接抛KeyError,建议先校验列名。
阶段三|出图、质量检查与数据流转
用 TechDraw 脚本自动出图并加尺寸标注
需要"模型一改、图纸自动重生成"时,TechDraw 的页面、视图、标注全部可以脚本创建。
import FreeCAD as App import TechDraw import FreeCADGui as Gui doc = App.getDocument("螺栓") part = doc.getObject("Head") # 模板路径:随 FreeCAD 安装的 A4 横向模板 tpl = doc.addObject("TechDraw::DrawViewTemplate", "Template") tpl.Template = App.getResourceDir() + "Mod/TechDraw/Templates/A4_Landscape_blank.svg" page = doc.addObject("TechDraw::DrawPage", "Page") page.Template = tpl view = doc.addObject("TechDraw::DrawViewPart", "FrontView") page.addView(view) view.Source = [part] view.Direction = App.Vector(0, -1, 0) # 从 -Y 方向投影 view.X, view.Y = 150, 105 view.Scale = 2.0 # 标注第一条边(视图边编号从 0 开始) dim = doc.addObject("TechDraw::DrawViewDimension", "Dim") dim.Type = "Distance" dim.References2D = [(view, "Edge0")] page.addView(dim) doc.recompute() Gui.Selection.addSelection(page) Gui.runCommand("TechDraw_KeepInPage") # 缩放页面适配视图核心 API 是DrawViewPart+DrawViewDimension,注意References2D里的边号依赖投影方向,换Direction后编号会重排,脚本里要固定一个投影方向。TechDraw 全部实现位于 src/Mod/TechDraw/。
脚本跑一遍几何体检,坏模型提前暴露
需要"交付前批量确认模型干净"时,用Part.Shape.check()做自动体检,比肉眼快得多。
import FreeCAD as App doc = App.ActiveDocument for obj in doc.Objects: if not hasattr(obj, "Shape"): continue # 跳过无几何的对象 try: ok = obj.Shape.isValid() # BRep 有效性 msgs = obj.Shape.check(True) # 返回错误信息列表 print(f"{obj.Label}: valid={ok}, issues={len(msgs)}") except Part.OCCError as e: print(f"{obj.Label}: 检查失败 - {e}")核心 API 是Shape.isValid()与Shape.check(),注意check(True)的第二参数是 verbose 开关,返回的字符串列表可以直接进报告。几何内核实现可参考 src/Mod/Part/App/。
用脚本批量导出 STL 并生成 CSV BOM
需要"一键交付制造"时,导出和 BOM 可以合并成一次遍历。
import FreeCAD as App import Mesh import csv doc = App.ActiveDocument rows = [] for obj in doc.Objects: if not hasattr(obj, "Shape") or not obj.Shape.Solids: continue # 逐件导出 STL,文件名用对象名 Mesh.export([obj], f"out/{obj.Name}.stl") # 按钢材密度 7.85 g/cm³ 估算质量 rows.append({"名称": obj.Label, "体积_mm3": round(obj.Shape.Volume, 1), "质量_g": round(obj.Shape.Volume * 0.00785, 2)}) with open("BOM.csv", "w", newline="", encoding="utf-8-sig") as f: w = csv.DictWriter(f, fieldnames=["名称", "体积_mm3", "质量_g"]) w.writeheader() w.writerows(rows)核心 API 是Mesh.export,注意 BOM 写出时用utf-8-sig编码,否则 Excel 打开中文列名会乱码。
综合实战:一条脚本串起完整流程
前面三类脚本组合起来,就是"建体 → 参数化 → 出图 → 体检 → 导出"的流水线。下面把它压成一个函数,参数全部抽到顶部:
import FreeCAD as App import Part import Mesh import csv def build_and_ship(spec_file, out_dir="out"): """spec_file: 列 = 名称,类型,尺寸1,尺寸2,尺寸的 CSV""" doc = App.newDocument("流水线") with open(spec_file, encoding="utf-8") as f: for row in csv.DictReader(f): if row["类型"] == "box": shape = Part.makeBox(float(row["尺寸1"]), float(row["尺寸2"]), 10) else: shape = Part.makeCylinder(float(row["尺寸1"]), float(row["尺寸2"])) feat = doc.addObject("Part::Feature", row["名称"]) feat.Shape = shape doc.recompute() # 体检 + 导出 + BOM,复用阶段三的写法 for obj in doc.Objects: print(obj.Name, obj.Shape.isValid()) Mesh.export([obj], f"{out_dir}/{obj.Name}.stl") # 调用:一行命令完成全部产物 build_and_ship("parts.csv")核心思路是"文档即数据":所有输入收敛到一个 CSV,脚本不写死任何零件名,换规格表就能换产品。
常见坑与排错速查
| 现象 | 原因 | 处理 |
|---|---|---|
| 3D 视图看不到脚本建的物体 | makeBox等返回的是Shape,未挂进文档 | 再执行addObject并赋值.Shape |
doc.recompute()后草图位置错乱 | 草图没绑Support/MapMode | 检查sk.Support与sk.MapMode |
| TechDraw 标注的边号对不上 | 投影方向改变导致边重编号 | 固定Direction,标注前打印边号确认 |
数组number改了没反应 | 改了源对象却没重算 | 末尾补doc.recompute() |
| BOM 在 Excel 里中文乱码 | 默认 UTF-8 无 BOM | 改用utf-8-sig写出 |
控制台脚本报App.Gui is None | 无头模式运行了 GUI API | 出图类命令(runCommand)只在有界面时执行 |
一个通用排错动作:报错时先打印doc.Name和各对象obj.State,多数"莫名失效"是上游对象计算失败、下游连坐。
延伸资源
- 官方文档源码在 src/Doc/sphinx/,其中 Scripting 章节与本文 API 一一对应。
- 想读实现时按模块找:基础几何看 src/Mod/Part/App/,参数化看 src/Mod/PartDesign/,出图看 src/Mod/TechDraw/,二维工具与阵列看 src/Mod/Draft/draftmake/。
- Python 侧绑定入口在 src/App/Document.pyi 与 src/Gui/ 的
*.pyi文件,类型标注齐全,编辑器会自动补全。 - 社区脚本可参考仓库内测试用例 src/Mod/Draft/TestDraft.py 与 src/Mod/TechDraw/TestTechDrawApp.py,它们是最贴近真实 API 用法的活教材。
三条起步建议:
- 从"批量导出 STL"这类 10 行以内的小脚本写起,先跑通
addObject → recompute → export闭环。 - 把尺寸参数全部外置成 CSV 或文档属性,脚本只负责"翻译",改模型时不动代码。
- 每个功能先读一遍对应测试文件再动手,能避开 80% 的参数坑。
【免费下载链接】FreeCADOfficial source code of FreeCAD, a free and opensource multiplatform 3D parametric modeler.项目地址: https://gitcode.com/GitHub_Trending/fr/FreeCAD
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考