热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Qt编写地图实现实时动态轨迹效果

实时动态轨迹主要是需要在地图上动态显示GPS的运动轨迹,也是编写地图时一个重要的功能。本文将利用Qt实现这一功能,需要的可以参考一下

一、前言

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

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

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

二、功能特点

定时器排队下载省市轮廓图点坐标集合存储到JS文件。

支持一个行政区域多个不规则区域下载。

自动计算行政区域的下载轮廓数量。

可精确选择省份、市区、县城,也可直接输入行政区域的名称。

可以设置下载间隔、随时开始下载和停止下载。

提供编辑边界功能,可以直接在地图上编辑好不规则区域的点集合,然后获取边界点集合数据,这个可以用来自己绘制区域拿到数据,比如某个乡镇甚至某个小区的行政区域数据,很牛逼。

三、体验地址

体验地址:https://pan.baidu.com/s/15ZKAlptW-rDcNq8zlzdYLg  提取码:uyes 文件名:bin_map.zip

国内站点:https://gitee.com/feiyangqingyun

国际站点:https://github.com/feiyangqingyun

四、效果图

五、相关代码

void frmMapGps::receiveDataFromJs(const QString &type, const QVariant &data)
{
    if (data.isNull()) {
        return;
    }

    //qDebug() <<"frmMapGps" <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 <tableWidgetSource->setRowCount(count);
            for (int i = 0; i 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 item(row, 1)->data(Qt::UserRole).toString();
        //第一个点和最后一个点不用处理
        if (row > 0 && row 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 <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 tableWidgetSource->item(i, 1)->data(Qt::UserRole).toString();
        points <tableWidgetSource->item(countSource - 1, 1)->data(Qt::UserRole).toString();
    if (points.last() != point) {
        points <tableWidgetTarget->clearContents();
    ui->tableWidgetTarget->setRowCount(count);
    for (int i = 0; i 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编写地图实现实时动态轨迹效果的详细内容,更多关于Qt地图实时动态轨迹的资料请关注其它相关文章!


推荐阅读
  • javascript  – 概述在Firefox上无法正常工作
    我试图提出一些自定义大纲,以达到一些Web可访问性建议.但我不能用Firefox制作.这就是它在Chrome上的外观:而那个图标实际上是一个锚点.在Firefox上,它只概述了整个 ... [详细]
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • VueCLI多页分目录打包的步骤记录
    本文介绍了使用VueCLI进行多页分目录打包的步骤,包括页面目录结构、安装依赖、获取Vue CLI需要的多页对象等内容。同时还提供了自定义不同模块页面标题的方法。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 本文详细介绍了MySQL表分区的创建、增加和删除方法,包括查看分区数据量和全库数据量的方法。欢迎大家阅读并给予点评。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 本文介绍了在MySQL8.0中如何查看性能并解析SQL执行顺序。首先介绍了查询性能工具的开启方法,然后详细解析了SQL执行顺序中的每个步骤,包括from、on、join、where、group by、having、select distinct、union、order by和limit。同时还介绍了虚拟表的概念和生成过程。通过本文的解析,读者可以更好地理解MySQL8.0中的性能查看和SQL执行顺序。 ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
author-avatar
mobiledu2502883017
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有