units_converter.h 7.4 KB

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