Merge pull request #4761 from nyalldawson/algs2

Port more processing algs to new API
This commit is contained in:
Nyall Dawson 2017-06-22 06:40:32 +10:00 committed by GitHub
commit b01cae0740
23 changed files with 1240 additions and 367 deletions

View File

@ -163,14 +163,16 @@ class QgsProcessingParameterDefinition
sipType = sipType_QgsProcessingParameterString; sipType = sipType_QgsProcessingParameterString;
else if ( sipCpp->type() == "expression" ) else if ( sipCpp->type() == "expression" )
sipType = sipType_QgsProcessingParameterExpression; sipType = sipType_QgsProcessingParameterExpression;
else if ( sipCpp->type() == "table" ) else if ( sipCpp->type() == "vector" )
sipType = sipType_QgsProcessingParameterTable; sipType = sipType_QgsProcessingParameterVectorLayer;
else if ( sipCpp->type() == "field" ) else if ( sipCpp->type() == "field" )
sipType = sipType_QgsProcessingParameterTableField; sipType = sipType_QgsProcessingParameterField;
else if ( sipCpp->type() == "source" ) else if ( sipCpp->type() == "source" )
sipType = sipType_QgsProcessingParameterFeatureSource; sipType = sipType_QgsProcessingParameterFeatureSource;
else if ( sipCpp->type() == "sink" ) else if ( sipCpp->type() == "sink" )
sipType = sipType_QgsProcessingParameterFeatureSink; sipType = sipType_QgsProcessingParameterFeatureSink;
else if ( sipCpp->type() == "vectorOut" )
sipType = sipType_QgsProcessingParameterVectorOutput;
else if ( sipCpp->type() == "rasterOut" ) else if ( sipCpp->type() == "rasterOut" )
sipType = sipType_QgsProcessingParameterRasterOutput; sipType = sipType_QgsProcessingParameterRasterOutput;
else if ( sipCpp->type() == "fileOut" ) else if ( sipCpp->type() == "fileOut" )
@ -1153,10 +1155,11 @@ class QgsProcessingParameterExpression : QgsProcessingParameterDefinition
}; };
class QgsProcessingParameterTable : QgsProcessingParameterDefinition class QgsProcessingParameterVectorLayer : QgsProcessingParameterDefinition
{ {
%Docstring %Docstring
A table (i.e. vector layers with or without geometry) parameter for processing algorithms. A vector layer (with or without geometry) parameter for processing algorithms. Consider using
the more versatile QgsProcessingParameterFeatureSource wherever possible.
.. versionadded:: 3.0 .. versionadded:: 3.0
%End %End
@ -1165,20 +1168,24 @@ class QgsProcessingParameterTable : QgsProcessingParameterDefinition
%End %End
public: public:
QgsProcessingParameterTable( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(), QgsProcessingParameterVectorLayer( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(),
bool optional = false ); bool optional = false );
%Docstring %Docstring
Constructor for QgsProcessingParameterTable. Constructor for QgsProcessingParameterVectorLayer.
%End %End
virtual QString type() const; virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
}; };
class QgsProcessingParameterTableField : QgsProcessingParameterDefinition class QgsProcessingParameterField : QgsProcessingParameterDefinition
{ {
%Docstring %Docstring
A table field parameter for processing algorithms. A vector layer or feature source field parameter for processing algorithms.
.. versionadded:: 3.0 .. versionadded:: 3.0
%End %End
@ -1195,13 +1202,13 @@ class QgsProcessingParameterTableField : QgsProcessingParameterDefinition
DateTime DateTime
}; };
QgsProcessingParameterTableField( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(), QgsProcessingParameterField( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(),
const QString &parentLayerParameterName = QString(), const QString &parentLayerParameterName = QString(),
DataType type = Any, DataType type = Any,
bool allowMultiple = false, bool allowMultiple = false,
bool optional = false ); bool optional = false );
%Docstring %Docstring
Constructor for QgsProcessingParameterTableField. Constructor for QgsProcessingParameterField.
%End %End
virtual QString type() const; virtual QString type() const;
@ -1354,6 +1361,60 @@ class QgsProcessingParameterFeatureSink : QgsProcessingParameterDefinition
virtual bool fromVariantMap( const QVariantMap &map ); virtual bool fromVariantMap( const QVariantMap &map );
};
class QgsProcessingParameterVectorOutput : QgsProcessingParameterDefinition
{
%Docstring
A vector layer output parameter. Consider using the more flexible QgsProcessingParameterFeatureSink wherever
possible.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsprocessingparameters.h"
%End
public:
QgsProcessingParameterVectorOutput( const QString &name, const QString &description = QString(), QgsProcessingParameterDefinition::LayerType type = QgsProcessingParameterDefinition::TypeVectorAny, const QVariant &defaultValue = QVariant(),
bool optional = false );
%Docstring
Constructor for QgsProcessingParameterVectorOutput.
%End
virtual QString type() const;
virtual bool isDestination() const;
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
QgsProcessingParameterDefinition::LayerType dataType() const;
%Docstring
Returns the layer type for layers associated with the parameter.
.. seealso:: setDataType()
:rtype: QgsProcessingParameterDefinition.LayerType
%End
bool hasGeometry() const;
%Docstring
Returns true if the layer is likely to include geometries. In cases were presence of geometry
cannot be reliably determined in advance, this method will default to returning true.
:rtype: bool
%End
void setDataType( QgsProcessingParameterDefinition::LayerType type );
%Docstring
Sets the layer ``type`` for the layers associated with the parameter.
.. seealso:: dataType()
%End
virtual QVariantMap toVariantMap() const;
virtual bool fromVariantMap( const QVariantMap &map );
}; };
class QgsProcessingParameterRasterOutput : QgsProcessingParameterDefinition class QgsProcessingParameterRasterOutput : QgsProcessingParameterDefinition

View File

@ -32,7 +32,7 @@ import plotly.graph_objs as go
from qgis.core import (QgsApplication, from qgis.core import (QgsApplication,
QgsProcessingUtils, QgsProcessingUtils,
QgsProcessingParameterFeatureSource, QgsProcessingParameterFeatureSource,
QgsProcessingParameterTableField, QgsProcessingParameterField,
QgsProcessingParameterFileOutput, QgsProcessingParameterFileOutput,
QgsProcessingOutputHtml) QgsProcessingOutputHtml)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
@ -60,12 +60,12 @@ class BarPlot(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer'))) self.tr('Input layer')))
self.addParameter(QgsProcessingParameterTableField(self.NAME_FIELD, self.addParameter(QgsProcessingParameterField(self.NAME_FIELD,
self.tr('Category name field'), self.tr('Category name field'),
None, self.INPUT, QgsProcessingParameterTableField.Any)) None, self.INPUT, QgsProcessingParameterField.Any))
self.addParameter(QgsProcessingParameterTableField(self.VALUE_FIELD, self.addParameter(QgsProcessingParameterField(self.VALUE_FIELD,
self.tr('Value field'), self.tr('Value field'),
None, self.INPUT, QgsProcessingParameterTableField.Numeric)) None, self.INPUT, QgsProcessingParameterField.Numeric))
self.addParameter(QgsProcessingParameterFileOutput(self.OUTPUT, self.tr('Added'), self.tr('HTML files (*.html)'))) self.addParameter(QgsProcessingParameterFileOutput(self.OUTPUT, self.tr('Added'), self.tr('HTML files (*.html)')))

View File

@ -37,7 +37,7 @@ from qgis.core import (QgsStatisticalSummary,
QgsFeatureRequest, QgsFeatureRequest,
QgsProcessingUtils, QgsProcessingUtils,
QgsProcessingParameterFeatureSource, QgsProcessingParameterFeatureSource,
QgsProcessingParameterTableField, QgsProcessingParameterField,
QgsProcessingParameterFileOutput, QgsProcessingParameterFileOutput,
QgsProcessingOutputHtml, QgsProcessingOutputHtml,
QgsProcessingOutputNumber) QgsProcessingOutputNumber)
@ -90,9 +90,9 @@ class BasicStatisticsForField(QgisAlgorithm):
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER, self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER,
self.tr('Input layer'))) self.tr('Input layer')))
self.addParameter(QgsProcessingParameterTableField(self.FIELD_NAME, self.addParameter(QgsProcessingParameterField(self.FIELD_NAME,
self.tr('Field to calculate statistics on'), self.tr('Field to calculate statistics on'),
None, self.INPUT_LAYER, QgsProcessingParameterTableField.Any)) None, self.INPUT_LAYER, QgsProcessingParameterField.Any))
self.addParameter(QgsProcessingParameterFileOutput(self.OUTPUT_HTML_FILE, self.tr('Statistics'), self.tr('HTML files (*.html)'), None, True)) self.addParameter(QgsProcessingParameterFileOutput(self.OUTPUT_HTML_FILE, self.tr('Statistics'), self.tr('HTML files (*.html)'), None, True))
self.addOutput(QgsProcessingOutputHtml(self.OUTPUT_HTML_FILE, self.tr('Statistics'))) self.addOutput(QgsProcessingOutputHtml(self.OUTPUT_HTML_FILE, self.tr('Statistics')))

View File

@ -28,12 +28,12 @@ __revision__ = '$Format:%H$'
from qgis.core import (QgsVectorDataProvider, from qgis.core import (QgsVectorDataProvider,
QgsFields, QgsFields,
QgsApplication, QgsApplication,
QgsProcessingUtils) QgsProcessingParameterVectorLayer,
QgsProcessingParameterField,
QgsProcessingParameterDefinition,
QgsProcessingOutputVectorLayer)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.parameters import ParameterTable
from processing.core.parameters import ParameterTableField
from processing.core.outputs import OutputVector
class CreateAttributeIndex(QgisAlgorithm): class CreateAttributeIndex(QgisAlgorithm):
@ -53,12 +53,11 @@ class CreateAttributeIndex(QgisAlgorithm):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.addParameter(ParameterTable(self.INPUT, self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT,
self.tr('Input Layer'))) self.tr('Input Layer')))
self.addParameter(ParameterTableField(self.FIELD, self.addParameter(QgsProcessingParameterField(self.FIELD,
self.tr('Attribute to index'), self.INPUT)) self.tr('Attribute to index'), None, self.INPUT))
self.addOutput(OutputVector(self.OUTPUT, self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Indexed layer')))
self.tr('Indexed layer'), True))
def name(self): def name(self):
return 'createattributeindex' return 'createattributeindex'
@ -67,9 +66,8 @@ class CreateAttributeIndex(QgisAlgorithm):
return self.tr('Create attribute index') return self.tr('Create attribute index')
def processAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
file_name = self.getParameterValue(self.INPUT) layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
layer = QgsProcessingUtils.mapLayerFromString(file_name, context) field = self.parameterAsString(parameters, self.FIELD, context)
field = self.getParameterValue(self.FIELD)
provider = layer.dataProvider() provider = layer.dataProvider()
field_index = layer.fields().lookupField(field) field_index = layer.fields().lookupField(field)
@ -84,4 +82,4 @@ class CreateAttributeIndex(QgisAlgorithm):
feedback.pushInfo(self.tr("Layer's data provider does not support " feedback.pushInfo(self.tr("Layer's data provider does not support "
"creating attribute indexes")) "creating attribute indexes"))
self.setOutputValue(self.OUTPUT, file_name) return {self.OUTPUT: layer.id()}

View File

@ -29,7 +29,7 @@ from qgis.core import (QgsApplication,
QgsProcessingUtils, QgsProcessingUtils,
QgsProcessingParameterFeatureSource, QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink, QgsProcessingParameterFeatureSink,
QgsProcessingParameterTableField, QgsProcessingParameterField,
QgsProcessingOutputVectorLayer) QgsProcessingOutputVectorLayer)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
@ -56,9 +56,9 @@ class DeleteColumn(QgisAlgorithm):
super().__init__() super().__init__()
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'))) self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer')))
self.addParameter(QgsProcessingParameterTableField(self.COLUMNS, self.addParameter(QgsProcessingParameterField(self.COLUMNS,
self.tr('Fields to delete'), self.tr('Fields to delete'),
None, self.INPUT, QgsProcessingParameterTableField.Any, True)) None, self.INPUT, QgsProcessingParameterField.Any, True))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Output layer'))) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Output layer')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Output layer"))) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Output layer")))

View File

@ -25,12 +25,13 @@ __copyright__ = '(C) 2015, Etienne Trimaille'
__revision__ = '$Format:%H$' __revision__ = '$Format:%H$'
from qgis.core import (QgsApplication, from qgis.core import (QgsApplication,
QgsProcessingUtils) QgsProcessingUtils,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterNumber,
QgsProcessingParameterFeatureSink,
QgsProcessingOutputVectorLayer,
QgsProcessingParameterDefinition)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.parameters import (ParameterVector,
ParameterNumber)
from processing.core.outputs import OutputVector
from processing.tools import dataobjects
class DeleteHoles(QgisAlgorithm): class DeleteHoles(QgisAlgorithm):
@ -53,12 +54,14 @@ class DeleteHoles(QgisAlgorithm):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.addParameter(ParameterVector(self.INPUT, self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer'), [dataobjects.TYPE_VECTOR_POLYGON])) self.tr('Input layer'), [QgsProcessingParameterDefinition.TypeVectorPolygon]))
self.addParameter(ParameterNumber(self.MIN_AREA, self.addParameter(QgsProcessingParameterNumber(self.MIN_AREA,
self.tr('Remove holes with area less than'), 0, 10000000.0, default=0.0, optional=True)) self.tr('Remove holes with area less than'), QgsProcessingParameterNumber.Double,
0, True, 0.0, 10000000.0))
self.addOutput(OutputVector(self.OUTPUT, self.tr('Cleaned'), datatype=[dataobjects.TYPE_VECTOR_POLYGON])) self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Cleaned'), QgsProcessingParameterDefinition.TypeVectorPolygon))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Cleaned'), QgsProcessingParameterDefinition.TypeVectorPolygon))
def name(self): def name(self):
return 'deleteholes' return 'deleteholes'
@ -67,29 +70,24 @@ class DeleteHoles(QgisAlgorithm):
return self.tr('Delete holes') return self.tr('Delete holes')
def processAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context) source = self.parameterAsSource(parameters, self.INPUT, context)
min_area = self.getParameterValue(self.MIN_AREA) min_area = self.parameterAsDouble(parameters, self.MIN_AREA, context)
if min_area is not None:
try:
min_area = float(min_area)
except:
pass
if min_area == 0.0: if min_area == 0.0:
min_area = -1.0 min_area = -1.0
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(layer.fields(), layer.wkbType(), layer.crs(), (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
context) source.fields(), source.wkbType(), source.sourceCrs())
features = QgsProcessingUtils.getFeatures(layer, context) features = source.getFeatures()
total = 100.0 / QgsProcessingUtils.featureCount(layer, context) total = 100.0 / source.featureCount()
for current, f in enumerate(features): for current, f in enumerate(features):
if feedback.isCanceled():
break
if f.hasGeometry(): if f.hasGeometry():
if min_area is not None:
f.setGeometry(f.geometry().removeInteriorRings(min_area)) f.setGeometry(f.geometry().removeInteriorRings(min_area))
else: sink.addFeature(f)
f.setGeometry(f.geometry().removeInteriorRings())
writer.addFeature(f)
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
del writer return {self.OUTPUT: dest_id}

View File

@ -30,15 +30,12 @@ import os
from qgis.core import (QgsWkbTypes, from qgis.core import (QgsWkbTypes,
QgsApplication, QgsApplication,
QgsProcessingUtils) QgsProcessingParameterFeatureSource,
QgsProcessingParameterNumber,
QgsProcessingParameterFeatureSink,
QgsProcessingOutputVectorLayer,
QgsProcessingParameterDefinition)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterNumber
from processing.core.outputs import OutputVector
from processing.tools import dataobjects
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
class DensifyGeometries(QgisAlgorithm): class DensifyGeometries(QgisAlgorithm):
@ -61,14 +58,15 @@ class DensifyGeometries(QgisAlgorithm):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.addParameter(ParameterVector(self.INPUT,
self.tr('Input layer'),
[dataobjects.TYPE_VECTOR_POLYGON, dataobjects.TYPE_VECTOR_LINE]))
self.addParameter(ParameterNumber(self.VERTICES,
self.tr('Vertices to add'), 1, 10000000, 1))
self.addOutput(OutputVector(self.OUTPUT, self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Densified'))) self.tr('Input layer'), [QgsProcessingParameterDefinition.TypeVectorPolygon, QgsProcessingParameterDefinition.TypeVectorLine]))
self.addParameter(QgsProcessingParameterNumber(self.VERTICES,
self.tr('Vertices to add'), QgsProcessingParameterNumber.Integer,
1, False, 1, 10000000))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Densified')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Densified')))
def name(self): def name(self):
return 'densifygeometries' return 'densifygeometries'
@ -77,22 +75,24 @@ class DensifyGeometries(QgisAlgorithm):
return self.tr('Densify geometries') return self.tr('Densify geometries')
def processAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context) source = self.parameterAsSource(parameters, self.INPUT, context)
vertices = self.getParameterValue(self.VERTICES) vertices = self.parameterAsInt(parameters, self.VERTICES, context)
isPolygon = layer.geometryType() == QgsWkbTypes.PolygonGeometry (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
writer = self.getOutputFromName( features = source.getFeatures()
self.OUTPUT).getVectorWriter(layer.fields(), layer.wkbType(), layer.crs(), context) total = 100.0 / source.featureCount()
features = QgsProcessingUtils.getFeatures(layer, context)
total = 100.0 / QgsProcessingUtils.featureCount(layer, context)
for current, f in enumerate(features): for current, f in enumerate(features):
if feedback.isCanceled():
break
feature = f feature = f
if feature.hasGeometry(): if feature.hasGeometry():
new_geometry = feature.geometry().densifyByCount(int(vertices)) new_geometry = feature.geometry().densifyByCount(vertices)
feature.setGeometry(new_geometry) feature.setGeometry(new_geometry)
writer.addFeature(feature) sink.addFeature(feature)
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
del writer return {self.OUTPUT: dest_id}

View File

@ -31,13 +31,12 @@ from math import sqrt
from qgis.core import (QgsWkbTypes, from qgis.core import (QgsWkbTypes,
QgsApplication, QgsApplication,
QgsProcessingUtils) QgsProcessingParameterFeatureSource,
QgsProcessingParameterNumber,
QgsProcessingParameterFeatureSink,
QgsProcessingOutputVectorLayer,
QgsProcessingParameterDefinition)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterNumber
from processing.core.outputs import OutputVector
from processing.tools import dataobjects
class DensifyGeometriesInterval(QgisAlgorithm): class DensifyGeometriesInterval(QgisAlgorithm):
@ -57,13 +56,15 @@ class DensifyGeometriesInterval(QgisAlgorithm):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.addParameter(ParameterVector(self.INPUT,
self.tr('Input layer'),
[dataobjects.TYPE_VECTOR_POLYGON, dataobjects.TYPE_VECTOR_LINE]))
self.addParameter(ParameterNumber(self.INTERVAL,
self.tr('Interval between vertices to add'), 0.0, 10000000.0, 1.0))
self.addOutput(OutputVector(self.OUTPUT, self.tr('Densified'))) self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer'), [QgsProcessingParameterDefinition.TypeVectorPolygon, QgsProcessingParameterDefinition.TypeVectorLine]))
self.addParameter(QgsProcessingParameterNumber(self.INTERVAL,
self.tr('Interval between vertices to add'), QgsProcessingParameterNumber.Double,
1, False, 0, 10000000))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Densified')))
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr('Densified')))
def name(self): def name(self):
return 'densifygeometriesgivenaninterval' return 'densifygeometriesgivenaninterval'
@ -72,23 +73,24 @@ class DensifyGeometriesInterval(QgisAlgorithm):
return self.tr('Densify geometries given an interval') return self.tr('Densify geometries given an interval')
def processAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context) source = self.parameterAsSource(parameters, self.INPUT, context)
interval = self.getParameterValue(self.INTERVAL) interval = self.parameterAsDouble(parameters, self.INTERVAL, context)
isPolygon = layer.geometryType() == QgsWkbTypes.PolygonGeometry (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
writer = self.getOutputFromName( features = source.getFeatures()
self.OUTPUT).getVectorWriter(layer.fields(), layer.wkbType(), layer.crs(), context) total = 100.0 / source.featureCount()
features = QgsProcessingUtils.getFeatures(layer, context)
total = 100.0 / QgsProcessingUtils.featureCount(layer, context)
for current, f in enumerate(features): for current, f in enumerate(features):
if feedback.isCanceled():
break
feature = f feature = f
if feature.hasGeometry(): if feature.hasGeometry():
new_geometry = feature.geometry().densifyByCount(float(interval)) new_geometry = feature.geometry().densifyByDistance(float(interval))
feature.setGeometry(new_geometry) feature.setGeometry(new_geometry)
writer.addFeature(feature) sink.addFeature(feature)
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
del writer return {self.OUTPUT: dest_id}

View File

@ -29,11 +29,11 @@ from qgis.core import (QgsFeatureRequest,
QgsWkbTypes, QgsWkbTypes,
QgsCoordinateReferenceSystem, QgsCoordinateReferenceSystem,
QgsApplication, QgsApplication,
QgsProcessingUtils) QgsProcessingParameterDefinition,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsProcessingOutputVectorLayer)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.parameters import ParameterVector
from processing.core.outputs import OutputVector
from processing.tools import dataobjects
class DropGeometry(QgisAlgorithm): class DropGeometry(QgisAlgorithm):
@ -55,11 +55,10 @@ class DropGeometry(QgisAlgorithm):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.addParameter(ParameterVector(self.INPUT_LAYER,
self.tr('Input layer'), [dataobjects.TYPE_VECTOR_POINT, self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT_LAYER, self.tr('Input layer'), [QgsProcessingParameterDefinition.TypeVectorPoint, QgsProcessingParameterDefinition.TypeVectorLine, QgsProcessingParameterDefinition.TypeVectorPolygon]))
dataobjects.TYPE_VECTOR_LINE, self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT_TABLE, self.tr('Dropped geometry')))
dataobjects.TYPE_VECTOR_POLYGON])) self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT_TABLE, self.tr("Dropped geometry")))
self.addOutput(OutputVector(self.OUTPUT_TABLE, self.tr('Dropped geometry')))
def name(self): def name(self):
return 'dropgeometries' return 'dropgeometries'
@ -68,17 +67,20 @@ class DropGeometry(QgisAlgorithm):
return self.tr('Drop geometries') return self.tr('Drop geometries')
def processAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context) source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
writer = self.getOutputFromName( (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_TABLE, context,
self.OUTPUT_TABLE).getVectorWriter(layer.fields(), QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem(), source.fields(), QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem())
context)
request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry) request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry)
features = QgsProcessingUtils.getFeatures(layer, context, request) features = source.getFeatures(request)
total = 100.0 / QgsProcessingUtils.featureCount(layer, context) total = 100.0 / source.featureCount()
for current, input_feature in enumerate(features): for current, input_feature in enumerate(features):
writer.addFeature(input_feature) if feedback.isCanceled():
break
input_feature.clearGeometry()
sink.addFeature(input_feature)
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
del writer return {self.OUTPUT_TABLE: dest_id}

View File

@ -65,7 +65,8 @@ from .ExtractByExpression import ExtractByExpression
# from .Centroids import Centroids # from .Centroids import Centroids
# from .Delaunay import Delaunay # from .Delaunay import Delaunay
# from .VoronoiPolygons import VoronoiPolygons # from .VoronoiPolygons import VoronoiPolygons
# from .DensifyGeometries import DensifyGeometries from .DensifyGeometries import DensifyGeometries
from .DensifyGeometriesInterval import DensifyGeometriesInterval
from .MultipartToSingleparts import MultipartToSingleparts from .MultipartToSingleparts import MultipartToSingleparts
# from .SimplifyGeometries import SimplifyGeometries # from .SimplifyGeometries import SimplifyGeometries
# from .LinesToPolygons import LinesToPolygons # from .LinesToPolygons import LinesToPolygons
@ -84,10 +85,9 @@ from .ExtentFromLayer import ExtentFromLayer
# from .RandomSelectionWithinSubsets import RandomSelectionWithinSubsets # from .RandomSelectionWithinSubsets import RandomSelectionWithinSubsets
# from .SelectByLocation import SelectByLocation # from .SelectByLocation import SelectByLocation
# from .Union import Union # from .Union import Union
# from .DensifyGeometriesInterval import DensifyGeometriesInterval
# from .SpatialJoin import SpatialJoin # from .SpatialJoin import SpatialJoin
from .DeleteColumn import DeleteColumn from .DeleteColumn import DeleteColumn
# from .DeleteHoles import DeleteHoles from .DeleteHoles import DeleteHoles
# from .DeleteDuplicateGeometries import DeleteDuplicateGeometries # from .DeleteDuplicateGeometries import DeleteDuplicateGeometries
# from .TextToFloat import TextToFloat # from .TextToFloat import TextToFloat
# from .ExtractByAttribute import ExtractByAttribute # from .ExtractByAttribute import ExtractByAttribute
@ -168,8 +168,8 @@ from .Aspect import Aspect
# from .SnapGeometries import SnapGeometriesToLayer # from .SnapGeometries import SnapGeometriesToLayer
# from .PoleOfInaccessibility import PoleOfInaccessibility # from .PoleOfInaccessibility import PoleOfInaccessibility
# from .RasterCalculator import RasterCalculator # from .RasterCalculator import RasterCalculator
# from .CreateAttributeIndex import CreateAttributeIndex from .CreateAttributeIndex import CreateAttributeIndex
# from .DropGeometry import DropGeometry from .DropGeometry import DropGeometry
from .BasicStatistics import BasicStatisticsForField from .BasicStatistics import BasicStatisticsForField
# from .Heatmap import Heatmap # from .Heatmap import Heatmap
# from .Orthogonalize import Orthogonalize # from .Orthogonalize import Orthogonalize
@ -205,14 +205,13 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
# LinesIntersection(), UniqueValues(), PointDistance(), # LinesIntersection(), UniqueValues(), PointDistance(),
# ReprojectLayer(), ExportGeometryInfo(), Centroids(), # ReprojectLayer(), ExportGeometryInfo(), Centroids(),
# Delaunay(), VoronoiPolygons(), SimplifyGeometries(), # Delaunay(), VoronoiPolygons(), SimplifyGeometries(),
# DensifyGeometries(), DensifyGeometriesInterval(),
# , SinglePartsToMultiparts(), # , SinglePartsToMultiparts(),
# PolygonsToLines(), LinesToPolygons(), ExtractNodes(), # PolygonsToLines(), LinesToPolygons(), ExtractNodes(),
# ConvexHull(), FixedDistanceBuffer(), # ConvexHull(), FixedDistanceBuffer(),
# VariableDistanceBuffer(), Dissolve(), Difference(), # VariableDistanceBuffer(), Dissolve(), Difference(),
# Intersection(), Union(), # Intersection(), Union(),
# RandomSelection(), RandomSelectionWithinSubsets(), # RandomSelection(), RandomSelectionWithinSubsets(),
# SelectByLocation(), RandomExtract(), DeleteHoles(), # SelectByLocation(), RandomExtract(),
# RandomExtractWithinSubsets(), ExtractByLocation(), # RandomExtractWithinSubsets(), ExtractByLocation(),
# SpatialJoin(), RegularPoints(), SymmetricalDifference(), # SpatialJoin(), RegularPoints(), SymmetricalDifference(),
# VectorSplit(), VectorGridLines(), VectorGridPolygons(), # VectorSplit(), VectorGridLines(), VectorGridPolygons(),
@ -250,8 +249,8 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
# RemoveNullGeometry(), # RemoveNullGeometry(),
# ExtendLines(), ExtractSpecificNodes(), # ExtendLines(), ExtractSpecificNodes(),
# GeometryByExpression(), SnapGeometriesToLayer(), # GeometryByExpression(), SnapGeometriesToLayer(),
# PoleOfInaccessibility(), CreateAttributeIndex(), # PoleOfInaccessibility(),
# DropGeometry(), #
# RasterCalculator(), Heatmap(), Orthogonalize(), # RasterCalculator(), Heatmap(), Orthogonalize(),
# ShortestPathPointToPoint(), ShortestPathPointToLayer(), # ShortestPathPointToPoint(), ShortestPathPointToLayer(),
# ShortestPathLayerToPoint(), ServiceAreaFromPoint(), # ShortestPathLayerToPoint(), ServiceAreaFromPoint(),
@ -267,7 +266,12 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
BoundingBox(), BoundingBox(),
CheckValidity(), CheckValidity(),
Clip(), Clip(),
CreateAttributeIndex(),
DeleteColumn(), DeleteColumn(),
DeleteHoles(),
DensifyGeometries(),
DensifyGeometriesInterval(),
DropGeometry(),
ExtentFromLayer(), ExtentFromLayer(),
ExtractByExpression(), ExtractByExpression(),
GridPolygon(), GridPolygon(),

View File

@ -40,7 +40,7 @@ from qgis.core import (QgsMapLayer,
QgsProcessingParameterMultipleLayers, QgsProcessingParameterMultipleLayers,
QgsProcessingParameterRasterLayer, QgsProcessingParameterRasterLayer,
QgsProcessingParameterDefinition, QgsProcessingParameterDefinition,
QgsProcessingParameterTable, QgsProcessingParameterVectorLayer,
QgsProcessingParameterFeatureSource) QgsProcessingParameterFeatureSource)
from processing.gui.MultipleInputDialog import MultipleInputDialog from processing.gui.MultipleInputDialog import MultipleInputDialog
@ -105,7 +105,7 @@ class BatchInputSelectionPanel(QWidget):
(isinstance(self.param, QgsProcessingParameterMultipleLayers) and (isinstance(self.param, QgsProcessingParameterMultipleLayers) and
self.param.layerType() == QgsProcessingParameterDefinition.TypeRaster)): self.param.layerType() == QgsProcessingParameterDefinition.TypeRaster)):
layers = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance()) layers = QgsProcessingUtils.compatibleRasterLayers(QgsProject.instance())
elif isinstance(self.param, QgsProcessingParameterTable): elif isinstance(self.param, QgsProcessingParameterVectorLayer):
layers = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance()) layers = QgsProcessingUtils.compatibleVectorLayers(QgsProject.instance())
else: else:
datatypes = [QgsProcessingParameterDefinition.TypeVectorAny] datatypes = [QgsProcessingParameterDefinition.TypeVectorAny]

View File

@ -36,7 +36,7 @@ from qgis.core import (QgsMapLayer,
QgsProcessingParameterFolderOutput, QgsProcessingParameterFolderOutput,
QgsProcessingParameterRasterLayer, QgsProcessingParameterRasterLayer,
QgsProcessingParameterFeatureSource, QgsProcessingParameterFeatureSource,
QgsProcessingParameterTable, QgsProcessingParameterVectorLayer,
QgsProcessingParameterMultipleLayers, QgsProcessingParameterMultipleLayers,
QgsProcessingParameterBoolean, QgsProcessingParameterBoolean,
QgsProcessingParameterEnum, QgsProcessingParameterEnum,
@ -114,7 +114,7 @@ class BatchOutputSelectionPanel(QWidget):
param = self.alg.parameterDefinitions()[dlg.param_index] param = self.alg.parameterDefinitions()[dlg.param_index]
if isinstance(param, (QgsProcessingParameterRasterLayer, if isinstance(param, (QgsProcessingParameterRasterLayer,
QgsProcessingParameterFeatureSource, QgsProcessingParameterFeatureSource,
QgsProcessingParameterTable, QgsProcessingParameterVectorLayer,
QgsProcessingParameterMultipleLayers)): QgsProcessingParameterMultipleLayers)):
v = widget.value() v = widget.value()
if isinstance(v, QgsMapLayer): if isinstance(v, QgsMapLayer):

View File

@ -58,8 +58,8 @@ from qgis.core import (
QgsProcessingParameterEnum, QgsProcessingParameterEnum,
QgsProcessingParameterString, QgsProcessingParameterString,
QgsProcessingParameterExpression, QgsProcessingParameterExpression,
QgsProcessingParameterTable, QgsProcessingParameterVectorLayer,
QgsProcessingParameterTableField, QgsProcessingParameterField,
QgsProcessingParameterFeatureSource, QgsProcessingParameterFeatureSource,
QgsProcessingFeatureSourceDefinition, QgsProcessingFeatureSourceDefinition,
QgsProcessingOutputRasterLayer, QgsProcessingOutputRasterLayer,
@ -531,7 +531,7 @@ class MultipleInputWidgetWrapper(WidgetWrapper):
elif self.param.layerType() == QgsProcessingParameterDefinition.TypeRaster: elif self.param.layerType() == QgsProcessingParameterDefinition.TypeRaster:
options = self.dialog.getAvailableValuesOfType(QgsProcessingParameterRasterLayer, QgsProcessingOutputRasterLayer) options = self.dialog.getAvailableValuesOfType(QgsProcessingParameterRasterLayer, QgsProcessingOutputRasterLayer)
elif self.param.layerType() == QgsProcessingParameterDefinition.TypeTable: elif self.param.layerType() == QgsProcessingParameterDefinition.TypeTable:
options = self.dialog.getAvailableValuesOfType(QgsProcessingParameterTable, OutputTable) options = self.dialog.getAvailableValuesOfType(QgsProcessingParameterVectorLayer, OutputTable)
else: else:
options = self.dialog.getAvailableValuesOfType(QgsProcessingParameterFile, OutputFile) options = self.dialog.getAvailableValuesOfType(QgsProcessingParameterFile, OutputFile)
options = sorted(options, key=lambda opt: self.dialog.resolveValueDescription(opt)) options = sorted(options, key=lambda opt: self.dialog.resolveValueDescription(opt))
@ -907,7 +907,7 @@ class StringWidgetWrapper(WidgetWrapper, ExpressionWidgetWrapperMixin):
else: else:
# strings, numbers, files and table fields are all allowed input types # strings, numbers, files and table fields are all allowed input types
strings = self.dialog.getAvailableValuesOfType([QgsProcessingParameterString, QgsProcessingParameterNumber, QgsProcessingParameterFile, strings = self.dialog.getAvailableValuesOfType([QgsProcessingParameterString, QgsProcessingParameterNumber, QgsProcessingParameterFile,
QgsProcessingParameterTableField, QgsProcessingParameterExpression], QgsProcessingOutputString) QgsProcessingParameterField, QgsProcessingParameterExpression], QgsProcessingOutputString)
options = [(self.dialog.resolveValueDescription(s), s) for s in strings] options = [(self.dialog.resolveValueDescription(s), s) for s in strings]
if self.param.multiLine(): if self.param.multiLine():
widget = MultilineTextPanel(options) widget = MultilineTextPanel(options)
@ -1079,7 +1079,7 @@ class TableWidgetWrapper(WidgetWrapper):
self.combo = QComboBox() self.combo = QComboBox()
layers = self.dialog.getAvailableValuesOfType(QgsProcessingParameterRasterLayer, QgsProcessingOutputRasterLayer) layers = self.dialog.getAvailableValuesOfType(QgsProcessingParameterRasterLayer, QgsProcessingOutputRasterLayer)
self.combo.setEditable(True) self.combo.setEditable(True)
tables = self.dialog.getAvailableValuesOfType(QgsProcessingParameterTable, OutputTable) tables = self.dialog.getAvailableValuesOfType(QgsProcessingParameterVectorLayer, OutputTable)
layers = self.dialog.getAvailableValuesOfType(QgsProcessingParameterFeatureSource, QgsProcessingOutputVectorLayer) layers = self.dialog.getAvailableValuesOfType(QgsProcessingParameterFeatureSource, QgsProcessingOutputVectorLayer)
if self.param.flags() & QgsProcessingParameterDefinition.FlagOptional: if self.param.flags() & QgsProcessingParameterDefinition.FlagOptional:
self.combo.addItem(self.NOT_SELECTED, None) self.combo.addItem(self.NOT_SELECTED, None)
@ -1154,17 +1154,17 @@ class TableFieldWidgetWrapper(WidgetWrapper):
widget = QgsFieldComboBox() widget = QgsFieldComboBox()
widget.setAllowEmptyFieldName(self.param.flags() & QgsProcessingParameterDefinition.FlagOptional) widget.setAllowEmptyFieldName(self.param.flags() & QgsProcessingParameterDefinition.FlagOptional)
widget.fieldChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) widget.fieldChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
if self.param.dataType() == QgsProcessingParameterTableField.Numeric: if self.param.dataType() == QgsProcessingParameterField.Numeric:
widget.setFilters(QgsFieldProxyModel.Numeric) widget.setFilters(QgsFieldProxyModel.Numeric)
elif self.param.dataType() == QgsProcessingParameterTableField.String: elif self.param.dataType() == QgsProcessingParameterField.String:
widget.setFilters(QgsFieldProxyModel.String) widget.setFilters(QgsFieldProxyModel.String)
elif self.param.dataType() == QgsProcessingParameterTableField.DateTime: elif self.param.dataType() == QgsProcessingParameterField.DateTime:
widget.setFilters(QgsFieldProxyModel.Date | QgsFieldProxyModel.Time) widget.setFilters(QgsFieldProxyModel.Date | QgsFieldProxyModel.Time)
return widget return widget
else: else:
widget = QComboBox() widget = QComboBox()
widget.setEditable(True) widget.setEditable(True)
fields = self.dialog.getAvailableValuesOfType([QgsProcessingParameterTableField, QgsProcessingParameterString], [QgsProcessingOutputString]) fields = self.dialog.getAvailableValuesOfType([QgsProcessingParameterField, QgsProcessingParameterString], [QgsProcessingOutputString])
if self.param.flags() & QgsProcessingParameterDefinition.FlagOptional: if self.param.flags() & QgsProcessingParameterDefinition.FlagOptional:
widget.addItem(self.NOT_SET, None) widget.addItem(self.NOT_SET, None)
for f in fields: for f in fields:
@ -1202,12 +1202,12 @@ class TableFieldWidgetWrapper(WidgetWrapper):
if self._layer is None: if self._layer is None:
return [] return []
fieldTypes = [] fieldTypes = []
if self.param.dataType() == QgsProcessingParameterTableField.String: if self.param.dataType() == QgsProcessingParameterField.String:
fieldTypes = [QVariant.String] fieldTypes = [QVariant.String]
elif self.param.dataType() == QgsProcessingParameterTableField.Numeric: elif self.param.dataType() == QgsProcessingParameterField.Numeric:
fieldTypes = [QVariant.Int, QVariant.Double, QVariant.LongLong, fieldTypes = [QVariant.Int, QVariant.Double, QVariant.LongLong,
QVariant.UInt, QVariant.ULongLong] QVariant.UInt, QVariant.ULongLong]
elif self.param.dataType() == QgsProcessingParameterTableField.DateTime: elif self.param.dataType() == QgsProcessingParameterField.DateTime:
fieldTypes = [QVariant.Date, QVariant.Time, QVariant.DateTime] fieldTypes = [QVariant.Date, QVariant.Time, QVariant.DateTime]
fieldNames = set() fieldNames = set()
@ -1303,7 +1303,7 @@ class WidgetWrapperFactory:
wrapper = StringWidgetWrapper wrapper = StringWidgetWrapper
elif param.type() == 'expression': elif param.type() == 'expression':
wrapper = ExpressionWidgetWrapper wrapper = ExpressionWidgetWrapper
elif param.type() == 'table': elif param.type() == 'vector':
wrapper = TableWidgetWrapper wrapper = TableWidgetWrapper
elif param.type() == 'field': elif param.type() == 'field':
wrapper = TableFieldWidgetWrapper wrapper = TableFieldWidgetWrapper

View File

@ -52,8 +52,8 @@ from qgis.core import (QgsApplication,
QgsProcessingParameterEnum, QgsProcessingParameterEnum,
QgsProcessingParameterString, QgsProcessingParameterString,
QgsProcessingParameterExpression, QgsProcessingParameterExpression,
QgsProcessingParameterTable, QgsProcessingParameterVectorLayer,
QgsProcessingParameterTableField, QgsProcessingParameterField,
QgsProcessingParameterFeatureSource, QgsProcessingParameterFeatureSource,
QgsProcessingModelAlgorithm) QgsProcessingModelAlgorithm)
from qgis.gui import QgsMessageBar from qgis.gui import QgsMessageBar

View File

@ -45,8 +45,8 @@ from qgis.core import (QgsCoordinateReferenceSystem,
QgsProcessingParameterEnum, QgsProcessingParameterEnum,
QgsProcessingParameterString, QgsProcessingParameterString,
QgsProcessingParameterExpression, QgsProcessingParameterExpression,
QgsProcessingParameterTable, QgsProcessingParameterVectorLayer,
QgsProcessingParameterTableField, QgsProcessingParameterField,
QgsProcessingParameterFeatureSource) QgsProcessingParameterFeatureSource)
from qgis.PyQt.QtCore import Qt from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtWidgets import (QDialog, from qgis.PyQt.QtWidgets import (QDialog,
@ -123,13 +123,13 @@ class ModelerParameterDefinitionDialog(QDialog):
self.state.setChecked(bool(self.param.defaultValue())) self.state.setChecked(bool(self.param.defaultValue()))
self.verticalLayout.addWidget(self.state) self.verticalLayout.addWidget(self.state)
elif self.paramType == ModelerParameterDefinitionDialog.PARAMETER_TABLE_FIELD or \ elif self.paramType == ModelerParameterDefinitionDialog.PARAMETER_TABLE_FIELD or \
isinstance(self.param, QgsProcessingParameterTableField): isinstance(self.param, QgsProcessingParameterField):
self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.verticalLayout.addWidget(QLabel(self.tr('Parent layer')))
self.parentCombo = QComboBox() self.parentCombo = QComboBox()
idx = 0 idx = 0
for param in list(self.alg.parameterComponents().values()): for param in list(self.alg.parameterComponents().values()):
definition = self.alg.parameterDefinition(param.parameterName()) definition = self.alg.parameterDefinition(param.parameterName())
if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterTable)): if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)):
self.parentCombo.addItem(definition.description(), definition.name()) self.parentCombo.addItem(definition.description(), definition.name())
if self.param is not None: if self.param is not None:
if self.param.parentLayerParameter() == definition.name(): if self.param.parentLayerParameter() == definition.name():
@ -218,7 +218,7 @@ class ModelerParameterDefinitionDialog(QDialog):
idx = 1 idx = 1
for param in list(self.alg.parameterComponents().values()): for param in list(self.alg.parameterComponents().values()):
definition = self.alg.parameterDefinition(param.parameterName()) definition = self.alg.parameterDefinition(param.parameterName())
if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterTable)): if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)):
self.parentCombo.addItem(definition.description(), definition.name()) self.parentCombo.addItem(definition.description(), definition.name())
if self.param is not None: if self.param is not None:
if self.param.parentLayerParameter() == definition.name(): if self.param.parentLayerParameter() == definition.name():
@ -301,21 +301,21 @@ class ModelerParameterDefinitionDialog(QDialog):
isinstance(self.param, QgsProcessingParameterBoolean)): isinstance(self.param, QgsProcessingParameterBoolean)):
self.param = QgsProcessingParameterBoolean(name, description, self.state.isChecked()) self.param = QgsProcessingParameterBoolean(name, description, self.state.isChecked())
elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_TABLE_FIELD or elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_TABLE_FIELD or
isinstance(self.param, QgsProcessingParameterTableField)): isinstance(self.param, QgsProcessingParameterField)):
if self.parentCombo.currentIndex() < 0: if self.parentCombo.currentIndex() < 0:
QMessageBox.warning(self, self.tr('Unable to define parameter'), QMessageBox.warning(self, self.tr('Unable to define parameter'),
self.tr('Wrong or missing parameter values')) self.tr('Wrong or missing parameter values'))
return return
parent = self.parentCombo.currentData() parent = self.parentCombo.currentData()
datatype = self.datatypeCombo.currentData() datatype = self.datatypeCombo.currentData()
self.param = QgsProcessingParameterTableField(name, description, None, parent, datatype, self.multipleCheck.isChecked()) self.param = QgsProcessingParameterField(name, description, None, parent, datatype, self.multipleCheck.isChecked())
elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_RASTER or elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_RASTER or
isinstance(self.param, QgsProcessingParameterRasterLayer)): isinstance(self.param, QgsProcessingParameterRasterLayer)):
self.param = QgsProcessingParameterRasterLayer( self.param = QgsProcessingParameterRasterLayer(
name, description) name, description)
elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_TABLE or elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_TABLE or
isinstance(self.param, QgsProcessingParameterTable)): isinstance(self.param, QgsProcessingParameterVectorLayer)):
self.param = QgsProcessingParameterTable( self.param = QgsProcessingParameterVectorLayer(
name, description) name, description)
elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_VECTOR or elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_VECTOR or
isinstance(self.param, QgsProcessingParameterFeatureSource)): isinstance(self.param, QgsProcessingParameterFeatureSource)):

View File

@ -50,7 +50,7 @@ from processing.script.ScriptAlgorithm import ScriptAlgorithm # NOQA
from processing.modeler.ModelerAlgorithmProvider import ModelerAlgorithmProvider # NOQA from processing.modeler.ModelerAlgorithmProvider import ModelerAlgorithmProvider # NOQA
from processing.algs.qgis.QGISAlgorithmProvider import QGISAlgorithmProvider # NOQA from processing.algs.qgis.QGISAlgorithmProvider import QGISAlgorithmProvider # NOQA
from processing.algs.grass7.Grass7AlgorithmProvider import Grass7AlgorithmProvider # NOQA #from processing.algs.grass7.Grass7AlgorithmProvider import Grass7AlgorithmProvider # NOQA
from processing.algs.gdal.GdalAlgorithmProvider import GdalAlgorithmProvider # NOQA from processing.algs.gdal.GdalAlgorithmProvider import GdalAlgorithmProvider # NOQA
from processing.algs.saga.SagaAlgorithmProvider import SagaAlgorithmProvider # NOQA from processing.algs.saga.SagaAlgorithmProvider import SagaAlgorithmProvider # NOQA
from processing.script.ScriptAlgorithmProvider import ScriptAlgorithmProvider # NOQA from processing.script.ScriptAlgorithmProvider import ScriptAlgorithmProvider # NOQA

View File

@ -15,16 +15,16 @@ tests:
# geometry: # geometry:
# precision: 7 # precision: 7
# #
# - name: Delete Holes - name: Delete Holes
# algorithm: qgis:deleteholes algorithm: qgis:deleteholes
# params: params:
# - name: polys.gml - name: polys.gml
# type: vector type: vector
# results: results:
# OUTPUT: OUTPUT:
# name: expected/polys_deleteholes.gml name: expected/polys_deleteholes.gml
# type: vector type: vector
#
- algorithm: qgis:clip - algorithm: qgis:clip
name: Clip lines by polygons name: Clip lines by polygons
params: params:
@ -128,18 +128,18 @@ tests:
# name: expected/intersection_collection_fallback.shp # name: expected/intersection_collection_fallback.shp
# type: vector # type: vector
# #
# - name: Densify geometries - name: Densify geometries
# algorithm: qgis:densifygeometries algorithm: qgis:densifygeometries
# params: params:
# INPUT: INPUT:
# name: multipolys.gml name: multipolys.gml
# type: vector type: vector
# VERTICES: 4 VERTICES: 4
# results: results:
# OUTPUT: OUTPUT:
# name: expected/multipolys_densify.gml name: expected/multipolys_densify.gml
# type: vector type: vector
#
# - name: Polygons to Lines # - name: Polygons to Lines
# algorithm: qgis:polygonstolines # algorithm: qgis:polygonstolines
# params: # params:
@ -1258,7 +1258,7 @@ tests:
# name: expected/remove_null_polys.gml # name: expected/remove_null_polys.gml
# type: vector # type: vector
# #
- algorithm: qgis:extractbyexpression - algorithm: native:extractbyexpression
name: Extract by Expression name: Extract by Expression
params: params:
EXPRESSION: left( "Name",1)='A' EXPRESSION: left( "Name",1)='A'
@ -1484,88 +1484,88 @@ tests:
# geometry: # geometry:
# precision: 7 # precision: 7
# #
# - algorithm: qgis:extractbyattribute - algorithm: native:extractbyattribute
# name: Extract by attribute (is null) name: Extract by attribute (is null)
# params: params:
# FIELD: intval FIELD: intval
# INPUT: INPUT:
# name: polys.gml name: polys.gml
# type: vector type: vector
# OPERATOR: '8' OPERATOR: '8'
# results: results:
# OUTPUT: OUTPUT:
# name: expected/extract_by_attribute_null.gml name: expected/extract_by_attribute_null.gml
# type: vector type: vector
#
# - algorithm: qgis:extractbyattribute - algorithm: native:extractbyattribute
# name: Extract by attribute (is not null) name: Extract by attribute (is not null)
# params: params:
# FIELD: intval FIELD: intval
# INPUT: INPUT:
# name: polys.gml name: polys.gml
# type: vector type: vector
# OPERATOR: '9' OPERATOR: '9'
# results: results:
# OUTPUT: OUTPUT:
# name: expected/extract_by_attribute_not_null.gml name: expected/extract_by_attribute_not_null.gml
# type: vector type: vector
#
# - algorithm: qgis:extractbyattribute - algorithm: native:extractbyattribute
# name: Extract by attribute (starts with) name: Extract by attribute (starts with)
# params: params:
# FIELD: name FIELD: name
# INPUT: INPUT:
# name: polys.gml name: polys.gml
# type: vector type: vector
# OPERATOR: '6' OPERATOR: '6'
# VALUE: A VALUE: A
# results: results:
# OUTPUT: OUTPUT:
# name: expected/extract_by_attribute_startswith.gml name: expected/extract_by_attribute_startswith.gml
# type: vector type: vector
#
# - algorithm: qgis:extractbyattribute - algorithm: native:extractbyattribute
# name: Extract by attribute (contains) name: Extract by attribute (contains)
# params: params:
# FIELD: name FIELD: name
# INPUT: INPUT:
# name: polys.gml name: polys.gml
# type: vector type: vector
# OPERATOR: '7' OPERATOR: '7'
# VALUE: aaa VALUE: aaa
# results: results:
# OUTPUT: OUTPUT:
# name: expected/extract_by_attribute_contains.gml name: expected/extract_by_attribute_contains.gml
# type: vector type: vector
#
# - algorithm: qgis:extractbyattribute - algorithm: native:extractbyattribute
# name: Extract by attribute (does not contain) name: Extract by attribute (does not contain)
# params: params:
# FIELD: name FIELD: name
# INPUT: INPUT:
# name: polys.gml name: polys.gml
# type: vector type: vector
# OPERATOR: '10' OPERATOR: '10'
# VALUE: a VALUE: a
# results: results:
# OUTPUT: OUTPUT:
# name: expected/extract_by_attribute_does_not_contain.gml name: expected/extract_by_attribute_does_not_contain.gml
# type: vector type: vector
#
# - algorithm: qgis:extractbyattribute - algorithm: native:extractbyattribute
# name: Extract by attribute (greater) name: Extract by attribute (greater)
# params: params:
# FIELD: floatval FIELD: floatval
# INPUT: INPUT:
# name: polys.gml name: polys.gml
# type: vector type: vector
# OPERATOR: '2' OPERATOR: '2'
# VALUE: '1' VALUE: '1'
# results: results:
# OUTPUT: OUTPUT:
# name: expected/extract_by_attribute_greater.gml name: expected/extract_by_attribute_greater.gml
# type: vector type: vector
#
# - algorithm: qgis:createattributeindex # - algorithm: qgis:createattributeindex
# name: Create Attribute Index (only tests for python errors, does not check result) # name: Create Attribute Index (only tests for python errors, does not check result)
# params: # params:
@ -1665,18 +1665,18 @@ tests:
# compare: # compare:
# geometry: # geometry:
# precision: 7 # precision: 7
#
# - algorithm: qgis:dropgeometries - algorithm: qgis:dropgeometries
# name: Drop geometries name: Drop geometries
# params: params:
# INPUT_LAYER: INPUT_LAYER:
# name: polys.gml name: polys.gml
# type: vector type: vector
# results: results:
# OUTPUT_TABLE: OUTPUT_TABLE:
# name: expected/dropped_geometry.csv name: expected/dropped_geometry.csv
# type: vector type: vector
#
# - algorithm: qgis:creategridlines # - algorithm: qgis:creategridlines
# name: Create grid (lines) # name: Create grid (lines)
# params: # params:
@ -1808,30 +1808,30 @@ tests:
geometry: geometry:
precision: 7 precision: 7
# - algorithm: qgis:deleteholes - algorithm: qgis:deleteholes
# name: Delete holes (no min) name: Delete holes (no min)
# params: params:
# INPUT: INPUT:
# name: custom/remove_holes.gml name: custom/remove_holes.gml
# type: vector type: vector
# MIN_AREA: 0.0 MIN_AREA: 0.0
# results: results:
# OUTPUT: OUTPUT:
# name: expected/removed_holes.gml name: expected/removed_holes.gml
# type: vector type: vector
#
# - algorithm: qgis:deleteholes - algorithm: qgis:deleteholes
# name: Delete holes (with min) name: Delete holes (with min)
# params: params:
# INPUT: INPUT:
# name: custom/remove_holes.gml name: custom/remove_holes.gml
# type: vector type: vector
# MIN_AREA: 5.0 MIN_AREA: 5.0
# results: results:
# OUTPUT: OUTPUT:
# name: expected/removed_holes_min_area.gml name: expected/removed_holes_min_area.gml
# type: vector type: vector
#
- algorithm: qgis:basicstatisticsforfields - algorithm: qgis:basicstatisticsforfields
name: Basic stats datetime name: Basic stats datetime
params: params:

View File

@ -3620,7 +3620,7 @@ void QgisApp::updateRecentProjectPaths()
{ {
QAction *action = mRecentProjectsMenu->addAction( QStringLiteral( "%1 (%2)" ).arg( recentProject.title != recentProject.path ? recentProject.title : QFileInfo( recentProject.path ).baseName(), QAction *action = mRecentProjectsMenu->addAction( QStringLiteral( "%1 (%2)" ).arg( recentProject.title != recentProject.path ? recentProject.title : QFileInfo( recentProject.path ).baseName(),
QDir::toNativeSeparators( recentProject.path ) ) ); QDir::toNativeSeparators( recentProject.path ) ) );
action->setEnabled( QFile::exists( ( recentProject.path ) ) ); //action->setEnabled( QFile::exists( ( recentProject.path ) ) );
action->setData( recentProject.path ); action->setData( recentProject.path );
} }

View File

@ -58,12 +58,15 @@ bool QgsNativeAlgorithms::supportsNonFileBasedOutput() const
void QgsNativeAlgorithms::loadAlgorithms() void QgsNativeAlgorithms::loadAlgorithms()
{ {
addAlgorithm( new QgsCentroidAlgorithm() );
addAlgorithm( new QgsBufferAlgorithm() ); addAlgorithm( new QgsBufferAlgorithm() );
addAlgorithm( new QgsDissolveAlgorithm() ); addAlgorithm( new QgsCentroidAlgorithm() );
addAlgorithm( new QgsClipAlgorithm() ); addAlgorithm( new QgsClipAlgorithm() );
addAlgorithm( new QgsTransformAlgorithm() ); addAlgorithm( new QgsDissolveAlgorithm() );
addAlgorithm( new QgsExtractByAttributeAlgorithm() );
addAlgorithm( new QgsExtractByExpressionAlgorithm() );
addAlgorithm( new QgsMultipartToSinglepartAlgorithm() );
addAlgorithm( new QgsSubdivideAlgorithm() ); addAlgorithm( new QgsSubdivideAlgorithm() );
addAlgorithm( new QgsTransformAlgorithm() );
} }
@ -244,8 +247,8 @@ QVariantMap QgsBufferAlgorithm::processAlgorithm( const QVariantMap &parameters,
QgsDissolveAlgorithm::QgsDissolveAlgorithm() QgsDissolveAlgorithm::QgsDissolveAlgorithm()
{ {
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) ); addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
addParameter( new QgsProcessingParameterTableField( QStringLiteral( "FIELD" ), QObject::tr( "Unique ID fields" ), QVariant(), addParameter( new QgsProcessingParameterField( QStringLiteral( "FIELD" ), QObject::tr( "Unique ID fields" ), QVariant(),
QStringLiteral( "INPUT" ), QgsProcessingParameterTableField::Any, true, true ) ); QStringLiteral( "INPUT" ), QgsProcessingParameterField::Any, true, true ) );
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Dissolved" ) ) ); addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Dissolved" ) ) );
addOutput( new QgsProcessingOutputVectorLayer( QStringLiteral( "OUTPUT" ), QObject::tr( "Dissolved" ) ) ); addOutput( new QgsProcessingOutputVectorLayer( QStringLiteral( "OUTPUT" ), QObject::tr( "Dissolved" ) ) );
@ -664,6 +667,380 @@ QVariantMap QgsSubdivideAlgorithm::processAlgorithm( const QVariantMap &paramete
return outputs; return outputs;
} }
QgsMultipartToSinglepartAlgorithm::QgsMultipartToSinglepartAlgorithm()
{
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Single parts" ) ) );
addOutput( new QgsProcessingOutputVectorLayer( QStringLiteral( "OUTPUT" ), QObject::tr( "Single parts" ) ) );
}
QString QgsMultipartToSinglepartAlgorithm::shortHelpString() const
{
return QObject::tr( "This algorithm takes a vector layer with multipart geometries and generates a new one in which all geometries contain "
"a single part. Features with multipart geometries are divided in as many different features as parts the geometry "
"contain, and the same attributes are used for each of them." );
}
QVariantMap QgsMultipartToSinglepartAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const
{
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !source )
return QVariantMap();
QgsWkbTypes::Type sinkType = QgsWkbTypes::singleType( source->wkbType() );
QString dest;
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, source->fields(),
sinkType, source->sourceCrs(), dest ) );
if ( !sink )
return QVariantMap();
long count = source->featureCount();
if ( count <= 0 )
return QVariantMap();
QgsFeature f;
QgsFeatureIterator it = source->getFeatures();
double step = 100.0 / count;
int current = 0;
while ( it.nextFeature( f ) )
{
if ( feedback->isCanceled() )
{
break;
}
QgsFeature out = f;
if ( out.hasGeometry() )
{
QgsGeometry inputGeometry = f.geometry();
if ( inputGeometry.isMultipart() )
{
Q_FOREACH ( const QgsGeometry &g, inputGeometry.asGeometryCollection() )
{
out.setGeometry( g );
sink->addFeature( out );
}
}
else
{
sink->addFeature( out );
}
}
else
{
// feature with null geometry
sink->addFeature( out );
}
feedback->setProgress( current * step );
current++;
}
QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
return outputs;
}
QgsExtractByExpressionAlgorithm::QgsExtractByExpressionAlgorithm()
{
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
addParameter( new QgsProcessingParameterExpression( QStringLiteral( "EXPRESSION" ), QObject::tr( "Expression" ), QVariant(), QStringLiteral( "INPUT" ) ) );
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Matching features" ) ) );
addOutput( new QgsProcessingOutputVectorLayer( QStringLiteral( "OUTPUT" ), QObject::tr( "Matching (expression)" ) ) );
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "FAIL_OUTPUT" ), QObject::tr( "Non-matching" ),
QgsProcessingParameterDefinition::TypeVectorAny, QVariant(), true ) );
addOutput( new QgsProcessingOutputVectorLayer( QStringLiteral( "FAIL_OUTPUT" ), QObject::tr( "Non-matching (expression)" ) ) );
}
QString QgsExtractByExpressionAlgorithm::shortHelpString() const
{
return QObject::tr( "This algorithm creates a new vector layer that only contains matching features from an input layer. "
"The criteria for adding features to the resulting layer is based on a QGIS expression.\n\n"
"For more information about expressions see the <a href =\"{qgisdocs}/user_manual/working_with_vector/expression.html\">user manual</a>" );
}
QVariantMap QgsExtractByExpressionAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const
{
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !source )
return QVariantMap();
QString expressionString = parameterAsExpression( parameters, QStringLiteral( "EXPRESSION" ), context );
QString matchingSinkId;
std::unique_ptr< QgsFeatureSink > matchingSink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, source->fields(),
source->wkbType(), source->sourceCrs(), matchingSinkId ) );
if ( !matchingSink )
return QVariantMap();
QString nonMatchingSinkId;
std::unique_ptr< QgsFeatureSink > nonMatchingSink( parameterAsSink( parameters, QStringLiteral( "FAIL_OUTPUT" ), context, source->fields(),
source->wkbType(), source->sourceCrs(), nonMatchingSinkId ) );
QgsExpression expression( expressionString );
if ( expression.hasParserError() )
{
// raise GeoAlgorithmExecutionException(expression.parserErrorString())
return QVariantMap();
}
QgsExpressionContext expressionContext = createExpressionContext( parameters, context );
long count = source->featureCount();
if ( count <= 0 )
return QVariantMap();
double step = 100.0 / count;
int current = 0;
if ( !nonMatchingSink )
{
// not saving failing features - so only fetch good features
QgsFeatureRequest req;
req.setFilterExpression( expressionString );
req.setExpressionContext( expressionContext );
QgsFeatureIterator it = source->getFeatures( req );
QgsFeature f;
while ( it.nextFeature( f ) )
{
if ( feedback->isCanceled() )
{
break;
}
matchingSink->addFeature( f );
feedback->setProgress( current * step );
current++;
}
}
else
{
// saving non-matching features, so we need EVERYTHING
expressionContext.setFields( source->fields() );
expression.prepare( &expressionContext );
QgsFeatureIterator it = source->getFeatures();
QgsFeature f;
while ( it.nextFeature( f ) )
{
if ( feedback->isCanceled() )
{
break;
}
expressionContext.setFeature( f );
if ( expression.evaluate( &expressionContext ).toBool() )
{
matchingSink->addFeature( f );
}
else
{
nonMatchingSink->addFeature( f );
}
feedback->setProgress( current * step );
current++;
}
}
QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), matchingSinkId );
if ( nonMatchingSink )
outputs.insert( QStringLiteral( "FAIL_OUTPUT" ), nonMatchingSinkId );
return outputs;
}
QgsExtractByAttributeAlgorithm::QgsExtractByAttributeAlgorithm()
{
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
addParameter( new QgsProcessingParameterField( QStringLiteral( "FIELD" ), QObject::tr( "Selection attribute" ), QVariant(), QStringLiteral( "INPUT" ) ) );
addParameter( new QgsProcessingParameterEnum( QStringLiteral( "OPERATOR" ), QObject::tr( "Operator" ), QStringList()
<< QObject::tr( "=" )
<< QObject::trUtf8( "" )
<< QObject::tr( ">" )
<< QObject::tr( ">=" )
<< QObject::tr( "<" )
<< QObject::tr( "<=" )
<< QObject::tr( "begins with" )
<< QObject::tr( "contains" )
<< QObject::tr( "is null" )
<< QObject::tr( "is not null" )
<< QObject::tr( "does not contain" ) ) );
addParameter( new QgsProcessingParameterString( QStringLiteral( "VALUE" ), QObject::tr( "Value" ), QVariant(), false, true ) );
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Extracted (attribute)" ) ) );
addOutput( new QgsProcessingOutputVectorLayer( QStringLiteral( "OUTPUT" ), QObject::tr( "Matching (attribute)" ) ) );
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "FAIL_OUTPUT" ), QObject::tr( "Extracted (non-matching)" ),
QgsProcessingParameterDefinition::TypeVectorAny, QVariant(), true ) );
addOutput( new QgsProcessingOutputVectorLayer( QStringLiteral( "FAIL_OUTPUT" ), QObject::tr( "Non-matching (attribute)" ) ) );
}
QString QgsExtractByAttributeAlgorithm::shortHelpString() const
{
return QObject::tr( " This algorithm creates a new vector layer that only contains matching features from an input layer. "
"The criteria for adding features to the resulting layer is defined based on the values "
"of an attribute from the input layer." );
}
QVariantMap QgsExtractByAttributeAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const
{
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !source )
return QVariantMap();
QString fieldName = parameterAsString( parameters, QStringLiteral( "FIELD" ), context );
Operation op = static_cast< Operation >( parameterAsEnum( parameters, QStringLiteral( "OPERATOR" ), context ) );
QString value = parameterAsString( parameters, QStringLiteral( "VALUE" ), context );
QString matchingSinkId;
std::unique_ptr< QgsFeatureSink > matchingSink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, source->fields(),
source->wkbType(), source->sourceCrs(), matchingSinkId ) );
if ( !matchingSink )
return QVariantMap();
QString nonMatchingSinkId;
std::unique_ptr< QgsFeatureSink > nonMatchingSink( parameterAsSink( parameters, QStringLiteral( "FAIL_OUTPUT" ), context, source->fields(),
source->wkbType(), source->sourceCrs(), nonMatchingSinkId ) );
int idx = source->fields().lookupField( fieldName );
QVariant::Type fieldType = source->fields().at( idx ).type();
if ( fieldType != QVariant::String && ( op == BeginsWith || op == Contains || op == DoesNotContain ) )
{
#if 0
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 ) )
#endif
return QVariantMap();
}
QString fieldRef = QgsExpression::quotedColumnRef( fieldName );
QString quotedVal = QgsExpression::quotedValue( value );
QString expr;
switch ( op )
{
case Equals:
expr = QStringLiteral( "%1 = %3" ).arg( fieldRef, quotedVal );
break;
case NotEquals:
expr = QStringLiteral( "%1 != %3" ).arg( fieldRef, quotedVal );
break;
case GreaterThan:
expr = QStringLiteral( "%1 > %3" ).arg( fieldRef, quotedVal );
break;
case GreaterThanEqualTo:
expr = QStringLiteral( "%1 >= %3" ).arg( fieldRef, quotedVal );
break;
case LessThan:
expr = QStringLiteral( "%1 < %3" ).arg( fieldRef, quotedVal );
break;
case LessThanEqualTo:
expr = QStringLiteral( "%1 <= %3" ).arg( fieldRef, quotedVal );
break;
case BeginsWith:
expr = QStringLiteral( "%1 LIKE '%2%'" ).arg( fieldRef, value );
break;
case Contains:
expr = QStringLiteral( "%1 LIKE '%%2%'" ).arg( fieldRef, value );
break;
case IsNull:
expr = QStringLiteral( "%1 IS NULL" ).arg( fieldRef );
break;
case IsNotNull:
expr = QStringLiteral( "%1 IS NOT NULL" ).arg( fieldRef );
break;
case DoesNotContain:
expr = QStringLiteral( "%1 NOT LIKE '%%2%'" ).arg( fieldRef, value );
break;
}
QgsExpression expression( expr );
if ( expression.hasParserError() )
{
// raise GeoAlgorithmExecutionException(expression.parserErrorString())
return QVariantMap();
}
QgsExpressionContext expressionContext = createExpressionContext( parameters, context );
long count = source->featureCount();
if ( count <= 0 )
return QVariantMap();
double step = 100.0 / count;
int current = 0;
if ( !nonMatchingSink )
{
// not saving failing features - so only fetch good features
QgsFeatureRequest req;
req.setFilterExpression( expr );
req.setExpressionContext( expressionContext );
QgsFeatureIterator it = source->getFeatures( req );
QgsFeature f;
while ( it.nextFeature( f ) )
{
if ( feedback->isCanceled() )
{
break;
}
matchingSink->addFeature( f );
feedback->setProgress( current * step );
current++;
}
}
else
{
// saving non-matching features, so we need EVERYTHING
expressionContext.setFields( source->fields() );
expression.prepare( &expressionContext );
QgsFeatureIterator it = source->getFeatures();
QgsFeature f;
while ( it.nextFeature( f ) )
{
if ( feedback->isCanceled() )
{
break;
}
expressionContext.setFeature( f );
if ( expression.evaluate( &expressionContext ).toBool() )
{
matchingSink->addFeature( f );
}
else
{
nonMatchingSink->addFeature( f );
}
feedback->setProgress( current * step );
current++;
}
}
QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), matchingSinkId );
if ( nonMatchingSink )
outputs.insert( QStringLiteral( "FAIL_OUTPUT" ), nonMatchingSinkId );
return outputs;
}
///@endcond ///@endcond

View File

@ -135,6 +135,67 @@ class QgsDissolveAlgorithm : public QgsProcessingAlgorithm
}; };
/**
* Native extract by attribute algorithm.
*/
class QgsExtractByAttributeAlgorithm : public QgsProcessingAlgorithm
{
public:
enum Operation
{
Equals,
NotEquals,
GreaterThan,
GreaterThanEqualTo,
LessThan,
LessThanEqualTo,
BeginsWith,
Contains,
IsNull,
IsNotNull,
DoesNotContain,
};
QgsExtractByAttributeAlgorithm();
QString name() const override { return QStringLiteral( "extractbyattribute" ); }
QString displayName() const override { return QObject::tr( "Extract by attribute" ); }
virtual QStringList tags() const override { return QObject::tr( "extract,filter,attribute,value,contains,null,field" ).split( ',' ); }
QString group() const override { return QObject::tr( "Vector selection tools" ); }
QString shortHelpString() const override;
protected:
virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const override;
};
/**
* Native extract by expression algorithm.
*/
class QgsExtractByExpressionAlgorithm : public QgsProcessingAlgorithm
{
public:
QgsExtractByExpressionAlgorithm();
QString name() const override { return QStringLiteral( "extractbyexpression" ); }
QString displayName() const override { return QObject::tr( "Extract by expression" ); }
virtual QStringList tags() const override { return QObject::tr( "extract,filter,expression,field" ).split( ',' ); }
QString group() const override { return QObject::tr( "Vector selection tools" ); }
QString shortHelpString() const override;
protected:
virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const override;
};
/** /**
* Native clip algorithm. * Native clip algorithm.
*/ */
@ -182,6 +243,29 @@ class QgsSubdivideAlgorithm : public QgsProcessingAlgorithm
}; };
/**
* Native multipart to singlepart algorithm.
*/
class QgsMultipartToSinglepartAlgorithm : public QgsProcessingAlgorithm
{
public:
QgsMultipartToSinglepartAlgorithm();
QString name() const override { return QStringLiteral( "multiparttosingleparts" ); }
QString displayName() const override { return QObject::tr( "Multipart to singleparts" ); }
virtual QStringList tags() const override { return QObject::tr( "multi,single,multiple,split,dump" ).split( ',' ); }
QString group() const override { return QObject::tr( "Vector geometry tools" ); }
QString shortHelpString() const override;
protected:
virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const override;
};
///@endcond PRIVATE ///@endcond PRIVATE
#endif // QGSNATIVEALGORITHMS_H #endif // QGSNATIVEALGORITHMS_H

View File

@ -744,14 +744,16 @@ QgsProcessingParameterDefinition *QgsProcessingParameters::parameterFromVariantM
def.reset( new QgsProcessingParameterString( name ) ); def.reset( new QgsProcessingParameterString( name ) );
else if ( type == QStringLiteral( "expression" ) ) else if ( type == QStringLiteral( "expression" ) )
def.reset( new QgsProcessingParameterExpression( name ) ); def.reset( new QgsProcessingParameterExpression( name ) );
else if ( type == QStringLiteral( "table" ) ) else if ( type == QStringLiteral( "vector" ) )
def.reset( new QgsProcessingParameterTable( name ) ); def.reset( new QgsProcessingParameterVectorLayer( name ) );
else if ( type == QStringLiteral( "field" ) ) else if ( type == QStringLiteral( "field" ) )
def.reset( new QgsProcessingParameterTableField( name ) ); def.reset( new QgsProcessingParameterField( name ) );
else if ( type == QStringLiteral( "source" ) ) else if ( type == QStringLiteral( "source" ) )
def.reset( new QgsProcessingParameterFeatureSource( name ) ); def.reset( new QgsProcessingParameterFeatureSource( name ) );
else if ( type == QStringLiteral( "sink" ) ) else if ( type == QStringLiteral( "sink" ) )
def.reset( new QgsProcessingParameterFeatureSink( name ) ); def.reset( new QgsProcessingParameterFeatureSink( name ) );
else if ( type == QStringLiteral( "vectorOut" ) )
def.reset( new QgsProcessingParameterVectorOutput( name ) );
else if ( type == QStringLiteral( "rasterOut" ) ) else if ( type == QStringLiteral( "rasterOut" ) )
def.reset( new QgsProcessingParameterRasterOutput( name ) ); def.reset( new QgsProcessingParameterRasterOutput( name ) );
else if ( type == QStringLiteral( "fileOut" ) ) else if ( type == QStringLiteral( "fileOut" ) )
@ -1731,13 +1733,53 @@ bool QgsProcessingParameterExpression::fromVariantMap( const QVariantMap &map )
return true; return true;
} }
QgsProcessingParameterTable::QgsProcessingParameterTable( const QString &name, const QString &description, const QVariant &defaultValue, bool optional ) QgsProcessingParameterVectorLayer::QgsProcessingParameterVectorLayer( const QString &name, const QString &description, const QVariant &defaultValue, bool optional )
: QgsProcessingParameterDefinition( name, description, defaultValue, optional ) : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
{ {
} }
QgsProcessingParameterTableField::QgsProcessingParameterTableField( const QString &name, const QString &description, const QVariant &defaultValue, const QString &parentLayerParameterName, DataType type, bool allowMultiple, bool optional ) bool QgsProcessingParameterVectorLayer::checkValueIsAcceptable( const QVariant &var, QgsProcessingContext *context ) const
{
if ( !var.isValid() )
return mFlags & FlagOptional;
if ( var.canConvert<QgsProperty>() )
{
return true;
}
if ( qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( var ) ) )
return true;
if ( var.type() != QVariant::String || var.toString().isEmpty() )
return mFlags & FlagOptional;
if ( !context )
{
// that's as far as we can get without a context
return true;
}
// try to load as layer
if ( QgsProcessingUtils::mapLayerFromString( var.toString(), *context ) )
return true;
return false;
}
QString QgsProcessingParameterVectorLayer::valueAsPythonString( const QVariant &val, QgsProcessingContext &context ) const
{
if ( val.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( val.value< QgsProperty >().asExpression() );
QVariantMap p;
p.insert( name(), val );
QgsVectorLayer *layer = QgsProcessingParameters::parameterAsVectorLayer( this, p, context );
return layer ? QgsProcessingUtils::normalizeLayerSource( layer->source() ).prepend( '\'' ).append( '\'' ) : QString();
}
QgsProcessingParameterField::QgsProcessingParameterField( const QString &name, const QString &description, const QVariant &defaultValue, const QString &parentLayerParameterName, DataType type, bool allowMultiple, bool optional )
: QgsProcessingParameterDefinition( name, description, defaultValue, optional ) : QgsProcessingParameterDefinition( name, description, defaultValue, optional )
, mParentLayerParameter( parentLayerParameterName ) , mParentLayerParameter( parentLayerParameterName )
, mDataType( type ) , mDataType( type )
@ -1746,7 +1788,7 @@ QgsProcessingParameterTableField::QgsProcessingParameterTableField( const QStrin
} }
bool QgsProcessingParameterTableField::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const bool QgsProcessingParameterField::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
{ {
if ( !input.isValid() ) if ( !input.isValid() )
return mFlags & FlagOptional; return mFlags & FlagOptional;
@ -1778,7 +1820,7 @@ bool QgsProcessingParameterTableField::checkValueIsAcceptable( const QVariant &i
return true; return true;
} }
QString QgsProcessingParameterTableField::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const QString QgsProcessingParameterField::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
{ {
if ( value.canConvert<QgsProperty>() ) if ( value.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() ); return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
@ -1805,37 +1847,37 @@ QString QgsProcessingParameterTableField::valueAsPythonString( const QVariant &v
return value.toString().prepend( '\'' ).append( '\'' ); return value.toString().prepend( '\'' ).append( '\'' );
} }
QString QgsProcessingParameterTableField::parentLayerParameter() const QString QgsProcessingParameterField::parentLayerParameter() const
{ {
return mParentLayerParameter; return mParentLayerParameter;
} }
void QgsProcessingParameterTableField::setParentLayerParameter( const QString &parentLayerParameter ) void QgsProcessingParameterField::setParentLayerParameter( const QString &parentLayerParameter )
{ {
mParentLayerParameter = parentLayerParameter; mParentLayerParameter = parentLayerParameter;
} }
QgsProcessingParameterTableField::DataType QgsProcessingParameterTableField::dataType() const QgsProcessingParameterField::DataType QgsProcessingParameterField::dataType() const
{ {
return mDataType; return mDataType;
} }
void QgsProcessingParameterTableField::setDataType( const DataType &dataType ) void QgsProcessingParameterField::setDataType( const DataType &dataType )
{ {
mDataType = dataType; mDataType = dataType;
} }
bool QgsProcessingParameterTableField::allowMultiple() const bool QgsProcessingParameterField::allowMultiple() const
{ {
return mAllowMultiple; return mAllowMultiple;
} }
void QgsProcessingParameterTableField::setAllowMultiple( bool allowMultiple ) void QgsProcessingParameterField::setAllowMultiple( bool allowMultiple )
{ {
mAllowMultiple = allowMultiple; mAllowMultiple = allowMultiple;
} }
QVariantMap QgsProcessingParameterTableField::toVariantMap() const QVariantMap QgsProcessingParameterField::toVariantMap() const
{ {
QVariantMap map = QgsProcessingParameterDefinition::toVariantMap(); QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
map.insert( QStringLiteral( "parent_layer" ), mParentLayerParameter ); map.insert( QStringLiteral( "parent_layer" ), mParentLayerParameter );
@ -1844,7 +1886,7 @@ QVariantMap QgsProcessingParameterTableField::toVariantMap() const
return map; return map;
} }
bool QgsProcessingParameterTableField::fromVariantMap( const QVariantMap &map ) bool QgsProcessingParameterField::fromVariantMap( const QVariantMap &map )
{ {
QgsProcessingParameterDefinition::fromVariantMap( map ); QgsProcessingParameterDefinition::fromVariantMap( map );
mParentLayerParameter = map.value( QStringLiteral( "parent_layer" ) ).toString(); mParentLayerParameter = map.value( QStringLiteral( "parent_layer" ) ).toString();
@ -2208,3 +2250,100 @@ bool QgsProcessingParameterFolderOutput::checkValueIsAcceptable( const QVariant
return true; return true;
} }
QgsProcessingParameterVectorOutput::QgsProcessingParameterVectorOutput( const QString &name, const QString &description, QgsProcessingParameterDefinition::LayerType type, const QVariant &defaultValue, bool optional )
: QgsProcessingParameterDefinition( name, description, defaultValue, optional )
, mDataType( type )
{
}
bool QgsProcessingParameterVectorOutput::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
{
QVariant var = input;
if ( !var.isValid() )
return mFlags & FlagOptional;
if ( var.canConvert<QgsProcessingOutputLayerDefinition>() )
{
QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( var );
var = fromVar.sink;
}
if ( var.canConvert<QgsProperty>() )
{
return true;
}
if ( var.type() != QVariant::String )
return false;
if ( var.toString().isEmpty() )
return mFlags & FlagOptional;
return true;
}
QString QgsProcessingParameterVectorOutput::valueAsPythonString( const QVariant &value, QgsProcessingContext & ) const
{
if ( value.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
if ( value.canConvert<QgsProcessingOutputLayerDefinition>() )
{
QgsProcessingOutputLayerDefinition fromVar = qvariant_cast<QgsProcessingOutputLayerDefinition>( value );
if ( fromVar.sink.propertyType() == QgsProperty::StaticProperty )
{
return QStringLiteral( "QgsProcessingOutputLayerDefinition('%1')" ).arg( fromVar.sink.staticValue().toString() );
}
else
{
return QStringLiteral( "QgsProcessingOutputLayerDefinition(QgsProperty.fromExpression('%1'))" ).arg( fromVar.sink.asExpression() );
}
}
return value.toString().prepend( '\'' ).append( '\'' );
}
QgsProcessingParameterDefinition::LayerType QgsProcessingParameterVectorOutput::dataType() const
{
return mDataType;
}
bool QgsProcessingParameterVectorOutput::hasGeometry() const
{
switch ( mDataType )
{
case TypeAny:
case TypeVectorAny:
case TypeVectorPoint:
case TypeVectorLine:
case TypeVectorPolygon:
case TypeTable:
return true;
case TypeRaster:
case TypeFile:
return false;
}
return true;
}
void QgsProcessingParameterVectorOutput::setDataType( QgsProcessingParameterDefinition::LayerType type )
{
mDataType = type;
}
QVariantMap QgsProcessingParameterVectorOutput::toVariantMap() const
{
QVariantMap map = QgsProcessingParameterDefinition::toVariantMap();
map.insert( QStringLiteral( "data_type" ), mDataType );
return map;
}
bool QgsProcessingParameterVectorOutput::fromVariantMap( const QVariantMap &map )
{
QgsProcessingParameterDefinition::fromVariantMap( map );
mDataType = static_cast< QgsProcessingParameterDefinition::LayerType >( map.value( QStringLiteral( "data_type" ) ).toInt() );
return true;
}

View File

@ -198,14 +198,16 @@ class CORE_EXPORT QgsProcessingParameterDefinition
sipType = sipType_QgsProcessingParameterString; sipType = sipType_QgsProcessingParameterString;
else if ( sipCpp->type() == "expression" ) else if ( sipCpp->type() == "expression" )
sipType = sipType_QgsProcessingParameterExpression; sipType = sipType_QgsProcessingParameterExpression;
else if ( sipCpp->type() == "table" ) else if ( sipCpp->type() == "vector" )
sipType = sipType_QgsProcessingParameterTable; sipType = sipType_QgsProcessingParameterVectorLayer;
else if ( sipCpp->type() == "field" ) else if ( sipCpp->type() == "field" )
sipType = sipType_QgsProcessingParameterTableField; sipType = sipType_QgsProcessingParameterField;
else if ( sipCpp->type() == "source" ) else if ( sipCpp->type() == "source" )
sipType = sipType_QgsProcessingParameterFeatureSource; sipType = sipType_QgsProcessingParameterFeatureSource;
else if ( sipCpp->type() == "sink" ) else if ( sipCpp->type() == "sink" )
sipType = sipType_QgsProcessingParameterFeatureSink; sipType = sipType_QgsProcessingParameterFeatureSink;
else if ( sipCpp->type() == "vectorOut" )
sipType = sipType_QgsProcessingParameterVectorOutput;
else if ( sipCpp->type() == "rasterOut" ) else if ( sipCpp->type() == "rasterOut" )
sipType = sipType_QgsProcessingParameterRasterOutput; sipType = sipType_QgsProcessingParameterRasterOutput;
else if ( sipCpp->type() == "fileOut" ) else if ( sipCpp->type() == "fileOut" )
@ -1121,32 +1123,35 @@ class CORE_EXPORT QgsProcessingParameterExpression : public QgsProcessingParamet
}; };
/** /**
* \class QgsProcessingParameterTable * \class QgsProcessingParameterVectorLayer
* \ingroup core * \ingroup core
* A table (i.e. vector layers with or without geometry) parameter for processing algorithms. * A vector layer (with or without geometry) parameter for processing algorithms. Consider using
* the more versatile QgsProcessingParameterFeatureSource wherever possible.
* \since QGIS 3.0 * \since QGIS 3.0
*/ */
class CORE_EXPORT QgsProcessingParameterTable : public QgsProcessingParameterDefinition class CORE_EXPORT QgsProcessingParameterVectorLayer : public QgsProcessingParameterDefinition
{ {
public: public:
/** /**
* Constructor for QgsProcessingParameterTable. * Constructor for QgsProcessingParameterVectorLayer.
*/ */
QgsProcessingParameterTable( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(), QgsProcessingParameterVectorLayer( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(),
bool optional = false ); bool optional = false );
QString type() const override { return QStringLiteral( "table" ); } QString type() const override { return QStringLiteral( "vector" ); }
bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
}; };
/** /**
* \class QgsProcessingParameterTableField * \class QgsProcessingParameterField
* \ingroup core * \ingroup core
* A table field parameter for processing algorithms. * A vector layer or feature source field parameter for processing algorithms.
* \since QGIS 3.0 * \since QGIS 3.0
*/ */
class CORE_EXPORT QgsProcessingParameterTableField : public QgsProcessingParameterDefinition class CORE_EXPORT QgsProcessingParameterField : public QgsProcessingParameterDefinition
{ {
public: public:
@ -1160,9 +1165,9 @@ class CORE_EXPORT QgsProcessingParameterTableField : public QgsProcessingParamet
}; };
/** /**
* Constructor for QgsProcessingParameterTableField. * Constructor for QgsProcessingParameterField.
*/ */
QgsProcessingParameterTableField( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(), QgsProcessingParameterField( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(),
const QString &parentLayerParameterName = QString(), const QString &parentLayerParameterName = QString(),
DataType type = Any, DataType type = Any,
bool allowMultiple = false, bool allowMultiple = false,
@ -1311,6 +1316,55 @@ class CORE_EXPORT QgsProcessingParameterFeatureSink : public QgsProcessingParame
QgsProcessingParameterDefinition::LayerType mDataType = QgsProcessingParameterDefinition::TypeVectorAny; QgsProcessingParameterDefinition::LayerType mDataType = QgsProcessingParameterDefinition::TypeVectorAny;
}; };
/**
* \class QgsProcessingParameterVectorOutput
* \ingroup core
* A vector layer output parameter. Consider using the more flexible QgsProcessingParameterFeatureSink wherever
* possible.
* \since QGIS 3.0
*/
class CORE_EXPORT QgsProcessingParameterVectorOutput : public QgsProcessingParameterDefinition
{
public:
/**
* Constructor for QgsProcessingParameterVectorOutput.
*/
QgsProcessingParameterVectorOutput( const QString &name, const QString &description = QString(), QgsProcessingParameterDefinition::LayerType type = QgsProcessingParameterDefinition::TypeVectorAny, const QVariant &defaultValue = QVariant(),
bool optional = false );
QString type() const override { return QStringLiteral( "vectorOut" ); }
bool isDestination() const override { return true; }
bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
/**
* Returns the layer type for layers associated with the parameter.
* \see setDataType()
*/
QgsProcessingParameterDefinition::LayerType dataType() const;
/**
* Returns true if the layer is likely to include geometries. In cases were presence of geometry
* cannot be reliably determined in advance, this method will default to returning true.
*/
bool hasGeometry() const;
/**
* Sets the layer \a type for the layers associated with the parameter.
* \see dataType()
*/
void setDataType( QgsProcessingParameterDefinition::LayerType type );
QVariantMap toVariantMap() const override;
bool fromVariantMap( const QVariantMap &map ) override;
private:
QgsProcessingParameterDefinition::LayerType mDataType = QgsProcessingParameterDefinition::TypeVectorAny;
};
/** /**
* \class QgsProcessingParameterRasterOutput * \class QgsProcessingParameterRasterOutput
* \ingroup core * \ingroup core

View File

@ -314,8 +314,10 @@ class TestQgsProcessing: public QObject
void parameterString(); void parameterString();
void parameterExpression(); void parameterExpression();
void parameterField(); void parameterField();
void parameterVectorLayer();
void parameterFeatureSource(); void parameterFeatureSource();
void parameterFeatureSink(); void parameterFeatureSink();
void parameterVectorOut();
void parameterRasterOut(); void parameterRasterOut();
void parameterFileOut(); void parameterFileOut();
void parameterFolderOut(); void parameterFolderOut();
@ -2507,7 +2509,7 @@ void TestQgsProcessing::parameterField()
QgsProcessingContext context; QgsProcessingContext context;
// not optional! // not optional!
std::unique_ptr< QgsProcessingParameterTableField > def( new QgsProcessingParameterTableField( "non_optional", QString(), QString(), QString(), QgsProcessingParameterTableField::Any, false, false ) ); std::unique_ptr< QgsProcessingParameterField > def( new QgsProcessingParameterField( "non_optional", QString(), QString(), QString(), QgsProcessingParameterField::Any, false, false ) );
QVERIFY( def->checkValueIsAcceptable( 1 ) ); QVERIFY( def->checkValueIsAcceptable( 1 ) );
QVERIFY( def->checkValueIsAcceptable( "test" ) ); QVERIFY( def->checkValueIsAcceptable( "test" ) );
QVERIFY( !def->checkValueIsAcceptable( QStringList() << "a" << "b" ) ); QVERIFY( !def->checkValueIsAcceptable( QStringList() << "a" << "b" ) );
@ -2525,7 +2527,7 @@ void TestQgsProcessing::parameterField()
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) ); QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
// multiple // multiple
def.reset( new QgsProcessingParameterTableField( "non_optional", QString(), QString(), QString(), QgsProcessingParameterTableField::Any, true, false ) ); def.reset( new QgsProcessingParameterField( "non_optional", QString(), QString(), QString(), QgsProcessingParameterField::Any, true, false ) );
QVERIFY( def->checkValueIsAcceptable( 1 ) ); QVERIFY( def->checkValueIsAcceptable( 1 ) );
QVERIFY( def->checkValueIsAcceptable( "test" ) ); QVERIFY( def->checkValueIsAcceptable( "test" ) );
QVERIFY( def->checkValueIsAcceptable( QStringList() << "a" << "b" ) ); QVERIFY( def->checkValueIsAcceptable( QStringList() << "a" << "b" ) );
@ -2544,7 +2546,7 @@ void TestQgsProcessing::parameterField()
QCOMPARE( def->valueAsPythonString( QStringList() << "a" << "b", context ), QStringLiteral( "['a','b']" ) ); QCOMPARE( def->valueAsPythonString( QStringList() << "a" << "b", context ), QStringLiteral( "['a','b']" ) );
QVariantMap map = def->toVariantMap(); QVariantMap map = def->toVariantMap();
QgsProcessingParameterTableField fromMap( "x" ); QgsProcessingParameterField fromMap( "x" );
QVERIFY( fromMap.fromVariantMap( map ) ); QVERIFY( fromMap.fromVariantMap( map ) );
QCOMPARE( fromMap.name(), def->name() ); QCOMPARE( fromMap.name(), def->name() );
QCOMPARE( fromMap.description(), def->description() ); QCOMPARE( fromMap.description(), def->description() );
@ -2553,11 +2555,11 @@ void TestQgsProcessing::parameterField()
QCOMPARE( fromMap.parentLayerParameter(), def->parentLayerParameter() ); QCOMPARE( fromMap.parentLayerParameter(), def->parentLayerParameter() );
QCOMPARE( fromMap.dataType(), def->dataType() ); QCOMPARE( fromMap.dataType(), def->dataType() );
QCOMPARE( fromMap.allowMultiple(), def->allowMultiple() ); QCOMPARE( fromMap.allowMultiple(), def->allowMultiple() );
def.reset( dynamic_cast< QgsProcessingParameterTableField *>( QgsProcessingParameters::parameterFromVariantMap( map ) ) ); def.reset( dynamic_cast< QgsProcessingParameterField *>( QgsProcessingParameters::parameterFromVariantMap( map ) ) );
QVERIFY( dynamic_cast< QgsProcessingParameterTableField *>( def.get() ) ); QVERIFY( dynamic_cast< QgsProcessingParameterField *>( def.get() ) );
// optional // optional
def.reset( new QgsProcessingParameterTableField( "optional", QString(), QString( "def" ), QString(), QgsProcessingParameterTableField::Any, false, true ) ); def.reset( new QgsProcessingParameterField( "optional", QString(), QString( "def" ), QString(), QgsProcessingParameterField::Any, false, true ) );
QVERIFY( def->checkValueIsAcceptable( 1 ) ); QVERIFY( def->checkValueIsAcceptable( 1 ) );
QVERIFY( def->checkValueIsAcceptable( "test" ) ); QVERIFY( def->checkValueIsAcceptable( "test" ) );
QVERIFY( !def->checkValueIsAcceptable( QStringList() << "a" << "b" ) ); QVERIFY( !def->checkValueIsAcceptable( QStringList() << "a" << "b" ) );
@ -2570,13 +2572,13 @@ void TestQgsProcessing::parameterField()
QCOMPARE( fields, QStringList() << "def" ); QCOMPARE( fields, QStringList() << "def" );
// optional, no default // optional, no default
def.reset( new QgsProcessingParameterTableField( "optional", QString(), QVariant(), QString(), QgsProcessingParameterTableField::Any, false, true ) ); def.reset( new QgsProcessingParameterField( "optional", QString(), QVariant(), QString(), QgsProcessingParameterField::Any, false, true ) );
params.insert( "optional", QVariant() ); params.insert( "optional", QVariant() );
fields = QgsProcessingParameters::parameterAsFields( def.get(), params, context ); fields = QgsProcessingParameters::parameterAsFields( def.get(), params, context );
QVERIFY( fields.isEmpty() ); QVERIFY( fields.isEmpty() );
//optional with multiples //optional with multiples
def.reset( new QgsProcessingParameterTableField( "optional", QString(), QString( "abc;def" ), QString(), QgsProcessingParameterTableField::Any, true, true ) ); def.reset( new QgsProcessingParameterField( "optional", QString(), QString( "abc;def" ), QString(), QgsProcessingParameterField::Any, true, true ) );
QVERIFY( def->checkValueIsAcceptable( 1 ) ); QVERIFY( def->checkValueIsAcceptable( 1 ) );
QVERIFY( def->checkValueIsAcceptable( "test" ) ); QVERIFY( def->checkValueIsAcceptable( "test" ) );
QVERIFY( def->checkValueIsAcceptable( QStringList() << "a" << "b" ) ); QVERIFY( def->checkValueIsAcceptable( QStringList() << "a" << "b" ) );
@ -2587,12 +2589,102 @@ void TestQgsProcessing::parameterField()
params.insert( "optional", QVariant() ); params.insert( "optional", QVariant() );
fields = QgsProcessingParameters::parameterAsFields( def.get(), params, context ); fields = QgsProcessingParameters::parameterAsFields( def.get(), params, context );
QCOMPARE( fields, QStringList() << "abc" << "def" ); QCOMPARE( fields, QStringList() << "abc" << "def" );
def.reset( new QgsProcessingParameterTableField( "optional", QString(), QVariantList() << "abc" << "def", QString(), QgsProcessingParameterTableField::Any, true, true ) ); def.reset( new QgsProcessingParameterField( "optional", QString(), QVariantList() << "abc" << "def", QString(), QgsProcessingParameterField::Any, true, true ) );
params.insert( "optional", QVariant() ); params.insert( "optional", QVariant() );
fields = QgsProcessingParameters::parameterAsFields( def.get(), params, context ); fields = QgsProcessingParameters::parameterAsFields( def.get(), params, context );
QCOMPARE( fields, QStringList() << "abc" << "def" ); QCOMPARE( fields, QStringList() << "abc" << "def" );
} }
void TestQgsProcessing::parameterVectorLayer()
{
// setup a context
QgsProject p;
p.setCrs( QgsCoordinateReferenceSystem::fromEpsgId( 28353 ) );
QString testDataDir = QStringLiteral( TEST_DATA_DIR ) + '/'; //defined in CmakeLists.txt
QString vector1 = testDataDir + "multipoint.shp";
QString raster = testDataDir + "landsat.tif";
QFileInfo fi1( raster );
QFileInfo fi2( vector1 );
QgsRasterLayer *r1 = new QgsRasterLayer( fi1.filePath(), "R1" );
QgsVectorLayer *v1 = new QgsVectorLayer( fi2.filePath(), "V4", "ogr" );
p.addMapLayers( QList<QgsMapLayer *>() << v1 << r1 );
QgsProcessingContext context;
context.setProject( &p );
// not optional!
std::unique_ptr< QgsProcessingParameterVectorLayer > def( new QgsProcessingParameterVectorLayer( "non_optional", QString(), QString( "somelayer" ), false ) );
QVERIFY( !def->checkValueIsAcceptable( false ) );
QVERIFY( !def->checkValueIsAcceptable( true ) );
QVERIFY( !def->checkValueIsAcceptable( 5 ) );
QVERIFY( def->checkValueIsAcceptable( "layer12312312" ) );
QVERIFY( !def->checkValueIsAcceptable( "" ) );
QVERIFY( !def->checkValueIsAcceptable( QVariant() ) );
QVERIFY( !def->checkValueIsAcceptable( QgsProcessingFeatureSourceDefinition( "layer1231123" ) ) );
QVERIFY( def->checkValueIsAcceptable( QVariant::fromValue( v1 ) ) );
QVERIFY( !def->checkValueIsAcceptable( QVariant::fromValue( r1 ) ) );
// should be OK
QVERIFY( def->checkValueIsAcceptable( "c:/Users/admin/Desktop/roads_clipped_transformed_v1_reprojected_final_clipped_aAAA.shp" ) );
// ... unless we use context, when the check that the layer actually exists is performed
QVERIFY( !def->checkValueIsAcceptable( "c:/Users/admin/Desktop/roads_clipped_transformed_v1_reprojected_final_clipped_aAAA.shp", &context ) );
// using existing map layer ID
QVariantMap params;
params.insert( "non_optional", v1->id() );
QCOMPARE( QgsProcessingParameters::parameterAsVectorLayer( def.get(), params, context )->id(), v1->id() );
// using existing layer
params.insert( "non_optional", QVariant::fromValue( v1 ) );
QCOMPARE( QgsProcessingParameters::parameterAsVectorLayer( def.get(), params, context )->id(), v1->id() );
// not vector layer
params.insert( "non_optional", r1->id() );
QVERIFY( !QgsProcessingParameters::parameterAsVectorLayer( def.get(), params, context ) );
// using existing non-vector layer
params.insert( "non_optional", QVariant::fromValue( r1 ) );
QVERIFY( !QgsProcessingParameters::parameterAsVectorLayer( def.get(), params, context ) );
// string representing a layer source
params.insert( "non_optional", vector1 );
QCOMPARE( QgsProcessingParameters::parameterAsVectorLayer( def.get(), params, context )->publicSource(), vector1 );
// nonsense string
params.insert( "non_optional", QString( "i'm not a layer, and nothing you can do will make me one" ) );
QVERIFY( !QgsProcessingParameters::parameterAsVectorLayer( def.get(), params, context ) );
QCOMPARE( def->valueAsPythonString( vector1, context ), QString( "'" ) + testDataDir + QStringLiteral( "multipoint.shp'" ) );
QCOMPARE( def->valueAsPythonString( v1->id(), context ), QString( "'" ) + testDataDir + QStringLiteral( "multipoint.shp'" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( v1 ), context ), QString( "'" ) + testDataDir + QStringLiteral( "multipoint.shp'" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
QVariantMap map = def->toVariantMap();
QgsProcessingParameterVectorLayer fromMap( "x" );
QVERIFY( fromMap.fromVariantMap( map ) );
QCOMPARE( fromMap.name(), def->name() );
QCOMPARE( fromMap.description(), def->description() );
QCOMPARE( fromMap.flags(), def->flags() );
QCOMPARE( fromMap.defaultValue(), def->defaultValue() );
def.reset( dynamic_cast< QgsProcessingParameterVectorLayer *>( QgsProcessingParameters::parameterFromVariantMap( map ) ) );
QVERIFY( dynamic_cast< QgsProcessingParameterVectorLayer *>( def.get() ) );
// optional
def.reset( new QgsProcessingParameterVectorLayer( "optional", QString(), v1->id(), true ) );
params.insert( "optional", QVariant() );
QCOMPARE( QgsProcessingParameters::parameterAsVectorLayer( def.get(), params, context )->id(), v1->id() );
QVERIFY( def->checkValueIsAcceptable( false ) );
QVERIFY( def->checkValueIsAcceptable( true ) );
QVERIFY( def->checkValueIsAcceptable( 5 ) );
QVERIFY( def->checkValueIsAcceptable( "layer12312312" ) );
QVERIFY( def->checkValueIsAcceptable( "c:/Users/admin/Desktop/roads_clipped_transformed_v1_reprojected_final_clipped_aAAA.shp" ) );
QVERIFY( def->checkValueIsAcceptable( "" ) );
QVERIFY( def->checkValueIsAcceptable( QVariant() ) );
QVERIFY( def->checkValueIsAcceptable( QgsProcessingFeatureSourceDefinition( "layer1231123" ) ) );
//optional with direct layer default
def.reset( new QgsProcessingParameterVectorLayer( "optional", QString(), QVariant::fromValue( v1 ), true ) );
QCOMPARE( QgsProcessingParameters::parameterAsVectorLayer( def.get(), params, context )->id(), v1->id() );
}
void TestQgsProcessing::parameterFeatureSource() void TestQgsProcessing::parameterFeatureSource()
{ {
// setup a context // setup a context
@ -2747,6 +2839,68 @@ void TestQgsProcessing::parameterFeatureSink()
} }
void TestQgsProcessing::parameterVectorOut()
{
// setup a context
QgsProject p;
p.setCrs( QgsCoordinateReferenceSystem::fromEpsgId( 28353 ) );
QgsProcessingContext context;
context.setProject( &p );
// not optional!
std::unique_ptr< QgsProcessingParameterVectorOutput > def( new QgsProcessingParameterVectorOutput( "non_optional", QString(), QgsProcessingParameterDefinition::TypeVectorAny, QString( "EPSG:3113" ), false ) );
QVERIFY( !def->checkValueIsAcceptable( false ) );
QVERIFY( !def->checkValueIsAcceptable( true ) );
QVERIFY( !def->checkValueIsAcceptable( 5 ) );
QVERIFY( def->checkValueIsAcceptable( "layer12312312" ) );
QVERIFY( !def->checkValueIsAcceptable( "" ) );
QVERIFY( !def->checkValueIsAcceptable( QVariant() ) );
QVERIFY( def->checkValueIsAcceptable( QgsProcessingOutputLayerDefinition( "layer1231123" ) ) );
// should be OK with or without context - it's an output layer!
QVERIFY( def->checkValueIsAcceptable( "c:/Users/admin/Desktop/roads_clipped_transformed_v1_reprojected_final_clipped_aAAA.shp" ) );
QVERIFY( def->checkValueIsAcceptable( "c:/Users/admin/Desktop/roads_clipped_transformed_v1_reprojected_final_clipped_aAAA.shp", &context ) );
QCOMPARE( def->valueAsPythonString( QStringLiteral( "abc" ), context ), QStringLiteral( "'abc'" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProcessingOutputLayerDefinition( "abc" ) ), context ), QStringLiteral( "QgsProcessingOutputLayerDefinition('abc')" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProcessingOutputLayerDefinition( QgsProperty::fromValue( "abc" ) ) ), context ), QStringLiteral( "QgsProcessingOutputLayerDefinition('abc')" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProcessingOutputLayerDefinition( QgsProperty::fromExpression( "\"abc\" || \"def\"" ) ) ), context ), QStringLiteral( "QgsProcessingOutputLayerDefinition(QgsProperty.fromExpression('\"abc\" || \"def\"'))" ) );
QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) );
QVariantMap map = def->toVariantMap();
QgsProcessingParameterVectorOutput fromMap( "x" );
QVERIFY( fromMap.fromVariantMap( map ) );
QCOMPARE( fromMap.name(), def->name() );
QCOMPARE( fromMap.description(), def->description() );
QCOMPARE( fromMap.flags(), def->flags() );
QCOMPARE( fromMap.defaultValue(), def->defaultValue() );
QCOMPARE( fromMap.dataType(), def->dataType() );
def.reset( dynamic_cast< QgsProcessingParameterVectorOutput *>( QgsProcessingParameters::parameterFromVariantMap( map ) ) );
QVERIFY( dynamic_cast< QgsProcessingParameterVectorOutput *>( def.get() ) );
// optional
def.reset( new QgsProcessingParameterVectorOutput( "optional", QString(), QgsProcessingParameterDefinition::TypeVectorAny, QString(), true ) );
QVERIFY( !def->checkValueIsAcceptable( false ) );
QVERIFY( !def->checkValueIsAcceptable( true ) );
QVERIFY( !def->checkValueIsAcceptable( 5 ) );
QVERIFY( def->checkValueIsAcceptable( "layer12312312" ) );
QVERIFY( def->checkValueIsAcceptable( "c:/Users/admin/Desktop/roads_clipped_transformed_v1_reprojected_final_clipped_aAAA.shp" ) );
QVERIFY( def->checkValueIsAcceptable( "" ) );
QVERIFY( def->checkValueIsAcceptable( QVariant() ) );
QVERIFY( def->checkValueIsAcceptable( QgsProcessingOutputLayerDefinition( "layer1231123" ) ) );
// test hasGeometry
QVERIFY( QgsProcessingParameterVectorOutput( "test", QString(), QgsProcessingParameterDefinition::TypeAny ).hasGeometry() );
QVERIFY( QgsProcessingParameterVectorOutput( "test", QString(), QgsProcessingParameterDefinition::TypeVectorAny ).hasGeometry() );
QVERIFY( QgsProcessingParameterVectorOutput( "test", QString(), QgsProcessingParameterDefinition::TypeVectorPoint ).hasGeometry() );
QVERIFY( QgsProcessingParameterVectorOutput( "test", QString(), QgsProcessingParameterDefinition::TypeVectorLine ).hasGeometry() );
QVERIFY( QgsProcessingParameterVectorOutput( "test", QString(), QgsProcessingParameterDefinition::TypeVectorPolygon ).hasGeometry() );
QVERIFY( !QgsProcessingParameterVectorOutput( "test", QString(), QgsProcessingParameterDefinition::TypeRaster ).hasGeometry() );
QVERIFY( !QgsProcessingParameterVectorOutput( "test", QString(), QgsProcessingParameterDefinition::TypeFile ).hasGeometry() );
QVERIFY( QgsProcessingParameterVectorOutput( "test", QString(), QgsProcessingParameterDefinition::TypeTable ).hasGeometry() );
}
void TestQgsProcessing::parameterRasterOut() void TestQgsProcessing::parameterRasterOut()
{ {
// setup a context // setup a context