QGIS二次开发,我的第一篇

来源:互联网 发布:英格拉姆体测数据 编辑:程序博客网 时间:2024/05/19 13:22

开始搞QGIS二次开发,希望能记录下开发的的点点滴滴,也是自己学习的笔记记录。

先直接上代码把:

#include<QtGui/QApplication>
#include<qgsapplication.h>
//扩展了Qapplication以便可以获取QGIS的特定资源,比如主题路径和数据库路径等。
#include<qgsproviderregistry.h>
//是一个单体类来管理数据访问程序(data provider),用于加载插件;
#include<qgsmaplayerregistry.h>
//此类用来记录现在已经加载的地图图层,并且提供方法来获取指向地;
#include<qgsvectorlayer.h>
//矢量图层;
#include<qgsmapcanvas.h>
//一个类保存了指向图层的指针,和图层是否可见等信息。是主要的地图区域,用于绘制地图。;
#include<QString>
#include<QApplication>
#include<QWidget>
#include <QStringList>




#include<QMessageBox>
#include<QObject>
#include <QList>
#include <QFileInfoList>
#include <QDir>
#include <QLibrary>
#include <QDebug>


#include <qgssymbollayerv2.h>
#include <qgssymbolv2.h>
#include <qgsmarkersymbollayerv2.h>
#include <qgsvectorlayerrenderer.h>
#include <qgsrendercontext.h>
#include <qgssinglesymbolrendererv2.h>//是一个渲染类,利用Qgssymbol来显示所有特征,可以用来渲染点,线 面用一个颜色(每个矢量图层必须有一个符号关联);
#include <qgssymbollayerv2.h>

//代码
int main( int argc, char *argv[] )
{
QgsApplication myApp( argc, argv, true );//在这里换成QgsApplication,方便调用QgsApplication的静态方法。
QgsApplication::setPrefixPath( "F:/QGISxiazai/dev", true );//设置插件路径;
QgsApplication::initQgis();


QgsProviderRegistry* provider = QgsProviderRegistry::instance();


// 改成你自己的点矢量文件路径
QString myLayerPath         = "E:/data/dierpi/point55.shp";
QString myLayerBaseName     = "airports"; //图层名称;

////打开矢量文件;
QList<QgsMapLayer*> myList;
QgsVectorLayer* veclayer = new QgsVectorLayer( myLayerPath, myLayerBaseName, "ogr", false );
if ( !veclayer )
{
return 0;
}
if ( veclayer->isValid() )
{
QMessageBox::information( 0, "", "layer is valid" );
veclayer->setProviderEncoding( "System" );
myList << veclayer;
}


if ( veclayer->geometryType() == QGis::Point )
{
// 创建 svgMarkerSymbolLayer
QgsSvgMarkerSymbolLayerV2* svgMarker = new QgsSvgMarkerSymbolLayerV2();
svgMarker->setPath( "F:/QGISxiazai/dev/svg/money/money_currency_exchange.svg" );


QgsSvgMarkerSymbolLayerV2* svgMarker1 = new QgsSvgMarkerSymbolLayerV2();
svgMarker1->setPath( "F:/QGISxiazai/dev/svg/money/money_atm.svg" );


QgsSymbolLayerV2List symList;
symList.append( svgMarker );
symList.append( svgMarker1 );///绑定;


QgsMarkerSymbolV2* markSym = new QgsMarkerSymbolV2( symList );
//分配一个地图渲染器,需要传入几何类型(vectorlayer是一个自我描述的类);
QgsSingleSymbolRendererV2* symRenderer = new QgsSingleSymbolRendererV2( markSym );

svgMarker->setSize( 5 );
svgMarker1->setSize( 5 );////大小设置;


veclayer->setRendererV2( symRenderer );
}
//实例化地图注册类之后,然后增加图层;
QgsMapLayerRegistry::instance()->addMapLayer( veclayer );
QList<QgsMapCanvasLayer> myLayerSet;
//向list数据中增加mapCanvasLayer;
myLayerSet.append( QgsMapCanvasLayer( veclayer ) );


QgsMapCanvas* mypMapCanvas = new QgsMapCanvas( 0, 0 );
mypMapCanvas->setExtent( veclayer->extent() );
//开启反锯齿效果;
mypMapCanvas->enableAntiAliasing( true );
mypMapCanvas->setCanvasColor( QColor( 255, 255, 255 ) );
mypMapCanvas->freeze( false );
//设定mapCanvas的数据集;
mypMapCanvas->setLayerSet( myLayerSet );
mypMapCanvas->setVisible( true );
mypMapCanvas->refresh();


return myApp.exec();
}


在这个工程之前需要把工程路径的各个库配置好;




在生成的EXE下要对应好相应的dll版本,才能正确运行;

x现在来分析一下代码:

几个类之间的关系

首先要讲的,是矢量图层样式相关的几个类,它们分别是

  • QgsVectorLayer
  • QgsSymbolV2
  • QgsSymbolLayerV2
  • QgsFeatureRendererV2

它们的关系是这样的。QgsFeatureRendererV2 控制着QgsVectorLayer 的“渲染”样式,而具体用什么样式来“渲染”,则是有 QgsSymbolV2来定义的,QgsSymbolLayerV2 是 QgsSymbolV2 的扩展。搞明白这几个类的关系有助于我们后面的理解。实际上,我们基本不会直接用到这几个类,大多数时候是在用它们的子类。

QgsVectorLayer 不必多说,只需要知道使用它的方法“setRendererV2()”来绑定它的 Renderer 就好了。

QgsFeatureRendererV2

来看看矢量图层都支持那些 Renderer,也就是 QgsFeatureRendererV2 这个类的派生关系,如下图 
这里写图片描述 
从图上可以看到,这里支持的渲染方式还是蛮多的,GIS的同学看到这些名字应该不会太陌生,就是我们设置图层属性面板时候的那个下拉菜单里面的内容,见下图。

这里写图片描述

这里内容太多,就不逐个介绍了,本篇文章中我们只关注一个最简单也是最常用的 QgsSingleSymbolRendererV2 ,也就是我们经常使用在点图层标记上的单个的样式。

QgsSymbolV2

这个类就是直接关系到图层显示的“造型”了,也就是在这里设置各种图层样式的属性。还是先来看看它的派生类关系。

这里写图片描述

简单说明一下,QgsFillSymbolV2 对应的是多边形矢量图层,QgsLineSymbolV2 对应的是线性矢量图层, 而QgsMarkerSymbolV2 自然就是对应点矢量图层了。

关于这些类的设置大多集中在“颜色”、“大小”、“透明度”等属性上,每个派生类也都有自己的一些属性,详细的情况还是建议大家看看 API 文档 。

QgsSymbolLayerV2

QGis扩展了简单的 Symbol 图层样式,将原来单一的 Symbol 变成了“图层”方式,使得样式可定制的自由度开阔了许多, 当然派生关系也多了很多,见下图。

这里写图片描述

从这个图里面可以看到,分别对应这多边形、线和点都有各自的样式图层,将一个矢量图形的图标拆分,基本每个地方都有可定制的余地,都有专门的样式图层类来控制。这里很多同学应该特别关注一下QgsSvgMarkerSymbolLayerV2 这个类,这个类允许我们使用自己做好的“svg”格式的图标来作为图层的显示样式,借助这个特性,我们能够将t做成图层显示成任何我们想要的样式,如下图效果。

这里写图片描述

调用机理

下面我将会通过一个非常简单的示例来阐述这些类的调用机理。

要做图层样式显示,自然需要一个矢量图层,于是

QString myLayerPath         = "D:/Data/qgis_sample_data/shapefiles/airports.shp";  // 修改为自己的文件路径QString myLayerBaseName     = "airports"; //图层名称;  QgsVectorLayer* vecLayer = new QgsVectorLayer( myLayerPath, myLayerBaseName, "ogr", false );  
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

这里我们以“”图层作为例子,直接copy代码的同学,需要将你的文件路径改为一个有效的“”图层文件路径。

然后,创建一个样式图层,也就是 QgsSymbolLayerV2 类型,但我们要使用“svg” 格式的图片作为显示样式,因此使用 QgsSymbolLayerV2 的派生类 QgsSvgMarkerSymbolLayerV2 。先不要太在意下面代码中构造函数里面的字符串,后面来讲它的作用。

// 创建 svgMarkerSymbolLayerQgsSvgMarkerSymbolLayerV2* svgMarker = new QgsSvgMarkerSymbolLayerV2( "money/money_bank2.svg" );
  • 1
  • 2
  • 1
  • 2

前面说过,这是一个样式图层,图层是可以叠加的,也就是说可以做好几个这样的样式,然后叠加上去显示,但是总归要有一个管理这些样式图层的集合,于是

QgsSymbolLayerV2List symList;
  • 1
  • 1

并将刚才创建的样式图层装到这个 List 里面去,喜欢的话你可以多装几个样式图层进去,这里就只装一个做演示。

symList.append( svgMarker );
  • 1
  • 1

做好了显示样式,还需要将这个样式传给图层”渲染器“才行,需要建立一个点图层的 Renderer,并且这个 Renderer 还只接受 QgsSymbolV2 这个类型的参数,于是需要将样式图层 QgsSymbolLayerV2 转换为 QgsSymbolV2 类型。由于这里是点图层,就用到 QgsSymbolV2 的子类 QgsMarkerSymbolV2 , 又通过 API 文档了解到这个类的构造函数接受 QgsSymbolLayerV2List 这个样式图层的集合,于是也就将 Symbol 和 SymbolLayer 联系了起来。代码如下。

QgsMarkerSymbolV2* markSym = new QgsMarkerSymbolV2( symList );QgsSingleSymbolRendererV2* symRenderer = new QgsSingleSymbolRendererV2( markSym );
  • 1
  • 2
  • 1
  • 2

最后,就只需要将这个图层渲染器连接到之前建立的矢量图层就好了

veclayer->setRendererV2( symRenderer );
  • 1
  • 1

这样,MapCanvas 刷新以后,就可以看到图层的显示效果了。如果觉得图标小,还可以加一句

svgMarker->setSize( 10 );
  • 1
  • 1

效果如下图: 
这里写图片描述

最后一点

上面的代码直接拷贝是会有问题的,效果应该是下面这样 
这里写图片描述

全是问号,为什么?

这是没有找到对应的 svg 图标,也就是刚才上面的那一句

QgsSvgMarkerSymbolLayerV2* svgMarker = new QgsSvgMarkerSymbolLayerV2( "money/money_bank2.svg" );
  • 1
  • 1

这里只给了文件的名称,并没有指出文件的路径,因此程序找不到对应的 svg 格式文件。

打开QGis源码,不难发现这里有两种方式传文件路径,一种是在全局设置一个 svg 文件夹的默认路径,另一种则是直接在创建类之后给出完整的文件路径。

  • 先设置默认路径,再传文件名作为构造函数的参数
// 放在 main 函数里设置路径QgsApplication myApp( argc, argv, true );QgsApplication::setPrefixPath( "C:/Program Files/qgis2.9.0", true );QgsApplication::initQgis();myApp.setDefaultSvgPaths( QStringList( "../images/svg" ) );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

之后就可以按照上文的方式传文件名 “money/money_bank2.svg” 进去了

QgsSvgMarkerSymbolLayerV2* svgMarker = new QgsSvgMarkerSymbolLayerV2( "money/money_bank2.svg" );
  • 1
  • 1
  • 直接给出完成的文件路径
QgsSvgMarkerSymbolLayerV2* svgMarker = new QgsSvgMarkerSymbolLayerV2();svgMarker->setPath( "C:/Program Files/qgis2.9.0/images/svg/money/money_bank2.svg" );
  • 1
  • 2
  • 1
  • 2

效果是一样的。

这里先借用别人的分析了,引自http://blog.csdn.net/deirjie/article/details/50464768


0 0
原创粉丝点击