Algorithms don't have to be split to prepare/process/postProcess

Since it's safe to evaluate parameters in background threads
now, it's usually going to be ok to evaluate everything in
the processAlgorithm step.

This keeps the algorithm code as simple as possible, and will
make porting faster.

Note that the prepare/postProcess virtual methods still exist
and can be used when an algorithm MUST do setup/cleanup work
in the main thread.
This commit is contained in:
Nyall Dawson 2017-07-01 12:21:11 +10:00
parent f39b7a0c4c
commit 8a84e134cc
46 changed files with 803 additions and 1339 deletions

View File

@ -259,7 +259,7 @@ class QgsProcessingAlgorithm
:rtype: bool
%End
bool runPrepared( QgsProcessingContext &context, QgsProcessingFeedback *feedback );
QVariantMap runPrepared( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback );
%Docstring
Runs the algorithm, which has been prepared by an earlier call to prepare().
This method is safe to call from any thread. Returns true if the algorithm was successfully executed.
@ -272,7 +272,7 @@ class QgsProcessingAlgorithm
This method modifies the algorithm instance, so it is not safe to call
on algorithms directly retrieved from QgsProcessingRegistry and QgsProcessingProvider. Instead, a copy
of the algorithm should be created with clone() and prepare()/runPrepared() called on the copy.
:rtype: bool
:rtype: QVariantMap
%End
QVariantMap postProcess( QgsProcessingContext &context, QgsProcessingFeedback *feedback );
@ -374,7 +374,7 @@ class QgsProcessingAlgorithm
:rtype: bool
%End
virtual bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) = 0 /VirtualErrorHandler=processing_exception_handler/;
virtual QVariantMap processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) = 0 /VirtualErrorHandler=processing_exception_handler/;
%Docstring
Runs the algorithm using the specified ``parameters``. Algorithms should implement
their custom processing logic here.
@ -389,10 +389,10 @@ class QgsProcessingAlgorithm
values such as statistical calculations.
.. seealso:: prepareAlgorithm()
.. seealso:: postProcessAlgorithm()
:rtype: bool
:rtype: QVariantMap
%End
virtual QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) = 0 /VirtualErrorHandler=processing_exception_handler/;
virtual QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) /VirtualErrorHandler=processing_exception_handler/;
%Docstring
Allows the algorithm to perform any required cleanup tasks. The returned variant map
includes the results evaluated by the algorithm. These may be output layer references, or calculated

View File

@ -835,11 +835,7 @@ Copies are protected to avoid slicing
protected:
virtual bool prepareAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback );
virtual bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback );
virtual QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback );
virtual QVariantMap processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback );
};

View File

@ -74,38 +74,28 @@ class AddTableField(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, self.tr('Added')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT_LAYER, self.tr('Added')))
self.source = None
self.fieldType = None
self.fieldLength = None
self.fieldName = None
self.fieldPrecision = None
self.sink = None
self.dest_id = None
def name(self):
return 'addfieldtoattributestable'
def displayName(self):
return self.tr('Add field to attributes table')
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
self.fieldType = self.parameterAsEnum(parameters, self.FIELD_TYPE, context)
self.fieldName = self.parameterAsString(parameters, self.FIELD_NAME, context)
self.fieldLength = self.parameterAsInt(parameters, self.FIELD_LENGTH, context)
self.fieldPrecision = self.parameterAsInt(parameters, self.FIELD_PRECISION, context)
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)
fields = self.source.fields()
fields.append(QgsField(self.fieldName, self.TYPES[self.fieldType], '',
self.fieldLength, self.fieldPrecision))
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context,
fields, self.source.wkbType(), self.source.sourceCrs())
return True
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())
def processAlgorithm(self, context, feedback):
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, input_feature in enumerate(features):
if feedback.isCanceled():
@ -116,10 +106,7 @@ class AddTableField(QgisAlgorithm):
attributes.append(None)
output_feature.setAttributes(attributes)
self.sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT_LAYER: self.dest_id}
return {self.OUTPUT_LAYER: dest_id}

View File

@ -68,30 +68,22 @@ class Aspect(QgisAlgorithm):
self.addParameter(QgsProcessingParameterRasterOutput(self.OUTPUT, self.tr('Aspect')))
self.addOutput(QgsProcessingOutputRasterLayer(self.OUTPUT, self.tr('Aspect')))
self.inputFile = None
self.outputFile = None
self.outputFormat = None
self.zFactor = None
def name(self):
return 'aspect'
def displayName(self):
return self.tr('Aspect')
def prepareAlgorithm(self, parameters, context, feedback):
self.inputFile = exportRasterLayer(self.parameterAsRasterLayer(parameters, self.INPUT, context))
self.zFactor = self.parameterAsDouble(parameters, self.Z_FACTOR, context)
def processAlgorithm(self, parameters, context, feedback):
inputFile = exportRasterLayer(self.parameterAsRasterLayer(parameters, self.INPUT, context))
zFactor = self.parameterAsDouble(parameters, self.Z_FACTOR, context)
self.outputFile = self.parameterAsRasterOutputLayer(parameters, self.OUTPUT, context)
outputFile = self.parameterAsRasterOutputLayer(parameters, self.OUTPUT, context)
self.outputFormat = raster.formatShortNameFromFileName(self.outputFile)
return True
outputFormat = raster.formatShortNameFromFileName(outputFile)
def processAlgorithm(self, context, feedback):
aspect = QgsAspectFilter(self.inputFile, self.outputFile, self.outputFormat)
aspect.setZFactor(self.zFactor)
return aspect.processRaster(feedback) == 0
aspect = QgsAspectFilter(inputFile, outputFile, outputFormat)
aspect.setZFactor(zFactor)
aspect.processRaster(feedback)
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.outputFile}
return {self.OUTPUT: outputFile}

View File

@ -51,10 +51,6 @@ class AutoincrementalField(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Incremented')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Incremented')))
self.source = None
self.sink = None
self.dest_id = None
def group(self):
return self.tr('Vector table tools')
@ -64,18 +60,16 @@ class AutoincrementalField(QgisAlgorithm):
def displayName(self):
return self.tr('Add autoincremental field')
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context)
fields = self.source.fields()
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
fields = source.fields()
fields.append(QgsField('AUTO', QVariant.Int))
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, self.source.wkbType(), self.source.sourceCrs())
return True
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, source.wkbType(), source.sourceCrs())
def processAlgorithm(self, context, feedback):
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, input_feature in enumerate(features):
if feedback.isCanceled():
break
@ -85,9 +79,7 @@ class AutoincrementalField(QgisAlgorithm):
attributes.append(current)
output_feature.setAttributes(attributes)
self.sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}
return {self.OUTPUT: dest_id}

View File

@ -119,52 +119,42 @@ class BasicStatisticsForField(QgisAlgorithm):
self.addOutput(QgsProcessingOutputNumber(self.THIRDQUARTILE, self.tr('Third quartile')))
self.addOutput(QgsProcessingOutputNumber(self.IQR, self.tr('Interquartile Range (IQR)')))
self.source = None
self.field = None
self.field_name = None
self.output_file = None
self.results = {}
def name(self):
return 'basicstatisticsforfields'
def displayName(self):
return self.tr('Basic statistics for fields')
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
self.field_name = self.parameterAsString(parameters, self.FIELD_NAME, context)
self.field = self.source.fields().at(self.source.fields().lookupField(self.field_name))
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
field_name = self.parameterAsString(parameters, self.FIELD_NAME, context)
field = source.fields().at(source.fields().lookupField(field_name))
self.output_file = self.parameterAsFileOutput(parameters, self.OUTPUT_HTML_FILE, context)
return True
output_file = self.parameterAsFileOutput(parameters, self.OUTPUT_HTML_FILE, context)
def processAlgorithm(self, context, feedback):
request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry).setSubsetOfAttributes([self.field_name], self.source.fields())
features = self.source.getFeatures(request)
count = self.source.featureCount()
request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry).setSubsetOfAttributes([field_name], source.fields())
features = source.getFeatures(request)
count = source.featureCount()
data = []
data.append(self.tr('Analyzed field: {}').format(self.field_name))
data.append(self.tr('Analyzed field: {}').format(field_name))
results = {}
if self.field.isNumeric():
d, self.results = self.calcNumericStats(features, feedback, self.field, count)
if field.isNumeric():
d, results = self.calcNumericStats(features, feedback, field, count)
data.extend(d)
elif self.field.type() in (QVariant.Date, QVariant.Time, QVariant.DateTime):
d, self.results = self.calcDateTimeStats(features, feedback, self.field, count)
elif field.type() in (QVariant.Date, QVariant.Time, QVariant.DateTime):
d, results = self.calcDateTimeStats(features, feedback, field, count)
data.extend(d)
else:
d, self.results = self.calcStringStats(features, feedback, self.field, count)
d, results = self.calcStringStats(features, feedback, field, count)
data.extend(d)
if self.output_file:
self.createHTML(self.output_file, data)
self.results[self.OUTPUT_HTML_FILE] = self.output_file
if output_file:
self.createHTML(output_file, data)
results[self.OUTPUT_HTML_FILE] = output_file
return True
def postProcessAlgorithm(self, context, feedback):
return self.results
return results
def calcNumericStats(self, features, feedback, field, count):
total = 100.0 / count if count else 0

View File

@ -58,10 +58,6 @@ class Boundary(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, self.tr('Boundary')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT_LAYER, self.tr("Boundaries")))
self.source = None
self.sink = None
self.dest_id = None
def icon(self):
return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'convex_hull.png'))
@ -74,11 +70,10 @@ class Boundary(QgisAlgorithm):
def displayName(self):
return self.tr('Boundary')
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
input_wkb = self.source.wkbType()
output_wkb = None
input_wkb = source.wkbType()
if QgsWkbTypes.geometryType(input_wkb) == QgsWkbTypes.LineGeometry:
output_wkb = QgsWkbTypes.MultiPoint
elif QgsWkbTypes.geometryType(input_wkb) == QgsWkbTypes.PolygonGeometry:
@ -88,13 +83,11 @@ class Boundary(QgisAlgorithm):
if QgsWkbTypes.hasM(input_wkb):
output_wkb = QgsWkbTypes.addM(output_wkb)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context,
self.source.fields(), output_wkb, self.source.sourceCrs())
return True
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context,
source.fields(), output_wkb, source.sourceCrs())
def processAlgorithm(self, context, feedback):
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, input_feature in enumerate(features):
if feedback.isCanceled():
@ -109,9 +102,7 @@ class Boundary(QgisAlgorithm):
output_feature.setGeometry(output_geometry)
self.sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT_LAYER: self.dest_id}
return {self.OUTPUT_LAYER: dest_id}

View File

@ -66,26 +66,20 @@ class BoundingBox(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_LAYER, self.tr('Bounds'), QgsProcessingParameterDefinition.TypeVectorPolygon))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT_LAYER, self.tr("Bounds")))
self.source = None
self.sink = None
self.dest_id = None
def name(self):
return 'boundingboxes'
def displayName(self):
return self.tr('Bounding boxes')
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context,
self.source.fields(), QgsWkbTypes.Polygon, self.source.sourceCrs())
return True
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context,
source.fields(), QgsWkbTypes.Polygon, source.sourceCrs())
def processAlgorithm(self, context, feedback):
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, input_feature in enumerate(features):
if feedback.isCanceled():
@ -100,9 +94,7 @@ class BoundingBox(QgisAlgorithm):
output_feature.setGeometry(output_geometry)
self.sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT_LAYER: self.dest_id}
return {self.OUTPUT_LAYER: dest_id}

View File

@ -93,60 +93,46 @@ class CheckValidity(QgisAlgorithm):
self.addOutput(QgsProcessingOutputVectorLayer(self.ERROR_OUTPUT, self.tr('Error output')))
self.addOutput(QgsProcessingOutputNumber(self.ERROR_COUNT, self.tr('Count of errors')))
self.method = None
self.source = None
self.valid_output_sink = None
self.valid_output_dest_id = None
self.valid_count = 0
self.invalid_output_sink = None
self.invalid_output_dest_id = None
self.invalid_count = 0
self.error_output_sink = None
self.error_output_dest_id = None
self.error_count = 0
def name(self):
return 'checkvalidity'
def displayName(self):
return self.tr('Check validity')
def prepareAlgorithm(self, parameters, context, feedback):
def processAlgorithm(self, parameters, context, feedback):
method_param = self.parameterAsEnum(parameters, self.METHOD, context)
if method_param == 0:
settings = QgsSettings()
self.method = int(settings.value(settings_method_key, 0)) - 1
if self.method < 0:
self.method = 0
method = int(settings.value(settings_method_key, 0)) - 1
if method < 0:
method = 0
else:
self.method = method_param - 1
method = method_param - 1
self.source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
results = self.doCheck(method, parameters, context, feedback)
return results
(self.valid_output_sink, self.valid_output_dest_id) = self.parameterAsSink(parameters, self.VALID_OUTPUT,
context,
self.source.fields(),
self.source.wkbType(),
self.source.sourceCrs())
def doCheck(self, method, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
invalid_fields = self.source.fields()
(valid_output_sink, valid_output_dest_id) = self.parameterAsSink(parameters, self.VALID_OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
valid_count = 0
invalid_fields = source.fields()
invalid_fields.append(QgsField('_errors', QVariant.String, 'string', 255))
(self.invalid_output_sink, self.invalid_output_dest_id) = self.parameterAsSink(parameters, self.INVALID_OUTPUT,
context,
invalid_fields,
self.source.wkbType(),
self.source.sourceCrs())
(invalid_output_sink, invalid_output_dest_id) = self.parameterAsSink(parameters, self.INVALID_OUTPUT, context,
invalid_fields, source.wkbType(), source.sourceCrs())
invalid_count = 0
error_fields = QgsFields()
error_fields.append(QgsField('message', QVariant.String, 'string', 255))
(self.error_output_sink, self.error_output_dest_id) = self.parameterAsSink(parameters, self.ERROR_OUTPUT, context,
error_fields, QgsWkbTypes.Point,
self.source.sourceCrs())
return True
(error_output_sink, error_output_dest_id) = self.parameterAsSink(parameters, self.ERROR_OUTPUT, context,
error_fields, QgsWkbTypes.Point, source.sourceCrs())
error_count = 0
def processAlgorithm(self, context, feedback):
features = self.source.getFeatures(QgsFeatureRequest(), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks)
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
features = source.getFeatures(QgsFeatureRequest(), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks)
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, inFeat in enumerate(features):
if feedback.isCanceled():
break
@ -155,10 +141,10 @@ class CheckValidity(QgisAlgorithm):
valid = True
if not geom.isNull() and not geom.isEmpty():
errors = list(geom.validateGeometry(self.method))
errors = list(geom.validateGeometry(method))
if errors:
# QGIS method return a summary at the end
if self.method == 1:
if method == 1:
errors.pop()
valid = False
reasons = []
@ -167,9 +153,9 @@ class CheckValidity(QgisAlgorithm):
error_geom = QgsGeometry.fromPoint(error.where())
errFeat.setGeometry(error_geom)
errFeat.setAttributes([error.what()])
if self.error_output_sink:
self.error_output_sink.addFeature(errFeat, QgsFeatureSink.FastInsert)
self.error_count += 1
if error_output_sink:
error_output_sink.addFeature(errFeat, QgsFeatureSink.FastInsert)
error_count += 1
reasons.append(error.what())
@ -183,28 +169,26 @@ class CheckValidity(QgisAlgorithm):
outFeat.setAttributes(attrs)
if valid:
if self.valid_output_sink:
self.valid_output_sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
self.valid_count += 1
if valid_output_sink:
valid_output_sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
valid_count += 1
else:
if self.invalid_output_sink:
self.invalid_output_sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
self.invalid_count += 1
if invalid_output_sink:
invalid_output_sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
invalid_count += 1
feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback):
results = {
self.VALID_COUNT: self.valid_count,
self.INVALID_COUNT: self.invalid_count,
self.ERROR_COUNT: self.error_count
self.VALID_COUNT: valid_count,
self.INVALID_COUNT: invalid_count,
self.ERROR_COUNT: error_count
}
if self.valid_output_sink:
results[self.VALID_OUTPUT] = self.valid_output_dest_id
if self.invalid_output_sink:
results[self.INVALID_OUTPUT] = self.invalid_output_dest_id
if self.error_output_sink:
results[self.ERROR_OUTPUT] = self.error_output_dest_id
if valid_output_sink:
results[self.VALID_OUTPUT] = valid_output_dest_id
if invalid_output_sink:
results[self.INVALID_OUTPUT] = invalid_output_dest_id
if error_output_sink:
results[self.ERROR_OUTPUT] = error_output_dest_id
return results

View File

@ -53,35 +53,27 @@ class CreateAttributeIndex(QgisAlgorithm):
self.tr('Attribute to index'), None, self.INPUT))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Indexed layer')))
self.layer = None
self.field = None
def name(self):
return 'createattributeindex'
def displayName(self):
return self.tr('Create attribute index')
def prepareAlgorithm(self, parameters, context, feedback):
self.layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
self.field = self.parameterAsString(parameters, self.FIELD, context)
return True
def processAlgorithm(self, parameters, context, feedback):
layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
field = self.parameterAsString(parameters, self.FIELD, context)
provider = layer.dataProvider()
def processAlgorithm(self, context, feedback):
provider = self.layer.dataProvider()
field_index = self.layer.fields().lookupField(self.field)
if field_index < 0 or self.layer.fields().fieldOrigin(field_index) != QgsFields.OriginProvider:
feedback.pushInfo(self.tr('Can not create attribute index on "{}"').format(self.field))
field_index = layer.fields().lookupField(field)
if field_index < 0 or layer.fields().fieldOrigin(field_index) != QgsFields.OriginProvider:
feedback.pushInfo(self.tr('Can not create attribute index on "{}"').format(field))
else:
provider_index = self.layer.fields().fieldOriginIndex(field_index)
provider_index = layer.fields().fieldOriginIndex(field_index)
if provider.capabilities() & QgsVectorDataProvider.CreateAttributeIndex:
if not provider.createAttributeIndex(provider_index):
feedback.pushInfo(self.tr('Could not create attribute index'))
else:
feedback.pushInfo(self.tr("Layer's data provider does not support "
"creating attribute indexes"))
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.layer.id()}
return {self.OUTPUT: layer.id()}

View File

@ -58,56 +58,46 @@ class DeleteColumn(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Output layer')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Output layer")))
self.source = None
self.fields_to_delete = None
self.sink = None
self.dest_id = None
self.field_indices = []
def name(self):
return 'deletecolumn'
def displayName(self):
return self.tr('Drop field(s)')
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context)
self.fields_to_delete = self.parameterAsFields(parameters, self.COLUMNS, context)
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
fields_to_delete = self.parameterAsFields(parameters, self.COLUMNS, context)
fields = self.source.fields()
fields = source.fields()
field_indices = []
# loop through twice - first we need to build up a list of original attribute indices
for f in self.fields_to_delete:
for f in fields_to_delete:
index = fields.lookupField(f)
self.field_indices.append(index)
field_indices.append(index)
# important - make sure we remove from the end so we aren't changing used indices as we go
self.field_indices.sort(reverse=True)
field_indices.sort(reverse=True)
# this second time we make a cleaned version of the fields
for index in self.field_indices:
for index in field_indices:
fields.remove(index)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, self.source.wkbType(), self.source.sourceCrs())
return True
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, source.wkbType(), source.sourceCrs())
def processAlgorithm(self, context, feedback):
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, f in enumerate(features):
if feedback.isCanceled():
break
attributes = f.attributes()
for index in self.field_indices:
for index in field_indices:
del attributes[index]
f.setAttributes(attributes)
self.sink.addFeature(f, QgsFeatureSink.FastInsert)
sink.addFeature(f, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}
return {self.OUTPUT: dest_id}

View File

@ -58,40 +58,31 @@ class DeleteHoles(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Cleaned'), QgsProcessingParameterDefinition.TypeVectorPolygon))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Cleaned'), QgsProcessingParameterDefinition.TypeVectorPolygon))
self.source = None
self.min_area = None
self.sink = None
self.dest_id = None
def name(self):
return 'deleteholes'
def displayName(self):
return self.tr('Delete holes')
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context)
self.min_area = self.parameterAsDouble(parameters, self.MIN_AREA, context)
if self.min_area == 0.0:
self.min_area = -1.0
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
min_area = self.parameterAsDouble(parameters, self.MIN_AREA, context)
if min_area == 0.0:
min_area = -1.0
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), self.source.wkbType(), self.source.sourceCrs())
return True
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
def processAlgorithm(self, context, feedback):
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, f in enumerate(features):
if feedback.isCanceled():
break
if f.hasGeometry():
f.setGeometry(f.geometry().removeInteriorRings(self.min_area))
self.sink.addFeature(f, QgsFeatureSink.FastInsert)
f.setGeometry(f.geometry().removeInteriorRings(min_area))
sink.addFeature(f, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}
return {self.OUTPUT: dest_id}

View File

@ -63,28 +63,21 @@ class DensifyGeometries(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Densified')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Densified')))
self.source = None
self.sink = None
self.vertices = None
self.dest_id = None
def name(self):
return 'densifygeometries'
def displayName(self):
return self.tr('Densify geometries')
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context)
self.vertices = self.parameterAsInt(parameters, self.VERTICES, context)
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
vertices = self.parameterAsInt(parameters, self.VERTICES, context)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), self.source.wkbType(), self.source.sourceCrs())
return True
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
def processAlgorithm(self, context, feedback):
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, f in enumerate(features):
if feedback.isCanceled():
@ -92,11 +85,9 @@ class DensifyGeometries(QgisAlgorithm):
feature = f
if feature.hasGeometry():
new_geometry = feature.geometry().densifyByCount(self.vertices)
new_geometry = feature.geometry().densifyByCount(vertices)
feature.setGeometry(new_geometry)
self.sink.addFeature(feature, QgsFeatureSink.FastInsert)
sink.addFeature(feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}
return {self.OUTPUT: dest_id}

View File

@ -61,40 +61,31 @@ class DensifyGeometriesInterval(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Densified')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Densified')))
self.source = None
self.interval = None
self.sink = None
self.dest_id = None
def name(self):
return 'densifygeometriesgivenaninterval'
def displayName(self):
return self.tr('Densify geometries given an interval')
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context)
self.interval = self.parameterAsDouble(parameters, self.INTERVAL, context)
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
interval = self.parameterAsDouble(parameters, self.INTERVAL, context)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), self.source.wkbType(), self.source.sourceCrs())
return True
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
def processAlgorithm(self, context, feedback):
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, f in enumerate(features):
if feedback.isCanceled():
break
feature = f
if feature.hasGeometry():
new_geometry = feature.geometry().densifyByDistance(float(self.interval))
new_geometry = feature.geometry().densifyByDistance(float(interval))
feature.setGeometry(new_geometry)
self.sink.addFeature(feature, QgsFeatureSink.FastInsert)
sink.addFeature(feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}
return {self.OUTPUT: dest_id}

View File

@ -55,36 +55,27 @@ class DropGeometry(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Dropped geometry')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Dropped geometry")))
self.source = None
self.sink = None
self.dest_id = None
def name(self):
return 'dropgeometries'
def displayName(self):
return self.tr('Drop geometries')
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem())
return True
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem())
def processAlgorithm(self, context, feedback):
request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry)
features = self.source.getFeatures(request)
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
features = source.getFeatures(request)
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, input_feature in enumerate(features):
if feedback.isCanceled():
break
input_feature.clearGeometry()
self.sink.addFeature(input_feature, QgsFeatureSink.FastInsert)
sink.addFeature(input_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}
return {self.OUTPUT: dest_id}

View File

@ -79,20 +79,15 @@ class ExtentFromLayer(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Extent')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Extent"), QgsProcessingParameterDefinition.TypeVectorPolygon))
self.source = None
self.byFeature = None
self.sink = None
self.dest_id = None
def name(self):
return 'polygonfromlayerextent'
def displayName(self):
return self.tr('Polygon from layer extent')
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
self.byFeature = self.parameterAsBool(parameters, self.BY_FEATURE, context)
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
byFeature = self.parameterAsBool(parameters, self.BY_FEATURE, context)
fields = QgsFields()
fields.append(QgsField('MINX', QVariant.Double))
@ -106,19 +101,15 @@ class ExtentFromLayer(QgisAlgorithm):
fields.append(QgsField('HEIGHT', QVariant.Double))
fields.append(QgsField('WIDTH', QVariant.Double))
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.Polygon, self.source.sourceCrs())
return True
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.Polygon, source.sourceCrs())
def processAlgorithm(self, context, feedback):
if self.byFeature:
self.featureExtent(self.source, context, self.sink, feedback)
if byFeature:
self.featureExtent(source, context, sink, feedback)
else:
self.layerExtent(self.source, self.sink, feedback)
return True
self.layerExtent(source, sink, feedback)
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}
return {self.OUTPUT: dest_id}
def layerExtent(self, source, sink, feedback):
rect = source.sourceExtent()

View File

@ -55,26 +55,20 @@ class FixGeometry(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Fixed geometries')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Fixed geometries")))
self.source = None
self.sink = None
self.dest_id = None
def name(self):
return 'fixgeometries'
def displayName(self):
return self.tr('Fix geometries')
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context)
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), QgsWkbTypes.multiType(self.source.wkbType()), self.source.sourceCrs())
return True
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), QgsWkbTypes.multiType(source.wkbType()), source.sourceCrs())
def processAlgorithm(self, context, feedback):
features = self.source.getFeatures(QgsFeatureRequest(), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks)
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
features = source.getFeatures(QgsFeatureRequest(), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks)
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, inputFeature in enumerate(features):
if feedback.isCanceled():
break
@ -92,7 +86,7 @@ class FixGeometry(QgisAlgorithm):
try:
g.convertToMultiType()
outputFeature.setGeometry(QgsGeometry(g))
self.sink.addFeature(outputFeature, QgsFeatureSink.FastInsert)
sink.addFeature(outputFeature, QgsFeatureSink.FastInsert)
except:
pass
feedback.setProgress(int(current * total))
@ -101,9 +95,7 @@ class FixGeometry(QgisAlgorithm):
outputGeometry.convertToMultiType()
outputFeature.setGeometry(outputGeometry)
self.sink.addFeature(outputFeature, QgsFeatureSink.FastInsert)
sink.addFeature(outputFeature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}
return {self.OUTPUT: dest_id}

View File

@ -102,52 +102,41 @@ class GridPolygon(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Grid')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Grid'), QgsProcessingParameterDefinition.TypeVectorPolygon))
self.idx = None
self.hSpacing = None
self.vSpacing = None
self.hOverlay = None
self.vOverlay = None
self.width = None
self.height = None
self.originX = None
self.originY = None
self.sink = None
self.dest_id = None
def name(self):
return 'creategridpolygon'
def displayName(self):
return self.tr('Create grid (polygon)')
def prepareAlgorithm(self, parameters, context, feedback):
self.idx = self.parameterAsEnum(parameters, self.TYPE, context)
def processAlgorithm(self, parameters, context, feedback):
idx = self.parameterAsEnum(parameters, self.TYPE, context)
self.hSpacing = self.parameterAsDouble(parameters, self.HSPACING, context)
self.vSpacing = self.parameterAsDouble(parameters, self.VSPACING, context)
self.hOverlay = self.parameterAsDouble(parameters, self.HOVERLAY, context)
self.vOverlay = self.parameterAsDouble(parameters, self.VOVERLAY, context)
hSpacing = self.parameterAsDouble(parameters, self.HSPACING, context)
vSpacing = self.parameterAsDouble(parameters, self.VSPACING, context)
hOverlay = self.parameterAsDouble(parameters, self.HOVERLAY, context)
vOverlay = self.parameterAsDouble(parameters, self.VOVERLAY, context)
bbox = self.parameterAsExtent(parameters, self.EXTENT, context)
crs = self.parameterAsCrs(parameters, self.CRS, context)
self.width = bbox.width()
self.height = bbox.height()
self.originX = bbox.xMinimum()
self.originY = bbox.yMaximum()
if self.hSpacing <= 0 or self.vSpacing <= 0:
width = bbox.width()
height = bbox.height()
originX = bbox.xMinimum()
originY = bbox.yMaximum()
if hSpacing <= 0 or vSpacing <= 0:
raise GeoAlgorithmExecutionException(
self.tr('Invalid grid spacing: {0}/{1}').format(self.hSpacing, self.vSpacing))
self.tr('Invalid grid spacing: {0}/{1}').format(hSpacing, vSpacing))
if self.width < self.hSpacing:
if width < hSpacing:
raise GeoAlgorithmExecutionException(
self.tr('Horizontal spacing is too small for the covered area'))
if self.hSpacing <= self.hOverlay or self.vSpacing <= self.vOverlay:
if hSpacing <= hOverlay or vSpacing <= vOverlay:
raise GeoAlgorithmExecutionException(
self.tr('Invalid overlay: {0}/{1}').format(self.hOverlay, self.vOverlay))
self.tr('Invalid overlay: {0}/{1}').format(hOverlay, vOverlay))
if self.height < self.vSpacing:
if height < vSpacing:
raise GeoAlgorithmExecutionException(
self.tr('Vertical spacing is too small for the covered area'))
@ -158,24 +147,20 @@ class GridPolygon(QgisAlgorithm):
fields.append(QgsField('bottom', QVariant.Double, '', 24, 16))
fields.append(QgsField('id', QVariant.Int, '', 10, 0))
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.Polygon, crs)
return True
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.Polygon, crs)
def processAlgorithm(self, context, feedback):
if self.idx == 0:
if idx == 0:
self._rectangleGrid(
self.sink, self.width, self.height, self.originX, self.originY, self.hSpacing, self.vSpacing, self.hOverlay, self.vOverlay, feedback)
elif self.idx == 1:
sink, width, height, originX, originY, hSpacing, vSpacing, hOverlay, vOverlay, feedback)
elif idx == 1:
self._diamondGrid(
self.sink, self.width, self.height, self.originX, self.originY, self.hSpacing, self.vSpacing, self.hOverlay, self.vOverlay, feedback)
elif self.idx == 2:
sink, width, height, originX, originY, hSpacing, vSpacing, hOverlay, vOverlay, feedback)
elif idx == 2:
self._hexagonGrid(
self.sink, self.width, self.height, self.originX, self.originY, self.hSpacing, self.vSpacing, self.hOverlay, self.vOverlay, feedback)
return True
sink, width, height, originX, originY, hSpacing, vSpacing, hOverlay, vOverlay, feedback)
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}
return {self.OUTPUT: dest_id}
def _rectangleGrid(self, sink, width, height, originX, originY,
hSpacing, vSpacing, hOverlay, vOverlay, feedback):

View File

@ -27,7 +27,9 @@ __revision__ = '$Format:%H$'
from qgis.core import (QgsVectorLayerExporter,
QgsSettings,
QgsApplication,
QgsFeatureSink,
QgsProcessingUtils,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterString,
QgsProcessingParameterField,
@ -106,86 +108,70 @@ class ImportIntoPostGIS(QgisAlgorithm):
self.addParameter(QgsProcessingParameterBoolean(self.FORCE_SINGLEPART,
self.tr('Create single-part geometries instead of multi-part'), False))
self.db = None
self.schema = None
self.overwrite = None
self.createIndex = None
self.convertLowerCase = None
self.dropStringLength = None
self.forceSinglePart = None
self.primaryKeyField = None
self.encoding = None
self.source = None
self.table = None
self.providerName = None
self.geomColumn = None
def name(self):
return 'importintopostgis'
def displayName(self):
return self.tr('Import into PostGIS')
def prepareAlgorithm(self, parameters, context, feedback):
def processAlgorithm(self, parameters, context, feedback):
connection = self.parameterAsString(parameters, self.DATABASE, context)
self.db = postgis.GeoDB.from_name(connection)
db = postgis.GeoDB.from_name(connection)
self.schema = self.parameterAsString(parameters, self.SCHEMA, context)
self.overwrite = self.parameterAsBool(parameters, self.OVERWRITE, context)
self.createIndex = self.parameterAsBool(parameters, self.CREATEINDEX, context)
self.convertLowerCase = self.parameterAsBool(parameters, self.LOWERCASE_NAMES, context)
self.dropStringLength = self.parameterAsBool(parameters, self.DROP_STRING_LENGTH, context)
self.forceSinglePart = self.parameterAsBool(parameters, self.FORCE_SINGLEPART, context)
self.primaryKeyField = self.parameterAsString(parameters, self.PRIMARY_KEY, context) or 'id'
self.encoding = self.parameterAsString(parameters, self.ENCODING, context)
schema = self.parameterAsString(parameters, self.SCHEMA, context)
overwrite = self.parameterAsBool(parameters, self.OVERWRITE, context)
createIndex = self.parameterAsBool(parameters, self.CREATEINDEX, context)
convertLowerCase = self.parameterAsBool(parameters, self.LOWERCASE_NAMES, context)
dropStringLength = self.parameterAsBool(parameters, self.DROP_STRING_LENGTH, context)
forceSinglePart = self.parameterAsBool(parameters, self.FORCE_SINGLEPART, context)
primaryKeyField = self.parameterAsString(parameters, self.PRIMARY_KEY, context) or 'id'
encoding = self.parameterAsString(parameters, self.ENCODING, context)
self.source = self.parameterAsSource(parameters, self.INPUT, context)
source = self.parameterAsSource(parameters, self.INPUT, context)
self.table = self.parameterAsString(parameters, self.TABLENAME, context)
if self.table:
self.table.strip()
if not self.table or self.table == '':
self.table = self.source.sourceName()
self.table = self.table.replace('.', '_')
self.table = self.table.replace(' ', '').lower()[0:62]
self.providerName = 'postgres'
table = self.parameterAsString(parameters, self.TABLENAME, context)
if table:
table.strip()
if not table or table == '':
table = source.sourceName()
table = table.replace('.', '_')
table = table.replace(' ', '').lower()[0:62]
providerName = 'postgres'
self.geomColumn = self.parameterAsString(parameters, self.GEOMETRY_COLUMN, context)
if not self.geomColumn:
self.geomColumn = 'geom'
return True
geomColumn = self.parameterAsString(parameters, self.GEOMETRY_COLUMN, context)
if not geomColumn:
geomColumn = 'geom'
def processAlgorithm(self, context, feedback):
options = {}
if self.overwrite:
if overwrite:
options['overwrite'] = True
if self.convertLowerCase:
if convertLowerCase:
options['lowercaseFieldNames'] = True
self.geomColumn = self.geomColumn.lower()
if self.dropStringLength:
geomColumn = geomColumn.lower()
if dropStringLength:
options['dropStringConstraints'] = True
if self.forceSinglePart:
if forceSinglePart:
options['forceSinglePartGeometryType'] = True
# Clear geometry column for non-geometry tables
if self.source.wkbType() == QgsWkbTypes.NoGeometry:
self.geomColumn = None
if source.wkbType() == QgsWkbTypes.NoGeometry:
geomColumn = None
uri = self.db.uri
uri.setDataSource(self.schema, self.table, self.geomColumn, '', self.primaryKeyField)
uri = db.uri
uri.setDataSource(schema, table, geomColumn, '', primaryKeyField)
if self.encoding:
options['fileEncoding'] = self.encoding
if encoding:
options['fileEncoding'] = encoding
exporter = QgsVectorLayerExporter(uri.uri(), self.providerName, self.source.fields(),
self.source.wkbType(), self.source.sourceCrs(), self.overwrite, options)
exporter = QgsVectorLayerExporter(uri.uri(), providerName, source.fields(),
source.wkbType(), source.sourceCrs(), overwrite, options)
if exporter.errorCode() != QgsVectorLayerExporter.NoError:
raise GeoAlgorithmExecutionException(
self.tr('Error importing to PostGIS\n{0}').format(exporter.errorMessage()))
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, f in enumerate(features):
if feedback.isCanceled():
break
@ -200,13 +186,11 @@ class ImportIntoPostGIS(QgisAlgorithm):
raise GeoAlgorithmExecutionException(
self.tr('Error importing to PostGIS\n{0}').format(exporter.errorMessage()))
if self.geomColumn and self.createIndex:
self.db.create_spatial_index(self.table, self.schema, self.geomColumn)
if geomColumn and createIndex:
db.create_spatial_index(table, schema, geomColumn)
self.db.vacuum_analyze(self.table, self.schema)
return True
db.vacuum_analyze(table, schema)
def postProcessAlgorithm(self, context, feedback):
return {}
def dbConnectionNames(self):

View File

@ -71,26 +71,13 @@ class ImportIntoSpatialite(QgisAlgorithm):
self.addParameter(QgsProcessingParameterBoolean(self.DROP_STRING_LENGTH, self.tr('Drop length constraints on character fields'), False))
self.addParameter(QgsProcessingParameterBoolean(self.FORCE_SINGLEPART, self.tr('Create single-part geometries instead of multi-part'), False))
self.db = None
self.overwrite = None
self.createIndex = None
self.dropStringLength = None
self.convertLowerCase = None
self.forceSinglePart = None
self.primaryKeyField = None
self.encoding = None
self.source = None
self.table = None
self.providerName = None
self.geomColumn = None
def name(self):
return 'importintospatialite'
def displayName(self):
return self.tr('Import into Spatialite')
def prepareAlgorithm(self, parameters, context, feedback):
def processAlgorithm(self, parameters, context, feedback):
database = self.parameterAsVectorLayer(parameters, self.DATABASE, context)
databaseuri = database.dataProvider().dataSourceUri()
uri = QgsDataSourceUri(databaseuri)
@ -98,64 +85,61 @@ class ImportIntoSpatialite(QgisAlgorithm):
if '|layerid' in databaseuri:
databaseuri = databaseuri[:databaseuri.find('|layerid')]
uri = QgsDataSourceUri('dbname=\'%s\'' % (databaseuri))
self.db = spatialite.GeoDB(uri)
db = spatialite.GeoDB(uri)
self.overwrite = self.parameterAsBool(parameters, self.OVERWRITE, context)
self.createIndex = self.parameterAsBool(parameters, self.CREATEINDEX, context)
self.convertLowerCase = self.parameterAsBool(parameters, self.LOWERCASE_NAMES, context)
self.dropStringLength = self.parameterAsBool(parameters, self.DROP_STRING_LENGTH, context)
self.forceSinglePart = self.parameterAsBool(parameters, self.FORCE_SINGLEPART, context)
self.primaryKeyField = self.parameterAsString(parameters, self.PRIMARY_KEY, context) or 'id'
self.encoding = self.parameterAsString(parameters, self.ENCODING, context)
overwrite = self.parameterAsBool(parameters, self.OVERWRITE, context)
createIndex = self.parameterAsBool(parameters, self.CREATEINDEX, context)
convertLowerCase = self.parameterAsBool(parameters, self.LOWERCASE_NAMES, context)
dropStringLength = self.parameterAsBool(parameters, self.DROP_STRING_LENGTH, context)
forceSinglePart = self.parameterAsBool(parameters, self.FORCE_SINGLEPART, context)
primaryKeyField = self.parameterAsString(parameters, self.PRIMARY_KEY, context) or 'id'
encoding = self.parameterAsString(parameters, self.ENCODING, context)
self.source = self.parameterAsSource(parameters, self.INPUT, context)
source = self.parameterAsSource(parameters, self.INPUT, context)
self.table = self.parameterAsString(parameters, self.TABLENAME, context)
if self.table:
self.table.strip()
if not self.table or self.table == '':
self.table = self.source.sourceName()
self.table = self.table.replace('.', '_')
self.table = self.table.replace(' ', '').lower()
self.providerName = 'spatialite'
table = self.parameterAsString(parameters, self.TABLENAME, context)
if table:
table.strip()
if not table or table == '':
table = source.sourceName()
table = table.replace('.', '_')
table = table.replace(' ', '').lower()
providerName = 'spatialite'
self.geomColumn = self.parameterAsString(parameters, self.GEOMETRY_COLUMN, context)
if not self.geomColumn:
self.geomColumn = 'geom'
geomColumn = self.parameterAsString(parameters, self.GEOMETRY_COLUMN, context)
if not geomColumn:
geomColumn = 'geom'
return True
def processAlgorithm(self, context, feedback):
options = {}
if self.overwrite:
if overwrite:
options['overwrite'] = True
if self.convertLowerCase:
if convertLowerCase:
options['lowercaseFieldNames'] = True
self.geomColumn = self.geomColumn.lower()
if self.dropStringLength:
geomColumn = geomColumn.lower()
if dropStringLength:
options['dropStringConstraints'] = True
if self.forceSinglePart:
if forceSinglePart:
options['forceSinglePartGeometryType'] = True
# Clear geometry column for non-geometry tables
if self.source.wkbType() == QgsWkbTypes.NoGeometry:
self.geomColumn = None
if source.wkbType() == QgsWkbTypes.NoGeometry:
geomColumn = None
uri = self.db.uri
uri.setDataSource('', self.table, self.geomColumn, '', self.primaryKeyField)
uri = db.uri
uri.setDataSource('', table, geomColumn, '', primaryKeyField)
if self.encoding:
options['fileEncoding'] = self.encoding
if encoding:
options['fileEncoding'] = encoding
exporter = QgsVectorLayerExporter(uri.uri(), self.providerName, self.source.fields(),
self.source.wkbType(), self.source.sourceCrs(), self.overwrite, options)
exporter = QgsVectorLayerExporter(uri.uri(), providerName, source.fields(),
source.wkbType(), source.sourceCrs(), overwrite, options)
if exporter.errorCode() != QgsVectorLayerExporter.NoError:
raise GeoAlgorithmExecutionException(
self.tr('Error importing to Spatialite\n{0}').format(exporter.errorMessage()))
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, f in enumerate(features):
if feedback.isCanceled():
break
@ -170,9 +154,7 @@ class ImportIntoSpatialite(QgisAlgorithm):
raise GeoAlgorithmExecutionException(
self.tr('Error importing to Spatialite\n{0}').format(exporter.errorMessage()))
if self.geomColumn and self.createIndex:
self.db.create_spatial_index(self.table, self.geomColumn)
return True
if geomColumn and createIndex:
db.create_spatial_index(table, geomColumn)
def postProcessAlgorithm(self, context, feedback):
return {}

View File

@ -68,26 +68,19 @@ class Merge(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Merged')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Merged')))
self.input_layers = []
self.fields = None
self.add_layer_field = None
self.add_path_field = None
self.sink = None
self.dest_id = None
self.dest_crs = None
def name(self):
return 'mergevectorlayers'
def displayName(self):
return self.tr('Merge vector layers')
def prepareAlgorithm(self, parameters, context, feedback):
self.input_layers = self.parameterAsLayerList(parameters, self.LAYERS, context)
def processAlgorithm(self, parameters, context, feedback):
input_layers = self.parameterAsLayerList(parameters, self.LAYERS, context)
layers = []
self.fields = QgsFields()
fields = QgsFields()
totalFeatureCount = 0
for layer in self.input_layers:
for layer in input_layers:
if layer.type() != QgsMapLayer.VectorLayer:
raise GeoAlgorithmExecutionException(
self.tr('All layers must be vector layers!'))
@ -102,7 +95,7 @@ class Merge(QgisAlgorithm):
for sindex, sfield in enumerate(layer.fields()):
found = None
for dfield in self.fields:
for dfield in fields:
if (dfield.name().upper() == sfield.name().upper()):
found = dfield
if (dfield.type() != sfield.type()):
@ -111,38 +104,35 @@ class Merge(QgisAlgorithm):
'data type than in other layers.'.format(sfield.name(), layerSource)))
if not found:
self.fields.append(sfield)
fields.append(sfield)
self.add_layer_field = False
if self.fields.lookupField('layer') < 0:
self.fields.append(QgsField('layer', QVariant.String, '', 100))
self.add_layer_field = True
self.add_path_field = False
if self.fields.lookupField('path') < 0:
self.fields.append(QgsField('path', QVariant.String, '', 200))
self.add_path_field = True
add_layer_field = False
if fields.lookupField('layer') < 0:
fields.append(QgsField('layer', QVariant.String, '', 100))
add_layer_field = True
add_path_field = False
if fields.lookupField('path') < 0:
fields.append(QgsField('path', QVariant.String, '', 200))
add_path_field = True
total = 100.0 / totalFeatureCount if totalFeatureCount else 1
self.dest_crs = layers[0].crs()
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.fields, layers[0].wkbType(), self.dest_crs)
return True
def processAlgorithm(self, context, feedback):
dest_crs = layers[0].crs()
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, layers[0].wkbType(), dest_crs)
featureCount = 0
for layer in self.layers:
for feature in layer.getFeatures(QgsFeatureRequest().setDestinationCrs(self.dest_crs)):
for layer in layers:
for feature in layer.getFeatures(QgsFeatureRequest().setDestinationCrs(dest_crs)):
if feedback.isCanceled():
break
sattributes = feature.attributes()
dattributes = []
for dindex, dfield in enumerate(self.fields):
if self.add_layer_field and dfield.name() == 'layer':
for dindex, dfield in enumerate(fields):
if add_layer_field and dfield.name() == 'layer':
dattributes.append(layer.name())
continue
if self.add_path_field and dfield.name() == 'path':
if add_path_field and dfield.name() == 'path':
dattributes.append(layer.publicSource())
continue
@ -164,10 +154,8 @@ class Merge(QgisAlgorithm):
dattributes.append(dattribute)
feature.setAttributes(dattributes)
self.sink.addFeature(feature, QgsFeatureSink.FastInsert)
sink.addFeature(feature, QgsFeatureSink.FastInsert)
featureCount += 1
feedback.setProgress(int(featureCount * self.total))
return True
feedback.setProgress(int(featureCount * total))
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}
return {self.OUTPUT: dest_id}

View File

@ -80,49 +80,39 @@ class PointsLayerFromTable(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Points from table'), type=QgsProcessingParameterDefinition.TypeVectorPoint))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Points from table'), type=QgsProcessingParameterDefinition.TypeVectorPoint))
self.source = None
self.x_field_index = None
self.y_field_index = None
self.z_field_index = None
self.m_field_index = None
self.sink = None
self.dest_id = None
def name(self):
return 'createpointslayerfromtable'
def displayName(self):
return self.tr('Create points layer from table')
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context)
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
fields = self.source.fields()
self.x_field_index = fields.lookupField(self.parameterAsString(parameters, self.XFIELD, context))
self.y_field_index = fields.lookupField(self.parameterAsString(parameters, self.YFIELD, context))
self.z_field_index = -1
fields = source.fields()
x_field_index = fields.lookupField(self.parameterAsString(parameters, self.XFIELD, context))
y_field_index = fields.lookupField(self.parameterAsString(parameters, self.YFIELD, context))
z_field_index = -1
if self.parameterAsString(parameters, self.ZFIELD, context):
self.z_field_index = fields.lookupField(self.parameterAsString(parameters, self.ZFIELD, context))
self.m_field_index = -1
z_field_index = fields.lookupField(self.parameterAsString(parameters, self.ZFIELD, context))
m_field_index = -1
if self.parameterAsString(parameters, self.MFIELD, context):
self.m_field_index = fields.lookupField(self.parameterAsString(parameters, self.MFIELD, context))
m_field_index = fields.lookupField(self.parameterAsString(parameters, self.MFIELD, context))
wkb_type = QgsWkbTypes.Point
if self.z_field_index >= 0:
if z_field_index >= 0:
wkb_type = QgsWkbTypes.addZ(wkb_type)
if self.m_field_index >= 0:
if m_field_index >= 0:
wkb_type = QgsWkbTypes.addM(wkb_type)
target_crs = self.parameterAsCrs(parameters, self.TARGET_CRS, context)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, wkb_type, target_crs)
return True
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, wkb_type, target_crs)
def processAlgorithm(self, context, feedback):
request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry)
features = self.source.getFeatures(request)
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, feature in enumerate(features):
if feedback.isCanceled():
@ -132,20 +122,20 @@ class PointsLayerFromTable(QgisAlgorithm):
attrs = feature.attributes()
try:
x = float(attrs[self.x_field_index])
y = float(attrs[self.y_field_index])
x = float(attrs[x_field_index])
y = float(attrs[y_field_index])
point = QgsPoint(x, y)
if self.z_field_index >= 0:
if z_field_index >= 0:
try:
point.addZValue(float(attrs[self.z_field_index]))
point.addZValue(float(attrs[z_field_index]))
except:
point.addZValue(0.0)
if self.m_field_index >= 0:
if m_field_index >= 0:
try:
point.addMValue(float(attrs[self.m_field_index]))
point.addMValue(float(attrs[m_field_index]))
except:
point.addMValue(0.0)
@ -153,8 +143,6 @@ class PointsLayerFromTable(QgisAlgorithm):
except:
pass # no geometry
self.sink.addFeature(feature)
return True
sink.addFeature(feature)
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}
return {self.OUTPUT: dest_id}

View File

@ -53,28 +53,20 @@ class PostGISExecuteSQL(QgisAlgorithm):
self.addParameter(db_param)
self.addParameter(QgsProcessingParameterString(self.SQL, self.tr('SQL query')))
self.connection = None
self.sql = None
def name(self):
return 'postgisexecutesql'
def displayName(self):
return self.tr('PostGIS execute SQL')
def prepareAlgorithm(self, parameters, context, feedback):
self.connection = self.parameterAsString(parameters, self.DATABASE, context)
self.sql = self.parameterAsString(parameters, self.SQL, context).replace('\n', ' ')
return True
def processAlgorithm(self, parameters, context, feedback):
connection = self.parameterAsString(parameters, self.DATABASE, context)
db = postgis.GeoDB.from_name(connection)
def processAlgorithm(self, context, feedback):
db = postgis.GeoDB.from_name(self.connection)
sql = self.parameterAsString(parameters, self.SQL, context).replace('\n', ' ')
try:
db._exec_sql_and_commit(str(self.sql))
db._exec_sql_and_commit(str(sql))
except postgis.DbError as e:
raise GeoAlgorithmExecutionException(
self.tr('Error executing SQL:\n{0}').format(str(e)))
return True
def postProcessAlgorithm(self, context, feedback):
return {}

View File

@ -66,54 +66,42 @@ class RandomExtract(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Extracted (random)')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Extracted (random)')))
self.source = None
self.method = None
self.value = None
self.featureCount = None
self.sink = None
self.dest_id = None
def name(self):
return 'randomextract'
def displayName(self):
return self.tr('Random extract')
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context)
self.method = self.parameterAsEnum(parameters, self.METHOD, context)
self.value = self.parameterAsInt(parameters, self.NUMBER, context)
self.featureCount = self.source.featureCount()
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
method = self.parameterAsEnum(parameters, self.METHOD, context)
if self.method == 0:
if self.value > self.featureCount:
features = source.getFeatures()
featureCount = source.featureCount()
value = self.parameterAsInt(parameters, self.NUMBER, context)
if method == 0:
if value > featureCount:
raise GeoAlgorithmExecutionException(
self.tr('Selected number is greater than feature count. '
'Choose a lower value and try again.'))
else:
if self.value > 100:
if value > 100:
raise GeoAlgorithmExecutionException(
self.tr("Percentage can't be greater than 100. Set a "
"different value and try again."))
self.value = int(round(self.value / 100.0000, 4) * self.featureCount)
value = int(round(value / 100.0000, 4) * featureCount)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), self.source.wkbType(), self.source.sourceCrs())
selran = random.sample(list(range(featureCount)), value)
return True
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
def processAlgorithm(self, context, feedback):
selran = random.sample(list(range(self.featureCount)), self.value)
features = self.source.getFeatures()
total = 100.0 / self.featureCount if self.featureCount else 1
total = 100.0 / featureCount if featureCount else 1
for i, feat in enumerate(features):
if feedback.isCanceled():
break
if i in selran:
self.sink.addFeature(feat, QgsFeatureSink.FastInsert)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
feedback.setProgress(int(i * total))
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}
return {self.OUTPUT: dest_id}

View File

@ -74,46 +74,38 @@ class RandomExtractWithinSubsets(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Extracted (random stratified)')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Extracted (random stratified)')))
self.source = None
self.method = None
self.field = None
self.value = None
self.sink = None
self.dest_id = None
def name(self):
return 'randomextractwithinsubsets'
def displayName(self):
return self.tr('Random extract within subsets')
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context)
self.method = self.parameterAsEnum(parameters, self.METHOD, context)
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
method = self.parameterAsEnum(parameters, self.METHOD, context)
self.field = self.parameterAsString(parameters, self.FIELD, context)
self.value = self.parameterAsInt(parameters, self.NUMBER, context)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), self.source.wkbType(), self.source.sourceCrs())
return True
field = self.parameterAsString(parameters, self.FIELD, context)
def processAlgorithm(self, context, feedback):
index = self.source.fields().lookupField(self.field)
index = source.fields().lookupField(field)
features = self.source.getFeatures()
featureCount = self.source.featureCount()
unique = self.source.uniqueValues(index)
if self.method == 0:
if self.value > featureCount:
features = source.getFeatures()
featureCount = source.featureCount()
unique = source.uniqueValues(index)
value = self.parameterAsInt(parameters, self.NUMBER, context)
if method == 0:
if value > featureCount:
raise GeoAlgorithmExecutionException(
self.tr('Selected number is greater that feature count. '
'Choose lesser value and try again.'))
else:
if self.value > 100:
if value > 100:
raise GeoAlgorithmExecutionException(
self.tr("Percentage can't be greater than 100. Set "
"correct value and try again."))
self.value = self.value / 100.0
value = value / 100.0
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
selran = []
total = 100.0 / (featureCount * len(unique)) if featureCount else 1
@ -127,17 +119,13 @@ class RandomExtractWithinSubsets(QgisAlgorithm):
feedback.setProgress(int(i * total))
for subset in classes.values():
selValue = self.value if self.method != 1 else int(round(self.value * len(subset), 0))
selValue = value if method != 1 else int(round(value * len(subset), 0))
selran.extend(random.sample(subset, selValue))
total = 100.0 / featureCount if featureCount else 1
for (i, feat) in enumerate(selran):
if feedback.isCanceled():
break
self.sink.addFeature(feat, QgsFeatureSink.FastInsert)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
feedback.setProgress(int(i * total))
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}
return {self.OUTPUT: dest_id}

View File

@ -81,66 +81,55 @@ class RegularPoints(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Regular points'), QgsProcessingParameterDefinition.TypeVectorPoint))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Regular points'), QgsProcessingParameterDefinition.TypeVectorPoint))
self.extent = None
self.spacing = None
self.inset = None
self.randomize = None
self.isSpacing = None
self.fields = None
self.sink = None
self.dest_id = None
def name(self):
return 'regularpoints'
def displayName(self):
return self.tr('Regular points')
def prepareAlgorithm(self, parameters, context, feedback):
self.extent = self.parameterAsExtent(parameters, self.EXTENT, context)
def processAlgorithm(self, parameters, context, feedback):
extent = self.parameterAsExtent(parameters, self.EXTENT, context)
self.spacing = self.parameterAsDouble(parameters, self.SPACING, context)
self.inset = self.parameterAsDouble(parameters, self.INSET, context)
self.randomize = self.parameterAsBool(parameters, self.RANDOMIZE, context)
self.isSpacing = self.parameterAsBool(parameters, self.IS_SPACING, context)
spacing = self.parameterAsDouble(parameters, self.SPACING, context)
inset = self.parameterAsDouble(parameters, self.INSET, context)
randomize = self.parameterAsBool(parameters, self.RANDOMIZE, context)
isSpacing = self.parameterAsBool(parameters, self.IS_SPACING, context)
crs = self.parameterAsCrs(parameters, self.CRS, context)
self.fields = QgsFields()
self.fields.append(QgsField('id', QVariant.Int, '', 10, 0))
fields = QgsFields()
fields.append(QgsField('id', QVariant.Int, '', 10, 0))
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.fields, QgsWkbTypes.Point, crs)
return True
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.Point, crs)
def processAlgorithm(self, context, feedback):
if self.randomize:
if randomize:
seed()
area = self.extent.width() * self.extent.height()
if self.isSpacing:
pSpacing = self.spacing
area = extent.width() * extent.height()
if isSpacing:
pSpacing = spacing
else:
pSpacing = sqrt(area / self.spacing)
pSpacing = sqrt(area / spacing)
f = QgsFeature()
f.initAttributes(1)
f.setFields(self.fields)
f.setFields(fields)
count = 0
total = 100.0 / (area / pSpacing)
y = self.extent.yMaximum() - self.inset
y = extent.yMaximum() - inset
extent_geom = QgsGeometry.fromRect(self.extent)
extent_geom = QgsGeometry.fromRect(extent)
extent_engine = QgsGeometry.createGeometryEngine(extent_geom.geometry())
extent_engine.prepareGeometry()
while y >= self.extent.yMinimum():
x = self.extent.xMinimum() + self.inset
while x <= self.extent.xMaximum():
while y >= extent.yMinimum():
x = extent.xMinimum() + inset
while x <= extent.xMaximum():
if feedback.isCanceled():
break
if self.randomize:
if randomize:
geom = QgsGeometry().fromPoint(QgsPointXY(
uniform(x - (pSpacing / 2.0), x + (pSpacing / 2.0)),
uniform(y - (pSpacing / 2.0), y + (pSpacing / 2.0))))
@ -150,13 +139,10 @@ class RegularPoints(QgisAlgorithm):
if extent_engine.intersects(geom.geometry()):
f.setAttribute('id', count)
f.setGeometry(geom)
self.sink.addFeature(f, QgsFeatureSink.FastInsert)
sink.addFeature(f, QgsFeatureSink.FastInsert)
x += pSpacing
count += 1
feedback.setProgress(int(count * total))
y = y - pSpacing
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}
return {self.OUTPUT: dest_id}

View File

@ -47,35 +47,27 @@ class SaveSelectedFeatures(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Selection')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Selection")))
self.vectorLayer = None
self.sink = None
self.dest_id = None
def name(self):
return 'saveselectedfeatures'
def displayName(self):
return self.tr('Save selected features')
def prepareAlgorithm(self, parameters, context, feedback):
self.vectorLayer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
def processAlgorithm(self, parameters, context, feedback):
vectorLayer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.vectorLayer.fields(), self.vectorLayer.wkbType(), self.vectorLayer.sourceCrs())
return True
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
vectorLayer.fields(), vectorLayer.wkbType(), vectorLayer.sourceCrs())
def processAlgorithm(self, context, feedback):
features = self.vectorLayer.getSelectedFeatures()
count = int(self.vectorLayer.selectedFeatureCount())
features = vectorLayer.getSelectedFeatures()
count = int(vectorLayer.selectedFeatureCount())
total = 100.0 / count if count else 1
for current, feat in enumerate(features):
if feedback.isCanceled():
break
self.sink.addFeature(feat, QgsFeatureSink.FastInsert)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}
return {self.OUTPUT: dest_id}

View File

@ -92,60 +92,47 @@ class SelectByAttribute(QgisAlgorithm):
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Selected (attribute)')))
self.layer = None
self.fieldName = None
self.operator = None
self.value = None
self.input = None
def name(self):
return 'selectbyattribute'
def displayName(self):
return self.tr('Select by attribute')
def prepareAlgorithm(self, parameters, context, feedback):
self.layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
def processAlgorithm(self, parameters, context, feedback):
layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
self.fieldName = self.parameterAsString(parameters, self.FIELD, context)
self.operator = self.OPERATORS[self.parameterAsEnum(parameters, self.OPERATOR, context)]
self.value = self.parameterAsString(parameters, self.VALUE, context)
fieldName = self.parameterAsString(parameters, self.FIELD, context)
operator = self.OPERATORS[self.parameterAsEnum(parameters, self.OPERATOR, context)]
value = self.parameterAsString(parameters, self.VALUE, context)
self.input = parameters[self.INPUT]
return True
fields = layer.fields()
def processAlgorithm(self, context, feedback):
fields = self.layer.fields()
idx = self.layer.fields().lookupField(self.fieldName)
idx = layer.fields().lookupField(fieldName)
fieldType = fields[idx].type()
if fieldType != QVariant.String and self.operator in self.STRING_OPERATORS:
if fieldType != QVariant.String and operator in self.STRING_OPERATORS:
op = ''.join(['"%s", ' % o for o in self.STRING_OPERATORS])
raise GeoAlgorithmExecutionException(
self.tr('Operators {0} can be used only with string fields.').format(op))
field_ref = QgsExpression.quotedColumnRef(self.fieldName)
quoted_val = QgsExpression.quotedValue(self.value)
if self.operator == 'is null':
field_ref = QgsExpression.quotedColumnRef(fieldName)
quoted_val = QgsExpression.quotedValue(value)
if operator == 'is null':
expression_string = '{} IS NULL'.format(field_ref)
elif self.operator == 'is not null':
elif operator == 'is not null':
expression_string = '{} IS NOT NULL'.format(field_ref)
elif self.operator == 'begins with':
expression_string = """%s LIKE '%s%%'""" % (field_ref, self.value)
elif self.operator == 'contains':
expression_string = """%s LIKE '%%%s%%'""" % (field_ref, self.value)
elif self.operator == 'does not contain':
expression_string = """%s NOT LIKE '%%%s%%'""" % (field_ref, self.value)
elif operator == 'begins with':
expression_string = """%s LIKE '%s%%'""" % (field_ref, value)
elif operator == 'contains':
expression_string = """%s LIKE '%%%s%%'""" % (field_ref, value)
elif operator == 'does not contain':
expression_string = """%s NOT LIKE '%%%s%%'""" % (field_ref, value)
else:
expression_string = '{} {} {}'.format(field_ref, self.operator, quoted_val)
expression_string = '{} {} {}'.format(field_ref, operator, quoted_val)
expression = QgsExpression(expression_string)
if expression.hasParserError():
raise GeoAlgorithmExecutionException(expression.parserErrorString())
self.layer.selectByExpression(expression_string)
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.input}
layer.selectByExpression(expression_string)
return {self.OUTPUT: parameters[self.INPUT]}

View File

@ -60,42 +60,30 @@ class SelectByExpression(QgisAlgorithm):
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Selected (attribute)')))
self.layer = None
self.behavior = None
self.input = None
self.expression = None
def name(self):
return 'selectbyexpression'
def displayName(self):
return self.tr('Select by expression')
def prepareAlgorithm(self, parameters, context, feedback):
self.layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
def processAlgorithm(self, parameters, context, feedback):
layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
method = self.parameterAsEnum(parameters, self.METHOD, context)
if method == 0:
self.behavior = QgsVectorLayer.SetSelection
behavior = QgsVectorLayer.SetSelection
elif method == 1:
self.behavior = QgsVectorLayer.AddToSelection
behavior = QgsVectorLayer.AddToSelection
elif method == 2:
self.behavior = QgsVectorLayer.RemoveFromSelection
behavior = QgsVectorLayer.RemoveFromSelection
elif method == 3:
self.behavior = QgsVectorLayer.IntersectSelection
behavior = QgsVectorLayer.IntersectSelection
self.expression = self.parameterAsString(parameters, self.EXPRESSION, context)
qExp = QgsExpression(self.expression)
expression = self.parameterAsString(parameters, self.EXPRESSION, context)
qExp = QgsExpression(expression)
if qExp.hasParserError():
raise GeoAlgorithmExecutionException(qExp.parserErrorString())
self.input = parameters[self.INPUT]
return True
def processAlgorithm(self, context, feedback):
self.layer.selectByExpression(self.expression, self.behavior)
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.input}
layer.selectByExpression(expression, behavior)
return {self.OUTPUT: parameters[self.INPUT]}

View File

@ -76,37 +76,28 @@ class SimplifyGeometries(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Simplified')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Simplified')))
self.source = None
self.tolerance = None
self.method = None
self.sink = None
self.dest_id = None
def name(self):
return 'simplifygeometries'
def displayName(self):
return self.tr('Simplify geometries')
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context)
self.tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)
self.method = self.parameterAsEnum(parameters, self.METHOD, context)
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context)
method = self.parameterAsEnum(parameters, self.METHOD, context)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), self.source.wkbType(), self.source.sourceCrs())
return True
def processAlgorithm(self, context, feedback):
pointsBefore = 0
pointsAfter = 0
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
simplifier = None
if self.method != 0:
simplifier = QgsMapToPixelSimplifier(QgsMapToPixelSimplifier.SimplifyGeometry, self.tolerance, self.method)
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
if method != 0:
simplifier = QgsMapToPixelSimplifier(QgsMapToPixelSimplifier.SimplifyGeometry, tolerance, method)
for current, input_feature in enumerate(features):
if feedback.isCanceled():
@ -116,20 +107,18 @@ class SimplifyGeometries(QgisAlgorithm):
input_geometry = input_feature.geometry()
pointsBefore += input_geometry.geometry().nCoordinates()
if self.method == 0: # distance
output_geometry = input_geometry.simplify(self.tolerance)
if method == 0: # distance
output_geometry = input_geometry.simplify(tolerance)
else:
output_geometry = simplifier.simplify(input_geometry)
pointsAfter += output_geometry.geometry().nCoordinates()
out_feature.setGeometry(output_geometry)
self.sink.addFeature(out_feature, QgsFeatureSink.FastInsert)
sink.addFeature(out_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
QgsMessageLog.logMessage(self.tr('Simplify: Input geometries have been simplified from {0} to {1} points').format(pointsBefore, pointsAfter),
self.tr('Processing'), QgsMessageLog.INFO)
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}
return {self.OUTPUT: dest_id}

View File

@ -66,48 +66,37 @@ class Smooth(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Smoothed')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Smoothed')))
self.source = None
self.iterations = None
self.offset = None
self.max_angle = None
self.sink = None
self.dest_id = None
def name(self):
return 'smoothgeometry'
def displayName(self):
return self.tr('Smooth geometry')
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context)
self.iterations = self.parameterAsInt(parameters, self.ITERATIONS, context)
self.offset = self.parameterAsDouble(parameters, self.OFFSET, context)
self.max_angle = self.parameterAsDouble(parameters, self.MAX_ANGLE, context)
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
iterations = self.parameterAsInt(parameters, self.ITERATIONS, context)
offset = self.parameterAsDouble(parameters, self.OFFSET, context)
max_angle = self.parameterAsDouble(parameters, self.MAX_ANGLE, context)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), self.source.wkbType(), self.source.sourceCrs())
return True
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
def processAlgorithm(self, context, feedback):
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
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
if input_feature.geometry():
output_geometry = input_feature.geometry().smooth(self.iterations, self.offset, -1, self.max_angle)
output_geometry = input_feature.geometry().smooth(iterations, offset, -1, max_angle)
if not output_geometry:
raise GeoAlgorithmExecutionException(
self.tr('Error smoothing geometry'))
output_feature.setGeometry(output_geometry)
self.sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}
return {self.OUTPUT: dest_id}

View File

@ -49,34 +49,26 @@ class SpatialiteExecuteSQL(QgisAlgorithm):
self.addParameter(QgsProcessingParameterVectorLayer(self.DATABASE, self.tr('File Database'), False, False))
self.addParameter(QgsProcessingParameterString(self.SQL, self.tr('SQL query'), '', True))
self.database = None
self.sql = None
def name(self):
return 'spatialiteexecutesql'
def displayName(self):
return self.tr('Spatialite execute SQL')
def prepareAlgorithm(self, parameters, context, feedback):
self.database = self.parameterAsVectorLayer(parameters, self.DATABASE, context)
self.sql = self.parameterAsString(parameters, self.SQL, context).replace('\n', ' ')
return True
def processAlgorithm(self, context, feedback):
databaseuri = self.database.dataProvider().dataSourceUri()
def processAlgorithm(self, parameters, context, feedback):
database = self.parameterAsVectorLayer(parameters, self.DATABASE, context)
databaseuri = database.dataProvider().dataSourceUri()
uri = QgsDataSourceUri(databaseuri)
if uri.database() is '':
if '|layerid' in databaseuri:
databaseuri = databaseuri[:databaseuri.find('|layerid')]
uri = QgsDataSourceUri('dbname=\'%s\'' % (databaseuri))
db = spatialite.GeoDB(uri)
sql = self.parameterAsString(parameters, self.SQL, context).replace('\n', ' ')
try:
db._exec_sql_and_commit(str(self.sql))
db._exec_sql_and_commit(str(sql))
except spatialite.DbError as e:
raise GeoAlgorithmExecutionException(
self.tr('Error executing SQL:\n{0}').format(str(e)))
return True
def postProcessAlgorithm(self, context, feedback):
return {}

View File

@ -70,39 +70,32 @@ class SymmetricalDifference(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Symmetrical difference')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Symmetrical difference')))
self.sourceA = None
self.sourceB = None
self.sink = None
self.dest_id = None
def name(self):
return 'symmetricaldifference'
def displayName(self):
return self.tr('Symmetrical difference')
def prepareAlgorithm(self, parameters, context, feedback):
self.sourceA = self.parameterAsSource(parameters, self.INPUT, context)
self.sourceB = self.parameterAsSource(parameters, self.OVERLAY, context)
def processAlgorithm(self, parameters, context, feedback):
sourceA = self.parameterAsSource(parameters, self.INPUT, context)
sourceB = self.parameterAsSource(parameters, self.OVERLAY, context)
geomType = QgsWkbTypes.multiType(self.sourceA.wkbType())
fields = vector.combineFields(self.sourceA.fields(), self.sourceB.fields())
geomType = QgsWkbTypes.multiType(sourceA.wkbType())
fields = vector.combineFields(sourceA.fields(), sourceB.fields())
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, geomType, self.sourceA.sourceCrs())
return True
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, geomType, sourceA.sourceCrs())
def processAlgorithm(self, context, feedback):
featB = QgsFeature()
outFeat = QgsFeature()
indexA = QgsSpatialIndex(self.sourceA)
indexB = QgsSpatialIndex(self.sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(self.sourceA.sourceCrs())))
indexA = QgsSpatialIndex(sourceA)
indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())))
total = 100.0 / (self.sourceA.featureCount() * self.sourceB.featureCount()) if self.sourceA.featureCount() and self.sourceB.featureCount() else 1
total = 100.0 / (sourceA.featureCount() * sourceB.featureCount()) if sourceA.featureCount() and sourceB.featureCount() else 1
count = 0
for featA in self.sourceA.getFeatures():
for featA in sourceA.getFeatures():
if feedback.isCanceled():
break
@ -111,8 +104,8 @@ class SymmetricalDifference(QgisAlgorithm):
attrs = featA.attributes()
intersects = indexB.intersects(geom.boundingBox())
request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([])
request.setDestinationCrs(self.sourceA.sourceCrs())
for featB in self.sourceB.getFeatures(request):
request.setDestinationCrs(sourceA.sourceCrs())
for featB in sourceB.getFeatures(request):
if feedback.isCanceled():
break
tmpGeom = featB.geometry()
@ -122,7 +115,7 @@ class SymmetricalDifference(QgisAlgorithm):
try:
outFeat.setGeometry(diffGeom)
outFeat.setAttributes(attrs)
self.sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
except:
QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'),
self.tr('Processing'), QgsMessageLog.WARNING)
@ -131,9 +124,9 @@ class SymmetricalDifference(QgisAlgorithm):
count += 1
feedback.setProgress(int(count * total))
length = len(self.sourceA.fields())
length = len(sourceA.fields())
for featA in self.sourceB.getFeatures(QgsFeatureRequest().setDestinationCrs(self.sourceA.sourceCrs())):
for featA in sourceB.getFeatures(QgsFeatureRequest().setDestinationCrs(sourceA.sourceCrs())):
if feedback.isCanceled():
break
@ -143,7 +136,7 @@ class SymmetricalDifference(QgisAlgorithm):
attrs = [NULL] * length + attrs
intersects = indexA.intersects(geom.boundingBox())
request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([])
for featB in self.sourceA.getFeatures(request):
for featB in sourceA.getFeatures(request):
if feedback.isCanceled():
break
@ -154,7 +147,7 @@ class SymmetricalDifference(QgisAlgorithm):
try:
outFeat.setGeometry(diffGeom)
outFeat.setAttributes(attrs)
self.sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
except:
QgsMessageLog.logMessage(self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'),
self.tr('Processing'), QgsMessageLog.WARNING)
@ -162,7 +155,5 @@ class SymmetricalDifference(QgisAlgorithm):
count += 1
feedback.setProgress(int(count * total))
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}
return {self.OUTPUT: dest_id}

View File

@ -66,51 +66,42 @@ class VectorSplit(QgisAlgorithm):
self.addOutput(QgsProcessingOutputFolder(self.OUTPUT, self.tr('Output directory')))
self.source = None
self.fieldName = None
self.directory = None
self.uniqueValues = None
self.sinks = {}
def name(self):
return 'splitvectorlayer'
def displayName(self):
return self.tr('Split vector layer')
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context)
self.fieldName = self.parameterAsString(parameters, self.FIELD, context)
self.directory = self.parameterAsString(parameters, self.OUTPUT, context)
mkdir(self.directory)
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
fieldName = self.parameterAsString(parameters, self.FIELD, context)
directory = self.parameterAsString(parameters, self.OUTPUT, context)
fieldIndex = self.source.fields().lookupField(self.fieldName)
self.uniqueValues = self.source.uniqueValues(fieldIndex)
mkdir(directory)
baseName = os.path.join(self.directory, '{0}'.format(self.fieldName))
self.sinks = {}
for current, i in enumerate(self.uniqueValues):
fieldIndex = source.fields().lookupField(fieldName)
uniqueValues = source.uniqueValues(fieldIndex)
baseName = os.path.join(directory, '{0}'.format(fieldName))
fields = source.fields()
crs = source.sourceCrs()
geomType = source.wkbType()
total = 100.0 / len(uniqueValues) if uniqueValues else 1
for current, i in enumerate(uniqueValues):
if feedback.isCanceled():
break
fName = u'{0}_{1}.shp'.format(baseName, str(i).strip())
feedback.pushInfo(self.tr('Creating layer: {}').format(fName))
sink, dest = QgsProcessingUtils.createFeatureSink(fName, context, self.source.fields, self.source.wkbType(), self.source.sourceCrs())
self.sinks[i] = sink
return True
def processAlgorithm(self, context, feedback):
total = 100.0 / len(self.uniqueValues) if self.uniqueValues else 1
for current, i in enumerate(self.uniqueValues):
if feedback.isCanceled():
break
sink, dest = QgsProcessingUtils.createFeatureSink(fName, context, fields, geomType, crs)
sink = self.sinks[i]
filter = '{} = {}'.format(QgsExpression.quotedColumnRef(self.fieldName), QgsExpression.quotedValue(i))
filter = '{} = {}'.format(QgsExpression.quotedColumnRef(fieldName), QgsExpression.quotedValue(i))
req = QgsFeatureRequest().setFilterExpression(filter)
count = 0
for f in self.source.getFeatures(req):
for f in source.getFeatures(req):
if feedback.isCanceled():
break
sink.addFeature(f, QgsFeatureSink.FastInsert)
@ -119,7 +110,5 @@ class VectorSplit(QgisAlgorithm):
del sink
feedback.setProgress(int(current * total))
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.directory}
return {self.OUTPUT: directory}

View File

@ -121,14 +121,11 @@ class ZonalStatistics(QgisAlgorithm):
self.rasterLayer = self.parameterAsRasterLayer(parameters, self.INPUT_RASTER, context)
return True
def processAlgorithm(self, context, feedback):
def processAlgorithm(self, parameters, context, feedback):
zs = QgsZonalStatistics(self.vectorLayer,
self.rasterLayer,
self.columnPrefix,
self.bandNumber,
QgsZonalStatistics.Statistics(self.selectedStats))
zs.calculateStatistics(feedback)
return True
def postProcessAlgorithm(self, context, feedback):
return {self.INPUT_VECTOR: self.vectorLayer}

View File

@ -248,7 +248,7 @@ class ScriptAlgorithm(QgsProcessingAlgorithm):
return True
def processAlgorithm(self, context, feedback):
def processAlgorithm(self, parameters, context, feedback):
self.ns['feedback'] = feedback
self.ns['context'] = context
@ -257,9 +257,6 @@ class ScriptAlgorithm(QgsProcessingAlgorithm):
for out in self.outputDefinitions():
self.results[out.name()] = self.ns[out.name()]
del self.ns
return True
def postProcessAlgorithm(self, context, feedback):
return self.results
def helpUrl(self):

View File

@ -138,7 +138,7 @@ class AlgorithmsTest(object):
pass
else:
results, ok = alg.run(parameters, context, feedback)
self.assertTrue(ok, parameters)
self.assertTrue(ok, 'params: {}, results: {}'.format(parameters, results))
self.check_results(results, context, defs['params'], defs['results'])
def load_params(self, params):

View File

@ -89,27 +89,23 @@ QgsCentroidAlgorithm *QgsCentroidAlgorithm::create() const
return new QgsCentroidAlgorithm();
}
bool QgsCentroidAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
QVariantMap QgsCentroidAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
mSource.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !mSource )
return false;
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !source )
return QVariantMap();
mSink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, mSinkId, mSource->fields(), QgsWkbTypes::Point, mSource->sourceCrs() ) );
if ( !mSink )
return false;
QString dest;
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(), QgsWkbTypes::Point, source->sourceCrs() ) );
if ( !sink )
return QVariantMap();
return true;
}
bool QgsCentroidAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFeedback *feedback )
{
long count = mSource->featureCount();
if ( count == 0 )
return true;
long count = source->featureCount();
if ( count <= 0 )
return QVariantMap();
QgsFeature f;
QgsFeatureIterator it = mSource->getFeatures();
QgsFeatureIterator it = source->getFeatures();
double step = 100.0 / count;
int current = 0;
@ -129,19 +125,14 @@ bool QgsCentroidAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessi
QgsMessageLog::logMessage( QObject::tr( "Error calculating centroid for feature %1" ).arg( f.id() ), QObject::tr( "Processing" ), QgsMessageLog::WARNING );
}
}
mSink->addFeature( out, QgsFeatureSink::FastInsert );
sink->addFeature( out, QgsFeatureSink::FastInsert );
feedback->setProgress( current * step );
current++;
}
mSink->flushBuffer();
return true;
}
QVariantMap QgsCentroidAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), mSinkId );
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
return outputs;
}
@ -178,47 +169,37 @@ QgsBufferAlgorithm *QgsBufferAlgorithm::create() const
return new QgsBufferAlgorithm();
}
bool QgsBufferAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
QVariantMap QgsBufferAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
mSource.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !mSource )
return false;
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !source )
return QVariantMap();
mSink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, mSinkId, mSource->fields(), QgsWkbTypes::Polygon, mSource->sourceCrs() ) );
if ( !mSink )
return false;
QString dest;
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(), QgsWkbTypes::Polygon, source->sourceCrs() ) );
if ( !sink )
return QVariantMap();
// fixed parameters
mDissolve = parameterAsBool( parameters, QStringLiteral( "DISSOLVE" ), context );
mSegments = parameterAsInt( parameters, QStringLiteral( "SEGMENTS" ), context );
mEndCapStyle = static_cast< QgsGeometry::EndCapStyle >( 1 + parameterAsInt( parameters, QStringLiteral( "END_CAP_STYLE" ), context ) );
mJoinStyle = static_cast< QgsGeometry::JoinStyle>( 1 + parameterAsInt( parameters, QStringLiteral( "JOIN_STYLE" ), context ) );
mMiterLimit = parameterAsDouble( parameters, QStringLiteral( "MITRE_LIMIT" ), context );
mBufferDistance = parameterAsDouble( parameters, QStringLiteral( "DISTANCE" ), context );
mDynamicBuffer = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DISTANCE" ) );
if ( mDynamicBuffer )
{
mDynamicBufferProperty = parameters.value( QStringLiteral( "DISTANCE" ) ).value< QgsProperty >();
mExpContext = context.expressionContext();
mDefaultBuffer = parameterDefinition( QStringLiteral( "DISTANCE" ) )->defaultValue().toDouble();
}
return true;
}
bool dissolve = parameterAsBool( parameters, QStringLiteral( "DISSOLVE" ), context );
int segments = parameterAsInt( parameters, QStringLiteral( "SEGMENTS" ), context );
QgsGeometry::EndCapStyle endCapStyle = static_cast< QgsGeometry::EndCapStyle >( 1 + parameterAsInt( parameters, QStringLiteral( "END_CAP_STYLE" ), context ) );
QgsGeometry::JoinStyle joinStyle = static_cast< QgsGeometry::JoinStyle>( 1 + parameterAsInt( parameters, QStringLiteral( "JOIN_STYLE" ), context ) );
double miterLimit = parameterAsDouble( parameters, QStringLiteral( "MITRE_LIMIT" ), context );
double bufferDistance = parameterAsDouble( parameters, QStringLiteral( "DISTANCE" ), context );
bool dynamicBuffer = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DISTANCE" ) );
const QgsProcessingParameterDefinition *distanceParamDef = parameterDefinition( QStringLiteral( "DISTANCE" ) );
bool QgsBufferAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFeedback *feedback )
{
long count = mSource->featureCount();
if ( count == 0 )
return false;
long count = source->featureCount();
if ( count <= 0 )
return QVariantMap();
QgsFeature f;
QgsFeatureIterator it = mSource->getFeatures();
QgsFeatureIterator it = source->getFeatures();
double step = 100.0 / count;
int current = 0;
double bufferDistance = mBufferDistance;
QList< QgsGeometry > bufferedGeometriesForDissolve;
QgsAttributes dissolveAttrs;
@ -234,50 +215,45 @@ bool QgsBufferAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessing
QgsFeature out = f;
if ( out.hasGeometry() )
{
if ( mDynamicBuffer )
if ( dynamicBuffer )
{
mExpContext.setFeature( f );
bufferDistance = mDynamicBufferProperty.valueAsDouble( mExpContext, mDefaultBuffer );
context.expressionContext().setFeature( f );
bufferDistance = QgsProcessingParameters::parameterAsDouble( distanceParamDef, parameters, context );
}
QgsGeometry outputGeometry = f.geometry().buffer( bufferDistance, mSegments, mEndCapStyle, mJoinStyle, mMiterLimit );
QgsGeometry outputGeometry = f.geometry().buffer( bufferDistance, segments, endCapStyle, joinStyle, miterLimit );
if ( !outputGeometry )
{
QgsMessageLog::logMessage( QObject::tr( "Error calculating buffer for feature %1" ).arg( f.id() ), QObject::tr( "Processing" ), QgsMessageLog::WARNING );
}
if ( mDissolve )
if ( dissolve )
bufferedGeometriesForDissolve << outputGeometry;
else
out.setGeometry( outputGeometry );
}
if ( !mDissolve )
mSink->addFeature( out, QgsFeatureSink::FastInsert );
if ( !dissolve )
sink->addFeature( out, QgsFeatureSink::FastInsert );
feedback->setProgress( current * step );
current++;
}
if ( mDissolve )
if ( dissolve )
{
QgsGeometry finalGeometry = QgsGeometry::unaryUnion( bufferedGeometriesForDissolve );
QgsFeature f;
f.setGeometry( finalGeometry );
f.setAttributes( dissolveAttrs );
mSink->addFeature( f, QgsFeatureSink::FastInsert );
sink->addFeature( f, QgsFeatureSink::FastInsert );
}
mSink->flushBuffer();
return true;
}
QVariantMap QgsBufferAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), mSinkId );
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
return outputs;
}
QgsDissolveAlgorithm::QgsDissolveAlgorithm()
{
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
@ -302,34 +278,31 @@ QgsDissolveAlgorithm *QgsDissolveAlgorithm::create() const
return new QgsDissolveAlgorithm();
}
bool QgsDissolveAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
QVariantMap QgsDissolveAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
mSource.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !mSource )
return false;
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !source )
return QVariantMap();
mSink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, mSinkId, mSource->fields(), QgsWkbTypes::multiType( mSource->wkbType() ), mSource->sourceCrs() ) );
QString dest;
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(), QgsWkbTypes::multiType( source->wkbType() ), source->sourceCrs() ) );
if ( !mSink )
return false;
if ( !sink )
return QVariantMap();
mFields = parameterAsFields( parameters, QStringLiteral( "FIELD" ), context );
return true;
}
QStringList fields = parameterAsFields( parameters, QStringLiteral( "FIELD" ), context );
bool QgsDissolveAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFeedback *feedback )
{
long count = mSource->featureCount();
if ( count == 0 )
return true;
long count = source->featureCount();
if ( count <= 0 )
return QVariantMap();
QgsFeature f;
QgsFeatureIterator it = mSource->getFeatures();
QgsFeatureIterator it = source->getFeatures();
double step = 100.0 / count;
int current = 0;
if ( mFields.isEmpty() )
if ( fields.isEmpty() )
{
// dissolve all - not using fields
bool firstFeature = true;
@ -367,14 +340,14 @@ bool QgsDissolveAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessi
}
outputFeature.setGeometry( QgsGeometry::unaryUnion( geomQueue ) );
mSink->addFeature( outputFeature, QgsFeatureSink::FastInsert );
sink->addFeature( outputFeature, QgsFeatureSink::FastInsert );
}
else
{
QList< int > fieldIndexes;
Q_FOREACH ( const QString &field, mFields )
Q_FOREACH ( const QString &field, fields )
{
int index = mSource->fields().lookupField( field );
int index = source->fields().lookupField( field );
if ( index >= 0 )
fieldIndexes << index;
}
@ -418,21 +391,15 @@ bool QgsDissolveAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessi
QgsFeature outputFeature;
outputFeature.setGeometry( QgsGeometry::unaryUnion( geomIt.value() ) );
outputFeature.setAttributes( attributeHash.value( geomIt.key() ) );
mSink->addFeature( outputFeature, QgsFeatureSink::FastInsert );
sink->addFeature( outputFeature, QgsFeatureSink::FastInsert );
feedback->setProgress( current * 100.0 / numberFeatures );
current++;
}
}
mSink->flushBuffer();
return true;
}
QVariantMap QgsDissolveAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), mSinkId );
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
return outputs;
}
@ -459,29 +426,25 @@ QgsClipAlgorithm *QgsClipAlgorithm::create() const
return new QgsClipAlgorithm();
}
bool QgsClipAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
QVariantMap QgsClipAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
mFeatureSource.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !mFeatureSource )
return false;
std::unique_ptr< QgsFeatureSource > featureSource( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !featureSource )
return QVariantMap();
mMaskSource.reset( parameterAsSource( parameters, QStringLiteral( "OVERLAY" ), context ) );
if ( !mMaskSource )
return false;
std::unique_ptr< QgsFeatureSource > maskSource( parameterAsSource( parameters, QStringLiteral( "OVERLAY" ), context ) );
if ( !maskSource )
return QVariantMap();
mSink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, mSinkId, mFeatureSource->fields(), QgsWkbTypes::multiType( mFeatureSource->wkbType() ), mFeatureSource->sourceCrs() ) );
QString dest;
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, featureSource->fields(), QgsWkbTypes::multiType( featureSource->wkbType() ), featureSource->sourceCrs() ) );
if ( !mSink )
return false;
if ( !sink )
return QVariantMap();
return true;
}
bool QgsClipAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFeedback *feedback )
{
// first build up a list of clip geometries
QList< QgsGeometry > clipGeoms;
QgsFeatureIterator it = mMaskSource->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QList< int >() ).setDestinationCrs( mFeatureSource->sourceCrs() ) );
QgsFeatureIterator it = maskSource->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QList< int >() ).setDestinationCrs( featureSource->sourceCrs() ) );
QgsFeature f;
while ( it.nextFeature( f ) )
{
@ -490,7 +453,7 @@ bool QgsClipAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFe
}
if ( clipGeoms.isEmpty() )
return true;
return QVariantMap();
// are we clipping against a single feature? if so, we can show finer progress reports
bool singleClipFeature = false;
@ -521,7 +484,7 @@ bool QgsClipAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFe
break;
}
QgsFeatureIterator inputIt = mFeatureSource->getFeatures( QgsFeatureRequest().setFilterRect( clipGeom.boundingBox() ) );
QgsFeatureIterator inputIt = featureSource->getFeatures( QgsFeatureRequest().setFilterRect( clipGeom.boundingBox() ) );
QgsFeatureList inputFeatures;
QgsFeature f;
while ( inputIt.nextFeature( f ) )
@ -576,7 +539,8 @@ bool QgsClipAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFe
QgsFeature outputFeature;
outputFeature.setGeometry( newGeometry );
outputFeature.setAttributes( inputFeature.attributes() );
mSink->addFeature( outputFeature, QgsFeatureSink::FastInsert );
sink->addFeature( outputFeature, QgsFeatureSink::FastInsert );
if ( singleClipFeature )
feedback->setProgress( current * step );
@ -588,17 +552,13 @@ bool QgsClipAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFe
feedback->setProgress( 100.0 * static_cast< double >( i ) / clipGeoms.length() );
}
}
mSink->flushBuffer();
return true;
}
QVariantMap QgsClipAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), mSinkId );
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
return outputs;
}
QgsTransformAlgorithm::QgsTransformAlgorithm()
{
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
@ -619,41 +579,29 @@ QgsTransformAlgorithm *QgsTransformAlgorithm::create() const
return new QgsTransformAlgorithm();
}
bool QgsTransformAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
QVariantMap QgsTransformAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
mSource.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !mSource )
return false;
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !source )
return QVariantMap();
mCrs = parameterAsCrs( parameters, QStringLiteral( "TARGET_CRS" ), context );
QgsCoordinateReferenceSystem targetCrs = parameterAsCrs( parameters, QStringLiteral( "TARGET_CRS" ), context );
mSink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, mSinkId, mSource->fields(), mSource->wkbType(), mCrs ) );
if ( !mSink )
return false;
QString dest;
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(), source->wkbType(), targetCrs ) );
if ( !sink )
return QVariantMap();
return true;
}
QVariantMap QgsTransformAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), mSinkId );
return outputs;
}
bool QgsTransformAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFeedback *feedback )
{
long count = mSource->featureCount();
if ( count == 0 )
return true;
long count = source->featureCount();
if ( count <= 0 )
return QVariantMap();
QgsFeature f;
QgsFeatureRequest req;
// perform reprojection in the iterators...
req.setDestinationCrs( mCrs );
req.setDestinationCrs( targetCrs );
QgsFeatureIterator it = mSource->getFeatures( req );
QgsFeatureIterator it = source->getFeatures( req );
double step = 100.0 / count;
int current = 0;
@ -664,12 +612,14 @@ bool QgsTransformAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcess
break;
}
mSink->addFeature( f, QgsFeatureSink::FastInsert );
sink->addFeature( f, QgsFeatureSink::FastInsert );
feedback->setProgress( current * step );
current++;
}
return true;
QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
return outputs;
}
@ -698,29 +648,25 @@ QgsSubdivideAlgorithm *QgsSubdivideAlgorithm::create() const
return new QgsSubdivideAlgorithm();
}
bool QgsSubdivideAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
QVariantMap QgsSubdivideAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
mSource.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !mSource )
return false;
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !source )
return QVariantMap();
mMaxNodes = parameterAsInt( parameters, QStringLiteral( "MAX_NODES" ), context );
mSink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, mSinkId, mSource->fields(),
QgsWkbTypes::multiType( mSource->wkbType() ), mSource->sourceCrs() ) );
if ( !mSink )
return false;
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();
return true;
}
bool QgsSubdivideAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFeedback *feedback )
{
long count = mSource->featureCount();
if ( count == 0 )
return true;
long count = source->featureCount();
if ( count <= 0 )
return QVariantMap();
QgsFeature f;
QgsFeatureIterator it = mSource->getFeatures();
QgsFeatureIterator it = source->getFeatures();
double step = 100.0 / count;
int current = 0;
@ -734,29 +680,25 @@ bool QgsSubdivideAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcess
QgsFeature out = f;
if ( out.hasGeometry() )
{
out.setGeometry( f.geometry().subdivide( mMaxNodes ) );
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 );
}
}
mSink->addFeature( out, QgsFeatureSink::FastInsert );
sink->addFeature( out, QgsFeatureSink::FastInsert );
feedback->setProgress( current * step );
current++;
}
mSink->flushBuffer();
return true;
}
QVariantMap QgsSubdivideAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), mSinkId );
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
return outputs;
}
QgsMultipartToSinglepartAlgorithm::QgsMultipartToSinglepartAlgorithm()
{
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
@ -777,30 +719,26 @@ QgsMultipartToSinglepartAlgorithm *QgsMultipartToSinglepartAlgorithm::create() c
return new QgsMultipartToSinglepartAlgorithm();
}
bool QgsMultipartToSinglepartAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
QVariantMap QgsMultipartToSinglepartAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
mSource.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !mSource )
return false;
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !source )
return QVariantMap();
QgsWkbTypes::Type sinkType = QgsWkbTypes::singleType( mSource->wkbType() );
QgsWkbTypes::Type sinkType = QgsWkbTypes::singleType( source->wkbType() );
mSink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, mSinkId, mSource->fields(),
sinkType, mSource->sourceCrs() ) );
if ( !mSink )
return false;
QString dest;
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(),
sinkType, source->sourceCrs() ) );
if ( !sink )
return QVariantMap();
return true;
}
bool QgsMultipartToSinglepartAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFeedback *feedback )
{
long count = mSource->featureCount();
if ( count == 0 )
return true;
long count = source->featureCount();
if ( count <= 0 )
return QVariantMap();
QgsFeature f;
QgsFeatureIterator it = mSource->getFeatures();
QgsFeatureIterator it = source->getFeatures();
double step = 100.0 / count;
int current = 0;
@ -820,34 +758,30 @@ bool QgsMultipartToSinglepartAlgorithm::processAlgorithm( QgsProcessingContext &
Q_FOREACH ( const QgsGeometry &g, inputGeometry.asGeometryCollection() )
{
out.setGeometry( g );
mSink->addFeature( out, QgsFeatureSink::FastInsert );
sink->addFeature( out, QgsFeatureSink::FastInsert );
}
}
else
{
mSink->addFeature( out, QgsFeatureSink::FastInsert );
sink->addFeature( out, QgsFeatureSink::FastInsert );
}
}
else
{
// feature with null geometry
mSink->addFeature( out, QgsFeatureSink::FastInsert );
sink->addFeature( out, QgsFeatureSink::FastInsert );
}
feedback->setProgress( current * step );
current++;
}
mSink->flushBuffer();
return true;
}
QVariantMap QgsMultipartToSinglepartAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), mSinkId );
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
return outputs;
}
QgsExtractByExpressionAlgorithm::QgsExtractByExpressionAlgorithm()
{
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
@ -872,50 +806,47 @@ QgsExtractByExpressionAlgorithm *QgsExtractByExpressionAlgorithm::create() const
return new QgsExtractByExpressionAlgorithm();
}
bool QgsExtractByExpressionAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
QVariantMap QgsExtractByExpressionAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
mSource.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !mSource )
return false;
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !source )
return QVariantMap();
mExpressionString = parameterAsExpression( parameters, QStringLiteral( "EXPRESSION" ), context );
QString expressionString = parameterAsExpression( parameters, QStringLiteral( "EXPRESSION" ), context );
mMatchingSink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, mMatchingSinkId, mSource->fields(),
mSource->wkbType(), mSource->sourceCrs() ) );
if ( !mMatchingSink )
return false;
QString matchingSinkId;
std::unique_ptr< QgsFeatureSink > matchingSink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, matchingSinkId, source->fields(),
source->wkbType(), source->sourceCrs() ) );
if ( !matchingSink )
return QVariantMap();
mNonMatchingSink.reset( parameterAsSink( parameters, QStringLiteral( "FAIL_OUTPUT" ), context, mNonMatchingSinkId, mSource->fields(),
mSource->wkbType(), mSource->sourceCrs() ) );
QString nonMatchingSinkId;
std::unique_ptr< QgsFeatureSink > nonMatchingSink( parameterAsSink( parameters, QStringLiteral( "FAIL_OUTPUT" ), context, nonMatchingSinkId, source->fields(),
source->wkbType(), source->sourceCrs() ) );
mExpressionContext = createExpressionContext( parameters, context );
return true;
}
bool QgsExtractByExpressionAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFeedback *feedback )
{
QgsExpression expression( mExpressionString );
QgsExpression expression( expressionString );
if ( expression.hasParserError() )
{
throw QgsProcessingException( expression.parserErrorString() );
}
QgsExpressionContext expressionContext = createExpressionContext( parameters, context );
long count = mSource->featureCount();
if ( count == 0 )
return true;
long count = source->featureCount();
if ( count <= 0 )
return QVariantMap();
double step = 100.0 / count;
int current = 0;
if ( !mNonMatchingSink )
if ( !nonMatchingSink )
{
// not saving failing features - so only fetch good features
QgsFeatureRequest req;
req.setFilterExpression( mExpressionString );
req.setExpressionContext( mExpressionContext );
req.setFilterExpression( expressionString );
req.setExpressionContext( expressionContext );
QgsFeatureIterator it = mSource->getFeatures( req );
QgsFeatureIterator it = source->getFeatures( req );
QgsFeature f;
while ( it.nextFeature( f ) )
{
@ -924,7 +855,7 @@ bool QgsExtractByExpressionAlgorithm::processAlgorithm( QgsProcessingContext &,
break;
}
mMatchingSink->addFeature( f, QgsFeatureSink::FastInsert );
matchingSink->addFeature( f, QgsFeatureSink::FastInsert );
feedback->setProgress( current * step );
current++;
@ -933,10 +864,10 @@ bool QgsExtractByExpressionAlgorithm::processAlgorithm( QgsProcessingContext &,
else
{
// saving non-matching features, so we need EVERYTHING
mExpressionContext.setFields( mSource->fields() );
expression.prepare( &mExpressionContext );
expressionContext.setFields( source->fields() );
expression.prepare( &expressionContext );
QgsFeatureIterator it = mSource->getFeatures();
QgsFeatureIterator it = source->getFeatures();
QgsFeature f;
while ( it.nextFeature( f ) )
{
@ -945,37 +876,30 @@ bool QgsExtractByExpressionAlgorithm::processAlgorithm( QgsProcessingContext &,
break;
}
mExpressionContext.setFeature( f );
if ( expression.evaluate( &mExpressionContext ).toBool() )
expressionContext.setFeature( f );
if ( expression.evaluate( &expressionContext ).toBool() )
{
mMatchingSink->addFeature( f, QgsFeatureSink::FastInsert );
matchingSink->addFeature( f, QgsFeatureSink::FastInsert );
}
else
{
mNonMatchingSink->addFeature( f, QgsFeatureSink::FastInsert );
nonMatchingSink->addFeature( f, QgsFeatureSink::FastInsert );
}
feedback->setProgress( current * step );
current++;
}
}
if ( mMatchingSink )
mMatchingSink->flushBuffer();
if ( mNonMatchingSink )
mNonMatchingSink->flushBuffer();
return true;
}
QVariantMap QgsExtractByExpressionAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), mMatchingSinkId );
if ( !mNonMatchingSinkId.isEmpty() )
outputs.insert( QStringLiteral( "FAIL_OUTPUT" ), mNonMatchingSinkId );
outputs.insert( QStringLiteral( "OUTPUT" ), matchingSinkId );
if ( nonMatchingSink )
outputs.insert( QStringLiteral( "FAIL_OUTPUT" ), nonMatchingSinkId );
return outputs;
}
QgsExtractByAttributeAlgorithm::QgsExtractByAttributeAlgorithm()
{
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
@ -1013,38 +937,34 @@ QgsExtractByAttributeAlgorithm *QgsExtractByAttributeAlgorithm::create() const
return new QgsExtractByAttributeAlgorithm();
}
bool QgsExtractByAttributeAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
QVariantMap QgsExtractByAttributeAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
mSource.reset( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !mSource )
return false;
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !source )
return QVariantMap();
mFieldName = parameterAsString( parameters, QStringLiteral( "FIELD" ), context );
mOp = static_cast< Operation >( parameterAsEnum( parameters, QStringLiteral( "OPERATOR" ), context ) );
mValue = parameterAsString( parameters, QStringLiteral( "VALUE" ), context );
QString fieldName = parameterAsString( parameters, QStringLiteral( "FIELD" ), context );
Operation op = static_cast< Operation >( parameterAsEnum( parameters, QStringLiteral( "OPERATOR" ), context ) );
QString value = parameterAsString( parameters, QStringLiteral( "VALUE" ), context );
mMatchingSink.reset( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, mMatchingSinkId, mSource->fields(),
mSource->wkbType(), mSource->sourceCrs() ) );
if ( !mMatchingSink )
return false;
QString matchingSinkId;
std::unique_ptr< QgsFeatureSink > matchingSink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, matchingSinkId, source->fields(),
source->wkbType(), source->sourceCrs() ) );
if ( !matchingSink )
return QVariantMap();
mNonMatchingSink.reset( parameterAsSink( parameters, QStringLiteral( "FAIL_OUTPUT" ), context, mNonMatchingSinkId, mSource->fields(),
mSource->wkbType(), mSource->sourceCrs() ) );
QString nonMatchingSinkId;
std::unique_ptr< QgsFeatureSink > nonMatchingSink( parameterAsSink( parameters, QStringLiteral( "FAIL_OUTPUT" ), context, nonMatchingSinkId, source->fields(),
source->wkbType(), source->sourceCrs() ) );
mExpressionContext = createExpressionContext( parameters, context );
return true;
}
int idx = source->fields().lookupField( fieldName );
QVariant::Type fieldType = source->fields().at( idx ).type();
bool QgsExtractByAttributeAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessingFeedback *feedback )
{
int idx = mSource->fields().lookupField( mFieldName );
QVariant::Type fieldType = mSource->fields().at( idx ).type();
if ( fieldType != QVariant::String && ( mOp == BeginsWith || mOp == Contains || mOp == DoesNotContain ) )
if ( fieldType != QVariant::String && ( op == BeginsWith || op == Contains || op == DoesNotContain ) )
{
QString method;
switch ( mOp )
switch ( op )
{
case BeginsWith:
method = QObject::tr( "begins with" );
@ -1063,10 +983,10 @@ bool QgsExtractByAttributeAlgorithm::processAlgorithm( QgsProcessingContext &, Q
throw QgsProcessingException( QObject::tr( "Operator '%1' can be used only with string fields." ).arg( method ) );
}
QString fieldRef = QgsExpression::quotedColumnRef( mFieldName );
QString quotedVal = QgsExpression::quotedValue( mValue );
QString fieldRef = QgsExpression::quotedColumnRef( fieldName );
QString quotedVal = QgsExpression::quotedValue( value );
QString expr;
switch ( mOp )
switch ( op )
{
case Equals:
expr = QStringLiteral( "%1 = %3" ).arg( fieldRef, quotedVal );
@ -1087,10 +1007,10 @@ bool QgsExtractByAttributeAlgorithm::processAlgorithm( QgsProcessingContext &, Q
expr = QStringLiteral( "%1 <= %3" ).arg( fieldRef, quotedVal );
break;
case BeginsWith:
expr = QStringLiteral( "%1 LIKE '%2%'" ).arg( fieldRef, mValue );
expr = QStringLiteral( "%1 LIKE '%2%'" ).arg( fieldRef, value );
break;
case Contains:
expr = QStringLiteral( "%1 LIKE '%%2%'" ).arg( fieldRef, mValue );
expr = QStringLiteral( "%1 LIKE '%%2%'" ).arg( fieldRef, value );
break;
case IsNull:
expr = QStringLiteral( "%1 IS NULL" ).arg( fieldRef );
@ -1099,31 +1019,34 @@ bool QgsExtractByAttributeAlgorithm::processAlgorithm( QgsProcessingContext &, Q
expr = QStringLiteral( "%1 IS NOT NULL" ).arg( fieldRef );
break;
case DoesNotContain:
expr = QStringLiteral( "%1 NOT LIKE '%%2%'" ).arg( fieldRef, mValue );
expr = QStringLiteral( "%1 NOT LIKE '%%2%'" ).arg( fieldRef, value );
break;
}
QgsExpression expression( expr );
if ( expression.hasParserError() )
{
throw QgsProcessingException( expression.parserErrorString() );
// raise GeoAlgorithmExecutionException(expression.parserErrorString())
return QVariantMap();
}
long count = mSource->featureCount();
if ( count == 0 )
return true;
QgsExpressionContext expressionContext = createExpressionContext( parameters, context );
long count = source->featureCount();
if ( count <= 0 )
return QVariantMap();
double step = 100.0 / count;
int current = 0;
if ( !mNonMatchingSink )
if ( !nonMatchingSink )
{
// not saving failing features - so only fetch good features
QgsFeatureRequest req;
req.setFilterExpression( expr );
req.setExpressionContext( mExpressionContext );
req.setExpressionContext( expressionContext );
QgsFeatureIterator it = mSource->getFeatures( req );
QgsFeatureIterator it = source->getFeatures( req );
QgsFeature f;
while ( it.nextFeature( f ) )
{
@ -1132,7 +1055,7 @@ bool QgsExtractByAttributeAlgorithm::processAlgorithm( QgsProcessingContext &, Q
break;
}
mMatchingSink->addFeature( f, QgsFeatureSink::FastInsert );
matchingSink->addFeature( f, QgsFeatureSink::FastInsert );
feedback->setProgress( current * step );
current++;
@ -1141,10 +1064,10 @@ bool QgsExtractByAttributeAlgorithm::processAlgorithm( QgsProcessingContext &, Q
else
{
// saving non-matching features, so we need EVERYTHING
mExpressionContext.setFields( mSource->fields() );
expression.prepare( &mExpressionContext );
expressionContext.setFields( source->fields() );
expression.prepare( &expressionContext );
QgsFeatureIterator it = mSource->getFeatures();
QgsFeatureIterator it = source->getFeatures();
QgsFeature f;
while ( it.nextFeature( f ) )
{
@ -1153,14 +1076,14 @@ bool QgsExtractByAttributeAlgorithm::processAlgorithm( QgsProcessingContext &, Q
break;
}
mExpressionContext.setFeature( f );
if ( expression.evaluate( &mExpressionContext ).toBool() )
expressionContext.setFeature( f );
if ( expression.evaluate( &expressionContext ).toBool() )
{
mMatchingSink->addFeature( f, QgsFeatureSink::FastInsert );
matchingSink->addFeature( f, QgsFeatureSink::FastInsert );
}
else
{
mNonMatchingSink->addFeature( f, QgsFeatureSink::FastInsert );
nonMatchingSink->addFeature( f, QgsFeatureSink::FastInsert );
}
feedback->setProgress( current * step );
@ -1168,21 +1091,12 @@ bool QgsExtractByAttributeAlgorithm::processAlgorithm( QgsProcessingContext &, Q
}
}
if ( mMatchingSink )
mMatchingSink->flushBuffer();
if ( mNonMatchingSink )
mNonMatchingSink->flushBuffer();
return true;
}
QVariantMap QgsExtractByAttributeAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), mMatchingSinkId );
if ( !mNonMatchingSinkId.isEmpty() )
outputs.insert( QStringLiteral( "FAIL_OUTPUT" ), mNonMatchingSinkId );
outputs.insert( QStringLiteral( "OUTPUT" ), matchingSinkId );
if ( nonMatchingSink )
outputs.insert( QStringLiteral( "FAIL_OUTPUT" ), nonMatchingSinkId );
return outputs;
}
///@endcond

View File

@ -64,16 +64,9 @@ class QgsCentroidAlgorithm : public QgsProcessingAlgorithm
protected:
bool prepareAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private:
std::unique_ptr< QgsFeatureSource > mSource;
std::unique_ptr< QgsFeatureSink > mSink;
QString mSinkId;
};
/**
@ -95,17 +88,9 @@ class QgsTransformAlgorithm : public QgsProcessingAlgorithm
protected:
bool prepareAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private:
std::unique_ptr< QgsFeatureSource > mSource;
std::unique_ptr< QgsFeatureSink > mSink;
QString mSinkId;
QgsCoordinateReferenceSystem mCrs;
};
/**
@ -127,27 +112,9 @@ class QgsBufferAlgorithm : public QgsProcessingAlgorithm
protected:
bool prepareAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private:
std::unique_ptr< QgsFeatureSource > mSource;
std::unique_ptr< QgsFeatureSink > mSink;
QString mSinkId;
bool mDissolve = false;
int mSegments = 8;
QgsGeometry::EndCapStyle mEndCapStyle = QgsGeometry::CapRound;
QgsGeometry::JoinStyle mJoinStyle = QgsGeometry::JoinStyleRound;
double mMiterLimit = 1;
double mBufferDistance = 1;
bool mDynamicBuffer = false;
QgsProperty mDynamicBufferProperty;
QVariantMap mDynamicParams;
double mDefaultBuffer;
QgsExpressionContext mExpContext;
};
/**
@ -169,17 +136,8 @@ class QgsDissolveAlgorithm : public QgsProcessingAlgorithm
protected:
bool prepareAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private:
std::unique_ptr< QgsFeatureSource > mSource;
std::unique_ptr< QgsFeatureSink > mSink;
QString mSinkId;
QStringList mFields;
virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
};
@ -217,22 +175,9 @@ class QgsExtractByAttributeAlgorithm : public QgsProcessingAlgorithm
protected:
bool prepareAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private:
std::unique_ptr< QgsFeatureSource > mSource;
std::unique_ptr< QgsFeatureSink > mMatchingSink;
QString mMatchingSinkId;
std::unique_ptr< QgsFeatureSink > mNonMatchingSink;
QString mNonMatchingSinkId;
QString mFieldName;
Operation mOp;
QString mValue;
QgsExpressionContext mExpressionContext;
};
/**
@ -254,20 +199,9 @@ class QgsExtractByExpressionAlgorithm : public QgsProcessingAlgorithm
protected:
bool prepareAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private:
std::unique_ptr< QgsFeatureSource > mSource;
std::unique_ptr< QgsFeatureSink > mMatchingSink;
QString mMatchingSinkId;
std::unique_ptr< QgsFeatureSink > mNonMatchingSink;
QString mNonMatchingSinkId;
QString mExpressionString;
QgsExpressionContext mExpressionContext;
};
/**
@ -289,18 +223,8 @@ class QgsClipAlgorithm : public QgsProcessingAlgorithm
protected:
bool prepareAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private:
std::unique_ptr< QgsFeatureSource > mFeatureSource;
std::unique_ptr< QgsFeatureSource > mMaskSource;
std::unique_ptr< QgsFeatureSink > mSink;
QString mSinkId;
virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
};
@ -324,17 +248,8 @@ class QgsSubdivideAlgorithm : public QgsProcessingAlgorithm
protected:
bool prepareAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private:
std::unique_ptr< QgsFeatureSource > mSource;
std::unique_ptr< QgsFeatureSink > mSink;
QString mSinkId;
int mMaxNodes = 64;
virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
};
@ -357,16 +272,9 @@ class QgsMultipartToSinglepartAlgorithm : public QgsProcessingAlgorithm
protected:
bool prepareAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private:
std::unique_ptr< QgsFeatureSource > mSource;
std::unique_ptr< QgsFeatureSink > mSink;
QString mSinkId;
};
///@endcond PRIVATE

View File

@ -265,6 +265,11 @@ bool QgsProcessingAlgorithm::prepareAlgorithm( const QVariantMap &, QgsProcessin
return true;
}
QVariantMap QgsProcessingAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
return QVariantMap();
}
const QgsProcessingParameterDefinition *QgsProcessingAlgorithm::parameterDefinition( const QString &name ) const
{
Q_FOREACH ( const QgsProcessingParameterDefinition *def, mParameters )
@ -329,14 +334,19 @@ QVariantMap QgsProcessingAlgorithm::run( const QVariantMap &parameters, QgsProce
if ( !res )
return QVariantMap();
res = alg->runPrepared( context, feedback );
if ( !res )
QVariantMap runRes = alg->runPrepared( parameters, context, feedback );
if ( !alg->mHasExecuted )
return QVariantMap();
if ( ok )
*ok = true;
return alg->postProcess( context, feedback );
QVariantMap ppRes = alg->postProcess( context, feedback );
if ( !ppRes.isEmpty() )
return ppRes;
else
return runRes;
}
bool QgsProcessingAlgorithm::prepare( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
@ -356,9 +366,9 @@ bool QgsProcessingAlgorithm::prepare( const QVariantMap &parameters, QgsProcessi
}
}
bool QgsProcessingAlgorithm::runPrepared( QgsProcessingContext &context, QgsProcessingFeedback *feedback )
QVariantMap QgsProcessingAlgorithm::runPrepared( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
Q_ASSERT_X( mHasPrepared, "QgsProcessingAlgorithm::runPrepared", "prepare() was not called for the algorithm instance" );
Q_ASSERT_X( mHasPrepared, "QgsProcessingAlgorithm::runPrepared", QString( "prepare() was not called for the algorithm instance %1" ).arg( name() ).toLatin1() );
Q_ASSERT_X( !mHasExecuted, "QgsProcessingAlgorithm::runPrepared", "runPrepared() was already called for this algorithm instance" );
// Hey kids, let's all be thread safe! It's the fun thing to do!
@ -388,8 +398,9 @@ bool QgsProcessingAlgorithm::runPrepared( QgsProcessingContext &context, QgsProc
try
{
mHasExecuted = processAlgorithm( *runContext, feedback );
QVariantMap runResults = processAlgorithm( parameters, *runContext, feedback );
mHasExecuted = true;
if ( mLocalContext )
{
// ok, time to clean things up. We need to push the temporary context back into
@ -397,7 +408,7 @@ bool QgsProcessingAlgorithm::runPrepared( QgsProcessingContext &context, QgsProc
// current thread, so we HAVE to do this here)
mLocalContext->pushToThread( context.thread() );
}
return mHasExecuted;
return runResults;
}
catch ( QgsProcessingException &e )
{
@ -409,14 +420,14 @@ bool QgsProcessingAlgorithm::runPrepared( QgsProcessingContext &context, QgsProc
// see above!
mLocalContext->pushToThread( context.thread() );
}
return false;
return QVariantMap();
}
}
QVariantMap QgsProcessingAlgorithm::postProcess( QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
Q_ASSERT_X( QThread::currentThread() == context.temporaryLayerStore()->thread(), "QgsProcessingAlgorithm::postProcess", "postProcess() must be called from the same thread the context was created in" );
Q_ASSERT_X( mHasExecuted, "QgsProcessingAlgorithm::postProcess", "runPrepared() was not called for the algorithm instance" );
Q_ASSERT_X( mHasExecuted, "QgsProcessingAlgorithm::postProcess", QString( "algorithm instance %1 was not executed" ).arg( name() ).toLatin1() );
Q_ASSERT_X( !mHasPostProcessed, "QgsProcessingAlgorithm::postProcess", "postProcess() was already called for this algorithm instance" );
if ( mLocalContext )

View File

@ -265,7 +265,7 @@ class CORE_EXPORT QgsProcessingAlgorithm
* on algorithms directly retrieved from QgsProcessingRegistry and QgsProcessingProvider. Instead, a copy
* of the algorithm should be created with clone() and prepare()/runPrepared() called on the copy.
*/
bool runPrepared( QgsProcessingContext &context, QgsProcessingFeedback *feedback );
QVariantMap runPrepared( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback );
/**
* Should be called in the main thread following the completion of runPrepared(). This method
@ -371,7 +371,7 @@ class CORE_EXPORT QgsProcessingAlgorithm
* \see prepareAlgorithm()
* \see postProcessAlgorithm()
*/
virtual bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) = 0 SIP_VIRTUALERRORHANDLER( processing_exception_handler );
virtual QVariantMap processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) = 0 SIP_VIRTUALERRORHANDLER( processing_exception_handler );
/**
* Allows the algorithm to perform any required cleanup tasks. The returned variant map
@ -389,7 +389,7 @@ class CORE_EXPORT QgsProcessingAlgorithm
* \see prepareAlgorithm()
* \see processAlgorithm()
*/
virtual QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) = 0 SIP_VIRTUALERRORHANDLER( processing_exception_handler );
virtual QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) SIP_VIRTUALERRORHANDLER( processing_exception_handler );
/**
* Evaluates the parameter with matching \a name to a static string value.

View File

@ -24,6 +24,7 @@
QgsProcessingAlgRunnerTask::QgsProcessingAlgRunnerTask( const QgsProcessingAlgorithm *algorithm, const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
: QgsTask( tr( "Running %1" ).arg( algorithm->name() ), QgsTask::CanCancel )
, mParameters( parameters )
, mContext( context )
, mFeedback( feedback )
, mAlgorithm( algorithm->create() )
@ -33,7 +34,7 @@ QgsProcessingAlgRunnerTask::QgsProcessingAlgRunnerTask( const QgsProcessingAlgor
mOwnedFeedback.reset( new QgsProcessingFeedback() );
mFeedback = mOwnedFeedback.get();
}
if ( !mAlgorithm->prepare( parameters, context, mFeedback ) )
if ( !mAlgorithm->prepare( mParameters, context, mFeedback ) )
cancel();
}
@ -48,7 +49,8 @@ bool QgsProcessingAlgRunnerTask::run()
bool ok = false;
try
{
ok = mAlgorithm->runPrepared( mContext, mFeedback );
mResults = mAlgorithm->runPrepared( mParameters, mContext, mFeedback );
ok = true;
}
catch ( QgsProcessingException & )
{
@ -60,9 +62,10 @@ bool QgsProcessingAlgRunnerTask::run()
void QgsProcessingAlgRunnerTask::finished( bool result )
{
Q_UNUSED( result );
QVariantMap ppResults;
if ( result )
{
mResults = mAlgorithm->postProcess( mContext, mFeedback );
ppResults = mAlgorithm->postProcess( mContext, mFeedback );
}
emit executed( result, mResults );
emit executed( result, !ppResults.isEmpty() ? ppResults : mResults );
}

View File

@ -65,6 +65,7 @@ class CORE_EXPORT QgsProcessingAlgRunnerTask : public QgsTask
private:
QVariantMap mParameters;
QVariantMap mResults;
QgsProcessingContext &mContext;
QgsProcessingFeedback *mFeedback = nullptr;

View File

@ -472,7 +472,7 @@ bool QgsProcessingModelAlgorithm::childOutputIsRequired( const QString &childId,
return false;
}
bool QgsProcessingModelAlgorithm::processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback )
QVariantMap QgsProcessingModelAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
QSet< QString > toExecute;
QMap< QString, ChildAlgorithm >::const_iterator childIt = mChildAlgorithms.constBegin();
@ -515,7 +515,7 @@ bool QgsProcessingModelAlgorithm::processAlgorithm( QgsProcessingContext &contex
const ChildAlgorithm &child = mChildAlgorithms[ childId ];
QVariantMap childParams = parametersForChildAlgorithm( child, mInputParameters, childResults );
QVariantMap childParams = parametersForChildAlgorithm( child, parameters, childResults );
feedback->setProgressText( QObject::tr( "Running %1 [%2/%3]" ).arg( child.description() ).arg( executed.count() + 1 ).arg( toExecute.count() ) );
//feedback->pushDebugInfo( "Parameters: " + ', '.join( [str( p ).strip() +
// '=' + str( p.value ) for p in alg.algorithm.parameters] ) )
@ -551,11 +551,6 @@ bool QgsProcessingModelAlgorithm::processAlgorithm( QgsProcessingContext &contex
feedback->pushDebugInfo( QObject::tr( "Model processed OK. Executed %1 algorithms total in %2 s." ).arg( executed.count() ).arg( totalTime.elapsed() / 1000.0 ) );
mResults = finalResults;
return true;
}
QVariantMap QgsProcessingModelAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
return mResults;
}
@ -655,12 +650,6 @@ QString QgsProcessingModelAlgorithm::asPythonCode() const
return lines.join( '\n' );
}
bool QgsProcessingModelAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &, QgsProcessingFeedback * )
{
mInputParameters = parameters;
return true;
}
QVariantMap QgsProcessingModelAlgorithm::helpContent() const
{
return mHelpContent;

View File

@ -826,10 +826,7 @@ class CORE_EXPORT QgsProcessingModelAlgorithm : public QgsProcessingAlgorithm
protected:
bool prepareAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
bool processAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap postProcessAlgorithm( QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
private:
@ -846,8 +843,6 @@ class CORE_EXPORT QgsProcessingModelAlgorithm : public QgsProcessingAlgorithm
//! Model source file
QString mSourceFile;
QVariantMap mInputParameters;
QVariantMap mResults;
void dependsOnChildAlgorithmsRecursive( const QString &childId, QSet<QString> &depends ) const;

View File

@ -42,9 +42,7 @@ class DummyAlgorithm : public QgsProcessingAlgorithm
QString name() const override { return mName; }
QString displayName() const override { return mName; }
bool processAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * ) override { return true; }
bool prepareAlgorithm( const QVariantMap &, QgsProcessingContext &, QgsProcessingFeedback * ) override { return true; }
QVariantMap postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * ) override { return QVariantMap(); }
QVariantMap processAlgorithm( const QVariantMap &, QgsProcessingContext &, QgsProcessingFeedback * ) override { return QVariantMap(); }
virtual Flags flags() const override { return mFlags; }
DummyAlgorithm *create() const override { return new DummyAlgorithm( name() ); }