QGIS二次开发01---临时绘制图层实现

本文聚焦于采用C++实现的开源GIS软件QGIS,指出其体系设计存在缺少类似SuperMap跟踪图层的缺陷。基于Qt,详细介绍了实现类似跟踪图层功能的方法,包括QGIS临时对象绘制的实现,如绘制几何对象和清除临时绘制,以及临时图层类的实现。

QGIS是采用C++实现的开源GIS软件,功能强大,但在实现中感觉体系设计中存在一定缺陷,比如缺少类似SuperMap的跟踪图层,实现不同类型、样式的几何对象的临时显示。本文就是实现类似SuperMap的跟踪图层功能,实现临时绘制对象的集中管理。

注意:以下实现均为Qt

一、QGIS临时对象绘制的实现

1、绘制几何对象

QGIS使用QgsRubberBand(橡皮擦,随时擦除,很形象)实现对象的临时绘制,可以支持三类几何对象PointGeometry、LineGeometry和PolygonGeometry的绘制,并通过设置不同的样式实现风格迥异。如下:


/**创建一个绘制线的橡皮擦指针*/
QgsRubberBand * rb = new QgsRubberBand(mapCanvas,QgsWkbTypes::LineGeometry);
/**设置橡皮擦样式*/
rb->setStrokeColor(QColor(255,0,0));
rb->setWidth(3);
QgsGeometry geoLine = QgsGeometry::fromPolylineXY(points);//points为线的点串
rb-setGeometry(geoLine);

说明:每个橡皮擦只能提供一种类型几何对象绘制,而且样式一致。一个橡皮擦对象可以绘制多个几何对象。也就是如果要实现不同类型和样式的几何对象绘制,就必须要根据情况生成不同的橡皮擦。

2、清除临时绘制

清除临时绘制有两种方法

//方法一
使用QgsRubberBand::reset(QgsWkbTypes::GeometryType type=GeometryType::LineGeometry)
//方法二
delete rb;            //rb是橡皮擦对象指针
rb = nullptr;         //置空指针,qt下的用法

二、临时图层类的实现

为了实现临时图层可以同时管理多个不同类型和样式的几何对象,就必须实现每个绘制的临时几何对象必须和一个橡皮擦对象的一一对应:

1、定义一个几何QMap<QString,QgsRubberBand *> mRbSet,用于保存橡皮擦对象,其中uuid作为key

2、临时绘制对象入集合

QgsRubberBand *rb = new QgsRubberBand(mapCanvas,你要绘制的几何对象类型);
QString uuid = QUuid::createUuid().toString();
//设置rb的样式
rb->setColor(QColor(255,0,0));
...
//创建geometry
QgsGeometry geo = ....;
//绘制
rb->addGeometry(geo);
mRbSet.insert(uuid,rb);//mRbSet是QMap<QString,QgsRubberBand *>的实例

3、移除指定的临时对象

1、根据uuid获取mRbSet中的对应项的值;
2、调用QgsRubberBand::reset(),删除橡皮擦指针;
3、mRbSet.remove(uuid);

4、hitTest的实现

获取与hitTest处相交的临时对象

//假设xy为经纬度
QList<QString> MyTrackingLayerHandler::hitTest(QgsPointXY xy){
    QList<QString> result = QList<QString>();

    int count = mRbSet.count();
    if(count==0)return result;

    QMapIterator<QString,QgsRubberBand *> iterator(mRbSet);
    while(iterator.hasNext()){
        iterator.next();
        QgsRubberBand *rb = iterator.value();
        QgsGeometry geo = rb->asGeometry();
        QgsGeometry target = buffer(xy,10);    //创建缓冲,缓冲10像素,主要是提高命中率

        if(geo.intersects(target)){
            result.append(iterator.key());
        }
    }


    return result;
}

/**
 * 以xy为中心点,缓冲off个像素
 * @brief SHQgisTrackingLayerHandler::buffer
 * @param xy
 * @param off
 * @return
 */
QgsGeometry MyTrackingLayerHandler::buffer(QgsPointXY xy,int off){

    QgsPointXY pixel = mMapCanvas->getCoordinateTransform()->transform(xy);
    QgsPointXY pixel1 = QgsPointXY(pixel.x()-off,pixel.y()-off);
    QgsPointXY pixel2 = QgsPointXY(pixel.x()+off,pixel.y()+off);

    QgsPointXY map1 = mMapCanvas->getCoordinateTransform()->toMapCoordinates(pixel1.x(),pixel1.y());
    QgsPointXY map2 = mMapCanvas->getCoordinateTransform()->toMapCoordinates(pixel2.x(),pixel2.y());

    QgsRectangle rect = QgsRectangle(map1,map2);

    return QgsGeometry::fromRect(rect);
}

<think>好的,我现在需要帮助用户解决在QtQGIS二次开发实现新建矢量图层并使用鼠标绘制形状的问题。首先,我得回顾一下用户之前提供的上下文和他们当前的请求。 用户之前问过如何新增矢量图层并在QGIS图像引擎上勾勒形状,我给出了一个详细的实现方案。现在用户的新问题是想实现鼠标绘制形状并新建矢量图层,同时他们提供了三个站内引用,这些引用提到了图层添加到工程和画布的区别、鼠标拖动问题以及临时绘制图的方法。 首先,我需要确认用户的具体需求:他们想要通过鼠标交互在新建的矢量图层上绘制几何形状。这可能包括创建图层、设置绘图工具、处理用户输入以及将绘制的几何图形保存到图层中。 接下来,我需要参考用户提供的引用内容。引用[1]提到,将图层添加到工程和画布是分开的,因此需要确保图层正确添加到工程并在画布上显示。引用[2]指出,必须调用setMapTool来启用鼠标拖动,否则可能出现无法拖动的问题,同时添加图层时需要QgsProject::instance()->addMapLayer。引用[3]提到使用QgsRubberBand进行临时绘制,并用UUID管理绘制对象。 结合之前的回答,我需要整合这些信息。用户可能需要以下步骤: 1. 创建矢量图层并添加到工程和画布。 2. 设置地图工具以捕获鼠标事件。 3. 使用QgsRubberBand实时显示绘制形状。 4. 将最终几何图形保存到图层。 需要考虑的问题包括:如何正确初始化绘图工具,如何处理不同几何类型(点、线、面),如何管理临时绘制对象,以及如何确保图层正确显示并保存数据。此外,引用[2]中提到必须设置地图工具,否则无法拖动,因此需要在激活绘图工具时正确处理,避免影响用户交互体验。 可能遇到的难点是确保坐标转换正确,特别是在不同坐标系下的绘制。此外,内存管理也很重要,比如及时清理临时绘制的对象,防止内存泄漏。 现在需要将这些步骤具体化,并参考之前的代码示例,结合用户提供的引用,给出一个清晰的实现方案。需要确保代码示例正确,包括创建图层、设置符号、处理绘图事件,并将几何图形添加到图层中。同时,要提醒用户注意可能的问题,比如图层有效性检查、坐标系设置以及性能优化建议。</think>以下是在QtQGIS二次开发实现鼠标绘制形状并创建矢量图层的完整解决方案,结合您提供的引用内容和技术要点: --- ### 一、核心实现流程 ```mermaid graph TD A[创建矢量图层] --> B[设置图层样式] B --> C[激活绘制工具] C --> D[实时绘制预览] D --> E[提交几何要素] ``` --- ### 二、分步骤实现(结合引用内容优化) #### 1. 创建矢量图层(支持动态坐标系) ```cpp // 根据绘制类型创建图层(示例为多边形) QgsWkbTypes::GeometryType geomType = QgsWkbTypes::PolygonGeometry; QString layerType = geomType == QgsWkbTypes::PolygonGeometry ? "Polygon" : geomType == QgsWkbTypes::LineGeometry ? "LineString" : "Point"; QgsVectorLayer* newLayer = new QgsVectorLayer( layerType + "?crs=EPSG:4326&field=id:integer", // 坐标系根据实际需求修改 "绘制图", "memory" ); // 必须同时执行以下两个操作[^1][^2] QgsProject::instance()->addMapLayer(newLayer); // 添加到工程 m_mapCanvas->setLayers(QList<QgsMapLayer*>() << newLayer); // 关联到画布 ``` #### 2
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值