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 enum Constants { 24 CONSTANT_FT2M, // ft2m stands for foot to meter. 25 CONSTANT_PI, // PI 26 CONSTANT_GRAVITY, // Gravity 27 CONSTANT_G, 28 CONSTANT_GAL_IMP2M3, // Gallon imp to m3 29 CONSTANT_LB2KG, // Pound to Kilogram 30 31 // Must be the last element. 32 CONSTANTS_COUNT 33 }; 34 35 // These values are a hard-coded subset of unitConstants in the units 36 // resources file. A unit test checks that all constants in the resource 37 // file are at least recognised by the code. Derived constants' values or 38 // hard-coded derivations are not checked. 39 static const double constantsValues[CONSTANTS_COUNT] = { 40 0.3048, // CONSTANT_FT2M 41 411557987.0 / 131002976.0, // CONSTANT_PI 42 9.80665, // CONSTANT_GRAVITY 43 6.67408E-11, // CONSTANT_G 44 0.00454609, // CONSTANT_GAL_IMP2M3 45 0.45359237, // CONSTANT_LB2KG 46 }; 47 48 typedef enum Signum { 49 NEGATIVE = -1, 50 POSITIVE = 1, 51 } Signum; 52 53 /* Represents a conversion factor */ 54 struct U_I18N_API Factor { 55 double factorNum = 1; 56 double factorDen = 1; 57 double offset = 0; 58 bool reciprocal = false; 59 int32_t constants[CONSTANTS_COUNT] = {}; 60 61 void multiplyBy(const Factor &rhs); 62 void divideBy(const Factor &rhs); 63 64 // Apply the power to the factor. 65 void power(int32_t power); 66 67 // Flip the `Factor`, for example, factor= 2/3, flippedFactor = 3/2 68 void flip(); 69 70 // Apply SI prefix to the `Factor` 71 void applySiPrefix(UMeasureSIPrefix siPrefix); 72 void substituteConstants(); 73 }; 74 75 /* 76 * Adds a single factor element to the `Factor`. e.g "ft3m", "2.333" or "cup2m3". But not "cup2m3^3". 77 */ 78 void U_I18N_API addSingleFactorConstant(StringPiece baseStr, int32_t power, Signum sigNum, 79 Factor &factor, UErrorCode &status); 80 81 /** 82 * Represents the conversion rate between `source` and `target`. 83 */ 84 struct U_I18N_API ConversionRate : public UMemory { 85 const MeasureUnitImpl source; 86 const MeasureUnitImpl target; 87 double factorNum = 1; 88 double factorDen = 1; 89 double sourceOffset = 0; 90 double targetOffset = 0; 91 bool reciprocal = false; 92 ConversionRateConversionRate93 ConversionRate(MeasureUnitImpl &&source, MeasureUnitImpl &&target) 94 : source(std::move(source)), target(std::move(target)) {} 95 }; 96 97 enum Convertibility { 98 RECIPROCAL, 99 CONVERTIBLE, 100 UNCONVERTIBLE, 101 }; 102 103 MeasureUnitImpl U_I18N_API extractCompoundBaseUnit(const MeasureUnitImpl &source, 104 const ConversionRates &conversionRates, 105 UErrorCode &status); 106 107 /** 108 * Check if the convertibility between `source` and `target`. 109 * For example: 110 * `meter` and `foot` are `CONVERTIBLE`. 111 * `meter-per-second` and `second-per-meter` are `RECIPROCAL`. 112 * `meter` and `pound` are `UNCONVERTIBLE`. 113 * 114 * NOTE: 115 * Only works with SINGLE and COMPOUND units. If one of the units is a 116 * MIXED unit, an error will occur. For more information, see UMeasureUnitComplexity. 117 */ 118 Convertibility U_I18N_API extractConvertibility(const MeasureUnitImpl &source, 119 const MeasureUnitImpl &target, 120 const ConversionRates &conversionRates, 121 UErrorCode &status); 122 123 /** 124 * Converts from a source `MeasureUnit` to a target `MeasureUnit`. 125 * 126 * NOTE: 127 * Only works with SINGLE and COMPOUND units. If one of the units is a 128 * MIXED unit, an error will occur. For more information, see UMeasureUnitComplexity. 129 */ 130 class U_I18N_API UnitConverter : public UMemory { 131 public: 132 /** 133 * Constructor of `UnitConverter`. 134 * NOTE: 135 * - source and target must be under the same category 136 * - e.g. meter to mile --> both of them are length units. 137 * 138 * @param source represents the source unit. 139 * @param target represents the target unit. 140 * @param ratesInfo Contains all the needed conversion rates. 141 * @param status 142 */ 143 UnitConverter(const MeasureUnitImpl &source, const MeasureUnitImpl &target, 144 const ConversionRates &ratesInfo, UErrorCode &status); 145 146 /** 147 * Convert a measurement expressed in the source unit to a measurement 148 * expressed in the target unit. 149 * 150 * @param inputValue the value to be converted. 151 * @return the converted value. 152 */ 153 double convert(double inputValue) const; 154 155 /** 156 * The inverse of convert(): convert a measurement expressed in the target 157 * unit to a measurement expressed in the source unit. 158 * 159 * @param inputValue the value to be converted. 160 * @return the converted value. 161 */ 162 double convertInverse(double inputValue) const; 163 164 private: 165 ConversionRate conversionRate_; 166 }; 167 168 } // namespace units 169 U_NAMESPACE_END 170 171 #endif //__UNITS_CONVERTER_H__ 172 173 #endif /* #if !UCONFIG_NO_FORMATTING */ 174