1 9 package org.jscience.physics.units; 10 11 import java.io.Serializable ; 12 import java.util.Set ; 13 14 import org.jscience.physics.quantities.Angle; 15 import org.jscience.physics.quantities.Quantity; 16 import org.jscience.physics.quantities.Dimensionless; 17 18 import javolution.util.FastComparator; 19 import javolution.util.FastMap; 20 import javolution.xml.XmlElement; 21 import javolution.xml.XmlFormat; 22 import javolution.lang.MathLib; 23 import javolution.lang.PersistentReference; 24 import javolution.lang.Text; 25 26 51 public abstract class Unit<Q extends Quantity> implements Serializable { 52 53 56 private static final FastMap<Unit, Unit> COLLECTION = new FastMap<Unit, Unit>( 57 1024).setKeyComparator(new Unit.Comparator()); 58 59 62 static final FastMap<String , Unit> SYMBOLS = new FastMap<String , Unit>(256) 63 .setKeyComparator(FastComparator.LEXICAL); 64 65 70 private static final XmlFormat<Unit> UNIT_XML = new XmlFormat<Unit>( 71 Unit.class) { 72 public void format(Unit unit, XmlElement xml) { 73 xml.setAttribute("name", unit.toText()); 74 } 75 76 public Unit parse(XmlElement xml) { 77 return Unit.valueOf(xml.getAttribute("name", Text.EMPTY)); 78 } 79 }; 80 81 84 private static final PersistentReference<FastMap<Unit, FastMap<Unit, Unit>>> MULT_TABLE = new PersistentReference<FastMap<Unit, FastMap<Unit, Unit>>>( 85 "org.jscience.physics.units.Unit#MULT_TABLE", 86 new FastMap<Unit, FastMap<Unit, Unit>>().setKeyComparator(FastComparator.DIRECT)); 87 88 91 public static final Unit<Dimensionless> ONE = new ProductUnit<Dimensionless>(); 92 static { 93 COLLECTION.put(ONE, ONE); 94 ONE._hashCode = ONE.hashCodeImpl(); 95 ONE._parentUnit = ONE; 96 ONE._toParentUnit = Converter.IDENTITY; 97 } 98 99 102 private transient Unit _inverse; 103 104 108 private transient int _hashCode; 109 110 113 String _symbol; 114 115 118 Unit<? super Q> _parentUnit; 119 120 123 Converter _toParentUnit; 124 125 128 Unit() { 129 } 130 131 135 141 protected abstract int hashCodeImpl(); 142 143 150 protected abstract boolean equalsImpl(Object that); 151 152 158 protected abstract Unit< ? super Q> getParentUnitImpl(); 159 160 165 protected abstract Converter toParentUnitImpl(); 166 167 171 180 public final Unit<? super Q> getParentUnit() { 181 return _parentUnit; 182 } 183 184 189 public final Converter toParentUnit() { 190 return _toParentUnit; 191 } 192 193 202 public final Unit<? super Q> getBaseUnits() { 203 if (_parentUnit == this) return this; 204 return _parentUnit.getBaseUnits(); 205 } 206 207 212 public final Converter toBaseUnits() { 213 if (_parentUnit == this) return Converter.IDENTITY; 214 return _parentUnit.toBaseUnits().concatenate(this._toParentUnit); 215 } 216 217 227 public final boolean isCompatible(Unit that) { 228 return (this._parentUnit == that._parentUnit) 229 || (this.getDimension() == that.getDimension()); 230 } 231 232 239 public final Dimension getDimension() { 240 if (_parentUnit != this) 241 return _parentUnit.getDimension(); 242 if (_parentUnit instanceof BaseUnit) 243 return ((BaseUnit< ? super Q>) _parentUnit)._dimension.get(); 244 ProductUnit< ? super Q> productUnit = (ProductUnit< ? super Q>) _parentUnit; 245 Dimension dimension = Dimension.NONE; 246 for (int i = 0; i < productUnit.size(); i++) { 247 ProductUnit.Element e = productUnit.get(i); 248 Dimension d = e.getUnit().getDimension().pow(e.getPow()).root( 249 e.getRoot()); 250 dimension = dimension.multiply(d); 251 } 252 return dimension; 253 } 254 255 263 public final Converter getConverterTo(Unit that) throws ConversionException { 264 if (this == that) 265 return Converter.IDENTITY; 266 if (this._parentUnit == that._parentUnit) 267 return that._toParentUnit.inverse().concatenate(this._toParentUnit); 268 Converter thisTransform = this.getTransform(); 269 Converter thatTransform = that.getTransform(); 270 if (this.isCompatible(that)) 271 return thatTransform.inverse().concatenate(thisTransform); 272 throw new ConversionException(this + " is not compatible with " + that 273 + " in current context"); 274 } 275 276 private Converter getTransform() { if (_parentUnit != this) 278 return _parentUnit.getTransform().concatenate(_toParentUnit); 279 if (_parentUnit instanceof BaseUnit) { 280 Converter transform = ((BaseUnit< ? super Q>) _parentUnit)._transform 281 .get(); 282 return transform.concatenate(_toParentUnit); 283 } 284 ProductUnit< ? super Q> productUnit = (ProductUnit< ? super Q>) _parentUnit; 285 double factor = 1.0; 286 for (int i = 0; i < productUnit.size(); i++) { 287 ProductUnit.Element e = productUnit.get(i); 288 Converter cvtr = e.getUnit().getTransform(); 289 if (!cvtr.isLinear()) 290 throw new ConversionException(e.getUnit() 291 + " is non-linear, cannot convert"); 292 factor *= MathLib.pow(cvtr.derivative(0), ((double) e.getPow()) 293 / ((double) e.getRoot())); 294 } 295 return (MathLib.abs(factor - 1.0) < 1e-9) ? _toParentUnit 296 : new MultiplyConverter(factor).concatenate(_toParentUnit); 297 } 298 299 314 public final <T extends Q> AlternateUnit<T> alternate(String symbol) { 315 AlternateUnit<T> newUnit = new AlternateUnit<T>(symbol, _parentUnit, 316 _toParentUnit); 317 return (AlternateUnit<T>) getInstance(newUnit); } 319 320 331 public final CompoundUnit<Q> compound(Unit<Q> subunit) { 332 CompoundUnit<Q> newUnit = new CompoundUnit<Q>(this, subunit); 333 return (CompoundUnit<Q>) getInstance(newUnit); } 335 336 346 public final Unit<Q> transform(Converter operation) { 347 TransformedUnit<Q> newUnit 348 = new TransformedUnit<Q>(this, operation); 349 return (Unit<Q>) getInstance(newUnit); } 351 352 360 public final Unit<Q> plus(double offset) { 361 return transform(new AddConverter(offset)); 362 } 363 364 373 public final Unit<Q> times(double scale) { 374 return transform(new MultiplyConverter(scale)); 375 } 376 377 383 public final <Q extends Quantity> Unit<Q> times(Unit that) { 384 FastMap<Unit, Unit> thisMult = MULT_TABLE.get().get(this); 385 if (thisMult == null) { 386 thisMult = new FastMap<Unit, Unit>().setKeyComparator(FastComparator.DIRECT); 387 synchronized (MULT_TABLE) { 388 MULT_TABLE.get().put(this, thisMult); 389 } 390 } 391 Unit product = thisMult.get(that); 392 if (product == null) { 393 product = ProductUnit.getProductInstance(this, that); 394 synchronized (thisMult) { 395 thisMult.put(that, product); 396 } 397 } 398 return product; 399 } 400 401 406 public final <Q extends Quantity> Unit<Q> inverse() { 407 if (_inverse != null) 408 return _inverse; 409 _inverse = ProductUnit.getQuotientInstance(ONE, this); 410 return _inverse; 411 } 412 413 419 public final <Q extends Quantity> Unit<Q> divide(Unit that) { 420 if (that._inverse != null) 421 return this.times(that._inverse); 422 that._inverse = ProductUnit.getQuotientInstance(ONE, that); 423 return this.times(that._inverse); 424 } 425 426 433 public final <Q extends Quantity> Unit<Q> root(int n) { 434 if (n > 0) { 435 return ProductUnit.getRootInstance(this, n); 436 } else if (n == 0) { 437 throw new ArithmeticException ("Root's order of zero"); 438 } else { return ONE.divide(this.root(-n)); 440 } 441 } 442 443 449 public final <Q extends Quantity> Unit<Q> pow(int n) { 450 if (n > 0) { 451 return this.times(this.pow(n - 1)); 452 } else if (n == 0) { 453 return (Unit<Q>) ONE; 454 } else { return ONE.divide(this.pow(-n)); 456 } 457 } 458 459 476 public Unit<Q> label(String label) { 477 synchronized (UnitFormat.UNIT_TO_LABEL) { 478 String prevLabel = UnitFormat.UNIT_TO_LABEL.put(this, label); 479 if (prevLabel != null) { 480 UnitFormat.LABEL_TO_UNIT.put(prevLabel, null); 481 } 482 if (label != null) { 483 UnitFormat.LABEL_TO_UNIT.put(label, this); 484 } 485 return this; 486 } 487 } 488 489 503 public Unit<Q> alias(String alias) { 504 synchronized (UnitFormat.ALIAS_TO_UNIT) { 505 UnitFormat.ALIAS_TO_UNIT.put(alias, this); 506 } 507 return this; 508 } 509 510 531 public static Unit valueOf(CharSequence csq) { 532 return UnitFormat.current().parse(csq); 533 } 534 535 542 public static Set <Unit> getInstances() { 543 return Unit.COLLECTION.unmodifiable().keySet(); 544 } 545 546 550 556 public Text toText() { 557 return UnitFormat.current().format(this); 558 } 559 560 565 public final String toString() { 566 return toText().toString(); 567 } 568 569 582 protected static <Q extends Quantity> Unit<Q> getInstance(Unit<Q> template) { 583 synchronized (COLLECTION) { 584 Unit<Q> unit = COLLECTION.get(template); 585 if (unit != null) 586 return unit; if ((template._symbol != null) 588 && SYMBOLS.containsKey(template._symbol)) 589 throw new IllegalArgumentException ("The symbol: " 590 + template._symbol 591 + " is currently associated to an instance of " 592 + unit.getClass()); 593 SYMBOLS.put(template._symbol, template); 594 COLLECTION.put(template, template); 595 template._hashCode = template.hashCodeImpl(); 596 template._parentUnit = template.getParentUnitImpl(); 597 template._toParentUnit = template.toParentUnitImpl(); 598 return template; 599 } 600 } 601 602 610 public final boolean equals(Object that) { 611 return this == that; 612 } 613 614 619 public final int hashCode() { 620 return _hashCode; 621 } 622 623 629 protected Object readResolve() { 630 return getInstance(this); 631 } 632 633 636 private static final class Comparator extends FastComparator<Unit> { 637 638 public int hashCodeOf(Unit unit) { 639 return unit.hashCodeImpl(); 640 } 641 642 public boolean areEqual(Unit u1, Unit u2) { 643 return u1.equalsImpl(u2); 644 } 645 646 public int compare(Unit u1, Unit u2) { 647 throw new UnsupportedOperationException (); 648 } 649 650 private static final long serialVersionUID = 1L; 651 } 652 } | Popular Tags |