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 const 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 const 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 const int xSize = floor_with_tolerance( ( finalExtent[2] - originX ) /
mCellSizeX );
322 const 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 const 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 const int bandCount = GDALGetRasterCount( hSrcDS.get() );
441 const 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 const 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 const CPLErr err = GDALRasterIO( hBand, GF_Read, px, py, 1, 1,
614 pafScanline, 1, 1, GDT_Float32, 0, 0 );
615 const double value = err == CE_None ? pafScanline[0] : std::numeric_limits<double>::quiet_NaN();
616 CPLFree( pafScanline );