QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
qgsalignraster.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalignraster.cpp
3 --------------------------------------
4 Date : June 2015
5 Copyright : (C) 2015 by Martin Dobias
6 Email : wonder dot sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgsalignraster.h"
17
18#include <cpl_conv.h>
19#include <gdalwarper.h>
20#include <limits>
21#include <ogr_srs_api.h>
22
24#include "qgsrectangle.h"
25
26#include <QPair>
27#include <QString>
28
29static double ceil_with_tolerance( double value )
30{
31 if ( std::fabs( value - std::round( value ) ) < 1e-6 )
32 return std::round( value );
33 else
34 return std::ceil( value );
35}
36
37static double floor_with_tolerance( double value )
38{
39 if ( std::fabs( value - std::round( value ) ) < 1e-6 )
40 return std::round( value );
41 else
42 return std::floor( value );
43}
44
45static double fmod_with_tolerance( double num, double denom )
46{
47 return num - floor_with_tolerance( num / denom ) * denom;
48}
49
50static QgsRectangle transform_to_extent( const double *geotransform, double xSize, double ySize )
51{
52 QgsRectangle r( geotransform[0], geotransform[3], geotransform[0] + geotransform[1] * xSize, geotransform[3] + geotransform[5] * ySize );
53 r.normalize();
54 return r;
55}
56
57static int CPL_STDCALL _progress( double dfComplete, const char *pszMessage, void *pProgressArg )
58{
59 Q_UNUSED( pszMessage )
60
61 QgsAlignRaster::ProgressHandler *handler = ( ( QgsAlignRaster * ) pProgressArg )->progressHandler();
62 if ( handler )
63 return handler->progress( dfComplete );
64 else
65 return true;
66}
67
68static CPLErr rescalePreWarpChunkProcessor( void *pKern, void *pArg )
69{
70 GDALWarpKernel *kern = ( GDALWarpKernel * ) pKern;
71 const double cellsize = ( ( double * ) pArg )[0];
72
73 for ( int nBand = 0; nBand < kern->nBands; ++nBand )
74 {
75 float *bandData = ( float * ) kern->papabySrcImage[nBand];
76 for ( int nLine = 0; nLine < kern->nSrcYSize; ++nLine )
77 {
78 for ( int nPixel = 0; nPixel < kern->nSrcXSize; ++nPixel )
79 {
80 bandData[nPixel] /= cellsize;
81 }
82 bandData += kern->nSrcXSize;
83 }
84 }
85 return CE_None;
86}
87
88static CPLErr rescalePostWarpChunkProcessor( void *pKern, void *pArg )
89{
90 GDALWarpKernel *kern = ( GDALWarpKernel * ) pKern;
91 const double cellsize = ( ( double * ) pArg )[1];
92
93 for ( int nBand = 0; nBand < kern->nBands; ++nBand )
94 {
95 float *bandData = ( float * ) kern->papabyDstImage[nBand];
96 for ( int nLine = 0; nLine < kern->nDstYSize; ++nLine )
97 {
98 for ( int nPixel = 0; nPixel < kern->nDstXSize; ++nPixel )
99 {
100 bandData[nPixel] *= cellsize;
101 }
102 bandData += kern->nDstXSize;
103 }
104 }
105 return CE_None;
106}
107
108
110{
111 // parameters
114 mClipExtent[0] = mClipExtent[1] = mClipExtent[2] = mClipExtent[3] = 0;
115
116 // derived variables
117 mXSize = mYSize = 0;
118 for ( int i = 0; i < 6; ++i )
119 mGeoTransform[i] = 0;
120}
121
122void QgsAlignRaster::setClipExtent( double xmin, double ymin, double xmax, double ymax )
123{
124 mClipExtent[0] = xmin;
125 mClipExtent[1] = ymin;
126 mClipExtent[2] = xmax;
127 mClipExtent[3] = ymax;
128}
129
131{
132 setClipExtent( extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum() );
133}
134
139
140
141bool QgsAlignRaster::setParametersFromRaster( const QString &filename, const QString &destWkt, QSizeF customCellSize, QPointF customGridOffset )
142{
143 return setParametersFromRaster( RasterInfo( filename ), destWkt, customCellSize, customGridOffset );
144}
145
146bool QgsAlignRaster::setParametersFromRaster( const RasterInfo &rasterInfo, const QString &customCRSWkt, QSizeF customCellSize, QPointF customGridOffset )
147{
148 if ( customCRSWkt.isEmpty() || customCRSWkt == rasterInfo.crs() )
149 {
150 // use ref. layer to init input
151 mCrsWkt = rasterInfo.crs();
152
153 if ( !customCellSize.isValid() )
154 {
155 mCellSizeX = rasterInfo.cellSize().width();
156 mCellSizeY = rasterInfo.cellSize().height();
157 }
158 else
159 {
160 mCellSizeX = customCellSize.width();
161 mCellSizeY = customCellSize.height();
162 }
163
164 if ( customGridOffset.x() < 0 || customGridOffset.y() < 0 )
165 {
166 if ( !customCellSize.isValid() )
167 {
168 // using original raster's grid offset to be aligned with origin
169 mGridOffsetX = rasterInfo.gridOffset().x();
170 mGridOffsetY = rasterInfo.gridOffset().y();
171 }
172 else
173 {
174 // if using custom cell size: offset so that we are aligned
175 // with the original raster's origin point
176 mGridOffsetX = fmod_with_tolerance( rasterInfo.origin().x(), customCellSize.width() );
177 mGridOffsetY = fmod_with_tolerance( rasterInfo.origin().y(), customCellSize.height() );
178 }
179 }
180 else
181 {
182 mGridOffsetX = customGridOffset.x();
183 mGridOffsetY = customGridOffset.y();
184 }
185 }
186 else
187 {
188 QSizeF cs;
189 QPointF go;
190 if ( !suggestedWarpOutput( rasterInfo, customCRSWkt, &cs, &go ) )
191 {
192 mCrsWkt = QStringLiteral( "_error_" );
195 return false;
196 }
197
198 mCrsWkt = customCRSWkt;
199
200 if ( !customCellSize.isValid() )
201 {
202 mCellSizeX = cs.width();
203 mCellSizeY = cs.height();
204 }
205 else
206 {
207 mCellSizeX = customCellSize.width();
208 mCellSizeY = customCellSize.height();
209 }
210
211 if ( customGridOffset.x() < 0 || customGridOffset.y() < 0 )
212 {
213 mGridOffsetX = go.x();
214 mGridOffsetY = go.y();
215 }
216 else
217 {
218 mGridOffsetX = customGridOffset.x();
219 mGridOffsetY = customGridOffset.x();
220 }
221 }
222 return true;
223}
224
225
227{
228 mErrorMessage.clear();
229
230 if ( mCrsWkt == QLatin1String( "_error_" ) )
231 {
232 mErrorMessage = QObject::tr( "Unable to reproject." );
233 return false;
234 }
235
236 if ( mCellSizeX == 0 || mCellSizeY == 0 )
237 {
238 mErrorMessage = QObject::tr( "Cell size must not be zero." );
239 return false;
240 }
241
242 mXSize = mYSize = 0;
243 std::fill_n( mGeoTransform, 6, 0 );
244
245 double finalExtent[4] = { 0, 0, 0, 0 };
246
247 // for each raster: determine their extent in projected cfg
248 for ( int i = 0; i < mRasters.count(); ++i )
249 {
250 Item &r = mRasters[i];
251
252 const RasterInfo info( r.inputFilename );
253
254 QSizeF cs;
255 QgsRectangle extent;
256 if ( !suggestedWarpOutput( info, mCrsWkt, &cs, nullptr, &extent ) )
257 {
258 mErrorMessage = QString( "Failed to get suggested warp output.\n\n"
259 "File:\n%1\n\n"
260 "Source WKT:\n%2\n\nDestination WKT:\n%3" )
261 .arg( r.inputFilename, info.mCrsWkt, mCrsWkt );
262 return false;
263 }
264
265 r.srcCellSizeInDestCRS = cs.width() * cs.height();
266
267 if ( finalExtent[0] == 0 && finalExtent[1] == 0 && finalExtent[2] == 0 && finalExtent[3] == 0 )
268 {
269 // initialize with the first layer
270 finalExtent[0] = extent.xMinimum();
271 finalExtent[1] = extent.yMinimum();
272 finalExtent[2] = extent.xMaximum();
273 finalExtent[3] = extent.yMaximum();
274 }
275 else
276 {
277 // use intersection of rects
278 if ( extent.xMinimum() > finalExtent[0] )
279 finalExtent[0] = extent.xMinimum();
280 if ( extent.yMinimum() > finalExtent[1] )
281 finalExtent[1] = extent.yMinimum();
282 if ( extent.xMaximum() < finalExtent[2] )
283 finalExtent[2] = extent.xMaximum();
284 if ( extent.yMaximum() < finalExtent[3] )
285 finalExtent[3] = extent.yMaximum();
286 }
287 }
288
289 // count in extra clip extent (if present)
290 // 1. align requested rect to the grid - extend the rect if necessary
291 // 2. intersect with clip extent with final extent
292
293 if ( !( mClipExtent[0] == 0 && mClipExtent[1] == 0 && mClipExtent[2] == 0 && mClipExtent[3] == 0 ) )
294 {
295 // extend clip extent to grid
296 const double clipX0 = floor_with_tolerance( ( mClipExtent[0] - mGridOffsetX ) / mCellSizeX ) * mCellSizeX + mGridOffsetX;
297 const double clipY0 = floor_with_tolerance( ( mClipExtent[1] - mGridOffsetY ) / mCellSizeY ) * mCellSizeY + mGridOffsetY;
298 const double clipX1 = ceil_with_tolerance( ( mClipExtent[2] - clipX0 ) / mCellSizeX ) * mCellSizeX + clipX0;
299 const double clipY1 = ceil_with_tolerance( ( mClipExtent[3] - clipY0 ) / mCellSizeY ) * mCellSizeY + clipY0;
300 if ( clipX0 > finalExtent[0] )
301 finalExtent[0] = clipX0;
302 if ( clipY0 > finalExtent[1] )
303 finalExtent[1] = clipY0;
304 if ( clipX1 < finalExtent[2] )
305 finalExtent[2] = clipX1;
306 if ( clipY1 < finalExtent[3] )
307 finalExtent[3] = clipY1;
308 }
309
310 // align to grid - shrink the rect if necessary
311 // output raster grid configuration (with no rotation/shear)
312 // ... and raster width/height
313
314 const double originX = ceil_with_tolerance( ( finalExtent[0] - mGridOffsetX ) / mCellSizeX ) * mCellSizeX + mGridOffsetX;
315 const double originY = ceil_with_tolerance( ( finalExtent[1] - mGridOffsetY ) / mCellSizeY ) * mCellSizeY + mGridOffsetY;
316 const int xSize = floor_with_tolerance( ( finalExtent[2] - originX ) / mCellSizeX );
317 const int ySize = floor_with_tolerance( ( finalExtent[3] - originY ) / mCellSizeY );
318
319 if ( xSize <= 0 || ySize <= 0 )
320 {
321 mErrorMessage = QObject::tr( "No common intersecting area." );
322 return false;
323 }
324
325 mXSize = xSize;
326 mYSize = ySize;
327
328 // build final geotransform...
329 mGeoTransform[0] = originX;
331 mGeoTransform[2] = 0;
332 mGeoTransform[3] = originY + ( mCellSizeY * ySize );
333 mGeoTransform[4] = 0;
335
336 return true;
337}
338
339
341{
342 return QSize( mXSize, mYSize );
343}
344
346{
347 return transform_to_extent( mGeoTransform, mXSize, mYSize );
348}
349
350
352{
353 mErrorMessage.clear();
354
355 // consider extent of all layers and setup geotransform and output grid size
356 if ( !checkInputParameters() )
357 return false;
358
359 //dump();
360
361 const auto constMRasters = mRasters;
362 for ( const Item &r : constMRasters )
363 {
364 if ( !createAndWarp( r ) )
365 return false;
366 }
367 return true;
368}
369
370
372{
373 qDebug( "---ALIGN------------------" );
374 qDebug( "wkt %s", mCrsWkt.toLatin1().constData() );
375 qDebug( "w/h %d,%d", mXSize, mYSize );
376 qDebug( "transform" );
377 qDebug( "%6.2f %6.2f %6.2f", mGeoTransform[0], mGeoTransform[1], mGeoTransform[2] );
378 qDebug( "%6.2f %6.2f %6.2f", mGeoTransform[3], mGeoTransform[4], mGeoTransform[5] );
379
380 const QgsRectangle e = transform_to_extent( mGeoTransform, mXSize, mYSize );
381 qDebug( "extent %s", e.toString().toLatin1().constData() );
382}
383
385{
386 int bestIndex = -1;
387 double bestCellArea = INFINITY;
388 QSizeF cs;
389 int i = 0;
390
391 // using WGS84 as a destination CRS... but maybe some projected CRS
392 // would be a better a choice to more accurately compute areas?
393 // (Why earth is not flat???)
394 const QgsCoordinateReferenceSystem destCRS( QStringLiteral( "EPSG:4326" ) );
395 const QString destWkt = destCRS.toWkt( Qgis::CrsWktVariant::PreferredGdal );
396
397 const auto constMRasters = mRasters;
398 for ( const Item &raster : constMRasters )
399 {
400 if ( !suggestedWarpOutput( RasterInfo( raster.inputFilename ), destWkt, &cs ) )
401 return false;
402
403 const double cellArea = cs.width() * cs.height();
404 if ( cellArea < bestCellArea )
405 {
406 bestCellArea = cellArea;
407 bestIndex = i;
408 }
409 ++i;
410 }
411
412 return bestIndex;
413}
414
415
417{
418 GDALDriverH hDriver = GDALGetDriverByName( "GTiff" );
419 if ( !hDriver )
420 {
421 mErrorMessage = QStringLiteral( "GDALGetDriverByName(GTiff) failed." );
422 return false;
423 }
424
425 // Open the source file.
426 const gdal::dataset_unique_ptr hSrcDS( GDALOpen( raster.inputFilename.toUtf8().constData(), GA_ReadOnly ) );
427 if ( !hSrcDS )
428 {
429 mErrorMessage = QObject::tr( "Unable to open input file: %1" ).arg( raster.inputFilename );
430 return false;
431 }
432
433 // Create output with same datatype as first input band.
434
435 const int bandCount = GDALGetRasterCount( hSrcDS.get() );
436 const GDALDataType eDT = GDALGetRasterDataType( GDALGetRasterBand( hSrcDS.get(), 1 ) );
437
438 // Create the output file.
439 const gdal::dataset_unique_ptr hDstDS( GDALCreate( hDriver, raster.outputFilename.toUtf8().constData(), mXSize, mYSize, bandCount, eDT, nullptr ) );
440 if ( !hDstDS )
441 {
442 mErrorMessage = QObject::tr( "Unable to create output file: %1" ).arg( raster.outputFilename );
443 return false;
444 }
445
446 // Write out the projection definition.
447 GDALSetProjection( hDstDS.get(), mCrsWkt.toLatin1().constData() );
448 GDALSetGeoTransform( hDstDS.get(), mGeoTransform );
449
450 // Copy the color table, if required.
451 GDALColorTableH hCT = GDALGetRasterColorTable( GDALGetRasterBand( hSrcDS.get(), 1 ) );
452 if ( hCT )
453 GDALSetRasterColorTable( GDALGetRasterBand( hDstDS.get(), 1 ), hCT );
454
455 // -----------------------------------------------------------------------
456
457 // Setup warp options.
458 gdal::warp_options_unique_ptr psWarpOptions( GDALCreateWarpOptions() );
459 psWarpOptions->hSrcDS = hSrcDS.get();
460 psWarpOptions->hDstDS = hDstDS.get();
461
462 psWarpOptions->nBandCount = GDALGetRasterCount( hSrcDS.get() );
463 psWarpOptions->panSrcBands = ( int * ) CPLMalloc( sizeof( int ) * psWarpOptions->nBandCount );
464 psWarpOptions->panDstBands = ( int * ) CPLMalloc( sizeof( int ) * psWarpOptions->nBandCount );
465 for ( int i = 0; i < psWarpOptions->nBandCount; ++i )
466 {
467 psWarpOptions->panSrcBands[i] = i + 1;
468 psWarpOptions->panDstBands[i] = i + 1;
469 }
470
471 psWarpOptions->eResampleAlg = static_cast<GDALResampleAlg>( raster.resampleMethod );
472
473 // our progress function
474 psWarpOptions->pfnProgress = _progress;
475 psWarpOptions->pProgressArg = this;
476
477 // Establish reprojection transformer.
478 psWarpOptions->pTransformerArg = GDALCreateGenImgProjTransformer( hSrcDS.get(), GDALGetProjectionRef( hSrcDS.get() ), hDstDS.get(), GDALGetProjectionRef( hDstDS.get() ), FALSE, 0.0, 1 );
479 psWarpOptions->pfnTransformer = GDALGenImgProjTransform;
480
481 double rescaleArg[2];
482 if ( raster.rescaleValues )
483 {
484 rescaleArg[0] = raster.srcCellSizeInDestCRS; // source cell size
485 rescaleArg[1] = mCellSizeX * mCellSizeY; // destination cell size
486 psWarpOptions->pfnPreWarpChunkProcessor = rescalePreWarpChunkProcessor;
487 psWarpOptions->pfnPostWarpChunkProcessor = rescalePostWarpChunkProcessor;
488 psWarpOptions->pPreWarpProcessorArg = rescaleArg;
489 psWarpOptions->pPostWarpProcessorArg = rescaleArg;
490 // force use of float32 data type as that is what our pre/post-processor uses
491 psWarpOptions->eWorkingDataType = GDT_Float32;
492 }
493
494 // Initialize and execute the warp operation.
495 GDALWarpOperation oOperation;
496 oOperation.Initialize( psWarpOptions.get() );
497 oOperation.ChunkAndWarpImage( 0, 0, mXSize, mYSize );
498
499 GDALDestroyGenImgProjTransformer( psWarpOptions->pTransformerArg );
500 return true;
501}
502
503bool QgsAlignRaster::suggestedWarpOutput( const QgsAlignRaster::RasterInfo &info, const QString &destWkt, QSizeF *cellSize, QPointF *gridOffset, QgsRectangle *rect )
504{
505 // Create a transformer that maps from source pixel/line coordinates
506 // to destination georeferenced coordinates (not destination
507 // pixel line). We do that by omitting the destination dataset
508 // handle (setting it to nullptr).
509 void *hTransformArg = GDALCreateGenImgProjTransformer( info.mDataset.get(), info.mCrsWkt.toLatin1().constData(), nullptr, destWkt.toLatin1().constData(), FALSE, 0, 1 );
510 if ( !hTransformArg )
511 return false;
512
513 // Get approximate output georeferenced bounds and resolution for file.
514 double adfDstGeoTransform[6];
515 double extents[4];
516 int nPixels = 0, nLines = 0;
517 CPLErr eErr;
518 eErr = GDALSuggestedWarpOutput2( info.mDataset.get(), GDALGenImgProjTransform, hTransformArg, adfDstGeoTransform, &nPixels, &nLines, extents, 0 );
519 GDALDestroyGenImgProjTransformer( hTransformArg );
520
521 if ( eErr != CE_None )
522 return false;
523
524 const QSizeF cs( std::fabs( adfDstGeoTransform[1] ), std::fabs( adfDstGeoTransform[5] ) );
525
526 if ( rect )
527 *rect = QgsRectangle( extents[0], extents[1], extents[2], extents[3] );
528 if ( cellSize )
529 *cellSize = cs;
530 if ( gridOffset )
531 *gridOffset = QPointF( fmod_with_tolerance( adfDstGeoTransform[0], cs.width() ), fmod_with_tolerance( adfDstGeoTransform[3], cs.height() ) );
532 return true;
533}
534
535
536//----------
537
538
539QgsAlignRaster::RasterInfo::RasterInfo( const QString &layerpath )
540{
541 mDataset.reset( GDALOpen( layerpath.toUtf8().constData(), GA_ReadOnly ) );
542 if ( !mDataset )
543 return;
544
545 mXSize = GDALGetRasterXSize( mDataset.get() );
546 mYSize = GDALGetRasterYSize( mDataset.get() );
547
548 ( void ) GDALGetGeoTransform( mDataset.get(), mGeoTransform );
549
550 // TODO: may be null or empty string
551 mCrsWkt = QString::fromLatin1( GDALGetProjectionRef( mDataset.get() ) );
552
553 mBandCnt = GDALGetBandNumber( mDataset.get() );
554}
555
557{
558 return QSizeF( std::fabs( mGeoTransform[1] ), std::fabs( mGeoTransform[5] ) );
559}
560
562{
563 return QPointF( fmod_with_tolerance( mGeoTransform[0], cellSize().width() ), fmod_with_tolerance( mGeoTransform[3], cellSize().height() ) );
564}
565
567{
568 return transform_to_extent( mGeoTransform, mXSize, mYSize );
569}
570
572{
573 return QPointF( mGeoTransform[0], mGeoTransform[3] );
574}
575
577{
578 qDebug( "---RASTER INFO------------------" );
579 qDebug( "wkt %s", mCrsWkt.toLatin1().constData() );
580 qDebug( "w/h %d,%d", mXSize, mYSize );
581 qDebug( "cell x/y %f,%f", cellSize().width(), cellSize().width() );
582
583 const QgsRectangle r = extent();
584 qDebug( "extent %s", r.toString().toLatin1().constData() );
585
586 qDebug( "transform" );
587 qDebug( "%6.2f %6.2f %6.2f", mGeoTransform[0], mGeoTransform[1], mGeoTransform[2] );
588 qDebug( "%6.2f %6.2f %6.2f", mGeoTransform[3], mGeoTransform[4], mGeoTransform[5] );
589}
590
591double QgsAlignRaster::RasterInfo::identify( double mx, double my )
592{
593 GDALRasterBandH hBand = GDALGetRasterBand( mDataset.get(), 1 );
594
595 // must not be rotated in order for this to work
596 const int px = int( ( mx - mGeoTransform[0] ) / mGeoTransform[1] );
597 const int py = int( ( my - mGeoTransform[3] ) / mGeoTransform[5] );
598
599 float *pafScanline = ( float * ) CPLMalloc( sizeof( float ) );
600 const CPLErr err = GDALRasterIO( hBand, GF_Read, px, py, 1, 1, pafScanline, 1, 1, GDT_Float32, 0, 0 );
601 const double value = err == CE_None ? pafScanline[0] : std::numeric_limits<double>::quiet_NaN();
602 CPLFree( pafScanline );
603
604 return value;
605}
@ PreferredGdal
Preferred format for conversion of CRS to WKT for use with the GDAL library.
Definition qgis.h:2441
Takes one or more raster layers and warps (resamples) them to a common grid.
void dump() const
write contents of the object to standard error stream - for debugging
int mYSize
Computed raster grid height.
bool setParametersFromRaster(const RasterInfo &rasterInfo, const QString &customCRSWkt=QString(), QSizeF customCellSize=QSizeF(), QPointF customGridOffset=QPointF(-1, -1))
Set destination CRS, cell size and grid offset from a raster file.
QSizeF cellSize() const
Gets output cell size.
QgsRectangle clipExtent() const
Gets clipping extent (region of interest).
QPointF gridOffset() const
double mGridOffsetX
Destination grid offset - expected to be in interval <0,cellsize).
QgsRectangle alignedRasterExtent() const
Returns the expected extent of the resulting aligned raster.
bool run()
Run the alignment process.
double mClipExtent[4]
Optional clip extent: sets "requested area" which be extended to fit the raster grid.
List mRasters
List of rasters to be aligned (with their output files and other options).
bool createAndWarp(const Item &raster)
Internal function for processing of one raster (1. create output, 2. do the alignment).
QString mCrsWkt
Destination CRS - stored in well-known text (WKT) format.
void setClipExtent(double xmin, double ymin, double xmax, double ymax)
Configure clipping extent (region of interest).
int mXSize
Computed raster grid width.
int suggestedReferenceLayer() const
Returns the index of the layer which has smallest cell size (returns -1 on error).
bool checkInputParameters()
Determine destination extent from the input rasters and calculate derived values.
double mCellSizeX
Destination cell size.
double mGeoTransform[6]
Computed geo-transform.
QgsAlignRasterData::RasterItem Item
static bool suggestedWarpOutput(const RasterInfo &info, const QString &destWkt, QSizeF *cellSize=nullptr, QPointF *gridOffset=nullptr, QgsRectangle *rect=nullptr)
Determine suggested output of raster warp to a different CRS. Returns true on success.
QSize alignedRasterSize() const
Returns the expected size of the resulting aligned raster.
QString mErrorMessage
Last error message from run().
Represents a coordinate reference system (CRS).
QString toWkt(Qgis::CrsWktVariant variant=Qgis::CrsWktVariant::Wkt1Gdal, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
A rectangle specified with double values.
Q_INVOKABLE QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
double xMinimum
double yMinimum
double xMaximum
double yMaximum
std::unique_ptr< GDALWarpOptions, GDALWarpOptionsDeleter > warp_options_unique_ptr
Scoped GDAL warp options.
std::unique_ptr< std::remove_pointer< GDALDatasetH >::type, GDALDatasetCloser > dataset_unique_ptr
Scoped GDAL dataset.
Qgis::GdalResampleAlgorithm resampleMethod
resampling method to be used
bool rescaleValues
rescaling of values according to the change of pixel size
double srcCellSizeInDestCRS
used for rescaling of values (if necessary)
QString inputFilename
filename of the source raster
QString outputFilename
filename of the newly created aligned raster (will be overwritten if exists already)
Helper struct to be sub-classed for progress reporting.
virtual bool progress(double complete)=0
Method to be overridden for progress reporting.
Utility class for gathering information about rasters.
QString crs() const
Returns the CRS in WKT format.
int mYSize
raster grid size Y
gdal::dataset_unique_ptr mDataset
handle to open GDAL dataset
void dump() const
Write contents of the object to standard error stream - for debugging.
RasterInfo(const QString &layerpath)
Construct raster info with a path to a raster file.
double mGeoTransform[6]
geotransform coefficients
QgsRectangle extent() const
Returns the extent of the raster.
QPointF gridOffset() const
Returns the grid offset.
QSizeF cellSize() const
Returns the cell size in map units.
double identify(double mx, double my)
Gets raster value at the given coordinates (from the first band).
int mXSize
raster grid size X
QPointF origin() const
Returns the origin of the raster.
int mBandCnt
number of raster's bands
QString mCrsWkt
CRS stored in WKT format.