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