KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > measure > units > ProductUnit


1 /*
2  * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
3  * Copyright (C) 2006 - JScience (http://jscience.org/)
4  * All rights reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software is
7  * freely granted, provided that this notice is preserved.
8  */

9 package javax.measure.units;
10
11 import java.io.Serializable JavaDoc;
12
13 import javax.measure.converters.ConversionException;
14 import javax.measure.converters.UnitConverter;
15 import javax.measure.quantities.Quantity;
16
17 /**
18  * <p> This class represents units formed by the product of rational powers of
19  * existing units.</p>
20  *
21  * <p> This class maintains the canonical form of this product (simplest
22  * form after factorization). For example:
23  * <code>METER.pow(2).divide(METER)</code> returns
24  * <code>METER</code>.</p>
25  *
26  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
27  * @version 3.1, April 22, 2006
28  * @see Unit#times(Unit)
29  * @see Unit#divide(Unit)
30  * @see Unit#pow(int)
31  * @see Unit#root(int)
32  */

33 public final class ProductUnit<Q extends Quantity> extends DerivedUnit<Q> {
34
35     /**
36      * Holds the units composing this product unit.
37      */

38     private final Element[] _elements;
39
40     /**
41      * Holds the hashcode (optimization).
42      */

43     private int _hashCode;
44
45     /**
46      * Default constructor (used solely to create <code>ONE</code> instance).
47      */

48     ProductUnit() {
49         _elements = new Element[0];
50     }
51
52     /**
53      * Copy constructor (allows for parameterization of product units).
54      *
55      * @param productUnit the product unit source.
56      * @throws ClassCastException if the specified unit is not
57      * a product unit.
58      */

59     public ProductUnit(Unit productUnit) {
60         _elements = ((ProductUnit)productUnit)._elements;
61     }
62
63     /**
64      * Product unit constructor.
65      *
66      * @param elements the product elements.
67      */

68     private ProductUnit(Element[] elements) {
69         _elements = elements;
70     }
71
72     /**
73      * Returns the unit defined from the product of the specifed elements.
74      *
75      * @param leftElems left multiplicand elements.
76      * @param rightElems right multiplicand elements.
77      * @return the corresponding unit.
78      */

79     @SuppressWarnings JavaDoc("unchecked")
80     private static Unit<? extends Quantity> getInstance(Element[] leftElems,
81             Element[] rightElems) {
82
83         // Merges left elements with right elements.
84
Element[] result = new Element[leftElems.length + rightElems.length];
85         int resultIndex = 0;
86         for (int i = 0; i < leftElems.length; i++) {
87             Unit unit = leftElems[i]._unit;
88             int p1 = leftElems[i]._pow;
89             int r1 = leftElems[i]._root;
90             int p2 = 0;
91             int r2 = 1;
92             for (int j = 0; j < rightElems.length; j++) {
93                 if (unit.equals(rightElems[j]._unit)) {
94                     p2 = rightElems[j]._pow;
95                     r2 = rightElems[j]._root;
96                     break; // No duplicate.
97
}
98             }
99             int pow = (p1 * r2) + (p2 * r1);
100             int root = r1 * r2;
101             if (pow != 0) {
102                 int gcd = gcd(Math.abs(pow), root);
103                 result[resultIndex++] = new Element(unit, pow / gcd, root / gcd);
104             }
105         }
106
107         // Appends remaining right elements not merged.
108
for (int i = 0; i < rightElems.length; i++) {
109             Unit unit = rightElems[i]._unit;
110             boolean hasBeenMerged = false;
111             for (int j = 0; j < leftElems.length; j++) {
112                 if (unit.equals(leftElems[j]._unit)) {
113                     hasBeenMerged = true;
114                     break;
115                 }
116             }
117             if (!hasBeenMerged) {
118                 result[resultIndex++] = rightElems[i];
119             }
120         }
121
122         // Returns or creates instance.
123
if (resultIndex == 0) {
124             return ONE;
125         } else if ((resultIndex == 1) && (result[0]._pow == result[0]._root)) {
126             return result[0]._unit;
127         } else {
128             Element[] elems = new Element[resultIndex];
129             for (int i = 0; i < resultIndex; i++) {
130                 elems[i] = result[i];
131             }
132             return new ProductUnit<Quantity>(elems);
133         }
134     }
135
136     /**
137      * Returns the product of the specified units.
138      *
139      * @param left the left unit operand.
140      * @param right the right unit operand.
141      * @return <code>left * right</code>
142      */

143     static Unit<? extends Quantity> getProductInstance(Unit left, Unit right) {
144         Element[] leftElems;
145         if (left instanceof ProductUnit) {
146             leftElems = ((ProductUnit) left)._elements;
147         } else {
148             leftElems = new Element[] { new Element(left, 1, 1) };
149         }
150         Element[] rightElems;
151         if (right instanceof ProductUnit) {
152             rightElems = ((ProductUnit) right)._elements;
153         } else {
154             rightElems = new Element[] { new Element(right, 1, 1) };
155         }
156         return getInstance(leftElems, rightElems);
157     }
158
159     /**
160      * Returns the quotient of the specified units.
161      *
162      * @param left the dividend unit operand.
163      * @param right the divisor unit operand.
164      * @return <code>dividend / divisor</code>
165      */

166     static Unit<? extends Quantity> getQuotientInstance(Unit left, Unit right) {
167         Element[] leftElems;
168         if (left instanceof ProductUnit) {
169             leftElems = ((ProductUnit) left)._elements;
170         } else {
171             leftElems = new Element[] { new Element(left, 1, 1) };
172         }
173         Element[] rightElems;
174         if (right instanceof ProductUnit) {
175             Element[] elems = ((ProductUnit) right)._elements;
176             rightElems = new Element[elems.length];
177             for (int i = 0; i < elems.length; i++) {
178                 rightElems[i] = new Element(elems[i]._unit, -elems[i]._pow,
179                         elems[i]._root);
180             }
181         } else {
182             rightElems = new Element[] { new Element(right, -1, 1) };
183         }
184         return getInstance(leftElems, rightElems);
185     }
186
187     /**
188      * Returns the product unit corresponding to the specified root of
189      * the specified unit.
190      *
191      * @param unit the unit.
192      * @param n the root's order (n &gt; 0).
193      * @return <code>unit^(1/nn)</code>
194      * @throws ArithmeticException if <code>n == 0</code>.
195      */

196     static Unit<? extends Quantity> getRootInstance(Unit unit, int n) {
197         Element[] unitElems;
198         if (unit instanceof ProductUnit) {
199             Element[] elems = ((ProductUnit) unit)._elements;
200             unitElems = new Element[elems.length];
201             for (int i = 0; i < elems.length; i++) {
202                 int gcd = gcd(Math.abs(elems[i]._pow), elems[i]._root * n);
203                 unitElems[i] = new Element(elems[i]._unit, elems[i]._pow / gcd,
204                         elems[i]._root * n / gcd);
205             }
206         } else {
207             unitElems = new Element[] { new Element(unit, 1, n) };
208         }
209         return getInstance(unitElems, new Element[0]);
210     }
211
212     /**
213      * Returns the product unit corresponding to this unit raised to
214      * the specified exponent.
215      *
216      * @param unit the unit.
217      * @param nn the exponent (nn &gt; 0).
218      * @return <code>unit^n</code>
219      */

220     static Unit<? extends Quantity> getPowInstance(Unit unit, int n) {
221         Element[] unitElems;
222         if (unit instanceof ProductUnit) {
223             Element[] elems = ((ProductUnit) unit)._elements;
224             unitElems = new Element[elems.length];
225             for (int i = 0; i < elems.length; i++) {
226                 int gcd = gcd(Math.abs(elems[i]._pow * n), elems[i]._root);
227                 unitElems[i] = new Element(elems[i]._unit, elems[i]._pow * n
228                         / gcd, elems[i]._root / gcd);
229             }
230         } else {
231             unitElems = new Element[] { new Element(unit, n, 1) };
232         }
233         return getInstance(unitElems, new Element[0]);
234     }
235
236     /**
237      * Returns the number of units in this product.
238      *
239      * @return the number of units being multiplied.
240      */

241     public int getUnitCount() {
242         return _elements.length;
243     }
244
245     /**
246      * Returns the unit at the specified position.
247      *
248      * @param index the index of the unit to return.
249      * @return the unit at the specified position.
250      * @throws IndexOutOfBoundsException if index is out of range
251      * <code>(index &lt; 0 || index &gt;= size())</code>.
252      */

253     @SuppressWarnings JavaDoc("unchecked")
254     public Unit<? extends Quantity> getUnit(int index) {
255         return _elements[index].getUnit();
256     }
257
258     /**
259      * Returns the power exponent of the unit at the specified position.
260      *
261      * @param index the index of the unit to return.
262      * @return the unit power exponent at the specified position.
263      * @throws IndexOutOfBoundsException if index is out of range
264      * <code>(index &lt; 0 || index &gt;= size())</code>.
265      */

266     public int getUnitPow(int index) {
267         return _elements[index].getPow();
268     }
269
270     /**
271      * Returns the root exponent of the unit at the specified position.
272      *
273      * @param index the index of the unit to return.
274      * @return the unit root exponent at the specified position.
275      * @throws IndexOutOfBoundsException if index is out of range
276      * <code>(index &lt; 0 || index &gt;= size())</code>.
277      */

278     public int getUnitRoot(int index) {
279         return _elements[index].getRoot();
280     }
281
282     /**
283      * Indicates if this product unit is considered equals to the specified
284      * object.
285      *
286      * @param that the object to compare for equality.
287      * @return <code>true</code> if <code>this</code> and <code>that</code>
288      * are considered equals; <code>false</code>otherwise.
289      */

290     public boolean equals(Object JavaDoc that) {
291         if (this == that)
292             return true;
293         if (that instanceof ProductUnit) {
294             // Two products are equals if they have the same elements
295
// regardless of the elements' order.
296
Element[] elems = ((ProductUnit) that)._elements;
297             if (_elements.length == elems.length) {
298                 for (int i = 0; i < _elements.length; i++) {
299                     boolean unitFound = false;
300                     for (int j = 0; j < elems.length; j++) {
301                         if (_elements[i]._unit.equals(elems[j]._unit)) {
302                             if ((_elements[i]._pow != elems[j]._pow)
303                                     || (_elements[i]._root != elems[j]._root)) {
304                                 return false;
305                             } else {
306                                 unitFound = true;
307                                 break;
308                             }
309                         }
310                     }
311                     if (!unitFound) {
312                         return false;
313                     }
314                 }
315                 return true;
316             }
317         }
318         return false;
319     }
320
321     @Override JavaDoc
322     // Implements abstract method.
323
public int hashCode() {
324         if (_hashCode != 0)
325             return _hashCode;
326         int code = 0;
327         for (int i = 0; i < _elements.length; i++) {
328             code += _elements[i]._unit.hashCode()
329                     * (_elements[i]._pow * 3 - _elements[i]._root * 2);
330         }
331         _hashCode = code;
332         return code;
333     }
334
335     @Override JavaDoc
336     @SuppressWarnings JavaDoc("unchecked")
337     public Unit<? super Q> getSystemUnit() {
338         if (isSystemUnit())
339             return this;
340         Unit systemUnit = ONE;
341         for (int i = 0; i < _elements.length; i++) {
342             Unit unit = _elements[i]._unit.getSystemUnit();
343             unit = unit.pow(_elements[i]._pow);
344             unit = unit.root(_elements[i]._root);
345             systemUnit = systemUnit.times(unit);
346         }
347         return systemUnit;
348     }
349
350     @Override JavaDoc
351     public UnitConverter toSystemUnit() {
352         if (isSystemUnit())
353             return UnitConverter.IDENTITY;
354         UnitConverter converter = UnitConverter.IDENTITY;
355         for (int i = 0; i < _elements.length; i++) {
356             UnitConverter cvtr = _elements[i]._unit.toSystemUnit();
357             if (!cvtr.isLinear())
358                 throw new ConversionException(_elements[i]._unit
359                         + " is non-linear, cannot convert");
360             if (_elements[i]._root != 1)
361                 throw new ConversionException(_elements[i]._unit
362                         + " holds a base unit with fractional exponent");
363             int pow = _elements[i]._pow;
364             if (pow < 0) { // Negative power.
365
pow = -pow;
366                 cvtr = cvtr.inverse();
367             }
368             for (int j = 0; j < pow; j++) {
369                 converter = converter.concatenate(cvtr);
370             }
371         }
372         return converter;
373     }
374
375     /**
376      * Indicates if this product unit is a system unit.
377      *
378      * @return <code>true</code> if all elements are system units;
379      * <code>false</code> otherwise.
380      */

381     private boolean isSystemUnit() {
382         for (int i = 0; i < _elements.length; i++) {
383             Unit u = _elements[i]._unit;
384             if (!u.getSystemUnit().equals(u))
385                 return false;
386         }
387         return true;
388     }
389
390     /**
391      * Returns the greatest common divisor (Euclid's algorithm).
392      *
393      * @param m the first number.
394      * @param nn the second number.
395      * @return the greatest common divisor.
396      */

397     private static int gcd(int m, int n) {
398         if (n == 0) {
399             return m;
400         } else {
401             return gcd(n, m % n);
402         }
403     }
404
405     /**
406      * Inner product element represents a rational power of a single unit.
407      */

408     private final static class Element implements Serializable JavaDoc {
409
410         /**
411          * Holds the single unit.
412          */

413         private final Unit _unit;
414
415         /**
416          * Holds the power exponent.
417          */

418         private final int _pow;
419
420         /**
421          * Holds the root exponent.
422          */

423         private final int _root;
424
425         /**
426          * Structural constructor.
427          *
428          * @param unit the unit.
429          * @param pow the power exponent.
430          * @param root the root exponent.
431          */

432         private Element(Unit unit, int pow, int root) {
433             _unit = unit;
434             _pow = pow;
435             _root = root;
436         }
437
438         /**
439          * Returns this element's unit.
440          *
441          * @return the single unit.
442          */

443         public Unit getUnit() {
444             return _unit;
445         }
446
447         /**
448          * Returns the power exponent. The power exponent can be negative
449          * but is always different from zero.
450          *
451          * @return the power exponent of the single unit.
452          */

453         public int getPow() {
454             return _pow;
455         }
456
457         /**
458          * Returns the root exponent. The root exponent is always greater
459          * than zero.
460          *
461          * @return the root exponent of the single unit.
462          */

463         public int getRoot() {
464             return _root;
465         }
466
467         private static final long serialVersionUID = 1L;
468     }
469
470     private static final long serialVersionUID = 1L;
471 }
Popular Tags