QGraphicsView实现简易地图5『经纬网格』
前文链接:QGraphicsView实现简易地图4『局部加载-地图漫游』
由于GCJ02 Web 墨卡托投影 纬度并不随像素等分,且两极跨度较大,因此本次演示采用的经纬网等分逻辑为等分像素。同等像素跨度之间,两级纬度变化较小,越靠近赤道附近纬度变化越大。以下将提供实现此需求的核心代码。
1、动态演示效果
2、静态展示图片

核心代码
void MapView::showGraticules()
{// 计算等分像素后的经纬度步长int gridCount = MapUtility::graticulesGridCount(m_curLevel);int mapSideCount = apUtility::mapSideCount(m_curLevel);double perLon = PIXMAP_SIZE * mapSideCount * 1.0 / gridCount;double perLat = perLon;// 计算呈现的瓦片地图左上角和右下角的场景坐标QPoint topLeftScenePos(m_topLeftTileCoord.x * PIXMAP_SIZE, m_topLeftTileCoord.y * PIXMAP_SIZE);QPoint bottomRightScenePos((m_bottomRightTileCoord.x + 1) * PIXMAP_SIZE, (m_bottomRightTileCoord.y + 1) * PIXMAP_SIZE);// 计算经纬线覆盖范围,此处采用的逻辑是经纬网覆盖区域>=呈现的瓦片地图区域int leftGridIndex = qFloor(topLeftScenePos.x() / perLon);int rightGridIndex = qCeil(bottomRightScenePos.x() / perLon);int topGridIndex = qFloor(topLeftScenePos.y() / perLat);int bottomGridIndex = qCeil(bottomRightScenePos.y() / perLat);if (leftGridIndex < 0)leftGridIndex = 0;if (rightGridIndex > gridCount)rightGridIndex = gridCount;if (topGridIndex < 0)topGridIndex = 0;if (bottomGridIndex > gridCount)bottomGridIndex = gridCount;// 视口宽度和高度int vw = viewport()->width();int vh = viewport()->height();// 场景宽度和高度int sw = MapUtility::sceneSize(m_curLevel);int sh = sw;// 视口右下角对应场景坐标QPointF bottomRightViewToScenePos = mapToScene(viewport()->rect().bottomRight());// 经纬网线条颜色、文本颜色QColor gridLineColor(255, 163, 70);QColor textColor(Qt::white);// 绘制经纬网:纬度线for (int row = topGridIndex; row <= bottomGridIndex; ++row){ // 纬度线double sceneY = row * perLat;QGraphicsLineItem *item = m_scene->addLine(topLeftScenePos.x(), sceneY, bottomRightScenePos.x(), sceneY);item->setPen(QPen(gridLineColor, 1, Qt::DotLine));item->setZValue(50);m_vecGraticulesItems.append(item);// 纬度文本double lat = MapUtility::latFromSceneY(sceneY, m_curLevel);QGraphicsTextItem *textItem = m_scene->addText(CommonUtility::convertToDMSLatSymbol(lat));textItem->setDefaultTextColor(Qt::white);QFont font = textItem->font();font.setFamily("微软雅黑");textItem->setFont(font);// 调整文本位置QRectF textBoundingRect = textItem->boundingRect();int sceneX = sw <= vw ? bottomRightScenePos.x() : bottomRightViewToScenePos.x();textItem->setPos(sceneX - textItem->boundingRect().width(), sceneY - textBoundingRect.height() / 2);m_vecGraticulesTextItems.append(textItem);}// 绘制经纬网:经度线for (int col = leftGridIndex; col <= rightGridIndex; ++col){// 经度线double sceneX = col * perLon;QGraphicsLineItem *item = m_scene->addLine(sceneX, topLeftScenePos.y(), sceneX, bottomRightScenePos.y());item->setPen(QPen(gridLineColor, 1, Qt::DotLine));item->setZValue(50);m_vecGraticulesItems.append(item);// 经度文本double lon = MapUtility::lonFromSceneX(sceneX, m_curLevel);QGraphicsTextItem *textItem = m_scene->addText(CommonUtility::convertToDMSLonSymbol(lon));textItem->setDefaultTextColor(Qt::white);QFont font = textItem->font();font.setFamily("微软雅黑");textItem->setFont(font);// 调整文本位置QRectF textBoundingRect = textItem->boundingRect();int sceneY = sh <= vh ? bottomRightScenePos.y() : bottomRightViewToScenePos.y();textItem->setPos(sceneX - textBoundingRect.width() / 2, sceneY - textItem->boundingRect().height());m_vecGraticulesTextItems.append(textItem);}
}
辅助代码
void CommonUtility::convertToDMS(double value, int &d, int &m, int &s)
{d = (int)(value); m = (int)((value - d) * 60);s = (int)(((value - d) * 60 - m) * 60);// 四舍五入float e = ((value - d) * 60 - m) * 60 - s;if (5 <= (int)(e * 10))s += 1;// 秒进位if (60 == s){s = 0;m += 1;}// 分进位if (60 == m){m = 0;d += 1;}
}QString CommonUtility::convertToDMS(double value)
{int d, m, s;convertToDMS(value, d, m, s);QString strM = QString::number(m).rightJustified(2, '0');QString strS = QString::number(s).rightJustified(2, '0');return QString("%1°%2′%3″").arg(d).arg(strM).arg(strS);
}QString CommonUtility::convertToDMSLonSymbol(double value)
{return QString("%1%2").arg(convertToDMS(fabs(value))).arg(value > 0 ? "E" : (value != 0 ? "W" : ""));
}QString CommonUtility::convertToDMSLatSymbol(double value)
{return QString("%1%2").arg(convertToDMS(fabs(value))).arg(value > 0 ? "N" : (value != 0 ? "S" : ""));
}
相关文章:
QGraphicsView实现简易地图5『经纬网格』
前文链接:QGraphicsView实现简易地图4『局部加载-地图漫游』 由于GCJ02 Web 墨卡托投影 纬度并不随像素等分,且两极跨度较大,因此本次演示采用的经纬网等分逻辑为等分像素。同等像素跨度之间,两级纬度变化较小,越靠近赤…...
RestTemplate 请求转发异常 ERR_CONTENT_DECODING_FAILED 200 (OK)
#1 问题描述 在基于Spring Boot的项目中实现了请求转发(使用 RestTemplate 的 exchange 方法)的功能,忽然在前端报net::ERR_CONTENT_DECODING_FAILED 200 (OK)的错误,后端及上游系统日志均显示请求已完成。 #2 原因探寻 上述错…...
用python实现一个异或计算器
有这样一条需求:计算某个文件中的数组每一行元素的最后一个参数,异或输出。 因为元素比较多,十几行,通过人工去计算异或值非常困难。 而在线异或的计算器,也需要人为输入这些数值,每次计算一个最终结果需…...
Sketch打不开AI文件?转换方法在这里
1、对比设计软件 Sketch 与 AI 软件功能 Sketch 与 Illustrator 都是行业内优秀的矢量图形设计软件,各有千秋。Sketch 从 2010 年面世,专注 APP 界面设计,深受初学者与专业人士喜爱。Illustrator 拥有更悠久的历史,是处理复杂图标…...
小游戏扫雷实现教学(详解)
目录 【前言】 一、模块化程序设计(多文件编程)介绍 1.概述 2.传统编程的方式 3.模块化程序设计的方法 二、扫雷代码设计思路 三、扫雷代码设计 1.创建菜单函数 2.实现9x9扫雷 3.初始化棋盘 4.打印棋盘 5.随机布置雷的位置 6.排查雷的信息 7.回…...
04 mysql innodb record
前言 最近看到了 何登成 大佬的 "深入MySQL源码 -- Step By Step" 的 pdf 呵呵 似乎是找到了一些 方向 之前对于 mysql 方面的东西, 更多的仅仅是简单的使用[业务中的各种增删改查], 以及一些面试题的背诵 这里会参照 MySQL Internals Manual 来大致的看一下 i…...
Centos7安装Docker
0.安装Docker Docker 分为 CE 和 EE 两大版本。CE 即社区版(免费,支持周期 7 个月),EE 即企业版,强调安全,付费使用,支持周期 24 个月。 Docker CE 分为 stable test 和 nightly 三个更新频道…...
Vue中如何更好地封装组件?
子组件接受父组件传递的事件 1.子组件使用事件名"$emit(父组件中传递的事件名,想给父组件传递的参数(可选))" click"$emit(click)" 2.子组件使用 v-on"$listeners" 父组件: <template><div id"app"><myCo…...
C语言的链表的相关操作
本变博客源于自己想复习一下C语言,所以便自己动手复习了一下链表的相关操作。做个人记录使用。 main.c #include <stdio.h> #include "list.h"int main() {student *a;printf("hello world\n") ;printf("----初始化列表----------\…...
Python3中typing模块
Python类型注解是Python 3.5版本之后引入的新特性,它可以让开发者在函数、变量等声明时为其指定类型。typing模型能够声明类型,防止运行时出现参数和返回值类型不符合的问题。 ### 1. 基本类型注解 def hello(name: str) -> str:return (Hello, na…...
C语言自动抓取淘宝商品详情网页数据,实现轻松高效爬虫
你是否曾经遇到过需要大量获取网页上的数据,但手动复制粘贴又太过费时费力?那么这篇文章就是为你而写。今天我们将会详细讨论如何使用C语言实现自动抓取网页上的数据。本文将会从以下8个方面进行逐步分析讨论。 1. HTTP协议的基本原理 在开始之前&…...
数据结构---跳表
目录标题 为什么会有跳表跳表的原理跳表的模拟实现准备工作find函数insert函数erase函数 测试效率比较 为什么会有跳表 在前面的学习过程中我们学习过链表这个容器,这个容器在头部和尾部插入数据的时间复杂度为O(1),但是该容器存在一个缺陷就是不管数据…...
为什么Tomcat的NIO在读取body时要模拟阻塞?
文章首发地址 Tomcat的NIO完全可以以非阻塞方式处理IO,为什么在读取body部分时要模拟阻塞呢?在Tomcat的NIO读取HTTP请求时,为了保证请求的正确性和可靠性,需要模拟阻塞模式,这是因为servlet规范里定义了ServletInputSt…...
26 | 谷歌应用APP数据分析
基于kaggle公开数据集,对谷歌应用市场的APP情况进行数据探索和分析。 from kaggle: https://www.kaggle.com/lava18/google-play-store-apps 分析思路: 0、数据准备 1、数据概览 2、种类对Rating的影响 3、定价策略 4、因素相关性分析 5、用户评价 6、总结 0、数据准备 (…...
BFS 五香豆腐
题目描述 经过谢老师n次的教导,dfc终于觉悟了——过于腐败是不对的。但是dfc自身却无法改变自己,于是他找到了你,请求你的帮助。 dfc的内心可以看成是5*5个分区组成,每个分区都可以决定的的去向,0表示继续爱好腐败&…...
opencv实战项目 手势识别-手势控制键盘
手势识别是一种人机交互技术,通过识别人的手势动作,从而实现对计算机、智能手机、智能电视等设备的操作和控制。 1. opencv实现手部追踪(定位手部关键点) 2.opencv实战项目 实现手势跟踪并返回位置信息(封装调用&am…...
1.作用域
1.1局部作用域 局部作用域分为函数作用域和块作用域。 1.函数作用域: 在函数内部声明的变量只能在函数内部被访问,外部无法直接访问。 总结: (1)函数内部声明的变量,在函数外部无法被访问 (2)函数的参数也是函数内部的局部变量 (3)不同函数…...
黑马B站八股文学习笔记
视频地址:https://www.yuque.com/linxun-bpyj0/linxun/vy91es9lyg7kbfnr 大纲 基础篇 基础篇要点:算法、数据结构、基础设计模式 1. 二分查找 要求 能够用自己语言描述二分查找算法能够手写二分查找代码能够解答一些变化后的考法 算法描述 前提&a…...
前端常用的上传下载文件的几种方式,直接上传、下载文件,读取.xlsx文件数据,导出.xlsx数据
一、通过调用接口下载文件 const onExport async () > {try {let res await axios.request({method: POST,url: 请求地址,responseType: blob,params: { data: null },headers: { Authorization: Bearer UserModule.token },//看看请求是否需要token});let reader new…...
FPGA应用学习笔记--时钟域的控制 亚稳态的解决
时钟域就是同一个时钟的区域,体现在laways语句边缘触发语句中,设计规模增大就会导致时钟不同步,有时差,就要设计多时钟域。 会经过与门的延时产生的新时钟域,这种其实不推荐使用,但在ascl里面很常见 在处理…...
终极免费PCB查看器:3分钟掌握OpenBoardView电路板分析技巧
终极免费PCB查看器:3分钟掌握OpenBoardView电路板分析技巧 【免费下载链接】OpenBoardView View .brd files 项目地址: https://gitcode.com/gh_mirrors/op/OpenBoardView 还在为复杂的.brd文件头疼吗?面对密密麻麻的电路板元件不知所措ÿ…...
STM32驱动WS2812的另一种思路:SPI模拟时序对比PWM方案,哪个更适合你的项目?
STM32驱动WS2812的深度方案对比:SPI模拟与PWM实现的技术解析与选型指南 在嵌入式LED控制领域,WS2812系列智能灯珠因其集成驱动电路和单线通信特性,已成为项目开发中的热门选择。面对不同应用场景对刷新率、稳定性和资源占用的差异化需求&…...
AGI学派认知鸿沟正在扩大:3类不可调和的根本分歧(本体论/学习机制/验证标准),92%的研究者尚未意识到其后果
第一章:AGI学派认知鸿沟正在扩大:3类不可调和的根本分歧(本体论/学习机制/验证标准),92%的研究者尚未意识到其后果 2026奇点智能技术大会(https://ml-summit.org) 当前AGI研究正经历一场静默的范式撕裂:三…...
【AGI医疗应用黄金窗口期】:2024年三大临床落地场景与72小时快速验证路径
第一章:AGI的医疗应用前景展望 2026奇点智能技术大会(https://ml-summit.org) 通用人工智能(AGI)正从理论构想加速迈向临床验证阶段,其在医疗健康领域的渗透已超越传统AI的单点优化范式,转向跨模态理解、动态推理与自…...
从零到一:基于Matlab与fruits-360数据集的水果识别实战
1. 环境准备与数据获取 第一次接触水果识别项目时,我完全被各种专业术语和复杂的代码吓到了。后来发现用Matlab的Deep Learning Toolbox配合fruits-360数据集,整个过程竟然可以如此简单。下面我就把踩过的坑和验证过的经验分享给大家。 首先需要准备的是…...
GitHub汉化插件终极指南:3分钟实现全中文界面,告别语言障碍
GitHub汉化插件终极指南:3分钟实现全中文界面,告别语言障碍 【免费下载链接】github-hans [废弃] {官方中文马上就来了} GitHub 汉化插件,GitHub 中文化界面。 (GitHub Translation To Chinese) 项目地址: https://gitcode.com/gh_mirrors/…...
想用Anti-UAV数据集练手无人机跟踪?这份保姆级下载、标注与使用指南请收好
Anti-UAV数据集实战:从零开始掌握无人机多模态跟踪技术 无人机跟踪技术正在成为计算机视觉领域的热点研究方向。对于刚接触这个领域的研究者和开发者来说,Anti-UAV数据集提供了一个绝佳的实践平台。这个多模态数据集不仅包含常规的RGB视频,还…...
Figma中文汉化插件终极指南:3分钟告别英文界面困扰
Figma中文汉化插件终极指南:3分钟告别英文界面困扰 【免费下载链接】figmaCN 中文 Figma 插件,设计师人工翻译校验 项目地址: https://gitcode.com/gh_mirrors/fi/figmaCN 还在为Figma的英文界面而烦恼吗?作为一名中文设计师ÿ…...
Nintendo Switch第三方控制器终极方案:sys-con深度技术解析与应用指南
Nintendo Switch第三方控制器终极方案:sys-con深度技术解析与应用指南 【免费下载链接】sys-con Nintendo Switch sysmodule that allows support for third-party controllers 项目地址: https://gitcode.com/gh_mirrors/sy/sys-con 在Nintendo Switch游戏生…...
终极解密:OpenCore如何解决PC安装macOS的三大核心挑战
终极解密:OpenCore如何解决PC安装macOS的三大核心挑战 【免费下载链接】OpenCore-Install-Guide Repo for the OpenCore Install Guide 项目地址: https://gitcode.com/gh_mirrors/op/OpenCore-Install-Guide 对于技术爱好者和中级用户而言,OpenC…...
