1*0e209d39SAndroid Build Coastguard Worker // © 2020 and later: Unicode, Inc. and others. 2*0e209d39SAndroid Build Coastguard Worker // License & terms of use: http://www.unicode.org/copyright.html 3*0e209d39SAndroid Build Coastguard Worker 4*0e209d39SAndroid Build Coastguard Worker #include "unicode/utypes.h" 5*0e209d39SAndroid Build Coastguard Worker 6*0e209d39SAndroid Build Coastguard Worker #if !UCONFIG_NO_FORMATTING 7*0e209d39SAndroid Build Coastguard Worker #ifndef __UNITS_CONVERTER_H__ 8*0e209d39SAndroid Build Coastguard Worker #define __UNITS_CONVERTER_H__ 9*0e209d39SAndroid Build Coastguard Worker 10*0e209d39SAndroid Build Coastguard Worker #include "cmemory.h" 11*0e209d39SAndroid Build Coastguard Worker #include "measunit_impl.h" 12*0e209d39SAndroid Build Coastguard Worker #include "unicode/errorcode.h" 13*0e209d39SAndroid Build Coastguard Worker #include "unicode/stringpiece.h" 14*0e209d39SAndroid Build Coastguard Worker #include "unicode/uobject.h" 15*0e209d39SAndroid Build Coastguard Worker #include "units_converter.h" 16*0e209d39SAndroid Build Coastguard Worker #include "units_data.h" 17*0e209d39SAndroid Build Coastguard Worker 18*0e209d39SAndroid Build Coastguard Worker U_NAMESPACE_BEGIN 19*0e209d39SAndroid Build Coastguard Worker namespace units { 20*0e209d39SAndroid Build Coastguard Worker 21*0e209d39SAndroid Build Coastguard Worker /* Internal Structure */ 22*0e209d39SAndroid Build Coastguard Worker 23*0e209d39SAndroid Build Coastguard Worker // Constants corresponding to unitConstants in CLDR's units.xml. 24*0e209d39SAndroid Build Coastguard Worker enum Constants { 25*0e209d39SAndroid Build Coastguard Worker CONSTANT_FT2M, // ft_to_m 26*0e209d39SAndroid Build Coastguard Worker CONSTANT_PI, // PI 27*0e209d39SAndroid Build Coastguard Worker CONSTANT_GRAVITY, // Gravity of earth (9.80665 m/s^2), "g". 28*0e209d39SAndroid Build Coastguard Worker CONSTANT_G, // Newtonian constant of gravitation, "G". 29*0e209d39SAndroid Build Coastguard Worker CONSTANT_GAL_IMP2M3, // Gallon imp to m3 30*0e209d39SAndroid Build Coastguard Worker CONSTANT_LB2KG, // Pound to Kilogram 31*0e209d39SAndroid Build Coastguard Worker CONSTANT_GLUCOSE_MOLAR_MASS, 32*0e209d39SAndroid Build Coastguard Worker CONSTANT_ITEM_PER_MOLE, 33*0e209d39SAndroid Build Coastguard Worker CONSTANT_METERS_PER_AU, 34*0e209d39SAndroid Build Coastguard Worker CONSTANT_SEC_PER_JULIAN_YEAR, 35*0e209d39SAndroid Build Coastguard Worker CONSTANT_SPEED_OF_LIGHT_METERS_PER_SECOND, 36*0e209d39SAndroid Build Coastguard Worker CONSTANT_SHO_TO_M3, // https://en.wikipedia.org/wiki/Japanese_units_of_measurement 37*0e209d39SAndroid Build Coastguard Worker CONSTANT_TSUBO_TO_M2, // https://en.wikipedia.org/wiki/Japanese_units_of_measurement 38*0e209d39SAndroid Build Coastguard Worker CONSTANT_SHAKU_TO_M, // https://en.wikipedia.org/wiki/Japanese_units_of_measurement 39*0e209d39SAndroid Build Coastguard Worker CONSTANT_AMU, // Atomic Mass Unit https://www.nist.gov/pml/special-publication-811/nist-guide-si-chapter-5-units-outside-si#table7 40*0e209d39SAndroid Build Coastguard Worker 41*0e209d39SAndroid Build Coastguard Worker // Must be the last element. 42*0e209d39SAndroid Build Coastguard Worker CONSTANTS_COUNT 43*0e209d39SAndroid Build Coastguard Worker }; 44*0e209d39SAndroid Build Coastguard Worker 45*0e209d39SAndroid Build Coastguard Worker // These values are a hard-coded subset of unitConstants in the units 46*0e209d39SAndroid Build Coastguard Worker // resources file. A unit test checks that all constants in the resource 47*0e209d39SAndroid Build Coastguard Worker // file are at least recognised by the code. Derived constants' values or 48*0e209d39SAndroid Build Coastguard Worker // hard-coded derivations are not checked. 49*0e209d39SAndroid Build Coastguard Worker // In ICU4J, these constants live in UnitConverter.Factor.getConversionRate(). 50*0e209d39SAndroid Build Coastguard Worker static const double constantsValues[CONSTANTS_COUNT] = { 51*0e209d39SAndroid Build Coastguard Worker 0.3048, // CONSTANT_FT2M 52*0e209d39SAndroid Build Coastguard Worker 411557987.0 / 131002976.0, // CONSTANT_PI 53*0e209d39SAndroid Build Coastguard Worker 9.80665, // CONSTANT_GRAVITY 54*0e209d39SAndroid Build Coastguard Worker 6.67408E-11, // CONSTANT_G 55*0e209d39SAndroid Build Coastguard Worker 0.00454609, // CONSTANT_GAL_IMP2M3 56*0e209d39SAndroid Build Coastguard Worker 0.45359237, // CONSTANT_LB2KG 57*0e209d39SAndroid Build Coastguard Worker 180.1557, // CONSTANT_GLUCOSE_MOLAR_MASS 58*0e209d39SAndroid Build Coastguard Worker 6.02214076E+23, // CONSTANT_ITEM_PER_MOLE 59*0e209d39SAndroid Build Coastguard Worker 149597870700, // CONSTANT_METERS_PER_AU 60*0e209d39SAndroid Build Coastguard Worker 31557600, // CONSTANT_SEC_PER_JULIAN_YEAR 61*0e209d39SAndroid Build Coastguard Worker 299792458, // CONSTANT_SPEED_OF_LIGHT_METERS_PER_SECOND 62*0e209d39SAndroid Build Coastguard Worker 2401.0 / (1331.0 * 1000.0), 63*0e209d39SAndroid Build Coastguard Worker 400.0 / 121.0, 64*0e209d39SAndroid Build Coastguard Worker 4.0 / 121.0, 65*0e209d39SAndroid Build Coastguard Worker 1.66053878283E-27, // CONSTANT_AMU 66*0e209d39SAndroid Build Coastguard Worker }; 67*0e209d39SAndroid Build Coastguard Worker 68*0e209d39SAndroid Build Coastguard Worker typedef enum Signum { 69*0e209d39SAndroid Build Coastguard Worker NEGATIVE = -1, 70*0e209d39SAndroid Build Coastguard Worker POSITIVE = 1, 71*0e209d39SAndroid Build Coastguard Worker } Signum; 72*0e209d39SAndroid Build Coastguard Worker 73*0e209d39SAndroid Build Coastguard Worker /* Represents a conversion factor */ 74*0e209d39SAndroid Build Coastguard Worker struct U_I18N_API Factor { 75*0e209d39SAndroid Build Coastguard Worker double factorNum = 1; 76*0e209d39SAndroid Build Coastguard Worker double factorDen = 1; 77*0e209d39SAndroid Build Coastguard Worker double offset = 0; 78*0e209d39SAndroid Build Coastguard Worker bool reciprocal = false; 79*0e209d39SAndroid Build Coastguard Worker 80*0e209d39SAndroid Build Coastguard Worker // Exponents for the symbolic constants 81*0e209d39SAndroid Build Coastguard Worker int32_t constantExponents[CONSTANTS_COUNT] = {}; 82*0e209d39SAndroid Build Coastguard Worker 83*0e209d39SAndroid Build Coastguard Worker void multiplyBy(const Factor &rhs); 84*0e209d39SAndroid Build Coastguard Worker void divideBy(const Factor &rhs); 85*0e209d39SAndroid Build Coastguard Worker 86*0e209d39SAndroid Build Coastguard Worker // Apply the power to the factor. 87*0e209d39SAndroid Build Coastguard Worker void power(int32_t power); 88*0e209d39SAndroid Build Coastguard Worker 89*0e209d39SAndroid Build Coastguard Worker // Apply SI or binary prefix to the Factor. 90*0e209d39SAndroid Build Coastguard Worker void applyPrefix(UMeasurePrefix unitPrefix); 91*0e209d39SAndroid Build Coastguard Worker 92*0e209d39SAndroid Build Coastguard Worker // Does an in-place substitution of the "symbolic constants" based on 93*0e209d39SAndroid Build Coastguard Worker // constantExponents (resetting the exponents). 94*0e209d39SAndroid Build Coastguard Worker // 95*0e209d39SAndroid Build Coastguard Worker // In ICU4J, see UnitConverter.Factor.getConversionRate(). 96*0e209d39SAndroid Build Coastguard Worker void substituteConstants(); 97*0e209d39SAndroid Build Coastguard Worker }; 98*0e209d39SAndroid Build Coastguard Worker 99*0e209d39SAndroid Build Coastguard Worker struct U_I18N_API ConversionInfo { 100*0e209d39SAndroid Build Coastguard Worker double conversionRate; 101*0e209d39SAndroid Build Coastguard Worker double offset; 102*0e209d39SAndroid Build Coastguard Worker bool reciprocal; 103*0e209d39SAndroid Build Coastguard Worker }; 104*0e209d39SAndroid Build Coastguard Worker 105*0e209d39SAndroid Build Coastguard Worker /* 106*0e209d39SAndroid Build Coastguard Worker * Adds a single factor element to the `Factor`. e.g "ft3m", "2.333" or "cup2m3". But not "cup2m3^3". 107*0e209d39SAndroid Build Coastguard Worker */ 108*0e209d39SAndroid Build Coastguard Worker void U_I18N_API addSingleFactorConstant(StringPiece baseStr, int32_t power, Signum sigNum, 109*0e209d39SAndroid Build Coastguard Worker Factor &factor, UErrorCode &status); 110*0e209d39SAndroid Build Coastguard Worker 111*0e209d39SAndroid Build Coastguard Worker /** 112*0e209d39SAndroid Build Coastguard Worker * Represents the conversion rate between `source` and `target`. 113*0e209d39SAndroid Build Coastguard Worker * TODO ICU-22683: COnsider moving the handling of special mappings (e.g. beaufort) to a separate 114*0e209d39SAndroid Build Coastguard Worker * struct. 115*0e209d39SAndroid Build Coastguard Worker */ 116*0e209d39SAndroid Build Coastguard Worker struct U_I18N_API ConversionRate : public UMemory { 117*0e209d39SAndroid Build Coastguard Worker const MeasureUnitImpl source; 118*0e209d39SAndroid Build Coastguard Worker const MeasureUnitImpl target; 119*0e209d39SAndroid Build Coastguard Worker CharString specialSource; 120*0e209d39SAndroid Build Coastguard Worker CharString specialTarget; 121*0e209d39SAndroid Build Coastguard Worker double factorNum = 1; 122*0e209d39SAndroid Build Coastguard Worker double factorDen = 1; 123*0e209d39SAndroid Build Coastguard Worker double sourceOffset = 0; 124*0e209d39SAndroid Build Coastguard Worker double targetOffset = 0; 125*0e209d39SAndroid Build Coastguard Worker bool reciprocal = false; 126*0e209d39SAndroid Build Coastguard Worker ConversionRateConversionRate127*0e209d39SAndroid Build Coastguard Worker ConversionRate(MeasureUnitImpl &&source, MeasureUnitImpl &&target) 128*0e209d39SAndroid Build Coastguard Worker : source(std::move(source)), target(std::move(target)), specialSource(), specialTarget() {} 129*0e209d39SAndroid Build Coastguard Worker }; 130*0e209d39SAndroid Build Coastguard Worker 131*0e209d39SAndroid Build Coastguard Worker enum Convertibility { 132*0e209d39SAndroid Build Coastguard Worker RECIPROCAL, 133*0e209d39SAndroid Build Coastguard Worker CONVERTIBLE, 134*0e209d39SAndroid Build Coastguard Worker UNCONVERTIBLE, 135*0e209d39SAndroid Build Coastguard Worker }; 136*0e209d39SAndroid Build Coastguard Worker 137*0e209d39SAndroid Build Coastguard Worker MeasureUnitImpl U_I18N_API extractCompoundBaseUnit(const MeasureUnitImpl &source, 138*0e209d39SAndroid Build Coastguard Worker const ConversionRates &conversionRates, 139*0e209d39SAndroid Build Coastguard Worker UErrorCode &status); 140*0e209d39SAndroid Build Coastguard Worker 141*0e209d39SAndroid Build Coastguard Worker /** 142*0e209d39SAndroid Build Coastguard Worker * Check if the convertibility between `source` and `target`. 143*0e209d39SAndroid Build Coastguard Worker * For example: 144*0e209d39SAndroid Build Coastguard Worker * `meter` and `foot` are `CONVERTIBLE`. 145*0e209d39SAndroid Build Coastguard Worker * `meter-per-second` and `second-per-meter` are `RECIPROCAL`. 146*0e209d39SAndroid Build Coastguard Worker * `meter` and `pound` are `UNCONVERTIBLE`. 147*0e209d39SAndroid Build Coastguard Worker * 148*0e209d39SAndroid Build Coastguard Worker * NOTE: 149*0e209d39SAndroid Build Coastguard Worker * Only works with SINGLE and COMPOUND units. If one of the units is a 150*0e209d39SAndroid Build Coastguard Worker * MIXED unit, an error will occur. For more information, see UMeasureUnitComplexity. 151*0e209d39SAndroid Build Coastguard Worker */ 152*0e209d39SAndroid Build Coastguard Worker Convertibility U_I18N_API extractConvertibility(const MeasureUnitImpl &source, 153*0e209d39SAndroid Build Coastguard Worker const MeasureUnitImpl &target, 154*0e209d39SAndroid Build Coastguard Worker const ConversionRates &conversionRates, 155*0e209d39SAndroid Build Coastguard Worker UErrorCode &status); 156*0e209d39SAndroid Build Coastguard Worker 157*0e209d39SAndroid Build Coastguard Worker /** 158*0e209d39SAndroid Build Coastguard Worker * Converts from a source `MeasureUnit` to a target `MeasureUnit`. 159*0e209d39SAndroid Build Coastguard Worker * 160*0e209d39SAndroid Build Coastguard Worker * NOTE: 161*0e209d39SAndroid Build Coastguard Worker * Only works with SINGLE and COMPOUND units. If one of the units is a 162*0e209d39SAndroid Build Coastguard Worker * MIXED unit, an error will occur. For more information, see UMeasureUnitComplexity. 163*0e209d39SAndroid Build Coastguard Worker */ 164*0e209d39SAndroid Build Coastguard Worker class U_I18N_API UnitsConverter : public UMemory { 165*0e209d39SAndroid Build Coastguard Worker public: 166*0e209d39SAndroid Build Coastguard Worker /** 167*0e209d39SAndroid Build Coastguard Worker * Constructor of `UnitConverter`. 168*0e209d39SAndroid Build Coastguard Worker * NOTE: 169*0e209d39SAndroid Build Coastguard Worker * - source and target must be under the same category 170*0e209d39SAndroid Build Coastguard Worker * - e.g. meter to mile --> both of them are length units. 171*0e209d39SAndroid Build Coastguard Worker * NOTE: 172*0e209d39SAndroid Build Coastguard Worker * This constructor creates an instance of `ConversionRates` internally. 173*0e209d39SAndroid Build Coastguard Worker * 174*0e209d39SAndroid Build Coastguard Worker * @param sourceIdentifier represents the source unit identifier. 175*0e209d39SAndroid Build Coastguard Worker * @param targetIdentifier represents the target unit identifier. 176*0e209d39SAndroid Build Coastguard Worker * @param status 177*0e209d39SAndroid Build Coastguard Worker */ 178*0e209d39SAndroid Build Coastguard Worker UnitsConverter(StringPiece sourceIdentifier, StringPiece targetIdentifier, UErrorCode &status); 179*0e209d39SAndroid Build Coastguard Worker 180*0e209d39SAndroid Build Coastguard Worker /** 181*0e209d39SAndroid Build Coastguard Worker * Constructor of `UnitConverter`. 182*0e209d39SAndroid Build Coastguard Worker * NOTE: 183*0e209d39SAndroid Build Coastguard Worker * - source and target must be under the same category 184*0e209d39SAndroid Build Coastguard Worker * - e.g. meter to mile --> both of them are length units. 185*0e209d39SAndroid Build Coastguard Worker * 186*0e209d39SAndroid Build Coastguard Worker * @param source represents the source unit. 187*0e209d39SAndroid Build Coastguard Worker * @param target represents the target unit. 188*0e209d39SAndroid Build Coastguard Worker * @param ratesInfo Contains all the needed conversion rates. 189*0e209d39SAndroid Build Coastguard Worker * @param status 190*0e209d39SAndroid Build Coastguard Worker */ 191*0e209d39SAndroid Build Coastguard Worker UnitsConverter(const MeasureUnitImpl &source, const MeasureUnitImpl &target, 192*0e209d39SAndroid Build Coastguard Worker const ConversionRates &ratesInfo, UErrorCode &status); 193*0e209d39SAndroid Build Coastguard Worker 194*0e209d39SAndroid Build Coastguard Worker /** 195*0e209d39SAndroid Build Coastguard Worker * Compares two single units and returns 1 if the first one is greater, -1 if the second 196*0e209d39SAndroid Build Coastguard Worker * one is greater and 0 if they are equal. 197*0e209d39SAndroid Build Coastguard Worker * 198*0e209d39SAndroid Build Coastguard Worker * NOTE: 199*0e209d39SAndroid Build Coastguard Worker * Compares only single units that are convertible. 200*0e209d39SAndroid Build Coastguard Worker */ 201*0e209d39SAndroid Build Coastguard Worker static int32_t compareTwoUnits(const MeasureUnitImpl &firstUnit, const MeasureUnitImpl &SecondUnit, 202*0e209d39SAndroid Build Coastguard Worker const ConversionRates &ratesInfo, UErrorCode &status); 203*0e209d39SAndroid Build Coastguard Worker 204*0e209d39SAndroid Build Coastguard Worker /** 205*0e209d39SAndroid Build Coastguard Worker * Convert a measurement expressed in the source unit to a measurement 206*0e209d39SAndroid Build Coastguard Worker * expressed in the target unit. 207*0e209d39SAndroid Build Coastguard Worker * 208*0e209d39SAndroid Build Coastguard Worker * @param inputValue the value to be converted. 209*0e209d39SAndroid Build Coastguard Worker * @return the converted value. 210*0e209d39SAndroid Build Coastguard Worker */ 211*0e209d39SAndroid Build Coastguard Worker double convert(double inputValue) const; 212*0e209d39SAndroid Build Coastguard Worker 213*0e209d39SAndroid Build Coastguard Worker /** 214*0e209d39SAndroid Build Coastguard Worker * The inverse of convert(): convert a measurement expressed in the target 215*0e209d39SAndroid Build Coastguard Worker * unit to a measurement expressed in the source unit. 216*0e209d39SAndroid Build Coastguard Worker * 217*0e209d39SAndroid Build Coastguard Worker * @param inputValue the value to be converted. 218*0e209d39SAndroid Build Coastguard Worker * @return the converted value. 219*0e209d39SAndroid Build Coastguard Worker */ 220*0e209d39SAndroid Build Coastguard Worker double convertInverse(double inputValue) const; 221*0e209d39SAndroid Build Coastguard Worker 222*0e209d39SAndroid Build Coastguard Worker ConversionInfo getConversionInfo() const; 223*0e209d39SAndroid Build Coastguard Worker 224*0e209d39SAndroid Build Coastguard Worker private: 225*0e209d39SAndroid Build Coastguard Worker ConversionRate conversionRate_; 226*0e209d39SAndroid Build Coastguard Worker 227*0e209d39SAndroid Build Coastguard Worker /** 228*0e209d39SAndroid Build Coastguard Worker * Initialises the object. 229*0e209d39SAndroid Build Coastguard Worker */ 230*0e209d39SAndroid Build Coastguard Worker void init(const ConversionRates &ratesInfo, UErrorCode &status); 231*0e209d39SAndroid Build Coastguard Worker 232*0e209d39SAndroid Build Coastguard Worker /** 233*0e209d39SAndroid Build Coastguard Worker * Convert from what should be discrete scale values for a particular unit like beaufort 234*0e209d39SAndroid Build Coastguard Worker * to a corresponding value in the base unit (which can have any decimal value, like meters/sec). 235*0e209d39SAndroid Build Coastguard Worker * This can handle different scales, specified by minBaseForScaleValues[]. 236*0e209d39SAndroid Build Coastguard Worker */ 237*0e209d39SAndroid Build Coastguard Worker double scaleToBase(double scaleValue, double minBaseForScaleValues[], int scaleMax) const; 238*0e209d39SAndroid Build Coastguard Worker 239*0e209d39SAndroid Build Coastguard Worker /** 240*0e209d39SAndroid Build Coastguard Worker * Convert from a value in the base unit (which can have any decimal value, like meters/sec) to a corresponding 241*0e209d39SAndroid Build Coastguard Worker * discrete value in a scale (like beaufort), where each scale value represents a range of base values. 242*0e209d39SAndroid Build Coastguard Worker * This can handle different scales, specified by minBaseForScaleValues[]. 243*0e209d39SAndroid Build Coastguard Worker */ 244*0e209d39SAndroid Build Coastguard Worker double baseToScale(double baseValue, double minBaseForScaleValues[], int scaleMax) const; 245*0e209d39SAndroid Build Coastguard Worker 246*0e209d39SAndroid Build Coastguard Worker }; 247*0e209d39SAndroid Build Coastguard Worker 248*0e209d39SAndroid Build Coastguard Worker } // namespace units 249*0e209d39SAndroid Build Coastguard Worker U_NAMESPACE_END 250*0e209d39SAndroid Build Coastguard Worker 251*0e209d39SAndroid Build Coastguard Worker #endif //__UNITS_CONVERTER_H__ 252*0e209d39SAndroid Build Coastguard Worker 253*0e209d39SAndroid Build Coastguard Worker #endif /* #if !UCONFIG_NO_FORMATTING */ 254