mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-18 00:03:05 -04:00
Refactor QgsPalettedRasterRenderer to allow "gaps" in pixel values
Previously the renderer required that pixel values followed sequential numerical order. This refactor allows values to be skipped, so that only certain color index will be rendered.
This commit is contained in:
parent
620a8394c9
commit
a157db7627
@ -1536,7 +1536,10 @@ QgsPaintEffectRegistry {#qgis_api_break_3_0_QgsPaintEffectRegistry}
|
||||
QgsPalettedRasterRenderer {#qgis_api_break_3_0_QgsPalettedRasterRenderer}
|
||||
-------------------------
|
||||
|
||||
- The rgbArray() method was made private
|
||||
- The rgbArray() method was removed
|
||||
- colors() has been removed, use classes() instead.
|
||||
- The constructor has a different signature and requires a list of classes instead of an array
|
||||
|
||||
|
||||
QgsPalLabeling {#qgis_api_break_3_0_QgsPalLabeling}
|
||||
--------------
|
||||
|
@ -4,8 +4,17 @@ class QgsPalettedRasterRenderer : QgsRasterRenderer
|
||||
#include "qgspalettedrasterrenderer.h"
|
||||
%End
|
||||
public:
|
||||
/** Renderer owns color array*/
|
||||
QgsPalettedRasterRenderer( QgsRasterInterface* input, int bandNumber, QColor* colorArray /Array,Transfer/, int nColors /ArraySize/, const QVector<QString>& labels = QVector<QString>() );
|
||||
|
||||
struct Class
|
||||
{
|
||||
|
||||
Class( const QColor &color, const QString &label );
|
||||
QColor color;
|
||||
QString label;
|
||||
};
|
||||
|
||||
typedef QMap< int, QgsPalettedRasterRenderer::Class > ClassData;
|
||||
QgsPalettedRasterRenderer( QgsRasterInterface *input, int bandNumber, const ClassData &classes );
|
||||
~QgsPalettedRasterRenderer();
|
||||
virtual QgsPalettedRasterRenderer * clone() const /Factory/;
|
||||
static QgsRasterRenderer* create( const QDomElement& elem, QgsRasterInterface* input ) /Factory/;
|
||||
@ -14,20 +23,13 @@ class QgsPalettedRasterRenderer : QgsRasterRenderer
|
||||
|
||||
/** Returns number of colors*/
|
||||
int nColors() const;
|
||||
/** Returns copy of color array (caller takes ownership)*/
|
||||
QColor* colors() const /Factory/;
|
||||
|
||||
/** Return optional category label
|
||||
* @note added in 2.1 */
|
||||
ClassData classes() const;
|
||||
QString label( int idx ) const;
|
||||
void setLabel( int idx, const QString &label );
|
||||
|
||||
/** Set category label
|
||||
* @note added in 2.1 */
|
||||
void setLabel( int idx, const QString& label );
|
||||
void writeXml( QDomDocument &doc, QDomElement &parentElem ) const;
|
||||
|
||||
void writeXml( QDomDocument& doc, QDomElement& parentElem ) const;
|
||||
|
||||
void legendSymbologyItems( QList< QPair< QString, QColor > >& symbolItems /Out/ ) const;
|
||||
void legendSymbologyItems( QList< QPair< QString, QColor > > &symbolItems /Out/ ) const;
|
||||
|
||||
QList<int> usesBands() const;
|
||||
|
||||
|
@ -26,34 +26,24 @@
|
||||
#include <QVector>
|
||||
#include <memory>
|
||||
|
||||
QgsPalettedRasterRenderer::QgsPalettedRasterRenderer( QgsRasterInterface *input, int bandNumber,
|
||||
QColor *colorArray, int nColors, const QVector<QString> &labels ):
|
||||
QgsRasterRenderer( input, QStringLiteral( "paletted" ) ), mBand( bandNumber ), mNColors( nColors ), mLabels( labels )
|
||||
{
|
||||
mColors = new QRgb[nColors];
|
||||
for ( int i = 0; i < nColors; ++i )
|
||||
{
|
||||
mColors[i] = qPremultiply( colorArray[i].rgba() );
|
||||
}
|
||||
delete[] colorArray;
|
||||
}
|
||||
|
||||
QgsPalettedRasterRenderer::QgsPalettedRasterRenderer( QgsRasterInterface *input, int bandNumber, QRgb *colorArray, int nColors, const QVector<QString> &labels ):
|
||||
QgsRasterRenderer( input, QStringLiteral( "paletted" ) ), mBand( bandNumber ), mColors( colorArray ), mNColors( nColors ), mLabels( labels )
|
||||
QgsPalettedRasterRenderer::QgsPalettedRasterRenderer( QgsRasterInterface *input, int bandNumber, const ClassData &classes )
|
||||
: QgsRasterRenderer( input, QStringLiteral( "paletted" ) )
|
||||
, mBand( bandNumber )
|
||||
, mClassData( classes )
|
||||
{
|
||||
updateArrays();
|
||||
}
|
||||
|
||||
QgsPalettedRasterRenderer::~QgsPalettedRasterRenderer()
|
||||
{
|
||||
delete[] mColors;
|
||||
delete[] mIsNoData;
|
||||
}
|
||||
|
||||
QgsPalettedRasterRenderer *QgsPalettedRasterRenderer::clone() const
|
||||
{
|
||||
QgsPalettedRasterRenderer *renderer = new QgsPalettedRasterRenderer( nullptr, mBand, rgbArray(), mNColors );
|
||||
QgsPalettedRasterRenderer *renderer = new QgsPalettedRasterRenderer( nullptr, mBand, mClassData );
|
||||
renderer->copyCommonProperties( this );
|
||||
|
||||
renderer->mLabels = mLabels;
|
||||
return renderer;
|
||||
}
|
||||
|
||||
@ -65,9 +55,7 @@ QgsRasterRenderer *QgsPalettedRasterRenderer::create( const QDomElement &elem, Q
|
||||
}
|
||||
|
||||
int bandNumber = elem.attribute( QStringLiteral( "band" ), QStringLiteral( "-1" ) ).toInt();
|
||||
int nColors = 0;
|
||||
QRgb *colors = nullptr;
|
||||
QVector<QString> labels;
|
||||
ClassData classData;
|
||||
|
||||
QDomElement paletteElem = elem.firstChildElement( QStringLiteral( "colorPalette" ) );
|
||||
if ( !paletteElem.isNull() )
|
||||
@ -76,89 +64,50 @@ QgsRasterRenderer *QgsPalettedRasterRenderer::create( const QDomElement &elem, Q
|
||||
|
||||
QDomElement entryElem;
|
||||
int value;
|
||||
nColors = 0;
|
||||
|
||||
// We cannot believe that data are correct, check first max value
|
||||
for ( int i = 0; i < paletteEntries.size(); ++i )
|
||||
{
|
||||
entryElem = paletteEntries.at( i ).toElement();
|
||||
// Could be written as doubles (with .0000) in old project files
|
||||
value = ( int )entryElem.attribute( QStringLiteral( "value" ), QStringLiteral( "0" ) ).toDouble();
|
||||
if ( value >= nColors && value <= 10000 ) nColors = value + 1;
|
||||
}
|
||||
QgsDebugMsgLevel( QString( "nColors = %1" ).arg( nColors ), 4 );
|
||||
|
||||
colors = new QRgb[ nColors ];
|
||||
|
||||
for ( int i = 0; i < nColors; ++i )
|
||||
{
|
||||
QColor color;
|
||||
QString label;
|
||||
entryElem = paletteEntries.at( i ).toElement();
|
||||
value = ( int )entryElem.attribute( QStringLiteral( "value" ), QStringLiteral( "0" ) ).toDouble();
|
||||
QgsDebugMsgLevel( entryElem.attribute( "color", "#000000" ), 4 );
|
||||
if ( value >= 0 && value < nColors )
|
||||
{
|
||||
QColor color = QColor( entryElem.attribute( QStringLiteral( "color" ), QStringLiteral( "#000000" ) ) );
|
||||
color = QColor( entryElem.attribute( QStringLiteral( "color" ), QStringLiteral( "#000000" ) ) );
|
||||
color.setAlpha( entryElem.attribute( QStringLiteral( "alpha" ), QStringLiteral( "255" ) ).toInt() );
|
||||
colors[value] = qPremultiply( color.rgba() );
|
||||
QString label = entryElem.attribute( QStringLiteral( "label" ) );
|
||||
if ( !label.isEmpty() )
|
||||
{
|
||||
if ( value >= labels.size() ) labels.resize( value + 1 );
|
||||
labels[value] = label;
|
||||
label = entryElem.attribute( QStringLiteral( "label" ) );
|
||||
classData.insert( value, Class( color, label ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsg( QString( "value %1 out of range" ).arg( value ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
QgsPalettedRasterRenderer *r = new QgsPalettedRasterRenderer( input, bandNumber, colors, nColors, labels );
|
||||
QgsPalettedRasterRenderer *r = new QgsPalettedRasterRenderer( input, bandNumber, classData );
|
||||
r->readXml( elem );
|
||||
return r;
|
||||
}
|
||||
|
||||
QColor *QgsPalettedRasterRenderer::colors() const
|
||||
QgsPalettedRasterRenderer::ClassData QgsPalettedRasterRenderer::classes() const
|
||||
{
|
||||
if ( mNColors < 1 )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
QColor *colorArray = new QColor[ mNColors ];
|
||||
for ( int i = 0; i < mNColors; ++i )
|
||||
{
|
||||
colorArray[i] = QColor::fromRgba( qUnpremultiply( mColors[i] ) );
|
||||
}
|
||||
return colorArray;
|
||||
return mClassData;
|
||||
}
|
||||
|
||||
QRgb *QgsPalettedRasterRenderer::rgbArray() const
|
||||
QString QgsPalettedRasterRenderer::label( int idx ) const
|
||||
{
|
||||
if ( mNColors < 1 )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
QRgb *rgbValues = new QRgb[mNColors];
|
||||
for ( int i = 0; i < mNColors; ++i )
|
||||
{
|
||||
rgbValues[i] = mColors[i];
|
||||
}
|
||||
return rgbValues;
|
||||
if ( !mClassData.contains( idx ) )
|
||||
return QString();
|
||||
|
||||
return mClassData.value( idx ).label;
|
||||
}
|
||||
|
||||
void QgsPalettedRasterRenderer::setLabel( int idx, const QString &label )
|
||||
{
|
||||
if ( idx >= mLabels.size() )
|
||||
{
|
||||
mLabels.resize( idx + 1 );
|
||||
}
|
||||
mLabels[idx] = label;
|
||||
if ( !mClassData.contains( idx ) )
|
||||
return;
|
||||
|
||||
mClassData[ idx ].label = label;
|
||||
}
|
||||
|
||||
QgsRasterBlock *QgsPalettedRasterRenderer::block( int bandNo, QgsRectangle const &extent, int width, int height, QgsRasterBlockFeedback *feedback )
|
||||
{
|
||||
std::unique_ptr< QgsRasterBlock > outputBlock( new QgsRasterBlock() );
|
||||
if ( !mInput || mNColors == 0 )
|
||||
if ( !mInput || mClassData.isEmpty() )
|
||||
{
|
||||
return outputBlock.release();
|
||||
}
|
||||
@ -211,6 +160,11 @@ QgsRasterBlock *QgsPalettedRasterRenderer::block( int bandNo, QgsRectangle cons
|
||||
continue;
|
||||
}
|
||||
int val = ( int ) inputBlock->value( i );
|
||||
if ( val > mMaxColorIndex || mIsNoData[ val ] )
|
||||
{
|
||||
outputData[i] = myDefaultColor;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !hasTransparency )
|
||||
{
|
||||
@ -248,16 +202,17 @@ void QgsPalettedRasterRenderer::writeXml( QDomDocument &doc, QDomElement &parent
|
||||
|
||||
rasterRendererElem.setAttribute( QStringLiteral( "band" ), mBand );
|
||||
QDomElement colorPaletteElem = doc.createElement( QStringLiteral( "colorPalette" ) );
|
||||
for ( int i = 0; i < mNColors; ++i )
|
||||
ClassData::const_iterator it = mClassData.constBegin();
|
||||
for ( ; it != mClassData.constEnd(); ++it )
|
||||
{
|
||||
QColor color = QColor::fromRgba( qUnpremultiply( mColors[i] ) );
|
||||
QColor color = it.value().color;
|
||||
QDomElement colorElem = doc.createElement( QStringLiteral( "paletteEntry" ) );
|
||||
colorElem.setAttribute( QStringLiteral( "value" ), i );
|
||||
colorElem.setAttribute( QStringLiteral( "value" ), it.key() );
|
||||
colorElem.setAttribute( QStringLiteral( "color" ), color.name() );
|
||||
colorElem.setAttribute( QStringLiteral( "alpha" ), color.alpha() );
|
||||
if ( !label( i ).isEmpty() )
|
||||
if ( !it.value().label.isEmpty() )
|
||||
{
|
||||
colorElem.setAttribute( QStringLiteral( "label" ), label( i ) );
|
||||
colorElem.setAttribute( QStringLiteral( "label" ), it.value().label );
|
||||
}
|
||||
colorPaletteElem.appendChild( colorElem );
|
||||
}
|
||||
@ -268,10 +223,25 @@ void QgsPalettedRasterRenderer::writeXml( QDomDocument &doc, QDomElement &parent
|
||||
|
||||
void QgsPalettedRasterRenderer::legendSymbologyItems( QList< QPair< QString, QColor > > &symbolItems ) const
|
||||
{
|
||||
for ( int i = 0; i < mNColors; ++i )
|
||||
QList< QPair< int, QPair< QString, QColor > > > legends;
|
||||
ClassData::const_iterator it = mClassData.constBegin();
|
||||
for ( ; it != mClassData.constEnd(); ++it )
|
||||
{
|
||||
QString lab = label( i ).isEmpty() ? QString::number( i ) : label( i );
|
||||
symbolItems.push_back( qMakePair( lab, QColor::fromRgba( qUnpremultiply( mColors[i] ) ) ) );
|
||||
QString lab = it.value().label.isEmpty() ? QString::number( it.key() ) : it.value().label;
|
||||
legends.push_back( qMakePair( it.key(), qMakePair( lab, it.value().color ) ) );
|
||||
}
|
||||
|
||||
// sort by color value
|
||||
std::sort( legends.begin(), legends.end(),
|
||||
[]( const QPair< int, QPair< QString, QColor > > &a, const QPair< int, QPair< QString, QColor > > &b ) -> bool
|
||||
{
|
||||
return a.first < b.first;
|
||||
} );
|
||||
|
||||
QList< QPair< int, QPair< QString, QColor > > >::const_iterator lIt = legends.constBegin();
|
||||
for ( ; lIt != legends.constEnd(); ++lIt )
|
||||
{
|
||||
symbolItems << lIt->second;
|
||||
}
|
||||
}
|
||||
|
||||
@ -284,3 +254,28 @@ QList<int> QgsPalettedRasterRenderer::usesBands() const
|
||||
}
|
||||
return bandList;
|
||||
}
|
||||
|
||||
void QgsPalettedRasterRenderer::updateArrays()
|
||||
{
|
||||
// find maximum color index
|
||||
ClassData::const_iterator mIt = mClassData.constBegin();
|
||||
for ( ; mIt != mClassData.constEnd(); ++mIt )
|
||||
{
|
||||
mMaxColorIndex = qMax( mMaxColorIndex, mIt.key() );
|
||||
}
|
||||
|
||||
delete [] mColors;
|
||||
delete [] mIsNoData;
|
||||
mColors = new QRgb[mMaxColorIndex + 1];
|
||||
mIsNoData = new bool[mMaxColorIndex + 1];
|
||||
std::fill( mIsNoData, mIsNoData + mMaxColorIndex, true );
|
||||
|
||||
int i = 0;
|
||||
ClassData::const_iterator it = mClassData.constBegin();
|
||||
for ( ; it != mClassData.constEnd(); ++it )
|
||||
{
|
||||
mColors[it.key()] = qPremultiply( it.value().color.rgba() );
|
||||
mIsNoData[it.key()] = false;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
@ -33,9 +33,28 @@ class CORE_EXPORT QgsPalettedRasterRenderer: public QgsRasterRenderer
|
||||
{
|
||||
public:
|
||||
|
||||
//! Renderer owns color array
|
||||
QgsPalettedRasterRenderer( QgsRasterInterface *input, int bandNumber, QColor *colorArray, int nColors, const QVector<QString> &labels = QVector<QString>() );
|
||||
QgsPalettedRasterRenderer( QgsRasterInterface *input, int bandNumber, QRgb *colorArray, int nColors, const QVector<QString> &labels = QVector<QString>() );
|
||||
//! Properties of a single value class
|
||||
struct Class
|
||||
{
|
||||
//! Constructor for Class
|
||||
Class( const QColor &color = QColor(), const QString &label = QString() )
|
||||
: color( color )
|
||||
, label( label )
|
||||
{}
|
||||
|
||||
//! Color to render value
|
||||
QColor color;
|
||||
//! Label for value
|
||||
QString label;
|
||||
};
|
||||
|
||||
//! Map of value to class properties
|
||||
typedef QMap< int, Class > ClassData;
|
||||
|
||||
/**
|
||||
* Constructor for QgsPalettedRasterRenderer.
|
||||
*/
|
||||
QgsPalettedRasterRenderer( QgsRasterInterface *input, int bandNumber, const ClassData &classes );
|
||||
~QgsPalettedRasterRenderer();
|
||||
|
||||
//! QgsPalettedRasterRenderer cannot be copied. Use clone() instead.
|
||||
@ -49,13 +68,16 @@ class CORE_EXPORT QgsPalettedRasterRenderer: public QgsRasterRenderer
|
||||
QgsRasterBlock *block( int bandNo, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback = nullptr ) override;
|
||||
|
||||
//! Returns number of colors
|
||||
int nColors() const { return mNColors; }
|
||||
//! Returns copy of color array (caller takes ownership)
|
||||
QColor *colors() const;
|
||||
int nColors() const { return mClassData.size(); }
|
||||
|
||||
/**
|
||||
* Returns a map of value to classes (colors) used by the renderer.
|
||||
*/
|
||||
ClassData classes() const;
|
||||
|
||||
/** Return optional category label
|
||||
* \since QGIS 2.1 */
|
||||
QString label( int idx ) const { return mLabels.value( idx ); }
|
||||
QString label( int idx ) const;
|
||||
|
||||
/** Set category label
|
||||
* \since QGIS 2.1 */
|
||||
@ -69,17 +91,16 @@ class CORE_EXPORT QgsPalettedRasterRenderer: public QgsRasterRenderer
|
||||
|
||||
private:
|
||||
|
||||
/** Returns copy of premultiplied rgb array (caller takes ownership)
|
||||
*/
|
||||
QRgb *rgbArray() const;
|
||||
|
||||
int mBand;
|
||||
int mMaxColorIndex = -INT_MAX;
|
||||
ClassData mClassData;
|
||||
|
||||
|
||||
//! Premultiplied color array
|
||||
QRgb *mColors = nullptr;
|
||||
//! Number of colors
|
||||
int mNColors;
|
||||
//! Optional category labels, size of vector may be < mNColors
|
||||
QVector<QString> mLabels;
|
||||
bool *mIsNoData = nullptr;
|
||||
void updateArrays();
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
@ -124,37 +124,17 @@ QgsRasterRenderer *QgsRasterRendererRegistry::defaultRendererForDrawingStyle( Qg
|
||||
int grayBand = 1; //reasonable default
|
||||
QList<QgsColorRampShader::ColorRampItem> colorEntries = provider->colorTable( grayBand );
|
||||
|
||||
//go through list and take maximum value (it could be that entries don't start at 0 or indices are not contiguous)
|
||||
int colorArraySize = 0;
|
||||
QList<QgsColorRampShader::ColorRampItem>::const_iterator colorIt = colorEntries.constBegin();
|
||||
for ( ; colorIt != colorEntries.constEnd(); ++colorIt )
|
||||
{
|
||||
if ( colorIt->value > colorArraySize )
|
||||
{
|
||||
colorArraySize = ( int )( colorIt->value );
|
||||
}
|
||||
}
|
||||
|
||||
colorArraySize += 1; //usually starts at 0
|
||||
QColor *colorArray = new QColor[ colorArraySize ];
|
||||
colorIt = colorEntries.constBegin();
|
||||
QVector<QString> labels;
|
||||
QgsPalettedRasterRenderer::ClassData classes;
|
||||
for ( ; colorIt != colorEntries.constEnd(); ++colorIt )
|
||||
{
|
||||
int idx = ( int )( colorIt->value );
|
||||
colorArray[idx] = colorIt->color;
|
||||
if ( !colorIt->label.isEmpty() )
|
||||
{
|
||||
if ( labels.size() <= idx ) labels.resize( idx + 1 );
|
||||
labels[idx] = colorIt->label;
|
||||
}
|
||||
classes.insert( idx, QgsPalettedRasterRenderer::Class( colorIt->color, colorIt->label ) );
|
||||
}
|
||||
|
||||
renderer = new QgsPalettedRasterRenderer( provider,
|
||||
grayBand,
|
||||
colorArray,
|
||||
colorArraySize,
|
||||
labels );
|
||||
classes );
|
||||
}
|
||||
break;
|
||||
case QgsRaster::MultiBandSingleBandGray:
|
||||
|
@ -62,20 +62,20 @@ QgsPalettedRendererWidget::QgsPalettedRendererWidget( QgsRasterLayer *layer, con
|
||||
QgsRasterRenderer *QgsPalettedRendererWidget::renderer()
|
||||
{
|
||||
int nColors = mTreeWidget->topLevelItemCount();
|
||||
QColor *colorArray = new QColor[nColors];
|
||||
QVector<QString> labels;
|
||||
QgsPalettedRasterRenderer::ClassData classes;
|
||||
bool ok = false;
|
||||
for ( int i = 0; i < nColors; ++i )
|
||||
{
|
||||
colorArray[i] = mTreeWidget->topLevelItem( i )->background( 1 ).color();
|
||||
int value = mTreeWidget->topLevelItem( i )->text( 0 ).toInt( &ok );
|
||||
if ( !ok )
|
||||
continue;
|
||||
|
||||
QColor color = mTreeWidget->topLevelItem( i )->background( 1 ).color();
|
||||
QString label = mTreeWidget->topLevelItem( i )->text( 2 );
|
||||
if ( !label.isEmpty() )
|
||||
{
|
||||
if ( i >= labels.size() ) labels.resize( i + 1 );
|
||||
labels[i] = label;
|
||||
}
|
||||
classes.insert( value, QgsPalettedRasterRenderer::Class( color, label ) );
|
||||
}
|
||||
int bandNumber = mBandComboBox->currentData().toInt();
|
||||
return new QgsPalettedRasterRenderer( mRasterLayer->dataProvider(), bandNumber, colorArray, nColors, labels );
|
||||
return new QgsPalettedRasterRenderer( mRasterLayer->dataProvider(), bandNumber, classes );
|
||||
}
|
||||
|
||||
void QgsPalettedRendererWidget::on_mTreeWidget_itemDoubleClicked( QTreeWidgetItem *item, int column )
|
||||
@ -110,16 +110,15 @@ void QgsPalettedRendererWidget::setFromRenderer( const QgsRasterRenderer *r )
|
||||
if ( pr )
|
||||
{
|
||||
//read values and colors and fill into tree widget
|
||||
int nColors = pr->nColors();
|
||||
QColor *colors = pr->colors();
|
||||
for ( int i = 0; i < nColors; ++i )
|
||||
QgsPalettedRasterRenderer::ClassData classes = pr->classes();
|
||||
QgsPalettedRasterRenderer::ClassData::const_iterator it = classes.constBegin();
|
||||
for ( ; it != classes.constEnd(); ++it )
|
||||
{
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem( mTreeWidget );
|
||||
item->setText( 0, QString::number( i ) );
|
||||
item->setBackground( 1, QBrush( colors[i] ) );
|
||||
item->setText( 2, pr->label( i ) );
|
||||
item->setText( 0, QString::number( it.key() ) );
|
||||
item->setBackground( 1, QBrush( it->color ) );
|
||||
item->setText( 2, it->label );
|
||||
}
|
||||
delete[] colors;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -32,6 +32,7 @@ from qgis.core import (QgsRaster,
|
||||
QgsRasterShader,
|
||||
QgsRasterTransparency,
|
||||
QgsRenderChecker,
|
||||
QgsPalettedRasterRenderer,
|
||||
QgsSingleBandGrayRenderer,
|
||||
QgsSingleBandPseudoColorRenderer)
|
||||
from utilities import unitTestDataPath
|
||||
@ -287,6 +288,81 @@ class TestQgsRasterLayer(unittest.TestCase):
|
||||
mmoUnserialized.readXml(parentElem)
|
||||
self.assertEqual(mmo, mmoUnserialized)
|
||||
|
||||
def testPaletted(self):
|
||||
""" test paletted raster renderer with raster with color table"""
|
||||
path = os.path.join(unitTestDataPath('raster'),
|
||||
'with_color_table.tif')
|
||||
info = QFileInfo(path)
|
||||
base_name = info.baseName()
|
||||
layer = QgsRasterLayer(path, base_name)
|
||||
self.assertTrue(layer.isValid(), 'Raster not loaded: {}'.format(path))
|
||||
|
||||
renderer = QgsPalettedRasterRenderer(layer.dataProvider(), 1,
|
||||
{3: QgsPalettedRasterRenderer.Class(QColor(255, 0, 0), 'class 1'),
|
||||
1: QgsPalettedRasterRenderer.Class(QColor(0, 255, 0), 'class 2')})
|
||||
|
||||
self.assertEqual(renderer.nColors(), 2)
|
||||
self.assertEqual(renderer.usesBands(), [1])
|
||||
|
||||
# test labels
|
||||
self.assertEqual(renderer.label(1), 'class 2')
|
||||
self.assertEqual(renderer.label(3), 'class 1')
|
||||
self.assertFalse(renderer.label(101))
|
||||
|
||||
# test legend symbology - should be sorted by value
|
||||
legend = renderer.legendSymbologyItems()
|
||||
self.assertEqual(legend[0][0], 'class 2')
|
||||
self.assertEqual(legend[1][0], 'class 1')
|
||||
self.assertEqual(legend[0][1].name(), '#00ff00')
|
||||
self.assertEqual(legend[1][1].name(), '#ff0000')
|
||||
|
||||
# test retrieving classes
|
||||
classes = renderer.classes()
|
||||
self.assertEqual(classes[1].label, 'class 2')
|
||||
self.assertEqual(classes[3].label, 'class 1')
|
||||
self.assertEqual(classes[1].color.name(), '#00ff00')
|
||||
self.assertEqual(classes[3].color.name(), '#ff0000')
|
||||
|
||||
# test set label
|
||||
# bad index
|
||||
renderer.setLabel(1212, 'bad')
|
||||
renderer.setLabel(3, 'new class')
|
||||
self.assertEqual(renderer.label(3), 'new class')
|
||||
|
||||
# clone
|
||||
new_renderer = renderer.clone()
|
||||
classes = new_renderer.classes()
|
||||
self.assertEqual(classes[1].label, 'class 2')
|
||||
self.assertEqual(classes[3].label, 'new class')
|
||||
self.assertEqual(classes[1].color.name(), '#00ff00')
|
||||
self.assertEqual(classes[3].color.name(), '#ff0000')
|
||||
|
||||
# write to xml and read
|
||||
doc = QDomDocument('testdoc')
|
||||
elem = doc.createElement('qgis')
|
||||
renderer.writeXml(doc, elem)
|
||||
restored = QgsPalettedRasterRenderer.create(elem.firstChild().toElement(), layer.dataProvider())
|
||||
self.assertTrue(restored)
|
||||
self.assertEqual(restored.usesBands(), [1])
|
||||
classes = restored.classes()
|
||||
self.assertTrue(classes)
|
||||
self.assertEqual(classes[1].label, 'class 2')
|
||||
self.assertEqual(classes[3].label, 'new class')
|
||||
self.assertEqual(classes[1].color.name(), '#00ff00')
|
||||
self.assertEqual(classes[3].color.name(), '#ff0000')
|
||||
|
||||
# render test
|
||||
layer.setRenderer(renderer)
|
||||
ms = QgsMapSettings()
|
||||
ms.setLayers([layer])
|
||||
ms.setExtent(layer.extent())
|
||||
|
||||
checker = QgsRenderChecker()
|
||||
checker.setControlName("expected_paletted_renderer")
|
||||
checker.setMapSettings(ms)
|
||||
|
||||
self.assertTrue(checker.runTest("expected_paletted_renderer"), "Paletted rendering test failed")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
BIN
tests/testdata/control_images/expected_paletted_renderer/expected_paletted_renderer.png
vendored
Normal file
BIN
tests/testdata/control_images/expected_paletted_renderer/expected_paletted_renderer.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
BIN
tests/testdata/raster/with_color_table.tif
vendored
Normal file
BIN
tests/testdata/raster/with_color_table.tif
vendored
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user