Skip to content

Commit

Permalink
Raster shader: store label precision
Browse files Browse the repository at this point in the history
  • Loading branch information
elpaso committed Nov 9, 2020
1 parent 58ce77f commit 02552e4
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 71 deletions.
16 changes: 16 additions & 0 deletions python/core/auto_generated/raster/qgsrastershaderfunction.sip.in
Expand Up @@ -113,11 +113,27 @@ Returns the minimum value for the raster shader.
virtual void legendSymbologyItems( QList< QPair< QString, QColor > > &symbolItems /Out/ ) const; virtual void legendSymbologyItems( QList< QPair< QString, QColor > > &symbolItems /Out/ ) const;
%Docstring %Docstring
Returns legend symbology items if provided by renderer. Returns legend symbology items if provided by renderer.
%End

int labelPrecision() const;
%Docstring
Returns label precision

.. versionadded:: 3.16
%End

void setLabelPrecision( int labelPrecision );
%Docstring
Sets label precision to ``labelPrecision``

.. versionadded:: 3.16
%End %End


protected: protected:






}; };
/************************************************************************ /************************************************************************
* This file has been generated automatically from * * This file has been generated automatically from *
Expand Down
Expand Up @@ -112,6 +112,7 @@ Loads min and max values from color ramp tree
%End %End


protected: protected:

void populateColormapTreeWidget( const QList<QgsColorRampShader::ColorRampItem> &colorRampItems ); void populateColormapTreeWidget( const QList<QgsColorRampShader::ColorRampItem> &colorRampItems );
%Docstring %Docstring
Populates color ramp tree from ramp items Populates color ramp tree from ramp items
Expand Down
2 changes: 2 additions & 0 deletions src/core/raster/qgscolorrampshader.cpp
Expand Up @@ -507,6 +507,7 @@ QDomElement QgsColorRampShader::writeXml( QDomDocument &doc ) const
colorRampShaderElem.setAttribute( QStringLiteral( "clip" ), clip() ); colorRampShaderElem.setAttribute( QStringLiteral( "clip" ), clip() );
colorRampShaderElem.setAttribute( QStringLiteral( "minimumValue" ), mMinimumValue ); colorRampShaderElem.setAttribute( QStringLiteral( "minimumValue" ), mMinimumValue );
colorRampShaderElem.setAttribute( QStringLiteral( "maximumValue" ), mMaximumValue ); colorRampShaderElem.setAttribute( QStringLiteral( "maximumValue" ), mMaximumValue );
colorRampShaderElem.setAttribute( QStringLiteral( "labelPrecision" ), mLabelPrecision );


// save source color ramp // save source color ramp
if ( sourceColorRamp() ) if ( sourceColorRamp() )
Expand Down Expand Up @@ -544,6 +545,7 @@ void QgsColorRampShader::readXml( const QDomElement &colorRampShaderElem )
setClip( colorRampShaderElem.attribute( QStringLiteral( "clip" ), QStringLiteral( "0" ) ) == QLatin1String( "1" ) ); setClip( colorRampShaderElem.attribute( QStringLiteral( "clip" ), QStringLiteral( "0" ) ) == QLatin1String( "1" ) );
setMinimumValue( colorRampShaderElem.attribute( QStringLiteral( "minimumValue" ) ).toDouble() ); setMinimumValue( colorRampShaderElem.attribute( QStringLiteral( "minimumValue" ) ).toDouble() );
setMaximumValue( colorRampShaderElem.attribute( QStringLiteral( "maximumValue" ) ).toDouble() ); setMaximumValue( colorRampShaderElem.attribute( QStringLiteral( "maximumValue" ) ).toDouble() );
setLabelPrecision( colorRampShaderElem.attribute( QStringLiteral( "labelPrecision" ), QStringLiteral( "6" ) ).toDouble() );


QList<QgsColorRampShader::ColorRampItem> itemList; QList<QgsColorRampShader::ColorRampItem> itemList;
QDomElement itemElem; QDomElement itemElem;
Expand Down
1 change: 1 addition & 0 deletions src/core/raster/qgscolorrampshader.h
Expand Up @@ -229,6 +229,7 @@ class CORE_EXPORT QgsColorRampShader : public QgsRasterShaderFunction


//! Do not render values out of range //! Do not render values out of range
bool mClip = false; bool mClip = false;

}; };


#endif #endif
1 change: 1 addition & 0 deletions src/core/raster/qgsrastershader.cpp
Expand Up @@ -115,3 +115,4 @@ void QgsRasterShader::readXml( const QDomElement &elem )
setRasterShaderFunction( colorRampShader ); setRasterShaderFunction( colorRampShader );
} }
} }

11 changes: 11 additions & 0 deletions src/core/raster/qgsrastershaderfunction.cpp
Expand Up @@ -69,3 +69,14 @@ bool QgsRasterShaderFunction::shade( double redValue, double greenValue, double


return false; return false;
} }


int QgsRasterShaderFunction::labelPrecision() const
{
return mLabelPrecision;
}

void QgsRasterShaderFunction::setLabelPrecision( int labelPrecision )
{
mLabelPrecision = labelPrecision;
}
16 changes: 16 additions & 0 deletions src/core/raster/qgsrastershaderfunction.h
Expand Up @@ -123,6 +123,18 @@ class CORE_EXPORT QgsRasterShaderFunction
*/ */
virtual void legendSymbologyItems( QList< QPair< QString, QColor > > &symbolItems SIP_OUT ) const { Q_UNUSED( symbolItems ) } virtual void legendSymbologyItems( QList< QPair< QString, QColor > > &symbolItems SIP_OUT ) const { Q_UNUSED( symbolItems ) }


/**
* Returns label precision
* \since QGIS 3.16
*/
int labelPrecision() const;

/**
* Sets label precision to \a labelPrecision
* \since QGIS 3.16
*/
void setLabelPrecision( int labelPrecision );

protected: protected:
//! \brief User defineable maximum value for the shading function //! \brief User defineable maximum value for the shading function
double mMaximumValue; double mMaximumValue;
Expand All @@ -132,5 +144,9 @@ class CORE_EXPORT QgsRasterShaderFunction


//! \brief Minimum maximum range for the shading function //! \brief Minimum maximum range for the shading function
double mMinimumMaximumRange; double mMinimumMaximumRange;

//! \brief Label precision
int mLabelPrecision = 6;

}; };
#endif #endif
169 changes: 98 additions & 71 deletions src/gui/raster/qgscolorrampshaderwidget.cpp
Expand Up @@ -144,6 +144,7 @@ void QgsColorRampShaderWidget::setExtent( const QgsRectangle &extent )
QgsColorRampShader QgsColorRampShaderWidget::shader() const QgsColorRampShader QgsColorRampShaderWidget::shader() const
{ {
QgsColorRampShader colorRampShader( mMin, mMax ); QgsColorRampShader colorRampShader( mMin, mMax );
colorRampShader.setLabelPrecision( mLabelPrecisionSpinBox->value() );
colorRampShader.setColorRampType( static_cast< QgsColorRampShader::Type >( mColorInterpolationComboBox->currentData().toInt() ) ); colorRampShader.setColorRampType( static_cast< QgsColorRampShader::Type >( mColorInterpolationComboBox->currentData().toInt() ) );
colorRampShader.setClassificationMode( static_cast< QgsColorRampShader::ClassificationMode >( mClassificationModeComboBox->currentData().toInt() ) ); colorRampShader.setClassificationMode( static_cast< QgsColorRampShader::ClassificationMode >( mClassificationModeComboBox->currentData().toInt() ) );
colorRampShader.setClip( mClipCheckBox->isChecked() ); colorRampShader.setClip( mClipCheckBox->isChecked() );
Expand Down Expand Up @@ -183,57 +184,9 @@ void QgsColorRampShaderWidget::autoLabel()
dumpClasses(); dumpClasses();
#endif #endif


QgsColorRampShader::Type interpolation = static_cast< QgsColorRampShader::Type >( mColorInterpolationComboBox->currentData().toInt() ); const QString unit = mUnitLineEdit->text();
bool discrete = interpolation == QgsColorRampShader::Discrete;
QString unit = mUnitLineEdit->text();
QString label;
int topLevelItemCount = mColormapTreeWidget->topLevelItemCount(); int topLevelItemCount = mColormapTreeWidget->topLevelItemCount();


auto applyPrecision = [ = ]( const QString & value )
{
Qgis::DataType dataType { mRasterDataProvider ? mRasterDataProvider->dataType( mBand ) : Qgis::DataType::Float64 };
switch ( dataType )
{
case Qgis::DataType::Int16:
case Qgis::DataType::UInt16:
case Qgis::DataType::Int32:
case Qgis::DataType::UInt32:
case Qgis::DataType::Byte:
case Qgis::DataType::CInt16:
case Qgis::DataType::CInt32:
case Qgis::DataType::ARGB32:
case Qgis::DataType::ARGB32_Premultiplied:
{
return QLocale().toString( QLocale().toLongLong( value ) );
}
case Qgis::DataType::Float32:
case Qgis::DataType::CFloat32:
{
double val { value.toFloat( ) };
if ( mLabelPrecisionSpinBox->value() < 0 )
{
const double factor = std::pow( 10, - mLabelPrecisionSpinBox->value() );
val = static_cast<qlonglong>( val / factor ) * factor;
return QLocale().toString( val, 'f', 0 );
}
return QLocale().toString( val, 'f', mLabelPrecisionSpinBox->value() );
}
case Qgis::DataType::Float64:
case Qgis::DataType::CFloat64:
case Qgis::DataType::UnknownDataType:
{
double val { value.toDouble( ) };
if ( mLabelPrecisionSpinBox->value() < 0 )
{
const double factor = std::pow( 10, - mLabelPrecisionSpinBox->value() );
val = static_cast<qlonglong>( val / factor ) * factor;
return QLocale().toString( val, 'f', 0 );
}
return QLocale().toString( val, 'f', mLabelPrecisionSpinBox->value() );
}
}
};

QTreeWidgetItem *currentItem = nullptr; QTreeWidgetItem *currentItem = nullptr;
for ( int i = 0; i < topLevelItemCount; ++i ) for ( int i = 0; i < topLevelItemCount; ++i )
{ {
Expand All @@ -244,29 +197,11 @@ void QgsColorRampShaderWidget::autoLabel()
continue; continue;
} }


if ( discrete ) const QString lbl = label( currentItem, i, unit );
{
if ( i == 0 )
{
label = "<= " + applyPrecision( currentItem->data( ValueColumn, Qt::ItemDataRole::DisplayRole ).toString() ) + unit;
}
else if ( currentItem->data( ValueColumn, Qt::ItemDataRole::DisplayRole ).toDouble( ) == std::numeric_limits<double>::infinity() )
{
label = "> " + applyPrecision( mColormapTreeWidget->topLevelItem( i - 1 )->data( ValueColumn, Qt::ItemDataRole::DisplayRole ).toString() ) + unit;
}
else
{
label = applyPrecision( mColormapTreeWidget->topLevelItem( i - 1 )->data( ValueColumn, Qt::ItemDataRole::DisplayRole ).toString() ) + " - " + applyPrecision( currentItem->data( ValueColumn, Qt::ItemDataRole::DisplayRole ).toString() ) + unit;
}
}
else
{
label = applyPrecision( currentItem->data( ValueColumn, Qt::ItemDataRole::DisplayRole ).toString() ) + unit;
}


if ( currentItem->text( LabelColumn ).isEmpty() || currentItem->text( LabelColumn ) == label || currentItem->foreground( LabelColumn ).color() == QColor( Qt::gray ) ) if ( currentItem->text( LabelColumn ).isEmpty() || currentItem->text( LabelColumn ) == lbl || currentItem->foreground( LabelColumn ).color() == QColor( Qt::gray ) )
{ {
currentItem->setText( LabelColumn, label ); currentItem->setText( LabelColumn, lbl );
currentItem->setForeground( LabelColumn, QBrush( QColor( Qt::gray ) ) ); currentItem->setForeground( LabelColumn, QBrush( QColor( Qt::gray ) ) );
} }
} }
Expand Down Expand Up @@ -496,23 +431,38 @@ void QgsColorRampShaderWidget::populateColormapTreeWidget( const QList<QgsColorR
{ {
mColormapTreeWidget->clear(); mColormapTreeWidget->clear();
QList<QgsColorRampShader::ColorRampItem>::const_iterator it = colorRampItems.constBegin(); QList<QgsColorRampShader::ColorRampItem>::const_iterator it = colorRampItems.constBegin();
int i = 0;
for ( ; it != colorRampItems.constEnd(); ++it ) for ( ; it != colorRampItems.constEnd(); ++it )
{ {
QgsTreeWidgetItemObject *newItem = new QgsTreeWidgetItemObject( mColormapTreeWidget ); QgsTreeWidgetItemObject *newItem = new QgsTreeWidgetItemObject( mColormapTreeWidget );
newItem->setText( ValueColumn, QLocale().toString( it->value, 'g', 15 ) );
newItem->setData( ValueColumn, Qt::ItemDataRole::DisplayRole, it->value ); newItem->setData( ValueColumn, Qt::ItemDataRole::DisplayRole, it->value );
newItem->setData( ColorColumn, Qt::ItemDataRole::EditRole, it->color ); newItem->setData( ColorColumn, Qt::ItemDataRole::EditRole, it->color );
newItem->setText( LabelColumn, it->label ); newItem->setText( LabelColumn, it->label );
newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable ); newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable );
connect( newItem, &QgsTreeWidgetItemObject::itemEdited, connect( newItem, &QgsTreeWidgetItemObject::itemEdited,
this, &QgsColorRampShaderWidget::mColormapTreeWidget_itemEdited ); this, &QgsColorRampShaderWidget::mColormapTreeWidget_itemEdited );
++i;
} }


#ifdef QGISDEBUG #ifdef QGISDEBUG
dumpClasses(); dumpClasses();
#endif #endif


setUnitFromLabels(); setUnitFromLabels();

// Now we have the suffix
const QString unit = mUnitLineEdit->text();
for ( i = 0; i < mColormapTreeWidget->topLevelItemCount(); i++ )
{
QgsTreeWidgetItemObject *currentItem { static_cast<QgsTreeWidgetItemObject *>( mColormapTreeWidget->topLevelItem( i ) ) };
QString lbl { label( currentItem, i, unit )};
if ( currentItem->text( LabelColumn ).isEmpty() || currentItem->text( LabelColumn ) == lbl || currentItem->foreground( LabelColumn ).color() == QColor( Qt::gray ) )
{
currentItem->setText( LabelColumn, lbl );
currentItem->setForeground( LabelColumn, QBrush( QColor( Qt::gray ) ) );
}
}

} }


void QgsColorRampShaderWidget::mLoadFromBandButton_clicked() void QgsColorRampShaderWidget::mLoadFromBandButton_clicked()
Expand Down Expand Up @@ -675,6 +625,8 @@ void QgsColorRampShaderWidget::setFromShader( const QgsColorRampShader &colorRam
btnColorRamp->setColorRampFromName( defaultPalette ); btnColorRamp->setColorRampFromName( defaultPalette );
} }


mLabelPrecisionSpinBox->setValue( colorRampShader.labelPrecision() );

populateColormapTreeWidget( colorRampShader.colorRampItemList() ); populateColormapTreeWidget( colorRampShader.colorRampItemList() );


emit widgetChanged(); emit widgetChanged();
Expand Down Expand Up @@ -787,6 +739,81 @@ void QgsColorRampShaderWidget::resetClassifyButton()
} }
} }


QString QgsColorRampShaderWidget::label( QTreeWidgetItem *currentItem, bool row, const QString unit )
{
auto applyPrecision = [ = ]( const QString & value )
{
Qgis::DataType dataType { mRasterDataProvider ? mRasterDataProvider->dataType( mBand ) : Qgis::DataType::Float64 };
switch ( dataType )
{
case Qgis::DataType::Int16:
case Qgis::DataType::UInt16:
case Qgis::DataType::Int32:
case Qgis::DataType::UInt32:
case Qgis::DataType::Byte:
case Qgis::DataType::CInt16:
case Qgis::DataType::CInt32:
case Qgis::DataType::ARGB32:
case Qgis::DataType::ARGB32_Premultiplied:
{
return QLocale().toString( QLocale().toLongLong( value ) );
}
case Qgis::DataType::Float32:
case Qgis::DataType::CFloat32:
{
double val { value.toFloat( ) };
if ( mLabelPrecisionSpinBox->value() < 0 )
{
const double factor = std::pow( 10, - mLabelPrecisionSpinBox->value() );
val = static_cast<qlonglong>( val / factor ) * factor;
return QLocale().toString( val, 'f', 0 );
}
return QLocale().toString( val, 'f', mLabelPrecisionSpinBox->value() );
}
case Qgis::DataType::Float64:
case Qgis::DataType::CFloat64:
case Qgis::DataType::UnknownDataType:
{
double val { value.toDouble( ) };
if ( mLabelPrecisionSpinBox->value() < 0 )
{
const double factor = std::pow( 10, - mLabelPrecisionSpinBox->value() );
val = static_cast<qlonglong>( val / factor ) * factor;
return QLocale().toString( val, 'f', 0 );
}
return QLocale().toString( val, 'f', mLabelPrecisionSpinBox->value() );
}
}
};

QgsColorRampShader::Type interpolation = static_cast< QgsColorRampShader::Type >( mColorInterpolationComboBox->currentData().toInt() );
bool discrete = interpolation == QgsColorRampShader::Discrete;
QString lbl;

if ( discrete )
{
if ( row == 0 )
{
lbl = "<= " + applyPrecision( currentItem->data( ValueColumn, Qt::ItemDataRole::DisplayRole ).toString() ) + unit;
}
else if ( currentItem->data( ValueColumn, Qt::ItemDataRole::DisplayRole ).toDouble( ) == std::numeric_limits<double>::infinity() )
{
lbl = "> " + applyPrecision( mColormapTreeWidget->topLevelItem( row - 1 )->data( ValueColumn, Qt::ItemDataRole::DisplayRole ).toString() ) + unit;
}
else
{
lbl = applyPrecision( mColormapTreeWidget->topLevelItem( row - 1 )->data( ValueColumn, Qt::ItemDataRole::DisplayRole ).toString() ) + " - " + applyPrecision( currentItem->data( ValueColumn, Qt::ItemDataRole::DisplayRole ).toString() ) + unit;
}
}
else
{
lbl = applyPrecision( currentItem->data( ValueColumn, Qt::ItemDataRole::DisplayRole ).toString() ) + unit;
}

return lbl;

}

void QgsColorRampShaderWidget::changeColor() void QgsColorRampShaderWidget::changeColor()
{ {
QList<QTreeWidgetItem *> itemList; QList<QTreeWidgetItem *> itemList;
Expand Down
3 changes: 3 additions & 0 deletions src/gui/raster/qgscolorrampshaderwidget.h
Expand Up @@ -102,6 +102,7 @@ class GUI_EXPORT QgsColorRampShaderWidget: public QWidget, protected Ui::QgsColo
void loadMinimumMaximumFromTree(); void loadMinimumMaximumFromTree();


protected: protected:

//! Populates color ramp tree from ramp items //! Populates color ramp tree from ramp items
void populateColormapTreeWidget( const QList<QgsColorRampShader::ColorRampItem> &colorRampItems ); void populateColormapTreeWidget( const QList<QgsColorRampShader::ColorRampItem> &colorRampItems );


Expand Down Expand Up @@ -150,6 +151,8 @@ class GUI_EXPORT QgsColorRampShaderWidget: public QWidget, protected Ui::QgsColo
double lineEditValue( const QLineEdit *lineEdit ) const; double lineEditValue( const QLineEdit *lineEdit ) const;
void resetClassifyButton(); void resetClassifyButton();


QString label( QTreeWidgetItem *item, bool row, const QString unit );

#ifdef QGISDEBUG #ifdef QGISDEBUG
//! Dump all the classes for debugging purposes //! Dump all the classes for debugging purposes
void dumpClasses(); void dumpClasses();
Expand Down

0 comments on commit 02552e4

Please sign in to comment.