Skip to content

Commit 5057f76

Browse files
committedOct 23, 2015
Adds the -crop_to_cutline parameter as optional to fix the gdalwarp deviation described in #4530. Option added to Clipper tool from GdalTools and Processing. It also adds the -tr xres yres parameter to GdalTools Clipper tool. Also get the original raster resolution.
1 parent c7eef14 commit 5057f76

File tree

4 files changed

+257
-63
lines changed

4 files changed

+257
-63
lines changed
 

‎python/plugins/GdalTools/tools/GdalTools_utils.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,22 @@ def getRasterExtent(parent, fileName):
364364
return QgsRectangle(xUL, yLR, xLR, yUL)
365365

366366

367+
# get raster resolution
368+
369+
def getRasterResolution(fileName):
370+
ds = gdal.Open(fileName)
371+
if ds is None:
372+
return
373+
374+
gt = ds.GetGeoTransform()
375+
376+
if gt is None:
377+
return
378+
else:
379+
xRes = abs(gt[1])
380+
yRes = abs(gt[5])
381+
return (xRes, yRes)
382+
367383
# This class is used to replace the QFileDialog class.
368384
# Its static methods are used in place of the respective QFileDialog ones to:
369385
# 1. set the last used directory

‎python/plugins/GdalTools/tools/doClipper.py

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
from widgetPluginBase import GdalToolsBasePluginWidget as BasePluginWidget
3232
import GdalTools_utils as Utils
3333

34-
3534
class GdalToolsDialog(QWidget, Ui_Widget, BasePluginWidget):
3635

3736
def __init__(self, iface):
@@ -46,12 +45,19 @@ def __init__(self, iface):
4645
self.extentSelector.setCanvas(self.canvas)
4746
self.outputFormat = Utils.fillRasterOutputFormat()
4847

48+
# set the default QDoubleSpinBoxes
49+
self.xRes.setValue(12.5)
50+
self.yRes.setValue(12.5)
51+
4952
self.setParamsStatus([
5053
(self.inSelector, SIGNAL("filenameChanged()")),
5154
(self.outSelector, SIGNAL("filenameChanged()")),
5255
(self.noDataSpin, SIGNAL("valueChanged(int)"), self.noDataCheck, 1700),
5356
(self.maskSelector, SIGNAL("filenameChanged()"), self.maskModeRadio, 1600),
54-
(self.alphaBandCheck, SIGNAL("stateChanged( int )")),
57+
(self.alphaBandCheck, SIGNAL("stateChanged(int)")),
58+
(self.cropToCutlineCheck, SIGNAL("stateChanged(int)")),
59+
([self.xRes, self.yRes], SIGNAL("valueChanged(double)"), self.keepResolutionRadio),
60+
([self.xRes, self.yRes], SIGNAL("valueChanged(double)"), self.setResolutionRadio),
5561
(self.extentSelector, [SIGNAL("selectionStarted()"), SIGNAL("newExtentDefined()")], self.extentModeRadio),
5662
(self.modeStackedWidget, SIGNAL("currentIndexChanged(int)"))
5763
])
@@ -63,9 +69,11 @@ def __init__(self, iface):
6369
self.connect(self.extentSelector, SIGNAL("selectionStarted()"), self.checkRun)
6470

6571
self.connect(self.extentModeRadio, SIGNAL("toggled(bool)"), self.switchClippingMode)
72+
self.connect(self.keepResolutionRadio, SIGNAL("toggled(bool)"), self.switchResolutionMode)
6673

6774
def show_(self):
6875
self.switchClippingMode()
76+
self.switchResolutionMode()
6977
BasePluginWidget.show_(self)
7078

7179
def onClosing(self):
@@ -82,6 +90,12 @@ def switchClippingMode(self):
8290
self.modeStackedWidget.setCurrentIndex(index)
8391
self.checkRun()
8492

93+
def switchResolutionMode(self):
94+
if self.keepResolutionRadio.isChecked():
95+
self.resolutionStackedWidget.setCurrentIndex(0)
96+
else:
97+
self.resolutionStackedWidget.setCurrentIndex(1)
98+
8599
def checkRun(self):
86100
if self.extentModeRadio.isChecked():
87101
enabler = self.extentSelector.isCoordsValid()
@@ -135,13 +149,14 @@ def getArguments(self):
135149

136150
def getArgsModeExtent(self):
137151
self.base.setPluginCommand("gdal_translate")
152+
inputFn = self.getInputFileName()
138153
arguments = []
139154
if self.noDataCheck.isChecked():
140155
arguments.append("-a_nodata")
141156
arguments.append(unicode(self.noDataSpin.value()))
142157
if self.extentModeRadio.isChecked() and self.extentSelector.isCoordsValid():
143158
rect = self.extentSelector.getExtent()
144-
if rect is not None:
159+
if rect is not None and not inputFn == '':
145160
arguments.append("-projwin")
146161
arguments.append(unicode(rect.xMinimum()))
147162
arguments.append(unicode(rect.yMaximum()))
@@ -150,32 +165,44 @@ def getArgsModeExtent(self):
150165
if not self.getOutputFileName() == '':
151166
arguments.append("-of")
152167
arguments.append(self.outputFormat)
153-
arguments.append(self.getInputFileName())
168+
arguments.append(inputFn)
154169
arguments.append(self.getOutputFileName())
155170
return arguments
156171

157172
def getArgsModeMask(self):
158173
self.base.setPluginCommand("gdalwarp")
174+
inputFn = self.getInputFileName()
159175
arguments = []
160176
if self.noDataCheck.isChecked():
161177
arguments.append("-dstnodata")
162178
arguments.append(unicode(self.noDataSpin.value()))
163179
if self.maskModeRadio.isChecked():
164180
mask = self.maskSelector.filename()
165-
if not mask == '':
181+
if not mask == '' and not inputFn == '':
166182
arguments.append("-q")
167183
arguments.append("-cutline")
168184
arguments.append(mask)
169185
if Utils.GdalConfig.versionNum() >= 1800:
170-
arguments.append("-crop_to_cutline")
186+
if self.cropToCutlineCheck.isChecked():
187+
arguments.append("-crop_to_cutline")
171188
if self.alphaBandCheck.isChecked():
172189
arguments.append("-dstalpha")
190+
if self.keepResolutionRadio.isChecked():
191+
arguments.append("-tr")
192+
resolution = Utils.getRasterResolution(self.getInputFileName())
193+
if resolution is not None:
194+
arguments.append(resolution[0])
195+
arguments.append(resolution[1])
196+
if self.setResolutionRadio.isChecked():
197+
arguments.append("-tr")
198+
arguments.append(unicode(self.xRes.value()))
199+
arguments.append(unicode(self.yRes.value()))
173200

174201
outputFn = self.getOutputFileName()
175202
if not outputFn == '':
176203
arguments.append("-of")
177204
arguments.append(self.outputFormat)
178-
arguments.append(self.getInputFileName())
205+
arguments.append(inputFn)
179206
arguments.append(outputFn)
180207
return arguments
181208

‎python/plugins/GdalTools/tools/widgetClipper.ui

Lines changed: 200 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
<rect>
77
<x>0</x>
88
<y>0</y>
9-
<width>338</width>
10-
<height>226</height>
9+
<width>485</width>
10+
<height>341</height>
1111
</rect>
1212
</property>
1313
<property name="sizePolicy">
@@ -22,6 +22,16 @@
2222
<layout class="QVBoxLayout" name="verticalLayout">
2323
<item>
2424
<layout class="QGridLayout" name="gridLayout">
25+
<item row="0" column="0">
26+
<widget class="QLabel" name="label_3">
27+
<property name="text">
28+
<string>&amp;Input file (raster)</string>
29+
</property>
30+
<property name="buddy">
31+
<cstring>inSelector</cstring>
32+
</property>
33+
</widget>
34+
</item>
2535
<item row="1" column="0">
2636
<widget class="QLabel" name="label_2">
2737
<property name="text">
@@ -32,12 +42,11 @@
3242
</property>
3343
</widget>
3444
</item>
35-
<item row="2" column="0">
36-
<widget class="QCheckBox" name="noDataCheck">
37-
<property name="text">
38-
<string>&amp;No data value</string>
39-
</property>
40-
</widget>
45+
<item row="0" column="1">
46+
<widget class="GdalToolsInOutSelector" name="inSelector" native="true"/>
47+
</item>
48+
<item row="1" column="1">
49+
<widget class="GdalToolsInOutSelector" name="outSelector" native="true"/>
4150
</item>
4251
<item row="2" column="1">
4352
<widget class="QSpinBox" name="noDataSpin">
@@ -49,22 +58,13 @@
4958
</property>
5059
</widget>
5160
</item>
52-
<item row="0" column="0">
53-
<widget class="QLabel" name="label_3">
61+
<item row="2" column="0">
62+
<widget class="QCheckBox" name="noDataCheck">
5463
<property name="text">
55-
<string>&amp;Input file (raster)</string>
56-
</property>
57-
<property name="buddy">
58-
<cstring>inSelector</cstring>
64+
<string>&amp;No data value</string>
5965
</property>
6066
</widget>
6167
</item>
62-
<item row="1" column="1">
63-
<widget class="GdalToolsInOutSelector" name="outSelector" native="true"/>
64-
</item>
65-
<item row="0" column="1">
66-
<widget class="GdalToolsInOutSelector" name="inSelector" native="true"/>
67-
</item>
6868
</layout>
6969
</item>
7070
<item>
@@ -73,31 +73,23 @@
7373
<string>Clipping mode</string>
7474
</property>
7575
<layout class="QGridLayout" name="gridLayout_2">
76-
<item row="0" column="0">
77-
<widget class="QRadioButton" name="extentModeRadio">
78-
<property name="text">
79-
<string>Extent</string>
80-
</property>
81-
<property name="checked">
82-
<bool>true</bool>
83-
</property>
84-
</widget>
85-
</item>
86-
<item row="0" column="1">
87-
<widget class="QRadioButton" name="maskModeRadio">
88-
<property name="text">
89-
<string>Mask layer</string>
90-
</property>
91-
</widget>
92-
</item>
9376
<item row="1" column="0" colspan="2">
9477
<widget class="QStackedWidget" name="modeStackedWidget">
9578
<property name="currentIndex">
9679
<number>1</number>
9780
</property>
9881
<widget class="QWidget" name="page">
9982
<layout class="QGridLayout" name="gridLayout_3">
100-
<property name="margin">
83+
<property name="leftMargin">
84+
<number>0</number>
85+
</property>
86+
<property name="topMargin">
87+
<number>0</number>
88+
</property>
89+
<property name="rightMargin">
90+
<number>0</number>
91+
</property>
92+
<property name="bottomMargin">
10193
<number>0</number>
10294
</property>
10395
<item row="0" column="0">
@@ -107,21 +99,34 @@
10799
</widget>
108100
<widget class="QWidget" name="page_2">
109101
<layout class="QGridLayout" name="gridLayout_4">
110-
<property name="margin">
102+
<property name="leftMargin">
103+
<number>0</number>
104+
</property>
105+
<property name="topMargin">
106+
<number>0</number>
107+
</property>
108+
<property name="rightMargin">
109+
<number>0</number>
110+
</property>
111+
<property name="bottomMargin">
111112
<number>0</number>
112113
</property>
114+
<item row="0" column="1">
115+
<widget class="GdalToolsInOutSelector" name="maskSelector" native="true"/>
116+
</item>
113117
<item row="2" column="0">
114-
<spacer name="verticalSpacer">
115-
<property name="orientation">
116-
<enum>Qt::Vertical</enum>
118+
<widget class="QCheckBox" name="cropToCutlineCheck">
119+
<property name="text">
120+
<string>Crop the extent of the target dataset to the extent of the cutline</string>
117121
</property>
118-
<property name="sizeHint" stdset="0">
119-
<size>
120-
<width>20</width>
121-
<height>40</height>
122-
</size>
122+
</widget>
123+
</item>
124+
<item row="1" column="0">
125+
<widget class="QCheckBox" name="alphaBandCheck">
126+
<property name="text">
127+
<string>Create an output alpha band</string>
123128
</property>
124-
</spacer>
129+
</widget>
125130
</item>
126131
<item row="0" column="0">
127132
<widget class="QLabel" name="label">
@@ -130,20 +135,160 @@
130135
</property>
131136
</widget>
132137
</item>
133-
<item row="0" column="1">
134-
<widget class="GdalToolsInOutSelector" name="maskSelector" native="true"/>
138+
<item row="3" column="0" rowspan="5" colspan="2">
139+
<widget class="QGroupBox" name="gridGroupBox">
140+
<layout class="QGridLayout" name="gridLayout_7">
141+
<item row="0" column="1" alignment="Qt::AlignHCenter">
142+
<widget class="QRadioButton" name="setResolutionRadio">
143+
<property name="text">
144+
<string>Set output file resolution</string>
145+
</property>
146+
</widget>
147+
</item>
148+
<item row="1" column="0" colspan="2">
149+
<widget class="QStackedWidget" name="resolutionStackedWidget">
150+
<property name="currentIndex">
151+
<number>1</number>
152+
</property>
153+
<widget class="QWidget" name="page_3"/>
154+
<widget class="QWidget" name="resolutionWidget">
155+
<layout class="QGridLayout" name="gridLayout_5" columnstretch="0,0,0,0,0">
156+
<property name="leftMargin">
157+
<number>9</number>
158+
</property>
159+
<property name="topMargin">
160+
<number>9</number>
161+
</property>
162+
<property name="rightMargin">
163+
<number>9</number>
164+
</property>
165+
<property name="bottomMargin">
166+
<number>9</number>
167+
</property>
168+
<item row="0" column="4">
169+
<widget class="QDoubleSpinBox" name="yRes">
170+
<property name="decimals">
171+
<number>1</number>
172+
</property>
173+
<property name="minimum">
174+
<double>0.100000000000000</double>
175+
</property>
176+
<property name="maximum">
177+
<double>999999.000000000000000</double>
178+
</property>
179+
<property name="singleStep">
180+
<double>0.100000000000000</double>
181+
</property>
182+
<property name="value">
183+
<double>12.500000000000000</double>
184+
</property>
185+
</widget>
186+
</item>
187+
<item row="0" column="2">
188+
<widget class="QDoubleSpinBox" name="xRes">
189+
<property name="decimals">
190+
<number>1</number>
191+
</property>
192+
<property name="minimum">
193+
<double>0.100000000000000</double>
194+
</property>
195+
<property name="maximum">
196+
<double>999999.000000000000000</double>
197+
</property>
198+
<property name="singleStep">
199+
<double>0.100000000000000</double>
200+
</property>
201+
<property name="value">
202+
<double>12.500000000000000</double>
203+
</property>
204+
</widget>
205+
</item>
206+
<item row="0" column="3">
207+
<widget class="QLabel" name="label_5">
208+
<property name="text">
209+
<string>Y Resolution</string>
210+
</property>
211+
<property name="alignment">
212+
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
213+
</property>
214+
</widget>
215+
</item>
216+
<item row="0" column="1">
217+
<widget class="QLabel" name="label_4">
218+
<property name="layoutDirection">
219+
<enum>Qt::LeftToRight</enum>
220+
</property>
221+
<property name="text">
222+
<string>X Resolution</string>
223+
</property>
224+
<property name="alignment">
225+
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
226+
</property>
227+
</widget>
228+
</item>
229+
</layout>
230+
</widget>
231+
</widget>
232+
</item>
233+
<item row="0" column="0" alignment="Qt::AlignHCenter">
234+
<widget class="QRadioButton" name="keepResolutionRadio">
235+
<property name="text">
236+
<string>Keep resolution of input raster</string>
237+
</property>
238+
<property name="checked">
239+
<bool>true</bool>
240+
</property>
241+
</widget>
242+
</item>
243+
</layout>
244+
</widget>
135245
</item>
136-
<item row="1" column="0">
137-
<widget class="QCheckBox" name="alphaBandCheck">
138-
<property name="text">
139-
<string>Create an output alpha band</string>
246+
<item row="10" column="0" colspan="2">
247+
<spacer name="verticalSpacer">
248+
<property name="orientation">
249+
<enum>Qt::Vertical</enum>
140250
</property>
141-
</widget>
251+
<property name="sizeHint" stdset="0">
252+
<size>
253+
<width>20</width>
254+
<height>40</height>
255+
</size>
256+
</property>
257+
</spacer>
142258
</item>
143259
</layout>
144260
</widget>
145261
</widget>
146262
</item>
263+
<item row="0" column="0" colspan="2">
264+
<widget class="QGroupBox" name="groupBox">
265+
<property name="title">
266+
<string/>
267+
</property>
268+
<layout class="QHBoxLayout" name="horizontalLayout">
269+
<item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
270+
<widget class="QRadioButton" name="extentModeRadio">
271+
<property name="text">
272+
<string>Extent</string>
273+
</property>
274+
<property name="checked">
275+
<bool>true</bool>
276+
</property>
277+
</widget>
278+
</item>
279+
<item alignment="Qt::AlignHCenter|Qt::AlignVCenter">
280+
<widget class="QRadioButton" name="maskModeRadio">
281+
<property name="layoutDirection">
282+
<enum>Qt::LeftToRight</enum>
283+
</property>
284+
<property name="text">
285+
<string>Mask layer</string>
286+
</property>
287+
</widget>
288+
</item>
289+
</layout>
290+
</widget>
291+
</item>
147292
</layout>
148293
</widget>
149294
</item>

‎python/plugins/processing/algs/gdal/ClipByMask.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class ClipByMask(GdalAlgorithm):
4646
NO_DATA = 'NO_DATA'
4747
MASK = 'MASK'
4848
ALPHA_BAND = 'ALPHA_BAND'
49+
CROP_TO_CUTLINE = 'CROP_TO_CUTLINE'
4950
KEEP_RESOLUTION = 'KEEP_RESOLUTION'
5051
EXTRA = 'EXTRA'
5152

@@ -60,6 +61,8 @@ def defineCharacteristics(self):
6061
'-9999'))
6162
self.addParameter(ParameterBoolean(self.ALPHA_BAND,
6263
self.tr('Create and output alpha band'), False))
64+
self.addParameter(ParameterBoolean(self.CROP_TO_CUTLINE,
65+
self.tr('Crop the extent of the target dataset to the extent of the cutline'), False))
6366
self.addParameter(ParameterBoolean(self.KEEP_RESOLUTION,
6467
self.tr('Keep resolution of output raster'), False))
6568
self.addParameter(ParameterString(self.EXTRA,
@@ -71,6 +74,7 @@ def getConsoleCommands(self):
7174
mask = self.getParameterValue(self.MASK)
7275
noData = unicode(self.getParameterValue(self.NO_DATA))
7376
addAlphaBand = self.getParameterValue(self.ALPHA_BAND)
77+
cropToCutline = self.getParameterValue(self.CROP_TO_CUTLINE)
7478
keepResolution = self.getParameterValue(self.KEEP_RESOLUTION)
7579
extra = unicode(self.getParameterValue(self.EXTRA))
7680

@@ -93,10 +97,12 @@ def getConsoleCommands(self):
9397

9498
arguments.append('-cutline')
9599
arguments.append(mask)
96-
arguments.append('-crop_to_cutline')
97100

98101
if addAlphaBand:
99102
arguments.append('-dstalpha')
103+
104+
if cropToCutline:
105+
arguments.append('-crop_to_cutline')
100106

101107
if len(extra) > 0:
102108
arguments.append(extra)

0 commit comments

Comments
 (0)
Please sign in to comment.