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