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