001/**
002 * MutableVector -- Holds the floating point coordinates of an nD vector that can be
003 * changed.
004 *
005 * Copyright (C) 2009-2015, Joseph A. Huwaldt. All rights reserved.
006 *
007 * This library is free software; you can redistribute it and/or modify it under the terms
008 * of the GNU Lesser General Public License as published by the Free Software Foundation;
009 * either version 2.1 of the License, or (at your option) any later version.
010 *
011 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
012 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
013 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
014 *
015 * You should have received a copy of the GNU Lesser General Public License along with
016 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place -
017 * Suite 330, Boston, MA 02111-1307, USA. Or visit: http://www.gnu.org/licenses/lgpl.html
018 */
019package geomss.geom;
020
021import jahuwaldt.js.param.*;
022import java.text.MessageFormat;
023import java.util.List;
024import java.util.Objects;
025import static java.util.Objects.requireNonNull;
026import javax.measure.converter.ConversionException;
027import javax.measure.converter.UnitConverter;
028import javax.measure.quantity.*;
029import javax.measure.unit.Unit;
030import javolution.context.ObjectFactory;
031import javolution.util.FastTable;
032import javolution.xml.XMLFormat;
033import javolution.xml.stream.XMLStreamException;
034import org.jscience.mathematics.number.Float64;
035import org.jscience.mathematics.vector.Float64Vector;
036
037/**
038 * A container that holds changeable coordinates of an n-dimensional vector which
039 * indicates direction, but not position.
040 * 
041 * <p> Modified by: Joseph A. Huwaldt </p>
042 * 
043 * @author Joseph A. Huwaldt, Date: June 13, 2009
044 * @version November 27, 2015
045 *
046 * @param <Q> The Quantity (unit type) of the elements of this vector.
047 */
048@SuppressWarnings({"serial", "CloneableImplementsClone"})
049public final class MutableVector<Q extends Quantity> extends GeomVector<Q> {
050
051    //  Use an immutable Vector as a backing for the MutableVector.
052    private Vector<Q> _vector;
053
054    /**
055     * Returns a dimensionless <code>MutableVector</code> instance of the specified
056     * dimension with all the coordinate values set to zero.
057     *
058     * @param dim the physical dimension of the vector to create.
059     * @return the vector having the specified dimension and zero meters for values.
060     */
061    public static MutableVector<Dimensionless> newInstance(int dim) {
062        MutableVector V = FACTORY.object();
063        V._vector = Vector.newInstance(dim);
064        return V;
065    }
066
067    /**
068     * Returns a <code>MutableVector</code> instance of the specified dimension and units
069     * with all the coordinate values set to zero.
070     *
071     * @param <Q>  The Quantity (unit type) of the returned vector.
072     * @param dim  the physical dimension of the vector to create.
073     * @param unit the unit in which the coordinates are stated. May not be null.
074     * @return the vector having the specified dimension and zero meters for values.
075     */
076    public static <Q extends Quantity> MutableVector<Q> newInstance(int dim, Unit<Q> unit) {
077        MutableVector V = FACTORY.object();
078        V._vector = Vector.newInstance(dim, requireNonNull(unit));
079        return V;
080    }
081
082    /**
083     * Returns a <code>Vector</code> instance containing the specified GeomVector values.
084     *
085     * @param <Q>    The Quantity (unit type) of the returned vector.
086     * @param vector the GeomVector to be placed in a new Vector instance. May not be null.
087     * @return the vector having the specified values.
088     */
089    public static <Q extends Quantity> MutableVector<Q> valueOf(GeomVector<Q> vector) {
090        MutableVector V = FACTORY.object();
091        V._vector = vector.immutable();
092        return V;
093    }
094
095    /**
096     * Returns a dimensionless <code>MutableVector</code> instance holding the specified
097     * <code>double</code> value or values.
098     *
099     * @param x The dimensionless coordinate values. May not be null.
100     * @return the vector having the specified value.
101     */
102    public static MutableVector<Dimensionless> valueOf(double... x) {
103        MutableVector V = FACTORY.object();
104        V._vector = Vector.valueOf(requireNonNull(x));
105        return V;
106    }
107
108    /**
109     * Returns a <code>MutableVector</code> instance holding the specified
110     * <code>double</code> value or values stated in the specified units.
111     *
112     * @param <Q>  The Quantity (unit type) of the returned vector.
113     * @param unit the unit in which the coordinates are stated. May not be null.
114     * @param x    the coordinate values stated in the specified unit. May not be null.
115     * @return the vector having the specified value.
116     */
117    public static <Q extends Quantity> MutableVector<Q> valueOf(Unit<Q> unit, double... x) {
118        MutableVector V = FACTORY.object();
119        V._vector = Vector.valueOf(requireNonNull(unit), requireNonNull(x));
120        return V;
121    }
122
123    /**
124     * Returns a <code>MutableVector</code> instance containing the specified vector of
125     * Parameter values with compatible units. All the values are converted to the same
126     * units as the 1st value.
127     *
128     * @param <Q>    The Quantity (unit type) of the returned vector.
129     * @param vector the vector of Parameter values stated in the specified unit. May not
130     *               be null.
131     * @return the vector having the specified values.
132     */
133    public static <Q extends Quantity> MutableVector<Q> valueOf(org.jscience.mathematics.vector.Vector<Parameter<Q>> vector) {
134        MutableVector V = FACTORY.object();
135        V._vector = Vector.valueOf(requireNonNull(vector));
136        return V;
137    }
138
139    /**
140     * Returns a <code>MutableVector</code> instance containing the specified list of
141     * Parameter values with compatible units. All the values are converted to the same
142     * units as the 1st value.
143     *
144     * @param <Q>    The Quantity (unit type) of the returned vector.
145     * @param values the list of Parameter values stated in the specified unit. May not be
146     *               null.
147     * @return the vector having the specified values.
148     */
149    public static <Q extends Quantity> MutableVector<Q> valueOf(List<Parameter<Q>> values) {
150        MutableVector<Q> V = FACTORY.object();
151        V._vector = Vector.valueOf(requireNonNull(values));
152        return V;
153    }
154
155    /**
156     * Returns a {@link MutableVector} instance containing the specified vector of Float64
157     * values stated in the specified units.
158     *
159     * @param <Q>    The Quantity (unit type) of the returned vector.
160     * @param vector the vector of Float64 values stated in the specified unit. May not be
161     *               null.
162     * @param unit   the unit in which the coordinates are stated. May not be null.
163     * @return the vector having the specified values.
164     */
165    public static <Q extends Quantity> MutableVector<Q> valueOf(org.jscience.mathematics.vector.Vector<Float64> vector, Unit<Q> unit) {
166        MutableVector V = FACTORY.object();
167        V._vector = Vector.valueOf(requireNonNull(vector), requireNonNull(unit));
168        return V;
169    }
170
171    /**
172     * Returns a <code>MutableVector</code> instance holding the specified
173     * <code>Parameter</code> values. All the values are converted to the same units as
174     * the first value.
175     *
176     * @param <Q>    The Quantity (unit type) of the returned vector.
177     * @param values A list of values to store in the vector. May not be null.
178     * @return the vector having the specified values in the units of x.
179     */
180    public static <Q extends Quantity> MutableVector<Q> valueOf(Parameter<Q>... values) {
181        MutableVector V = FACTORY.object();
182        V._vector = Vector.valueOf(requireNonNull(values));
183        return V;
184    }
185
186    /**
187     * Returns a <code>MutableVector</code> instance holding the specified
188     * <code>GeomPoint</code> values.
189     *
190     * @param point A point who's coordinates are to be stored in the vector (making it a
191     *              position vector). May not be null.
192     * @return the vector having the specified point coordinate values in it.
193     */
194    public static MutableVector<Length> valueOf(GeomPoint point) {
195        MutableVector V = FACTORY.object();
196        V._vector = Vector.valueOf(requireNonNull(point));
197        return V;
198    }
199
200    /**
201     * Returns the number of physical dimensions of this vector.
202     *
203     * @return The number of physical dimensions of this vector.
204     */
205    @Override
206    public int getPhyDimension() {
207        return _vector.getPhyDimension();
208    }
209
210    /**
211     * Set the value of a vector dimension to the specified Parameter.
212     *
213     * @param i     the dimension index.
214     * @param value The new value of the parameter to set at <code>i</code>. May not be
215     *              null.
216     * @throws IndexOutOfBoundsException <code>(i &lt; 0) || (i &ge; getPhyDimension())</code>
217     */
218    public void set(int i, Parameter<Q> value) {
219        requireNonNull(value);
220        
221        //  Get a list of values in this point.
222        FastTable<Parameter<Q>> values = FastTable.newInstance();
223        int size = _vector.getPhyDimension();
224        for (int j = 0; j < size; ++j) {
225            values.add(_vector.get(j));
226        }
227
228        //  Change the dimension indicated.
229        values.set(i, value);
230        _vector = Vector.valueOf(values);
231        FastTable.recycle(values);
232
233        fireChangeEvent();  //  Notify change listeners.
234    }
235
236    /**
237     * Set the value of elements of this vector to the elements of the specified vector.
238     *
239     * @param v The new vector to make this vector equal to. May not be null.
240     * @throws DimensionException <code>(v.getPhyDimension() != getPhyDimension())</code>
241     */
242    public void set(GeomVector<Q> v) {
243        int numDims = getPhyDimension();
244        if (v.getPhyDimension() != numDims)
245            throw new DimensionException(RESOURCES.getString("consistantPointDim"));
246        _vector = v.immutable();
247    }
248
249    /**
250     * Set the value of a vector dimension to the specified double in the current vector
251     * units.
252     *
253     * @param i     the dimension index.
254     * @param value The new value of the parameter to set at <code>i</code> in the current
255     *              units of this vector.
256     * @throws IndexOutOfBoundsException <code>(i &lt; 0) || (i &ge; getPhyDimension())</code>
257     */
258    public void setValue(int i, double value) {
259        //  Create a Parameter object.
260        Parameter<Q> param = Parameter.valueOf(value, getUnit());
261
262        //  Set the specified dimension to the new parameter object.
263        set(i, param);
264    }
265
266    /**
267     * Returns the value of the Parameter in this vector as a <code>double</code>, stated
268     * in this vector's {@link #getUnit unit}.
269     *
270     * @param i the dimension index.
271     * @return the value of the Parameter at <code>i</code>.
272     * @throws IndexOutOfBoundsException <code>(i &lt; 0) || (i &ge; getPhyDimension())</code>
273     */
274    @Override
275    public double getValue(int i) {
276        return _vector.getValue(i);
277    }
278
279    /**
280     * Returns the value of the Parameter in this vector as a <code>double</code>, stated
281     * in the specified units.
282     *
283     * @param i    the dimension index.
284     * @param unit the unit to return the value in. May not be null.
285     * @return the value of the Parameter at <code>i</code> in the specified unit.
286     * @throws IndexOutOfBoundsException <code>(i &lt; 0) || (i &ge; getPhyDimension())</code>
287     */
288    @Override
289    public double getValue(int i, Unit<Q> unit) {
290        double value = _vector.getValue(i);
291        Unit<Q> thisUnit = getUnit();
292        if (unit.equals(thisUnit))
293            return value;
294        UnitConverter cvtr = Parameter.converterOf(thisUnit, unit);
295        if (cvtr == UnitConverter.IDENTITY) { // No conversion necessary.
296            return value;
297        }
298        return cvtr.convert(value);
299    }
300
301    /**
302     * Set the origin point for this vector. The origin is used as a reference for drawing
303     * the vector and is <i>not</i> a part of the state of this vector and is not used in
304     * any calculations with this vector.
305     *
306     * @param origin The point to set as the origin of this vector. May not be null.
307     */
308    @Override
309    public void setOrigin(Point origin) {
310        _vector.setOrigin(requireNonNull(origin));
311    }
312
313    /**
314     * Return the origin point for this vector.
315     *
316     * @return The origin point for this vector.
317     */
318    @Override
319    public Point getOrigin() {
320        return _vector.getOrigin();
321    }
322
323    /**
324     * Returns the {@link #norm}, magnitude, or length value of this vector (square root
325     * of the dot product of this vector and itself).
326     *
327     * @return <code>this.norm().getValue()</code>.
328     */
329    @Override
330    public double normValue() {
331        return _vector.normValue();
332    }
333
334    /**
335     * Returns the negation of this vector.
336     *
337     * @return <code>-this</code>.
338     */
339    @Override
340    public Vector<Q> opposite() {
341        return _vector.opposite();
342    }
343
344    /**
345     * Returns the sum of this vector with the one specified. The unit of the output
346     * vector will be the units of this vector.
347     *
348     * @param that the vector to be added. May not be null.
349     * @return <code>this + that</code>.
350     * @throws DimensionException if vector dimensions are different.
351     */
352    @Override
353    public Vector<Q> plus(GeomVector<Q> that) {
354        return _vector.plus(that);
355    }
356
357    /**
358     * Returns the sum of this vector with the parameter specified. The input parameter is
359     * added to each component of this vector. The unit of the output vector will be the
360     * units of this vector.
361     *
362     * @param that the parameter to be added to each element of this vector. May not be null.
363     * @return <code>this + that</code>.
364     */
365    @Override
366    public Vector<Q> plus(Parameter<Q> that) {
367        return _vector.plus(that);
368    }
369
370    /**
371     * Returns the difference between this vector and the one specified. The unit of the
372     * output vector will be the units of this vector.
373     *
374     * @param that the vector to be subtracted from this vector. May not be null.
375     * @return <code>this - that</code>.
376     * @throws DimensionException if vector dimensions are different.
377     */
378    @Override
379    public Vector<Q> minus(GeomVector<Q> that) {
380        return _vector.minus(that);
381    }
382
383    /**
384     * Subtracts the supplied Parameter from each element of this vector and returns the
385     * result. The unit of the output vector will be the units of this vector.
386     *
387     * @param that the Parameter to be subtracted from each element of this vector. May
388     *             not be null.
389     * @return <code>this - that</code>.
390     */
391    @Override
392    public Vector<Q> minus(Parameter<Q> that) {
393        return _vector.minus(that);
394    }
395
396    /**
397     * Returns the product of this vector with the specified coefficient (dimensionless).
398     *
399     * @param k the coefficient multiplier.
400     * @return <code>this · k</code>
401     */
402    @Override
403    public Vector<Q> times(double k) {
404        return _vector.times(k);
405    }
406
407    /**
408     * Returns the product of this vector with the specified coefficient.
409     *
410     * @param k the coefficient multiplier. May not be null.
411     * @return <code>this · k</code>
412     */
413    @Override
414    public Vector<? extends Quantity> times(Parameter<?> k) {
415        return _vector.times(k);
416    }
417
418    /**
419     * Returns the dot product (scalar product) of this vector with the one specified.
420     *
421     * @param that the vector multiplier. May not be null.
422     * @return <code>this · that</code>
423     * @throws DimensionException if <code>this.dimension() != that.dimension()</code>
424     * @see <a href="http://en.wikipedia.org/wiki/Dot_product">
425     * Wikipedia: Dot Product</a>
426     */
427    @Override
428    public Parameter<? extends Quantity> times(GeomVector<?> that) {
429        return _vector.times(that);
430    }
431
432    /**
433     * Returns the element-by-element product of this vector with the one specified.
434     *
435     * @param that the vector multiplier. May not be null.
436     * @return <code>this .* that</code>
437     * @throws DimensionException if <code>this.dimension() != that.dimension()</code>
438     */
439    @Override
440    public Vector<? extends Quantity> timesEBE(GeomVector<?> that) {
441        return _vector.timesEBE(that);
442    }
443
444    /**
445     * Returns the cross product of two vectors.
446     *
447     * @param that the vector multiplier. May not be null.
448     * @return <code>this x that</code>
449     * @throws DimensionException if
450     * <code>(that.getDimension() != this.getDimension())</code>
451     * @see <a href="http://en.wikipedia.org/wiki/Cross_product">
452     * Wikipedia: Cross Product</a>
453     */
454    @Override
455    public Vector<? extends Quantity> cross(GeomVector<?> that) {
456        return _vector.cross(that);
457    }
458
459    /**
460     * Returns this vector with each element divided by the specified divisor
461     * (dimensionless).
462     *
463     * @param divisor the divisor.
464     * @return <code>this / divisor</code>.
465     */
466    @Override
467    public Vector<Q> divide(double divisor) {
468        return _vector.divide(divisor);
469    }
470
471    /**
472     * Returns this vector with each element divided by the specified divisor.
473     *
474     * @param divisor the divisor. May not be null.
475     * @return <code>this / divisor</code>.
476     */
477    @Override
478    public Vector<? extends Quantity> divide(Parameter<?> divisor) {
479        return _vector.divide(divisor);
480    }
481
482    /**
483     * Return an immutable version of this vector.
484     *
485     * @return An immutable version of this vector.
486     */
487    @Override
488    public Vector<Q> immutable() {
489        return _vector;
490    }
491
492    /**
493     * Returns this vector converted to a unit vector by dividing all the vector's
494     * elements by the length ({@link #norm}) of this vector.
495     *
496     * @return This vector converted to a unit vector.
497     */
498    @Override
499    public Vector<Dimensionless> toUnitVector() {
500        return _vector.toUnitVector();
501    }
502
503    /**
504     * Returns the unit in which the {@link #getValue values} in this vector are stated
505     * in.
506     *
507     * @return The unit in which the values in this vector are stated.
508     */
509    @Override
510    public Unit getUnit() {
511        return _vector.getUnit();
512    }
513
514    /**
515     * Returns the equivalent to this vector but stated in the specified unit.
516     *
517     * @param unit the unit of the vector to be returned. May not be null.
518     * @return an equivalent to this vector but stated in the specified unit.
519     * @throws ConversionException if the the input unit is not compatible with this unit.
520     */
521    @Override
522    public MutableVector to(Unit unit) throws ConversionException {
523        if (unit.equals(getUnit()))
524            return this;
525        MutableVector V = FACTORY.object();
526        V._vector = this._vector.to(unit);
527        return V;
528    }
529
530    /**
531     * Return a copy of this vector converted to the specified number of physical
532     * dimensions. If the number of dimensions is greater than this element, then zeros
533     * are added to the additional dimensions. If the number of dimensions is less than
534     * this element, then the extra dimensions are simply dropped (truncated). If the new
535     * dimensions are the same as the dimension of this element, then this element is
536     * simply returned.
537     *
538     * @param newDim The dimension of the vector to return.
539     * @return A copy of this vector converted to the new dimensions.
540     */
541    @Override
542    public MutableVector<Q> toDimension(int newDim) {
543        if (newDim < 1)
544            throw new IllegalArgumentException(RESOURCES.getString("vectorDimGT0"));
545        int thisDim = this.getPhyDimension();
546        if (newDim == thisDim)
547            return this;
548
549        MutableVector<Q> V = FACTORY.object();
550        V._vector = this._vector.toDimension(newDim);
551
552        return V;
553    }
554
555    /**
556     * Returns a copy of this Vector instance
557     * {@link javolution.context.AllocatorContext allocated} by the calling thread
558     * (possibly on the stack).
559     *
560     * @return an identical and independent copy of this vector.
561     */
562    @Override
563    public MutableVector<Q> copy() {
564        return copyOf(this);
565    }
566
567    /**
568     * Return a copy of this object with any transformations or subranges removed
569     * (applied).
570     *
571     * @return A copy of this object with any transformations or subranges removed.
572     */
573    @Override
574    public Vector<Q> copyToReal() {
575        return Vector.valueOf(_vector);
576    }
577
578    /**
579     * Returns a <code>ParameterVector</code> representation of this vector.
580     *
581     * @return A ParameterVector that is equivalent to this vector.
582     */
583    @Override
584    public ParameterVector<Q> toParameterVector() {
585        return _vector.toParameterVector();
586    }
587
588    /**
589     * Returns a <code>Float64Vector</code> containing the elements of this vector stated
590     * in the current units.
591     *
592     * @return A Float64Vector that contains the elements of this vector in the current
593     *         units.
594     */
595    @Override
596    public Float64Vector toFloat64Vector() {
597        return _vector.toFloat64Vector();
598    }
599
600    /**
601     * Compares this vector against the specified object for strict equality (same values
602     * and same units).
603     *
604     * @param obj the object to compare with.
605     * @return <code>true</code> if this vector is identical to that vector;
606     *         <code>false</code> otherwise.
607     */
608    @Override
609    public boolean equals(Object obj) {
610        if (this == obj)
611            return true;
612        if ((obj == null) || (obj.getClass() != this.getClass()))
613            return false;
614
615        MutableVector that = (MutableVector)obj;
616        return this._vector.equals(that._vector)
617                && super.equals(obj);
618    }
619
620    /**
621     * Returns the hash code for this parameter.
622     *
623     * @return the hash code value.
624     */
625    @Override
626    public int hashCode() {
627        return 31*super.hashCode() + Objects.hash(_vector);
628    }
629
630    /**
631     * Recycles a <code>MutableVector</code> instance immediately (on the stack when
632     * executing in a <code>StackContext</code>).
633     *
634     * @param instance The instance to be recycled.
635     */
636    public static void recycle(MutableVector instance) {
637        FACTORY.recycle(instance);
638    }
639
640    /**
641     * Holds the default XML representation for this object.
642     */
643    @SuppressWarnings("FieldNameHidesFieldInSuperclass")
644    protected static final XMLFormat<MutableVector> XML = new XMLFormat<MutableVector>(MutableVector.class) {
645
646        @Override
647        public MutableVector newInstance(Class<MutableVector> cls, InputElement xml) throws XMLStreamException {
648            return FACTORY.object();
649        }
650
651        @Override
652        public void read(InputElement xml, MutableVector obj) throws XMLStreamException {
653
654            Unit unit = Unit.valueOf(xml.getAttribute("unit"));
655            if (!(Length.UNIT.isCompatible(unit) || Dimensionless.UNIT.isCompatible(unit)))
656                throw new XMLStreamException(
657                        MessageFormat.format(RESOURCES.getString("incompatibleUnits"),
658                                "MutableVector", "length"));
659
660            GeomVector.XML.read(xml, obj);     // Call parent read.
661
662            FastTable<Float64> valueList = FastTable.newInstance();
663            while (xml.hasNext()) {
664                Float64 value = xml.getNext();
665                valueList.add(value);
666            }
667
668            obj._vector = Vector.valueOf(Float64Vector.valueOf(valueList), unit);
669
670        }
671
672        @Override
673        public void write(MutableVector obj, OutputElement xml) throws XMLStreamException {
674            GeomVector.XML.write(obj, xml);    // Call parent write.
675
676            xml.setAttribute("unit", obj.getUnit().toString());
677            int size = obj._vector.getPhyDimension();
678            for (int i = 0; i < size; ++i)
679                xml.add(Float64.valueOf(obj._vector.getValue(i)));
680
681        }
682    };
683
684    ///////////////////////
685    // Factory creation. //
686    ///////////////////////
687    private MutableVector() { }
688
689    @SuppressWarnings("unchecked")
690    private static final ObjectFactory<MutableVector> FACTORY = new ObjectFactory<MutableVector>() {
691        @Override
692        protected MutableVector create() {
693            return new MutableVector();
694        }
695
696        @Override
697        protected void cleanup(MutableVector obj) {
698            obj.reset();
699        }
700    };
701
702    @SuppressWarnings("unchecked")
703    private static <Q extends Quantity> MutableVector<Q> copyOf(MutableVector<Q> original) {
704        MutableVector<Q> V = FACTORY.object();
705        V._vector = original._vector.copy();
706        original.copyState(V);
707        return V;
708    }
709}