Qgis二次开发-实现缩略图、标注

news2024/12/24 21:37:09

1.效果图

2.简介

因为上述动作是和画布进行交互,所以首先需要自定义一个地图交互工具类,由于做的比较简单,只需要重写实现鼠标点击事件。

void canvasPressEvent(QgsMapMouseEvent *e) override;

其次就是在地图画布上画标注图片(svg格式),以及缩略图片(其他格式的),以及经纬度坐标文字。

以下是参考如何画svg标注,栅格图片,文字等。

Qgis二次开发-QgsAnnotationItem(添加文字、图片标注(支持svg、png、jpg等常用图片格式))_Mr.codeee的博客-CSDN博客

首先说一下我遇到的问题, 经纬度的文字坐标需要画在符号标注的下方,但是qgis未提供设置偏移量的一个接口。

这是修改前的样子:

可以看见很影响美观,以下是构造文字的标记类。

QgsAnnotationPointTextItem* textItem
     = new QgsAnnotationPointTextItem(showText, QgsPoint(p.x(), p.y()));

有的同学认为只需要在y的坐标上加上个偏移量就行了,但是随着地图的放大和缩小,文字标注会离图标越来越远,像下面的这样。

后面就又想了办法,随着地图的放大和缩小将y偏移量跟着放大和缩小。(如果有更好的方法,请指教)

connect(mapCanvas, &QgsMapCanvas::zoomLastStatusChanged,
						this, &QgsMapToolSelectItem::slotZoomLastStatusChanged);

void QgsMapToolSelectItem::slotZoomLastStatusChanged(bool)
{
	//qDebug() << "pre zoom = " << preScale;
	//qDebug() << "cur zoom = " << m_canvas->scale();

	
	//QgsVectorLayer *layer;
	double offsetY = 0.0;
	if (m_canvas->scale() > 32000000)
	{
	}
	else if (m_canvas->scale() > 16000000)
	{
		//qDebug() << "max 8000000";
		offsetY = 3;
	}
	else if (m_canvas->scale() > 8000000)
	{
		//qDebug() << "max 8000000";
		offsetY = 1.5;
	}
	else if (m_canvas->scale() > 4000000)
	{
		//qDebug() << "max 4000000";
		offsetY = 0.75;
	}
	else if (m_canvas->scale() > 2000000)
	{
		//qDebug() << "max 2000000";
		offsetY = 0.375;
	}
	else if (m_canvas->scale() > 1000000)
	{
		//qDebug() << "max 1000000";
		offsetY = 0.1875;
	}
	else if(m_canvas->scale() > 500000)
	{
		//qDebug() << "max 500000";
		offsetY = 0.09375;
	}
	else if (m_canvas->scale() > 250000)
	{
		//qDebug() << "max 250000";
		offsetY = 0.046875;
	}
	else if (m_canvas->scale() > 125000)
	{
		//qDebug() << "max 125000";
		offsetY = 0.02343;
	}
	else if (m_canvas->scale() > 62500)
	{
		//qDebug() << "max 125000";
		offsetY = 0.01175;
	}
	else if (m_canvas->scale() > 31250)
	{
		offsetY = 0.00585;
	}
	else if (m_canvas->scale() > 15625)
	{
		offsetY = 0.00293;
	}
	else if (m_canvas->scale() > 7812)
	{
		offsetY = 0.0014648;
	}
	else
	{
		offsetY = 0.0007324;
	}

	for (int i = 0; i < m_lstSvgItems.size(); i++)
	{
		QgsPointXY xy = m_lstSvgItems.at(i).geo.asPoint();
		m_lstSvgItems.at(i).text->setPoint(QgsPoint(xy.x(), xy.y() - offsetY));
	}
}

然后如何做到缩略图的显隐呢,就是将缩略图的图层从画布中添加或者删除。

以下是地图工具类:

#include "QgsMapToolSelectItem.h"
#include "QgsMapToolIdentify.h"
#include "qgsapplication.h"
#include "qgsvectorlayer.h"
#include <QMessageBox>
#include <qgsfeature.h>
#include <qgsvectorlayer.h>
#include <qgsrectangle.h>
#include <QMouseEvent>
#include <qgsmapcanvas.h>
#include <qgsmaptoolidentify.h>
#include <qgsmaptool.h>
#include <qgssymbollayer.h>
#include <qgsannotationmarkeritem.h>
#include <qgsannotationlayer.h>
#include <qgsmarkersymbollayer.h>
#include <qgssinglesymbolrenderer.h>
#include <qgsrubberband.h>
#include "QgsMapToolSelectItem.h"
#include <qgsrasterlayer.h>
#include <qgspallabeling.h>
#include <qgsvectorlayerlabeling.h>

extern QList<QgsMapLayer *> g_layers;
double preScale = 0.0;

QgsMapToolSelectItem::QgsMapToolSelectItem(QgsMapCanvas *mapCanvas)
	: QgsMapToolIdentify(mapCanvas)
	, m_canvas(mapCanvas)
{
	connect(mapCanvas, &QgsMapCanvas::zoomLastStatusChanged,
						this, &QgsMapToolSelectItem::slotZoomLastStatusChanged);

	preScale = mapCanvas->scale();
}

static int xOffset = 1;
static int yOffset = 1;
void QgsMapToolSelectItem::drawIcon(const st_draw_icon &point)
{
	SvgItem item;
    //作了一个随机值偏移
	xOffset = qrand() % 10;
	yOffset = qrand() % 10;
	QgsPointXY pointXy = QgsPointXY(point.longitude + xOffset, point.latitude + yOffset);

	drawSvgIcon(pointXy, point.symbolPath,item);

	drawThumbnail(pointXy, point.filePath, item);

	drawText(pointXy, item);

	m_lstSvgItems.append(item);
}


void QgsMapToolSelectItem::drawIcon(const QList<st_draw_icon> &icons)
{
	int count = icons.size();
	for (int i = 0; i < count; i++)
	{
		drawIcon(icons.at(i));
	}
}

void QgsMapToolSelectItem::drawSvgIcon(const QgsPointXY &p, const QString &filePath, SvgItem &item)
{
	//画图标
	QgsRubberBand *rb = new QgsRubberBand(m_canvas, QgsWkbTypes::PointGeometry);
	rb->setScale(0.03);
	rb->setOpacity(0.8);
	rb->setIcon(QgsRubberBand::IconType::ICON_SVG);    //设置图标类型
	//rb->setIconSize(1);														//设置图标尺寸 
	rb->setSvgIcon(filePath, QPoint(-16 , -16));        //设置图标文件路径和偏移
	QgsGeometry geo = QgsGeometry::fromPointXY(p);	//经纬度
	rb->addGeometry(geo);                              //绘制

	item.geo = geo;
	item.name = "item1";
	item.isSelected = false;
	item.rubberBand = rb;
}


void QgsMapToolSelectItem::drawThumbnail(const QgsPointXY &p,const QString &fileName, SvgItem &item)
{
	QgsCoordinateTransformContext coordinateTransformContext;
	//先构造出一个能加注记的图层
	QgsAnnotationLayer* annotationLayer = new QgsAnnotationLayer("annotationLayer", QgsAnnotationLayer::LayerOptions(coordinateTransformContext));

	//第一个小SvgMarkerSymbol,加载资源路径相对路径绝对路径都行
	QgsRasterMarkerSymbolLayer * svgMarker = new QgsRasterMarkerSymbolLayer(fileName);

	//设置第一个和第二个SvgMarkerSymbol的尺寸
	svgMarker->setSize(40);
	svgMarker->setOffset(QPointF(0, 0-svgMarker->size()/2));

	//可以svg的叠加
	QgsSymbolLayerList symList;
	symList.append(svgMarker->clone());//最好用这个clone要不然删除会有内存泄漏

	//new出QgsMarkerSymbol类的对象
	QgsMarkerSymbol* markSym = new QgsMarkerSymbol(symList);

	//构造时传入地理坐标,有必要后期改成鼠标事件点击来创建QgsAnnotationMarkerItem
	QgsAnnotationMarkerItem* annotationMarkerItem = new QgsAnnotationMarkerItem(QgsPoint(p.x(), p.y()));
	annotationMarkerItem->setSymbol(markSym->clone());//给Item加上Svg图像

	annotationLayer->addItem(annotationMarkerItem->clone());//画布添加Item

	item.layer = annotationLayer;
}

void QgsMapToolSelectItem::drawText(const QgsPointXY &p, SvgItem &item)
{
	QgsCoordinateTransformContext coordinateTransformContext;
	//先构造出一个能加注记的图层
	QgsAnnotationLayer *textLayer = new QgsAnnotationLayer("annotationLayer",
		QgsAnnotationLayer::LayerOptions(coordinateTransformContext));

	//构造时传入地理坐标,有必要后期改成鼠标事件点击来创建QgsAnnotationMarkerItem
	QString showText = QString("%1,%2").arg(QString::number(p.x(),'f',6)).arg(QString::number(p.y(), 'f', 6));
	QgsAnnotationPointTextItem* textItem = new QgsAnnotationPointTextItem(showText, QgsPoint(p.x(), p.y()));
	textItem->setAlignment(Qt::AlignHCenter);
	QgsTextFormat format;
	QFont font;
	font.setBold(true);
	font.setPointSize(13);
	format.setFont(font);
	format.setColor(QColor(255, 255, 255));
	textItem->setFormat(format);
	textLayer->addItem(textItem);//画布添加Item

	g_layers.push_front(textLayer);

	item.text = textItem;
	m_canvas->setLayers(g_layers);
	m_canvas->refresh();
}


void QgsMapToolSelectItem::slotZoomLastStatusChanged(bool)
{
	//qDebug() << "pre zoom = " << preScale;
	//qDebug() << "cur zoom = " << m_canvas->scale();

	
	//QgsVectorLayer *layer;
	double offsetY = 0.0;
	if (m_canvas->scale() > 32000000)
	{
	}
	else if (m_canvas->scale() > 16000000)
	{
		//qDebug() << "max 8000000";
		offsetY = 3;
	}
	else if (m_canvas->scale() > 8000000)
	{
		//qDebug() << "max 8000000";
		offsetY = 1.5;
	}
	else if (m_canvas->scale() > 4000000)
	{
		//qDebug() << "max 4000000";
		offsetY = 0.75;
	}
	else if (m_canvas->scale() > 2000000)
	{
		//qDebug() << "max 2000000";
		offsetY = 0.375;
	}
	else if (m_canvas->scale() > 1000000)
	{
		//qDebug() << "max 1000000";
		offsetY = 0.1875;
	}
	else if(m_canvas->scale() > 500000)
	{
		//qDebug() << "max 500000";
		offsetY = 0.09375;
	}
	else if (m_canvas->scale() > 250000)
	{
		//qDebug() << "max 250000";
		offsetY = 0.046875;
	}
	else if (m_canvas->scale() > 125000)
	{
		//qDebug() << "max 125000";
		offsetY = 0.02343;
	}
	else if (m_canvas->scale() > 62500)
	{
		//qDebug() << "max 125000";
		offsetY = 0.01175;
	}
	else if (m_canvas->scale() > 31250)
	{
		offsetY = 0.00585;
	}
	else if (m_canvas->scale() > 15625)
	{
		offsetY = 0.00293;
	}
	else if (m_canvas->scale() > 7812)
	{
		offsetY = 0.0014648;
	}
	else
	{
		offsetY = 0.0007324;
	}

	for (int i = 0; i < m_lstSvgItems.size(); i++)
	{
		QgsPointXY xy = m_lstSvgItems.at(i).geo.asPoint();
		m_lstSvgItems.at(i).text->setPoint(QgsPoint(xy.x(), xy.y() - offsetY));
	}
}


void QgsMapToolSelectItem::canvasPressEvent(QgsMapMouseEvent * e)
{
	QgsGeometry startGeo = QgsGeometry::fromPointXY(toMapCoordinates(e->pos()));
	QgsPointXY p = startGeo.asPoint();

	for (int i = 0; i < m_lstSvgItems.size(); i++)
	{
		SvgItem item = m_lstSvgItems.at(i);

		QgsVector qgsVector = item.geo.asPoint() - p;
		//qDebug() << "qgsVector ( x = " << qgsVector.x() << " y = " << qgsVector.y() << " )";

		//设置在这个范围中点击,保证能点到对象
		if ((-0.5 < qgsVector.x() && qgsVector.x() < 0.5) &&
			(-0.5 < qgsVector.y() && qgsVector.y() < 0.5))
		{
			item.isSelected = !item.isSelected;
			if (item.isSelected)
			{
				g_layers.push_front(item.layer);

				//annotationLayer图层添加到我的图层容器中
				m_canvas->setLayers(g_layers);

				m_canvas->refresh();
			}
			else
			{
				g_layers.removeOne(item.layer);

				//annotationLayer图层添加到我的图层容器中
				m_canvas->setLayers(g_layers);

				m_canvas->refresh();
			}
			m_lstSvgItems.replace(i, item);
		}
	}

	m_canvas->refresh();
}

3.完整工程

https://download.csdn.net/download/wzz953200463/88082963icon-default.png?t=N6B9https://download.csdn.net/download/wzz953200463/88082963

4.相关参考

Qgis二次开发-QgsAnnotationItem(添加文字、图片标注(支持svg、png、jpg等常用图片格式))_Mr.codeee的博客-CSDN博客

Qgis二次开发-QgsMapTool地图交互工具详解_Mr.codeee的博客-CSDN博客 

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

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

相关文章

Docker中的网络

文章目录 一、Docker 网络1.1 Docker 网络实现原理1.2 查看容器的输出和日志信息Docker 的网络模式 二、资源控制2.1 CPU 资源控制2.2 对内存使用的限制 一、Docker 网络 1.1 Docker 网络实现原理 Docker使用Linux桥接&#xff0c;在宿主机虚拟一个Docker容器网桥(docker0)&a…

CentOS7安装并远程连接MySQL8.0.33

一、前言 学习MySQL进阶篇时需要在CentOS上安装MySQL&#xff0c;然后远程连接使用&#xff0c;于是就抽了两天时间把瑞吉外卖的Linux篇给看了95% 本篇是摘选了学习笔记中关于安装MySQL的部分&#xff0c;作为参考也作为分享 二、安装MySQL 先检测当前系统中是否已安装MySQL…

平头哥 TH1520 RISC-V BeagleV-Ahead使用Thead-Yocto自定义构建系统 最详细版本

使用Thead-Yocto自定义BeagleV-Ahead系统 Thead-Yocto简述 官网&#xff1a;https://www.yoctoproject.org/ THE YOCTO PROJECT. IT’S NOT AN EMBEDDED LINUX DISTRIBUTION,IT CREATES A CUSTOM ONE FOR YOU. YOCTO项目&#xff1a;他不是一个嵌入式Linux发行版&#xff0c…

SQL SERVER安装

其中服务器名称输入./自己本机电脑名称. nchar类型一个单位可以放一个汉字-------长度短的补空格一个字节8位一个汉字两个字节 char类型两个单位可以放一个汉字 nvarchar类型是可变长度-----------长度短不会补空格 varchar类型是可变长度两个单位可以放一个汉字---------…

电脑显示连接上WiFi,但没办法上网

问题: 电脑显示已经连接上WiFi。但是百度不出来东西&#xff0c;也没办法打开任何网页。 解决方法&#xff1a; win10系统 在左下角搜索栏&#xff0c;搜索“代理服务器设置”。 找到手动设置代理 —》关闭“使用代理服务” 【默认是打开的】 关闭之后即可上网~~

Python(三十四)条件表达式

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

数据结构--线性表两种存储方式的总结以及应用

这里写目录标题 顺序表和链表的比较存储密度链表的优缺点二者特点的比较以及使用场景 应用线性表的合并有序表的合并用顺序表实现用链表实现 案例实现多项式运算稀疏多项式的运算链表的创建多项式相加图书管理系统 顺序表和链表的比较 存储密度 链表的优缺点 二者特点的比较以…

mybatis学习笔记之在WEB中应用MyBatis

文章目录 数据库表的设计和准备数据环境搭建前端页面编写后端代码实现后端代码目录dao层servicewebpojoUtils 数据库表的设计和准备数据 环境搭建 在pom.xml中配置依赖&#xff08;logback、mybatis、mysql、servlet&#xff09; 注意引入tomcat 前端页面编写 <!DOCTYPE …

Ubuntu 网络配置指导手册

一、前言 从Ubuntu 17.10 Artful开始&#xff0c;Netplan取代ifupdown成为默认的配置实用程序&#xff0c;网络管理改成 netplan 方式处理&#xff0c;不在再采用从/etc/network/interfaces 里固定 IP 的配置 &#xff0c;配置写在 /etc/netplan/01-network-manager-all.yaml 或…

《Docker基础知识解析:容器与虚拟化的区别与优势,选择最佳方案优化云计算应用》

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

【MATLAB第57期】基于MATLAB的双隐含层BP神经网络回归预测模型(无工具箱版本及工具箱版本对比)

【MATLAB第57期】基于MATLAB的双隐含层BP神经网络回归预测模型&#xff08;无工具箱版本及工具箱版本对比&#xff09; 一、无工具箱版本 1.数据设置 数据为案例数据 。103行样本&#xff0c;7输入1输出数据。 2.参数设置 训练函数 梯度下降 HiddenUnit1Num10;%隐层1结点数…

Thinkphp+vue中小企业人事管理系统q731f

运行环境:phpstudy/wamp/xammp等 开发语言&#xff1a;php 后端框架&#xff1a;Thinkphp5 前端框架&#xff1a;vue.js 服务器&#xff1a;apache 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat/phpmyadmin中小企业人事管理系统的主要开发目标如下&#xff1a; &…

性能测试之 cpu 篇

目录 1 前言&#xff1a; 2.1 cpu 介绍 2.1.1 上下文切换 2.1.2 运行队列 2.1.3 CPU 利用率 2.2 cpu 性能监控 2.2.1 vmstat 的使用 2.2.2 案例学习:持续的 CPU 利用率 2.2.3 案例学习:超负荷调度 2.2.4. mpstat 工具的使用 2.2.5. 案例学习: 未充分使用的处理量 2…

windows-文件夹-默认打开方式被修改-修改为资源管理器

文章目录 1.方法2.总结 1.方法 如果文件夹默认修改方式被修改&#xff0c;可以打开注册表 按windowsR输入&#xff1a; regedit然后修改注册表项 HKEY_CLASSES_ROOT\Directory\shell将其它值删除&#xff0c;键入默认的windows资源管理器 %systemroot%\explorer如下图所示&…

【PostgreSQL内核学习(五)—— 查询规划(预处理)】

查询规划——预处理 预处理提升子链接/子查询预处理表达式预处理HAVING子句 声明&#xff1a;本文的部分内容参考了他人的文章。在编写过程中&#xff0c;我们尊重他人的知识产权和学术成果&#xff0c;力求遵循合理使用原则&#xff0c;并在适用的情况下注明引用来源。 本文主…

【网络教程】如何快速的解决WordPress“另一更新正在进行”的问题

文章目录 WordPress提示“另一更新正在进行”解决方案手动删除数据库记录使用插件WordPress提示“另一更新正在进行” 当我们在更新WordPress的插件或者升级WordPress时会出现后台提示“另一更新正在进行”,如下图 当我们点击更新后,出现下图提示 出现上述问题是由于在升级Wo…

瑞吉外卖开发笔记 七(redis、Spring Cache)

缓存优化 问题说明 用户数量多&#xff0c;系统访问量大频繁访问数据库&#xff0c;系统性能下降&#xff0c;用户体验差 环境搭建 maven坐标 在项目的pom.xm1文件中导入spring data redis的maven坐标: <dependency> <groupId>org.springframework.boot</g…

【Hello mysql】 mysql的视图

Mysql专栏&#xff1a;Mysql 本篇博客简介&#xff1a;介绍mysql的视图 介绍mysql的视图 基本概念基本使用创建视图修改视图删除视图 视图规则和限制总结 基本概念 视图是一个虚拟表&#xff0c;其内容由查询定义。同真实的表一样&#xff0c;视图包含一系列带有名称的列和行数…

基于帧差法和形态学处理的行驶车辆跟踪算法matlab仿真

目录 1.算法理论概述 2.部分核心程序 3.算法运行软件版本 4.算法运行效果图预览 5.算法完整程序工程 1.算法理论概述 车辆跟踪是计算机视觉领域中的一个重要问题&#xff0c;它在交通监控、智能交通系统、自动驾驶等领域具有广泛的应用。本文介绍一种基于帧差法和形态学处…

maven安装配置、命令

maven: 是一个apache的一个开源项目&#xff0c;是一个项目管理工具&#xff0c;用来帮助开发者管理项目中的 jar&#xff08;mysql&#xff0c;jaskson&#xff0c;jwt&#xff09;&#xff0c;以及 jar 之间的依赖关系、完成项目的编译、测试、打包和发布等工作。 为什么学习…