一、前言

实时动态轨迹经历过很多个版本的迭代,此功能最初是一个客户定制的,主要是需要在地图上动态显示GPS的运动轨迹,有个应用场景就是一个带有监控的车子,实时在运动中,后台可以接收到经纬度信息,需要绘制对应的轨迹,相当于这些摄像机点位是动态移动的,这样就可以观测到摄像机的实时位置信息,双击摄像机还可以弹出画面实时预览,很直观。

GPS运动轨迹这个功能,也需要用到js的知识,其实就是封装一个js函数,绘制对应的线条路径,这个轨迹点可能包括的信息有经度、纬度、速度、时间、是否标记、时间等信息,写个结构体封装下,方便后期拓展,是否标记的含义是是否改点同时作为一个设备点添加,分段线的含义。

后面陆续增加了可以设置旋转角度、可以过滤坐标点这两个要点,设置旋转角度采用的是内置的setRotation函数,流程是先从一堆覆盖物中通过唯一标识比如name找到当前要移动的点,然后对这个标注点调用setRotation设置要旋转的角度值,所以这里衍生了另外一个需求,如何计算两个点之间的旋转角度值,这个值必须是提前计算好的,这就要用到数学知识了,用atan2来计算,同时做矫正。

二、功能特点

  1. 定时器排队下载省市轮廓图点坐标集合存储到JS文件。
  2. 支持一个行政区域多个不规则区域下载。
  3. 自动计算行政区域的下载轮廓数量。
  4. 可精确选择省份、市区、县城,也可直接输入行政区域的名称。
  5. 可以设置下载间隔、随时开始下载和停止下载。
  6. 提供编辑边界功能,可以直接在地图上编辑好不规则区域的点集合,然后获取边界点集合数据,这个可以用来自己绘制区域拿到数据,比如某个乡镇甚至某个小区的行政区域数据,很牛逼。

三、体验地址

  1. 体验地址:https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A 提取码:o05q 文件名:bin_map.zip
  2. 国内站点:https://gitee.com/feiyangqingyun
  3. 国际站点:https://github.com/feiyangqingyun
  4. 个人主页:https://blog.csdn.net/feiyangqingyun
  5. 知乎主页:https://www.zhihu.com/people/feiyangqingyun/

四、效果图

五、相关代码

void frmMapGps::receiveDataFromJs(const QString &type, const QVariant &data)
{
if (data.isNull()) {
return;
} //qDebug() << "frmMapGps" << type << data;
QString result = data.toString();
if (type == "point") {
if (ui->ckSelectAddr->isChecked()) {
//判断哪里勾选了就设置到哪里
QString point = WebHelper::getLngLat2(result);
//判断哪里勾选了就设置到哪里
if (ui->rbtnStartAddr->isChecked()) {
ui->txtStartAddr->setText(point);
} else {
ui->txtEndAddr->setText(point);
}
}
} else if (type == "routepoints") {
//将查询路径转换成经纬度坐标点集合数据显示
routeDatas.clear();
ui->tableWidgetSource->clearContents();
//可能会有多个路径集合,目前测试下来都是一个路径集合
QStringList datas = result.split("|");
foreach (QString data, datas) {
QStringList points = data.split(";");
routeDatas << points;
int count = points.count();
ui->tableWidgetSource->setRowCount(count);
for (int i = 0; i < count; ++i) {
addItem(ui->tableWidgetSource, i, points.at(i));
}
} setInfo(0, 0, 0);
}
} void frmMapGps::runJs(const QString &js)
{
web->runJs(js);
} void frmMapGps::on_btnSearchData_clicked()
{
QString startAddr = ui->txtStartAddr->text().trimmed();
QString endAddr = ui->txtEndAddr->text().trimmed();
baidu->setRotueInfo(2, 0, startAddr, endAddr);
this->loadMap();
} void frmMapGps::moveMarker()
{
QTableWidget *tableWidget = getTableWidget();
int row = tableWidget->currentRow();
int count = tableWidget->rowCount();
if (row >= 0 && row < count) {
//找出和上一个点之间的角度
int angle = 0;
QString point = tableWidget->item(row, 1)->data(Qt::UserRole).toString();
//第一个点和最后一个点不用处理
if (row > 0 && row < count - 1) {
//上一个点坐标
QString point2 = tableWidget->item(row - 1, 1)->data(Qt::UserRole).toString();
//计算当前上一个点和当前点的旋转角度
angle = WebHelper::getAngle(point2, point);
} //执行移动设备点函数,参数带旋转角度
QString js = QString("moveMarker('%1', '%2', %3)").arg(name).arg(point).arg(angle);
runJs(js); //重新绘制轨迹点
if (ui->cboxMoveMode->currentIndex() == 0) {
//清空之前的轨迹点
js = QString("deleteOverlay('Polyline')");
runJs(js); //取出第一个点到当前焦点所在行的点组成已经走过的轨迹点集合重新绘制
QStringList points;
for (int i = 0; i <= row; ++i) {
points << tableWidget->item(i, 1)->data(Qt::UserRole).toString();
} js = QString("addPolyline('%1')").arg(points.join("|"));
runJs(js);
} //显示当前第几个数据
setInfo(angle, row + 1, count);
tableWidget->setCurrentCell(row + 1, 0);
} else {
on_btnTestData_clicked();
}
} void frmMapGps::on_btnTestData_clicked()
{
QTableWidget *tableWidget = getTableWidget();
if (ui->btnTestData->text() == "模拟轨迹") {
//限制最小数量
if (tableWidget->rowCount() < 2) {
return;
} //第一步: 添加一个标记
name = ui->txtDeviceName->text().trimmed();
if (name.isEmpty()) {
name = "马航MH370";
} //图片文件在可执行文件下的config/device目录
QString icon = "./device/device_airplane.png";
int size = 60;
QString js = QString("addMarker('%1', '', '', '', 60, '%1', 0, 0, '%2', %3)").arg(name).arg(icon).arg(size);
runJs(js); //第二步: 移到第一个点
tableWidget->setFocus();
tableWidget->setCurrentCell(0, 0);
ui->btnTestData->setText("停止模拟");
ui->tabWidget->setTabEnabled(ui->tableWidgetSource->isVisible() ? 1 : 0, false); //第三步: 启动定时器并立即执行一次
int index = ui->cboxMoveInterval->currentIndex();
timer->start(ui->cboxMoveInterval->itemData(index).toInt());
moveMarker();
} else {
//清空标记
QString js = QString("deleteMarker('%1')").arg(name);
runJs(js); //停止定时器
timer->stop();
ui->btnTestData->setText("模拟轨迹");
ui->tabWidget->setTabEnabled(ui->tableWidgetSource->isVisible() ? 1 : 0, true);
}
} void frmMapGps::on_btnCheckData_clicked()
{
if (timer->isActive()) {
return;
} //第一步: 计算总数,求平均值=实际总数/预期总数+1,预期总数>=实际总数则不用处理
int countSource = ui->tableWidgetSource->rowCount();
int countTarget = ui->txtPointCount->text().trimmed().toInt();
if (countTarget >= countSource) {
QUIHelper::showMessageBoxError("目标点数不能大于等于原数据点数!");
ui->txtPointCount->setFocus();
return;
} //第二步: 根据平均值挨个取出值
QStringList points;
int avg = countSource / countTarget + 1;
for (int i = 0; i < countSource; i += avg) {
QString point = ui->tableWidgetSource->item(i, 1)->data(Qt::UserRole).toString();
points << point;
} //必须加上末尾这个作为结束,如果刚好除尽则不用
QString point = ui->tableWidgetSource->item(countSource - 1, 1)->data(Qt::UserRole).toString();
if (points.last() != point) {
points << point;
} //第三步: 将数据重新填入筛选数据列表
int count = points.count();
ui->tableWidgetTarget->clearContents();
ui->tableWidgetTarget->setRowCount(count);
for (int i = 0; i < count; ++i) {
addItem(ui->tableWidgetTarget, i, points.at(i));
} ui->tabWidget->setCurrentIndex(1);
} void frmMapGps::on_btnDrawData_clicked()
{
if (routeDatas.count() == 0) {
QUIHelper::showMessageBoxError("请先单击查询路线获取路线的坐标点集合!");
return;
} //清空之前的轨迹点
runJs("deleteOverlay('Polyline')"); //将收到的路径点集合分线段绘制
foreach (QStringList data, routeDatas) {
QString points = data.join("|");
QString js = QString("addPolyline('%1', '#ff0000')").arg(points);
runJs(js);
}
}

Qt编写地图综合应用56-实时动态轨迹的更多相关文章

  1. Qt编写的开源帖子集合(懒人专用)

    回顾自己学习Qt以来九年了,在这九年多时间里面,从本论坛学习不到不少的东西,今天特意整了一下自己开源过的资源的帖子,整理一起方便大家直接跳转下载,不统计不知道,一统计吓一跳,不知不觉开源了这么多代码, ...

  2. Qt编写项目作品大全(自定义控件+输入法+大屏电子看板+视频监控+楼宇对讲+气体安全等)

    一.自定义控件大全 (一).控件介绍 超过160个精美控件,涵盖了各种仪表盘.进度条.进度球.指南针.曲线图.标尺.温度计.导航条.导航栏,flatui.高亮按钮.滑动选择器.农历等.远超qwt集成的 ...

  3. Qt编写安防视频监控系统(界面很漂亮)

    一.前言 视频监控系统在整个安防领域,已经做到了烂大街的程序,全国起码几百家公司做过类似的系统,当然这一方面的需求量也是非常旺盛的,各种定制化的需求越来越多,尤其是这几年借着人脸识别的东风,发展更加迅 ...

  4. Qt编写自定义控件二动画按钮

    现在的web发展越来越快,很多流行的布局样式,都是从web开始的,写惯了Qt widgets 项目,很多时候想改进一下现有的人机交互,尤其是在现有的按钮上加一些动画的效果,例如鼠标移上去变大,移开还原 ...

  5. Qt编写自定义控件11-设备防区按钮控件

    前言 在很多项目应用中,需要根据数据动态生成对象显示在地图上,比如地图标注,同时还需要可拖动对象到指定位置显示,能有多种状态指示,安防领域一般用来表示防区或者设备,可以直接显示防区号,有多种状态颜色指 ...

  6. Qt编写数据可视化大屏界面电子看板系统

    一.前言 目前大屏大数据可视化UI这块非常火,趁热也用Qt来实现一个,Qt这个一站式超大型GUI超市,没有什么他做不了的,大屏电子看板当然也不在话下,有了QSS和QPainter这两个无敌的工具组合, ...

  7. Qt编写安防视频监控系统18-云台控制

    一.前言 云台控制是视频监控系统中必备的一个功能,对球机进行上下左右的移动,还有焦距的控制,其实核心就是控制XYZ三个坐标轴,为了开发这个模块,特意研究了各种云台控制的方法和开源库比如soap,有些厂 ...

  8. Qt编写数据可视化大屏界面电子看板13-基础版

    一.前言 之前发布的Qt编写的可视化大屏电子看板系统,很多开发者比较感兴趣,也收到了很多反馈意见,纵观市面上的大屏系统,基本上都是B/S结构的web版本,需要在后台进行自定义配置模块,绑定数据源等,其 ...

  9. Qt编写气体安全管理系统10-数据导出

    一.前言 数据导出一般指导出到excel表格,可能有部分用户还需要导出到pdf,因为pdf基本上不可编辑,防止用户重新编辑导出的数据,excel可能绝大部分用过电脑的人都知道,广为流行,主要就是微软的 ...

  10. Qt编写自定义控件61-通用移动

    一.前言 通用移动类,目标就是为了实现放入任意的控件以后,支持鼠标拖动,在容器中或者父类中拖动,这个应用场景非常多,比如在地图上放置的设备,需要用户自行按下拖动到指定的合适的位置,然后保存设备的位置坐 ...

随机推荐

  1. Win11使用Translucent TB设置Windows导航栏透明失败解决方案

    Win11使用Translucent TB设置Windows导航栏透明失败解决方案 Translucent TB下载方式:直接在Windows自带的Microsoft应用商店里面搜索下载就可以了 1. ...

  2. 基于 KubeSphere 的 Nebula Graph 多云架构管理实践

    本文是杭州站 Meetup 讲师乔雷根据其分享内容整理而成的文章. 图数据库是一种使用图结构进行语义查询的数据库,它使用节点.边和属性来表示和存储数据.图数据库的应用领域非常广泛,在反应事物之间联系的 ...

  3. OpenELB 在 CVTE 的最佳实践

    作者:大飞哥,视源电子股份运维工程师, KubeSphere 社区用户委员会广州站站长,KubeSphere Ambassador. 公司介绍 广州视源电子科技股份有限公司(以下简称视源股份)成立于 ...

  4. [离线计算-Spark|Hive] 大数据应用性能指标采集工具改造落地

    背景 主要介绍针对平台的spark应用程序,在不修改用户程序的情况下 如何采集其资源和性能指标为后续分析使用,如性能优化,资源使用计价等. 分析挑战 在应用程序级别关联大量进程的指标 在分布式环境中, ...

  5. 5.6 Linux Vim撤销和恢复撤销快捷键

    使用 Vim 编辑文件内容时,经常会有如下 2 种需求: 对文件内容做了修改之后,却发现整个修改过程是错误或者没有必要的,想将文件恢复到修改之前的样子. 将文件内容恢复之后,经过仔细考虑,又感觉还是刚 ...

  6. 4-11.3 C++中的显式类转换

    目录 static_cast 1.用来改变基本类型:一般是高精度转低精度 2.恢复void* 指针类型 const_cast 用来去除底层const(low-level const) reinterp ...

  7. Redis学习笔记整理

    一.Redis概述 1.redis简介 Redis(REmote DIctionary Server 远程字典服务器)是一款开源的,用ANSI C编写.支持网络.基于内存.亦可持久化的日志型.Key- ...

  8. Redis示例配置文件

    # 注意单位问题:当需要设置内存大小的时候,可以使用类似1k.5GB.4M这样的常见格式: # # 1k => 1000 bytes # 1m => # 1kb => 1024 by ...

  9. 鸿蒙NEXT开发案例:转盘

    [1]引言(完整代码在最后面) 在鸿蒙NEXT系统中,开发一个有趣且实用的转盘应用不仅可以提升用户体验,还能展示鸿蒙系统的强大功能.本文将详细介绍如何使用鸿蒙NEXT系统开发一个转盘应用,涵盖从组件定 ...

  10. 【原创】PREEMPT-RT 系统cpu使用率周期CPU飙高问题

    PREEMPT-RT 系统cpu使用率周期CPU飙高问题 目录 PREEMPT-RT 系统cpu使用率周期CPU飙高问题 背景 现象 复现条件 原因 解决措施 背景 在22年进行PREEMPT-RT系 ...