1 | /* |
2 | * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences. |
3 | * Copyright (C) 2007 - 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; |
10 | |
11 | import javax.measure.converter.UnitConverter; |
12 | import javax.measure.quantity.Quantity; |
13 | import javax.measure.unit.CompoundUnit; |
14 | import javax.measure.unit.Unit; |
15 | |
16 | /** |
17 | * <p> This class represents a measurement vector of two or more dimensions. |
18 | * For example:[code] |
19 | * VectorMeasure<Length> dimension = VectorMeasure.valueOf(12.0, 30.0, 40.0, MILLIMETER); |
20 | * VectorMeasure<Velocity> v2d = VectorMeasure.valueOf(-2.2, -3.0, KNOTS); |
21 | * VectorMeasure<ElectricCurrent> c2d = VectorMeasure.valueOf(-7.3, 3.5, NANOAMPERE); |
22 | * [/code] |
23 | * </p> |
24 | * |
25 | * <p> Subclasses may provide fixed dimensions specializations:[code] |
26 | * class Velocity2D extends VectorMeasure<Velocity> { |
27 | * public Velocity2D(double x, double y, Unit<Velocity> unit) { |
28 | * ... |
29 | * } |
30 | * } |
31 | * [/code]</p> |
32 | * |
33 | * <p> Measurement vectors may use {@link CompoundUnit compound units}:[code] |
34 | * VectorMeasure<Angle> latLong = VectorMeasure.valueOf(12.345, 22.23, DEGREE_ANGLE); |
35 | * Unit<Angle> HOUR_MINUTE_SECOND_ANGLE = DEGREE_ANGLE.compound(MINUTE_ANGLE).compound(SECOND_ANGLE); |
36 | * System.out.println(latLong.to(HOUR_MINUTE_SECOND_ANGLE)); |
37 | * |
38 | * > [12°19'42", 22°12'48"] [/code]</p> |
39 | * |
40 | * <p> Instances of this class (and sub-classes) are immutable.</p> |
41 | * |
42 | * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> |
43 | * @version 4.3, October 3, 2007 |
44 | */ |
45 | public abstract class VectorMeasure<Q extends Quantity> extends Measure<double[], Q> { |
46 | |
47 | /** |
48 | * Default constructor (for sub-classes). |
49 | */ |
50 | protected VectorMeasure() { |
51 | } |
52 | |
53 | /** |
54 | * Returns a 2-dimensional measurement vector. |
55 | * |
56 | * @param x the first vector component value. |
57 | * @param y the second vector component value. |
58 | * @param unit the measurement unit. |
59 | */ |
60 | public static <Q extends Quantity> VectorMeasure<Q> valueOf( |
61 | double x, double y, Unit<Q> unit) { |
62 | return new TwoDimensional<Q>(x, y, unit); |
63 | } |
64 | |
65 | /** |
66 | * Returns a 3-dimensional measurement vector. |
67 | * |
68 | * @param x the first vector component value. |
69 | * @param y the second vector component value. |
70 | * @param z the third vector component value. |
71 | * @param unit the measurement unit. |
72 | */ |
73 | public static <Q extends Quantity> VectorMeasure<Q> valueOf( |
74 | double x, double y, double z, Unit<Q> unit) { |
75 | return new ThreeDimensional<Q>(x, y, z, unit); |
76 | } |
77 | |
78 | /** |
79 | * Returns a multi-dimensional measurement vector. |
80 | * |
81 | * @param components the vector component values. |
82 | * @param unit the measurement unit. |
83 | */ |
84 | public static <Q extends Quantity> VectorMeasure<Q> valueOf(double[] components, |
85 | Unit<Q> unit) { |
86 | return new MultiDimensional<Q>(components, unit); |
87 | } |
88 | |
89 | /** |
90 | * Returns the measurement vector equivalent to this one but stated in the |
91 | * specified unit. |
92 | * |
93 | * @param unit the new measurement unit. |
94 | * @return the vector measure stated in the specified unit. |
95 | */ |
96 | public abstract VectorMeasure<Q> to(Unit<Q> unit); |
97 | |
98 | /** |
99 | * Returns the norm of this measurement vector stated in the specified |
100 | * unit. |
101 | * |
102 | * @param unit the unit in which the norm is stated. |
103 | * @return <code>|this|</code> |
104 | */ |
105 | public abstract double doubleValue(Unit<Q> unit); |
106 | |
107 | /** |
108 | * Returns the <code>String</code> representation of this measurement |
109 | * vector (for example <code>[2.3 m/s, 5.6 m/s]</code>). |
110 | * |
111 | * @return the textual representation of the measurement vector. |
112 | */ |
113 | public String toString() { |
114 | double[] values = getValue(); |
115 | Unit<Q> unit = getUnit(); |
116 | StringBuffer tmp = new StringBuffer(); |
117 | tmp.append('['); |
118 | for (double v : values) { |
119 | if (tmp.length() > 1) { |
120 | tmp.append(", "); |
121 | } |
122 | if (unit instanceof CompoundUnit) { |
123 | MeasureFormat.DEFAULT.formatCompound(v, unit, tmp, null); |
124 | } else { |
125 | tmp.append(v).append(" ").append(unit); |
126 | } |
127 | } |
128 | tmp.append("] "); |
129 | return tmp.toString(); |
130 | } |
131 | |
132 | // Holds 2-dimensional implementation. |
133 | private static class TwoDimensional<Q extends Quantity> extends VectorMeasure<Q> { |
134 | |
135 | private final double _x; |
136 | |
137 | private final double _y; |
138 | |
139 | private final Unit<Q> _unit; |
140 | |
141 | private TwoDimensional(double x, double y, Unit<Q> unit) { |
142 | _x = x; |
143 | _y = y; |
144 | _unit = unit; |
145 | |
146 | } |
147 | @Override |
148 | public double doubleValue(Unit<Q> unit) { |
149 | double norm = Math.sqrt(_x * _x + _y * _y); |
150 | if ((unit == _unit) || (unit.equals(_unit))) |
151 | return norm; |
152 | return _unit.getConverterTo(unit).convert(norm); |
153 | } |
154 | |
155 | @Override |
156 | public Unit<Q> getUnit() { |
157 | return _unit; |
158 | } |
159 | |
160 | @Override |
161 | public double[] getValue() { |
162 | return new double[] { _x, _y }; |
163 | } |
164 | |
165 | @Override |
166 | public TwoDimensional<Q> to(Unit<Q> unit) { |
167 | if ((unit == _unit) || (unit.equals(_unit))) |
168 | return this; |
169 | UnitConverter cvtr = _unit.getConverterTo(unit); |
170 | return new TwoDimensional<Q>(cvtr.convert(_x), cvtr.convert(_y), unit); |
171 | } |
172 | |
173 | private static final long serialVersionUID = 1L; |
174 | |
175 | } |
176 | |
177 | // Holds 3-dimensional implementation. |
178 | private static class ThreeDimensional<Q extends Quantity> extends VectorMeasure<Q> { |
179 | |
180 | private final double _x; |
181 | |
182 | private final double _y; |
183 | |
184 | private final double _z; |
185 | |
186 | private final Unit<Q> _unit; |
187 | |
188 | private ThreeDimensional(double x, double y, double z, Unit<Q> unit) { |
189 | _x = x; |
190 | _y = y; |
191 | _z = z; |
192 | _unit = unit; |
193 | |
194 | } |
195 | @Override |
196 | public double doubleValue(Unit<Q> unit) { |
197 | double norm = Math.sqrt(_x * _x + _y * _y + _z * _z); |
198 | if ((unit == _unit) || (unit.equals(_unit))) |
199 | return norm; |
200 | return _unit.getConverterTo(unit).convert(norm); |
201 | } |
202 | |
203 | @Override |
204 | public Unit<Q> getUnit() { |
205 | return _unit; |
206 | } |
207 | |
208 | @Override |
209 | public double[] getValue() { |
210 | return new double[] { _x, _y, _z }; |
211 | } |
212 | |
213 | @Override |
214 | public ThreeDimensional<Q> to(Unit<Q> unit) { |
215 | if ((unit == _unit) || (unit.equals(_unit))) |
216 | return this; |
217 | UnitConverter cvtr = _unit.getConverterTo(unit); |
218 | return new ThreeDimensional<Q>(cvtr.convert(_x), cvtr.convert(_y), cvtr.convert(_z), unit); |
219 | } |
220 | |
221 | private static final long serialVersionUID = 1L; |
222 | |
223 | } |
224 | // Holds multi-dimensional implementation. |
225 | private static class MultiDimensional<Q extends Quantity> extends VectorMeasure<Q> { |
226 | |
227 | private final double[] _components; |
228 | |
229 | private final Unit<Q> _unit; |
230 | |
231 | private MultiDimensional(double[] components, Unit<Q> unit) { |
232 | _components = components.clone(); |
233 | _unit = unit; |
234 | } |
235 | |
236 | @Override |
237 | public double doubleValue(Unit<Q> unit) { |
238 | double normSquare = _components[0] * _components[0]; |
239 | for (int i=1, n=_components.length; i < n;) { |
240 | double d = _components[i++]; |
241 | normSquare += d * d; |
242 | } |
243 | if ((unit == _unit) || (unit.equals(_unit))) |
244 | return Math.sqrt(normSquare); |
245 | return _unit.getConverterTo(unit).convert(Math.sqrt(normSquare)); |
246 | } |
247 | |
248 | @Override |
249 | public Unit<Q> getUnit() { |
250 | return _unit; |
251 | } |
252 | |
253 | @Override |
254 | public double[] getValue() { |
255 | return _components.clone(); |
256 | } |
257 | |
258 | @Override |
259 | public MultiDimensional<Q> to(Unit<Q> unit) { |
260 | if ((unit == _unit) || (unit.equals(_unit))) |
261 | return this; |
262 | UnitConverter cvtr = _unit.getConverterTo(unit); |
263 | double[] newValues = new double[_components.length]; |
264 | for (int i=0; i < _components.length; i++) { |
265 | newValues[i] = cvtr.convert(_components[i]); |
266 | } |
267 | return new MultiDimensional<Q>(newValues, unit); |
268 | } |
269 | |
270 | private static final long serialVersionUID = 1L; |
271 | |
272 | } |
273 | } |