001/*
002*   ParameterVector -- A n-dimensional vector of Parameter objects.
003*
004*   Copyright (C) 2009-2014 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.util.List;
025
026import javax.measure.unit.Unit;
027import javax.measure.unit.SI;
028import javax.measure.unit.NonSI;
029import javax.measure.converter.UnitConverter;
030import javax.measure.converter.ConversionException;
031import javax.measure.quantity.*;
032
033import javolution.lang.MathLib;
034import javolution.context.ObjectFactory;
035import javolution.context.StackContext;
036import javolution.lang.ValueType;
037import javolution.util.FastTable;
038import javolution.xml.XMLFormat;
039import javolution.xml.stream.XMLStreamException;
040import javolution.xml.XMLSerializable;
041
042import org.jscience.mathematics.number.Float64;
043import org.jscience.mathematics.vector.*;
044
045
046/**
047* <p> This class represents an n-dimensional {@link Vector vector} of {@link Parameter}
048*       elements sharing the same units.</p>
049* 
050*  <p>  Modified by:  Joseph A. Huwaldt   </p>
051*
052*  @author  Joseph A. Huwaldt   Date: March 27, 2009
053*  @version March 1, 2014
054**/
055public class ParameterVector<Q extends Quantity> extends AbstractParamVector<Q,ParameterVector<Q>>
056                                        implements ValueType, XMLSerializable {
057
058        private static final long serialVersionUID = -1026285730707259617L;
059
060        /**
061        *  Constant used to identify the X (0) coordinate in the vector.
062        **/
063        public static final int X = 0;
064        
065        /**
066        *  Constant used to identify the Y (1) coordinate in the vector.
067        **/
068        public static final int Y = 1;
069        
070        /**
071        *  Constant used to identify the Z (2) coordinate in the vector.
072        **/
073        public static final int Z = 2;
074        
075
076        /**
077        *  The coordinates are stored in this vector.
078        *  Serialization is handled by this class since Float64Vector is not Serializable.
079        **/
080        protected transient Float64Vector _data;
081        
082        /**
083        *  Holds the unit of the coordinates.
084        **/
085        protected Unit<Q> _unit;
086        
087        
088        /**
089        * Returns a 2D {@link ParameterVector} instance holding the specified <code>double</code> values
090        * stated in the specified units.
091        *
092        * @param x the x value stated in the specified unit.
093        * @param y the y value stated in the specified unit.
094        * @param unit the unit in which the coordinates are stated.
095        * @return the vector having the specified values.
096        */
097        public static <Q extends Quantity> ParameterVector<Q> valueOf(double x, double y, Unit<Q> unit) {
098                ParameterVector<Q> V = newInstance(unit);
099                
100                V._data = Float64Vector.valueOf(x, y);
101                
102                return V;
103        }
104        
105        /**
106        * Returns a {@link ParameterVector} instance holding the specified <code>double</code> values
107        * stated in the specified units.
108        *
109        * @param x the x value stated in the specified unit.
110        * @param y the y value stated in the specified unit.
111        * @param z the z value stated in the specified unit.
112        * @param unit the unit in which the coordinates are stated.
113        * @return the vector having the specified values.
114        */
115        public static <Q extends Quantity> ParameterVector<Q> valueOf(double x, double y, double z, Unit<Q> unit) {
116                ParameterVector<Q> V = newInstance(unit);
117                
118                V._data = Float64Vector.valueOf(x, y, z);
119                
120                return V;
121        }
122
123        /**
124        * Returns a {@link ParameterVector} instance holding the specified <code>double</code> values
125        * stated in the specified units.
126        *
127        * @param unit the unit in which the coordinates are stated.
128        * @param values A list of values to store in the vector.
129        * @return the vector having the specified values.
130        */
131        public static <Q extends Quantity> ParameterVector<Q> valueOf(Unit<Q> unit, double... values) {
132                ParameterVector<Q> V = newInstance(unit);
133                
134                V._data = Float64Vector.valueOf(values);
135                
136                return V;
137        }
138
139        /**
140        * Returns a {@link ParameterVector} instance holding the specified <code>Parameter</code> values.
141        * All the values are converted to the same units as the x value.
142        *
143        * @param x the x value.
144        * @param y the y value.
145        * @param z the z value.
146        * @return the vector having the specified values in the units of x.
147        */
148        public static <Q extends Quantity> ParameterVector<Q> valueOf(Parameter<Q> x, Parameter<Q> y, Parameter<Q> z) {
149                
150                Unit<Q> unit = x.getUnit();
151                ParameterVector<Q> V = newInstance(unit);
152                V._data = Float64Vector.valueOf(x.getValue(), y.getValue(unit), z.getValue(unit));
153                
154                return V;
155        }
156
157        /**
158        * Returns a {@link ParameterVector} instance holding the specified <code>Parameter</code> values.
159        * All the values are converted to the same units as the first value.
160        *
161        * @param values A list of values to store in the vector.
162        * @return the vector having the specified values in the units of x.
163        */
164        public static <Q extends Quantity> ParameterVector<Q> valueOf(List<Parameter<Q>> values) {
165                FastTable<Float64> valueList = FastTable.newInstance();
166                
167                Unit<Q> unit = values.get(0).getUnit();
168        int size = values.size();
169        for (int i=0; i < size; ++i) {
170            Parameter<Q> param = values.get(i);
171                        Float64 value = Float64.valueOf(param.getValue(unit));
172                        valueList.add(value);
173                }
174                
175                ParameterVector<Q> V = newInstance(unit);
176                V._data = Float64Vector.valueOf(valueList);
177                
178                FastTable.recycle(valueList);
179                
180                return V;
181        }
182        
183        /**
184        * Returns a {@link ParameterVector} instance holding the specified <code>Parameter</code> values.
185        * All the values are converted to the same units as the first value.
186        *
187        * @param values A list of values to store in the vector.
188        * @return the vector having the specified values in the units of x.
189        */
190        public static <Q extends Quantity> ParameterVector<Q> valueOf(Parameter<Q>... values) {
191                FastTable<Float64> valueList = FastTable.newInstance();
192                
193                Unit<Q> unit = values[0].getUnit();
194        int size = values.length;
195        for (int i=0; i < size; ++i) {
196            Parameter<Q> param = values[i];
197                        Float64 value = Float64.valueOf(param.getValue(unit));
198                        valueList.add(value);
199                }
200                
201                ParameterVector<Q> V = newInstance(unit);
202                V._data = Float64Vector.valueOf(valueList);
203                
204                FastTable.recycle(valueList);
205                
206                return V;
207        }
208        
209        /**
210        * Returns a {@link ParameterVector} instance containing the specified vector of Float64 values
211        * stated in the specified units.
212        *
213        * @param vector the vector of Float64 values stated in the specified unit. 
214        * @param unit the unit in which the coordinates are stated.
215        * @return the vector having the specified values.
216        */
217        public static <Q extends Quantity> ParameterVector<Q> valueOf(Vector<Float64> vector, Unit<Q> unit) {
218                
219                ParameterVector<Q> V = newInstance(unit);
220                V._data = Float64Vector.valueOf(vector);
221                
222                return V;
223        }
224
225        /**
226        * Returns a {@link ParameterVector} instance containing the 
227        * specified vector of Parameter values with compatible units.
228        * All the values are converted to the same units as the 1st value.
229        *
230        * @param vector the vector of Parameter values stated in the specified unit. 
231        * @return the vector having the specified values.
232        */
233        public static <Q extends Quantity> ParameterVector<Q> valueOf(Vector<Parameter<Q>> vector) {
234                if (vector instanceof ParameterVector)
235                        return (ParameterVector<Q>)vector;
236                
237                Unit<Q> unit = vector.get(0).getUnit();         
238                FastTable<Float64> valueList = FastTable.newInstance();
239                
240                int size = vector.getDimension();
241                for (int i=0; i < size; ++i) {
242                        Parameter<Q> param = vector.get(i);
243                        Float64 value = Float64.valueOf(param.getValue(unit));
244                        valueList.add(value);
245                }
246                
247                ParameterVector<Q> V = newInstance(unit);
248                V._data = Float64Vector.valueOf(valueList);
249                
250                FastTable.recycle(valueList);
251                
252                return V;
253        }
254
255
256        /**
257        *  Returns a Vector3D representation of this vector if possible.
258        *
259        *  @return A Vector3D that is equivalent to this vector
260        *  @throws DimensionException if this vector has any number of dimensions
261        *          other than 3.
262        **/
263    @Override
264        public Vector3D<Q> toVector3D() {
265                if (getDimension() != 3)
266                        throw new DimensionException( RESOURCES.getString("pvNumElementsErr") );
267                return (Vector3D<Q>)Vector3D.valueOf(this);
268        }
269        
270        /**
271        *  Return the specified {@link Vector3D} object as a <code>ParameterVector</code> instance.
272        *
273        *  @param vector  The <code>Vector3D</code> object to be converted to a <code>ParameterVector</code>.
274        *  @return A <code>ParameterVector</code> instance that is equivalent to the
275        *          supplied <code>Vector3D</code> object.
276        **/
277    @Override
278        public ParameterVector<Q> fromVector3D(Vector3D<Q> vector) {
279                return (ParameterVector<Q>)ParameterVector.valueOf(vector);
280        }
281        
282        /**
283        * Returns the number of elements held by this vector.
284        *
285        * @return this vector dimension.
286        */
287        @Override
288        public int getDimension() {
289                return _data.getDimension();
290        }
291
292        /**
293        * Returns the value of a Parameter from this vector.
294        *
295        * @param  i the dimension index.
296        * @return the value of the parameter at <code>i</code>.
297        * @throws IndexOutOfBoundsException <code>(i < 0) || (i >= dimension())</code>
298        */
299        @Override
300        public Parameter<Q> get(int i) {
301                return Parameter.valueOf(getValue(i), getUnit());
302        }
303
304        /**
305        * Returns the value of the Parameter in this vector as a <code>double</code>,
306        * stated in this vector's {@link #getUnit unit}.
307        *
308        * @param  i the dimension index.
309        * @return the value of the Parameter at <code>i</code>.
310        * @throws IndexOutOfBoundsException <code>(i < 0) || (i >= dimension())</code>
311        */
312    @Override
313        public double getValue(int i) {
314                return _data.getValue(i);
315        }
316
317        /**
318        * Returns the {@link #norm}, magnitude, or length value of this vector.
319        *
320        * @return <code>this.norm().doubleValue()</code>.
321        */
322    @Override
323        public double normValue() {
324                return _data.normValue();
325        }
326
327        /**
328        * Returns the negation of this vector.
329        *
330        * @return <code>-this</code>.
331        */
332        @Override
333        public ParameterVector<Q> opposite() {
334                ParameterVector<Q> V = newInstance(this._unit);
335                V._data = this._data.opposite();
336                return V;
337        }
338
339        /**
340        * Returns the sum of this vector with the one specified.
341        * The unit of the output vector will be the units of
342        * this vector.
343        *
344        * @param   that the vector to be added.
345        * @return  <code>this + that</code>.
346        * @throws  DimensionException if vector dimensions are different.
347        * @throws  ConversionException if the input vector is not in units
348        *          consistent with this vector.
349        */
350        @Override
351        public ParameterVector<Q> plus(Vector<Parameter<Q>> that) {
352                
353                if (that.getDimension() != this.getDimension())
354                        throw new DimensionException();
355                
356                //      Convert input vector to a Float64Vector (with unit conversion if necessary).
357                Float64Vector thatData = toFloat64Vector(that, this._unit);
358                
359                ParameterVector<Q> V = newInstance(this._unit);
360                V._data = this._data.plus(thatData);
361                
362                return V;
363        }
364        
365        /**
366        * Returns the sum of this vector with the parameter specified.
367        * The input parameter is added to each component of this vector.
368        * The unit of the output vector will be the units of
369        * this vector.
370        *
371        * @param   that the parameter to be added to each element of this vector.
372        * @return  <code>this + that</code>.
373        */
374    @Override
375        public ParameterVector<Q> plus(Parameter<Q> that) {
376                
377                //      Convert input parameter to the units of this vector.
378                double thatValue = that.getValue(this._unit);
379                
380        StackContext.enter();
381        try {
382            FastTable<Float64> valueList = FastTable.newInstance();
383            int numDims = _data.getDimension();
384            for (int i = 0; i < numDims; ++i) {
385                double value = this._data.getValue(i) + thatValue;
386                valueList.add(Float64.valueOf(value));
387            }
388            ParameterVector<Q> V = newInstance(this._unit);
389            V._data = Float64Vector.valueOf(valueList);
390
391            return StackContext.outerCopy(V);
392        } finally {
393            StackContext.exit();
394        }
395        }
396        
397        /**
398        * Returns the difference between this vector and the one specified.
399        * The unit of the output vector will be the units of
400        * this vector.
401        *
402        * @param  that the vector to be subtracted.
403        * @return <code>this - that</code>.
404        * @throws  DimensionException if vector dimensions are different.
405        * @throws  ConversionException if the input vector is not in units
406        *          consistent with this vector.
407        */
408        @Override
409        public ParameterVector<Q> minus(Vector<Parameter<Q>> that) {
410                
411                if (that.getDimension() != this.getDimension())
412                        throw new DimensionException();
413                
414                //      Convert input vector to a Float64Vector (with unit conversion if necessary).
415                Float64Vector thatData = toFloat64Vector(that, this._unit);
416                
417                ParameterVector<Q> V = newInstance(this._unit);
418                V._data = this._data.minus(thatData);
419                
420                return V;
421        }
422
423        /**
424        * Subtracts the supplied Parameter from each element of this vector and returns
425        * the result.  The unit of the output vector will be the units of
426        * this vector.
427        *
428        * @param  that the Parameter to be subtracted from each element of this vector.
429        * @return <code>this - that</code>.
430        */
431    @Override
432        public ParameterVector<Q> minus(Parameter<Q> that) {
433                
434                //      Convert input parameter to the units of this vector.
435                double thatValue = that.getValue(this._unit);
436                
437        StackContext.enter();
438        try {
439            FastTable<Float64> valueList = FastTable.newInstance();
440            int numDims = _data.getDimension();
441            for (int i = 0; i < numDims; ++i) {
442                double value = this._data.getValue(i) - thatValue;
443                valueList.add(Float64.valueOf(value));
444            }
445            ParameterVector<Q> V = newInstance(this._unit);
446            V._data = Float64Vector.valueOf(valueList);
447
448            return StackContext.outerCopy(V);
449        } finally {
450            StackContext.exit();
451        }
452        }
453        
454        /**
455        * Returns the product of this vector with the specified coefficient.
456        *
457        * @param  k the coefficient multiplier.
458        * @return <code>this times k</code>
459        */
460        @Override
461        @SuppressWarnings({ "unchecked", "rawtypes" })
462        public ParameterVector times(Parameter k) {
463                ParameterVector V = FACTORY.object();
464                
465                V._unit = Parameter.productOf(this.getUnit(), k.getUnit());
466                V._data = this._data.times(k.getValue());
467
468                return V;
469        }
470        
471        /**
472        * Returns the product of this vector with the specified coefficient.
473        *
474        * @param  k the coefficient multiplier.
475        * @return <code>this times k</code>
476        */
477    @Override
478        public ParameterVector<Q> times(double k) {
479                ParameterVector<Q> V = newInstance(this._unit);
480                V._data = _data.times(k);
481                return V;
482        }       
483        
484        /**
485        * Returns the dot product of this vector with the one specified.
486        *
487        * @param  that the vector multiplier.
488        * @return <code>this times that</code>
489        * @throws DimensionException if <code>this.dimension() != that.dimension()</code>
490        * @see <a href="http://en.wikipedia.org/wiki/Dot_product">
491        *       Wikipedia: Dot Product</a>
492        */
493        @SuppressWarnings("rawtypes")
494        @Override
495        public Parameter times(Vector that) {
496                
497                if (that.getDimension() != this.getDimension())
498                        throw new DimensionException();
499                
500                //      Convert input vector to a Float64Vector.
501                @SuppressWarnings("unchecked")
502                Float64Vector thatData = toFloat64Vector(that, null);
503                
504                Float64 f = this._data.times(thatData);
505                Unit<?> unit = Parameter.productOf(this.getUnit(),((Parameter)that.get(X)).getUnit());
506                
507                return Parameter.valueOf(f.doubleValue(), unit);
508        }
509        
510        /**
511        * Returns the element-by-element product of this vector with the one specified.
512        *
513        * @param  that the vector multiplier.
514        * @return <code>this .* that</code>
515        * @throws DimensionException if <code>this.dimension() != that.dimension()</code>
516        */
517        @SuppressWarnings("rawtypes")
518        public ParameterVector timesEBE(Vector that) {
519                
520                if (that.getDimension() != this.getDimension())
521                        throw new DimensionException();
522                
523        StackContext.enter();
524        try {
525            //  Convert input vector to a Float64Vector.
526            @SuppressWarnings("unchecked")
527            Float64Vector thatData = toFloat64Vector(that, null);
528
529            Unit<?> unit = Parameter.productOf(this.getUnit(), ((Parameter) that.get(X)).getUnit());
530
531            //  Carry out the multiplication.
532            FastTable<Float64> valueList = FastTable.newInstance();
533            int size = getDimension();
534            for (int i = 0; i < size; ++i) {
535                double value = this._data.getValue(i) * thatData.getValue(i);
536                valueList.add(Float64.valueOf(value));
537            }
538
539            ParameterVector<?> V = newInstance(unit);
540            V._data = Float64Vector.valueOf(valueList);
541
542            return StackContext.outerCopy(V);
543        } finally {
544            StackContext.exit();
545        }
546        }
547        
548        /**
549        * Returns the cross product of two vectors.
550        *
551        * @param  that the vector multiplier.
552        * @return <code>this x that</code>
553        * @throws DimensionException if <code>(that.getDimension() != this.getDimension())</code> 
554        * @see <a href="http://en.wikipedia.org/wiki/Cross_product">
555        *         Wikipedia: Cross Product</a>
556        */
557        @SuppressWarnings({ "unchecked", "rawtypes" })
558        @Override
559        public ParameterVector cross(Vector that) {
560                
561                if (that.getDimension() != this.getDimension())
562                        throw new DimensionException();
563                
564                //      Convert input vector to a Float64Vector.
565                Float64Vector thatData = toFloat64Vector(that, null);
566                
567                Unit<?> unit = Parameter.productOf(this.getUnit(), ((Parameter)that.get(X)).getUnit());
568                
569                ParameterVector V = newInstance(unit);
570                V._data = this._data.cross(thatData);
571
572                return V;
573        }
574        
575        /**
576        * Returns this vector with each element divided by the specified divisor.
577        *
578        * @param  that the divisor.
579        * @return <code>this / that</code>.
580        */
581        public ParameterVector<?> divide(Parameter<?> that) {
582                return times(that.inverse());
583        }
584
585        /**
586        *  Returns this vector converted to a unit vector by dividing all the
587        *  vector's elements by the length ({@link #norm}) of this vector.
588        **/
589        @SuppressWarnings("unchecked")
590        public ParameterVector<Dimensionless> toUnitVector() {
591                double magnitude = this.normValue();
592                if (this.getUnit().equals(Dimensionless.UNIT) && MathLib.abs(magnitude-1) <= Parameter.EPS)
593                        return (ParameterVector<Dimensionless>)this;
594                ParameterVector<Dimensionless> V = newInstance(Dimensionless.UNIT);
595                V._data = this._data.times(1.0/magnitude);
596                return V;
597        }
598        
599        /**
600        * Returns a copy of this vector 
601        * {@link javolution.context.AllocatorContext allocated} 
602        * by the calling thread (possibly on the stack).
603        *       
604        * @return an identical and independent copy of this vector.
605        */
606        @Override
607        public ParameterVector<Q> copy() {
608                return copyOf(this);
609        }
610        
611        /**
612        *  Returns the unit in which the {@link #getValue values} in this vector
613        *  are stated in.
614        **/
615    @Override
616        public Unit<Q> getUnit() {
617                return _unit;
618        }
619        
620        /**
621        * Returns the equivalent to this vector but stated in the 
622        * specified unit. 
623        *
624        * @param  unit the unit of the vector to be returned.
625        * @return a vector equivalent to this vector but stated in the 
626        *               specified unit.
627        * @throws ConversionException if the current model does not allows for
628        *               conversion to the specified unit.
629        */
630        @SuppressWarnings("unchecked")
631    @Override
632        public <R extends Quantity> ParameterVector<R> to(Unit<R> unit) {
633                if ((_unit == unit) || this._unit.equals(unit))
634                        return (ParameterVector<R>)this;
635                
636        StackContext.enter();
637        try {
638            UnitConverter cvtr = Parameter.converterOf(_unit, unit);
639            if (cvtr == UnitConverter.IDENTITY) { // No conversion necessary.
640                ParameterVector<R> result = (ParameterVector<R>) copyOf(this);
641                result._unit = unit;
642                return StackContext.outerCopy((ParameterVector<R>)result);
643            }
644
645            FastTable<Float64> valueList = FastTable.newInstance();
646            int size = _data.getDimension();
647            for (int i = 0; i < size; ++i) {
648                double value = cvtr.convert(_data.getValue(i));
649                valueList.add(Float64.valueOf(value));
650            }
651            
652            ParameterVector<R> result = newInstance(unit);
653            result._data = Float64Vector.valueOf(valueList);
654
655            return StackContext.outerCopy(result);
656        } finally {
657            StackContext.exit();
658        }
659        }
660
661        /**
662        * Casts this ParameterVector to a parameterized unit of specified nature or 
663        * throw a <code>ClassCastException</code> if the dimension of the 
664        * specified quantity and this parameter's unit dimension do not match.
665        * 
666        * @param  type the quantity class identifying the nature of the unit.
667        * @return this ParameterVector parameterized with the specified type.
668        * @throws ClassCastException if the dimension of this parameter's unit is different 
669        *               from the specified quantity dimension.
670        * @throws UnsupportedOperationException if the specified quantity class
671        *               does not have a public static field named "UNIT" holding the 
672        *               standard unit for the quantity.
673        */
674        @SuppressWarnings("unchecked")
675        public <T extends Quantity> ParameterVector<T> asType(Class<T> type) throws ClassCastException {
676                @SuppressWarnings("unused")
677                Unit<T> u = _unit.asType(type); //      If no exception is thrown, the cast is valid.
678                return (ParameterVector<T>)this;
679        }
680   
681        /**
682        *  Returns the values stored in this vector, stated in this vector's
683        *  {@link #getUnit unit}, as a Float64Vector.
684        **/
685        public Float64Vector toFloat64Vector() {
686                return _data;
687        }
688        
689        /**
690        * Compares this ParameterVector against the specified object for strict 
691        * equality (same values and same units).
692        *
693        * @param  obj the object to compare with.
694        * @return <code>true</code> if this vector is identical to that
695        *               vector; <code>false</code> otherwise.
696        **/
697    @Override
698        public boolean equals(Object obj) {
699                if (this == obj)
700                        return true;
701                if ((obj == null) || (obj.getClass() != this.getClass()))
702                        return false;
703                
704                ParameterVector<?> that = (ParameterVector<?>)obj;
705                if(!this._data.equals(that._data))
706                        return false;
707                
708                return this._unit.equals(that._unit);
709        }
710
711        /**
712        * Returns the hash code for this parameter.
713        * 
714        * @return the hash code value.
715        */
716    @Override
717        public int hashCode() {
718                int hash = 7;
719                
720                int var_code = _unit.hashCode();
721                hash = hash*31 + var_code;
722                
723                var_code = _data.hashCode();
724                hash = hash*31 + var_code;
725                
726                return hash;
727        }
728
729        /**
730        *  Convert a vector of Parameter objects to a Float64Vector stated in
731        *  the specified units.  If the units are null, no conversion occurs.
732        **/
733        private static <Q extends Quantity> Float64Vector toFloat64Vector(Vector<Parameter<Q>> that, Unit<Q> unit) {
734                
735        StackContext.enter();
736        try {
737            Float64Vector thatData;
738            Unit<?> oldUnit;
739            if (that instanceof ParameterVector) {
740                ParameterVector<Q> V = ((ParameterVector<Q>) that);
741                thatData = V.toFloat64Vector();
742                oldUnit = V.getUnit();
743
744            } else if (that instanceof Coordinate3D) {
745                Vector3D<Q> T = ((Coordinate3D<Q>) that).toVector3D();
746                if (!Length.UNIT.isCompatible(T.getUnit()))
747                    throw new ConversionException(RESOURCES.getString("incompatibleUnits").
748                            replace("<NAME/>", "input vector").replace("<TYPE/>", "length"));
749                oldUnit = T.getUnit();
750                thatData = T.toFloat64Vector();
751
752            } else {
753                ParameterVector<Q> V = valueOf(that);
754                thatData = V.toFloat64Vector();
755                oldUnit = V.getUnit();
756            }
757
758
759            //  Convert that vector's units to the specified units if necessary.
760            if (unit != null) {
761                if (!unit.equals(oldUnit)) {
762                    UnitConverter cvtr = Parameter.converterOf(oldUnit, unit);
763                    if (cvtr != UnitConverter.IDENTITY) {
764                        FastTable<Float64> valueList = FastTable.newInstance();
765                        int size = thatData.getDimension();
766                        for (int i = 0; i < size; ++i) {
767                            double value = cvtr.convert(thatData.getValue(i));
768                            valueList.add(Float64.valueOf(value));
769                        }
770                        thatData = Float64Vector.valueOf(valueList);
771                    }
772                }
773            }
774
775            return StackContext.outerCopy(thatData);
776        } finally {
777            StackContext.exit();
778        }
779        }
780        
781
782        /**
783        *  During serialization, this will write out the Float64Vector as a
784        *  simple series of <code>double</code> values.    This method is ONLY called by the Java
785        *  Serialization mechanism and should not otherwise be used.
786        **/
787        private void writeObject( java.io.ObjectOutputStream out ) throws java.io.IOException {
788        
789                // Call the default write object method.
790                out.defaultWriteObject();
791                
792                //      Write out the number of elements.
793                int size = _data.getDimension();
794                out.writeInt( size );
795                
796                //      Write out the coordinate values.
797                for (int i=0; i < size; ++i)
798                        out.writeDouble( _data.getValue(i) );
799                
800        }
801
802        /**
803        *  During de-serialization, this will handle the reconstruction
804        *  of the Float64Vector.  This method is ONLY called by the Java
805        *  Serialization mechanism and should not otherwise be used.
806        **/
807        private void readObject( java.io.ObjectInputStream in ) throws java.io.IOException, ClassNotFoundException {
808        
809                // Call the default read object method.
810                in.defaultReadObject();
811
812                //      Read in the number of elements.
813                int size = in.readInt();
814                
815                //      Read in the coordinate values.
816                FastTable<Float64> valueList = FastTable.newInstance();
817                for (int i=0; i < size; ++i ) {
818                        double value = in.readDouble();
819                        valueList.add(Float64.valueOf(value));
820                }
821                
822                _data = Float64Vector.valueOf(valueList);
823                
824                FastTable.recycle(valueList);
825        }
826        
827        /**
828        * Holds the default XML representation. For example:
829        * <pre>
830        *       &lt;ParameterVector unit = "m"&gt;
831        *               &lt;Float64 value="1.0" /&gt;
832        *               &lt;Float64 value="0.0" /&gt;
833        *               &lt;Float64 value="2.0" /&gt;
834        *       &lt;/ParameterVector&gt;
835        * </pre>
836        */
837        @SuppressWarnings("rawtypes")
838        protected static final XMLFormat<ParameterVector> XML = new XMLFormat<ParameterVector>(ParameterVector.class) {
839
840                @Override
841                public ParameterVector<?> newInstance(Class<ParameterVector> cls, InputElement xml) throws XMLStreamException {
842                        
843                        Unit<?> unit = Unit.valueOf(xml.getAttribute("unit"));
844                        ParameterVector<?> V = ParameterVector.newInstance(unit);
845                        
846                        FastTable<Float64> valueList = FastTable.newInstance();
847                        while (xml.hasNext()) {
848                                Float64 value = xml.getNext();
849                                valueList.add(value);
850                        }
851                        V._data = Float64Vector.valueOf(valueList);
852                        
853                        FastTable.recycle(valueList);
854                        
855                        return V;
856                }
857
858                @Override
859                public void read(InputElement xml, ParameterVector V) throws XMLStreamException {
860                        //      Nothing to do.
861                }
862
863                @Override
864                public void write(ParameterVector V, OutputElement xml) throws XMLStreamException {
865                                
866                        xml.setAttribute("unit", V._unit.toString());
867                        int size = V._data.getDimension();
868                        for (int i=0; i < size; ++i)
869                                xml.add(V._data.get(i));
870                        
871                }
872        };
873        
874        ///////////////////////
875        // Factory creation. //
876        ///////////////////////
877
878        protected ParameterVector() {}
879        
880        @SuppressWarnings("rawtypes")
881        private static final ObjectFactory<ParameterVector> FACTORY = new ObjectFactory<ParameterVector>() {
882                @Override
883                protected ParameterVector create() {
884                        return new ParameterVector();
885                }
886        };
887
888        /**
889        *  Return a new instance of the ParameterVector class with the specified unit.
890        *  The <code>_data</code> value will be undefined and must be set before
891        *  using the returned object for anything.
892        **/
893        @SuppressWarnings("unchecked")
894        protected static <Q extends Quantity> ParameterVector<Q> newInstance(Unit<Q> unit) {
895        if (unit == null)
896            throw new NullPointerException("Unit can not be null.");
897                ParameterVector<Q> measure = FACTORY.object();
898                measure._unit = unit;
899                return measure;
900        }
901
902        @SuppressWarnings("unchecked")
903        private static <Q extends Quantity> ParameterVector<Q> copyOf(ParameterVector<Q> original) {
904                ParameterVector<Q> measure = FACTORY.object();
905                measure._unit = original._unit;
906                measure._data = original._data.copy();
907                return measure;
908        }
909
910
911        /**
912        *  Tests the methods in this class.
913        **/
914    public static void main (String args[]) {
915                System.out.println("Testing ParameterVector:  test = result [correct result]");
916                
917                ParameterVector<Length> v1 = ParameterVector.valueOf(1, 2, 3, NonSI.FOOT);
918                System.out.println("v1 = " + v1);
919                System.out.println("  converted to m       = " + v1.to(SI.METER) + " [{0.3048 m, 0.6096 m, 0.9144 m}]");
920                System.out.println("  v1.norm()            = " + v1.norm() + " [3.74165738677394 ft]");
921                System.out.println("  v1.opposite()        = " + v1.opposite() + " [{-1.0 ft, -2.0 ft, -3.0 ft}]");
922                System.out.println("  v1.toUnitVector()    = " + v1.toUnitVector() + " [{0.267261241912424 , 0.534522483824849 , 0.801783725737273 }]");
923                
924                Parameter<Length> point = Parameter.valueOf(24, NonSI.INCH);
925                System.out.println("point = " + point);
926                System.out.println("  v1 + point           = " + v1.plus(point) + " [{3.0 ft, 4.0 ft, 5.0 ft}]");
927                System.out.println("  v1 - point           = " + v1.minus(point) + " [{-1.0 ft, 0.0 ft, 1.0 ft}]");
928                System.out.println("  v1 * 2               = " + v1.times(2) + " [{2.0 ft, 4.0 ft, 6.0 ft}]");
929                
930                ParameterVector<?> areaVector = (ParameterVector<?>)v1.times(point);
931                System.out.println("  v1 * point           = " + areaVector);
932                System.out.println("  converted to ft²     = " + areaVector.to(NonSI.SQUARE_FOOT) + " [{2.0 ft², 4.0 ft², 6.0 ft²}]");
933                
934                
935                ParameterVector<Length> v2 = ParameterVector.valueOf(1, 1, 1, SI.METER);
936                ParameterVector<?> v1xv2 = (ParameterVector<?>)v1.cross(v2);
937                System.out.println("v2 = " + v2);
938                System.out.println("  v1 + v2 = " + v1.plus(v2) + " [{4.28083989501312 ft, 5.28083989501312 ft, 6.28083989501312 ft}]");
939                System.out.println("  v1 - v2 = " + v1.minus(v2) + " [{-2.28083989501312 ft, -1.28083989501312 ft, -0.280839895013123 ft}]");
940                System.out.println("  v1 · v2 = " + v1.times(v2.to(NonSI.FOOT)) + " [19.6850393700787 ft²]");
941                System.out.println("  v1.cross(v2) = " + v1xv2.to(NonSI.FOOT.pow(2)) + " [{-3.28083989501312 ft^2, 6.56167979002625 ft^2, -3.28083989501312 ft^2}]");
942                System.out.println("  v1.angle(v2) = " + v1.angle(v2).to(NonSI.DEGREE_ANGLE) + " [73.6090476746643 deg]");
943                
944                //      Write out XML data.
945                try {
946                        System.out.println();
947                        
948                        // Creates some useful aliases for class names.
949                        javolution.xml.XMLBinding binding = new javolution.xml.XMLBinding();
950                        binding.setAlias(org.jscience.mathematics.number.Float64.class, "Float64");
951                        
952                        javolution.xml.XMLObjectWriter writer = javolution.xml.XMLObjectWriter.newInstance(System.out);
953                        writer.setIndentation("    ");
954                        writer.setBinding(binding);
955                        writer.write(v1, "ParameterVector", ParameterVector.class);
956                        writer.flush();
957                        
958                        System.out.println();
959                } catch (Exception e) {
960                        e.printStackTrace();
961                }
962    }
963}