项目介绍
1.简介
这是基于Qt+OSG的项目,可支持在局域网内多机器上同步进行操作地球(目前仅支持鼠标对球面的点击和缩放操作),可在球面上绘制点、线、面(可调整线宽),选择节点可对绘制的图形进行删除、撤销等操作,另外可在球面上展示特效(下雪,下雨,火焰等等),可在球表面上播放视频,可连接网络上的数据在球面展示。本项目已经开源到github,链接已经放在文末,有兴趣的童鞋可对本项目提出建议或提交修改(bug,优化等),看到了我会第一时间进行反馈。😊
(目前仅支持Windows系统)
2.环境搭建
开发环境:
💻Windows10+VS2017+Qt5.12.3
🌏OpenSceneGraph-3.6.5+OSGEarth-2.10+CMake-3.22.1
编译参考教程链接已经放在文末尾,过程可能还有细微的不同,有问题可在评论区讨论。
注意:VS编译前后的版本一定要保持一致,不然可能出现各种莫名奇妙的问题
3.设计思路
- 将OSGEarth嵌入到Qt的MainWindow当中,创建停靠窗口,在停靠窗口当中进行做绝大多数的功能,在底下的状态栏中以展示球面的经纬度坐标。
- 在进行同步时所用的思路是:在球面上进行鼠标操作时,实际上,点击(缩放)并不能第一时间到达球体,而是通过一个中转的服务器程序到达,服务器程序功能目前非常简单,只负责接收和广播,这时,如不考虑丢包的情况,到达每个球体的操作的时序都是一致的。
- 在使用网络数据时,为了防止没网的时候出现界面卡顿的情况使用了多线程加载。
4.部分源码
- 中转服务器程序核心代码
#include <iostream>
#include"broadcaster.h"
#include"receiver.h"
int main()
{
Broadcaster BC;
Receiver RC;
BC.setPort(static_cast<short int>(8101));
RC.setPort(static_cast<short int>(8100));
char *currentPtr;
char *startPtr;
//char *endPtr;
int num = 1024;
currentPtr = startPtr = new char[num];
printf("服务器信息如下:\n");
while (true)
{
RC.setBuffer(startPtr, 1024);
unsigned int readsize = RC.sync();
static int i = 0;
//printf("缓存区数据的大小为%u,计数值为:%d\n", readsize,i++);
BC.setBuffer(startPtr, 1024);
BC.sync();
}
return 0;
}
- 控制绘制模式
bool CPickHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
switch (ea.getEventType())
{
case osgGA::GUIEventAdapter::PUSH:
{
//std::cout << "handle:"<<ea.getX() << ":"<<ea.getY()<<std::endl;;
//pick(ea.getX(), ea.getY());
//drawDot(mLonLatAlt.x(), mLonLatAlt.y());
//std::cout << "ml" << mLonLatAlt.x() << ":" << mLonLatAlt.y()<<std::endl;
//std::cout << "button:" << ea.getButton()<<std::endl;
int button = ea.getButton();
if (button == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
{
//判断选择绘制类型
if (mSelected==SelectedDraw::NONE)
{
pick(ea.getX(), ea.getY());
if (m_oc->mViewerMode != OsgContainer::ViewerMode::STAND_ALONE)
{
m_oc->mOperaPacket._operaType = 0;
m_oc->mOperaPacket._llaX = ea.getX();
m_oc->mOperaPacket._llaY = ea.getY();
}
}
else if (mSelected == SelectedDraw::DOT)
{
pick(ea.getX(), ea.getY());
if(mIsPickObject)
{
drawDot(mLonLatAlt.x(), mLonLatAlt.y());
if (m_oc->mViewerMode != OsgContainer::ViewerMode::STAND_ALONE)
{
m_oc->mOperaPacket._operaType = 1;
m_oc->mOperaPacket._llaX = mLonLatAlt.x();
m_oc->mOperaPacket._llaY = mLonLatAlt.y();
}
}
}
else if (mSelected==SelectedDraw::LINE)
{
pick(ea.getX(), ea.getY());
if (mIsPickObject)
{
if (mLineN >= 2)
{
mLineVec->push_back(mLonLatAlt);
drawLine();
mLineXArr[1] = mLonLatAlt.x();
mLineYArr[1] = mLonLatAlt.y();
if (m_oc->mViewerMode != OsgContainer::ViewerMode::STAND_ALONE)
{
m_oc->mOperaPacket._operaType = 2;
for (int i = 0; i < 2; i++)
{
m_oc->mOperaPacket._llaXArr[i] = mLineXArr[i];
m_oc->mOperaPacket._llaYArr[i] = mLineYArr[i];
}
m_oc->mOperaPacket._llaSize = 2;
}
}
else
{
mLineVec->push_back(mLonLatAlt);
mLineN++;
mLineXArr[0] = mLonLatAlt.x();
mLineYArr[0] = mLonLatAlt.y();
}
}
}
else if(mSelected == SelectedDraw::TRIANGLES)
{
pick(ea.getX(), ea.getY());
if (mIsPickObject)
{
if (mLineN>=3)
{
mLineVec->push_back(mLonLatAlt);
drawTriangles();
mLineXArr[2] = mLonLatAlt.x();
mLineYArr[2] = mLonLatAlt.y();
if (m_oc->mViewerMode != OsgContainer::ViewerMode::STAND_ALONE)
{
m_oc->mOperaPacket._operaType = 3;
for (int i = 0; i < 3; i++)
{
m_oc->mOperaPacket._llaXArr[i] = mLineXArr[i];
m_oc->mOperaPacket._llaYArr[i] = mLineYArr[i];
}
m_oc->mOperaPacket._llaSize = 3;
}
}
else
{
mLineVec->push_back(mLonLatAlt);
mLineN++;
int n = mLineN - 2;
mLineXArr[n] = mLonLatAlt.x();
mLineYArr[n] = mLonLatAlt.y();
}
}
}
else if (mSelected == SelectedDraw::PARALLELOGRAM)
{
pick(ea.getX(), ea.getY());
if (mIsPickObject)
{
if (mLineN >= 4)
{
drawParallelogram();
}
else
{
mLineVec->push_back(mLonLatAlt);
mLineN++;
}
}
}
else //无选择时
{
return false;
}
}
else if (button == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON)
{
reDrawXXX();
pick(ea.getX(), ea.getY());
}
return false;
}
case osgGA::GUIEventAdapter::MOVE:
{
}
case osgGA::GUIEventAdapter::DRAG:
{
}
case osgGA::GUIEventAdapter::RELEASE:
{
int button = ea.getButton();
if (button == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
{
m_oc->mOperaPacket._llaX = ea.getX();
m_oc->mOperaPacket._llaY = ea.getY();
}
}
default:
return false;
}
}
功能演示
-
主要(核心)功能
1.同步旋转
2.同步绘制点线面
3.删除撤销重做
-
其它功能
1.播放视频
2.几个特效显示特效
3.连接网络数据
地址
1.源码地址
主程序:https://github.com/whyzzd/OSG
2.编译OSG参考博文地址
osgEarth源码编译(Win10+VS2019+OSG3.6.5+osgEarth2.10.0)
OSG源码编译
OSG教程::基于VS2013的64位OSGEarth编译
osg、osgearth教程VS2017_aspiretop的博客-程序员资料
再次提醒:最后使用的VS版本一定要和编译出来的库版本保持一致