18 #include <gdalwarper.h> 
   19 #include <ogr_srs_api.h> 
   30 static double ceil_with_tolerance( 
double value )
 
   32   if ( std::fabs( value - std::round( value ) ) < 1e-6 )
 
   33     return std::round( value );
 
   35     return std::ceil( value );
 
   38 static double floor_with_tolerance( 
double value )
 
   40   if ( std::fabs( value - std::round( value ) ) < 1e-6 )
 
   41     return std::round( value );
 
   43     return std::floor( value );
 
   46 static double fmod_with_tolerance( 
double num, 
double denom )
 
   48   return num - floor_with_tolerance( num / denom ) * denom;
 
   52 static QgsRectangle transform_to_extent( 
const double *geotransform, 
double xSize, 
double ySize )
 
   56                   geotransform[0] + geotransform[1] * xSize,
 
   57                   geotransform[3] + geotransform[5] * ySize );
 
   63 static int CPL_STDCALL _progress( 
double dfComplete, 
const char *pszMessage, 
void *pProgressArg )
 
   65   Q_UNUSED( pszMessage )
 
   69     return handler->
progress( dfComplete );
 
   75 static CPLErr rescalePreWarpChunkProcessor( 
void *pKern, 
void *pArg )
 
   77   GDALWarpKernel *kern = ( GDALWarpKernel * ) pKern;
 
   78   double cellsize = ( ( 
double * )pArg )[0];
 
   80   for ( 
int nBand = 0; nBand < kern->nBands; ++nBand )
 
   82     float *bandData = ( 
float * ) kern->papabySrcImage[nBand];
 
   83     for ( 
int nLine = 0; nLine < kern->nSrcYSize; ++nLine )
 
   85       for ( 
int nPixel = 0; nPixel < kern->nSrcXSize; ++nPixel )
 
   87         bandData[nPixel] /= cellsize;
 
   89       bandData += kern->nSrcXSize;
 
   96 static CPLErr rescalePostWarpChunkProcessor( 
void *pKern, 
void *pArg )
 
   98   GDALWarpKernel *kern = ( GDALWarpKernel * ) pKern;
 
   99   double cellsize = ( ( 
double * )pArg )[1];
 
  101   for ( 
int nBand = 0; nBand < kern->nBands; ++nBand )
 
  103     float *bandData = ( 
float * ) kern->papabyDstImage[nBand];
 
  104     for ( 
int nLine = 0; nLine < kern->nDstYSize; ++nLine )
 
  106       for ( 
int nPixel = 0; nPixel < kern->nDstXSize; ++nPixel )
 
  108         bandData[nPixel] *= cellsize;
 
  110       bandData += kern->nDstXSize;
 
  127   for ( 
int i = 0; i < 6; ++i )
 
  159   if ( customCRSWkt.isEmpty() || customCRSWkt == rasterInfo.
crs() )
 
  164     if ( !customCellSize.isValid() )
 
  175     if ( customGridOffset.x() < 0 || customGridOffset.y() < 0 )
 
  177       if ( !customCellSize.isValid() )
 
  187         mGridOffsetX = fmod_with_tolerance( rasterInfo.
origin().x(), customCellSize.width() );
 
  188         mGridOffsetY = fmod_with_tolerance( rasterInfo.
origin().y(), customCellSize.height() );
 
  203       mCrsWkt = QStringLiteral( 
"_error_" );
 
  211     if ( !customCellSize.isValid() )
 
  222     if ( customGridOffset.x() < 0 || customGridOffset.y() < 0 )
 
  241   if ( 
mCrsWkt == QLatin1String( 
"_error_" ) )
 
  249     mErrorMessage = QObject::tr( 
"Cell size must not be zero." );
 
  256   double finalExtent[4] = { 0, 0, 0, 0 };
 
  259   for ( 
int i = 0; i < 
mRasters.count(); ++i )
 
  269       mErrorMessage = QString( 
"Failed to get suggested warp output.\n\n" 
  271                                "Source WKT:\n%2\n\nDestination WKT:\n%3" )
 
  280     if ( finalExtent[0] == 0 && finalExtent[1] == 0 && finalExtent[2] == 0 && finalExtent[3] == 0 )
 
  291       if ( extent.
xMinimum() > finalExtent[0] ) finalExtent[0] = extent.
xMinimum();
 
  292       if ( extent.
yMinimum() > finalExtent[1] ) finalExtent[1] = extent.
yMinimum();
 
  293       if ( extent.
xMaximum() < finalExtent[2] ) finalExtent[2] = extent.
xMaximum();
 
  294       if ( extent.
yMaximum() < finalExtent[3] ) finalExtent[3] = extent.
yMaximum();
 
  309     if ( clipX0 > finalExtent[0] ) finalExtent[0] = clipX0;
 
  310     if ( clipY0 > finalExtent[1] ) finalExtent[1] = clipY0;
 
  311     if ( clipX1 < finalExtent[2] ) finalExtent[2] = clipX1;
 
  312     if ( clipY1 < finalExtent[3] ) finalExtent[3] = clipY1;
 
  321   int xSize = floor_with_tolerance( ( finalExtent[2] - originX ) / 
mCellSizeX );
 
  322   int ySize = floor_with_tolerance( ( finalExtent[3] - originY ) / 
mCellSizeY );
 
  324   if ( xSize <= 0 || ySize <= 0 )
 
  326     mErrorMessage = QObject::tr( 
"No common intersecting area." );
 
  366   const auto constMRasters = 
mRasters;
 
  367   for ( 
const Item &r : constMRasters )
 
  378   qDebug( 
"---ALIGN------------------" );
 
  379   qDebug( 
"wkt %s", 
mCrsWkt.toLatin1().constData() );
 
  381   qDebug( 
"transform" );
 
  386   qDebug( 
"extent %s", e.
toString().toLatin1().constData() );
 
  392   double bestCellArea = INFINITY;
 
  402   const auto constMRasters = 
mRasters;
 
  403   for ( 
const Item &raster : constMRasters )
 
  408     double cellArea = cs.width() * cs.height();
 
  409     if ( cellArea < bestCellArea )
 
  411       bestCellArea = cellArea;
 
  423   GDALDriverH hDriver = GDALGetDriverByName( 
"GTiff" );
 
  426     mErrorMessage = QStringLiteral( 
"GDALGetDriverByName(GTiff) failed." );
 
  440   int bandCount = GDALGetRasterCount( hSrcDS.get() );
 
  441   GDALDataType eDT = GDALGetRasterDataType( GDALGetRasterBand( hSrcDS.get(), 1 ) );
 
  445                                    bandCount, eDT, 
nullptr ) );
 
  453   GDALSetProjection( hDstDS.get(), 
mCrsWkt.toLatin1().constData() );
 
  457   GDALColorTableH hCT = GDALGetRasterColorTable( GDALGetRasterBand( hSrcDS.get(), 1 ) );
 
  459     GDALSetRasterColorTable( GDALGetRasterBand( hDstDS.get(), 1 ), hCT );
 
  465   psWarpOptions->hSrcDS = hSrcDS.get();
 
  466   psWarpOptions->hDstDS = hDstDS.get();
 
  468   psWarpOptions->nBandCount = GDALGetRasterCount( hSrcDS.get() );
 
  469   psWarpOptions->panSrcBands = ( 
int * ) CPLMalloc( 
sizeof( 
int ) * psWarpOptions->nBandCount );
 
  470   psWarpOptions->panDstBands = ( 
int * ) CPLMalloc( 
sizeof( 
int ) * psWarpOptions->nBandCount );
 
  471   for ( 
int i = 0; i < psWarpOptions->nBandCount; ++i )
 
  473     psWarpOptions->panSrcBands[i] = i + 1;
 
  474     psWarpOptions->panDstBands[i] = i + 1;
 
  477   psWarpOptions->eResampleAlg = 
static_cast< GDALResampleAlg 
>( raster.
resampleMethod );
 
  480   psWarpOptions->pfnProgress = _progress;
 
  481   psWarpOptions->pProgressArg = 
this;
 
  484   psWarpOptions->pTransformerArg =
 
  485     GDALCreateGenImgProjTransformer( hSrcDS.get(), GDALGetProjectionRef( hSrcDS.get() ),
 
  486                                      hDstDS.get(), GDALGetProjectionRef( hDstDS.get() ),
 
  488   psWarpOptions->pfnTransformer = GDALGenImgProjTransform;
 
  490   double rescaleArg[2];
 
  495     psWarpOptions->pfnPreWarpChunkProcessor = rescalePreWarpChunkProcessor;
 
  496     psWarpOptions->pfnPostWarpChunkProcessor = rescalePostWarpChunkProcessor;
 
  497     psWarpOptions->pPreWarpProcessorArg = rescaleArg;
 
  498     psWarpOptions->pPostWarpProcessorArg = rescaleArg;
 
  500     psWarpOptions->eWorkingDataType = GDT_Float32;
 
  504   GDALWarpOperation oOperation;
 
  505   oOperation.Initialize( psWarpOptions.get() );
 
  508   GDALDestroyGenImgProjTransformer( psWarpOptions->pTransformerArg );
 
  518   void *hTransformArg = GDALCreateGenImgProjTransformer( info.
mDataset.get(), info.
mCrsWkt.toLatin1().constData(), 
nullptr, destWkt.toLatin1().constData(), FALSE, 0, 1 );
 
  519   if ( !hTransformArg )
 
  523   double adfDstGeoTransform[6];
 
  525   int nPixels = 0, nLines = 0;
 
  527   eErr = GDALSuggestedWarpOutput2( info.
mDataset.get(),
 
  528                                    GDALGenImgProjTransform, hTransformArg,
 
  529                                    adfDstGeoTransform, &nPixels, &nLines, extents, 0 );
 
  530   GDALDestroyGenImgProjTransformer( hTransformArg );
 
  532   if ( eErr != CE_None )
 
  535   QSizeF cs( std::fabs( adfDstGeoTransform[1] ), std::fabs( adfDstGeoTransform[5] ) );
 
  538     *rect = 
QgsRectangle( extents[0], extents[1], extents[2], extents[3] );
 
  542     *
gridOffset = QPointF( fmod_with_tolerance( adfDstGeoTransform[0], cs.width() ),
 
  543                            fmod_with_tolerance( adfDstGeoTransform[3], cs.height() ) );
 
  553   mDataset.reset( GDALOpen( layerpath.toLocal8Bit().constData(), GA_ReadOnly ) );
 
  563   mCrsWkt = QString::fromLatin1( GDALGetProjectionRef( 
mDataset.get() ) );
 
  591   qDebug( 
"---RASTER INFO------------------" );
 
  592   qDebug( 
"wkt %s", 
mCrsWkt.toLatin1().constData() );
 
  597   qDebug( 
"extent %s", r.
toString().toLatin1().constData() );
 
  599   qDebug( 
"transform" );
 
  606   GDALRasterBandH hBand = GDALGetRasterBand( mDataset.get(), 1 );
 
  612   float *pafScanline = ( 
float * ) CPLMalloc( 
sizeof( 
float ) );
 
  613   CPLErr err = GDALRasterIO( hBand, GF_Read, px, py, 1, 1,
 
  614                              pafScanline, 1, 1, GDT_Float32, 0, 0 );
 
  615   double value = err == CE_None ? pafScanline[0] : std::numeric_limits<double>::quiet_NaN();
 
  616   CPLFree( pafScanline );
 
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).
@ WKT_PREFERRED_GDAL
Preferred format for conversion of CRS to WKT for use with the GDAL library.
QString toWkt(WktVariant variant=WKT1_GDAL, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
A rectangle specified with double values.
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
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.
bool rescaleValues
rescaling of values according to the change of pixel size
QgsAlignRaster::ResampleAlg resampleMethod
resampling method to be used
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.