Jack Huang's Blog


  • 首页

  • 标签

  • 归档

  • 搜索

FlightGear的Nasal脚本语言学习笔记

发表于 2021-03-30 | 更新于 2021-04-17

Nasal是FlightGear内建的脚本语言。 它最初是由安迪·罗斯(Andy Ross)为个人项目编写和开发的,于2003年11月被集成到FlightGear中,并且从那时起一直在不断地开发,改进和完善。 随着时间的流逝,它可能已成为FlightGear的最强大功能,并已用于创建各种各样的系统,从野火到控制显示单元。

在FlightGear中,Nasal支持读取和写入内部属性,通过扩展功能访问内部数据,创建GUI对话框等等。注意到Nasal是一种与JavaScript语法类似的脚本语言,但是它能够与FlightGear之间进行双向交互,实现非常强大的功能,这主要是通过CppBind实现的。

创建可点击的面板

FlightGear中创建可点击的面板有两种方法:

  • 热点区域:在某个位置创建可点击表面
  • 拾取:使一整个对象可以被点击

可点击面板的测试

使用“Ctrl+C”可显示所有可点击的面板对象。

属性浏览器

属性树是FlightGear的神经系统,连接着FlightGear的各个子系统,是各个子系统之间交互的桥梁。因此,需要属性浏览器窗口查看各个属性的变化。打开属性浏览器的方式有两种:

  • 通过按键 Ctrl+/ 打开属性浏览器
  • 通过主菜单 Debug > Browse Internal Properties 打开属性浏览器

详细模式

在属性浏览器窗口中,通过按键 Ctrl+. 可用来切换属性浏览器的详细模式(Verbose mode)。在详细模式下,可获得属性的额外信息,例如属性的类型、属性上侦听器的数量等。

参考链接

  1. Nasal scripting language,by flightgear.
  2. Nasal library,by flightgear.
  3. Bindings,by flightgear.
  4. Category:Howto,by flightgear.
  5. Howto:Animate models,by flightgear.
  6. Howto:Make a clickable panel,by flightgear.
  7. Howto:Creating 3D instruments,by flightgear.
  8. Property tree,by flightgear.
  9. PropertyList XML files,by flightgear.
  10. Property browser,by flightgear.
  11. Effect Framework,by flightgear.
  12. Canvas EFIS Framework,by flightgear.
  13. Nasal/CppBind,by flightgear.
  14. Howto:Extend Nasal,by flightgear.
  15. Canvas ND Framework,by flightgear.

Word文档压缩方法

发表于 2021-03-30

编写完一个大型Word文档之后,发现文档大小远远超过预期。那么如何压缩word文档,使其满足我们的要求呢?

首先要了解大型word文档”虚胖”的原因,然后我们才能针对性性的压缩。大型word文档”虚胖”的原因具体如下:

  1. 文档中有大量图片
  2. 文档中有Visio图、公式
  3. 文档中有大量交叉引用
  4. 文档在编辑过程中保存了大量无关内容

针对原因1,解决方案是保存文档时设置压缩图片的选项为电子邮件”96ppi”。
针对原因2和原因3,解决方案是全选word文档,使用快捷键“ctrl+shift+f9”,将会去除引用,将Visio图和公式转换成图片。
针对原因4,解决方案是将word文档内容全选,复制到新的word文档。

参考链接

  1. word中VISIO图批量转为图片格式,by baidu.

数据流分析

发表于 2021-03-29

数据流分析 是一种用于收集计算机程序在不同点计算的值的信息的技术。

基本原理

数据流分析试图获得程序中每一点的特定信息。通常,在基本块的界限内就可以获得这些信息,因为很容易计算基本块中的信息。在前向流分析(forward flow analysis)中,一个块的结束状态是这个块起始状态的一个函数。函数由块内的语句的影响信息组成。一个块的开始状态是它的前驱的结束状态的函数。这就产生了一系列的数据流方程:

对于每一个块$b:$

$$ out_b = trans_{b}(in_b) $$
$$ in_b = join_{p \in pred_b}(out_p) $$

在这里,$trans_b$ 是块 $b$ 的 转移函数。它作用于入口状态$in_b$,并产生出口状态$out_b$。连接运算符 $join$ 将块 $b$ 的前驱节点 $p \in pred_b$ 的出口状态联合起来,产生入口状态 $b$。

在求解这一系列方程之后,块的入口和出口状态可以被用来获得程序在块内的属性。每条语句的转移函数可以被分别的用于获得在一个基本块内的某一点的信息。

参考链接

  1. 数据流分析,by wikipedia.

OSG学习笔记

发表于 2021-03-17 | 更新于 2022-12-11

OpenSceneGraph是一个开源3D图形应用程序编程接口,应用程序开发人员在诸如视觉模拟,计算机游戏,虚拟现实,科学可视化和建模等领域中使用该接口。

OSG 编译运行问题

OSG指出GL版本问题

CMake设置了GL3的开关,结果编译完后,好多例子无法正常运行。

原因:GL3对GL1、GL2不兼容

解决办法:去掉GL3选项

GL3(3.3),属于OpenGL的高版本驱动所支持的接口,需要完全使用可编程管线.

不开启GL3设置,其实也可以使用GL3的特性,论坛作者提到osg使用了兼容模式,编写OpenGL3.3以上着色器,配置兼容模式即可使用。

获取OSG指出的OpengGL版本,可参考How to obtain OpenGL version from within OpenSceneGraph。

OSG运行的坑:WINGDIAPI(GL.h)

在VS运行OSG程序时,要将预处理器设置为WIN32,否则GL.h头文件会报错。

osg键盘事件不响应的解决方法

1、换输入法为英文状态
2、(若1不行)换键盘为美式键盘

osgQt键盘事件不响应的解决方法

请参考osg嵌入Qt后,键盘响应以及程序退出崩溃问题解决。

OSG开发技巧

OpenGL中的功能与OSG对应功能

OSG 调试

打开cmd,输入如下命令:

1
2
SET OSG_NOTIFY_LEVEL=DEBUG
osgviewer cow.osgt

坐标系

OSG中采用的X轴正方向向右,Y轴正方向朝里,Z轴正方向向上。

OpenGL中采用的X轴正方向向右,Y轴正方向朝上,Z轴正方向朝外。

OSG与OpenGL坐标系

图1 OSG与OpenGL坐标系

显示模型坐标轴

使用如下命令显示模型坐标轴:

1
osgviewer cessna.osgt axes.osgt

OSG相机默认视角

osg::Camare的默认姿态:

  • 位置在 0,0,0
  • 姿态是:向下看(Z轴负向 0,0,-1)
  • 头向前(Y轴正向 0,1,0,也就是说相机是正着的)

OSG渲染状态管理

OpenGL是一个状态机,在OpenGL中如果设置一种状态(比如设置当前的绘制颜色:glColor,那么实际上是设置了OpenGL颜色绘制状态为某种颜色,如果后续没有调用glColor去修改颜色,那么之后所有绘制的对象都使用之前设置的颜色。),在没有修改它的时候,该状态就会一直保持。在OpenGL使用中的状态有以下两种方式:

  • 仅仅通过glEnable和glDisable开启和关闭状态
    这里面也有两种不同的取值:

    • 1.1 不涉及和其他状态相关,比如GL_DITHER、GL_POINT_SPRITE等;
    • 1.2 涉及和其他状态的联动,比如GL_ALPHA_TEST、GL_BLEND等,需要使用glEnable开启状态
  • 和1.2种的某种状态对应,但是需要设置状态的值(比如glAlphaFunc、glBlendFunc)

在OSG中对OpenGL的状态进行了封装,在OSG中称第一种情形为Mode(模式),称第二种情况为Attribute(属性),使用osg::StateAttribute来封装OpenGL的状态。

在OSG中涉及到状态管理的类有3个,分别是 osg::State, osg::StateSet, osg::StateAttribute。

OSG渲染

OSG可以使得绘制遍历,也就是将数据传送给OpenGL管线,在一个单独的线程中运行。他必须与每一帧中的其他绘制遍历相同步,但是绘制遍历的部分可以与来自下一帧的更新遍历相重叠,从而改善渲染效率并减少帧延迟。这意味着osgViewer::Viewer的frame()方法会在绘制工作依然处于活动状态时返回。那么更新回调中的数据变化也许会与未完成的渲染操作相冲突,从而导致不可预期的行为,甚至崩溃。

OSG在setDataVariance()方法中提供了解决方法,该方法属于osg::Object类,这是所有场景对象的基类。这可以设置为三个枚举值之一:UNSPECIFIED(默认),STATIC与DYNAMIC。场景图中的DYNAMIC对象必须在绘制遍历的开始进行处理。也就是,渲染后端应确保所有节点以及被指定为DYNAMIC的场景对象在下一帧的更新与裁剪遍历开始之前已完成绘制。然而,STATIC对象,在更新与绘制过程中会保持不变,从而会被稍后渲染且不会阻塞帧速率。

Object::DataVariance

要设置一个Object 对象的数据变量,可以调用setDataVariance()并设置输入参数为Object::DataVariance 枚举量。初始状态下,变度的值是UNSPECIFIED。用户程序可以将数据变度更改为STATIC 或者DYNAMIC。OSG 将确保绘制遍历在所有的DYNAMIC 节点和数据处理完成后才会返回。

场景数据动态更新的核心就是设置数据变度属性DataVariance,它决定了OSG在多线程渲染的过程中的执行策略:只有所有DYNAMIC属性的对象被渲染完毕之后,OSG才会开始执行下一帧的用户更新操作;这样有效地可以避免数据的过快更新造成当前的渲染动作出错,以致系统崩溃。

OSG绘制几何体

默认情况下,OSG使用顶点数组与显示列表来管理与渲染几何。然而,这会依据不同的数据类型与渲染策略而发生变化。

OSG矩阵相乘

OSG使用行向量与行为主矩阵在右侧原则(right-hand rule)下来执行前相乘(vectormatrix)。然而,OpenGL使用列为主矩阵与列向量来执行后相乘(matrixvector)。

OSG节点的增加,删除,隐藏和开关

osg::Switch 从osg::Group继承而来,是一个管理类,除了可以当成osg::Group使用外,它还可以控制子类的显示与隐藏, 这种隐藏是不耗费内存的,与 SetNodeMask对比有明显的优势,SetNodeMask只是隐藏了结点,但结点仍被绘制。

OSG纹理

osg::Texture2D类要求纹理坐标正规化为[0,1],否则他会使用纹理封装来处理多余的部分。他会检测纹理的维度在尺寸上是否全部为2的幂次,例如64x64或256x512,并且在默认情况下会使用OpenGL的gluScaleImage()函数在内部缩放不是2的幂次的图像,这对于读取任意的图像非常方便,但是需要更多的系统时间并会占用较大的图形内存尺寸。

OSG状态

正常情况下,节点的状态集将会影响当前节点及其子节点。例如,节点transformation1的osg::PolygonMode属性将会使得其所有子节点显示为轮廓图。然而,子节点的状态集可以覆盖父节点的状态集,也就是,渲染状态将会由父节点继承,除非子节点改变这一行为。

非正常情况下,父节点可以使用osg::StateAttribute::OVERRIDE标记,以强制其所有的子节点继承其属性或模式。子节点也可以使用osg::StateAttribute::PROTECTED标记,来改变其继承性,从而会导致不同的结果。

OSG Viewer

osgViewer::View类是osgViewer::Viewer类的超类。他接受设置根节点作为场景数据,并添加相机操作器与事件处理器来使用用户事件。osgViewer::View与osgViewer::Viewer之间的区别在于前者不能被直接用作单个查看器,也就是,他没有run()或frame()方法。

1
2
osgViewer::CompositeViewer multiviewer;
multiviewer.addView( view );

OSG事件响应

可参考osg demo12 响应鼠标事件

OSG多个着色器

当OSG的父节点附加一个着色器,子节点附加另一个着色器会发生什么事情?

答案是子节点渲染时,其自身着色器会生效,而不会运行父节点着色器。

3D模型转换

osgconv是一种非常有用的的工具来读取标准的3D格式,如OpenFlight,3DS,Alias Wavefront
(OBJ) etc,并且可以将它们转换为一种OSG所支持的格式,如OSG中的ASCII格式的.osg,二进制格式的.ive。
在程序运行的默认情况下,优化导入的场景图,将形成的这样结果:场景图读取的数据量将会更少且速度会更
快。尤其值得指出的是,.ive格式的的文件,快速装载数据的能力使它非常适合数据页和大型的数据库。

使用方法如下:

1
2
osgconv cow.obj cow.ive
osgconv --compressed cow.obj cow.ive

参考链接

  1. OpenSceneGraph,by wikipedia.
  2. OSG渲染引擎架构——整体认识,by wikipedia.
  3. OSG渲染状态管理,by csxiaoshui.
  4. OSG中的DataVariance,by codetd.
  5. OpenGL中的功能与OSG对应功能,by 南水之源.
  6. OpenGL——颜色混合 glBlendFunc函数,by Timidkid.
  7. OpenGL Display List学习,by Antplay.
  8. osg学习(五十二)加载的牛模型cow.osg没有纹理 黑色,by hankern.
  9. OSG仿真案例(4)——创建烟雾粒子效果,by rexinx.
  10. OSG中的DataVariance,by sunflower_cs.
  11. OSG渲染状态管理,by csxiaoshui.
  12. OpenSceneGraph plugin not included in Conan?,by stackoverflow.
  13. osg示例解析之osgparticle(1) ,by csxiaoshui.
  14. 欢迎来到OpenGL的世界,by learnopengl.
  15. OSG调试经验,by 醉逍遥_祥.
  16. OSG使用GLSL各个版本例子,by 封狼居胥_COU.
  17. OSG运行的坑:WINGDIAPI(GL.h),by lessssssss.
  18. OSG 3.6.3 版本编译一些问题,by longlongway2012.
  19. 01-01-osg下GL3环境搭建,by Longlongwaytogo.
  20. OSG报警特效学习总结 ,by JosephDcc.
  21. OSG 绘制Geometry使用,by jdq0603.
  22. OSG三维渲染引擎–OSG渲染引擎中坐标系,by 苏黎.
  23. How to obtain OpenGL version from within OpenSceneGraph,by Victoria Rudakova.
  24. OSG运行的坑:WINGDIAPI(GL.h),by lessssssss.
  25. OSG可绘制体Drawable,by csxiaoshui.
  26. OSG 渲染剖析 之 Geometry 的 VBO生成,by Night_Aurora.
  27. osg绘制四边形,by mob60475700473b.
  28. osg setRenderBinDetails 使用,by longlongway2012.
  29. ogs节点的增加,删除,隐藏和开关,by 先锋小牛.
  30. osg demo12 响应鼠标事件,by analyst_yuci.
  31. [osg-users] Multiple Shaders,by J. Brent Spears.
  32. OSG 中默认的 Shader,by 洛克人杰洛.
  33. osgconv使用指南(转),by 3D入魔.
  34. osg嵌入Qt后,键盘响应以及程序退出崩溃问题解决,by 程序开发园.
  35. OSG相机,by wb175208.

OpenGL学习笔记

发表于 2021-03-13 | 更新于 2022-11-27

OpenGL(英语:Open Graphics Library,译名:开放图形库或者“开放式图形库”)是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口(API)。这个接口由近350个不同的函数调用组成,用来从简单的图形比特绘制复杂的三维景象。而另一种程序接口系统是仅用于Microsoft Windows上的Direct3D。OpenGL常用于CAD、虚拟现实、科学可视化程序和电子游戏开发。

核心模式与立即渲染模式

早期的OpenGL使用立即渲染模式(Immediate mode,也就是固定渲染管线),这个模式下绘制图形很方便。OpenGL的大多数功能都被库隐藏起来,开发者很少有控制OpenGL如何进行计算的自由。而开发者迫切希望能有更多的灵活性。随着时间推移,规范越来越灵活,开发者对绘图细节有了更多的掌控。立即渲染模式确实容易使用和理解,但是效率太低。因此从OpenGL3.2开始,规范文档开始废弃立即渲染模式,并鼓励开发者在OpenGL的核心模式(Core-profile)下进行开发,这个分支的规范完全移除了旧的特性。

当使用OpenGL的核心模式时,OpenGL迫使我们使用现代的函数。当我们试图使用一个已废弃的函数时,OpenGL会抛出一个错误并终止绘图。现代函数的优势是更高的灵活性和效率,然而也更难于学习。立即渲染模式从OpenGL实际运作中抽象掉了很多细节,因此它在易于学习的同时,也很难让人去把握OpenGL具体是如何运作的。现代函数要求使用者真正理解OpenGL和图形编程,它有一些难度,然而提供了更多的灵活性,更高的效率,更重要的是可以更深入的理解图形编程。

着色器

着色器(Shader)是运行在GPU上的小程序。这些小程序为图形渲染管线的某个特定部分而运行。从基本意义上来说,着色器只是一种把输入转化为输出的程序。着色器也是一种非常独立的程序,因为它们之间不能相互通信;它们之间唯一的沟通只有通过输入和输出。

GPU渲染管线

图1 GPU渲染管线

着色器分类

每个着色器使用这两个关键字设定输入和输出,只要一个输出变量与下一个着色器阶段的输入匹配,它就会传递下去。但在顶点和片段着色器中会有点不同。

顶点着色器

用来描述顶点属性(如位置、颜色等)的程序。顶点是二维或者三维空间中的一个点,比如二维或者三维图形的端点或交点。

1
2
3
4
5
6
//顶点着色器程序
var VSHADER_SCOURCE =
'void main() {\n' +
' gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n' +
' gl_PointSize = 5.0;\n'+
'}\n';

细分着色器

曲面细分着色器包含细分控制着色器 (Tessellation Control Shader / Hull Shader) 和细分计算着色器 (Tessellation Evaluation Shader / Domain Shader) 。在这个阶段可以操作三角形 (tri patch) 、四边形 (quad patch) 或者线段 (isoline) 等 patch 。

低精度网格、置换贴图和法线贴图等,在曲面细分着色器 (Tessellation Shader) 中,使用合适的细分算法,可以生成高精度网格,从而提高游戏画面的细节。

几何着色器

几何着色器(Geometry Shader)是由第四代显卡着色器架构 Shader Model 4 正式引入的第三个着色器,属于渲染管线的一个可选阶段,位于曲面细分(Tessellation)和光栅化(Rasterization)之间。顶点着色器以顶点数据作为输入数据,而几何着色器则以完整的图元(Primitive)作为输入数据。例如,以三角形的三个顶点作为输入,然后输出对应的图元。与顶点着色器不能销毁或创建顶点不同,几何着色器的主要亮点就是可以创建或销毁几何图元,此功能让GPU可以实现一些有趣的效果。例如,根据输入图元类型扩展为一个或更多其他类型的图元,或者不输出任何图元。需要注意的是,几何着色器的输出图元不一定和输入图元相同。几何着色器的一个拿手好戏就是将一个点扩展为一个四边形(即两个三角形)。

1
2
3
4
5
6
7
8
9
10
11
12
13
#version 330 core
layout (points) in;
layout (line_strip, max_vertices = 2) out;

void main() {
gl_Position = gl_in[0].gl_Position + vec4(-0.1, 0.0, 0.0, 0.0);
EmitVertex();

gl_Position = gl_in[0].gl_Position + vec4(0.1, 0.0, 0.0, 0.0);
EmitVertex();

EndPrimitive();
}

片元着色器

进行逐片元处理过程如光照的程序。片元可理解为像素。

1
2
3
4
5
//片元着色器程序
var FSHADER_SCOURCE =
'void main() {\n' +
' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
'}\n';

变量

attribute变量

attribute变量是只能在vertex shader中使用的变量。(它不能在fragment shader中声明attribute变量,也不能被fragment shader中使用)

一般用attribute变量来表示一些顶点的数据,如:顶点坐标,法线,纹理坐标,顶点颜色等。

uniform变量

Uniform变量简单理解就是一个GLSL shader中的全局常量,可以随意在任意shader(vertex shader, geometry shader, or fragment shader)访问,不同的shader中uniform是一起链接的,初始化之后,不能修改其值,否则会引起编译错误。

varying变量

varying变量是vertex和fragment shader之间做数据传递用的。一般vertex shader修改varying变量的值,然后fragment shader使用该varying变量的值。因此varying变量在vertex和fragment shader二者之间的声明必须是一致的。application不能使用此变量。

坐标系

OSG中采用的X轴正方向向右,Y轴正方向朝里,Z轴正方向向上。

OpenGL中采用的X轴正方向向右,Y轴正方向朝上,Z轴正方向朝外。

OSG与OpenGL坐标系

图2 OSG与OpenGL坐标系

参考链接

  1. OpenGL,by wikipedia.
  2. LearnOpenGL,by Joey de Vries.
  3. 着色器,by wikipedia.
  4. 几何着色器,by 学无止境.
  5. 曲面细分着色器 1 简介,by MultivacX.
  6. Rendering Pipeline Overview,by opengl homepage.
  7. OpenGL 4.0的Tessellation Shader(细分曲面着色器),by zenny_chen.
  8. OpenGL基础 - 统一变量Uniform,by 靖空间.
  9. 点到平面的距离公式,by 翰墨小生.
  10. OSG 碰撞检测之多面体求交器代码解读(PloytopeIntersector),by 风一样消逝的青春.
  11. OpenGL(八) 显示列表,by -牧野-.
  12. OSG三维渲染引擎–OSG渲染引擎中坐标系,by 苏黎.
  13. OpenGL学习笔记(12)基本光照,by Clingingboy.
  14. GLSL 三种变量类型(uniform,attribute和varying)理解,by wo不懂.
  15. OpenGL之glPolygonMode函数的用法,by 草上爬_.

doxygen编译安装与文档生成

发表于 2021-03-09 | 更新于 2021-03-10

Doxygen是一个适用于C++、C、Java、Objective-C、Python、IDL(CORBA和Microsoft flavors)、Fortran、VHDL、PHP、C#和D语言的文档生成器。它可以在大多数类Unix操作系统、macOS以及Microsoft Windows上运行。由于该文档是直接写在源代码中的,因此比较容易保持更新。Doxygen可以交叉引用和源代码,使文件的读者可以很容易地引用实际的源代码。

编译安装

Windows平台

Windows平台编译安装doxygen请参考链接Compiling from source on Windows。

文档生成

请参考Doxygen快速入门。

参考链接

  1. Compiling from source on Windows,by doxygen.
  2. Doxygen,by wikipedia.
  3. Doxygen文档生成工具教程,by chend0316.
  4. Doxygen快速入门,by 路明.
  5. User:Callahanp/Flightgear and Simgear Code/Doxygen,by flightgear wiki.

源代码分析的方法

发表于 2021-03-01 | 更新于 2021-03-02

源码分析的目的是讲解代码要解决什么问题、代码如何解决问题的以及代码为什么要这么解决问题。

源码分析的入手点是软件而不是源代码。软件( Software )是一个宽泛的概念,包括应用程序、工具箱和框架等等。软件可以说是由代码组成的,那么我们强调入手点是软件而不是源代码的原因是什么呢?

源码分析从源代码入手,就容易落入具体实现的窠臼当中;而代码构成的软件整体,有其被创造的背景、要解决的问题、演进过程中面临的困难和决策,以及最终所为用户认知的形态。源码分析从软件整体入手,才能够脱离技术人员对技术本身的痴迷的影响,从务实的角度讲解代码要解决什么问题、代码如何解决问题的以及代码为什么要这么解决问题。

《深入理解 Spring MVC 源代码》的讲解按照目录分成三个部分。

第一部分主要从使用的角度入手,由开发者最熟悉的功能切入,讲解了基本组件包括控制器、模型和视图在抽象层面上是如何被支持的。在此基础上对 MVC 模型最承担逻辑的控制器展开了详细的介绍,尤其是平时容易被终端开发者忽略的请求是如何进入框架和流程以及返回值是如何交付给请求方的。最后用简短的篇幅简略地介绍了 WebFlux 的发展趋势和一些常见的配置项。

第二部分接着从源码切入,首先介绍了源码阅读的一些技术技巧,再对 Spring MVC 框架的启动、MVC 框架请求分发的核心 DispatcherServlet 类的功能、RequestMapping 的查找原理和请求处理方法的执行过程一一进行具体的介绍。每个细节部分也是按照这种主题加解决方法的模式,先抛出一个问题,抽象地讨论解决思路,再结合代码讲解关键细节,最后简略地做完整性补充和扩展讨论。

第三部分可以单独拆开来,是在完成了源码分析以后以一个常见的基于 Spring MVC 实现微信公众号快速开发框架的例子来介绍 Spring MVC 的实用过程。通过分析时下热点的具体实例,可以让读者清晰的看到前面所讲的知识点在实践中到底是怎么被运用的,哪些一定会涉及且常常会被实现考虑在内,哪些是在哪种特定情况下会涉及的,以及哪些是平常看不到的或者不需要重点钻研的。

参考链接

  1. 源码分析怎么做?, by tison.
  2. 程序员阅读源码是一种什么心态?源码对编程意义何在?如何才能更好阅读代码?,by zhihu.

JavaScript从字符串中创建函数的方法

发表于 2021-02-26

以下链接中提供了四种JavaScript从字符串中创建函数的方法,可以学习以下。

Is there a way to create a function from a string with javascript?

参考链接

  1. Is there a way to create a function from a string with javascript?,by phnah.

QT核心机制与原理

发表于 2021-02-06 | 更新于 2023-08-17

要想学到QT的精髓,必须对QT的核心机制信号与槽、元对象系统、事件模型有充分的理解。

信号与槽

信号和槽是一种高级接口,它们被应用于对象之间的通信,它们是Qt 的核心特性,也是Qt不同于其它同类工具包的重要地方之一。

信号(signal)

当对象的状态发生改变时,信号被某一个对象发射( emit)。只有定义过这个信号的类或者其派生类能够发射这个信号。当一个信号被发射时,与其相关联的槽将被执行,就象一个正常的函数调用一样。信号-槽机制独立于任何GUI 事件循环。只有当所有的槽正确返回以后,发射函数(emit)才返回。

槽(slot)

槽是普通的C++成员函数,可以被正常调用,不同之处是它们可以与信号( signal)相关联。当与其关联的信号被发射时,这个槽就会被调用。槽可以有参数,但槽的参数不能有缺省值。

信号与槽的关联

槽和普通的C++成员函数几乎是一样的-可以是虚函数;可以被重载;可以是共有的、 保护的或是私有的,并且也可以被其它C++成员函数直接调用;还有,它们的参数可以是任意类型。唯一不同的是:槽还可以和信号连接在一起,在这种情况下,每当发射这个信号的时候,就会自动调用这个槽。

connect()语句看起来会是如下的样子:

1
connect(sender,SIGNAL(signal),receiver,SLOT(slot));

这里的sender 和receiver 是指向QObject 的指针,signal 和slot 是不带参数的函数名。实际上,SIGNAL()宏和SLOT()会把它们的参数转换成相应的字符串。

从QObject 或其子类(例如Qwidget)派生的类都能够使用信号和槽机制。这种机制本身是在QObject 中实现的,并不只局限于图形用户界面编程中:当对象的状态得到改变时, 它可以某种方式将信号发射(emit)出去,但它并不了解是谁在接收这个信号。

元对象系统

Qt 的元对象系统是一个基于标准C++的扩展,能够使C++更好的适应真正的组件GUI 编程。它为Qt 提供了支持对象间通信的信号与槽机制、实时类型信息和动态属性系统等方面的功能。

元对象系统在Qt 中主要有以下三部分构成:QObject 类、Q_OBJECT 宏和元对象编译器moc。

元对象系统机制

Qt 的主要成就之一是使用了一种机制对C++进行了扩展,并且使用这种机制创建了独立的软件组件。这些组件可以绑定在一起,但任何一个组件对于它所要连接的组件的情况事先都不了解。

这种机制称为元对象系统(meta-object system),它提供了关键的两项技术:信号-槽以及内省(introspection)。内省功能对于实现信号和槽是必需的,并且允许应用程序的开发人员在运行时获得有关QObject 子类的“元信息”(meta-information),包括一个含有对象的类名以及它所支持的信号和槽的列表。这一机制也支持属性(广泛用于Qt 设计师中)和文本翻译(用于国际化),并且它也为QtScirpt 模块奠定了基础。

标准C++没有对Qt 的元对象系统所需要的动态元信息提供支持。Qt 通过提供一个独立的moc 工具解决了这个问题,moc 解析Q_OBJECT 类的定义并且通过C++函数提供可供使用的信息。由于moc 使用纯C++来实现它的所有功能,所以Qt 的元对象系统可以在任意C++ 编译器上工作。

元对象工具(moc)

Qt 的信号和槽机制是采用标准C++ 来实现的。该实现使用C++ 预处理器和Qt 所包括的moc(元对象编译器)。元对象编译器读取应用程序的头文件,并生成必要的代码,以支持信号和槽机制。

事件模型

应用程序对象将系统消息接收为Qt 事件。应用程序可以按照不同的粒度对事件加以监控、过滤并做出响应。

在Qt 中,事件是指从QEvent 继承的对象。Qt 将事件发送给每个QObject 对象,这样对象便可对事件做出响应。也就是说, Qt 的事件处理机制主要是基于QEvent 类来实现的,QEvent 类是其他事件类的基类。当一个事件产生时, Qt 就会构造一个QEvent 子类的实例来表述该事件,然后将该事件发送到相应的对象上进行处理。

Qt 的主事件循环能够从事件队列中获取本地窗口系统事件,然后判断事件类型,并将事件分发给特定的接收对象。主事件循环通过调用QCoreApplication::exec() 启动, 随着QCoreApplication::exit()结束,本地的事件循环可用利用QEventLoop 构建。作为事件分发器的QAbstractEventDispatcher 管理着Qt 的事件队列,事件分发器从窗口系统或其他事件源接收事件,然后将他们发送给QCoreApplication 或QApplication 的实例进行处理或继续分发。QAbstractEventDispatcher 为事件分发提供了良好的保护措施。

事件与信号的区别

(1) 使用场合和时机不同一般情况下,在“使用”窗口部件时,我们经常需要使用信号,并且会遵循信号与槽的机制;而在“实现”窗口部件时,我们就不得不考虑如何处理事件了。举个例子,当使用QPushButton 时,我们对于它的clicked()信号往往更为关注,而很少关心促成发射该信号的底层的鼠标或者键盘事件。但是,如果要实现一个类似于QPushButton 的类,我们就需要编写一定的处理鼠标和键盘事件的代码,而且在必要的时候,仍然需要发射和接收clicked()信号。

(2)使用的机制和原理不同

事件类似于Windows 里的消息,它的发出者一般是窗口系统。相对信号和槽机制,它比较“底层”,它同时支持异步和同步的通信机制,一个事件产生时将被放到事件队列里,然后我们就可以继续执行该事件“后面”的代码。事件的机制是非阻塞的。

信号和槽机制相对而言比较“高层”,它的发出者一般是对象。从本质上看,它类似于传统的回调机制,是不支持异步调用的。

(3) 信号与槽在多线程时支持异步调用

在单线程应用时,你可以把信号与槽看成是一种对象间的同步通信机制,这是因为在这种情况下,信号的释放过程是阻塞的,一定要等到槽函数返回后这个过程才结束,也就是不支持异步调用。

参考链接

  1. 第13 章Qt 核心机制与原理,by wizardforcel.
  2. 如何才能学到Qt的精髓?,by zhihu.
  3. Qt中资源文件的使用及意义,by Stephan_zry.
  4. Qt:Qt资源系统,by qt技术开发老杰.

jsplumb学习笔记

发表于 2021-02-02 | 更新于 2021-11-27

jsPlumb 是一个用于在 html 元素之间生成连接线的 javascript 库。类似的工具还有 jointjs、GoJS、mxGraph 等。下面简单介绍jsplumb的相关内容。

基本概念

  • Souce 源节点
  • Target 目标节点
  • Anchor 锚点
  • Endpoint 端点
  • Connector 连接
  • Overlay 连接装饰

初始化

1
2
3
4
5
jsPlumb.ready(function() {
...
// your jsPlumb related init code goes here
...
});

创建实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var firstInstance = jsPlumb.getInstance();

firstInstance.importDefaults({
Connector : [ "Bezier", { curviness: 150 } ],
Anchors : [ "TopCenter", "BottomCenter" ]
});

firstInstance.connect({
source:"element1",
target:"element2",
scope:"someScope"
});

var secondInstance = jsPlumb.getInstance({
PaintStyle:{
strokeWidth:6,
stroke:"#567567",
outlineStroke:"black",
outlineWidth:1
},
Connector:[ "Bezier", { curviness: 30 } ],
Endpoint:[ "Dot", { radius:5 } ],
EndpointStyle : { fill: "#567567" },
Anchor : [ 0.5, 0.5, 1, 1 ]
});

secondInstance.connect({
source:"element4",
target:"element3",
scope:"someScope"
});

参考链接

  1. jsplumb 中文基础教程,by wangduanduan.
  2. 记一次绘图框架技术选型: jsPlumb VS mxGraph,by yejinzhan.
  3. jsPlumb Community Edition,by jsplumbtoolkit.
  4. jsPlumb 文档翻译,by shawchen08.
  5. Vue.js 技术揭秘,by huangyi.
  6. jsPlumb Connection event is triggering more than once,by stackflow.
上一页1…232425…52下一页

Jack Huang

519 日志
66 标签
© 2025 Jack Huang
由 Hexo 强力驱动
|
主题 — NexT.Muse