001/**
002 * Vector -- Holds the floating point coordinates of an nD vector.
003 *
004 * Copyright (C) 2009-2016, Joseph A. Huwaldt. All rights reserved.
005 *
006 * This library is free software; you can redistribute it and/or modify it under the terms
007 * of the GNU Lesser General Public License as published by the Free Software Foundation;
008 * either version 2.1 of the License, or (at your option) any later version.
009 *
010 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
011 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
012 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
013 *
014 * You should have received a copy of the GNU Lesser General Public License along with
015 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place -
016 * Suite 330, Boston, MA 02111-1307, USA. Or visit: http://www.gnu.org/licenses/lgpl.html
017 */
018package geomss.geom;
019
020import jahuwaldt.js.param.Parameter;
021import jahuwaldt.js.param.ParameterVector;
022import java.text.MessageFormat;
023import java.util.List;
024import static java.util.Objects.nonNull;
025import static java.util.Objects.isNull;
026import static java.util.Objects.requireNonNull;
027import javax.measure.converter.ConversionException;
028import javax.measure.converter.UnitConverter;
029import javax.measure.quantity.Dimensionless;
030import javax.measure.quantity.Length;
031import javax.measure.quantity.Quantity;
032import javax.measure.unit.Unit;
033import javolution.context.ArrayFactory;
034import javolution.context.ObjectFactory;
035import javolution.lang.MathLib;
036import javolution.lang.ValueType;
037import javolution.util.FastTable;
038import javolution.xml.XMLFormat;
039import javolution.xml.stream.XMLStreamException;
040import org.jscience.mathematics.number.Float64;
041import org.jscience.mathematics.vector.Float64Vector;
042
043/**
044 * A container that holds the coordinates of an n-dimensional vector which indicates
045 * direction, but not position.
046 * 
047 * <p> Modified by: Joseph A. Huwaldt </p>
048 * 
049 * @author Joseph A. Huwaldt, Date: June 13, 2009
050 * @version September 10, 2016
051 *
052 * @param <Q> The Quantity (unit type) associated with this vector's coordinate values.
053 */
054@SuppressWarnings({"serial", "CloneableImplementsClone"})
055public final class Vector<Q extends Quantity> extends GeomVector<Q> implements ValueType {
056
057    /**
058     * The coordinate values are stored in this array.
059     */
060    private transient double[] _data;
061
062    /**
063     * The number of dimensions in the data.
064     */
065    private int _numDims;
066
067    /**
068     * Holds the unit of the coordinates.
069     */
070    private Unit<Q> _unit;
071
072    //  The origin for this vector.
073    private Point _origin;
074
075    /**
076     * Returns a dimensionless <code>Vector</code> instance of the specified dimension
077     * with all the coordinate values set to zero.
078     *
079     * @param numDims the physical dimension of the vector to create.
080     * @return the dimensionless vector having the specified dimension and zeros for
081     *         values.
082     */
083    public static Vector<Dimensionless> newInstance(int numDims) {
084        Vector V = Vector.newInstancePvt(numDims, Dimensionless.UNIT);
085        
086        for (int i = 0; i < numDims; ++i)
087            V._data[i] = 0;
088
089        return V;
090    }
091
092    /**
093     * Returns a <code>Vector</code> instance of the specified dimension and units with
094     * all the coordinate values set to zero.
095     *
096     * @param <Q>     The Quantity (unit type) associated with the new vector's coordinate
097     *                values.
098     * @param numDims the physical dimension of the vector to create.
099     * @param unit    the unit in which the coordinates are stated. May not be null.
100     * @return the vector having the specified dimension and zero meters for values.
101     */
102    public static <Q extends Quantity> Vector<Q> newInstance(int numDims, Unit<Q> unit) {
103        Vector V = Vector.newInstancePvt(numDims, unit);
104
105        for (int i = 0; i < numDims; ++i)
106            V._data[i] = 0;
107
108        return V;
109    }
110
111    /**
112     * Returns a <code>Vector</code> instance containing the specified GeomVector values.
113     *     
114     * @param <Q>    The Quantity (unit type) associated with the new vector's coordinate
115     *               values.
116     * @param vector The GeomVector to be placed in a new Vector instance. May not be null.
117     * @return the vector having the specified values.
118     */
119    public static <Q extends Quantity> Vector<Q> valueOf(GeomVector<Q> vector) {
120        if (vector instanceof Vector)
121            return (Vector<Q>)vector;
122
123        Vector V = Vector.newInstancePvt(vector);
124
125        int numDims = V._numDims;
126        for (int i = 0; i < numDims; ++i)
127            V._data[i] = vector.getValue(i);
128
129        return V;
130    }
131
132    /**
133     * Returns a dimensionless <code>Vector</code> instance holding the specified
134     * <code>double</code> value or values.
135     *
136     * @param x the dimensionless coordinate values. May not be null.
137     * @return the vector having the specified value and dimensionless units.
138     */
139    public static Vector<Dimensionless> valueOf(double... x) {
140        int numDims = x.length;
141        Vector V = Vector.newInstancePvt(numDims, Dimensionless.UNIT);
142
143        for (int i = 0; i < numDims; ++i)
144            V._data[i] = x[i];
145
146        return V;
147    }
148
149    /**
150     * Returns a <code>Vector</code> instance holding the specified <code>double</code>
151     * value or values stated in the specified units.
152     *     
153     * @param <Q>  The Quantity (unit type) associated with the new vector's coordinate
154     *             values.
155     * @param unit the unit in which the coordinates are stated. May not be null.
156     * @param x    the coordinate values stated in the specified unit. May not be null.
157     * @return the vector having the specified value.
158     */
159    public static <Q extends Quantity> Vector<Q> valueOf(Unit<Q> unit, double... x) {
160        int numDims = x.length;
161        Vector V = Vector.newInstancePvt(numDims, unit);
162
163        for (int i = 0; i < numDims; ++i)
164            V._data[i] = x[i];
165
166        return V;
167    }
168
169    /**
170     * Returns a <code>Vector</code> instance containing the specified vector of Parameter
171     * values with compatible units. All the values are converted to the same units as the
172     * 1st value.
173     *     
174     * @param <Q>    The Quantity (unit type) associated with the new vector's coordinate
175     *               values.
176     * @param vector the vector of Parameter values stated in the specified unit. May not be null.
177     * @return the vector having the specified values.
178     */
179    public static <Q extends Quantity> Vector<Q> valueOf(org.jscience.mathematics.vector.Vector<Parameter<Q>> vector) {
180        int numDims = vector.getDimension();
181        Unit<Q> unit = vector.get(0).getUnit();
182        Vector V = Vector.newInstancePvt(numDims, unit);
183
184        for (int i = 0; i < numDims; ++i)
185            V._data[i] = vector.get(i).getValue(unit);
186
187        return V;
188    }
189
190    /**
191     * Returns a <code>Vector</code> instance containing the specified list of Parameter
192     * values with compatible units. All the values are converted to the same units as the
193     * 1st value.
194     *
195     * @param <Q>    The Quantity (unit type) associated with the new vector's coordinate
196     *               values.
197     * @param values the list of Parameter values stated in the specified unit. May not be
198     *               null.
199     * @return the vector having the specified values.
200     */
201    public static <Q extends Quantity> Vector<Q> valueOf(List<Parameter<Q>> values) {
202        int numDims = values.size();
203        Unit<Q> unit = values.get(0).getUnit();
204        Vector<Q> V = Vector.newInstancePvt(numDims, unit);
205
206        for (int i = 0; i < numDims; ++i)
207            V._data[i] = values.get(i).getValue(unit);
208
209        return V;
210    }
211
212    /**
213     * Returns a {@link Vector} instance containing the specified vector of Float64 values
214     * stated in the specified units.
215     *
216     * @param <Q>    The Quantity (unit type) associated with the new vector's coordinate
217     *               values.
218     * @param vector the vector of Float64 values stated in the specified unit. May not be
219     *               null.
220     * @param unit   The unit in which the coordinates are stated. May not be null.
221     * @return the vector having the specified values.
222     */
223    public static <Q extends Quantity> Vector<Q> valueOf(org.jscience.mathematics.vector.Vector<Float64> vector, Unit<Q> unit) {
224        int numDims = vector.getDimension();
225        Vector V = Vector.newInstancePvt(numDims, unit);
226
227        for (int i = 0; i < numDims; ++i)
228            V._data[i] = vector.get(i).doubleValue();
229
230        return V;
231    }
232
233    /**
234     * Returns a <code>Vector</code> instance holding the specified <code>Parameter</code>
235     * values. All the values are converted to the same units as the first value.
236     *     
237     * @param <Q>    The Quantity (unit type) associated with the new vector's coordinate
238     *               values.
239     * @param values A list of values to store in the vector. May not be null.
240     * @return the vector having the specified values in the units of x.
241     */
242    public static <Q extends Quantity> Vector<Q> valueOf(Parameter<Q>... values) {
243        int numDims = values.length;
244        Unit<Q> unit = values[0].getUnit();
245        Vector V = Vector.newInstancePvt(numDims, unit);
246
247        for (int i = 0; i < numDims; ++i)
248            V._data[i] = values[i].getValue(unit);
249
250        return V;
251    }
252
253    /**
254     * Returns a <code>Vector</code> instance holding the specified <code>GeomPoint</code>
255     * values.
256     *
257     * @param point A point who's coordinates are to be stored in the vector (making it a
258     *              position vector). May not be null.
259     * @return the vector having the specified point coordinate values in it.
260     */
261    public static Vector<Length> valueOf(GeomPoint point) {
262        int numDims = point.getPhyDimension();
263        Unit<Length> unit = point.getUnit();
264        Vector V = Vector.newInstancePvt(numDims, unit);
265
266        Point pnt = point.immutable();
267        for (int i = 0; i < numDims; ++i)
268            V._data[i] = pnt.getValue(i, unit);
269        V._origin = pnt;
270
271        return V;
272    }
273
274    /**
275     * Returns the number of physical dimensions of this vector.
276     *
277     * @return The number of physical dimensions of this vector.
278     */
279    @Override
280    public int getPhyDimension() {
281        return _numDims;
282    }
283
284    /**
285     * Returns the value of the Parameter in this vector as a <code>double</code>, stated
286     * in this vector's {@link #getUnit unit}.
287     *
288     * @param i the dimension index.
289     * @return the value of the Parameter at <code>i</code>.
290     * @throws IndexOutOfBoundsException
291     * <code>(i &lt; 0) || (i &ge; getPhyDimension())</code>
292     */
293    @Override
294    public double getValue(int i) {
295        return _data[i];
296    }
297
298    /**
299     * Returns the value of the Parameter in this vector as a <code>double</code>, stated
300     * in the specified units.
301     *
302     * @param i    the dimension index.
303     * @param unit the unit to return the value in. May not be null.
304     * @return the value of the Parameter at <code>i</code> in the specified unit.
305     * @throws IndexOutOfBoundsException
306     * <code>(i &lt; 0) || (i &ge; getPhyDimension())</code>
307     */
308    @Override
309    public double getValue(int i, Unit<Q> unit) {
310        double value = _data[i];
311        Unit<Q> thisUnit = getUnit();
312        if (unit.equals(thisUnit))
313            return value;
314        UnitConverter cvtr = Parameter.converterOf(thisUnit, unit);
315        if (cvtr == UnitConverter.IDENTITY) { // No conversion necessary.
316            return value;
317        }
318        return cvtr.convert(value);
319    }
320
321    /**
322     * Set the origin point for this vector. The origin is used as a reference for drawing
323     * the vector and is <i>not</i> a part of the state of this vector and is not used in
324     * any calculations with this vector.
325     * 
326     * @param origin The point to use as the origin of this vector (may not be null).
327     */
328    @Override
329    public void setOrigin(Point origin) {
330        requireNonNull(origin, MessageFormat.format(RESOURCES.getString("paramNullErr"), "origin"));
331        _origin = origin;
332    }
333
334    /**
335     * Return the origin point for this vector. If no origin has been explicitly set,
336     * then the coordinate system origin in the default units is returned.
337     *
338     * @return The origin point for this vector.
339     */
340    @Override
341    public Point getOrigin() {
342        if (isNull(_origin))
343            return Point.newInstance(getPhyDimension());
344        return _origin;
345    }
346
347    /**
348     * Returns the {@link #norm}, magnitude, or length value of this vector (square root
349     * of the dot product of this vector and itself).
350     *
351     * @return <code>this.norm().doubleValue()</code>.
352     */
353    @Override
354    public double normValue() {
355        double[] data = _data;
356        double s2 = data[0];
357        s2 *= s2;
358        for (int i = 1; i < _numDims; ++i) {
359            double vi = data[i];
360            s2 += vi * vi;
361        }
362        return MathLib.sqrt(s2);
363    }
364
365    /**
366     * Returns the negation of this vector.
367     *
368     * @return <code>-this</code>.
369     */
370    @Override
371    public Vector<Q> opposite() {
372        Vector V = newInstancePvt(this);
373
374        int numDims = _numDims;
375        double[] thisData = this._data;
376        for (int i = 0; i < numDims; ++i)
377            V._data[i] = -thisData[i];
378
379        return V;
380    }
381
382    /**
383     * Returns the sum of this vector with the one specified. The unit of the output
384     * vector will be the units of this vector.
385     *
386     * @param that the vector to be added. May not be null.
387     * @return <code>this + that</code>.
388     * @throws DimensionException if vector dimensions are different.
389     */
390    @Override
391    public Vector<Q> plus(GeomVector<Q> that) {
392        int numDims = _numDims;
393        if (that.getPhyDimension() != numDims)
394            throw new DimensionException(RESOURCES.getString("dimensionErr"));
395        Unit<Q> unit = _unit;
396
397        Vector V = newInstancePvt(this);
398        double[] thisData = this._data;
399        for (int i = 0; i < numDims; ++i)
400            V._data[i] = thisData[i] + that.getValue(i, unit);
401
402        return V;
403    }
404
405    /**
406     * Returns the sum of this vector with the parameter specified. The input parameter is
407     * added to each component of this vector. The unit of the output vector will be the
408     * units of this vector.
409     *
410     * @param that the parameter to be added to each element of this vector. May not be
411     *             null.
412     * @return <code>this + that</code>.
413     */
414    @Override
415    public Vector<Q> plus(Parameter<Q> that) {
416        int numDims = _numDims;
417        Unit<Q> unit = _unit;
418
419        //  Convert input parameter to the units of this vector.
420        double thatValue = that.getValue(unit);
421
422        Vector V = newInstancePvt(this);
423        double[] thisData = this._data;
424        for (int i = 0; i < numDims; ++i)
425            V._data[i] = thisData[i] + thatValue;
426
427        return V;
428    }
429
430    /**
431     * Returns the difference between this vector and the one specified. The unit of the
432     * output vector will be the units of this vector.
433     *
434     * @param that the vector to be subtracted from this vector. May not be null.
435     * @return <code>this - that</code>.
436     * @throws DimensionException if vector dimensions are different.
437     */
438    @Override
439    public Vector<Q> minus(GeomVector<Q> that) {
440        int numDims = _numDims;
441        if (that.getPhyDimension() != numDims)
442            throw new DimensionException(RESOURCES.getString("dimensionErr"));
443        Unit<Q> unit = _unit;
444
445        Vector V = newInstancePvt(this);
446        double[] thisData = this._data;
447        for (int i = 0; i < numDims; ++i)
448            V._data[i] = thisData[i] - that.getValue(i, unit);
449
450        return V;
451    }
452
453    /**
454     * Subtracts the supplied Parameter from each element of this vector and returns the
455     * result. The unit of the output vector will be the units of this vector.
456     *
457     * @param that the Parameter to be subtracted from each element of this vector. May
458     *             not be null.
459     * @return <code>this - that</code>.
460     */
461    @Override
462    public Vector<Q> minus(Parameter<Q> that) {
463        int numDims = _numDims;
464        Unit<Q> unit = _unit;
465
466        //  Convert input parameter to the units of this vector.
467        double thatValue = that.getValue(unit);
468
469        Vector V = newInstancePvt(this);
470        double[] thisData = this._data;
471        for (int i = 0; i < numDims; ++i)
472            V._data[i] = thisData[i] - thatValue;
473
474        return V;
475    }
476
477    /**
478     * Returns the product of this vector with the specified coefficient (dimensionless).
479     *
480     * @param k the coefficient multiplier.
481     * @return <code>this · k</code>
482     */
483    @Override
484    public Vector<Q> times(double k) {
485        Vector V = newInstancePvt(this);
486
487        int numDims = _numDims;
488        double[] thisData = this._data;
489        for (int i = 0; i < numDims; ++i)
490            V._data[i] = thisData[i] * k;
491
492        return V;
493    }
494
495    /**
496     * Returns the product of this vector with the specified coefficient.
497     *
498     * @param k the coefficient multiplier. May not be null.
499     * @return <code>this · k</code>
500     */
501    @Override
502    public Vector<? extends Quantity> times(Parameter<?> k) {
503        int numDims = _numDims;
504        Unit unit = Parameter.productOf(this.getUnit(), k.getUnit());
505
506        double thatValue = k.getValue();
507
508        Vector V = newInstancePvt(numDims, unit);
509        double[] thisData = this._data;
510        for (int i = 0; i < numDims; ++i)
511            V._data[i] = thisData[i] * thatValue;
512        V._origin = _origin;
513
514        return V;
515    }
516
517    /**
518     * Returns the dot product (scalar product) of this vector with the one specified.
519     *
520     * @param that the vector multiplier. May not be null.
521     * @return <code>this · that</code>
522     * @throws DimensionException if <code>this.dimension() != that.dimension()</code>
523     * @see <a href="http://en.wikipedia.org/wiki/Dot_product">
524     * Wikipedia: Dot Product</a>
525     */
526    @Override
527    public Parameter<? extends Quantity> times(GeomVector<?> that) {
528        int numDims = _numDims;
529        if (that.getPhyDimension() != numDims)
530            throw new DimensionException(RESOURCES.getString("dimensionErr"));
531        Unit unit = Parameter.productOf(this.getUnit(), that.getUnit());
532
533        Float64 s = this.toFloat64Vector().times(that.toFloat64Vector());
534
535        return Parameter.valueOf(s.doubleValue(), unit);
536    }
537
538    /**
539     * Returns the element-by-element product of this vector with the one specified.
540     *
541     * @param that the vector multiplier. May not be null.
542     * @return <code>this .* that</code>
543     * @throws DimensionException if <code>this.dimension() != that.dimension()</code>
544     */
545    @Override
546    public Vector<? extends Quantity> timesEBE(GeomVector<?> that) {
547        int numDims = _numDims;
548        if (that.getPhyDimension() != numDims)
549            throw new DimensionException(RESOURCES.getString("dimensionErr"));
550        Unit unit = Parameter.productOf(this.getUnit(), that.getUnit());
551
552        Vector V = newInstancePvt(numDims, unit);
553        double[] thisData = this._data;
554        for (int i = 0; i < numDims; ++i)
555            V._data[i] = thisData[i] * that.getValue(i);
556        V._origin = _origin;
557
558        return V;
559    }
560
561    /**
562     * Returns the cross product of two vectors.
563     *
564     * @param that the vector multiplier. May not be null.
565     * @return <code>this x that</code>
566     * @throws DimensionException if
567     * <code>(that.getDimension() != this.getDimension())</code>
568     * @see <a href="http://en.wikipedia.org/wiki/Cross_product">
569     * Wikipedia: Cross Product</a>
570     */
571    @Override
572    public Vector<? extends Quantity> cross(GeomVector<?> that) {
573        int numDims = _numDims;
574        if (that.getPhyDimension() != numDims)
575            throw new DimensionException(RESOURCES.getString("dimensionErr"));
576        Unit unit = Parameter.productOf(this.getUnit(), that.getUnit());
577
578        Float64Vector xv = this.toFloat64Vector().cross(that.toFloat64Vector());
579
580        Vector V = Vector.valueOf(xv, unit);
581        V._origin = _origin;
582
583        return V;
584    }
585
586    /**
587     * Returns this vector with each element divided by the specified divisor
588     * (dimensionless).
589     *
590     * @param divisor the divisor.
591     * @return <code>this / divisor</code>.
592     */
593    @Override
594    public Vector<Q> divide(double divisor) {
595        return times(1.0 / divisor);
596    }
597
598    /**
599     * Returns this vector with each element divided by the specified divisor.
600     *
601     * @param divisor the divisor. May not be null.
602     * @return <code>this / divisor</code>.
603     */
604    @Override
605    public Vector<? extends Quantity> divide(Parameter<?> divisor) {
606        return times(divisor.inverse());
607    }
608
609    /**
610     * Return an immutable version of this vector.
611     *
612     * @return An immutable version of this vector.
613     */
614    @Override
615    public Vector<Q> immutable() {
616        return this;
617    }
618
619    /**
620     * Returns this vector converted to a unit vector by dividing all the vector's
621     * elements by the length ({@link #norm}) of this vector.
622     *
623     * @return This vector converted to a unit vector by dividing all the vector's
624     *         elements by the length of this vector.
625     */
626    @Override
627    public Vector<Dimensionless> toUnitVector() {
628        double magnitude = this.normValue();
629        if (this.getUnit().equals(Dimensionless.UNIT) && MathLib.abs(magnitude - 1) <= Parameter.SQRT_EPS)
630            return (Vector<Dimensionless>)this;
631        //if (MathLib.abs(magnitude) <= Parameter.SQRT_EPS)
632        //    throw new ArithmeticException(RESOURCES.getString("zeroMagVector"));
633
634        int numDims = _numDims;
635        Vector V = newInstancePvt(numDims, Dimensionless.UNIT);
636        double[] thisData = this._data;
637        for (int i = 0; i < numDims; ++i)
638            V._data[i] = thisData[i] / magnitude;
639        V._origin = _origin;
640
641        return V;
642    }
643
644    /**
645     * Returns the unit in which the {@link #getValue values} in this vector are stated
646     * in.
647     *
648     * @return The units in which this vector is stated in.
649     */
650    @Override
651    public Unit getUnit() {
652        return _unit;
653    }
654
655    /**
656     * Returns the equivalent to this vector but stated in the specified unit.
657     *
658     * @param unit the unit of the vector to be returned. May not be null.
659     * @return an equivalent to this vector but stated in the specified unit.
660     * @throws ConversionException if the the input unit is not compatible with this unit.
661     */
662    @Override
663    public Vector to(Unit unit) {
664        if (_unit == unit || unit.equals(_unit))
665            return this;
666
667        UnitConverter cvtr = Parameter.converterOf(_unit, unit);
668        if (cvtr == UnitConverter.IDENTITY) { // No conversion necessary.
669            return this;
670        }
671
672        int numDims = _numDims;
673        Vector V = Vector.newInstancePvt(numDims, unit);
674        double[] thisData = this._data;
675        for (int i = 0; i < numDims; ++i)
676            V._data[i] = cvtr.convert(thisData[i]);
677        V._origin = _origin;
678
679        return V;
680    }
681
682    /**
683     * Return a copy of this vector converted to the specified number of physical
684     * dimensions. If the number of dimensions is greater than this element, then zeros
685     * are added to the additional dimensions. If the number of dimensions is less than
686     * this element, then the extra dimensions are simply dropped (truncated). If the new
687     * dimensions are the same as the dimension of this element, then this element is
688     * simply returned.
689     *
690     * @param newDim The dimension of the vector to return.
691     * @return A copy of this vector converted to the new dimensions.
692     */
693    @Override
694    public Vector<Q> toDimension(int newDim) {
695        if (newDim < 1)
696            throw new IllegalArgumentException(RESOURCES.getString("vectorDimGT0"));
697        int thisDim = this.getPhyDimension();
698        if (newDim == thisDim)
699            return this;
700
701        int numDims = newDim;
702        if (newDim > thisDim)
703            numDims = thisDim;
704
705        Vector<Q> V = Vector.newInstancePvt(newDim, _unit);
706        double[] thisData = this._data;
707        for (int i = 0; i < numDims; ++i)
708            V._data[i] = thisData[i];
709        for (int i = numDims; i < newDim; ++i)
710            V._data[i] = 0;
711        V._origin = (isNull(_origin) ? null : _origin.toDimension(newDim));
712
713        return V;
714    }
715
716    /**
717     * Returns a copy of this Vector instance
718     * {@link javolution.context.AllocatorContext allocated} by the calling thread
719     * (possibly on the stack).
720     *
721     * @return an identical and independent copy of this vector.
722     */
723    @Override
724    public Vector<Q> copy() {
725        return copyOf(this);
726    }
727
728    /**
729     * Return a copy of this object with any transformations or subranges removed
730     * (applied).
731     *
732     * @return A copy of this object with any transformations or subranges removed.
733     */
734    @Override
735    public Vector<Q> copyToReal() {
736        return copy();
737    }
738
739    /**
740     * Returns a <code>ParameterVector</code> representation of this vector.
741     *
742     * @return A ParameterVector that is equivalent to this vector.
743     */
744    @Override
745    public ParameterVector<Q> toParameterVector() {
746        return ParameterVector.valueOf(this.toFloat64Vector(), getUnit());
747    }
748
749    /**
750     * Returns a <code>Float64Vector</code> containing the elements of this vector stated
751     * in the current units.
752     *
753     * @return A Float64Vector that contains the elements of this vector in the current
754     *         units.
755     */
756    @Override
757    public Float64Vector toFloat64Vector() {
758        FastTable<Float64> table = FastTable.newInstance();
759        for (int i = 0; i < _numDims; ++i)
760            table.add(Float64.valueOf(_data[i]));
761
762        Float64Vector f64 = Float64Vector.valueOf(table);
763
764        FastTable.recycle(table);
765        return f64;
766    }
767
768    /**
769     * Compares this vector against the specified object for strict equality (same values
770     * and same units).
771     *
772     * @param obj the object to compare with.
773     * @return <code>true</code> if this vector is identical to that vector;
774     *         <code>false</code> otherwise.
775     */
776    @Override
777    public boolean equals(Object obj) {
778        if (this == obj)
779            return true;
780        if ((obj == null) || (obj.getClass() != this.getClass()))
781            return false;
782
783        Vector that = (Vector)obj;
784        if (this._numDims != that._numDims)
785            return false;
786        if (!this._unit.equals(that._unit))
787            return false;
788        for (int i = 0; i < _numDims; ++i)
789            if (this._data[i] != that._data[i])
790                return false;
791
792        return super.equals(obj);
793    }
794
795    /**
796     * Returns the hash code for this parameter.
797     *
798     * @return the hash code value.
799     */
800    @Override
801    public int hashCode() {
802        int hash = super.hashCode();
803
804        hash = hash * 31 + _unit.hashCode();
805        for (int i = 0; i < _numDims; ++i) {
806            hash = hash * 31 + makeVarCode(_data[i]);
807        }
808
809        return hash;
810    }
811
812    private static int makeVarCode(double value) {
813        long bits = Double.doubleToLongBits(value);
814        int var_code = (int)(bits ^ (bits >>> 32));
815        return var_code;
816    }
817    
818    /**
819     * Recycles a <code>Vector</code> instance immediately (on the stack when executing in
820     * a <code>StackContext</code>).
821     *
822     * @param instance The instance to be recycled.
823     */
824    public static void recycle(Vector instance) {
825        FACTORY.recycle(instance);
826    }
827
828    /**
829     * Holds the default XML representation for this object.
830     */
831    @SuppressWarnings("FieldNameHidesFieldInSuperclass")
832    protected static final XMLFormat<Vector> XML = new XMLFormat<Vector>(Vector.class) {
833
834        @Override
835        public Vector newInstance(Class<Vector> cls, InputElement xml) throws XMLStreamException {
836            return FACTORY.object();
837        }
838
839        @Override
840        public void read(InputElement xml, Vector obj) throws XMLStreamException {
841
842            //  Read in the units.
843            Unit unit = Unit.valueOf(xml.getAttribute("unit"));
844            if (!(Length.UNIT.isCompatible(unit) || Dimensionless.UNIT.isCompatible(unit)))
845                throw new XMLStreamException(
846                        MessageFormat.format(RESOURCES.getString("incompatibleUnits"),
847                                "Vector", "length"));
848            obj._unit = unit;
849
850            // Call parent read.
851            GeomVector.XML.read(xml, obj);
852
853            //  Read in the origin point (if it is there).
854            obj._origin = xml.get("Origin");
855            
856            //  Read in the vector components.
857            FastTable<Float64> valueList = FastTable.newInstance();
858            while (xml.hasNext()) {
859                Float64 value = xml.getNext();
860                valueList.add(value);
861            }
862            int numDims = valueList.size();
863            obj._numDims = numDims;
864            obj._data = ArrayFactory.DOUBLES_FACTORY.array(numDims);
865            for (int i = 0; i < numDims; ++i)
866                obj._data[i] = valueList.get(i).doubleValue();
867        }
868
869        @Override
870        public void write(Vector obj, OutputElement xml) throws XMLStreamException {
871            //  Write out the units.
872            xml.setAttribute("unit", obj.getUnit().toString());
873            
874            // Call parent write.
875            GeomVector.XML.write(obj, xml);
876
877            //  Write out the origin point if it is not the coordinate system origin.
878            Point o = obj._origin;
879            if (nonNull(o) && !o.isApproxEqual(Point.newInstance(obj._numDims)))
880                xml.add(obj._origin, "Origin");
881            
882            //  Write out the vector components.
883            int size = obj._numDims;
884            for (int i = 0; i < size; ++i)
885                xml.add(Float64.valueOf(obj._data[i]));
886            
887        }
888    };
889
890    /**
891     * Allocate a recyclable array that can contain Vector objects using factory methods.
892     * <p>
893     * WARNING: The array returned may <I>not</I> be zeroed. Any object references in the
894     * returned array must be assumed to be invalid. Also, the returned array may be
895     * larger than the requested size! The array returned by this method can be recycled
896     * by recycleArray().
897     * </p>
898     *
899     * @param size The minimum number of elements for the returned array to contain.
900     * @return An array that can contain Vector objects allocated using factory methods.
901     * @see #recycleArray
902     */
903    public static Vector[] allocateArray(int size) {
904        return VECTORARRAY_FACTORY.array(size);
905    }
906
907    /**
908     * Recycle an array of Vector objects that was created by Vector.allocateArray().
909     *
910     * @param arr The array to be recycled. The array must have been created by this the
911     *            allocateArray() method!
912     * @see #allocateArray
913     */
914    public static void recycleArray(Vector[] arr) {
915        VECTORARRAY_FACTORY.recycle(arr);
916    }
917    
918    ///////////////////////
919    // Factory creation. //
920    ///////////////////////
921    private static ArrayFactory<Vector[]> VECTORARRAY_FACTORY = new ArrayFactory<Vector[]>() {
922        @Override
923        protected Vector[] create(int size) {
924            return new Vector[size];
925        }
926    };
927
928    private Vector() { }
929
930    @SuppressWarnings("unchecked")
931    private static final ObjectFactory<Vector> FACTORY = new ObjectFactory<Vector>() {
932        @Override
933        protected Vector create() {
934            return new Vector();
935        }
936
937        @Override
938        protected void cleanup(Vector obj) {
939            obj.reset();
940        }
941    };
942
943    private static Vector newInstancePvt(int numDims, Unit unit) {
944        Vector V = FACTORY.object();
945        V._unit = requireNonNull(unit);
946        V._numDims = numDims;
947        V._data = ArrayFactory.DOUBLES_FACTORY.array(numDims);
948        V._origin = null;
949        return V;
950    }
951
952    private static Vector newInstancePvt(GeomVector original) {
953        int numDims = original.getPhyDimension();
954        Unit unit = original.getUnit();
955        Vector V = newInstancePvt(numDims, unit);
956        V._origin = original.getOrigin();
957        return V;
958    }
959
960    @SuppressWarnings("unchecked")
961    private static <Q extends Quantity> Vector<Q> copyOf(Vector<Q> original) {
962        Vector<Q> V = newInstancePvt(original);
963        System.arraycopy(original._data, 0, V._data, 0, original._numDims);
964        V._origin = (isNull(original._origin) ? null : original._origin.copy());
965        original.copyState(V);
966        return V;
967    }
968}