文章目录
- 前言
- 数据查询
- QGis
- 代码实现
- 获取图层数据的字段QgsField
- 获取图层数据QgsFeature以及QgsAttribute
- 数据选择
- QGis
- 代码实现
- 创建虚拟图层并保存为shape文件
- QGis
- 代码实现
- 总结
前言
- 前几章分别介绍了qgis二次开发环境搭建、整体框架、二次开发初始化、Map canvas、矢量图层加载、栅格图层加载
- 本章介绍矢量图层加载之后对图层数据的查询、选择以及保存
- 说明:文章中的示例代码均来自开源项目qgis_cpp_api_apps
为了获取地理空间数据的详细信息及统计结果,需要使用数据选择、筛选、查询与统计等方法。
数据查询可以获得矢量数据与栅格数据的属性信息;
数据选择(仅针对矢量图层)是指通过空间位置、属性信息等特征选取的部分地理要素,被选择的地理要素可以进一步被其他的编辑工具或分析工具处理;
数据筛选是指通过表达式等方式仅加载矢量数据中的部分要素,以便进一步制图或处理;
数据统计可以针对这些属性信息进行统计操作。
数据查询
QGis
- 以myplaces.shp为例,添加图层后,右键菜单选择Open Attribute Table, 如下图
- 可以看到一个二维表格,显示矢量图层的数据,如下图
- 其数据存储和关系型数据库相同
- 表头NAME、PLACE、ADDR_CITY等等相当于数据库中的字段,在QGis中以
QgsField
类表示 - 每一行是一个Feature,feature除表中的数据外还有空间属性,在QGis中以
QgsFeature
类表示 - 每一行的每一列是一个具体的数据,在QGis中以
QgsAttributes
类表示 - 可以从表格中筛选数据,点击下图所示按钮
- 输入表达式,如下图
- 选择Filter Current Selection后,点击按钮后,效果如下图所示
代码实现
获取图层数据的字段QgsField
- 类
QgsField
代表字段,详情见文档 - 类
QgsVectorLayer
中的函数QgsFields fields()
用于获取字段
void MainWindow::getFieldsSlot()
{
//添加测试图层
QString filename = QStringLiteral("maps/shapefile/myplaces.shp");
QFileInfo ff(filename);
QgsVectorLayer* layer = (QgsVectorLayer*)mApp->addVectorLayer(filename,ff.baseName());
zoomToFirstLayer<QgsVectorLayer*>();
mVectorDataDockWidget->show();
mVectorDataDockWidget->plainTextEdit()->clear();
for(auto field : layer->fields())
{
mVectorDataDockWidget->plainTextEdit()->appendPlainText(QString("%1:%2").arg(field.name()).arg(field.typeName()));
}
}
获取图层数据QgsFeature以及QgsAttribute
- 类
QgsFeature
代表图层中一个特征,该特征包含一个featureId,空间特征(点、线、面以及其坐标)和字段/值属性列表。详情见文档 - 类
QgsAttributes
是feature的字段/值属性,详情见文档 - 类
QgsVectorLayer
的函数QgsFeatureIterator getFeatures( const QgsFeatureRequest &request = QgsFeatureRequest() )
用户获取features,其参数QgsFeatureRequest
用于过滤数据,默认参数会获取所有feature - 类
QgsFeature
的函数attributes()用于获取feature的属性 - 首先演示获取所有feature,代码如下
void MainWindow::getFeaturesSlot()
{
//添加测试图层
QString filename = QStringLiteral("maps/shapefile/myplaces.shp");
QFileInfo ff(filename);
QgsVectorLayer* layer = (QgsVectorLayer*)mApp->addVectorLayer(filename,ff.baseName());
zoomToFirstLayer<QgsVectorLayer*>();
mVectorDataDockWidget->show();
mVectorDataDockWidget->plainTextEdit()->clear();
QgsFeatureIterator it = layer->getFeatures();
QgsFeature f;
while(it.nextFeature(f))
{
QString str;
str.append(QString("%1").arg(f.id()));
str.append(" ");
QgsAttributes attrs = f.attributes();
for(int i = 0;i < attrs.size();++i)
{
str.append(attrs[i].toString());
str.append(" ");
}
mVectorDataDockWidget->plainTextEdit()->appendPlainText(str);
}
}
- 筛选数据的代码如下,将字段RAINFALL的值大于200.0的保留
QString str = QString("\"RAINFALL\" > 200.0");
auto request = QgsFeatureRequest().setFilterExpression(str);
QgsFeatureIterator it = layer->getFeatures(request);
- 完整测试代码如下
void MainWindow::getFeaturesSlot()
{
//添加测试图层
QString filename = QStringLiteral("maps/shapefile/myplaces.shp");
QFileInfo ff(filename);
QgsVectorLayer* layer = (QgsVectorLayer*)mApp->addVectorLayer(filename,ff.baseName());
zoomToFirstLayer<QgsVectorLayer*>();
mVectorDataDockWidget->show();
mVectorDataDockWidget->plainTextEdit()->clear();
//带feature的expression
QString str = QString("\"RAINFALL\" > 200.0");
auto request = QgsFeatureRequest().setFilterExpression(str);
QgsFeatureIterator it = layer->getFeatures(request);
QgsFeature f;
while(it.nextFeature(f))
{
QString str;
str.append(QString("%1").arg(f.id()));
str.append(" ");
QgsAttributes attrs = f.attributes();
for(int i = 0;i < attrs.size();++i)
{
str.append(attrs[i].toString());
str.append(" ");
}
mVectorDataDockWidget->plainTextEdit()->appendPlainText(str);
}
}
数据选择
QGis
- 在“Attributes Toolbar”工具栏中,单击按钮右侧的下拉按钮,弹出的菜单中展示了交互式选择的四种方式,如下图所示
- 选择要素之后,颜色变为黄色,如下图
- 在默认情况下,选择的要素以黄色的点、线或黄色面填充符号突出显示在地图画布上。在QGIS的“Options”对话框的“Canvas & Legend”选项卡中,通过“Selection color”选项即可更改选择要素的颜色
代码实现
- 类
QgsVectorLayer
的一组选择函数实现了多种选择方式,代码如下
void select( QgsFeatureId featureId );
void select( const QgsFeatureIds &featureIds );
void selectAll();
void selectByRect( QgsRectangle &rect, Qgis::SelectBehavior behavior = Qgis::SelectBehavior::SetSelection );
void selectByExpression( const QString &expression, Qgis::SelectBehavior behavior = Qgis::SelectBehavior::SetSelection, QgsExpressionContext *context = nullptr );
void selectByIds( const QgsFeatureIds &ids, Qgis::SelectBehavior behavior = Qgis::SelectBehavior::SetSelection );
void deselect( QgsFeatureId featureId );
void deselect( const QgsFeatureIds &featureIds );
void removeSelection();
void reselect();
void modifySelection( const QgsFeatureIds &selectIds, const QgsFeatureIds &deselectIds );
- 完整测试代码如下
void MainWindow::selectFeaturesSlot()
{
//添加测试图层
QString filename = QStringLiteral("maps/shapefile/myplaces.shp");
QFileInfo ff(filename);
QgsVectorLayer* layer = (QgsVectorLayer*)mApp->addVectorLayer(filename,ff.baseName());
zoomToFirstLayer<QgsVectorLayer*>();
QString expression = QString("\"RAINFALL\" > 200.0");
//选择所有
// layer->selectAll();
//按照id选择
// QgsFeatureId id = 0;
// layer->select(id);
//按照多个id选择
// QgsFeatureIds ids;
// ids << 0 << 1 << 2 << 3;
// layer->select(ids);
//按照表达式选择
// layer->selectByExpression(expression);
//按照区域选择,并且使用rubberband显示区域
QgsRectangle rect(1006585,6222254,1010253,6219118);
layer->selectByRect(rect);
QgsPointXY point1(1006585,6222254);
QgsPointXY point2(1010253,6222254);
QgsPointXY point3(1006585,6219118);
QgsPointXY point4(1010253,6219118);
QgsRubberBand *rubberBand = new QgsRubberBand(mApp->mapCanvas(),QgsWkbTypes::PolygonGeometry);
rubberBand->addPoint(point1);
rubberBand->addPoint(point2);
rubberBand->addPoint(point4);
rubberBand->addPoint(point3);
rubberBand->show();
//选择feature并且闪烁
// QgsMapCanvasUtils::flashMatchingFeatures(mApp->mapCanvas(),layer,expression);
//选择Feature并zoom
// QgsMapCanvasUtils::zoomToMatchingFeatures(mApp->mapCanvas(),layer,expression);
}
创建虚拟图层并保存为shape文件
虚拟图层是在不改变矢量数据源的情况下,改变某些空间或属性信息,或者组合多个矢量图层,并以虚拟图层的方式展现数据。虚拟图层并不直接指向数据源,而是通过SQL查询语句等引用一个或多个矢量图层。
QGis
- 此处介绍如何通过虚拟图层将“2017.xlsx”文件连接到吉林省地级行政区划文件(jilin_dist.shp)
- 分别加载这两个图层
- 打开图层jilin_dist的Attribute Table,如下图
- 打开图层2017–Sheet1的Attribute Table,如下图
- 添加一个虚拟图层,将上述两个图层的数据连接到一起
- 在“Layer name”文本框中输入新生成的虚拟图层的名称;在“Embedded layers”组合框中单击“Import”按钮,将上述两个图层加入列表中,并在“Local name”选项中设置图层名称,同时将其作为SQL查询语句的表名称。单击“Add”按钮可以输入图层位置;单击“Remove”按钮可以删除图层。在“Query”文本框中输入以下查询语句:
SELECT * FROM jilin_dist left outer join prec on jilin_dist.NAME = prec.city;
- 该语句可以通过jilin_dist图层的“NAME”字段和prec图层的“city”字段将prec图层的属性连接到jilin_dist图层中。
- 单击“Add”按钮即可在图层列表中看到该虚拟图层。打开virtual_layer图层的Attribute Table可以看到连接后的数据表,如下图
代码实现
- 类
QgsVirtualLayerDefinition
定义虚拟图层连接信息,详情见文档 - 其成员函数
void addSource( const QString &name, const QString &source, const QString &provider, const QString &encoding = "" );
用于添加添加图层。代码如下
//QgsVirtualLayerDefinition
QgsVirtualLayerDefinition def;
//add embedded layers
def.addSource("prec","maps/virtuallayer/2017.xlsx|layername=Sheet1","ogr");
def.addSource("jilin_dist","maps/virtuallayer/jilin_dist.shp","ogr");
- 成员函数
void setQuery( const QString &query )
用于设置查询语句
//查询语句
def.setQuery("SELECT * FROM jilin_dist left outer join prec on jilin_dist.NAME = prec.city;");
- 新建矢量图层
QgsVectorLayer
,数据源provider传入virtual,代码如下
const QgsVectorLayer::LayerOptions options { QgsProject::instance()->transformContext() };
QgsVectorLayer *vl = new QgsVectorLayer( def.toString(), QStringLiteral( "test" ), QStringLiteral( "virtual" ), options );
- 类
QgsVectorFileWriter
用于将图层保存至文件,详情见文档 - 其成员函数
writeAsVectorFormatV3
用于保存,虚拟图层保存至文件的代码如下
QgsVectorFileWriter::SaveVectorOptions opt;
QgsVectorFileWriter::writeAsVectorFormatV3(vl,"maps/virtuallayer/myvurtual.shp",QgsProject::instance()->transformContext(),opt);
- 保存的图层文件如下
总结
- 分别演示了:
- QGis软件矢量图层数据的查询、选择和保存
- 二次开发c++ api的图层数据的查询、选择和保存