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