1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.utils.units;
18
19 import java.io.Serializable;
20 import java.util.List;
21
22 import org.hipparchus.fraction.Fraction;
23 import org.hipparchus.util.FastMath;
24 import org.hipparchus.util.Precision;
25 import org.orekit.errors.OrekitException;
26 import org.orekit.errors.OrekitMessages;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 public class Unit implements Serializable {
43
44
45 public static final Unit NONE = new Unit("n/a", 1.0, Fraction.ZERO, Fraction.ZERO, Fraction.ZERO, Fraction.ZERO, Fraction.ZERO);
46
47
48 public static final Unit ONE = new Unit("1", 1.0, Fraction.ZERO, Fraction.ZERO, Fraction.ZERO, Fraction.ZERO, Fraction.ZERO);
49
50
51 public static final Unit PERCENT = new Unit("%", 1.0e-2, Fraction.ZERO, Fraction.ZERO, Fraction.ZERO, Fraction.ZERO, Fraction.ZERO);
52
53
54 public static final Unit SECOND = new Unit("s", 1.0, Fraction.ZERO, Fraction.ZERO, Fraction.ONE, Fraction.ZERO, Fraction.ZERO);
55
56
57 public static final Unit MINUTE = SECOND.scale("min", 60.0);
58
59
60 public static final Unit HOUR = MINUTE.scale("h", 60);
61
62
63 public static final Unit DAY = HOUR.scale("d", 24.0);
64
65
66
67
68 public static final Unit YEAR = DAY.scale("a", 365.25);
69
70
71 public static final Unit HERTZ = SECOND.power("Hz", Fraction.MINUS_ONE);
72
73
74 public static final Unit METRE = new Unit("m", 1.0, Fraction.ZERO, Fraction.ONE, Fraction.ZERO, Fraction.ZERO, Fraction.ZERO);
75
76
77 public static final Unit KILOMETRE = METRE.scale("km", 1000.0);
78
79
80 public static final Unit KILOGRAM = new Unit("kg", 1.0, Fraction.ONE, Fraction.ZERO, Fraction.ZERO, Fraction.ZERO, Fraction.ZERO);
81
82
83 public static final Unit GRAM = KILOGRAM.scale("g", 1.0e-3);
84
85
86 public static final Unit AMPERE = new Unit("A", 1.0, Fraction.ZERO, Fraction.ZERO, Fraction.ZERO, Fraction.ONE, Fraction.ZERO);
87
88
89 public static final Unit RADIAN = new Unit("rad", 1.0, Fraction.ZERO, Fraction.ZERO, Fraction.ZERO, Fraction.ZERO, Fraction.ONE);
90
91
92 public static final Unit DEGREE = RADIAN.scale("°", FastMath.toRadians(1.0));
93
94
95 public static final Unit ARC_MINUTE = DEGREE.scale("′", 1.0 / 60.0);
96
97
98 public static final Unit ARC_SECOND = ARC_MINUTE.scale("″", 1.0 / 60.0);
99
100
101 public static final Unit REVOLUTION = RADIAN.scale("rev", 2.0 * FastMath.PI);
102
103
104 public static final Unit NEWTON = KILOGRAM.multiply(null, METRE).divide("N", SECOND.power(null, Fraction.TWO));
105
106
107 public static final Unit PASCAL = NEWTON.divide("Pa", METRE.power(null, Fraction.TWO));
108
109
110 public static final Unit BAR = PASCAL.scale("bar", 100000.0);
111
112
113 public static final Unit JOULE = NEWTON.multiply("J", METRE);
114
115
116 public static final Unit WATT = JOULE.divide("W", SECOND);
117
118
119 public static final Unit COULOMB = SECOND.multiply("C", AMPERE);
120
121
122 public static final Unit VOLT = WATT.divide("V", AMPERE);
123
124
125 public static final Unit OHM = VOLT.divide("Ω", AMPERE);
126
127
128 public static final Unit TESLA = VOLT.multiply(null, SECOND).divide("T", METRE.power(null, Fraction.TWO));
129
130
131 public static final Unit SOLAR_FLUX_UNIT = WATT.divide(null, METRE.power(null, Fraction.TWO).multiply(null, HERTZ)).scale("sfu", 1.0e-22);
132
133
134 public static final Unit TOTAL_ELECTRON_CONTENT_UNIT = METRE.power(null, new Fraction(-2)).scale("TECU", 1.0e+16);
135
136
137 private static final long serialVersionUID = 20210402L;
138
139
140 private final String name;
141
142
143 private final double scale;
144
145
146 private final Fraction mass;
147
148
149 private final Fraction length;
150
151
152 private final Fraction time;
153
154
155 private final Fraction current;
156
157
158 private final Fraction angle;
159
160
161
162
163
164
165
166
167
168
169 public Unit(final String name, final double scale,
170 final Fraction mass, final Fraction length,
171 final Fraction time, final Fraction current,
172 final Fraction angle) {
173 this.name = name;
174 this.scale = scale;
175 this.mass = mass;
176 this.length = length;
177 this.time = time;
178 this.current = current;
179 this.angle = angle;
180 }
181
182
183
184
185 public String getName() {
186 return name;
187 }
188
189
190
191
192 public double getScale() {
193 return scale;
194 }
195
196
197
198
199 public Fraction getMass() {
200 return mass;
201 }
202
203
204
205
206 public Fraction getLength() {
207 return length;
208 }
209
210
211
212
213 public Fraction getTime() {
214 return time;
215 }
216
217
218
219
220 public Fraction getCurrent() {
221 return current;
222 }
223
224
225
226
227 public Fraction getAngle() {
228 return angle;
229 }
230
231
232
233
234
235 public boolean sameDimension(final Unit other) {
236 return time.equals(other.time) && length.equals(other.length) &&
237 mass.equals(other.mass) && current.equals(other.current) &&
238 angle.equals(other.angle);
239 }
240
241
242
243
244 public Unit sameDimensionSI() {
245 final StringBuilder builder = new StringBuilder();
246 append(builder, KILOGRAM.name, mass);
247 append(builder, METRE.name, length);
248 append(builder, SECOND.name, time);
249 append(builder, AMPERE.name, current);
250 append(builder, RADIAN.name, angle);
251 if (builder.length() == 0) {
252 builder.append('1');
253 }
254 return new Unit(builder.toString(), 1.0, mass, length, time, current, angle);
255 }
256
257
258
259
260
261
262 private void append(final StringBuilder builder, final String dim, final Fraction exp) {
263 if (!exp.isZero()) {
264 if (builder.length() > 0) {
265 builder.append('.');
266 }
267 builder.append(dim);
268 if (exp.getDenominator() == 1) {
269 if (exp.getNumerator() != 1) {
270 builder.append(Integer.toString(exp.getNumerator()).
271 replace('-', '⁻').
272 replace('0', '⁰').
273 replace('1', '¹').
274 replace('2', '²').
275 replace('3', '³').
276 replace('4', '⁴').
277 replace('5', '⁵').
278 replace('6', '⁶').
279 replace('7', '⁷').
280 replace('8', '⁸').
281 replace('9', '⁹'));
282 }
283 } else {
284 builder.
285 append("^(").
286 append(exp.getNumerator()).
287 append('/').
288 append(exp.getDenominator()).
289 append(')');
290 }
291 }
292 }
293
294
295
296
297
298 public Unit alias(final String newName) {
299 return new Unit(newName, scale, mass, length, time, current, angle);
300 }
301
302
303
304
305
306
307 public Unit scale(final String newName, final double factor) {
308 return new Unit(newName, factor * scale, mass, length, time, current, angle);
309 }
310
311
312
313
314
315
316 public Unit power(final String newName, final Fraction exponent) {
317
318 final int num = exponent.getNumerator();
319 final int den = exponent.getDenominator();
320 double s = (num == 1) ? scale : FastMath.pow(scale, num);
321 if (den > 1) {
322 if (den == 2) {
323 s = FastMath.sqrt(s);
324 } else if (den == 3) {
325 s = FastMath.cbrt(s);
326 } else {
327 s = FastMath.pow(s, 1.0 / den);
328 }
329 }
330
331 return new Unit(newName, s,
332 mass.multiply(exponent), length.multiply(exponent),
333 time.multiply(exponent), current.multiply(current),
334 angle.multiply(exponent));
335 }
336
337
338
339
340
341 public Unit sqrt(final String newName) {
342 return new Unit(newName, FastMath.sqrt(scale),
343 mass.divide(2), length.divide(2),
344 time.divide(2), current.divide(2),
345 angle.divide(2));
346 }
347
348
349
350
351
352
353 public Unit multiply(final String newName, final Unit other) {
354 return new Unit(newName, scale * other.scale,
355 mass.add(other.mass), length.add(other.length),
356 time.add(other.time), current.add(other.current),
357 angle.add(other.angle));
358 }
359
360
361
362
363
364
365 public Unit divide(final String newName, final Unit other) {
366 return new Unit(newName, scale / other.scale,
367 mass.subtract(other.mass), length.subtract(other.length),
368 time.subtract(other.time), current.subtract(other.current),
369 angle.subtract(other.angle));
370 }
371
372
373
374
375
376 public double toSI(final double value) {
377 return value * scale;
378 }
379
380
381
382
383
384 public double toSI(final Double value) {
385 return value == null ? Double.NaN : value.doubleValue() * scale;
386 }
387
388
389
390
391
392 public double fromSI(final double value) {
393 return value / scale;
394 }
395
396
397
398
399
400 public double fromSI(final Double value) {
401 return value == null ? Double.NaN : value.doubleValue() / scale;
402 }
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477 public static Unit parse(final String unitSpecification) {
478
479
480 final List<PowerTerm> terms = Parser.buildTermsList(unitSpecification);
481
482 if (terms == null) {
483
484 return Unit.NONE;
485 }
486
487
488 Unit unit = Unit.ONE;
489 for (final PowerTerm term : terms) {
490 try {
491 Unit u = PrefixedUnit.valueOf(term.getBase().toString());
492 if (!Fraction.ONE.equals(term.getExponent())) {
493 u = u.power(null, term.getExponent());
494 }
495 u = u.scale(null, term.getScale());
496 unit = unit.multiply(null, u);
497 } catch (IllegalArgumentException iae) {
498 throw new OrekitException(OrekitMessages.UNKNOWN_UNIT, term.getBase());
499 }
500 }
501
502
503 return unit.alias(unitSpecification);
504
505 }
506
507
508
509
510
511
512
513
514 public boolean equals(final Object unit) {
515
516 if (unit == this) {
517
518 return true;
519 }
520
521 if (unit instanceof Unit) {
522 final Unit u = (Unit) unit;
523 return Precision.equals(scale, u.scale, 1) &&
524 mass.equals(u.mass) && length.equals(u.length) && time.equals(u.time) &&
525 current.equals(u.current) && angle.equals(u.angle);
526 }
527
528 return false;
529
530 }
531
532
533
534
535 public int hashCode() {
536 return 0x67e7 ^
537 (Double.hashCode(scale) << 12) ^
538 (mass.hashCode() << 10) ^
539 (length.hashCode() << 8) ^
540 (time.hashCode() << 6) ^
541 (current.hashCode() << 4) ^
542 (angle.hashCode() << 2);
543 }
544
545
546 @Override
547 public String toString() {
548 return getName();
549 }
550
551 }