Skip to content
Permalink
Browse files

[FEATURE] Port CheckValidity alg to new API

Also make outputs optional from the alg - now you can select
which outputs you need for your model!
  • Loading branch information
nyalldawson committed Jun 9, 2017
1 parent 6b55300 commit 8c73bcbcfe2cdccbbf31e389840e67b648f511c1
@@ -158,6 +158,8 @@ def calcNumericStats(self, features, feedback, field, count):
total = 100.0 / float(count)
stat = QgsStatisticalSummary()
for current, ft in enumerate(features):
if feedback.isCanceled():
break
stat.addVariant(ft[field.name()])
feedback.setProgress(int(current * total))
stat.finalize()
@@ -205,6 +207,8 @@ def calcStringStats(self, features, feedback, field, count):
total = 100.0 / float(count)
stat = QgsStringStatisticalSummary()
for current, ft in enumerate(features):
if feedback.isCanceled():
break
stat.addValue(ft[field.name()])
feedback.setProgress(int(current * total))
stat.finalize()
@@ -235,6 +239,8 @@ def calcDateTimeStats(self, features, feedback, field, count):
total = 100.0 / float(count)
stat = QgsDateTimeStatisticalSummary()
for current, ft in enumerate(features):
if feedback.isCanceled():
break
stat.addValue(ft[field.name()])
feedback.setProgress(int(current * total))
stat.finalize()
@@ -36,11 +36,14 @@
QgsField,
QgsWkbTypes,
QgsProcessingUtils,
QgsFields)
QgsFields,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterEnum,
QgsProcessingParameterFeatureSink,
QgsProcessingOutputVectorLayer,
QgsProcessingParameterDefinition
)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterSelection
from processing.core.outputs import OutputVector

settings_method_key = "/qgis/digitizing/validate_geometries"
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
@@ -66,26 +69,17 @@ def __init__(self):
'QGIS',
'GEOS']

self.addParameter(ParameterVector(
self.INPUT_LAYER,
self.tr('Input layer')))
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER,
self.tr('Input layer')))
self.addParameter(QgsProcessingParameterEnum(self.METHOD,
self.tr('Method'), self.methods))

self.addParameter(ParameterSelection(
self.METHOD,
self.tr('Method'),
self.methods))

self.addOutput(OutputVector(
self.VALID_OUTPUT,
self.tr('Valid output')))

self.addOutput(OutputVector(
self.INVALID_OUTPUT,
self.tr('Invalid output')))

self.addOutput(OutputVector(
self.ERROR_OUTPUT,
self.tr('Error output')))
self.addParameter(QgsProcessingParameterFeatureSink(self.VALID_OUTPUT, self.tr('Valid output'), QgsProcessingParameterDefinition.TypeVectorAny, '', True))
self.addOutput(QgsProcessingOutputVectorLayer(self.VALID_OUTPUT, self.tr('Valid output')))
self.addParameter(QgsProcessingParameterFeatureSink(self.INVALID_OUTPUT, self.tr('Invalid output'), QgsProcessingParameterDefinition.TypeVectorAny, '', True))
self.addOutput(QgsProcessingOutputVectorLayer(self.INVALID_OUTPUT, self.tr('Invalid output')))
self.addParameter(QgsProcessingParameterFeatureSink(self.ERROR_OUTPUT, self.tr('Error output'), QgsProcessingParameterDefinition.TypeVectorAny, '', True))
self.addOutput(QgsProcessingOutputVectorLayer(self.ERROR_OUTPUT, self.tr('Error output')))

def name(self):
return 'checkvalidity'
@@ -94,51 +88,48 @@ def displayName(self):
return self.tr('Check validity')

def processAlgorithm(self, parameters, context, feedback):
settings = QgsSettings()
initial_method_setting = settings.value(settings_method_key, 1)

method = self.getParameterValue(self.METHOD)
if method != 0:
settings.setValue(settings_method_key, method)
try:
self.doCheck(context, feedback)
finally:
settings.setValue(settings_method_key, initial_method_setting)

def doCheck(self, context, feedback):
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)

settings = QgsSettings()
method = int(settings.value(settings_method_key, 1))

valid_output = self.getOutputFromName(self.VALID_OUTPUT)
valid_fields = layer.fields()
valid_writer = valid_output.getVectorWriter(valid_fields, layer.wkbType(), layer.crs(), context)
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
else:
method = method_param - 1

results = self.doCheck(method, parameters, context, feedback)
return results

def doCheck(self, method, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)

(valid_output_sink, valid_output_dest_id) = self.parameterAsSink(parameters, self.VALID_OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
valid_count = 0

invalid_output = self.getOutputFromName(self.INVALID_OUTPUT)
invalid_fields = layer.fields()
invalid_fields.append(QgsField('_errors',
QVariant.String,
255))
invalid_writer = invalid_output.getVectorWriter(invalid_fields, layer.wkbType(), layer.crs(), context)
invalid_fields = 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

error_output = self.getOutputFromName(self.ERROR_OUTPUT)
error_fields = QgsFields()
error_fields.append(QgsField('message', QVariant.String, 255))
error_writer = error_output.getVectorWriter(error_fields, QgsWkbTypes.Point, layer.crs(), context)
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

features = QgsProcessingUtils.getFeatures(layer, context)
total = 100.0 / QgsProcessingUtils.featureCount(layer, context)
features = source.getFeatures()
total = 100.0 / source.featureCount()
for current, inFeat in enumerate(features):
if feedback.isCanceled():
break
geom = inFeat.geometry()
attrs = inFeat.attributes()

valid = True
if not geom.isNull() and not geom.isEmpty():
errors = list(geom.validateGeometry())
errors = list(geom.validateGeometry(method))
if errors:
# QGIS method return a summary at the end
if method == 1:
@@ -150,7 +141,8 @@ def doCheck(self, context, feedback):
error_geom = QgsGeometry.fromPoint(error.where())
errFeat.setGeometry(error_geom)
errFeat.setAttributes([error.what()])
error_writer.addFeature(errFeat)
if error_output_sink:
error_output_sink.addFeature(errFeat)
error_count += 1

reasons.append(error.what())
@@ -165,22 +157,22 @@ def doCheck(self, context, feedback):
outFeat.setAttributes(attrs)

if valid:
valid_writer.addFeature(outFeat)
if valid_output_sink:
valid_output_sink.addFeature(outFeat)
valid_count += 1

else:
invalid_writer.addFeature(outFeat)
if invalid_output_sink:
invalid_output_sink.addFeature(outFeat)
invalid_count += 1

feedback.setProgress(int(current * total))

del valid_writer
del invalid_writer
del error_writer

if valid_count != 0:
context.addLayerToLoadOnCompletion(valid_output.value)
if invalid_count != 0:
context.addLayerToLoadOnCompletion(invalid_output.value)
if error_count != 0:
context.addLayerToLoadOnCompletion(error_output.value)
results = {}
if valid_output_sink:
results[self.VALID_OUTPUT] = valid_output_dest_id
if invalid_output_sink:
results[self.INVALID_OUTPUT] = invalid_output_dest_id
if error_output_sink:
results[self.ERROR_OUTPUT] = error_output_dest_id
return results
@@ -136,7 +136,7 @@
# from .SplitLinesWithLines import SplitLinesWithLines
# from .FieldsMapper import FieldsMapper
# from .Datasources2Vrt import Datasources2Vrt
# from .CheckValidity import CheckValidity
from .CheckValidity import CheckValidity
# from .OrientedMinimumBoundingBox import OrientedMinimumBoundingBox
# from .Smooth import Smooth
# from .ReverseLineDirection import ReverseLineDirection
@@ -237,7 +237,7 @@ def getAlgs(self):
# SelectByExpression(), HypsometricCurves(),
# SplitWithLines(), SplitLinesWithLines(), CreateConstantRaster(),
# FieldsMapper(), SelectByAttributeSum(), Datasources2Vrt(),
# CheckValidity(), OrientedMinimumBoundingBox(), Smooth(),
# OrientedMinimumBoundingBox(), Smooth(),
# ReverseLineDirection(), SpatialIndex(), DefineProjection(),
# RectanglesOvalsDiamondsVariable(),
# RectanglesOvalsDiamondsFixed(), MergeLines(),
@@ -265,6 +265,7 @@ def getAlgs(self):
BasicStatisticsForField(),
Boundary(),
BoundingBox(),
CheckValidity(),
Clip(),
DeleteColumn(),
ExtentFromLayer()

0 comments on commit 8c73bcb

Please sign in to comment.
You can’t perform that action at this time.