基于QT的运动参数提取与轨迹重现

前言

本项目中的原始数据可通过GPS模块读取串口内容或者直接利用手机某些APP导出原始文件得到,大概数据图如下:

本项目的核心就是利用上述数据,重现出整个运动轨迹并显示一些运动信息(包括速度、方向、位置等)。

项目演示地址:https://www.bilibili.com/video/BV1KF411W7oF

下面过程中涉及到QT编写的程序大家最好复制到QT的界面中看,不然没有高亮啥的看的挺难受的。

GUI界面的设计

  1. 软件启动界面:

    软件启动界面由QT中的闪屏方法编写,在启动时会显示软件的名称以及加载中的字样。

  2. 软件运行主界面:

    软件运行主界面和主流软件主界面编写类似,是基于QT中的qmainwindow类编写的。从上到下依次有菜单栏、工具栏、主界面以及状态栏。菜单栏中文件菜单用于导入数据,调试菜单用于控制绘制过程的开始、暂停、结束,编辑菜单用于清除轨迹信息以及显示运动过程中的最大最小经纬度和最大最小高度数据。而工具栏中是常用的几个操作,只需点击对应的按钮即可执行相应的操作。状态栏用于显示实时的运动状态信息以及轨迹的绘制进程,并实时提示用户的操作。

  3. 软件运行悬浮界面:

    当按下工具栏中的显示轨迹信息按钮后,会启动一个可以由用户随意拖动的悬浮框界面。在这个界面中可以由柱形图看到运动速度和高度的直观变化,以及轨迹颜色与运动速度的对应关系。

  4. GUI界面的构造函数:

    gpsMainWindow::gpsMainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::gpsMainWindow)
    {ui->setupUi(this);setWindowTitle("GPS轨迹重现");//设置窗口名字resize(1440,900);// 设置初始窗口尺寸setWindowIcon(QIcon(":/images/main.png"));//设置主窗口图标menuBar();//菜单栏:淡绿色;下拉菜单:深天蓝this->setStyleSheet("QMenu::item:selected{background-color:#00BFFF;}\QMenuBar{background-color:#90EE90;}");toolBar();myBar->setOrientation(Qt::Horizontal);//设置进度条为水平样式ui->statusbar->addPermanentWidget(myBar);//将进度条添加到永久显示即状态栏右下角m_webEngineView = new QWebEngineView();//为指针分配内存m_webChannel = new QWebChannel();/*向QWebChannel对象注册Qt对象,下面的注册的就是当前对象注意:这里注册时所用的名字“cppObject”,就是js获取qt对象时所使用的索引名将设置好的QWebChannel对象设置为当前页面的通道,即调用QWebEnginePage的setWebChannel方法如果没有正确注册webchannel,在js调用qt对象时会出现qt对象为undefined的情况覆盖默认的用户代理字符串,将其设置为HttpUserAgent_H5加载web视图,QUrl后跟自己的html文件的路径*///m_webEngineView->setAttribute(Qt::WA_DeleteOnClose);//关闭子窗体时调用子窗体的析构函数m_webChannel->registerObject(QStringLiteral("cppObject"), this);m_webEngineView->page()->setWebChannel(m_webChannel);m_webEngineView->page()->profile()->setHttpUserAgent(HttpUserAgent_H5);m_webEngineView->load(QUrl("qrc:/leaflet/gaodeGPSdraw.html"));//m_webEngineView->show();//在新窗口显示web视图setCentralWidget(m_webEngineView);//在主窗口显示web视图myBar->setFixedSize(400,60);
    }gpsMainWindow::~gpsMainWindow()
    {delete ui;m_webChannel->deregisterObject(this);
    }
    

运动数据的提取与格式转换

  • 通信协议:

    NMEA-0183是美国国家海洋电子协会(National Marine Electronics Association )为海用电子设备制定的标准格式。目前已成了GPS导航设备统一的RTCM(Radio Technical Commission for Maritime services)标准协议。

    本实验中,主要运用到了该协议中的“GPRMC”和“GPRMC”和“GPRMC”和“GPGGA”两个命令,其格式分别如下:

    $GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*<13>

    <1> UTC(Coordinated Universal Time)时间,hhmmss(时分秒)格式

    <2> 定位状态,A=有效定位,V=无效定位

    <3> Latitude,纬度ddmm.mmmm(度分)格式(前导位数不足则补0)

    <4> 纬度半球N(北半球)或S(南半球)

    <5> Longitude,经度dddmm.mmmm(度分)格式(前导位数不足则补0)

    <6> 经度半球E(东经)或W(西经)

    <7> 地面速率(000.0~999.9节,Knot,前导位数不足则补0)

    <8> 地面航向(000.0~359.9度,以真北为参考基准,前导位数不足则补0)

    <9> UTC日期,ddmmyy(日月年)格式

    <10> Magnetic Variation,磁偏角(000.0~180.0度,前导位数不足则补0)

    <11> Declination,磁偏角方向,E(东)或W(西)

    <12> Mode Indicator,模式指示(仅NMEA0183 3.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效)

    <13> 校验和。

    $GPGGA,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,M,<10>,M,<11>,<12>

    <1> UTC时间,hhmmss(时分秒)格式

    <2> 纬度ddmm.mmmm(度分)格式(前面的0也将被传输)

    <3> 纬度半球N(北半球)或S(南半球)

    <4> 经度dddmm.mmmm(度分)格式(前面的0也将被传输)

    <5> 经度半球E(东经)或W(西经)

    <6> GPS状态:0=未定位,1=非差分定位,2=差分定位,6=正在估算

    <7> 正在使用解算位置的卫星数量(00~12)(前面的0也将被传输)

    <8> HDOP水平精度因子(0.5~99.9)

    <9> 海拔高度(-9999.9~99999.9)

    <10> 地球椭球面相对大地水准面的高度

    <11> 差分时间(从最近一次接收到差分信号开始的秒数,如果不是差分定位将为空)

    <12> 差分站ID号0000~1023(前面的0也将被传输,如果不是差分定位将为空)

  • 数据格式:

    如上图所示,在一个典型的存放数据的文本文件中,除去GPRMC和GPGGA格式的数据外还有很多其他格式的无用数据。而在有用的数据中,每个运动信息都是由逗号分隔开的。因此可以先将GPRMC和GPGGA格式的数据找出来存放到一个链表中,然后再对链表的每一项进行运动信息的提取。

  • 数据提取程序:

    数据提取程序中也涉及到了数据的导入操作,由于要求是由用户对话框导入(这样也符合用户操作的逻辑习惯),因此在导入前先对导入的数据的有效性进行了判断,防止由于用户的操作不当未导入数据或者导入无效数据导致程序卡死的情况出现。

    其中,函数**screenGPSMessage()**将文件打开,并读取和筛查数据。每次读取文本中的一行数据,使用字符串的方法“split(“,”)”,可将一行的数据按“,”为分隔符,将第一个逗号前的字符和两个逗号之间字符存入一个字符串列表中,然后判断第一个字符串,根据协议,当“GPRMC”和“​GPGGA”两个命令同时出现时,“​GPRMC”总是在前,所以先判断第一个字符串是否为“​GPRMC”,如果是就进行数据的校准和存储,这将会在接下来讨论,存储完毕后,依据协议,下一命令大概率是“​GPGGA”,所以在这个判断语句内,再次读取一行数据,并分割存储,然后判断第一个字符串是否为“GPGGA”,如果是,则执行“​GPGGA”对应的数据校准和存储程序,如果不是,结束判断。如果第一次读取命令首字符串不是“GPRMC”,那么继续继续判断是否为“$GPGGA”,如果是,则进行相应的数据校准和存储程序。重复执行,直至数据全部读取完成。

  • 数据格式的转换:

    首先我们需要了解常用的地图坐标系,总的来说有以下三种:
    (1)天地图:CGCS2000,2000国家大地坐标系;我们其实很多时候直接用WGS84的坐标来代替CGCS2000坐标。因为CGCS2000的定义与WGS84实质一样。采用的参考椭球非常接近。扁率差异引起椭球面上的纬度和高度变化最大达0.1mm当前测量精度范围内,可以忽略这点差异。可以说两者相容至cm级水平,但若一点的坐标精度达不到cm水平,则不认为CGCS2000和WGS84的坐标是相容的。

    (2)百度地图:bd09II坐标。首先了解一下火星坐标,它是在国际标准坐标WGS-84上进行的一次加密,由于国内的电子地图都要至少使用火星坐标进行一次加密,百度直接就任性一些,直接自己又研究了一套加密算法,来了个二次加密,这就是我们所熟知的百度坐标(BD-09)。

    (3)高德地图:gcj02坐标,也称为火星坐标。火星坐标是国家测绘局为了国家安全在原始坐标的基础上进行偏移得到的坐标,基本国内的电子地图、导航设备都是采用的这一坐标系或在这一坐标的基础上进行二次加密得到的。
    在本次实验中,考虑到为了更加清晰准确地重现运动轨迹,并可以实现大范围的轨迹重现,特选用高德离线地图。相比于在线地图,离线地图的加载更快,不受网络状况的干扰,也不会在运行过程中出现大范围的白边。从网上了解到WGS84ToGCJ02格式的数据转换公式后,得到转换函数为:

    此函数调用后将返回高德地图下的实际经纬度坐标,经验证,坐标定位地非常准确,轨迹基本和实际完全一致。

导入地图和绘制轨迹

  1. leaflet的基本使用:

    Leaflet 是一个为建设移动设备友好的互动地图,而开发的现代的、开源的 JavaScript库 。虽然前端地图框架不少,但leaflet凭借简单、易用、上手快、拓展多、轻量级等优点,让我选择了它。此外,leaflet的官网还有丰富的教程以及帮助文档,大大降低了我们的开发难度。而它在移动端应用开发的优势,更是完美契合本次实验的要求。综合考虑后,决定使用leaflet作为地图框架。

    在官网下载leaflet的js包解压后即可使用leaflet库了,在使用前要在程序开头加上下面两句:

    <link rel="stylesheet" href="./leaflet.css"/>
    <script src="./leaflet.js"></script>
    
  2. 利用leaflet库绘制轨迹:

绘制轨迹其实就是利用两点确定一条直线,依据得到的数据每两点画一条线后得到 总轨迹。因此查阅leaflet的帮助文档后可知利用polyline函数可以实现直线的绘制

此外,为保证绘制的轨迹会随着地图的移动而实时移动,我们需要确保我们绘制点的坐标一直保持在地图的中心,为此利用leaflet中的panto函数,使得轨迹会随着绘制的进行而移动。在绘制过程中,速度会不断地发生变化,因此要设置不同的速度区间用不同颜色的轨迹标识,并在速度低时地图等级高,速度高时地图等级低,利用setzoom函数实现不同等级的设定。

/*
* Function name :drawPoint
* Description   : 画点
* Parameter     : 无
* Return        :无
*/
function drawPoint() {if (drawPointNum >= num_list.length-1) {clearInterval(interval);alert("stop", drawPointNum);drawPointNum = 0;return;}var wgs84togcj02 = tracelist[drawPointNum];var wgs84togcj022 = tracelist[drawPointNum + 1];var speed = speedlist[drawPointNum];var latlngs = [[wgs84togcj02[1], wgs84togcj02[0]],[wgs84togcj022[1], wgs84togcj022[0]],];if(spdMax<30){map.setZoom(18);}else if(wgs84togcj02[1]>30.08&&wgs84togcj02[1]          <30.80&&wgs84togcj02[0]>103.09&&wgs84togcj02[0]<104.76&&speed<120){map.setZoom(16);}else if(wgs84togcj02[1]>26.05&&wgs84togcj02[1]<34.3&&wgs84togcj02[0]>97.35&&wgs84togcj02[0]<108.55&&speed<300){map.setZoom(14);}else{map.setZoom(12);}if(speed>=0&&speed<30){L.polyline(latlngs, { color: "yellow", weight: 4, opacity: 100 }).addTo(map);}else if(speed>=30&&speed<60){L.polyline(latlngs, { color: "purple", weight: 4, opacity: 100 }).addTo(map);}else if(speed>=60&&speed<90){L.polyline(latlngs, { color: "blue", weight: 4, opacity: 100 }).addTo(map);}else if(speed>=90&&speed<120){L.polyline(latlngs, { color: "green", weight: 4, opacity: 100 }).addTo(map);}else if(speed>=120&&speed<200){L.polyline(latlngs, { color: "black", weight: 4, opacity: 100 }).addTo(map);}else if(speed>=200&&speed<350){L.polyline(latlngs, { color: "red", weight: 4, opacity: 100 }).addTo(map);}else{L.polyline(latlngs, { color: "white", weight: 4, opacity: 100 }).addTo(map);}//drawPointNum++;drawPointNum = drawPointNum + 2;  //加快轨迹绘制速度map.panTo([wgs84togcj022[1], wgs84togcj022[0]]);fromWebToCpp();
}
  1. QT与JS的交互:

由于程序运行主界面是基于QT开发的,因此用户事件的输入其实是在QT中实现的,而绘图功能的实现却是在JS或者说是一个网页实现的。因此必须有一个桥梁建立起QT与JS之间的关系,实现二者的消息互通。幸运的是,QT内置了很多的类如QWebEngineView、QWebChannel、QJsonObject等来实现这一功能。我们只需要先向QWebChannel对象注册QT对象,获得js获取qt对象时所使用的索引名,并将设置好的QWebChannel对象设置为当前页面的通道,最后加载web视图即可。
而在JS端,首先要将qwebchannel.js文件引入在内,然后在页面初始化时创建一个QWebChannel对象,里面的第一个参数是qt.webChannelTransport,只有Qt端正确地向页面设置了webchannel才能取到,否则会是undefined。 QWebChannel对象里的channel.objects对应了Qt里实现向webchannel注册的对象表,channel.objects.cppObject即为从表中取出名为"cppObject"的对象,然后赋给window的bridge对象。
QT端主要程序:

void gpsMainWindow::JsDraw()
{QJsonArray num_json, num2_json, num3_json;//声明QJsonArrayQJsonDocument num_document, num2_document, num3_document;  //将QJSonArray改为QJsonDocument类QByteArray num_byteArray, num2_byteArray, num3_byteArray;current = head;double *pos;//pos[0]——纬度  pos[1]——经度while(current->next != NULL)//将数组传入num_json{pos = WGS84ToGCJ02(current->getGprmc()->getLantitude(),current->getGprmc()->getLongitude());double x =pos[1];double y = pos[0];double s = current->getGprmc()->getLandSpeed();if(x<=137.8347&&x>=72.004&&y<=55.8271&&y>=0.8293){//qDebug()<<"经度"<<x;//qDebug()<<"纬度"<<y;//在数组末尾插入值num_json.append(x);num2_json.append(y);num3_json.append(s);}current = current->next->next;}/*设置array作为文档中的主对象将QJsonDocument转换为UTF-8编码的format格式的JSON文档Indented:按照json风格生成字符串,自动缩进Compact:紧凑格式,直接生成一堆字符串,就是不换行,但是占用空间小*/num_document.setArray(num_json);num2_document.setArray(num2_json);num3_document.setArray(num3_json);num_byteArray = num_document.toJson(QJsonDocument::Compact);num2_byteArray = num2_document.toJson(QJsonDocument::Compact);num3_byteArray = num3_document.toJson(QJsonDocument::Compact);QString numJson(num_byteArray);//再转为QStringQString num2Json(num2_byteArray);QString num3Json(num3_byteArray);//每个arg()将替换编号最小的未替换位置QString cmd = QString("getPathData(\"%1\",\"%2\",\"%3\")").arg(numJson).arg(num2Json).arg(num3Json);m_webEngineView->page()->runJavaScript(cmd);//运行JS代码
}

网页端主要程序:

/* Function name :getPathData
* Description   : 得到经纬度数据和速度数据
* Parameter     : 纬度列表,经度列表,速度列表
* Return        :无
*/
function getPathData(numlist, num2list,num3list) {num_list.length = 0;num2_list.length = 0;num3_list.length = 0;tracelist.length = 0;speedlist.length = 0;drawPointNum = 0;/* substring(indexStart[, indexEnd]) 方法返回一个字符串在开始索引到结束索引之间的一个子集,或从开始索引直到字符串的末尾的一个子集参数  indexStart:需要截取的第一个字符的索引,该索引位置的字符作为返回的字符串的首字母indexEnd:可选。一个 0 到字符串长度之间的整数,以该数字为索引的字符不包含在截取的字符串内split() 方法使用指定的分隔符字符串将一个String对象分割成子字符串数组,以一个指定的分割字串来决定每个拆分的位置*/num_list = numlist.substring(1, numlist.length - 1);num2_list = num2list.substring(1, num2list.length - 1);num3_list = num3list.substring(1, num3list.length - 1);num_list = num_list.split(",");num2_list = num2_list.split(",");num3_list = num3_list.split(",");for (i = 0; i < num_list.length; i++) {point = [num_list[i], num2_list[i]];tracelist.push(point); //将每个点压入数组if(Number(num3_list[i])>Number(spdMax)){spdMax = num3_list[i];}if(Number(num3_list[i])<Number(spdMin)){spdMin = num3_list[i];}if(Number(num_list[i])>Number(logMax)){logMax = num_list[i];}if(Number(num_list[i])<(logMin)){logMin = num_list[i];}if(Number(num2_list[i])>(latMax)){latMax = num2_list[i];}if(Number(num2_list[i])<(latMin)){latMin = num2_list[i];}speedlist.push(num3_list[i]);}startDrawPoint();
}//window.onload的功能是为了在页面加载完成后立即调用函数
window.onload = function () {if (navigator.userAgent.indexOf("Toon-pc") !== -1){// 初始化时创建了一个QWebChannel对象,里面的第一个参数qt.webChannelTransport,只有Qt端正确地向页面设置了webchannel才能取到,否则会是undefined// QWebChannel对象里的channel.objects对应了Qt里实现向webchannel注册的对象表,channel.objects.cppObject即为从表中取出名为"cppObject"的对象,然后赋给window的bridge对象// window作为全局变量,代表了脚本正在运行的窗口new QWebChannel(window.qt.webChannelTransport, function (channel) {window.bridge = channel.objects.cppObject;});}
};

界面的美化与功能的完善

  • 菜单栏、工具栏、状态栏的编写:

    void gpsMainWindow::menuBar()
    {//新建菜单QMenu *toolButtonMenu_1 = new QMenu(this);toolButtonMenu_1->setTitle("文件(F)");QMenu *toolButtonMenu_2 = new QMenu(this);toolButtonMenu_2->setTitle("调试(D)");QMenu *toolButtonMenu_3 = new QMenu(this);toolButtonMenu_3->setTitle("编辑(E)");//新建行为QAction *toolButtonAction1 = new QAction(this);QAction *toolButtonAction2 = new QAction(this);QAction *toolButtonAction3 = new QAction(this);QAction *toolButtonAction4 = new QAction(this);QAction *toolButtonAction5 = new QAction(this);QAction *toolButtonAction6 = new QAction(this);QAction *toolButtonAction7 = new QAction(this);//命名行为定位toolButtonAction1->setText("导入文件");toolButtonAction2->setText("开始");toolButtonAction3->setText("暂停");toolButtonAction4->setText("继续");toolButtonAction5->setText("清除");toolButtonAction6->setText("速度信息");toolButtonAction7->setText("位置信息");//为行为定位添加图标toolButtonAction1->setIcon(QIcon(":/images/input.png"));toolButtonAction2->setIcon(QIcon(":/images/start.png"));toolButtonAction3->setIcon(QIcon(":/images/mpause.png"));toolButtonAction4->setIcon(QIcon(":/images/mcontinue.png"));toolButtonAction5->setIcon(QIcon(":/images/refresh.png"));toolButtonAction6->setIcon(QIcon(":/images/speed.png"));toolButtonAction7->setIcon(QIcon(":/images/loglat.png"));//添加定位槽connect(toolButtonAction1,SIGNAL(triggered()),this,SLOT(fileIn()));connect(toolButtonAction2,SIGNAL(triggered()),this,SLOT(start()));connect(toolButtonAction3,SIGNAL(triggered()),this,SLOT(pause()));connect(toolButtonAction4,SIGNAL(triggered()),this,SLOT(myContinue()));connect(toolButtonAction5,SIGNAL(triggered()),this,SLOT(clearPath()));connect(toolButtonAction6,SIGNAL(triggered()),this,SLOT(spdInfo()));connect(toolButtonAction7,SIGNAL(triggered()),this,SLOT(posInfo()));//添加行为toolButtonMenu_1->addAction(toolButtonAction1);toolButtonMenu_2->addAction(toolButtonAction2);toolButtonMenu_2->addAction(toolButtonAction3);toolButtonMenu_2->addAction(toolButtonAction4);toolButtonMenu_3->addAction(toolButtonAction5);toolButtonMenu_3->addAction(toolButtonAction6);toolButtonMenu_3->addAction(toolButtonAction7);//向菜单栏中添加工具栏ui->menubar->addMenu(toolButtonMenu_1);ui->menubar->addMenu(toolButtonMenu_2);ui->menubar->addMenu(toolButtonMenu_3);}
    
    void gpsMainWindow::toolBar()
    {ui->toolBar->setMovable(false);//设置工具栏不可移动toolBtn1->setText(tr("导入GPS数据"));toolBtn2->setText(tr("GPS轨迹绘制"));toolBtn3->setText(tr("暂停"));toolBtn4->setText(tr("继续"));toolBtn5->setText(tr("清除轨迹"));toolBtn6->setText("显示轨迹信息");//工具栏按钮图标toolBtn1->setIcon(QIcon(":/images/data.png"));toolBtn2->setIcon(QIcon(":/images/draw.png"));toolBtn3->setIcon(QIcon(":/images/pause.png"));toolBtn4->setIcon(QIcon(":/images/continue.png"));toolBtn5->setIcon(QIcon(":/images/clear.png"));toolBtn6->setIcon(QIcon(":/images/information.png"));//设置文字在图标之后toolBtn1->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);toolBtn2->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);toolBtn3->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);toolBtn4->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);toolBtn5->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);toolBtn6->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);//添加connect(toolBtn1,SIGNAL(clicked()),this,SLOT(fileIn()));connect(toolBtn2,SIGNAL(clicked()),this,SLOT(start()));connect(toolBtn3,SIGNAL(clicked()),this,SLOT(pause()));connect(toolBtn4,SIGNAL(clicked()),this,SLOT(myContinue()));connect(toolBtn5,SIGNAL(clicked()),this,SLOT(clearPath()));connect(toolBtn6,SIGNAL(clicked()),this,SLOT(dispInfo()));// 设置弹出模式toolBtn1->setPopupMode(QToolButton::DelayedPopup);toolBtn2->setPopupMode(QToolButton::DelayedPopup);toolBtn3->setPopupMode(QToolButton::DelayedPopup);toolBtn4->setPopupMode(QToolButton::DelayedPopup);toolBtn5->setPopupMode(QToolButton::DelayedPopup);toolBtn6->setPopupMode(QToolButton::DelayedPopup);//添加按钮至工具栏ui->toolBar->addWidget(toolBtn1);ui->toolBar->addWidget(toolBtn2);ui->toolBar->addWidget(toolBtn3);ui->toolBar->addWidget(toolBtn4);ui->toolBar->addWidget(toolBtn5);ui->toolBar->addWidget(toolBtn6);//添加状态至工具栏checkBox->setText(QString("离线"));checkBox->setCheckState(Qt::Checked);ui->toolBar->addWidget(checkBox);}
    
    void gpsMainWindow::setMessage()
    {if(current->next == NULL){return;}QString status;//status = current->getGprmc()->getPositionStatus();QString latMessage;QString lonMessage;QString altMessage;QString speMessage;QString drcMessage;QString drawProgess;double *pos = WGS84ToGCJ02(current->getGprmc()->getLantitude(),current->getGprmc()->getLongitude());double x =pos[1];double y = pos[0];if(x<=137.8347&&x>=72.004&&y<=55.8271&&y>=0.8293){latMessage =  "纬度:"+QString::number(y)+" "+current->getGprmc()->getLatHalfBall();lonMessage =  "经度:"+QString::number(x)+" "+current->getGprmc()->getLogHalfBall();altMessage =  "海拔:"+QString::number(current->getGpgga()->getAltitude())+"m ";speMessage =  "速度:"+QString::number(current->getGprmc()->getLandSpeed())+"km/h ";drcMessage =  "地面航向:"+QString::number(current->getGprmc()->getLandDirection());drawProgess =  "进度:"+QString::number(current->getGprmc()->getNums()/nums*100);ui->statusbar->showMessage(latMessage+" "+lonMessage+" "+altMessage+speMessage+drcMessage+"° "+drawProgess+"%");logTB->setText(lonMessage);lanTB->setText(latMessage);spdTB->setText(speMessage);altTB->setText(altMessage);myBar->setValue(int(current->getGprmc()->getNums()/nums*100));//设置进度条speedSlider->setValue(int(current->getGprmc()->getLandSpeed()));//设置速度滑块heightSlider->setValue(int(current->getGpgga()->getAltitude()));//设置高度滑块}current = current->next;
    }
    
  • 运动信息直观显示窗口的编写:

    void gpsMainWindow::dispInfo()
    {QDockWidget *dock = new QDockWidget("运动状态直观显示",this);//添加停靠窗口dock->setFeatures(QDockWidget::DockWidgetFloatable);//设置为可悬浮heightSlider->setMinimum(0);speedSlider->setMinimum(0);heightSlider->setMaximum(8000);speedSlider->setMaximum(1000);speedSlider->setStyleSheet(spdStyle);heightSlider->setStyleSheet(altStyle);QHBoxLayout *HLay1=new QHBoxLayout;HLay1->addWidget(heightSlider);HLay1->addWidget(speedSlider);QFont *tbFont = new QFont;tbFont->setPointSize(14);logTB->setFixedSize(400,70);lanTB->setFixedSize(400,70);spdTB->setFixedSize(400,70);altTB->setFixedSize(400,70);logTB->setFont(*tbFont);lanTB->setFont(*tbFont);spdTB->setFont(*tbFont);altTB->setFont(*tbFont);QVBoxLayout *VLay=new QVBoxLayout;VLay->addWidget(logTB);VLay->addWidget(lanTB);VLay->addWidget(spdTB);VLay->addWidget(altTB);colorLabel->setFixedSize(300,800);QPixmap color(":/images/color.png");colorLabel->setPixmap(color);QHBoxLayout *HLay2=new QHBoxLayout;HLay2->addLayout(HLay1);HLay2->addLayout(VLay);HLay2->addWidget(colorLabel);sWidget->setLayout(HLay2);dock->setWidget(sWidget);addDockWidget(Qt::RightDockWidgetArea,dock);}
    
  • 功能函数的编写:

    void gpsMainWindow::start()
    {if(pathEmpty == 0){QString warning = "警告:还未导入数据,请先导入数据后再进行绘制轨迹";ui->statusbar->showMessage(warning);return;}JsDraw();current = head;
    }void gpsMainWindow::fileIn()
    {filePath = QFileDialog::getOpenFileName(this, "Please choose a path file","../gps/data","Txt Files(*.txt );;All(*.*)");if (filePath.isEmpty()==false){pathEmpty = 1;}else{ui->statusbar->showMessage("警告:路径为空或文件不存在");pathEmpty = 0;return;}screenGPSMessage();
    }void gpsMainWindow::pause()
    {QString cmd = QString("pauseDraw()");m_webEngineView->page()->runJavaScript(cmd);//运行JS代码
    }void gpsMainWindow::myContinue()
    {QString cmd = QString("continueDraw()");m_webEngineView->page()->runJavaScript(cmd);//运行JS代码
    }void gpsMainWindow::clearPath()
    {m_webEngineView->reload();ui->statusbar->clearMessage();myBar->setValue(0);QString cmd = QString("clearPath()");m_webEngineView->page()->runJavaScript(cmd);//运行JS代码
    }void gpsMainWindow::spdInfo()
    {QString cmd = QString("dispSpdMaxMin()");m_webEngineView->page()->runJavaScript(cmd);//运行JS代码
    }void gpsMainWindow::posInfo()
    {QString cmd = QString("dispLogLat()");m_webEngineView->page()->runJavaScript(cmd);//运行JS代码
    }
    function pauseDraw()
    {clearInterval(interval);alert("已暂停");
    }function continueDraw()
    {alert("已继续");interval = setInterval(drawPoint, 10);
    }function clearPath()
    {alert("已清除");//清除操作在Qt中执行,这里只是弹出网页提示
    }function dispSpdMaxMin()
    {alert("本次行程的速度最大值为:"+spdMax+"\n最小值为:"+spdMin);//显示速度最大最小值
    }function dispLogLat()
    {alert("本次行程经度的最大值为:"+logMax+"最小值为:"+logMin+"\n本次行程纬度的最大值为:"+latMax+"最小值为:"+latMin);
    }
    

结果演示

详见基于QT的运动参数提取与轨迹重现

基于QT的运动参数提取与轨迹重现相关推荐

  1. GPS参数提取及轨迹重现

    本项目分为两个版本: 1.基于百度地图API的轨迹快速重现,项目体验地址:GPS轨迹重现在线版 2.基于Leaflet的状态及轨迹重现,项目体验地址:GPS数据提取及轨迹重现 两者均采用在线地图,都需 ...

  2. GPS参数提取与轨迹重现实验

    一个简单的小实验,还有很多地方需要改进. 一.实验工具: ①C++ builder ②Google earth--定位和获取校准点的经纬度,界定截图的大致范围 ③Getscreen--配合Google ...

  3. html音频控制的参数,基于内容的音频参数提取与动画控制实现

    摘要:互联网上传送的数据以图像信息和音频信息等多媒体信息为主.近几年来,多媒体信息越来越趋向多元化和综合化,因而音频信息和视觉信息综合化也成为趋势.在此基础上,音频信息转化成视觉信息成为迫切需求.该系 ...

  4. 参数提取类毕业论文文献包含哪些?

    本文是为大家整理的参数提取主题相关的10篇毕业论文文献,包括5篇期刊论文和5篇学位论文,为参数提取选题相关人员撰写毕业论文提供参考. 1.[期刊论文]高精度GaAs PHEMT小信号模型参数提取 期刊 ...

  5. 基于matlab的脉搏信号参数提取,基于Matlab的脉搏信号参数提取.pdf

    基于Matlab的脉搏信号参数提取.pdf 第25卷第1期 2010年2月 山东建筑大学学报Vo1 25 No 1 JOURNAL OF SHANDONG JIANZHU UNIVERSITY Feb ...

  6. 基于MATLAB 的运动模糊图像复原

    基于MATLAB 的运动模糊图像复原 研究目的 在交通系统. 刑事取证中图像的关键信息至关重要, 但是在交通. 公安.银行. 医学.工业监视.军事侦察和日常生活中常常由于摄像设备的光学系统的失真. 调 ...

  7. 基于MATLAB的运动模糊图像处理

    基于MATLAB的运动模糊图像处理 研究目的 在交通系统.刑事取证中图像的关键信息至关重要,但是在交通.公安.银行.医学.工业监视.军事侦察和日常生活中常常由于摄像设备的光学系统的失真.调焦不准或相对 ...

  8. 基于matlab的运动模糊图像处理,基于matlab运动模糊图像处理

    基于matlab运动模糊图像处理 基于 MATLAB 的运动模糊图像处 理 提醒: 我参考了文献里的书目和网上的一些代码而完成的,所以误差会比较大,目前 对于从网上下载的模糊图片的处理效果很不好, 这 ...

  9. 基于FFmpeg的运动视频分析

    本文来自英特尔资深软件工程师李忠,张华在LiveVideoStackCon 2018大会上的分享,由LiveVideoStack整理而成.分享中两位老师重点介绍了基于FFmpeg的运动视频分析技术架构 ...

最新文章

  1. 修改element默认样式_ggplot2作图:修改主题元素的外观样式(整体修改)
  2. centos .php 源码,CentOS 源码安装PHP
  3. libsvm的安装和使用(1)
  4. Obj文件和Bin文件
  5. dns服务器正则表达式验证,js如何对域名和ip进行校验?(正则表达式)
  6. 在 phpMyAdmin 里添加新用户帐号
  7. u8api openapi_使用OpenAPI规范进行更好的API测试
  8. css 设置overflow:scroll 滚动条的样式
  9. 输出匹配项:grep
  10. Log_Analysis_using_OSSEC.md
  11. python的unicode编码表_Python-编码
  12. JavaEE 启示录
  13. java调用Shell脚本
  14. 21接力题典1800 数一 重积分 P46 T18
  15. 【软考 系统架构设计师】软件架构设计⑦ 构件与中间件技术
  16. 自强不息系列之Python 线性查找
  17. 小程序商家如何做低成本裂变活动?
  18. matlab dfe 仿真,Matlab Simulink
  19. 消费管理系统java代码_SSH框架+Mysql数据库开发java web会员积分消费管理系统
  20. 毕业论文word排版技巧

热门文章

  1. 3--新唐nuc980 kernel支持jffs2, Jffs2文件系统制作, 内核挂载jffs2, uboot网口设置,uboot支持tftp
  2. 好久都没去过电影院了!用Python网络爬虫来看看最近电影院都有哪些上映的电影
  3. 【已解决】ImportError: torch.utils.ffi is deprecated. Please use cpp extensions instead.
  4. symfony老版本自主学习
  5. 周末北大学拳散记--搜狐畅游招聘
  6. Linux学习-40-格式化分区mkfs、mke2fs命令用法
  7. 酷讯网半年内两换CEO 风投要业绩被指心太急
  8. NDI是什么?NDI协议传输让网络直播更有趣
  9. esc中文是什么意思_汽车ESC什么意思 汽车ESC有什么用
  10. ZCMU-1133- 第九章:致我们终将逝去的青春