mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-28 00:05:33 -04:00
[processing] evaluate parameters before executing algorithm
This allows a better use of expressions
This commit is contained in:
parent
01f380863f
commit
e353d226a8
@ -199,7 +199,7 @@ class GeoAlgorithm(object):
|
|||||||
self.setOutputCRS()
|
self.setOutputCRS()
|
||||||
self.resolveTemporaryOutputs()
|
self.resolveTemporaryOutputs()
|
||||||
self.resolveDataObjects()
|
self.resolveDataObjects()
|
||||||
self.resolveMinCoveringExtent()
|
self.evaluateParameterValues()
|
||||||
self.checkOutputFileExtensions()
|
self.checkOutputFileExtensions()
|
||||||
self.runPreExecutionScript(progress)
|
self.runPreExecutionScript(progress)
|
||||||
self.processAlgorithm(progress)
|
self.processAlgorithm(progress)
|
||||||
@ -207,7 +207,7 @@ class GeoAlgorithm(object):
|
|||||||
self.convertUnsupportedFormats(progress)
|
self.convertUnsupportedFormats(progress)
|
||||||
self.runPostExecutionScript(progress)
|
self.runPostExecutionScript(progress)
|
||||||
except GeoAlgorithmExecutionException as gaee:
|
except GeoAlgorithmExecutionException as gaee:
|
||||||
lines = [self.tr('Uncaught error while executing algorithm')]
|
lines = [self.tr('Error while executing algorithm')]
|
||||||
lines.append(traceback.format_exc())
|
lines.append(traceback.format_exc())
|
||||||
ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, gaee.msg)
|
ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, gaee.msg)
|
||||||
raise GeoAlgorithmExecutionException(gaee.msg, lines, gaee)
|
raise GeoAlgorithmExecutionException(gaee.msg, lines, gaee)
|
||||||
@ -340,11 +340,9 @@ class GeoAlgorithm(object):
|
|||||||
if not os.path.isabs(out.value):
|
if not os.path.isabs(out.value):
|
||||||
continue
|
continue
|
||||||
if isinstance(out, OutputRaster):
|
if isinstance(out, OutputRaster):
|
||||||
exts = \
|
exts = dataobjects.getSupportedOutputRasterLayerExtensions()
|
||||||
dataobjects.getSupportedOutputRasterLayerExtensions()
|
|
||||||
elif isinstance(out, OutputVector):
|
elif isinstance(out, OutputVector):
|
||||||
exts = \
|
exts = dataobjects.getSupportedOutputVectorLayerExtensions()
|
||||||
dataobjects.getSupportedOutputVectorLayerExtensions()
|
|
||||||
elif isinstance(out, OutputTable):
|
elif isinstance(out, OutputTable):
|
||||||
exts = dataobjects.getSupportedOutputTableExtensions()
|
exts = dataobjects.getSupportedOutputTableExtensions()
|
||||||
elif isinstance(out, OutputHTML):
|
elif isinstance(out, OutputHTML):
|
||||||
@ -360,60 +358,12 @@ class GeoAlgorithm(object):
|
|||||||
out.value = out.value + '.' + exts[0]
|
out.value = out.value + '.' + exts[0]
|
||||||
|
|
||||||
|
|
||||||
def canUseAutoExtent(self):
|
def evaluateParameterValues(self):
|
||||||
for param in self.parameters:
|
for param in self.parameters:
|
||||||
if isinstance(param, (ParameterRaster, ParameterVector)):
|
try:
|
||||||
return True
|
param.evaluate(self)
|
||||||
if isinstance(param, ParameterMultipleInput):
|
except ValueError, e:
|
||||||
return True
|
raise GeoAlgorithmExecutionException(str(e))
|
||||||
return False
|
|
||||||
|
|
||||||
def resolveMinCoveringExtent(self):
|
|
||||||
for param in self.parameters:
|
|
||||||
if isinstance(param, ParameterExtent):
|
|
||||||
if param.value is None:
|
|
||||||
param.value = self.getMinCoveringExtent()
|
|
||||||
|
|
||||||
def getMinCoveringExtent(self):
|
|
||||||
first = True
|
|
||||||
found = False
|
|
||||||
for param in self.parameters:
|
|
||||||
if param.value:
|
|
||||||
if isinstance(param, (ParameterRaster, ParameterVector)):
|
|
||||||
if isinstance(param.value, (QgsRasterLayer,
|
|
||||||
QgsVectorLayer)):
|
|
||||||
layer = param.value
|
|
||||||
else:
|
|
||||||
layer = dataobjects.getObject(param.value)
|
|
||||||
if layer:
|
|
||||||
found = True
|
|
||||||
self.addToRegion(layer, first)
|
|
||||||
first = False
|
|
||||||
elif isinstance(param, ParameterMultipleInput):
|
|
||||||
layers = param.value.split(';')
|
|
||||||
for layername in layers:
|
|
||||||
layer = dataobjects.getObject(layername)
|
|
||||||
if layer:
|
|
||||||
found = True
|
|
||||||
self.addToRegion(layer, first)
|
|
||||||
first = False
|
|
||||||
if found:
|
|
||||||
return '{},{},{},{}'.format(
|
|
||||||
self.xmin, self.xmax, self.ymin, self.ymax)
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def addToRegion(self, layer, first):
|
|
||||||
if first:
|
|
||||||
self.xmin = layer.extent().xMinimum()
|
|
||||||
self.xmax = layer.extent().xMaximum()
|
|
||||||
self.ymin = layer.extent().yMinimum()
|
|
||||||
self.ymax = layer.extent().yMaximum()
|
|
||||||
else:
|
|
||||||
self.xmin = min(self.xmin, layer.extent().xMinimum())
|
|
||||||
self.xmax = max(self.xmax, layer.extent().xMaximum())
|
|
||||||
self.ymin = min(self.ymin, layer.extent().yMinimum())
|
|
||||||
self.ymax = max(self.ymax, layer.extent().yMaximum())
|
|
||||||
|
|
||||||
def resolveTemporaryOutputs(self):
|
def resolveTemporaryOutputs(self):
|
||||||
"""Sets temporary outputs (output.value = None) with a
|
"""Sets temporary outputs (output.value = None) with a
|
||||||
|
|||||||
@ -33,11 +33,12 @@ import os
|
|||||||
from inspect import isclass
|
from inspect import isclass
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
|
from qgis.utils import iface
|
||||||
from qgis.PyQt.QtCore import QCoreApplication
|
from qgis.PyQt.QtCore import QCoreApplication
|
||||||
from qgis.core import QgsRasterLayer, QgsVectorLayer, QgsMapLayer, QgsCoordinateReferenceSystem
|
from qgis.core import (QgsRasterLayer, QgsVectorLayer, QgsMapLayer, QgsCoordinateReferenceSystem,
|
||||||
|
QgsExpressionContext, QgsExpressionContextUtils, QgsExpression, QgsExpressionContextScope)
|
||||||
|
|
||||||
from processing.tools.vector import resolveFieldIndex, features
|
from processing.tools.vector import resolveFieldIndex, features
|
||||||
from processing.tools.system import isWindows
|
|
||||||
from processing.tools import dataobjects
|
from processing.tools import dataobjects
|
||||||
|
|
||||||
def parseBool(s):
|
def parseBool(s):
|
||||||
@ -58,7 +59,47 @@ def _splitParameterOptions(line):
|
|||||||
def _createDescriptiveName(s):
|
def _createDescriptiveName(s):
|
||||||
return s.replace('_', ' ')
|
return s.replace('_', ' ')
|
||||||
|
|
||||||
class Parameter(object):
|
def _expressionContext():
|
||||||
|
context = QgsExpressionContext()
|
||||||
|
context.appendScope(QgsExpressionContextUtils.globalScope())
|
||||||
|
context.appendScope(QgsExpressionContextUtils.projectScope())
|
||||||
|
processingScope = QgsExpressionContextScope()
|
||||||
|
layers = dataobjects.getAllLayers()
|
||||||
|
for layer in layers:
|
||||||
|
name = layer.name()
|
||||||
|
processingScope.setVariable('%s_minx' % name, layer.extent().xMinimum())
|
||||||
|
processingScope.setVariable('%s_miny' % name, layer.extent().yMinimum())
|
||||||
|
processingScope.setVariable('%s_maxx' % name, layer.extent().xMaximum())
|
||||||
|
processingScope.setVariable('%s_maxy' % name, layer.extent().yMaximum())
|
||||||
|
if isinstance(layer, QgsRasterLayer):
|
||||||
|
cellsize = (layer.extent().xMaximum()
|
||||||
|
- layer.extent().xMinimum()) / layer.width()
|
||||||
|
processingScope.setVariable('%s_cellsize' % name, cellsize)
|
||||||
|
|
||||||
|
layers = dataobjects.getRasterLayers()
|
||||||
|
for layer in layers:
|
||||||
|
for i in range(layer.bandCount()):
|
||||||
|
stats = layer.dataProvider().bandStatistics(i + 1)
|
||||||
|
processingScope.setVariable('%s_band%i_avg' % (name, i + 1), stats.mean)
|
||||||
|
processingScope.setVariable('%s_band%i_stddev' % (name, i + 1), stats.stdDev)
|
||||||
|
processingScope.setVariable('%s_band%i_min' % (name, i + 1), stats.minimumValue)
|
||||||
|
processingScope.setVariable('%s_band%i_max' % (name, i + 1), stats.maximumValue)
|
||||||
|
|
||||||
|
extent = iface.mapCanvas().extent()
|
||||||
|
processingScope.setVariable('canvasextent_minx', extent.xMinimum())
|
||||||
|
processingScope.setVariable('canvasextent_miny', extent.yMinimum())
|
||||||
|
processingScope.setVariable('canvasextent_maxx', extent.xMaximum())
|
||||||
|
processingScope.setVariable('canvasextent_maxy', extent.yMaximum())
|
||||||
|
|
||||||
|
extent = iface.mapCanvas().fullExtent()
|
||||||
|
processingScope.setVariable('fullextent_minx', extent.xMinimum())
|
||||||
|
processingScope.setVariable('fullextent_miny', extent.yMinimum())
|
||||||
|
processingScope.setVariable('fullextent_maxx', extent.xMaximum())
|
||||||
|
processingScope.setVariable('fullextent_maxy', extent.yMaximum())
|
||||||
|
context.appendScope(processingScope)
|
||||||
|
return context
|
||||||
|
|
||||||
|
class Parameter:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Base class for all parameters that a geoalgorithm might
|
Base class for all parameters that a geoalgorithm might
|
||||||
@ -149,6 +190,9 @@ class Parameter(object):
|
|||||||
# or a wrapper instance
|
# or a wrapper instance
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
def evaluate(self, alg):
|
||||||
|
pass
|
||||||
|
|
||||||
class ParameterBoolean(Parameter):
|
class ParameterBoolean(Parameter):
|
||||||
|
|
||||||
default_metadata = {
|
default_metadata = {
|
||||||
@ -330,6 +374,51 @@ class ParameterExtent(Parameter):
|
|||||||
default = definition.strip()[len('extent') + 1:] or None
|
default = definition.strip()[len('extent') + 1:] or None
|
||||||
return ParameterExtent(name, descName, default, isOptional)
|
return ParameterExtent(name, descName, default, isOptional)
|
||||||
|
|
||||||
|
def evaluate(self, alg):
|
||||||
|
if self.optional and not bool(self.value):
|
||||||
|
self.value = self.getMinCoveringExtent()
|
||||||
|
|
||||||
|
def getMinCoveringExtent(self, alg):
|
||||||
|
first = True
|
||||||
|
found = False
|
||||||
|
for param in alg.parameters:
|
||||||
|
if param.value:
|
||||||
|
if isinstance(param, (ParameterRaster, ParameterVector)):
|
||||||
|
if isinstance(param.value, (QgsRasterLayer,
|
||||||
|
QgsVectorLayer)):
|
||||||
|
layer = param.value
|
||||||
|
else:
|
||||||
|
layer = dataobjects.getObject(param.value)
|
||||||
|
if layer:
|
||||||
|
found = True
|
||||||
|
self.addToRegion(layer, first)
|
||||||
|
first = False
|
||||||
|
elif isinstance(param, ParameterMultipleInput):
|
||||||
|
layers = param.value.split(';')
|
||||||
|
for layername in layers:
|
||||||
|
layer = dataobjects.getObject(layername)
|
||||||
|
if layer:
|
||||||
|
found = True
|
||||||
|
self.addToRegion(layer, first)
|
||||||
|
first = False
|
||||||
|
if found:
|
||||||
|
return '{},{},{},{}'.format(
|
||||||
|
self.xmin, self.xmax, self.ymin, self.ymax)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def addToRegion(self, layer, first):
|
||||||
|
if first:
|
||||||
|
self.xmin = layer.extent().xMinimum()
|
||||||
|
self.xmax = layer.extent().xMaximum()
|
||||||
|
self.ymin = layer.extent().yMinimum()
|
||||||
|
self.ymax = layer.extent().yMaximum()
|
||||||
|
else:
|
||||||
|
self.xmin = min(self.xmin, layer.extent().xMinimum())
|
||||||
|
self.xmax = max(self.xmax, layer.extent().xMaximum())
|
||||||
|
self.ymin = min(self.ymin, layer.extent().yMinimum())
|
||||||
|
self.ymax = max(self.ymax, layer.extent().yMaximum())
|
||||||
|
|
||||||
|
|
||||||
class ParameterPoint(Parameter):
|
class ParameterPoint(Parameter):
|
||||||
|
|
||||||
@ -715,6 +804,15 @@ class ParameterNumber(Parameter):
|
|||||||
self.value = None
|
self.value = None
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
if isinstance(n, basestring):
|
||||||
|
try:
|
||||||
|
v = self._evaluate(n)
|
||||||
|
float(v)
|
||||||
|
self.value = n
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
try:
|
try:
|
||||||
if float(n) - int(float(n)) == 0:
|
if float(n) - int(float(n)) == 0:
|
||||||
value = int(float(n))
|
value = int(float(n))
|
||||||
@ -746,6 +844,31 @@ class ParameterNumber(Parameter):
|
|||||||
default = definition.strip()[len('number') + 1:] or None
|
default = definition.strip()[len('number') + 1:] or None
|
||||||
return ParameterNumber(name, descName, default=default, optional=isOptional)
|
return ParameterNumber(name, descName, default=default, optional=isOptional)
|
||||||
|
|
||||||
|
def _evaluate(self, v):
|
||||||
|
exp = QgsExpression(v)
|
||||||
|
if exp.hasParserError():
|
||||||
|
raise ValueError(self.tr("Error in parameter expression: ") + exp.parserErrorString())
|
||||||
|
result = exp.evaluate(_expressionContext())
|
||||||
|
if exp.hasEvalError():
|
||||||
|
raise ValueError("Error evaluating parameter expression: " + exp.evalErrorString())
|
||||||
|
return result
|
||||||
|
|
||||||
|
def evaluate(self, alg):
|
||||||
|
if isinstance(self.value, basestring):
|
||||||
|
self.value = self._evaluate(self.value)
|
||||||
|
|
||||||
|
def expressionContext(self):
|
||||||
|
return _expressionContext()
|
||||||
|
|
||||||
|
def getValueAsCommandLineParameter(self):
|
||||||
|
if self.value is None:
|
||||||
|
return str(None)
|
||||||
|
if isinstance(self.value, basestring):
|
||||||
|
return '"%s"' % self.value
|
||||||
|
return str(self.value)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ParameterRange(Parameter):
|
class ParameterRange(Parameter):
|
||||||
|
|
||||||
def __init__(self, name='', description='', default=None, optional=False):
|
def __init__(self, name='', description='', default=None, optional=False):
|
||||||
@ -919,6 +1042,13 @@ class ParameterSelection(Parameter):
|
|||||||
return ParameterSelection(name, descName, options, optional=isOptional)
|
return ParameterSelection(name, descName, options, optional=isOptional)
|
||||||
|
|
||||||
|
|
||||||
|
class ParameterEvaluationException(Exception):
|
||||||
|
|
||||||
|
def __init__(self, param, msg):
|
||||||
|
Exception.__init__(msg)
|
||||||
|
self.param = param
|
||||||
|
|
||||||
|
|
||||||
class ParameterString(Parameter):
|
class ParameterString(Parameter):
|
||||||
|
|
||||||
default_metadata = {
|
default_metadata = {
|
||||||
@ -977,6 +1107,18 @@ class ParameterString(Parameter):
|
|||||||
else:
|
else:
|
||||||
return ParameterString(name, descName, multiline=True, optional=isOptional)
|
return ParameterString(name, descName, multiline=True, optional=isOptional)
|
||||||
|
|
||||||
|
def evaluate(self, alg):
|
||||||
|
exp = QgsExpression(self.value)
|
||||||
|
if exp.hasParserError():
|
||||||
|
raise ValueError(self.tr("Error in parameter expression: ") + exp.parserErrorString())
|
||||||
|
result = exp.evaluate(_expressionContext())
|
||||||
|
if exp.hasEvalError():
|
||||||
|
raise ValueError("Error evaluating parameter expression: " + exp.evalErrorString())
|
||||||
|
self.value = result
|
||||||
|
|
||||||
|
def expressionContext(self):
|
||||||
|
return _expressionContext()
|
||||||
|
|
||||||
class ParameterTable(ParameterDataObject):
|
class ParameterTable(ParameterDataObject):
|
||||||
|
|
||||||
default_metadata = {
|
default_metadata = {
|
||||||
|
|||||||
@ -31,7 +31,7 @@ from qgis.PyQt.QtCore import Qt
|
|||||||
from qgis.PyQt.QtWidgets import QMessageBox, QApplication, QPushButton, QWidget, QVBoxLayout
|
from qgis.PyQt.QtWidgets import QMessageBox, QApplication, QPushButton, QWidget, QVBoxLayout
|
||||||
from qgis.PyQt.QtGui import QCursor, QColor, QPalette
|
from qgis.PyQt.QtGui import QCursor, QColor, QPalette
|
||||||
|
|
||||||
from qgis.core import QgsMapLayerRegistry, QgsExpressionContext, QgsExpressionContextUtils, QgsExpression
|
from qgis.core import QgsMapLayerRegistry
|
||||||
|
|
||||||
from processing.core.ProcessingLog import ProcessingLog
|
from processing.core.ProcessingLog import ProcessingLog
|
||||||
from processing.core.ProcessingConfig import ProcessingConfig
|
from processing.core.ProcessingConfig import ProcessingConfig
|
||||||
@ -62,8 +62,6 @@ from processing.core.outputs import OutputRaster
|
|||||||
from processing.core.outputs import OutputVector
|
from processing.core.outputs import OutputVector
|
||||||
from processing.core.outputs import OutputTable
|
from processing.core.outputs import OutputTable
|
||||||
|
|
||||||
from processing.tools import dataobjects
|
|
||||||
|
|
||||||
|
|
||||||
class AlgorithmDialog(AlgorithmDialogBase):
|
class AlgorithmDialog(AlgorithmDialogBase):
|
||||||
|
|
||||||
@ -114,18 +112,6 @@ class AlgorithmDialog(AlgorithmDialogBase):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def evaluateExpression(self, text):
|
|
||||||
context = QgsExpressionContext()
|
|
||||||
context.appendScope(QgsExpressionContextUtils.globalScope())
|
|
||||||
context.appendScope(QgsExpressionContextUtils.projectScope())
|
|
||||||
exp = QgsExpression(text)
|
|
||||||
if exp.hasParserError():
|
|
||||||
raise Exception(exp.parserErrorString())
|
|
||||||
result = exp.evaluate(context)
|
|
||||||
if exp.hasEvalError():
|
|
||||||
raise ValueError(exp.evalErrorString())
|
|
||||||
return result
|
|
||||||
|
|
||||||
def setParamValue(self, param, wrapper, alg=None):
|
def setParamValue(self, param, wrapper, alg=None):
|
||||||
return param.setValue(wrapper.value())
|
return param.setValue(wrapper.value())
|
||||||
|
|
||||||
|
|||||||
@ -1,153 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
***************************************************************************
|
|
||||||
NumberInputDialog.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 range
|
|
||||||
|
|
||||||
__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
|
|
||||||
|
|
||||||
from qgis.PyQt import uic
|
|
||||||
from qgis.PyQt.QtWidgets import QDialog, QTreeWidgetItem, QMessageBox
|
|
||||||
from qgis.core import QgsRasterLayer
|
|
||||||
|
|
||||||
from qgis.utils import iface
|
|
||||||
from processing.tools import dataobjects
|
|
||||||
|
|
||||||
pluginPath = os.path.split(os.path.dirname(__file__))[0]
|
|
||||||
WIDGET, BASE = uic.loadUiType(
|
|
||||||
os.path.join(pluginPath, 'ui', 'DlgNumberInput.ui'))
|
|
||||||
|
|
||||||
|
|
||||||
class NumberInputDialog(BASE, WIDGET):
|
|
||||||
|
|
||||||
def __init__(self, isInteger):
|
|
||||||
super(NumberInputDialog, self).__init__(None)
|
|
||||||
self.setupUi(self)
|
|
||||||
|
|
||||||
if hasattr(self.leFormula, 'setPlaceholderText'):
|
|
||||||
self.leFormula.setPlaceholderText(
|
|
||||||
self.tr('[Enter your formula here]'))
|
|
||||||
|
|
||||||
self.treeValues.doubleClicked.connect(self.addValue)
|
|
||||||
|
|
||||||
self.value = None
|
|
||||||
self.isInteger = isInteger
|
|
||||||
|
|
||||||
if not self.isInteger:
|
|
||||||
self.lblWarning.hide()
|
|
||||||
|
|
||||||
self.fillTree()
|
|
||||||
|
|
||||||
def fillTree(self):
|
|
||||||
layersItem = QTreeWidgetItem()
|
|
||||||
layersItem.setText(0, self.tr('Values from data layers extents'))
|
|
||||||
self.treeValues.addTopLevelItem(layersItem)
|
|
||||||
layers = dataobjects.getAllLayers()
|
|
||||||
for layer in layers:
|
|
||||||
layerItem = QTreeWidgetItem()
|
|
||||||
layerItem.setText(0, str(layer.name()))
|
|
||||||
layerItem.addChild(TreeValueItem(self.tr('Min X'),
|
|
||||||
layer.extent().xMinimum()))
|
|
||||||
layerItem.addChild(TreeValueItem(self.tr('Max X'),
|
|
||||||
layer.extent().xMaximum()))
|
|
||||||
layerItem.addChild(TreeValueItem(self.tr('Min Y'),
|
|
||||||
layer.extent().yMinimum()))
|
|
||||||
layerItem.addChild(TreeValueItem(self.tr('Max Y'),
|
|
||||||
layer.extent().yMaximum()))
|
|
||||||
if isinstance(layer, QgsRasterLayer):
|
|
||||||
cellsize = (layer.extent().xMaximum()
|
|
||||||
- layer.extent().xMinimum()) / layer.width()
|
|
||||||
layerItem.addChild(TreeValueItem(self.tr('Cellsize'),
|
|
||||||
cellsize))
|
|
||||||
layersItem.addChild(layerItem)
|
|
||||||
|
|
||||||
layersItem = QTreeWidgetItem()
|
|
||||||
layersItem.setText(0, self.tr('Values from raster layers statistics'))
|
|
||||||
self.treeValues.addTopLevelItem(layersItem)
|
|
||||||
layers = dataobjects.getRasterLayers()
|
|
||||||
for layer in layers:
|
|
||||||
for i in range(layer.bandCount()):
|
|
||||||
stats = layer.dataProvider().bandStatistics(i + 1)
|
|
||||||
layerItem = QTreeWidgetItem()
|
|
||||||
layerItem.setText(0, str(layer.name()))
|
|
||||||
layerItem.addChild(TreeValueItem(self.tr('Mean'), stats.mean))
|
|
||||||
layerItem.addChild(TreeValueItem(self.tr('Std. deviation'),
|
|
||||||
stats.stdDev))
|
|
||||||
layerItem.addChild(TreeValueItem(self.tr('Max value'),
|
|
||||||
stats.maximumValue))
|
|
||||||
layerItem.addChild(TreeValueItem(self.tr('Min value'),
|
|
||||||
stats.minimumValue))
|
|
||||||
layersItem.addChild(layerItem)
|
|
||||||
|
|
||||||
canvasItem = QTreeWidgetItem()
|
|
||||||
canvasItem.setText(0, self.tr('Values from QGIS map canvas'))
|
|
||||||
self.treeValues.addTopLevelItem(canvasItem)
|
|
||||||
extent = iface.mapCanvas().extent()
|
|
||||||
extentItem = QTreeWidgetItem()
|
|
||||||
extentItem.setText(0, self.tr('Current extent'))
|
|
||||||
extentItem.addChild(TreeValueItem(self.tr('Min X'), extent.xMinimum()))
|
|
||||||
extentItem.addChild(TreeValueItem(self.tr('Max X'), extent.xMaximum()))
|
|
||||||
extentItem.addChild(TreeValueItem(self.tr('Min Y'), extent.yMinimum()))
|
|
||||||
extentItem.addChild(TreeValueItem(self.tr('Max Y'), extent.yMaximum()))
|
|
||||||
canvasItem.addChild(extentItem)
|
|
||||||
|
|
||||||
extent = iface.mapCanvas().fullExtent()
|
|
||||||
extentItem = QTreeWidgetItem()
|
|
||||||
extentItem.setText(0,
|
|
||||||
self.tr('Full extent of all layers in map canvas'))
|
|
||||||
extentItem.addChild(TreeValueItem(self.tr('Min X'), extent.xMinimum()))
|
|
||||||
extentItem.addChild(TreeValueItem(self.tr('Max X'), extent.xMaximum()))
|
|
||||||
extentItem.addChild(TreeValueItem(self.tr('Min Y'), extent.yMinimum()))
|
|
||||||
extentItem.addChild(TreeValueItem(self.tr('Max Y'), extent.yMaximum()))
|
|
||||||
canvasItem.addChild(extentItem)
|
|
||||||
|
|
||||||
def addValue(self):
|
|
||||||
item = self.treeValues.currentItem()
|
|
||||||
if isinstance(item, TreeValueItem):
|
|
||||||
formula = self.leFormula.text() + ' ' + str(item.value)
|
|
||||||
self.leFormula.setText(formula.strip())
|
|
||||||
|
|
||||||
def accept(self):
|
|
||||||
try:
|
|
||||||
self.value = float(eval(str(self.leFormula.text())))
|
|
||||||
if self.isInteger:
|
|
||||||
self.value = int(round(self.value))
|
|
||||||
QDialog.accept(self)
|
|
||||||
except:
|
|
||||||
QMessageBox.critical(self, self.tr('Wrong expression'),
|
|
||||||
self.tr('The expression entered is not correct'))
|
|
||||||
|
|
||||||
def reject(self):
|
|
||||||
self.value = None
|
|
||||||
QDialog.reject(self)
|
|
||||||
|
|
||||||
|
|
||||||
class TreeValueItem(QTreeWidgetItem):
|
|
||||||
|
|
||||||
def __init__(self, name, value):
|
|
||||||
QTreeWidgetItem.__init__(self)
|
|
||||||
self.value = value
|
|
||||||
self.setText(0, name + ': ' + str(value))
|
|
||||||
@ -32,131 +32,44 @@ from qgis.PyQt import uic
|
|||||||
from qgis.PyQt.QtCore import pyqtSignal
|
from qgis.PyQt.QtCore import pyqtSignal
|
||||||
from qgis.PyQt.QtWidgets import QDialog
|
from qgis.PyQt.QtWidgets import QDialog
|
||||||
|
|
||||||
from math import log10, floor
|
|
||||||
from qgis.core import (QgsDataSourceUri,
|
from qgis.core import (QgsDataSourceUri,
|
||||||
QgsCredentials,
|
QgsCredentials,
|
||||||
QgsExpressionContext,
|
|
||||||
QgsExpressionContextUtils,
|
|
||||||
QgsExpression,
|
QgsExpression,
|
||||||
QgsRasterLayer,
|
QgsRasterLayer)
|
||||||
QgsExpressionContextScope)
|
|
||||||
from qgis.gui import QgsEncodingFileDialog, QgsExpressionBuilderDialog
|
from qgis.gui import QgsEncodingFileDialog, QgsExpressionBuilderDialog
|
||||||
from qgis.utils import iface
|
from qgis.utils import iface
|
||||||
from processing.tools import dataobjects
|
|
||||||
|
|
||||||
pluginPath = os.path.split(os.path.dirname(__file__))[0]
|
pluginPath = os.path.split(os.path.dirname(__file__))[0]
|
||||||
WIDGET, BASE = uic.loadUiType(
|
WIDGET, BASE = uic.loadUiType(
|
||||||
os.path.join(pluginPath, 'ui', 'widgetNumberSelector.ui'))
|
os.path.join(pluginPath, 'ui', 'widgetBaseSelector.ui'))
|
||||||
|
|
||||||
|
|
||||||
class NumberInputPanel(BASE, WIDGET):
|
class NumberInputPanel(BASE, WIDGET):
|
||||||
|
|
||||||
hasChanged = pyqtSignal()
|
hasChanged = pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, number, minimum, maximum, isInteger):
|
def __init__(self, param):
|
||||||
super(NumberInputPanel, self).__init__(None)
|
super(NumberInputPanel, self).__init__(None)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
|
|
||||||
self.spnValue.setExpressionsEnabled(True)
|
self.param = param
|
||||||
self.isInteger = isInteger
|
self.text = param.default
|
||||||
if self.isInteger:
|
|
||||||
self.spnValue.setDecimals(0)
|
|
||||||
else:
|
|
||||||
# Guess reasonable step value
|
|
||||||
if (maximum == 0 or maximum) and (minimum == 0 or minimum):
|
|
||||||
self.spnValue.setSingleStep(self.calculateStep(minimum, maximum))
|
|
||||||
|
|
||||||
if maximum == 0 or maximum:
|
self.btnSelect.clicked.connect(self.showExpressionsBuilder)
|
||||||
self.spnValue.setMaximum(maximum)
|
self.leText.textChanged.connect(lambda: self.hasChanged.emit())
|
||||||
else:
|
|
||||||
self.spnValue.setMaximum(99999999)
|
|
||||||
if minimum == 0 or minimum:
|
|
||||||
self.spnValue.setMinimum(minimum)
|
|
||||||
else:
|
|
||||||
self.spnValue.setMinimum(-99999999)
|
|
||||||
|
|
||||||
# Set default value
|
|
||||||
if number == 0 or number:
|
|
||||||
self.spnValue.setValue(float(number))
|
|
||||||
self.spnValue.setClearValue(float(number))
|
|
||||||
elif minimum == 0 or minimum:
|
|
||||||
self.spnValue.setValue(float(minimum))
|
|
||||||
self.spnValue.setClearValue(float(minimum))
|
|
||||||
else:
|
|
||||||
self.spnValue.setValue(0)
|
|
||||||
self.spnValue.setClearValue(0)
|
|
||||||
|
|
||||||
self.btnCalc.setFixedHeight(self.spnValue.height())
|
|
||||||
|
|
||||||
self.btnCalc.clicked.connect(self.showExpressionsBuilder)
|
|
||||||
|
|
||||||
self.spnValue.valueChanged.connect(lambda: self.hasChanged.emit())
|
|
||||||
|
|
||||||
def showExpressionsBuilder(self):
|
def showExpressionsBuilder(self):
|
||||||
context = self.expressionContext()
|
context = self.param.expressionContext()
|
||||||
dlg = QgsExpressionBuilderDialog(None, self.spnValue.text(), self, 'generic', context)
|
dlg = QgsExpressionBuilderDialog(None, self.leText.text(), self, 'generic', context)
|
||||||
dlg.setWindowTitle(self.tr('Expression based input'))
|
dlg.setWindowTitle(self.tr('Expression based input'))
|
||||||
if dlg.exec_() == QDialog.Accepted:
|
if dlg.exec_() == QDialog.Accepted:
|
||||||
exp = QgsExpression(dlg.expressionText())
|
exp = QgsExpression(dlg.expressionText())
|
||||||
if not exp.hasParserError():
|
if not exp.hasParserError():
|
||||||
result = exp.evaluate(context)
|
self.setValue(dlg.expressionText())
|
||||||
if not exp.hasEvalError():
|
|
||||||
try:
|
|
||||||
self.spnValue.setValue(float(result))
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def expressionContext(self):
|
|
||||||
context = QgsExpressionContext()
|
|
||||||
context.appendScope(QgsExpressionContextUtils.globalScope())
|
|
||||||
context.appendScope(QgsExpressionContextUtils.projectScope())
|
|
||||||
processingScope = QgsExpressionContextScope()
|
|
||||||
layers = dataobjects.getAllLayers()
|
|
||||||
for layer in layers:
|
|
||||||
name = layer.name()
|
|
||||||
processingScope.setVariable('%s_minx' % name, layer.extent().xMinimum())
|
|
||||||
processingScope.setVariable('%s_miny' % name, layer.extent().yMinimum())
|
|
||||||
processingScope.setVariable('%s_maxx' % name, layer.extent().xMaximum())
|
|
||||||
processingScope.setVariable('%s_maxy' % name, layer.extent().yMaximum())
|
|
||||||
if isinstance(layer, QgsRasterLayer):
|
|
||||||
cellsize = (layer.extent().xMaximum()
|
|
||||||
- layer.extent().xMinimum()) / layer.width()
|
|
||||||
processingScope.setVariable('%s_cellsize' % name, cellsize)
|
|
||||||
|
|
||||||
layers = dataobjects.getRasterLayers()
|
|
||||||
for layer in layers:
|
|
||||||
for i in range(layer.bandCount()):
|
|
||||||
stats = layer.dataProvider().bandStatistics(i + 1)
|
|
||||||
processingScope.setVariable('%s_band%i_avg' % (name, i + 1), stats.mean)
|
|
||||||
processingScope.setVariable('%s_band%i_stddev' % (name, i + 1), stats.stdDev)
|
|
||||||
processingScope.setVariable('%s_band%i_min' % (name, i + 1), stats.minimumValue)
|
|
||||||
processingScope.setVariable('%s_band%i_max' % (name, i + 1), stats.maximumValue)
|
|
||||||
|
|
||||||
extent = iface.mapCanvas().extent()
|
|
||||||
processingScope.setVariable('canvasextent_minx', extent.xMinimum())
|
|
||||||
processingScope.setVariable('canvasextent_miny', extent.yMinimum())
|
|
||||||
processingScope.setVariable('canvasextent_maxx', extent.xMaximum())
|
|
||||||
processingScope.setVariable('canvasextent_maxy', extent.yMaximum())
|
|
||||||
|
|
||||||
extent = iface.mapCanvas().fullExtent()
|
|
||||||
processingScope.setVariable('fullextent_minx', extent.xMinimum())
|
|
||||||
processingScope.setVariable('fullextent_miny', extent.yMinimum())
|
|
||||||
processingScope.setVariable('fullextent_maxx', extent.xMaximum())
|
|
||||||
processingScope.setVariable('fullextent_maxy', extent.yMaximum())
|
|
||||||
context.appendScope(processingScope)
|
|
||||||
return context
|
|
||||||
|
|
||||||
def getValue(self):
|
def getValue(self):
|
||||||
return self.spnValue.value()
|
return self.leText.text()
|
||||||
|
|
||||||
def setValue(self, value):
|
def setValue(self, value):
|
||||||
self.spnValue.setValue(value)
|
self.leText.setText(unicode(value))
|
||||||
|
|
||||||
def calculateStep(self, minimum, maximum):
|
|
||||||
valueRange = maximum - minimum
|
|
||||||
if valueRange <= 1.0:
|
|
||||||
step = valueRange / 10.0
|
|
||||||
# round to 1 significant figure
|
|
||||||
return round(step, -int(floor(log10(step))))
|
|
||||||
else:
|
|
||||||
return 1.0
|
|
||||||
|
|||||||
74
python/plugins/processing/gui/StringInputPanel.py
Normal file
74
python/plugins/processing/gui/StringInputPanel.py
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
***************************************************************************
|
||||||
|
NumberInputPanel.py
|
||||||
|
---------------------
|
||||||
|
Date : August 2016
|
||||||
|
Copyright : (C) 2016 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. *
|
||||||
|
* *
|
||||||
|
***************************************************************************
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = 'Victor Olaya'
|
||||||
|
__date__ = 'August 2016'
|
||||||
|
__copyright__ = '(C) 2016, Victor Olaya'
|
||||||
|
|
||||||
|
# This will get replaced with a git SHA1 when you do a git archive
|
||||||
|
|
||||||
|
__revision__ = '$Format:%H$'
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from qgis.PyQt import uic
|
||||||
|
from qgis.PyQt.QtCore import pyqtSignal
|
||||||
|
from qgis.PyQt.QtWidgets import QDialog
|
||||||
|
|
||||||
|
from qgis.core import (QgsDataSourceUri,
|
||||||
|
QgsCredentials,
|
||||||
|
QgsExpression,
|
||||||
|
QgsRasterLayer)
|
||||||
|
from qgis.gui import QgsEncodingFileDialog, QgsExpressionBuilderDialog
|
||||||
|
from qgis.utils import iface
|
||||||
|
|
||||||
|
pluginPath = os.path.split(os.path.dirname(__file__))[0]
|
||||||
|
WIDGET, BASE = uic.loadUiType(
|
||||||
|
os.path.join(pluginPath, 'ui', 'widgetBaseSelector.ui'))
|
||||||
|
|
||||||
|
|
||||||
|
class StringInputPanel(BASE, WIDGET):
|
||||||
|
|
||||||
|
hasChanged = pyqtSignal()
|
||||||
|
|
||||||
|
def __init__(self, param):
|
||||||
|
super(StringInputPanel, self).__init__(None)
|
||||||
|
self.setupUi(self)
|
||||||
|
|
||||||
|
self.param = param
|
||||||
|
self.text = param.default
|
||||||
|
|
||||||
|
self.btnSelect.clicked.connect(self.showExpressionsBuilder)
|
||||||
|
self.leText.textChanged.connect(lambda: self.hasChanged.emit())
|
||||||
|
|
||||||
|
def showExpressionsBuilder(self):
|
||||||
|
context = self.param.expressionContext()
|
||||||
|
dlg = QgsExpressionBuilderDialog(None, self.leText.text(), self, 'generic', context)
|
||||||
|
dlg.setWindowTitle(self.tr('Expression based input'))
|
||||||
|
if dlg.exec_() == QDialog.Accepted:
|
||||||
|
exp = QgsExpression(dlg.expressionText())
|
||||||
|
if not exp.hasParserError():
|
||||||
|
self.setValue(dlg.expressionText())
|
||||||
|
|
||||||
|
|
||||||
|
def getValue(self):
|
||||||
|
return self.leText.text()
|
||||||
|
|
||||||
|
def setValue(self, value):
|
||||||
|
self.leText.setText(unicode(value))
|
||||||
@ -50,6 +50,7 @@ from processing.gui.MultipleInputPanel import MultipleInputPanel
|
|||||||
from processing.gui.BatchInputSelectionPanel import BatchInputSelectionPanel
|
from processing.gui.BatchInputSelectionPanel import BatchInputSelectionPanel
|
||||||
from processing.gui.FixedTablePanel import FixedTablePanel
|
from processing.gui.FixedTablePanel import FixedTablePanel
|
||||||
from processing.gui.ExtentSelectionPanel import ExtentSelectionPanel
|
from processing.gui.ExtentSelectionPanel import ExtentSelectionPanel
|
||||||
|
from processing.gui.StringInputPanel import StringInputPanel
|
||||||
|
|
||||||
|
|
||||||
DIALOG_STANDARD = 'standard'
|
DIALOG_STANDARD = 'standard'
|
||||||
@ -442,8 +443,7 @@ class NumberWidgetWrapper(WidgetWrapper):
|
|||||||
|
|
||||||
def createWidget(self):
|
def createWidget(self):
|
||||||
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
|
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
|
||||||
return NumberInputPanel(self.param.default, self.param.min, self.param.max,
|
return NumberInputPanel(self.param)
|
||||||
self.param.isInteger)
|
|
||||||
else:
|
else:
|
||||||
widget = QComboBox()
|
widget = QComboBox()
|
||||||
widget.setEditable(True)
|
widget.setEditable(True)
|
||||||
@ -605,9 +605,9 @@ class StringWidgetWrapper(WidgetWrapper):
|
|||||||
if self.param.default:
|
if self.param.default:
|
||||||
widget.setPlainText(self.param.default)
|
widget.setPlainText(self.param.default)
|
||||||
else:
|
else:
|
||||||
widget = QLineEdit()
|
widget = StringInputPanel(self.param)
|
||||||
if self.param.default:
|
if self.param.default:
|
||||||
widget.setText(self.param.default)
|
widget.setValue(self.param.default)
|
||||||
elif self.dialogType == DIALOG_BATCH:
|
elif self.dialogType == DIALOG_BATCH:
|
||||||
widget = QLineEdit()
|
widget = QLineEdit()
|
||||||
if self.param.default:
|
if self.param.default:
|
||||||
@ -642,22 +642,10 @@ class StringWidgetWrapper(WidgetWrapper):
|
|||||||
if self.param.multiline:
|
if self.param.multiline:
|
||||||
text = self.widget.toPlainText()
|
text = self.widget.toPlainText()
|
||||||
else:
|
else:
|
||||||
text = self.widget.text()
|
text = self.widget.getValue()
|
||||||
|
|
||||||
if self.param.evaluateExpressions:
|
|
||||||
try:
|
|
||||||
text = self.evaluateExpression(text)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
return text
|
return text
|
||||||
if self.dialogType == DIALOG_BATCH:
|
if self.dialogType == DIALOG_BATCH:
|
||||||
text = self.widget.text()
|
text = self.widget.text()
|
||||||
if self.param.evaluateExpressions:
|
|
||||||
try:
|
|
||||||
text = self.evaluateExpression(text)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
return text
|
|
||||||
else:
|
else:
|
||||||
if self.param.multiline:
|
if self.param.multiline:
|
||||||
value = self.widget.getValue()
|
value = self.widget.getValue()
|
||||||
|
|||||||
@ -1,58 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>Form</class>
|
|
||||||
<widget class="QWidget" name="Form">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>251</width>
|
|
||||||
<height>23</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Form</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
|
||||||
<property name="spacing">
|
|
||||||
<number>2</number>
|
|
||||||
</property>
|
|
||||||
<property name="margin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<widget class="QgsDoubleSpinBox" name="spnValue">
|
|
||||||
<property name="decimals">
|
|
||||||
<number>6</number>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
|
||||||
<double>-99999999.999999001622200</double>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<double>99999999.999999001622200</double>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="btnCalc">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Open number input dialog</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>QgsDoubleSpinBox</class>
|
|
||||||
<extends>QDoubleSpinBox</extends>
|
|
||||||
<header>qgis.gui</header>
|
|
||||||
<container>1</container>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
||||||
Loading…
x
Reference in New Issue
Block a user