PluginProbe
TablePress – Tables in WordPress made easy / 3.4
TablePress – Tables in WordPress made easy v3.4
3.4 3.3.4 3.3.3 3.3.2 3.3.1 trunk 1.12 1.14 1.9.2 2.0.4 2.1.7 2.1.8 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3 2.3.1 2.3.2 2.4 2.4.1 2.4.2 2.4.3 All 45 releases
tablepress / libraries / vendor / PhpSpreadsheet / Calculation / Engineering / ConvertUOM.php

ConvertUOM.php in TablePress – Tables in WordPress made easy 3.4, at libraries/vendor/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php

695 lines 31.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace TablePress\PhpOffice\PhpSpreadsheet\Calculation\Engineering;
4
5 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
6 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Exception;
7 use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
8
9 class ConvertUOM
10 {
11 use ArrayEnabled;
12
13 public const CATEGORY_WEIGHT_AND_MASS = 'Weight and Mass';
14 public const CATEGORY_DISTANCE = 'Distance';
15 public const CATEGORY_TIME = 'Time';
16 public const CATEGORY_PRESSURE = 'Pressure';
17 public const CATEGORY_FORCE = 'Force';
18 public const CATEGORY_ENERGY = 'Energy';
19 public const CATEGORY_POWER = 'Power';
20 public const CATEGORY_MAGNETISM = 'Magnetism';
21 public const CATEGORY_TEMPERATURE = 'Temperature';
22 public const CATEGORY_VOLUME = 'Volume and Liquid Measure';
23 public const CATEGORY_AREA = 'Area';
24 public const CATEGORY_INFORMATION = 'Information';
25 public const CATEGORY_SPEED = 'Speed';
26
27 /**
28 * Details of the Units of measure that can be used in CONVERTUOM().
29 *
30 * @var array<string, array{Group: string, UnitName: string, AllowPrefix: bool}>
31 */
32 private static array $conversionUnits = [
33 // Weight and Mass
34 'g' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Gram', 'AllowPrefix' => true],
35 'sg' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Slug', 'AllowPrefix' => false],
36 'lbm' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Pound mass (avoirdupois)', 'AllowPrefix' => false],
37 'u' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'U (atomic mass unit)', 'AllowPrefix' => true],
38 'ozm' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Ounce mass (avoirdupois)', 'AllowPrefix' => false],
39 'grain' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Grain', 'AllowPrefix' => false],
40 'cwt' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'U.S. (short) hundredweight', 'AllowPrefix' => false],
41 'shweight' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'U.S. (short) hundredweight', 'AllowPrefix' => false],
42 'uk_cwt' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Imperial hundredweight', 'AllowPrefix' => false],
43 'lcwt' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Imperial hundredweight', 'AllowPrefix' => false],
44 'hweight' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Imperial hundredweight', 'AllowPrefix' => false],
45 'stone' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Stone', 'AllowPrefix' => false],
46 'ton' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Ton', 'AllowPrefix' => false],
47 'uk_ton' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Imperial ton', 'AllowPrefix' => false],
48 'LTON' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Imperial ton', 'AllowPrefix' => false],
49 'brton' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'UnitName' => 'Imperial ton', 'AllowPrefix' => false],
50 // Distance
51 'm' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Meter', 'AllowPrefix' => true],
52 'mi' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Statute mile', 'AllowPrefix' => false],
53 'Nmi' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Nautical mile', 'AllowPrefix' => false],
54 'in' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Inch', 'AllowPrefix' => false],
55 'ft' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Foot', 'AllowPrefix' => false],
56 'yd' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Yard', 'AllowPrefix' => false],
57 'ang' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Angstrom', 'AllowPrefix' => true],
58 'ell' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Ell', 'AllowPrefix' => false],
59 'ly' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Light Year', 'AllowPrefix' => false],
60 'parsec' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Parsec', 'AllowPrefix' => false],
61 'pc' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Parsec', 'AllowPrefix' => false],
62 'Pica' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Pica (1/72 in)', 'AllowPrefix' => false],
63 'Picapt' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Pica (1/72 in)', 'AllowPrefix' => false],
64 'pica' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'Pica (1/6 in)', 'AllowPrefix' => false],
65 'survey_mi' => ['Group' => self::CATEGORY_DISTANCE, 'UnitName' => 'U.S survey mile (statute mile)', 'AllowPrefix' => false],
66 // Time
67 'yr' => ['Group' => self::CATEGORY_TIME, 'UnitName' => 'Year', 'AllowPrefix' => false],
68 'day' => ['Group' => self::CATEGORY_TIME, 'UnitName' => 'Day', 'AllowPrefix' => false],
69 'd' => ['Group' => self::CATEGORY_TIME, 'UnitName' => 'Day', 'AllowPrefix' => false],
70 'hr' => ['Group' => self::CATEGORY_TIME, 'UnitName' => 'Hour', 'AllowPrefix' => false],
71 'mn' => ['Group' => self::CATEGORY_TIME, 'UnitName' => 'Minute', 'AllowPrefix' => false],
72 'min' => ['Group' => self::CATEGORY_TIME, 'UnitName' => 'Minute', 'AllowPrefix' => false],
73 'sec' => ['Group' => self::CATEGORY_TIME, 'UnitName' => 'Second', 'AllowPrefix' => true],
74 's' => ['Group' => self::CATEGORY_TIME, 'UnitName' => 'Second', 'AllowPrefix' => true],
75 // Pressure
76 'Pa' => ['Group' => self::CATEGORY_PRESSURE, 'UnitName' => 'Pascal', 'AllowPrefix' => true],
77 'p' => ['Group' => self::CATEGORY_PRESSURE, 'UnitName' => 'Pascal', 'AllowPrefix' => true],
78 'atm' => ['Group' => self::CATEGORY_PRESSURE, 'UnitName' => 'Atmosphere', 'AllowPrefix' => true],
79 'at' => ['Group' => self::CATEGORY_PRESSURE, 'UnitName' => 'Atmosphere', 'AllowPrefix' => true],
80 'mmHg' => ['Group' => self::CATEGORY_PRESSURE, 'UnitName' => 'mm of Mercury', 'AllowPrefix' => true],
81 'psi' => ['Group' => self::CATEGORY_PRESSURE, 'UnitName' => 'PSI', 'AllowPrefix' => true],
82 'Torr' => ['Group' => self::CATEGORY_PRESSURE, 'UnitName' => 'Torr', 'AllowPrefix' => true],
83 // Force
84 'N' => ['Group' => self::CATEGORY_FORCE, 'UnitName' => 'Newton', 'AllowPrefix' => true],
85 'dyn' => ['Group' => self::CATEGORY_FORCE, 'UnitName' => 'Dyne', 'AllowPrefix' => true],
86 'dy' => ['Group' => self::CATEGORY_FORCE, 'UnitName' => 'Dyne', 'AllowPrefix' => true],
87 'lbf' => ['Group' => self::CATEGORY_FORCE, 'UnitName' => 'Pound force', 'AllowPrefix' => false],
88 'pond' => ['Group' => self::CATEGORY_FORCE, 'UnitName' => 'Pond', 'AllowPrefix' => true],
89 // Energy
90 'J' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'Joule', 'AllowPrefix' => true],
91 'e' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'Erg', 'AllowPrefix' => true],
92 'c' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'Thermodynamic calorie', 'AllowPrefix' => true],
93 'cal' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'IT calorie', 'AllowPrefix' => true],
94 'eV' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'Electron volt', 'AllowPrefix' => true],
95 'ev' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'Electron volt', 'AllowPrefix' => true],
96 'HPh' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'Horsepower-hour', 'AllowPrefix' => false],
97 'hh' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'Horsepower-hour', 'AllowPrefix' => false],
98 'Wh' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'Watt-hour', 'AllowPrefix' => true],
99 'wh' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'Watt-hour', 'AllowPrefix' => true],
100 'flb' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'Foot-pound', 'AllowPrefix' => false],
101 'BTU' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'BTU', 'AllowPrefix' => false],
102 'btu' => ['Group' => self::CATEGORY_ENERGY, 'UnitName' => 'BTU', 'AllowPrefix' => false],
103 // Power
104 'HP' => ['Group' => self::CATEGORY_POWER, 'UnitName' => 'Horsepower', 'AllowPrefix' => false],
105 'h' => ['Group' => self::CATEGORY_POWER, 'UnitName' => 'Horsepower', 'AllowPrefix' => false],
106 'W' => ['Group' => self::CATEGORY_POWER, 'UnitName' => 'Watt', 'AllowPrefix' => true],
107 'w' => ['Group' => self::CATEGORY_POWER, 'UnitName' => 'Watt', 'AllowPrefix' => true],
108 'PS' => ['Group' => self::CATEGORY_POWER, 'UnitName' => 'Pferdestärke', 'AllowPrefix' => false],
109 // Magnetism
110 'T' => ['Group' => self::CATEGORY_MAGNETISM, 'UnitName' => 'Tesla', 'AllowPrefix' => true],
111 'ga' => ['Group' => self::CATEGORY_MAGNETISM, 'UnitName' => 'Gauss', 'AllowPrefix' => true],
112 // Temperature
113 'C' => ['Group' => self::CATEGORY_TEMPERATURE, 'UnitName' => 'Degrees Celsius', 'AllowPrefix' => false],
114 'cel' => ['Group' => self::CATEGORY_TEMPERATURE, 'UnitName' => 'Degrees Celsius', 'AllowPrefix' => false],
115 'F' => ['Group' => self::CATEGORY_TEMPERATURE, 'UnitName' => 'Degrees Fahrenheit', 'AllowPrefix' => false],
116 'fah' => ['Group' => self::CATEGORY_TEMPERATURE, 'UnitName' => 'Degrees Fahrenheit', 'AllowPrefix' => false],
117 'K' => ['Group' => self::CATEGORY_TEMPERATURE, 'UnitName' => 'Kelvin', 'AllowPrefix' => false],
118 'kel' => ['Group' => self::CATEGORY_TEMPERATURE, 'UnitName' => 'Kelvin', 'AllowPrefix' => false],
119 'Rank' => ['Group' => self::CATEGORY_TEMPERATURE, 'UnitName' => 'Degrees Rankine', 'AllowPrefix' => false],
120 'Reau' => ['Group' => self::CATEGORY_TEMPERATURE, 'UnitName' => 'Degrees Réaumur', 'AllowPrefix' => false],
121 // Volume
122 'l' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Litre', 'AllowPrefix' => true],
123 'L' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Litre', 'AllowPrefix' => true],
124 'lt' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Litre', 'AllowPrefix' => true],
125 'tsp' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Teaspoon', 'AllowPrefix' => false],
126 'tspm' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Modern Teaspoon', 'AllowPrefix' => false],
127 'tbs' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Tablespoon', 'AllowPrefix' => false],
128 'oz' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Fluid Ounce', 'AllowPrefix' => false],
129 'cup' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cup', 'AllowPrefix' => false],
130 'pt' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'U.S. Pint', 'AllowPrefix' => false],
131 'us_pt' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'U.S. Pint', 'AllowPrefix' => false],
132 'uk_pt' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'U.K. Pint', 'AllowPrefix' => false],
133 'qt' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Quart', 'AllowPrefix' => false],
134 'uk_qt' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Imperial Quart (UK)', 'AllowPrefix' => false],
135 'gal' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Gallon', 'AllowPrefix' => false],
136 'uk_gal' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Imperial Gallon (UK)', 'AllowPrefix' => false],
137 'ang3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Angstrom', 'AllowPrefix' => true],
138 'ang^3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Angstrom', 'AllowPrefix' => true],
139 'barrel' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'US Oil Barrel', 'AllowPrefix' => false],
140 'bushel' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'US Bushel', 'AllowPrefix' => false],
141 'in3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Inch', 'AllowPrefix' => false],
142 'in^3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Inch', 'AllowPrefix' => false],
143 'ft3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Foot', 'AllowPrefix' => false],
144 'ft^3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Foot', 'AllowPrefix' => false],
145 'ly3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Light Year', 'AllowPrefix' => false],
146 'ly^3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Light Year', 'AllowPrefix' => false],
147 'm3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Meter', 'AllowPrefix' => true],
148 'm^3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Meter', 'AllowPrefix' => true],
149 'mi3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Mile', 'AllowPrefix' => false],
150 'mi^3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Mile', 'AllowPrefix' => false],
151 'yd3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Yard', 'AllowPrefix' => false],
152 'yd^3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Yard', 'AllowPrefix' => false],
153 'Nmi3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Nautical Mile', 'AllowPrefix' => false],
154 'Nmi^3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Nautical Mile', 'AllowPrefix' => false],
155 'Pica3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Pica', 'AllowPrefix' => false],
156 'Pica^3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Pica', 'AllowPrefix' => false],
157 'Picapt3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Pica', 'AllowPrefix' => false],
158 'Picapt^3' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Cubic Pica', 'AllowPrefix' => false],
159 'GRT' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Gross Registered Ton', 'AllowPrefix' => false],
160 'regton' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Gross Registered Ton', 'AllowPrefix' => false],
161 'MTON' => ['Group' => self::CATEGORY_VOLUME, 'UnitName' => 'Measurement Ton (Freight Ton)', 'AllowPrefix' => false],
162 // Area
163 'ha' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Hectare', 'AllowPrefix' => true],
164 'uk_acre' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'International Acre', 'AllowPrefix' => false],
165 'us_acre' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'US Survey/Statute Acre', 'AllowPrefix' => false],
166 'ang2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Angstrom', 'AllowPrefix' => true],
167 'ang^2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Angstrom', 'AllowPrefix' => true],
168 'ar' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Are', 'AllowPrefix' => true],
169 'ft2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Feet', 'AllowPrefix' => false],
170 'ft^2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Feet', 'AllowPrefix' => false],
171 'in2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Inches', 'AllowPrefix' => false],
172 'in^2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Inches', 'AllowPrefix' => false],
173 'ly2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Light Years', 'AllowPrefix' => false],
174 'ly^2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Light Years', 'AllowPrefix' => false],
175 'm2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Meters', 'AllowPrefix' => true],
176 'm^2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Meters', 'AllowPrefix' => true],
177 'Morgen' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Morgen', 'AllowPrefix' => false],
178 'mi2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Miles', 'AllowPrefix' => false],
179 'mi^2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Miles', 'AllowPrefix' => false],
180 'Nmi2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Nautical Miles', 'AllowPrefix' => false],
181 'Nmi^2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Nautical Miles', 'AllowPrefix' => false],
182 'Pica2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Pica', 'AllowPrefix' => false],
183 'Pica^2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Pica', 'AllowPrefix' => false],
184 'Picapt2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Pica', 'AllowPrefix' => false],
185 'Picapt^2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Pica', 'AllowPrefix' => false],
186 'yd2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Yards', 'AllowPrefix' => false],
187 'yd^2' => ['Group' => self::CATEGORY_AREA, 'UnitName' => 'Square Yards', 'AllowPrefix' => false],
188 // Information
189 'byte' => ['Group' => self::CATEGORY_INFORMATION, 'UnitName' => 'Byte', 'AllowPrefix' => true],
190 'bit' => ['Group' => self::CATEGORY_INFORMATION, 'UnitName' => 'Bit', 'AllowPrefix' => true],
191 // Speed
192 'm/s' => ['Group' => self::CATEGORY_SPEED, 'UnitName' => 'Meters per second', 'AllowPrefix' => true],
193 'm/sec' => ['Group' => self::CATEGORY_SPEED, 'UnitName' => 'Meters per second', 'AllowPrefix' => true],
194 'm/h' => ['Group' => self::CATEGORY_SPEED, 'UnitName' => 'Meters per hour', 'AllowPrefix' => true],
195 'm/hr' => ['Group' => self::CATEGORY_SPEED, 'UnitName' => 'Meters per hour', 'AllowPrefix' => true],
196 'mph' => ['Group' => self::CATEGORY_SPEED, 'UnitName' => 'Miles per hour', 'AllowPrefix' => false],
197 'admkn' => ['Group' => self::CATEGORY_SPEED, 'UnitName' => 'Admiralty Knot', 'AllowPrefix' => false],
198 'kn' => ['Group' => self::CATEGORY_SPEED, 'UnitName' => 'Knot', 'AllowPrefix' => false],
199 ];
200
201 /**
202 * Details of the Multiplier prefixes that can be used with Units of Measure in CONVERTUOM().
203 *
204 * @var array<string, array{multiplier: float, name: string}>
205 */
206 private static array $conversionMultipliers = [
207 'Y' => ['multiplier' => 1E24, 'name' => 'yotta'],
208 'Z' => ['multiplier' => 1E21, 'name' => 'zetta'],
209 'E' => ['multiplier' => 1E18, 'name' => 'exa'],
210 'P' => ['multiplier' => 1E15, 'name' => 'peta'],
211 'T' => ['multiplier' => 1E12, 'name' => 'tera'],
212 'G' => ['multiplier' => 1E9, 'name' => 'giga'],
213 'M' => ['multiplier' => 1E6, 'name' => 'mega'],
214 'k' => ['multiplier' => 1E3, 'name' => 'kilo'],
215 'h' => ['multiplier' => 1E2, 'name' => 'hecto'],
216 'e' => ['multiplier' => 1E1, 'name' => 'dekao'],
217 'da' => ['multiplier' => 1E1, 'name' => 'dekao'],
218 'd' => ['multiplier' => 1E-1, 'name' => 'deci'],
219 'c' => ['multiplier' => 1E-2, 'name' => 'centi'],
220 'm' => ['multiplier' => 1E-3, 'name' => 'milli'],
221 'u' => ['multiplier' => 1E-6, 'name' => 'micro'],
222 'n' => ['multiplier' => 1E-9, 'name' => 'nano'],
223 'p' => ['multiplier' => 1E-12, 'name' => 'pico'],
224 'f' => ['multiplier' => 1E-15, 'name' => 'femto'],
225 'a' => ['multiplier' => 1E-18, 'name' => 'atto'],
226 'z' => ['multiplier' => 1E-21, 'name' => 'zepto'],
227 'y' => ['multiplier' => 1E-24, 'name' => 'yocto'],
228 ];
229
230 /**
231 * Details of the Multiplier prefixes that can be used with Units of Measure in CONVERTUOM().
232 *
233 * @var array<string, array{multiplier: float|int, name: string}>
234 */
235 private static array $binaryConversionMultipliers = [
236 'Yi' => ['multiplier' => 2 ** 80, 'name' => 'yobi'],
237 'Zi' => ['multiplier' => 2 ** 70, 'name' => 'zebi'],
238 'Ei' => ['multiplier' => 2 ** 60, 'name' => 'exbi'],
239 'Pi' => ['multiplier' => 2 ** 50, 'name' => 'pebi'],
240 'Ti' => ['multiplier' => 2 ** 40, 'name' => 'tebi'],
241 'Gi' => ['multiplier' => 2 ** 30, 'name' => 'gibi'],
242 'Mi' => ['multiplier' => 2 ** 20, 'name' => 'mebi'],
243 'ki' => ['multiplier' => 2 ** 10, 'name' => 'kibi'],
244 ];
245
246 /**
247 * Details of the Units of measure conversion factors, organised by group.
248 *
249 * @var array<string, array<string, float>>
250 */
251 private static array $unitConversions = [
252 // Conversion uses gram (g) as an intermediate unit
253 self::CATEGORY_WEIGHT_AND_MASS => [
254 'g' => 1.0,
255 'sg' => 6.85217658567918E-05,
256 'lbm' => 2.20462262184878E-03,
257 'u' => 6.02214179421676E+23,
258 'ozm' => 3.52739619495804E-02,
259 'grain' => 1.54323583529414E+01,
260 'cwt' => 2.20462262184878E-05,
261 'shweight' => 2.20462262184878E-05,
262 'uk_cwt' => 1.96841305522212E-05,
263 'lcwt' => 1.96841305522212E-05,
264 'hweight' => 1.96841305522212E-05,
265 'stone' => 1.57473044417770E-04,
266 'ton' => 1.10231131092439E-06,
267 'uk_ton' => 9.84206527611061E-07,
268 'LTON' => 9.84206527611061E-07,
269 'brton' => 9.84206527611061E-07,
270 ],
271 // Conversion uses meter (m) as an intermediate unit
272 self::CATEGORY_DISTANCE => [
273 'm' => 1.0,
274 'mi' => 6.21371192237334E-04,
275 'Nmi' => 5.39956803455724E-04,
276 'in' => 3.93700787401575E+01,
277 'ft' => 3.28083989501312E+00,
278 'yd' => 1.09361329833771E+00,
279 'ang' => 1.0E+10,
280 'ell' => 8.74890638670166E-01,
281 'ly' => 1.05700083402462E-16,
282 'parsec' => 3.24077928966473E-17,
283 'pc' => 3.24077928966473E-17,
284 'Pica' => 2.83464566929134E+03,
285 'Picapt' => 2.83464566929134E+03,
286 'pica' => 2.36220472440945E+02,
287 'survey_mi' => 6.21369949494950E-04,
288 ],
289 // Conversion uses second (s) as an intermediate unit
290 self::CATEGORY_TIME => [
291 'yr' => 3.16880878140289E-08,
292 'day' => 1.15740740740741E-05,
293 'd' => 1.15740740740741E-05,
294 'hr' => 2.77777777777778E-04,
295 'mn' => 1.66666666666667E-02,
296 'min' => 1.66666666666667E-02,
297 'sec' => 1.0,
298 's' => 1.0,
299 ],
300 // Conversion uses Pascal (Pa) as an intermediate unit
301 self::CATEGORY_PRESSURE => [
302 'Pa' => 1.0,
303 'p' => 1.0,
304 'atm' => 9.86923266716013E-06,
305 'at' => 9.86923266716013E-06,
306 'mmHg' => 7.50063755419211E-03,
307 'psi' => 1.45037737730209E-04,
308 'Torr' => 7.50061682704170E-03,
309 ],
310 // Conversion uses Newton (N) as an intermediate unit
311 self::CATEGORY_FORCE => [
312 'N' => 1.0,
313 'dyn' => 1.0E+5,
314 'dy' => 1.0E+5,
315 'lbf' => 2.24808923655339E-01,
316 'pond' => 1.01971621297793E+02,
317 ],
318 // Conversion uses Joule (J) as an intermediate unit
319 self::CATEGORY_ENERGY => [
320 'J' => 1.0,
321 'e' => 9.99999519343231E+06,
322 'c' => 2.39006249473467E-01,
323 'cal' => 2.38846190642017E-01,
324 'eV' => 6.24145700000000E+18,
325 'ev' => 6.24145700000000E+18,
326 'HPh' => 3.72506430801000E-07,
327 'hh' => 3.72506430801000E-07,
328 'Wh' => 2.77777916238711E-04,
329 'wh' => 2.77777916238711E-04,
330 'flb' => 2.37304222192651E+01,
331 'BTU' => 9.47815067349015E-04,
332 'btu' => 9.47815067349015E-04,
333 ],
334 // Conversion uses Horsepower (HP) as an intermediate unit
335 self::CATEGORY_POWER => [
336 'HP' => 1.0,
337 'h' => 1.0,
338 'W' => 7.45699871582270E+02,
339 'w' => 7.45699871582270E+02,
340 'PS' => 1.01386966542400E+00,
341 ],
342 // Conversion uses Tesla (T) as an intermediate unit
343 self::CATEGORY_MAGNETISM => [
344 'T' => 1.0,
345 'ga' => 10000.0,
346 ],
347 // Conversion uses litre (l) as an intermediate unit
348 self::CATEGORY_VOLUME => [
349 'l' => 1.0,
350 'L' => 1.0,
351 'lt' => 1.0,
352 'tsp' => 2.02884136211058E+02,
353 'tspm' => 2.0E+02,
354 'tbs' => 6.76280454036860E+01,
355 'oz' => 3.38140227018430E+01,
356 'cup' => 4.22675283773038E+00,
357 'pt' => 2.11337641886519E+00,
358 'us_pt' => 2.11337641886519E+00,
359 'uk_pt' => 1.75975398639270E+00,
360 'qt' => 1.05668820943259E+00,
361 'uk_qt' => 8.79876993196351E-01,
362 'gal' => 2.64172052358148E-01,
363 'uk_gal' => 2.19969248299088E-01,
364 'ang3' => 1.0E+27,
365 'ang^3' => 1.0E+27,
366 'barrel' => 6.28981077043211E-03,
367 'bushel' => 2.83775932584017E-02,
368 'in3' => 6.10237440947323E+01,
369 'in^3' => 6.10237440947323E+01,
370 'ft3' => 3.53146667214886E-02,
371 'ft^3' => 3.53146667214886E-02,
372 'ly3' => 1.18093498844171E-51,
373 'ly^3' => 1.18093498844171E-51,
374 'm3' => 1.0E-03,
375 'm^3' => 1.0E-03,
376 'mi3' => 2.39912758578928E-13,
377 'mi^3' => 2.39912758578928E-13,
378 'yd3' => 1.30795061931439E-03,
379 'yd^3' => 1.30795061931439E-03,
380 'Nmi3' => 1.57426214685811E-13,
381 'Nmi^3' => 1.57426214685811E-13,
382 'Pica3' => 2.27769904358706E+07,
383 'Pica^3' => 2.27769904358706E+07,
384 'Picapt3' => 2.27769904358706E+07,
385 'Picapt^3' => 2.27769904358706E+07,
386 'GRT' => 3.53146667214886E-04,
387 'regton' => 3.53146667214886E-04,
388 'MTON' => 8.82866668037215E-04,
389 ],
390 // Conversion uses hectare (ha) as an intermediate unit
391 self::CATEGORY_AREA => [
392 'ha' => 1.0,
393 'uk_acre' => 2.47105381467165E+00,
394 'us_acre' => 2.47104393046628E+00,
395 'ang2' => 1.0E+24,
396 'ang^2' => 1.0E+24,
397 'ar' => 1.0E+02,
398 'ft2' => 1.07639104167097E+05,
399 'ft^2' => 1.07639104167097E+05,
400 'in2' => 1.55000310000620E+07,
401 'in^2' => 1.55000310000620E+07,
402 'ly2' => 1.11725076312873E-28,
403 'ly^2' => 1.11725076312873E-28,
404 'm2' => 1.0E+04,
405 'm^2' => 1.0E+04,
406 'Morgen' => 4.0E+00,
407 'mi2' => 3.86102158542446E-03,
408 'mi^2' => 3.86102158542446E-03,
409 'Nmi2' => 2.91553349598123E-03,
410 'Nmi^2' => 2.91553349598123E-03,
411 'Pica2' => 8.03521607043214E+10,
412 'Pica^2' => 8.03521607043214E+10,
413 'Picapt2' => 8.03521607043214E+10,
414 'Picapt^2' => 8.03521607043214E+10,
415 'yd2' => 1.19599004630108E+04,
416 'yd^2' => 1.19599004630108E+04,
417 ],
418 // Conversion uses bit (bit) as an intermediate unit
419 self::CATEGORY_INFORMATION => [
420 'bit' => 1.0,
421 'byte' => 0.125,
422 ],
423 // Conversion uses Meters per Second (m/s) as an intermediate unit
424 self::CATEGORY_SPEED => [
425 'm/s' => 1.0,
426 'm/sec' => 1.0,
427 'm/h' => 3.60E+03,
428 'm/hr' => 3.60E+03,
429 'mph' => 2.23693629205440E+00,
430 'admkn' => 1.94260256941567E+00,
431 'kn' => 1.94384449244060E+00,
432 ],
433 ];
434
435 /**
436 * getConversionGroups
437 * Returns a list of the different conversion groups for UOM conversions.
438 *
439 * @return string[]
440 */
441 public static function getConversionCategories(): array
442 {
443 $conversionGroups = [];
444 foreach (self::$conversionUnits as $conversionUnit) {
445 $conversionGroups[] = $conversionUnit['Group'];
446 }
447
448 return array_merge(array_unique($conversionGroups));
449 }
450
451 /**
452 * getConversionGroupUnits
453 * Returns an array of units of measure, for a specified conversion group, or for all groups.
454 *
455 * @param ?string $category The group whose units of measure you want to retrieve
456 *
457 * @return string[][]
458 */
459 public static function getConversionCategoryUnits(?string $category = null): array
460 {
461 $conversionGroups = [];
462 foreach (self::$conversionUnits as $conversionUnit => $conversionGroup) {
463 if (($category === null) || ($conversionGroup['Group'] == $category)) {
464 $conversionGroups[$conversionGroup['Group']][] = $conversionUnit;
465 }
466 }
467
468 return $conversionGroups;
469 }
470
471 /**
472 * getConversionGroupUnitDetails.
473 *
474 * @param ?string $category The group whose units of measure you want to retrieve
475 *
476 * @return array<string, list<array<string, string>>>
477 */
478 public static function getConversionCategoryUnitDetails(?string $category = null): array
479 {
480 $conversionGroups = [];
481 foreach (self::$conversionUnits as $conversionUnit => $conversionGroup) {
482 if (($category === null) || ($conversionGroup['Group'] == $category)) {
483 $conversionGroups[$conversionGroup['Group']][] = [
484 'unit' => $conversionUnit,
485 'description' => $conversionGroup['UnitName'],
486 ];
487 }
488 }
489
490 return $conversionGroups;
491 }
492
493 /**
494 * getConversionMultipliers
495 * Returns an array of the Multiplier prefixes that can be used with Units of Measure in CONVERTUOM().
496 *
497 * @return array<string, array{multiplier: float, name: string}>
498 */
499 public static function getConversionMultipliers(): array
500 {
501 return self::$conversionMultipliers;
502 }
503
504 /**
505 * getBinaryConversionMultipliers
506 * Returns an array of the additional Multiplier prefixes that can be used with Information Units of Measure in CONVERTUOM().
507 *
508 * @return array<string, array{multiplier: float|int, name: string}>
509 */
510 public static function getBinaryConversionMultipliers(): array
511 {
512 return self::$binaryConversionMultipliers;
513 }
514
515 /**
516 * CONVERT.
517 *
518 * Converts a number from one measurement system to another.
519 * For example, CONVERT can translate a table of distances in miles to a table of distances
520 * in kilometers.
521 *
522 * Excel Function:
523 * CONVERT(value,fromUOM,toUOM)
524 *
525 * @param array<mixed>|float|int|string $value the value in fromUOM to convert
526 * Or can be an array of values
527 * @param string|string[] $fromUOM the units for value
528 * Or can be an array of values
529 * @param string|string[] $toUOM the units for the result
530 * Or can be an array of values
531 *
532 * @return float|mixed[]|string Result, or a string containing an error
533 * If an array of numbers is passed as an argument, then the returned result will also be an array
534 * with the same dimensions
535 */
536 public static function CONVERT($value, $fromUOM, $toUOM)
537 {
538 if (is_array($value) || is_array($fromUOM) || is_array($toUOM)) {
539 return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $fromUOM, $toUOM);
540 }
541
542 if (!is_numeric($value)) {
543 return ExcelError::VALUE();
544 }
545
546 try {
547 [$fromUOM, $fromCategory, $fromMultiplier] = self::getUOMDetails($fromUOM);
548 [$toUOM, $toCategory, $toMultiplier] = self::getUOMDetails($toUOM);
549 } catch (Exception $exception) {
550 return ExcelError::NA();
551 }
552
553 if ($fromCategory !== $toCategory) {
554 return ExcelError::NA();
555 }
556
557 // @var float $value
558 $value *= $fromMultiplier;
559
560 if (($fromUOM === $toUOM) && ($fromMultiplier === $toMultiplier)) {
561 // We've already factored $fromMultiplier into the value, so we need
562 // to reverse it again
563 return $value / $fromMultiplier;
564 } elseif ($fromUOM === $toUOM) {
565 return $value / $toMultiplier;
566 } elseif ($fromCategory === self::CATEGORY_TEMPERATURE) {
567 return self::convertTemperature($fromUOM, $toUOM, $value);
568 }
569
570 $baseValue = $value * (1.0 / self::$unitConversions[$fromCategory][$fromUOM]);
571
572 return ($baseValue * self::$unitConversions[$fromCategory][$toUOM]) / $toMultiplier;
573 }
574
575 /** @return array{0: string, 1: string, 2: float} */
576 private static function getUOMDetails(string $uom): array
577 {
578 if (isset(self::$conversionUnits[$uom])) {
579 $unitCategory = self::$conversionUnits[$uom]['Group'];
580
581 return [$uom, $unitCategory, 1.0];
582 }
583
584 // Check 1-character standard metric multiplier prefixes
585 $multiplierType = substr($uom, 0, 1);
586 $uom = (string) substr($uom, 1);
587 if (isset(self::$conversionUnits[$uom], self::$conversionMultipliers[$multiplierType])) {
588 if (self::$conversionUnits[$uom]['AllowPrefix'] === false) {
589 throw new Exception('Prefix not allowed for UoM');
590 }
591 $unitCategory = self::$conversionUnits[$uom]['Group'];
592
593 return [$uom, $unitCategory, self::$conversionMultipliers[$multiplierType]['multiplier']];
594 }
595
596 $multiplierType .= substr($uom, 0, 1);
597 $uom = (string) substr($uom, 1);
598
599 // Check 2-character standard metric multiplier prefixes
600 if (isset(self::$conversionUnits[$uom], self::$conversionMultipliers[$multiplierType])) {
601 if (self::$conversionUnits[$uom]['AllowPrefix'] === false) {
602 throw new Exception('Prefix not allowed for UoM');
603 }
604 $unitCategory = self::$conversionUnits[$uom]['Group'];
605
606 return [$uom, $unitCategory, self::$conversionMultipliers[$multiplierType]['multiplier']];
607 }
608
609 // Check 2-character binary multiplier prefixes
610 if (isset(self::$conversionUnits[$uom], self::$binaryConversionMultipliers[$multiplierType])) {
611 if (self::$conversionUnits[$uom]['AllowPrefix'] === false) {
612 throw new Exception('Prefix not allowed for UoM');
613 }
614 $unitCategory = self::$conversionUnits[$uom]['Group'];
615 if ($unitCategory !== 'Information') {
616 throw new Exception('Binary Prefix is only allowed for Information UoM');
617 }
618
619 return [$uom, $unitCategory, self::$binaryConversionMultipliers[$multiplierType]['multiplier']];
620 }
621
622 throw new Exception('UoM Not Found');
623 }
624
625 /**
626 * @param float|int $value
627 * @return float|int
628 */
629 protected static function convertTemperature(string $fromUOM, string $toUOM, $value)
630 {
631 $fromUOM = self::resolveTemperatureSynonyms($fromUOM);
632 $toUOM = self::resolveTemperatureSynonyms($toUOM);
633
634 if ($fromUOM === $toUOM) {
635 return $value;
636 }
637
638 // Convert to Kelvin
639 switch ($fromUOM) {
640 case 'F':
641 $value = ($value - 32) / 1.8 + 273.15;
642
643 break;
644 case 'C':
645 $value += 273.15;
646
647 break;
648 case 'Rank':
649 $value /= 1.8;
650
651 break;
652 case 'Reau':
653 $value = $value * 1.25 + 273.15;
654
655 break;
656 }
657
658 // Convert from Kelvin
659 switch ($toUOM) {
660 case 'F':
661 $value = ($value - 273.15) * 1.8 + 32.00;
662
663 break;
664 case 'C':
665 $value -= 273.15;
666
667 break;
668 case 'Rank':
669 $value *= 1.8;
670
671 break;
672 case 'Reau':
673 $value = ($value - 273.15) * 0.80000;
674
675 break;
676 }
677
678 return $value;
679 }
680
681 private static function resolveTemperatureSynonyms(string $uom): string
682 {
683 switch ($uom) {
684 case 'fah':
685 return 'F';
686 case 'cel':
687 return 'C';
688 case 'kel':
689 return 'K';
690 default:
691 return $uom;
692 }
693 }
694 }
695