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

1.效果图

Qgis二次开发-实现缩略图、标注_第1张图片

2.简介

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

void canvasPressEvent(QgsMapMouseEvent *e) override;

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

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

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

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

这是修改前的样子:

Qgis二次开发-实现缩略图、标注_第2张图片

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

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

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

Qgis二次开发-实现缩略图、标注_第3张图片

后面就又想了办法,随着地图的放大和缩小将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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "QgsMapToolSelectItem.h"
#include 
#include 
#include 

extern QList 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 &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博客 

你可能感兴趣的:(Qgis,qt,qgis,标注,缩略图)