001/* 002 * Units of Measurement Reference Implementation 003 * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. 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-363 nor the names of its 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 tec.units.ri; 031 032import java.util.Map; 033 034import javax.measure.Dimension; 035import javax.measure.Quantity; 036import javax.measure.Unit; 037import javax.measure.IncommensurableException; 038import javax.measure.UnconvertibleException; 039import javax.measure.UnitConverter; 040import javax.measure.quantity.Dimensionless; 041 042import tec.units.ri.format.SimpleUnitFormat; 043import tec.units.ri.function.AddConverter; 044import tec.units.ri.function.MultiplyConverter; 045import tec.units.ri.function.RationalConverter; 046import tec.units.ri.quantity.QuantityDimension; 047import tec.units.ri.spi.DimensionalModel; 048import tec.units.ri.unit.AlternateUnit; 049import tec.units.ri.unit.AnnotatedUnit; 050import tec.units.ri.unit.ProductUnit; 051import tec.units.ri.unit.TransformedUnit; 052import tec.units.ri.unit.Units; 053 054/** 055 * <p> 056 * The class represents units founded on the seven SI base units for seven base quantities assumed to be mutually independent. 057 * </p> 058 * 059 * <p> 060 * For all physics units, units conversions are symmetrical: <code>u1.getConverterTo(u2).equals(u2.getConverterTo(u1).inverse())</code>. Non-physical 061 * units (e.g. currency units) for which conversion is not symmetrical should have their own separate class hierarchy and are considered distinct 062 * (e.g. financial units), although they can always be combined with physics units (e.g. "€/Kg", "$/h"). 063 * </p> 064 * 065 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> 066 * @author <a href="mailto:units@catmedia.us">Werner Keil</a> 067 * @version 1.0.4, June 7, 2017 068 * @since 1.0 069 */ 070public abstract class AbstractUnit<Q extends Quantity<Q>> implements Unit<Q>, Comparable<Unit<Q>> { 071 072 /** 073 * 074 */ 075 // private static final long serialVersionUID = -4344589505537030204L; 076 077 /** 078 * Holds the dimensionless unit <code>ONE</code>. 079 * 080 * @see <a href="https://en.wikipedia.org/wiki/Natural_units#Choosing_constants_to_normalize"> Wikipedia: Natural Units - Choosing constants to 081 * normalize</a> 082 * @see <a href= "http://www.av8n.com/physics/dimensionless-units.htm">Units of Dimension One</a> 083 */ 084 public static final Unit<Dimensionless> ONE = new ProductUnit<Dimensionless>(); 085 086 /** 087 * Holds the name. 088 */ 089 protected String name; 090 091 /** 092 * Holds the symbol. 093 */ 094 private String symbol; 095 096 /** 097 * Default constructor. 098 */ 099 protected AbstractUnit() { 100 } 101 102 /** 103 * Compares this unit to the specified unit. The default implementation compares the name and symbol of both this unit and the specified unit. 104 * 105 * @return a negative integer, zero, or a positive integer as this unit is less than, equal to, or greater than the specified unit. 106 */ 107 public int compareTo(Unit<Q> that) { 108 if (name != null && getSymbol() != null) { 109 return name.compareTo(that.getName()) + getSymbol().compareTo(that.getSymbol()); 110 } else if (name == null) { 111 if (getSymbol() != null && that.getSymbol() != null) { 112 return getSymbol().compareTo(that.getSymbol()); 113 } else { 114 return -1; 115 } 116 } else if (getSymbol() == null) { 117 if (name != null) { 118 return name.compareTo(that.getName()); 119 } else { 120 return -1; 121 } 122 } else { 123 return -1; 124 } 125 } 126 127 /** 128 * Indicates if this unit belongs to the set of coherent SI units (unscaled SI units). 129 * 130 * The base and coherent derived units of the SI form a coherent set, designated the set of coherent SI units. The word coherent is used here in the 131 * following sense: when coherent units are used, equations between the numerical values of quantities take exactly the same form as the equations 132 * between the quantities themselves. Thus if only units from a coherent set are used, conversion factors between units are never required. 133 * 134 * @return <code>equals(toSystemUnit())</code> 135 */ 136 public boolean isSystemUnit() { 137 AbstractUnit<Q> si = this.toSystemUnit(); 138 return (this == si) || this.equals(si); 139 } 140 141 /** 142 * Returns the unscaled standard (SI) unit from which this unit is derived. 143 * 144 * The SI unit can be be used to identify a quantity given the unit. For example: 145 * <code> static boolean isAngularVelocity(AbstractUnit<?> unit) { 146 * return unit.toSystemUnit().equals(RADIAN.divide(SECOND)); } 147 * assert(REVOLUTION.divide(MINUTE).isAngularVelocity()); // Returns true. 148 * </code> 149 * 150 * @return the unscaled metric unit from which this unit is derived. 151 */ 152 protected abstract AbstractUnit<Q> toSystemUnit(); 153 154 /** 155 * Returns the converter from this unit to its unscaled {@link #toSystemUnit standard} unit. 156 * 157 * @return <code>getConverterTo(this.toSystemUnit())</code> 158 * @see #toSystemUnit 159 */ 160 public abstract UnitConverter getSystemConverter(); 161 162 /** 163 * Annotates the specified unit. Annotation does not change the unit semantic. Annotations are often written between curly braces behind units. For 164 * example: <code> Unit<Volume> PERCENT_VOL = 165 * Units.PERCENT.annotate("vol"); // "%{vol}" AbstractUnit<Mass> KG_TOTAL = 166 * Units.KILOGRAM.annotate("total"); // "kg{total}" AbstractUnit<Dimensionless> 167 * RED_BLOOD_CELLS = ONE.annotate("RBC"); // "{RBC}" </code> 168 * 169 * Note: Annotations of system units are not considered themselves as system units. 170 * 171 * @param annotation 172 * the unit annotation. 173 * @return the annotated unit. 174 */ 175 public AnnotatedUnit<Q> annotate(String annotation) { 176 return new AnnotatedUnit<Q>(this, annotation); 177 } 178 179 /** 180 * Returns the physics unit represented by the specified characters. 181 * 182 * Locale-sensitive unit parsing may be handled using the OSGi {@link javax.measure.spi.UnitFormatService} or for non-OSGi applications instances of 183 * {@link SimpleUnitFormat}. 184 * 185 * <p> 186 * Note: The standard format supports dimensionless units.<code> AbstractUnit<Dimensionless> PERCENT = 187 * AbstractUnit.parse("100").inverse().asType(Dimensionless.class); </code> 188 * </p> 189 * 190 * @param charSequence 191 * the character sequence to parse. 192 * @return <code>SimpleUnitFormat.getInstance().parse(csq)</code> 193 * @throws ParserException 194 * if the specified character sequence cannot be parsed correctly. 195 */ 196 public static Unit<?> parse(CharSequence charSequence) { 197 return SimpleUnitFormat.getInstance().parse(charSequence); 198 } 199 200 /** 201 * Returns the standard {@link String} representation of this unit. The string produced for a given unit is always the same; it is not affected by 202 * the locale. It can be used as a canonical string representation for exchanging units, or as a key for a Map, Hashtable, etc. 203 * 204 * Locale-sensitive unit parsing should be handled using the OSGi {@link tec.units.ri.SimpleUnitFormat.service.UnitFormat} service (or 205 * {@link SimpleUnitFormat} for non-OSGi applications). 206 * 207 * @return <code>SimpleUnitFormat.getInstance().format(this)</code> 208 */ 209 @Override 210 public String toString() { 211 return SimpleUnitFormat.getInstance().format(this); 212 /* 213 * final Appendable tmp = new StringBuilder(); try { return 214 * SimpleUnitFormat.getInstance().format(this, tmp).toString(); } catch 215 * (IOException ioException) { throw new Error(ioException); // Should 216 * never happen. } finally { // if (tmp!=null) tmp.clear(); } 217 */ 218 } 219 220 // /////////////////////////////////////////////////////// 221 // Implements org.unitsofmeasurement.Unit<Q> interface // 222 // /////////////////////////////////////////////////////// 223 224 /** 225 * Returns the system unit (unscaled SI unit) from which this unit is derived. They can be be used to identify a quantity given the unit. For 226 * example:[code] static boolean isAngularVelocity(AbstractUnit<?> unit) { return unit.getSystemUnit().equals(RADIAN.divide(SECOND)); } 227 * assert(REVOLUTION.divide(MINUTE).isAngularVelocity()); // Returns true. [/code] 228 * 229 * @return the unscaled metric unit from which this unit is derived. 230 */ 231 public final AbstractUnit<Q> getSystemUnit() { 232 return toSystemUnit(); 233 } 234 235 /** 236 * Indicates if this unit is compatible with the unit specified. To be compatible both units must be physics units having the same fundamental 237 * dimension. 238 * 239 * @param that 240 * the other unit. 241 * @return <code>true</code> if this unit and that unit have equals fundamental dimension according to the current physics model; <code>false</code> 242 * otherwise. 243 */ 244 public final boolean isCompatible(Unit<?> that) { 245 if ((this == that) || this.equals(that)) 246 return true; 247 if (!(that instanceof AbstractUnit)) 248 return false; 249 Dimension thisDimension = this.getDimension(); 250 Dimension thatDimension = that.getDimension(); 251 if (thisDimension.equals(thatDimension)) 252 return true; 253 DimensionalModel model = DimensionalModel.current(); // Use 254 // dimensional 255 // analysis 256 // model. 257 return model.getFundamentalDimension(thisDimension).equals(model.getFundamentalDimension(thatDimension)); 258 } 259 260 /** 261 * Casts this unit to a parameterized unit of specified nature or throw a ClassCastException if the dimension of the specified quantity and this 262 * unit's dimension do not match (regardless whether or not the dimensions are independent or not). 263 * 264 * @param type 265 * the quantity class identifying the nature of the unit. 266 * @throws ClassCastException 267 * if the dimension of this unit is different from the SI dimension of the specified type. 268 * @see Units#getUnit(Class) 269 */ 270 @SuppressWarnings("unchecked") 271 public final <T extends Quantity<T>> Unit<T> asType(Class<T> type) { 272 Dimension typeDimension = QuantityDimension.of(type); 273 if ((typeDimension != null) && (!typeDimension.equals(this.getDimension()))) 274 throw new ClassCastException("The unit: " + this + " is not compatible with quantities of type " + type); 275 return (Unit<T>) this; 276 } 277 278 public abstract Map<? extends Unit<?>, Integer> getBaseUnits(); 279 280 public abstract Dimension getDimension(); 281 282 protected void setName(String name) { 283 this.name = name; 284 } 285 286 public String getName() { 287 return name; 288 } 289 290 public String getSymbol() { 291 return symbol; 292 } 293 294 protected void setSymbol(String s) { 295 this.symbol = s; 296 } 297 298 public final UnitConverter getConverterTo(Unit<Q> that) throws UnconvertibleException { 299 if ((this == that) || this.equals(that)) 300 return AbstractConverter.IDENTITY; // Shortcut. 301 Unit<Q> thisSystemUnit = this.getSystemUnit(); 302 Unit<Q> thatSystemUnit = that.getSystemUnit(); 303 if (!thisSystemUnit.equals(thatSystemUnit)) 304 try { 305 return getConverterToAny(that); 306 } catch (IncommensurableException e) { 307 throw new UnconvertibleException(e); 308 } 309 UnitConverter thisToSI = this.getSystemConverter(); 310 UnitConverter thatToSI = that.getConverterTo(thatSystemUnit); 311 return thatToSI.inverse().concatenate(thisToSI); 312 } 313 314 @SuppressWarnings("rawtypes") 315 public final UnitConverter getConverterToAny(Unit<?> that) throws IncommensurableException, UnconvertibleException { 316 if (!isCompatible(that)) 317 throw new IncommensurableException(this + " is not compatible with " + that); 318 AbstractUnit thatAbstr = (AbstractUnit) that; // Since both units are 319 // compatible they must 320 // be both abstract 321 // units. 322 DimensionalModel model = DimensionalModel.current(); 323 AbstractUnit thisSystemUnit = this.getSystemUnit(); 324 UnitConverter thisToDimension = model.getDimensionalTransform(thisSystemUnit.getDimension()).concatenate(this.getSystemConverter()); 325 AbstractUnit thatSystemUnit = thatAbstr.getSystemUnit(); 326 UnitConverter thatToDimension = model.getDimensionalTransform(thatSystemUnit.getDimension()).concatenate(thatAbstr.getSystemConverter()); 327 return thatToDimension.inverse().concatenate(thisToDimension); 328 } 329 330 @Override 331 public final Unit<Q> alternate(String symbol) { 332 return new AlternateUnit<Q>(this, symbol); 333 } 334 335 @Override 336 public final Unit<Q> transform(UnitConverter operation) { 337 Unit<Q> systemUnit = this.getSystemUnit(); 338 UnitConverter cvtr; 339 if (this.isSystemUnit()) { 340 cvtr = this.getSystemConverter().concatenate(operation); 341 } else { 342 cvtr = operation; 343 } 344 if (cvtr.equals(AbstractConverter.IDENTITY)) { 345 return systemUnit; 346 } else { 347 return new TransformedUnit<>(null, this, systemUnit, cvtr); 348 } 349 } 350 351 @Override 352 public final Unit<Q> shift(double offset) { 353 if (offset == 0) 354 return this; 355 return transform(new AddConverter(offset)); 356 } 357 358 @Override 359 public final Unit<Q> multiply(double factor) { 360 if (factor == 1) 361 return this; 362 if (isLongValue(factor)) 363 return transform(new RationalConverter((long) factor, 1)); 364 return transform(new MultiplyConverter(factor)); 365 } 366 367 private static boolean isLongValue(double value) { 368 return !((value < Long.MIN_VALUE) || (value > Long.MAX_VALUE)) && Math.floor(value) == value; 369 } 370 371 /** 372 * Returns the product of this unit with the one specified. 373 * 374 * <p> 375 * Note: If the specified unit (that) is not a physical unit, then <code>that.multiply(this)</code> is returned. 376 * </p> 377 * 378 * @param that 379 * the unit multiplicand. 380 * @return <code>this * that</code> 381 */ 382 public final Unit<?> multiply(Unit<?> that) { 383 if (that instanceof AbstractUnit) 384 return multiply((AbstractUnit<?>) that); 385 return that.multiply(this); // Commutatif. 386 } 387 388 /** 389 * Returns the product of this physical unit with the one specified. 390 * 391 * @param that 392 * the physical unit multiplicand. 393 * @return <code>this * that</code> 394 */ 395 public final Unit<?> multiply(AbstractUnit<?> that) { 396 if (this.equals(ONE)) 397 return that; 398 if (that.equals(ONE)) 399 return this; 400 return ProductUnit.getProductInstance(this, that); 401 } 402 403 /** 404 * Returns the inverse of this physical unit. 405 * 406 * @return <code>1 / this</code> 407 */ 408 public final Unit<?> inverse() { 409 if (this.equals(ONE)) 410 return this; 411 return ProductUnit.getQuotientInstance(ONE, this); 412 } 413 414 /** 415 * Returns the result of dividing this unit by the specifified divisor. If the factor is an integer value, the division is exact. For example: 416 * 417 * <pre> 418 * <code> 419 * QUART = GALLON_LIQUID_US.divide(4); // Exact definition. 420 * </code> 421 * </pre> 422 * 423 * @param divisor 424 * the divisor value. 425 * @return this unit divided by the specified divisor. 426 */ 427 public final Unit<Q> divide(double divisor) { 428 if (divisor == 1) 429 return this; 430 if (isLongValue(divisor)) 431 return transform(new RationalConverter(1, (long) divisor)); 432 return transform(new MultiplyConverter(1.0 / divisor)); 433 } 434 435 /** 436 * Returns the quotient of this unit with the one specified. 437 * 438 * @param that 439 * the unit divisor. 440 * @return <code>this.multiply(that.inverse())</code> 441 */ 442 public final Unit<?> divide(Unit<?> that) { 443 return this.multiply(that.inverse()); 444 } 445 446 /** 447 * Returns a unit equals to the given root of this unit. 448 * 449 * @param n 450 * the root's order. 451 * @return the result of taking the given root of this unit. 452 * @throws ArithmeticException 453 * if <code>n == 0</code> or if this operation would result in an unit with a fractional exponent. 454 */ 455 public final Unit<?> root(int n) { 456 if (n > 0) 457 return ProductUnit.getRootInstance(this, n); 458 else if (n == 0) 459 throw new ArithmeticException("Root's order of zero"); 460 else 461 // n < 0 462 return ONE.divide(this.root(-n)); 463 } 464 465 /** 466 * Returns a unit equals to this unit raised to an exponent. 467 * 468 * @param n 469 * the exponent. 470 * @return the result of raising this unit to the exponent. 471 */ 472 public final Unit<?> pow(int n) { 473 if (n > 0) 474 return this.multiply(this.pow(n - 1)); 475 else if (n == 0) 476 return ONE; 477 else 478 // n < 0 479 return ONE.divide(this.pow(-n)); 480 } 481 482 // ////////////////////////////////////////////////////////////// 483 // Ensures that sub-classes implements hashCode/equals method. 484 // ////////////////////////////////////////////////////////////// 485 486 @Override 487 public abstract int hashCode(); 488 489 @Override 490 public abstract boolean equals(Object that); 491}