QGraphicsView实现简易地图1『加载离线瓦片地图』

news2024/9/25 23:16:37

最简单粗暴的加载方式,将每一层级的所有瓦片地图全部加载
注:该方式仅能够在瓦片地图层级较低时使用,否则卡顿!!!

瓦片地图数据来源:水经注-高德地图-卫星地图
瓦片地图瓦片大小:256 * 256像素
瓦片地图坐标投影:GCJ02 Web 墨卡托投影

1、动态演示效果:
在这里插入图片描述

2、静态展示图片:
在这里插入图片描述
核心代码
1、数据定义

#define PIXMAP_SIZE 256

// 瓦片坐标
struct TileCoord
{
	double x;
	double y;
};

// 经纬度坐标
struct GeoCoord
{
	GeoCoord() = default;
	GeoCoord(double _lon, double _lat) : lon(_lon), lat(_lat) {}
	double lon;  // 经度
	double lat;  // 纬度
};

2、MapUtility类

class MapUtility
{
public:
	// 场景坐标转经纬度
	static GeoCoord mapFromScene(QPointF scenePos, int level);

private:
	// 场景坐标转瓦片坐标(瓦片坐标系)
	static QPoint tileCoordFromScene(QPointF scenePos, int level);
	// 场景坐标转所在瓦片像素点坐标
	static QPointF tilePixelCoordFromScene(QPointF scenePos, int level);
};
#include "MapUtility.h"
#include "TileUtility.h"

GeoCoord MapUtility::mapFromScene(QPointF scenePos, int level)
{
	QPoint tileCoord = tileCoordFromScene(scenePos, level);
	QPointF tilePixelCoord = tilePixelCoordFromScene(scenePos, level);
	
	return TileUtility::pixelToLonLat(tilePixelCoord.x(), tilePixelCoord.y(), tileCoord.x(), tileCoord.y(), level);
}

QPoint MapUtility::tileCoordFromScene(QPointF scenePos, int level)
{
	int tileX = std::floor(scenePos.x() / PIXMAP_SIZE);
	int tileY = std::floor(scenePos.y() / PIXMAP_SIZE);

	return QPoint(tileX, tileY);
}

QPointF MapUtility::tilePixelCoordFromScene(QPointF scenePos, int level)
{
	QPoint tileCoord = tileCoordFromScene(scenePos, level);
	double left = tileCoord.x() * PIXMAP_SIZE;	// scenePos所在瓦片的左侧位于场景中的坐标
	double top = tileCoord.y() * PIXMAP_SIZE;	// scenePos所在瓦片的上侧位于场景中的坐标

	return QPointF(scenePos.x() - left, scenePos.y() - top);
}

3、TileUtility类

class TileUtility
{
	friend class MapUtility;

private:
	/**
	* 将地图层级下瓦片的像素点转换到经纬度
	* 瓦片地图左上角为(0, 0)点
	* @param pixelX   瓦片像素点X
	* @param pixelY   瓦片像素点Y
	* @param tileX    瓦片坐标X
	* @param tileY    瓦片坐标Y
	* @param level    瓦片层级
	*/
	static GeoCoord pixelToLonLat(double pixelX, double pixelY, int tileX, int tileY, int level);
	static double pixelXToLon(double pixelX, double tileX, int level);
	static double pixelXToLat(double pixelY, double tileY, int level);
	static double mathSinH(double value);

	/**
	* 获取地图层级下X/Y轴上的瓦片数量
	* @param level    瓦片层级
	* @return 		  瓦片数量
	*/
	static int mapSize(int level);
};
GeoCoord TileUtility::pixelToLonLat(double pixelX, double pixelY, int tileX, int tileY, int level)
{
	double lon = pixelXToLon(pixelX, tileX, level);
	double lat = pixelXToLat(pixelY, tileY, level);

	return GeoCoord(lon, lat);
}

double TileUtility::pixelXToLon(double pixelX, double tileX, int level)
{
	const double pixelXToTileAddition = pixelX / PIXMAP_SIZE;
	const double lon = (tileX + pixelXToTileAddition) / mapSize(level) * 360 - 180;

	return lon;
}

double TileUtility::pixelXToLat(double pixelY, double tileY, int level)
{
	const double pixelYToTileAddition = pixelY / PIXMAP_SIZE;
	const double lat = qAtan(mathSinH(M_PI * (1 - 2 * (tileY + pixelYToTileAddition) / mapSize(level)))) * 180.0 / M_PI;

	return lat;
}

double TileUtility::mathSinH(double value)
{
	return (qExp(value) - qExp(-value)) / 2;
}

int TileUtility::mapSize(int level)
{
	return pow(2, level);
}

4、场景粗暴加载瓦片地图

void MapScene::updateScene()
{
	QString dirPath = QString("F:/MapData/GaoDeMap/Map/MapPng/L0%1").arg(m_curLevel + 1);
	int size = pow(2, m_curLevel);
	for (int row = 0; row < size; ++row)
	{
		for (int col = 0; col < size; ++col)
		{
			QString fileName = QString("%1/Map_%2-%3.png").arg(dirPath)
				.arg(QString::number(row + 1).rightJustified(2, '0')).arg(QString::number(col + 1).rightJustified(2, '0'));
			QPixmap pixmap(fileName);
			QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
			item->setPos(PIXMAP_SIZE * col, PIXMAP_SIZE * row);
			addItem(item);
		}
	}
}

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

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

相关文章

损失函数篇 | YOLOv8 更换损失函数之 MPDIoU | 《2023 一种用于高效准确的边界框回归的损失函数》

论文地址:https://arxiv.org/pdf/2307.07662v1.pdf 边界框回归(Bounding Box Regression,BBR)在目标检测和实例分割中得到了广泛应用,是目标定位的重要步骤。然而,对于边界框回归的大多数现有损失函数来说,当预测的边界框与真值边界框具有相同的长宽比,但宽度和高度的…

想学Python高级编程?必须了解这个小技巧:match-case!

大家好&#xff0c;这里是程序员晚枫&#xff0c;小破站/知乎/小红书/抖音都叫这个名字。 上次给大家分享了Python高级编程第一讲&#xff1a;从使用类型提示开始 &#xff1b;今天分享Python高级编程第二讲&#xff1a;深入解析Python中switch case的使用方法。 写在前面 分…

Python时间处理:探索time模块

日常工作中&#xff0c;经常涉及到一些时间的转换操作&#xff0c;比如某些业务针对时间的操作要转成不同的时区&#xff0c;有的要转换格式入库&#xff0c;有的需要跟时间对比等等&#xff0c;接下来我们一起来看一下python里面是怎么去处理时间的。 time模块简单介绍 Python…

C语言实现扫雷游戏

test.c源文件 - 扫雷游戏测试 game.h头文件 - 扫雷游戏函数的声明 game.c源文件 - 扫雷游戏函数的实现 1.布置雷 -- 存放雷的雷盘 9*9 数组设计成11*11 上下左右方各多一行&#xff0c;保证周围8的范围 雷 - 1 不是雷 - 0 2.排查雷 主题测试源文件代码 &…

MySQL基础扎实——如何优化DISTINCT

在优化 MySQL 中的 DISTINCT 查询时&#xff0c;以下是一些常见的方法和技巧&#xff1a; 索引优化&#xff1a;为涉及 DISTINCT 的列创建索引。索引可以加速列值的查找和比较&#xff0c;以提高查询性能。请注意&#xff0c;在表中存在大量重复值的情况下&#xff0c;索引可能…

[个人笔记] vCenter设置时区和NTP同步

VMware虚拟化 - 运维篇 第三章 vCenter设置时区和NTP同步 VMware虚拟化 - 运维篇系列文章回顾vCenter设置时区和NTP同步&#xff08;附加&#xff09;ESXi设置alias参考链接 系列文章回顾 第一章 vCenter给虚机添加RDM磁盘 第二章 vCenter回收活跃虚拟机的剩余可用空间 vCente…

JavaEE——文件操作和IO

文章目录 一、认识什么是文件二、Java对文件的操作三、文件内容读写——数据流1. 对字节流中的读操作解释2.对字节流中写操作解释3.解释 input 、output 和 closs() 方法4. Scanner 在文件中的使用 四、简单使用代码操作文件 一、认识什么是文件 狭义的文件&#xff1a; 指的是…

Web博客项目及jwt的学习

这几天完善了发布博客&#xff0c;完成了收藏博客的功能 博客项目 一共有三种身份&#xff1a; 访客&#xff08;未登录&#xff09;&#xff0c;用户&#xff0c;管理员。 其中管理员拥有的功能最多&#xff0c;其次是用户&#xff0c;然后是访客。 从功能上看&#xff1a…

Java面向对象编程实战详解(图书管理系统示例)

文章目录 面向编程概念图书管理系统示例需求分析设计阶段编码实现创建目录结构Book类的编码BookList类的编码User类的编码AdminUser类的编码NormalUser类的编码启动类的编写具体的操作实现IOperation接口新增图书的实现借阅图书的实现删除图书的实现显示图书的实现查找图书的实…

51单片机双机通信

对于这个51单片机双机通信&#xff0c;之前无聊做的玩的&#xff0c;但是既然写了一篇51单片机串行口通信的博客&#xff0c;那就顺便出来供大家学习&#xff0c;希望能够帮助到一些刚刚接触51单片机的朋友。废话不多讲&#xff0c;直接上正题。 1、实习任务 1.1 任务目的 通…

AIGC人工智能辅助开发:提升效率、优化代码、实现智能编程

文章目录 1. 什么是AIGC人工智能辅助开发&#xff1f;2. AIGC的优势和应用场景2.1 提升开发效率2.2 优化代码质量2.3 实现智能编程 3. 如何用好AIGC人工智能辅助开发&#xff1f;3.1 选择合适的AIGC工具3.2 理解AIGC的工作原理3.3 逐步应用AIGC辅助开发3.4 主动参与AIGC的学习和…

Raki的读paper小记:RWKV: Reinventing RNNs for the Transformer Era

Abstract&Introduction&Related Work 研究任务 基础模型架构已有方法和相关工作 RNN&#xff0c;CNN&#xff0c;Transformer稀疏注意力&#xff08;Beltagy等人&#xff0c;2020年&#xff1b;Kitaev等人&#xff0c;2020年&#xff1b;Guo等人&#xff0c;2022年&am…

组合模式——树形结构的处理

1、简介 1.1、概述 树形结构在软件中随处可见&#xff0c;例如操作系统中的目录结构、应用软件中的菜单、办公系统中的公司组织结构等。如何运用面向对象的方式来处理这种树形结构是组合模式需要解决的问题。组合模式通过一种巧妙的设计方案使得用户可以一致性地处理整个树形…

Flowable-中间事件-补偿中间抛出事件

定义 补偿中间抛出事件用于触发一个补偿&#xff0c;当执行到达补偿中间抛出事件时触发该流程已完成活动 的边界补偿事件&#xff08;Compensate Boundary Interrputing Event&#xff09;&#xff0c;完成补偿操作后自动执行后继路线。 图形标记 补偿中间抛出事件显示为普通…

【elasticsearch系】1.初识玩转elasticSearch

首先给大家介绍下我使用的版本是7.17.3这个版本&#xff0c;关于之前6.x的版本还是有些区别的。 elasticSearch Elasticsearch 是一个分布式文档存储。Elasticsearch 不是将信息存储为列式数据行&#xff0c;而是存储已序列化为 JSON 文档的复杂数据结构。存储文档时&#xff0…

PHP8的数据类型-PHP8知识详解

在PHP8中&#xff0c;变量不需要事先声明&#xff0c;赋值即声明。 不同的数据类型其实就是所储存数据的不同种类。在PHP8.0、8.1中都有所增加。以下是PHP8的15种数据类型&#xff1a; 1、字符串&#xff08;String&#xff09;&#xff1a;用于存储文本数据&#xff0c;可以使…

【深度学习】High-Resolution Image Synthesis with Latent Diffusion Models,论文

13 Apr 2022 论文&#xff1a;https://arxiv.org/abs/2112.10752 代码&#xff1a;https://github.com/CompVis/latent-diffusion 文章目录 PS基本概念运作原理 AbstractIntroductionRelated WorkMethodPerceptual Image CompressionLatent Diffusion Models Conditioning Mec…

【13】STM32·HAL库-正点原子SYSTEM文件夹 | SysTick工作原理、寄存器介绍 | printf函数使用、重定向

目录 1.sys文件夹介绍&#xff08;掌握&#xff09;2.deley文件夹介绍&#xff08;掌握&#xff09;2.1deley文件夹函数简介2.2SysTick工作原理2.3SysTick寄存器介绍2.4delay_init()函数&#xff08;F1&#xff09;2.5delay_us()函数&#xff08;F1&#xff09;2.6delay_ms()函…

网络安全-防御需知

目录 网络安全-防御 1.网络安全常识及术语 资产 漏洞 0day 1day 后门 exploit APT 2.什么会出现网络安全问题&#xff1f; 网络环境的开放性 协议栈自身的脆弱性 操作系统自身的漏洞 人为原因 客观原因 硬件原因 缓冲区溢出攻击 缓冲区溢出攻击原理 其他攻击…

Java另一种debug方法(not remote jmv debug),类似python远程debug方式

这种Debug类似python的debug方式&#xff0c;是运行时将业务代码及依赖推送到Linux并使用Linux的java运行运行程。只要本地能运行&#xff0c;就能自动将代码推送到Linux运行&#xff0c;不需打包及设置远程debug jvm参数&#xff0c;适合一些项目Debug调试 运行时会推送一些依…