From 17a29f90d641b6b8f97b4cf8e068e2067da050ec Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Sun, 14 Feb 2016 14:40:44 +1100 Subject: [PATCH] Add area units to QgsUnitTypes (refs #13209) --- python/core/qgsunittypes.sip | 54 +++++- src/core/qgsunittypes.cpp | 259 ++++++++++++++++++++++++++ src/core/qgsunittypes.h | 60 +++++- tests/src/python/test_qgsunittypes.py | 100 +++++++++- 4 files changed, 470 insertions(+), 3 deletions(-) diff --git a/python/core/qgsunittypes.sip b/python/core/qgsunittypes.sip index 4ba7d114c502..1944711913e9 100644 --- a/python/core/qgsunittypes.sip +++ b/python/core/qgsunittypes.sip @@ -21,6 +21,20 @@ class QgsUnitTypes UnknownType, /*!< unknown unit type */ }; + //! Units of area + enum AreaUnit + { + SquareMeters, /*!< square meters */ + SquareKilometers, /*!< square kilometers */ + SquareFeet, /*!< square feet */ + SquareYards, /*!< square yards */ + SquareMiles, /*!< square miles */ + Hectares, /*!< hectares */ + Acres, /*!< acres */ + SquareDegrees, /*!< square degrees, for planar geographic CRS area measurements */ + UnknownAreaUnit, /*!< unknown areal unit */ + }; + /** Returns the type for a distance unit. */ static DistanceUnitType unitType( QGis::UnitType unit ); @@ -42,7 +56,7 @@ class QgsUnitTypes /** Returns a translated string representing a distance unit. * @param unit unit to convert to string - * @see fromString() + * @see stringToDistanceUnit() */ static QString toString( QGis::UnitType unit ); @@ -60,6 +74,44 @@ class QgsUnitTypes */ static double fromUnitToUnitFactor( QGis::UnitType fromUnit, QGis::UnitType toUnit ); + /** Returns the type for an areal unit. + */ + static DistanceUnitType unitType( AreaUnit unit ); + + /** Encodes an areal unit to a string. + * @param unit unit to encode + * @returns encoded string + * @see decodeAreaUnit() + */ + static QString encodeUnit( AreaUnit unit ); + + /** Decodes an areal unit from a string. + * @param string string to decode + * @param ok optional boolean, will be set to true if string was converted successfully + * @returns decoded units + * @see encodeUnit() + */ + static AreaUnit decodeAreaUnit( const QString& string, bool *ok = 0 ); + + /** Returns a translated string representing an areal unit. + * @param unit unit to convert to string + * @see stringToAreaUnit() + */ + static QString toString( AreaUnit unit ); + + /** Converts a translated string to an areal unit. + * @param string string representing an areal unit + * @param ok optional boolean, will be set to true if string was converted successfully + * @see toString() + */ + static AreaUnit stringToAreaUnit( const QString& string, bool *ok = 0 ); + + /** Returns the conversion factor between the specified areal units. + * @param fromUnit area unit to convert from + * @param toUnit area unit to convert to + * @returns multiplication factor to convert between units + */ + static double fromUnitToUnitFactor( AreaUnit fromUnit, AreaUnit toUnit ); /** Encodes a symbol unit to a string. * @param unit unit to encode diff --git a/src/core/qgsunittypes.cpp b/src/core/qgsunittypes.cpp index 75dca1f684e3..8ddf5389a830 100644 --- a/src/core/qgsunittypes.cpp +++ b/src/core/qgsunittypes.cpp @@ -41,6 +41,29 @@ QgsUnitTypes::DistanceUnitType QgsUnitTypes::unitType( QGis::UnitType unit ) return UnknownType; } +QgsUnitTypes::DistanceUnitType QgsUnitTypes::unitType( QgsUnitTypes::AreaUnit unit ) +{ + switch ( unit ) + { + case SquareMeters: + case SquareKilometers: + case SquareFeet: + case SquareYards: + case SquareMiles: + case Hectares: + case Acres: + return Standard; + + case SquareDegrees: + return Geographic; + + case UnknownAreaUnit: + return UnknownType; + } + + return UnknownType; +} + QString QgsUnitTypes::encodeUnit( QGis::UnitType unit ) { switch ( unit ) @@ -203,6 +226,242 @@ double QgsUnitTypes::fromUnitToUnitFactor( QGis::UnitType fromUnit, QGis::UnitTy return 1.0; } +QString QgsUnitTypes::encodeUnit( QgsUnitTypes::AreaUnit unit ) +{ + switch ( unit ) + { + case SquareMeters: + return "m2"; + case SquareKilometers: + return "km2"; + case SquareFeet: + return "ft2"; + case SquareYards: + return "y2"; + case SquareMiles: + return "mi2"; + case Hectares: + return "ha"; + case Acres: + return "ac"; + case SquareDegrees: + return "deg2"; + case UnknownAreaUnit: + return ""; + } + return QString(); +} + +QgsUnitTypes::AreaUnit QgsUnitTypes::decodeAreaUnit( const QString& string, bool* ok ) +{ + QString normalized = string.trimmed().toLower(); + + if ( ok ) + *ok = true; + + if ( normalized == encodeUnit( SquareMeters ) ) + return SquareMeters; + if ( normalized == encodeUnit( SquareKilometers ) ) + return SquareKilometers; + if ( normalized == encodeUnit( SquareFeet ) ) + return SquareFeet; + if ( normalized == encodeUnit( SquareYards ) ) + return SquareYards; + if ( normalized == encodeUnit( SquareMiles ) ) + return SquareMiles; + if ( normalized == encodeUnit( Hectares ) ) + return Hectares; + if ( normalized == encodeUnit( Acres ) ) + return Acres; + if ( normalized == encodeUnit( SquareMiles ) ) + return SquareMiles; + if ( normalized == encodeUnit( SquareDegrees ) ) + return SquareDegrees; + if ( normalized == encodeUnit( UnknownAreaUnit ) ) + return UnknownAreaUnit; + + if ( ok ) + *ok = false; + + return UnknownAreaUnit; +} + +QString QgsUnitTypes::toString( QgsUnitTypes::AreaUnit unit ) +{ + switch ( unit ) + { + case SquareMeters: + return QCoreApplication::translate( "QgsUnitTypes::AreaUnit", "square meters" ); + case SquareKilometers: + return QCoreApplication::translate( "QgsUnitTypes::AreaUnit", "square kilometers" ); + case SquareFeet: + return QCoreApplication::translate( "QgsUnitTypes::AreaUnit", "square feet" ); + case SquareYards: + return QCoreApplication::translate( "QgsUnitTypes::AreaUnit", "square yards" ); + case SquareMiles: + return QCoreApplication::translate( "QgsUnitTypes::AreaUnit", "square miles" ); + case Hectares: + return QCoreApplication::translate( "QgsUnitTypes::AreaUnit", "hectares" ); + case Acres: + return QCoreApplication::translate( "QgsUnitTypes::AreaUnit", "acres" ); + case SquareDegrees: + return QCoreApplication::translate( "QgsUnitTypes::AreaUnit", "square degrees" ); + case UnknownAreaUnit: + return QCoreApplication::translate( "QgsUnitTypes::AreaUnit", "" ); + } + return QString(); +} + +QgsUnitTypes::AreaUnit QgsUnitTypes::stringToAreaUnit( const QString& string, bool* ok ) +{ + QString normalized = string.trimmed().toLower(); + + if ( ok ) + *ok = true; + + if ( normalized == toString( SquareMeters ) ) + return SquareMeters; + if ( normalized == toString( SquareKilometers ) ) + return SquareKilometers; + if ( normalized == toString( SquareFeet ) ) + return SquareFeet; + if ( normalized == toString( SquareYards ) ) + return SquareYards; + if ( normalized == toString( SquareMiles ) ) + return SquareMiles; + if ( normalized == toString( Hectares ) ) + return Hectares; + if ( normalized == toString( Acres ) ) + return Acres; + if ( normalized == toString( SquareDegrees ) ) + return SquareDegrees; + if ( normalized == toString( UnknownAreaUnit ) ) + return UnknownAreaUnit; + if ( ok ) + *ok = false; + + return UnknownAreaUnit; +} + +double QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::AreaUnit fromUnit, QgsUnitTypes::AreaUnit toUnit ) +{ +#define KM2_TO_M2 1000000.0 +#define FT2_TO_M2 0.09290304 +#define YD2_TO_M2 0.83612736 +#define MI2_TO_M2 2589988.110336 +#define HA_TO_M2 10000.0 +#define AC_TO_FT2 43560.0 +#define DEG2_TO_M2 12392029030.5 + + // Calculate the conversion factor between the specified units + if ( fromUnit != toUnit ) + { + switch ( fromUnit ) + { + case SquareMeters: + { + if ( toUnit == SquareKilometers ) return 1.0 / KM2_TO_M2; + if ( toUnit == SquareFeet ) return 1.0 / FT2_TO_M2; + if ( toUnit == SquareYards ) return 1.0 / YD2_TO_M2; + if ( toUnit == SquareMiles ) return 1.0 / MI2_TO_M2; + if ( toUnit == Hectares ) return 1.0 / HA_TO_M2; + if ( toUnit == Acres ) return 1.0 / AC_TO_FT2 / FT2_TO_M2; + if ( toUnit == SquareDegrees ) return 1.0 / DEG2_TO_M2; + + break; + } + case SquareKilometers: + { + if ( toUnit == SquareMeters ) return KM2_TO_M2; + if ( toUnit == SquareFeet ) return KM2_TO_M2 / FT2_TO_M2 ; + if ( toUnit == SquareYards ) return KM2_TO_M2 / YD2_TO_M2; + if ( toUnit == SquareMiles ) return KM2_TO_M2 / MI2_TO_M2; + if ( toUnit == Hectares ) return KM2_TO_M2 / HA_TO_M2; + if ( toUnit == Acres ) return KM2_TO_M2 / AC_TO_FT2 / FT2_TO_M2 ; + if ( toUnit == SquareDegrees ) return KM2_TO_M2 / DEG2_TO_M2; + + break; + } + case SquareFeet: + { + if ( toUnit == SquareMeters ) return FT2_TO_M2; + if ( toUnit == SquareKilometers ) return FT2_TO_M2 / KM2_TO_M2; + if ( toUnit == SquareYards ) return FT2_TO_M2 / YD2_TO_M2; + if ( toUnit == SquareMiles ) return FT2_TO_M2 / MI2_TO_M2; + if ( toUnit == Hectares ) return FT2_TO_M2 / HA_TO_M2; + if ( toUnit == Acres ) return 1.0 / AC_TO_FT2; + if ( toUnit == SquareDegrees ) return FT2_TO_M2 / DEG2_TO_M2; + + break; + } + + case SquareYards: + { + if ( toUnit == SquareMeters ) return YD2_TO_M2; + if ( toUnit == SquareKilometers ) return YD2_TO_M2 / KM2_TO_M2; + if ( toUnit == SquareFeet ) return YD2_TO_M2 / FT2_TO_M2; + if ( toUnit == SquareMiles ) return YD2_TO_M2 / MI2_TO_M2; + if ( toUnit == Hectares ) return YD2_TO_M2 / HA_TO_M2; + if ( toUnit == Acres ) return YD2_TO_M2 / FT2_TO_M2 / AC_TO_FT2; + if ( toUnit == SquareDegrees ) return YD2_TO_M2 / DEG2_TO_M2; + break; + } + + case SquareMiles: + { + if ( toUnit == SquareMeters ) return MI2_TO_M2; + if ( toUnit == SquareKilometers ) return MI2_TO_M2 / KM2_TO_M2; + if ( toUnit == SquareFeet ) return MI2_TO_M2 / FT2_TO_M2; + if ( toUnit == SquareYards ) return MI2_TO_M2 / YD2_TO_M2; + if ( toUnit == Hectares ) return MI2_TO_M2 / HA_TO_M2; + if ( toUnit == Acres ) return MI2_TO_M2 / FT2_TO_M2 / AC_TO_FT2; + if ( toUnit == SquareDegrees ) return MI2_TO_M2 / DEG2_TO_M2; + break; + } + + case Hectares: + { + if ( toUnit == SquareMeters ) return HA_TO_M2; + if ( toUnit == SquareKilometers ) return HA_TO_M2 / KM2_TO_M2; + if ( toUnit == SquareFeet ) return HA_TO_M2 / FT2_TO_M2; + if ( toUnit == SquareYards ) return HA_TO_M2 / YD2_TO_M2; + if ( toUnit == SquareMiles ) return HA_TO_M2 / MI2_TO_M2; + if ( toUnit == Acres ) return HA_TO_M2 / FT2_TO_M2 / AC_TO_FT2; + if ( toUnit == SquareDegrees ) return HA_TO_M2 / DEG2_TO_M2; + break; + } + + case Acres: + { + if ( toUnit == SquareMeters ) return AC_TO_FT2 * FT2_TO_M2; + if ( toUnit == SquareKilometers ) return AC_TO_FT2 * FT2_TO_M2 / KM2_TO_M2; + if ( toUnit == SquareFeet ) return AC_TO_FT2; + if ( toUnit == SquareYards ) return AC_TO_FT2 * FT2_TO_M2 / YD2_TO_M2; + if ( toUnit == SquareMiles ) return AC_TO_FT2 * FT2_TO_M2 / MI2_TO_M2; + if ( toUnit == Hectares ) return AC_TO_FT2 * FT2_TO_M2 / HA_TO_M2; + if ( toUnit == SquareDegrees ) return AC_TO_FT2 * FT2_TO_M2 / DEG2_TO_M2; + break; + } + + case SquareDegrees: + { + if ( toUnit == SquareMeters ) return DEG2_TO_M2; + if ( toUnit == SquareKilometers ) return DEG2_TO_M2 / KM2_TO_M2; + if ( toUnit == SquareFeet ) return DEG2_TO_M2 / FT2_TO_M2; + if ( toUnit == SquareYards ) return DEG2_TO_M2 / YD2_TO_M2; + if ( toUnit == SquareMiles ) return DEG2_TO_M2 / MI2_TO_M2; + if ( toUnit == Hectares ) return DEG2_TO_M2 / HA_TO_M2; + if ( toUnit == Acres ) return DEG2_TO_M2 / FT2_TO_M2 / AC_TO_FT2; + break; + } + + case UnknownAreaUnit: + break; + } + } + return 1.0; +} + QString QgsUnitTypes::encodeUnit( QgsSymbolV2::OutputUnit unit ) { switch ( unit ) diff --git a/src/core/qgsunittypes.h b/src/core/qgsunittypes.h index 575945f8ee41..3a694eaeeb46 100644 --- a/src/core/qgsunittypes.h +++ b/src/core/qgsunittypes.h @@ -46,6 +46,22 @@ class CORE_EXPORT QgsUnitTypes UnknownType, /*!< unknown unit type */ }; + //! Units of area + enum AreaUnit + { + SquareMeters = 0, /*!< square meters */ + SquareKilometers, /*!< square kilometers */ + SquareFeet, /*!< square feet */ + SquareYards, /*!< square yards */ + SquareMiles, /*!< square miles */ + Hectares, /*!< hectares */ + Acres, /*!< acres */ + SquareDegrees, /*!< square degrees, for planar geographic CRS area measurements */ + UnknownAreaUnit, /*!< unknown areal unit */ + }; + + // DISTANCE UNITS + /** Returns the type for a distance unit. */ static DistanceUnitType unitType( QGis::UnitType unit ); @@ -67,7 +83,7 @@ class CORE_EXPORT QgsUnitTypes /** Returns a translated string representing a distance unit. * @param unit unit to convert to string - * @see fromString() + * @see stringToDistanceUnit() */ static QString toString( QGis::UnitType unit ); @@ -85,6 +101,48 @@ class CORE_EXPORT QgsUnitTypes */ static double fromUnitToUnitFactor( QGis::UnitType fromUnit, QGis::UnitType toUnit ); + // AREAL UNITS + + /** Returns the type for an areal unit. + */ + static DistanceUnitType unitType( AreaUnit unit ); + + /** Encodes an areal unit to a string. + * @param unit unit to encode + * @returns encoded string + * @see decodeAreaUnit() + */ + static QString encodeUnit( AreaUnit unit ); + + /** Decodes an areal unit from a string. + * @param string string to decode + * @param ok optional boolean, will be set to true if string was converted successfully + * @returns decoded units + * @see encodeUnit() + */ + static AreaUnit decodeAreaUnit( const QString& string, bool *ok = 0 ); + + /** Returns a translated string representing an areal unit. + * @param unit unit to convert to string + * @see stringToAreaUnit() + */ + static QString toString( AreaUnit unit ); + + /** Converts a translated string to an areal unit. + * @param string string representing an areal unit + * @param ok optional boolean, will be set to true if string was converted successfully + * @see toString() + */ + static AreaUnit stringToAreaUnit( const QString& string, bool *ok = 0 ); + + /** Returns the conversion factor between the specified areal units. + * @param fromUnit area unit to convert from + * @param toUnit area unit to convert to + * @returns multiplication factor to convert between units + */ + static double fromUnitToUnitFactor( AreaUnit fromUnit, AreaUnit toUnit ); + + // SYMBOL UNITS /** Encodes a symbol unit to a string. * @param unit unit to encode diff --git a/tests/src/python/test_qgsunittypes.py b/tests/src/python/test_qgsunittypes.py index a9925aef7e27..253fdad3d89e 100644 --- a/tests/src/python/test_qgsunittypes.py +++ b/tests/src/python/test_qgsunittypes.py @@ -78,11 +78,81 @@ def testDistanceUnitsToFromString(self): self.assertEqual(res, QGis.UnknownUnit) # Test that string is cleaned before conversion - res, ok = QgsUnitTypes.decodeDistanceUnit(' {} '.format(QgsUnitTypes.toString(QGis.Feet).upper())) + res, ok = QgsUnitTypes.stringToDistanceUnit(' {} '.format(QgsUnitTypes.toString(QGis.Feet).upper())) print ' {} '.format(QgsUnitTypes.toString(QGis.Feet).upper()) assert ok self.assertEqual(res, QGis.Feet) + def testAreaUnitType(self): + """Test QgsUnitTypes::unitType() for area units """ + expected = {QgsUnitTypes.SquareMeters: QgsUnitTypes.Standard, + QgsUnitTypes.SquareKilometers: QgsUnitTypes.Standard, + QgsUnitTypes.SquareFeet: QgsUnitTypes.Standard, + QgsUnitTypes.SquareYards: QgsUnitTypes.Standard, + QgsUnitTypes.SquareMiles: QgsUnitTypes.Standard, + QgsUnitTypes.Hectares: QgsUnitTypes.Standard, + QgsUnitTypes.Acres: QgsUnitTypes.Standard, + QgsUnitTypes.SquareDegrees: QgsUnitTypes.Geographic, + QgsUnitTypes.UnknownAreaUnit: QgsUnitTypes.UnknownType, + } + + for t in expected.keys(): + self.assertEqual(QgsUnitTypes.unitType(t), expected[t]) + + def testEncodeDecodeAreaUnits(self): + """Test encoding and decoding area units""" + units = [QgsUnitTypes.SquareMeters, + QgsUnitTypes.SquareKilometers, + QgsUnitTypes.SquareFeet, + QgsUnitTypes.SquareYards, + QgsUnitTypes.SquareMiles, + QgsUnitTypes.Hectares, + QgsUnitTypes.Acres, + QgsUnitTypes.SquareDegrees, + QgsUnitTypes.UnknownAreaUnit] + + for u in units: + res, ok = QgsUnitTypes.decodeAreaUnit(QgsUnitTypes.encodeUnit(u)) + assert ok + self.assertEqual(res, u) + + # Test decoding bad units + res, ok = QgsUnitTypes.decodeAreaUnit('bad') + self.assertFalse(ok) + self.assertEqual(res, QgsUnitTypes.UnknownAreaUnit) + + # Test that string is cleaned before decoding + res, ok = QgsUnitTypes.decodeAreaUnit(' Ha ') + assert ok + self.assertEqual(res, QgsUnitTypes.Hectares) + + def testAreaUnitsToFromString(self): + """Test converting area units to and from translated strings""" + units = [QgsUnitTypes.SquareMeters, + QgsUnitTypes.SquareKilometers, + QgsUnitTypes.SquareFeet, + QgsUnitTypes.SquareYards, + QgsUnitTypes.SquareMiles, + QgsUnitTypes.Hectares, + QgsUnitTypes.Acres, + QgsUnitTypes.SquareDegrees, + QgsUnitTypes.UnknownAreaUnit] + + for u in units: + res, ok = QgsUnitTypes.stringToAreaUnit(QgsUnitTypes.toString(u)) + assert ok + self.assertEqual(res, u) + + # Test converting bad strings + res, ok = QgsUnitTypes.stringToAreaUnit('bad') + self.assertFalse(ok) + self.assertEqual(res, QgsUnitTypes.UnknownAreaUnit) + + # Test that string is cleaned before conversion + res, ok = QgsUnitTypes.stringToAreaUnit(' {} '.format(QgsUnitTypes.toString(QgsUnitTypes.SquareMiles).upper())) + assert ok + self.assertEqual(res, QgsUnitTypes.SquareMiles) + def testEncodeDecodeSymbolUnits(self): """Test encoding and decoding symbol units""" units = [QgsSymbolV2.MM, @@ -132,6 +202,34 @@ def testFromUnitToUnitFactor(self): msg='got {:.7f}, expected 1.0 when converting from {} to unknown units'.format(res, expected_factor, QgsUnitTypes.toString(from_unit))) + def testAreaFromUnitToUnitFactor(self): + """Test calculation of conversion factor between areal units""" + + expected = {QgsUnitTypes.SquareMeters: {QgsUnitTypes.SquareMeters: 1.0, QgsUnitTypes.SquareKilometers: 1e-6, QgsUnitTypes.SquareFeet: 10.7639104, QgsUnitTypes.SquareYards: 1.19599, QgsUnitTypes.SquareMiles: 3.86102e-7, QgsUnitTypes.Hectares: 0.0001, QgsUnitTypes.Acres: 0.000247105, QgsUnitTypes.SquareDegrees: 0.000000000080697, QgsUnitTypes.UnknownAreaUnit: 1.0}, + QgsUnitTypes.SquareKilometers: {QgsUnitTypes.SquareMeters: 1e6, QgsUnitTypes.SquareKilometers: 1, QgsUnitTypes.SquareFeet: 10763910.4167097, QgsUnitTypes.SquareYards: 1195990.04630108, QgsUnitTypes.SquareMiles: 0.386102158, QgsUnitTypes.Hectares: 100, QgsUnitTypes.Acres: 247.105381467, QgsUnitTypes.SquareDegrees: 0.000080697034968, QgsUnitTypes.UnknownAreaUnit: 1.0}, + QgsUnitTypes.SquareFeet: {QgsUnitTypes.SquareMeters: 0.092903, QgsUnitTypes.SquareKilometers: 9.2903e-8, QgsUnitTypes.SquareFeet: 1.0, QgsUnitTypes.SquareYards: 0.11111111111, QgsUnitTypes.SquareMiles: 3.58701e-8, QgsUnitTypes.Hectares: 9.2903e-6, QgsUnitTypes.Acres: 2.29568e-5, QgsUnitTypes.SquareDegrees: 0.000000000007497, QgsUnitTypes.UnknownAreaUnit: 1.0}, + QgsUnitTypes.SquareYards: {QgsUnitTypes.SquareMeters: 0.836127360, QgsUnitTypes.SquareKilometers: 8.36127e-7, QgsUnitTypes.SquareFeet: 9.0, QgsUnitTypes.SquareYards: 1.0, QgsUnitTypes.SquareMiles: 3.22831e-7, QgsUnitTypes.Hectares: 8.3612736E-5, QgsUnitTypes.Acres: 0.00020661157, QgsUnitTypes.SquareDegrees: 0.000000000067473, QgsUnitTypes.UnknownAreaUnit: 1.0}, + QgsUnitTypes.SquareMiles: {QgsUnitTypes.SquareMeters: 2589988.110336, QgsUnitTypes.SquareKilometers: 2.589988110, QgsUnitTypes.SquareFeet: 27878400, QgsUnitTypes.SquareYards: 3097600, QgsUnitTypes.SquareMiles: 1.0, QgsUnitTypes.Hectares: 258.998811, QgsUnitTypes.Acres: 640, QgsUnitTypes.SquareDegrees: 0.000209004361107, QgsUnitTypes.UnknownAreaUnit: 1.0}, + QgsUnitTypes.Hectares: {QgsUnitTypes.SquareMeters: 10000, QgsUnitTypes.SquareKilometers: 0.01, QgsUnitTypes.SquareFeet: 107639.1041670972, QgsUnitTypes.SquareYards: 11959.9004630, QgsUnitTypes.SquareMiles: 0.00386102, QgsUnitTypes.Hectares: 1.0, QgsUnitTypes.Acres: 2.471053814, QgsUnitTypes.SquareDegrees: 0.000000806970350, QgsUnitTypes.UnknownAreaUnit: 1.0}, + QgsUnitTypes.Acres: {QgsUnitTypes.SquareMeters: 4046.8564224, QgsUnitTypes.SquareKilometers: 0.00404686, QgsUnitTypes.SquareFeet: 43560, QgsUnitTypes.SquareYards: 4840, QgsUnitTypes.SquareMiles: 0.0015625, QgsUnitTypes.Hectares: 0.404685642, QgsUnitTypes.Acres: 1.0, QgsUnitTypes.SquareDegrees: 0.000000326569314, QgsUnitTypes.UnknownAreaUnit: 1.0}, + QgsUnitTypes.SquareDegrees: {QgsUnitTypes.SquareMeters: 12392029030.5, QgsUnitTypes.SquareKilometers: 12392.029030499, QgsUnitTypes.SquareFeet: 133386690365.5682220, QgsUnitTypes.SquareYards: 14820743373.9520263, QgsUnitTypes.SquareMiles: 4784.5891573967, QgsUnitTypes.Hectares: 1239202.903050, QgsUnitTypes.Acres: 3062137.060733889, QgsUnitTypes.SquareDegrees: 1.0, QgsUnitTypes.UnknownAreaUnit: 1.0}} + + for from_unit in expected.keys(): + for to_unit in expected[from_unit].keys(): + expected_factor = expected[from_unit][to_unit] + res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, to_unit) + self.assertAlmostEqual(res, + expected_factor, + msg='got {:.15f}, expected {:.15f} when converting from {} to {}'.format(res, expected_factor, + QgsUnitTypes.toString(from_unit), + QgsUnitTypes.toString(to_unit))) + #test conversion to unknown units + res = QgsUnitTypes.fromUnitToUnitFactor(from_unit, QgsUnitTypes.UnknownAreaUnit) + self.assertAlmostEqual(res, + 1.0, + msg='got {:.7f}, expected 1.0 when converting from {} to unknown units'.format(res, expected_factor, + QgsUnitTypes.toString(from_unit))) + if __name__ == "__main__": unittest.main()