Skip to content

Commit ba03f1a

Browse files
committed
Move minimum layer extent calculation to c++
1 parent 189f804 commit ba03f1a

File tree

17 files changed

+113
-46
lines changed

17 files changed

+113
-46
lines changed

python/core/processing/qgsprocessingutils.sip

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,12 @@ class QgsProcessingUtils
152152
available in Python bindings as createFeatureSink()
153153
%End
154154

155+
static QgsRectangle combineLayerExtents( const QList< QgsMapLayer *> layers, const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() );
156+
%Docstring
157+
Combines the extent of several map ``layers``. If specified, the target ``crs``
158+
will be used to transform the layer's extent to the desired output reference system.
159+
:rtype: QgsRectangle
160+
%End
155161

156162
};
157163

python/plugins/processing/algs/gdal/ClipByExtent.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ def getConsoleCommands(self, parameters):
8888
noData = self.getParameterValue(self.NO_DATA)
8989
opts = self.getParameterValue(self.OPTIONS)
9090
projwin = self.getParameterValue(self.PROJWIN)
91+
layer = self.getParameterValue(self.INPUT)
92+
if not projwin:
93+
projwin = QgsProcessingUtils.combineLayerExtents([layer])
9194

9295
if noData is not None:
9396
noData = str(noData)

python/plugins/processing/algs/gdal/ogr2ogrclipextent.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ def getConsoleCommands(self, parameters):
6969
inLayer = self.getParameterValue(self.INPUT_LAYER)
7070
ogrLayer = ogrConnectionString(inLayer)[1:-1]
7171
clipExtent = self.getParameterValue(self.CLIP_EXTENT)
72+
if not clipExtent:
73+
clipExtent = QgsProcessingUtils.combineLayerExtents([inLayer])
7274

7375
output = self.getOutputFromName(self.OUTPUT_LAYER)
7476
outFile = output.value

python/plugins/processing/algs/gdal/ogr2ogrtopostgis.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ def getConsoleCommands(self, parameters):
203203
simplify = str(self.getParameterValue(self.SIMPLIFY))
204204
segmentize = str(self.getParameterValue(self.SEGMENTIZE))
205205
spat = self.getParameterValue(self.SPAT)
206+
if not spat:
207+
spat = QgsProcessingUtils.combineLayerExtents([inLayer])
206208
clip = self.getParameterValue(self.CLIP)
207209
where = str(self.getParameterValue(self.WHERE))
208210
wherestring = '-where "' + where + '"'

python/plugins/processing/algs/gdal/ogr2ogrtopostgislist.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ def getConsoleCommands(self, parameters):
205205
simplify = self.getParameterValue(self.SIMPLIFY)
206206
segmentize = self.getParameterValue(self.SEGMENTIZE)
207207
spat = self.getParameterValue(self.SPAT)
208+
if not spat:
209+
spat = QgsProcessingUtils.combineLayerExtents([inLayer])
208210
clip = self.getParameterValue(self.CLIP)
209211
where = self.getParameterValue(self.WHERE)
210212
gt = self.getParameterValue(self.GT)

python/plugins/processing/algs/gdal/rasterize.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ def getConsoleCommands(self, parameters):
106106
inLayer = self.getParameterValue(self.INPUT)
107107
noData = self.getParameterValue(self.NO_DATA)
108108
rastext = str(self.getParameterValue(self.RAST_EXT))
109+
if not rastext:
110+
rastext = QgsProcessingUtils.combineLayerExtents([inLayer])
109111
opts = self.getParameterValue(self.OPTIONS)
110112
out = self.getOutputValue(self.OUTPUT)
111113

python/plugins/processing/algs/gdal/translate.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,15 @@ def group(self):
104104
return self.tr('Raster conversion')
105105

106106
def getConsoleCommands(self, parameters):
107+
inLayer = self.getParameterValue(self.INPUT)
107108
out = self.getOutputValue(translate.OUTPUT)
108109
outsize = str(self.getParameterValue(self.OUTSIZE))
109110
outsizePerc = str(self.getParameterValue(self.OUTSIZE_PERC))
110111
noData = self.getParameterValue(self.NO_DATA)
111112
expand = self.getParameterFromName(self.EXPAND).options[self.getParameterValue(self.EXPAND)][1]
112113
projwin = str(self.getParameterValue(self.PROJWIN))
114+
if not projwin:
115+
projwin = QgsProcessingUtils.combineLayerExtents([inLayer])
113116
crsId = self.getParameterValue(self.SRS)
114117
sds = self.getParameterValue(self.SDS)
115118
opts = self.getParameterValue(self.OPTIONS)

python/plugins/processing/algs/gdal/warp.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,13 @@ def group(self):
122122
return self.tr('Raster projections')
123123

124124
def getConsoleCommands(self, parameters):
125+
inLayer = self.getParameterValue(self.INPUT)
125126
srccrs = self.getParameterValue(self.SOURCE_SRS)
126127
dstcrs = self.getParameterValue(self.DEST_SRS)
127128
useRasterExtent = self.getParameterValue(self.USE_RASTER_EXTENT)
128129
rasterExtent = self.getParameterValue(self.RASTER_EXTENT)
130+
if not rasterExtent:
131+
rasterExtent = QgsProcessingUtils.combineLayerExtents([inLayer])
129132
extentCrs = self.getParameterValue(self.EXTENT_CRS)
130133
opts = self.getParameterValue(self.OPTIONS)
131134
noData = self.getParameterValue(self.NO_DATA)

python/plugins/processing/algs/grass7/Grass7Algorithm.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,9 @@ def processInputs(self):
371371

372372
region = \
373373
str(self.getParameterValue(self.GRASS_REGION_EXTENT_PARAMETER))
374+
if not region:
375+
region = QgsProcessingUtils.combineLayerExtents(layers)
376+
374377
regionCoords = region.split(',')
375378
command = 'g.region'
376379
command += ' n=' + str(regionCoords[3])

python/plugins/processing/algs/grass7/nviz7.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ def processAlgorithm(self, parameters, context, feedback):
102102

103103
region = \
104104
str(self.getParameterValue(self.GRASS_REGION_EXTENT_PARAMETER))
105+
if not region:
106+
region = QgsProcessingUtils.combineLayerExtents(layers)
107+
105108
regionCoords = region.split(',')
106109
command = 'g.region '
107110
command += 'n=' + str(regionCoords[3])

python/plugins/processing/algs/qgis/FindProjection.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ def processAlgorithm(self, parameters, context, feedback):
8787
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)
8888

8989
extent = self.getParameterValue(self.TARGET_AREA).split(',')
90+
if not extent:
91+
extent = QgsProcessingUtils.combineLayerExtents([layer])
9092
target_crs = QgsCoordinateReferenceSystem(self.getParameterValue(self.TARGET_AREA_CRS))
9193

9294
target_geom = QgsGeometry.fromRect(QgsRectangle(float(extent[0]), float(extent[2]),

python/plugins/processing/algs/qgis/RasterCalculator.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ def processAlgorithm(self, parameters, context, feedback):
127127

128128
output = self.getOutputValue(self.OUTPUT)
129129
extentValue = self.getParameterValue(self.EXTENT)
130+
if not extentValue:
131+
extentValue = QgsProcessingUtils.combineLayerExtents(layersValue)
130132

131133
if extentValue:
132134
extent = extentValue.split(',')

python/plugins/processing/algs/saga/SagaAlgorithm.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,10 @@ def processAlgorithm(self, parameters, context, feedback):
204204
raise GeoAlgorithmExecutionException(
205205
self.tr('Unsupported file format'))
206206

207+
# TODO - set minimum extent
208+
if not extent:
209+
extent = QgsProcessingUtils.combineLayerExtents([layer])
210+
207211
# 2: Set parameters and outputs
208212
command = self.undecoratedGroup + ' "' + self.cmdname + '"'
209213
command += ' ' + ' '.join(self.hardcodedStrings)

python/plugins/processing/core/parameters.py

Lines changed: 1 addition & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
from qgis.core import (QgsRasterLayer, QgsVectorLayer, QgsMapLayer, QgsCoordinateReferenceSystem,
4343
QgsExpressionContext, QgsExpressionContextUtils, QgsExpression, QgsExpressionContextScope,
4444
QgsProject,
45+
QgsRectangle,
4546
QgsVectorFileWriter,
4647
QgsProcessingParameterDefinition)
4748

@@ -356,52 +357,6 @@ def fromScriptCode(self, line):
356357
default = definition.strip()[len('extent') + 1:] or None
357358
return ParameterExtent(name, descName, default, isOptional)
358359

359-
def evaluate(self, alg):
360-
if self.flags() & QgsProcessingParameterDefinition.FlagOptional and not bool(self.value):
361-
self.value = self.getMinCoveringExtent(alg)
362-
363-
def getMinCoveringExtent(self, alg):
364-
first = True
365-
found = False
366-
context = dataobjects.createContext()
367-
for param in alg.parameters:
368-
if param.value:
369-
if isinstance(param, (ParameterRaster, ParameterVector)):
370-
if isinstance(param.value, (QgsRasterLayer,
371-
QgsVectorLayer)):
372-
layer = param.value
373-
else:
374-
layer = QgsProcessingUtils.mapLayerFromString(param.value, context)
375-
if layer:
376-
found = True
377-
self.addToRegion(layer, first)
378-
first = False
379-
elif isinstance(param, ParameterMultipleInput):
380-
layers = param.value.split(';')
381-
for layername in layers:
382-
layer = QgsProcessingUtils.mapLayerFromString(layername, context)
383-
if layer:
384-
found = True
385-
self.addToRegion(layer, first)
386-
first = False
387-
if found:
388-
return '{},{},{},{}'.format(
389-
self.xmin, self.xmax, self.ymin, self.ymax)
390-
else:
391-
return None
392-
393-
def addToRegion(self, layer, first):
394-
if first:
395-
self.xmin = layer.extent().xMinimum()
396-
self.xmax = layer.extent().xMaximum()
397-
self.ymin = layer.extent().yMinimum()
398-
self.ymax = layer.extent().yMaximum()
399-
else:
400-
self.xmin = min(self.xmin, layer.extent().xMinimum())
401-
self.xmax = max(self.xmax, layer.extent().xMaximum())
402-
self.ymin = min(self.ymin, layer.extent().yMinimum())
403-
self.ymax = max(self.ymax, layer.extent().yMaximum())
404-
405360

406361
class ParameterPoint(Parameter):
407362

src/core/processing/qgsprocessingutils.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "qgsprocessingutils.h"
1919
#include "qgsproject.h"
2020
#include "qgssettings.h"
21+
#include "qgscsexception.h"
2122
#include "qgsprocessingcontext.h"
2223
#include "qgsvectorlayerexporter.h"
2324
#include "qgsvectorfilewriter.h"
@@ -400,3 +401,37 @@ void QgsProcessingUtils::createFeatureSinkPython( QgsFeatureSink **sink, QString
400401
}
401402

402403

404+
QgsRectangle QgsProcessingUtils::combineLayerExtents( const QList<QgsMapLayer *> layers, const QgsCoordinateReferenceSystem &crs )
405+
{
406+
QgsRectangle extent;
407+
Q_FOREACH ( QgsMapLayer *layer, layers )
408+
{
409+
if ( !layer )
410+
continue;
411+
412+
if ( crs.isValid() )
413+
{
414+
//transform layer extent to target CRS
415+
QgsCoordinateTransform ct( layer->crs(), crs );
416+
try
417+
{
418+
QgsRectangle reprojExtent = ct.transformBoundingBox( layer->extent() );
419+
extent.combineExtentWith( reprojExtent );
420+
}
421+
catch ( QgsCsException & )
422+
{
423+
// can't reproject... what to do here? hmmm?
424+
// let's ignore this layer for now, but maybe we should just use the original extent?
425+
}
426+
}
427+
else
428+
{
429+
extent.combineExtentWith( layer->extent() );
430+
}
431+
432+
}
433+
return extent;
434+
}
435+
436+
437+

src/core/processing/qgsprocessingutils.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,11 @@ class CORE_EXPORT QgsProcessingUtils
180180
const QgsCoordinateReferenceSystem &crs,
181181
QgsProcessingContext &context ) SIP_PYNAME( createFeatureSink );
182182

183+
/**
184+
* Combines the extent of several map \a layers. If specified, the target \a crs
185+
* will be used to transform the layer's extent to the desired output reference system.
186+
*/
187+
static QgsRectangle combineLayerExtents( const QList< QgsMapLayer *> layers, const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() );
183188

184189
private:
185190

tests/src/core/testqgsprocessing.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ class TestQgsProcessing: public QObject
216216
void parameterVectorLayer();
217217
void parameterOutputVectorLayer();
218218
void checkParamValues();
219+
void combineLayerExtent();
219220

220221
private:
221222

@@ -2181,5 +2182,39 @@ void TestQgsProcessing::checkParamValues()
21812182
a.checkParameterVals();
21822183
}
21832184

2185+
void TestQgsProcessing::combineLayerExtent()
2186+
{
2187+
QgsRectangle ext = QgsProcessingUtils::combineLayerExtents( QList< QgsMapLayer *>() );
2188+
QVERIFY( ext.isNull() );
2189+
2190+
QString testDataDir = QStringLiteral( TEST_DATA_DIR ) + '/'; //defined in CmakeLists.txt
2191+
2192+
QString raster1 = testDataDir + "tenbytenraster.asc";
2193+
QString raster2 = testDataDir + "landsat.tif";
2194+
QFileInfo fi1( raster1 );
2195+
QgsRasterLayer *r1 = new QgsRasterLayer( fi1.filePath(), "R1" );
2196+
QFileInfo fi2( raster2 );
2197+
QgsRasterLayer *r2 = new QgsRasterLayer( fi2.filePath(), "R2" );
2198+
2199+
ext = QgsProcessingUtils::combineLayerExtents( QList< QgsMapLayer *>() << r1 );
2200+
QGSCOMPARENEAR( ext.xMinimum(), 1535375.000000, 10 );
2201+
QGSCOMPARENEAR( ext.xMaximum(), 1535475, 10 );
2202+
QGSCOMPARENEAR( ext.yMinimum(), 5083255, 10 );
2203+
QGSCOMPARENEAR( ext.yMaximum(), 5083355, 10 );
2204+
2205+
ext = QgsProcessingUtils::combineLayerExtents( QList< QgsMapLayer *>() << r1 << r2 );
2206+
QGSCOMPARENEAR( ext.xMinimum(), 781662, 10 );
2207+
QGSCOMPARENEAR( ext.xMaximum(), 1535475, 10 );
2208+
QGSCOMPARENEAR( ext.yMinimum(), 3339523, 10 );
2209+
QGSCOMPARENEAR( ext.yMaximum(), 5083355, 10 );
2210+
2211+
// with reprojection
2212+
ext = QgsProcessingUtils::combineLayerExtents( QList< QgsMapLayer *>() << r1 << r2, QgsCoordinateReferenceSystem::fromEpsgId( 3785 ) );
2213+
QGSCOMPARENEAR( ext.xMinimum(), 1995320, 10 );
2214+
QGSCOMPARENEAR( ext.xMaximum(), 2008833, 10 );
2215+
QGSCOMPARENEAR( ext.yMinimum(), 3523084, 10 );
2216+
QGSCOMPARENEAR( ext.yMaximum(), 3536664, 10 );
2217+
}
2218+
21842219
QGSTEST_MAIN( TestQgsProcessing )
21852220
#include "testqgsprocessing.moc"

0 commit comments

Comments
 (0)