Qt/C++地图标注点的添加删除移动旋转/指定不同图标和动图/拿到单击信号

news2024/9/21 16:25:51

一、前言说明

标注点在地图开发中是最常见的应用场景之一,比如在地图上需要显示设备的位置,基本上都是添加标注点,指定图片和尺寸已经经纬度坐标位置。这个功能在每种地图内核中都提供的,这个并没有任何难点,在这个功能点上最大难题或者说是设计细节就是,标注点该如何对齐,比如水滴形状的图标一般是底部居中对齐更美观,刚好水滴的头在指定的经纬度坐标上,整个图标位于正上方。还有一种情况是圆形的图标,这种最美观的方式是中间居中对齐,也就是图片的中心点在指定的经纬度坐标上,更符合实际的情况,如果说是底部,则看起来可能会很怪。

不同地图内核提供了不同的函数设置图标位置,百度地图是通过setOffset设置偏移值,这个值需要自己根据图片的大小自己计算好再设置。高德地图是通过setAnchor指定位置字符串来设置,比如setAnchor(‘center’)是中间居中,setAnchor(‘bottom-center’)是底部居中,这种方式蛮好的,他会自己根据图片尺寸进行设置。天地图是通过设置marker的属性参数iconAnchor偏移值控制。腾讯地图很特殊,他是通过设置图标MarkerImage对象的anchor参数来控制的。

在marker标注点的旁边还可以显示一个跟随的文本,表示名称之类的信息,百度地图和高德地图都在marker对象的函数中就提供了处理,而天地图和腾讯地图需要自己new一个label对象,这个对象设置对应的位置为marker的位置来实现。

二、功能特点

  1. 支持多种地图内核,默认采用百度地图,可选高德地图、天地图、腾讯地图等。
  2. 同时支持在线地图和离线地图两种模式,离线地图方便在不联网的场景中使用。
  3. 支持各种地图控件的启用,比如地图导航、地图类型、缩略图、比例尺、全景导航、实时路况、绘图工具、结果面板等。
  4. 支持多种地图功能的动态启用禁用,比如地图拖曳、键盘操作、滚轮缩放、双击放大、连续缩放、地图测距等。
  5. 提供众多js函数接口用于交互,参数极其丰富,能够想到的应用场景需求都有。
  6. 统一的信号槽机制,地图中的结果统一信号发送出去,收到后根据type类型区分。
  7. 支持地图交互,比如鼠标按下获取对应位置的经纬度。单击标注点弹出对应点的信息。
  8. 支持添加标注、删除标注、移动标注、清空标注。
  9. 标注点可以指定图标图片和尺寸,支持gif动图,支持指定以图片中心对齐还是底部中心对齐。可以设置旋转角度,带富文本提示信息。
  10. 标注点事件支持单击发信号通知和自己弹框显示信息。
  11. 提供地址转坐标和坐标转地址接口。
  12. 支持各种图形绘制,包括折线图、多边形、矩形、圆形、弧线等。
  13. 可显示悬浮的绘图工具栏,直接在地图上划线、标注点、矩形、圆形等。
  14. 支持各种区域搜索,比如矩形区域、圆形区域,可以按照关键字匹配将搜索结果显示在地图中。
  15. 可动态添加离线的行政区边界点数据。可以搜索行政区划并获取该区域的边界点数据。数据可以保存到文件以便离线使用。
  16. 支持点聚合功能,多个小标注点合并到一个大标注点,防止点密集导致交互不友好。
  17. 可以添加海量点,每个点都可以单击获取对应坐标和信息。
  18. 所有的覆盖物信息比如标注点、矩形、多边形、折线图等,都可以主动获取对应的信息比如坐标点和路径等。
  19. 支持路径规划,支持公交路线、自驾路线、步行路线、骑行路线,不同查询支持不同策略,可选最少时间、最少换乘、不走高架等。
  20. 路径规划结果可以显示在地图中,也可以获取到路径点坐标集合。这个数据可以保存到文件,以便发给机器人或者无人机做导航用来轨迹移动。
  21. 可以设置不同的地图视图比如街道图、卫星图、混合图。
  22. 可以设置不同的样式,比如午夜蓝、青草绿等样式风格。
  23. 可以设置地图的旋转角度和倾斜角度。
  24. 提供经纬度坐标纠偏转换功能,比如传入的GPS坐标需要转换到百度地图坐标或者高德地图坐标。各种坐标系转换全部离线函数,支持地球坐标系WGS-84、火星坐标系GCJ-02、百度坐标系BD-09之间的互相转换,涵盖了各种地图的坐标系。
  25. 提供动态轨迹点移动功能,按照给定的经纬度坐标集合平滑移动。
  26. 同时支持qwidget和qml,支持编译到安卓系统运行。

三、使用说明

  1. 从左侧地图上鼠标按下选点,对应经纬度坐标会填充到坐标文本框中。填写好对应的标注的名称,单击添加标注按钮,左侧地图中会出现一个标注点,鼠标单击对应的标准点,会弹出提示单击了哪个标注点。
  2. 添加标注按钮的左侧是选择图片的类型,支持各种图片和尺寸,包括动图。默认图标文件在可执行文件下的mapimage目录。
  • 默认图标:不指定图片文件,每种地图都有自己内置风格的标注图片。
  • 水滴图标:指定一张水滴形状的图片,底部居中对齐。
  • 圆形图标:指定一张宽高一样的圆形图片,居中对齐。
  • 索引图标:指定一张大图,从中取固定位置的图标,网页中常见的方式。
  • 动画图标:指定一张gif动图文件,底部居中对齐。
  1. 在名称文本框中输入要删除的标注点名称,单击删除标注按钮,可以删除对应的标注点。
  2. 在名称文本框中输入要删除的标注点名称,然后左侧地图中鼠标选点,单击移动旋转按钮,会自动将标注点移动到新的位置,并设置45度旋转。
  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

五、效果图

在这里插入图片描述

六、相关代码

#include "frmmapdemomarker.h"
#include "ui_frmmapdemomarker.h"
#include "qthelper.h"
#include "maphelper.h"

frmMapDemoMarker::frmMapDemoMarker(QWidget *parent) : QWidget(parent), ui(new Ui::frmMapDemoMarker)
{
    ui->setupUi(this);
    this->initConfig();
}

frmMapDemoMarker::~frmMapDemoMarker()
{
    delete ui;
}

void frmMapDemoMarker::initConfig()
{
    ui->cboxIcon->setCurrentIndex(AppConfig::MapDemoIcon);
    connect(ui->cboxIcon, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig()));
}

void frmMapDemoMarker::saveConfig()
{
    AppConfig::MapDemoIcon = ui->cboxIcon->currentIndex();
    AppConfig::writeConfig();
}

void frmMapDemoMarker::receiveDataFromJs(const QString &type, const QVariant &data)
{
    //不可见不用继续/说明不是本界面的操作触发的
    if (!this->isVisible()) {
        return;
    }

    QString result = data.toString();
    if (type == "click") {
        QString point = MapHelper::getLngLat2(result);
        ui->txtPoint->setText(point);
    } else if (type == "marker") {
        QtHelper::showMessageBoxInfo("当前单击了: " + result);
    } else if (type == "geocoderresult") {
        QStringList list = result.split("|");
        QString flag = list.first();
        if (flag == "AddrToPoint") {
            QString point = MapHelper::getLngLat2(list.last());
            ui->txtPoint->setText(point);
        } else if (flag == "PointToAddr") {
            ui->txtAddr->setText(list.last());
        }
    } else if (type == "searchresult") {
        //搞个文本框用于显示获取到的结果
        static QTextEdit *edit = NULL;
        if (!edit) {
            edit = new QTextEdit;
            edit->resize(800, 600);
            edit->setReadOnly(true);
        }

        edit->setWindowTitle("搜索结果");
        edit->setText(MapHelper::getSearchResult(result));
        edit->show();
    }
}

void frmMapDemoMarker::on_btnAddMarker_clicked()
{
    QString name = ui->txtName->text().trimmed();
    QString point = ui->txtPoint->text().trimmed();

    QString image;
    int width = 23;
    int height = 25;
    bool center = false;
    static int index = -1;

    //可以指定本地图片文件或者网络图片/可设置图片的图标索引和尺寸等
    int icon = ui->cboxIcon->currentIndex();
    if (icon == 1) {
        image = "../mapimage/marker.png";
        width = 45;
        height = 65;
    } else if (icon == 2) {
        image = "../mapimage/marker0.png";
        width = 50;
        height = 50;
        center = true;
    } else if (icon == 3) {
        image = "../mapimage/ipc_red.png";
        width = 25;
        height = 30;
    } else if (icon == 4) {
        image = "../mapimage/markers.png";
        //image = "http://api.map.baidu.com/img/markers.png";
        index++;
        //图标有限重置索引
        if (index == 13) {
            index = 0;
        }
    } else if (icon == 5) {
        image = "../mapimage/gif_person.gif";
        width = 68;
        height = 100;
        //可以通过换行来实现垂直展示文字
        name = "垂<br/>直<br/>文<br/>字";
    }

    //可以测试不同的默认值参数
    QString js = QString("addMarker('%1', '%2', '%1')").arg(name).arg(point);
    js = QString("addMarker('%1', '%2', '%1', '%3')").arg(name).arg(point).arg(image);
    js = QString("addMarker('%1', '%2', '%1', '%3', %4, %5, %6, %7)").arg(name).arg(point).arg(image).arg(width).arg(height).arg(center).arg(index);
    emit runJs(js);

    //设置单击事件
    js = QString("setClick('%1', 2)").arg(name);
    emit runJs(js);

    //自动将序号递增
    if (name.startsWith("标注点")) {
        int index = name.mid(3, name.length()).toInt();
        name = QString("标注点%1").arg(index + 1);
        ui->txtName->setText(name);
    }
}

void frmMapDemoMarker::on_btnDeleteMarker_clicked()
{
    QString name = ui->txtName->text().trimmed();
    QString js = QString("deleteMarker('%1')").arg(name);
    emit runJs(js);
}

void frmMapDemoMarker::on_btnSetMarker_clicked()
{
    QString name = ui->txtName->text().trimmed();
    QString point = ui->txtPoint->text().trimmed();
    QString js = QString("setMarker('%1', '%2', %3)").arg(name).arg(point).arg(20);
    emit runJs(js);
}

void frmMapDemoMarker::on_btnClearMarker_clicked()
{
    emit runJs("deleteMarker()");
}

void frmMapDemoMarker::on_btnResetMarker_clicked()
{
    //先清空所有点
    on_btnClearMarker_clicked();

    //然后添加多个点/这里随机生成坐标
    QStringList names;
    names << "测试点1" << "测试点2" << "测试点3" << "测试点4" << "测试点5";
    for (int i = 0; i < names.count(); ++i) {
        QString point = QString("121.%1%2,31.%3%4").arg(rand() % 7).arg(rand() % 100).arg(rand() % 4).arg(rand() % 100);
        QString js = QString("addMarker('%1', '%2', '%1')").arg(names.at(i), point);
        emit runJs(js);
    }
}

void frmMapDemoMarker::on_btnAddrToPoint_clicked()
{
    QString addr = ui->txtAddr->text().trimmed();
    emit runJs(QString("getPointByAddr('AddrToPoint', '%1')").arg(addr));
}

void frmMapDemoMarker::on_btnPointToAddr_clicked()
{
    QString point = ui->txtPoint->text().trimmed();
    emit runJs(QString("getAddrByPoint('PointToAddr', '%1')").arg(point));
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2051684.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

类和对象 - 构造函数

文章目录 一、语言的向前兼容二、默认成员函数三、构造函数3.1 概念3.2 自己定义的构造函数3.2.1 有参和无参的构造函数3.2.1 有缺省参数的构造函数 3.3 默认构造函数3.3.1 几种默认构造函数3.3.2 默认构造函数的特点 3.4 编译器生成的默认构造函数3.4.1 函数初始化规则 四、构…

Android:动态更新app启动图标和应用名

一、需求背景 每逢重要佳节&#xff0c;很多应用启动图标会自动更新为对应佳节的图标&#xff0c;应用无需更新。 二、效果图 更新后的启动图标和应用名称 三、实现流程 Android app只能替换内置的icon&#xff0c;因此需要提前将logo图标放入App资源文件件里 实际项目App更新…

vue 路由用法 router-view

通过router-view 点击子路由显示子路由关于我们的内容&#xff0c;点击关于信息显示关于信息内容。

【Golang】火焰图空白部分是什么?

起因 被同事灵魂拷问&#xff1a;图中这块空白是什么东西&#xff1f; 豆包回答说是数据采样不完整&#xff0c;特定函数或代码段未被调用之类的原因&#xff0c;感觉都不太合理。 之前看过一篇文章说&#xff1a;Heap Profiling的采样是无时无刻不在发生的&#xff0c;执行…

【数据结构】——十大排序详解分析及对比

【数据结构】——十大排序详解分析及对比 文章目录 【数据结构】——十大排序详解分析及对比前言1. 排序的概念及其运用1.1 排序的概念1.2 排序的应用 2. 插入排序2.1 直接插入排序2.2 希尔排序 3. 选择排序3.1 选择排序3.2 堆排序 4 交换排序4.1 冒泡排序4.2 快速排序4.2.1 霍…

SOMEIP_ETS_047: echoUTF16FIXED_with_odd_number

测试目的&#xff1a; 验证设备&#xff08;DUT&#xff09;是否能够正确处理一个在终止符之后多出一个字节的echoUTF16FIXED字符串&#xff0c;并能够去除这个多余的字节。 描述 本测试用例旨在检查DUT在接收到一个不符合UTF16FIXED字符串规范&#xff08;即在终止符之后多…

Snipaste 的一款替代工具 PixPin,支持 gif 截图、长截图和 OCR 文字识别,功能不是一点点强!

Snipaste 的一款替代工具 PixPin&#xff0c;支持 gif 截图、长截图和 OCR 文字识别&#xff0c;功能不是一点点强&#xff01; PixPin 的名字来源于“Pixel Pin”&#xff0c;简单来说是一个截图、贴图的工具&#xff0c;但是 PixPin 以截图和贴图两大功能为核心做了大量的优…

高数4.3 分部积分法

1.性质 2.例题1-sin 有sinx ,cosx一定要想法变成一次方&#xff0c;有tanx,secx,cotx,cscx 要想法变换成偶次幂。 幂和三角函数在一次&#xff0c;要把三角函数放在d&#xff08;&#xff09;里面。 3. 例题2-tan 4. 例题3-反三角

树莓派开发笔记04-树莓派的PWM输出

github主页&#xff1a;https://github.com/snqx-lqh gitee主页&#xff1a;https://gitee.com/snqx-lqh 本项目github地址&#xff1a;https://github.com/snqx-lqh/RaspberryPiLearningNotes 本项目gitee地址&#xff1a;https://gitee.com/snqx-lqh/RaspberryPiLearningNote…

07结构型设计模式——装饰器模式

一、装饰器模式简介 装饰器模式&#xff08; Decorator Pattern&#xff09;又称包装模式。通过一种面向客户端透明的方式来扩展对象的功能&#xff0c;是继承关系的一个替换方案。装饰器模式就是把要添加的附加功能分别放在单独的类中&#xff0c;并让这个类包含它要装饰的对…

求前n项和5.3.1

求他的前n项和 #include <stdio.h>int main() {int n;int i;double sum0.0;scanf("%d", &n);for(i1; i<n; i){sum1.0/i;}printf("%f", sum);return 0; } 一个变量是输入的变量 一个变量要表达递增的 另外一个变量把他们加起来表示总和…

整数分解5.3.2

题 前面写过逆序的 最后一个数后面不要有空格 #include <stdio.h>int main() {int x;scanf("%d",&x);int d;do{dx%10;printf("%d",d);if(x>10){printf(" ");}x/10;}while(x>0);printf("\n");return 0; } 现在这个是…

0818---算法

牛牛快递 如何输入一个字符&#xff1f; java中Scanner类没有.nextChar import java.utol.Scanner; Scanner in new Scanner(System.in); char b in.next().charAt(0);思路&#xff1a; 创建一个Scanner对象&#xff0c;调用Scanner对象的next()方法获取控制台输入的字符串…

Java二十三种设计模式-备忘录模式(19/23)

本文深入探讨了备忘录模式&#xff0c;从定义、组成、实现到使用场景、优缺点、与其他模式的比较&#xff0c;以及最佳实践和替代方案&#xff0c;全面解析了如何在软件开发中有效地保存和恢复对象状态&#xff0c;以支持复杂的撤销操作和历史状态管理。 备忘录模式&#xff1a…

【JAVA OOP】Day09 抽象方法、抽象类、接口、引用类型数组

Day09目标&#xff1a; 理解抽象方法、抽象类的应用场景&#xff1b; 掌握抽象方法、抽象类的语法&#xff1b; 理解接口的应用场景&#xff1b; 掌握接口的语法、应用&#xff1b; 掌握引用类型数组的用法&#xff1b; 代码量&#xff1a;课上120行&#xff0c;课下240行…

AvaloniaChat—从源码构建指南

AvaloniaChat介绍 一个使用大型语言模型进行翻译的简单应用。 我自己的主要使用场景 在看英文文献的过程中&#xff0c;比较喜欢对照着翻译看&#xff0c;因此希望一边是英文一边是中文&#xff0c;虽然某些软件已经自带了翻译功能&#xff0c;但还是喜欢大语言模型的翻译&…

2-69 基于matlab的三坐标雷达目标跟踪数据融合

基于matlab的三坐标雷达目标跟踪数据融合,采用的是概率数据关联算法和EKF&#xff0c;展示了目标的真实轨迹和跟踪滤波轨迹&#xff0c;以及数据融合的轨迹。程序已调通&#xff0c;可直接运行。 2-69 三坐标雷达目标跟踪数据融合 - 小红书 (xiaohongshu.com)

『 Linux 』利用UDP套接字简单进行网络通信

文章目录 Socket常见API转网络字节序网络数据传输的读网络数据传输的写 简单的UDP网络程序服务端基本结构Init() 服务端的初始化Run() 服务端的运行服务端启动及测试 简单的UDP网络程序客户端服务端客户端相互通信测试服务端通过传入命令处理实现远程命令执行参考代码 Socket常…

STM32————串口发送和接收数据包

首先进行实验&#xff0c;对于代码在上一节的基础上&#xff0c;先定义新变量以及增加一个发送数据包函数&#xff1a; 本代码设置FF为包头&#xff0c;FE为包尾&#xff0c;中间为需要传输的数据&#xff0c;一次为4个&#xff0c;之后是接收数据包的函数 当标志位为1代表接收…

SpringBoot+Vue实现大文件上传(分片上传)

SpringBootVue实现大文件上传&#xff08;分片上传&#xff09; 1 环境 SpringBoot 3.2.1&#xff0c;Vue 2&#xff0c;ElementUI 2 问题 前几篇文章&#xff0c;可以用于较小文件的上传&#xff0c;对于较大文件来说&#xff0c;为了提高上传效率和可靠性&#xff0c;可以采…