FreeCAD简介

FreeCAD是基于OpenCASCADE的开源CAD/CAE软件,完全开源(GPL的LGPL许可证),官方源码地址,详情可参考维基百科,百度百科等等。

如果要编译FreeCAD,最好采用官方提供的LibPack,否则第三方库难以找全。FreeCAD LibPack官方看起来使用VS2008以及VS2013,这二个版本最常用。github上可以下载,但以前的sourceforge地址还可以找到vs2010以及vs2012的,可能没有那么齐全或者新。

## 准备开始
我以前的编译删除了,当初专门安装了VS2013,不过也没怎么好好看,而现在已经卸载了;考虑到只有VS2012 x64版的FreeCAD LibPack,不想大动干戈安装VS2013,所以还是使用VS2012 x64版编译。不知道官方什么时候能够出个 VS2015/VS2017 的LibPack,事实上只需要VS2015就够了,因为vs2015/vs2017在二进制上可以兼容。

解压FreeCAD-0.16.6712.zip至文件夹,再解压FreeCADLibs_11.0_x64_VC11.7z至同级目录,以前者为cmake的source目录,后者为cmake的binary目录。

FreeCADLibs_11.0_x64_VC11.7z 缺少boost 1.55版的boost python库,此为必要库,无法忽略,下载boost 1.55版的x64预编译包,拷贝出其中boost python的lib与dll文件分别放至解压目录之下的lib/dll目录。没有这一步操作,cmake会在src/Mod/Path/libarea里的CMakeLists.txt查找boost_python失败。

在FreeCAD-0.16.6712源码里,打开文件夹下的CMakeLists.txt,修改第125行处的 set(FREECAD_LIBPACK_DIR \({CMAKE_SOURCE_DIR} CACHE PATH "Directory of the FreeCAD LibPack"),其中的\){CMAKE_SOURCE_DIR}替换成为${CMAKE_BINARY_DIR},调用CMake构建工程,默认不做别的修改,生成vs2012 x64的项目工程文件。

编译时,在 src/App/Document.cpp 内会在 tie(edge, inserted) 处由于 tie 的调用不明确导致失败,可以明确在添加调用 boost::tie(edge, inserted),该文件内总计有二个位置需要修改。

为什么不使用最新的源码以及LibPack,因为官方不提供vs2015,vs2017版本的,完全自己补充所有第三方库,会有很大的工作量。

第三方库粗略记录

FreeCADLibs_10.0_x64_VC11.7z 里在include目录是按第三方库名称各自放置的,比较明晰,但是发现后面版本的FreeCAD LibPack都不再是这样的了。

没列举齐全的第三方库表格如下:

Lib Name version in LibPack_11.0_x64_VC11 Link to get it
Python Python 2.7.8 http://www.python.org/
PySide 1.2.2 http://wiki.qt.io/PySide
shiboken 1.2.2 http://shiboken.readthedocs.io/en/latest/
Qt Qt 4 https://www.qt.io/
Boost 1.55.0 http://www.boost.org/
Coin3D 4.0 https://bitbucket.org/Coin3D/coin/wiki/Home
SoQt 1.2 https://bitbucket.org/Coin3D/soqt
OpenCASCADE oce-16(对应6.7.1) http://www.opencascade.com

在以上第三方库中,PySide是Python与Qt的融合,可以使用Python语言构建Gui。建议是在Python2.7系列中使用,支持部分Python3,与PySide有相同功能的PyQt相对成熟一些,但商用需要付费,估计这是FreeCAD采用PySide的原因,PySide是Qt官方出的,完成了对Qt4.8版本的完整实现,支持Qt5的PySide2也可以在github中找到。shiboken作何用途,我还没弄得很明白。

FreeCAD对Python是重度依赖,不能缺失。如果自己来搞第三方库,就必须先搞定Python,PySide,Boost,shiboken,所以使用官方提供的LibPack是可以节省不少麻烦的。

## 工程项目的构成
认为在FreeCAD_trunk之下的项目可以分为三类:基础工程项目框架(仅包括FreeCAD打头的7个工程);模块项目(比如Start/StartGui、Part/PartGui等,位于src/Mod文件夹之下);辅助依赖类(比如area等)。此分类或有遗漏,不过最重要的应该是前面二个分类的工程项目。

基础框架工程项目

工程项目 产生文件 备注
FreeCADMain FreeCAD.exe FreeCAD主执行启动文件,main()函数所在地
FreeCADMainPy FreeCAD.pyd 兼容Python的扩展dll,导出initFreeCAD()
FreeCADMainCmd FreeCADCmd.exe App::Application::Config()["RunMode"]有三种模式,Gui、Exit、Console,这里对应的是Exit模式,执行(argc, argv)之后自动退出
FreeCADGui FreeCADGui.dll 命名空间Gui,Command,Workbench,View3dInventor(视图),Gui层的Document
FreeCADGuiPy FreeCADGui.pyd 兼容Python的扩展dll
FreeCADBase FreeCADBase.dll 代码基础与上层,命名空间Base,Type类型体系,InterpreterSingleton脚本解释器
FreeCADApp FreeCADApp.dll 表征exe执行所在的应用,命名空间App,App::GetApplication()可以获取唯一的那个pcSingleton指针,App层Document

以上这些就建构了FreeCAD运行的基础框架,它们实际上仅使用了Python, Boost, PySide, shiboken, xerces-c, zlib, coin3d等这些,其余的Mod都是模块扩展,依赖诸如OCE,PCL,Eigen3,libqhull等等,每个Mod工程项目分为带Gui的及不带Gui的版本。带Gui的项目定义了可用的Command,Workbench(工作台),显示等这些。

当前FreeCAD所持有的模块

  • Start, StartGui
  • Part, PartGui
  • Points, PointsGui
  • Sketcher, SketcherGui
  • PartDesign, PartDesignGui
  • ......

## FreeCAD启动流程

启动模式

FreeCAD 有三种启动方式,Gui模式,Exit控制台,Python脚本模式;分别对应的起始工程项目是 FreeCADMain, FreeCADMainCmd, FreeCADMainPy。

FreeCAD对Python的扩展

在 FreeCADApp 项目内的 App::Application 的构造函数里,可以看到 PyObject* pAppModule = Py_InitModule3("FreeCAD", Application::Methods, FreeCAD_doc); 语句,这应该是定义一个Python的扩展模块,名称为FreeCAD,扩展的成员函数在静态成员数据Mehods数组内。

在 FreeCADGui 项目内的 Gui::Application 的构造函数里,可以看到 PyObject* module = Py_InitModule3("FreeCADGui", Application::Methods, "The functions in the FreeCADGui module ....."); 语句,定义一个名称为 FreeCADGui 的Python扩展模块。

而在 FreeCADBase 项目内有 Base::Interpreter() 函数返回 InterpreterSingleton::Instance() ; 它的init(int argc, char* argv[])成员函数,在初始化Python,嵌入解释器。

在 FreeCADInit.py脚本里,会简化设定 App = FreeCAD, Gui = FreeCADGui。

本质上FreeCAD是运行在Python解释器上的,也就是说它是通过扩展Python,然后所有的命令(Command类,仅在Gui模式下会有)都是通过执行Python的语句来实现的。所以FreeCAD可以没有Gui界面执行,但是不能没有python,本身内部嵌入了python的解释器。

例举一个Box的创建命令是这样的:

C++
void CmdPartBox::activated(int iMsg)
{
QString cmd;
cmd = qApp->translate("CmdPartBox","Cube");
openCommand((const char*)cmd.toUtf8()); doCommand(Doc,"App.ActiveDocument.addObject(\"Part::Box\",\"Box\")");
cmd = QString::fromLatin1("App.ActiveDocument.ActiveObject.Label = \"%1\"")
.arg(qApp->translate("CmdPartBox","Cube"));
doCommand(Doc,(const char*)cmd.toUtf8());
commitCommand();
updateActive();
doCommand(Gui, "Gui.SendMsgToActiveView(\"ViewFit\")");
}

里边这些都是发送给解释器的Python语句,执行后会在界面上的Python Console窗口播报Python执行语句,这样录制宏就简单极了,此外也可以全部采用Python来建模或者写个功能实现,比如就有个SheetMetal就完全是用Python来实现。

启动代码

需要注意的是 FreeCADApp 内有 App::Application, FreeCADGui 内有 Gui::Application。

启动流程就是 App::Application::init(argc, argv); 如果是 Exit模式,则执行 App::Application::runApplication() 估计是处理了一下命令参数完毕之后就退出了。而如果是 Gui模式,则还要 Gui::Application::initApplication,再有 Gui::Application::runApplication。

与Qt的经典启动模式相比,这些代码都位于 Gui::Application::runApplication 内。GUISingleApplication mainApp; 对应 QApplication;而 Gui::MainWindow mv; 对应 QMainWindow。

因为可以没有Gui界面启动,所以文档也分为 App::Document, Gui::Document,具体的内容存储全在 App::Document 内。

Mod下的模块启动

  • 在 App::Application::initApplication() 里会执行名为 FreeCADInit.py 的脚本;该脚本会遍历 Mod 下所有目录,执行 Init.py
  • 在 Gui::Application::runApplication() 里会执行名为 FreeCADGuiInit.py 的脚本;此脚本会遍历 Mod 下所有目录,执行 InitGui.py

界面与命令描述

在 Gui 内有个 CommandManager,所有的命令Command都往这里边加。Command命令的目标是产生NewObject加入Document,特征附有属性,然后recompute()执行计算,这样就可以重生成,响应修改属性的结果。

它的QAction的变灰动作是通过在 MainWindow 里定义一个计时器,调用 updateActions() 函数,遍历每一个Command,调用testActivate(); 以设定QAction是否可用。

Workbench 设计得不错,成员函数 activate() 会做setupToolBars(), setupDockWindows(), setupMenuBar()等设定菜单,工具栏,停靠窗口 (注意:此函数非虚函数,不能被重载)。觉得不好的地方是定义得太细了,得经常切换Workbench或者使用Complete Workbench来得到所有的可用命令。

## 使用感觉
觉得不习惯的地方,FreeCAD有点反操作,比如倒圆角,你必须首先选择了一条边缘,然后才能去倒圆角。(指的是PartDesign下面的Fillet(只接受一条边缘),Part下边也有Fillet(估计可以多选))。

FreeCAD源码初步了解的更多相关文章

  1. FreeCAD源码阅读笔记

    本文目标在于记录在FreeCAD源码阅读中了解到的一些东西. FreeCAD编译 FreeCAD源码的编译最好使用官方提供的LibPack,否则第三方库难以找全,找到之后还需要自己编译,此外还不知道C ...

  2. vue-style-loader源码初步分析

    背景: 首先声明一下,我只是个菜鸡,为了解决问题才去看的源码,解决完问题之后也就没有兴趣看其他部分代码了,所以这篇文章是一次很低层次的解读,角度也相当片面,想必会有很多喷点吧. 事情的经过是这样,今年 ...

  3. 学习 MyBatis 的一点小总结 —— 底层源码初步分析

    目录 MyBatis 如何获取数据库源? MyBatis 如何获取 sql 语句? MyBatis 如何执行 sql 语句? MyBatis 如何实现不同类型数据之间的转换? 在过去程序员使用 JDB ...

  4. Orchard源码--初步(1)

    1.打开解决方案Orachard.sln 2.直接启动项目调试 3.接着你会看到下图 呵呵,有点啰嗦( ̄︶ ̄)↗ 涨 4.点击上图的‘Finish Setup’后

  5. 阅读nsq源码 ---初步架构设计图

     

  6. JUC源码学习笔记3——AQS等待队列和CyclicBarrier,BlockingQueue

    一丶Condition 1.概述 任何一个java对象都拥有一组定义在Object中的监视器方法--wait(),wait(long timeout),notify(),和notifyAll()方法, ...

  7. [dpdk] 熟悉SDK与初步使用 (四)(L3 Forwarding源码分析)

    接续前节:[dpdk] 熟悉SDK与初步使用 (三)(IP Fragmentation源码分析) 前文中的最后一个问题,搁置,并没有找到答案.所以继续阅读其他例子的代码,想必定能在其他位置看到答案. ...

  8. Spark Streaming揭秘 Day5 初步贯通源码

    Spark Streaming揭秘 Day5 初步贯通源码 引子 今天,让我们从Spark Streaming最重要的三个环节出发,让我们通过走读,逐步贯通源码,还记得Day1提到的三个谜团么,让我们 ...

  9. 在android源码环境下写上层应用的一个初步解决方法

    在android源码环境下编写上层应用,一直以来我都觉得很麻烦.因为如果单纯将应用导入eclipse,那么framework层一些定制的API无法自动提示和补全,使用起来不太方便:如果将整个andro ...

随机推荐

  1. linux服务器系统盘坏且系统盘为软raid的修复方法

    1 需要换新盘的情况 1.1 一块盘grub损坏修复 一块盘grub损坏修复(可通过另一块盘进入系统的情况).更换硬盘的方式,可以热插拔,也可以服务器断电后更换,但如果是热插拔,可能会导致盘符变更.坏 ...

  2. 实现一个函数clone,可以对JavaScript中的5种主要的数据类型(包括Number、String、Object、Array、Boolean)进行值复制

    记录一下,方便以后复制粘贴 // 方法一: Object.prototype.clone = function() { var o = this.constructor === Array ? [] ...

  3. EF 排序扩展

    public static class LinqOrderEx { private static IOrderedQueryable<T> OrderingHelper<T>( ...

  4. 使用 WebStorm IDE 调试 Pomelo 应用程序

    使用得心应手的IDE来开发应用程序,可以使我们的工作事半功倍.而调试则更可以让我们准确的定位BUG,发现问题.本文讲述如何使用 WebStorm 这个怪兽级JavaScript IDE来调试 Chat ...

  5. 关于无限试用JetBrains产品的方案

    JetBrains免费试用期限为30天,通过对其试用机制的设想,找到了其破解试用机制的方案,具体如下: 在选择试用JetBrains产品的时候,它会在 C:\Users\用户名\对应产品\config ...

  6. PJ初赛复习日记

    PA姑娘的PJ初赛复习日记 by Pleiades_Antares PJ初赛考试马上就要开始了(今年应该是10.13吧?),作为蒟蒻的我们怎么能不复习呢? 众所周知,复习方法有很多很多种-- 比如 ( ...

  7. svn 更新

    dev更新流程: 1.打开软件,文件—>打开,弹出右边对话框链接dev地址      2.在窗口输入cd /var/www/user 回车 3.输入svn up 则更新dev代码完成 本地提交到 ...

  8. 前端性能优化成神之路—资源合并与压缩减少HTTP请求

    资源合并与压缩减少HTTP请求的概要 资源合并与压缩减少HTTP请求主要的两个优化点是减少HTTP请求的数量和减少请求资源的大小 http协议是无状态的应用层协议,意味着每次http请求都需要建立通信 ...

  9. python中requests已安装却仍报No module named requests错的原因

    调用pip list可见已经成功安装了: requests 但是在运行时仍报错: userdeMacBook-Pro:xiaohui user$ python test_web.py Tracebac ...

  10. day06数据类型----元组、字典、集合

    一.元组(tuple):     python中将一些不能修改的值称为不可变的,而不可变的列表则被称之为元组. 注意元组一旦被定义则不可修改,因此一般我们不定义空元组. 元组是有序的,可存放多个数据| ...