日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

FreeCAD源码分析:FreeCADMain模块

發(fā)布時(shí)間:2024/3/24 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 FreeCAD源码分析:FreeCADMain模块 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

FreeCAD源碼分析:FreeCADCmd\FreeCADMain\FreeCADPy模塊

濟(jì)南友泉軟件有限公司

?

FreeCAD提供了控制臺(tái)、GUI、Python等三種運(yùn)行模式,分別對(duì)應(yīng)FreeCADCmd、FreeCADMain、FreeCADPy。由于這三者的代碼結(jié)構(gòu)比較相似,但FreeCADMain相對(duì)復(fù)雜一些,因此,本文著重就FreeCADMain展開分析。了解清楚FreeCADMain模塊,就可以輕松掌握FreeCADMainCmd、FreeCADMainPy模塊的原理。

注:FreeCADMain也提供了控制臺(tái)模式運(yùn)行。

一、模塊功能概述

FreeCADMain主要用于根據(jù)配置參數(shù)(默認(rèn)參數(shù)、用戶參數(shù))啟動(dòng)軟件FreeCAD,具體來說,主要功能包括:

  • 配置參數(shù)

生成默認(rèn)配置參數(shù),解析用戶輸入?yún)?shù),訂制FreeCAD的啟動(dòng)特性。

  • dmp文件

軟件意外崩潰時(shí),輸出堆棧信息到crash.dmp文件(默認(rèn)位置%APPDATA%\FreeCAD)。

  • 日志重定向

將標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)錯(cuò)誤、標(biāo)準(zhǔn)日志等重定向到日志文件。

  • 啟動(dòng)軟件

根據(jù)配置參數(shù)啟動(dòng)GUI版本或者Console版本的FreeCAD。

二、處理流程

通過分析MainGui.cpp以研究FreeCADMain的主要功能的實(shí)現(xiàn)流程。

?? 2.1 移除PYTHONHOME環(huán)境變量

PYTHONHOME環(huán)境變量指向Python的安裝目錄,通常不需要用戶自己設(shè)置該變量。為了防止多個(gè)版本的Python對(duì)FreeCAD的影響,在main函數(shù)進(jìn)入之后,首先移除了PYTHONHOME環(huán)境變量。

#if defined (FC_OS_LINUX) || defined(FC_OS_BSD)// Make sure to setup the Qt locale system before setting LANG and LC_ALL to C.// which is needed to use the system locale settings.(void)QLocale::system();#if QT_VERSION < 0x050000// http://www.freecadweb.org/tracker/view.php?id=399// Because of setting LANG=C the Qt automagic to use the correct encoding// for file names is broken. This is a workaround to force the use of UTF-8 encodingQFile::setEncodingFunction(myEncoderFunc);QFile::setDecodingFunction(myDecoderFunc);#endif// See https://forum.freecadweb.org/viewtopic.php?f=18&t=20600// See Gui::Application::runApplication()putenv("LC_NUMERIC=C");putenv("PYTHONPATH=");#elif defined(FC_OS_MACOSX)(void)QLocale::system();putenv("PYTHONPATH=");#else_putenv("PYTHONPATH="); // https://forum.freecadweb.org/viewtopic.php?f=4&t=18288 // https://forum.freecadweb.org/viewtopic.php?f=3&t=20515 const char* fc_py_home = getenv("FC_PYTHONHOME"); if (fc_py_home) _putenv_s("PYTHONHOME", fc_py_home); else _putenv("PYTHONHOME="); #endif

?? 2.2 配置默認(rèn)軟件參數(shù)

靜態(tài)成員函數(shù)Application::Config返回靜態(tài)對(duì)象Application::mConfig對(duì)象,

static std::map<std::string,std::string> mConfig;

mConfig以字符串的形式保存了不同參數(shù)對(duì)應(yīng)的參數(shù)值。通過設(shè)置mConfig就可以指定FreeCAD的啟動(dòng)特性。
???

// Name and Version of the ApplicationApp::Application::Config()["ExeName"] = "FreeCAD";App::Application::Config()["ExeVendor"] = "FreeCAD";App::Application::Config()["AppDataSkipVendor"] = "true";App::Application::Config()["MaintainerUrl"] = "http://www.freecadweb.org/wiki/Main_Page";// set the banner (for logging and console)App::Application::Config()["CopyrightInfo"] = sBanner;App::Application::Config()["AppIcon"] = "freecad";App::Application::Config()["SplashScreen"] = "freecadsplash";App::Application::Config()["StartWorkbench"] = "StartWorkbench";//App::Application::Config()["HiddenDockWindow"] = "Property editor";App::Application::Config()["SplashAlignment" ] = "Bottom|Left";App::Application::Config()["SplashTextColor" ] = "#ffffff"; // whiteApp::Application::Config()["SplashInfoColor" ] = "#c8c8c8"; // light grey

?? 2.3 啟動(dòng)模式

FreeCAD具有GUI、Console等運(yùn)行兩種模式。通過設(shè)置“Console”/“RunMode”可以指定FreeCAD的運(yùn)行模式。

名稱

取值范圍

默認(rèn)值

Console

0 : 不啟動(dòng)控制臺(tái)

1 : 啟動(dòng)控制臺(tái)

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將啟動(dòng)控制臺(tái)。

如果“RunMode”為“Gui”或者“Internal”,將會(huì)調(diào)用FreeCADGui模塊以界面模式啟動(dòng)FreeCAD;否則將會(huì)調(diào)用FreeCADMainCmd以控制臺(tái)模式啟動(dòng)FreeCAD。

// if console option is set then run in cmd modeif (App::Application::Config()["Console"] == "1")App::Application::runApplication();if (App::Application::Config()["RunMode"] == "Gui" ||App::Application::Config()["RunMode"] == "Internal")Gui::Application::runApplication();elseApp::Application::runApplication();

? 2.4 導(dǎo)出崩潰信息

通過調(diào)用dbghelp.dll中MiniDumpWriteDump函數(shù),修改軟件運(yùn)行時(shí)堆棧信息導(dǎo)出到mConfig["UserAppData"]\creash.dmp文件中。

// create a dump file when the application crashesstd::string dmpfile = App::Application::getUserAppDataDir();dmpfile += "crash.dmp";InitMiniDumpWriter(dmpfile);

? 2.5 重定向日志輸出

Base::RedirectStdOutput、Base::RedirectStdLog、RedirectStdError均繼承自std::streambuf。Base::RedirectStdOutput、Base::RedirectStdLog將輸出、日志等重定向到了Base::Console的Log函數(shù);RedirectStdError則將錯(cuò)誤重定向到Base::Console的Error函數(shù)。

通過調(diào)用std:: basic_ios::rdbuf函數(shù)設(shè)置std::cout、std::clog、std::cerr等流對(duì)象的緩沖區(qū)可以分別完成標(biāo)準(zhǔn)輸出、日志、錯(cuò)誤等輸出的重定向。

Base::RedirectStdOutput stdcout;Base::RedirectStdLog stdclog;Base::RedirectStdError stdcerr;std::streambuf* oldcout = std::cout.rdbuf(&stdcout);std::streambuf* oldclog = std::clog.rdbuf(&stdclog);std::streambuf* oldcerr = std::cerr.rdbuf(&stdcerr);

FreeCAD退出之前,需要恢復(fù)標(biāo)準(zhǔn)輸出、日志、錯(cuò)誤等流對(duì)象緩沖區(qū)。

std::cout.rdbuf(oldcout);std::clog.rdbuf(oldclog);std::cerr.rdbuf(oldcerr);

三、控制臺(tái)應(yīng)用程序

App::Application類用于FreeCAD主程序的抽象。實(shí)現(xiàn)配置參數(shù)管理、文檔管理等功能。

?? 3.1 初始化

應(yīng)用程序類調(diào)用init成員函數(shù)完成應(yīng)用程序的初始化工作,init函數(shù)的原型為:

static void init(int argc, char ** argv);

參數(shù)說明:

argc: argv數(shù)組中的長度,由主函數(shù)main傳入

argv: 參數(shù)列表,由main函數(shù)傳入

根據(jù)傳入的參數(shù),調(diào)用initConfig()函數(shù)初始化配置參數(shù),并將默認(rèn)配置參數(shù)存放到mConfig中,

static std::map<std::string,std::string> mConfig;

mConfig主要配置參數(shù)參見附錄A

?? 3.2 參數(shù)管理

App::Application使用mConfig保存基本的軟件信息,包括程序名稱、用戶參數(shù)目錄、系統(tǒng)參數(shù)目錄等。

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

App::Application使用一系列ParameterManager類型對(duì)象來管理軟件參數(shù),

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

可以通過

ParameterManager不僅可以加載、導(dǎo)出DOM格式的參數(shù)文件,而且提供多種接口以方便的獲取整形、浮點(diǎn)型、布爾類型的參數(shù)值。

mpcPramManager有兩個(gè)比較重要的參數(shù)管理器,即_pcSysParamMngr_pcUserParamMngr

ParameterManager *App::Application::_pcSysParamMngr; ParameterManager *App::Application::_pcUserParamMngr;

在Application::LoadParameters()中,_pcUserParamMngr 會(huì)加載mConfig["UserParameter"] 指定的文件(mConfig["UserAppData"]\user.cfg)文件來完成對(duì);_pcSysParamMngr會(huì)加載mConfig["SystemParameter"](默認(rèn)是mConfig["UserAppData"]\system.cfg)

?? 3.3 文檔管理

基于信號(hào)-槽機(jī)制,App::Application提供了創(chuàng)建、打開、激活、關(guān)閉文檔等一系列文檔操作函數(shù)。??

App::Document* newDocument(const char * Name=0l, const char * UserName=0l);/// Closes the document \a name and removes it from the application.bool closeDocument(const char* name);/// find a unique document namestd::string getUniqueDocumentName(const char *Name) const;/// Open an existing document from a fileApp::Document* openDocument(const char * FileName=0l);/// Retrieve the active documentApp::Document* getActiveDocument(void) const;/// Retrieve a named documentApp::Document* getDocument(const char *Name) const;/// gets the (internal) name of the documentconst char * getDocumentName(const App::Document* ) const;/// get a list of all documents in the applicationstd::vector<App::Document*> getDocuments() const;/// Set the active documentvoid setActiveDocument(App::Document* pDoc);void setActiveDocument(const char *Name);/// close all documents (without saving)void closeAllDocuments(void);

四、重定向輸出類

FreeCADBase模塊提供了RedirectStdOutput、RedirectStdError、RedirectStdLog等三個(gè)類用于日志輸出重定向。

class BaseExport RedirectStdOutput : public std::streambuf { public:RedirectStdOutput();protected:int overflow(int c = EOF);int sync();private:std::string buffer; };class BaseExport RedirectStdError : public std::streambuf { public:RedirectStdError();protected:int overflow(int c = EOF);int sync();private:std::string buffer; };class BaseExport RedirectStdLog : public std::streambuf { public:RedirectStdLog();protected:int overflow(int c = EOF);int sync();private:std::string buffer; };

可以看到,這三個(gè)類的實(shí)現(xiàn)比較相似。這三個(gè)類都繼承自std::streambuf類。

using streambuf = basic_streambuf<char, char_traits<char>>;

streambuf實(shí)際上是std::basic_streambuf模板類char類型的實(shí)例化之后得到的一個(gè)類。

當(dāng)有新的字符插入時(shí),就會(huì)調(diào)用overflow(int c)函數(shù),參數(shù)c就是要插入的字符。sync()函數(shù)用于清空緩沖區(qū)中的內(nèi)容。

? 4.1 RedirectStdOutput

由于RedirectStdOutput、RedirectStdError、RedirectStdLog等三個(gè)類的實(shí)現(xiàn)方式比較相似,這里僅對(duì)RedirectStdOutput進(jìn)行分析。

在RedirectStdOutput的構(gòu)造函數(shù)中,設(shè)置了緩沖區(qū)的大小,

RedirectStdOutput::RedirectStdOutput() {buffer.reserve(80); }

當(dāng)有新的字符需要插入的時(shí)候,overflow函數(shù)將字符放到內(nèi)部字符串的最后面,同事返回當(dāng)前字符串的長度。

int RedirectStdOutput::overflow(int c) {if (c != EOF)buffer.push_back((char)c);return c; }

調(diào)用sync函數(shù),將字符串當(dāng)前的內(nèi)容通過Base::Console().Log函數(shù)輸出。

int RedirectStdOutput::sync() {// Print as log as this might be verboseif (!buffer.empty()) {Base::Console().Log("%s", buffer.c_str());buffer.clear();}return 0; }

? 4.2 ConsoleSingleton

ConsoleSigleton用于信息、警告、錯(cuò)誤等輸出。程序運(yùn)行時(shí),只有一個(gè)ConsoleSigleton對(duì)象。可以通過Base::Console()獲取該唯一的控制臺(tái)輸出對(duì)象。

#include <Base/Console.h>Base::Console().Log("Stage: %d",i);

ConsoleSigleton提供了多種工作模式,可以通SetConsoleMode函數(shù)進(jìn)行設(shè)置,

/// Change modevoid SetConsoleMode(ConsoleMode m);

?

五、界面應(yīng)用程序類

略(Gui::Application與App::Application比較相似),參照FreeCADApp源碼分析。

?

六、FreeCADMainCmd模塊

FreeCADMainCmd構(gòu)建生成FreeCADCmd(_d).exe程序,實(shí)際上是直接調(diào)用FreeCADApp模塊完成FreeCAD啟動(dòng)。

?

七、FreeCADMainPy模塊

FreeCADMainPy構(gòu)建生成FreeCAD(_d).pyd動(dòng)態(tài)鏈接庫,用于在Python環(huán)境中導(dǎo)入FreeCAD模塊。MainPy.cpp文件中,定義了Python FreeCAD模塊的入口函數(shù),

PyMOD_INIT_FUNC(FreeCAD) {// Init phase ===========================================================App::Application::Config()["ExeName"] = "FreeCAD";App::Application::Config()["ExeVendor"] = "FreeCAD";App::Application::Config()["AppDataSkipVendor"] = "true";int argc=1;char** argv;argv = (char**)malloc(sizeof(char*)* (argc+1));#if defined(FC_OS_WIN32)argv[0] = (char*)malloc(MAX_PATH);strncpy(argv[0],App::Application::Config()["AppHomePath"].c_str(),MAX_PATH);argv[0][MAX_PATH-1] = '\0'; // ensure null termination #elif defined(FC_OS_CYGWIN)HMODULE hModule = GetModuleHandle("FreeCAD.dll");char szFileName [MAX_PATH];GetModuleFileNameA(hModule, szFileName, MAX_PATH-1);argv[0] = (char*)malloc(MAX_PATH);strncpy(argv[0],szFileName,MAX_PATH);argv[0][MAX_PATH-1] = '\0'; // ensure null termination #elif defined(FC_OS_LINUX) || defined(FC_OS_BSD)putenv("LANG=C");putenv("LC_ALL=C");// get whole path of the libraryDl_info info; #if PY_MAJOR_VERSION >= 3int ret = dladdr((void*)PyInit_FreeCAD, &info); #elseint ret = dladdr((void*)initFreeCAD, &info); #endifif ((ret == 0) || (!info.dli_fname)) {free(argv);PyErr_SetString(PyExc_ImportError, "Cannot get path of the FreeCAD module!"); #if PY_MAJOR_VERSION >= 3return 0; #elsereturn; #endif}argv[0] = (char*)malloc(PATH_MAX);strncpy(argv[0], info.dli_fname,PATH_MAX);argv[0][PATH_MAX-1] = '\0'; // ensure null termination// this is a workaround to avoid a crash in libuuid.so #elif defined(FC_OS_MACOSX)// The MacOS approach uses the Python sys.path list to find the path// to FreeCAD.so - this should be OS-agnostic, except these two// strings, and the call to access().const static char libName[] = "/FreeCAD.so";const static char upDir[] = "/../";char *buf = NULL;PyObject *pySysPath = PySys_GetObject("path");if ( PyList_Check(pySysPath) ) {int i;// pySysPath should be a *PyList of strings - iterate through it// backwards since the FreeCAD path was likely appended just before// we were imported.for (i = PyList_Size(pySysPath) - 1; i >= 0 ; --i) {const char *basePath;PyObject *pyPath = PyList_GetItem(pySysPath, i);long sz = 0;#if PY_MAJOR_VERSION >= 3if ( PyUnicode_Check(pyPath) ) {// Python 3 stringbasePath = PyUnicode_AsUTF8AndSize(pyPath, &sz);} #elseif ( PyString_Check(pyPath) ) {// Python 2 string typePyString_AsStringAndSize(pyPath, &basePath, &sz);}else if ( PyUnicode_Check(pyPath) ) {// Python 2 unicode type - explicitly use UTF-8 codecPyObject *fromUnicode = PyUnicode_AsUTF8String(pyPath);PyString_AsStringAndSize(fromUnicode, &basePath, &sz);Py_XDECREF(fromUnicode);} #endif // #if/else PY_MAJOR_VERSION >= 3else {continue;}if (sz + sizeof(libName) > PATH_MAX) {continue;}// buf gets assigned to argv[0], which is free'd at the endbuf = (char *)malloc(sz + sizeof(libName));if (buf == NULL) {break;}strcpy(buf, basePath);// append libName to bufstrcat(buf, libName);if (access(buf, R_OK | X_OK) == 0) {// The FreeCAD "home" path is one level up from// libName, so replace libName with upDir.strcpy(buf + sz, upDir);buf[sz + sizeof(upDir)] = '\0';break;}} // end for (i = PyList_Size(pySysPath) - 1; i >= 0 ; --i) {} // end if ( PyList_Check(pySysPath) ) {if (buf == NULL) {PyErr_SetString(PyExc_ImportError, "Cannot get path of the FreeCAD module!"); #if PY_MAJOR_VERSION >= 3return 0; #elsereturn; #endif}argv[0] = buf; #else # error "Implement: Retrieve the path of the module for your platform." #endifargv[argc] = 0;try {// Inits the ApplicationApp::Application::init(argc,argv);}catch (const Base::Exception& e) {std::string appName = App::Application::Config()["ExeName"];std::stringstream msg;msg << "While initializing " << appName << " the following exception occurred: '"<< e.what() << "'\n\n";msg << "\nPlease contact the application's support team for more information.\n\n";printf("Initialization of %s failed:\n%s", appName.c_str(), msg.str().c_str());}free(argv[0]);free(argv);#if PY_MAJOR_VERSION >= 3//PyObject* module = _PyImport_FindBuiltin("FreeCAD");PyObject* modules = PyImport_GetModuleDict();PyObject* module = PyDict_GetItemString(modules, "FreeCAD");if (!module) {PyErr_SetString(PyExc_ImportError, "Failed to load FreeCAD module!");}return module; #endif }

?

?

?

附錄A: FreeCAD配置參數(shù)

名稱

默認(rèn)值

描述

APPDATA

操作系統(tǒng)內(nèi)置環(huán)境變量,例如

C:\Users\Administrator\AppData

?

AppDataSkipVendor

true

?

ExeVendor

FreeCAD

?

ExeName

FreeCAD

?

UserAppData

$( APPDATA)\FreeCAD

?

UserParameter

$(UserAppData)\user.cfg

?

SystemParameter

$(UserAppData)\system.cfg

?

參考資料

  • FreeCAD Developer hub
  • ?

    總結(jié)

    以上是生活随笔為你收集整理的FreeCAD源码分析:FreeCADMain模块的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。