001/* 002 * Units of Measurement Reference Implementation 003 * Copyright (c) 2005-2018, Jean-Marie Dautelle, Werner Keil, Otavio Santana. 004 * 005 * All rights reserved. 006 * 007 * Redistribution and use in source and binary forms, with or without modification, 008 * are permitted provided that the following conditions are met: 009 * 010 * 1. Redistributions of source code must retain the above copyright notice, 011 * this list of conditions and the following disclaimer. 012 * 013 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions 014 * and the following disclaimer in the documentation and/or other materials provided with the distribution. 015 * 016 * 3. Neither the name of JSR-385, Indriya nor the names of their contributors may be used to endorse or promote products 017 * derived from this software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 021 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 023 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 026 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package tech.units.indriya; 031 032import java.lang.reflect.ParameterizedType; 033import java.lang.reflect.Type; 034import java.math.BigInteger; 035import java.util.HashMap; 036import java.util.Map; 037 038import javax.measure.Dimension; 039import javax.measure.IncommensurableException; 040import javax.measure.Prefix; 041import javax.measure.Quantity; 042import javax.measure.UnconvertibleException; 043import javax.measure.Unit; 044import javax.measure.UnitConverter; 045import javax.measure.quantity.Dimensionless; 046 047import tech.units.indriya.format.LocalUnitFormat; 048import tech.units.indriya.format.SimpleUnitFormat; 049import tech.units.indriya.function.AddConverter; 050import tech.units.indriya.function.MultiplyConverter; 051import tech.units.indriya.function.PowerOfIntConverter; 052import tech.units.indriya.function.RationalConverter; 053import tech.units.indriya.quantity.QuantityDimension; 054import tech.units.indriya.spi.DimensionalModel; 055import tech.units.indriya.unit.AlternateUnit; 056import tech.units.indriya.unit.AnnotatedUnit; 057import tech.units.indriya.unit.ProductUnit; 058import tech.units.indriya.unit.TransformedUnit; 059import tech.units.indriya.unit.Units; 060import tech.uom.lib.common.function.Nameable; 061import tech.uom.lib.common.function.SymbolSupplier; 062 063/** 064 * <p> 065 * The class represents units founded on the seven <b>SI</b> base units for 066 * seven base quantities assumed to be mutually independent. 067 * </p> 068 * 069 * <p> 070 * For all physics units, unit conversions are symmetrical: 071 * <code>u1.getConverterTo(u2).equals(u2.getConverterTo(u1).inverse())</code>. 072 * Non-physical units (e.g. currency units) for which conversion is not 073 * symmetrical should have their own separate class hierarchy and are considered 074 * distinct (e.g. financial units), although they can always be combined with 075 * physics units (e.g. "€/Kg", "$/h"). 076 * </p> 077 * 078 * @see <a href= 079 * "http://en.wikipedia.org/wiki/International_System_of_Units">Wikipedia: 080 * International System of Units</a> 081 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> 082 * @author <a href="mailto:units@catmedia.us">Werner Keil</a> 083 * @version 1.3, June 29, 2018 084 * @since 1.0 085 */ 086public abstract class AbstractUnit<Q extends Quantity<Q>> implements ComparableUnit<Q>, Nameable, SymbolSupplier { 087 088 /** 089 * 090 */ 091 private static final long serialVersionUID = -4344589505537030204L; 092 093 /** 094 * Holds the dimensionless unit <code>ONE</code>. 095 * 096 * @see <a href= 097 * "https://en.wikipedia.org/wiki/Natural_units#Choosing_constants_to_normalize"> 098 * Wikipedia: Natural Units - Choosing constants to normalize</a> 099 * @see <a href= "http://www.av8n.com/physics/dimensionless-units.htm">Units of 100 * Dimension One</a> 101 */ 102 public static final Unit<Dimensionless> ONE = new ProductUnit<>(); 103 104 /** 105 * Holds the name. 106 */ 107 protected String name; 108 109 /** 110 * Holds the symbol. 111 */ 112 private String symbol; 113 114 /** 115 * Holds the unique symbols collection (base units or alternate units). 116 */ 117 protected static final Map<String, Unit<?>> SYMBOL_TO_UNIT = new HashMap<>(); 118 119 /** 120 * Default constructor. 121 */ 122 protected AbstractUnit() { 123 } 124 125 protected Type getActualType() { 126 ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass(); 127 return parameterizedType.getActualTypeArguments()[0].getClass().getGenericInterfaces()[0]; 128 } 129 130 /** 131 * Indicates if this unit belongs to the set of coherent SI units (unscaled SI 132 * units). 133 * 134 * The base and coherent derived units of the SI form a coherent set, designated 135 * the set of coherent SI units. The word coherent is used here in the following 136 * sense: when coherent units are used, equations between the numerical values 137 * of quantities take exactly the same form as the equations between the 138 * quantities themselves. Thus if only units from a coherent set are used, 139 * conversion factors between units are never required. 140 * 141 * @return <code>equals(toSystemUnit())</code> 142 */ 143 @Override 144 public boolean isSystemUnit() { 145 Unit<Q> sys = this.toSystemUnit(); 146 return (this == sys) || this.equals(sys); 147 } 148 149 /** 150 * Returns the unscaled {@link SI} unit from which this unit is derived. 151 * 152 * The SI unit can be be used to identify a quantity given the unit. For 153 * example:<code> static boolean isAngularVelocity(AbstractUnit<?> unit) { 154 * return unit.toSystemUnit().equals(RADIAN.divide(SECOND)); } assert(REVOLUTION.divide(MINUTE).isAngularVelocity()); // Returns true. </code> 155 * 156 * @return the unscaled metric unit from which this unit is derived. 157 */ 158 protected abstract Unit<Q> toSystemUnit(); 159 160 /** 161 * Returns the converter from this unit to its unscaled {@link #toSysemUnit 162 * System Unit} unit. 163 * 164 * @return <code>getConverterTo(this.toSystemUnit())</code> 165 * @see #toSystemUnit 166 */ 167 public abstract UnitConverter getSystemConverter(); 168 169 /** 170 * Annotates the specified unit. Annotation does not change the unit semantic. 171 * Annotations are often written between curly braces behind units. For 172 * example:<br> 173 * <code> Unit<Volume> PERCENT_VOL = ((AbstractUnit)Units.PERCENT).annotate("vol"); // "%{vol}" Unit<Mass> KG_TOTAL = 174 * ((AbstractUnit)Units.KILOGRAM).annotate("total"); // "kg{total}" Unit<Dimensionless> RED_BLOOD_CELLS = ((AbstractUnit)Units.ONE).annotate("RBC"); // "{RBC}" </code> 175 * 176 * Note: Annotation of system units are not considered themselves as system 177 * units. 178 * 179 * @param annotation 180 * the unit annotation. 181 * @return the annotated unit. 182 */ 183 public Unit<Q> annotate(String annotation) { 184 return new AnnotatedUnit<>(this, annotation); 185 } 186 187 /* 188 * Returns the combination of this unit with the specified sub-unit. Compound 189 * units are typically used for formatting purpose. Examples of compound 190 * units:<code> Unit<Length> FOOT_INCH = FOOT.compound(INCH); Unit<Time> 191 * HOUR_MINUTE_SECOND = HOUR.compound(MINUTE).compound(SECOND); </code> 192 * 193 * @param that the least significant unit to combine with this unit. 194 * 195 * @return the corresponding compound unit. 196 * 197 * public final Unit<Q> compound(Unit<Q> that) { return new 198 * CompoundUnit<Q>(this, that); } 199 */ 200 201 /** 202 * Returns the abstract unit represented by the specified characters as per 203 * default format. 204 * 205 * Locale-sensitive unit parsing could be handled using {@link LocalUnitFormat} 206 * in subclasses of AbstractUnit. 207 * 208 * <p> 209 * Note: The standard format supports dimensionless 210 * units.<code> AbstractUnit<Dimensionless> PERCENT = 211 * AbstractUnit.parse("100").inverse().asType(Dimensionless.class); </code> 212 * </p> 213 * 214 * @param charSequence 215 * the character sequence to parse. 216 * @return <code>SimpleUnitFormat.getInstance().parse(csq, new ParsePosition(0))</code> 217 * @throws MeasurementParseException 218 * if the specified character sequence cannot be correctly parsed 219 * (e.g. not UCUM compliant). 220 */ 221 public static Unit<?> parse(CharSequence charSequence) { 222 return SimpleUnitFormat.getInstance().parse(charSequence); 223 } 224 225 /** 226 * Returns the standard representation of this physics unit. The string produced 227 * for a given unit is always the same; it is not affected by the locale. It can 228 * be used as a canonical string representation for exchanging units, or as a 229 * key for a Hashtable, etc. 230 * 231 * Locale-sensitive unit parsing could be handled using {@link LocalUnitFormat} 232 * in subclasses of AbstractUnit. 233 * 234 * @return <code>SimpleUnitFormat.getInstance().format(this)</code> 235 */ 236 @Override 237 public String toString() { 238 return SimpleUnitFormat.getInstance().format(this); 239 } 240 241 // /////////////////////////////////////////////////////// 242 // Implements javax.measure.Unit<Q> interface // 243 // /////////////////////////////////////////////////////// 244 245 /** 246 * Returns the system unit (unscaled SI unit) from which this unit is derived. 247 * They can be be used to identify a quantity given the unit. For example:<br> 248 * <code> static boolean isAngularVelocity(AbstractUnit<?> unit) {<br> return unit.getSystemUnit().equals(RADIAN.divide(SECOND));<br>} 249 * <br>assert(REVOLUTION.divide(MINUTE).isAngularVelocity()); // Returns true. </code> 250 * 251 * @return the unscaled metric unit from which this unit is derived. 252 */ 253 @Override 254 public final Unit<Q> getSystemUnit() { 255 return toSystemUnit(); 256 } 257 258 /** 259 * Indicates if this unit is compatible with the unit specified. To be 260 * compatible both units must be physics units having the same fundamental 261 * dimension. 262 * 263 * @param that 264 * the other unit. 265 * @return <code>true</code> if this unit and that unit have equals fundamental 266 * dimension according to the current physics model; <code>false</code> 267 * otherwise. 268 */ 269 @Override 270 public final boolean isCompatible(Unit<?> that) { 271 return internalIsCompatible(that, true); 272 } 273 274 /** 275 * Casts this unit to a parameterized unit of specified nature or throw a 276 * ClassCastException if the dimension of the specified quantity and this unit's 277 * dimension do not match (regardless whether or not the dimensions are 278 * independent or not). 279 * 280 * @param type 281 * the quantity class identifying the nature of the unit. 282 * @throws ClassCastException 283 * if the dimension of this unit is different from the SI dimension 284 * of the specified type. 285 * @see Units#getUnit(Class) 286 */ 287 @SuppressWarnings("unchecked") 288 @Override 289 public final <T extends Quantity<T>> AbstractUnit<T> asType(Class<T> type) { 290 Dimension typeDimension = QuantityDimension.of(type); 291 if ((typeDimension != null) && (!typeDimension.equals(this.getDimension()))) 292 throw new ClassCastException("The unit: " + this + " is not compatible with quantities of type " + type); 293 return (AbstractUnit<T>) this; 294 } 295 296 @Override 297 public abstract Map<? extends Unit<?>, Integer> getBaseUnits(); 298 299 @Override 300 public abstract Dimension getDimension(); 301 302 protected void setName(String name) { 303 this.name = name; 304 } 305 306 public String getName() { 307 return name; 308 } 309 310 public String getSymbol() { 311 return symbol; 312 } 313 314 protected void setSymbol(String s) { 315 this.symbol = s; 316 } 317 318 @Override 319 public final UnitConverter getConverterTo(Unit<Q> that) throws UnconvertibleException { 320 return internalGetConverterTo(that, true); 321 } 322 323 @SuppressWarnings("rawtypes") 324 @Override 325 public final UnitConverter getConverterToAny(Unit<?> that) throws IncommensurableException, UnconvertibleException { 326 if (!isCompatible(that)) 327 throw new IncommensurableException(this + " is not compatible with " + that); 328 AbstractUnit thatAbstr = (AbstractUnit) that; // Since both units are 329 // compatible they must 330 // be both physics 331 // units. 332 DimensionalModel model = DimensionalModel.current(); 333 Unit thisSystemUnit = this.getSystemUnit(); 334 UnitConverter thisToDimension = model.getDimensionalTransform(thisSystemUnit.getDimension()) 335 .concatenate(this.getSystemConverter()); 336 Unit thatSystemUnit = thatAbstr.getSystemUnit(); 337 UnitConverter thatToDimension = model.getDimensionalTransform(thatSystemUnit.getDimension()) 338 .concatenate(thatAbstr.getSystemConverter()); 339 return thatToDimension.inverse().concatenate(thisToDimension); 340 } 341 342 @SuppressWarnings({ "rawtypes", "unchecked" }) 343 @Override 344 public final Unit<Q> alternate(String symbol) { 345 return new AlternateUnit(this, symbol); 346 } 347 348 @Override 349 public final Unit<Q> transform(UnitConverter operation) { 350 Unit<Q> systemUnit = this.getSystemUnit(); 351 UnitConverter cvtr; 352 if (this.isSystemUnit()) { 353 cvtr = this.getSystemConverter().concatenate(operation); 354 } else { 355 cvtr = operation; 356 } 357 if (cvtr.isIdentity()) { 358 return systemUnit; 359 } else { 360 return new TransformedUnit<>(null, this, systemUnit, cvtr); 361 } 362 } 363 364 @Override 365 public final Unit<Q> shift(double offset) { 366 if (offset == 0) 367 return this; 368 return transform(new AddConverter(offset)); 369 } 370 371 @Override 372 public final Unit<Q> multiply(double factor) { 373 if (factor == 1) 374 return this; 375 return transform(converterOf(factor)); 376 } 377 378 /** 379 * Internal helper for isCompatible 380 */ 381 private final boolean internalIsCompatible(Unit<?> that, boolean checkEquals) { 382 if (checkEquals) { 383 if ((this == that) || this.equals(that)) 384 return true; 385 } else { 386 if (this == that) 387 return true; 388 } 389 if (!(that instanceof AbstractUnit)) 390 return false; 391 Dimension thisDimension = this.getDimension(); 392 Dimension thatDimension = that.getDimension(); 393 if (thisDimension.equals(thatDimension)) 394 return true; 395 DimensionalModel model = DimensionalModel.current(); // Use 396 // dimensional 397 // analysis 398 // model. 399 return model.getFundamentalDimension(thisDimension).equals(model.getFundamentalDimension(thatDimension)); 400 } 401 402 private final UnitConverter internalGetConverterTo(Unit<Q> that, boolean useEquals) throws UnconvertibleException { 403 if (useEquals) { 404 if ((this == that) || this.equals(that)) 405 return AbstractConverter.IDENTITY; 406 } else { 407 if (this == that) 408 return AbstractConverter.IDENTITY; 409 } 410 Unit<Q> thisSystemUnit = this.getSystemUnit(); 411 Unit<Q> thatSystemUnit = that.getSystemUnit(); 412 if (!thisSystemUnit.equals(thatSystemUnit)) 413 try { 414 return getConverterToAny(that); 415 } catch (IncommensurableException e) { 416 throw new UnconvertibleException(e); 417 } 418 UnitConverter thisToSI = this.getSystemConverter(); 419 UnitConverter thatToSI = that.getConverterTo(thatSystemUnit); 420 return thatToSI.inverse().concatenate(thisToSI); 421 } 422 423 private static boolean isLongValue(double value) { 424 return !((value < Long.MIN_VALUE) || (value > Long.MAX_VALUE)) && Math.floor(value) == value; 425 } 426 427 private static UnitConverter converterOf(double factor) { 428 if (isLongValue(factor)) { 429 return new RationalConverter(BigInteger.valueOf((long) factor), BigInteger.ONE); 430 } 431 return new MultiplyConverter(factor); 432 } 433 434 /** 435 * Returns the product of this unit with the one specified. 436 * 437 * <p> 438 * Note: If the specified unit (that) is not a physical unit, then 439 * <code>that.multiply(this)</code> is returned. 440 * </p> 441 * 442 * @param that 443 * the unit multiplicand. 444 * @return <code>this * that</code> 445 */ 446 @Override 447 public final Unit<?> multiply(Unit<?> that) { 448 if (that instanceof AbstractUnit) 449 return multiply((AbstractUnit<?>) that); 450 // return that.multiply(this); // Commutatif. 451 return ProductUnit.ofProduct(this, that); 452 } 453 454 /** 455 * Returns the product of this physical unit with the one specified. 456 * 457 * @param that 458 * the physical unit multiplicand. 459 * @return <code>this * that</code> 460 */ 461 protected final Unit<?> multiply(AbstractUnit<?> that) { 462 if (this.equals(ONE)) 463 return that; 464 if (that.equals(ONE)) 465 return this; 466 return ProductUnit.ofProduct(this, that); 467 } 468 469 /** 470 * Returns the inverse of this physical unit. 471 * 472 * @return <code>1 / this</code> 473 */ 474 @Override 475 public final Unit<?> inverse() { 476 if (this.equals(ONE)) 477 return this; 478 return ProductUnit.ofQuotient(ONE, this); 479 } 480 481 /** 482 * Returns the result of dividing this unit by the specified divisor. If the 483 * factor is an integer value, the division is exact. For example: 484 * 485 * <pre> 486 * <code> 487 * QUART = GALLON_LIQUID_US.divide(4); // Exact definition. 488 * </code> 489 * </pre> 490 * 491 * @param divisor 492 * the divisor value. 493 * @return this unit divided by the specified divisor. 494 */ 495 @Override 496 public final Unit<Q> divide(double divisor) { 497 if (divisor == 1) 498 return this; 499 if (isLongValue(divisor)) //TODO [ahuber] you can not reach every long with a double! 500 return transform(new RationalConverter(BigInteger.ONE, BigInteger.valueOf((long) divisor))); 501 return transform(new MultiplyConverter(1.0 / divisor)); 502 } 503 504 /** 505 * Returns the quotient of this unit with the one specified. 506 * 507 * @param that 508 * the unit divisor. 509 * @return <code>this.multiply(that.inverse())</code> 510 */ 511 @Override 512 public final Unit<?> divide(Unit<?> that) { 513 return this.multiply(that.inverse()); 514 } 515 516 /** 517 * Returns the quotient of this physical unit with the one specified. 518 * 519 * @param that 520 * the physical unit divisor. 521 * @return <code>this.multiply(that.inverse())</code> 522 */ 523 protected final Unit<?> divide(AbstractUnit<?> that) { 524 return this.multiply(that.inverse()); 525 } 526 527 /** 528 * Returns a unit equals to the given root of this unit. 529 * 530 * @param n 531 * the root's order. 532 * @return the result of taking the given root of this unit. 533 * @throws ArithmeticException 534 * if <code>n == 0</code> or if this operation would result in an 535 * unit with a fractional exponent. 536 */ 537 @Override 538 public final Unit<?> root(int n) { 539 if (n > 0) 540 return ProductUnit.ofRoot(this, n); 541 else if (n == 0) 542 throw new ArithmeticException("Root's order of zero"); 543 else 544 // n < 0 545 return ONE.divide(this.root(-n)); 546 } 547 548 /** 549 * Returns a unit equals to this unit raised to an exponent. 550 * 551 * @param n 552 * the exponent. 553 * @return the result of raising this unit to the exponent. 554 */ 555 @Override 556 public Unit<?> pow(int n) { 557 if (n > 0) 558 return this.multiply(this.pow(n - 1)); 559 else if (n == 0) 560 return ONE; 561 else 562 // n < 0 563 return ONE.divide(this.pow(-n)); 564 } 565 566 @Override 567 public Unit<Q> prefix(Prefix prefix) { 568 return this.transform(PowerOfIntConverter.of(prefix)); 569 } 570 571 /** 572 * Compares this unit to the specified unit. The default implementation compares 573 * the name and symbol of both this unit and the specified unit. 574 * 575 * @return a negative integer, zero, or a positive integer as this unit is less 576 * than, equal to, or greater than the specified unit. 577 */ 578 public int compareTo(Unit<Q> that) { 579 if (name != null && getSymbol() != null) { 580 return name.compareTo(that.getName()) + getSymbol().compareTo(that.getSymbol()); 581 } else if (name == null) { 582 if (getSymbol() != null && that.getSymbol() != null) { 583 return getSymbol().compareTo(that.getSymbol()); 584 } else { 585 return -1; 586 } 587 } else if (getSymbol() == null) { 588 if (name != null) { 589 return name.compareTo(that.getName()); 590 } else { 591 return -1; 592 } 593 } else { 594 UnitConverter conv = getConverterTo(that); 595 if (conv instanceof AbstractConverter) { 596 return ((AbstractConverter) conv).compareTo(that.getConverterTo(this)); 597 } 598 return -1; 599 } 600 } 601 602 @Override 603 public boolean isEquivalentOf(Unit<Q> that) { 604 if (this.compareTo(that) == 0) 605 return true; 606 return this.getConverterTo(that).isIdentity(); 607 //[ahuber] was ... return this.getConverterTo(that).equals(that.getConverterTo(this)); 608 } 609 610 // ////////////////////////////////////////////////////////////// 611 // Ensures that sub-classes implement the hashCode method. 612 // ////////////////////////////////////////////////////////////// 613 614 @Override 615 public abstract boolean equals(Object obj); 616 617 @Override 618 public abstract int hashCode(); 619 620 /** 621 * Utility class for number comparison and equality 622 */ 623 protected static final class Equalizer { 624 /** 625 * Indicates if this unit is considered equals to the specified object. order). 626 * 627 * @param obj 628 * the object to compare for equality. 629 * @return <code>true</code> if <code>this</code> and <code>obj</code> are 630 * considered equal; <code>false</code>otherwise. 631 */ 632 public static boolean areEqual(@SuppressWarnings("rawtypes") AbstractUnit u1, @SuppressWarnings("rawtypes") AbstractUnit u2) { 633 /* 634 * if (u1 != null && u2 != null) { if (u1.getName() != null && u1.getSymbol() != 635 * null) { return u1.getName().equals(u2.getName()) && 636 * u1.getSymbol().equals(u2.getSymbol()) && u1.internalIsCompatible(u2, false); 637 * } else if (u1.getSymbol() != null) { return 638 * u1.getSymbol().equals(u2.getSymbol()) && u1.internalIsCompatible(u2, false); 639 * } else { return u1.toString().equals(u2.toString()) && 640 * u1.internalIsCompatible(u2, false); } } else { 641 */ 642 if (u1 == u2) 643 return true; 644 return false; 645 } 646 } 647 648 649 650}