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 */ 009package javax.measure; 010 011import javax.measure.converter.UnitConverter; 012import javax.measure.quantity.Quantity; 013import javax.measure.unit.CompoundUnit; 014import 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 */ 045public abstract class VectorMeasure<Q extends Quantity> extends Measure<double[], Q> { 046 047 /** 048 * Default constructor (for sub-classes). 049 */ 050 protected VectorMeasure() { 051 } 052 053 /** 054 * Returns a 2-dimensional measurement vector. 055 * 056 * @param x the first vector component value. 057 * @param y the second vector component value. 058 * @param unit the measurement unit. 059 */ 060 public static <Q extends Quantity> VectorMeasure<Q> valueOf( 061 double x, double y, Unit<Q> unit) { 062 return new TwoDimensional<Q>(x, y, unit); 063 } 064 065 /** 066 * Returns a 3-dimensional measurement vector. 067 * 068 * @param x the first vector component value. 069 * @param y the second vector component value. 070 * @param z the third vector component value. 071 * @param unit the measurement unit. 072 */ 073 public static <Q extends Quantity> VectorMeasure<Q> valueOf( 074 double x, double y, double z, Unit<Q> unit) { 075 return new ThreeDimensional<Q>(x, y, z, unit); 076 } 077 078 /** 079 * Returns a multi-dimensional measurement vector. 080 * 081 * @param components the vector component values. 082 * @param unit the measurement unit. 083 */ 084 public static <Q extends Quantity> VectorMeasure<Q> valueOf(double[] components, 085 Unit<Q> unit) { 086 return new MultiDimensional<Q>(components, unit); 087 } 088 089 /** 090 * Returns the measurement vector equivalent to this one but stated in the 091 * specified unit. 092 * 093 * @param unit the new measurement unit. 094 * @return the vector measure stated in the specified unit. 095 */ 096 public abstract VectorMeasure<Q> to(Unit<Q> unit); 097 098 /** 099 * 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}