FreeCAD源码分析:FreeCADApp模块

 

FreeCAD源码分析:FreeCADApp模块

济南友泉软件有限公司

一、模块功能概述

FreeCADApp实现了整形、浮点型等基本类型的持久化支持,在此基础之上封装了大量的文档对象。基于属性与文档对象,FreeCADApp模块主要提供了文档对象管理、文档管理、参数管理等功能。

  • 常用属性

       App::Property提供了持久化属性的基类,FreeCAD提供了整形、浮点数等大量常用数据类型。

  • 文档对象

文档对象是文档操作的对象,提供了GeoFeature、PartFeature、MeshFeature等大量常用文档对象。

  • 文档对象管理

App::Document提供了文档对象创建、访问、修改、删除等接口。

  • 文档管理

      App::Application实现多文档的打开、切换、保存、关闭等功能。

  • 参数管理

     保存系统与用户定制的相关参数信息。

二、数据持久化

数据持久化是将数据存储到硬盘等持久性介质或者从硬盘等持久性介质读取数据到内存对象。Document类提供了基于属性的持久化服务。

    2.1 信号-槽机制:一种观察者模式

signals2基于Boost里另一个库signals实现了线程安全的观察者模式,基于函数回调机制实现信号/槽的绑定和触发事件。在signals2中,观察者模式被称为信号/插槽(signals and slots),它是一种函数回调机制,一个信号关联了多个插槽,当信号发出时,所有关联它的插槽都会被调用。

许多成熟的软件系统都用到了这种信号、槽机制(另一个常用的名称是事件处理机制;event/event handler),它可以很好地解耦一组相互协作的类,有的语言甚至直接内建了对它的支持,signals2以库的形式为C++增加了这个重要的功能。

signals2库位于命名空间boost::signals2中,为了使用它,需要包含头文件<boost/signals2.hpp>。

信号(signal)可以理解成为事件,在boost里面,signal是一个模板类,它定义为

template<typename Signature,
typename Combiner = boost::signals2::optional_last_value<R>,
typename Group = int, typename GroupCompare = std::less<Group>,
typename SlotFunction = boost::function<Signature>,
typename ExtendedSlotFunction = boost::function<R(const connection &, T1, T2, ..., TN)>,
typename Mutex = boost::signals2::mutex>
class signal;

插槽(slot)可以是任意的可调用对象,包括函数指针、函数对象、以及它们的bind表达式和function对象,signal内部使用function作为容器来保存这些可调用对象。

通过boost::signals2::signal的成员函数connect() 与disconnect()可以管理signal与slot之间的链接关系。

示例:

#include <boost/signals2.hpp>
#include <iostream>

struct Hello
{
  void operator()() const
  {
    std::cout << "Hello";
  }
};


struct World
{
  void operator()() const
  {
    std::cout << ", World!" << std::endl;
  }
};


int main()
{
  // Signal with no arguments and a void return value
  boost::signals2::signal<void()> sig;

  // Connect a Hello and World slot
  sig.connect(Hello());
  sig.connect(World());

  // Call all of the slots
  sig();
}

同时,App::Document预定义基本的信号

信号

描述

signalBeforeChange

signal before changing an doc property

signalChanged

signal on changed doc property

signalNewObject

signal on new Object

signalDeletedObject

signal on deleted Object

signalBeforeChangeObject

signal before changing an Object

signalChangedObject

signal on changed Object

signalRelabelObject

signal on relabeled Object

signalActivatedObject

signal on activated Object

signalTransactionAppend

signal on created object

signalTransactionRemove

signal on removed object

signalUndo

signal on undo

signalRedo

signal on redo

signalSaveDocument

signal on load/save document. this signal is given when the document gets streamed. you can use this hook to write additional information in the file (like the Gui::Document does).

signalRestoreDocument

signalExportObjects

signalExportViewObjects

signalImportObjects;

signalImportViewObjects

signalStartSave

signal starting a save action to a file

signalFinishSave

signal finishing a save action to a file

signalRecomputed

 

signalRecomputedObject

 

signalOpenTransaction

signal a new opened transactio

signalCommitTransaction

signal a committed transaction

ignalAbortTransaction

signal an aborted transaction

  2.2 属性数据

属性用于在文档中存储特性、界面输出等参数。Property类是整型、浮点型、枚举型、字符串等其他属性类的基类。

类名

描述

主要方法

PropertyInteger

长整型

void setValue(long)

long getValue(void) const

PropertyPath

文件路径

void setValue(const char *)

void setValue(const boost::filesystem::path &)

boost::filesystem::path getValue(void) const

PropertyEnumeration

枚举类型

void setEnums(const char** plEnums)

void setValue(const char* value)

void setValue(long)

void setValue(const Enumeration &source)

long getValue(void) const

const char * getValueAsString(void) const;

Enumeration getEnum(void) const;

std::vector<std::string> getEnumVector(void) const;

const char ** getEnums(void) const;

PropertyIntegerConstraint

整数区间

void setConstraints(const Constraints* sConstraint)   const Constraints*  getConstraints(void) const

PropertyPercent

整数区间[0,100]

 

PropertyIntegerList

整数列表

void setValue(long)

long operator[] (const int idx) const 

void  set1Value (const int idx, long value)

void setValues (const std::vector<long>& values)

const std::vector<long> &getValues(void) const

PropertyIntegerSet

整数集合

void setValue(long)

void setValue(void)

void addValue (long value)

void setValues (const std::set<long>& values)

const std::set<long> &getValues(void) const

PropertyMap

Key-Value映射表

void setValue(void)

void setValue(const std::string& key,const std::string& value)

void setValues(const std::map<std::string,std::string>&);

const std::string& operator[] (const std::string& key) const

void  set1Value (const std::string& key, const std::string& value)

const std::map<std::string,std::string> &getValues(void) const

PropertyFloat

双精度浮点数

void setValue(double lValue)

double getValue(void) const

PropertyFloatConstraint

实数区间

void setConstraints(const Constraints* sConstrain)

const Constraints*  getConstraints(void) const;

PropertyPrecision

实数精度,默认1e-3

 

PropertyFloatList

实数列表

void setValue(double);

void setValue (void){}

double operator[] (const int idx) const 

void set1Value (const int idx, double value)

void setValues (const std::vector<double>& values);

const std::vector<double> &getValues(void) const

PropertyString

字符串

void setValue(const char* sString);

void setValue(const std::string &sString);

const char* getValue(void) const;

const std::string& getStrValue(void) const

bool isEmpty(void)

PropertyUUID

通用唯一识别码UUID

void setValue(const Base::Uuid &);

void setValue(const char* sString);

void setValue(const std::string &sString);

const std::string& getValueStr(void) const;

const Base::Uuid& getValue(void) const

PropertyFont

字体名称

 

PropertyStringList

字符串列表

void setValue(const std::string&);

void setValues(const std::vector<std::string>&);

void setValues(const std::list<std::string>&);

const std::string& operator[] (const int idx) const 

void  set1Value (const int idx, const std::string& value)

const std::vector<std::string> &getValues(void) const

PropertyBool

布尔值

void setValue(bool lValue)

bool getValue(void) const

PropertyBoolList

布尔值列表

void setValue(bool)

void  set1Value (const int idx, bool value)

void setValues (const boost::dynamic_bitset<>& values)

const boost::dynamic_bitset<> &getValues(void) const

PropertyColor

颜色RGB

void setValue(const Color &col);

void setValue(float r, float g, float b, float a=0.0f);

void setValue(uint32_t rgba);

const Color &getValue(void) const;

PropertyColorList

颜色列表

void setValue(const Color&);

const Color& operator[] (const int idx) const 

void  set1Value (const int idx, const Color& value)

void setValues (const std::vector<Color>& values)

const std::vector<Color> &getValues(void) const

PropertyMaterial

材质

void setValue(const Material &mat)

void setAmbientColor(const Color& col)

void setDiffuseColor(const Color& col)

void setSpecularColor(const Color& col)

void setEmissiveColor(const Color& col)

void setShininess(float)

void setTransparency(float)

const Material &getValue(void) const

PropertyMaterialList

材质列表

void setValue(const Material&)

 const Material& operator[] (const int idx) const 

void  set1Value(const int idx, const Material& value)

void setValues(const std::vector<Material>& values)

const std::vector<Material> &getValues(void) const

     

PropertyContainer是属性容器,所有包含属性的类的基类都要继承自PropertyContainer,可以通过提供的宏来简化属性容器的定义。

示例:

//Annotation.h

class AppExport Annotation : public DocumentObject
{
    PROPERTY_HEADER(App::Annotation);

public:
    /// Constructor
    Annotation(void);
    virtual ~Annotation();


    App::PropertyStringList LabelText;
    App::PropertyVector Position;


    /// returns the type name of the ViewProvider
    const char* getViewProviderName(void) const {

        return "Gui::ViewProviderAnnotation";
    }
};


//Annotation.cpp

PROPERTY_SOURCE(App::Annotation, App::DocumentObject)


Annotation::Annotation()
{
    ADD_PROPERTY(LabelText ,(""));
    ADD_PROPERTY(Position,(Base::Vector3d()));
}


Annotation::~Annotation()
{
}

PropertyContainer内部实际上使用PropertyData类型对象存储了属性的描述信息(元数据),

static PropertyContainer::PropertyData::propertyData

PropertyData内部包含了一个PropertyData::PropertySpec类型的数组,用于描述所有的属性描述信息(元数据),主要包括名称、组、文档描述、位置、类型等。

struct PropertySpec
{
  const char* Name;
  const char * Group;
  const char * Docu;
  short Offset,Type;
};

为了方便计算PropertySpec中的offset字段,提供了PropertyData::OffsetBase类。

  2.3 文档对象管理

文档对象(也称作Feature)是文档操作操作的对象,通常文档对象显示在FreeCAD treeview。关闭文档的时候,会保存文档对象;打开文档的时候,会恢复文档对象。

图片[1]-FreeCAD源码分析:FreeCADApp模块-卡核

App::DocumentObject是所有文档对象的基类,定义了文档对象的标签、可见性等基本属性。

属性名称

类型

描述

Expression Engine

PropertyExpressionEngin

a list of expressions.

Label

PropertyString

the user editable name of this object, it is an arbitrary UTF8 string. By default, it is the same as the Name

     

常用的文档对象主要包括:

文档对象派生类

描述

FeaturePython

an empty object that can be used for different purposes, depending on the added properties.

GeoFeature

the base object of all geometrical objects, that is, of objects that have a Placement property that defines their position in the 3D view.

PartFeature

derived from App GeoFeature, and the parent class of objects with 2D and 3D topological shapes.

MeshFeature

derived from App GeoFeature, and the parent class of objects with 2D and 3D meshes.

    2.3.1 创建文档对象

根据文档对象类型创建文档对象。

DocumentObject *Document::addObject(const char* sType, const char* pObjectName = 0, bool isNew = true);

    2.3.2 访问文档对象

根据文档对象名称获取指定的文档对象。

DocumentObject * Document::getObject(const char *Name) const;

根据指定类型的文档对象列表。
 

template<typename T>
inline std::vector<T*> Document::getObjectsOfType() const

    2.3.3 删除文档对象

void Document::removeObject(const char* sName);

  2.4 状态管理

App::Document实现了基于文档对象的touch、更新等状态维护。

void purgeTouched()

Remove all modifications. After this call The document becomes Valid again.

bool isTouched(void) const

check if there is any touched object in this document

std::vector<App::DocumentObject *> getTouched(void) const

returns all touched objects

void setClosable(bool)

set the document to be closable, this is on by default.

bool isClosable() const

check whether the document can be closed

int recompute()

Recompute all touched features and return the number of recalculated features

void recomputeFeature(DocumentObject* Feat)

Recompute only one feature

  2.5 事务管理

事务是一些列操作序列的几何。App::Document提供了基于事务的Undo、Redo功能;

void openTransaction(const char* name=0)

Open a new command Undo/Redo, an UTF-8 name can be specified

void commitTransaction()

Commit the Command transaction. Do nothing If there is no Command transaction open.

void abortTransaction()

Abort the actually running transaction.

bool isTransactionEmpty() const

Check if a transaction is open and its list is empty.

void setUndoLimit(unsigned int UndoMemSize=0)

Set the Undo limit in Byte!

void setMaxUndoStackSize(unsigned int UndoMaxStackSize=20)

Set the Undo limit as stack size

void clearUndos()

Remove all stored Undos and Redos

std::vector<std::string> getAvailableUndoNames() const

Returns a list of the Undo names

bool undo()

Will UNDO one step, returns False if no undo was done (Undos == 0).

int getAvailableRedos() const

Returns the number of stored Redos. If greater than 0 Redo will be effective.

std::vector<std::string> getAvailableRedoNames() const

Returns a list of the Redo names.

bool redo()

Will REDO one step, returns False if no redo was done (Redos == 0).

三、应用程序类

Application提供了多文档应用程序开发的框架,支持文档操作、参数管理、模块管理、软件启动等相关服务。同时,Application提供了基于boost::signals2的信号-槽机制。存在全局唯一的一个Application对象。

  3.1 文档管理

文档操作包括新建、打开、关闭等操作,同时提供了活动文档的切换操作。

  • 新建文档

App::Document* App::Application::newDocument(const char * Name=0l, const char * UserName=0l)

第一个参数是一个标识符,可以通过getUniqueDocumentName函数生成一个不重复的标识符,这个标识符适用于内部唯一标识一个文档对象;第二个参数是用于显示文档名字的字符串。

  • 打开文档

App::Document* App::Application::openDocument(const char * FileName=0l)

用于打开指定的XML格式文档。如果文档存在,直接返回文档对象;如果不存在,则调用newDocument函数创建文档对象。

  • 活动文档

活动文档是当前用户正在操作的文件数据,可以根据需要切换活动文档。

void App::Application::setActiveDocument(App::Document* pDoc);

void App::Application::setActiveDocument(const char *Name);

  • 关闭文档

文档修改完毕,可以关闭文档以将修改同步更新到磁盘文件。

bool App::Application::closeDocument(const char* name);

void App::Application::closeAllDocuments(void);

3.2 参数管理

App::Application使用mConfig保存基本的软件信息,包括程序名称、用户参数目录、系统参数目录等。

std::map<std::string,std::string> Application::mConfig

App::Application使用一系列ParameterManager类型对象来管理软件参数,

std::map<std::string,ParameterManager *> mpcPramManager;

可以通过ParameterManager不仅可以加载、导出DOM格式的参数文件,而且提供多种接口以方便的获取整形、浮点型、布尔类型的参数值。mpcPramManager中有两个比较重要的参数管理器,即_pcSysParamMngr与_pcUserParamMngr,

ParameterManager *App::Application::_pcSysParamMngr;

ParameterManager *App::Application::_pcUserParamMngr;

在Application::LoadParameters()中,_pcUserParamMngr 会加载mConfig[“UserParameter”] 指定的文件(mConfig[“UserAppData”]\\user.cfg)文件来完成对;_pcSysParamMngr会加载mConfig[“SystemParameter”](默认是mConfig[“UserAppData”]\\system.cfg)

  3.3 目录管理

针对不同的平台,App::Application将FreeCAD系统信息以及用户配置信息存储到不同的目录下。

 

描述

const char* getHomePath(void) const

void Application::initConfig(int argc, char ** argv)调用时根据argv[0]设置.

保存在App::Application_mConfig[“AppHomePath”]

static std::string getTempPath()

  1. Windows

通过GetTempPath()返回,取值为

  1. The path specified by the TMP environment variable.
  2. The path specified by the TEMP environment variable.
  3. The path specified by the USERPROFILE environment variable.
  4. The Windows directory.
  1. Linux
  1. 环境变量”TMPDIR”
  2. 默认值“/tmp”

static std::string getTempFileName(const char* FileName=0)

根据FileName在TempPath中创建临时文件

static std::string getUserAppDataDir()

  1. Window

通过SHGetFolderPath获取CSIDL_APPDATA,即

C:\\Documents and Settings\\username\\Application Data 

  1. Linux

环境变量”FREECAD_USER_DATA”

static std::string getUserMacroDir()

mConfig[“UserAppData”] + “Macro/”

static std::string getResourceDir()

mConfig[“AppHomePath”] + “data/”

static std::string getHelpDir()

mConfig[“AppHomePath”] + “doc/”

  3.4 模块管理

略。(后续模块开发时讲解)

  3.5 软件启动

FreeCAD具有GUI、Console等运行两种模式。通过设置“Console”/“RunMode”可以指定FreeCAD的运行模式。

名称 取值范围 默认值
Console

0 : 不启动控制台

1 : 启动控制台

0
RunMode

Gui :  界面模式

Internal :

Gui
// Init phase ===========================================================
// sets the default run mode for FC, starts with gui if not overridden in InitConfig...
        App::Application::Config()["RunMode"] = "Gui";
        App::Application::Config()["Console"] = "0";

如果“Console”为“1”,则FreeCAD将启动控制台。

如果“RunMode”为“Gui”或者“Internal”,将会调用FreeCADGui模块以界面模式启动FreeCAD;否则将会调用FreeCADMainCmd以控制台模式启动FreeCAD。

        // if console option is set then run in cmd mode
        if (App::Application::Config()["Console"] == "1")
            App::Application::runApplication();

        if (App::Application::Config()["RunMode"] == "Gui" ||

            App::Application::Config()["RunMode"] == "Internal")
            Gui::Application::runApplication();

        else
            App::Application::runApplication();

参考资料

  1. FreeCAD Developer hub
  2. Chapter 36. Boost.Signals2
  3. FreeCAD App::DocumentObject
 
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片