赞
踩
这部分参考了博主 Jacory_Gao的博文QGis二次开发基础 – 矢量图层的显示样式,这篇博文起到很好的渲染方面的导引作用,但是有些部分函数的结构和现在用的3.10不太一样了。而且发现里面描写的思路和我开发过程的翻看API的文档思路不太一样,于是重新撰写一遍。
要是有大佬们愿意指点一下开发思路,快来吧。搬板凳听课。
上一篇文章介绍了如何新建空白图层并向图层内新增特征。但如果不加其他的渲染(即显示方式的设置),很难进行多样化的数据显示,出来的效果就如下面两张图所示。
显然上面两张图是没办法满足我们的~所以,继续往下做。
博文中需要用到的几个大类:
QgsVectorLayer
QgsFeatureRenderer
QgsSymbol
QgsSymbolLayerList
在API文档中,给了这样一个函数
void setRenderer (QgsFeatureRenderer *r)
Sets renderer which will be invoked to represent this layer.-----QGIS 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
从QgsSymbol
的官方文档可以看出,其中又细分了三个子类,分别对应着多边形、线、点的渲染。
为了渲染不同的图层,构造对应的子类即可。接下逐一分析点Marker,线Line图层。
观察两个类的构造函数,会发现其传入的参数都是同一个,
QgsMarkerSymbol (const QgsSymbolLayerList &layers=QgsSymbolLayerList())
QgsLineSymbol (const QgsSymbolLayerList &layers=QgsSymbolLayerList())
其构造需要传入参数QgsSymbolLayerList
,因此接下来需要分析怎么构造该类
发现QgsSymbolLayerList
并不是一个独立的类,而是一个QList
(Qgis中带List的都表示QList)
typedef QList<QgsSymbolLayer *> QgsSymbolLayerList;
内部存储的为QgsSymbolLayer
,那么就转到如何构建这个图层了。
下面这个继承关系图,可以看出基本分类还是按照点、线、面进行了子类的派生。我们下一步就只需要构建对应的子类便可。
根据上面乱七八糟的分析,基本要重新设置图层的渲染器,就是按照下图的步骤进行
采用的是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();
采用的是QgsSymboLaye
r的子类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 );
这段代码的目的:是为了实现在图层上显示可以自定义方向的箭头。
原始的方案是希望通过点图层实现,调整图层中每个点渲染的方式,或者改变每个点的相对角度等,但最后并没有找到相关的设定。只能设定渲染的角度,这将会统一改变这个图层下每一个点的角度。
后来的方案希望通过线图层实现,给出一个点与角度,按照默认的长度算出另一个点的坐标,将其作为一条线,并通过下面的方式进行渲染,形成箭头图标。
存在的问题这样需要自己去自适应箭头的长度,如果给定默认值会导致在不同比例尺下的畸变。然后也依然无法实现一个图层表示多个自定义角度的航标。只能通过多个图层来实现。
潜在的解决方案通过构建分类渲染器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 );
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。