• 7. 矢量图层数据查询选择和保存


    前言

    为了获取地理空间数据的详细信息及统计结果,需要使用数据选择、筛选、查询与统计等方法。
    数据查询可以获得矢量数据与栅格数据的属性信息;
    数据选择(仅针对矢量图层)是指通过空间位置、属性信息等特征选取的部分地理要素,被选择的地理要素可以进一步被其他的编辑工具或分析工具处理;
    数据筛选是指通过表达式等方式仅加载矢量数据中的部分要素,以便进一步制图或处理;
    数据统计可以针对这些属性信息进行统计操作。

    数据查询

    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();
    
        mVectorDataDockWidget->show();
        mVectorDataDockWidget->plainTextEdit()->clear();
        for(auto field : layer->fields())
        {
            mVectorDataDockWidget->plainTextEdit()->appendPlainText(QString("%1:%2").arg(field.name()).arg(field.typeName()));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述
    在这里插入图片描述

    获取图层数据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();
    
        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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    在这里插入图片描述
    在这里插入图片描述

    • 筛选数据的代码如下,将字段RAINFALL的值大于200.0的保留
        QString str = QString("\"RAINFALL\" > 200.0");
        auto request = QgsFeatureRequest().setFilterExpression(str);
        QgsFeatureIterator it = layer->getFeatures(request);
    
    • 1
    • 2
    • 3
    • 完整测试代码如下
    void MainWindow::getFeaturesSlot()
    {
        //添加测试图层
        QString filename = QStringLiteral("maps/shapefile/myplaces.shp");
        QFileInfo ff(filename);
        QgsVectorLayer* layer = (QgsVectorLayer*)mApp->addVectorLayer(filename,ff.baseName());
        zoomToFirstLayer();
    
        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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    在这里插入图片描述

    数据选择

    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 );
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 完整测试代码如下
    void MainWindow::selectFeaturesSlot()
    {
        //添加测试图层
        QString filename = QStringLiteral("maps/shapefile/myplaces.shp");
        QFileInfo ff(filename);
        QgsVectorLayer* layer = (QgsVectorLayer*)mApp->addVectorLayer(filename,ff.baseName());
        zoomToFirstLayer();
    
        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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    在这里插入图片描述
    在这里插入图片描述

    创建虚拟图层并保存为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;
    
    • 1
    • 该语句可以通过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");
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 成员函数void setQuery( const QString &query )用于设置查询语句
        //查询语句
        def.setQuery("SELECT * FROM jilin_dist left outer join prec on jilin_dist.NAME = prec.city;");
    
    • 1
    • 2
    • 新建矢量图层QgsVectorLayer,数据源provider传入virtual,代码如下
    const QgsVectorLayer::LayerOptions options { QgsProject::instance()->transformContext() };
    QgsVectorLayer *vl = new QgsVectorLayer( def.toString(), QStringLiteral( "test" ), QStringLiteral( "virtual" ), options );
    
    • 1
    • 2
    • QgsVectorFileWriter用于将图层保存至文件,详情见文档
    • 其成员函数writeAsVectorFormatV3用于保存,虚拟图层保存至文件的代码如下
            QgsVectorFileWriter::SaveVectorOptions opt;
            QgsVectorFileWriter::writeAsVectorFormatV3(vl,"maps/virtuallayer/myvurtual.shp",QgsProject::instance()->transformContext(),opt);
    
    • 1
    • 2

    在这里插入图片描述
    在这里插入图片描述

    • 保存的图层文件如下
      在这里插入图片描述

    总结

    • 分别演示了:
      • QGis软件矢量图层数据的查询、选择和保存
      • 二次开发c++ api的图层数据的查询、选择和保存
  • 相关阅读:
    C#界面里Form.HelpButton 属性的使用
    C++入门知识
    使用git 命令pull代码,冲突后解决以及重新提交代码
    浏览器是如何对页面进行渲染的呢?
    HTML+CSS详细知识点复习(上)
    HTML的表单标签和无语义标签的讲解
    【第43篇】CLIP:从自然语言监督中学习可迁移的视觉模型
    Solidity - 安全 - 重入攻击(Reentrancy)
    win7常见问题
    .Net/C#分库分表高性能O(1)瀑布流分页
  • 原文地址:https://blog.csdn.net/richie12/article/details/133984015