FreeCAD框架解析

时间:2024-03-10 07:00:55


FreeCAD模块开发指南

1. 整体印象

FreeCAD的设计核心特征

  1. 跨平台

  2. 支持命令行模式进行操作

  3. 参数化建模

  4. 插件式架构,便于功能的结构与增减

  5. 支持多种模型格式

    定制的文件格式:*.FCstd is a zip file container of many different types of information, such as geometry, scripts or thumbnail icons.

软件结构层次

  1. CAD引擎(App)
  2. GUI交互界面

模型对象

  1. 应用程序文档:结构参数
  2. 视图文档:颜色、线条表示、灯光、视角与渲染方式

依赖:

  • OpenCASCADE as CAD kernel
  • OpenInventor/Coin3D/pivy for 3D scene rendering
  • Qt and \'Qt for Python\' (aka PySide2) for GUI
  • Python scripting and wrapping: PyCXX, swig, boost.python
  • Other powerful software libraries like Xerces XML, boost

其他知识点:

  1. 3D模型通过OpenGL渲染,借助OpenInventor库实现

    使用OpenInventor开发包,程序员可以快速、简洁地开发出各种类型的交互式三维图形软件。OIV具有平台无关性,它可以在Microsoft Windows、Unix、Linux等多种操作系统中使用。OIV允许使用C、C++、Java、DotNet多种编程语言进行程序开发。经过多年的发展,OIV已经基本上成为面向对象的3D图形开发“事实上”的工业标准。广泛地应用于机械工程设计与仿真、医学和科学图像、地理科学、石油钻探、虚拟现实、科学数据可视化等领域。

    obj = FreeCAD.ActiveDocument.ActiveObject
    viewprovider = obj.ViewObject
    print viewprovider.toString()
    
  2. 什么是Coin3D: 开源的OpenInventor实现

    目前世界上比较成熟的Open Inventor(以下简称OIV)开发包有三个,它们分别由SGI(http://www.sgi.com),TGS(http://www.tgs.com)和SIM(http://www.coin3d.org)公司开发的。SGI是最早提出并开发OIV的公司。但SGI的OIV主要用在UNIX操作系统下,没有提供对Microsoft Windows操作系统的支持。TGS公司是最早将OIV由Unix系统移植到Microsoft Windows下的公司。TGS的OIV是目前世界上使用最多的OIV版本。但TGS的OIV是一个商业软件开发包,其购买开发版权的费用非常昂贵,不适合普通用户学习和使用。SIM公司开发的Coin3D OIV可以同时在UNIX和Microsoft Windows下使用。这是一个开放源码的OIV开发包,使用协议采用的是GPL协议。非常适合希望学习使用OIV的普通用户。

  3. Pivy又是什么:Coin3D\'s Python wrapping

    Coin3D implements the same API but not source code with Open Inventor, via clean room implementation compatible Stable release Open Inventor v2.1. Kongsberg ended development of Coin3D in 2011 and released the code under the BSD 3-clause license. It is possible to draw object in OpenInventor Scene by Python, via Coin3D\'s python wrapper pivy , see https://www.freecadweb.org/wiki/Pivy

    VTK, is another open source and cross-platform visualization library, which ParaView is based on. Interoperation is possible, see Method for converting output from the VTK pipeline into Inventor nodes. From 0.17 and beyond, VTK pipeline is added to Fem mpivy trackers - A small python library of pivy/coin3D-based objects for rendering lines / nodes at the scenegraph level for user interface feedback. Implemented originally as a part of the FreeCAD Trails Workbench. odule.

  4. OpenCASCADE: CAD kernel,但仅用在Part_Workbench中

    First of all FreeCAD works without OpenCASCADE. That is an important feature, not everything needs geometric modeling, for example the Robot Workbench. OCC is only incorporated by the Part Workbench.

学习路径

  1. 熟悉FreeCADGui的操作流程
  2. 熟悉Python脚本编程,从录制宏开始
  3. 熟悉FreeCAD的关键class,例如:Base, App, Gui, Part
  4. 开发Python的拓展模块
  5. C++与Python混合开发
  6. 开发3D渲染代码(继承自ViewProvider类)

2. 源码目录与模块划分

  • Base: 基类对象定义
  • App: 非GUI的代码,包括:
    • 文档
    • 属性
    • 文档对象
  • Gui: 基于Qt的的Gui代码
  • CXX: 修改PyCXX的Python子模块
  • Ext: 全部的子模块,每个模块独立一个目录命名
  • Main: FreeCADCmd.exe, FreeCADGui.exe
  • Mod: 子模块代码目录
  • Tools: 编译工具fcbt.py
  • Doc: 通过doxygen生成文档

其他

  • 3rdParty: boost/pivy/zlib等
  • zipios++: zip库
  • Build: 设置版本号
  • FCConfig.h & fc.sh: OpenCASCADE相关的环境变量
  • XDGData: 用于生成Linux的桌面图标

list of Mod:

  • Sketcher: 草绘工具
  • OpenSCAD: Part的底层函数,推荐用户换用Part模块函数操作
  • Part: 用于实体图像的表达
  • PartDesign: 用于创建实体(Skecher -> Part)
  • Draft
  • Drawing: 3D图像生成平面图(Part -> DXF/SVG)
  • Assembly
  • Cam: CAM & CNC
  • Path: CAM的刀具轨迹

3. 编译源码

homepage: 官方编译教程

安装依赖

sudo apt build-dep freecad

编译

mkdir freecad-build
cd freecad-build
cmake ../freecad-source -DBUILD_QT5=ON -DPYTHON_EXECUTABLE=/usr/bin/python3
make -j$(nproc --ignore=2)

-j2 选项用于选择编译时占用的内核数量(默认为1),可以用于加速编译。

4. 定制FreeCAD

homepage: 官方入门教程

homepage: FreeCAD脚本基础

homepage: FreeCAD脚本教程

4.1. 脚本操作

示例:

  • FreeCAD.ActiveDocument : 将返回当前(活动)的文件
  • FreeCAD.ActiveDocument.Blob : 在你的文档中访问一个被称为“斑点”对象
  • FreeCADGui.ActiveDocument : 将返回到当前文档相关的文档视图
  • FreeCADGui.ActiveDocument.Blob : 要访问的图形表示(视图)我们的blob对象部分
  • FreeCADGui.ActiveDocument.ActiveView : 将返回当前视图

4.1.1. 基本操作

When you start FreeCAD, the Python console already loads two base modules: FreeCAD and FreeCADGui (which can also be accessed by their shortcuts App and Gui).

新建文档(模型):

>>> doc = FreeCAD.newDocument()
# 以下内容在Python cosole中自动完成
>>> App.setActiveDocument("Unnamed1")
>>> App.ActiveDocument=App.getDocument("Unnamed1")
>>> Gui.ActiveDocument=Gui.getDocument("Unnamed1")

创建对象:

box = doc.addObject("Part::Box", "myBox")
doc.recompute()  # 刷新并显示模型

访问和设置模型参数:

box.Height = 5

Vectors and placements

myvec = FreeCAD.Vector(2, 0, 0)
myvec.x
myvec.y
othervec = FreeCAD.Vector(0, 3, 0)
sumvec = myvec.add(othervec)

box.Placement
box.Placement.Base  # 以及 Rotation 属性
box.Placement.Base = sumvec

otherpla = FreeCAD.Placement()
box.Placement = otherpla

图形显示的操作:

vo = box.ViewObject

vo.Transparency = 80
vo.hide()
vo.show()

4.1.2. 模块简介

The most important modules in FreeCAD that we\'ll look at in this tutorial are: Part, Mesh, Sketcher and Draft.

Mesh网格

import Mesh
mymesh = Mesh.createSphere()
mymesh.Facets
mymesh.Points

meshobj = doc.addObject("Mesh::Feature", "MyMesh")
meshobj.Mesh = mymesh
doc.recompute()

Part零件

import Part
myshape = Part.makeSphere(10)
myshape.Volume
myshape.Area
# Part.show(myshape)  # 等同于下面3行
shapeobj = doc.addObject("Part::Feature", "MyShape")
shapeobj.Shape = myshape
doc.recompute()

Draft

import Draft
rec = Draft.makeRectangle(5, 2)
mvec = FreeCAD.Vector(4, 4, 0)
Draft.move(rec, mvec)
Draft.move(box, mvec)

Gui

from PySide import QtGui
QtGui.QMessageBox.information(None, "Apollo program", "Houston, we have a problem")

4.2. API

homepage

FreeCAD API

FreeCADGui API

ViewObject API

Part API

Mesh API

Draft API

Selection API

4.2.1. Part Module

homepage

The Part Workbench is the basic layer that exposes the OCCT drawing functions to all workbenches in FreeCAD.

Primitives Tools:

Modifying objects:

Measure Tools:

Other tools:

4.3. 创建工作台

homepage: Workbench creation

class MyWorkbench (Workbench):

    MenuText = "My Workbench"
    ToolTip = "A description of my workbench"
    Icon = """paste here the contents of a 16x16 xpm icon"""

    def Initialize(self):
        """This function is executed when FreeCAD starts"""
        import MyModuleA, MyModuleB # import here all the needed files that create your FreeCAD commands
        self.list = ["MyCommand1, MyCommand2"] # A list of command names created in the line above
        self.appendToolbar("My Commands",self.list) # creates a new toolbar with your commands
        self.appendMenu("My New Menu",self.list) # creates a new menu
        self.appendMenu(["An existing Menu","My submenu"],self.list) # appends a submenu to an existing menu

    def Activated(self):
        """This function is executed when the workbench is activated"""
        return

    def Deactivated(self):
        """This function is executed when the workbench is deactivated"""
        return

    def ContextMenu(self, recipient):
        """This is executed whenever the user right-clicks on screen"""
        # "recipient" will be either "view" or "tree"
        self.appendContextMenu("My commands",self.list) # add commands to the context menu

    def GetClassName(self):
        # this function is mandatory if this is a full python workbench
        return "Gui::PythonWorkbench"

Gui.addWorkbench(MyWorkbench())

Python command definition

class My_Command_Class():
    """My new command"""

    def GetResources(self):
        return {\'Pixmap\'  : \'My_Command_Icon\', # the name of a svg file available in the resources
                \'Accel\' : "Shift+S", # a default shortcut (optional)
                \'MenuText\': "My New Command",
                \'ToolTip\' : "What my new command does"}

    def Activated(self):
        """Do something here"""
        return

    def IsActive(self):
        """Here you can define if the command must be active or not (greyed) if certain conditions
        are met or not. This function is optional."""
        return True

FreeCADGui.addCommand(\'My_Command\',My_Command_Class())

"Compiling" your resource file

import os, glob

qrc_filename = \'temp.qrc\'
if os.path.exists(qrc_filename):
    os.remove(qrc_filename)

qrc = \'\'\'<RCC>
\t<qresource prefix="/">\'\'\'
for fn in glob.glob(\'./icons/*.svg\'):
    qrc = qrc + \'\n\t\t<file>%s</file>\' % fn
qrc = qrc + \'\'\'\n\t</qresource>
</RCC>\'\'\'

print(qrc)

f = open(qrc_filename,\'w\')
f.write(qrc)
f.close()

os.system(
    \'pyside-rcc -o a2p_Resources2.py {}\'.format(qrc_filename))
os.system(
    \'pyside-rcc -py3 -o a2p_Resources3.py {}\'.format(qrc_filename))

os.remove(qrc_filename)