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;
400 QString destWkt = destCRS.
toWkt();
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() );
506 oOperation.ChunkAndWarpImage( 0, 0,
mXSize, mYSize );
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 ) );
557 mXSize = GDALGetRasterXSize( mDataset.get() );
558 mYSize = GDALGetRasterYSize( mDataset.get() );
560 ( void ) GDALGetGeoTransform( mDataset.get(),
mGeoTransform );
563 mCrsWkt = QString::fromLatin1( GDALGetProjectionRef( mDataset.get() ) );
565 mBandCnt = GDALGetBandNumber( 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 );
A rectangle specified with double values.
double mCellSizeX
Destination cell size.
QgsRectangle extent() const
Returns the extent of the raster.
double mGridOffsetX
Destination grid offset - expected to be in interval <0,cellsize)
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.
gdal::dataset_unique_ptr mDataset
handle to open GDAL dataset
bool rescaleValues
rescaling of values according to the change of pixel size
double identify(double mx, double my)
Gets raster value at the given coordinates (from the first band)
List mRasters
List of rasters to be aligned (with their output files and other options)
QSizeF cellSize() const
Returns the cell size in map units.
bool run()
Run the alignment process.
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.
virtual bool progress(double complete)=0
Method to be overridden for progress reporting.
std::unique_ptr< GDALWarpOptions, GDALWarpOptionsDeleter > warp_options_unique_ptr
Scoped GDAL warp options.
QgsRectangle alignedRasterExtent() const
Returns the expected extent of the resulting aligned raster.
QPointF origin() const
Returns the origin of the raster.
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) ...
int mYSize
Computed raster grid height.
QString crs() const
Returns the CRS in WKT format.
QSize alignedRasterSize() const
Returns the expected size of the resulting aligned raster.
Definition of one raster layer for alignment.
bool checkInputParameters()
Determine destination extent from the input rasters and calculate derived values. ...
QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be truncated to the sp...
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)
QPointF gridOffset() const
Returns the grid offset.
QString mCrsWkt
CRS stored in WKT format.
void dump() const
write contents of the object to standard error stream - for debugging
int mXSize
Computed raster grid width.
void dump() const
Write contents of the object to standard error stream - for debugging.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double xMaximum() const
Returns the x maximum value (right side of rectangle).
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.
This class represents a coordinate reference system (CRS).
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
int suggestedReferenceLayer() const
Returns the index of the layer which has smallest cell size (returns -1 on error) ...
QString mErrorMessage
Last error message from run()
std::unique_ptr< std::remove_pointer< GDALDatasetH >::type, GDALDatasetCloser > dataset_unique_ptr
Scoped GDAL dataset.
QgsAlignRaster::ResampleAlg resampleMethod
resampling method to be used
QString inputFilename
filename of the source raster
QgsRectangle clipExtent() const
Gets clipping extent (region of interest).
double mGeoTransform[6]
Computed geo-transform.
Utility class for gathering information about rasters.
QString mCrsWkt
Destination CRS - stored in well-known text (WKT) format.
QPointF gridOffset() const
QString toWkt(WktVariant variant=WKT1_GDAL, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
bool createAndWarp(const Item &raster)
Internal function for processing of one raster (1. create output, 2. do the alignment) ...
QSizeF cellSize() const
Gets output cell size.