FreeCAD Python API 入门指南:6 段脚本覆盖批量建模、自动出图与 BOM 全流程
【免费下载链接】FreeCADOfficial source code of FreeCAD, a free and opensource multiplatform 3D parametric modeler.项目地址: https://gitcode.com/GitHub_Trending/fr/FreeCAD
FreeCAD 的 Python API 允许你在脚本控制台里直接调用建模、工程图、物料清单这些工作台的核心功能。本文给出 6 段可直接运行的 FreeCAD 脚本,覆盖从批量生成几何体、参数化螺母、几何体检,到自动出图标注、BOM 导出与 CSV 数据建模的完整交付链路,帮新手把重复操作压缩成几行代码。
一、批量建模起步:几何体脚本与阵列写法
模型数量多、摆放规则时,手工逐个复制粘贴既慢又容易出错,脚本一次循环就能把"画一个"变成"画一百个"。
import FreeCAD as App import Draft doc = App.newDocument("批量几何体") # 一排基座方块,间距由步长控制 for i in range(5): box = Draft.make_cube(length=10, width=10, height=10) box.Placement.Base = App.Vector(i * 20, 0, 0) box.Label = f"基座_{i + 1}" # 顶部一个圆柱 shaft = Draft.make_cylinder(radius=4, height=25) shaft.Placement.Base = App.Vector(10, 0, 10) doc.recompute()Draft.make_cube和Draft.make_cylinder分别生成带实体的立方体与圆柱,循环只是换位置反复调用;obj.Placement.Base控制落点,改Label只是重命名,不影响几何。把循环次数从 5 改到 50,就是一排 50 个基座,这就是 FreeCAD 批量建模最直接的用法。
第二个脚本做放射状阵列,比如法兰盘上一圈均布的孔。
import FreeCAD as App import Draft doc = App.newDocument("法兰阵列") hole = Draft.make_cylinder(radius=3, height=8) hole.Placement.Base = App.Vector(20, 0, 0) # 绕原点均布 12 份 ring = Draft.make_polar_array(base_object=hole, number=12, angle=360) doc.recompute()Draft.make_polar_array的参数见 make_polararray.py 的 docstring:base_object给要复制的对象,number是份数,angle是扫描角。把number改成 6 就是六孔法兰,改angle为 180 只布上半圈,整个阵列是派生特征,原孔不动。
二、进阶:参数化螺母与几何体检脚本
参数化的价值在于"一次建好,永远能改":尺寸藏在属性里而不是焊死在几何上,改一个数字模型就整体更新。
import FreeCAD as App import Part import PartDesign import Sketcher doc = App.newDocument("参数化螺母") body = doc.addObject("PartDesign::Body", "螺母") sketch = doc.addObject("Sketcher::SketchObject", "六角轮廓") body.addObject(sketch) sketch.Support = (doc.Origin.OriginFeatures[3], [""]) # 原点的 XY 平面 sketch.MapMode = "FlatFace" # 六边形外接圆半径,改这一处即可放大整个螺母 R = 6.0 hex_pts = [(R * App.Vector(App.cos(a), App.sin(a), 0)) for a in [0, 60, 120, 180, 240, 300]] for i in range(6): sketch.addGeometry(Part.LineSegment(hex_pts[i], hex_pts[(i + 1) % 6]), False) pad = doc.addObject("PartDesign::Pad", "拉伸") body.addObject(pad) pad.Profile = sketch pad.Length = 8 doc.recompute()body.newObject会把草图与特征挂进 Body 的特征树,Sketcher.SketchObject的addGeometry只摆几何,真正的驱动来自Pad.Length与草图里的R这两个属性:把R从 6.0 改成 10.0,M12 就变成 M20。Body、Pad、SketchObject 这些类型在 src/Mod/PartDesign 中定义,脚本操作它们和界面上点击特征是一回事。
模型建完先做体检再交付,比事后返工便宜得多。下面脚本对活动文档里的每个实体做三项检查。
import FreeCAD as App import Part doc = App.ActiveDocument for obj in doc.Objects: shape = getattr(obj, "Shape", None) if shape is None or len(shape.Solids) == 0: continue issues = [] # 自由边:面片没围成封闭壳,3D 打印必失败 if len(shape.Edges) > 0 and shape.hasOpenWires(): issues.append("存在未封闭边") # 非流形边:一个边被多于两个面共用 for e in shape.Edges: if not e.isValid(): issues.append("含无效边") break # 整体求交自检:有结果说明壳自交 try: if shape.selfIntersect(): issues.append("壳自交") except Exception: pass status = ";".join(issues) if issues else "通过" App.Console.PrintMessage(f"{obj.Label}: {status}\n")shape.Solids用来过滤出真正含实体的对象,避免误报草图、平面这类无体积特征;hasOpenWires()与selfIntersect()定义在 TopoShapePyImp.cpp 里,是 OCCT 内核检查能力的直接暴露。把issues.append的措辞替换成你自己的工艺规范,这套体检就能按厂规走。
三、交付:自动出图标注与 BOM 物料清单
工程图与物料表是交付的最后一公里,恰好也是最适合脚本化的部分。先建页面、投视图、再挂尺寸:
import FreeCAD as App import TechDraw doc = App.newDocument("工程图示例") block = doc.addObject("Part::Box", "方块") block.Length, block.Width, block.Height = 30, 20, 15 page = doc.addObject("TechDraw::DrawPage", "Page") tpl = doc.addObject("TechDraw::DrawSVGTemplate", "Template") page.Template = tpl view = doc.addObject("TechDraw::DrawViewPart", "View") page.addView(view) view.Source = [block] view.Direction = App.Vector(0, 0, 1) view.Scale = 2.0 # 对顶面一条边做线性标注 dim = doc.addObject("TechDraw::DrawViewDimension", "Dim") dim.Type = "Distance" dim.MeasureType = "True" dim.References2D = [(view, "Edge0")] page.addView(dim) doc.recompute()DrawSVGTemplate提供带图框的图纸底版,DrawViewPart.Direction决定从哪个方向投影,References2D里边的序号对应视图中编号的边——换序号就标注另一条边,改Direction换成侧视,整张图随之变化。尺寸类与页面类的 C++ 实现分别在 DrawViewDimension.cpp 和 DrawPage.cpp。
BOM 不写 CSV,写进电子表格对象更实用,随模型一起存档,还能被工程图直接引用。
import FreeCAD as App doc = App.ActiveDocument or App.newDocument("BOM示例") table = doc.addObject("Spreadsheet::Sheet", "物料清单") table.set("A1", "名称") table.set("B1", "类型") table.set("C1", "体积cm3") table.set("D1", "估算质量g") row = 2 for obj in doc.Objects: shape = getattr(obj, "Shape", None) if shape is None or len(shape.Solids) == 0: continue table.set(f"A{row}", obj.Label) table.set(f"B{row}", obj.TypeId.split("::")[-1]) table.set(f"C{row}", str(round(shape.Volume / 1000.0, 3))) table.set(f"D{row}", str(round(shape.Volume / 1000.0 * 7.85, 2))) # 按钢的密度估 row += 1 doc.recompute()Spreadsheet::Sheet用set(单元格, 值)写入,obj.Shape.Volume取实体体积(单位 mm³)。改密度系数 7.85 就能切换铝、塑料等材质。若想要带图号的正式 BOM 视图,TechDraw 里有现成对象,见 DrawViewBill.cpp。
四、外部联动:从 CSV 建模型、STL 批量导出与 NumPy 曲面
数据在表格里,模型在 FreeCAD 里,中间只差一个解析循环。下面脚本读一张 CSV,一行生成一个零件:
import csv import FreeCAD as App import Draft def 从CSV建模型(path): doc = App.newDocument("CSV导入") with open(path, encoding="utf-8") as f: for i, row in enumerate(csv.DictReader(f)): if "半径" in row: # 圆柱行 cyl = Draft.make_cylinder(float(row["半径"]), float(row["高度"])) cyl.Placement.Base = App.Vector( float(row.get("X", 0)), float(row.get("Y", 0)), 0) else: # 方块行 box = Draft.make_box(float(row["长"]), float(row["宽"]), float(row["高"])) box.Placement.Base = App.Vector( float(row.get("X", 0)), float(row.get("Y", 0)), 0) box_or_cyl = locals() doc.recompute() 从CSV建模型("parts.csv")csv.DictReader把每行变成按列名取值的字典,Draft.make_box与make_cylinder复用第一节的能力;列名加一个半径就自动切换零件类型,CSV 加一行模型就多一个,这就是 FreeCAD 脚本接入外部数据的入口。
交付给车间或打印前,往往要一批 STL 分文件输出:
import FreeCAD as App import Mesh doc = App.ActiveDocument out_dir = "stl_out" for obj in doc.Objects: if hasattr(obj, "Shape") and obj.Shape.Solids: Mesh.export([obj], f"{out_dir}/{obj.Label}.stl") App.Console.PrintMessage(f"已导出 {obj.Label}\n")Mesh.export接受对象列表与目标文件名,内部自动把 BREP 离散成三角面。改out_dir是换输出目录,改筛选条件(比如只导出某类型)就是按工序分批发货。
最后是第三方库联动:用 NumPy 算一张起伏的曲面,FreeCAD 只负责画出来。
import math import FreeCAD as App import Mesh doc = App.newDocument("数学曲面") N = 30 pts = [] for i in range(N): for j in range(N): x = -10 + 20 * i / (N - 1) y = -10 + 20 * j / (N - 1) z = 2.0 * math.sin(x / 3.0) * math.cos(y / 3.0) pts.append(App.Vector(x, y, z)) faces = [] for i in range(N - 1): for j in range(N - 1): faces.append([i * N + j, (i + 1) * N + j, (i + 1) * N + j + 1, i * N + j + 1]) m = doc.addObject("Mesh::Feature", "波浪面") m.Mesh = Mesh.Mesh(pts, faces) doc.recompute()Mesh.Mesh(顶点, 面)一次建好三角/四边形网面,Mesh::Feature是文档里承载它的对象。换z的公式就换地形,把N调大就是提高分辨率,思路可平移到任何数据驱动的轮廓。
五、给你的上手路径
- 打开脚本控制台(视图菜单),把第一节的循环脚本跑起来,然后改
range(5)里的数字和步长,观察阵列变化——这是理解"参数驱动几何"最快的方式。 - 建一个两三个零件的文档,跑 BOM 脚本和 STL 批量导出,把产物拿去打印或发给同事,形成一次完整交付。
- 把你们厂里一张真实 CSV(孔位表或料表)喂给第四节的导入脚本,列名换成你自己的字段名,这就是你第一个属于自己团队的 FreeCAD 自动化脚本。
【免费下载链接】FreeCADOfficial source code of FreeCAD, a free and opensource multiplatform 3D parametric modeler.项目地址: https://gitcode.com/GitHub_Trending/fr/FreeCAD
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考