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);
}