QGraphicsView实现简易地图4『局部加载-地图漫游』

news2024/10/2 12:28:12

前文链接:QGraphicsView实现简易地图3『局部加载-地图缩放』
当鼠标拖动地图移动时,需要实时增补和删减瓦片地图,大致思路是计算地图从各方向移动时进出视口的瓦片坐标值,根据变化后的瓦片坐标值来增减地图瓦片,以下将提供实现此需求的核心代码。
1、动态演示效果


2、静态展示图片
在这里插入图片描述

核心代码

void MapView::moveScene()
{
	QString appPath = QApplication::applicationDirPath();
	QString dirPath = QString("%1/MapData/GaoDeMap/Map/MapPng/L0%2").arg(appPath).arg(m_curLevel + 1);
	// 视口宽度和高度
	int w = viewport()->width();
	int h = viewport()->height();

	// 计算呈现的瓦片地图左上角的场景坐标和视口坐标、呈现的瓦片地图右下角的场景坐标和视口坐标
	QPoint topLeftScenePos(m_topLeftTileCoord.x * PIXMAP_SIZE, m_topLeftTileCoord.y * PIXMAP_SIZE);
	QPointF topLeftViewPos = mapFromScene(topLeftScenePos);
	QPoint bottomRightScenePos(m_bottomRightTileCoord.x * PIXMAP_SIZE, m_bottomRightTileCoord.y * PIXMAP_SIZE);
	QPointF bottomRightViewPos = mapFromScene(bottomRightScenePos);
	
	// 1、水平瓦片坐标控制:判断最左侧瓦片是否完全进入视口、最右侧瓦片是否完全离开视口
	if (topLeftViewPos.x() > 0)
	{
		int count = qCeil(topLeftViewPos.x() / PIXMAP_SIZE);	// 左侧进入视口瓦片数量
		int oldLeftTileCoordX = m_topLeftTileCoord.x;			// 保存原左侧瓦片坐标X
		m_topLeftTileCoord.x -= count;							// 更新现左侧瓦片坐标X

		// 增加从左侧进入视口的图片
		for (int row = m_topLeftTileCoord.y; row <= m_bottomRightTileCoord.y; ++row)
		{
			for (int col = m_topLeftTileCoord.x; col < oldLeftTileCoordX; ++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);
				m_scene->addItem(item);
				m_mapItems[row][col] = item;
			}
		}
	}
	if (bottomRightViewPos.x() > w)
	{
		int count = qFloor((bottomRightViewPos.x() - w) / PIXMAP_SIZE) + 1;	// 右侧离开视口瓦片数量
		int oldRightTileCoordX = m_bottomRightTileCoord.x;					// 保存原右侧瓦片坐标X
		m_bottomRightTileCoord.x -= count;									// 更新现右侧瓦片坐标X

		// 删除从右侧离开视口的图片
		for (int row = m_topLeftTileCoord.y; row <= m_bottomRightTileCoord.y; ++row)
		{
			for (int col = oldRightTileCoordX; col > m_bottomRightTileCoord.x; --col)
			{
				QGraphicsPixmapItem *item = m_mapItems[row][col];
				m_scene->removeItem(item);
				m_mapItems[row].remove(col);
				delete item;
			}
		}
	}

	// 2、水平瓦片坐标控制:判断最右侧瓦片是否完全进入视口、最左侧瓦片是否完全离开视口
	if (bottomRightViewPos.x() + 255 < w)
	{
		int count = qCeil((w - (bottomRightViewPos.x() + 255)) / PIXMAP_SIZE);	// 右侧进入视口瓦片数量
		int oldRightTileCoordX = m_bottomRightTileCoord.x;						// 保存原右侧瓦片坐标X
		m_bottomRightTileCoord.x += count;										// 保存现右侧瓦片坐标X

		// 增加从右侧进入视口的图片
		for (int row = m_topLeftTileCoord.y; row <= m_bottomRightTileCoord.y; ++row)
		{
			for (int col = m_bottomRightTileCoord.x; col > oldRightTileCoordX; --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);
				m_scene->addItem(item);
				m_mapItems[row][col] = item;
			}
		}
	}

	if (topLeftViewPos.x() + 255 < 0)
	{
		int count = qFloor(fabs(topLeftViewPos.x()) / PIXMAP_SIZE);	// 左侧离开视口瓦片数量
		int oldLeftTileCoordX = m_topLeftTileCoord.x;				// 保存原左侧瓦片坐标X
		m_topLeftTileCoord.x += count;								// 保存现左侧瓦片坐标X

		// 删除从左侧离开视口的图片
		for (int row = m_topLeftTileCoord.y; row <= m_bottomRightTileCoord.y; ++row)
		{
			for (int col = oldLeftTileCoordX; col < m_topLeftTileCoord.x; ++col)
			{
				QGraphicsPixmapItem *item = m_mapItems[row][col];
				m_scene->removeItem(item);
				m_mapItems[row].remove(col);
				delete item;
			}
		}
	}

	// 3、垂直瓦片坐标控制:判断最上侧瓦片是否完全进入视口,最下侧瓦片是否完全离开视口
	if (topLeftViewPos.y() > 0)
	{
		int count = qCeil(topLeftViewPos.y() / PIXMAP_SIZE);	// 上侧进入视口瓦片数量
		int oldTopTileCoordY = m_topLeftTileCoord.y;			// 保存原上侧瓦片坐标Y
		m_topLeftTileCoord.y -= count;							// 保存现上侧瓦片坐标Y

		// 增加从上侧进入视口的图片
		for (int row = m_topLeftTileCoord.y; row < oldTopTileCoordY; ++row)
		{
			for (int col = m_topLeftTileCoord.x; col <= m_bottomRightTileCoord.x; ++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);
				m_scene->addItem(item);
				m_mapItems[row][col] = item;
			}
		}
	}

	if (bottomRightViewPos.y() > h)
	{
		int count = qFloor((bottomRightViewPos.y() - h) / PIXMAP_SIZE) + 1;	// 下侧离开视口瓦片数量
		int oldBottomTileCoordY = m_bottomRightTileCoord.y;					// 保存原下侧瓦片坐标Y
		m_bottomRightTileCoord.y -= count;									// 保存现下侧瓦片坐标Y

		// 删除从下侧离开视口的图片
		for (int row = oldBottomTileCoordY; row > m_bottomRightTileCoord.y; --row)
		{
			for (int col = m_topLeftTileCoord.x; col <= m_bottomRightTileCoord.x; ++col)
			{
				QGraphicsPixmapItem *item = m_mapItems[row][col];
				m_scene->removeItem(item);
				m_mapItems[row].remove(col);
				delete item;
			}
		}
	}

	// 4、垂直瓦片坐标控制:判断最下侧瓦片是否完全进入视口,最上侧瓦片是否完全离开视口
	if (bottomRightViewPos.y() + 255 < h)
	{
		int count = qCeil((h - (bottomRightViewPos.y() + 255)) / PIXMAP_SIZE);	// 下侧进入视口瓦片数量
		int oldBottomTileCoordY = m_bottomRightTileCoord.y;						// 保存原下侧瓦片坐标Y
		m_bottomRightTileCoord.y += count;										// 保存现下侧瓦片坐标Y

		// 增加从下侧进入视口的图片
		for (int row = m_bottomRightTileCoord.y; row > oldBottomTileCoordY; --row)
		{
			for (int col = m_topLeftTileCoord.x; col <= m_bottomRightTileCoord.x; ++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);
				m_scene->addItem(item);
				m_mapItems[row][col] = item;
			}
		}
	}

	if (topLeftViewPos.y() + 255 < 0)
	{
		int count = qFloor(fabs(topLeftViewPos.y()) / PIXMAP_SIZE);	// 上侧离开视口瓦片数量
		int oldTopTileCoordY = m_topLeftTileCoord.y;				// 保存原上侧瓦片坐标Y
		m_topLeftTileCoord.y += count;								// 保存现上侧瓦片坐标Y

		// 删除从上侧离开视口的图片
		for (int row = oldTopTileCoordY; row < m_topLeftTileCoord.y; ++row)
		{
			for (int col = m_topLeftTileCoord.x; col <= m_bottomRightTileCoord.x; ++col)
			{
				QGraphicsPixmapItem *item = m_mapItems[row][col];
				m_scene->removeItem(item);
				m_mapItems[row].remove(col);
				delete item;
			}
		}
	}
}

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

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

相关文章

c51单片机串行通信示例代码(单片机--单片机通信)(附带proteus线路图)

//这个发送端代码 #include "reg51.h" #include "myheader.h" #define uchar unsigned char long int sleep_i0; long int main_i0; void main() {uchar sendx[6]{2,0,2,3,8,1};sleep(2000);TMOD0x20;TH10XF4;//根据波特率计算公式这里需要设置为这么多才能…

微服务系列(2)--注册中心

在博文&#xff1a;微服务系列(1)里我们提到过注册中心的概念&#xff0c;简单来说微服务注册中心是一个用于存储和管理微服务实例信息的组件&#xff0c;它提供了服务注册、服务发现、服务健康检查等功能&#xff0c;以确保微服务之间的稳定通信。在微服务架构中&#xff0c;各…

火爆全网,Jmeter接口自动化-参数化CSV实战详解(超级详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 一般来说&#xf…

MachineLearningWu_16/P72-P77_Diagnostic

x.1 导数&#xff0c;计算图&#xff0c;大型网络 计算图就是根据链式法则求取偏导&#xff0c;大型网络就是多层网络堆叠而成。 x.2 Diagnostic 在我们对深度学习有了一些认知后&#xff0c;最重要的就是模型的诊断&#xff0c;以带有L1正则化的线性回归为例&#xff0c;我…

【Linux】系统内核中System.map中字段含义解释

可以通过命令行过来初始化内容 cat System.map-4.18.0-193.el8.x86_64 | grep pci | grep initcall "T"&#xff1a;表示该符号是一个全局函数&#xff0c;可以被其他模块或文件访问。 "D"&#xff1a;表示该符号是一个全局数据对象&#xff0c;可以被其…

玩转轻叶H5:批量功能上线,落地页创建更高效

在营销领域&#xff0c;落地页作为营销过程的最后一环&#xff0c;不仅要准确传达产品或服务的独特卖点&#xff0c;也要提升互动的友好度&#xff0c;完成承接用户和转化用户的价值作用。 为了满足营销人员的落地页自建需求&#xff0c;我们推出了轻叶H5制作工具&#xff0c;帮…

CVPR 2023 | 4D雷达场景流的跨模态监督学习

注1:本文系“计算成像最新论文速览”系列之一,致力于简洁清晰地介绍、解读非视距成像领域最新的顶会/顶刊论文(包括但不限于 Nature/Science及其子刊; CVPR, ICCV, ECCV, SIGGRAPH, TPAMI; Light‐Science & Applications, Optica 等)。 本次介绍的论文是:CVPR 2023 | 4D雷…

请求转发和请求重定向

目录 1. 定义层面 2. 请求方层面 3. 数据共享层面 4. 最终 url 层面 5. 代码实现层面 请求转发 请求重定向 在Java中&#xff0c;跳转网页的方式有两种&#xff0c;一种是请求转发&#xff0c;另一种是请求重定向&#xff0c;而实际上&#xff0c;这两种方式是有着明显…

最小生成树——prim算法

prim算法详解 prim算法简介prim算法步骤prim复杂度prim样例题目公路修建题目描述输入格式输出格式样例样例输入样例输出 提示 prim样例代码 prim算法简介 P r i m Prim Prim算法是一种用于解决最小生成树问题的贪心算法。最小生成树是一个连通图的生成树&#xff0c;它的所有边…

Vue+SpringBoot项目开发:登录页面美化,登录功能实现(三)

写在开始:一个搬砖程序员的随缘记录上一章写了从零开始VueSpringBoot后台管理系统&#xff1a;Vue3TypeScript项目搭建 VueTypeScript的前端项目已经搭建完成了 这一章的内容是引入element-plus和axios实现页面的布局和前后端数据的串联&#xff0c;实现一个登陆的功能&#x…

LVGL学习笔记 28 - 键盘keyboard

目录 1. 设置关联文本框 2. 设置模式 2.1 LV_KEYBOARD_MODE_TEXT_LOWER 2.2 LV_KEYBOARD_MODE_TEXT_UPPER 2.3 LV_KEYBOARD_MODE_SPECIAL 2.4 LV_KEYBOARD_MODE_NUMBER 2.5 LV_KEYBOARD_MODE_USER_1 ~ LV_KEYBOARD_MODE_USER_4 3. 使能弹窗模式 4. 更改按键布局 5. 事…

uniapp----分包

系列文章目录 uniapp-----封装接口 uniapp-----分包 目录 系列文章目录 uniapp-----封装接口 uniapp-----分包 前言 二、使用步骤 1.创建文件 ​编辑 2.min.js的修改 2.1 subPackages 代码如下&#xff08;示例&#xff09;&#xff1a; 2.2 preloadRule 代码如下&am…

第一次PR经历

第一次PR测试地址&#xff1a;https://github.com/firstcontributions/first-contributions说明文档&#xff1a; https://github.com/firstcontributions/first-contributions/blob/main/translations/README.zh-cn.md

SAP MM学习笔记17-在库品目评价中的标准原价 S 和移动平均价格 V

SAP中有2种价格&#xff0c;标准原价 S 和 移动平均价格 V。 1&#xff0c;标准原价 S 2&#xff0c;移动平均价格 V 在MM03 会计1 Tab中&#xff0c;现行评价区域中&#xff0c;有原价管理区分。 比如下面这个物料 100-100&#xff0c; 它的原价管理区分是 S。 它的合计额…

在Vue中动态引入图片为什么要用require

静态资源和动态资源 静态资源 动态的添加src 动态资源 我们通过网络请求从后端获取的资源 动态的添加src会被当成静态资源 动态的添加src最终会被打包成&#xff1a; 动态的添加图片最会会被编译成一个静态的字符串&#xff0c;然后再浏览器运行中会去项目中查找这个资源…

ucharts-地图

以唐山地图为例&#xff1a; 先去找需要的区域入下图&#xff0c;会得到一堆的经纬度&#xff0c;我把他它放到静态文件里&#xff0c;需要的是它的features <template><view class"charts-box"><qiun-data-charts type"map":opts"o…

Redis中的数据类型

Redis中的数据类型 Redis存储的是key-value结构的数据&#xff0c;其中key是字符串类型&#xff0c;value有5种常用的数据类型: 字符串string哈希hash列表list集合set有序集合sorted set

【24择校指南】温州大学计算机考研考情分析

温州大学(C) 考研难度&#xff08;☆&#xff09; 内容&#xff1a;23考情概况&#xff08;拟录取和复试分数人数统计&#xff09;、院校概况、23专业目录、23复试详情、各科目以及各专业考情分析。 正文1349字&#xff0c;预计阅读&#xff1a;3分钟。 2023考情概况 温州…

Tomcat的一些配置问题(server.xml/catalina.sh)

在同一机器中运行多个Tomcat时&#xff0c;如果不修改server.xml的端口参数&#xff0c;会出现端口冲突使得Tomcat异常&#xff1b;Tomcat默认配置中&#xff0c;JAVA_OPTS不会设置太大&#xff0c;一般需要在catalina.sh中增加一行配置来加大该参数值。 目录 1.Server.xml配置…

监控Kubernetes 控制面组件的关键指标

控制面组件的监控&#xff0c;包括 APIServer、Controller-manager&#xff08;简称 CM&#xff09;、Scheduler、etcd 四个组件。 1、APIServer APIServer 的核心职能是 Kubernetes 集群的 API 总入口&#xff0c;Kube-Proxy、Kubelet、Controller-Manager、Scheduler 等都需…