QT(5.12)+Qgis(3.10) 点图层及线图层渲染

这部分参考了博主 Jacory_Gao的博文QGis二次开发基础 – 矢量图层的显示样式,这篇博文起到很好的渲染方面的导引作用,但是有些部分函数的结构和现在用的3.10不太一样了。而且发现里面描写的思路和我开发过程的翻看API的文档思路不太一样,于是重新撰写一遍。

要是有大佬们愿意指点一下开发思路,快来吧。搬板凳听课。

上一篇文章介绍了如何新建空白图层并向图层内新增特征。但如果不加其他的渲染(即显示方式的设置),很难进行多样化的数据显示,出来的效果就如下面两张图所示。
点图层线图层
显然上面两张图是没办法满足我们的~所以,继续往下做。

1 Qgis 中渲染的逻辑结构

博文中需要用到的几个大类:

  • QgsVectorLayer
  • QgsFeatureRenderer
  • QgsSymbol
  • QgsSymbolLayerList

1.1 首先从QgsVectorLayer看起

在API文档中,给了这样一个函数
void setRenderer (QgsFeatureRenderer *r)

Sets renderer which will be invoked to represent this layer.-----QGIS API
设置会被激活用于代表这个图层的渲染器

因此我们为了改变图层的渲染样式,所需要的事情就是构建一个我们想要的QgsFeatureRenderer

1.2 到QgsFeatureRenderer

API文档里对QgsFeatureRenderer的架构图
官网API文档架构图-QgsFeatureRenderer
可以从这个图中看出Qgis支持的所有渲染器格式,包括2.5D显示,分类显示,热力图,反向显示等等等。
我们这里只需要基本的改变显示样式的功能,因此关注其中的QgsSingleSymbolRenderer
因此现在的任务就是构建一个QgsSingleSymbolRenderer,因此看看其构造函数
QgsSingleSymbolRenderer::QgsSingleSymbolRenderer ( QgsSymbol * symbol )

在构造函数的描述下有一句话,表示我们传入的QgsSymbol,会用来渲染每一个特征,因此也反映了在singlesymbol的渲染中,不支持对每一个特征点进行单独的渲染设置,例如调整每个点渲染的方向。(如果采用分类渲染,或者改变了原来特征点的性质也有可能,但目前来看,点并不具有角度的性质)
The same symbol will be used to render every feature. Ownership of symbol is transferred to the renderer.

为了构造该渲染器,需要先构造QgsSymbol
ok,问题又转移到了如何构造一个QgsSymbol

1.3 到QgsSymbol

QgsSymbol的官方文档可以看出,其中又细分了三个子类,分别对应着多边形、线、点的渲染。
为了渲染不同的图层,构造对应的子类即可。接下逐一分析点Marker,线Line图层。
QgsSymbol官方API文档
观察两个类的构造函数,会发现其传入的参数都是同一个,
QgsMarkerSymbol (const QgsSymbolLayerList &layers=QgsSymbolLayerList())

QgsLineSymbol (const QgsSymbolLayerList &layers=QgsSymbolLayerList())
其构造需要传入参数QgsSymbolLayerList,因此接下来需要分析怎么构造该类

1.4 到QgsSymbolLayerList

发现QgsSymbolLayerList并不是一个独立的类,而是一个QList(Qgis中带List的都表示QList)
typedef QList<QgsSymbolLayer *> QgsSymbolLayerList;
内部存储的为QgsSymbolLayer,那么就转到如何构建这个图层了。

1.5 到 QgsSymbolLayer

下面这个继承关系图,可以看出基本分类还是按照点、线、面进行了子类的派生。我们下一步就只需要构建对应的子类便可。
QgsSymbolLayer官方关系图

1.6 总结

根据上面乱七八糟的分析,基本要重新设置图层的渲染器,就是按照下图的步骤进行

QgsFeatureRenderer的子类
QgsSymbol的子类
传入
点图层
线图层
构建QgsSingleSymbolRenderer
构建QgsMarkerSymbol
构建QgsLineSymbol
构建QgsSymbolLayer对应子类
QgsSymbolLayerList
调用QgsVectorLayer::setRenderer

2 点图层渲染代码实现

采用的是QgsSymbolLayer的子类QgsSvgMarkerSymbolLayer,传入矢量图标进行渲染

    My_MapCanvas->freeze();

    // 获取SVG矢量图标,绘制矢量图层
    QString Image_Path = QFileDialog::getOpenFileName(this,tr("Select a SVG Image"),"D:/QGIS_Code/QGIS_BASIC5/Qgis_Basic5/OSGeo4W64/apps/qgis-ltr/svg",tr("Image Files (*.svg)"));
    QgsSvgMarkerSymbolLayer* svg_Marker =  new QgsSvgMarkerSymbolLayer(Image_Path);

    // 创建QgsSymbolLayerList
    QgsSymbolLayerList Sym_Layer_List;
    Sym_Layer_List.append(svg_Marker);

    // 构建QgsMarkerSymbol
    QgsMarkerSymbol* MarkerSymbol = new QgsMarkerSymbol(Sym_Layer_List);

    // 构建QgsSingleSymbolRenderer, 即最终图层的渲染器
    QgsSingleSymbolRenderer* Sym_Renderer = new QgsSingleSymbolRenderer( MarkerSymbol );

    // 设置当前图层的渲染器
    CurrentLayer->setRenderer( Sym_Renderer );
    
    My_MapCanvas->freeze( false );
    My_MapCanvas->refresh();

3 线图层渲染代码实现

采用的是QgsSymboLayer的子类QgsSimpleLineSymbolLayer
然后调用该类的方法,设置颜色、样式、宽度等

	//设置线图层的样式,包括color, width (in millimeters) and penStyle
    QgsSimpleLineSymbolLayer* Line_Renderer_Layer = new QgsSimpleLineSymbolLayer();
    Line_Renderer_Layer->setColor(Qt::red);
    Line_Renderer_Layer->setPenStyle(Qt::PenStyle::DotLine);

    // 创建矢量图层列表,QgsSymbolLayerList就是重新定义了一个特殊的QList
    QgsSymbolLayerList Sym_Layer_List;
    Sym_Layer_List.append(Line_Renderer_Layer);

    // 构建QgsLineSymbol
    QgsLineSymbol* LineSymbol = new QgsLineSymbol(Sym_Layer_List);

    // 构建QgsSingleSymbolRenderer, 即最终图层的渲染器
    QgsSingleSymbolRenderer* Sym_Renderer = new QgsSingleSymbolRenderer( LineSymbol );
//    qDebug() << "Sym_Renderer" << Sym_Renderer;
    // 设置当前图层的渲染器
    CurrentLayer->setRenderer( Sym_Renderer );

4 箭头图层渲染代码实现

这段代码的目的:是为了实现在图层上显示可以自定义方向的箭头。
原始的方案是希望通过点图层实现,调整图层中每个点渲染的方式,或者改变每个点的相对角度等,但最后并没有找到相关的设定。只能设定渲染的角度,这将会统一改变这个图层下每一个点的角度。
后来的方案希望通过线图层实现,给出一个点与角度,按照默认的长度算出另一个点的坐标,将其作为一条线,并通过下面的方式进行渲染,形成箭头图标。
存在的问题这样需要自己去自适应箭头的长度,如果给定默认值会导致在不同比例尺下的畸变。然后也依然无法实现一个图层表示多个自定义角度的航标。只能通过多个图层来实现。
潜在的解决方案通过构建分类渲染器categorized renderer实现,或一个图层一个航标,多图层的管理进行实现。

    QgsArrowSymbolLayer* Arrow_Layer = new QgsArrowSymbolLayer();
    Arrow_Layer->setArrowType(QgsArrowSymbolLayer::ArrowType::ArrowPlain);

    // 创建矢量图层列表,QgsSymbolLayerList就是重新定义了一个特殊的QList
    QgsSymbolLayerList Sym_Layer_List;
    Sym_Layer_List.append(Arrow_Layer);

    // 构建QgsLineSymbol
    QgsLineSymbol* LineSymbol = new QgsLineSymbol(Sym_Layer_List);

    // 构建QgsSingleSymbolRenderer, 即最终图层的渲染器
    QgsSingleSymbolRenderer* Sym_Renderer = new QgsSingleSymbolRenderer( LineSymbol );

    // 设置当前图层的渲染器
    CurrentLayer->setRenderer( Sym_Renderer );

5 实现的效果

线图层

线图层-箭头
线图层-红色虚线
黑色实线

点图层

渲染成Qgis自带的hotel样式

猜你喜欢

转载自blog.csdn.net/j_in2018/article/details/107759640