001/*
002 *   AbstractParamVector -- A partial implementation of a vector of Parameter objects.
003 *
004 *   Copyright (C) 2008-2015, by Joseph A. Huwaldt.
005 *   All rights reserved.
006 *   
007 *   This library is free software; you can redistribute it and/or
008 *   modify it under the terms of the GNU Lesser General Public
009 *   License as published by the Free Software Foundation; either
010 *   version 2 of the License, or (at your option) any later version.
011 *   
012 *   This library is distributed in the hope that it will be useful,
013 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
014 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015 *   Lesser General Public License for more details.
016 *
017 *   You should have received a copy of the GNU Lesser General Public License
018 *   along with this program; if not, write to the Free Software
019 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
020 *   Or visit:  http://www.gnu.org/licenses/lgpl.html
021 */
022package jahuwaldt.js.param;
023
024import java.text.MessageFormat;
025import java.util.ResourceBundle;
026import javax.measure.Measurable;
027import javax.measure.converter.ConversionException;
028import javax.measure.quantity.Angle;
029import javax.measure.quantity.Quantity;
030import javax.measure.unit.SI;
031import javax.measure.unit.Unit;
032import javolution.lang.MathLib;
033import javolution.lang.Realtime;
034import org.jscience.mathematics.structure.VectorSpaceNormed;
035import org.jscience.mathematics.vector.DimensionException;
036import org.jscience.mathematics.vector.Vector;
037
038/**
039 * This class represents an n-dimensional {@link Vector vector} of {@link Parameter}
040 * elements.
041 * 
042 * <p> Modified by: Joseph A. Huwaldt </p>
043 * 
044 * @author Joseph A. Huwaldt, Date: November 21, 2008
045 * @version October 31, 2015
046 *
047 * @param <Q> The Quantity (unit type, such as Length or Volume) of this parameter.
048 * @param <T> The type of AbstractParamVector.
049 */
050public abstract class AbstractParamVector<Q extends Quantity, T extends AbstractParamVector<Q, T>> extends
051        Vector<Parameter<Q>> implements
052        VectorSpaceNormed<Vector<Parameter<Q>>, Parameter<Q>>, Measurable<Q>, Realtime {
053
054    /**
055     * The resource bundle for this package.
056     */
057    protected static final ResourceBundle RESOURCES = Parameter.RESOURCES;
058
059    /**
060     * Returns a Vector3D representation of this vector if possible.
061     *
062     * @return A Vector3D that is equivalent to this vector
063     * @throws DimensionException if this vector has any number of dimensions other than
064     * 3.
065     */
066    public abstract Vector3D<Q> toVector3D();
067
068    /**
069     * Return the specified {@link Vector3D} object as a vector of a particular subtype of
070     * this class.
071     *
072     * @param vector The <code>Vector3D</code> object to be converted to a specific subtype
073     *               of this class.
074     * @return An instance of a specific subtype of this class that is equivalent to the
075     *         supplied <code>Vector3D</code> object.
076     * @throws ConversionException if the sub-type can not represent the units used in the
077     * supplied vector.
078     */
079    public abstract T fromVector3D(Vector3D<Q> vector) throws ConversionException;
080
081    /**
082     * Returns the value of the Parameter in this vector as a <code>double</code> in the
083     * current units of the specified dimension of this vector.
084     *
085     * @param i the dimension index.
086     * @return the value of the Parameter at <code>i</code>.
087     * @throws IndexOutOfBoundsException <code>(i &lt; 0) || (i > dimension()-1)</code>
088     */
089    public double getValue(int i) {
090        return get(i).getValue();
091    }
092
093    /**
094     * Returns the Euclidian norm, magnitude, or length of this vector (square root of the
095     * dot product of this vector and itself).
096     *
097     * @return <code>sqrt(this · this)</code>.
098     */
099    @Override
100    public Parameter<Q> norm() {
101        return Parameter.valueOf(normValue(), getUnit());
102    }
103
104    /**
105     * Returns the {@link #norm}, magnitude, or length value of this vector.
106     *
107     * @return <code>this.norm().getValue()</code>.
108     */
109    public abstract double normValue();
110
111    /**
112     * Returns the Euclidian norm, magnitude, or length of this vector (square root of the
113     * dot product of this vector and itself).
114     *
115     * @return <code>sqrt(this · this)</code>.
116     */
117    public Parameter<Q> mag() {
118        return norm();
119    }
120
121    /**
122     * Returns the {@link #norm}, magnitude, or length value of this vector.
123     *
124     * @return <code>this.norm().doubleValue()</code>.
125     */
126    public double magValue() {
127        return normValue();
128    }
129
130    /**
131     * Returns the sum of this vector with the parameter specified. The unit of the output
132     * vector will be the units of this vector.
133     *
134     * @param that the parameter to be added to this vector.
135     * @return <code>this + that</code>.
136     */
137    public abstract T plus(Parameter<Q> that);
138
139    /**
140     * Subtracts the supplied Parameter from this vector. The unit of the output vector
141     * will be the units of this vector.
142     *
143     * @param that the Parameter to be subtracted from this vector.
144     * @return <code>this - that</code>.
145     */
146    public abstract T minus(Parameter<Q> that);
147
148    /**
149     * Returns the product of this vector with the specified coefficient.
150     *
151     * @param k the coefficient multiplier.
152     * @return <code>this · k</code>
153     */
154    public abstract T times(double k);
155
156    /**
157     * Returns the dot product of this vector with the one specified.
158     *
159     * @param that the vector multiplier.
160     * @return <code>this · that</code>
161     * @throws DimensionException if <code>this.dimension() != that.dimension()</code>
162     * @see <a href="http://en.wikipedia.org/wiki/Dot_product">
163     * Wikipedia: Dot Product</a>
164     */
165    public Parameter<?> dot(Vector that) {
166        return times(that);
167    }
168
169    /**
170     * Returns this vector with each element divided by the specified divisor
171     * (dimensionless).
172     *
173     * @param divisor the divisor.
174     * @return <code>this / divisor</code>.
175     */
176    public T divide(double divisor) {
177        return times(1. / divisor);
178    }
179
180    /**
181     * Returns the angle between this vector and the specified vector.
182     *
183     * @param that the vector to which the angle will be determined.
184     * @return <code>acos(this · that)/(norm(this)*norm(that))</code>
185     */
186    public Parameter<Angle> angle(AbstractParamVector that) {
187        double scalar = this.times(that).getValue();
188        double abs1 = this.normValue();
189        double abs2 = that.to(this.getUnit()).normValue();
190
191        double argument = 1.;
192        double dum = abs1 * abs2;
193        if (dum > Parameter.SQRT_EPS)
194            argument = scalar / dum;
195
196        if (argument > 1.)
197            argument = 1.;
198        else if (argument < -1.)
199            argument = -1.;
200
201        return Parameter.valueOf(MathLib.acos(argument), SI.RADIAN);
202    }
203
204    /**
205     * Returns the unit in which the values in this vector are stated.
206     *
207     * @return The unit in which the values in this vector are stated
208     */
209    public abstract Unit<Q> getUnit();
210
211    /**
212     * Returns the equivalent to this vector but stated in the specified unit.
213     *
214     * @param <R>  The Quantity (unit type) of the vector being output.
215     * @param unit the unit of the vector to be returned.
216     * @return a vector equivalent to this vector but stated in the specified unit.
217     * @throws ConversionException if the current model does not allows for conversion to
218     * the specified unit.
219     */
220    public abstract <R extends Quantity> AbstractParamVector<R, ? extends AbstractParamVector> to(Unit<R> unit);
221
222    /**
223     * Returns the value of this measurable stated in the specified unit as a
224     * <code>double</code>. This implementation returns the {@link #normValue} stated in
225     * the specified units.
226     *
227     * @param unit the unit in which this measurable value is stated.
228     * @return the numeric value after conversion to type <code>double</code>.
229     */
230    @Override
231    public double doubleValue(Unit<Q> unit) {
232        Unit<?> thisUnit = getUnit();
233        return ((thisUnit == unit) || thisUnit.equals(unit)) ? this.normValue() : this.to(unit).normValue();
234    }
235
236    /**
237     * Returns the estimated integral value of this measurable stated in the specified
238     * unit as a <code>long</code>. This implementation returns the {@link #normValue}
239     * stated in the specified units.
240     *
241     * <p>
242     * Note: This method differs from the <code>Number.longValue()</code> in the sense
243     * that the closest integer value is returned and an ArithmeticException is raised
244     * instead of a bit truncation in case of overflow (safety critical).</p>
245     *
246     * @param unit the unit in which the measurable value is stated.
247     * @return the numeric value after conversion to type <code>long</code>.
248     * @throws ArithmeticException if this quantity cannot be represented as a
249     * <code>long</code> number in the specified unit.
250     */
251    @Override
252    public final long longValue(Unit<Q> unit) {
253        if (!getUnit().equals(unit))
254            return this.to(unit).longValue(unit);
255        double doubleValue = this.normValue();
256        if ((doubleValue >= Long.MIN_VALUE) && (doubleValue <= Long.MAX_VALUE))
257            return Math.round(doubleValue);
258        throw new ArithmeticException(
259                MessageFormat.format(RESOURCES.getString("canNotBeLong"), doubleValue, getUnit()));
260    }
261
262    /**
263     * Compares the {@link #norm} of this measure with the specified measurable object.
264     *
265     * @param that the measure to compare with.
266     * @return a negative integer, zero, or a positive integer as this measure is less
267     *         than, equal to, or greater than that measurable.
268     * @throws ConversionException if the current model does not allows for these measure
269     * to be compared.
270     */
271    @Override
272    public int compareTo(Measurable<Q> that) {
273        double thatValue = that.doubleValue(getUnit());
274        return Double.compare(this.normValue(), thatValue);
275    }
276
277    /**
278     * Fills the input Java array with the values of the coordinates of this vector in
279     * the current units.
280     * 
281     * @param array An existing array of at least this.getDimension() size that will be
282     * filled with the values from this vector.
283     * @return The input Java array filled with the coordinate values from this vector.
284     */
285    public double[] toArray(double[] array) {
286        int size = this.getDimension();
287        for (int i=size-1; i >= 0; --i) {
288            array[i] = this.getValue(i);
289        }
290        return array;
291    }
292    
293    /**
294     * Returns a new Java array that contains the values of the coordinates of this vector in
295     * the current units.
296     * 
297     * @return A new Java array of values from this vector.
298     */
299    public double[] toArray() {
300        double[] arr = new double[this.getDimension()];
301        return toArray(arr);
302    }
303}