Merge pull request #60945 from alexbruy/processing-export-geometry-info-cpp

port Add geometry attributes algorithm to C++
This commit is contained in:
Alexander Bruy 2025-04-14 20:04:33 +01:00 committed by GitHub
commit b5019cbfb0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 362 additions and 279 deletions

View File

@ -57,11 +57,6 @@ qgis:executesql: >
The result of the query will be added as a new layer.
qgis:exportaddgeometrycolumns: >
This algorithm computes geometric properties of the features in a vector layer. It generates a new vector layer with the same content as the input one, but with additional attributes in its attributes table, containing geometric measurements.
Depending on the geometry type of the vector layer, the attributes added to the table will be different.
qgis:findprojection: >
This algorithm allows creation of a shortlist of possible candidate coordinate reference systems for a layer with an unknown projection.

View File

@ -1,266 +0,0 @@
"""
***************************************************************************
ExportGeometryInfo.py
---------------------
Date : August 2012
Copyright : (C) 2012 by Victor Olaya
Email : volayaf at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
__author__ = "Victor Olaya"
__date__ = "August 2012"
__copyright__ = "(C) 2012, Victor Olaya"
import os
import math
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtCore import QMetaType
from qgis.core import (
NULL,
Qgis,
QgsApplication,
QgsCoordinateTransform,
QgsField,
QgsFields,
QgsWkbTypes,
QgsPointXY,
QgsFeatureSink,
QgsDistanceArea,
QgsProcessingUtils,
QgsProcessingException,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterEnum,
QgsProcessingParameterFeatureSink,
QgsUnitTypes,
)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
class ExportGeometryInfo(QgisAlgorithm):
INPUT = "INPUT"
METHOD = "CALC_METHOD"
OUTPUT = "OUTPUT"
def icon(self):
return QgsApplication.getThemeIcon(
"/algorithms/mAlgorithmAddGeometryAttributes.svg"
)
def svgIconPath(self):
return QgsApplication.iconPath(
"/algorithms/mAlgorithmAddGeometryAttributes.svg"
)
def tags(self):
return self.tr(
"export,add,information,measurements,areas,lengths,perimeters,latitudes,longitudes,x,y,z,extract,points,lines,polygons,sinuosity,fields"
).split(",")
def group(self):
return self.tr("Vector geometry")
def groupId(self):
return "vectorgeometry"
def __init__(self):
super().__init__()
self.export_z = False
self.export_m = False
self.distance_area = None
self.distance_conversion_factor = 1
self.area_conversion_factor = 1
self.calc_methods = [
self.tr("Layer CRS"),
self.tr("Project CRS"),
self.tr("Ellipsoidal"),
]
def initAlgorithm(self, config=None):
self.addParameter(
QgsProcessingParameterFeatureSource(self.INPUT, self.tr("Input layer"))
)
self.addParameter(
QgsProcessingParameterEnum(
self.METHOD,
self.tr("Calculate using"),
options=self.calc_methods,
defaultValue=0,
)
)
self.addParameter(
QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr("Added geom info"))
)
def name(self):
return "exportaddgeometrycolumns"
def displayName(self):
return self.tr("Add geometry attributes")
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
raise QgsProcessingException(
self.invalidSourceError(parameters, self.INPUT)
)
method = self.parameterAsEnum(parameters, self.METHOD, context)
wkb_type = source.wkbType()
fields = source.fields()
new_fields = QgsFields()
if (
QgsWkbTypes.geometryType(wkb_type)
== QgsWkbTypes.GeometryType.PolygonGeometry
):
new_fields.append(QgsField("area", QMetaType.Type.Double))
new_fields.append(QgsField("perimeter", QMetaType.Type.Double))
elif (
QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.GeometryType.LineGeometry
):
new_fields.append(QgsField("length", QMetaType.Type.Double))
if not QgsWkbTypes.isMultiType(source.wkbType()):
new_fields.append(QgsField("straightdis", QMetaType.Type.Double))
new_fields.append(QgsField("sinuosity", QMetaType.Type.Double))
else:
if QgsWkbTypes.isMultiType(source.wkbType()):
new_fields.append(QgsField("numparts", QMetaType.Type.Int))
else:
new_fields.append(QgsField("xcoord", QMetaType.Type.Double))
new_fields.append(QgsField("ycoord", QMetaType.Type.Double))
if QgsWkbTypes.hasZ(source.wkbType()):
self.export_z = True
new_fields.append(QgsField("zcoord", QMetaType.Type.Double))
if QgsWkbTypes.hasM(source.wkbType()):
self.export_m = True
new_fields.append(QgsField("mvalue", QMetaType.Type.Double))
fields = QgsProcessingUtils.combineFields(fields, new_fields)
(sink, dest_id) = self.parameterAsSink(
parameters, self.OUTPUT, context, fields, wkb_type, source.sourceCrs()
)
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
coordTransform = None
# Calculate with:
# 0 - layer CRS
# 1 - project CRS
# 2 - ellipsoidal
self.distance_area = QgsDistanceArea()
if method == 2:
self.distance_area.setSourceCrs(
source.sourceCrs(), context.transformContext()
)
self.distance_area.setEllipsoid(context.ellipsoid())
self.distance_conversion_factor = QgsUnitTypes.fromUnitToUnitFactor(
self.distance_area.lengthUnits(), context.distanceUnit()
)
self.area_conversion_factor = QgsUnitTypes.fromUnitToUnitFactor(
self.distance_area.areaUnits(), context.areaUnit()
)
elif method == 1:
if not context.project():
raise QgsProcessingException(
self.tr("No project is available in this context")
)
coordTransform = QgsCoordinateTransform(
source.sourceCrs(), context.project().crs(), context.project()
)
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, f in enumerate(features):
if feedback.isCanceled():
break
outFeat = f
attrs = f.attributes()
inGeom = f.geometry()
if inGeom:
if coordTransform is not None:
inGeom.transform(coordTransform)
if inGeom.type() == QgsWkbTypes.GeometryType.PointGeometry:
attrs.extend(self.point_attributes(inGeom))
elif inGeom.type() == QgsWkbTypes.GeometryType.PolygonGeometry:
attrs.extend(self.polygon_attributes(inGeom))
else:
attrs.extend(self.line_attributes(inGeom))
# ensure consistent count of attributes - otherwise null
# geometry features will have incorrect attribute length
# and provider may reject them
if len(attrs) < len(fields):
attrs += [NULL] * (len(fields) - len(attrs))
outFeat.setAttributes(attrs)
sink.addFeature(outFeat, QgsFeatureSink.Flag.FastInsert)
feedback.setProgress(int(current * total))
sink.finalize()
return {self.OUTPUT: dest_id}
def point_attributes(self, geometry):
attrs = []
if not geometry.isMultipart():
pt = geometry.constGet()
attrs.append(pt.x())
attrs.append(pt.y())
# add point z/m
if self.export_z:
attrs.append(pt.z())
if self.export_m:
attrs.append(pt.m())
else:
attrs = [geometry.constGet().numGeometries()]
return attrs
def line_attributes(self, geometry):
if geometry.isMultipart():
return [self.distance_area.measureLength(geometry)]
else:
curve = geometry.constGet()
p1 = curve.startPoint()
p2 = curve.endPoint()
straight_distance = (
self.distance_conversion_factor
* self.distance_area.measureLine(QgsPointXY(p1), QgsPointXY(p2))
)
sinuosity = curve.sinuosity()
if math.isnan(sinuosity):
sinuosity = NULL
return [
self.distance_conversion_factor
* self.distance_area.measureLength(geometry),
straight_distance,
sinuosity,
]
def polygon_attributes(self, geometry):
area = self.area_conversion_factor * self.distance_area.measureArea(geometry)
perimeter = (
self.distance_conversion_factor
* self.distance_area.measurePerimeter(geometry)
)
return [area, perimeter]

View File

@ -31,7 +31,6 @@ from .CheckValidity import CheckValidity
from .Climb import Climb
from .EliminateSelection import EliminateSelection
from .ExecuteSQL import ExecuteSQL
from .ExportGeometryInfo import ExportGeometryInfo
from .FieldPyculator import FieldsPyculator
from .FindProjection import FindProjection
from .GeometryConvert import GeometryConvert
@ -95,7 +94,6 @@ class QgisAlgorithmProvider(QgsProcessingProvider):
Climb(),
EliminateSelection(),
ExecuteSQL(),
ExportGeometryInfo(),
FieldsPyculator(),
FindProjection(),
GeometryConvert(),

View File

@ -100,7 +100,7 @@ def initMenusAndToolbars():
defaultMenuEntries.update(
{
"qgis:checkvalidity": geometryToolsMenu,
"qgis:exportaddgeometrycolumns": geometryToolsMenu,
"native:exportaddgeometrycolumns": geometryToolsMenu,
"native:centroids": geometryToolsMenu,
"native:delaunaytriangulation": geometryToolsMenu,
"native:voronoipolygons": geometryToolsMenu,

View File

@ -2242,7 +2242,7 @@ tests:
name: expected/smoothed_lines_max_angle.gml
type: vector
- algorithm: qgis:exportaddgeometrycolumns
- algorithm: native:exportaddgeometrycolumns
name: Add Geometry PointZ
params:
CALC_METHOD: '0'
@ -2254,7 +2254,7 @@ tests:
name: expected/add_geometry_pointz.gml
type: vector
- algorithm: qgis:exportaddgeometrycolumns
- algorithm: native:exportaddgeometrycolumns
name: Export line info
params:
CALC_METHOD: 0
@ -2266,7 +2266,7 @@ tests:
name: expected/export_line_info.gml
type: vector
- algorithm: qgis:exportaddgeometrycolumns
- algorithm: native:exportaddgeometrycolumns
name: Export multiline info
params:
CALC_METHOD: 0
@ -2278,7 +2278,7 @@ tests:
name: expected/export_multiline_info.gml
type: vector
- algorithm: qgis:exportaddgeometrycolumns
- algorithm: native:exportaddgeometrycolumns
name: Export multipoint info (GEOS < 3.9)
condition:
geos:
@ -2293,7 +2293,7 @@ tests:
name: expected/add_geometry_info_multipoint.gml
type: vector
- algorithm: qgis:exportaddgeometrycolumns
- algorithm: native:exportaddgeometrycolumns
name: Export multipoint info (GEOS >= 3.9)
condition:
geos:

View File

@ -100,6 +100,7 @@ set(QGIS_ANALYSIS_SRCS
processing/qgsalgorithmexecutespatialitequeryregistered.cpp
processing/qgsalgorithmexplode.cpp
processing/qgsalgorithmexplodehstore.cpp
processing/qgsalgorithmexportgeometryattributes.cpp
processing/qgsalgorithmexportlayersinformation.cpp
processing/qgsalgorithmexportmesh.cpp
processing/qgsalgorithmexporttopostgresql.cpp

View File

@ -0,0 +1,288 @@
/***************************************************************************
qgsalgorithmexportgeometryattributes.cpp
---------------------
begin : February 2025
copyright : (C) 2025 by Alexander Bruy
email : alexander dot bruy at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsalgorithmexportgeometryattributes.h"
#include "qgsunittypes.h"
#include "qgsgeometrycollection.h"
#include "qgscurve.h"
///@cond PRIVATE
QString QgsExportGeometryAttributesAlgorithm::name() const
{
return QStringLiteral( "exportaddgeometrycolumns" );
}
QString QgsExportGeometryAttributesAlgorithm::displayName() const
{
return QObject::tr( "Add geometry attributes" );
}
QStringList QgsExportGeometryAttributesAlgorithm::tags() const
{
return QObject::tr( "export,add,information,measurements,areas,lengths,perimeters,latitudes,longitudes,x,y,z,extract,points,lines,polygons,sinuosity,fields" ).split( ',' );
}
QString QgsExportGeometryAttributesAlgorithm::group() const
{
return QObject::tr( "Vector geometry" );
}
QString QgsExportGeometryAttributesAlgorithm::groupId() const
{
return QStringLiteral( "vectorgeometry" );
}
QString QgsExportGeometryAttributesAlgorithm::shortHelpString() const
{
return QObject::tr( "Computes geometric properties of the features in a vector layer. Algorithm generates a new "
"vector layer with the same content as the input one, but with additional attributes in its "
"attributes table, containing geometric measurements.\n\n"
"Depending on the geometry type of the vector layer, the attributes added to the table will "
"be different." );
}
QgsExportGeometryAttributesAlgorithm *QgsExportGeometryAttributesAlgorithm::createInstance() const
{
return new QgsExportGeometryAttributesAlgorithm();
}
void QgsExportGeometryAttributesAlgorithm::initAlgorithm( const QVariantMap & )
{
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ), QList<int>() << static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) ) );
const QStringList options = QStringList()
<< QObject::tr( "Cartesian Calculations in Layer's CRS" )
<< QObject::tr( "Cartesian Calculations in Project's CRS" )
<< QObject::tr( "Ellipsoidal Calculations" );
addParameter( new QgsProcessingParameterEnum( QStringLiteral( "METHOD" ), QObject::tr( "Calculate using" ), options, false, 0 ) );
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Added geometry info" ) ) );
}
bool QgsExportGeometryAttributesAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
{
Q_UNUSED( parameters );
mProjectCrs = context.project()->crs();
return true;
}
QVariantMap QgsExportGeometryAttributesAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
std::unique_ptr<QgsProcessingFeatureSource> source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !source )
throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
const int method = parameterAsEnum( parameters, QStringLiteral( "METHOD" ), context );
const Qgis::WkbType wkbType = source->wkbType();
QgsFields fields = source->fields();
QgsFields newFields;
bool exportZ = false;
bool exportM = false;
if ( QgsWkbTypes::geometryType( wkbType ) == Qgis::GeometryType::Polygon )
{
newFields.append( QgsField( QStringLiteral( "area" ), QMetaType::Type::Double ) );
newFields.append( QgsField( QStringLiteral( "perimeter" ), QMetaType::Type::Double ) );
}
else if ( QgsWkbTypes::geometryType( wkbType ) == Qgis::GeometryType::Line )
{
newFields.append( QgsField( QStringLiteral( "length" ), QMetaType::Type::Double ) );
if ( !QgsWkbTypes::isMultiType( wkbType ) )
{
newFields.append( QgsField( QStringLiteral( "straightdis" ), QMetaType::Type::Double ) );
newFields.append( QgsField( QStringLiteral( "sinuosity" ), QMetaType::Type::Double ) );
}
}
else
{
if ( QgsWkbTypes::isMultiType( wkbType ) )
{
newFields.append( QgsField( QStringLiteral( "numparts" ), QMetaType::Type::Int ) );
}
else
{
newFields.append( QgsField( QStringLiteral( "xcoord" ), QMetaType::Type::Double ) );
newFields.append( QgsField( QStringLiteral( "ycoord" ), QMetaType::Type::Double ) );
if ( QgsWkbTypes::hasZ( wkbType ) )
{
newFields.append( QgsField( QStringLiteral( "zcoord" ), QMetaType::Type::Double ) );
exportZ = true;
}
if ( QgsWkbTypes::hasM( wkbType ) )
{
newFields.append( QgsField( QStringLiteral( "mvalue" ), QMetaType::Type::Double ) );
exportM = true;
}
}
}
fields = QgsProcessingUtils::combineFields( fields, newFields );
QString dest;
std::unique_ptr<QgsFeatureSink> sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, wkbType, source->sourceCrs() ) );
if ( !sink )
{
throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
}
QgsCoordinateTransform transform;
mDa = QgsDistanceArea();
if ( method == 2 )
{
mDa.setSourceCrs( source->sourceCrs(), context.transformContext() );
mDa.setEllipsoid( context.ellipsoid() );
mDistanceConversionFactor = QgsUnitTypes::fromUnitToUnitFactor( mDa.lengthUnits(), context.distanceUnit() );
mAreaConversionFactor = QgsUnitTypes::fromUnitToUnitFactor( mDa.areaUnits(), context.areaUnit() );
}
else if ( method == 1 )
{
if ( !context.project() )
{
throw QgsProcessingException( QObject::tr( "No project is available in this context" ) );
}
transform = QgsCoordinateTransform( source->sourceCrs(), mProjectCrs, context.transformContext() );
}
QgsFeatureIterator it = source->getFeatures();
const double step = source->featureCount() > 0 ? 100.0 / source->featureCount() : 0;
long i = 0;
QgsFeature f;
while ( it.nextFeature( f ) )
{
if ( feedback->isCanceled() )
{
break;
}
QgsFeature outputFeature( f );
QgsAttributes attrs = f.attributes();
QgsGeometry geom = f.geometry();
if ( !geom.isNull() )
{
if ( transform.isValid() )
{
try
{
geom.transform( transform );
}
catch ( QgsCsException &e )
{
throw QgsProcessingException( QObject::tr( "Could not transform feature to project's CRS: %1" ).arg( e.what() ) );
}
}
if ( geom.type() == Qgis::GeometryType::Point )
{
attrs << pointAttributes( geom, exportZ, exportM );
}
else if ( geom.type() == Qgis::GeometryType::Polygon )
{
attrs << polygonAttributes( geom );
}
else
{
attrs << lineAttributes( geom );
}
}
// ensure consistent count of attributes - otherwise null geometry features will have incorrect attribute
// length and provider may reject them
while ( attrs.size() < fields.size() )
{
attrs.append( QVariant() );
}
outputFeature.setAttributes( attrs );
if ( !sink->addFeature( outputFeature, QgsFeatureSink::FastInsert ) )
{
throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
}
i++;
feedback->setProgress( i * step );
}
sink->finalize();
QVariantMap results;
results.insert( QStringLiteral( "OUTPUT" ), dest );
return results;
}
QgsAttributes QgsExportGeometryAttributesAlgorithm::pointAttributes( const QgsGeometry &geom, const bool exportZ, const bool exportM )
{
QgsAttributes attrs;
if ( !geom.isMultipart() )
{
auto point = qgsgeometry_cast<const QgsPoint *>( geom.constGet() );
attrs.append( point->x() );
attrs.append( point->y() );
// add point Z/M
if ( exportZ )
{
attrs.append( point->z() );
}
if ( exportM )
{
attrs.append( point->m() );
}
}
else
{
attrs.append( qgsgeometry_cast<const QgsGeometryCollection *>( geom.constGet() )->numGeometries() );
}
return attrs;
}
QgsAttributes QgsExportGeometryAttributesAlgorithm::lineAttributes( const QgsGeometry &geom )
{
QgsAttributes attrs;
if ( geom.isMultipart() )
{
attrs.append( mDistanceConversionFactor * mDa.measureLength( geom ) );
}
else
{
auto curve = qgsgeometry_cast<const QgsCurve *>( geom.constGet() );
const QgsPoint p1 = curve->startPoint();
const QgsPoint p2 = curve->endPoint();
const double straightDistance = mDistanceConversionFactor * mDa.measureLine( QgsPointXY( p1 ), QgsPointXY( p2 ) );
const double sinuosity = curve->sinuosity();
attrs.append( mDistanceConversionFactor * mDa.measureLength( geom ) );
attrs.append( straightDistance );
attrs.append( std::isnan( sinuosity ) ? QVariant() : sinuosity );
}
return attrs;
}
QgsAttributes QgsExportGeometryAttributesAlgorithm::polygonAttributes( const QgsGeometry &geom )
{
const double area = mAreaConversionFactor * mDa.measureArea( geom );
const double perimeter = mDistanceConversionFactor * mDa.measurePerimeter( geom );
return QgsAttributes() << area << perimeter;
}
///@endcond

View File

@ -0,0 +1,65 @@
/***************************************************************************
qgsalgorithmexportgeometryattributes.h
---------------------
begin : February 2025
copyright : (C) 2025 by Alexander Bruy
email : alexander dot bruy at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSALGORITHMEXPORTGEOMETRYATTRIBUTES_H
#define QGSALGORITHMEXPORTGEOMETRYATTRIBUTES_H
#define SIP_NO_FILE
#include "qgis_sip.h"
#include "qgsprocessingalgorithm.h"
#include "qgsapplication.h"
///@cond PRIVATE
/**
* Native export geometry attributes algorithm.
*/
class QgsExportGeometryAttributesAlgorithm : public QgsProcessingAlgorithm
{
public:
QgsExportGeometryAttributesAlgorithm() = default;
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
QIcon icon() const override { return QgsApplication::getThemeIcon( QStringLiteral( "/algorithms/mAlgorithmAddGeometryAttributes.svg" ) ); }
QString svgIconPath() const override { return QgsApplication::iconPath( QStringLiteral( "/algorithms/mAlgorithmAddGeometryAttributes.svg" ) ); }
QString name() const override;
QString displayName() const override;
QStringList tags() const override;
QString group() const override;
QString groupId() const override;
QString shortHelpString() const override;
QgsExportGeometryAttributesAlgorithm *createInstance() const override SIP_FACTORY;
protected:
bool prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private:
QgsAttributes pointAttributes( const QgsGeometry &geom, const bool exportZ, const bool exportM );
QgsAttributes polygonAttributes( const QgsGeometry &geom );
QgsAttributes lineAttributes( const QgsGeometry &geom );
QgsDistanceArea mDa;
QgsCoordinateReferenceSystem mProjectCrs;
double mDistanceConversionFactor = 1;
double mAreaConversionFactor = 1;
};
///@endcond PRIVATE
#endif // QGSALGORITHMEXPORTGEOMETRYATTRIBUTES_H

View File

@ -83,6 +83,7 @@
#include "qgsalgorithmexporttospreadsheet.h"
#include "qgsalgorithmexplode.h"
#include "qgsalgorithmexplodehstore.h"
#include "qgsalgorithmexportgeometryattributes.h"
#include "qgsalgorithmexportlayersinformation.h"
#include "qgsalgorithmexporttopostgresql.h"
#include "qgsalgorithmextendlines.h"
@ -369,6 +370,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
addAlgorithm( new QgsExecuteSpatialiteQueryAlgorithm() );
addAlgorithm( new QgsExplodeAlgorithm() );
addAlgorithm( new QgsExplodeHstoreAlgorithm() );
addAlgorithm( new QgsExportGeometryAttributesAlgorithm() );
addAlgorithm( new QgsExportLayersInformationAlgorithm() );
addAlgorithm( new QgsExportLayerMetadataAlgorithm() );
addAlgorithm( new QgsExportMeshVerticesAlgorithm );