xref: /aosp_15_r20/external/icu/libicu/cts_headers/units_converter.h (revision 0e209d3975ff4a8c132096b14b0e9364a753506e)
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