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