Skip to content

Commit d3b4786

Browse files
author
brushtyler
committedApr 15, 2011
add cutline option to clipper to fix #3066
git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@15712 c8812cc2-4d05-0410-92ff-de0c093fc19c

File tree

5 files changed

+224
-62
lines changed

5 files changed

+224
-62
lines changed
 

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

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
# -*- coding: utf-8 -*-
22

33
# Utility functions
4-
# -------------------------------------------------
5-
# getLastUsedDir()
6-
# setLastUsedDir( QString *file_or_dir path )
7-
# -------------------------------------------------
84

95
from PyQt4.QtCore import *
106
from PyQt4.QtGui import *
@@ -137,27 +133,31 @@ def removeAllLayers(self):
137133
LayerRegistry.layers = []
138134
self.emit( SIGNAL( "layersChanged" ) )
139135

136+
@classmethod
137+
def isRaster(self, layer):
138+
# only gdal raster layers
139+
if layer.type() != layer.RasterLayer:
140+
return False
141+
if layer.usesProvider() and layer.providerKey() != 'gdal':
142+
return False
143+
return True
144+
140145
def getRasterLayers(self):
141-
layers = []
142-
names = []
146+
layers = filter( self.isRaster, LayerRegistry.layers )
147+
names = map( lambda x: x.name(), layers )
148+
return ( layers, names )
143149

144-
for layer in LayerRegistry.layers:
145-
# only gdal raster layers
146-
if layer.type() == layer.RasterLayer:
147-
if layer.usesProvider() and layer.providerKey() != 'gdal':
148-
continue
149-
layers.append(layer)
150-
names.append(layer.name())
151-
return (layers, names)
150+
@classmethod
151+
def isVector(self, layer):
152+
if layer.type() != layer.VectorLayer:
153+
return False
154+
return True
152155

153156
def getVectorLayers(self):
154-
layers = []
155-
names = []
156-
for layer in LayerRegistry.layers:
157-
if layer.type() == layer.VectorLayer:
158-
layers.append(layer)
159-
names.append(layer.name())
160-
return (layers, names)
157+
layers = filter( self.isVector, LayerRegistry.layers )
158+
names = map( lambda x: x.name(), layers )
159+
return ( layers, names )
160+
161161

162162
def getRasterFiles(path, recursive=False):
163163
rasters = QStringList()
@@ -271,6 +271,30 @@ def getRasterSRS( parent, fileName ):
271271
srs = info[ 0 ] + ":" + info[ 1 ]
272272
return srs
273273

274+
def getRasterExtent(parent, fileName):
275+
processSRS = QProcess( parent )
276+
processSRS.start( "gdalinfo", QStringList() << fileName, QIODevice.ReadOnly )
277+
arr = QByteArray()
278+
if processSRS.waitForFinished():
279+
arr = processSRS.readAllStandardOutput()
280+
processSRS.close()
281+
282+
if arr.isEmpty():
283+
return
284+
285+
info = QString( arr ).split( "\n" )
286+
ulCoord = info[ info.indexOf( QRegExp( "^Upper\sLeft.*" ) ) ].simplified()
287+
lrCoord = info[ info.indexOf( QRegExp( "^Lower\sRight.*" ) ) ].simplified()
288+
ulCoord = ulCoord[ulCoord.indexOf( "(" ) + 1 : ulCoord.indexOf( ")" ) - 1].split( "," )
289+
lrCoord = lrCoord[lrCoord.indexOf( "(" ) + 1 : lrCoord.indexOf( ")" ) - 1].split( "," )
290+
xUL = ulCoord[0].toDouble()[0]
291+
yUL = ulCoord[1].toDouble()[0]
292+
xLR = lrCoord[0].toDouble()[0]
293+
yLR = lrCoord[1].toDouble()[0]
294+
295+
return QgsRectangle( xUL, yLR, xLR, yUL )
296+
297+
274298
# This class is used to replace the QFileDialog class.
275299
# Its static methods are used in place of the respective QFileDialog ones to:
276300
# 1. set the last used directory

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ def __init__(self, parent, iface, pluginBase, pluginName, pluginCommand):
3737
self.connect(self.process, SIGNAL("finished(int, QProcess::ExitStatus)"), self.processFinished)
3838

3939
self.setupUi(self)
40+
self.arguments = QStringList()
4041

4142
self.connect(self.buttonBox, SIGNAL("rejected()"), self.reject)
4243
self.connect(self.buttonBox, SIGNAL("accepted()"), self.accept)
@@ -51,19 +52,19 @@ def __init__(self, parent, iface, pluginBase, pluginName, pluginCommand):
5152
self.plugin.setFocus()
5253

5354
self.setWindowTitle(pluginName)
55+
self.setPluginCommand(pluginCommand)
5456

57+
def setPluginCommand(self, cmd):
5558
# on Windows replace the .py with .bat extension
56-
if platform.system() == "Windows" and pluginCommand[-3:] == ".py":
57-
self.command = pluginCommand[:-3] + ".bat"
59+
if platform.system() == "Windows" and cmd[-3:] == ".py":
60+
self.command = cmd[:-3] + ".bat"
5861
else:
59-
self.command = pluginCommand
62+
self.command = cmd
6063

61-
if pluginCommand[-3:] == ".py":
62-
self.helpFileName = pluginCommand[:-3] + ".html"
64+
if cmd[-3:] == ".py":
65+
self.helpFileName = cmd[:-3] + ".html"
6366
else:
64-
self.helpFileName = pluginCommand + ".html"
65-
66-
self.arguments = QStringList()
67+
self.helpFileName = cmd + ".html"
6768

6869
def reject(self):
6970
if self.process.state() != QProcess.NotRunning:

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

Lines changed: 79 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,34 +20,56 @@ def __init__(self, iface):
2020

2121
self.extentSelector.setCanvas(self.canvas)
2222
self.outputFormat = Utils.fillRasterOutputFormat()
23+
self.layers = []
24+
self.maskLayers = []
2325

2426
self.setParamsStatus(
2527
[
2628
(self.inputLayerCombo, [SIGNAL("currentIndexChanged(int)"), SIGNAL("editTextChanged(const QString &)")] ),
2729
(self.outputFileEdit, SIGNAL("textChanged(const QString &)")),
28-
(self.noDataSpin, SIGNAL("valueChanged(int)"), self.noDataCheck),
29-
( self.extentSelector, [SIGNAL("selectionStarted()"), SIGNAL("newExtentDefined()")] )
30+
(self.noDataSpin, SIGNAL("valueChanged(int)"), self.noDataCheck, "1.7.0"),
31+
(self.maskLayerCombo, [SIGNAL("currentIndexChanged(int)"), SIGNAL("editTextChanged(const QString &)")], self.maskModeRadio, "1.6.0"),
32+
( self.extentSelector, [SIGNAL("selectionStarted()"), SIGNAL("newExtentDefined()")] ),
33+
(self.modeStackedWidget, SIGNAL("currentIndexChanged(int)"))
3034
]
3135
)
3236

3337
self.connect(self.selectInputFileButton, SIGNAL("clicked()"), self.fillInputFileEdit)
3438
self.connect(self.selectOutputFileButton, SIGNAL("clicked()"), self.fillOutputFileEdit)
39+
self.connect(self.selectMaskFileButton, SIGNAL("clicked()"), self.fillMaskFileEdit)
3540
self.connect(self.extentSelector, SIGNAL("newExtentDefined()"), self.checkRun)
3641
self.connect(self.extentSelector, SIGNAL("selectionStarted()"), self.checkRun)
3742

43+
self.connect(self.extentModeRadio, SIGNAL("toggled(bool)"), self.switchClippingMode)
44+
3845
def show_(self):
39-
self.extentSelector.start()
46+
self.switchClippingMode()
4047
BasePluginWidget.show_(self)
4148

4249
def onClosing(self):
4350
self.extentSelector.stop()
4451
BasePluginWidget.onClosing(self)
4552

53+
def switchClippingMode(self):
54+
if self.extentModeRadio.isChecked():
55+
index = 0
56+
self.extentSelector.start()
57+
else:
58+
self.extentSelector.stop()
59+
index = 1
60+
self.modeStackedWidget.setCurrentIndex( index )
61+
self.checkRun()
62+
4663
def checkRun(self):
47-
self.base.enableRun( self.extentSelector.getExtent() != None )
64+
if self.extentModeRadio.isChecked():
65+
enabler = self.extentSelector.isCoordsValid()
66+
else:
67+
enabler = not self.getMaskFileName().isEmpty()
68+
self.base.enableRun( enabler )
4869

4970
def onLayersChanged(self):
5071
self.fillInputLayerCombo()
72+
self.fillMaskLayerCombo()
5173

5274
def fillInputLayerCombo(self):
5375
self.inputLayerCombo.clear()
@@ -74,26 +96,73 @@ def fillOutputFileEdit(self):
7496
self.outputFormat = Utils.fillRasterOutputFormat(lastUsedFilter, outputFile)
7597
self.outputFileEdit.setText(outputFile)
7698

99+
def fillMaskLayerCombo(self):
100+
self.maskLayerCombo.clear()
101+
self.maskLayers = filter( lambda x: x.geometryType() == QGis.Polygon, Utils.LayerRegistry.instance().getVectorLayers()[0] )
102+
self.maskLayerCombo.addItems( map( lambda x: x.name(), self.maskLayers ) )
103+
self.checkRun()
104+
105+
def fillMaskFileEdit( self ):
106+
lastUsedFilter = Utils.FileFilter.lastUsedVectorFilter()
107+
maskFile = Utils.FileDialog.getOpenFileName(self, self.tr( "Select the mask file" ), Utils.FileFilter.allVectorsFilter(), lastUsedFilter )
108+
if maskFile.isEmpty():
109+
return
110+
Utils.FileFilter.setLastUsedVectorFilter(lastUsedFilter)
111+
112+
self.maskLayerCombo.setCurrentIndex(-1)
113+
self.maskLayerCombo.setEditText( maskFile )
114+
self.checkRun()
115+
77116
def getArguments(self):
117+
if not self.extentModeRadio.isChecked():
118+
return self.getArgsModeMask()
119+
return self.getArgsModeExtent()
120+
121+
def getArgsModeExtent(self):
122+
self.base.setPluginCommand( "gdal_translate" )
78123
arguments = QStringList()
79124
if self.noDataCheck.isChecked():
80125
arguments << "-a_nodata"
81126
arguments << str(self.noDataSpin.value())
82-
if self.extentSelector.isCoordsValid():
127+
if self.extentModeRadio.isChecked() and self.extentSelector.isCoordsValid():
83128
rect = self.extentSelector.getExtent()
84129
if rect != None:
85130
arguments << "-projwin"
86131
arguments << str(rect.xMinimum())
87132
arguments << str(rect.yMaximum())
88133
arguments << str(rect.xMaximum())
89134
arguments << str(rect.yMinimum())
135+
if Utils.GdalConfig.version() >= "1.7.0":
136+
arguments << "-q"
90137
if not self.getOutputFileName().isEmpty():
91138
arguments << "-of"
92139
arguments << self.outputFormat
93140
arguments << self.getInputFileName()
94141
arguments << self.getOutputFileName()
95142
return arguments
96143

144+
def getArgsModeMask(self):
145+
self.base.setPluginCommand( "gdalwarp" )
146+
arguments = QStringList()
147+
if self.noDataCheck.isChecked():
148+
arguments << "-dstnodata"
149+
arguments << str(self.noDataSpin.value())
150+
if self.maskModeRadio.isChecked():
151+
mask = self.getMaskFileName()
152+
if not mask.isEmpty():
153+
arguments << "-q"
154+
arguments << "-cutline"
155+
arguments << mask
156+
arguments << "-dstalpha"
157+
158+
outputFn = self.getOutputFileName()
159+
if not outputFn.isEmpty():
160+
arguments << "-of"
161+
arguments << self.outputFormat
162+
arguments << self.getInputFileName()
163+
arguments << outputFn
164+
return arguments
165+
97166
def getOutputFileName(self):
98167
return self.outputFileEdit.text()
99168

@@ -102,6 +171,11 @@ def getInputFileName(self):
102171
return self.layers[self.inputLayerCombo.currentIndex()].source()
103172
return self.inputLayerCombo.currentText()
104173

174+
def getMaskFileName(self):
175+
if self.maskLayerCombo.currentIndex() >= 0:
176+
return self.maskLayers[self.maskLayerCombo.currentIndex()].source()
177+
return self.maskLayerCombo.currentText()
178+
105179
def addLayerIntoCanvas(self, fileInfo):
106180
self.iface.addRasterLayer(fileInfo.filePath())
107181

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

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -110,41 +110,19 @@ def getOutputFileName(self):
110110
def addLayerIntoCanvas(self, fileInfo):
111111
self.iface.addRasterLayer(fileInfo.filePath())
112112

113-
def getRectangle( self, file ):
114-
processSRS = QProcess( self )
115-
processSRS.start( "gdalinfo", QStringList() << file, QIODevice.ReadOnly )
116-
arr = QByteArray()
117-
if processSRS.waitForFinished():
118-
arr = processSRS.readAllStandardOutput()
119-
processSRS.close()
120-
121-
if arr.isEmpty():
122-
return None
123-
124-
info = QString( arr ).split( "\n" )
125-
ulCoord = info[ info.indexOf( QRegExp( "^Upper\sLeft.*" ) ) ].simplified()
126-
lrCoord = info[ info.indexOf( QRegExp( "^Lower\sRight.*" ) ) ].simplified()
127-
ulCoord = ulCoord[ulCoord.indexOf( "(" ) + 1 : ulCoord.indexOf( ")" ) - 1].split( "," )
128-
lrCoord = lrCoord[lrCoord.indexOf( "(" ) + 1 : lrCoord.indexOf( ")" ) - 1].split( "," )
129-
xUL = ulCoord[0].toDouble()[0]
130-
yUL = ulCoord[1].toDouble()[0]
131-
xLR = lrCoord[0].toDouble()[0]
132-
yLR = lrCoord[1].toDouble()[0]
133-
134-
return QgsRectangle( xUL, yLR, xLR, yUL )
135-
136113
def getExtent( self ):
137114
files = self.inputFilesEdit.text().split( "," )
138115

139116
i = 0
140117
res = rect2 = None
141118
for fileName in files:
142119
if res == None:
143-
res = self.getRectangle( fileName )
120+
res = Utils.getRasterExtent( self, fileName )
144121
continue
145-
rect2 = self.getRectangle( fileName )
122+
rect2 = Utils.getRasterExtent( self, fileName )
146123
if rect2 == None:
147124
continue
148125
res = res.intersect( rect2 )
149126

150127
return res
128+

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

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<x>0</x>
88
<y>0</y>
99
<width>338</width>
10-
<height>172</height>
10+
<height>227</height>
1111
</rect>
1212
</property>
1313
<property name="sizePolicy">
@@ -109,11 +109,96 @@
109109
<item>
110110
<widget class="QGroupBox" name="extentGroup">
111111
<property name="title">
112-
<string>Extent</string>
112+
<string>Clipping mode</string>
113113
</property>
114114
<layout class="QGridLayout" name="gridLayout_2">
115115
<item row="0" column="0">
116-
<widget class="GdalToolsExtentSelector" name="extentSelector" native="true"/>
116+
<widget class="QRadioButton" name="extentModeRadio">
117+
<property name="text">
118+
<string>Extent</string>
119+
</property>
120+
<property name="checked">
121+
<bool>true</bool>
122+
</property>
123+
</widget>
124+
</item>
125+
<item row="0" column="1">
126+
<widget class="QRadioButton" name="maskModeRadio">
127+
<property name="text">
128+
<string>Mask layer</string>
129+
</property>
130+
</widget>
131+
</item>
132+
<item row="1" column="0" colspan="2">
133+
<widget class="QStackedWidget" name="modeStackedWidget">
134+
<property name="currentIndex">
135+
<number>0</number>
136+
</property>
137+
<widget class="QWidget" name="page">
138+
<layout class="QGridLayout" name="gridLayout_3">
139+
<property name="margin">
140+
<number>0</number>
141+
</property>
142+
<item row="0" column="0">
143+
<widget class="GdalToolsExtentSelector" name="extentSelector" native="true"/>
144+
</item>
145+
</layout>
146+
</widget>
147+
<widget class="QWidget" name="page_2">
148+
<layout class="QGridLayout" name="gridLayout_4">
149+
<property name="margin">
150+
<number>0</number>
151+
</property>
152+
<item row="0" column="1">
153+
<layout class="QHBoxLayout" name="horizontalLayout_5">
154+
<item>
155+
<widget class="QComboBox" name="maskLayerCombo">
156+
<property name="sizePolicy">
157+
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
158+
<horstretch>0</horstretch>
159+
<verstretch>0</verstretch>
160+
</sizepolicy>
161+
</property>
162+
<property name="editable">
163+
<bool>true</bool>
164+
</property>
165+
<property name="insertPolicy">
166+
<enum>QComboBox::NoInsert</enum>
167+
</property>
168+
</widget>
169+
</item>
170+
<item>
171+
<widget class="QPushButton" name="selectMaskFileButton">
172+
<property name="text">
173+
<string>Select...</string>
174+
</property>
175+
</widget>
176+
</item>
177+
</layout>
178+
</item>
179+
<item row="1" column="0">
180+
<spacer name="verticalSpacer">
181+
<property name="orientation">
182+
<enum>Qt::Vertical</enum>
183+
</property>
184+
<property name="sizeHint" stdset="0">
185+
<size>
186+
<width>20</width>
187+
<height>40</height>
188+
</size>
189+
</property>
190+
</spacer>
191+
</item>
192+
<item row="0" column="0">
193+
<widget class="QLabel" name="label">
194+
<property name="text">
195+
<string>Mask layer</string>
196+
</property>
197+
</widget>
198+
</item>
199+
</layout>
200+
</widget>
201+
</widget>
117202
</item>
118203
</layout>
119204
</widget>

0 commit comments

Comments
 (0)
Please sign in to comment.