PyCharm 中 FREECAD 二次开发:从基础建模到深度定制
一、引言
在当今的三维建模与设计领域,FREECAD 以其开源、参数化设计的强大特性,成为众多工程师、设计师和开发者的首选工具。然而,面对日益复杂和多样化的设计需求,仅仅依靠 FREECAD 的原生功能往往难以满足。此时,二次开发就显得尤为重要。PyCharm 作为一款功能强大的 Python 集成开发环境(IDE),为 FREECAD 的二次开发提供了便捷、高效的开发平台。通过 PyCharm,开发者可以利用 Python 语言结合 FREECAD 的 API,实现个性化的功能拓展,从而极大地提升工作效率和设计质量。
二、FREECAD 二次开发基础结构
2.1 核心模块概述
FREECAD 的二次开发主要围绕其 Python API 展开,其中Part
、Sketch
和Gui
等核心模块是开发的关键。Part
模块用于基础几何建模,提供了创建各种基本几何形状(如长方体、圆柱体、球体等)的功能;Sketch
模块则专注于草图绘制,为创建二维草图提供了丰富的工具;Gui
模块则用于用户界面定制,允许开发者创建自定义的菜单、工具栏和对话框等。
2.2 基础模型创建
在 PyCharm 中进行 FREECAD 二次开发,首先要完成 FREECAD 的 Python 环境配置。完成配置后,通过import FreeCAD
即可导入核心库,开启开发之旅。以下是创建基础模型的代码示例:
import FreeCAD# 新建文档
doc = FreeCAD.newDocument("BoxDocument")
# 添加长方体对象
box = doc.addObject("Part::Box", "MyBox")
# 设置尺寸
box.Length = 20
box.Width = 15
box.Height = 10
# 触发文档计算更新模型
doc.recompute()
运行上述代码后,FREECAD 会自动弹出窗口展示创建的长方体。若想为模型添加颜色和材质,可结合AppGui
模块实现:
import FreeCAD
import FreeCADGui# 新建文档与长方体
doc = FreeCAD.newDocument("ColoredBox")
box = doc.addObject("Part::Box", "ColoredBox")
box.Length = 20
box.Width = 15
box.Height = 10# 设置颜色(RGB值,范围0 - 1)
box.ViewObject.ShapeColor = (0.2, 0.6, 0.8)
# 应用材质(简单示例,实际可加载更多材质库)
box.ViewObject.DisplayMode = "Shaded"doc.recompute()
除了长方体,我们还可以创建其他基本几何形状,如圆柱体和球体:
import FreeCAD# 新建文档
doc = FreeCAD.newDocument("GeometryDocument")# 创建圆柱体
cylinder = doc.addObject("Part::Cylinder", "MyCylinder")
cylinder.Radius = 5
cylinder.Height = 15
# 创建球体
sphere = doc.addObject("Part::Sphere", "MySphere")
sphere.Radius = 8doc.recompute()
2.3 布尔运算
在 FREECAD 中,布尔运算可以用于组合和修改几何形状。以下是一个使用布尔运算创建复杂形状的示例:
import FreeCAD# 新建文档
doc = FreeCAD.newDocument("BooleanDocument")# 创建一个长方体
box = doc.addObject("Part::Box", "Box")
box.Length = 20
box.Width = 15
box.Height = 10# 创建一个圆柱体
cylinder = doc.addObject("Part::Cylinder", "Cylinder")
cylinder.Radius = 5
cylinder.Height = 15
cylinder.Placement.Base = FreeCAD.Vector(10, 7.5, 0)# 进行布尔差运算
cut = doc.addObject("Part::Cut", "Cut")
cut.Base = box
cut.Tool = cylinderdoc.recompute()
三、参数化设计与动态模型更新
3.1 参数化设计原理
参数化设计是 FREECAD 二次开发的核心优势之一。通过将模型的尺寸、位置等属性定义为参数,开发者可以方便地修改这些参数,从而实现模型的动态更新。这种设计方式使得模型的修改和调整更加灵活,大大提高了设计效率。
3.2 圆柱阵列的参数化设计
以创建可动态调整尺寸的圆柱阵列为例,先定义参数变量,再通过函数控制模型更新:
import FreeCAD# 新建文档
doc = FreeCAD.newDocument("ParametricArray")# 定义基础参数
radius = 5
height = 10
num_columns = 3
num_rows = 3
spacing_x = 15
spacing_y = 15# 定义创建单个圆柱的函数
def create_cylinder(doc, name, pos_x, pos_y):cylinder = doc.addObject("Part::Cylinder", name)cylinder.Radius = radiuscylinder.Height = heightcylinder.Placement.Base = FreeCAD.Vector(pos_x, pos_y, 0)return cylinder# 循环创建圆柱阵列
for row in range(num_rows):for col in range(num_columns):x = col * spacing_xy = row * spacing_ycylinder_name = f"Cylinder_{row}_{col}"create_cylinder(doc, cylinder_name, x, y)doc.recompute()# 定义更新函数,可动态修改阵列参数
def update_array(new_radius, new_height, new_num_columns, new_num_rows, new_spacing_x, new_spacing_y):global radius, height, num_columns, num_rows, spacing_x, spacing_yradius = new_radiusheight = new_heightnum_columns = new_num_columnsnum_rows = new_num_rowsspacing_x = new_spacing_xspacing_y = new_spacing_y# 删除原有圆柱for obj in doc.Objects:doc.removeObject(obj.Name)# 重新创建阵列for row in range(num_rows):for col in range(num_columns):x = col * spacing_xy = row * spacing_ycylinder_name = f"Cylinder_{row}_{col}"create_cylinder(doc, cylinder_name, x, y)doc.recompute()
调用update_array(8, 15, 4, 4, 20, 20)
,就能实时修改圆柱阵列的尺寸和数量。
3.3 更复杂的参数化设计示例:齿轮模型
以下是一个创建简单齿轮模型的参数化设计示例:
import FreeCAD
import math# 新建文档
doc = FreeCAD.newDocument("GearDocument")# 定义齿轮参数
module = 2
teeth = 20
pressure_angle = 20
pitch_diameter = module * teeth
base_diameter = pitch_diameter * math.cos(math.radians(pressure_angle))
outer_diameter = pitch_diameter + 2 * module# 创建齿轮草图
sketch = doc.addObject("Sketcher::SketchObject", "GearSketch")
sketch.Support = (doc.getObject("XY_Plane"), [""])
sketch.MapMode = "FlatFace"# 绘制齿轮齿形(简化示例)
for i in range(teeth):angle = 2 * math.pi * i / teethx1 = pitch_diameter / 2 * math.cos(angle)y1 = pitch_diameter / 2 * math.sin(angle)x2 = outer_diameter / 2 * math.cos(angle)y2 = outer_diameter / 2 * math.sin(angle)sketch.addGeometry(FreeCAD.Geom.LineSegment(FreeCAD.Vector(x1, y1, 0), FreeCAD.Vector(x2, y2, 0)))# 拉伸草图形成齿轮
gear = doc.addObject("PartDesign::Pad", "Gear")
gear.Profile = sketch
gear.Length = 10doc.recompute()
四、用户界面深度定制
4.1 自定义工具栏
借助Gui
模块,能在 FREECAD 中创建自定义菜单、工具栏和对话框。以下是创建自定义工具栏的示例:
import FreeCADGui
from PySide2 import QtGui, QtCore# 定义工具栏类
class MyToolbar:def __init__(self):self.toolbar = FreeCADGui.getMainWindow().addToolBar("MyToolbar")self.create_buttons()def create_buttons(self):# 按钮1:创建长方体create_box_icon = QtGui.QIcon(":/icons/box_icon.png") # 需提前准备图标文件create_box_btn = self.toolbar.addAction(create_box_icon, "Create Box")create_box_btn.triggered.connect(self.create_box_action)# 按钮2:更新圆柱阵列update_array_icon = QtGui.QIcon(":/icons/update_icon.png")update_array_btn = self.toolbar.addAction(update_array_icon, "Update Array")update_array_btn.triggered.connect(self.update_array_action)def create_box_action(self):doc = FreeCAD.newDocument("FromToolbarBox")box = doc.addObject("Part::Box", "ToolbarBox")box.Length = 10box.Width = 10box.Height = 10doc.recompute()def update_array_action(self):update_array(6, 12, 3, 3, 18, 18) # 调用前面定义的更新函数# 注册工具栏
my_toolbar = MyToolbar()
4.2 自定义对话框
若要创建复杂对话框,实现用户输入参数后动态生成模型,可使用PySide2
库:
from PySide2.QtWidgets import QDialog, QVBoxLayout, QLabel, QLineEdit, QPushButton
import FreeCADclass InputDialog(QDialog):def __init__(self):super().__init__()self.init_ui()def init_ui(self):layout = QVBoxLayout()# 输入框1:圆柱半径self.radius_label = QLabel("Cylinder Radius:")self.radius_input = QLineEdit()layout.addWidget(self.radius_label)layout.addWidget(self.radius_input)# 输入框2:圆柱高度self.height_label = QLabel("Cylinder Height:")self.height_input = QLineEdit()layout.addWidget(self.height_label)layout.addWidget(self.height_input)# 确定按钮self.ok_button = QPushButton("Create Cylinder")self.ok_button.clicked.connect(self.create_cylinder)layout.addWidget(self.ok_button)self.setLayout(layout)self.setWindowTitle("Input Parameters")def create_cylinder(self):try:radius = float(self.radius_input.text())height = float(self.height_input.text())doc = FreeCAD.newDocument("DialogCylinder")cylinder = doc.addObject("Part::Cylinder", "DialogCylinder")cylinder.Radius = radiuscylinder.Height = heightdoc.recompute()self.accept()except ValueError:print("Invalid input!")# 调用对话框
dialog = InputDialog()
if dialog.exec_():print("Cylinder created successfully!")
4.3 自定义菜单
除了工具栏和对话框,我们还可以创建自定义菜单:
import FreeCADGui
from PySide2 import QtGui# 创建自定义菜单
menu = FreeCADGui.getMainWindow().menuBar().addMenu("MyCustomMenu")# 创建菜单项1:创建球体
action1 = QtGui.QAction("Create Sphere", FreeCADGui.getMainWindow())
action1.triggered.connect(lambda: create_sphere())
menu.addAction(action1)# 创建菜单项2:保存文档
action2 = QtGui.QAction("Save Document", FreeCADGui.getMainWindow())
action2.triggered.connect(lambda: save_document())
menu.addAction(action2)def create_sphere():doc = FreeCAD.newDocument("SphereDocument")sphere = doc.addObject("Part::Sphere", "MySphere")sphere.Radius = 10doc.recompute()def save_document():doc = FreeCAD.ActiveDocumentif doc:doc.saveAs("saved_document.FCStd")
五、复杂模型与数据交互
5.1 从外部文件读取数据生成模型
在大型项目中,常需从外部文件读取数据生成模型。例如,从 CSV 文件读取点坐标生成三维点:
import FreeCAD
import csvdoc = FreeCAD.newDocument("PointsFromCSV")# 假设CSV文件格式为 x,y,z
with open('points.csv', 'r') as file:reader = csv.reader(file)next(reader) # 跳过表头for row in reader:x, y, z = map(float, row)point = doc.addObject("Part::Point", f"Point_{x}_{y}_{z}")point.Placement.Base = FreeCAD.Vector(x, y, z)doc.recompute()
5.2 将模型数据导出到其他格式
如需将 FREECAD 模型数据导出为其他格式(如 STL),可参考以下代码:
import FreeCAD
import Partdoc = FreeCAD.ActiveDocument
for obj in doc.Objects:if hasattr(obj, "Shape"):shape = obj.Shapestl_file_path = f"{obj.Name}.stl"Part.show(shape).exportStl(stl_file_path)
5.3 与数据库交互
我们还可以将 FREECAD 模型数据存储到数据库中,以下是一个使用 SQLite 数据库的示例:
import FreeCAD
import sqlite3# 连接到SQLite数据库
conn = sqlite3.connect('model_data.db')
c = conn.cursor()# 创建表
c.execute('''CREATE TABLE IF NOT EXISTS models(id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,type TEXT,radius REAL,height REAL)''')# 获取当前文档中的模型数据
doc = FreeCAD.ActiveDocument
for obj in doc.Objects:if hasattr(obj, "Radius") and hasattr(obj, "Height"):name = obj.Nametype_ = obj.TypeIdradius = obj.Radiusheight = obj.Heightc.execute("INSERT INTO models (name, type, radius, height) VALUES (?,?,?,?)", (name, type_, radius, height))# 提交更改并关闭连接
conn.commit()
conn.close()
六、调试与优化技巧
6.1 调试技巧
在 PyCharm 中调试 FREECAD 代码,断点和变量查看功能十分实用。例如,在更新模型的函数中设置断点:
def update_array(new_radius, new_height, new_num_columns, new_num_rows, new_spacing_x, new_spacing_y):global radius, height, num_columns, num_rows, spacing_x, spacing_yradius = new_radiusheight = new_heightnum_columns = new_num_columnsnum_rows = new_num_rowsspacing_x = new_spacing_xspacing_y = new_spacing_y# 在删除对象前设置断点,检查参数是否正确传递breakpoint()for obj in doc.Objects:doc.removeObject(obj.Name)# 重新创建阵列for row in range(num_rows):for col in range(num_columns):x = col * spacing_xy = row * spacing_ycylinder_name = f"Cylinder_{row}_{col}"create_cylinder(doc, cylinder_name, x, y)doc.recompute()
运行时 PyCharm 会在断点处暂停,便于查看变量状态。
6.2 优化技巧
为了提高代码的性能和效率,应避免在循环中频繁调用doc.recompute()
,可在完成多个修改操作后统一调用。另外,合理使用函数和类来封装代码,提高代码的可读性和可维护性。
七、结论
通过以上的介绍和丰富的代码示例,我们可以看到,使用 PyCharm 进行 FREECAD 二次开发具有强大的功能和广泛的应用前景。从基础的几何建模到复杂的参数化设计,从用户界面定制到数据交互,开发者可以根据自己的需求灵活运用各种技术和方法,实现个性化的功能拓展。在实际开发过程中,不断积累经验,掌握调试和优化技巧,能够进一步提高开发效率和代码质量。希望本文能够为广大 FREECAD 开发者提供有益的参考和帮助,让大家在三维建模的道路上走得更远。