QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
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(
261 "Failed to get suggested warp output.\n\n"
262 "File:\n%1\n\n"
263 "Source WKT:\n%2\n\nDestination WKT:\n%3"
264 )
265 .arg( r.inputFilename, info.mCrsWkt, mCrsWkt );
266 return false;
267 }
268
269 r.srcCellSizeInDestCRS = cs.width() * cs.height();
270
271 if ( finalExtent[0] == 0 && finalExtent[1] == 0 && finalExtent[2] == 0 && finalExtent[3] == 0 )
272 {
273 // initialize with the first layer
274 finalExtent[0] = extent.xMinimum();
275 finalExtent[1] = extent.yMinimum();
276 finalExtent[2] = extent.xMaximum();
277 finalExtent[3] = extent.yMaximum();
278 }
279 else
280 {
281 // use intersection of rects
282 if ( extent.xMinimum() > finalExtent[0] )
283 finalExtent[0] = extent.xMinimum();
284 if ( extent.yMinimum() > finalExtent[1] )
285 finalExtent[1] = extent.yMinimum();
286 if ( extent.xMaximum() < finalExtent[2] )
287 finalExtent[2] = extent.xMaximum();
288 if ( extent.yMaximum() < finalExtent[3] )
289 finalExtent[3] = extent.yMaximum();
290 }
291 }
292
293 // count in extra clip extent (if present)
294 // 1. align requested rect to the grid - extend the rect if necessary
295 // 2. intersect with clip extent with final extent
296
297 if ( !( mClipExtent[0] == 0 && mClipExtent[1] == 0 && mClipExtent[2] == 0 && mClipExtent[3] == 0 ) )
298 {
299 // extend clip extent to grid
300 const double clipX0 = floor_with_tolerance( ( mClipExtent[0] - mGridOffsetX ) / mCellSizeX ) * mCellSizeX + mGridOffsetX;
301 const double clipY0 = floor_with_tolerance( ( mClipExtent[1] - mGridOffsetY ) / mCellSizeY ) * mCellSizeY + mGridOffsetY;
302 const double clipX1 = ceil_with_tolerance( ( mClipExtent[2] - clipX0 ) / mCellSizeX ) * mCellSizeX + clipX0;
303 const double clipY1 = ceil_with_tolerance( ( mClipExtent[3] - clipY0 ) / mCellSizeY ) * mCellSizeY + clipY0;
304 if ( clipX0 > finalExtent[0] )
305 finalExtent[0] = clipX0;
306 if ( clipY0 > finalExtent[1] )
307 finalExtent[1] = clipY0;
308 if ( clipX1 < finalExtent[2] )
309 finalExtent[2] = clipX1;
310 if ( clipY1 < finalExtent[3] )
311 finalExtent[3] = clipY1;
312 }
313
314 // align to grid - shrink the rect if necessary
315 // output raster grid configuration (with no rotation/shear)
316 // ... and raster width/height
317
318 const double originX = ceil_with_tolerance( ( finalExtent[0] - mGridOffsetX ) / mCellSizeX ) * mCellSizeX + mGridOffsetX;
319 const double originY = ceil_with_tolerance( ( finalExtent[1] - mGridOffsetY ) / mCellSizeY ) * mCellSizeY + mGridOffsetY;
320 const int xSize = floor_with_tolerance( ( finalExtent[2] - originX ) / mCellSizeX );
321 const int ySize = floor_with_tolerance( ( finalExtent[3] - originY ) / mCellSizeY );
322
323 if ( xSize <= 0 || ySize <= 0 )
324 {
325 mErrorMessage = QObject::tr( "No common intersecting area." );
326 return false;
327 }
328
329 mXSize = xSize;
330 mYSize = ySize;
331
332 // build final geotransform...
333 mGeoTransform[0] = originX;
335 mGeoTransform[2] = 0;
336 mGeoTransform[3] = originY + ( mCellSizeY * ySize );
337 mGeoTransform[4] = 0;
339
340 return true;
341}
342
343
345{
346 return QSize( mXSize, mYSize );
347}
348
350{
351 return transform_to_extent( mGeoTransform, mXSize, mYSize );
352}
353
354
356{
357 mErrorMessage.clear();
358
359 // consider extent of all layers and setup geotransform and output grid size
360 if ( !checkInputParameters() )
361 return false;
362
363 //dump();
364
365 const auto constMRasters = mRasters;
366 for ( const Item &r : constMRasters )
367 {
368 if ( !createAndWarp( r ) )
369 return false;
370 }
371 return true;
372}
373
374
376{
377 qDebug( "---ALIGN------------------" );
378 qDebug( "wkt %s", mCrsWkt.toLatin1().constData() );
379 qDebug( "w/h %d,%d", mXSize, mYSize );
380 qDebug( "transform" );
381 qDebug( "%6.2f %6.2f %6.2f", mGeoTransform[0], mGeoTransform[1], mGeoTransform[2] );
382 qDebug( "%6.2f %6.2f %6.2f", mGeoTransform[3], mGeoTransform[4], mGeoTransform[5] );
383
384 const QgsRectangle e = transform_to_extent( mGeoTransform, mXSize, mYSize );
385 qDebug( "extent %s", e.toString().toLatin1().constData() );
386}
387
389{
390 int bestIndex = -1;
391 double bestCellArea = INFINITY;
392 QSizeF cs;
393 int i = 0;
394
395 // using WGS84 as a destination CRS... but maybe some projected CRS
396 // would be a better a choice to more accurately compute areas?
397 // (Why earth is not flat???)
398 const QgsCoordinateReferenceSystem destCRS( u"EPSG:4326"_s );
399 const QString destWkt = destCRS.toWkt( Qgis::CrsWktVariant::PreferredGdal );
400
401 const auto constMRasters = mRasters;
402 for ( const Item &raster : constMRasters )
403 {
404 if ( !suggestedWarpOutput( RasterInfo( raster.inputFilename ), destWkt, &cs ) )
405 return false;
406
407 const double cellArea = cs.width() * cs.height();
408 if ( cellArea < bestCellArea )
409 {
410 bestCellArea = cellArea;
411 bestIndex = i;
412 }
413 ++i;
414 }
415
416 return bestIndex;
417}
418
419
421{
422 GDALDriverH hDriver = GDALGetDriverByName( "GTiff" );
423 if ( !hDriver )
424 {
425 mErrorMessage = u"GDALGetDriverByName(GTiff) failed."_s;
426 return false;
427 }
428
429 // Open the source file.
430 const gdal::dataset_unique_ptr hSrcDS( GDALOpen( raster.inputFilename.toUtf8().constData(), GA_ReadOnly ) );
431 if ( !hSrcDS )
432 {
433 mErrorMessage = QObject::tr( "Unable to open input file: %1" ).arg( raster.inputFilename );
434 return false;
435 }
436
437 // Create output with same datatype as first input band.
438
439 const int bandCount = GDALGetRasterCount( hSrcDS.get() );
440 const GDALDataType eDT = GDALGetRasterDataType( GDALGetRasterBand( hSrcDS.get(), 1 ) );
441
442 // Create the output file.
443 const gdal::dataset_unique_ptr hDstDS( GDALCreate( hDriver, raster.outputFilename.toUtf8().constData(), mXSize, mYSize, bandCount, eDT, nullptr ) );
444 if ( !hDstDS )
445 {
446 mErrorMessage = QObject::tr( "Unable to create output file: %1" ).arg( raster.outputFilename );
447 return false;
448 }
449
450 // Write out the projection definition.
451 GDALSetProjection( hDstDS.get(), mCrsWkt.toLatin1().constData() );
452 GDALSetGeoTransform( hDstDS.get(), mGeoTransform );
453
454 // Copy the color table, if required.
455 GDALColorTableH hCT = GDALGetRasterColorTable( GDALGetRasterBand( hSrcDS.get(), 1 ) );
456 if ( hCT )
457 GDALSetRasterColorTable( GDALGetRasterBand( hDstDS.get(), 1 ), hCT );
458
459 // -----------------------------------------------------------------------
460
461 // Setup warp options.
462 gdal::warp_options_unique_ptr psWarpOptions( GDALCreateWarpOptions() );
463 psWarpOptions->hSrcDS = hSrcDS.get();
464 psWarpOptions->hDstDS = hDstDS.get();
465
466 psWarpOptions->nBandCount = GDALGetRasterCount( hSrcDS.get() );
467 psWarpOptions->panSrcBands = ( int * ) CPLMalloc( sizeof( int ) * psWarpOptions->nBandCount );
468 psWarpOptions->panDstBands = ( int * ) CPLMalloc( sizeof( int ) * psWarpOptions->nBandCount );
469 for ( int i = 0; i < psWarpOptions->nBandCount; ++i )
470 {
471 psWarpOptions->panSrcBands[i] = i + 1;
472 psWarpOptions->panDstBands[i] = i + 1;
473 }
474
475 psWarpOptions->eResampleAlg = static_cast<GDALResampleAlg>( raster.resampleMethod );
476
477 // our progress function
478 psWarpOptions->pfnProgress = _progress;
479 psWarpOptions->pProgressArg = this;
480
481 // Establish reprojection transformer.
482 psWarpOptions->pTransformerArg = GDALCreateGenImgProjTransformer( hSrcDS.get(), GDALGetProjectionRef( hSrcDS.get() ), hDstDS.get(), GDALGetProjectionRef( hDstDS.get() ), FALSE, 0.0, 1 );
483 psWarpOptions->pfnTransformer = GDALGenImgProjTransform;
484
485 double rescaleArg[2];
486 if ( raster.rescaleValues )
487 {
488 rescaleArg[0] = raster.srcCellSizeInDestCRS; // source cell size
489 rescaleArg[1] = mCellSizeX * mCellSizeY; // destination cell size
490 psWarpOptions->pfnPreWarpChunkProcessor = rescalePreWarpChunkProcessor;
491 psWarpOptions->pfnPostWarpChunkProcessor = rescalePostWarpChunkProcessor;
492 psWarpOptions->pPreWarpProcessorArg = rescaleArg;
493 psWarpOptions->pPostWarpProcessorArg = rescaleArg;
494 // force use of float32 data type as that is what our pre/post-processor uses
495 psWarpOptions->eWorkingDataType = GDT_Float32;
496 }
497
498 // Initialize and execute the warp operation.
499 GDALWarpOperation oOperation;
500 oOperation.Initialize( psWarpOptions.get() );
501 oOperation.ChunkAndWarpImage( 0, 0, mXSize, mYSize );
502
503 GDALDestroyGenImgProjTransformer( psWarpOptions->pTransformerArg );
504 return true;
505}
506
507bool QgsAlignRaster::suggestedWarpOutput( const QgsAlignRaster::RasterInfo &info, const QString &destWkt, QSizeF *cellSize, QPointF *gridOffset, QgsRectangle *rect )
508{
509 // Create a transformer that maps from source pixel/line coordinates
510 // to destination georeferenced coordinates (not destination
511 // pixel line). We do that by omitting the destination dataset
512 // handle (setting it to nullptr).
513 void *hTransformArg = GDALCreateGenImgProjTransformer( info.mDataset.get(), info.mCrsWkt.toLatin1().constData(), nullptr, destWkt.toLatin1().constData(), FALSE, 0, 1 );
514 if ( !hTransformArg )
515 return false;
516
517 // Get approximate output georeferenced bounds and resolution for file.
518 double adfDstGeoTransform[6];
519 double extents[4];
520 int nPixels = 0, nLines = 0;
521 CPLErr eErr;
522 eErr = GDALSuggestedWarpOutput2( info.mDataset.get(), GDALGenImgProjTransform, hTransformArg, adfDstGeoTransform, &nPixels, &nLines, extents, 0 );
523 GDALDestroyGenImgProjTransformer( hTransformArg );
524
525 if ( eErr != CE_None )
526 return false;
527
528 const QSizeF cs( std::fabs( adfDstGeoTransform[1] ), std::fabs( adfDstGeoTransform[5] ) );
529
530 if ( rect )
531 *rect = QgsRectangle( extents[0], extents[1], extents[2], extents[3] );
532 if ( cellSize )
533 *cellSize = cs;
534 if ( gridOffset )
535 *gridOffset = QPointF( fmod_with_tolerance( adfDstGeoTransform[0], cs.width() ), fmod_with_tolerance( adfDstGeoTransform[3], cs.height() ) );
536 return true;
537}
538
539
540//----------
541
542
543QgsAlignRaster::RasterInfo::RasterInfo( const QString &layerpath )
544{
545 mDataset.reset( GDALOpen( layerpath.toUtf8().constData(), GA_ReadOnly ) );
546 if ( !mDataset )
547 return;
548
549 mXSize = GDALGetRasterXSize( mDataset.get() );
550 mYSize = GDALGetRasterYSize( mDataset.get() );
551
552 ( void ) GDALGetGeoTransform( mDataset.get(), mGeoTransform );
553
554 // TODO: may be null or empty string
555 mCrsWkt = QString::fromLatin1( GDALGetProjectionRef( mDataset.get() ) );
556
557 mBandCnt = GDALGetBandNumber( mDataset.get() );
558}
559
561{
562 return QSizeF( std::fabs( mGeoTransform[1] ), std::fabs( mGeoTransform[5] ) );
563}
564
566{
567 return QPointF( fmod_with_tolerance( mGeoTransform[0], cellSize().width() ), fmod_with_tolerance( mGeoTransform[3], cellSize().height() ) );
568}
569
571{
572 return transform_to_extent( mGeoTransform, mXSize, mYSize );
573}
574
576{
577 return QPointF( mGeoTransform[0], mGeoTransform[3] );
578}
579
581{
582 qDebug( "---RASTER INFO------------------" );
583 qDebug( "wkt %s", mCrsWkt.toLatin1().constData() );
584 qDebug( "w/h %d,%d", mXSize, mYSize );
585 qDebug( "cell x/y %f,%f", cellSize().width(), cellSize().width() );
586
587 const QgsRectangle r = extent();
588 qDebug( "extent %s", r.toString().toLatin1().constData() );
589
590 qDebug( "transform" );
591 qDebug( "%6.2f %6.2f %6.2f", mGeoTransform[0], mGeoTransform[1], mGeoTransform[2] );
592 qDebug( "%6.2f %6.2f %6.2f", mGeoTransform[3], mGeoTransform[4], mGeoTransform[5] );
593}
594
595double QgsAlignRaster::RasterInfo::identify( double mx, double my )
596{
597 GDALRasterBandH hBand = GDALGetRasterBand( mDataset.get(), 1 );
598
599 // must not be rotated in order for this to work
600 const int px = int( ( mx - mGeoTransform[0] ) / mGeoTransform[1] );
601 const int py = int( ( my - mGeoTransform[3] ) / mGeoTransform[5] );
602
603 float *pafScanline = ( float * ) CPLMalloc( sizeof( float ) );
604 const CPLErr err = GDALRasterIO( hBand, GF_Read, px, py, 1, 1, pafScanline, 1, 1, GDT_Float32, 0, 0 );
605 const double value = err == CE_None ? pafScanline[0] : std::numeric_limits<double>::quiet_NaN();
606 CPLFree( pafScanline );
607
608 return value;
609}
@ PreferredGdal
Preferred format for conversion of CRS to WKT for use with the GDAL library.
Definition qgis.h:2530
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 rounded to the spec...
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.