Hosan开源项目是液压、电力等行业的仿真开源软件,由瑞典林平大学开发,可以仿真电力、液压等。更具体的了解,请参考:《Hopsan -- 液压、电力等行业的仿真开源软件》。

Hosan开源项目编译参考:《Hopsan完全编译构建指南》、《Hopsan的源码编译》。

代码梳理、流程分析如下:

(1):HopsanEssentials的构造函数

在HopsanGUI/CoreAccess.cpp文件的顶部声明了一个hopsan::HopsanEssentials类型的全局变量gHopsanCore,本工程启动时,首先就会调用HopsanEssentials的构造函数,流程如下:

  1. 创建NodeFactory对象mpNodeFactory。
  2. 创建ComponentFactory对象mpComponentFactory。
  3. 如果是第一次调用构造函数,则创建QuantityRegister类对象mpQuantityRegister。在该类中,构造测试量和其单位的映射,如:速度为键,速度的单位m/s。
  4. 构造LoadExternal类对象mpExternalLoader,以便加载外部dll中包含的元件。
  5. 然后以步骤1创建的对象mpNodeFactory为参数,调用register_default_nodes函数,该函数返回后,mpNodeFactory就包含了系统所有默认的节点。
  6. 调用步骤2的mpComponentFactory对象中的registerCreatorFunction函数。注意:这个函数的第二个参数是一个函数指针,该函数指针是以类模板实现的,能支持任何返回值类型且无参数的任何函数。每个被创建的对象所在的类都有一个静态的Creator()函数,在其中创建该类的对象,如下:
  7. 做一些错误检测及清除错误状态的工作,如:看已经注册过的组件是否重复注册等。

(1.1)ClassFactory类

ClassFactory类是一个模板类,如下:

template <typename _Key, typename _Base, typename _Predicator = std::less<_Key> >class ClassFactory
{
}

说明:

  • _Base 是创出函数的返回值,即1节中6步骤中提到的registerCreatorFunction函数第2个参数表示的函数指针的返回值。
  • Key是区分创建组件的关键字,本项目一般是字符串类型,如:“NodeSignal”字符串表示NodeSignal类的组件、DummyComponent表示DummyComponent类的组件等等。
  • _Predicator是map的排序准则,默认是按第一个参数key小写排序。

NodeFactory、ComponentFactory都是ClassFactory模板类的实例,如下:

typedef ClassFactory<HString, Node> NodeFactory;
typedef ClassFactory<HString, Component> ComponentFactory;

(1.2)registerCreatorFunction

ClassFactory模板类的registerCreatorFunction功能如下:

  • 将以key为键,创建组件的构造器也即函数指针为值的键值对, 插入名为mFactoryMap的map中,方便以后查找。
  • 将key为键,创建组件的构造器也即函数指针为值构成的pair插入语 mRegStatusVector,以便在构造函数提示信息,参见1节中的步骤7。

(1.3)类的继承关系

(2)执行流程

(2.1)界面启动流程

  1. main函数被调用。
  2. 创建DesktopHandler对象,并调用该对象的setupPaths()函数安装一些目录。
  3. 创建Configuration对象,设置一些配置信息。
  4. 创建CopyStack对象。
  5. 创建GUIMessageHandler对象,用于处理应用程序的警告、错误、普通消息。
  6. 创建MainWindow对象,并调用其createContents函数创建各种面板、主界面等。
  7. 处理命令行参数。
  8. 闪屏提示。
  9. 调用MainWindow对象的initializeWorkspace函数,加载各种组件库等。
  10. 主程序、主界面启动。

流程如下:

(2.2) initializeWorkspace

流程如下:

  1. 以路径graphics/builtinCAF/hidden/builtin_hidden.xml为参数,InternalLib为第二个参数,Hidden为第三个参数调用LibraryHandler类的loadLibrary,即加载隐藏的内部组件。
  2. 调用LibraryHandler类的loadLibrary 函数加载

../componentLibraries/defaultLibrary/defaultComponentLibrary.xml配置文件中的组件。

3 调用LibraryHandler类的loadLibrary 函数加载如下目录下的组件:

../componentLibraries/autoLibs/

4 调用LibraryHandler类的loadLibrary 函数加载

graphics/builtinCAF/visible/builtin_visible.xml配置文件中的组件。

5 加载以前创建的外部库(在元件树)

6 创建plot widget对象gpPlotWidget,并隐藏。

7 创建FindWidget对象,并隐藏。

8 处理命令行中参数包含.hmf的参数,认为此参数就是模型文件,并加载该模型到视图。

9 调整元件树窗体部件、向闪屏界面发送加载组件完成信息。

(2.3)LibraryHandler类的loadLibrary函数(第1个参数是表示路径的字符串)

流程如下:

(2.4) LibraryHandler类的loadLibrary函数(第1个参数是SharedComponentLibraryPtrT类型)

  1. 读取第1参数即pLibrary的xml文件指向的信息,并绑定这些信息到pLibrary对象。
  2. 将pLibrary对象对象加入到类型为Qlist的mLoadedLibraries成员变量。
  3. 调用CoreLibraryAccess类的loadComponentLib函数加载pLibrary表示的库。
  4. 调用recompileLibrary函数编译该库。
  5. 再次调用CoreLibraryAccess类的loadComponentLib函数加载pLibrary表示的库。
  6. 如果pLibrary库的版本号小于0.3,则递归搜索pLibrary库目录下的xml文件且xml节点是hopsanobjectappearance的文件,并把该文件的绝对路径加入到pLibrary库的cafFiles
  7. 遍历pLibrary库的cafFiles,对每个遍历到的元素构建ModelObjectAppearance对象,也就是组件的外表对象,如:组件在树视图、设计视图上的名称、图标等。
  8. 如果步骤7)中的ModelObjectAppearance对象的typeName类型不是subsystem且不是ConditionalSubsystem,则去1.1节中的ClassFactory类中看这种类型是不是注册过,如果没注册或者其hmf文件不存在,则弹出加载这种类型的组件失败的错误。
  9. 构造ComponentLibraryEntry对象,并设置该对象的各种属性,并将该对象加入到mLibraryEntries,并告知闪屏界面,正在加载这个组件。
  10. 加载类型不为InternalLib的其它用户自定义的类型到配置文件。
  11. 发送contentsChanged信号,以便形成组件树视图。

(2.5)CoreLibraryAccess类的loadComponentLib

流程如下:

(2.6)组件注册文件的生成

子目录下的后缀名为.cci的文件内容如下:

pComponentFactory->registerCreatorFunction("SignalFirstOrderFilter",SignalFirstOrderFilter::Creator);

这些组件注册代码是由generateLibraryFiles.py通过python生成的

开源项目Hopsan代码梳理、流程分析相关推荐

  1. Vue项目启动代码执行流程分析

    相信来看看这篇文章的童鞋,都对Vue已经有了大致的了解.所以,话不多说,直接进入正题. 首先看下图: 一般一个初步的Vue项目创建好之后都会有这三个文件:index.html .main.js .Ap ...

  2. 「Vue 学习笔记 1」Vue 项目快速搭建,初始项目各个文件夹作用介绍和启动代码执行流程分析

    「Vue 学习笔记 1」Vue 项目快速搭建,初始项目各个文件夹作用介绍和启动代码执行流程分析 前言 一.我的开发环境 二.使用 Vue CLI (Vue 脚手架)快速搭建项目 三.初始项目的目录结构 ...

  3. 开源项目贡献代码流程

    原来在github上断断续续给许多项目提交过pr(pull requests),比较有成就感的是参与的datax-web项目,目前已近1.8k star.现将开源项目贡献代码流程成文,方便后续更多的同 ...

  4. 如何有效地学习开源项目的代码?

    对于计算机专业的同学来说,网络上丰富的开源代码是一笔极为宝贵的财富.通过对开源代码的学习与钻研,大家能从中学到很多书本上.课堂上学习不到的实践知识.如何学习开源代码以及如何学好开源代码成为了大家经常关 ...

  5. android简单项目及代码_Android 开源项目 (AOSP) 代码搜索工具正式发布

    我们非常高兴的为各位开发者们介绍一个 Android 开源项目 (AOSP) 的代码搜索工具: https://cs.android.com Android 开源项目的代码由一系列 Git 管理的代码 ...

  6. 给开源项目贡献代码的经历

    工作好几年了还没有成为一名开源贡献者,实属失败,最近进行了人生中的第一次给开源项目贡献代码,记录一下.温馨提示:文章较长,不想听我啰嗦的,直接看最后总结. 背景 作为一个 技术开发者 怎么能没有属于自 ...

  7. 饿了么开源项目Hermes跨进程架构分析1-服务端注册

    文章目录 1 注册实现 1.1 创建aidl文件 1.2 服务端实现 1.2.1 HermesService 1.2.2 创建Request和Responce 1.2.3 创建单例UserManage ...

  8. 《开源思索集》一如何更有效地学习开源项目的代码?

    本节书摘来异步社区<开源思索集>一书中的第2章,第2.1节,作者: 庄表伟 责编: 杨海玲, 更多章节内容可以访问云栖社区"异步社区"公众号查看. 如何更有效地学习开源 ...

  9. 给开源项目贡献代码_您可以为开源做出6种非代码贡献

    给开源项目贡献代码 贡献开源! 履历表看起来很棒! 这是可喜的工作! 在您的整个职业生涯中,您可能听说过很多人做出过这些陈述或类似的陈述. 他们没有错-为开源做贡献是一个多方面的有益工作-但是,当软件 ...

最新文章

  1. python变量按其作用域可分为_python变量的作用域一
  2. php 上个月天数,php日期所在月的天数_PHP教程
  3. HiveSQL中复杂数据类型操作
  4. MATLAB 线型 颜色 和 标记点组合使用
  5. [luogu4128][shoi2006]有色图
  6. cocos2dX 之数据存储
  7. Linux文件系统IO:直接IO原理与实现:缓存I/O、直接I/O
  8. Codeforces Round #750 (Div. 2)
  9. SnippetsLab:让代码信手拈来
  10. 婚礼一条龙服务成为新亮点
  11. 超详细的QSS样式表入门Demo
  12. 【转载】标准电阻阻值表及说明
  13. 硬件加密芯片介绍 及 加密芯片选择(加密IC) 加密芯片原理
  14. 多日之苦终得救:“威金”专杀工具发布(转)
  15. 介绍一下Emily----大一
  16. android N 移除 webview
  17. 学计算机的用双核CPU够吗,电脑cpu核数越多越好吗
  18. 作为一个前端开发工程师,你会怼人吗?
  19. RPC 就好像是谈一场异地恋
  20. 基于C#弹幕类射击游戏的实现——(五)主场景

热门文章

  1. 全国一等奖,他的学习之路。
  2. linux等陆不上ftp,vsftp连接不上解决方法
  3. android getwindow 在fragment不能使用,Android Fragment 布局使用 fitsSystemWindows = true 无效解决方案...
  4. 过程计算机控制综合课程设计,自动化10本 12升《计算机控制综合课程设计》任务书...
  5. 浅析NTFS 文件系统数据流安全问题
  6. 高中经历——高考专业被调剂毁了童年梦想
  7. python之路---03 整型 bool 字符串 for循环
  8. mybatis:延迟加载时不要在get/set方法上面添加final关键字(原创)
  9. windows64下安装MySQLdb连接数据库
  10. 【uva1380 - 一个调度问题】思路题+树形dp