2 * $RCSfile: GVector.java,v $
4 * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7 * This code is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 only, as
9 * published by the Free Software Foundation. Sun designates this
10 * particular file as subject to the "Classpath" exception as provided
11 * by Sun in the LICENSE file that accompanied this code.
13 * This code is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * version 2 for more details (a copy is included in the LICENSE file that
17 * accompanied this code).
19 * You should have received a copy of the GNU General Public License version
20 * 2 along with this work; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
23 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
24 * CA 95054 USA or visit www.sun.com if you need additional information or
28 * $Date: 2008/02/28 20:18:50 $
32 package javax.vecmath;
34 import java.lang.Math;
37 * A double precision, general, dynamically-resizable,
38 * one-dimensional vector class. Index numbering begins with zero.
41 public class GVector implements java.io.Serializable, Cloneable {
46 // Compatible with 1.1
47 static final long serialVersionUID = 1398850036893875112L;
50 * Constructs a new GVector of the specified
51 * length with all vector elements initialized to 0.
52 * @param length the number of elements in this GVector.
54 public GVector(int length)
59 values = new double[length];
60 for(i = 0; i < length; i++) values[i] = 0.0;
64 * Constructs a new GVector from the specified array elements.
65 * The length of this GVector is set to the length of the
66 * specified array. The array elements are copied into this new
68 * @param vector the values for the new GVector.
70 public GVector(double[] vector)
74 length = vector.length;
75 values = new double[vector.length];
76 for(i = 0; i < length; i++) values[i] = vector[i];
80 * Constructs a new GVector from the specified vector.
81 * The vector elements are copied into this new GVector.
82 * @param vector the source GVector for this new GVector.
84 public GVector(GVector vector)
88 values = new double[vector.length];
89 length = vector.length;
90 for(i = 0; i < length; i++) values[i] = vector.values[i];
94 * Constructs a new GVector and copies the initial values
95 * from the specified tuple.
96 * @param tuple the source for the new GVector's initial values
98 public GVector(Tuple2f tuple)
100 values = new double[2];
101 values[0] = (double)tuple.x;
102 values[1] = (double)tuple.y;
107 * Constructs a new GVector and copies the initial values
108 * from the specified tuple.
109 * @param tuple the source for the new GVector's initial values
111 public GVector(Tuple3f tuple)
113 values = new double[3];
114 values[0] = (double)tuple.x;
115 values[1] = (double)tuple.y;
116 values[2] = (double)tuple.z;
121 * Constructs a new GVector and copies the initial values
122 * from the specified tuple.
123 * @param tuple the source for the new GVector's initial values
125 public GVector(Tuple3d tuple)
127 values = new double[3];
135 * Constructs a new GVector and copies the initial values
136 * from the specified tuple.
137 * @param tuple the source for the new GVector's initial values
139 public GVector(Tuple4f tuple)
141 values = new double[4];
142 values[0] = (double)tuple.x;
143 values[1] = (double)tuple.y;
144 values[2] = (double)tuple.z;
145 values[3] = (double)tuple.w;
150 * Constructs a new GVector and copies the initial values
151 * from the specified tuple.
152 * @param tuple the source for the new GVector's initial values
154 public GVector(Tuple4d tuple)
156 values = new double[4];
165 * Constructs a new GVector of the specified length and
166 * initializes it by copying the specified number of elements from
167 * the specified array. The array must contain at least
168 * <code>length</code> elements (i.e., <code>vector.length</code> >=
169 * <code>length</code>. The length of this new GVector is set to
170 * the specified length.
171 * @param vector The array from which the values will be copied.
172 * @param length The number of values copied from the array.
174 public GVector(double vector[], int length) {
177 this.length = length;
178 values = new double [length];
179 for(i=0;i<length;i++) {
180 values[i] = vector[i];
185 * Returns the square root of the sum of the squares of this
186 * vector (its length in n-dimensional space).
187 * @return length of this vector
190 public final double norm()
195 for(i=0;i<length;i++) {
196 sq += values[i]*values[i];
199 return(Math.sqrt(sq));
204 * Returns the sum of the squares of this
205 * vector (its length squared in n-dimensional space).
206 * @return length squared of this vector
208 public final double normSquared()
213 for(i=0;i<length;i++) {
214 sq += values[i]*values[i];
221 * Sets the value of this vector to the normalization of vector v1.
222 * @param v1 the un-normalized vector
224 public final void normalize(GVector v1)
229 if( length != v1.length)
230 throw new MismatchedSizeException(VecMathI18N.getString("GVector0"));
232 for(i=0;i<length;i++) {
233 sq += v1.values[i]*v1.values[i];
237 invMag = 1.0/Math.sqrt(sq);
239 for(i=0;i<length;i++) {
240 values[i] = v1.values[i]*invMag;
246 * Normalizes this vector in place.
248 public final void normalize()
253 for(i=0;i<length;i++) {
254 sq += values[i]*values[i];
258 invMag = 1.0/Math.sqrt(sq);
260 for(i=0;i<length;i++) {
261 values[i] = values[i]*invMag;
267 * Sets the value of this vector to the scalar multiplication
268 * of the scale factor with the vector v1.
269 * @param s the scalar value
270 * @param v1 the source vector
272 public final void scale(double s, GVector v1)
275 if( length != v1.length)
276 throw new MismatchedSizeException(VecMathI18N.getString("GVector1"));
278 for(i=0;i<length;i++) {
279 values[i] = v1.values[i]*s;
284 * Scales this vector by the scale factor s.
285 * @param s the scalar value
287 public final void scale(double s)
291 for(i=0;i<length;i++) {
292 values[i] = values[i]*s;
297 * Sets the value of this vector to the scalar multiplication by s
298 * of vector v1 plus vector v2 (this = s*v1 + v2).
299 * @param s the scalar value
300 * @param v1 the vector to be multiplied
301 * @param v2 the vector to be added
303 public final void scaleAdd(double s, GVector v1, GVector v2)
308 if( v2.length != v1.length )
309 throw new MismatchedSizeException(VecMathI18N.getString("GVector2"));
311 if( length != v1.length )
312 throw new MismatchedSizeException(VecMathI18N.getString("GVector3"));
314 for(i=0;i<length;i++) {
315 values[i] = v1.values[i]*s + v2.values[i];
320 * Sets the value of this vector to sum of itself and the specified
322 * @param vector the second vector
324 public final void add(GVector vector)
328 if( length != vector.length )
329 throw new MismatchedSizeException(VecMathI18N.getString("GVector4"));
331 for(i = 0; i < length; i++) {
332 this.values[i] += vector.values[i];
337 * Sets the value of this vector to the vector sum of vectors vector1
339 * @param vector1 the first vector
340 * @param vector2 the second vector
342 public final void add(GVector vector1, GVector vector2)
346 if( vector1.length != vector2.length )
347 throw new MismatchedSizeException(VecMathI18N.getString("GVector5"));
349 if( length != vector1.length )
350 throw new MismatchedSizeException(VecMathI18N.getString("GVector6"));
352 for(i = 0; i < length; i++)
353 this.values[i] = vector1.values[i] + vector2.values[i];
357 * Sets the value of this vector to the vector difference of itself
358 * and vector (this = this - vector).
359 * @param vector the other vector
361 public final void sub(GVector vector)
365 if( length != vector.length )
366 throw new MismatchedSizeException(VecMathI18N.getString("GVector7"));
368 for(i = 0; i < length; i++) {
369 this.values[i] -= vector.values[i];
374 * Sets the value of this vector to the vector difference
375 * of vectors vector1 and vector2 (this = vector1 - vector2).
376 * @param vector1 the first vector
377 * @param vector2 the second vector
379 public final void sub(GVector vector1, GVector vector2)
384 if( vector1.length != vector2.length )
385 throw new MismatchedSizeException(VecMathI18N.getString("GVector8"));
387 if( length != vector1.length )
388 throw new MismatchedSizeException(VecMathI18N.getString("GVector9"));
390 for(i = 0; i < length; i++)
391 this.values[i] = vector1.values[i] - vector2.values[i];
395 * Multiplies matrix m1 times Vector v1 and places the result
396 * into this vector (this = m1*v1).
397 * @param m1 The matrix in the multiplication
398 * @param v1 The vector that is multiplied
400 public final void mul(GMatrix m1, GVector v1) {
401 if (m1.getNumCol() != v1.length)
402 throw new MismatchedSizeException(VecMathI18N.getString("GVector10"));
404 if (length != m1.getNumRow())
405 throw new MismatchedSizeException(VecMathI18N.getString("GVector11"));
411 v = (double []) values.clone();
414 for(int j=length-1; j>=0; j--){
416 for(int i=v1.length-1;i>=0; i--){
417 values[j] += m1.values[j][i] * v[i];
423 * Multiplies the transpose of vector v1 (ie, v1 becomes a row
424 * vector with respect to the multiplication) times matrix m1
425 * and places the result into this vector
426 * (this = transpose(v1)*m1). The result is technically a
427 * row vector, but the GVector class only knows about column
428 * vectors, and so the result is stored as a column vector.
429 * @param m1 The matrix in the multiplication
430 * @param v1 The vector that is temporarily transposed
432 public final void mul(GVector v1, GMatrix m1) {
433 if (m1.getNumRow() != v1.length)
434 throw new MismatchedSizeException(VecMathI18N.getString("GVector12"));
436 if (length != m1.getNumCol())
437 throw new MismatchedSizeException(VecMathI18N.getString("GVector13"));
443 v = (double []) values.clone();
446 for (int j=length-1; j>=0; j--){
448 for(int i=v1.length-1; i>=0; i--){
449 values[j] += m1.values[i][j] * v[i];
455 * Negates the value of this vector: this = -this.
457 public final void negate() {
458 for(int i=length-1; i>=0; i--) {
459 this.values[i] *= -1.0;
464 * Sets all the values in this vector to zero.
466 public final void zero() {
467 for (int i=0; i < this.length; i++) {
468 this.values[i] = 0.0;
473 * Changes the size of this vector dynamically. If the size is increased
474 * no data values will be lost. If the size is decreased, only those data
475 * values whose vector positions were eliminated will be lost.
476 * @param length number of desired elements in this vector
478 public final void setSize(int length) {
479 double[] tmp = new double[length];
482 if( this.length < length)
490 this.length = length;
497 * Sets the value of this vector to the values found in the array
498 * parameter. The array should be at least equal in length to
499 * the number of elements in the vector.
500 * @param vector the source array
502 public final void set(double[] vector) {
503 for(int i = length-1; i >=0; i--)
504 values[i] = vector[i];
508 * Sets the value of this vector to the values found in vector vector.
509 * @param vector the source vector
511 public final void set(GVector vector) {
514 if (length < vector.length) {
515 length = vector.length;
516 values = new double[length];
517 for(i = 0; i < length; i++)
518 values[i] = vector.values[i];
520 for(i = 0; i < vector.length; i++)
521 values[i] = vector.values[i];
522 for(i = vector.length; i < length; i++)
528 * Sets the value of this vector to the values in tuple
529 * @param tuple the source for the new GVector's new values
531 public final void set(Tuple2f tuple)
535 values = new double[2];
537 values[0] = (double)tuple.x;
538 values[1] = (double)tuple.y;
539 for(int i = 2; i < length; i++) values[i] = 0.0;
544 * Sets the value of this vector to the values in tuple
545 * @param tuple the source for the new GVector's new values
547 public final void set(Tuple3f tuple)
551 values = new double[3];
553 values[0] = (double)tuple.x;
554 values[1] = (double)tuple.y;
555 values[2] = (double)tuple.z;
556 for(int i = 3; i < length; i++) values[i] = 0.0;
560 * Sets the value of this vector to the values in tuple
561 * @param tuple the source for the new GVector's new values
563 public final void set(Tuple3d tuple)
567 values = new double[3];
572 for(int i = 3; i < length; i++) values[i] = 0.0;
576 * Sets the value of this vector to the values in tuple
577 * @param tuple the source for the new GVector's new values
579 public final void set(Tuple4f tuple)
583 values = new double[4];
585 values[0] = (double)tuple.x;
586 values[1] = (double)tuple.y;
587 values[2] = (double)tuple.z;
588 values[3] = (double)tuple.w;
589 for(int i = 4; i < length; i++) values[i] = 0.0;
593 * Sets the value of this vector to the values in tuple
594 * @param tuple the source for the new GVector's new values
596 public final void set(Tuple4d tuple)
600 values = new double[4];
606 for(int i = 4; i < length; i++) values[i] = 0.0;
610 * Returns the number of elements in this vector.
611 * @return number of elements in this vector
613 public final int getSize()
615 return values.length;
619 * Retrieves the value at the specified index value of this vector.
620 * @param index the index of the element to retrieve (zero indexed)
621 * @return the value at the indexed element
623 public final double getElement(int index)
625 return values[index];
630 * Modifies the value at the specified index of this vector.
631 * @param index the index if the element to modify (zero indexed)
632 * @param value the new vector element value
634 public final void setElement(int index, double value)
636 values[index] = value;
640 * Returns a string that contains the values of this GVector.
641 * @return the String representation
643 public String toString() {
644 StringBuffer buffer = new StringBuffer(length*8);
648 for(i=0;i<length;i++) {
649 buffer.append(values[i]).append(" ");
652 return buffer.toString();
658 * Returns a hash code value based on the data values in this
659 * object. Two different GVector objects with identical data
660 * values (i.e., GVector.equals returns true) will return the
661 * same hash number. Two GVector objects with different data
662 * members may return the same hash value, although this is not
664 * @return the integer hash code value
666 public int hashCode() {
669 for (int i = 0; i < length; i++) {
670 bits = 31L * bits + VecMathUtil.doubleToLongBits(values[i]);
673 return (int) (bits ^ (bits >> 32));
678 * Returns true if all of the data members of GVector vector1 are
679 * equal to the corresponding data members in this GVector.
680 * @param vector1 The vector with which the comparison is made.
681 * @return true or false
683 public boolean equals(GVector vector1)
686 if( length != vector1.length) return false;
688 for(int i = 0;i<length;i++) {
689 if( values[i] != vector1.values[i]) return false;
694 catch (NullPointerException e2) { return false; }
698 * Returns true if the Object o1 is of type GMatrix and all of the
699 * data members of o1 are equal to the corresponding data members in
701 * @param o1 The object with which the comparison is made.
702 * @return true or false
704 public boolean equals(Object o1)
707 GVector v2 = (GVector) o1;
709 if( length != v2.length) return false;
711 for(int i = 0;i<length;i++) {
712 if( values[i] != v2.values[i]) return false;
716 catch (ClassCastException e1) { return false; }
717 catch (NullPointerException e2) { return false; }
722 * Returns true if the L-infinite distance between this vector
723 * and vector v1 is less than or equal to the epsilon parameter,
724 * otherwise returns false. The L-infinite
725 * distance is equal to
726 * MAX[abs(x1-x2), abs(y1-y2), . . . ].
727 * @param v1 The vector to be compared to this vector
728 * @param epsilon the threshold value
730 public boolean epsilonEquals(GVector v1, double epsilon)
734 if( length != v1.length) return false;
736 for(int i = 0;i<length;i++) {
737 diff = values[i] - v1.values[i];
738 if( (diff<0?-diff:diff) > epsilon) return false;
744 * Returns the dot product of this vector and vector v1.
745 * @param v1 the other vector
746 * @return the dot product of this and v1
748 public final double dot(GVector v1)
750 if( length != v1.length)
751 throw new MismatchedSizeException(VecMathI18N.getString("GVector14"));
754 for(int i = 0;i<length;i++) {
755 result += values[i] * v1.values[i];
762 * Solves for x in Ax = b, where x is this vector (nx1), A is mxn,
763 * b is mx1, and A = U*W*transpose(V); U,W,V must
764 * be precomputed and can be found by taking the singular value
765 * decomposition (SVD) of A using the method SVD found in the
767 * @param U The U matrix produced by the GMatrix method SVD
768 * @param W The W matrix produced by the GMatrix method SVD
769 * @param V The V matrix produced by the GMatrix method SVD
770 * @param b The b vector in the linear equation Ax = b
772 public final void SVDBackSolve(GMatrix U, GMatrix W, GMatrix V, GVector b)
774 if( !(U.nRow == b.getSize() &&
776 U.nRow == W.nRow ) ) {
777 throw new MismatchedSizeException(VecMathI18N.getString("GVector15"));
780 if( !(W.nCol == values.length &&
782 W.nCol == V.nRow ) ) {
783 throw new MismatchedSizeException(VecMathI18N.getString("GVector23"));
786 GMatrix tmp = new GMatrix( U.nRow, W.nCol);
788 tmp.mulTransposeRight( U, W);
795 * LU Decomposition Back Solve; this method takes the LU matrix
796 * and the permutation vector produced by the GMatrix method LUD
797 * and solves the equation (LU)*x = b by placing the solution vector
798 * x into this vector. This vector should be the same length or
800 * @param LU The matrix into which the lower and upper decompostions
802 * @param b The b vector in the equation (LU)*x = b
803 * @param permutation The row permuations that were necessary to
804 * produce the LU matrix parameter
806 public final void LUDBackSolve(GMatrix LU, GVector b, GVector permutation)
808 int size = LU.nRow*LU.nCol;
810 double[] temp = new double[size];
811 double[] result = new double[size];
812 int[] row_perm = new int[b.getSize()];
815 if( LU.nRow != b.getSize() ) {
816 throw new MismatchedSizeException(VecMathI18N.getString("GVector16"));
819 if( LU.nRow != permutation.getSize() ) {
820 throw new MismatchedSizeException(VecMathI18N.getString("GVector24"));
823 if (LU.nRow != LU.nCol) {
824 throw new MismatchedSizeException(VecMathI18N.getString("GVector25"));
827 for(i=0;i<LU.nRow;i++) {
828 for(j=0;j<LU.nCol;j++) {
829 temp[i*LU.nCol+j] = LU.values[i][j];
833 for(i=0;i<size;i++) result[i] = 0.0;
834 for(i=0;i<LU.nRow;i++) result[i*LU.nCol] = b.values[i];
835 for(i=0;i<LU.nCol;i++) row_perm[i] = (int)permutation.values[i];
837 GMatrix.luBacksubstitution(LU.nRow, temp, row_perm, result);
839 for(i=0;i<LU.nRow;i++) this.values[i] = result[i*LU.nCol];
843 * Returns the (n-space) angle in radians between this vector and
844 * the vector parameter; the return value is constrained to the
846 * @param v1 The other vector
847 * @return The angle in radians in the range [0,PI]
849 public final double angle(GVector v1)
851 return( Math.acos( this.dot(v1) / ( this.norm()*v1.norm() ) ) );
856 * @deprecated Use interpolate(GVector, GVector, double) instead
858 public final void interpolate(GVector v1, GVector v2, float alpha) {
859 interpolate(v1, v2, (double)alpha);
864 * @deprecated Use interpolate(GVector, double) instead
866 public final void interpolate(GVector v1, float alpha) {
867 interpolate(v1, (double)alpha);
872 * Linearly interpolates between vectors v1 and v2 and places the
873 * result into this tuple: this = (1-alpha)*v1 + alpha*v2.
874 * @param v1 the first vector
875 * @param v2 the second vector
876 * @param alpha the alpha interpolation parameter
878 public final void interpolate(GVector v1, GVector v2, double alpha)
880 if( v2.length != v1.length )
881 throw new MismatchedSizeException(VecMathI18N.getString("GVector20"));
883 if( length != v1.length )
884 throw new MismatchedSizeException(VecMathI18N.getString("GVector21"));
886 for(int i=0;i<length;i++) {
887 values[i] = (1-alpha)*v1.values[i] + alpha*v2.values[i];
892 * Linearly interpolates between this vector and vector v1 and
893 * places the result into this tuple: this = (1-alpha)*this + alpha*v1.
894 * @param v1 the first vector
895 * @param alpha the alpha interpolation parameter
897 public final void interpolate(GVector v1, double alpha)
899 if( v1.length != length )
900 throw new MismatchedSizeException(VecMathI18N.getString("GVector22"));
902 for(int i=0;i<length;i++) {
903 values[i] = (1-alpha)*values[i] + alpha*v1.values[i];
908 * Creates a new object of the same class as this object.
910 * @return a clone of this instance.
911 * @exception OutOfMemoryError if there is not enough memory.
912 * @see java.lang.Cloneable
915 public Object clone() {
918 v1 = (GVector)super.clone();
919 } catch (CloneNotSupportedException e) {
920 // this shouldn't happen, since we are Cloneable
921 throw new InternalError();
924 // Also need to clone array of values
925 v1.values = new double[length];
926 for (int i = 0; i < length; i++) {
927 v1.values[i] = values[i];