mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Create specific expression context scope for child algorithms
Contains variables for model parameters, algorithm results for other child algorithms which are not dependent on the algorithm. Allows removal of final pieces of ModelerAlgorithm code
This commit is contained in:
parent
d8086e549d
commit
82ef7d2a89
@ -877,6 +877,13 @@ Copies are protected to avoid slicing
|
||||
:rtype: list of QgsProcessingModelAlgorithm.ChildParameterSource
|
||||
%End
|
||||
|
||||
QgsExpressionContextScope *createExpressionContextScopeForChildAlgorithm( const QString &childId, QgsProcessingContext &context, const QVariantMap &modelParameters = QVariantMap(),
|
||||
const QVariantMap &results = QVariantMap() ) const /Factory/;
|
||||
%Docstring
|
||||
Creates a new expression context scope for a child algorithm within the model.
|
||||
:rtype: QgsExpressionContextScope
|
||||
%End
|
||||
|
||||
protected:
|
||||
|
||||
virtual QVariantMap processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback );
|
||||
|
@ -343,27 +343,6 @@ class ParameterNumber(Parameter):
|
||||
variables['@%s_max' % name] = stats.maximumValue
|
||||
return variables
|
||||
|
||||
def evaluateForModeler(self, value, model):
|
||||
if isinstance(value, numbers.Number):
|
||||
return value
|
||||
variables = {}
|
||||
for param in model.parameters:
|
||||
if isinstance(param, ParameterNumber):
|
||||
variables["@" + param.name()] = param.value
|
||||
if isinstance(param, (ParameterRaster, ParameterVector)):
|
||||
variables.update(self._layerVariables(param))
|
||||
|
||||
for alg in list(model.algs.values()):
|
||||
for out in alg.algorithm.outputs:
|
||||
if isinstance(out, OutputNumber):
|
||||
variables["@%s_%s" % (alg.name(), out.name)] = out.value
|
||||
if isinstance(out, (OutputRaster, OutputVector)):
|
||||
variables.update(self._layerVariables(out, alg))
|
||||
for k, v in list(variables.items()):
|
||||
value = value.replace(k, str(v))
|
||||
|
||||
return value
|
||||
|
||||
|
||||
class ParameterRange(Parameter):
|
||||
|
||||
|
@ -34,8 +34,8 @@ from qgis.PyQt.QtWidgets import QDialog, QTreeWidgetItem
|
||||
|
||||
from qgis.core import (QgsMessageLog,
|
||||
QgsProcessingUtils,
|
||||
QgsProcessingParameterDefinition)
|
||||
from processing.modeler.ModelerAlgorithm import ModelerAlgorithm
|
||||
QgsProcessingParameterDefinition,
|
||||
QgsProcessingModelAlgorithm)
|
||||
|
||||
pluginPath = os.path.split(os.path.dirname(__file__))[0]
|
||||
WIDGET, BASE = uic.loadUiType(
|
||||
@ -55,7 +55,7 @@ class HelpEditionDialog(BASE, WIDGET):
|
||||
|
||||
self.alg = alg
|
||||
self.descriptions = {}
|
||||
if isinstance(self.alg, ModelerAlgorithm):
|
||||
if isinstance(self.alg, QgsProcessingModelAlgorithm):
|
||||
self.descriptions = self.alg.helpContent()
|
||||
else:
|
||||
if self.alg.descriptionFile is not None:
|
||||
|
@ -36,14 +36,9 @@ from qgis.PyQt.QtWidgets import QDialog
|
||||
from qgis.core import (QgsExpression,
|
||||
QgsProcessingParameterNumber,
|
||||
QgsProcessingOutputNumber,
|
||||
QgsProcessingOutputVectorLayer,
|
||||
QgsProcessingOutputRasterLayer,
|
||||
QgsProcessingParameterFeatureSource,
|
||||
QgsProcessingModelAlgorithm,
|
||||
QgsProcessingParameterRasterLayer)
|
||||
QgsProcessingModelAlgorithm)
|
||||
from qgis.gui import QgsExpressionBuilderDialog
|
||||
from processing.modeler.ModelerAlgorithm import ValueFromInput, ValueFromOutput, CompoundValue
|
||||
from processing.tools.dataobjects import createExpressionContext
|
||||
from processing.tools.dataobjects import createExpressionContext, createContext
|
||||
|
||||
pluginPath = os.path.split(os.path.dirname(__file__))[0]
|
||||
NUMBER_WIDGET, NUMBER_BASE = uic.loadUiType(
|
||||
@ -77,47 +72,14 @@ class ModellerNumberInputPanel(BASE, WIDGET):
|
||||
|
||||
def showExpressionsBuilder(self):
|
||||
context = createExpressionContext()
|
||||
dlg = QgsExpressionBuilderDialog(None, str(self.leText.text()), self, 'generic', context)
|
||||
processing_context = createContext()
|
||||
scope = self.modelParametersDialog.model.createExpressionContextScopeForChildAlgorithm(self.modelParametersDialog.childId, processing_context)
|
||||
context.appendScope(scope)
|
||||
|
||||
context.popScope()
|
||||
values = self.modelParametersDialog.getAvailableValuesOfType(QgsProcessingParameterNumber, QgsProcessingOutputNumber)
|
||||
variables = {}
|
||||
for value in values:
|
||||
if isinstance(value, QgsProcessingModelAlgorithm.ChildParameterSource):
|
||||
if value.source() == QgsProcessingModelAlgorithm.ChildParameterSource.ModelParameter:
|
||||
name = value.parameterName()
|
||||
element = self.modelParametersDialog.model.parameterDefinition(name)
|
||||
desc = element.description()
|
||||
elif value.source() == QgsProcessingModelAlgorithm.ChildParameterSource.ChildOutput:
|
||||
name = "%s_%s" % (value.outputChildId(), value.outputName())
|
||||
alg = self.modelParametersDialog.model.childAlgorithm(value.outputChildId())
|
||||
out = alg.algorithm().outputDefinition(value.outputName())
|
||||
desc = self.tr("Output '{0}' from algorithm '{1}'").format(out.description(), alg.description())
|
||||
variables[name] = desc
|
||||
values = self.modelParametersDialog.getAvailableValuesOfType([QgsProcessingParameterFeatureSource, QgsProcessingParameterRasterLayer],
|
||||
[QgsProcessingOutputVectorLayer, QgsProcessingOutputRasterLayer])
|
||||
for value in values:
|
||||
if isinstance(value, QgsProcessingModelAlgorithm.ChildParameterSource):
|
||||
if value.source() == QgsProcessingModelAlgorithm.ChildParameterSource.ModelParameter:
|
||||
name = value.parameterName()
|
||||
element = self.modelParametersDialog.model.parameterDefinition(name)
|
||||
desc = element.description()
|
||||
elif value.source() == QgsProcessingModelAlgorithm.ChildParameterSource.ChildOutput:
|
||||
name = "%s_%s" % (value.outputChildId(), value.outputName())
|
||||
alg = self.modelParametersDialog.model.childAlgorithm(value.outputChildId())
|
||||
out = alg.algorithm().outputDefinition(value.outputName())
|
||||
desc = self.tr("Output '{0}' from algorithm '{1}'").format(out.description(), alg.description())
|
||||
variables['%s_minx' % name] = self.tr("Minimum X of {0}").format(desc)
|
||||
variables['%s_miny' % name] = self.tr("Minimum Y of {0}").format(desc)
|
||||
variables['%s_maxx' % name] = self.tr("Maximum X of {0}").format(desc)
|
||||
variables['%s_maxy' % name] = self.tr("Maximum Y of {0}").format(desc)
|
||||
if isinstance(element, (QgsProcessingParameterRasterLayer, QgsProcessingOutputRasterLayer)):
|
||||
variables['%s_min' % name] = self.tr("Minimum value of {0}").format(desc)
|
||||
variables['%s_max' % name] = self.tr("Maximum value of {0}").format(desc)
|
||||
variables['%s_avg' % name] = self.tr("Mean value of {0}").format(desc)
|
||||
variables['%s_stddev' % name] = self.tr("Standard deviation of {0}").format(desc)
|
||||
for variable, desc in variables.items():
|
||||
dlg.expressionBuilder().registerItem("Modeler", variable, "@" + variable, desc, highlightedItem=True)
|
||||
highlighted = scope.variableNames()
|
||||
context.setHighlightedVariables(highlighted)
|
||||
|
||||
dlg = QgsExpressionBuilderDialog(None, str(self.leText.text()), self, 'generic', context)
|
||||
|
||||
dlg.setWindowTitle(self.tr('Expression based input'))
|
||||
if dlg.exec_() == QDialog.Accepted:
|
||||
|
@ -30,10 +30,9 @@ import shutil
|
||||
from qgis.PyQt.QtWidgets import QFileDialog, QMessageBox
|
||||
from qgis.PyQt.QtCore import QFileInfo
|
||||
|
||||
from qgis.core import QgsApplication, QgsSettings
|
||||
from qgis.core import QgsApplication, QgsSettings, QgsProcessingModelAlgorithm
|
||||
|
||||
from processing.gui.ToolboxAction import ToolboxAction
|
||||
from processing.modeler.ModelerAlgorithm import ModelerAlgorithm
|
||||
from processing.modeler.WrongModelException import WrongModelException
|
||||
from processing.modeler.ModelerUtils import ModelerUtils
|
||||
|
||||
@ -59,7 +58,7 @@ class AddModelFromFileAction(ToolboxAction):
|
||||
settings.setValue('Processing/lastModelsDir',
|
||||
QFileInfo(filename).absoluteDir().absolutePath())
|
||||
|
||||
alg = ModelerAlgorithm()
|
||||
alg = QgsProcessingModelAlgorithm()
|
||||
if not alg.fromFile(filename):
|
||||
QMessageBox.warning(
|
||||
self.toolbox,
|
||||
|
@ -26,10 +26,9 @@ __copyright__ = '(C) 2012, Victor Olaya'
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
import os
|
||||
from qgis.core import QgsApplication
|
||||
from qgis.core import QgsApplication, QgsProcessingModelAlgorithm
|
||||
from qgis.PyQt.QtWidgets import QMessageBox
|
||||
from processing.gui.ContextAction import ContextAction
|
||||
from processing.modeler.ModelerAlgorithm import ModelerAlgorithm
|
||||
|
||||
|
||||
class DeleteModelAction(ContextAction):
|
||||
@ -38,7 +37,7 @@ class DeleteModelAction(ContextAction):
|
||||
self.name = self.tr('Delete model', 'DeleteModelAction')
|
||||
|
||||
def isEnabled(self):
|
||||
return isinstance(self.itemData, ModelerAlgorithm)
|
||||
return isinstance(self.itemData, QgsProcessingModelAlgorithm)
|
||||
|
||||
def execute(self):
|
||||
reply = QMessageBox.question(
|
||||
|
@ -25,9 +25,8 @@ __copyright__ = '(C) 2012, Victor Olaya'
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
from qgis.core import QgsApplication
|
||||
from qgis.core import QgsApplication, QgsProcessingModelAlgorithm
|
||||
from processing.gui.ContextAction import ContextAction
|
||||
from processing.modeler.ModelerAlgorithm import ModelerAlgorithm
|
||||
from processing.modeler.ModelerDialog import ModelerDialog
|
||||
|
||||
|
||||
@ -37,7 +36,7 @@ class EditModelAction(ContextAction):
|
||||
self.name = self.tr('Edit model', 'EditModelAction')
|
||||
|
||||
def isEnabled(self):
|
||||
return isinstance(self.itemData, ModelerAlgorithm)
|
||||
return isinstance(self.itemData, QgsProcessingModelAlgorithm)
|
||||
|
||||
def execute(self):
|
||||
alg = self.itemData
|
||||
|
@ -1,178 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
ModelerAlgorithm.py
|
||||
---------------------
|
||||
Date : August 2012
|
||||
Copyright : (C) 2012 by Victor Olaya
|
||||
Email : volayaf at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
from builtins import str
|
||||
from builtins import object
|
||||
|
||||
__author__ = 'Victor Olaya'
|
||||
__date__ = 'August 2012'
|
||||
__copyright__ = '(C) 2012, Victor Olaya'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
import os.path
|
||||
import sys
|
||||
import copy
|
||||
import time
|
||||
import json
|
||||
from qgis.PyQt.QtCore import QPointF
|
||||
from operator import attrgetter
|
||||
|
||||
from qgis.core import (QgsApplication,
|
||||
QgsProcessingAlgorithm,
|
||||
QgsProcessingParameterDefinition,
|
||||
QgsProcessingParameterBoolean,
|
||||
QgsProcessingParameterCrs,
|
||||
QgsProcessingParameterMapLayer,
|
||||
QgsProcessingParameterExtent,
|
||||
QgsProcessingParameterPoint,
|
||||
QgsProcessingParameterFile,
|
||||
QgsProcessingParameterMatrix,
|
||||
QgsProcessingParameterMultipleLayers,
|
||||
QgsProcessingParameterNumber,
|
||||
QgsProcessingParameterRange,
|
||||
QgsProcessingParameterRasterLayer,
|
||||
QgsProcessingParameterEnum,
|
||||
QgsProcessingParameterString,
|
||||
QgsProcessingParameterExpression,
|
||||
QgsProcessingParameterVectorLayer,
|
||||
QgsProcessingParameterField,
|
||||
QgsProcessingParameterFeatureSource,
|
||||
QgsProcessingModelAlgorithm)
|
||||
from qgis.gui import QgsMessageBar
|
||||
from qgis.utils import iface
|
||||
from processing.modeler.WrongModelException import WrongModelException
|
||||
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
|
||||
|
||||
from processing.gui.Help2Html import getHtmlFromDescriptionsDict
|
||||
|
||||
pluginPath = os.path.split(os.path.dirname(__file__))[0]
|
||||
|
||||
|
||||
class ValueFromInput(object):
|
||||
|
||||
def __init__(self, name=""):
|
||||
self.name = name
|
||||
|
||||
def todict(self):
|
||||
return self.__dict__
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def __eq__(self, other):
|
||||
try:
|
||||
return self.name == other.name
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
class ValueFromOutput(object):
|
||||
|
||||
def __init__(self, alg="", output=""):
|
||||
self.alg = alg
|
||||
self.output = output
|
||||
|
||||
def todict(self):
|
||||
return self.__dict__
|
||||
|
||||
def __eq__(self, other):
|
||||
try:
|
||||
return self.alg == other.alg and self.output == other.output
|
||||
except:
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
return self.alg + ":" + self.output
|
||||
|
||||
|
||||
class CompoundValue(object):
|
||||
|
||||
def __init__(self, values=[], definition=""):
|
||||
self.values = values
|
||||
self.definition = definition
|
||||
|
||||
def todict(self):
|
||||
return self.__dict__
|
||||
|
||||
def __eq__(self, other):
|
||||
try:
|
||||
return self.values == other.values and self.definition == other.definition
|
||||
except:
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
return self.definition
|
||||
|
||||
def asPythonParameter(self):
|
||||
return "" # TODO
|
||||
|
||||
|
||||
class ModelerAlgorithm(QgsProcessingModelAlgorithm):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
# Geoalgorithms in this model. A dict of Algorithm objects, with names as keys
|
||||
self.algs = {}
|
||||
|
||||
def prepareAlgorithm(self, alg):
|
||||
algInstance = alg.algorithm()
|
||||
for param in algInstance.parameterDefinitions():
|
||||
if not param.flags() & QgsProcessingParameterDefinition.FlagHidden:
|
||||
if param.name() in alg.params:
|
||||
value = self.resolveValue(alg.params[param.name()], param)
|
||||
else:
|
||||
if iface is not None:
|
||||
iface.messageBar().pushMessage(self.tr("Warning"),
|
||||
self.tr("Parameter {0} in algorithm {1} in the model is run with default value! Edit the model to make sure that this is correct.").format(param.name(), alg.displayName()),
|
||||
QgsMessageBar.WARNING, 4)
|
||||
value = param.defaultValue()
|
||||
|
||||
# note to self - these are parameters, not outputs
|
||||
for out in algInstance.outputDefinitions():
|
||||
if not out.flags() & QgsProcessingParameterDefinition.FlagHidden:
|
||||
if out.name() in alg.outputs:
|
||||
name = self.getSafeNameForOutput(alg.childId(), out.name())
|
||||
modelOut = self.getOutputFromName(name)
|
||||
if modelOut:
|
||||
out.value = modelOut.value
|
||||
else:
|
||||
out.value = None
|
||||
|
||||
return algInstance
|
||||
|
||||
def getSafeNameForOutput(self, algName, outName):
|
||||
return outName + '_ALG' + algName
|
||||
|
||||
def resolveValue(self, value, param):
|
||||
if value is None:
|
||||
v = None
|
||||
if isinstance(value, list):
|
||||
v = ";".join([self.resolveValue(v, param) for v in value])
|
||||
elif isinstance(value, CompoundValue):
|
||||
v = self.resolveValue(value.definition, param)
|
||||
elif isinstance(value, ValueFromInput):
|
||||
v = self.getParameterFromName(value.name).value
|
||||
elif isinstance(value, ValueFromOutput):
|
||||
v = self.algs[value.alg].algorithm().outputDefinition(value.output).value
|
||||
else:
|
||||
v = value
|
||||
return param.evaluateForModeler(v, self)
|
@ -32,12 +32,12 @@ from qgis.PyQt.QtXml import QDomDocument
|
||||
from qgis.core import (QgsApplication,
|
||||
QgsProcessingProvider,
|
||||
QgsMessageLog,
|
||||
QgsProcessingModelAlgorithm,
|
||||
QgsProcessingUtils,
|
||||
QgsXmlUtils)
|
||||
|
||||
from processing.core.ProcessingConfig import ProcessingConfig, Setting
|
||||
from processing.modeler.ModelerUtils import ModelerUtils
|
||||
from processing.modeler.ModelerAlgorithm import ModelerAlgorithm
|
||||
from processing.modeler.WrongModelException import WrongModelException
|
||||
from processing.modeler.EditModelAction import EditModelAction
|
||||
from processing.modeler.CreateNewModelAction import CreateNewModelAction
|
||||
@ -109,7 +109,7 @@ class ModelerAlgorithmProvider(QgsProcessingProvider):
|
||||
try:
|
||||
fullpath = os.path.join(path, descriptionFile)
|
||||
|
||||
alg = ModelerAlgorithm()
|
||||
alg = QgsProcessingModelAlgorithm()
|
||||
if alg.fromFile(fullpath):
|
||||
if alg.name():
|
||||
alg.setSourceFilePath(fullpath)
|
||||
|
@ -48,7 +48,6 @@ from qgis.gui import QgsMessageBar
|
||||
from processing.gui.HelpEditionDialog import HelpEditionDialog
|
||||
from processing.gui.AlgorithmDialog import AlgorithmDialog
|
||||
from processing.modeler.ModelerParameterDefinitionDialog import ModelerParameterDefinitionDialog
|
||||
from processing.modeler.ModelerAlgorithm import ModelerAlgorithm
|
||||
from processing.modeler.ModelerParametersDialog import ModelerParametersDialog
|
||||
from processing.modeler.ModelerUtils import ModelerUtils
|
||||
from processing.modeler.ModelerScene import ModelerScene
|
||||
@ -244,7 +243,7 @@ class ModelerDialog(BASE, WIDGET):
|
||||
self.repaintModel()
|
||||
|
||||
else:
|
||||
self.model = ModelerAlgorithm()
|
||||
self.model = QgsProcessingModelAlgorithm()
|
||||
self.model.setProvider(QgsApplication.processingRegistry().providerById('model'))
|
||||
|
||||
self.fillInputsTree()
|
||||
@ -475,7 +474,7 @@ class ModelerDialog(BASE, WIDGET):
|
||||
ModelerUtils.modelsFolders()[0],
|
||||
self.tr('Processing models (*.model3 *.MODEL3)'))
|
||||
if filename:
|
||||
alg = ModelerAlgorithm()
|
||||
alg = QgsProcessingModelAlgorithm()
|
||||
if alg.fromFile(filename):
|
||||
self.model = alg
|
||||
self.model.setProvider(QgsApplication.processingRegistry().providerById('model'))
|
||||
|
@ -32,7 +32,6 @@ from qgis.core import (QgsProcessingParameterDefinition,
|
||||
QgsProcessingModelAlgorithm)
|
||||
from processing.modeler.ModelerGraphicItem import ModelerGraphicItem
|
||||
from processing.modeler.ModelerArrowItem import ModelerArrowItem
|
||||
from processing.modeler.ModelerAlgorithm import CompoundValue
|
||||
|
||||
|
||||
class ModelerScene(QGraphicsScene):
|
||||
@ -78,9 +77,6 @@ class ModelerScene(QGraphicsScene):
|
||||
break
|
||||
if value.outputChildId() in self.algItems:
|
||||
items.append((self.algItems[value.outputChildId()], i))
|
||||
elif isinstance(value, CompoundValue):
|
||||
for v in value.values:
|
||||
items.extend(self.getItemsFromParamValue(v))
|
||||
return items
|
||||
|
||||
def paintModel(self, model, controls=True):
|
||||
|
@ -351,7 +351,7 @@ QString QgsProcessingModelAlgorithm::helpUrl() const
|
||||
return QgsProcessingUtils::formatHelpMapAsHtml( mHelpContent, this );
|
||||
}
|
||||
|
||||
QVariantMap QgsProcessingModelAlgorithm::parametersForChildAlgorithm( const ChildAlgorithm &child, const QVariantMap &modelParameters, const QMap< QString, QVariantMap > &results, const QgsExpressionContext &expressionContext ) const
|
||||
QVariantMap QgsProcessingModelAlgorithm::parametersForChildAlgorithm( const ChildAlgorithm &child, const QVariantMap &modelParameters, const QVariantMap &results, const QgsExpressionContext &expressionContext ) const
|
||||
{
|
||||
QVariantMap childParams;
|
||||
Q_FOREACH ( const QgsProcessingParameterDefinition *def, child.algorithm()->parameterDefinitions() )
|
||||
@ -381,7 +381,7 @@ QVariantMap QgsProcessingModelAlgorithm::parametersForChildAlgorithm( const Chil
|
||||
|
||||
case ChildParameterSource::ChildOutput:
|
||||
{
|
||||
QVariantMap linkedChildResults = results.value( source.outputChildId() );
|
||||
QVariantMap linkedChildResults = results.value( source.outputChildId() ).toMap();
|
||||
paramParts << linkedChildResults.value( source.outputName() );
|
||||
break;
|
||||
}
|
||||
@ -494,7 +494,7 @@ QVariantMap QgsProcessingModelAlgorithm::processAlgorithm( const QVariantMap &pa
|
||||
|
||||
QgsExpressionContext baseContext = createExpressionContext( parameters, context );
|
||||
|
||||
QMap< QString, QVariantMap > childResults;
|
||||
QVariantMap childResults;
|
||||
QVariantMap finalResults;
|
||||
QSet< QString > executed;
|
||||
bool executedAlg = true;
|
||||
@ -525,7 +525,8 @@ QVariantMap QgsProcessingModelAlgorithm::processAlgorithm( const QVariantMap &pa
|
||||
const ChildAlgorithm &child = mChildAlgorithms[ childId ];
|
||||
|
||||
QgsExpressionContext expContext = baseContext;
|
||||
expContext << QgsExpressionContextUtils::processingAlgorithmScope( child.algorithm(), parameters, context );
|
||||
expContext << QgsExpressionContextUtils::processingAlgorithmScope( child.algorithm(), parameters, context )
|
||||
<< createExpressionContextScopeForChildAlgorithm( childId, context, parameters, childResults );
|
||||
|
||||
QVariantMap childParams = parametersForChildAlgorithm( child, parameters, childResults, expContext );
|
||||
feedback->setProgressText( QObject::tr( "Running %1 [%2/%3]" ).arg( child.description() ).arg( executed.count() + 1 ).arg( toExecute.count() ) );
|
||||
@ -662,6 +663,147 @@ QString QgsProcessingModelAlgorithm::asPythonCode() const
|
||||
return lines.join( '\n' );
|
||||
}
|
||||
|
||||
QgsExpressionContextScope *QgsProcessingModelAlgorithm::createExpressionContextScopeForChildAlgorithm( const QString &childId, QgsProcessingContext &context, const QVariantMap &modelParameters, const QVariantMap &results ) const
|
||||
{
|
||||
QVariantMap variables;
|
||||
std::unique_ptr< QgsExpressionContextScope > scope( new QgsExpressionContextScope() );
|
||||
ChildParameterSources sources = availableSourcesForChild( childId, QStringList() << QgsProcessingParameterNumber::typeName(),
|
||||
QStringList() << QgsProcessingOutputNumber::typeName() );
|
||||
Q_FOREACH ( const ChildParameterSource &source, sources )
|
||||
{
|
||||
QString name;
|
||||
QVariant value;
|
||||
|
||||
switch ( source.source() )
|
||||
{
|
||||
case ChildParameterSource::ModelParameter:
|
||||
{
|
||||
name = source.parameterName();
|
||||
value = modelParameters.value( source.parameterName() );
|
||||
break;
|
||||
}
|
||||
case ChildParameterSource::ChildOutput:
|
||||
{
|
||||
name = QStringLiteral( "%1_%2" ).arg( mChildAlgorithms.value( source.outputChildId() ).description().isEmpty() ?
|
||||
source.outputChildId() : mChildAlgorithms.value( source.outputChildId() ).description(), source.outputName() );
|
||||
value = results.value( source.outputChildId() ).toMap().value( source.outputName() );
|
||||
break;
|
||||
}
|
||||
|
||||
case ChildParameterSource::Expression:
|
||||
case ChildParameterSource::StaticValue:
|
||||
continue;
|
||||
|
||||
};
|
||||
|
||||
variables.insert( name, value );
|
||||
}
|
||||
|
||||
sources = availableSourcesForChild( childId, QStringList()
|
||||
<< QgsProcessingParameterVectorLayer::typeName()
|
||||
<< QgsProcessingParameterRasterLayer::typeName(),
|
||||
QStringList() << QgsProcessingOutputVectorLayer::typeName()
|
||||
<< QgsProcessingOutputRasterLayer::typeName() );
|
||||
|
||||
Q_FOREACH ( const ChildParameterSource &source, sources )
|
||||
{
|
||||
QString name;
|
||||
QVariant value;
|
||||
|
||||
switch ( source.source() )
|
||||
{
|
||||
case ChildParameterSource::ModelParameter:
|
||||
{
|
||||
name = source.parameterName();
|
||||
value = modelParameters.value( source.parameterName() );
|
||||
break;
|
||||
}
|
||||
case ChildParameterSource::ChildOutput:
|
||||
{
|
||||
name = QStringLiteral( "%1_%2" ).arg( mChildAlgorithms.value( source.outputChildId() ).description().isEmpty() ?
|
||||
source.outputChildId() : mChildAlgorithms.value( source.outputChildId() ).description(), source.outputName() );
|
||||
value = results.value( source.outputChildId() ).toMap().value( source.outputName() );
|
||||
break;
|
||||
}
|
||||
|
||||
case ChildParameterSource::Expression:
|
||||
case ChildParameterSource::StaticValue:
|
||||
continue;
|
||||
|
||||
};
|
||||
|
||||
QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( qvariant_cast<QObject *>( value ) );
|
||||
if ( !layer )
|
||||
layer = QgsProcessingUtils::mapLayerFromString( value.toString(), context );
|
||||
|
||||
variables.insert( QStringLiteral( "%1_minx" ).arg( name ), layer ? layer->extent().xMinimum() : QVariant() );
|
||||
variables.insert( QStringLiteral( "%1_miny" ).arg( name ), layer ? layer->extent().yMinimum() : QVariant() );
|
||||
variables.insert( QStringLiteral( "%1_maxx" ).arg( name ), layer ? layer->extent().xMaximum() : QVariant() );
|
||||
variables.insert( QStringLiteral( "%1_maxy" ).arg( name ), layer ? layer->extent().yMaximum() : QVariant() );
|
||||
}
|
||||
|
||||
sources = availableSourcesForChild( childId, QStringList()
|
||||
<< QgsProcessingParameterFeatureSource::typeName() );
|
||||
Q_FOREACH ( const ChildParameterSource &source, sources )
|
||||
{
|
||||
QString name;
|
||||
QVariant value;
|
||||
|
||||
switch ( source.source() )
|
||||
{
|
||||
case ChildParameterSource::ModelParameter:
|
||||
{
|
||||
name = source.parameterName();
|
||||
value = modelParameters.value( source.parameterName() );
|
||||
break;
|
||||
}
|
||||
case ChildParameterSource::ChildOutput:
|
||||
{
|
||||
name = QStringLiteral( "%1_%2" ).arg( mChildAlgorithms.value( source.outputChildId() ).description().isEmpty() ?
|
||||
source.outputChildId() : mChildAlgorithms.value( source.outputChildId() ).description(), source.outputName() );
|
||||
value = results.value( source.outputChildId() ).toMap().value( source.outputName() );
|
||||
break;
|
||||
}
|
||||
|
||||
case ChildParameterSource::Expression:
|
||||
case ChildParameterSource::StaticValue:
|
||||
continue;
|
||||
|
||||
};
|
||||
|
||||
QgsFeatureSource *featureSource = nullptr;
|
||||
if ( value.canConvert<QgsProcessingFeatureSourceDefinition>() )
|
||||
{
|
||||
QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( value );
|
||||
value = fromVar.source;
|
||||
}
|
||||
if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( value ) ) )
|
||||
{
|
||||
featureSource = layer;
|
||||
}
|
||||
if ( !featureSource )
|
||||
{
|
||||
if ( QgsVectorLayer *vl = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( value.toString(), context ) ) )
|
||||
featureSource = vl;
|
||||
}
|
||||
|
||||
variables.insert( QStringLiteral( "%1_minx" ).arg( name ), featureSource ? featureSource->sourceExtent().xMinimum() : QVariant() );
|
||||
variables.insert( QStringLiteral( "%1_miny" ).arg( name ), featureSource ? featureSource->sourceExtent().yMinimum() : QVariant() );
|
||||
variables.insert( QStringLiteral( "%1_maxx" ).arg( name ), featureSource ? featureSource->sourceExtent().xMaximum() : QVariant() );
|
||||
variables.insert( QStringLiteral( "%1_maxy" ).arg( name ), featureSource ? featureSource->sourceExtent().yMaximum() : QVariant() );
|
||||
}
|
||||
|
||||
QVariantMap::const_iterator varIt = variables.constBegin();
|
||||
for ( ; varIt != variables.constEnd(); ++varIt )
|
||||
{
|
||||
QString name = varIt.key();
|
||||
name = name.replace( QRegularExpression( "[\\s'\"\\(\\):]" ), QStringLiteral( "_" ) );
|
||||
scope->addVariable( QgsExpressionContextScope::StaticVariable( name, varIt.value(), true ) );
|
||||
}
|
||||
|
||||
return scope.release();
|
||||
}
|
||||
|
||||
QgsProcessingModelAlgorithm::ChildParameterSources QgsProcessingModelAlgorithm::availableSourcesForChild( const QString &childId, const QStringList ¶meterTypes, const QStringList &outputTypes, const QList<int> dataTypes ) const
|
||||
{
|
||||
ChildParameterSources sources;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "qgis_core.h"
|
||||
#include "qgis.h"
|
||||
#include "qgsprocessingalgorithm.h"
|
||||
#include "qgsprocessingcontext.h"
|
||||
|
||||
///@cond NOT_STABLE
|
||||
|
||||
@ -866,6 +867,12 @@ class CORE_EXPORT QgsProcessingModelAlgorithm : public QgsProcessingAlgorithm
|
||||
QList< QgsProcessingModelAlgorithm::ChildParameterSource > availableSourcesForChild( const QString &childId, const QStringList ¶meterTypes = QStringList(),
|
||||
const QStringList &outputTypes = QStringList(), const QList< int > dataTypes = QList< int >() ) const;
|
||||
|
||||
/**
|
||||
* Creates a new expression context scope for a child algorithm within the model.
|
||||
*/
|
||||
QgsExpressionContextScope *createExpressionContextScopeForChildAlgorithm( const QString &childId, QgsProcessingContext &context, const QVariantMap &modelParameters = QVariantMap(),
|
||||
const QVariantMap &results = QVariantMap() ) const SIP_FACTORY;
|
||||
|
||||
protected:
|
||||
|
||||
QVariantMap processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
@ -890,7 +897,7 @@ class CORE_EXPORT QgsProcessingModelAlgorithm : public QgsProcessingAlgorithm
|
||||
void dependsOnChildAlgorithmsRecursive( const QString &childId, QSet<QString> &depends ) const;
|
||||
void dependentChildAlgorithmsRecursive( const QString &childId, QSet<QString> &depends ) const;
|
||||
|
||||
QVariantMap parametersForChildAlgorithm( const ChildAlgorithm &child, const QVariantMap &modelParameters, const QMap<QString, QVariantMap> &results, const QgsExpressionContext &expressionContext ) const;
|
||||
QVariantMap parametersForChildAlgorithm( const ChildAlgorithm &child, const QVariantMap &modelParameters, const QVariantMap &results, const QgsExpressionContext &expressionContext ) const;
|
||||
|
||||
/**
|
||||
* Returns true if an output from a child algorithm is required elsewhere in
|
||||
|
@ -4788,7 +4788,7 @@ void TestQgsProcessing::modelExecution()
|
||||
QgsProcessingOutputLayerDefinition layerDef( "memory:" );
|
||||
layerDef.destinationName = "my_dest";
|
||||
modelInputs.insert( "cx3:MY_OUT", QVariant::fromValue( layerDef ) );
|
||||
QMap<QString, QVariantMap> childResults;
|
||||
QVariantMap childResults;
|
||||
QVariantMap params = model2.parametersForChildAlgorithm( model2.childAlgorithm( "cx1" ), modelInputs, childResults, expContext );
|
||||
QCOMPARE( params.value( "DISSOLVE" ).toBool(), false );
|
||||
QCOMPARE( params.value( "DISTANCE" ).toInt(), 271 );
|
||||
|
Loading…
x
Reference in New Issue
Block a user