Skip to content

Commit 19d8605

Browse files
authoredJan 1, 2019
Merge pull request #8770 from alexbruy/processing-backports
[processing] Add cell size parameter to native interpolation algorithms (fix #18556, #20114)
2 parents d5029f4 + 580ff83 commit 19d8605

File tree

7 files changed

+549
-270
lines changed

7 files changed

+549
-270
lines changed
 

‎python/plugins/processing/algs/qgis/IdwInterpolation.py

Lines changed: 33 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -31,62 +31,26 @@
3131

3232
from qgis.core import (QgsRectangle,
3333
QgsProcessingUtils,
34-
QgsProcessingParameterDefinition,
3534
QgsProcessingParameterNumber,
3635
QgsProcessingParameterExtent,
36+
QgsProcessingParameterDefinition,
3737
QgsProcessingParameterRasterDestination,
3838
QgsProcessingException)
3939
from qgis.analysis import (QgsInterpolator,
4040
QgsIDWInterpolator,
4141
QgsGridFileWriter)
4242

4343
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
44+
from processing.algs.qgis.ui.InterpolationWidgets import ParameterInterpolationData, ParameterPixelSize
4445

4546
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
4647

4748

48-
class ParameterInterpolationData(QgsProcessingParameterDefinition):
49-
50-
def __init__(self, name='', description=''):
51-
super().__init__(name, description)
52-
self.setMetadata({
53-
'widget_wrapper': 'processing.algs.qgis.ui.InterpolationDataWidget.InterpolationDataWidgetWrapper'
54-
})
55-
56-
def type(self):
57-
return 'idw_interpolation_data'
58-
59-
def clone(self):
60-
return ParameterInterpolationData(self.name(), self.description())
61-
62-
@staticmethod
63-
def parseValue(value):
64-
if value is None:
65-
return None
66-
67-
if value == '':
68-
return None
69-
70-
if isinstance(value, str):
71-
return value if value != '' else None
72-
else:
73-
return ParameterInterpolationData.dataToString(value)
74-
75-
@staticmethod
76-
def dataToString(data):
77-
s = ''
78-
for c in data:
79-
s += '{}::~::{}::~::{:d}::~::{:d};'.format(c[0],
80-
c[1],
81-
c[2],
82-
c[3])
83-
return s[:-1]
84-
85-
8649
class IdwInterpolation(QgisAlgorithm):
8750

8851
INTERPOLATION_DATA = 'INTERPOLATION_DATA'
8952
DISTANCE_COEFFICIENT = 'DISTANCE_COEFFICIENT'
53+
PIXEL_SIZE = 'PIXEL_SIZE'
9054
COLUMNS = 'COLUMNS'
9155
ROWS = 'ROWS'
9256
EXTENT = 'EXTENT'
@@ -111,15 +75,31 @@ def initAlgorithm(self, config=None):
11175
self.addParameter(QgsProcessingParameterNumber(self.DISTANCE_COEFFICIENT,
11276
self.tr('Distance coefficient P'), type=QgsProcessingParameterNumber.Double,
11377
minValue=0.0, maxValue=99.99, defaultValue=2.0))
114-
self.addParameter(QgsProcessingParameterNumber(self.COLUMNS,
115-
self.tr('Number of columns'),
116-
minValue=0, maxValue=10000000, defaultValue=300))
117-
self.addParameter(QgsProcessingParameterNumber(self.ROWS,
118-
self.tr('Number of rows'),
119-
minValue=0, maxValue=10000000, defaultValue=300))
12078
self.addParameter(QgsProcessingParameterExtent(self.EXTENT,
12179
self.tr('Extent'),
12280
optional=False))
81+
pixel_size_param = ParameterPixelSize(self.PIXEL_SIZE,
82+
self.tr('Output raster size'),
83+
layersData=self.INTERPOLATION_DATA,
84+
extent=self.EXTENT,
85+
minValue=0.0,
86+
default=0.1)
87+
self.addParameter(pixel_size_param)
88+
89+
cols_param = QgsProcessingParameterNumber(self.COLUMNS,
90+
self.tr('Number of columns'),
91+
optional=True,
92+
minValue=0, maxValue=10000000)
93+
cols_param.setFlags(cols_param.flags() | QgsProcessingParameterDefinition.FlagHidden)
94+
self.addParameter(cols_param)
95+
96+
rows_param = QgsProcessingParameterNumber(self.ROWS,
97+
self.tr('Number of rows'),
98+
optional=True,
99+
minValue=0, maxValue=10000000)
100+
rows_param.setFlags(rows_param.flags() | QgsProcessingParameterDefinition.FlagHidden)
101+
self.addParameter(rows_param)
102+
123103
self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
124104
self.tr('Interpolated')))
125105

@@ -132,11 +112,17 @@ def displayName(self):
132112
def processAlgorithm(self, parameters, context, feedback):
133113
interpolationData = ParameterInterpolationData.parseValue(parameters[self.INTERPOLATION_DATA])
134114
coefficient = self.parameterAsDouble(parameters, self.DISTANCE_COEFFICIENT, context)
135-
columns = self.parameterAsInt(parameters, self.COLUMNS, context)
136-
rows = self.parameterAsInt(parameters, self.ROWS, context)
137115
bbox = self.parameterAsExtent(parameters, self.EXTENT, context)
116+
pixel_size = self.parameterAsDouble(parameters, self.PIXEL_SIZE, context)
138117
output = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
139118

119+
columns = self.parameterAsInt(parameters, self.COLUMNS, context)
120+
rows = self.parameterAsInt(parameters, self.ROWS, context)
121+
if columns == 0:
122+
columns = max(round(bbox.width() / pixel_size) + 1, 1)
123+
if rows == 0:
124+
rows = max(round(bbox.height() / pixel_size) + 1, 1)
125+
140126
if interpolationData is None:
141127
raise QgsProcessingException(
142128
self.tr('You need to specify at least one input layer.'))

‎python/plugins/processing/algs/qgis/TinInterpolation.py

Lines changed: 33 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@
3131

3232
from qgis.core import (QgsProcessingUtils,
3333
QgsProcessing,
34-
QgsProcessingParameterDefinition,
3534
QgsProcessingParameterEnum,
3635
QgsProcessingParameterNumber,
3736
QgsProcessingParameterExtent,
37+
QgsProcessingParameterDefinition,
3838
QgsProcessingParameterRasterDestination,
3939
QgsWkbTypes,
4040
QgsProcessingParameterFeatureSink,
@@ -45,51 +45,15 @@
4545
QgsGridFileWriter)
4646

4747
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
48+
from processing.algs.qgis.ui.InterpolationWidgets import ParameterInterpolationData, ParameterPixelSize
4849

4950
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
5051

5152

52-
class ParameterInterpolationData(QgsProcessingParameterDefinition):
53-
54-
def __init__(self, name='', description=''):
55-
super().__init__(name, description)
56-
self.setMetadata({
57-
'widget_wrapper': 'processing.algs.qgis.ui.InterpolationDataWidget.InterpolationDataWidgetWrapper'
58-
})
59-
60-
def type(self):
61-
return 'tin_interpolation_data'
62-
63-
def clone(self):
64-
return ParameterInterpolationData(self.name(), self.description())
65-
66-
@staticmethod
67-
def parseValue(value):
68-
if value is None:
69-
return None
70-
71-
if value == '':
72-
return None
73-
74-
if isinstance(value, str):
75-
return value if value != '' else None
76-
else:
77-
return ParameterInterpolationData.dataToString(value)
78-
79-
@staticmethod
80-
def dataToString(data):
81-
s = ''
82-
for c in data:
83-
s += '{}::~:: {}::~:: {:d}::~:: {:d};'.format(c[0],
84-
c[1],
85-
c[2],
86-
c[3])
87-
return s[:-1]
88-
89-
9053
class TinInterpolation(QgisAlgorithm):
9154
INTERPOLATION_DATA = 'INTERPOLATION_DATA'
9255
METHOD = 'METHOD'
56+
PIXEL_SIZE = 'PIXEL_SIZE'
9357
COLUMNS = 'COLUMNS'
9458
ROWS = 'ROWS'
9559
EXTENT = 'EXTENT'
@@ -119,15 +83,31 @@ def initAlgorithm(self, config=None):
11983
self.tr('Interpolation method'),
12084
options=self.METHODS,
12185
defaultValue=0))
122-
self.addParameter(QgsProcessingParameterNumber(self.COLUMNS,
123-
self.tr('Number of columns'),
124-
minValue=0, maxValue=10000000, defaultValue=300))
125-
self.addParameter(QgsProcessingParameterNumber(self.ROWS,
126-
self.tr('Number of rows'),
127-
minValue=0, maxValue=10000000, defaultValue=300))
12886
self.addParameter(QgsProcessingParameterExtent(self.EXTENT,
12987
self.tr('Extent'),
13088
optional=False))
89+
pixel_size_param = ParameterPixelSize(self.PIXEL_SIZE,
90+
self.tr('Output raster size'),
91+
layersData=self.INTERPOLATION_DATA,
92+
extent=self.EXTENT,
93+
minValue=0.0,
94+
default=0.1)
95+
self.addParameter(pixel_size_param)
96+
97+
cols_param = QgsProcessingParameterNumber(self.COLUMNS,
98+
self.tr('Number of columns'),
99+
optional=True,
100+
minValue=0, maxValue=10000000)
101+
cols_param.setFlags(cols_param.flags() | QgsProcessingParameterDefinition.FlagHidden)
102+
self.addParameter(cols_param)
103+
104+
rows_param = QgsProcessingParameterNumber(self.ROWS,
105+
self.tr('Number of rows'),
106+
optional=True,
107+
minValue=0, maxValue=10000000)
108+
rows_param.setFlags(rows_param.flags() | QgsProcessingParameterDefinition.FlagHidden)
109+
self.addParameter(rows_param)
110+
131111
self.addParameter(QgsProcessingParameterRasterDestination(self.OUTPUT,
132112
self.tr('Interpolated')))
133113

@@ -147,11 +127,17 @@ def displayName(self):
147127
def processAlgorithm(self, parameters, context, feedback):
148128
interpolationData = ParameterInterpolationData.parseValue(parameters[self.INTERPOLATION_DATA])
149129
method = self.parameterAsEnum(parameters, self.METHOD, context)
150-
columns = self.parameterAsInt(parameters, self.COLUMNS, context)
151-
rows = self.parameterAsInt(parameters, self.ROWS, context)
152130
bbox = self.parameterAsExtent(parameters, self.EXTENT, context)
131+
pixel_size = self.parameterAsDouble(parameters, self.PIXEL_SIZE, context)
153132
output = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
154133

134+
columns = self.parameterAsInt(parameters, self.COLUMNS, context)
135+
rows = self.parameterAsInt(parameters, self.ROWS, context)
136+
if columns == 0:
137+
columns = max(round(bbox.width() / pixel_size) + 1, 1)
138+
if rows == 0:
139+
rows = max(round(bbox.height() / pixel_size) + 1, 1)
140+
155141
if interpolationData is None:
156142
raise QgsProcessingException(
157143
self.tr('You need to specify at least one input layer.'))

‎python/plugins/processing/algs/qgis/ui/InterpolationDataWidget.py

Lines changed: 0 additions & 171 deletions
This file was deleted.
Lines changed: 402 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,402 @@
1+
# -*- coding: utf-8 -*-
2+
3+
"""
4+
***************************************************************************
5+
InterpolationDataWidget.py
6+
---------------------
7+
Date : December 2016
8+
Copyright : (C) 2016 by Alexander Bruy
9+
Email : alexander dot bruy at gmail dot com
10+
***************************************************************************
11+
* *
12+
* This program is free software; you can redistribute it and/or modify *
13+
* it under the terms of the GNU General Public License as published by *
14+
* the Free Software Foundation; either version 2 of the License, or *
15+
* (at your option) any later version. *
16+
* *
17+
***************************************************************************
18+
"""
19+
20+
__author__ = 'Alexander Bruy'
21+
__date__ = 'December 2016'
22+
__copyright__ = '(C) 2016, Alexander Bruy'
23+
24+
# This will get replaced with a git SHA1 when you do a git archive
25+
26+
__revision__ = '$Format:%H$'
27+
28+
import os
29+
30+
from qgis.PyQt import uic
31+
from qgis.PyQt.QtCore import pyqtSignal
32+
from qgis.PyQt.QtWidgets import (QTreeWidgetItem,
33+
QComboBox
34+
)
35+
from qgis.core import (QgsApplication,
36+
QgsMapLayer,
37+
QgsMapLayerProxyModel,
38+
QgsWkbTypes,
39+
QgsRectangle,
40+
QgsReferencedRectangle,
41+
QgsCoordinateReferenceSystem,
42+
QgsProcessingUtils,
43+
QgsProcessingParameterNumber,
44+
QgsProcessingParameterDefinition
45+
)
46+
from qgis.core import QgsFieldProxyModel
47+
from qgis.analysis import QgsInterpolator
48+
49+
from processing.gui.wrappers import WidgetWrapper, DIALOG_STANDARD
50+
from processing.tools import dataobjects
51+
52+
pluginPath = os.path.dirname(__file__)
53+
54+
55+
class ParameterInterpolationData(QgsProcessingParameterDefinition):
56+
57+
def __init__(self, name='', description=''):
58+
super().__init__(name, description)
59+
self.setMetadata({
60+
'widget_wrapper': 'processing.algs.qgis.ui.InterpolationWidgets.InterpolationDataWidgetWrapper'
61+
})
62+
63+
def type(self):
64+
return 'idw_interpolation_data'
65+
66+
def clone(self):
67+
return ParameterInterpolationData(self.name(), self.description())
68+
69+
@staticmethod
70+
def parseValue(value):
71+
if value is None:
72+
return None
73+
74+
if value == '':
75+
return None
76+
77+
if isinstance(value, str):
78+
return value if value != '' else None
79+
else:
80+
return ParameterInterpolationData.dataToString(value)
81+
82+
@staticmethod
83+
def dataToString(data):
84+
s = ''
85+
for c in data:
86+
s += '{}::~::{}::~::{:d}::~::{:d};'.format(c[0],
87+
c[1],
88+
c[2],
89+
c[3])
90+
return s[:-1]
91+
92+
93+
WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, 'interpolationdatawidgetbase.ui'))
94+
95+
96+
class InterpolationDataWidget(BASE, WIDGET):
97+
98+
hasChanged = pyqtSignal()
99+
100+
def __init__(self):
101+
super(InterpolationDataWidget, self).__init__(None)
102+
self.setupUi(self)
103+
104+
self.btnAdd.setIcon(QgsApplication.getThemeIcon('/symbologyAdd.svg'))
105+
self.btnRemove.setIcon(QgsApplication.getThemeIcon('/symbologyRemove.svg'))
106+
107+
self.btnAdd.clicked.connect(self.addLayer)
108+
self.btnRemove.clicked.connect(self.removeLayer)
109+
110+
self.cmbLayers.layerChanged.connect(self.layerChanged)
111+
self.cmbLayers.setFilters(QgsMapLayerProxyModel.VectorLayer)
112+
self.cmbFields.setFilters(QgsFieldProxyModel.Numeric)
113+
self.cmbFields.setLayer(self.cmbLayers.currentLayer())
114+
115+
def addLayer(self):
116+
layer = self.cmbLayers.currentLayer()
117+
118+
attribute = ''
119+
if self.chkUseZCoordinate.isChecked():
120+
attribute = 'Z_COORD'
121+
else:
122+
attribute = self.cmbFields.currentField()
123+
124+
self._addLayerData(layer.name(), attribute)
125+
self.hasChanged.emit()
126+
127+
def removeLayer(self):
128+
item = self.layersTree.currentItem()
129+
if not item:
130+
return
131+
self.layersTree.invisibleRootItem().removeChild(item)
132+
self.hasChanged.emit()
133+
134+
def layerChanged(self, layer):
135+
self.chkUseZCoordinate.setEnabled(False)
136+
self.chkUseZCoordinate.setChecked(False)
137+
138+
if layer is None or not layer.isValid():
139+
return
140+
141+
provider = layer.dataProvider()
142+
if not provider:
143+
return
144+
145+
if QgsWkbTypes.hasZ(provider.wkbType()):
146+
self.chkUseZCoordinate.setEnabled(True)
147+
148+
self.cmbFields.setLayer(layer)
149+
150+
def _addLayerData(self, layerName, attribute):
151+
item = QTreeWidgetItem()
152+
item.setText(0, layerName)
153+
item.setText(1, attribute)
154+
self.layersTree.addTopLevelItem(item)
155+
156+
comboBox = QComboBox()
157+
comboBox.addItem(self.tr('Points'))
158+
comboBox.addItem(self.tr('Structure lines'))
159+
comboBox.addItem(self.tr('Break lines'))
160+
comboBox.setCurrentIndex(0)
161+
self.layersTree.setItemWidget(item, 2, comboBox)
162+
163+
def setValue(self, value):
164+
self.layersTree.clear()
165+
rows = value.split(';')
166+
for i, r in enumerate(rows):
167+
v = r.split('::~::')
168+
self.addLayerData(v[0], v[1])
169+
170+
comboBox = self.layersTree.itemWidget(self.layersTree.topLevelItem(i), 2)
171+
comboBox.setCurrentIndex(comboBox.findText(v[3]))
172+
self.hasChanged.emit()
173+
174+
def value(self):
175+
layers = ''
176+
context = dataobjects.createContext()
177+
for i in range(self.layersTree.topLevelItemCount()):
178+
item = self.layersTree.topLevelItem(i)
179+
if item:
180+
layerName = item.text(0)
181+
layer = QgsProcessingUtils.mapLayerFromString(layerName, context)
182+
if not layer:
183+
continue
184+
185+
provider = layer.dataProvider()
186+
if not provider:
187+
continue
188+
189+
interpolationAttribute = item.text(1)
190+
interpolationSource = QgsInterpolator.ValueAttribute
191+
if interpolationAttribute == 'Z_COORD':
192+
interpolationSource = QgsInterpolator.ValueZ
193+
fieldIndex = -1
194+
else:
195+
fieldIndex = layer.fields().indexFromName(interpolationAttribute)
196+
197+
comboBox = self.layersTree.itemWidget(self.layersTree.topLevelItem(i), 2)
198+
inputTypeName = comboBox.currentText()
199+
if inputTypeName == self.tr('Points'):
200+
inputType = QgsInterpolator.SourcePoints
201+
elif inputTypeName == self.tr('Structure lines'):
202+
inputType = QgsInterpolator.SourceStructureLines
203+
else:
204+
inputType = QgsInterpolator.SourceBreakLines
205+
206+
layers += '{}::~::{:d}::~::{:d}::~::{:d};'.format(layer.source(),
207+
interpolationSource,
208+
fieldIndex,
209+
inputType)
210+
return layers[:-1]
211+
212+
213+
class InterpolationDataWidgetWrapper(WidgetWrapper):
214+
215+
def createWidget(self):
216+
widget = InterpolationDataWidget()
217+
widget.hasChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
218+
return widget
219+
220+
def setValue(self, value):
221+
self.widget.setValue(value)
222+
223+
def value(self):
224+
return self.widget.value()
225+
226+
227+
class ParameterPixelSize(QgsProcessingParameterNumber):
228+
229+
def __init__(self, name='', description='', layersData=None, extent=None, minValue=None, default=None, optional=False):
230+
QgsProcessingParameterNumber.__init__(self, name, description, QgsProcessingParameterNumber.Double, default, optional, minValue)
231+
self.setMetadata({
232+
'widget_wrapper': 'processing.algs.qgis.ui.InterpolationWidgets.PixelSizeWidgetWrapper'
233+
})
234+
235+
self.layersData = layersData
236+
self.extent = extent
237+
self.layers = []
238+
239+
def clone(self):
240+
copy = ParameterPixelSize(self.name(), self.description(), self.layersData, self.extent, self.minimum(), self.defaultValue(), self.flags() & QgsProcessingParameterDefinition.FlagOptional)
241+
return copy
242+
243+
244+
WIDGET, BASE = uic.loadUiType(os.path.join(pluginPath, 'RasterResolutionWidget.ui'))
245+
246+
247+
class PixelSizeWidget(BASE, WIDGET):
248+
249+
def __init__(self):
250+
super(PixelSizeWidget, self).__init__(None)
251+
self.setupUi(self)
252+
self.context = dataobjects.createContext()
253+
254+
self.extent = QgsRectangle()
255+
self.layers = []
256+
257+
self.mCellXSpinBox.setShowClearButton(False)
258+
self.mCellYSpinBox.setShowClearButton(False)
259+
self.mRowsSpinBox.setShowClearButton(False)
260+
self.mColumnsSpinBox.setShowClearButton(False)
261+
262+
self.mCellYSpinBox.valueChanged.connect(self.mCellXSpinBox.setValue)
263+
self.mCellXSpinBox.valueChanged.connect(self.pixelSizeChanged)
264+
self.mRowsSpinBox.valueChanged.connect(self.rowsChanged)
265+
self.mColumnsSpinBox.valueChanged.connect(self.columnsChanged)
266+
267+
def setLayers(self, layersData):
268+
self.extent = QgsRectangle()
269+
self.layers = []
270+
for row in layersData.split(';'):
271+
v = row.split('::~::')
272+
# need to keep a reference until interpolation is complete
273+
layer = QgsProcessingUtils.variantToSource(v[0], self.context)
274+
if layer:
275+
self.layers.append(layer)
276+
bbox = layer.sourceExtent()
277+
if self.extent.isEmpty():
278+
self.extent = bbox
279+
else:
280+
self.extent.combineExtentWith(bbox)
281+
282+
self.pixelSizeChanged()
283+
284+
def setExtent(self, extent):
285+
if extent is not None:
286+
tokens = extent.split(' ')[0].split(',')
287+
ext = QgsRectangle(float(tokens[0]), float(tokens[2]), float(tokens[1]), float(tokens[3]))
288+
if len(tokens) > 1:
289+
self.extent = QgsReferencedRectangle(ext, QgsCoordinateReferenceSystem(tokens[1][1:-1]))
290+
else:
291+
self.extent = ext
292+
self.pixelSizeChanged()
293+
294+
def pixelSizeChanged(self):
295+
cell_size = self.mCellXSpinBox.value()
296+
if cell_size <= 0:
297+
return
298+
299+
self.mCellYSpinBox.blockSignals(True)
300+
self.mCellYSpinBox.setValue(cell_size)
301+
self.mCellYSpinBox.blockSignals(False)
302+
rows = max(round(self.extent.height() / cell_size) + 1, 1)
303+
cols = max(round(self.extent.width() / cell_size) + 1, 1)
304+
self.mRowsSpinBox.blockSignals(True)
305+
self.mRowsSpinBox.setValue(rows)
306+
self.mRowsSpinBox.blockSignals(False)
307+
self.mColumnsSpinBox.blockSignals(True)
308+
self.mColumnsSpinBox.setValue(cols)
309+
self.mColumnsSpinBox.blockSignals(False)
310+
311+
def rowsChanged(self):
312+
rows = self.mRowsSpinBox.value()
313+
if rows <= 0:
314+
return
315+
cell_size = self.extent.height() / rows
316+
cols = max(round(self.extent.width() / cell_size) + 1, 1)
317+
self.mColumnsSpinBox.blockSignals(True)
318+
self.mColumnsSpinBox.setValue(cols)
319+
self.mColumnsSpinBox.blockSignals(False)
320+
for w in [self.mCellXSpinBox, self.mCellYSpinBox]:
321+
w.blockSignals(True)
322+
w.setValue(cell_size)
323+
w.blockSignals(False)
324+
325+
def columnsChanged(self):
326+
cols = self.mColumnsSpinBox.value()
327+
if cols < 2:
328+
return
329+
cell_size = self.extent.width() / (cols - 1)
330+
rows = max(round(self.extent.height() / cell_size), 1)
331+
self.mRowsSpinBox.blockSignals(True)
332+
self.mRowsSpinBox.setValue(rows)
333+
self.mRowsSpinBox.blockSignals(False)
334+
for w in [self.mCellXSpinBox, self.mCellYSpinBox]:
335+
w.blockSignals(True)
336+
w.setValue(cell_size)
337+
w.blockSignals(False)
338+
339+
def setValue(self, value):
340+
try:
341+
numeric_value = float(value)
342+
except:
343+
return False
344+
345+
self.mCellXSpinBox.setValue(numeric_value)
346+
self.mCellYSpinBox.setValue(numeric_value)
347+
return True
348+
349+
def value(self):
350+
return self.mCellXSpinBox.value()
351+
352+
353+
class PixelSizeWidgetWrapper(WidgetWrapper):
354+
355+
def __init__(self, param, dialog, row=0, col=0, **kwargs):
356+
super().__init__(param, dialog, row, col, **kwargs)
357+
self.context = dataobjects.createContext()
358+
359+
def _panel(self):
360+
return PixelSizeWidget()
361+
362+
def createWidget(self):
363+
if self.dialogType == DIALOG_STANDARD:
364+
return self._panel()
365+
else:
366+
w = QgsDoubleSpinBox()
367+
w.setShowClearButton(False)
368+
w.setMinimum(0)
369+
w.setMaximum(99999999999)
370+
w.setDecimals(6)
371+
w.setToolTip(self.tr('Resolution of each pixel in output raster, in layer units'))
372+
return w
373+
374+
def postInitialize(self, wrappers):
375+
if self.dialogType != DIALOG_STANDARD:
376+
return
377+
378+
for wrapper in wrappers:
379+
if wrapper.parameterDefinition().name() == self.param.layersData:
380+
self.setLayers(wrapper.parameterValue())
381+
wrapper.widgetValueHasChanged.connect(self.layersChanged)
382+
elif wrapper.parameterDefinition().name() == self.param.extent:
383+
self.setExtent(wrapper.parameterValue())
384+
wrapper.widgetValueHasChanged.connect(self.extentChanged)
385+
386+
def layersChanged(self, wrapper):
387+
self.setLayers(wrapper.parameterValue())
388+
389+
def setLayers(self, layersData):
390+
self.widget.setLayers(layersData)
391+
392+
def extentChanged(self, wrapper):
393+
self.setExtent(wrapper.parameterValue())
394+
395+
def setExtent(self, extent):
396+
self.widget.setExtent(extent)
397+
398+
def setValue(self, value):
399+
return self.widget.setValue(value)
400+
401+
def value(self):
402+
return self.widget.value()

‎python/plugins/processing/gui/ExtentSelectionPanel.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
from qgis.PyQt import uic
3232
from qgis.PyQt.QtWidgets import QMenu, QAction, QInputDialog
3333
from qgis.PyQt.QtGui import QCursor
34-
from qgis.PyQt.QtCore import QCoreApplication
34+
from qgis.PyQt.QtCore import QCoreApplication, pyqtSignal
3535

3636
from qgis.gui import QgsMessageBar
3737
from qgis.utils import iface
@@ -56,10 +56,14 @@
5656

5757
class ExtentSelectionPanel(BASE, WIDGET):
5858

59+
hasChanged = pyqtSignal()
60+
5961
def __init__(self, dialog, param):
6062
super(ExtentSelectionPanel, self).__init__(None)
6163
self.setupUi(self)
6264

65+
self.leText.textChanged.connect(lambda: self.hasChanged.emit())
66+
6367
self.dialog = dialog
6468
self.param = param
6569
self.crs = QgsProject.instance().crs()

‎python/plugins/processing/gui/wrappers.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,9 @@ class ExtentWidgetWrapper(WidgetWrapper):
393393

394394
def createWidget(self):
395395
if self.dialogType in (DIALOG_STANDARD, DIALOG_BATCH):
396-
return ExtentSelectionPanel(self.dialog, self.parameterDefinition())
396+
widget = ExtentSelectionPanel(self.dialog, self.parameterDefinition())
397+
widget.hasChanged.connect(lambda: self.widgetValueHasChanged.emit(self))
398+
return widget
397399
else:
398400
widget = QComboBox()
399401
widget.setEditable(True)

‎python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1751,6 +1751,76 @@ tests:
17511751

17521752
- algorithm: qgis:idwinterpolation
17531753
name: IDW interpolation using attribute
1754+
params:
1755+
DISTANCE_COEFFICIENT: 2.0
1756+
EXTENT: 0.0,8.0,-5.0,3.0 [EPSG:4326]
1757+
INTERPOLATION_DATA:
1758+
name: pointsz.gml::~::0::~::1::~::0
1759+
type: interpolation
1760+
PIXEL_SIZE: 0.026667
1761+
results:
1762+
OUTPUT:
1763+
hash:
1764+
- 76d59e1a9905e97fde7da598022d50ec7de15994e61a59e2b6dc952f
1765+
- 6d2da87e58dfe8fdfb3a1b66543bc68870f7e3292a9ca2674ea3a523
1766+
type: rasterhash
1767+
1768+
- algorithm: qgis:idwinterpolation
1769+
name: IDW interpolation using Z value
1770+
params:
1771+
DISTANCE_COEFFICIENT: 2.0
1772+
EXTENT: 0.0,8.0,-5.0,3.0 [EPSG:4326]
1773+
INTERPOLATION_DATA:
1774+
name: pointsz.gml::~::1::~::1::~::0
1775+
type: interpolation
1776+
PIXEL_SIZE: 0.026667
1777+
results:
1778+
OUTPUT:
1779+
hash:
1780+
- 76d59e1a9905e97fde7da598022d50ec7de15994e61a59e2b6dc952f
1781+
- 6d2da87e58dfe8fdfb3a1b66543bc68870f7e3292a9ca2674ea3a523
1782+
type: rasterhash
1783+
1784+
- algorithm: qgis:tininterpolation
1785+
name: TIN interpolation using attribute
1786+
params:
1787+
EXTENT: 0.0,8.0,-5.0,3.0 [EPSG:4326]
1788+
INTERPOLATION_DATA:
1789+
name: pointsz.gml::~::0::~::1::~::0
1790+
type: interpolation
1791+
METHOD: 0
1792+
PIXEL_SIZE: 0.026667
1793+
results:
1794+
OUTPUT:
1795+
hash:
1796+
- 1e07ea5c90a16f87df812042d3e89dd5b1216defa7714921f306de94
1797+
- 6e533a4c2c2e8ef5ca62814a7ad6dd29cb0f0f6eea85baf2a2802870
1798+
type: rasterhash
1799+
#TRIANGULATION_FILE:
1800+
# name: expected/triangulation.gml
1801+
# type: vector
1802+
1803+
- algorithm: qgis:tininterpolation
1804+
name: TIN interpolation using Z value
1805+
params:
1806+
EXTENT: 0.0,8.0,-5.0,3.0 [EPSG:4326]
1807+
INTERPOLATION_DATA:
1808+
name: pointsz.gml::~::1::~::-1::~::0
1809+
type: interpolation
1810+
METHOD: 0
1811+
PIXEL_SIZE: 0.026667
1812+
results:
1813+
OUTPUT:
1814+
hash:
1815+
- 1e07ea5c90a16f87df812042d3e89dd5b1216defa7714921f306de94
1816+
- 6d2da87e58dfe8fdfb3a1b66543bc68870f7e3292a9ca2674ea3a523
1817+
type: rasterhash
1818+
#TRIANULATION_FILE:
1819+
# name: expected/triangulation.gml
1820+
# type: vector
1821+
1822+
- algorithm: qgis:idwinterpolation
1823+
name: IDW interpolation using attribute (old parameters)
17541824
params:
17551825
COLUMNS: 300
17561826
DISTANCE_COEFFICIENT: 2.0
@@ -1767,7 +1837,7 @@ tests:
17671837
type: rasterhash
17681838

17691839
- algorithm: qgis:idwinterpolation
1770-
name: IDW interpolation using Z value
1840+
name: IDW interpolation using Z value (old parameters)
17711841
params:
17721842
COLUMNS: 300
17731843
DISTANCE_COEFFICIENT: 2.0
@@ -1784,7 +1854,7 @@ tests:
17841854
type: rasterhash
17851855

17861856
- algorithm: qgis:tininterpolation
1787-
name: TIN interpolation using attribute
1857+
name: TIN interpolation using attribute (old parameters)
17881858
params:
17891859
COLUMNS: 300
17901860
EXTENT: 0, 8, -5, 3
@@ -1804,7 +1874,7 @@ tests:
18041874
# type: vector
18051875

18061876
- algorithm: qgis:tininterpolation
1807-
name: TIN interpolation using Z value
1877+
name: TIN interpolation using Z value (old parameters)
18081878
params:
18091879
COLUMNS: 300
18101880
EXTENT: 0, 8, -5, 3

0 commit comments

Comments
 (0)
Please sign in to comment.