Skip to content

Commit

Permalink
Merge pull request #47173 from alexbruy/identify-number-format
Browse files Browse the repository at this point in the history
Homogenize number of decimal places in Identify tool (fix #27929)
  • Loading branch information
elpaso committed Feb 4, 2022
2 parents 91cf895 + db9e483 commit d5d3ed6
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 12 deletions.
20 changes: 18 additions & 2 deletions src/core/qgsunittypes.cpp
Expand Up @@ -2890,7 +2890,15 @@ QString QgsUnitTypes::formatDistance( double distance, int decimals, QgsUnitType
if ( dist.unit != DistanceUnknownUnit )
unitText = QChar( ' ' ) + QgsUnitTypes::toAbbreviatedString( dist.unit );

return QStringLiteral( "%L1%2" ).arg( dist.value, 0, 'f', decimals ).arg( unitText );
if ( qgsDoubleNear( dist.value, 0 ) )
{
unitText = QChar( ' ' ) + QgsUnitTypes::toAbbreviatedString( unit );
return QStringLiteral( "%L1%2" ).arg( distance, 0, 'e', decimals ).arg( unitText );
}
else
{
return QStringLiteral( "%L1%2" ).arg( dist.value, 0, 'f', decimals ).arg( unitText );
}
}

QString QgsUnitTypes::formatArea( double area, int decimals, QgsUnitTypes::AreaUnit unit, bool keepBaseUnit )
Expand All @@ -2902,7 +2910,15 @@ QString QgsUnitTypes::formatArea( double area, int decimals, QgsUnitTypes::AreaU
if ( areaValue.unit != AreaUnknownUnit )
unitText = QChar( ' ' ) + QgsUnitTypes::toAbbreviatedString( areaValue.unit );

return QStringLiteral( "%L1%2" ).arg( areaValue.value, 0, 'f', decimals ).arg( unitText );
if ( qgsDoubleNear( areaValue.value, 0 ) )
{
unitText = QChar( ' ' ) + QgsUnitTypes::toAbbreviatedString( unit );
return QStringLiteral( "%L1%2" ).arg( area, 0, 'e', decimals ).arg( unitText );
}
else
{
return QStringLiteral( "%L1%2" ).arg( areaValue.value, 0, 'f', decimals ).arg( unitText );
}
}

QString QgsUnitTypes::encodeUnit( RenderUnit unit )
Expand Down
4 changes: 2 additions & 2 deletions src/gui/qgsmaptoolidentify.cpp
Expand Up @@ -1184,15 +1184,15 @@ QString QgsMapToolIdentify::formatDistance( double distance, QgsUnitTypes::Dista
QgsSettings settings;
bool baseUnit = settings.value( QStringLiteral( "qgis/measure/keepbaseunit" ), true ).toBool();

return QgsDistanceArea::formatDistance( distance, 3, unit, baseUnit );
return QgsDistanceArea::formatDistance( distance, mCoordinatePrecision, unit, baseUnit );
}

QString QgsMapToolIdentify::formatArea( double area, QgsUnitTypes::AreaUnit unit ) const
{
QgsSettings settings;
bool baseUnit = settings.value( QStringLiteral( "qgis/measure/keepbaseunit" ), true ).toBool();

return QgsDistanceArea::formatArea( area, 3, unit, baseUnit );
return QgsDistanceArea::formatArea( area, mCoordinatePrecision, unit, baseUnit );
}

void QgsMapToolIdentify::formatChanged( QgsRasterLayer *layer )
Expand Down
17 changes: 13 additions & 4 deletions tests/src/app/testqgsmaptoolidentifyaction.cpp
Expand Up @@ -252,8 +252,8 @@ void TestQgsMapToolIdentifyAction::closestPoint()
//check that closest point attributes are present
QList<QgsMapToolIdentify::IdentifyResult> result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << tempLayer.get() );
QCOMPARE( result.length(), 1 );
QCOMPARE( result.at( 0 ).mDerivedAttributes[tr( "Closest X" )], QStringLiteral( "2484588" ) );
QCOMPARE( result.at( 0 ).mDerivedAttributes[tr( "Closest Y" )], QStringLiteral( "2399800" ) );
QCOMPARE( result.at( 0 ).mDerivedAttributes[tr( "Closest X" )], QStringLiteral( "2484588.000" ) );
QCOMPARE( result.at( 0 ).mDerivedAttributes[tr( "Closest Y" )], QStringLiteral( "2399800.000" ) );
QCOMPARE( result.at( 0 ).mDerivedAttributes[tr( "Interpolated M" )].left( 4 ), QStringLiteral( "36.7" ) );
QCOMPARE( result.at( 0 ).mDerivedAttributes[tr( "Interpolated Z" )].left( 4 ), QStringLiteral( "14.8" ) );

Expand All @@ -272,8 +272,8 @@ void TestQgsMapToolIdentifyAction::closestPoint()
mapPoint = canvas->getCoordinateTransform()->transform( 2484589, 2399800 );
result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << tempLayer2.get() );
QCOMPARE( result.length(), 1 );
QCOMPARE( result.at( 0 ).mDerivedAttributes[tr( "Closest X" )], QStringLiteral( "2484588" ) );
QCOMPARE( result.at( 0 ).mDerivedAttributes[tr( "Closest Y" )], QStringLiteral( "2399800" ) );
QCOMPARE( result.at( 0 ).mDerivedAttributes[tr( "Closest X" )], QStringLiteral( "2484588.000" ) );
QCOMPARE( result.at( 0 ).mDerivedAttributes[tr( "Closest Y" )], QStringLiteral( "2399800.000" ) );
QCOMPARE( result.at( 0 ).mDerivedAttributes[tr( "Interpolated M" )].left( 4 ), QStringLiteral( "11.9" ) );
QCOMPARE( result.at( 0 ).mDerivedAttributes[tr( "Interpolated Z" )].left( 4 ), QStringLiteral( "1.96" ) );
}
Expand Down Expand Up @@ -303,6 +303,9 @@ void TestQgsMapToolIdentifyAction::lengthCalculation()
QgsProject::instance()->setEllipsoid( QStringLiteral( "WGS84" ) );
QgsProject::instance()->setDistanceUnits( QgsUnitTypes::DistanceMeters );

QgsProject::instance()->writeEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/Automatic" ), false );
QgsProject::instance()->writeEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/DecimalPlaces" ), 3 );

const QgsPointXY mapPoint = canvas->getCoordinateTransform()->transform( 2484588, 2425722 );

std::unique_ptr< QgsMapToolIdentifyAction > action( new QgsMapToolIdentifyAction( canvas ) );
Expand Down Expand Up @@ -426,6 +429,9 @@ void TestQgsMapToolIdentifyAction::perimeterCalculation()
QgsProject::instance()->setEllipsoid( QStringLiteral( "WGS84" ) );
QgsProject::instance()->setDistanceUnits( QgsUnitTypes::DistanceMeters );

QgsProject::instance()->writeEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/Automatic" ), false );
QgsProject::instance()->writeEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/DecimalPlaces" ), 3 );

const QgsPointXY mapPoint = canvas->getCoordinateTransform()->transform( 2484588, 2425722 );

std::unique_ptr< QgsMapToolIdentifyAction > action( new QgsMapToolIdentifyAction( canvas ) );
Expand Down Expand Up @@ -501,6 +507,9 @@ void TestQgsMapToolIdentifyAction::areaCalculation()
QgsProject::instance()->setEllipsoid( QStringLiteral( "WGS84" ) );
QgsProject::instance()->setAreaUnits( QgsUnitTypes::AreaSquareMeters );

QgsProject::instance()->writeEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/Automatic" ), false );
QgsProject::instance()->writeEntry( QStringLiteral( "PositionPrecision" ), QStringLiteral( "/DecimalPlaces" ), 3 );

const QgsPointXY mapPoint = canvas->getCoordinateTransform()->transform( 2484588, 2425722 );

std::unique_ptr< QgsMapToolIdentifyAction > action( new QgsMapToolIdentifyAction( canvas ) );
Expand Down
103 changes: 99 additions & 4 deletions tests/src/python/test_qgsunittypes.py
Expand Up @@ -16,13 +16,15 @@
from qgis.core import QgsUnitTypes
from qgis.PyQt.QtCore import QLocale

# enforce C locale because the tests expect it
# (decimal separators / thousand separators)
QLocale.setDefault(QLocale.c())


class TestQgsUnitTypes(unittest.TestCase):

def setUp(self):
super().setUp()
# enforce C locale because the tests expect it
# (decimal separators / thousand separators)
QLocale.setDefault(QLocale.c())

def testEncodeDecodeUnitType(self):
"""Test encoding and decoding unit type"""
units = [QgsUnitTypes.TypeDistance,
Expand Down Expand Up @@ -1183,6 +1185,99 @@ def testFormatAngle(self):
self.assertEqual(QgsUnitTypes.formatAngle(1, -1, QgsUnitTypes.AngleMilNATO), '1 mil')
self.assertEqual(QgsUnitTypes.formatAngle(1, -1, QgsUnitTypes.AngleUnknownUnit), '1.00')

def testFormatDistance(self):
"""Test formatting distances"""
# keep base unit
self.assertEqual(QgsUnitTypes.formatDistance(100, 3, QgsUnitTypes.DistanceMeters, True), '100.000 m')
self.assertEqual(QgsUnitTypes.formatDistance(10, 2, QgsUnitTypes.DistanceKilometers, True), '10.00 km')
self.assertEqual(QgsUnitTypes.formatDistance(1, 0, QgsUnitTypes.DistanceFeet, True), '1 ft')
self.assertEqual(QgsUnitTypes.formatDistance(1.11111111, 4, QgsUnitTypes.DistanceNauticalMiles, True), '1.1111 NM')
self.assertEqual(QgsUnitTypes.formatDistance(1.99999999, 2, QgsUnitTypes.DistanceYards, True), '2.00 yd')
self.assertEqual(QgsUnitTypes.formatDistance(1, 2, QgsUnitTypes.DistanceMiles, True), '1.00 mi')
self.assertEqual(QgsUnitTypes.formatDistance(1, 2, QgsUnitTypes.DistanceDegrees, True), '1.00 deg')
self.assertEqual(QgsUnitTypes.formatDistance(1, 2, QgsUnitTypes.DistanceCentimeters, True), '1.00 cm')
self.assertEqual(QgsUnitTypes.formatDistance(1, 2, QgsUnitTypes.DistanceMillimeters, True), '1.00 mm')
self.assertEqual(QgsUnitTypes.formatDistance(1, 2, QgsUnitTypes.DistanceUnknownUnit, True), '1.00')

# don't keep base unit
self.assertEqual(QgsUnitTypes.formatDistance(10, 3, QgsUnitTypes.DistanceMeters, False), '10.000 m')
self.assertEqual(QgsUnitTypes.formatDistance(1001, 3, QgsUnitTypes.DistanceMeters, False), '1.001 km')
self.assertEqual(QgsUnitTypes.formatDistance(0.05, 2, QgsUnitTypes.DistanceMeters, False), '5.00 cm')
self.assertEqual(QgsUnitTypes.formatDistance(0.005, 2, QgsUnitTypes.DistanceMeters, False), '5.00 mm')
self.assertEqual(QgsUnitTypes.formatDistance(10, 2, QgsUnitTypes.DistanceKilometers, False), '10.00 km')
self.assertEqual(QgsUnitTypes.formatDistance(0.5, 2, QgsUnitTypes.DistanceKilometers, False), '500.00 m')
self.assertEqual(QgsUnitTypes.formatDistance(10, 2, QgsUnitTypes.DistanceFeet, False), '10.00 ft')
self.assertEqual(QgsUnitTypes.formatDistance(6000, 2, QgsUnitTypes.DistanceFeet, False), '1.14 mi')
self.assertEqual(QgsUnitTypes.formatDistance(10, 2, QgsUnitTypes.DistanceYards, False), '10.00 yd')
self.assertEqual(QgsUnitTypes.formatDistance(2500, 2, QgsUnitTypes.DistanceYards, False), '1.42 mi')
self.assertEqual(QgsUnitTypes.formatDistance(1, 2, QgsUnitTypes.DistanceMiles, False), '1.00 mi')
self.assertEqual(QgsUnitTypes.formatDistance(0.5, 2, QgsUnitTypes.DistanceMiles, False), '2640.00 ft')
self.assertEqual(QgsUnitTypes.formatDistance(1.11111111, 4, QgsUnitTypes.DistanceNauticalMiles, False), '1.1111 NM')
self.assertEqual(QgsUnitTypes.formatDistance(0.001, 4, QgsUnitTypes.DistanceDegrees, False), '0.0010 deg')
self.assertEqual(QgsUnitTypes.formatDistance(100, 2, QgsUnitTypes.DistanceCentimeters, False), '100.00 cm')
self.assertEqual(QgsUnitTypes.formatDistance(1000, 2, QgsUnitTypes.DistanceMillimeters, False), '1000.00 mm')
self.assertEqual(QgsUnitTypes.formatDistance(1, 2, QgsUnitTypes.DistanceUnknownUnit, False), '1.00')

# small values should not be displayed as zeroes, instead fallback to scientific notation
self.assertEqual(QgsUnitTypes.formatDistance(0.00168478, 2, QgsUnitTypes.DistanceMeters, False), '1.68 mm')
self.assertEqual(QgsUnitTypes.formatDistance(0.00000168478, 2, QgsUnitTypes.DistanceMeters, False), '1.68e-06 m')
self.assertEqual(QgsUnitTypes.formatDistance(0.00168478, 2, QgsUnitTypes.DistanceMeters, True), '1.68e-03 m')

# test different locales
QLocale.setDefault(QLocale(QLocale.Italian))
self.assertEqual(QgsUnitTypes.formatDistance(10, 3, QgsUnitTypes.DistanceMeters, False), '10,000 m')
self.assertEqual(QgsUnitTypes.formatDistance(0.5, 2, QgsUnitTypes.DistanceMiles, False), '2.640,00 ft')

def testFormatArea(self):
"""Test formatting areas"""
# keep base unit
self.assertEqual(QgsUnitTypes.formatArea(100, 3, QgsUnitTypes.AreaSquareMeters, True), '100.000 m²')
self.assertEqual(QgsUnitTypes.formatArea(10, 2, QgsUnitTypes.AreaSquareKilometers, True), '10.00 km²')
self.assertEqual(QgsUnitTypes.formatArea(1, 0, QgsUnitTypes.AreaSquareFeet, True), '1 ft²')
self.assertEqual(QgsUnitTypes.formatArea(1.11111111, 4, QgsUnitTypes.AreaSquareYards, True), '1.1111 yd²')
self.assertEqual(QgsUnitTypes.formatArea(1.99999999, 2, QgsUnitTypes.AreaSquareMiles, True), '2.00 mi²')
self.assertEqual(QgsUnitTypes.formatArea(1, 2, QgsUnitTypes.AreaHectares, True), '1.00 ha')
self.assertEqual(QgsUnitTypes.formatArea(1, 2, QgsUnitTypes.AreaAcres, True), '1.00 ac')
self.assertEqual(QgsUnitTypes.formatArea(1, 2, QgsUnitTypes.AreaSquareNauticalMiles, True), '1.00 NM²')
self.assertEqual(QgsUnitTypes.formatArea(1, 2, QgsUnitTypes.AreaSquareDegrees, True), '1.00 deg²')
self.assertEqual(QgsUnitTypes.formatArea(1, 2, QgsUnitTypes.AreaSquareCentimeters, True), '1.00 cm²')
self.assertEqual(QgsUnitTypes.formatArea(1, 2, QgsUnitTypes.AreaSquareMillimeters, True), '1.00 mm²')
self.assertEqual(QgsUnitTypes.formatArea(1, 2, QgsUnitTypes.AreaUnknownUnit, True), '1.00')

# don't keep base unit
self.assertEqual(QgsUnitTypes.formatArea(100, 2, QgsUnitTypes.AreaSquareMeters, False), '100.00 m²')
self.assertEqual(QgsUnitTypes.formatArea(2000000, 2, QgsUnitTypes.AreaSquareMeters, False), '2.00 km²')
self.assertEqual(QgsUnitTypes.formatArea(10001, 2, QgsUnitTypes.AreaSquareMeters, False), '1.00 ha')
self.assertEqual(QgsUnitTypes.formatArea(100, 2, QgsUnitTypes.AreaSquareKilometers, False), '100.00 km²')
self.assertEqual(QgsUnitTypes.formatArea(0.5, 2, QgsUnitTypes.AreaSquareKilometers, False), '0.50 km²')
self.assertEqual(QgsUnitTypes.formatArea(27879000, 2, QgsUnitTypes.AreaSquareFeet, False), '1.00 mi²')
self.assertEqual(QgsUnitTypes.formatArea(2787, 2, QgsUnitTypes.AreaSquareFeet, False), '2787.00 ft²')
self.assertEqual(QgsUnitTypes.formatArea(3099000, 2, QgsUnitTypes.AreaSquareYards, False), '1.00 mi²')
self.assertEqual(QgsUnitTypes.formatArea(309, 2, QgsUnitTypes.AreaSquareYards, False), '309.00 yd²')
self.assertEqual(QgsUnitTypes.formatArea(10, 2, QgsUnitTypes.AreaSquareMiles, False), '10.00 mi²')
self.assertEqual(QgsUnitTypes.formatArea(0.05, 2, QgsUnitTypes.AreaSquareMiles, False), '0.05 mi²')
self.assertEqual(QgsUnitTypes.formatArea(10, 2, QgsUnitTypes.AreaHectares, False), '10.00 ha')
self.assertEqual(QgsUnitTypes.formatArea(110, 2, QgsUnitTypes.AreaHectares, False), '1.10 km²')
self.assertEqual(QgsUnitTypes.formatArea(10, 2, QgsUnitTypes.AreaAcres, False), '10.00 ac')
self.assertEqual(QgsUnitTypes.formatArea(650, 2, QgsUnitTypes.AreaAcres, False), '1.02 mi²')
self.assertEqual(QgsUnitTypes.formatArea(0.01, 2, QgsUnitTypes.AreaSquareNauticalMiles, False), '0.01 NM²')
self.assertEqual(QgsUnitTypes.formatArea(100, 2, QgsUnitTypes.AreaSquareNauticalMiles, False), '100.00 NM²')
self.assertEqual(QgsUnitTypes.formatArea(0.0001, 4, QgsUnitTypes.AreaSquareDegrees, False), '0.0001 deg²')
self.assertEqual(QgsUnitTypes.formatArea(0.0001, 4, QgsUnitTypes.AreaSquareDegrees, False), '0.0001 deg²')
self.assertEqual(QgsUnitTypes.formatArea(1000, 4, QgsUnitTypes.AreaSquareMillimeters, False), '0.0010 m²')
self.assertEqual(QgsUnitTypes.formatArea(100, 3, QgsUnitTypes.AreaSquareCentimeters, False), '0.010 m²')
self.assertEqual(QgsUnitTypes.formatArea(10, 2, QgsUnitTypes.AreaUnknownUnit, False), '10.00')

# small values should not be displayed as zeroes, instead fallback to scientific notation
self.assertEqual(QgsUnitTypes.formatArea(0.00168478, 4, QgsUnitTypes.AreaSquareMeters, False), '0.0017 m²')
self.assertEqual(QgsUnitTypes.formatArea(0.00168478, 2, QgsUnitTypes.AreaSquareMeters, False), '1.68e-03 m²')
self.assertEqual(QgsUnitTypes.formatArea(0.00168478, 2, QgsUnitTypes.AreaSquareMeters, True), '1.68e-03 m²')

# test different locales
QLocale.setDefault(QLocale(QLocale.Italian))
self.assertEqual(QgsUnitTypes.formatArea(100, 2, QgsUnitTypes.AreaSquareKilometers, False), '100,00 km²')
self.assertEqual(QgsUnitTypes.formatArea(2787, 2, QgsUnitTypes.AreaSquareFeet, False), '2.787,00 ft²')

def testEncodeDecodeLayoutUnits(self):
"""Test encoding and decoding layout units"""
units = [QgsUnitTypes.LayoutMillimeters,
Expand Down

0 comments on commit d5d3ed6

Please sign in to comment.