Skip to content

Commit

Permalink
Add numeric formatting option to round to number of significant figures
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jan 9, 2020
1 parent f4f8a53 commit ad6684b
Show file tree
Hide file tree
Showing 13 changed files with 191 additions and 27 deletions.
Expand Up @@ -20,6 +20,12 @@ A numeric formatter which returns a simple text representation of a value.
%End
public:

enum RoundingType
{
DecimalPlaces,
SignificantFigures,
};

QgsBasicNumericFormat();
%Docstring
Default constructor
Expand Down Expand Up @@ -104,6 +110,20 @@ numberDecimalPlaces()).
.. seealso:: :py:func:`showTrailingZeros`

.. seealso:: :py:func:`setNumberDecimalPlaces`
%End

RoundingType roundingType() const;
%Docstring
Returns the rounding type, which controls the behavior of the numberDecimalPlaces() setting.

.. seealso:: :py:func:`setDirectionFormat`
%End

void setRoundingType( RoundingType type );
%Docstring
Sets the rounding ``type``, which controls the behavior of the numberDecimalPlaces() setting.

.. seealso:: :py:func:`roundingType`
%End

protected:
Expand Down
Expand Up @@ -57,7 +57,7 @@ described in the returned strings.
.. seealso:: :py:func:`setDirectionFormat`
%End

void setDirectionFormat( const FormatDirectionOption &format );
void setDirectionFormat( FormatDirectionOption format );
%Docstring
Sets the directional formatting option, which controls how bearing direction is
described in the returned strings.
Expand Down
Expand Up @@ -55,7 +55,7 @@ Returns the format of the incoming values.
.. seealso:: :py:func:`setInputValues`
%End

void setInputValues( const InputValues &format );
void setInputValues( InputValues format );
%Docstring
Sets the ``format`` of the incoming values.

Expand Down
42 changes: 40 additions & 2 deletions src/core/numericformats/qgsbasicnumericformat.cpp
Expand Up @@ -62,11 +62,37 @@ QString QgsBasicNumericFormat::formatDouble( double value, const QgsNumericForma
os.imbue( std::locale( os.getloc(), new formatter( context.thousandsSeparator(), mShowThousandsSeparator, context.decimalSeparator() ) ) );

if ( !mUseScientific )
os << std::fixed << std::setprecision( mNumberDecimalPlaces );
{
switch ( mRoundingType )
{
case DecimalPlaces:
os << std::fixed << std::setprecision( mNumberDecimalPlaces );
os << value;
break;

case SignificantFigures:
{
if ( qgsDoubleNear( value, 0 ) )
{
os << std::fixed << std::setprecision( mNumberDecimalPlaces - 1 ) << value;
}
else
{
// digits before decimal point
const int d = std::floor( std::log10( value < 0 ? -value : value ) ) + 1;
double order = std::pow( 10.0, mNumberDecimalPlaces - d );
os << std::fixed << std::setprecision( std::max( mNumberDecimalPlaces - d, 0 ) ) << std::round( value * order ) / order;
}
break;
}
}
}
else
{
os << std::scientific << std::setprecision( mNumberDecimalPlaces );
os << value;
}

os << value;
QString res = QString::fromStdWString( os.str() );

if ( mShowPlusSign && value > 0 )
Expand Down Expand Up @@ -118,6 +144,7 @@ QVariantMap QgsBasicNumericFormat::configuration( const QgsReadWriteContext & )
res.insert( QStringLiteral( "show_thousand_separator" ), mShowThousandsSeparator );
res.insert( QStringLiteral( "show_plus" ), mShowPlusSign );
res.insert( QStringLiteral( "show_trailing_zeros" ), mShowTrailingZeros );
res.insert( QStringLiteral( "rounding_type" ), static_cast< int >( mRoundingType ) );
return res;
}

Expand All @@ -127,6 +154,7 @@ void QgsBasicNumericFormat::setConfiguration( const QVariantMap &configuration,
mShowThousandsSeparator = configuration.value( QStringLiteral( "show_thousand_separator" ), true ).toBool();
mShowPlusSign = configuration.value( QStringLiteral( "show_plus" ), false ).toBool();
mShowTrailingZeros = configuration.value( QStringLiteral( "show_trailing_zeros" ), false ).toBool();
mRoundingType = static_cast< RoundingType >( configuration.value( QStringLiteral( "rounding_type" ), static_cast< int >( DecimalPlaces ) ).toInt() );
}

int QgsBasicNumericFormat::numberDecimalPlaces() const
Expand Down Expand Up @@ -168,3 +196,13 @@ void QgsBasicNumericFormat::setShowTrailingZeros( bool showTrailingZeros )
{
mShowTrailingZeros = showTrailingZeros;
}

QgsBasicNumericFormat::RoundingType QgsBasicNumericFormat::roundingType() const
{
return mRoundingType;
}

void QgsBasicNumericFormat::setRoundingType( QgsBasicNumericFormat::RoundingType type )
{
mRoundingType = type;
}
25 changes: 25 additions & 0 deletions src/core/numericformats/qgsbasicnumericformat.h
Expand Up @@ -32,6 +32,15 @@ class CORE_EXPORT QgsBasicNumericFormat : public QgsNumericFormat
{
public:

/**
* Sets rounding type and behavior of the numberDecimalPlaces() setting.
*/
enum RoundingType
{
DecimalPlaces, //!< Maximum number of decimal places
SignificantFigures, //!< Maximum number of significant figures
};

/**
* Default constructor
*/
Expand Down Expand Up @@ -103,6 +112,20 @@ class CORE_EXPORT QgsBasicNumericFormat : public QgsNumericFormat
*/
void setShowTrailingZeros( bool show );

/**
* Returns the rounding type, which controls the behavior of the numberDecimalPlaces() setting.
*
* \see setDirectionFormat()
*/
RoundingType roundingType() const;

/**
* Sets the rounding \a type, which controls the behavior of the numberDecimalPlaces() setting.
*
* \see roundingType()
*/
void setRoundingType( RoundingType type );

protected:

/**
Expand All @@ -118,6 +141,8 @@ class CORE_EXPORT QgsBasicNumericFormat : public QgsNumericFormat
bool mShowThousandsSeparator = true;
bool mShowPlusSign = false;
bool mShowTrailingZeros = false;

RoundingType mRoundingType = DecimalPlaces;
};

#endif // QGSBASICNUMERICFORMAT_H
2 changes: 1 addition & 1 deletion src/core/numericformats/qgsbearingnumericformat.h
Expand Up @@ -68,7 +68,7 @@ class CORE_EXPORT QgsBearingNumericFormat : public QgsBasicNumericFormat
*
* \see directionFormat()
*/
void setDirectionFormat( const FormatDirectionOption &format );
void setDirectionFormat( FormatDirectionOption format );

void setConfiguration( const QVariantMap &configuration, const QgsReadWriteContext &context ) override;

Expand Down
1 change: 1 addition & 0 deletions src/core/numericformats/qgscurrencynumericformat.cpp
Expand Up @@ -69,6 +69,7 @@ QgsNumericFormat *QgsCurrencyNumericFormat::create( const QVariantMap &configura
// override base class default for number of decimal places -- we want to default to 2, showing trailing zeros
res->setNumberDecimalPlaces( configuration.value( QStringLiteral( "decimals" ), 2 ).toInt() );
res->setShowTrailingZeros( configuration.value( QStringLiteral( "show_trailing_zeros" ), true ).toBool() );
res->setRoundingType( QgsBasicNumericFormat::DecimalPlaces );

return res.release();
}
Expand Down
3 changes: 2 additions & 1 deletion src/core/numericformats/qgspercentagenumericformat.cpp
Expand Up @@ -75,6 +75,7 @@ QgsNumericFormat *QgsPercentageNumericFormat::create( const QVariantMap &configu
std::unique_ptr< QgsPercentageNumericFormat > res = qgis::make_unique< QgsPercentageNumericFormat >();
res->setConfiguration( configuration, context );
res->mInputValues = static_cast< InputValues >( configuration.value( QStringLiteral( "input_values" ), static_cast< int >( ValuesArePercentage ) ).toInt() );
res->setRoundingType( QgsBasicNumericFormat::DecimalPlaces );
return res.release();
}

Expand All @@ -90,7 +91,7 @@ QgsPercentageNumericFormat::InputValues QgsPercentageNumericFormat::inputValues(
return mInputValues;
}

void QgsPercentageNumericFormat::setInputValues( const InputValues &inputValues )
void QgsPercentageNumericFormat::setInputValues( InputValues inputValues )
{
mInputValues = inputValues;
}
2 changes: 1 addition & 1 deletion src/core/numericformats/qgspercentagenumericformat.h
Expand Up @@ -62,7 +62,7 @@ class CORE_EXPORT QgsPercentageNumericFormat : public QgsBasicNumericFormat
*
* \see inputValues()
*/
void setInputValues( const InputValues &format );
void setInputValues( InputValues format );

private:

Expand Down
1 change: 1 addition & 0 deletions src/core/numericformats/qgsscientificnumericformat.cpp
Expand Up @@ -52,6 +52,7 @@ QgsNumericFormat *QgsScientificNumericFormat::create( const QVariantMap &configu
{
std::unique_ptr< QgsScientificNumericFormat > res = qgis::make_unique< QgsScientificNumericFormat >();
res->setConfiguration( configuration, context );
res->setRoundingType( QgsBasicNumericFormat::DecimalPlaces );
return res.release();
}

Expand Down
31 changes: 31 additions & 0 deletions src/gui/numericformats/qgsnumericformatwidget.cpp
Expand Up @@ -59,6 +59,26 @@ QgsBasicNumericFormatWidget::QgsBasicNumericFormatWidget( const QgsNumericFormat
if ( !mBlockSignals )
emit changed();
} );

connect( mRadDecimalPlaces, &QRadioButton::toggled, this, [ = ]( bool checked )
{
if ( !checked )
return;

mFormat->setRoundingType( QgsBasicNumericFormat::DecimalPlaces );
if ( !mBlockSignals )
emit changed();
} );

connect( mRadSignificantFigures, &QRadioButton::toggled, this, [ = ]( bool checked )
{
if ( !checked )
return;

mFormat->setRoundingType( QgsBasicNumericFormat::SignificantFigures );
if ( !mBlockSignals )
emit changed();
} );
}

QgsBasicNumericFormatWidget::~QgsBasicNumericFormatWidget() = default;
Expand All @@ -72,6 +92,17 @@ void QgsBasicNumericFormatWidget::setFormat( QgsNumericFormat *format )
mShowPlusCheckBox->setChecked( mFormat->showPlusSign() );
mShowTrailingZerosCheckBox->setChecked( mFormat->showTrailingZeros() );
mShowThousandsCheckBox->setChecked( mFormat->showThousandsSeparator() );
switch ( mFormat->roundingType() )
{
case QgsBasicNumericFormat::DecimalPlaces:
mRadDecimalPlaces->setChecked( true );
break;

case QgsBasicNumericFormat::SignificantFigures:
mRadSignificantFigures->setChecked( true );
break;
}

mBlockSignals = false;
}

Expand Down
57 changes: 37 additions & 20 deletions src/ui/numericformats/qgsbasicnumericformatwidgetbase.ui
Expand Up @@ -6,18 +6,31 @@
<rect>
<x>0</x>
<y>0</y>
<width>245</width>
<height>297</height>
<width>221</width>
<height>285</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
<item row="6" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Decimal places</string>
<string>Round to</string>
</property>
</widget>
</item>
Expand All @@ -28,20 +41,7 @@
</property>
</widget>
</item>
<item row="4" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0" colspan="2">
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="mShowThousandsCheckBox">
<property name="text">
<string>Show thousands separator</string>
Expand All @@ -51,20 +51,37 @@
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="mShowPlusCheckBox">
<property name="text">
<string>Show plus sign</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<item row="5" column="0" colspan="2">
<widget class="QCheckBox" name="mShowTrailingZerosCheckBox">
<property name="text">
<string>Show trailing zeros</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QRadioButton" name="mRadDecimalPlaces">
<property name="text">
<string>Decimal places</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QRadioButton" name="mRadSignificantFigures">
<property name="text">
<string>Significant figures</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
Expand Down

0 comments on commit ad6684b

Please sign in to comment.