前言
本章讲述使用qgis c++ Api加载各种类型的矢量地图数据显示。
- 说明:文章中的示例代码均来自开源项目qgis_cpp_api_apps
加载矢量(vector)图层
在QGIS中,图层并不保存数据的实体,而是引用各种类型的数据源,并利用图层样式等属性渲染数据。
- 类
QgsVectorLayer
代表矢量图层,首先看一下官方文档
The QgsVectorLayer is instantiated by specifying the name of a data provider, such as postgres or wfs, and url defining the specific data set to connect to. The vector layer constructor in turn instantiates a QgsVectorDataProvider subclass corresponding to the provider type, and passes it the url. The data provider connects to the data source.
- 实例化
QgsVectorLayer
需要提供data provider的名称以及文件路径或url,其构造函数如下
QgsVectorLayer (const QString &path=QString(), const QString &baseName=QString(), const QString &providerLib="ogr", const QgsVectorLayer::LayerOptions &options=QgsVectorLayer::LayerOptions())
- data provider可以指定的值包括:
Provider | 说明 |
---|---|
ogr | OGR提供了一组基于标准的接口和函数库,用于处理和操作地理空间数据。 |
delimitedtext | 文本数据按指定的分隔符进行分割 |
gpx | GPX(GPS eXchange Format,GPS交换格式)是一种用于存储坐标数据的 XML 文件格式 |
spatialite | Spatialite是SQLite数据库的空间数据引擎。 |
memory | 数据存在内存中 |
postgres | POSTGRES是一个对象-关系型数据库管理系统(ORDBMS) |
mssql | MSSQL是指微软的SQLServer数据库服务器 |
wfs | WFS(Web Feature Service)是一种允许用户在分布式环境下通过HTTP对空间数据进行增加、删除、修改、查询的GIS数据服务 |
grass | GRASS GIS是一个开源的地理信息系统,可用于处理栅格、拓扑矢量、影像和图表数据。 |
-
data provider分两类,内置和外部,外部data provider以动态库的形式存在,如下图
以下是完整加载data provider后的输出
C:\src\OSGeo4W\src\qgis-ltr-dev\qgis\src\core\providers\qgsproviderregistry.cpp(337) : (QgsProviderRegistry::init) [633ms] Loaded 25 providers (OAPIF;WFS;arcgisfeatureserver;arcgismapserver;copc;delimitedtext;ept;gdal;geonode;gpx;hana;mdal;memory;mesh_memory;mssql;ogr;pdal;postgres;postgresraster;spatialite;vectortile;virtual;virtualraster;wcs;wms)
下边分别加载不同data provider的数据
ogr
Accesses data using the OGR drivers (https://gdal.org/drivers/vector/index.html). The url is the OGR connection string. A wide variety of data formats can be accessed using this driver, including file based formats used by many GIS systems, database formats, and web services. Some of these formats are also supported by custom data providers listed below.
OGR是用于读写矢量数据的抽象数据模型类库,是GDAL开源项目的一个分支,也采用X/MIT协议发布。
- OGR支持的矢量数据格式完整列表见链接
-
常见的矢量数据包括Shapefile、KML/KMZ、DXF/DMG、GPX、OSM等多种类型
Shapefile
- 一个Shapefile数据仅存储单一要素类型(如点、线、面)
- 一个Shapefile只包含一个图层
QGis导入.shp文件
QGis中打开后缀名为.shp格式的矢量图层
代码导入
- 传入文件路径,图层名,provider名称,构造
QgsVectorLayer
- 调用
QgsProject
的成员函数addMapLayer
即可
void MainWindow::addShpSlot()
{
QString filename = QStringLiteral("maps/shapefile/protected_areas.shp");
QFileInfo ff(filename);
//创建图层
QgsVectorLayer* vecLayer = new QgsVectorLayer(filename,ff.baseName(),"ogr");
if(!vecLayer->isValid())
{
QMessageBox::critical(this,tr("error"),tr("invalid layer"));
return;
}
QgsProject::instance()->addMapLayer(vecLayer);
zoomToFirstLayer<QgsVectorLayer*>();
}
gpx
GPX是一种以xml格式记录的坐标轨迹文件,通常由GPS设备生成
GPX通常包括航点(Waypoints)、路线(Routes)和轨迹(Tracks)三个主要图层。
QGis导入GPX文件
不同于Shapefile,GPX文件通常包含多个图层,在QGis中会提示用户选择图层
选择之后,添加图层
代码导入
- 基本流程和Shapefile一致
- ==注意:==路径参数,要通过在文件路径添加后缀
|layername=tracks
如下示例代码
void MainWindow::addGpxSlot()
{
QString filename = QStringLiteral("maps/route.gpx");
QFileInfo ff(filename);
//创建图层
QgsVectorLayer* route_pointsLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=route_points"),"route_points","ogr");
QgsVectorLayer* routesLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=routes"),"routes","ogr");
QgsVectorLayer* tracks_pointsLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=track_points"),"track_points","ogr");
QgsVectorLayer* tracksLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=tracks"),"tracks","ogr");
QgsVectorLayer* waypointsLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=waypoints"),"waypoints","ogr");
QList<QgsMapLayer *> mapLayers;
mapLayers << route_pointsLayer << routesLayer << tracks_pointsLayer << tracksLayer << waypointsLayer;
QgsProject::instance()->addMapLayers(mapLayers);
zoomToFirstLayer<QgsVectorLayer*>();
}
- 这样添加有一个问题,需要事先知道文件包含的图层名称,后边的章节会讲述如何获取包含的图层
- 这里QgsVectorLayer第三个参数provider传入的是ogr,也可以传入gpx,功能相同,但是uri不同,详情见下章
gpkg
全称是GeoPackage,是一种开放的、基于标准的、独立于平台的、可移植的、自描述的、用于传输地理空间信息的紧凑数据格式。
它是一个独立于平台的SQLite数据库文件,其中包含矢量要素、不同比例尺的图像和光栅映射的瓦矩阵集、属性(非空间数据)以及扩展机制。
QGis导入GPKG文件
gpkg基于SQLite,一般会存储多个图层,在QGis中会提示用户选择图层
代码导入
- 流程同gpx,示例代码如下
void MainWindow::addGpkgSlot()
{
QString filename = QStringLiteral("maps/points_gpkg.gpkg");
QFileInfo ff(filename);
//创建图层
QgsVectorLayer* points_gpkgLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=points_gpkg"),"points_gpkg","ogr");
QgsVectorLayer* points_smallLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=points_small"),"points_small","ogr");
QList<QgsMapLayer *> mapLayers;
mapLayers << points_gpkgLayer << points_smallLayer;
QgsProject::instance()->addMapLayers(mapLayers);
zoomToFirstLayer<QgsVectorLayer*>();
}
geojson
包含空间信息的数据交换格式,经常用于Web服务,进行数据交换
QGis导入GeoJson文件
代码导入
- 流程和Shapefile相同,代码如下
void MainWindow::addGeoJsonSlot()
{
QString filename = QStringLiteral("maps/grid_4326.geojson");
QFileInfo ff(filename);
QgsVectorLayer* vecLayer = new QgsVectorLayer(filename,ff.baseName(),"ogr");
if(!vecLayer->isValid())
{
QMessageBox::critical(this,tr("error"),tr("invalid layer"));
return;
}
QgsProject::instance()->addMapLayer(vecLayer);
zoomToFirstLayer<QgsVectorLayer*>();
}
gml
地理标记语言(GML)是一种用可扩展标记语言(XML)编写地理信息的方式,以方便地理信息的传输和存储。可以将其视为描述应用程序架构的XML语法,应用程序架构描述特定领域或给定上下文中的概念结构。
QGis导入GML
代码导入
void MainWindow::addGmlSlot()
{
QString filename = QStringLiteral("maps/linedensity.gml");
QFileInfo ff(filename);
QgsVectorLayer* vecLayer = new QgsVectorLayer(filename,ff.baseName(),"ogr");
if(!vecLayer->isValid())
{
QMessageBox::critical(this,tr("error"),tr("invalid layer"));
return;
}
QgsProject::instance()->addMapLayer(vecLayer);
zoomToFirstLayer<QgsVectorLayer*>();
}
kml/kmz
Keyhole 标记语言 (KML) 是一种基于 XML 的格式,用于存储地理数据和相关内容,是一种官方的开放地理空间联盟 (OGC) 标准。 KML 格式便于在 Internet 上发布并可通过许多免费应用程序(例如 Google Earth 和 ArcGIS Explorer)进行查看,因此常用于与非 GIS 用户共享地理数据。 KML 文件以 .kml 或 .kmz(表示压缩的 KML 文件)为扩展名。
QGis导入Kml
代码导入
void MainWindow::addKmlSlot()
{
QString filename = QStringLiteral("maps/multilayer.kml");
QFileInfo ff(filename);
//创建图层
QgsVectorLayer* layer1 = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=Layer1"),"Layer1","ogr");
QgsVectorLayer* layer2 = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=Layer2"),"Layer2","ogr");
QgsVectorLayer* layer3 = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=Layer3"),"Layer3","ogr");
QList<QgsMapLayer *> mapLayers;
mapLayers << layer1 << layer2 << layer3;
QgsProject::instance()->addMapLayers(mapLayers);
zoomToFirstLayer<QgsVectorLayer*>();
}
dxf/dwg
DXF 是Autodesk公司开发的用于AutoCAD与其它软件之间进行CAD数据交换的CAD数据文件格式
QGis导入dxf
代码导入
-
注意:这里使用了新参数
geometrytype=Point
和geometrytype=LineString
- 由于layername相同,所以使用geometrytype区分不同类型图层
void MainWindow::addDxfSlot()
{
QString filename = QStringLiteral("maps/points_lines_3d.dxf");
QFileInfo ff(filename);
//创建图层
QgsVectorLayer* points_gpkgLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=entities|geometrytype=LineString"),"entities1","ogr");
QgsVectorLayer* points_smallLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=entities|geometrytype=Point"),"entities2","ogr");
QList<QgsMapLayer *> mapLayers;
mapLayers << points_gpkgLayer << points_smallLayer;
QgsProject::instance()->addMapLayers(mapLayers);
zoomToFirstLayer<QgsVectorLayer*>();
}
Coverage
Coverage 是一种用于存储矢量数据的地理相关数据模型,它包含地理要素的空间(位置)数据和属性(描述性)数据。Coverage 使用一组要素类来表示地理要素。每个要素类存储一组点、线(弧)、面或注记(文本)。Coverage 可以具有拓扑,用于确定要素间的关系。
Coverage 以目录形式存储,而目录中的每个要素类则以一组文件的形式进行存储。
QGis导入Coverage矢量数据
-
注意: 这里Source Type选的是Directory
代码导入
void MainWindow::addCoverageSlot()
{
QString filename = QStringLiteral("maps/CoverageDir/testvector");
QFileInfo ff(filename);
QgsVectorLayer* aaLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=aa"),"aa","ogr");
QgsVectorLayer* ARCLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=ARC"),"ARC","ogr");
QgsVectorLayer* CNTLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=CNT"),"CNT","ogr");
QgsVectorLayer* PALLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("|layername=PAL"),"PAC","ogr");
QList<QgsMapLayer *> mapLayers;
mapLayers << aaLayer << ARCLayer << CNTLayer << PALLayer;
QgsProject::instance()->addMapLayers(mapLayers);
zoomToFirstLayer<QgsVectorLayer*>();
}
ogr参数总结
- 加载图层的过程中用到了
layerName,geometryType
等参数,这里给出ogr支持的所有参数 - qgis源码中qgsogrprovidermetadata.cpp中encodeUri函数
QString QgsOgrProviderMetadata::encodeUri( const QVariantMap &parts ) const
{
const QString vsiPrefix = parts.value( QStringLiteral( "vsiPrefix" ) ).toString();
const QString vsiSuffix = parts.value( QStringLiteral( "vsiSuffix" ) ).toString();
const QString path = parts.value( QStringLiteral( "path" ) ).toString();
const QString layerName = parts.value( QStringLiteral( "layerName" ) ).toString();
const QString layerId = parts.value( QStringLiteral( "layerId" ) ).toString();
const QString subset = parts.value( QStringLiteral( "subset" ) ).toString();
const QString geometryType = parts.value( QStringLiteral( "geometryType" ) ).toString();
const QString authcfg = parts.value( QStringLiteral( "authcfg" ) ).toString();
const QStringList openOptions = parts.value( QStringLiteral( "openOptions" ) ).toStringList();
const QString uniqueGeometryType = parts.value( QStringLiteral( "uniqueGeometryType" ) ).toString();
......
}
gpx
Provider reads tracks, routes, and waypoints from a GPX file. The url defines the name of the file, and the type of data to retrieve from it ("track", "route", or "waypoint").
An example url is "/home/user/data/holiday.gpx?type=route"
- 注意: 这次使用的data provider是gpx
QGis导入gpx
代码导入
-
注意 uri格式是
maps/route.gpx?type=route
,并且只支持route,track和waypoint
void MainWindow::addGpx1Slot()
{
QString filename = QStringLiteral("maps/route.gpx");
QFileInfo ff(filename);
QgsVectorLayer* routesLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("?type=route"),"route","gpx");
QgsVectorLayer* tracksLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("?type=track"),"track","gpx");
QgsVectorLayer* waypointsLayer = new QgsVectorLayer(QString("%1%2").arg(filename).arg("?type=waypoint"),"waypoint","gpx");
QList<QgsMapLayer *> mapLayers;
mapLayers << routesLayer << tracksLayer << waypointsLayer;
QgsProject::instance()->addMapLayers(mapLayers);
zoomToFirstLayer<QgsVectorLayer*>();
}
总结
- 分别使用qgis软件和代码导入了ogr,gpx支持的图层格式