Skip to content

Commit 9fce669

Browse files
committed
Improved raster singleband pseudocolor classification GUI
1 parent 7a82041 commit 9fce669

10 files changed

+200
-49
lines changed

python/core/symbology-ng/qgsvectorcolorrampv2.sip

+4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ class QgsVectorColorRampV2
1616
public:
1717
virtual ~QgsVectorColorRampV2();
1818

19+
virtual int count() const = 0;
20+
21+
virtual double value( int index ) const = 0;
22+
1923
virtual QColor color( double value ) const = 0;
2024

2125
virtual QString type() const = 0;

src/core/raster/qgscolorrampshader.cpp

+10-7
Original file line numberDiff line numberDiff line change
@@ -169,22 +169,25 @@ bool QgsColorRampShader::interpolatedColor( double theValue, int*
169169
QgsColorRampShader::ColorRampItem myPreviousColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex - 1 );
170170
myCurrentRampRange = myColorRampItem.value - myPreviousColorRampItem.value;
171171
myOffsetInRange = theValue - myPreviousColorRampItem.value;
172+
double scale = myOffsetInRange / myCurrentRampRange;
172173

173-
*theReturnRedValue = ( int )(( double ) myPreviousColorRampItem.color.red() + ((( double )( myColorRampItem.color.red() - myPreviousColorRampItem.color.red() ) / myCurrentRampRange ) * myOffsetInRange ) );
174-
*theReturnGreenValue = ( int )(( double ) myPreviousColorRampItem.color.green() + ((( double )( myColorRampItem.color.green() - myPreviousColorRampItem.color.green() ) / myCurrentRampRange ) * myOffsetInRange ) );
175-
*theReturnBlueValue = ( int )(( double ) myPreviousColorRampItem.color.blue() + ((( double )( myColorRampItem.color.blue() - myPreviousColorRampItem.color.blue() ) / myCurrentRampRange ) * myOffsetInRange ) );
174+
*theReturnRedValue = ( int )(( double ) myPreviousColorRampItem.color.red() + (( double )( myColorRampItem.color.red() - myPreviousColorRampItem.color.red() ) * scale ) ) ;
175+
*theReturnGreenValue = ( int )(( double ) myPreviousColorRampItem.color.green() + (( double )( myColorRampItem.color.green() - myPreviousColorRampItem.color.green() ) * scale ) );
176+
*theReturnBlueValue = ( int )(( double ) myPreviousColorRampItem.color.blue() + (( double )( myColorRampItem.color.blue() - myPreviousColorRampItem.color.blue() ) * scale ) );
176177
if ( mMaximumColorCacheSize >= mColorCache.size() )
177178
{
178179
QColor myNewColor( *theReturnRedValue, *theReturnGreenValue, *theReturnBlueValue );
179180
mColorCache.insert( theValue, myNewColor );
180181
}
181182
return true;
182183
}
183-
else if ( mCurrentColorRampItemIndex == 0 && theValue <= myColorRampItem.value )
184+
// Values outside total range are rendered if mClip is false
185+
else if (( mCurrentColorRampItemIndex == 0 && ( myTinyDiff <= DOUBLE_DIFF_THRESHOLD || ( !mClip && theValue <= myColorRampItem.value ) ) )
186+
|| ( mCurrentColorRampItemIndex == myColorRampItemCount - 1 && ( myTinyDiff <= DOUBLE_DIFF_THRESHOLD || ( !mClip && theValue >= myColorRampItem.value ) ) ) )
184187
{
185-
QgsColorRampShader::ColorRampItem myPreviousColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex - 1 );
186-
myCurrentRampRange = myColorRampItem.value - myPreviousColorRampItem.value;
187-
myOffsetInRange = theValue - myPreviousColorRampItem.value;
188+
//QgsColorRampShader::ColorRampItem myPreviousColorRampItem = mColorRampItemList.value( mCurrentColorRampItemIndex - 1 );
189+
//myCurrentRampRange = myColorRampItem.value - myPreviousColorRampItem.value;
190+
//myOffsetInRange = theValue - myPreviousColorRampItem.value;
188191

189192
*theReturnRedValue = myColorRampItem.color.red();
190193
*theReturnGreenValue = myColorRampItem.color.green();

src/core/raster/qgscolorrampshader.h

+6
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ class CORE_EXPORT QgsColorRampShader : public QgsRasterShaderFunction
9393

9494
void legendSymbologyItems( QList< QPair< QString, QColor > >& symbolItems ) const;
9595

96+
void setClip( bool clip ) { mClip = clip; }
97+
bool clip() const { return mClip; }
98+
9699
private:
97100
/** Current index from which to start searching the color table*/
98101
int mCurrentColorRampItemIndex;
@@ -129,6 +132,9 @@ class CORE_EXPORT QgsColorRampShader : public QgsRasterShaderFunction
129132
* mValueClassification. Interpolates the color between two class breaks
130133
* linearly.*/
131134
bool interpolatedColor( double, int*, int*, int* );
135+
136+
/** Do not render values out of range */
137+
bool mClip;
132138
};
133139

134140
#endif

src/core/raster/qgsrastershader.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ void QgsRasterShader::writeXML( QDomDocument& doc, QDomElement& parent ) const
140140
{
141141
QDomElement colorRampShaderElem = doc.createElement( "colorrampshader" );
142142
colorRampShaderElem.setAttribute( "colorRampType", colorRampShader->colorRampTypeAsQString() );
143+
colorRampShaderElem.setAttribute( "clip", colorRampShader->clip() );
143144
//items
144145
QList<QgsColorRampShader::ColorRampItem> itemList = colorRampShader->colorRampItemList();
145146
QList<QgsColorRampShader::ColorRampItem>::const_iterator itemIt = itemList.constBegin();
@@ -164,6 +165,7 @@ void QgsRasterShader::readXML( const QDomElement& elem )
164165
{
165166
QgsColorRampShader* colorRampShader = new QgsColorRampShader();
166167
colorRampShader->setColorRampType( colorRampShaderElem.attribute( "colorRampType", "INTERPOLATED" ) );
168+
colorRampShader->setClip( colorRampShaderElem.attribute( "clip", "0" ) == "1" );
167169

168170
QList<QgsColorRampShader::ColorRampItem> itemList;
169171
QDomElement itemElem;

src/core/symbology-ng/qgsvectorcolorrampv2.cpp

+28
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,22 @@ QgsVectorColorRampV2* QgsVectorGradientColorRampV2::create( const QgsStringMap&
9191
return r;
9292
}
9393

94+
double QgsVectorGradientColorRampV2::value( int index ) const
95+
{
96+
if ( index <= 0 )
97+
{
98+
return 0;
99+
}
100+
else if ( index >= mStops.size() + 1 )
101+
{
102+
return 1;
103+
}
104+
else
105+
{
106+
return mStops[index-1].offset;
107+
}
108+
}
109+
94110
QColor QgsVectorGradientColorRampV2::color( double value ) const
95111
{
96112
if ( mStops.isEmpty() )
@@ -232,6 +248,12 @@ QgsVectorColorRampV2* QgsVectorRandomColorRampV2::create( const QgsStringMap& pr
232248
return new QgsVectorRandomColorRampV2( count, hueMin, hueMax, satMin, satMax, valMin, valMax );
233249
}
234250

251+
double QgsVectorRandomColorRampV2::value( int index ) const
252+
{
253+
if ( mColors.size() < 1 ) return 0;
254+
return index / mColors.size() - 1;
255+
}
256+
235257
QColor QgsVectorRandomColorRampV2::color( double value ) const
236258
{
237259
int colorCnt = mColors.count();
@@ -312,6 +334,12 @@ QList<int> QgsVectorColorBrewerColorRampV2::listSchemeVariants( QString schemeNa
312334
return QgsColorBrewerPalette::listSchemeVariants( schemeName );
313335
}
314336

337+
double QgsVectorColorBrewerColorRampV2::value( int index ) const
338+
{
339+
if ( mPalette.size() < 1 ) return 0;
340+
return index / mPalette.size() - 1;
341+
}
342+
315343
QColor QgsVectorColorBrewerColorRampV2::color( double value ) const
316344
{
317345
if ( mPalette.isEmpty() || value < 0 || value > 1 )

src/core/symbology-ng/qgsvectorcolorrampv2.h

+16-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ class CORE_EXPORT QgsVectorColorRampV2
2626
public:
2727
virtual ~QgsVectorColorRampV2() {}
2828

29+
// Number of defined colors
30+
virtual int count() const = 0;
31+
32+
// Relative value (0,1) of color at index
33+
virtual double value( int index ) const = 0;
34+
2935
virtual QColor color( double value ) const = 0;
3036

3137
virtual QString type() const = 0;
@@ -38,7 +44,7 @@ class CORE_EXPORT QgsVectorColorRampV2
3844

3945
struct QgsGradientStop
4046
{
41-
double offset;
47+
double offset; // relative (0,1)
4248
QColor color;
4349
QgsGradientStop( double o, const QColor& c ) : offset( o ), color( c ) { }
4450
};
@@ -58,6 +64,10 @@ class CORE_EXPORT QgsVectorGradientColorRampV2 : public QgsVectorColorRampV2
5864

5965
static QgsVectorColorRampV2* create( const QgsStringMap& properties = QgsStringMap() );
6066

67+
virtual int count() const { return mStops.count() + 2; }
68+
69+
virtual double value( int index ) const;
70+
6171
virtual QColor color( double value ) const;
6272

6373
virtual QString type() const { return "gradient"; }
@@ -106,6 +116,8 @@ class CORE_EXPORT QgsVectorRandomColorRampV2 : public QgsVectorColorRampV2
106116

107117
static QgsVectorColorRampV2* create( const QgsStringMap& properties = QgsStringMap() );
108118

119+
virtual double value( int index ) const;
120+
109121
virtual QColor color( double value ) const;
110122

111123
virtual QString type() const { return "random"; }
@@ -150,6 +162,8 @@ class CORE_EXPORT QgsVectorColorBrewerColorRampV2 : public QgsVectorColorRampV2
150162

151163
static QgsVectorColorRampV2* create( const QgsStringMap& properties = QgsStringMap() );
152164

165+
virtual double value( int index ) const;
166+
153167
virtual QColor color( double value ) const;
154168

155169
virtual QString type() const { return "colorbrewer"; }
@@ -159,6 +173,7 @@ class CORE_EXPORT QgsVectorColorBrewerColorRampV2 : public QgsVectorColorRampV2
159173
virtual QgsStringMap properties() const;
160174

161175
QString schemeName() const { return mSchemeName; }
176+
virtual int count() const { return mColors; }
162177
int colors() const { return mColors; }
163178

164179
void setSchemeName( QString schemeName ) { mSchemeName = schemeName; loadPalette(); }
@@ -212,7 +227,6 @@ class CORE_EXPORT QgsCptCityColorRampV2 : public QgsVectorGradientColorRampV2
212227

213228
void loadPalette() { loadFile(); }
214229
bool hasMultiStops() const { return mMultiStops; }
215-
int count() const { return mStops.count() + 2; }
216230

217231
QString fileName() const;
218232
bool loadFile();

src/gui/raster/qgsrasterminmaxwidget.h

+3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ class GUI_EXPORT QgsRasterMinMaxWidget: public QWidget, private Ui::QgsRasterMin
3333

3434
void setBands( const QList<int> & theBands ) { mBands = theBands; }
3535

36+
// Load programmaticaly with current values
37+
void load() { on_mLoadPushButton_clicked(); }
38+
3639
signals:
3740
void load( int theBandNo, double theMin, double theMax, int origin );
3841

src/gui/raster/qgssinglebandpseudocolorrendererwidget.cpp

+48-4
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,19 @@
3232
QgsSingleBandPseudoColorRendererWidget::QgsSingleBandPseudoColorRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent ):
3333
QgsRasterRendererWidget( layer, extent )
3434
{
35+
QSettings settings;
36+
3537
setupUi( this );
3638

3739
mColormapTreeWidget->setColumnWidth( 1, 50 );
3840

41+
QString defaultPalette = settings.value( "/Raster/defaultPalette", "Spectral" ).toString();
42+
3943
mColorRampComboBox->populate( QgsStyleV2::defaultStyle() );
4044

45+
QgsDebugMsg( "defaultPalette = " + defaultPalette );
46+
mColorRampComboBox->setCurrentIndex( mColorRampComboBox->findText( defaultPalette ) );
47+
4148
if ( !mRasterLayer )
4249
{
4350
return;
@@ -74,13 +81,22 @@ QgsSingleBandPseudoColorRendererWidget::QgsSingleBandPseudoColorRendererWidget(
7481
mColorInterpolationComboBox->addItem( tr( "Linear" ), 1 );
7582
mColorInterpolationComboBox->addItem( tr( "Exact" ), 2 );
7683
mColorInterpolationComboBox->setCurrentIndex( 1 );
77-
mClassificationModeComboBox->addItem( tr( "Equal interval" ) );
84+
mClassificationModeComboBox->addItem( tr( "Continuous" ), Continuous );
85+
mClassificationModeComboBox->addItem( tr( "Equal interval" ), EqualInterval );
7886
//quantile would be nice as well
7987

8088
mNumberOfEntriesSpinBox->setValue( 5 ); // some default
8189

8290
setFromRenderer( layer->renderer() );
8391

92+
// If there is currently no min/max, load default with user current default options
93+
if ( mMinLineEdit->text().isEmpty() || mMaxLineEdit->text().isEmpty() )
94+
{
95+
mMinMaxWidget->load();
96+
}
97+
98+
on_mClassificationModeComboBox_currentIndexChanged( 0 );
99+
84100
resetClassifyButton();
85101
}
86102

@@ -92,6 +108,7 @@ QgsRasterRenderer* QgsSingleBandPseudoColorRendererWidget::renderer()
92108
{
93109
QgsRasterShader* rasterShader = new QgsRasterShader();
94110
QgsColorRampShader* colorRampShader = new QgsColorRampShader();
111+
colorRampShader->setClip( mClipCheckBox->isChecked() );
95112

96113
//iterate through mColormapTreeWidget and set colormap info of layer
97114
QList<QgsColorRampShader::ColorRampItem> colorRampItems;
@@ -217,16 +234,31 @@ void QgsSingleBandPseudoColorRendererWidget::on_mClassifyButton_clicked()
217234

218235
//int bandNr = mBandComboBox->itemData( bandComboIndex ).toInt();
219236
//QgsRasterBandStats myRasterBandStats = mRasterLayer->dataProvider()->bandStatistics( bandNr );
220-
int numberOfEntries = mNumberOfEntriesSpinBox->value();
237+
int numberOfEntries = 0;
221238

222239
QList<double> entryValues;
223240
QList<QColor> entryColors;
224241

225242
double min = lineEditValue( mMinLineEdit );
226243
double max = lineEditValue( mMaxLineEdit );
227244

228-
if ( mClassificationModeComboBox->currentText() == tr( "Equal interval" ) )
245+
QgsVectorColorRampV2* colorRamp = mColorRampComboBox->currentColorRamp();
246+
247+
if ( mClassificationModeComboBox->itemData( mClassificationModeComboBox->currentIndex() ).toInt() == Continuous )
248+
{
249+
if ( colorRamp )
250+
{
251+
numberOfEntries = colorRamp->count();
252+
for ( int i = 0; i < colorRamp->count(); ++i )
253+
{
254+
double value = colorRamp->value( i );
255+
entryValues.push_back( min + value * ( max - min ) );
256+
}
257+
}
258+
}
259+
else // EqualInterval
229260
{
261+
numberOfEntries = mNumberOfEntriesSpinBox->value();
230262
//double currentValue = myRasterBandStats.minimumValue;
231263
double currentValue = min;
232264
double intervalDiff;
@@ -265,7 +297,6 @@ void QgsSingleBandPseudoColorRendererWidget::on_mClassifyButton_clicked()
265297
}
266298
#endif
267299

268-
QgsVectorColorRampV2* colorRamp = mColorRampComboBox->currentColorRamp();
269300
if ( ! colorRamp )
270301
{
271302
//hard code color range from blue -> red (previous default)
@@ -307,6 +338,18 @@ void QgsSingleBandPseudoColorRendererWidget::on_mClassifyButton_clicked()
307338
}
308339
}
309340

341+
void QgsSingleBandPseudoColorRendererWidget::on_mClassificationModeComboBox_currentIndexChanged( int index )
342+
{
343+
mNumberOfEntriesSpinBox->setEnabled( mClassificationModeComboBox->itemData( index ).toInt() == EqualInterval );
344+
}
345+
346+
void QgsSingleBandPseudoColorRendererWidget::on_mColorRampComboBox_currentIndexChanged( int index )
347+
{
348+
Q_UNUSED( index );
349+
QSettings settings;
350+
settings.setValue( "/Raster/defaultPalette", mColorRampComboBox->currentText() );
351+
}
352+
310353
void QgsSingleBandPseudoColorRendererWidget::populateColormapTreeWidget( const QList<QgsColorRampShader::ColorRampItem>& colorRampItems )
311354
{
312355
mColormapTreeWidget->clear();
@@ -545,6 +588,7 @@ void QgsSingleBandPseudoColorRendererWidget::setFromRenderer( const QgsRasterRen
545588
newItem->setBackground( 1, QBrush( it->color ) );
546589
newItem->setText( 2, it->label );
547590
}
591+
mClipCheckBox->setChecked( colorRampShader->clip() );
548592
}
549593
}
550594
setLineEditValue( mMinLineEdit, pr->classificationMin() );

src/gui/raster/qgssinglebandpseudocolorrendererwidget.h

+8
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ class GUI_EXPORT QgsSingleBandPseudoColorRendererWidget: public QgsRasterRendere
2828
{
2929
Q_OBJECT
3030
public:
31+
enum Mode
32+
{
33+
Continuous = 1, // Using breaks from color palette
34+
EqualInterval = 2
35+
};
36+
3137
QgsSingleBandPseudoColorRendererWidget( QgsRasterLayer* layer, const QgsRectangle &extent = QgsRectangle() );
3238
~QgsSingleBandPseudoColorRendererWidget();
3339

@@ -56,6 +62,8 @@ class GUI_EXPORT QgsSingleBandPseudoColorRendererWidget: public QgsRasterRendere
5662
void on_mMaxLineEdit_textChanged( const QString & text ) { Q_UNUSED( text ); resetClassifyButton(); }
5763
void on_mMinLineEdit_textEdited( const QString & text ) { Q_UNUSED( text ); mMinMaxOrigin = QgsRasterRenderer::MinMaxUser; showMinMaxOrigin(); }
5864
void on_mMaxLineEdit_textEdited( const QString & text ) { Q_UNUSED( text ); mMinMaxOrigin = QgsRasterRenderer::MinMaxUser; showMinMaxOrigin(); }
65+
void on_mClassificationModeComboBox_currentIndexChanged( int index );
66+
void on_mColorRampComboBox_currentIndexChanged( int index );
5967

6068
private:
6169
void setLineEditValue( QLineEdit *theLineEdit, double theValue );

0 commit comments

Comments
 (0)