Upgrade ported python algs to be thread ready

This commit is contained in:
Nyall Dawson 2017-06-28 19:55:08 +10:00
parent c2621b1275
commit cd7776ca1c
36 changed files with 912 additions and 576 deletions

View File

@ -74,28 +74,38 @@ 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 processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT_LAYER, 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)
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)
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())
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
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
def processAlgorithm(self, context, feedback):
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
for current, input_feature in enumerate(features):
if feedback.isCanceled():
@ -106,7 +116,10 @@ class AddTableField(QgisAlgorithm):
attributes.append(None)
output_feature.setAttributes(attributes)
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
self.sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return {self.OUTPUT_LAYER: dest_id}
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT_LAYER: self.dest_id}

View File

@ -47,7 +47,7 @@ pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
class Aspect(QgisAlgorithm):
INPUT_LAYER = 'INPUT_LAYER'
INPUT = 'INPUT'
Z_FACTOR = 'Z_FACTOR'
OUTPUT_LAYER = 'OUTPUT_LAYER'
@ -60,13 +60,18 @@ class Aspect(QgisAlgorithm):
def __init__(self):
super().__init__()
self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT_LAYER,
self.addParameter(QgsProcessingParameterRasterLayer(self.INPUT,
self.tr('Elevation layer')))
self.addParameter(QgsProcessingParameterNumber(self.Z_FACTOR,
self.tr('Z factor'), QgsProcessingParameterNumber.Double,
1, False, 1, 999999.99))
self.addParameter(QgsProcessingParameterRasterOutput(self.OUTPUT_LAYER, self.tr('Aspect')))
self.addOutput(QgsProcessingOutputRasterLayer(self.OUTPUT_LAYER, self.tr('Aspect')))
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'
@ -74,16 +79,19 @@ class Aspect(QgisAlgorithm):
def displayName(self):
return self.tr('Aspect')
def processAlgorithm(self, parameters, context, feedback):
inputFile = exportRasterLayer(self.parameterAsRasterLayer(parameters, self.INPUT_LAYER, context))
zFactor = self.parameterAsDouble(parameters, self.Z_FACTOR, context)
def prepareAlgorithm(self, parameters, context, feedback):
self.inputFile = exportRasterLayer(self.parameterAsRasterLayer(parameters, self.INPUT, context))
self.zFactor = self.parameterAsDouble(parameters, self.Z_FACTOR, context)
outputFile = self.parameterAsRasterOutputLayer(parameters, self.OUTPUT_LAYER, context)
self.outputFile = self.parameterAsRasterOutputLayer(parameters, self.OUTPUT, context)
outputFormat = raster.formatShortNameFromFileName(outputFile)
self.outputFormat = raster.formatShortNameFromFileName(self.outputFile)
return True
aspect = QgsAspectFilter(inputFile, outputFile, outputFormat)
aspect.setZFactor(zFactor)
aspect.processRaster(feedback)
def processAlgorithm(self, context, feedback):
aspect = QgsAspectFilter(self.inputFile, self.outputFile, self.outputFormat)
aspect.setZFactor(self.zFactor)
return aspect.processRaster(feedback) == 0
return {self.OUTPUT_LAYER: outputFile}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.outputFile}

View File

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

View File

@ -119,42 +119,52 @@ 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 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))
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))
output_file = self.parameterAsFileOutput(parameters, self.OUTPUT_HTML_FILE, context)
self.output_file = self.parameterAsFileOutput(parameters, self.OUTPUT_HTML_FILE, context)
return True
request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry).setSubsetOfAttributes([field_name], source.fields())
features = source.getFeatures(request)
count = source.featureCount()
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()
data = []
data.append(self.tr('Analyzed field: {}').format(field_name))
results = {}
data.append(self.tr('Analyzed field: {}').format(self.field_name))
if field.isNumeric():
d, results = self.calcNumericStats(features, feedback, field, count)
if self.field.isNumeric():
d, self.results = self.calcNumericStats(features, feedback, self.field, count)
data.extend(d)
elif field.type() in (QVariant.Date, QVariant.Time, QVariant.DateTime):
d, results = self.calcDateTimeStats(features, feedback, field, count)
elif self.field.type() in (QVariant.Date, QVariant.Time, QVariant.DateTime):
d, self.results = self.calcDateTimeStats(features, feedback, self.field, count)
data.extend(d)
else:
d, results = self.calcStringStats(features, feedback, field, count)
d, self.results = self.calcStringStats(features, feedback, self.field, count)
data.extend(d)
if output_file:
self.createHTML(output_file, data)
results[self.OUTPUT_HTML_FILE] = output_file
if self.output_file:
self.createHTML(self.output_file, data)
self.results[self.OUTPUT_HTML_FILE] = self.output_file
return results
return True
def postProcessAlgorithm(self, context, feedback):
return self.results
def calcNumericStats(self, features, feedback, field, count):
total = 100.0 / count if count else 0

View File

@ -58,6 +58,10 @@ 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'))
@ -70,10 +74,11 @@ class Boundary(QgisAlgorithm):
def displayName(self):
return self.tr('Boundary')
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
input_wkb = source.wkbType()
input_wkb = self.source.wkbType()
output_wkb = None
if QgsWkbTypes.geometryType(input_wkb) == QgsWkbTypes.LineGeometry:
output_wkb = QgsWkbTypes.MultiPoint
elif QgsWkbTypes.geometryType(input_wkb) == QgsWkbTypes.PolygonGeometry:
@ -83,11 +88,13 @@ class Boundary(QgisAlgorithm):
if QgsWkbTypes.hasM(input_wkb):
output_wkb = QgsWkbTypes.addM(output_wkb)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context,
source.fields(), output_wkb, source.sourceCrs())
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context,
self.source.fields(), output_wkb, self.source.sourceCrs())
return True
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
def processAlgorithm(self, context, feedback):
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
for current, input_feature in enumerate(features):
if feedback.isCanceled():
@ -102,7 +109,9 @@ class Boundary(QgisAlgorithm):
output_feature.setGeometry(output_geometry)
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
self.sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return True
return {self.OUTPUT_LAYER: dest_id}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT_LAYER: self.dest_id}

View File

@ -66,20 +66,26 @@ 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 processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context,
source.fields(), QgsWkbTypes.Polygon, source.sourceCrs())
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT_LAYER, context,
self.source.fields(), QgsWkbTypes.Polygon, self.source.sourceCrs())
return True
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
def processAlgorithm(self, context, feedback):
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
for current, input_feature in enumerate(features):
if feedback.isCanceled():
@ -94,7 +100,9 @@ class BoundingBox(QgisAlgorithm):
output_feature.setGeometry(output_geometry)
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
self.sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return True
return {self.OUTPUT_LAYER: dest_id}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT_LAYER: self.dest_id}

View File

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

View File

@ -53,27 +53,35 @@ 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 processAlgorithm(self, parameters, context, feedback):
layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
field = self.parameterAsString(parameters, self.FIELD, context)
provider = layer.dataProvider()
def prepareAlgorithm(self, parameters, context, feedback):
self.layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
self.field = self.parameterAsString(parameters, self.FIELD, context)
return True
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))
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))
else:
provider_index = layer.fields().fieldOriginIndex(field_index)
provider_index = self.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
return {self.OUTPUT: layer.id()}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.layer.id()}

View File

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

View File

@ -58,31 +58,40 @@ 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 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
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
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), self.source.wkbType(), self.source.sourceCrs())
return True
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
def processAlgorithm(self, context, feedback):
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
for current, f in enumerate(features):
if feedback.isCanceled():
break
if f.hasGeometry():
f.setGeometry(f.geometry().removeInteriorRings(min_area))
sink.addFeature(f, QgsFeatureSink.FastInsert)
f.setGeometry(f.geometry().removeInteriorRings(self.min_area))
self.sink.addFeature(f, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return True
return {self.OUTPUT: dest_id}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}

View File

@ -63,21 +63,28 @@ 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 processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
vertices = self.parameterAsInt(parameters, self.VERTICES, context)
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context)
self.vertices = self.parameterAsInt(parameters, self.VERTICES, context)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), self.source.wkbType(), self.source.sourceCrs())
return True
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
def processAlgorithm(self, context, feedback):
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
for current, f in enumerate(features):
if feedback.isCanceled():
@ -85,9 +92,11 @@ class DensifyGeometries(QgisAlgorithm):
feature = f
if feature.hasGeometry():
new_geometry = feature.geometry().densifyByCount(vertices)
new_geometry = feature.geometry().densifyByCount(self.vertices)
feature.setGeometry(new_geometry)
sink.addFeature(feature, QgsFeatureSink.FastInsert)
self.sink.addFeature(feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return True
return {self.OUTPUT: dest_id}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}

View File

@ -61,31 +61,40 @@ 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 processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
interval = self.parameterAsDouble(parameters, self.INTERVAL, context)
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context)
self.interval = self.parameterAsDouble(parameters, self.INTERVAL, context)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), self.source.wkbType(), self.source.sourceCrs())
return True
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
def processAlgorithm(self, context, feedback):
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.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(interval))
new_geometry = feature.geometry().densifyByDistance(float(self.interval))
feature.setGeometry(new_geometry)
sink.addFeature(feature, QgsFeatureSink.FastInsert)
self.sink.addFeature(feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return True
return {self.OUTPUT: dest_id}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}

View File

@ -39,8 +39,8 @@ from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
class DropGeometry(QgisAlgorithm):
INPUT_LAYER = 'INPUT_LAYER'
OUTPUT_TABLE = 'OUTPUT_TABLE'
INPUT = 'INPUT'
OUTPUT = 'OUTPUT'
def tags(self):
return self.tr('remove,drop,delete,geometry,objects').split(',')
@ -51,9 +51,13 @@ class DropGeometry(QgisAlgorithm):
def __init__(self):
super().__init__()
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER, self.tr('Input layer'), [QgsProcessingParameterDefinition.TypeVectorPoint, QgsProcessingParameterDefinition.TypeVectorLine, QgsProcessingParameterDefinition.TypeVectorPolygon]))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_TABLE, self.tr('Dropped geometry')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT_TABLE, self.tr("Dropped geometry")))
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'), [QgsProcessingParameterDefinition.TypeVectorPoint, QgsProcessingParameterDefinition.TypeVectorLine, QgsProcessingParameterDefinition.TypeVectorPolygon]))
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'
@ -61,21 +65,26 @@ class DropGeometry(QgisAlgorithm):
def displayName(self):
return self.tr('Drop geometries')
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_TABLE, context,
source.fields(), QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem())
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, context, feedback):
request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry)
features = source.getFeatures(request)
total = 100.0 / source.featureCount() if source.featureCount() else 0
features = self.source.getFeatures(request)
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
for current, input_feature in enumerate(features):
if feedback.isCanceled():
break
input_feature.clearGeometry()
sink.addFeature(input_feature, QgsFeatureSink.FastInsert)
self.sink.addFeature(input_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return {self.OUTPUT_TABLE: dest_id}
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}

View File

@ -79,15 +79,20 @@ 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 processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
byFeature = self.parameterAsBool(parameters, self.BY_FEATURE, context)
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
self.byFeature = self.parameterAsBool(parameters, self.BY_FEATURE, context)
fields = QgsFields()
fields.append(QgsField('MINX', QVariant.Double))
@ -101,15 +106,19 @@ class ExtentFromLayer(QgisAlgorithm):
fields.append(QgsField('HEIGHT', QVariant.Double))
fields.append(QgsField('WIDTH', QVariant.Double))
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.Polygon, source.sourceCrs())
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.Polygon, self.source.sourceCrs())
return True
if byFeature:
self.featureExtent(source, context, sink, feedback)
def processAlgorithm(self, context, feedback):
if self.byFeature:
self.featureExtent(self.source, context, self.sink, feedback)
else:
self.layerExtent(source, sink, feedback)
self.layerExtent(self.source, self.sink, feedback)
return True
return {self.OUTPUT: dest_id}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}
def layerExtent(self, source, sink, feedback):
rect = source.sourceExtent()

View File

@ -55,20 +55,26 @@ 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 processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
def prepareAlgorithm(self, parameters, context, feedback):
self.source = self.parameterAsSource(parameters, self.INPUT, context)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), QgsWkbTypes.multiType(source.wkbType()), source.sourceCrs())
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), QgsWkbTypes.multiType(self.source.wkbType()), self.source.sourceCrs())
return True
features = source.getFeatures(QgsFeatureRequest(), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks)
total = 100.0 / source.featureCount() if source.featureCount() else 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
for current, inputFeature in enumerate(features):
if feedback.isCanceled():
break
@ -86,7 +92,7 @@ class FixGeometry(QgisAlgorithm):
try:
g.convertToMultiType()
outputFeature.setGeometry(QgsGeometry(g))
sink.addFeature(outputFeature, QgsFeatureSink.FastInsert)
self.sink.addFeature(outputFeature, QgsFeatureSink.FastInsert)
except:
pass
feedback.setProgress(int(current * total))
@ -95,7 +101,9 @@ class FixGeometry(QgisAlgorithm):
outputGeometry.convertToMultiType()
outputFeature.setGeometry(outputGeometry)
sink.addFeature(outputFeature, QgsFeatureSink.FastInsert)
self.sink.addFeature(outputFeature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return True
return {self.OUTPUT: dest_id}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}

View File

@ -102,41 +102,52 @@ 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 processAlgorithm(self, parameters, context, feedback):
idx = self.parameterAsEnum(parameters, self.TYPE, context)
def prepareAlgorithm(self, parameters, context, feedback):
self.idx = self.parameterAsEnum(parameters, self.TYPE, 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)
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)
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()
width = bbox.width()
height = bbox.height()
originX = bbox.xMinimum()
originY = bbox.yMaximum()
if hSpacing <= 0 or vSpacing <= 0:
if self.hSpacing <= 0 or self.vSpacing <= 0:
raise GeoAlgorithmExecutionException(
self.tr('Invalid grid spacing: {0}/{1}').format(hSpacing, vSpacing))
self.tr('Invalid grid spacing: {0}/{1}').format(self.hSpacing, self.vSpacing))
if width < hSpacing:
if self.width < self.hSpacing:
raise GeoAlgorithmExecutionException(
self.tr('Horizontal spacing is too small for the covered area'))
if hSpacing <= hOverlay or vSpacing <= vOverlay:
if self.hSpacing <= self.hOverlay or self.vSpacing <= self.vOverlay:
raise GeoAlgorithmExecutionException(
self.tr('Invalid overlay: {0}/{1}').format(hOverlay, vOverlay))
self.tr('Invalid overlay: {0}/{1}').format(self.hOverlay, self.vOverlay))
if height < vSpacing:
if self.height < self.vSpacing:
raise GeoAlgorithmExecutionException(
self.tr('Vertical spacing is too small for the covered area'))
@ -147,20 +158,24 @@ class GridPolygon(QgisAlgorithm):
fields.append(QgsField('bottom', QVariant.Double, '', 24, 16))
fields.append(QgsField('id', QVariant.Int, '', 10, 0))
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.Polygon, crs)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.Polygon, crs)
return True
if idx == 0:
def processAlgorithm(self, context, feedback):
if self.idx == 0:
self._rectangleGrid(
sink, width, height, originX, originY, hSpacing, vSpacing, hOverlay, vOverlay, feedback)
elif idx == 1:
self.sink, self.width, self.height, self.originX, self.originY, self.hSpacing, self.vSpacing, self.hOverlay, self.vOverlay, feedback)
elif self.idx == 1:
self._diamondGrid(
sink, width, height, originX, originY, hSpacing, vSpacing, hOverlay, vOverlay, feedback)
elif idx == 2:
self.sink, self.width, self.height, self.originX, self.originY, self.hSpacing, self.vSpacing, self.hOverlay, self.vOverlay, feedback)
elif self.idx == 2:
self._hexagonGrid(
sink, width, height, originX, originY, hSpacing, vSpacing, hOverlay, vOverlay, feedback)
self.sink, self.width, self.height, self.originX, self.originY, self.hSpacing, self.vSpacing, self.hOverlay, self.vOverlay, feedback)
return True
return {self.OUTPUT: dest_id}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}
def _rectangleGrid(self, sink, width, height, originX, originY,
hSpacing, vSpacing, hOverlay, vOverlay, feedback):

View File

@ -27,9 +27,7 @@ __revision__ = '$Format:%H$'
from qgis.core import (QgsVectorLayerExporter,
QgsSettings,
QgsApplication,
QgsFeatureSink,
QgsProcessingUtils,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterString,
QgsProcessingParameterField,
@ -38,10 +36,6 @@ from qgis.core import (QgsVectorLayerExporter,
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.parameters import ParameterBoolean
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterString
from processing.core.parameters import ParameterTableField
from processing.tools import postgis
@ -112,70 +106,86 @@ 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 processAlgorithm(self, parameters, context, feedback):
def prepareAlgorithm(self, parameters, context, feedback):
connection = self.parameterAsString(parameters, self.DATABASE, context)
db = postgis.GeoDB.from_name(connection)
self.db = postgis.GeoDB.from_name(connection)
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.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)
source = self.parameterAsSource(parameters, self.INPUT, context)
self.source = self.parameterAsSource(parameters, self.INPUT, context)
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.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'
geomColumn = self.parameterAsString(parameters, self.GEOMETRY_COLUMN, context)
if not geomColumn:
geomColumn = 'geom'
self.geomColumn = self.parameterAsString(parameters, self.GEOMETRY_COLUMN, context)
if not self.geomColumn:
self.geomColumn = 'geom'
return True
def processAlgorithm(self, context, feedback):
options = {}
if overwrite:
if self.overwrite:
options['overwrite'] = True
if convertLowerCase:
if self.convertLowerCase:
options['lowercaseFieldNames'] = True
geomColumn = geomColumn.lower()
if dropStringLength:
self.geomColumn = self.geomColumn.lower()
if self.dropStringLength:
options['dropStringConstraints'] = True
if forceSinglePart:
if self.forceSinglePart:
options['forceSinglePartGeometryType'] = True
# Clear geometry column for non-geometry tables
if source.wkbType() == QgsWkbTypes.NoGeometry:
geomColumn = None
if self.source.wkbType() == QgsWkbTypes.NoGeometry:
self.geomColumn = None
uri = db.uri
uri.setDataSource(schema, table, geomColumn, '', primaryKeyField)
uri = self.db.uri
uri.setDataSource(self.schema, self.table, self.geomColumn, '', self.primaryKeyField)
if encoding:
options['fileEncoding'] = encoding
if self.encoding:
options['fileEncoding'] = self.encoding
exporter = QgsVectorLayerExporter(uri.uri(), providerName, source.fields(),
source.wkbType(), source.sourceCrs(), overwrite, options)
exporter = QgsVectorLayerExporter(uri.uri(), self.providerName, self.source.fields(),
self.source.wkbType(), self.source.sourceCrs(), self.overwrite, options)
if exporter.errorCode() != QgsVectorLayerExporter.NoError:
raise GeoAlgorithmExecutionException(
self.tr('Error importing to PostGIS\n{0}').format(exporter.errorMessage()))
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
for current, f in enumerate(features):
if feedback.isCanceled():
break
@ -190,11 +200,13 @@ class ImportIntoPostGIS(QgisAlgorithm):
raise GeoAlgorithmExecutionException(
self.tr('Error importing to PostGIS\n{0}').format(exporter.errorMessage()))
if geomColumn and createIndex:
db.create_spatial_index(table, schema, geomColumn)
if self.geomColumn and self.createIndex:
self.db.create_spatial_index(self.table, self.schema, self.geomColumn)
db.vacuum_analyze(table, schema)
self.db.vacuum_analyze(self.table, self.schema)
return True
def postProcessAlgorithm(self, context, feedback):
return {}
def dbConnectionNames(self):

View File

@ -28,8 +28,6 @@ __revision__ = '$Format:%H$'
from qgis.core import (QgsDataSourceUri,
QgsFeatureSink,
QgsVectorLayerExporter,
QgsApplication,
QgsProcessingUtils,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterField,
@ -73,13 +71,26 @@ 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 processAlgorithm(self, parameters, context, feedback):
def prepareAlgorithm(self, parameters, context, feedback):
database = self.parameterAsVectorLayer(parameters, self.DATABASE, context)
databaseuri = database.dataProvider().dataSourceUri()
uri = QgsDataSourceUri(databaseuri)
@ -87,61 +98,64 @@ class ImportIntoSpatialite(QgisAlgorithm):
if '|layerid' in databaseuri:
databaseuri = databaseuri[:databaseuri.find('|layerid')]
uri = QgsDataSourceUri('dbname=\'%s\'' % (databaseuri))
db = spatialite.GeoDB(uri)
self.db = spatialite.GeoDB(uri)
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.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)
source = self.parameterAsSource(parameters, self.INPUT, context)
self.source = self.parameterAsSource(parameters, self.INPUT, context)
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.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'
geomColumn = self.parameterAsString(parameters, self.GEOMETRY_COLUMN, context)
if not geomColumn:
geomColumn = 'geom'
self.geomColumn = self.parameterAsString(parameters, self.GEOMETRY_COLUMN, context)
if not self.geomColumn:
self.geomColumn = 'geom'
return True
def processAlgorithm(self, context, feedback):
options = {}
if overwrite:
if self.overwrite:
options['overwrite'] = True
if convertLowerCase:
if self.convertLowerCase:
options['lowercaseFieldNames'] = True
geomColumn = geomColumn.lower()
if dropStringLength:
self.geomColumn = self.geomColumn.lower()
if self.dropStringLength:
options['dropStringConstraints'] = True
if forceSinglePart:
if self.forceSinglePart:
options['forceSinglePartGeometryType'] = True
# Clear geometry column for non-geometry tables
if source.wkbType() == QgsWkbTypes.NoGeometry:
geomColumn = None
if self.source.wkbType() == QgsWkbTypes.NoGeometry:
self.geomColumn = None
uri = db.uri
uri.setDataSource('', table, geomColumn, '', primaryKeyField)
uri = self.db.uri
uri.setDataSource('', self.table, self.geomColumn, '', self.primaryKeyField)
if encoding:
options['fileEncoding'] = encoding
if self.encoding:
options['fileEncoding'] = self.encoding
exporter = QgsVectorLayerExporter(uri.uri(), providerName, source.fields(),
source.wkbType(), source.sourceCrs(), overwrite, options)
exporter = QgsVectorLayerExporter(uri.uri(), self.providerName, self.source.fields(),
self.source.wkbType(), self.source.sourceCrs(), self.overwrite, options)
if exporter.errorCode() != QgsVectorLayerExporter.NoError:
raise GeoAlgorithmExecutionException(
self.tr('Error importing to Spatialite\n{0}').format(exporter.errorMessage()))
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.source.featureCount() else 0
for current, f in enumerate(features):
if feedback.isCanceled():
break
@ -156,7 +170,9 @@ class ImportIntoSpatialite(QgisAlgorithm):
raise GeoAlgorithmExecutionException(
self.tr('Error importing to Spatialite\n{0}').format(exporter.errorMessage()))
if geomColumn and createIndex:
db.create_spatial_index(table, geomColumn)
if self.geomColumn and self.createIndex:
self.db.create_spatial_index(self.table, self.geomColumn)
return True
def postProcessAlgorithm(self, context, feedback):
return {}

View File

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

View File

@ -53,20 +53,28 @@ 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 processAlgorithm(self, parameters, context, feedback):
connection = self.parameterAsString(parameters, self.DATABASE, context)
db = postgis.GeoDB.from_name(connection)
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
sql = self.parameterAsString(parameters, self.SQL, context).replace('\n', ' ')
def processAlgorithm(self, context, feedback):
db = postgis.GeoDB.from_name(self.connection)
try:
db._exec_sql_and_commit(str(sql))
db._exec_sql_and_commit(str(self.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

@ -28,9 +28,7 @@ __revision__ = '$Format:%H$'
import random
from qgis.core import (QgsApplication,
QgsFeatureSink,
QgsProcessingUtils,
from qgis.core import (QgsFeatureSink,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterEnum,
QgsProcessingParameterNumber,
@ -38,7 +36,6 @@ from qgis.core import (QgsApplication,
QgsProcessingOutputVectorLayer)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.outputs import OutputVector
class RandomExtract(QgisAlgorithm):
@ -69,42 +66,54 @@ 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 processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
method = self.parameterAsEnum(parameters, self.METHOD, context)
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()
features = source.getFeatures()
featureCount = source.featureCount()
value = self.parameterAsInt(parameters, self.NUMBER, context)
if method == 0:
if value > featureCount:
if self.method == 0:
if self.value > self.featureCount:
raise GeoAlgorithmExecutionException(
self.tr('Selected number is greater than feature count. '
'Choose a lower value and try again.'))
else:
if value > 100:
if self.value > 100:
raise GeoAlgorithmExecutionException(
self.tr("Percentage can't be greater than 100. Set a "
"different value and try again."))
value = int(round(value / 100.0000, 4) * featureCount)
self.value = int(round(self.value / 100.0000, 4) * self.featureCount)
selran = random.sample(list(range(featureCount)), value)
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), self.source.wkbType(), self.source.sourceCrs())
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
return True
total = 100.0 / featureCount if featureCount else 1
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
for i, feat in enumerate(features):
if feedback.isCanceled():
break
if i in selran:
sink.addFeature(feat, QgsFeatureSink.FastInsert)
self.sink.addFeature(feat, QgsFeatureSink.FastInsert)
feedback.setProgress(int(i * total))
return {self.OUTPUT: dest_id}
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}

View File

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

View File

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

View File

@ -26,12 +26,10 @@ __copyright__ = '(C) 2012, Victor Olaya'
__revision__ = '$Format:%H$'
from qgis.core import (QgsFeatureSink,
QgsProcessingUtils,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterFeatureSink,
QgsProcessingOutputVectorLayer)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
class SaveSelectedFeatures(QgisAlgorithm):
@ -49,27 +47,35 @@ 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 processAlgorithm(self, parameters, context, feedback):
vectorLayer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
def prepareAlgorithm(self, parameters, context, feedback):
self.vectorLayer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
vectorLayer.fields(), vectorLayer.wkbType(), vectorLayer.sourceCrs())
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.vectorLayer.fields(), self.vectorLayer.wkbType(), self.vectorLayer.sourceCrs())
return True
features = vectorLayer.getSelectedFeatures()
count = int(vectorLayer.selectedFeatureCount())
def processAlgorithm(self, context, feedback):
features = self.vectorLayer.getSelectedFeatures()
count = int(self.vectorLayer.selectedFeatureCount())
total = 100.0 / count if count else 1
for current, feat in enumerate(features):
if feedback.isCanceled():
break
sink.addFeature(feat, QgsFeatureSink.FastInsert)
self.sink.addFeature(feat, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return True
return {self.OUTPUT: dest_id}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}

View File

@ -92,47 +92,60 @@ 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 processAlgorithm(self, parameters, context, feedback):
layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
def prepareAlgorithm(self, parameters, context, feedback):
self.layer = self.parameterAsVectorLayer(parameters, self.INPUT, 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.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)
fields = layer.fields()
self.input = parameters[self.INPUT]
return True
idx = layer.fields().lookupField(fieldName)
def processAlgorithm(self, context, feedback):
fields = self.layer.fields()
idx = self.layer.fields().lookupField(self.fieldName)
fieldType = fields[idx].type()
if fieldType != QVariant.String and operator in self.STRING_OPERATORS:
if fieldType != QVariant.String and self.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(fieldName)
quoted_val = QgsExpression.quotedValue(value)
if operator == 'is null':
field_ref = QgsExpression.quotedColumnRef(self.fieldName)
quoted_val = QgsExpression.quotedValue(self.value)
if self.operator == 'is null':
expression_string = '{} IS NULL'.format(field_ref)
elif operator == 'is not null':
elif self.operator == 'is not null':
expression_string = '{} IS NOT NULL'.format(field_ref)
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)
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)
else:
expression_string = '{} {} {}'.format(field_ref, operator, quoted_val)
expression_string = '{} {} {}'.format(field_ref, self.operator, quoted_val)
expression = QgsExpression(expression_string)
if expression.hasParserError():
raise GeoAlgorithmExecutionException(expression.parserErrorString())
layer.selectByExpression(expression_string)
return {self.OUTPUT: parameters[self.INPUT]}
self.layer.selectByExpression(expression_string)
return True
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.input}

View File

@ -60,30 +60,42 @@ 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 processAlgorithm(self, parameters, context, feedback):
layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
def prepareAlgorithm(self, parameters, context, feedback):
self.layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
method = self.parameterAsEnum(parameters, self.METHOD, context)
if method == 0:
behavior = QgsVectorLayer.SetSelection
self.behavior = QgsVectorLayer.SetSelection
elif method == 1:
behavior = QgsVectorLayer.AddToSelection
self.behavior = QgsVectorLayer.AddToSelection
elif method == 2:
behavior = QgsVectorLayer.RemoveFromSelection
self.behavior = QgsVectorLayer.RemoveFromSelection
elif method == 3:
behavior = QgsVectorLayer.IntersectSelection
self.behavior = QgsVectorLayer.IntersectSelection
expression = self.parameterAsString(parameters, self.EXPRESSION, context)
qExp = QgsExpression(expression)
self.expression = self.parameterAsString(parameters, self.EXPRESSION, context)
qExp = QgsExpression(self.expression)
if qExp.hasParserError():
raise GeoAlgorithmExecutionException(qExp.parserErrorString())
layer.selectByExpression(expression, behavior)
return {self.OUTPUT: parameters[self.INPUT]}
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}

View File

@ -76,28 +76,37 @@ 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 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)
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)
(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
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
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
if method != 0:
simplifier = QgsMapToPixelSimplifier(QgsMapToPixelSimplifier.SimplifyGeometry, tolerance, method)
simplifier = None
if self.method != 0:
simplifier = QgsMapToPixelSimplifier(QgsMapToPixelSimplifier.SimplifyGeometry, self.tolerance, self.method)
for current, input_feature in enumerate(features):
if feedback.isCanceled():
@ -107,18 +116,20 @@ class SimplifyGeometries(QgisAlgorithm):
input_geometry = input_feature.geometry()
pointsBefore += input_geometry.geometry().nCoordinates()
if method == 0: # distance
output_geometry = input_geometry.simplify(tolerance)
if self.method == 0: # distance
output_geometry = input_geometry.simplify(self.tolerance)
else:
output_geometry = simplifier.simplify(input_geometry)
pointsAfter += output_geometry.geometry().nCoordinates()
out_feature.setGeometry(output_geometry)
sink.addFeature(out_feature, QgsFeatureSink.FastInsert)
self.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
return {self.OUTPUT: dest_id}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}

View File

@ -66,37 +66,48 @@ 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 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)
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)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
self.source.fields(), self.source.wkbType(), self.source.sourceCrs())
return True
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
def processAlgorithm(self, context, feedback):
features = self.source.getFeatures()
total = 100.0 / self.source.featureCount() if self.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(iterations, offset, -1, max_angle)
output_geometry = input_feature.geometry().smooth(self.iterations, self.offset, -1, self.max_angle)
if not output_geometry:
raise GeoAlgorithmExecutionException(
self.tr('Error smoothing geometry'))
output_feature.setGeometry(output_geometry)
sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
self.sink.addFeature(output_feature, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
return True
return {self.OUTPUT: dest_id}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}

View File

@ -49,26 +49,34 @@ 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 processAlgorithm(self, parameters, context, feedback):
database = self.parameterAsVectorLayer(parameters, self.DATABASE, context)
databaseuri = database.dataProvider().dataSourceUri()
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()
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(sql))
db._exec_sql_and_commit(str(self.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,32 +70,39 @@ 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 processAlgorithm(self, parameters, context, feedback):
sourceA = self.parameterAsSource(parameters, self.INPUT, context)
sourceB = self.parameterAsSource(parameters, self.OVERLAY, context)
def prepareAlgorithm(self, parameters, context, feedback):
self.sourceA = self.parameterAsSource(parameters, self.INPUT, context)
self.sourceB = self.parameterAsSource(parameters, self.OVERLAY, context)
geomType = QgsWkbTypes.multiType(sourceA.wkbType())
fields = vector.combineFields(sourceA.fields(), sourceB.fields())
geomType = QgsWkbTypes.multiType(self.sourceA.wkbType())
fields = vector.combineFields(self.sourceA.fields(), self.sourceB.fields())
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, geomType, sourceA.sourceCrs())
(self.sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, geomType, self.sourceA.sourceCrs())
return True
def processAlgorithm(self, context, feedback):
featB = QgsFeature()
outFeat = QgsFeature()
indexA = QgsSpatialIndex(sourceA)
indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())))
indexA = QgsSpatialIndex(self.sourceA)
indexB = QgsSpatialIndex(self.sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(self.sourceA.sourceCrs())))
total = 100.0 / (sourceA.featureCount() * sourceB.featureCount()) if sourceA.featureCount() and sourceB.featureCount() else 1
total = 100.0 / (self.sourceA.featureCount() * self.sourceB.featureCount()) if self.sourceA.featureCount() and self.sourceB.featureCount() else 1
count = 0
for featA in sourceA.getFeatures():
for featA in self.sourceA.getFeatures():
if feedback.isCanceled():
break
@ -104,8 +111,8 @@ class SymmetricalDifference(QgisAlgorithm):
attrs = featA.attributes()
intersects = indexB.intersects(geom.boundingBox())
request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([])
request.setDestinationCrs(sourceA.sourceCrs())
for featB in sourceB.getFeatures(request):
request.setDestinationCrs(self.sourceA.sourceCrs())
for featB in self.sourceB.getFeatures(request):
if feedback.isCanceled():
break
tmpGeom = featB.geometry()
@ -115,7 +122,7 @@ class SymmetricalDifference(QgisAlgorithm):
try:
outFeat.setGeometry(diffGeom)
outFeat.setAttributes(attrs)
sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
self.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)
@ -124,9 +131,9 @@ class SymmetricalDifference(QgisAlgorithm):
count += 1
feedback.setProgress(int(count * total))
length = len(sourceA.fields())
length = len(self.sourceA.fields())
for featA in sourceB.getFeatures(QgsFeatureRequest().setDestinationCrs(sourceA.sourceCrs())):
for featA in self.sourceB.getFeatures(QgsFeatureRequest().setDestinationCrs(self.sourceA.sourceCrs())):
if feedback.isCanceled():
break
@ -136,7 +143,7 @@ class SymmetricalDifference(QgisAlgorithm):
attrs = [NULL] * length + attrs
intersects = indexA.intersects(geom.boundingBox())
request = QgsFeatureRequest().setFilterFids(intersects).setSubsetOfAttributes([])
for featB in sourceA.getFeatures(request):
for featB in self.sourceA.getFeatures(request):
if feedback.isCanceled():
break
@ -147,7 +154,7 @@ class SymmetricalDifference(QgisAlgorithm):
try:
outFeat.setGeometry(diffGeom)
outFeat.setAttributes(attrs)
sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
self.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)
@ -155,5 +162,7 @@ class SymmetricalDifference(QgisAlgorithm):
count += 1
feedback.setProgress(int(count * total))
return True
return {self.OUTPUT: dest_id}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.dest_id}

View File

@ -28,7 +28,6 @@ __revision__ = '$Format:%H$'
import os
from qgis.PyQt.QtGui import QIcon
from qgis.core import (QgsProcessingUtils,
QgsFeatureSink,
QgsProcessingParameterFeatureSource,
@ -39,10 +38,6 @@ from qgis.core import (QgsProcessingUtils,
QgsFeatureRequest)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterTableField
from processing.core.outputs import OutputDirectory
from processing.tools import vector
from processing.tools.system import mkdir
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
@ -71,42 +66,51 @@ 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 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)
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)
mkdir(directory)
fieldIndex = self.source.fields().lookupField(self.fieldName)
self.uniqueValues = self.source.uniqueValues(fieldIndex)
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):
baseName = os.path.join(self.directory, '{0}'.format(self.fieldName))
self.sinks = {}
for current, i in enumerate(self.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
sink, dest = QgsProcessingUtils.createFeatureSink(fName, context, fields, geomType, crs)
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
filter = '{} = {}'.format(QgsExpression.quotedColumnRef(fieldName), QgsExpression.quotedValue(i))
sink = self.sinks[i]
filter = '{} = {}'.format(QgsExpression.quotedColumnRef(self.fieldName), QgsExpression.quotedValue(i))
req = QgsFeatureRequest().setFilterExpression(filter)
count = 0
for f in source.getFeatures(req):
for f in self.source.getFeatures(req):
if feedback.isCanceled():
break
sink.addFeature(f, QgsFeatureSink.FastInsert)
@ -115,5 +119,7 @@ class VectorSplit(QgisAlgorithm):
del sink
feedback.setProgress(int(current * total))
return True
return {self.OUTPUT: directory}
def postProcessAlgorithm(self, context, feedback):
return {self.OUTPUT: self.directory}

View File

@ -94,30 +94,40 @@ class ZonalStatistics(QgisAlgorithm):
self.tr('Zonal statistics'),
QgsProcessingParameterDefinition.TypeVectorPolygon))
self.bandNumber = None
self.columnPrefix = None
self.selectedStats = None
self.vectorLayer = None
self.rasterLayer = None
def name(self):
return 'zonalstatistics'
def displayName(self):
return self.tr('Zonal Statistics')
def processAlgorithm(self, parameters, context, feedback):
bandNumber = self.parameterAsInt(parameters, self.RASTER_BAND, context)
columnPrefix = self.parameterAsString(parameters, self.COLUMN_PREFIX, context)
def prepareAlgorithm(self, parameters, context, feedback):
self.bandNumber = self.parameterAsInt(parameters, self.RASTER_BAND, context)
self.columnPrefix = self.parameterAsString(parameters, self.COLUMN_PREFIX, context)
st = self.parameterAsEnums(parameters, self.STATISTICS, context)
vectorLayer = self.parameterAsVectorLayer(parameters, self.INPUT_VECTOR, context)
rasterLayer = self.parameterAsRasterLayer(parameters, self.INPUT_RASTER, context)
keys = list(self.STATS.keys())
selectedStats = 0
self.selectedStats = 0
for i in st:
selectedStats |= self.STATS[keys[i]]
self.selectedStats |= self.STATS[keys[i]]
zs = QgsZonalStatistics(vectorLayer,
rasterLayer,
columnPrefix,
bandNumber,
selectedStats)
self.vectorLayer = self.parameterAsVectorLayer(parameters, self.INPUT_VECTOR, context)
self.rasterLayer = self.parameterAsRasterLayer(parameters, self.INPUT_RASTER, context)
return True
def processAlgorithm(self, context, feedback):
zs = QgsZonalStatistics(self.vectorLayer,
self.rasterLayer,
self.columnPrefix,
self.bandNumber,
self.selectedStats)
zs.calculateStatistics(feedback)
return True
return {self.INPUT_VECTOR: vectorLayer}
def postProcessAlgorithm(self, context, feedback):
return {self.INPUT_VECTOR: self.vectorLayer}

View File

@ -75,6 +75,10 @@ class ScriptAlgorithm(QgsProcessingAlgorithm):
if descriptionFile is not None:
self.defineCharacteristicsFromFile()
self.ns = {}
self.cleaned_script = None
self.results = {}
def clone(self):
return ScriptAlgorithm(self.descriptionFile)
@ -178,11 +182,7 @@ class ScriptAlgorithm(QgsProcessingAlgorithm):
self.tr('Could not load script: {0}.\n'
'Problem with line "{1}"', 'ScriptAlgorithm').format(self.descriptionFile or '', line))
def processAlgorithm(self, parameters, context, feedback):
ns = {}
ns['scriptDescriptionFile'] = self.descriptionFile
def prepareAlgorithm(self, parameters, context, feedback):
for param in self.parameterDefinitions():
method = None
if param.type() == "boolean":
@ -224,20 +224,19 @@ class ScriptAlgorithm(QgsProcessingAlgorithm):
method = self.parameterAsSource
if method:
ns[param.name()] = method(parameters, param.name(), context)
self.ns[param.name()] = method(parameters, param.name(), context)
self.ns['scriptDescriptionFile'] = self.descriptionFile
for out in self.outputDefinitions():
ns[out.name()] = None
self.ns[out.name()] = None
ns['self'] = self
ns['parameters'] = parameters
ns['feedback'] = feedback
ns['context'] = context
self.ns['self'] = self
self.ns['parameters'] = parameters
expression_context = self.createExpressionContext(parameters, context)
variables = re.findall('@[a-zA-Z0-9_]*', self.script)
script = 'import processing\n'
script += self.script
context = self.createExpressionContext(parameters, context)
for var in variables:
varname = var[1:]
if context.hasVariable(varname):
@ -245,12 +244,22 @@ class ScriptAlgorithm(QgsProcessingAlgorithm):
else:
# messy - it's probably NOT a variable, and instead an email address or some other string containing '@'
QgsMessageLog.logMessage(self.tr('Cannot find variable: {0}').format(varname), self.tr('Processing'), QgsMessageLog.WARNING)
self.cleaned_script = script
exec((script), ns)
results = {}
return True
def processAlgorithm(self, context, feedback):
self.ns['feedback'] = feedback
self.ns['context'] = context
exec((self.cleaned_script), self.ns)
self.results = {}
for out in self.outputDefinitions():
results[out.name()] = ns[out.name()]
return results
self.results[out.name()] = self.ns[out.name()]
return True
def postProcessAlgorithm(self, context, feedback):
return self.results
def helpUrl(self):
if self.descriptionFile is None:

View File

@ -9,7 +9,7 @@ tests:
type: vector # Param is a vector layer
name: polys.gml # file name
results: # A map of results (only one here)
OUTPUT_LAYER:
OUTPUT:
type: vector # Expected result is a vector layer
name: expected/polys_centroid.gml # The relative filepath from the processing testdata directory
compare:
@ -735,7 +735,7 @@ tests:
name: lines.gml
type: vector
results:
OUTPUT_LAYER:
OUTPUT:
name: expected/centroid_lines.gml
type: vector
compare:
@ -749,7 +749,7 @@ tests:
name: multilines.gml
type: vector
results:
OUTPUT_LAYER:
OUTPUT:
name: expected/centroid_multilines.gml
type: vector
compare:
@ -763,7 +763,7 @@ tests:
name: multipoints.gml
type: vector
results:
OUTPUT_LAYER:
OUTPUT:
name: expected/centroid_multipoint.gml
type: vector
compare:
@ -777,7 +777,7 @@ tests:
name: multipolys.gml
type: vector
results:
OUTPUT_LAYER:
OUTPUT:
name: expected/centroid_multipolys.gml
type: vector
compare:
@ -791,7 +791,7 @@ tests:
name: points.gml
type: vector
results:
OUTPUT_LAYER:
OUTPUT:
name: expected/centroid_points.gml
type: vector
compare:
@ -805,7 +805,7 @@ tests:
name: polys.gml
type: vector
results:
OUTPUT_LAYER:
OUTPUT:
name: expected/centroid_polys.gml
type: vector
compare:
@ -1037,12 +1037,12 @@ tests:
- algorithm: qgis:aspect
name: Aspect from QGIS analysis library
params:
INPUT_LAYER:
INPUT:
name: dem.tif
type: raster
Z_FACTOR: 1.0
results:
OUTPUT_LAYER:
OUTPUT:
hash: 762865ee485a6736d188402aa10e6fd38a812a9e45a7dd2d4885a63a
type: rasterhash
@ -1670,11 +1670,11 @@ tests:
- algorithm: qgis:dropgeometries
name: Drop geometries
params:
INPUT_LAYER:
INPUT:
name: polys.gml
type: vector
results:
OUTPUT_TABLE:
OUTPUT:
name: expected/dropped_geometry.csv
type: vector

View File

@ -142,7 +142,7 @@ bool QgsCentroidAlgorithm::processAlgorithm( QgsProcessingContext &, QgsProcessi
QVariantMap QgsCentroidAlgorithm::postProcessAlgorithm( QgsProcessingContext &, QgsProcessingFeedback * )
{
QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT_LAYER" ), mSinkId );
outputs.insert( QStringLiteral( "OUTPUT" ), mSinkId );
return outputs;
}

View File

@ -4610,7 +4610,7 @@ void TestQgsProcessing::modelerAlgorithm()
QMap<QString, QgsProcessingModelAlgorithm::ModelOutput> alg7c1outputs;
QgsProcessingModelAlgorithm::ModelOutput alg7c1out1( QStringLiteral( "my_output" ) );
alg7c1out1.setChildId( "cx1" );
alg7c1out1.setChildOutputName( "OUTPUT_LAYER" );
alg7c1out1.setChildOutputName( "OUTPUT" );
alg7c1out1.setDescription( QStringLiteral( "my output" ) );
alg7c1outputs.insert( QStringLiteral( "my_output" ), alg7c1out1 );
alg7c1.setModelOutputs( alg7c1outputs );
@ -4630,7 +4630,7 @@ void TestQgsProcessing::modelerAlgorithm()
QMap<QString, QgsProcessingModelAlgorithm::ModelOutput> alg7c2outputs;
QgsProcessingModelAlgorithm::ModelOutput alg7c2out1( QStringLiteral( "my_output2" ) );
alg7c2out1.setChildId( "cx2" );
alg7c2out1.setChildOutputName( "OUTPUT_LAYER" );
alg7c2out1.setChildOutputName( "OUTPUT" );
alg7c2out1.setDescription( QStringLiteral( "my output2" ) );
alg7c2outputs.insert( QStringLiteral( "my_output2" ), alg7c2out1 );
alg7c2.setModelOutputs( alg7c2outputs );
@ -4700,7 +4700,7 @@ void TestQgsProcessing::modelExecution()
alg2c1.addParameterSources( "DISSOLVE", QgsProcessingModelAlgorithm::ChildParameterSources() << QgsProcessingModelAlgorithm::ChildParameterSource::fromStaticValue( false ) );
QMap<QString, QgsProcessingModelAlgorithm::ModelOutput> outputs1;
QgsProcessingModelAlgorithm::ModelOutput out1( "MODEL_OUT_LAYER" );
out1.setChildOutputName( "OUTPUT_LAYER" );
out1.setChildOutputName( "OUTPUT" );
outputs1.insert( QStringLiteral( "MODEL_OUT_LAYER" ), out1 );
alg2c1.setModelOutputs( outputs1 );
model2.addChildAlgorithm( alg2c1 );
@ -4720,7 +4720,7 @@ void TestQgsProcessing::modelExecution()
QCOMPARE( params.value( "END_CAP_STYLE" ).toInt(), 1 );
QCOMPARE( params.value( "JOIN_STYLE" ).toInt(), 2 );
QCOMPARE( params.value( "INPUT" ).toString(), QStringLiteral( "my_layer_id" ) );
QCOMPARE( params.value( "OUTPUT_LAYER" ).toString(), QStringLiteral( "dest.shp" ) );
QCOMPARE( params.value( "OUTPUT" ).toString(), QStringLiteral( "dest.shp" ) );
QCOMPARE( params.count(), 7 );
QVariantMap results;
@ -4735,7 +4735,7 @@ void TestQgsProcessing::modelExecution()
model2.addChildAlgorithm( alg2c2 );
params = model2.parametersForChildAlgorithm( model2.childAlgorithm( "cx2" ), modelInputs, childResults );
QCOMPARE( params.value( "INPUT" ).toString(), QStringLiteral( "dest.shp" ) );
QCOMPARE( params.value( "OUTPUT_LAYER" ).toString(), QStringLiteral( "memory:" ) );
QCOMPARE( params.value( "OUTPUT" ).toString(), QStringLiteral( "memory:" ) );
QCOMPARE( params.count(), 2 );
// a child with an optional output
@ -4770,8 +4770,8 @@ void TestQgsProcessing::modelExecution()
"##my_out=output outputVector\n"
"results={}\n"
"outputs['cx1']=processing.run('native:buffer', {'DISSOLVE':false,'DISTANCE':parameters['DIST'],'END_CAP_STYLE':1,'INPUT':parameters['SOURCE_LAYER'],'JOIN_STYLE':2,'SEGMENTS':16}, context=context, feedback=feedback)\n"
"results['MODEL_OUT_LAYER']=outputs['cx1']['OUTPUT_LAYER']\n"
"outputs['cx2']=processing.run('native:centroids', {'INPUT':outputs['cx1']['OUTPUT_LAYER']}, context=context, feedback=feedback)\n"
"results['MODEL_OUT_LAYER']=outputs['cx1']['OUTPUT']\n"
"outputs['cx2']=processing.run('native:centroids', {'INPUT':outputs['cx1']['OUTPUT']}, context=context, feedback=feedback)\n"
"outputs['cx3']=processing.run('native:extractbyexpression', {'EXPRESSION':true,'INPUT':outputs['cx1']['OUTPUT_LAYER'],'OUTPUT':parameters['MY_OUT']}, context=context, feedback=feedback)\n"
"results['MY_OUT']=outputs['cx3']['OUTPUT']\n"
"return results" ).split( '\n' );