mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Merge pull request #4873 from nyalldawson/processing_feature_alg
Add QgsProcessingFeatureBasedAlgorithm subclass
This commit is contained in:
commit
857f8437d1
@ -30,6 +30,8 @@ class QgsProcessingAlgorithm
|
||||
%ConvertToSubClassCode
|
||||
if ( dynamic_cast< QgsProcessingModelAlgorithm * >( sipCpp ) != NULL )
|
||||
sipType = sipType_QgsProcessingModelAlgorithm;
|
||||
else if ( dynamic_cast< QgsProcessingFeatureBasedAlgorithm * >( sipCpp ) != NULL )
|
||||
sipType = sipType_QgsProcessingFeatureBasedAlgorithm;
|
||||
else
|
||||
sipType = sipType_QgsProcessingAlgorithm;
|
||||
%End
|
||||
@ -717,6 +719,136 @@ QFlags<QgsProcessingAlgorithm::Flag> operator|(QgsProcessingAlgorithm::Flag f1,
|
||||
|
||||
|
||||
|
||||
class QgsProcessingFeatureBasedAlgorithm : QgsProcessingAlgorithm
|
||||
{
|
||||
%Docstring
|
||||
An abstract QgsProcessingAlgorithm base class for processing algorithms which operate "feature-by-feature".
|
||||
|
||||
Feature based algorithms are algorithms which operate on individual features in isolation. These
|
||||
are algorithms where one feature is output for each input feature, and the output feature result
|
||||
for each input feature is not dependent on any other features present in the source.
|
||||
|
||||
For instance, algorithms like "centroids" and "buffers" are feature based algorithms since the centroid
|
||||
or buffer of a feature is calculated for each feature in isolation. An algorithm like "dissolve"
|
||||
is NOT suitable for a feature based algorithm as the dissolved output depends on multiple input features
|
||||
and these features cannot be processed in isolation.
|
||||
|
||||
Using QgsProcessingFeatureBasedAlgorithm as the base class for feature based algorithms allows
|
||||
shortcutting much of the common algorithm code for handling iterating over sources and pushing
|
||||
features to output sinks. It also allows the algorithm execution to be optimised in future
|
||||
(for instance allowing automatic multi-thread processing of the algorithm, or use of the
|
||||
algorithm in "chains", avoiding the need for temporary outputs in multi-step models).
|
||||
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsprocessingalgorithm.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
QgsProcessingFeatureBasedAlgorithm();
|
||||
%Docstring
|
||||
Constructor for QgsProcessingFeatureBasedAlgorithm.
|
||||
%End
|
||||
|
||||
protected:
|
||||
|
||||
virtual void initAlgorithm( const QVariantMap &configuration = QVariantMap() );
|
||||
|
||||
|
||||
virtual QString outputName() const = 0;
|
||||
%Docstring
|
||||
Returns the translated, user visible name for any layers created by this algorithm.
|
||||
This name will be used as the default name when loading the resultant layer into a
|
||||
QGIS project.
|
||||
:rtype: str
|
||||
%End
|
||||
|
||||
virtual QgsProcessing::LayerType outputLayerType() const;
|
||||
%Docstring
|
||||
Returns the layer type for layers generated by this algorithm, if
|
||||
this is possible to determine in advance.
|
||||
:rtype: QgsProcessing.LayerType
|
||||
%End
|
||||
|
||||
virtual QgsWkbTypes::Type outputWkbType( QgsWkbTypes::Type inputWkbType ) const;
|
||||
%Docstring
|
||||
Maps the input WKB geometry type (``inputWkbType``) to the corresponding
|
||||
output WKB type generated by the algorithm. The default behavior is that the algorithm maintains
|
||||
the same WKB type.
|
||||
This is called once by the base class when creating the output sink for the algorithm (i.e. it is
|
||||
not called once per feature processed).
|
||||
:rtype: QgsWkbTypes.Type
|
||||
%End
|
||||
|
||||
virtual QgsFields outputFields( const QgsFields &inputFields ) const;
|
||||
%Docstring
|
||||
Maps the input source fields (``inputFields``) to corresponding
|
||||
output fields generated by the algorithm. The default behavior is that the algorithm maintains
|
||||
the same fields as are input.
|
||||
Algorithms which add, remove or modify existing fields should override this method and
|
||||
implement logic here to indicate which fields are output by the algorithm.
|
||||
|
||||
This is called once by the base class when creating the output sink for the algorithm (i.e. it is
|
||||
not called once per feature processed).
|
||||
:rtype: QgsFields
|
||||
%End
|
||||
|
||||
virtual QgsCoordinateReferenceSystem outputCrs( const QgsCoordinateReferenceSystem &inputCrs ) const;
|
||||
%Docstring
|
||||
Maps the input source coordinate reference system (``inputCrs``) to a corresponding
|
||||
output CRS generated by the algorithm. The default behavior is that the algorithm maintains
|
||||
the same CRS as the input source.
|
||||
|
||||
This is called once by the base class when creating the output sink for the algorithm (i.e. it is
|
||||
not called once per feature processed).
|
||||
:rtype: QgsCoordinateReferenceSystem
|
||||
%End
|
||||
|
||||
virtual void initParameters( const QVariantMap &configuration = QVariantMap() );
|
||||
%Docstring
|
||||
Initializes any extra parameters added by the algorithm subclass. There is no need
|
||||
to declare the input source or output sink, as these are automatically created by
|
||||
QgsProcessingFeatureBasedAlgorithm.
|
||||
%End
|
||||
|
||||
QgsCoordinateReferenceSystem sourceCrs() const;
|
||||
%Docstring
|
||||
Returns the source's coordinate reference system. This will only return a valid CRS when
|
||||
called from a subclasses' processFeature() implementation.
|
||||
:rtype: QgsCoordinateReferenceSystem
|
||||
%End
|
||||
|
||||
virtual QgsFeature processFeature( const QgsFeature &feature, QgsProcessingFeedback *feedback ) = 0;
|
||||
%Docstring
|
||||
Processes an individual input ``feature`` from the source. Algorithms should implement their
|
||||
logic in this method for performing the algorithm's operation (e.g. replacing the feature's
|
||||
geometry with the centroid of the original feature geometry for a 'centroid' type
|
||||
algorithm).
|
||||
|
||||
Implementations should return the modified feature. Returning an invalid feature (e.g.
|
||||
a default constructed QgsFeature) will indicate that this feature should be 'skipped',
|
||||
and will not be added to the algorithm's output. Subclasses can use this approach to
|
||||
filter the incoming features as desired.
|
||||
|
||||
The provided ``feedback`` object can be used to push messages to the log and for giving feedback
|
||||
to users. Note that handling of progress reports and algorithm cancelation is handled by
|
||||
the base class and subclasses do not need to reimplement this logic.
|
||||
|
||||
Algorithms can throw a QgsProcessingException if a fatal error occurred which should
|
||||
prevent the algorithm execution from continuing. This can be annoying for users though as it
|
||||
can break valid model execution - so use with extreme caution, and consider using
|
||||
``feedback`` to instead report non-fatal processing failures for features instead.
|
||||
:rtype: QgsFeature
|
||||
%End
|
||||
|
||||
virtual QVariantMap processAlgorithm( const QVariantMap ¶meters,
|
||||
QgsProcessingContext &context, QgsProcessingFeedback *feedback );
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
|
@ -160,6 +160,9 @@ qgis:distancetonearesthub: >
|
||||
qgis:dropgeometries: >
|
||||
This algorithm removes any geometries from an input layer and returns a layer containing only the feature attributes.
|
||||
|
||||
qgis:dropmzvalues: >
|
||||
This algorithm can remove any measure (M) or Z values from input geometries.
|
||||
|
||||
qgis:eliminateselectedpolygons: >
|
||||
This algorithm combines selected polygons of the input layer with certain adjacent polygons by erasing their common boundary. The adjacent polygon can be either the one with the largest or smallest area or the one sharing the largest common boundary with the polygon to be eliminated. The selected features will always be eliminated whether the option "Use only selected features" is set or not.
|
||||
Eliminate is normally used to get rid of sliver polygons, i.e. tiny polygons that are a result of polygon intersection processes where boundaries of the inputs are similar but not identical.
|
||||
@ -503,6 +506,10 @@ qgis:selectbyexpression: >
|
||||
qgis:selectbylocation: >
|
||||
This algorithm creates a selection in a vector layer. The criteria for selecting features is based on the spatial relationship between each feature and the features in an additional layer.
|
||||
|
||||
qgis:setmvalue: >
|
||||
This algorithm sets the M value for geometries in a layer.
|
||||
|
||||
If M values already exist in the layer, they will be overwritten with the new value. If no M values exist, the geometry will be upgraded to include M values and the specified value used as the initial M value for all geometries.
|
||||
|
||||
qgis:setstyleforrasterlayer: >
|
||||
This algorithm sets the style of a raster layer. The style must be defined in a QML file.
|
||||
@ -510,6 +517,11 @@ qgis:setstyleforrasterlayer: >
|
||||
qgis:setstyleforvectorlayer: >
|
||||
This algorithm sets the style of a vector layer. The style must be defined in a QML file.
|
||||
|
||||
qgis:setzvalue: >
|
||||
This algorithm sets the Z value for geometries in a layer.
|
||||
|
||||
If Z values already exist in the layer, they will be overwritten with the new value. If no Z values exist, the geometry will be upgraded to include Z values and the specified value used as the initial Z value for all geometries.
|
||||
|
||||
qgis:simplifygeometries: >
|
||||
This algorithm simplifies the geometries in a line or polygon layer. It creates a new layer with the same features as the ones in the input layer, but with geometries containing a lower number of vertices.
|
||||
|
||||
|
@ -27,19 +27,14 @@ __revision__ = '$Format:%H$'
|
||||
|
||||
from qgis.PyQt.QtCore import QVariant
|
||||
from qgis.core import (QgsField,
|
||||
QgsFeatureSink,
|
||||
QgsProcessingParameterFeatureSource,
|
||||
QgsProcessingParameterString,
|
||||
QgsProcessingParameterNumber,
|
||||
QgsProcessingParameterEnum,
|
||||
QgsProcessingParameterFeatureSink)
|
||||
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
|
||||
QgsProcessingParameterEnum)
|
||||
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
|
||||
|
||||
|
||||
class AddTableField(QgisAlgorithm):
|
||||
class AddTableField(QgisFeatureBasedAlgorithm):
|
||||
|
||||
OUTPUT_LAYER = 'OUTPUT_LAYER'
|
||||
INPUT_LAYER = 'INPUT_LAYER'
|
||||
FIELD_NAME = 'FIELD_NAME'
|
||||
FIELD_TYPE = 'FIELD_TYPE'
|
||||
FIELD_LENGTH = 'FIELD_LENGTH'
|
||||
@ -55,10 +50,9 @@ class AddTableField(QgisAlgorithm):
|
||||
self.type_names = [self.tr('Integer'),
|
||||
self.tr('Float'),
|
||||
self.tr('String')]
|
||||
self.field = None
|
||||
|
||||
def initAlgorithm(self, config=None):
|
||||
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER,
|
||||
self.tr('Input layer')))
|
||||
def initParameters(self, config=None):
|
||||
self.addParameter(QgsProcessingParameterString(self.FIELD_NAME,
|
||||
self.tr('Field name')))
|
||||
self.addParameter(QgsProcessingParameterEnum(self.FIELD_TYPE,
|
||||
@ -68,7 +62,6 @@ class AddTableField(QgisAlgorithm):
|
||||
10, False, 1, 255))
|
||||
self.addParameter(QgsProcessingParameterNumber(self.FIELD_PRECISION,
|
||||
self.tr('Field precision'), QgsProcessingParameterNumber.Integer, 0, False, 0, 10))
|
||||
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, self.tr('Added')))
|
||||
|
||||
def name(self):
|
||||
return 'addfieldtoattributestable'
|
||||
@ -76,33 +69,25 @@ class AddTableField(QgisAlgorithm):
|
||||
def displayName(self):
|
||||
return self.tr('Add field to attributes table')
|
||||
|
||||
def processAlgorithm(self, parameters, context, feedback):
|
||||
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
|
||||
def outputName(self):
|
||||
return self.tr('Added')
|
||||
|
||||
fieldType = self.parameterAsEnum(parameters, self.FIELD_TYPE, context)
|
||||
fieldName = self.parameterAsString(parameters, self.FIELD_NAME, context)
|
||||
fieldLength = self.parameterAsInt(parameters, self.FIELD_LENGTH, context)
|
||||
fieldPrecision = self.parameterAsInt(parameters, self.FIELD_PRECISION, context)
|
||||
def prepareAlgorithm(self, parameters, context, feedback):
|
||||
field_type = self.parameterAsEnum(parameters, self.FIELD_TYPE, context)
|
||||
field_name = self.parameterAsString(parameters, self.FIELD_NAME, context)
|
||||
field_length = self.parameterAsInt(parameters, self.FIELD_LENGTH, context)
|
||||
field_precision = self.parameterAsInt(parameters, self.FIELD_PRECISION, context)
|
||||
|
||||
fields = source.fields()
|
||||
fields.append(QgsField(fieldName, self.TYPES[fieldType], '',
|
||||
fieldLength, fieldPrecision))
|
||||
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context,
|
||||
fields, source.wkbType(), source.sourceCrs())
|
||||
self.field = QgsField(field_name, self.TYPES[field_type], '',
|
||||
field_length, field_precision)
|
||||
return True
|
||||
|
||||
features = source.getFeatures()
|
||||
total = 100.0 / source.featureCount() if source.featureCount() else 0
|
||||
def outputFields(self, inputFields):
|
||||
inputFields.append(self.field)
|
||||
return inputFields
|
||||
|
||||
for current, input_feature in enumerate(features):
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
|
||||
output_feature = input_feature
|
||||
attributes = input_feature.attributes()
|
||||
attributes.append(None)
|
||||
output_feature.setAttributes(attributes)
|
||||
|
||||
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
|
||||
feedback.setProgress(int(current * total))
|
||||
|
||||
return {self.OUTPUT_LAYER: dest_id}
|
||||
def processFeature(self, feature, feedback):
|
||||
attributes = feature.attributes()
|
||||
attributes.append(None)
|
||||
feature.setAttributes(attributes)
|
||||
return feature
|
||||
|
@ -26,26 +26,15 @@ __copyright__ = '(C) 2012, Victor Olaya'
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
from qgis.PyQt.QtCore import QVariant
|
||||
from qgis.core import (QgsField,
|
||||
QgsFeatureSink,
|
||||
QgsProcessingParameterFeatureSource,
|
||||
QgsProcessingParameterFeatureSink)
|
||||
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
|
||||
from qgis.core import (QgsField)
|
||||
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
|
||||
|
||||
|
||||
class AutoincrementalField(QgisAlgorithm):
|
||||
|
||||
INPUT = 'INPUT'
|
||||
OUTPUT = 'OUTPUT'
|
||||
class AutoincrementalField(QgisFeatureBasedAlgorithm):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def initAlgorithm(self, config=None):
|
||||
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
|
||||
self.tr('Input layer')))
|
||||
|
||||
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Incremented')))
|
||||
self.current = 0
|
||||
|
||||
def group(self):
|
||||
return self.tr('Vector table tools')
|
||||
@ -56,26 +45,16 @@ class AutoincrementalField(QgisAlgorithm):
|
||||
def displayName(self):
|
||||
return self.tr('Add autoincremental field')
|
||||
|
||||
def processAlgorithm(self, parameters, context, feedback):
|
||||
source = self.parameterAsSource(parameters, self.INPUT, context)
|
||||
fields = source.fields()
|
||||
fields.append(QgsField('AUTO', QVariant.Int))
|
||||
def outputName(self):
|
||||
return self.tr('Incremented')
|
||||
|
||||
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
|
||||
fields, source.wkbType(), source.sourceCrs())
|
||||
def outputFields(self, inputFields):
|
||||
inputFields.append(QgsField('AUTO', QVariant.Int))
|
||||
return inputFields
|
||||
|
||||
features = source.getFeatures()
|
||||
total = 100.0 / source.featureCount() if source.featureCount() else 0
|
||||
for current, input_feature in enumerate(features):
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
|
||||
output_feature = input_feature
|
||||
attributes = input_feature.attributes()
|
||||
attributes.append(current)
|
||||
output_feature.setAttributes(attributes)
|
||||
|
||||
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
|
||||
feedback.setProgress(int(current * total))
|
||||
|
||||
return {self.OUTPUT: dest_id}
|
||||
def processFeature(self, feature, feedback):
|
||||
attributes = feature.attributes()
|
||||
attributes.append(self.current)
|
||||
self.current += 1
|
||||
feature.setAttributes(attributes)
|
||||
return feature
|
||||
|
@ -29,24 +29,17 @@ import os
|
||||
|
||||
from qgis.core import (QgsGeometry,
|
||||
QgsWkbTypes,
|
||||
QgsFeatureSink,
|
||||
QgsProcessing,
|
||||
QgsProcessingException,
|
||||
QgsProcessingParameterFeatureSource,
|
||||
QgsProcessingParameterFeatureSink)
|
||||
QgsProcessingException)
|
||||
|
||||
|
||||
from qgis.PyQt.QtGui import QIcon
|
||||
|
||||
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
|
||||
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
|
||||
|
||||
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
|
||||
|
||||
|
||||
class BoundingBox(QgisAlgorithm):
|
||||
|
||||
INPUT_LAYER = 'INPUT_LAYER'
|
||||
OUTPUT_LAYER = 'OUTPUT_LAYER'
|
||||
class BoundingBox(QgisFeatureBasedAlgorithm):
|
||||
|
||||
def icon(self):
|
||||
return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'matrix.png'))
|
||||
@ -57,39 +50,26 @@ class BoundingBox(QgisAlgorithm):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def initAlgorithm(self, config=None):
|
||||
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER, self.tr('Input layer')))
|
||||
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, self.tr('Bounds'), QgsProcessing.TypeVectorPolygon))
|
||||
|
||||
def name(self):
|
||||
return 'boundingboxes'
|
||||
|
||||
def displayName(self):
|
||||
return self.tr('Bounding boxes')
|
||||
|
||||
def processAlgorithm(self, parameters, context, feedback):
|
||||
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
|
||||
def outputName(self):
|
||||
return self.tr('Bounds')
|
||||
|
||||
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context,
|
||||
source.fields(), QgsWkbTypes.Polygon, source.sourceCrs())
|
||||
def outputWkbType(self, inputWkb):
|
||||
return QgsWkbTypes.Polygon
|
||||
|
||||
features = source.getFeatures()
|
||||
total = 100.0 / source.featureCount() if source.featureCount() else 0
|
||||
def processFeature(self, feature, feedback):
|
||||
input_geometry = feature.geometry()
|
||||
if input_geometry:
|
||||
output_geometry = QgsGeometry.fromRect(input_geometry.boundingBox())
|
||||
if not output_geometry:
|
||||
raise QgsProcessingException(
|
||||
self.tr('Error calculating bounding box'))
|
||||
|
||||
for current, input_feature in enumerate(features):
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
output_feature = input_feature
|
||||
input_geometry = input_feature.geometry()
|
||||
if input_geometry:
|
||||
output_geometry = QgsGeometry.fromRect(input_geometry.boundingBox())
|
||||
if not output_geometry:
|
||||
raise QgsProcessingException(
|
||||
self.tr('Error calculating bounding box'))
|
||||
feature.setGeometry(output_geometry)
|
||||
|
||||
output_feature.setGeometry(output_geometry)
|
||||
|
||||
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
|
||||
feedback.setProgress(int(current * total))
|
||||
|
||||
return {self.OUTPUT_LAYER: dest_id}
|
||||
return feature
|
||||
|
94
python/plugins/processing/algs/qgis/DropMZValues.py
Normal file
94
python/plugins/processing/algs/qgis/DropMZValues.py
Normal file
@ -0,0 +1,94 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
DropMZValues.py
|
||||
--------------
|
||||
Date : July 2017
|
||||
Copyright : (C) 2017 by Nyall Dawson
|
||||
Email : nyall dot dawson 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__ = 'Nyall Dawson'
|
||||
__date__ = 'July 2017'
|
||||
__copyright__ = '(C) 2017, Nyall Dawson'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive323
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
import os
|
||||
|
||||
from qgis.core import (QgsGeometry,
|
||||
QgsWkbTypes,
|
||||
QgsProcessingParameterBoolean)
|
||||
|
||||
|
||||
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
|
||||
|
||||
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
|
||||
|
||||
|
||||
class DropMZValues(QgisFeatureBasedAlgorithm):
|
||||
|
||||
DROP_M_VALUES = 'DROP_M_VALUES'
|
||||
DROP_Z_VALUES = 'DROP_Z_VALUES'
|
||||
|
||||
def group(self):
|
||||
return self.tr('Vector geometry tools')
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.drop_m = False
|
||||
self.drop_z = False
|
||||
|
||||
def name(self):
|
||||
return 'dropmzvalues'
|
||||
|
||||
def displayName(self):
|
||||
return self.tr('Drop M/Z Values')
|
||||
|
||||
def outputName(self):
|
||||
return self.tr('Z/M Dropped')
|
||||
|
||||
def tags(self):
|
||||
return self.tr('drop,set,convert,m,measure,z,25d,3d,values').split(',')
|
||||
|
||||
def initParameters(self, config=None):
|
||||
self.addParameter(QgsProcessingParameterBoolean(self.DROP_M_VALUES,
|
||||
self.tr('Drop M Values'), defaultValue=False))
|
||||
self.addParameter(QgsProcessingParameterBoolean(self.DROP_Z_VALUES,
|
||||
self.tr('Drop Z Values'), defaultValue=False))
|
||||
|
||||
def outputWkbType(self, inputWkb):
|
||||
wkb = inputWkb
|
||||
if self.drop_m:
|
||||
wkb = QgsWkbTypes.dropM(wkb)
|
||||
if self.drop_z:
|
||||
wkb = QgsWkbTypes.dropZ(wkb)
|
||||
return wkb
|
||||
|
||||
def prepareAlgorithm(self, parameters, context, feedback):
|
||||
self.drop_m = self.parameterAsBool(parameters, self.DROP_M_VALUES, context)
|
||||
self.drop_z = self.parameterAsBool(parameters, self.DROP_Z_VALUES, context)
|
||||
return True
|
||||
|
||||
def processFeature(self, feature, feedback):
|
||||
input_geometry = feature.geometry()
|
||||
if input_geometry:
|
||||
new_geom = input_geometry.geometry().clone()
|
||||
if self.drop_m:
|
||||
new_geom.dropMValue()
|
||||
if self.drop_z:
|
||||
new_geom.dropZValue()
|
||||
feature.setGeometry(QgsGeometry(new_geom))
|
||||
|
||||
return feature
|
@ -56,6 +56,7 @@ from .DensifyGeometries import DensifyGeometries
|
||||
from .DensifyGeometriesInterval import DensifyGeometriesInterval
|
||||
from .Difference import Difference
|
||||
from .DropGeometry import DropGeometry
|
||||
from .DropMZValues import DropMZValues
|
||||
from .ExtentFromLayer import ExtentFromLayer
|
||||
from .ExtractNodes import ExtractNodes
|
||||
from .FixGeometry import FixGeometry
|
||||
@ -89,6 +90,8 @@ from .SelectByAttribute import SelectByAttribute
|
||||
from .SelectByExpression import SelectByExpression
|
||||
from .ServiceAreaFromLayer import ServiceAreaFromLayer
|
||||
from .ServiceAreaFromPoint import ServiceAreaFromPoint
|
||||
from .SetMValue import SetMValue
|
||||
from .SetZValue import SetZValue
|
||||
from .ShortestPathLayerToPoint import ShortestPathLayerToPoint
|
||||
from .ShortestPathPointToLayer import ShortestPathPointToLayer
|
||||
from .ShortestPathPointToPoint import ShortestPathPointToPoint
|
||||
@ -243,6 +246,7 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
|
||||
DensifyGeometriesInterval(),
|
||||
Difference(),
|
||||
DropGeometry(),
|
||||
DropMZValues(),
|
||||
ExtentFromLayer(),
|
||||
ExtractNodes(),
|
||||
FixGeometry(),
|
||||
@ -276,6 +280,8 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
|
||||
SelectByExpression(),
|
||||
ServiceAreaFromLayer(),
|
||||
ServiceAreaFromPoint(),
|
||||
SetMValue(),
|
||||
SetZValue(),
|
||||
ShortestPathLayerToPoint(),
|
||||
ShortestPathPointToLayer(),
|
||||
ShortestPathPointToPoint(),
|
||||
|
@ -25,7 +25,7 @@ __copyright__ = '(C) 2017, Nyall Dawson'
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
from qgis.core import QgsProcessingAlgorithm
|
||||
from qgis.core import QgsProcessingAlgorithm, QgsProcessingFeatureBasedAlgorithm
|
||||
from qgis.PyQt.QtCore import QCoreApplication
|
||||
from processing.algs.help import shortHelp
|
||||
|
||||
@ -50,3 +50,25 @@ class QgisAlgorithm(QgsProcessingAlgorithm):
|
||||
|
||||
def createInstance(self):
|
||||
return type(self)()
|
||||
|
||||
|
||||
class QgisFeatureBasedAlgorithm(QgsProcessingFeatureBasedAlgorithm):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def shortHelpString(self):
|
||||
return shortHelp.get(self.id(), None)
|
||||
|
||||
def tr(self, string, context=''):
|
||||
if context == '':
|
||||
context = self.__class__.__name__
|
||||
return QCoreApplication.translate(context, string)
|
||||
|
||||
def trAlgorithm(self, string, context=''):
|
||||
if context == '':
|
||||
context = self.__class__.__name__
|
||||
return string, QCoreApplication.translate(context, string)
|
||||
|
||||
def createInstance(self):
|
||||
return type(self)()
|
||||
|
86
python/plugins/processing/algs/qgis/SetMValue.py
Normal file
86
python/plugins/processing/algs/qgis/SetMValue.py
Normal file
@ -0,0 +1,86 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
SetMValue.py
|
||||
--------------
|
||||
Date : July 2017
|
||||
Copyright : (C) 2017 by Nyall Dawson
|
||||
Email : nyall dot dawson 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__ = 'Nyall Dawson'
|
||||
__date__ = 'July 2017'
|
||||
__copyright__ = '(C) 2017, Nyall Dawson'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive323
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
import os
|
||||
|
||||
from qgis.core import (QgsGeometry,
|
||||
QgsWkbTypes,
|
||||
QgsProcessingParameterNumber)
|
||||
|
||||
|
||||
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
|
||||
|
||||
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
|
||||
|
||||
|
||||
class SetMValue(QgisFeatureBasedAlgorithm):
|
||||
|
||||
M_VALUE = 'M_VALUE'
|
||||
|
||||
def group(self):
|
||||
return self.tr('Vector geometry tools')
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.m_value = 0
|
||||
|
||||
def name(self):
|
||||
return 'setmvalue'
|
||||
|
||||
def displayName(self):
|
||||
return self.tr('Set M Value')
|
||||
|
||||
def outputName(self):
|
||||
return self.tr('M Added')
|
||||
|
||||
def tags(self):
|
||||
return self.tr('set,add,m,measure,values').split(',')
|
||||
|
||||
def initParameters(self, config=None):
|
||||
self.addParameter(QgsProcessingParameterNumber(self.M_VALUE,
|
||||
self.tr('M Value'), QgsProcessingParameterNumber.Double, defaultValue=0.0))
|
||||
|
||||
def outputWkbType(self, inputWkb):
|
||||
return QgsWkbTypes.addM(inputWkb)
|
||||
|
||||
def prepareAlgorithm(self, parameters, context, feedback):
|
||||
self.m_value = self.parameterAsDouble(parameters, self.M_VALUE, context)
|
||||
return True
|
||||
|
||||
def processFeature(self, feature, feedback):
|
||||
input_geometry = feature.geometry()
|
||||
if input_geometry:
|
||||
new_geom = input_geometry.geometry().clone()
|
||||
if QgsWkbTypes.hasM(new_geom.wkbType()):
|
||||
# addMValue won't alter existing M values, so drop them first
|
||||
new_geom.dropMValue()
|
||||
|
||||
new_geom.addMValue(self.m_value)
|
||||
|
||||
feature.setGeometry(QgsGeometry(new_geom))
|
||||
|
||||
return feature
|
86
python/plugins/processing/algs/qgis/SetZValue.py
Normal file
86
python/plugins/processing/algs/qgis/SetZValue.py
Normal file
@ -0,0 +1,86 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
SetZValue.py
|
||||
--------------
|
||||
Date : July 2017
|
||||
Copyright : (C) 2017 by Nyall Dawson
|
||||
Email : nyall dot dawson 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__ = 'Nyall Dawson'
|
||||
__date__ = 'July 2017'
|
||||
__copyright__ = '(C) 2017, Nyall Dawson'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive323
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
import os
|
||||
|
||||
from qgis.core import (QgsGeometry,
|
||||
QgsWkbTypes,
|
||||
QgsProcessingParameterNumber)
|
||||
|
||||
|
||||
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
|
||||
|
||||
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
|
||||
|
||||
|
||||
class SetZValue(QgisFeatureBasedAlgorithm):
|
||||
|
||||
Z_VALUE = 'Z_VALUE'
|
||||
|
||||
def group(self):
|
||||
return self.tr('Vector geometry tools')
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.z_value = 0
|
||||
|
||||
def name(self):
|
||||
return 'setzvalue'
|
||||
|
||||
def displayName(self):
|
||||
return self.tr('Set Z Value')
|
||||
|
||||
def outputName(self):
|
||||
return self.tr('Z Added')
|
||||
|
||||
def tags(self):
|
||||
return self.tr('set,add,z,25d,3d,values').split(',')
|
||||
|
||||
def initParameters(self, config=None):
|
||||
self.addParameter(QgsProcessingParameterNumber(self.Z_VALUE,
|
||||
self.tr('Z Value'), QgsProcessingParameterNumber.Double, defaultValue=0.0))
|
||||
|
||||
def outputWkbType(self, inputWkb):
|
||||
return QgsWkbTypes.addZ(inputWkb)
|
||||
|
||||
def prepareAlgorithm(self, parameters, context, feedback):
|
||||
self.z_value = self.parameterAsDouble(parameters, self.Z_VALUE, context)
|
||||
return True
|
||||
|
||||
def processFeature(self, feature, feedback):
|
||||
input_geometry = feature.geometry()
|
||||
if input_geometry:
|
||||
new_geom = input_geometry.geometry().clone()
|
||||
if QgsWkbTypes.hasZ(new_geom.wkbType()):
|
||||
# addZValue won't alter existing Z values, so drop them first
|
||||
new_geom.dropZValue()
|
||||
|
||||
new_geom.addZValue(self.z_value)
|
||||
|
||||
feature.setGeometry(QgsGeometry(new_geom))
|
||||
|
||||
return feature
|
BIN
python/plugins/processing/tests/testdata/custom/pointszm.dbf
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/custom/pointszm.dbf
vendored
Normal file
Binary file not shown.
1
python/plugins/processing/tests/testdata/custom/pointszm.prj
vendored
Normal file
1
python/plugins/processing/tests/testdata/custom/pointszm.prj
vendored
Normal file
@ -0,0 +1 @@
|
||||
GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
|
1
python/plugins/processing/tests/testdata/custom/pointszm.qpj
vendored
Normal file
1
python/plugins/processing/tests/testdata/custom/pointszm.qpj
vendored
Normal file
@ -0,0 +1 @@
|
||||
GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]
|
BIN
python/plugins/processing/tests/testdata/custom/pointszm.shp
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/custom/pointszm.shp
vendored
Normal file
Binary file not shown.
BIN
python/plugins/processing/tests/testdata/custom/pointszm.shx
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/custom/pointszm.shx
vendored
Normal file
Binary file not shown.
BIN
python/plugins/processing/tests/testdata/expected/m_dropped.dbf
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/m_dropped.dbf
vendored
Normal file
Binary file not shown.
1
python/plugins/processing/tests/testdata/expected/m_dropped.prj
vendored
Normal file
1
python/plugins/processing/tests/testdata/expected/m_dropped.prj
vendored
Normal file
@ -0,0 +1 @@
|
||||
GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
|
1
python/plugins/processing/tests/testdata/expected/m_dropped.qpj
vendored
Normal file
1
python/plugins/processing/tests/testdata/expected/m_dropped.qpj
vendored
Normal file
@ -0,0 +1 @@
|
||||
GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]
|
BIN
python/plugins/processing/tests/testdata/expected/m_dropped.shp
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/m_dropped.shp
vendored
Normal file
Binary file not shown.
BIN
python/plugins/processing/tests/testdata/expected/m_dropped.shx
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/m_dropped.shx
vendored
Normal file
Binary file not shown.
BIN
python/plugins/processing/tests/testdata/expected/set_m_value.dbf
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/set_m_value.dbf
vendored
Normal file
Binary file not shown.
77
python/plugins/processing/tests/testdata/expected/set_m_value.gml
vendored
Normal file
77
python/plugins/processing/tests/testdata/expected/set_m_value.gml
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ogr:FeatureCollection
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation=""
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:gml="http://www.opengis.net/gml">
|
||||
<gml:boundedBy>
|
||||
<gml:Box>
|
||||
<gml:coord><gml:X>0</gml:X><gml:Y>-5</gml:Y></gml:coord>
|
||||
<gml:coord><gml:X>8</gml:X><gml:Y>3</gml:Y></gml:coord>
|
||||
</gml:Box>
|
||||
</gml:boundedBy>
|
||||
|
||||
<gml:featureMember>
|
||||
<ogr:set_m_value fid="points.0">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>1,1</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:id>1</ogr:id>
|
||||
<ogr:id2>2</ogr:id2>
|
||||
</ogr:set_m_value>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:set_m_value fid="points.1">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3,3</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:id>2</ogr:id>
|
||||
<ogr:id2>1</ogr:id2>
|
||||
</ogr:set_m_value>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:set_m_value fid="points.2">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>2,2</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:id>3</ogr:id>
|
||||
<ogr:id2>0</ogr:id2>
|
||||
</ogr:set_m_value>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:set_m_value fid="points.3">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>5,2</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:id>4</ogr:id>
|
||||
<ogr:id2>2</ogr:id2>
|
||||
</ogr:set_m_value>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:set_m_value fid="points.4">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>4,1</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:id>5</ogr:id>
|
||||
<ogr:id2>1</ogr:id2>
|
||||
</ogr:set_m_value>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:set_m_value fid="points.5">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0,-5</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:id>6</ogr:id>
|
||||
<ogr:id2>0</ogr:id2>
|
||||
</ogr:set_m_value>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:set_m_value fid="points.6">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>8,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:id>7</ogr:id>
|
||||
<ogr:id2>0</ogr:id2>
|
||||
</ogr:set_m_value>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:set_m_value fid="points.7">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>7,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:id>8</ogr:id>
|
||||
<ogr:id2>0</ogr:id2>
|
||||
</ogr:set_m_value>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:set_m_value fid="points.8">
|
||||
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
|
||||
<ogr:id>9</ogr:id>
|
||||
<ogr:id2>0</ogr:id2>
|
||||
</ogr:set_m_value>
|
||||
</gml:featureMember>
|
||||
</ogr:FeatureCollection>
|
1
python/plugins/processing/tests/testdata/expected/set_m_value.prj
vendored
Normal file
1
python/plugins/processing/tests/testdata/expected/set_m_value.prj
vendored
Normal file
@ -0,0 +1 @@
|
||||
GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
|
1
python/plugins/processing/tests/testdata/expected/set_m_value.qpj
vendored
Normal file
1
python/plugins/processing/tests/testdata/expected/set_m_value.qpj
vendored
Normal file
@ -0,0 +1 @@
|
||||
GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]
|
BIN
python/plugins/processing/tests/testdata/expected/set_m_value.shp
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/set_m_value.shp
vendored
Normal file
Binary file not shown.
BIN
python/plugins/processing/tests/testdata/expected/set_m_value.shx
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/set_m_value.shx
vendored
Normal file
Binary file not shown.
BIN
python/plugins/processing/tests/testdata/expected/set_z_value.dbf
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/set_z_value.dbf
vendored
Normal file
Binary file not shown.
1
python/plugins/processing/tests/testdata/expected/set_z_value.prj
vendored
Normal file
1
python/plugins/processing/tests/testdata/expected/set_z_value.prj
vendored
Normal file
@ -0,0 +1 @@
|
||||
GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
|
1
python/plugins/processing/tests/testdata/expected/set_z_value.qpj
vendored
Normal file
1
python/plugins/processing/tests/testdata/expected/set_z_value.qpj
vendored
Normal file
@ -0,0 +1 @@
|
||||
GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]
|
BIN
python/plugins/processing/tests/testdata/expected/set_z_value.shp
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/set_z_value.shp
vendored
Normal file
Binary file not shown.
BIN
python/plugins/processing/tests/testdata/expected/set_z_value.shx
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/set_z_value.shx
vendored
Normal file
Binary file not shown.
BIN
python/plugins/processing/tests/testdata/expected/z_dropped.dbf
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/z_dropped.dbf
vendored
Normal file
Binary file not shown.
1
python/plugins/processing/tests/testdata/expected/z_dropped.prj
vendored
Normal file
1
python/plugins/processing/tests/testdata/expected/z_dropped.prj
vendored
Normal file
@ -0,0 +1 @@
|
||||
GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
|
1
python/plugins/processing/tests/testdata/expected/z_dropped.qpj
vendored
Normal file
1
python/plugins/processing/tests/testdata/expected/z_dropped.qpj
vendored
Normal file
@ -0,0 +1 @@
|
||||
GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]
|
BIN
python/plugins/processing/tests/testdata/expected/z_dropped.shp
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/z_dropped.shp
vendored
Normal file
Binary file not shown.
BIN
python/plugins/processing/tests/testdata/expected/z_dropped.shx
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/z_dropped.shx
vendored
Normal file
Binary file not shown.
BIN
python/plugins/processing/tests/testdata/expected/zm_dropped.dbf
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/zm_dropped.dbf
vendored
Normal file
Binary file not shown.
1
python/plugins/processing/tests/testdata/expected/zm_dropped.prj
vendored
Normal file
1
python/plugins/processing/tests/testdata/expected/zm_dropped.prj
vendored
Normal file
@ -0,0 +1 @@
|
||||
GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
|
1
python/plugins/processing/tests/testdata/expected/zm_dropped.qpj
vendored
Normal file
1
python/plugins/processing/tests/testdata/expected/zm_dropped.qpj
vendored
Normal file
@ -0,0 +1 @@
|
||||
GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]
|
BIN
python/plugins/processing/tests/testdata/expected/zm_dropped.shp
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/zm_dropped.shp
vendored
Normal file
Binary file not shown.
BIN
python/plugins/processing/tests/testdata/expected/zm_dropped.shx
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/zm_dropped.shx
vendored
Normal file
Binary file not shown.
@ -415,66 +415,66 @@ tests:
|
||||
- algorithm: qgis:boundingboxes
|
||||
name: Bounding boxes for lines
|
||||
params:
|
||||
INPUT_LAYER:
|
||||
INPUT:
|
||||
name: lines.gml
|
||||
type: vector
|
||||
results:
|
||||
OUTPUT_LAYER:
|
||||
OUTPUT:
|
||||
name: expected/lines_bounds.gml
|
||||
type: vector
|
||||
|
||||
- algorithm: qgis:boundingboxes
|
||||
name: Bounding boxes for multilines
|
||||
params:
|
||||
INPUT_LAYER:
|
||||
INPUT:
|
||||
name: multilines.gml
|
||||
type: vector
|
||||
results:
|
||||
OUTPUT_LAYER:
|
||||
OUTPUT:
|
||||
name: expected/multiline_bounds.gml
|
||||
type: vector
|
||||
|
||||
- algorithm: qgis:boundingboxes
|
||||
name: Bounding boxes for multipolygons
|
||||
params:
|
||||
INPUT_LAYER:
|
||||
INPUT:
|
||||
name: multipolys.gml
|
||||
type: vector
|
||||
results:
|
||||
OUTPUT_LAYER:
|
||||
OUTPUT:
|
||||
name: expected/multipoly_bounds.gml
|
||||
type: vector
|
||||
|
||||
- algorithm: qgis:boundingboxes
|
||||
name: Bounding boxes for points
|
||||
params:
|
||||
INPUT_LAYER:
|
||||
INPUT:
|
||||
name: points.gml
|
||||
type: vector
|
||||
results:
|
||||
OUTPUT_LAYER:
|
||||
OUTPUT:
|
||||
name: expected/point_bounds.gml
|
||||
type: vector
|
||||
|
||||
- algorithm: qgis:boundingboxes
|
||||
name: Bounding boxes for polygons
|
||||
params:
|
||||
INPUT_LAYER:
|
||||
INPUT:
|
||||
name: polys.gml
|
||||
type: vector
|
||||
results:
|
||||
OUTPUT_LAYER:
|
||||
OUTPUT:
|
||||
name: expected/poly_bounds.gml
|
||||
type: vector
|
||||
|
||||
- algorithm: qgis:boundingboxes
|
||||
name: Bounding boxes for multipoints
|
||||
params:
|
||||
INPUT_LAYER:
|
||||
INPUT:
|
||||
name: multipoints.gml
|
||||
type: vector
|
||||
results:
|
||||
OUTPUT_LAYER:
|
||||
OUTPUT:
|
||||
name: expected/multipoint_bounds.gml
|
||||
type: vector
|
||||
|
||||
@ -522,6 +522,69 @@ tests:
|
||||
name: expected/multiline_boundary.gml
|
||||
type: vector
|
||||
|
||||
- algorithm: qgis:setmvalue
|
||||
name: Set M Value
|
||||
params:
|
||||
INPUT:
|
||||
name: points.gml
|
||||
type: vector
|
||||
M_VALUE: 7
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/set_m_value.shp
|
||||
type: vector
|
||||
|
||||
- algorithm: qgis:setzvalue
|
||||
name: Set Z Value
|
||||
params:
|
||||
INPUT:
|
||||
name: points.gml
|
||||
type: vector
|
||||
Z_VALUE: 6
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/set_z_value.shp
|
||||
type: vector
|
||||
|
||||
- algorithm: qgis:dropmzvalues
|
||||
name: Drop M Value
|
||||
params:
|
||||
INPUT:
|
||||
name: custom/pointszm.shp
|
||||
type: vector
|
||||
DROP_Z_VALUES: False
|
||||
DROP_M_VALUES: True
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/m_dropped.shp
|
||||
type: vector
|
||||
|
||||
- algorithm: qgis:dropmzvalues
|
||||
name: Drop Z Value
|
||||
params:
|
||||
INPUT:
|
||||
name: custom/pointszm.shp
|
||||
type: vector
|
||||
DROP_Z_VALUES: True
|
||||
DROP_M_VALUES: False
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/z_dropped.shp
|
||||
type: vector
|
||||
|
||||
- algorithm: qgis:dropmzvalues
|
||||
name: Drop ZM Value
|
||||
params:
|
||||
INPUT:
|
||||
name: custom/pointszm.shp
|
||||
type: vector
|
||||
DROP_Z_VALUES: True
|
||||
DROP_M_VALUES: True
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/zm_dropped.shp
|
||||
type: vector
|
||||
|
||||
- algorithm: qgis:pointonsurface
|
||||
name: Point on polygon surface
|
||||
params:
|
||||
@ -2556,11 +2619,11 @@ tests:
|
||||
FIELD_NAME: field
|
||||
FIELD_PRECISION: 2
|
||||
FIELD_TYPE: '1'
|
||||
INPUT_LAYER:
|
||||
INPUT:
|
||||
name: custom/points.shp
|
||||
type: vector
|
||||
results:
|
||||
OUTPUT_LAYER:
|
||||
OUTPUT:
|
||||
name: expected/add_field.gml
|
||||
type: vector
|
||||
|
||||
|
@ -87,53 +87,19 @@ QgsCentroidAlgorithm *QgsCentroidAlgorithm::createInstance() const
|
||||
return new QgsCentroidAlgorithm();
|
||||
}
|
||||
|
||||
QVariantMap QgsCentroidAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
|
||||
QgsFeature QgsCentroidAlgorithm::processFeature( const QgsFeature &f, QgsProcessingFeedback *feedback )
|
||||
{
|
||||
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
|
||||
if ( !source )
|
||||
return QVariantMap();
|
||||
|
||||
QString dest;
|
||||
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(), QgsWkbTypes::Point, source->sourceCrs() ) );
|
||||
if ( !sink )
|
||||
return QVariantMap();
|
||||
|
||||
long count = source->featureCount();
|
||||
if ( count <= 0 )
|
||||
return QVariantMap();
|
||||
|
||||
QgsFeature f;
|
||||
QgsFeatureIterator it = source->getFeatures();
|
||||
|
||||
double step = 100.0 / count;
|
||||
int current = 0;
|
||||
while ( it.nextFeature( f ) )
|
||||
QgsFeature feature = f;
|
||||
if ( feature.hasGeometry() )
|
||||
{
|
||||
if ( feedback->isCanceled() )
|
||||
feature.setGeometry( feature.geometry().centroid() );
|
||||
if ( !feature.geometry() )
|
||||
{
|
||||
break;
|
||||
feedback->pushInfo( QObject::tr( "Error calculating centroid for feature %1" ).arg( feature.id() ) );
|
||||
}
|
||||
|
||||
QgsFeature out = f;
|
||||
if ( out.hasGeometry() )
|
||||
{
|
||||
out.setGeometry( f.geometry().centroid() );
|
||||
if ( !out.geometry() )
|
||||
{
|
||||
QgsMessageLog::logMessage( QObject::tr( "Error calculating centroid for feature %1" ).arg( f.id() ), QObject::tr( "Processing" ), QgsMessageLog::WARNING );
|
||||
}
|
||||
}
|
||||
sink->addFeature( out, QgsFeatureSink::FastInsert );
|
||||
|
||||
feedback->setProgress( current * step );
|
||||
current++;
|
||||
}
|
||||
|
||||
QVariantMap outputs;
|
||||
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
|
||||
return outputs;
|
||||
return feature;
|
||||
}
|
||||
|
||||
//
|
||||
// QgsBufferAlgorithm
|
||||
//
|
||||
@ -188,13 +154,11 @@ QVariantMap QgsBufferAlgorithm::processAlgorithm( const QVariantMap ¶meters,
|
||||
const QgsProcessingParameterDefinition *distanceParamDef = parameterDefinition( QStringLiteral( "DISTANCE" ) );
|
||||
|
||||
long count = source->featureCount();
|
||||
if ( count <= 0 )
|
||||
return QVariantMap();
|
||||
|
||||
QgsFeature f;
|
||||
QgsFeatureIterator it = source->getFeatures();
|
||||
|
||||
double step = 100.0 / count;
|
||||
double step = count > 0 ? 100.0 / count : 1;
|
||||
int current = 0;
|
||||
|
||||
QList< QgsGeometry > bufferedGeometriesForDissolve;
|
||||
@ -289,13 +253,11 @@ QVariantMap QgsDissolveAlgorithm::processAlgorithm( const QVariantMap ¶meter
|
||||
QStringList fields = parameterAsFields( parameters, QStringLiteral( "FIELD" ), context );
|
||||
|
||||
long count = source->featureCount();
|
||||
if ( count <= 0 )
|
||||
return QVariantMap();
|
||||
|
||||
QgsFeature f;
|
||||
QgsFeatureIterator it = source->getFeatures();
|
||||
|
||||
double step = 100.0 / count;
|
||||
double step = count > 0 ? 100.0 / count : 1;
|
||||
int current = 0;
|
||||
|
||||
if ( fields.isEmpty() )
|
||||
@ -456,8 +418,11 @@ QVariantMap QgsClipAlgorithm::processAlgorithm( const QVariantMap ¶meters, Q
|
||||
clipGeoms << f.geometry();
|
||||
}
|
||||
|
||||
QVariantMap outputs;
|
||||
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
|
||||
|
||||
if ( clipGeoms.isEmpty() )
|
||||
return QVariantMap();
|
||||
return outputs;
|
||||
|
||||
// are we clipping against a single feature? if so, we can show finer progress reports
|
||||
bool singleClipFeature = false;
|
||||
@ -557,17 +522,13 @@ QVariantMap QgsClipAlgorithm::processAlgorithm( const QVariantMap ¶meters, Q
|
||||
}
|
||||
}
|
||||
|
||||
QVariantMap outputs;
|
||||
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
|
||||
return outputs;
|
||||
}
|
||||
|
||||
|
||||
void QgsTransformAlgorithm::initAlgorithm( const QVariantMap & )
|
||||
void QgsTransformAlgorithm::initParameters( const QVariantMap & )
|
||||
{
|
||||
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
|
||||
addParameter( new QgsProcessingParameterCrs( QStringLiteral( "TARGET_CRS" ), QObject::tr( "Target CRS" ), QStringLiteral( "EPSG:4326" ) ) );
|
||||
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Reprojected" ) ) );
|
||||
}
|
||||
|
||||
QString QgsTransformAlgorithm::shortHelpString() const
|
||||
@ -582,57 +543,41 @@ QgsTransformAlgorithm *QgsTransformAlgorithm::createInstance() const
|
||||
return new QgsTransformAlgorithm();
|
||||
}
|
||||
|
||||
QVariantMap QgsTransformAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
|
||||
bool QgsTransformAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * )
|
||||
{
|
||||
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
|
||||
if ( !source )
|
||||
return QVariantMap();
|
||||
mDestCrs = parameterAsCrs( parameters, QStringLiteral( "TARGET_CRS" ), context );
|
||||
return true;
|
||||
}
|
||||
|
||||
QgsCoordinateReferenceSystem targetCrs = parameterAsCrs( parameters, QStringLiteral( "TARGET_CRS" ), context );
|
||||
|
||||
QString dest;
|
||||
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(), source->wkbType(), targetCrs ) );
|
||||
if ( !sink )
|
||||
return QVariantMap();
|
||||
|
||||
long count = source->featureCount();
|
||||
if ( count <= 0 )
|
||||
return QVariantMap();
|
||||
|
||||
QgsFeature f;
|
||||
QgsFeatureRequest req;
|
||||
// perform reprojection in the iterators...
|
||||
req.setDestinationCrs( targetCrs );
|
||||
|
||||
QgsFeatureIterator it = source->getFeatures( req );
|
||||
|
||||
double step = 100.0 / count;
|
||||
int current = 0;
|
||||
while ( it.nextFeature( f ) )
|
||||
QgsFeature QgsTransformAlgorithm::processFeature( const QgsFeature &f, QgsProcessingFeedback * )
|
||||
{
|
||||
QgsFeature feature = f;
|
||||
if ( !mCreatedTransform )
|
||||
{
|
||||
if ( feedback->isCanceled() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
sink->addFeature( f, QgsFeatureSink::FastInsert );
|
||||
feedback->setProgress( current * step );
|
||||
current++;
|
||||
mCreatedTransform = true;
|
||||
mTransform = QgsCoordinateTransform( sourceCrs(), mDestCrs );
|
||||
}
|
||||
|
||||
QVariantMap outputs;
|
||||
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
|
||||
return outputs;
|
||||
if ( feature.hasGeometry() )
|
||||
{
|
||||
QgsGeometry g = feature.geometry();
|
||||
if ( g.transform( mTransform ) == 0 )
|
||||
{
|
||||
feature.setGeometry( g );
|
||||
}
|
||||
else
|
||||
{
|
||||
feature.clearGeometry();
|
||||
}
|
||||
}
|
||||
return feature;
|
||||
}
|
||||
|
||||
|
||||
void QgsSubdivideAlgorithm::initAlgorithm( const QVariantMap & )
|
||||
void QgsSubdivideAlgorithm::initParameters( const QVariantMap & )
|
||||
{
|
||||
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
|
||||
addParameter( new QgsProcessingParameterNumber( QStringLiteral( "MAX_NODES" ), QObject::tr( "Maximum nodes in parts" ), QgsProcessingParameterNumber::Integer,
|
||||
256, false, 8, 100000 ) );
|
||||
|
||||
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Subdivided" ) ) );
|
||||
}
|
||||
|
||||
QString QgsSubdivideAlgorithm::shortHelpString() const
|
||||
@ -650,53 +595,29 @@ QgsSubdivideAlgorithm *QgsSubdivideAlgorithm::createInstance() const
|
||||
return new QgsSubdivideAlgorithm();
|
||||
}
|
||||
|
||||
QVariantMap QgsSubdivideAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
|
||||
QgsWkbTypes::Type QgsSubdivideAlgorithm::outputWkbType( QgsWkbTypes::Type inputWkbType ) const
|
||||
{
|
||||
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
|
||||
if ( !source )
|
||||
return QVariantMap();
|
||||
return QgsWkbTypes::multiType( inputWkbType );
|
||||
}
|
||||
|
||||
int maxNodes = parameterAsInt( parameters, QStringLiteral( "MAX_NODES" ), context );
|
||||
QString dest;
|
||||
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(),
|
||||
QgsWkbTypes::multiType( source->wkbType() ), source->sourceCrs() ) );
|
||||
if ( !sink )
|
||||
return QVariantMap();
|
||||
|
||||
long count = source->featureCount();
|
||||
if ( count <= 0 )
|
||||
return QVariantMap();
|
||||
|
||||
QgsFeature f;
|
||||
QgsFeatureIterator it = source->getFeatures();
|
||||
|
||||
double step = 100.0 / count;
|
||||
int current = 0;
|
||||
while ( it.nextFeature( f ) )
|
||||
QgsFeature QgsSubdivideAlgorithm::processFeature( const QgsFeature &f, QgsProcessingFeedback *feedback )
|
||||
{
|
||||
QgsFeature feature = f;
|
||||
if ( feature.hasGeometry() )
|
||||
{
|
||||
if ( feedback->isCanceled() )
|
||||
feature.setGeometry( feature.geometry().subdivide( mMaxNodes ) );
|
||||
if ( !feature.geometry() )
|
||||
{
|
||||
break;
|
||||
feedback->reportError( QObject::tr( "Error calculating subdivision for feature %1" ).arg( feature.id() ) );
|
||||
}
|
||||
|
||||
QgsFeature out = f;
|
||||
if ( out.hasGeometry() )
|
||||
{
|
||||
out.setGeometry( f.geometry().subdivide( maxNodes ) );
|
||||
if ( !out.geometry() )
|
||||
{
|
||||
QgsMessageLog::logMessage( QObject::tr( "Error calculating subdivision for feature %1" ).arg( f.id() ), QObject::tr( "Processing" ), QgsMessageLog::WARNING );
|
||||
}
|
||||
}
|
||||
sink->addFeature( out, QgsFeatureSink::FastInsert );
|
||||
|
||||
feedback->setProgress( current * step );
|
||||
current++;
|
||||
}
|
||||
return feature;
|
||||
}
|
||||
|
||||
QVariantMap outputs;
|
||||
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
|
||||
return outputs;
|
||||
bool QgsSubdivideAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * )
|
||||
{
|
||||
mMaxNodes = parameterAsInt( parameters, QStringLiteral( "MAX_NODES" ), context );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -734,13 +655,11 @@ QVariantMap QgsMultipartToSinglepartAlgorithm::processAlgorithm( const QVariantM
|
||||
return QVariantMap();
|
||||
|
||||
long count = source->featureCount();
|
||||
if ( count <= 0 )
|
||||
return QVariantMap();
|
||||
|
||||
QgsFeature f;
|
||||
QgsFeatureIterator it = source->getFeatures();
|
||||
|
||||
double step = 100.0 / count;
|
||||
double step = count > 0 ? 100.0 / count : 1;
|
||||
int current = 0;
|
||||
while ( it.nextFeature( f ) )
|
||||
{
|
||||
@ -833,10 +752,8 @@ QVariantMap QgsExtractByExpressionAlgorithm::processAlgorithm( const QVariantMap
|
||||
QgsExpressionContext expressionContext = createExpressionContext( parameters, context );
|
||||
|
||||
long count = source->featureCount();
|
||||
if ( count <= 0 )
|
||||
return QVariantMap();
|
||||
|
||||
double step = 100.0 / count;
|
||||
double step = count > 0 ? 100.0 / count : 1;
|
||||
int current = 0;
|
||||
|
||||
if ( !nonMatchingSink )
|
||||
@ -1032,10 +949,8 @@ QVariantMap QgsExtractByAttributeAlgorithm::processAlgorithm( const QVariantMap
|
||||
QgsExpressionContext expressionContext = createExpressionContext( parameters, context );
|
||||
|
||||
long count = source->featureCount();
|
||||
if ( count <= 0 )
|
||||
return QVariantMap();
|
||||
|
||||
double step = 100.0 / count;
|
||||
double step = count > 0 ? 100.0 / count : 1;
|
||||
int current = 0;
|
||||
|
||||
if ( !nonMatchingSink )
|
||||
@ -1137,10 +1052,8 @@ QVariantMap QgsRemoveNullGeometryAlgorithm::processAlgorithm( const QVariantMap
|
||||
std::unique_ptr< QgsFeatureSink > nullSink( parameterAsSink( parameters, QStringLiteral( "NULL_OUTPUT" ), context, nullSinkId, source->fields() ) );
|
||||
|
||||
long count = source->featureCount();
|
||||
if ( count <= 0 )
|
||||
return QVariantMap();
|
||||
|
||||
double step = 100.0 / count;
|
||||
double step = count > 0 ? 100.0 / count : 1;
|
||||
int current = 0;
|
||||
|
||||
QgsFeature f;
|
||||
|
@ -48,7 +48,7 @@ class QgsNativeAlgorithms: public QgsProcessingProvider
|
||||
/**
|
||||
* Native centroid algorithm.
|
||||
*/
|
||||
class QgsCentroidAlgorithm : public QgsProcessingAlgorithm
|
||||
class QgsCentroidAlgorithm : public QgsProcessingFeatureBasedAlgorithm
|
||||
{
|
||||
|
||||
public:
|
||||
@ -57,28 +57,29 @@ class QgsCentroidAlgorithm : public QgsProcessingAlgorithm
|
||||
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
|
||||
QString name() const override { return QStringLiteral( "centroids" ); }
|
||||
QString displayName() const override { return QObject::tr( "Centroids" ); }
|
||||
virtual QStringList tags() const override { return QObject::tr( "centroid,center,average,point,middle" ).split( ',' ); }
|
||||
QStringList tags() const override { return QObject::tr( "centroid,center,average,point,middle" ).split( ',' ); }
|
||||
QString group() const override { return QObject::tr( "Vector geometry tools" ); }
|
||||
QString shortHelpString() const override;
|
||||
QgsCentroidAlgorithm *createInstance() const override SIP_FACTORY;
|
||||
|
||||
protected:
|
||||
|
||||
virtual QVariantMap processAlgorithm( const QVariantMap ¶meters,
|
||||
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
QString outputName() const override { return QObject::tr( "Centroids" ); }
|
||||
QgsProcessing::LayerType outputLayerType() const override { return QgsProcessing::TypeVectorPoint; }
|
||||
QgsWkbTypes::Type outputWkbType( QgsWkbTypes::Type inputWkbType ) const override { Q_UNUSED( inputWkbType ); return QgsWkbTypes::Point; }
|
||||
|
||||
QgsFeature processFeature( const QgsFeature &feature, QgsProcessingFeedback *feedback ) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Native transform algorithm.
|
||||
*/
|
||||
class QgsTransformAlgorithm : public QgsProcessingAlgorithm
|
||||
class QgsTransformAlgorithm : public QgsProcessingFeatureBasedAlgorithm
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
QgsTransformAlgorithm() = default;
|
||||
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
|
||||
QString name() const override { return QStringLiteral( "reprojectlayer" ); }
|
||||
QString displayName() const override { return QObject::tr( "Reproject layer" ); }
|
||||
virtual QStringList tags() const override { return QObject::tr( "transform,reproject,crs,srs,warp" ).split( ',' ); }
|
||||
@ -88,8 +89,18 @@ class QgsTransformAlgorithm : public QgsProcessingAlgorithm
|
||||
|
||||
protected:
|
||||
|
||||
virtual QVariantMap processAlgorithm( const QVariantMap ¶meters,
|
||||
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
void initParameters( const QVariantMap &configuration = QVariantMap() ) override;
|
||||
QgsCoordinateReferenceSystem outputCrs( const QgsCoordinateReferenceSystem & ) const override { return mDestCrs; }
|
||||
QString outputName() const override { return QObject::tr( "Reprojected" ); }
|
||||
|
||||
bool prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
QgsFeature processFeature( const QgsFeature &feature, QgsProcessingFeedback *feedback ) override;
|
||||
|
||||
private:
|
||||
|
||||
bool mCreatedTransform = false;
|
||||
QgsCoordinateReferenceSystem mDestCrs;
|
||||
QgsCoordinateTransform mTransform;
|
||||
|
||||
};
|
||||
|
||||
@ -233,13 +244,13 @@ class QgsClipAlgorithm : public QgsProcessingAlgorithm
|
||||
/**
|
||||
* Native subdivide algorithm.
|
||||
*/
|
||||
class QgsSubdivideAlgorithm : public QgsProcessingAlgorithm
|
||||
class QgsSubdivideAlgorithm : public QgsProcessingFeatureBasedAlgorithm
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
QgsSubdivideAlgorithm() = default;
|
||||
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
|
||||
void initParameters( const QVariantMap &configuration = QVariantMap() ) override;
|
||||
QString name() const override { return QStringLiteral( "subdivide" ); }
|
||||
QString displayName() const override { return QObject::tr( "Subdivide" ); }
|
||||
virtual QStringList tags() const override { return QObject::tr( "subdivide,segmentize,split,tesselate" ).split( ',' ); }
|
||||
@ -248,9 +259,16 @@ class QgsSubdivideAlgorithm : public QgsProcessingAlgorithm
|
||||
QgsSubdivideAlgorithm *createInstance() const override SIP_FACTORY;
|
||||
|
||||
protected:
|
||||
QString outputName() const override { return QObject::tr( "Subdivided" ); }
|
||||
|
||||
virtual QVariantMap processAlgorithm( const QVariantMap ¶meters,
|
||||
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
QgsWkbTypes::Type outputWkbType( QgsWkbTypes::Type inputWkbType ) const override;
|
||||
QgsFeature processFeature( const QgsFeature &feature, QgsProcessingFeedback *feedback ) override;
|
||||
|
||||
bool prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
|
||||
private:
|
||||
|
||||
int mMaxNodes = -1;
|
||||
|
||||
};
|
||||
|
||||
|
@ -608,3 +608,64 @@ bool QgsProcessingAlgorithm::createAutoOutputForParameter( QgsProcessingParamete
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// QgsProcessingFeatureBasedAlgorithm
|
||||
//
|
||||
|
||||
void QgsProcessingFeatureBasedAlgorithm::initAlgorithm( const QVariantMap &config )
|
||||
{
|
||||
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
|
||||
initParameters( config );
|
||||
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), outputName(), outputLayerType() ) );
|
||||
}
|
||||
|
||||
QgsCoordinateReferenceSystem QgsProcessingFeatureBasedAlgorithm::sourceCrs() const
|
||||
{
|
||||
if ( mSource )
|
||||
return mSource->sourceCrs();
|
||||
else
|
||||
return QgsCoordinateReferenceSystem();
|
||||
}
|
||||
|
||||
QVariantMap QgsProcessingFeatureBasedAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
|
||||
{
|
||||
mSource.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
|
||||
if ( !mSource )
|
||||
return QVariantMap();
|
||||
|
||||
QString dest;
|
||||
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest,
|
||||
outputFields( mSource->fields() ),
|
||||
outputWkbType( mSource->wkbType() ),
|
||||
outputCrs( mSource->sourceCrs() ) ) );
|
||||
if ( !sink )
|
||||
return QVariantMap();
|
||||
|
||||
long count = mSource->featureCount();
|
||||
|
||||
QgsFeature f;
|
||||
QgsFeatureIterator it = mSource->getFeatures();
|
||||
|
||||
double step = count > 0 ? 100.0 / count : 1;
|
||||
int current = 0;
|
||||
while ( it.nextFeature( f ) )
|
||||
{
|
||||
if ( feedback->isCanceled() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
QgsFeature transformed = processFeature( f, feedback );
|
||||
if ( transformed.isValid() )
|
||||
sink->addFeature( transformed, QgsFeatureSink::FastInsert );
|
||||
|
||||
feedback->setProgress( current * step );
|
||||
current++;
|
||||
}
|
||||
|
||||
mSource.reset();
|
||||
|
||||
QVariantMap outputs;
|
||||
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
|
||||
return outputs;
|
||||
}
|
||||
|
@ -53,6 +53,8 @@ class CORE_EXPORT QgsProcessingAlgorithm
|
||||
SIP_CONVERT_TO_SUBCLASS_CODE
|
||||
if ( dynamic_cast< QgsProcessingModelAlgorithm * >( sipCpp ) != NULL )
|
||||
sipType = sipType_QgsProcessingModelAlgorithm;
|
||||
else if ( dynamic_cast< QgsProcessingFeatureBasedAlgorithm * >( sipCpp ) != NULL )
|
||||
sipType = sipType_QgsProcessingFeatureBasedAlgorithm;
|
||||
else
|
||||
sipType = sipType_QgsProcessingAlgorithm;
|
||||
SIP_END
|
||||
@ -697,6 +699,130 @@ Q_DECLARE_OPERATORS_FOR_FLAGS( QgsProcessingAlgorithm::Flags )
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \class QgsProcessingFeatureBasedAlgorithm
|
||||
* \ingroup core
|
||||
* An abstract QgsProcessingAlgorithm base class for processing algorithms which operate "feature-by-feature".
|
||||
*
|
||||
* Feature based algorithms are algorithms which operate on individual features in isolation. These
|
||||
* are algorithms where one feature is output for each input feature, and the output feature result
|
||||
* for each input feature is not dependent on any other features present in the source.
|
||||
*
|
||||
* For instance, algorithms like "centroids" and "buffers" are feature based algorithms since the centroid
|
||||
* or buffer of a feature is calculated for each feature in isolation. An algorithm like "dissolve"
|
||||
* is NOT suitable for a feature based algorithm as the dissolved output depends on multiple input features
|
||||
* and these features cannot be processed in isolation.
|
||||
*
|
||||
* Using QgsProcessingFeatureBasedAlgorithm as the base class for feature based algorithms allows
|
||||
* shortcutting much of the common algorithm code for handling iterating over sources and pushing
|
||||
* features to output sinks. It also allows the algorithm execution to be optimised in future
|
||||
* (for instance allowing automatic multi-thread processing of the algorithm, or use of the
|
||||
* algorithm in "chains", avoiding the need for temporary outputs in multi-step models).
|
||||
*
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
|
||||
class CORE_EXPORT QgsProcessingFeatureBasedAlgorithm : public QgsProcessingAlgorithm
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsProcessingFeatureBasedAlgorithm.
|
||||
*/
|
||||
QgsProcessingFeatureBasedAlgorithm() = default;
|
||||
|
||||
protected:
|
||||
|
||||
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
|
||||
|
||||
/**
|
||||
* Returns the translated, user visible name for any layers created by this algorithm.
|
||||
* This name will be used as the default name when loading the resultant layer into a
|
||||
* QGIS project.
|
||||
*/
|
||||
virtual QString outputName() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the layer type for layers generated by this algorithm, if
|
||||
* this is possible to determine in advance.
|
||||
*/
|
||||
virtual QgsProcessing::LayerType outputLayerType() const { return QgsProcessing::TypeVectorAny; }
|
||||
|
||||
/**
|
||||
* Maps the input WKB geometry type (\a inputWkbType) to the corresponding
|
||||
* output WKB type generated by the algorithm. The default behavior is that the algorithm maintains
|
||||
* the same WKB type.
|
||||
* This is called once by the base class when creating the output sink for the algorithm (i.e. it is
|
||||
* not called once per feature processed).
|
||||
*/
|
||||
virtual QgsWkbTypes::Type outputWkbType( QgsWkbTypes::Type inputWkbType ) const { return inputWkbType; }
|
||||
|
||||
/**
|
||||
* Maps the input source fields (\a inputFields) to corresponding
|
||||
* output fields generated by the algorithm. The default behavior is that the algorithm maintains
|
||||
* the same fields as are input.
|
||||
* Algorithms which add, remove or modify existing fields should override this method and
|
||||
* implement logic here to indicate which fields are output by the algorithm.
|
||||
*
|
||||
* This is called once by the base class when creating the output sink for the algorithm (i.e. it is
|
||||
* not called once per feature processed).
|
||||
*/
|
||||
virtual QgsFields outputFields( const QgsFields &inputFields ) const { return inputFields; }
|
||||
|
||||
/**
|
||||
* Maps the input source coordinate reference system (\a inputCrs) to a corresponding
|
||||
* output CRS generated by the algorithm. The default behavior is that the algorithm maintains
|
||||
* the same CRS as the input source.
|
||||
*
|
||||
* This is called once by the base class when creating the output sink for the algorithm (i.e. it is
|
||||
* not called once per feature processed).
|
||||
*/
|
||||
virtual QgsCoordinateReferenceSystem outputCrs( const QgsCoordinateReferenceSystem &inputCrs ) const { return inputCrs; }
|
||||
|
||||
/**
|
||||
* Initializes any extra parameters added by the algorithm subclass. There is no need
|
||||
* to declare the input source or output sink, as these are automatically created by
|
||||
* QgsProcessingFeatureBasedAlgorithm.
|
||||
*/
|
||||
virtual void initParameters( const QVariantMap &configuration = QVariantMap() ) { Q_UNUSED( configuration ); }
|
||||
|
||||
/**
|
||||
* Returns the source's coordinate reference system. This will only return a valid CRS when
|
||||
* called from a subclasses' processFeature() implementation.
|
||||
*/
|
||||
QgsCoordinateReferenceSystem sourceCrs() const;
|
||||
|
||||
/**
|
||||
* Processes an individual input \a feature from the source. Algorithms should implement their
|
||||
* logic in this method for performing the algorithm's operation (e.g. replacing the feature's
|
||||
* geometry with the centroid of the original feature geometry for a 'centroid' type
|
||||
* algorithm).
|
||||
*
|
||||
* Implementations should return the modified feature. Returning an invalid feature (e.g.
|
||||
* a default constructed QgsFeature) will indicate that this feature should be 'skipped',
|
||||
* and will not be added to the algorithm's output. Subclasses can use this approach to
|
||||
* filter the incoming features as desired.
|
||||
*
|
||||
* The provided \a feedback object can be used to push messages to the log and for giving feedback
|
||||
* to users. Note that handling of progress reports and algorithm cancelation is handled by
|
||||
* the base class and subclasses do not need to reimplement this logic.
|
||||
*
|
||||
* Algorithms can throw a QgsProcessingException if a fatal error occurred which should
|
||||
* prevent the algorithm execution from continuing. This can be annoying for users though as it
|
||||
* can break valid model execution - so use with extreme caution, and consider using
|
||||
* \a feedback to instead report non-fatal processing failures for features instead.
|
||||
*/
|
||||
virtual QgsFeature processFeature( const QgsFeature &feature, QgsProcessingFeedback *feedback ) = 0;
|
||||
|
||||
virtual QVariantMap processAlgorithm( const QVariantMap ¶meters,
|
||||
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
|
||||
private:
|
||||
|
||||
std::unique_ptr< QgsFeatureSource > mSource;
|
||||
|
||||
};
|
||||
|
||||
#endif // QGSPROCESSINGALGORITHM_H
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user