Skip to content
Permalink
Browse files
Don't crash collecting stats when band is not valid
unreported

Cherry-picked from master 6039ded.
  • Loading branch information
elpaso authored and nyalldawson committed Nov 1, 2021
1 parent 25aaacf commit d6f67c63833c9bcf1fd499bb6284adc9972cacf4
Showing with 100 additions and 96 deletions.
  1. +100 −96 src/core/raster/qgspalettedrasterrenderer.cpp
@@ -476,135 +476,139 @@ QgsPalettedRasterRenderer::ClassData QgsPalettedRasterRenderer::classDataFromRas
return ClassData();

ClassData data;
qlonglong numClasses = 0;

if ( feedback )
feedback->setProgress( 0 );

// Collect unique values for float rasters
if ( raster->dataType( bandNumber ) == Qgis::DataType::Float32 || raster->dataType( bandNumber ) == Qgis::DataType::Float64 )
if ( bandNumber > 0 && bandNumber <= raster->bandCount() )
{
qlonglong numClasses = 0;

if ( feedback && feedback->isCanceled() )
{
return data;
}
if ( feedback )
feedback->setProgress( 0 );

std::set<double> values;
// Collect unique values for float rasters
if ( raster->dataType( bandNumber ) == Qgis::DataType::Float32 || raster->dataType( bandNumber ) == Qgis::DataType::Float64 )
{

int maxWidth = QgsRasterIterator::DEFAULT_MAXIMUM_TILE_WIDTH;
int maxHeight = QgsRasterIterator::DEFAULT_MAXIMUM_TILE_HEIGHT;
if ( feedback && feedback->isCanceled() )
{
return data;
}

QgsRasterIterator iter( raster );
iter.startRasterRead( bandNumber, raster->xSize(), raster->ySize(), raster->extent(), feedback );
std::set<double> values;

int nbBlocksWidth = static_cast< int >( std::ceil( 1.0 * raster->xSize() / maxWidth ) );
int nbBlocksHeight = static_cast< int >( std::ceil( 1.0 * raster->ySize() / maxHeight ) );
int nbBlocks = nbBlocksWidth * nbBlocksHeight;
const int maxWidth = QgsRasterIterator::DEFAULT_MAXIMUM_TILE_WIDTH;
const int maxHeight = QgsRasterIterator::DEFAULT_MAXIMUM_TILE_HEIGHT;

int iterLeft = 0;
int iterTop = 0;
int iterCols = 0;
int iterRows = 0;
std::unique_ptr< QgsRasterBlock > rasterBlock;
QgsRectangle blockExtent;
bool isNoData = false;
while ( iter.readNextRasterPart( bandNumber, iterCols, iterRows, rasterBlock, iterLeft, iterTop, &blockExtent ) )
{
if ( feedback )
feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
QgsRasterIterator iter( raster );
iter.startRasterRead( bandNumber, raster->xSize(), raster->ySize(), raster->extent(), feedback );

if ( feedback && feedback->isCanceled() )
break;
const int nbBlocksWidth = static_cast< int >( std::ceil( 1.0 * raster->xSize() / maxWidth ) );
const int nbBlocksHeight = static_cast< int >( std::ceil( 1.0 * raster->ySize() / maxHeight ) );
const int nbBlocks = nbBlocksWidth * nbBlocksHeight;

for ( int row = 0; row < iterRows; row++ )
int iterLeft = 0;
int iterTop = 0;
int iterCols = 0;
int iterRows = 0;
std::unique_ptr< QgsRasterBlock > rasterBlock;
QgsRectangle blockExtent;
bool isNoData = false;
while ( iter.readNextRasterPart( bandNumber, iterCols, iterRows, rasterBlock, iterLeft, iterTop, &blockExtent ) )
{
if ( feedback )
feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );

if ( feedback && feedback->isCanceled() )
break;

for ( int column = 0; column < iterCols; column++ )
for ( int row = 0; row < iterRows; row++ )
{
if ( feedback && feedback->isCanceled() )
break;

const double currentValue = rasterBlock->valueAndNoData( row, column, isNoData );
if ( numClasses >= MAX_FLOAT_CLASSES )
{
QgsMessageLog::logMessage( QStringLiteral( "Number of classes exceeded maximum (%1)." ).arg( MAX_FLOAT_CLASSES ), QStringLiteral( "Raster" ) );
break;
}
if ( !isNoData && values.find( currentValue ) == values.end() )
for ( int column = 0; column < iterCols; column++ )
{
values.insert( currentValue );
data.push_back( Class( currentValue, QColor(), QLocale().toString( currentValue ) ) );
numClasses++;
if ( feedback && feedback->isCanceled() )
break;

const double currentValue = rasterBlock->valueAndNoData( row, column, isNoData );
if ( numClasses >= MAX_FLOAT_CLASSES )
{
QgsMessageLog::logMessage( QStringLiteral( "Number of classes exceeded maximum (%1)." ).arg( MAX_FLOAT_CLASSES ), QStringLiteral( "Raster" ) );
break;
}
if ( !isNoData && values.find( currentValue ) == values.end() )
{
values.insert( currentValue );
data.push_back( Class( currentValue, QColor(), QLocale().toString( currentValue ) ) );
numClasses++;
}
}
}
}
// must be sorted
std::sort( data.begin(), data.end(), []( const Class & a, const Class & b ) -> bool
{
return a.value < b.value;
} );
}
// must be sorted
std::sort( data.begin(), data.end(), []( const Class & a, const Class & b ) -> bool
{
return a.value < b.value;
} );
}
else
{
// get min and max value from raster
QgsRasterBandStats stats = raster->bandStatistics( bandNumber, QgsRasterBandStats::Min | QgsRasterBandStats::Max, QgsRectangle(), 0, feedback );
if ( feedback && feedback->isCanceled() )
return ClassData();

double min = stats.minimumValue;
double max = stats.maximumValue;
// need count of every individual value
int bins = std::ceil( max - min ) + 1;
if ( bins <= 0 )
return ClassData();

QgsRasterHistogram histogram = raster->histogram( bandNumber, bins, min, max, QgsRectangle(), 0, false, feedback );
if ( feedback && feedback->isCanceled() )
return ClassData();

double interval = ( histogram.maximum - histogram.minimum + 1 ) / histogram.binCount;
double currentValue = histogram.minimum;
for ( int idx = 0; idx < histogram.binCount; ++idx )
else
{
int count = histogram.histogramVector.at( idx );
if ( count > 0 )
// get min and max value from raster
const QgsRasterBandStats stats = raster->bandStatistics( bandNumber, QgsRasterBandStats::Min | QgsRasterBandStats::Max, QgsRectangle(), 0, feedback );
if ( feedback && feedback->isCanceled() )
return ClassData();

const double min = stats.minimumValue;
const double max = stats.maximumValue;
// need count of every individual value
const int bins = std::ceil( max - min ) + 1;
if ( bins <= 0 )
return ClassData();

const QgsRasterHistogram histogram = raster->histogram( bandNumber, bins, min, max, QgsRectangle(), 0, false, feedback );
if ( feedback && feedback->isCanceled() )
return ClassData();

const double interval = ( histogram.maximum - histogram.minimum + 1 ) / histogram.binCount;
double currentValue = histogram.minimum;
for ( int idx = 0; idx < histogram.binCount; ++idx )
{
data << Class( currentValue, QColor(), QLocale().toString( currentValue ) );
numClasses++;
const int count = histogram.histogramVector.at( idx );
if ( count > 0 )
{
data << Class( currentValue, QColor(), QLocale().toString( currentValue ) );
numClasses++;
}
currentValue += interval;
}
currentValue += interval;
}
}

// assign colors from ramp
if ( ramp && numClasses > 0 )
{
int i = 0;

if ( QgsRandomColorRamp *randomRamp = dynamic_cast<QgsRandomColorRamp *>( ramp ) )
// assign colors from ramp
if ( ramp && numClasses > 0 )
{
//ramp is a random colors ramp, so inform it of the total number of required colors
//this allows the ramp to pregenerate a set of visually distinctive colors
randomRamp->setTotalColorCount( data.count() );
}
int i = 0;

if ( numClasses > 1 )
numClasses -= 1; //avoid duplicate first color
if ( QgsRandomColorRamp *randomRamp = dynamic_cast<QgsRandomColorRamp *>( ramp ) )
{
//ramp is a random colors ramp, so inform it of the total number of required colors
//this allows the ramp to pregenerate a set of visually distinctive colors
randomRamp->setTotalColorCount( data.count() );
}

QgsPalettedRasterRenderer::ClassData::iterator cIt = data.begin();
for ( ; cIt != data.end(); ++cIt )
{
if ( feedback )
if ( numClasses > 1 )
numClasses -= 1; //avoid duplicate first color

QgsPalettedRasterRenderer::ClassData::iterator cIt = data.begin();
for ( ; cIt != data.end(); ++cIt )
{
// Show no less than 1%, then the max between class fill and real progress
feedback->setProgress( std::max<int>( 1, 100 * ( i + 1 ) / numClasses ) );
if ( feedback )
{
// Show no less than 1%, then the max between class fill and real progress
feedback->setProgress( std::max<int>( 1, 100 * ( i + 1 ) / numClasses ) );
}
cIt->color = ramp->color( i / static_cast<double>( numClasses ) );
i++;
}
cIt->color = ramp->color( i / static_cast<double>( numClasses ) );
i++;
}
}
return data;

0 comments on commit d6f67c6

Please sign in to comment.