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