Skip to content

Commit

Permalink
Merge pull request #8550 from elpaso/bugfix-20583-19760-raster-calcul…
Browse files Browse the repository at this point in the history
…ator

Raster calculator crash and hang fixes. Fixes #20583 #19760
  • Loading branch information
elpaso committed Nov 28, 2018
2 parents c5549be + b3ed482 commit e2a2aec
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 26 deletions.
2 changes: 2 additions & 0 deletions src/app/qgisapp.cpp
Expand Up @@ -5689,6 +5689,7 @@ void QgisApp::showRasterCalculator()
QgsFeedback feedback;
connect( &feedback, &QgsFeedback::progressChanged, &p, &QProgressDialog::setValue );
connect( &p, &QProgressDialog::canceled, &feedback, &QgsFeedback::cancel );
p.show();
QgsRasterCalculator::Result res = static_cast< QgsRasterCalculator::Result >( rc.processCalculation( &feedback ) );
switch ( res )
{
Expand Down Expand Up @@ -5735,6 +5736,7 @@ void QgisApp::showRasterCalculator()
Qgis::Critical );
break;
}
p.hide();
}
}

Expand Down
62 changes: 36 additions & 26 deletions src/providers/gdal/qgsgdalprovider.cpp
Expand Up @@ -659,7 +659,7 @@ QgsRasterBlock *QgsGdalProvider::block( int bandNo, const QgsRectangle &extent,
return block;
}

void QgsGdalProvider::readBlock( int bandNo, int xBlock, int yBlock, void *block )
void QgsGdalProvider::readBlock( int bandNo, int xBlock, int yBlock, void *data )
{
QMutexLocker locker( mpMutex );
if ( !initIfNeeded() )
Expand All @@ -677,25 +677,25 @@ void QgsGdalProvider::readBlock( int bandNo, int xBlock, int yBlock, void *block
// We have to read with correct data type consistent with other readBlock functions
int xOff = xBlock * mXBlockSize;
int yOff = yBlock * mYBlockSize;
gdalRasterIO( myGdalBand, GF_Read, xOff, yOff, mXBlockSize, mYBlockSize, block, mXBlockSize, mYBlockSize, ( GDALDataType ) mGdalDataType.at( bandNo - 1 ), 0, 0 );
gdalRasterIO( myGdalBand, GF_Read, xOff, yOff, mXBlockSize, mYBlockSize, data, mXBlockSize, mYBlockSize, ( GDALDataType ) mGdalDataType.at( bandNo - 1 ), 0, 0 );
}

void QgsGdalProvider::readBlock( int bandNo, QgsRectangle const &extent, int pixelWidth, int pixelHeight, void *block, QgsRasterBlockFeedback *feedback )
void QgsGdalProvider::readBlock( int bandNo, QgsRectangle const &extent, int pixelWidth, int pixelHeight, void *data, QgsRasterBlockFeedback *feedback )
{
QMutexLocker locker( mpMutex );
if ( !initIfNeeded() )
return;

QgsDebugMsgLevel( "thePixelWidth = " + QString::number( pixelWidth ), 5 );
QgsDebugMsgLevel( "thePixelHeight = " + QString::number( pixelHeight ), 5 );
QgsDebugMsgLevel( "theExtent: " + extent.toString(), 5 );
QgsDebugMsgLevel( "pixelWidth = " + QString::number( pixelWidth ), 5 );
QgsDebugMsgLevel( "pixelHeight = " + QString::number( pixelHeight ), 5 );
QgsDebugMsgLevel( "extent: " + extent.toString(), 5 );

for ( int i = 0; i < 6; i++ )
{
QgsDebugMsgLevel( QStringLiteral( "transform : %1" ).arg( mGeoTransform[i] ), 5 );
}

int dataSize = dataTypeSize( bandNo );
size_t dataSize = static_cast<size_t>( dataTypeSize( bandNo ) );

// moved to block()
#if 0
Expand All @@ -713,14 +713,14 @@ void QgsGdalProvider::readBlock( int bandNo, QgsRectangle const &extent, int pi
}
#endif

QgsRectangle myRasterExtent = extent.intersect( mExtent );
if ( myRasterExtent.isEmpty() )
QgsRectangle rasterExtent = extent.intersect( mExtent );
if ( rasterExtent.isEmpty() )
{
QgsDebugMsg( QStringLiteral( "draw request outside view extent." ) );
return;
}
QgsDebugMsgLevel( "mExtent: " + mExtent.toString(), 5 );
QgsDebugMsgLevel( "myRasterExtent: " + myRasterExtent.toString(), 5 );
QgsDebugMsgLevel( "extent: " + mExtent.toString(), 5 );
QgsDebugMsgLevel( "rasterExtent: " + rasterExtent.toString(), 5 );

double xRes = extent.width() / pixelWidth;
double yRes = extent.height() / pixelHeight;
Expand Down Expand Up @@ -751,7 +751,7 @@ void QgsGdalProvider::readBlock( int bandNo, QgsRectangle const &extent, int pi
right = std::round( ( myRasterExtent.xMaximum() - extent.xMinimum() ) / xRes ) - 1;
}
#endif
QRect subRect = QgsRasterBlock::subRect( extent, pixelWidth, pixelHeight, myRasterExtent );
QRect subRect = QgsRasterBlock::subRect( extent, pixelWidth, pixelHeight, rasterExtent );
int top = subRect.top();
int bottom = subRect.bottom();
int left = subRect.left();
Expand Down Expand Up @@ -804,23 +804,23 @@ void QgsGdalProvider::readBlock( int bandNo, QgsRectangle const &extent, int pi
// another resampling here which appeares to be quite fast

// Get necessary src extent aligned to src resolution
if ( mExtent.xMinimum() < myRasterExtent.xMinimum() )
if ( mExtent.xMinimum() < rasterExtent.xMinimum() )
{
srcLeft = static_cast<int>( std::floor( ( myRasterExtent.xMinimum() - mExtent.xMinimum() ) / srcXRes ) );
srcLeft = static_cast<int>( std::floor( ( rasterExtent.xMinimum() - mExtent.xMinimum() ) / srcXRes ) );
}
if ( mExtent.xMaximum() > myRasterExtent.xMaximum() )
if ( mExtent.xMaximum() > rasterExtent.xMaximum() )
{
srcRight = static_cast<int>( std::floor( ( myRasterExtent.xMaximum() - mExtent.xMinimum() ) / srcXRes ) );
srcRight = static_cast<int>( std::floor( ( rasterExtent.xMaximum() - mExtent.xMinimum() ) / srcXRes ) );
}

// GDAL states that mGeoTransform[3] is top, may it also be bottom and mGeoTransform[5] positive?
if ( mExtent.yMaximum() > myRasterExtent.yMaximum() )
if ( mExtent.yMaximum() > rasterExtent.yMaximum() )
{
srcTop = static_cast<int>( std::floor( -1. * ( mExtent.yMaximum() - myRasterExtent.yMaximum() ) / srcYRes ) );
srcTop = static_cast<int>( std::floor( -1. * ( mExtent.yMaximum() - rasterExtent.yMaximum() ) / srcYRes ) );
}
if ( mExtent.yMinimum() < myRasterExtent.yMinimum() )
if ( mExtent.yMinimum() < rasterExtent.yMinimum() )
{
srcBottom = static_cast<int>( std::floor( -1. * ( mExtent.yMaximum() - myRasterExtent.yMinimum() ) / srcYRes ) );
srcBottom = static_cast<int>( std::floor( -1. * ( mExtent.yMaximum() - rasterExtent.yMinimum() ) / srcYRes ) );
}

QgsDebugMsgLevel( QStringLiteral( "srcTop = %1 srcBottom = %2 srcLeft = %3 srcRight = %4" ).arg( srcTop ).arg( srcBottom ).arg( srcLeft ).arg( srcRight ), 5 );
Expand All @@ -847,19 +847,29 @@ void QgsGdalProvider::readBlock( int bandNo, QgsRectangle const &extent, int pi
QgsDebugMsgLevel( QStringLiteral( "tmpXMin = %1 tmpYMax = %2 tmpWidth = %3 tmpHeight = %4" ).arg( tmpXMin ).arg( tmpYMax ).arg( tmpWidth ).arg( tmpHeight ), 5 );

// Allocate temporary block
char *tmpBlock = ( char * )qgsMalloc( dataSize * tmpWidth * tmpHeight );
size_t bufferSize = dataSize * static_cast<size_t>( tmpWidth ) * static_cast<size_t>( tmpHeight );
#ifdef Q_PROCESSOR_X86_32
// Safety check for 32 bit systems
qint64 _buffer_size = dataSize * static_cast<qint64>( tmpWidth ) * static_cast<qint64>( tmpHeight );
if ( _buffer_size != static_cast<qint64>( bufferSize ) )
{
QgsDebugMsg( QStringLiteral( "Integer overflow calculating buffer size on a 32 bit system." ) );
return;
}
#endif
char *tmpBlock = static_cast<char *>( qgsMalloc( bufferSize ) );
if ( ! tmpBlock )
{
QgsDebugMsgLevel( QStringLiteral( "Couldn't allocate temporary buffer of %1 bytes" ).arg( dataSize * tmpWidth * tmpHeight ), 5 );
return;
}
GDALRasterBandH gdalBand = getBand( bandNo );
GDALDataType type = ( GDALDataType )mGdalDataType.at( bandNo - 1 );
GDALDataType type = static_cast<GDALDataType>( mGdalDataType.at( bandNo - 1 ) );
CPLErrorReset();

CPLErr err = gdalRasterIO( gdalBand, GF_Read,
srcLeft, srcTop, srcWidth, srcHeight,
( void * )tmpBlock,
static_cast<void *>( tmpBlock ),
tmpWidth, tmpHeight, type,
0, 0, feedback );

Expand All @@ -873,15 +883,15 @@ void QgsGdalProvider::readBlock( int bandNo, QgsRectangle const &extent, int pi
double tmpXRes = srcWidth * srcXRes / tmpWidth;
double tmpYRes = srcHeight * srcYRes / tmpHeight; // negative

double y = myRasterExtent.yMaximum() - 0.5 * yRes;
double y = rasterExtent.yMaximum() - 0.5 * yRes;
for ( int row = 0; row < height; row++ )
{
int tmpRow = static_cast<int>( std::floor( -1. * ( tmpYMax - y ) / tmpYRes ) );

char *srcRowBlock = tmpBlock + dataSize * tmpRow * tmpWidth;
char *dstRowBlock = ( char * )block + dataSize * ( top + row ) * pixelWidth;
char *dstRowBlock = ( char * )data + dataSize * ( top + row ) * pixelWidth;

double x = ( myRasterExtent.xMinimum() + 0.5 * xRes - tmpXMin ) / tmpXRes; // cell center
double x = ( rasterExtent.xMinimum() + 0.5 * xRes - tmpXMin ) / tmpXRes; // cell center
double increment = xRes / tmpXRes;

char *dst = dstRowBlock + dataSize * left;
Expand Down

0 comments on commit e2a2aec

Please sign in to comment.