楼主: Amy9999
66 0

[作业] 12.2 调用QGIS Native C++空间分析算法 [推广有奖]

  • 0关注
  • 0粉丝

等待验证会员

小学生

14%

还不是VIP/贵宾

-

威望
0
论坛币
0 个
通用积分
0
学术水平
0 点
热心指数
0 点
信用等级
0 点
经验
40 点
帖子
3
精华
0
在线时间
0 小时
注册时间
2018-9-10
最后登录
2018-9-10

楼主
Amy9999 发表于 2025-12-2 17:33:45 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币

前言

QGis平台集成了多种类型的算法,主要包括基于原生C++开发的QGIS算法、使用Python编写的QGIS脚本算法,以及第三方提供的GDAL相关工具。本文重点介绍如何调用QGIS原生C++实现的算法模块。

所有示例代码均来源于开源项目 qgis_cpp_api_apps,仅供学习与参考。

常用算法应用示例

本文选取三个典型算法进行说明:在多边形内生成随机点(Random points in polygons)、裁剪(Clip)以及缓冲区分析(Buffer),以展示QGIS中核心算法的实际调用方式。

随机点生成:Random Points in Polygons

该功能常用于地理空间数据的采样设计、监督分类中的训练样本选取,以及精度评估过程中的验证点布设。例如,在采用最小距离法或最大似然法对区域土地利用类型进行分类时,通常需要先获取具有代表性的训练样本,这些样本可通过随机点方式生成。同样地,在进行模型验证和混淆矩阵构建时,也需要大量独立验证点,其位置亦可借助此类方法自动产生。

以文件 jilin_dist.shp 为例,首先加载该矢量图层。

随后进入“工具箱” → “矢量创建(Vector creation)” → 选择“Random points in polygons”工具。

设置参数如下:指定生成点的数量为10个。

执行后生成结果如下图所示:

代码实现机制解析

所有QGIS处理算法均继承自一个统一的基类:

QgsProcessingAlgorithm

该基类定义了算法的基本结构与行为规范,详细信息可查阅官方文档。其类关系图如下:

其中关键成员函数如下:

QgsProcessingAlgorithm *create( const QVariantMap &configuration = QVariantMap() )

该函数负责实例化具体的算法对象。

算法的集中管理由以下类完成:

QgsProcessingRegistry

此管理器负责注册、查找和创建各类算法,具体说明见相关文档。

在使用任何算法前,必须完成初始化操作,初始化代码如下:

QgsApplication::processingRegistry()->addProvider( new QgsNativeAlgorithms( QgsApplication::processingRegistry() ) );

通过以下类的方法可以创建指定ID的算法实例:

QgsProcessingRegistry

其内部函数

QgsProcessingAlgorithm *createAlgorithmById( const QString &id, const QVariantMap &configuration = QVariantMap() )

会调用对应算法类的create方法来完成实例化。

针对“在多边形内生成随机点”的功能,其实现类为:

QgsRandomPointsInPolygonsAlgorithm

该类的关键成员函数之一是:

name()

用于返回算法的名称,该名称将在createAlgorithmById中被用来定位并创建实例。

示例代码如下:

QString QgsRandomPointsInPolygonsAlgorithm::name() const
{
    return QStringLiteral( "randompointsinpolygons" );
}

需要注意的是,算法的完整ID由前缀字符串与类名组合而成:

native:

例如:

const QString id = "native:randompointsinpolygons";

创建算法实例的标准代码格式如下:

QgsProcessingAlgorithm *algorithm = QgsApplication::processingRegistry()->createAlgorithmById(id, conf);
createAlgorithmById

其中第二个参数 conf 是配置项,类型为键值对字典:

QVariantMap

该字典的构造逻辑可在各算法类的初始化函数中找到依据,如:

initAlgorithm

具体代码如下:

void QgsRandomPointsInPolygonsAlgorithm::initAlgorithm( const QVariantMap & )
{
  addParameter( new QgsProcessingParameterFeatureSource( INPUT, QObject::tr( "Input polygon layer" ), QList< int >() << QgsProcessing::TypeVectorPolygon ) );
  std::unique_ptr< QgsProcessingParameterNumber > numberPointsParam = std::make_unique< QgsProcessingParameterNumber >( POINTS_NUMBER, QObject::tr( "Number of points for each feature" ), QgsProcessingParameterNumber::Integer, 1, false, 1 );
  numberPointsParam->setIsDynamic( true );
  numberPointsParam->setDynamicPropertyDefinition( QgsPropertyDefinition( POINTS_NUMBER, QObject::tr( "Number of points for each feature" ), QgsPropertyDefinition::IntegerPositive ) );
  numberPointsParam->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
  addParameter( numberPointsParam.release() );

  std::unique_ptr< QgsProcessingParameterDistance > minDistParam = std::make_unique< QgsProcessingParameterDistance >( MIN_DISTANCE, QObject::tr( "Minimum distance between points" ), 0, INPUT, true, 0 );
  minDistParam->setIsDynamic( true );
  minDistParam->setDynamicPropertyDefinition( QgsPropertyDefinition( MIN_DISTANCE, QObject::tr( "Minimum distance between points" ), QgsPropertyDefinition::DoublePositive ) );
  minDistParam->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
  addParameter( minDistParam.release() );

  std::unique_ptr< QgsProcessingParameterDistance > minDistGlobalParam = std::make_unique< QgsProcessingParameterDistance >( MIN_DISTANCE_GLOBAL, QObject::tr( "Global minimum distance between points" ), 0, INPUT, true, 0 );
  minDistGlobalParam->setFlags( minDistGlobalParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
  addParameter( minDistGlobalParam.release() );

  std::unique_ptr< QgsProcessingParameterNumber > maxAttemptsParam = std::make_unique< QgsProcessingParameterNumber >( MAX_TRIES_PER_POINT, QObject::tr( "Maximum number of search attempts (for Min. dist. > 0)" ), QgsProcessingParameterNumber::Integer, 10, true, 1 );
  maxAttemptsParam->setFlags( maxAttemptsParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
  maxAttemptsParam->setIsDynamic( true );
  maxAttemptsParam->setDynamicPropertyDefinition( QgsPropertyDefinition( MAX_TRIES_PER_POINT, QObject::tr( "Maximum number of attempts per point (for Min. dist. > 0)" ), QgsPropertyDefinition::IntegerPositiveGreaterZero ) );
  maxAttemptsParam->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
  addParameter( maxAttemptsParam.release() );

  std::unique_ptr< QgsProcessingParameterNumber > randomSeedParam = std::make_unique< QgsProcessingParameterNumber >( SEED, QObject::tr( "Random seed" ), QgsProcessingParameterNumber::Integer, QVariant(), true, 1 );
  randomSeedParam->setFlags( randomSeedParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
  addParameter( randomSeedParam.release() );

  std::unique_ptr< QgsProcessingParameterBoolean > includePolygonAttrParam = std::make_unique< QgsProcessingParameterBoolean >( INCLUDE_POLYGON_ATTRIBUTES, QObject::tr( "Include polygon attributes" ), true );
  includePolygonAttrParam->setFlags( includePolygonAttrParam->flags() | QgsProcessingParameterDefinition::FlagAdvanced );
  addParameter( includePolygonAttrParam.release() );

  addParameter( new
                QgsProcessingParameterFeatureSink( OUTPUT, QObject::tr( "Random points in polygons" ), QgsProcessing::TypeVectorPoint ) );

  addOutput( new QgsProcessingOutputNumber( OUTPUT_POINTS, QObject::tr( "Total number of points generated" ) ) );
  addOutput( new QgsProcessingOutputNumber( POINTS_MISSED, QObject::tr( "Number of missed points" ) ) );
  addOutput( new QgsProcessingOutputNumber( POLYGONS_WITH_MISSED_POINTS, QObject::tr( "Number of polygons with missed points" ) ) );
  addOutput( new QgsProcessingOutputNumber( FEATURES_WITH_EMPTY_OR_NO_GEOMETRY, QObject::tr( "Number of features with empty or no geometry" ) ) );
}

算法对象创建完成后,需执行运行流程才能获得输出结果。运行支持两种模式:主线程运行与后台线程运行。若算法耗时较长,推荐使用后台运行方式,以免造成界面无响应。

完整的测试调用代码如下:

void MainWindow::processingRandomPointsSlot()
{
    QgsVectorLayer* layer = addTestShape(QStringLiteral("maps/processing/jilin_dist.shp"));
    const QString id = "native:randompointsinpolygons";
    QVariantMap conf;
    conf.insert(QStringLiteral("INPUT"), layer->id()); // 支持图层ID或物理路径
    conf.insert(QStringLiteral("POINTS_NUMBER"), "10");
    QgsProcessingOutputLayerDefinition value("TEMPORARY_OUTPUT");
    conf.insert(QStringLiteral("OUTPUT"), value);

    QgsProcessingAlgorithm *algorithm = QgsApplication::processingRegistry()->createAlgorithmById(id, conf);
    QgsProcessingContext *context = new QgsProcessingContext;
    context->setProject(QgsProject::instance());
    QgsProcessingFeedback *feedback = new QgsProcessingFeedback(false);

#if 0
    // 此处采用主线程运行方式
    algorithm->prepare(conf, *context, feedback);
#endif
}
void MainWindow::processingClipSlot()
{
    QgsVectorLayer* layer = addTestShape(QStringLiteral("maps/processing/dongbei_roads.shp"));
    const QString id = "native:clip";
    QVariantMap conf;

    // 使用图层ID作为输入,而非直接路径
    conf.insert(QStringLiteral("INPUT"), layer->id());
    conf.insert(QStringLiteral("OVERLAY"), "maps/processing/jilin_dist.shp");

    QgsProcessingOutputLayerDefinition value("TEMPORARY_OUTPUT");
    conf.insert(QStringLiteral("OUTPUT"), value);

    auto algorithm = QgsApplication::processingRegistry()->createAlgorithmById(id, conf);
    QgsProcessingContext *context = new QgsProcessingContext;
    context->setProject(QgsProject::instance());

    QgsProcessingFeedback *feedback = new QgsProcessingFeedback(false);

#if 0
    // 主线程中执行算法
    algorithm->prepare(conf, *context, feedback);
    QVariantMap runResults = algorithm->run(conf, *context, feedback);
    QgsMapLayer *tempLayer = context->getMapLayer(runResults["OUTPUT"].toString());
    if(layer)
    {
        QgsProject::instance()->addMapLayer(tempLayer);
    }
#else
    // 在独立线程中运行处理任务
    mContext = context;
    QgsProcessingAlgRunnerTask *algTask = new QgsProcessingAlgRunnerTask(algorithm, conf, *mContext, feedback);
    connect(algTask, &QgsProcessingAlgRunnerTask::executed, this, &MainWindow::algExecuted);
    QgsApplication::taskManager()->addTask(algTask);
#endif
}
const QString id = "native:clip";

按参考面要素裁剪矢量数据说明

“按参考面要素裁剪”是一种基于矢量叠加分析的空间操作方法,其核心是利用一个面状参考图层对目标图层进行几何裁剪,保留目标图层中位于参考面范围内的部分。该功能在区域范围提取、局部数据生成等场景中具有广泛应用。

本示例以吉林省地级行政区划(jilin_dist.shp)作为裁剪范围,对东北地区公路网(dongbei_roads.shp)进行裁剪,最终生成仅包含吉林境内公路的矢量网络数据。原始地图数据来源于《QGIS软件及其应用教程》配套资源。

操作步骤

  1. 加载数据:首先将“jilin_dist.shp”与“dongbei_roads.shp”两个图层导入QGIS项目中。
  2. 打开处理工具箱:在“Processing Toolbox”面板中,定位至“Vector overlay”工具集,双击选择“Clip”工具,系统将弹出配置对话框。
  1. 设置参数:
    • Input layer:选择待裁剪的目标图层“dongbei_roads”;
    • Overlay layer:选择作为裁剪边界的参考面图层“jilin_dist”;
    • Clipped:指定输出文件的保存路径或使用临时图层;
  2. 执行操作:点击“Run”按钮启动裁剪流程,完成后结果图层将自动加载至地图视图。

效果展示

裁剪完成后,原覆盖整个东北地区的公路网络被限制在吉林省行政边界内,形成精确的区域交通数据子集。此过程有效实现了空间数据的范围过滤与局部提取。

代码实现逻辑说明

上述C++代码实现了与图形界面相同的功能。其处理流程与“随机生成点”类似,均基于QGIS的Processing框架进行封装调用。关键在于指定正确的算法ID(本例为"native:clip"),并正确配置输入输出参数。当采用多线程模式时,通过QgsProcessingAlgRunnerTask将任务提交至任务管理器异步执行,避免阻塞主界面。

在QGis的二次开发过程中,调用QGIS(native c++)算法是一个关键环节。通过使用相关接口和任务管理机制,可以实现对原生算法的高效执行。

具体实现方式如下:当处于线程环境中时,首先将上下文信息赋值给成员变量 mContext,以便后续操作中使用。接着创建一个 QgsProcessingAlgRunnerTask 实例,传入目标算法、配置参数、上下文对象以及反馈对象。该任务对象用于异步运行指定的处理算法。

为确保任务执行完成后能及时响应结果,需将任务的 executed 信号与主窗口中的槽函数 algExecuted 进行连接。最后,通过 QgsApplication::taskManager() 获取任务管理器,并将新创建的任务添加进去,由系统负责调度执行。

上述方法实现了在不阻塞主线程的前提下运行复杂的地理处理算法,提升了应用的响应性和稳定性。

总结

本文详细阐述了如何在QGis平台进行二次开发时,调用其内置的 native C++ 算法模块。通过合理利用任务机制与信号槽体系,能够安全、高效地完成算法调用与结果处理,为构建功能丰富的插件或独立应用提供了技术支持。

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:native 空间分析 GIS ATI Application

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
jg-xs1
拉您进交流群
GMT+8, 2025-12-5 17:01