Jack Huang's Blog


  • 首页

  • 标签

  • 归档

  • 搜索

FlightGear多屏多视口设置方法

发表于 2021-06-03 | 更新于 2021-06-23

在玩FlightGear的过程中,可能需要将视景分角度投影到不同显示器上,或者在一个显示器窗口上投影不同角度的视景。下面记录该需求实现方法。

投影到不同显示器

在FGDATA文件夹根目录下创建camera-views.xml文件夹,写入如下内容:

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<?xml version="1.0"?>
<PropertyList>
<camera-group>
<window>
<name type="string">Front</name>
<host-name type="string"></host-name>
<display>0</display>
<screen>0</screen>
<fullscreen type = "bool">false</fullscreen>
<decoration type = "bool">false</decoration>
<x>0</x>
<y>0</y>
<width>1920</width>
<height>1080</height>
</window>

<window>
<name type="string">Right</name>
<host-name type="string"></host-name>
<display>0</display>
<screen>1</screen>
<fullscreen type = "bool">false</fullscreen>
<decoration type = "bool">false</decoration>
<x>0</x>
<y>0</y>
<width>1280</width>
<height>720</height>
</window>

<gui>
<window>
<name type="string">Front</name>
</window>
</gui>

<camera>
<name type="string">Front</name>
<window>
<name>Front</name>
</window>

<view>
<heading-deg type = "double">0.0</heading-deg>
<roll-deg type = "double">0.0</roll-deg>
<pitch-deg type = "double">0.0</pitch-deg>
</view>

<viewport>
<x>0</x>
<y>0</y>
<width>1920</width>
<height>1080</height>
</viewport>

</camera>
<camera>
<name type="string">Right</name>
<window>
<name>Right</name>
</window>

<view>
<heading-deg type = "double">-45.0</heading-deg>
<roll-deg type = "double">0.0</roll-deg>
<pitch-deg type = "double">0.0</pitch-deg>
</view>

<viewport>
<x>0</x>
<y>0</y>
<width>1280</width>
<height>720</height>
</viewport>

</camera>
</camera-group>
</PropertyList>

在FGDATA文件夹根目录下找到defaults.xml配置文件,修改如下配置内容,加入camera-views.xml配置文件。

1
2
<rendering include="camera-views.xml">
</rendering>

投影到窗口不同地方

在FGDATA文件夹根目录下创建camera-views.xml文件夹,写入如下内容:

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
<?xml version="1.0"?>
<PropertyList>
<camera-group>
<window>
<name type="string">Front</name>
<host-name type="string"></host-name>
<display>0</display>
<screen>0</screen>
<fullscreen type = "bool">false</fullscreen>
<decoration type = "bool">false</decoration>
<x>0</x>
<y>0</y>
<width>1920</width>
<height>1080</height>
</window>

<gui>
<window>
<name type="string">Front</name>
</window>
</gui>

<camera>
<name type="string">Main</name>
<window>
<name>Front</name>
</window>

<view>
<heading-deg type = "double">0.0</heading-deg>
<roll-deg type = "double">0.0</roll-deg>
<pitch-deg type = "double">0.0</pitch-deg>
</view>

<viewport>
<x>0</x>
<y>0</y>
<width>1920</width>
<height>1080</height>
</viewport>

</camera>
<camera>
<name type="string">Left-Down</name>
<window>
<name>Front</name>
</window>

<view>
<heading-deg type = "double">0.0</heading-deg>
<roll-deg type = "double">0.0</roll-deg>
<pitch-deg type = "double">0.0</pitch-deg>
</view>

<viewport>
<x>0</x>
<y>0</y>
<width>320</width>
<height>180</height>
</viewport>

</camera>
<camera>
<name type="string">Right-Down</name>
<window>
<name>Front</name>
</window>

<view>
<heading-deg type = "double">0.0</heading-deg>
<roll-deg type = "double">0.0</roll-deg>
<pitch-deg type = "double">0.0</pitch-deg>
</view>

<viewport>
<x>1600</x>
<y>0</y>
<width>320</width>
<height>180</height>
</viewport>

</camera>
<camera>
<name type="string">Right-Up</name>
<window>
<name>Front</name>
</window>

<view>
<heading-deg type = "double">0.0</heading-deg>
<roll-deg type = "double">0.0</roll-deg>
<pitch-deg type = "double">0.0</pitch-deg>
</view>

<viewport>
<x>1600</x>
<y>900</y>
<width>320</width>
<height>180</height>
</viewport>

</camera>
</camera-group>
</PropertyList>

在FGDATA文件夹根目录下找到defaults.xml配置文件,修改如下配置内容,加入camera-views.xml配置文件。

1
2
<rendering include="camera-views.xml">
</rendering>

参考链接

  1. Multi-Display setup,by flightgear.
  2. Howto:Configure camera view windows,by flightgear.

软件签名验证的方法

发表于 2021-05-26

GNU Privacy Guard(GnuPG或GPG)是一个密码学软件,用于加密、签名通信内容及管理非对称密码学的密钥。GnuPG是自由软件,遵循IETF订定的OpenPGP技术标准设计,并与PGP保持兼容。

安装 GnuPG

对于 Windows 的用户:

如果您使用 Windows, 下载 Gpg4win并运行其安装包。

为了验证签名,您需要在 Windows 命令行(“cmd.exe”)中输入一些命令。

对于 macOS 的用户:

如果您正在使用 macOS,您可以安装 GPGTools。

为了验证签名,您需要在(“应用程序”下的)终端中输入一些命令

对于 GNU/Linux 的用户:

如果你使用 GNU/Linux,那么可能在你的系统中已经安装了 GnuPG,因为大多数 Linux 发行版都预装了它。

使用GnuPG

生成密钥对

GnuPG使用非对称密码体制算法生成一对密钥对,其中公钥可公开,私钥必须保密。

1
gpg --gen-key

验证软件签名

验证下载文件的第一步是与任何提供文件下载的人建立信任。出于此,需要下载这个文件的公钥,并且验证公钥的拥有者是否是他或者她自称的。

在下载完文件拥有者的公钥后,使用 gpg 命令导入公钥到你的 keyring 中:

1
2
3
4
5
6
gpg --import signing-key.asc
gpg --fingerprint 3DBDC284
gpg --edit-key 3DBDC284
gpg --list-keys
gpg --verify openSUSE-Tumbleweed-DVD-x86_64-Snapshot20170529-Media.iso.sha256
gpg --verify file.ext.asc file.ext

参考链接

  1. GPG入门教程,by 阮一峰.
  2. 利用 GPG 签名验证文件的完整及可靠性,by Silearner.

Office使用技巧笔记

发表于 2021-05-19 | 更新于 2022-12-15

记录各类Office使用技巧,以备使用。

MathType批量修改公式字体和大小

Word中的公式自动编号

参考链接

  1. 怎样使公式与编号上下对齐?,by 碎碎思.
  2. Word 2016 撰写论文(1): 公式居中、编号右对齐,by TechArtisan6.
  3. MathType中如何批量修改公式字体和大小,by 有你.
  4. Microsoft Office Word 中的公式自动编号,by stardsd .

flypath3d使用方法简介

发表于 2021-05-17

做科研的小伙伴们在使用matlab绘制飞行器轨迹时,总是感叹大牛绘制的图美观大方,而自己绘制的图则简陋到了极点。但现在有了flypath3d,导师再也不用担心我的绘图了。

飞行器轨迹

图1 飞行器轨迹

flypath3d简介

flypath3d打包了一个免费的Matlab软件,用于导弹和空中目标轨迹的3D可视化,为计算机仿真提供了可视参考。 由于其多功能性和易用性,该软件可以帮助产生有吸引力的演示文稿,以用于各种科学或公共宣传目的。该软件可免费用于科学和教育用途。 您也可以出于任何目的修改和/或分发此软件。 但是,使用包装时,请记住引用该论文。

flypath3d安装

该包由使用“ package_setup”命令安装在Matlab环境中的几个M代码文件组成。 它提供了通过放置连续的对象来构造复杂的3D场景的功能,这些对象实际上在布局中起到了构建块的作用。

下载flypath3d软件包并将其解压缩到目标目录。 接下来执行配置脚本:

1
package_setup

这样,flypath3d就安装好了,可以开始使用它了。

参考链接

  1. flypath3d,by Witold Bużantowicz.

MongoDB学习笔记

发表于 2021-05-11 | 更新于 2023-02-11

MongoDB是一种NoSQL类型数据库,与关系型数据库相比,它具有很强的灵活性,无需类似Sequelize这样的ORM库,即可直接访问。例如,使用nodejs访问MongoDB:

1
2
3
4
5
6
7
8
const { MongoClient } = require("mongodb");
const db= await MongoClient.connect(appConfig.mongoUri);
var dbo = db.db(appConfig.mongodbName);
var actions = await dbo.collection("actions").find({"equipmentId":req.query.equipmentId}, {
"limit":parseInt(req.query.limit) || 25,
"skip":parseInt(req.query.offset)|| 0
}).toArray();
db.close()

尽管MongoDB很灵活,但在设计其数据模型时,为了确保数据组织的一致性,应遵循一下原则:

  • 一个文档就是一个实体对象,应精心设计
  • 文档中包含的任何对象,都对应实体

分页查询及排序

请参考以下代码:

1
2
3
4
var departments = await dbConnect.collection("departments").find({}, {
"limit":parseInt(req.query.limit) || 25,
"skip":parseInt(req.query.offset)|| 0
}).sort({_id:-1}).toArray();

更新数组中某个对象的字段值

请参考MongoDB更新数组中某个对象的元素。

参考链接

  1. The MongoDB 4.4 Manual,by mongodb.
  2. Sequelize ORM,by sequelize.
  3. MongoDB 分页查询的方法及性能,by 笋干.
  4. 移动测试开发 Mongodb 的分页优化及索引使用,by opentest-oper@360.cn.
  5. MongoDB更新数组中某个对象的元素,by zackku.
  6. Mongodb数组操作$(update)、$占位符更新嵌套数组、嵌套文档集合,by OceanSky6.

Hexo使用帮助

发表于 2021-05-10 | 更新于 2022-05-21

记录Hexo使用过程的一些经验。

插入图片问题

请参考Asset Folders。

搜索无效问题

请参考Hexo博客Next主题站内搜索模块相关,解决搜索无效、一直loading的问题。

Node.js 版本限制

Hexo 版本 最低兼容 Node.js 版本
6.0+ 12.13.0
5.0+ 10.13.0
4.1 - 4.2 8.10
4.0 8.6
3.3 - 3.9 6.9
3.2 - 3.3 0.12
3.0 - 3.1 0.10 or iojs
0.0.1 - 2.8 0.10

参考链接

  1. Asset Folders,by hexo.
  2. Hexo Next 解决 Busuanzi 统计浏览失效,by HelloDavid.
  3. Hexo博客Next主题站内搜索模块相关,解决搜索无效、一直loading的问题,by AomanHao.
  4. Hexo文档,by hexo.

Vuejs学习笔记

发表于 2021-05-10 | 更新于 2024-05-24

在使用Vuejs开发的过程中,遇到了一些技术问题,在此记录一下。

对象克隆

作为响应式的开发框架,vuejs组件的data选项中元素将会被修改。vuejs将使用 ES5 的 Object.defineProperty函数修改 data 选项中的元素,使之成为响应式对象。 注意,在保存这些对象时,应该去掉其多余的用于响应的属性,可以采用如下代码:

1
observeProp=JSON.parse(JSON.stringify(observeProp))

数组遍历

注意Array.forEach方法通常情况下不会改变数据元素的值。

Vue实例方法与全局API

vue实例方法:vm.$set、vm.$del、vm.$nextTick等,挂在Vue.prototype上的方法。

全局API: Vue.directive、Vue.filter、Vue.component等,挂在Vue构造函数上的方法。

ElementUI切换暗黑主题

1
2
3
npm i -D element-theme-dark
# Then, in code
import 'element-theme-dark';

具体请参考:

  • Element UI dark theme

参考链接

  1. javascript对象的浅拷贝、深拷贝和Object.assign方法浅析,by 侯贝贝.
  2. js 对象克隆的三种方式,by 加了白糖的老干妈.
  3. JavaScript 的 4 种数组遍历方法: for VS forEach() VS for/in VS for/of,by Fundebug.
  4. forEach究竟能不能改变数组的值,by ZhengKehang.
  5. Vue.js 技术揭秘,by ustbhuangy.
  6. 15 张前端高清知识地图,强烈建议收藏,by 望道同学.
  7. 理解Object.defineProperty的作用,by 戎马.
  8. vue3 区别于 vue2 的“与众不同”,by 喆星高照.
  9. 解析vue2.x源码之vue实例方法与全局API,by 前端小白 - GavinWu.
  10. Element UI dark theme,by Arattian.

GUI桌面开发框架选择与对比

发表于 2021-04-28 | 更新于 2023-11-16

当前桌面GUI程序开发有很多框架,都有各自的优缺点。结合自身需求,最终选择QT Widgets进行桌面GUI程序开发。

GUI框架对比

GUI框架对比

图1 GUI框架对比

当前QT GUI开发有两种方案,一种是使用QT Widgets技术,另一种是使用QT Quick技术。如果从技术成熟度和开发效率角度考虑,可以考虑采用QT Widgets技术进行传统桌面程序开发。

QT版本选择

QT有很多版本,各个版本之间可能不兼容,应根据需求选择合适的版本。常用的QT LTS版本有:

  • Qt4: 4.8.7 4.X 系列终结版本
  • Qt5: 5.6 LTS 长期支持版本
  • Qt5: 5.9 LTS 长期支持版本
  • Qt5: 5.12 LTS 长期支持版本
  • Qt5: 5.15 LTS 长期支持版本
  • Qt6:2020年12月8日发布了

Qt6 在 Win 平台将只支持 Win10 及其以上。嵌入式类应用最好用QT 4.8版本。支持Win XP最好选择QT 5.6.3 版本。

QT应用部署

windeployqt是一个用于将Qt部署到Windows的小工具。这个工具可以在 QTDIR/bin/windeployqt下面找到。它需要在命令行环境下使用。

windeployqt以一个.exe或者一个含有.exe的文件夹作为参数。它会扫描可执行文件以寻找这个可执行文件的依赖。如果使用–qmldir选项传递目录,windeployqt会使用qmlimportscanner工具来扫描文件夹中的QML文件以获取QML导入的依赖。被扫描出来的依赖将会被复制到这个可执行文件夹中。

对于Windows桌面应用程序,编译器所需要的运行时文件也会被复制到部署文件夹中。

有时候应用程序可能会需要额外的第三方库(例如,数据库相关的库),这些库不会被windeployqt添加,需要手动添加。

1
windeployqt musicplayer1.exe

参考链接

  1. Qt,by wikipedia.
  2. Qt最好用评价最高的是哪个版本?,by lk989898.
  3. 如何选择合适的Qt5版本?,by bailutuo7403.
  4. Qt5对WinXP系统的支持和兼容情况,by libaineu2004.
  5. Qt之应用部署(Windows),by 码农家园.
  6. Qt示例入门指南详解:下载安装,by duan.
  7. windeploypt.exe的使用与避坑(windows平台),by 撬动未来的支点.

Git Patch使用帮助

发表于 2021-04-28

多人协作开发,需要将别人开发的代码合并。这时使用git patch命令合并是最方便。下面介绍这种方法。

git patch作用

  • 什么是patch? 简单来讲,patch中存储的是你对代码的修改
  • 什么是生成patch? 生成patch就是记录你对代码的修改并将其保存在patch文件中
  • 什么是打patch? 打patch就是将patch文件中对代码的修改,应用到源代码,从而把对代码的修改应用到code中。

git patch用法

生成patch

1
2
3
4
5
6
7
8
$ git format-patch HEAD^    #生成最近的1次commit的patch
$ git format-patch HEAD^^   #生成最近的2次commit的patch
$ git format-patch HEAD^^^   #生成最近的3次commit的patch
$ git format-patch HEAD^^^^   #生成最近的4次commit的patch
$ git format-patch <r1>..<r2> #生成两个commit间的修改的patch(包含两个commit. <r1>和<r2>都是具体的commit号)
$ git format-patch -1 <r1> #生成单个commit的patch
$ git format-patch <r1> #生成某commit以来的修改patch(不包含该commit)
$ git format-patch --root <r1> #生成从根到r1提交的所有patch

应用patch

检查patch/diff是否能正常打入:

1
2
git apply --check 【path/to/xxx.patch】
git apply --check 【path/to/xxx.diff】

打入patch/diff:

1
2
3
git apply 【path/to/xxx.patch】
git apply 【path/to/xxx.diff】
git am 【path/to/xxx.patch】

TortoiseGit patch用法

TortoiseGit是一个Git版本控制客户端,作为Microsoft Windows的外壳扩展实现。它在GNU通用公共许可协议下作为自由软件发布。使用TortoiseGit 的 Create Patch Serial和 Apply Patch Serial两个菜单可以很方便的产生和应用补丁。

参考链接

  1. TortoiseGit,by wikipedia.
  2. 如何用git命令生成Patch和打Patch,by 青山牧云人.
  3. Git 打补丁– patch 和 diff 的使用(详细),by alanwangmodify.

OSG鼠标拾取拖拽物体的原理

发表于 2021-04-13 | 更新于 2021-04-14

在3D世界中,通过鼠标拾取拖拽物体是一个神奇事情,它的具体实现方法如下:

  1. 将鼠标点击视口的二维坐标转换成3D世界中的三维坐标。
  2. 视点出发到鼠标点击位置的可形成一条射线,在场景节点树上遍历,查找与射线相交的节点。
  3. 获得拾取节点与视点之间距离,从而计算得到鼠标释放时拾取节点的位置,平移拾取节点到目标位置。

2D坐标转3D坐标参考

1
2
3
4
5
6
7
8
9
10
11
12
osg::Vec3 screenToWorld(osgViewer::Viewer* viewer,double dx,double dy)
{
osg::Camera *camera = viewer->getCamera();
osg::Matrix viewMat = camera->getViewMatrix(); //获取当前视图矩阵
osg::Matrix projMat = camera->getProjectionMatrix();//获取投影矩阵
osg::Matrix windMat = camera->getViewport()->computeWindowMatrix();//获取窗口矩阵
osg::Matrix MVPW = viewMat * projMat *windMat; //视图-》投影-》窗口变换

osg::Matrix inverseMVPW = osg::Matrix::inverse(MVPW);
osg::Vec3 mouseWorld = osg::Vec3(dx, dy, 0) * inverseMVPW;
return mouseWorld;
}

获取拾取节点代码参考

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
//参数说明:firstPos:是当前摄像机的位置。endPos:为偏移坐标值,eye + curRayLineDir*100
//curRayLineDir = mouseWorldPos(屏幕点转三维点使用上面的函数) - eye;
//curRayLineDir.normallize();
void CIntersectEventHandler::rayLinePick(const osg::Vec3& firstPos,const osg::Vec3& endPos)
{
osg::ref_ptr<osgUtil::LineSegmentIntersector> lineSegmentIntesector = \
new osgUtil::LineSegmentIntersector(firstPos,endPos);
osgUtil::IntersectionVisitor intersectionVisitor(lineSegmentIntesector);

m_matNode->accept(intersectionVisitor);//m_matNode为你拾取的物体

osgUtil::LineSegmentIntersector::Intersections intersections;
if (lineSegmentIntesector->containsIntersections())
{
intersections = lineSegmentIntesector->getIntersections();
for(auto iter = intersections.begin(); iter != intersections.end(); ++iter)
{
osg::NodePath nodePath = iter->nodePath;
m_pickPoint = iter->getWorldIntersectPoint();
for(int i=0; i<nodePath.size(); ++i)
{
m_pickObj = dynamic_cast<osg::MatrixTransform*>(nodePath[i]);//拾取到的node
}
}
}
}

拖拽物体参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//我是在osgGA::GUIEventAdapter::DRAG进行拖拽的功能
if(m_pickObj && m_bLeftMouseBtn)//这个布尔值就是晓得鼠标的左键是否按下了。
{
//获取当前的摄像机的位置
osg::Vec3 eye = viewer->getCamera()->getInverseViewMatrix().getTrans();
//计算当前摄像机与pick到的模型之间的距离是多少
osg::Vec3 offset = m_pickPoint - eye;
int dist = offset.length();
//计算当前的鼠标屏幕点映射到三维中的值
osg::Vec3 mouseWorldPos = screenToWorld(viewer,ea.getX(),ea.getY());
//计算当前鼠标三维点与摄像机的方向
osg::Vec3 rayDir = mouseWorldPos - eye;
rayDir.normalize();
//最后计算物体拖拽时最终的世界位置
osg::Vec3 curPos = eye + rayDir*dist;
m_pickObj->setMatrix(osg::Matrix::translate(curPos));
}

参考链接

  1. OSG实现鼠标拖拽物体,by 码农家园.
  2. OSG拾取对应的实体,by 成魔的羔羊.
上一页1…222324…52下一页

Jack Huang

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