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