001: /*
002: * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
003: * Copyright (C) 2007 - JScience (http://jscience.org/)
004: * All rights reserved.
005: *
006: * Permission to use, copy, modify, and distribute this software is
007: * freely granted, provided that this notice is preserved.
008: */
009: package javax.measure;
010:
011: import javax.measure.converter.UnitConverter;
012: import javax.measure.quantity.Quantity;
013: import javax.measure.unit.CompoundUnit;
014: import javax.measure.unit.Unit;
015:
016: /**
017: * <p> This class represents a measurement vector of two or more dimensions.
018: * For example:[code]
019: * VectorMeasure<Length> dimension = VectorMeasure.valueOf(12.0, 30.0, 40.0, MILLIMETER);
020: * VectorMeasure<Velocity> v2d = VectorMeasure.valueOf(-2.2, -3.0, KNOTS);
021: * VectorMeasure<ElectricCurrent> c2d = VectorMeasure.valueOf(-7.3, 3.5, NANOAMPERE);
022: * [/code]
023: * </p>
024: *
025: * <p> Subclasses may provide fixed dimensions specializations:[code]
026: * class Velocity2D extends VectorMeasure<Velocity> {
027: * public Velocity2D(double x, double y, Unit<Velocity> unit) {
028: * ...
029: * }
030: * }
031: * [/code]</p>
032: *
033: * <p> Measurement vectors may use {@link CompoundUnit compound units}:[code]
034: * VectorMeasure<Angle> latLong = VectorMeasure.valueOf(12.345, 22.23, DEGREE_ANGLE);
035: * Unit<Angle> HOUR_MINUTE_SECOND_ANGLE = DEGREE_ANGLE.compound(MINUTE_ANGLE).compound(SECOND_ANGLE);
036: * System.out.println(latLong.to(HOUR_MINUTE_SECOND_ANGLE));
037: *
038: * > [12°19'42", 22°12'48"] [/code]</p>
039: *
040: * <p> Instances of this class (and sub-classes) are immutable.</p>
041: *
042: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
043: * @version 4.3, October 3, 2007
044: */
045: public abstract class VectorMeasure<Q extends Quantity> extends
046: Measure<double[], Q> {
047:
048: /**
049: * Default constructor (for sub-classes).
050: */
051: protected VectorMeasure() {
052: }
053:
054: /**
055: * Returns a 2-dimensional measurement vector.
056: *
057: * @param x the first vector component value.
058: * @param y the second vector component value.
059: * @param unit the measurement unit.
060: */
061: public static <Q extends Quantity> VectorMeasure<Q> valueOf(
062: double x, double y, Unit<Q> unit) {
063: return new TwoDimensional<Q>(x, y, unit);
064: }
065:
066: /**
067: * Returns a 3-dimensional measurement vector.
068: *
069: * @param x the first vector component value.
070: * @param y the second vector component value.
071: * @param z the third vector component value.
072: * @param unit the measurement unit.
073: */
074: public static <Q extends Quantity> VectorMeasure<Q> valueOf(
075: double x, double y, double z, Unit<Q> unit) {
076: return new ThreeDimensional<Q>(x, y, z, unit);
077: }
078:
079: /**
080: * Returns a multi-dimensional measurement vector.
081: *
082: * @param components the vector component values.
083: * @param unit the measurement unit.
084: */
085: public static <Q extends Quantity> VectorMeasure<Q> valueOf(
086: double[] components, Unit<Q> unit) {
087: return new MultiDimensional<Q>(components, unit);
088: }
089:
090: /**
091: * Returns the measurement vector equivalent to this one but stated in the
092: * specified unit.
093: *
094: * @param unit the new measurement unit.
095: * @return the vector measure stated in the specified unit.
096: */
097: public abstract VectorMeasure<Q> to(Unit<Q> unit);
098:
099: /**
100: * Returns the norm of this measurement vector stated in the specified
101: * unit.
102: *
103: * @param unit the unit in which the norm is stated.
104: * @return <code>|this|</code>
105: */
106: public abstract double doubleValue(Unit<Q> unit);
107:
108: /**
109: * Returns the <code>String</code> representation of this measurement
110: * vector (for example <code>[2.3 m/s, 5.6 m/s]</code>).
111: *
112: * @return the textual representation of the measurement vector.
113: */
114: public String toString() {
115: double[] values = getValue();
116: Unit<Q> unit = getUnit();
117: StringBuffer tmp = new StringBuffer();
118: tmp.append('[');
119: for (double v : values) {
120: if (tmp.length() > 1) {
121: tmp.append(", ");
122: }
123: if (unit instanceof CompoundUnit) {
124: MeasureFormat.DEFAULT
125: .formatCompound(v, unit, tmp, null);
126: } else {
127: tmp.append(v).append(" ").append(unit);
128: }
129: }
130: tmp.append("] ");
131: return tmp.toString();
132: }
133:
134: // Holds 2-dimensional implementation.
135: private static class TwoDimensional<Q extends Quantity> extends
136: VectorMeasure<Q> {
137:
138: private final double _x;
139:
140: private final double _y;
141:
142: private final Unit<Q> _unit;
143:
144: private TwoDimensional(double x, double y, Unit<Q> unit) {
145: _x = x;
146: _y = y;
147: _unit = unit;
148:
149: }
150:
151: @Override
152: public double doubleValue(Unit<Q> unit) {
153: double norm = Math.sqrt(_x * _x + _y * _y);
154: if ((unit == _unit) || (unit.equals(_unit)))
155: return norm;
156: return _unit.getConverterTo(unit).convert(norm);
157: }
158:
159: @Override
160: public Unit<Q> getUnit() {
161: return _unit;
162: }
163:
164: @Override
165: public double[] getValue() {
166: return new double[] { _x, _y };
167: }
168:
169: @Override
170: public TwoDimensional<Q> to(Unit<Q> unit) {
171: if ((unit == _unit) || (unit.equals(_unit)))
172: return this ;
173: UnitConverter cvtr = _unit.getConverterTo(unit);
174: return new TwoDimensional<Q>(cvtr.convert(_x), cvtr
175: .convert(_y), unit);
176: }
177:
178: private static final long serialVersionUID = 1L;
179:
180: }
181:
182: // Holds 3-dimensional implementation.
183: private static class ThreeDimensional<Q extends Quantity> extends
184: VectorMeasure<Q> {
185:
186: private final double _x;
187:
188: private final double _y;
189:
190: private final double _z;
191:
192: private final Unit<Q> _unit;
193:
194: private ThreeDimensional(double x, double y, double z,
195: Unit<Q> unit) {
196: _x = x;
197: _y = y;
198: _z = z;
199: _unit = unit;
200:
201: }
202:
203: @Override
204: public double doubleValue(Unit<Q> unit) {
205: double norm = Math.sqrt(_x * _x + _y * _y + _z * _z);
206: if ((unit == _unit) || (unit.equals(_unit)))
207: return norm;
208: return _unit.getConverterTo(unit).convert(norm);
209: }
210:
211: @Override
212: public Unit<Q> getUnit() {
213: return _unit;
214: }
215:
216: @Override
217: public double[] getValue() {
218: return new double[] { _x, _y, _z };
219: }
220:
221: @Override
222: public ThreeDimensional<Q> to(Unit<Q> unit) {
223: if ((unit == _unit) || (unit.equals(_unit)))
224: return this ;
225: UnitConverter cvtr = _unit.getConverterTo(unit);
226: return new ThreeDimensional<Q>(cvtr.convert(_x), cvtr
227: .convert(_y), cvtr.convert(_z), unit);
228: }
229:
230: private static final long serialVersionUID = 1L;
231:
232: }
233:
234: // Holds multi-dimensional implementation.
235: private static class MultiDimensional<Q extends Quantity> extends
236: VectorMeasure<Q> {
237:
238: private final double[] _components;
239:
240: private final Unit<Q> _unit;
241:
242: private MultiDimensional(double[] components, Unit<Q> unit) {
243: _components = components.clone();
244: _unit = unit;
245: }
246:
247: @Override
248: public double doubleValue(Unit<Q> unit) {
249: double normSquare = _components[0] * _components[0];
250: for (int i = 1, n = _components.length; i < n;) {
251: double d = _components[i++];
252: normSquare += d * d;
253: }
254: if ((unit == _unit) || (unit.equals(_unit)))
255: return Math.sqrt(normSquare);
256: return _unit.getConverterTo(unit).convert(
257: Math.sqrt(normSquare));
258: }
259:
260: @Override
261: public Unit<Q> getUnit() {
262: return _unit;
263: }
264:
265: @Override
266: public double[] getValue() {
267: return _components.clone();
268: }
269:
270: @Override
271: public MultiDimensional<Q> to(Unit<Q> unit) {
272: if ((unit == _unit) || (unit.equals(_unit)))
273: return this ;
274: UnitConverter cvtr = _unit.getConverterTo(unit);
275: double[] newValues = new double[_components.length];
276: for (int i = 0; i < _components.length; i++) {
277: newValues[i] = cvtr.convert(_components[i]);
278: }
279: return new MultiDimensional<Q>(newValues, unit);
280: }
281:
282: private static final long serialVersionUID = 1L;
283:
284: }
285: }
|