Qt/C++百度地图/高德地图/天地图/腾讯地图/谷歌地图/加载绘图工具栏
一、前言说明
在地图中提供一个绘图工具栏,可以便捷的在地图上添加各种覆盖物,比如折线、多边形、矩形、圆形等,然后可以获取这些覆盖物的路径以及中心点等属性。这里有几个小插曲,比如百度地图gl版本默认不提供这个功能,是通过引入第三方的开源的js文件来实现的。还有个惊喜就是天地图一开始也以为没有这个功能,翻遍了文档才发现提供了militarySymbols这个控件,非常强大,居然提供了几十种形状,而且有各种箭头形状,满足了更多的场景需求,说实话这点还是很惊讶的。
高德地图并没有提供绘图工具栏悬浮条,但是提供了对应的函数处理,所以可以自定义一个工具栏用来处理。腾讯地图一开始也是以为没有,后面才发现有个drawing.DrawingManager控件,添加到地图上,默认顶部居中展示绘图工具栏。
二、功能特点
- 支持多种地图内核,默认采用百度地图,可选高德地图、天地图、腾讯地图、谷歌地图等。
- 同时支持在线地图和离线地图两种模式,离线地图方便在不联网的场景中使用。
- 支持各种地图控件的启用,比如地图导航、地图类型、缩略图、比例尺、全景导航、实时路况、绘图工具、结果面板等。
- 支持多种地图功能的动态启用禁用,比如地图拖曳、键盘操作、滚轮缩放、双击放大、连续缩放、地图测距等。
- 提供众多js函数接口用于交互,参数极其丰富,能够想到的应用场景需求都有。
- 统一的信号槽机制,地图中的结果统一信号发送出去,收到后根据type类型区分。
- 支持地图交互,比如鼠标按下获取对应位置的经纬度。单击标注点弹出对应点的信息。
- 支持添加标注、删除标注、移动标注、清空标注。
- 标注点可以指定图标图片和尺寸,支持gif动图,支持指定以图片中心对齐还是底部中心对齐。可以设置旋转角度,带富文本提示信息。
- 标注点事件支持单击发信号通知和自己弹框显示信息。
- 提供地址转坐标和坐标转地址接口。
- 支持各种图形绘制,包括折线图、多边形、矩形、圆形、弧线等。
- 可显示悬浮的绘图工具栏,直接在地图上划线、标注点、矩形、圆形等。
- 支持各种区域搜索,比如矩形区域、圆形区域,可以按照关键字匹配将搜索结果显示在地图中。
- 可动态添加离线的行政区边界点数据。可以搜索行政区划并获取该区域的边界点数据。数据可以保存到文件以便离线使用。
- 支持点聚合功能,多个小标注点合并到一个大标注点,防止点密集导致交互不友好。
- 可以添加海量点,每个点都可以单击获取对应坐标和信息。
- 所有的覆盖物信息比如标注点、矩形、多边形、折线图等,都可以主动获取对应的信息比如坐标点和路径等。
- 支持路径规划,支持公交路线、自驾路线、步行路线、骑行路线,不同查询支持不同策略,可选最少时间、最少换乘、不走高架等。
- 路径规划结果可以显示在地图中,也可以获取到路径点坐标集合。这个数据可以保存到文件,以便发给机器人或者无人机做导航用来轨迹移动。
- 可以设置不同的地图视图比如街道图、卫星图、混合图。
- 可以设置不同的样式,比如午夜蓝、青草绿等样式风格。
- 可以设置地图的旋转角度和倾斜角度。
- 提供经纬度坐标纠偏转换功能,比如传入的GPS坐标需要转换到百度地图坐标或者高德地图坐标。各种坐标系转换全部离线函数,支持地球坐标系WGS-84、火星坐标系GCJ-02、百度坐标系BD-09之间的互相转换,涵盖了各种地图的坐标系。
- 提供动态轨迹点移动功能,按照给定的经纬度坐标集合平滑移动。
- 同时支持qwidget和qml,支持编译到安卓系统运行。
三、使用说明
四、相关链接
- 体验地址:https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A 提取码:o05q 名称:bin_map.zip
- 国内站点:https://gitee.com/feiyangqingyun
- 国际站点:https://github.com/feiyangqingyun
五、效果图
六、相关代码
void MapObjBaiDu::addDrawingTool()
{if (!(mapControl & MapControl_Drawing)) {return;}//初始化绘图工具栏html << QString(" var styleOptions = getOverlayProperty();");html << QString(" var drawingManager = new BMapLib.DrawingManager(map, {");html << QString(" isOpen:false,");html << QString(" enableDrawingTool:true,");html << QString(" drawingToolOptions:{anchor:BMAP_ANCHOR_TOP_RIGHT, offset:new BMap.Size(100, 5)},");html << QString(" circleOptions:styleOptions, polylineOptions:styleOptions, polygonOptions:styleOptions, rectangleOptions:styleOptions");html << QString(" });");//添加监听事件获取绘制结果html << QString(" drawingManager.addEventListener('overlaycomplete', function(e) {");html << QString(" overlays.push(e.overlay);");html << QString(" receiveData('overlaycomplete');");html << QString(" });");//执行指定的绘制动作html << QString(" function doDraw(type) {");html << QString(" drawingManager.close();");html << QString(" if (type == 'marker') {");html << QString(" drawingManager.setDrawingMode(BMAP_DRAWING_MARKER);");html << QString(" } else if (type == 'polyline') {");html << QString(" drawingManager.setDrawingMode(BMAP_DRAWING_POLYLINE);");html << QString(" } else if (type == 'polygon') {");html << QString(" drawingManager.setDrawingMode(BMAP_DRAWING_POLYGON);");html << QString(" } else if (type == 'rectangle') {");html << QString(" drawingManager.setDrawingMode(BMAP_DRAWING_RECTANGLE);");html << QString(" } else if (type == 'circle') {");html << QString(" drawingManager.setDrawingMode(BMAP_DRAWING_CIRCLE);");html << QString(" }");html << QString(" if (type != 'cancel') {");html << QString(" drawingManager.open();");html << QString(" }");html << QString(" }");
}void MapObjGaoDe::addDrawingTool()
{//初始化鼠标绘制工具/高德没有悬浮的工具栏/需要自己写网页实现html << QString(" var mouseTool;");html << QString(" function initDraw() {");html << QString(" if (mouseTool) {return}");html << QString(" mouseTool = new AMap.MouseTool(map);");html << QString(" mouseTool.on('draw', function(e) {");html << QString(" var overlay = e.obj;");html << QString(" var type = getOverlayType(overlay);");html << QString(" clickEditor(type, overlay);");html << QString(" overlays.push(overlay);");html << QString(" });");html << QString(" }");//执行指定的绘制动作html << QString(" function doDraw(type) {");html << QString(" initDraw();");html << QString(" var styleOptions = {};");html << QString(" //styleOptions = {fillColor:'#ff0000', strokeColor:'#ff0000'};");html << QString(" if (type == 'marker') {");html << QString(" mouseTool.marker({icon:'../mapimage/marker_min.png'});");html << QString(" } else if (type == 'polyline') {");html << QString(" mouseTool.polyline(styleOptions);");html << QString(" } else if (type == 'polygon') {");html << QString(" mouseTool.polygon(styleOptions);");html << QString(" } else if (type == 'rectangle') {");html << QString(" mouseTool.rectangle(styleOptions);");html << QString(" } else if (type == 'circle') {");html << QString(" mouseTool.circle(styleOptions);");html << QString(" } else {");html << QString(" mouseTool.close();");html << QString(" }");html << QString(" }");//识别单击事件切换编辑器html << QString(" function clickEditor(type, overlay) {");html << QString(" overlay.off('click');");html << QString(" overlay.on('click', function(e) {");html << QString(" initEditor(edit ? type : '', e.target);");html << QString(" if (editor) {");html << QString(" editor.open();");html << QString(" }");html << QString(" });");html << QString(" }");//初始化覆盖物对应的编辑对象/高德地图通过编辑器来实现编辑html << QString(" var editor = null;");html << QString(" function initEditor(type, overlay) {");html << QString(" if (editor) {");html << QString(" editor.close();");html << QString(" editor = null;");html << QString(" }");html << QString(" if (type == 'polyline') {");html << QString(" editor = new AMap.%1(map, overlay);").arg(polylineEditor);html << QString(" } else if (type == 'polygon') {");html << QString(" editor = new AMap.%1(map, overlay);").arg(polygonEditor);html << QString(" } else if (type == 'rectangle') {");html << QString(" editor = new AMap.%1(map, overlay);").arg(rectangleEditor);html << QString(" } else if (type == 'circle') {");html << QString(" editor = new AMap.%1(map, overlay);").arg(circleEditor);html << QString(" }");html << QString(" }");//启用禁用编辑html << QString(" var edit = false;");html << QString(" function enableEdit(enable) {");html << QString(" edit = enable;");html << QString(" if (!edit && editor) {");html << QString(" editor.close();");html << QString(" editor = null;");html << QString(" }");//标注点单独设置可拖动/非标注点全部采用编辑对象html << QString(" for (var i = 0; i < overlays.length; ++i) {");html << QString(" var overlay = overlays[i];");html << QString(" if (overlay instanceof AMap.Marker) {");html << QString(" overlay.setDraggable(edit);");html << QString(" }");html << QString(" }");html << QString(" }");
}void MapObjGoogle::addDrawingTool()
{if (!(mapControl & MapControl_Drawing)) {return;}//初始化绘图工具栏html << QString(" var styleOptions = getOverlayProperty();");html << QString(" var drawingManager = new GMap.drawing.DrawingManager({");html << QString(" drawingControl:true,");html << QString(" drawingControlOptions:{position:GMap.ControlPosition.TOP_CENTER},");html << QString(" circleOptions:styleOptions, polylineOptions:styleOptions, polygonOptions:styleOptions, rectangleOptions:styleOptions");html << QString(" });");html << QString(" drawingManager.setMap(map);");//添加监听事件获取绘制结果html << QString(" GMap.event.addListener(drawingManager, 'overlaycomplete', function(e) {");html << QString(" var overlay = e.overlay;");html << QString(" overlay.type = e.type;");html << QString(" overlays.push(overlay);");html << QString(" });");//执行指定的绘制动作html << QString(" function doDraw(type) {");html << QString(" drawingManager.setDrawingMode(null);");html << QString(" if (type == 'marker') {");html << QString(" drawingManager.setDrawingMode(GMap.drawing.OverlayType.MARKER);");html << QString(" } else if (type == 'polyline') {");html << QString(" drawingManager.setDrawingMode(GMap.drawing.OverlayType.POLYLINE);");html << QString(" } else if (type == 'polygon') {");html << QString(" drawingManager.setDrawingMode(GMap.drawing.OverlayType.POLYGON);");html << QString(" } else if (type == 'rectangle') {");html << QString(" drawingManager.setDrawingMode(GMap.drawing.OverlayType.RECTANGLE);");html << QString(" } else if (type == 'circle') {");html << QString(" drawingManager.setDrawingMode(GMap.drawing.OverlayType.CIRCLE);");html << QString(" }");html << QString(" }");
}void MapObjTian::addDrawingTool()
{//执行指定的绘制动作/每次绘制完成都会自动关闭/需要拦截事件重新开启html << QString(" var mouseTool;");html << QString(" function doDraw(type) {");html << QString(" if (mouseTool) {");html << QString(" mouseTool.close();");html << QString(" mouseTool = null;");html << QString(" }");html << QString(" if (type == 'marker') {");html << QString(" mouseTool = new T.MarkTool(map, {follow: true});");html << QString(" mouseTool.addEventListener('mouseup', function(e) {");html << QString(" overlays.push(e.currentMarker);");html << QString(" openDraw();");html << QString(" });");html << QString(" } else if (type == 'polyline') {");html << QString(" mouseTool = new T.PolylineTool(map);");html << QString(" mouseTool.addEventListener('draw', function(e) {");html << QString(" overlays.push(e.currentPolyline);");html << QString(" openDraw();");html << QString(" });");html << QString(" } else if (type == 'polygon') {");html << QString(" mouseTool = new T.PolygonTool(map);");html << QString(" mouseTool.addEventListener('draw', function(e) {");html << QString(" overlays.push(e.currentPolygon);");html << QString(" openDraw();");html << QString(" });");html << QString(" } else if (type == 'rectangle') {");html << QString(" mouseTool = new T.RectangleTool(map);");html << QString(" mouseTool.addEventListener('draw', function(e) {");html << QString(" overlays.push(e.currentRectangle);");html << QString(" openDraw();");html << QString(" });");html << QString(" } else if (type == 'circle') {");html << QString(" mouseTool = new T.CircleTool(map, {follow: true});");html << QString(" mouseTool.addEventListener('drawend', function(e) {");html << QString(" overlays.push(e.currentCircle);");html << QString(" openDraw();");html << QString(" });");html << QString(" }");html << QString(" if (type != 'cancel') {");html << QString(" mouseTool.open();");html << QString(" }");html << QString(" }");//延时打开鼠标绘制工具html << QString(" function openDraw() {");html << QString(" setTimeout(function(){mouseTool.open()}, 100);");html << QString(" }");
}
相关文章:

Qt/C++百度地图/高德地图/天地图/腾讯地图/谷歌地图/加载绘图工具栏
一、前言说明 在地图中提供一个绘图工具栏,可以便捷的在地图上添加各种覆盖物,比如折线、多边形、矩形、圆形等,然后可以获取这些覆盖物的路径以及中心点等属性。这里有几个小插曲,比如百度地图gl版本默认不提供这个功能…...
Vue2 与 Vue3 的区别有哪些
Vue 2 和 Vue 3 在许多方面都有显著的区别,包括性能、API 设计、功能特性等。以下是它们主要的区别: 1. 响应式系统 Vue 2: 基于 Object.defineProperty: Vue 2 使用 Object.defineProperty 来实现响应式数据。这种方法在处理对象属性时有一定的局限性…...
加锁造成的线程优先级反转
优先级反转(Priority Inversion),也称优先级翻转,一般是在优先级不同的多线程环境中发生。在桌面操作系统中,线程的优先级不是太重要,因此较少见优先级反转的现象。但是,优先级反转是实时操作系统(RTOS)中一个常见的问题,特别是在采用优先级调度算法的系统中。这个问…...
【日常记录-Java】SpringBoot中使用无返回值的异步方法
Author:赵志乾 Date:2024-09-05 Declaration:All Right Reserved!!! 1. 简介 在SpringBoot中,使用Async注解可以很方便地标记一个方法为异步执行。好处是调用者无需等待这些方法完成便可继续执…...

【深度学习】多层感知机的从零开始实现与简洁实现
可以说,到现在我们才真正接触到深度网络。最简单的深度网络称为多层感知机。 多层感知机由多层神经元组成,每一层与它的上一层相连,从中接收输入;同时每一层也与它的下一层相连,影响当前层的神经元。 和以前相同&…...

4、Django Admin对自定义的计算字段进行排序
通常,Django会为模型属性字段,自动添加排序功能。当你添加计算字段时,Django不知道如何执行order_by,因此它不会在该字段上添加排序功能。 如果要在计算字段上添加排序,则必须告诉Django需要排序的内容。你可以通过在…...

rsync搭建全网备份
rsync搭建全网备份 1. 总体概述1.1 目标1.2 简易指导图1.3 涉及工具或命令1.4 环境 2. 实施2.1 配置备份服务器2.2 备份文件准备2.3 整合命令2.4 扩展功能 1. 总体概述 1.1 目标 本次搭建目标: 每天定时把服务器数据备份到备份服务器备份完成后进行校验把过期数据…...

网络安全售前入门09安全服务——安全加固服务
目录 1.服务概述 2.流程及工具 2.1服务流程 2.2服务工具 3.服务内容 4.服务方式 5.风险规避措施 6.服务输出 1.服务概述 安全加固服务是参照风险评估、等保测评、安全检查等工作的结果,基于科学的安全思维方式、长期的安全…...
【Android】GreenDao数据库的使用方式
需求 使用GreenDao数据库进行数据的存储。 介绍 GreenDao 是一个轻量级的对象关系映射(ORM)库,用于简化 Android 应用中的数据库操作。它提供了以下主要功能: 简化数据库操作:通过注解定义实体类,Green…...
搜索算法之线性搜索详细解读(附带Java代码解读)
1. 基本概念 线性搜索(Linear Search),也称为顺序搜索,是一种在列表中查找特定元素的算法。它从列表的第一个元素开始,逐个检查每个元素,直到找到目标元素或检查完所有元素。 2. 工作原理 线性搜索的操作…...

Quartz.Net_依赖注入
简述 有时会遇到需要在IJob实现类中依赖注入其他类或接口的情况,但Quartz的默认JobFactory并不能识别具有有参构造函数的IJob实现类,也就无法进行依赖注入 需要被依赖注入的类: public class TestClass {public TestClass(Type jobType, s…...

【系统架构设计师-2011年】综合知识-答案及详解
更多内容请见: 备考系统架构设计师-核心总结索引 文章目录 【第1题】【第2~4题】【第5~7题】【第8题】【第9题】【第10题】【第11题】【第12题】【第13题】【第14题】【第15题】【第16题】【第17题】【第18~19题】【第20~21题】【第22题】【第23题】【第24题】【第25题】【第2…...

World of Warcraft [CLASSIC][80][Grandel]Sapphire Hive Drone
Sapphire Hive Drone 蓝玉虫巢雄蜂 蓝玉虫巢巨峰 索拉查盆地 实用性不强,好看是好看,模型很大,无奈栏位太少...
Unity 对接 Android 第三方广告,App 切换到后台后,再次打开时,第三方广告被销毁导致无法触发回调逻辑的问题
该问题是由发行进行游戏测试时遇到并反馈的。大致情况如下: 1. 当触发了插屏广告后,在关闭广告前将 App 切换到后台,之后再次打开 App,此时插屏广告消失,并切游戏卡死。 2. 当触发激励视频广告后,在广告展…...
Kafka Broker处于高负载状态(例如消息处理量大或系统资源不足),无法及时响应消费者的请求
Caused by: org.apache.kafka.common.errors.TimeoutException: Timeout of 60000ms expired before the position for partition activity-0 could be determined。 出现这个错误的原因是Kafka消费者在尝试获取分区(activity-0)的位置信息时,超时了。在60秒内无法确…...

相关二叉树进阶面试题的讲解?看这一篇足矣
引子:我们在之前学过c语言的二叉树,但是c来做更好!本期要讲的题目如下(其实有点拖欠了,很久之前,就想写这个了,今天终于克服自己的欲望,达成了这个愿望) 1, 二叉树创建字…...
Nginx部署前端Vue项目的深度解析
目录 一、准备工作 1.1 开发环境 1.2 服务器环境 1.3 Nginx安装 二、构建Vue项目 三、上传静态文件到服务器 四、配置Nginx 五、测试并重新加载Nginx 六、访问Vue应用 七、高级配置 7.1 启用HTTPS 7.2 启用Gzip压缩 7.3 缓存控制 八、常见问题与解决方案 8.1 40…...

PHP一站式解决方案高级房产系统小程序源码
一站式解决方案,高级房产系统让房产管理更轻松 🏠【开篇:告别繁琐,迎接高效房产管理新时代】🏠 你是否还在为房产管理的繁琐流程而头疼?从房源录入、客户咨询到合同签订、售后服务,每一个环节…...

轻量级模型解读——EfficientNet系列
EfficientNet自2019年谷歌提出以来,经历了三个版本,2019EfficientNet ——> 2020EfficientNet-Lite——> 2021EfficientNetv2 文章目录 1、EfficientNet2、EfficientNetv23、EfficientNet-Lite 对于EfficientNet和EfficientNetv2的解读可见另外两篇…...

深入浅出SRS—RTMP实现
RTMP 直播是 SRS 最典型的使用场景,客户端使用 RTMP 协议向 SRS 推流,使用 RTMP 协议从 SRS 拉流,SRS 作为一个 RTMP 直播服务器实现媒体的转发。同时,RTMP 是 SRS 的中转协议,其他协议之间的互通需要先转为 RTMP&…...

css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...

Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...

MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...

Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…...