summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/jogamp/vecmath/Matrix3d.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/jogamp/vecmath/Matrix3d.java')
-rw-r--r--src/main/java/org/jogamp/vecmath/Matrix3d.java3317
1 files changed, 3317 insertions, 0 deletions
diff --git a/src/main/java/org/jogamp/vecmath/Matrix3d.java b/src/main/java/org/jogamp/vecmath/Matrix3d.java
new file mode 100644
index 0000000..afd88f9
--- /dev/null
+++ b/src/main/java/org/jogamp/vecmath/Matrix3d.java
@@ -0,0 +1,3317 @@
+/*
+ * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package org.jogamp.vecmath;
+
+
+/**
+ * A double precision floating point 3 by 3 matrix.
+ * Primarily to support 3D rotations.
+ *
+ */
+public class Matrix3d implements java.io.Serializable, Cloneable {
+
+ // Compatible with 1.1
+ static final long serialVersionUID = 6837536777072402710L;
+
+ /**
+ * The first matrix element in the first row.
+ */
+ public double m00;
+
+ /**
+ * The second matrix element in the first row.
+ */
+ public double m01;
+
+ /**
+ * The third matrix element in the first row.
+ */
+ public double m02;
+
+ /**
+ * The first matrix element in the second row.
+ */
+ public double m10;
+
+ /**
+ * The second matrix element in the second row.
+ */
+ public double m11;
+
+ /**
+ * The third matrix element in the second row.
+ */
+ public double m12;
+
+ /**
+ * The first matrix element in the third row.
+ */
+ public double m20;
+
+ /**
+ * The second matrix element in the third row.
+ */
+ public double m21;
+
+ /**
+ * The third matrix element in the third row.
+ */
+ public double m22;
+
+ //double[] tmp = new double[9]; // scratch matrix
+ //double[] tmp_rot = new double[9]; // scratch matrix
+ //double[] tmp_scale = new double[3]; // scratch matrix
+ private static final double EPS = 1.110223024E-16;
+
+ /**
+ * Constructs and initializes a Matrix3d from the specified nine values.
+ * @param m00 the [0][0] element
+ * @param m01 the [0][1] element
+ * @param m02 the [0][2] element
+ * @param m10 the [1][0] element
+ * @param m11 the [1][1] element
+ * @param m12 the [1][2] element
+ * @param m20 the [2][0] element
+ * @param m21 the [2][1] element
+ * @param m22 the [2][2] element
+ */
+ public Matrix3d(double m00, double m01, double m02,
+ double m10, double m11, double m12,
+ double m20, double m21, double m22)
+ {
+ this.m00 = m00;
+ this.m01 = m01;
+ this.m02 = m02;
+
+ this.m10 = m10;
+ this.m11 = m11;
+ this.m12 = m12;
+
+ this.m20 = m20;
+ this.m21 = m21;
+ this.m22 = m22;
+
+ }
+
+ /**
+ * Constructs and initializes a Matrix3d from the specified nine-
+ * element array.
+ * @param v the array of length 9 containing in order
+ */
+ public Matrix3d(double[] v)
+ {
+ this.m00 = v[0];
+ this.m01 = v[1];
+ this.m02 = v[2];
+
+ this.m10 = v[3];
+ this.m11 = v[4];
+ this.m12 = v[5];
+
+ this.m20 = v[6];
+ this.m21 = v[7];
+ this.m22 = v[8];
+
+ }
+
+ /**
+ * Constructs a new matrix with the same values as the
+ * Matrix3d parameter.
+ * @param m1 the source matrix
+ */
+ public Matrix3d(Matrix3d m1)
+ {
+ this.m00 = m1.m00;
+ this.m01 = m1.m01;
+ this.m02 = m1.m02;
+
+ this.m10 = m1.m10;
+ this.m11 = m1.m11;
+ this.m12 = m1.m12;
+
+ this.m20 = m1.m20;
+ this.m21 = m1.m21;
+ this.m22 = m1.m22;
+
+ }
+
+ /**
+ * Constructs a new matrix with the same values as the
+ * Matrix3f parameter.
+ * @param m1 the source matrix
+ */
+ public Matrix3d(Matrix3f m1)
+ {
+ this.m00 = m1.m00;
+ this.m01 = m1.m01;
+ this.m02 = m1.m02;
+
+ this.m10 = m1.m10;
+ this.m11 = m1.m11;
+ this.m12 = m1.m12;
+
+ this.m20 = m1.m20;
+ this.m21 = m1.m21;
+ this.m22 = m1.m22;
+
+ }
+
+ /**
+ * Constructs and initializes a Matrix3d to all zeros.
+ */
+ public Matrix3d()
+ {
+ this.m00 = 0.0;
+ this.m01 = 0.0;
+ this.m02 = 0.0;
+
+ this.m10 = 0.0;
+ this.m11 = 0.0;
+ this.m12 = 0.0;
+
+ this.m20 = 0.0;
+ this.m21 = 0.0;
+ this.m22 = 0.0;
+
+ }
+
+ /**
+ * Returns a string that contains the values of this Matrix3d.
+ * @return the String representation
+ */
+ @Override
+ public String toString() {
+ return
+ this.m00 + ", " + this.m01 + ", " + this.m02 + "\n" +
+ this.m10 + ", " + this.m11 + ", " + this.m12 + "\n" +
+ this.m20 + ", " + this.m21 + ", " + this.m22 + "\n";
+ }
+
+ /**
+ * Sets this Matrix3d to identity.
+ */
+ public final void setIdentity()
+ {
+ this.m00 = 1.0;
+ this.m01 = 0.0;
+ this.m02 = 0.0;
+
+ this.m10 = 0.0;
+ this.m11 = 1.0;
+ this.m12 = 0.0;
+
+ this.m20 = 0.0;
+ this.m21 = 0.0;
+ this.m22 = 1.0;
+ }
+
+ /**
+ * Sets the scale component of the current matrix by factoring
+ * out the current scale (by doing an SVD) and multiplying by
+ * the new scale.
+ * @param scale the new scale amount
+ */
+ public final void setScale(double scale)
+ {
+
+ double[] tmp_rot = new double[9]; // scratch matrix
+ double[] tmp_scale = new double[3]; // scratch matrix
+
+ getScaleRotate(tmp_scale, tmp_rot);
+
+ this.m00 = tmp_rot[0] * scale;
+ this.m01 = tmp_rot[1] * scale;
+ this.m02 = tmp_rot[2] * scale;
+
+ this.m10 = tmp_rot[3] * scale;
+ this.m11 = tmp_rot[4] * scale;
+ this.m12 = tmp_rot[5] * scale;
+
+ this.m20 = tmp_rot[6] * scale;
+ this.m21 = tmp_rot[7] * scale;
+ this.m22 = tmp_rot[8] * scale;
+ }
+
+ /**
+ * Sets the specified element of this matrix3f to the value provided.
+ * @param row the row number to be modified (zero indexed)
+ * @param column the column number to be modified (zero indexed)
+ * @param value the new value
+ */
+ public final void setElement(int row, int column, double value)
+ {
+ switch (row)
+ {
+ case 0:
+ switch(column)
+ {
+ case 0:
+ this.m00 = value;
+ break;
+ case 1:
+ this.m01 = value;
+ break;
+ case 2:
+ this.m02 = value;
+ break;
+ default:
+ throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix3d0"));
+ }
+ break;
+
+ case 1:
+ switch(column)
+ {
+ case 0:
+ this.m10 = value;
+ break;
+ case 1:
+ this.m11 = value;
+ break;
+ case 2:
+ this.m12 = value;
+ break;
+ default:
+ throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix3d0"));
+ }
+ break;
+
+
+ case 2:
+ switch(column)
+ {
+ case 0:
+ this.m20 = value;
+ break;
+ case 1:
+ this.m21 = value;
+ break;
+ case 2:
+ this.m22 = value;
+ break;
+ default:
+ throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix3d0"));
+ }
+ break;
+
+ default:
+ throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix3d0"));
+ }
+ }
+
+ /**
+ * Retrieves the value at the specified row and column of the specified
+ * matrix.
+ * @param row the row number to be retrieved (zero indexed)
+ * @param column the column number to be retrieved (zero indexed)
+ * @return the value at the indexed element.
+ */
+ public final double getElement(int row, int column)
+ {
+ switch (row)
+ {
+ case 0:
+ switch(column)
+ {
+ case 0:
+ return(this.m00);
+ case 1:
+ return(this.m01);
+ case 2:
+ return(this.m02);
+ default:
+ break;
+ }
+ break;
+ case 1:
+ switch(column)
+ {
+ case 0:
+ return(this.m10);
+ case 1:
+ return(this.m11);
+ case 2:
+ return(this.m12);
+ default:
+ break;
+ }
+ break;
+
+ case 2:
+ switch(column)
+ {
+ case 0:
+ return(this.m20);
+ case 1:
+ return(this.m21);
+ case 2:
+ return(this.m22);
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix3d1"));
+ }
+
+ /**
+ * Copies the matrix values in the specified row into the vector parameter.
+ * @param row the matrix row
+ * @param v the vector into which the matrix row values will be copied
+ */
+ public final void getRow(int row, Vector3d v) {
+ if( row == 0 ) {
+ v.x = m00;
+ v.y = m01;
+ v.z = m02;
+ } else if(row == 1) {
+ v.x = m10;
+ v.y = m11;
+ v.z = m12;
+ } else if(row == 2) {
+ v.x = m20;
+ v.y = m21;
+ v.z = m22;
+ } else {
+ throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix3d2"));
+ }
+
+ }
+
+ /**
+ * Copies the matrix values in the specified row into the array parameter.
+ * @param row the matrix row
+ * @param v the array into which the matrix row values will be copied
+ */
+ public final void getRow(int row, double v[]) {
+ if( row == 0 ) {
+ v[0] = m00;
+ v[1] = m01;
+ v[2] = m02;
+ } else if(row == 1) {
+ v[0] = m10;
+ v[1] = m11;
+ v[2] = m12;
+ } else if(row == 2) {
+ v[0] = m20;
+ v[1] = m21;
+ v[2] = m22;
+ } else {
+ throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix3d2"));
+ }
+
+ }
+
+ /**
+ * Copies the matrix values in the specified column into the vector
+ * parameter.
+ * @param column the matrix column
+ * @param v the vector into which the matrix row values will be copied
+ */
+ public final void getColumn(int column, Vector3d v) {
+ if( column == 0 ) {
+ v.x = m00;
+ v.y = m10;
+ v.z = m20;
+ } else if(column == 1) {
+ v.x = m01;
+ v.y = m11;
+ v.z = m21;
+ }else if(column == 2){
+ v.x = m02;
+ v.y = m12;
+ v.z = m22;
+ } else {
+ throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix3d4"));
+ }
+
+ }
+
+ /**
+ * Copies the matrix values in the specified column into the array
+ * parameter.
+ * @param column the matrix column
+ * @param v the array into which the matrix row values will be copied
+ */
+ public final void getColumn(int column, double v[]) {
+ if( column == 0 ) {
+ v[0] = m00;
+ v[1] = m10;
+ v[2] = m20;
+ } else if(column == 1) {
+ v[0] = m01;
+ v[1] = m11;
+ v[2] = m21;
+ }else if(column == 2) {
+ v[0] = m02;
+ v[1] = m12;
+ v[2] = m22;
+ }else {
+ throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix3d4"));
+ }
+
+ }
+
+
+ /**
+ * Sets the specified row of this matrix3d to the 4 values provided.
+ * @param row the row number to be modified (zero indexed)
+ * @param x the first column element
+ * @param y the second column element
+ * @param z the third column element
+ */
+ public final void setRow(int row, double x, double y, double z)
+ {
+ switch (row) {
+ case 0:
+ this.m00 = x;
+ this.m01 = y;
+ this.m02 = z;
+ break;
+
+ case 1:
+ this.m10 = x;
+ this.m11 = y;
+ this.m12 = z;
+ break;
+
+ case 2:
+ this.m20 = x;
+ this.m21 = y;
+ this.m22 = z;
+ break;
+
+ default:
+ throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix3d6"));
+ }
+ }
+
+ /**
+ * Sets the specified row of this matrix3d to the Vector provided.
+ * @param row the row number to be modified (zero indexed)
+ * @param v the replacement row
+ */
+ public final void setRow(int row, Vector3d v)
+ {
+ switch (row) {
+ case 0:
+ this.m00 = v.x;
+ this.m01 = v.y;
+ this.m02 = v.z;
+ break;
+
+ case 1:
+ this.m10 = v.x;
+ this.m11 = v.y;
+ this.m12 = v.z;
+ break;
+
+ case 2:
+ this.m20 = v.x;
+ this.m21 = v.y;
+ this.m22 = v.z;
+ break;
+
+ default:
+ throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix3d6"));
+ }
+ }
+
+ /**
+ * Sets the specified row of this matrix3d to the three values provided.
+ * @param row the row number to be modified (zero indexed)
+ * @param v the replacement row
+ */
+ public final void setRow(int row, double v[])
+ {
+ switch (row) {
+ case 0:
+ this.m00 = v[0];
+ this.m01 = v[1];
+ this.m02 = v[2];
+ break;
+
+ case 1:
+ this.m10 = v[0];
+ this.m11 = v[1];
+ this.m12 = v[2];
+ break;
+
+ case 2:
+ this.m20 = v[0];
+ this.m21 = v[1];
+ this.m22 = v[2];
+ break;
+
+ default:
+ throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix3d6"));
+ }
+ }
+
+ /**
+ * Sets the specified column of this matrix3d to the three values provided.
+ * @param column the column number to be modified (zero indexed)
+ * @param x the first row element
+ * @param y the second row element
+ * @param z the third row element
+ */
+ public final void setColumn(int column, double x, double y, double z)
+ {
+ switch (column) {
+ case 0:
+ this.m00 = x;
+ this.m10 = y;
+ this.m20 = z;
+ break;
+
+ case 1:
+ this.m01 = x;
+ this.m11 = y;
+ this.m21 = z;
+ break;
+
+ case 2:
+ this.m02 = x;
+ this.m12 = y;
+ this.m22 = z;
+ break;
+
+ default:
+ throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix3d9"));
+ }
+ }
+
+ /**
+ * Sets the specified column of this matrix3d to the vector provided.
+ * @param column the column number to be modified (zero indexed)
+ * @param v the replacement column
+ */
+ public final void setColumn(int column, Vector3d v)
+ {
+ switch (column) {
+ case 0:
+ this.m00 = v.x;
+ this.m10 = v.y;
+ this.m20 = v.z;
+ break;
+
+ case 1:
+ this.m01 = v.x;
+ this.m11 = v.y;
+ this.m21 = v.z;
+ break;
+
+ case 2:
+ this.m02 = v.x;
+ this.m12 = v.y;
+ this.m22 = v.z;
+ break;
+
+ default:
+ throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix3d9"));
+ }
+ }
+
+ /**
+ * Sets the specified column of this matrix3d to the three values provided.
+ * @param column the column number to be modified (zero indexed)
+ * @param v the replacement column
+ */
+ public final void setColumn(int column, double v[])
+ {
+ switch (column) {
+ case 0:
+ this.m00 = v[0];
+ this.m10 = v[1];
+ this.m20 = v[2];
+ break;
+
+ case 1:
+ this.m01 = v[0];
+ this.m11 = v[1];
+ this.m21 = v[2];
+ break;
+
+ case 2:
+ this.m02 = v[0];
+ this.m12 = v[1];
+ this.m22 = v[2];
+ break;
+
+ default:
+ throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix3d9"));
+ }
+ }
+
+ /**
+ * Performs an SVD normalization of this matrix to calculate
+ * and return the uniform scale factor. If the matrix has non-uniform
+ * scale factors, the largest of the x, y, and z scale factors will
+ * be returned. This matrix is not modified.
+ * @return the scale factor of this matrix
+ */
+ public final double getScale()
+ {
+
+ double[] tmp_scale = new double[3]; // scratch matrix
+ double[] tmp_rot = new double[9]; // scratch matrix
+ getScaleRotate(tmp_scale, tmp_rot);
+
+ return( max3(tmp_scale) );
+
+ }
+
+ /**
+ * Adds a scalar to each component of this matrix.
+ * @param scalar the scalar adder
+ */
+ public final void add(double scalar)
+ {
+ m00 += scalar;
+ m01 += scalar;
+ m02 += scalar;
+
+ m10 += scalar;
+ m11 += scalar;
+ m12 += scalar;
+
+ m20 += scalar;
+ m21 += scalar;
+ m22 += scalar;
+
+ }
+
+ /**
+ * Adds a scalar to each component of the matrix m1 and places
+ * the result into this. Matrix m1 is not modified.
+ * @param scalar the scalar adder
+ * @param m1 the original matrix values
+ */
+ public final void add(double scalar, Matrix3d m1)
+ {
+ this.m00 = m1.m00 + scalar;
+ this.m01 = m1.m01 + scalar;
+ this.m02 = m1.m02 + scalar;
+
+ this.m10 = m1.m10 + scalar;
+ this.m11 = m1.m11 + scalar;
+ this.m12 = m1.m12 + scalar;
+
+ this.m20 = m1.m20 + scalar;
+ this.m21 = m1.m21 + scalar;
+ this.m22 = m1.m22 + scalar;
+ }
+
+ /**
+ * Sets the value of this matrix to the matrix sum of matrices m1 and m2.
+ * @param m1 the first matrix
+ * @param m2 the second matrix
+ */
+ public final void add(Matrix3d m1, Matrix3d m2)
+ {
+ this.m00 = m1.m00 + m2.m00;
+ this.m01 = m1.m01 + m2.m01;
+ this.m02 = m1.m02 + m2.m02;
+
+ this.m10 = m1.m10 + m2.m10;
+ this.m11 = m1.m11 + m2.m11;
+ this.m12 = m1.m12 + m2.m12;
+
+ this.m20 = m1.m20 + m2.m20;
+ this.m21 = m1.m21 + m2.m21;
+ this.m22 = m1.m22 + m2.m22;
+ }
+
+ /**
+ * Sets the value of this matrix to the sum of itself and matrix m1.
+ * @param m1 the other matrix
+ */
+ public final void add(Matrix3d m1)
+ {
+ this.m00 += m1.m00;
+ this.m01 += m1.m01;
+ this.m02 += m1.m02;
+
+ this.m10 += m1.m10;
+ this.m11 += m1.m11;
+ this.m12 += m1.m12;
+
+ this.m20 += m1.m20;
+ this.m21 += m1.m21;
+ this.m22 += m1.m22;
+ }
+
+ /**
+ * Sets the value of this matrix to the matrix difference
+ * of matrices m1 and m2.
+ * @param m1 the first matrix
+ * @param m2 the second matrix
+ */
+ public final void sub(Matrix3d m1, Matrix3d m2)
+ {
+ this.m00 = m1.m00 - m2.m00;
+ this.m01 = m1.m01 - m2.m01;
+ this.m02 = m1.m02 - m2.m02;
+
+ this.m10 = m1.m10 - m2.m10;
+ this.m11 = m1.m11 - m2.m11;
+ this.m12 = m1.m12 - m2.m12;
+
+ this.m20 = m1.m20 - m2.m20;
+ this.m21 = m1.m21 - m2.m21;
+ this.m22 = m1.m22 - m2.m22;
+ }
+
+ /**
+ * Sets the value of this matrix to the matrix difference of itself and
+ * matrix m1 (this = this - m1).
+ * @param m1 the other matrix
+ */
+ public final void sub(Matrix3d m1)
+ {
+ this.m00 -= m1.m00;
+ this.m01 -= m1.m01;
+ this.m02 -= m1.m02;
+
+ this.m10 -= m1.m10;
+ this.m11 -= m1.m11;
+ this.m12 -= m1.m12;
+
+ this.m20 -= m1.m20;
+ this.m21 -= m1.m21;
+ this.m22 -= m1.m22;
+ }
+
+ /**
+ * Sets the value of this matrix to its transpose.
+ */
+ public final void transpose()
+ {
+ double temp;
+
+ temp = this.m10;
+ this.m10 = this.m01;
+ this.m01 = temp;
+
+ temp = this.m20;
+ this.m20 = this.m02;
+ this.m02 = temp;
+
+ temp = this.m21;
+ this.m21 = this.m12;
+ this.m12 = temp;
+ }
+
+ /**
+ * Sets the value of this matrix to the transpose of the argument matrix.
+ * @param m1 the matrix to be transposed
+ */
+ public final void transpose(Matrix3d m1)
+ {
+ if (this != m1) {
+ this.m00 = m1.m00;
+ this.m01 = m1.m10;
+ this.m02 = m1.m20;
+
+ this.m10 = m1.m01;
+ this.m11 = m1.m11;
+ this.m12 = m1.m21;
+
+ this.m20 = m1.m02;
+ this.m21 = m1.m12;
+ this.m22 = m1.m22;
+ } else
+ this.transpose();
+ }
+
+ /**
+ * Sets the value of this matrix to the matrix conversion of the
+ * double precision quaternion argument.
+ * @param q1 the quaternion to be converted
+ */
+ public final void set(Quat4d q1)
+ {
+ this.m00 = (1.0 - 2.0*q1.y*q1.y - 2.0*q1.z*q1.z);
+ this.m10 = (2.0*(q1.x*q1.y + q1.w*q1.z));
+ this.m20 = (2.0*(q1.x*q1.z - q1.w*q1.y));
+
+ this.m01 = (2.0*(q1.x*q1.y - q1.w*q1.z));
+ this.m11 = (1.0 - 2.0*q1.x*q1.x - 2.0*q1.z*q1.z);
+ this.m21 = (2.0*(q1.y*q1.z + q1.w*q1.x));
+
+ this.m02 = (2.0*(q1.x*q1.z + q1.w*q1.y));
+ this.m12 = (2.0*(q1.y*q1.z - q1.w*q1.x));
+ this.m22 = (1.0 - 2.0*q1.x*q1.x - 2.0*q1.y*q1.y);
+ }
+
+ /**
+ * Sets the value of this matrix to the matrix conversion of the
+ * double precision axis and angle argument.
+ * @param a1 the axis and angle to be converted
+ */
+ public final void set(AxisAngle4d a1)
+ {
+ double mag = Math.sqrt( a1.x*a1.x + a1.y*a1.y + a1.z*a1.z);
+
+ if( mag < EPS ) {
+ m00 = 1.0;
+ m01 = 0.0;
+ m02 = 0.0;
+
+ m10 = 0.0;
+ m11 = 1.0;
+ m12 = 0.0;
+
+ m20 = 0.0;
+ m21 = 0.0;
+ m22 = 1.0;
+ } else {
+ mag = 1.0/mag;
+ double ax = a1.x*mag;
+ double ay = a1.y*mag;
+ double az = a1.z*mag;
+
+ double sinTheta = Math.sin(a1.angle);
+ double cosTheta = Math.cos(a1.angle);
+ double t = 1.0 - cosTheta;
+
+ double xz = ax * az;
+ double xy = ax * ay;
+ double yz = ay * az;
+
+ m00 = t * ax * ax + cosTheta;
+ m01 = t * xy - sinTheta * az;
+ m02 = t * xz + sinTheta * ay;
+
+ m10 = t * xy + sinTheta * az;
+ m11 = t * ay * ay + cosTheta;
+ m12 = t * yz - sinTheta * ax;
+
+ m20 = t * xz - sinTheta * ay;
+ m21 = t * yz + sinTheta * ax;
+ m22 = t * az * az + cosTheta;
+ }
+ }
+
+ /**
+ * Sets the value of this matrix to the matrix conversion of the
+ * single precision quaternion argument.
+ * @param q1 the quaternion to be converted
+ */
+ public final void set(Quat4f q1)
+ {
+ this.m00 = (1.0 - 2.0*q1.y*q1.y - 2.0*q1.z*q1.z);
+ this.m10 = (2.0*(q1.x*q1.y + q1.w*q1.z));
+ this.m20 = (2.0*(q1.x*q1.z - q1.w*q1.y));
+
+ this.m01 = (2.0*(q1.x*q1.y - q1.w*q1.z));
+ this.m11 = (1.0 - 2.0*q1.x*q1.x - 2.0*q1.z*q1.z);
+ this.m21 = (2.0*(q1.y*q1.z + q1.w*q1.x));
+
+ this.m02 = (2.0*(q1.x*q1.z + q1.w*q1.y));
+ this.m12 = (2.0*(q1.y*q1.z - q1.w*q1.x));
+ this.m22 = (1.0 - 2.0*q1.x*q1.x - 2.0*q1.y*q1.y);
+ }
+
+ /**
+ * Sets the value of this matrix to the matrix conversion of the
+ * single precision axis and angle argument.
+ * @param a1 the axis and angle to be converted
+ */
+ public final void set(AxisAngle4f a1)
+ {
+ double mag = Math.sqrt( a1.x*a1.x + a1.y*a1.y + a1.z*a1.z);
+ if( mag < EPS ) {
+ m00 = 1.0;
+ m01 = 0.0;
+ m02 = 0.0;
+
+ m10 = 0.0;
+ m11 = 1.0;
+ m12 = 0.0;
+
+ m20 = 0.0;
+ m21 = 0.0;
+ m22 = 1.0;
+ } else {
+ mag = 1.0/mag;
+ double ax = a1.x*mag;
+ double ay = a1.y*mag;
+ double az = a1.z*mag;
+ double sinTheta = Math.sin(a1.angle);
+ double cosTheta = Math.cos(a1.angle);
+ double t = 1.0 - cosTheta;
+
+ double xz = ax * az;
+ double xy = ax * ay;
+ double yz = ay * az;
+
+ m00 = t * ax * ax + cosTheta;
+ m01 = t * xy - sinTheta * az;
+ m02 = t * xz + sinTheta * ay;
+
+ m10 = t * xy + sinTheta * az;
+ m11 = t * ay * ay + cosTheta;
+ m12 = t * yz - sinTheta * ax;
+
+ m20 = t * xz - sinTheta * ay;
+ m21 = t * yz + sinTheta * ax;
+ m22 = t * az * az + cosTheta;
+ }
+ }
+
+ /**
+ * Sets the value of this matrix to the double value of the Matrix3f
+ * argument.
+ * @param m1 the matrix3d to be converted to double
+ */
+ public final void set(Matrix3f m1)
+ {
+ this.m00 = m1.m00;
+ this.m01 = m1.m01;
+ this.m02 = m1.m02;
+
+ this.m10 = m1.m10;
+ this.m11 = m1.m11;
+ this.m12 = m1.m12;
+
+ this.m20 = m1.m20;
+ this.m21 = m1.m21;
+ this.m22 = m1.m22;
+ }
+
+ /**
+ * Sets the value of this matrix to the value of the Matrix3d
+ * argument.
+ * @param m1 the source matrix3d
+ */
+ public final void set(Matrix3d m1)
+ {
+ this.m00 = m1.m00;
+ this.m01 = m1.m01;
+ this.m02 = m1.m02;
+
+ this.m10 = m1.m10;
+ this.m11 = m1.m11;
+ this.m12 = m1.m12;
+
+ this.m20 = m1.m20;
+ this.m21 = m1.m21;
+ this.m22 = m1.m22;
+ }
+
+ /**
+ * Sets the values in this Matrix3d equal to the row-major
+ * array parameter (ie, the first three elements of the
+ * array will be copied into the first row of this matrix, etc.).
+ * @param m the double precision array of length 9
+ */
+ public final void set(double[] m)
+ {
+ m00 = m[0];
+ m01 = m[1];
+ m02 = m[2];
+
+ m10 = m[3];
+ m11 = m[4];
+ m12 = m[5];
+
+ m20 = m[6];
+ m21 = m[7];
+ m22 = m[8];
+
+ }
+
+ /**
+ * Sets the value of this matrix to the matrix inverse
+ * of the passed matrix m1.
+ * @param m1 the matrix to be inverted
+ */
+ public final void invert(Matrix3d m1)
+ {
+ invertGeneral( m1 );
+ }
+
+ /**
+ * Inverts this matrix in place.
+ */
+ public final void invert()
+ {
+ invertGeneral( this );
+ }
+
+ /**
+ * General invert routine. Inverts m1 and places the result in "this".
+ * Note that this routine handles both the "this" version and the
+ * non-"this" version.
+ *
+ * Also note that since this routine is slow anyway, we won't worry
+ * about allocating a little bit of garbage.
+ */
+ private final void invertGeneral(Matrix3d m1) {
+ double result[] = new double[9];
+ int row_perm[] = new int[3];
+ int i;
+ double[] tmp = new double[9]; // scratch matrix
+
+ // Use LU decomposition and backsubstitution code specifically
+ // for floating-point 3x3 matrices.
+
+ // Copy source matrix to t1tmp
+ tmp[0] = m1.m00;
+ tmp[1] = m1.m01;
+ tmp[2] = m1.m02;
+
+ tmp[3] = m1.m10;
+ tmp[4] = m1.m11;
+ tmp[5] = m1.m12;
+
+ tmp[6] = m1.m20;
+ tmp[7] = m1.m21;
+ tmp[8] = m1.m22;
+
+
+ // Calculate LU decomposition: Is the matrix singular?
+ if (!luDecomposition(tmp, row_perm)) {
+ // Matrix has no inverse
+ throw new SingularMatrixException(VecMathI18N.getString("Matrix3d12"));
+ }
+
+ // Perform back substitution on the identity matrix
+ for(i=0;i<9;i++) result[i] = 0.0;
+ result[0] = 1.0; result[4] = 1.0; result[8] = 1.0;
+ luBacksubstitution(tmp, row_perm, result);
+
+ this.m00 = result[0];
+ this.m01 = result[1];
+ this.m02 = result[2];
+
+ this.m10 = result[3];
+ this.m11 = result[4];
+ this.m12 = result[5];
+
+ this.m20 = result[6];
+ this.m21 = result[7];
+ this.m22 = result[8];
+
+ }
+
+ /**
+ * Given a 3x3 array "matrix0", this function replaces it with the
+ * LU decomposition of a row-wise permutation of itself. The input
+ * parameters are "matrix0" and "dimen". The array "matrix0" is also
+ * an output parameter. The vector "row_perm[3]" is an output
+ * parameter that contains the row permutations resulting from partial
+ * pivoting. The output parameter "even_row_xchg" is 1 when the
+ * number of row exchanges is even, or -1 otherwise. Assumes data
+ * type is always double.
+ *
+ * This function is similar to luDecomposition, except that it
+ * is tuned specifically for 3x3 matrices.
+ *
+ * @return true if the matrix is nonsingular, or false otherwise.
+ */
+ //
+ // Reference: Press, Flannery, Teukolsky, Vetterling,
+ // _Numerical_Recipes_in_C_, Cambridge University Press,
+ // 1988, pp 40-45.
+ //
+ static boolean luDecomposition(double[] matrix0,
+ int[] row_perm) {
+
+ double row_scale[] = new double[3];
+
+ // Determine implicit scaling information by looping over rows
+ {
+ int i, j;
+ int ptr, rs;
+ double big, temp;
+
+ ptr = 0;
+ rs = 0;
+
+ // For each row ...
+ i = 3;
+ while (i-- != 0) {
+ big = 0.0;
+
+ // For each column, find the largest element in the row
+ j = 3;
+ while (j-- != 0) {
+ temp = matrix0[ptr++];
+ temp = Math.abs(temp);
+ if (temp > big) {
+ big = temp;
+ }
+ }
+
+ // Is the matrix singular?
+ if (big == 0.0) {
+ return false;
+ }
+ row_scale[rs++] = 1.0 / big;
+ }
+ }
+
+ {
+ int j;
+ int mtx;
+
+ mtx = 0;
+
+ // For all columns, execute Crout's method
+ for (j = 0; j < 3; j++) {
+ int i, imax, k;
+ int target, p1, p2;
+ double sum, big, temp;
+
+ // Determine elements of upper diagonal matrix U
+ for (i = 0; i < j; i++) {
+ target = mtx + (3*i) + j;
+ sum = matrix0[target];
+ k = i;
+ p1 = mtx + (3*i);
+ p2 = mtx + j;
+ while (k-- != 0) {
+ sum -= matrix0[p1] * matrix0[p2];
+ p1++;
+ p2 += 3;
+ }
+ matrix0[target] = sum;
+ }
+
+ // Search for largest pivot element and calculate
+ // intermediate elements of lower diagonal matrix L.
+ big = 0.0;
+ imax = -1;
+ for (i = j; i < 3; i++) {
+ target = mtx + (3*i) + j;
+ sum = matrix0[target];
+ k = j;
+ p1 = mtx + (3*i);
+ p2 = mtx + j;
+ while (k-- != 0) {
+ sum -= matrix0[p1] * matrix0[p2];
+ p1++;
+ p2 += 3;
+ }
+ matrix0[target] = sum;
+
+ // Is this the best pivot so far?
+ if ((temp = row_scale[i] * Math.abs(sum)) >= big) {
+ big = temp;
+ imax = i;
+ }
+ }
+
+ if (imax < 0) {
+ throw new RuntimeException(VecMathI18N.getString("Matrix3d13"));
+ }
+
+ // Is a row exchange necessary?
+ if (j != imax) {
+ // Yes: exchange rows
+ k = 3;
+ p1 = mtx + (3*imax);
+ p2 = mtx + (3*j);
+ while (k-- != 0) {
+ temp = matrix0[p1];
+ matrix0[p1++] = matrix0[p2];
+ matrix0[p2++] = temp;
+ }
+
+ // Record change in scale factor
+ row_scale[imax] = row_scale[j];
+ }
+
+ // Record row permutation
+ row_perm[j] = imax;
+
+ // Is the matrix singular
+ if (matrix0[(mtx + (3*j) + j)] == 0.0) {
+ return false;
+ }
+
+ // Divide elements of lower diagonal matrix L by pivot
+ if (j != (3-1)) {
+ temp = 1.0 / (matrix0[(mtx + (3*j) + j)]);
+ target = mtx + (3*(j+1)) + j;
+ i = 2 - j;
+ while (i-- != 0) {
+ matrix0[target] *= temp;
+ target += 3;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Solves a set of linear equations. The input parameters "matrix1",
+ * and "row_perm" come from luDecompostionD3x3 and do not change
+ * here. The parameter "matrix2" is a set of column vectors assembled
+ * into a 3x3 matrix of floating-point values. The procedure takes each
+ * column of "matrix2" in turn and treats it as the right-hand side of the
+ * matrix equation Ax = LUx = b. The solution vector replaces the
+ * original column of the matrix.
+ *
+ * If "matrix2" is the identity matrix, the procedure replaces its contents
+ * with the inverse of the matrix from which "matrix1" was originally
+ * derived.
+ */
+ //
+ // Reference: Press, Flannery, Teukolsky, Vetterling,
+ // _Numerical_Recipes_in_C_, Cambridge University Press,
+ // 1988, pp 44-45.
+ //
+ static void luBacksubstitution(double[] matrix1,
+ int[] row_perm,
+ double[] matrix2) {
+
+ int i, ii, ip, j, k;
+ int rp;
+ int cv, rv;
+
+ // rp = row_perm;
+ rp = 0;
+
+ // For each column vector of matrix2 ...
+ for (k = 0; k < 3; k++) {
+ // cv = &(matrix2[0][k]);
+ cv = k;
+ ii = -1;
+
+ // Forward substitution
+ for (i = 0; i < 3; i++) {
+ double sum;
+
+ ip = row_perm[rp+i];
+ sum = matrix2[cv+3*ip];
+ matrix2[cv+3*ip] = matrix2[cv+3*i];
+ if (ii >= 0) {
+ // rv = &(matrix1[i][0]);
+ rv = i*3;
+ for (j = ii; j <= i-1; j++) {
+ sum -= matrix1[rv+j] * matrix2[cv+3*j];
+ }
+ }
+ else if (sum != 0.0) {
+ ii = i;
+ }
+ matrix2[cv+3*i] = sum;
+ }
+
+ // Backsubstitution
+ // rv = &(matrix1[3][0]);
+ rv = 2*3;
+ matrix2[cv+3*2] /= matrix1[rv+2];
+
+ rv -= 3;
+ matrix2[cv+3*1] = (matrix2[cv+3*1] -
+ matrix1[rv+2] * matrix2[cv+3*2]) / matrix1[rv+1];
+
+ rv -= 3;
+ matrix2[cv+4*0] = (matrix2[cv+3*0] -
+ matrix1[rv+1] * matrix2[cv+3*1] -
+ matrix1[rv+2] * matrix2[cv+3*2]) / matrix1[rv+0];
+
+ }
+ }
+
+ /**
+ * Computes the determinant of this matrix.
+ * @return the determinant of the matrix
+ */
+ public final double determinant()
+ {
+ double total;
+
+ total = this.m00*(this.m11*this.m22 - this.m12*this.m21)
+ + this.m01*(this.m12*this.m20 - this.m10*this.m22)
+ + this.m02*(this.m10*this.m21 - this.m11*this.m20);
+ return total;
+ }
+
+ /**
+ * Sets the value of this matrix to a scale matrix with
+ * the passed scale amount.
+ * @param scale the scale factor for the matrix
+ */
+ public final void set(double scale)
+ {
+ this.m00 = scale;
+ this.m01 = 0.0;
+ this.m02 = 0.0;
+
+ this.m10 = 0.0;
+ this.m11 = scale;
+ this.m12 = 0.0;
+
+ this.m20 = 0.0;
+ this.m21 = 0.0;
+ this.m22 = scale;
+ }
+
+ /**
+ * Sets the value of this matrix to a counter clockwise rotation
+ * about the x axis.
+ * @param angle the angle to rotate about the X axis in radians
+ */
+ public final void rotX(double angle)
+ {
+ double sinAngle, cosAngle;
+
+ sinAngle = Math.sin(angle);
+ cosAngle = Math.cos(angle);
+
+ this.m00 = 1.0;
+ this.m01 = 0.0;
+ this.m02 = 0.0;
+
+ this.m10 = 0.0;
+ this.m11 = cosAngle;
+ this.m12 = -sinAngle;
+
+ this.m20 = 0.0;
+ this.m21 = sinAngle;
+ this.m22 = cosAngle;
+ }
+
+ /**
+ * Sets the value of this matrix to a counter clockwise rotation
+ * about the y axis.
+ * @param angle the angle to rotate about the Y axis in radians
+ */
+ public final void rotY(double angle)
+ {
+ double sinAngle, cosAngle;
+
+ sinAngle = Math.sin(angle);
+ cosAngle = Math.cos(angle);
+
+ this.m00 = cosAngle;
+ this.m01 = 0.0;
+ this.m02 = sinAngle;
+
+ this.m10 = 0.0;
+ this.m11 = 1.0;
+ this.m12 = 0.0;
+
+ this.m20 = -sinAngle;
+ this.m21 = 0.0;
+ this.m22 = cosAngle;
+ }
+
+ /**
+ * Sets the value of this matrix to a counter clockwise rotation
+ * about the z axis.
+ * @param angle the angle to rotate about the Z axis in radians
+ */
+ public final void rotZ(double angle)
+ {
+ double sinAngle, cosAngle;
+
+ sinAngle = Math.sin(angle);
+ cosAngle = Math.cos(angle);
+
+ this.m00 = cosAngle;
+ this.m01 = -sinAngle;
+ this.m02 = 0.0;
+
+ this.m10 = sinAngle;
+ this.m11 = cosAngle;
+ this.m12 = 0.0;
+
+ this.m20 = 0.0;
+ this.m21 = 0.0;
+ this.m22 = 1.0;
+ }
+
+ /**
+ * Multiplies each element of this matrix by a scalar.
+ * @param scalar The scalar multiplier.
+ */
+ public final void mul(double scalar)
+ {
+ m00 *= scalar;
+ m01 *= scalar;
+ m02 *= scalar;
+
+ m10 *= scalar;
+ m11 *= scalar;
+ m12 *= scalar;
+
+ m20 *= scalar;
+ m21 *= scalar;
+ m22 *= scalar;
+
+ }
+
+ /**
+ * Multiplies each element of matrix m1 by a scalar and places
+ * the result into this. Matrix m1 is not modified.
+ * @param scalar the scalar multiplier
+ * @param m1 the original matrix
+ */
+ public final void mul(double scalar, Matrix3d m1)
+ {
+ this.m00 = scalar * m1.m00;
+ this.m01 = scalar * m1.m01;
+ this.m02 = scalar * m1.m02;
+
+ this.m10 = scalar * m1.m10;
+ this.m11 = scalar * m1.m11;
+ this.m12 = scalar * m1.m12;
+
+ this.m20 = scalar * m1.m20;
+ this.m21 = scalar * m1.m21;
+ this.m22 = scalar * m1.m22;
+
+ }
+
+ /**
+ * Sets the value of this matrix to the result of multiplying itself
+ * with matrix m1.
+ * @param m1 the other matrix
+ */
+ public final void mul(Matrix3d m1)
+ {
+ double m00, m01, m02,
+ m10, m11, m12,
+ m20, m21, m22;
+
+ m00 = this.m00*m1.m00 + this.m01*m1.m10 + this.m02*m1.m20;
+ m01 = this.m00*m1.m01 + this.m01*m1.m11 + this.m02*m1.m21;
+ m02 = this.m00*m1.m02 + this.m01*m1.m12 + this.m02*m1.m22;
+
+ m10 = this.m10*m1.m00 + this.m11*m1.m10 + this.m12*m1.m20;
+ m11 = this.m10*m1.m01 + this.m11*m1.m11 + this.m12*m1.m21;
+ m12 = this.m10*m1.m02 + this.m11*m1.m12 + this.m12*m1.m22;
+
+ m20 = this.m20*m1.m00 + this.m21*m1.m10 + this.m22*m1.m20;
+ m21 = this.m20*m1.m01 + this.m21*m1.m11 + this.m22*m1.m21;
+ m22 = this.m20*m1.m02 + this.m21*m1.m12 + this.m22*m1.m22;
+
+ this.m00 = m00; this.m01 = m01; this.m02 = m02;
+ this.m10 = m10; this.m11 = m11; this.m12 = m12;
+ this.m20 = m20; this.m21 = m21; this.m22 = m22;
+ }
+
+ /**
+ * Sets the value of this matrix to the result of multiplying
+ * the two argument matrices together.
+ * @param m1 the first matrix
+ * @param m2 the second matrix
+ */
+ public final void mul(Matrix3d m1, Matrix3d m2)
+ {
+ if (this != m1 && this != m2) {
+ this.m00 = m1.m00*m2.m00 + m1.m01*m2.m10 + m1.m02*m2.m20;
+ this.m01 = m1.m00*m2.m01 + m1.m01*m2.m11 + m1.m02*m2.m21;
+ this.m02 = m1.m00*m2.m02 + m1.m01*m2.m12 + m1.m02*m2.m22;
+
+ this.m10 = m1.m10*m2.m00 + m1.m11*m2.m10 + m1.m12*m2.m20;
+ this.m11 = m1.m10*m2.m01 + m1.m11*m2.m11 + m1.m12*m2.m21;
+ this.m12 = m1.m10*m2.m02 + m1.m11*m2.m12 + m1.m12*m2.m22;
+
+ this.m20 = m1.m20*m2.m00 + m1.m21*m2.m10 + m1.m22*m2.m20;
+ this.m21 = m1.m20*m2.m01 + m1.m21*m2.m11 + m1.m22*m2.m21;
+ this.m22 = m1.m20*m2.m02 + m1.m21*m2.m12 + m1.m22*m2.m22;
+ } else {
+ double m00, m01, m02,
+ m10, m11, m12,
+ m20, m21, m22; // vars for temp result matrix
+
+ m00 = m1.m00*m2.m00 + m1.m01*m2.m10 + m1.m02*m2.m20;
+ m01 = m1.m00*m2.m01 + m1.m01*m2.m11 + m1.m02*m2.m21;
+ m02 = m1.m00*m2.m02 + m1.m01*m2.m12 + m1.m02*m2.m22;
+
+ m10 = m1.m10*m2.m00 + m1.m11*m2.m10 + m1.m12*m2.m20;
+ m11 = m1.m10*m2.m01 + m1.m11*m2.m11 + m1.m12*m2.m21;
+ m12 = m1.m10*m2.m02 + m1.m11*m2.m12 + m1.m12*m2.m22;
+
+ m20 = m1.m20*m2.m00 + m1.m21*m2.m10 + m1.m22*m2.m20;
+ m21 = m1.m20*m2.m01 + m1.m21*m2.m11 + m1.m22*m2.m21;
+ m22 = m1.m20*m2.m02 + m1.m21*m2.m12 + m1.m22*m2.m22;
+
+ this.m00 = m00; this.m01 = m01; this.m02 = m02;
+ this.m10 = m10; this.m11 = m11; this.m12 = m12;
+ this.m20 = m20; this.m21 = m21; this.m22 = m22;
+ }
+ }
+
+ /**
+ * Multiplies this matrix by matrix m1, does an SVD normalization
+ * of the result, and places the result back into this matrix
+ * this = SVDnorm(this*m1).
+ * @param m1 the matrix on the right hand side of the multiplication
+ */
+ public final void mulNormalize(Matrix3d m1){
+
+ double[] tmp = new double[9]; // scratch matrix
+ double[] tmp_rot = new double[9]; // scratch matrix
+ double[] tmp_scale = new double[3]; // scratch matrix
+
+ tmp[0] = this.m00*m1.m00 + this.m01*m1.m10 + this.m02*m1.m20;
+ tmp[1] = this.m00*m1.m01 + this.m01*m1.m11 + this.m02*m1.m21;
+ tmp[2] = this.m00*m1.m02 + this.m01*m1.m12 + this.m02*m1.m22;
+
+ tmp[3] = this.m10*m1.m00 + this.m11*m1.m10 + this.m12*m1.m20;
+ tmp[4] = this.m10*m1.m01 + this.m11*m1.m11 + this.m12*m1.m21;
+ tmp[5] = this.m10*m1.m02 + this.m11*m1.m12 + this.m12*m1.m22;
+
+ tmp[6] = this.m20*m1.m00 + this.m21*m1.m10 + this.m22*m1.m20;
+ tmp[7] = this.m20*m1.m01 + this.m21*m1.m11 + this.m22*m1.m21;
+ tmp[8] = this.m20*m1.m02 + this.m21*m1.m12 + this.m22*m1.m22;
+
+ compute_svd( tmp, tmp_scale, tmp_rot);
+
+ this.m00 = tmp_rot[0];
+ this.m01 = tmp_rot[1];
+ this.m02 = tmp_rot[2];
+
+ this.m10 = tmp_rot[3];
+ this.m11 = tmp_rot[4];
+ this.m12 = tmp_rot[5];
+
+ this.m20 = tmp_rot[6];
+ this.m21 = tmp_rot[7];
+ this.m22 = tmp_rot[8];
+
+ }
+
+
+ /**
+ * Multiplies matrix m1 by matrix m2, does an SVD normalization
+ * of the result, and places the result into this matrix
+ * this = SVDnorm(m1*m2).
+ * @param m1 the matrix on the left hand side of the multiplication
+ * @param m2 the matrix on the right hand side of the multiplication
+ */
+ public final void mulNormalize(Matrix3d m1, Matrix3d m2){
+
+ double[] tmp = new double[9]; // scratch matrix
+ double[] tmp_rot = new double[9]; // scratch matrix
+ double[] tmp_scale = new double[3]; // scratch matrix
+
+ tmp[0] = m1.m00*m2.m00 + m1.m01*m2.m10 + m1.m02*m2.m20;
+ tmp[1] = m1.m00*m2.m01 + m1.m01*m2.m11 + m1.m02*m2.m21;
+ tmp[2] = m1.m00*m2.m02 + m1.m01*m2.m12 + m1.m02*m2.m22;
+
+ tmp[3] = m1.m10*m2.m00 + m1.m11*m2.m10 + m1.m12*m2.m20;
+ tmp[4] = m1.m10*m2.m01 + m1.m11*m2.m11 + m1.m12*m2.m21;
+ tmp[5] = m1.m10*m2.m02 + m1.m11*m2.m12 + m1.m12*m2.m22;
+
+ tmp[6] = m1.m20*m2.m00 + m1.m21*m2.m10 + m1.m22*m2.m20;
+ tmp[7] = m1.m20*m2.m01 + m1.m21*m2.m11 + m1.m22*m2.m21;
+ tmp[8] = m1.m20*m2.m02 + m1.m21*m2.m12 + m1.m22*m2.m22;
+
+ compute_svd( tmp, tmp_scale, tmp_rot);
+
+ this.m00 = tmp_rot[0];
+ this.m01 = tmp_rot[1];
+ this.m02 = tmp_rot[2];
+
+ this.m10 = tmp_rot[3];
+ this.m11 = tmp_rot[4];
+ this.m12 = tmp_rot[5];
+
+ this.m20 = tmp_rot[6];
+ this.m21 = tmp_rot[7];
+ this.m22 = tmp_rot[8];
+
+ }
+
+ /**
+ * Multiplies the transpose of matrix m1 times the transpose of matrix
+ * m2, and places the result into this.
+ * @param m1 the matrix on the left hand side of the multiplication
+ * @param m2 the matrix on the right hand side of the multiplication
+ */
+ public final void mulTransposeBoth(Matrix3d m1, Matrix3d m2)
+ {
+ if (this != m1 && this != m2) {
+ this.m00 = m1.m00*m2.m00 + m1.m10*m2.m01 + m1.m20*m2.m02;
+ this.m01 = m1.m00*m2.m10 + m1.m10*m2.m11 + m1.m20*m2.m12;
+ this.m02 = m1.m00*m2.m20 + m1.m10*m2.m21 + m1.m20*m2.m22;
+
+ this.m10 = m1.m01*m2.m00 + m1.m11*m2.m01 + m1.m21*m2.m02;
+ this.m11 = m1.m01*m2.m10 + m1.m11*m2.m11 + m1.m21*m2.m12;
+ this.m12 = m1.m01*m2.m20 + m1.m11*m2.m21 + m1.m21*m2.m22;
+
+ this.m20 = m1.m02*m2.m00 + m1.m12*m2.m01 + m1.m22*m2.m02;
+ this.m21 = m1.m02*m2.m10 + m1.m12*m2.m11 + m1.m22*m2.m12;
+ this.m22 = m1.m02*m2.m20 + m1.m12*m2.m21 + m1.m22*m2.m22;
+ } else {
+ double m00, m01, m02,
+ m10, m11, m12,
+ m20, m21, m22; // vars for temp result matrix
+
+ m00 = m1.m00*m2.m00 + m1.m10*m2.m01 + m1.m20*m2.m02;
+ m01 = m1.m00*m2.m10 + m1.m10*m2.m11 + m1.m20*m2.m12;
+ m02 = m1.m00*m2.m20 + m1.m10*m2.m21 + m1.m20*m2.m22;
+
+ m10 = m1.m01*m2.m00 + m1.m11*m2.m01 + m1.m21*m2.m02;
+ m11 = m1.m01*m2.m10 + m1.m11*m2.m11 + m1.m21*m2.m12;
+ m12 = m1.m01*m2.m20 + m1.m11*m2.m21 + m1.m21*m2.m22;
+
+ m20 = m1.m02*m2.m00 + m1.m12*m2.m01 + m1.m22*m2.m02;
+ m21 = m1.m02*m2.m10 + m1.m12*m2.m11 + m1.m22*m2.m12;
+ m22 = m1.m02*m2.m20 + m1.m12*m2.m21 + m1.m22*m2.m22;
+
+ this.m00 = m00; this.m01 = m01; this.m02 = m02;
+ this.m10 = m10; this.m11 = m11; this.m12 = m12;
+ this.m20 = m20; this.m21 = m21; this.m22 = m22;
+ }
+
+ }
+
+ /**
+ * Multiplies matrix m1 times the transpose of matrix m2, and
+ * places the result into this.
+ * @param m1 the matrix on the left hand side of the multiplication
+ * @param m2 the matrix on the right hand side of the multiplication
+ */
+ public final void mulTransposeRight(Matrix3d m1, Matrix3d m2)
+ {
+ if (this != m1 && this != m2) {
+ this.m00 = m1.m00*m2.m00 + m1.m01*m2.m01 + m1.m02*m2.m02;
+ this.m01 = m1.m00*m2.m10 + m1.m01*m2.m11 + m1.m02*m2.m12;
+ this.m02 = m1.m00*m2.m20 + m1.m01*m2.m21 + m1.m02*m2.m22;
+
+ this.m10 = m1.m10*m2.m00 + m1.m11*m2.m01 + m1.m12*m2.m02;
+ this.m11 = m1.m10*m2.m10 + m1.m11*m2.m11 + m1.m12*m2.m12;
+ this.m12 = m1.m10*m2.m20 + m1.m11*m2.m21 + m1.m12*m2.m22;
+
+ this.m20 = m1.m20*m2.m00 + m1.m21*m2.m01 + m1.m22*m2.m02;
+ this.m21 = m1.m20*m2.m10 + m1.m21*m2.m11 + m1.m22*m2.m12;
+ this.m22 = m1.m20*m2.m20 + m1.m21*m2.m21 + m1.m22*m2.m22;
+ } else {
+ double m00, m01, m02,
+ m10, m11, m12,
+ m20, m21, m22; // vars for temp result matrix
+
+ m00 = m1.m00*m2.m00 + m1.m01*m2.m01 + m1.m02*m2.m02;
+ m01 = m1.m00*m2.m10 + m1.m01*m2.m11 + m1.m02*m2.m12;
+ m02 = m1.m00*m2.m20 + m1.m01*m2.m21 + m1.m02*m2.m22;
+
+ m10 = m1.m10*m2.m00 + m1.m11*m2.m01 + m1.m12*m2.m02;
+ m11 = m1.m10*m2.m10 + m1.m11*m2.m11 + m1.m12*m2.m12;
+ m12 = m1.m10*m2.m20 + m1.m11*m2.m21 + m1.m12*m2.m22;
+
+ m20 = m1.m20*m2.m00 + m1.m21*m2.m01 + m1.m22*m2.m02;
+ m21 = m1.m20*m2.m10 + m1.m21*m2.m11 + m1.m22*m2.m12;
+ m22 = m1.m20*m2.m20 + m1.m21*m2.m21 + m1.m22*m2.m22;
+
+ this.m00 = m00; this.m01 = m01; this.m02 = m02;
+ this.m10 = m10; this.m11 = m11; this.m12 = m12;
+ this.m20 = m20; this.m21 = m21; this.m22 = m22;
+ }
+ }
+
+
+ /**
+ * Multiplies the transpose of matrix m1 times matrix m2, and
+ * places the result into this.
+ * @param m1 the matrix on the left hand side of the multiplication
+ * @param m2 the matrix on the right hand side of the multiplication
+ */
+ public final void mulTransposeLeft(Matrix3d m1, Matrix3d m2) {
+ if (this != m1 && this != m2) {
+ this.m00 = m1.m00*m2.m00 + m1.m10*m2.m10 + m1.m20*m2.m20;
+ this.m01 = m1.m00*m2.m01 + m1.m10*m2.m11 + m1.m20*m2.m21;
+ this.m02 = m1.m00*m2.m02 + m1.m10*m2.m12 + m1.m20*m2.m22;
+
+ this.m10 = m1.m01*m2.m00 + m1.m11*m2.m10 + m1.m21*m2.m20;
+ this.m11 = m1.m01*m2.m01 + m1.m11*m2.m11 + m1.m21*m2.m21;
+ this.m12 = m1.m01*m2.m02 + m1.m11*m2.m12 + m1.m21*m2.m22;
+
+ this.m20 = m1.m02*m2.m00 + m1.m12*m2.m10 + m1.m22*m2.m20;
+ this.m21 = m1.m02*m2.m01 + m1.m12*m2.m11 + m1.m22*m2.m21;
+ this.m22 = m1.m02*m2.m02 + m1.m12*m2.m12 + m1.m22*m2.m22;
+ } else {
+ double m00, m01, m02,
+ m10, m11, m12,
+ m20, m21, m22; // vars for temp result matrix
+
+ m00 = m1.m00*m2.m00 + m1.m10*m2.m10 + m1.m20*m2.m20;
+ m01 = m1.m00*m2.m01 + m1.m10*m2.m11 + m1.m20*m2.m21;
+ m02 = m1.m00*m2.m02 + m1.m10*m2.m12 + m1.m20*m2.m22;
+
+ m10 = m1.m01*m2.m00 + m1.m11*m2.m10 + m1.m21*m2.m20;
+ m11 = m1.m01*m2.m01 + m1.m11*m2.m11 + m1.m21*m2.m21;
+ m12 = m1.m01*m2.m02 + m1.m11*m2.m12 + m1.m21*m2.m22;
+
+ m20 = m1.m02*m2.m00 + m1.m12*m2.m10 + m1.m22*m2.m20;
+ m21 = m1.m02*m2.m01 + m1.m12*m2.m11 + m1.m22*m2.m21;
+ m22 = m1.m02*m2.m02 + m1.m12*m2.m12 + m1.m22*m2.m22;
+
+ this.m00 = m00; this.m01 = m01; this.m02 = m02;
+ this.m10 = m10; this.m11 = m11; this.m12 = m12;
+ this.m20 = m20; this.m21 = m21; this.m22 = m22;
+ }
+ }
+
+
+
+ /**
+ * Performs singular value decomposition normalization of this matrix.
+ */
+ public final void normalize(){
+ double[] tmp_rot = new double[9]; // scratch matrix
+ double[] tmp_scale = new double[3]; // scratch matrix
+
+ getScaleRotate( tmp_scale, tmp_rot );
+
+ this.m00 = tmp_rot[0];
+ this.m01 = tmp_rot[1];
+ this.m02 = tmp_rot[2];
+
+ this.m10 = tmp_rot[3];
+ this.m11 = tmp_rot[4];
+ this.m12 = tmp_rot[5];
+
+ this.m20 = tmp_rot[6];
+ this.m21 = tmp_rot[7];
+ this.m22 = tmp_rot[8];
+
+ }
+
+
+ /**
+ * Perform singular value decomposition normalization of matrix m1 and
+ * place the normalized values into this.
+ * @param m1 Provides the matrix values to be normalized
+ */
+ public final void normalize(Matrix3d m1){
+
+ double[] tmp = new double[9]; // scratch matrix
+ double[] tmp_rot = new double[9]; // scratch matrix
+ double[] tmp_scale = new double[3]; // scratch matrix
+
+ tmp[0] = m1.m00;
+ tmp[1] = m1.m01;
+ tmp[2] = m1.m02;
+
+ tmp[3] = m1.m10;
+ tmp[4] = m1.m11;
+ tmp[5] = m1.m12;
+
+ tmp[6] = m1.m20;
+ tmp[7] = m1.m21;
+ tmp[8] = m1.m22;
+
+ compute_svd( tmp, tmp_scale, tmp_rot);
+
+ this.m00 = tmp_rot[0];
+ this.m01 = tmp_rot[1];
+ this.m02 = tmp_rot[2];
+
+ this.m10 = tmp_rot[3];
+ this.m11 = tmp_rot[4];
+ this.m12 = tmp_rot[5];
+
+ this.m20 = tmp_rot[6];
+ this.m21 = tmp_rot[7];
+ this.m22 = tmp_rot[8];
+ }
+
+
+ /**
+ * Perform cross product normalization of this matrix.
+ */
+
+ public final void normalizeCP()
+ {
+ double mag = 1.0/Math.sqrt(m00*m00 + m10*m10 + m20*m20);
+ m00 = m00*mag;
+ m10 = m10*mag;
+ m20 = m20*mag;
+
+ mag = 1.0/Math.sqrt(m01*m01 + m11*m11 + m21*m21);
+ m01 = m01*mag;
+ m11 = m11*mag;
+ m21 = m21*mag;
+
+ m02 = m10*m21 - m11*m20;
+ m12 = m01*m20 - m00*m21;
+ m22 = m00*m11 - m01*m10;
+ }
+
+
+ /**
+ * Perform cross product normalization of matrix m1 and place the
+ * normalized values into this.
+ * @param m1 Provides the matrix values to be normalized
+ */
+ public final void normalizeCP(Matrix3d m1)
+ {
+ double mag = 1.0/Math.sqrt(m1.m00*m1.m00 + m1.m10*m1.m10 + m1.m20*m1.m20);
+ m00 = m1.m00*mag;
+ m10 = m1.m10*mag;
+ m20 = m1.m20*mag;
+
+ mag = 1.0/Math.sqrt(m1.m01*m1.m01 + m1.m11*m1.m11 + m1.m21*m1.m21);
+ m01 = m1.m01*mag;
+ m11 = m1.m11*mag;
+ m21 = m1.m21*mag;
+
+ m02 = m10*m21 - m11*m20;
+ m12 = m01*m20 - m00*m21;
+ m22 = m00*m11 - m01*m10;
+ }
+
+ /**
+ * Returns true if all of the data members of Matrix3d m1 are
+ * equal to the corresponding data members in this Matrix3d.
+ * @param m1 the matrix with which the comparison is made
+ * @return true or false
+ */
+ public boolean equals(Matrix3d m1)
+ {
+ try {
+ return(this.m00 == m1.m00 && this.m01 == m1.m01 && this.m02 == m1.m02
+ && this.m10 == m1.m10 && this.m11 == m1.m11 && this.m12 == m1.m12
+ && this.m20 == m1.m20 && this.m21 == m1.m21 && this.m22 == m1.m22);
+ }
+ catch (NullPointerException e2) { return false; }
+
+ }
+
+ /**
+ * Returns true if the Object t1 is of type Matrix3d and all of the
+ * data members of t1 are equal to the corresponding data members in
+ * this Matrix3d.
+ * @param t1 the matrix with which the comparison is made
+ * @return true or false
+ */
+ @Override
+ public boolean equals(Object t1)
+ {
+ try {
+ Matrix3d m2 = (Matrix3d) t1;
+ return(this.m00 == m2.m00 && this.m01 == m2.m01 && this.m02 == m2.m02
+ && this.m10 == m2.m10 && this.m11 == m2.m11 && this.m12 == m2.m12
+ && this.m20 == m2.m20 && this.m21 == m2.m21 && this.m22 == m2.m22);
+ }
+ catch (ClassCastException e1) { return false; }
+ catch (NullPointerException e2) { return false; }
+
+ }
+
+ /**
+ * Returns true if the L-infinite distance between this matrix
+ * and matrix m1 is less than or equal to the epsilon parameter,
+ * otherwise returns false. The L-infinite
+ * distance is equal to
+ * MAX[i=0,1,2 ; j=0,1,2 ; abs(this.m(i,j) - m1.m(i,j)]
+ * @param m1 the matrix to be compared to this matrix
+ * @param epsilon the threshold value
+ */
+ public boolean epsilonEquals(Matrix3d m1, double epsilon)
+ {
+ double diff;
+
+ diff = m00 - m1.m00;
+ if((diff<0?-diff:diff) > epsilon) return false;
+
+ diff = m01 - m1.m01;
+ if((diff<0?-diff:diff) > epsilon) return false;
+
+ diff = m02 - m1.m02;
+ if((diff<0?-diff:diff) > epsilon) return false;
+
+ diff = m10 - m1.m10;
+ if((diff<0?-diff:diff) > epsilon) return false;
+
+ diff = m11 - m1.m11;
+ if((diff<0?-diff:diff) > epsilon) return false;
+
+ diff = m12 - m1.m12;
+ if((diff<0?-diff:diff) > epsilon) return false;
+
+ diff = m20 - m1.m20;
+ if((diff<0?-diff:diff) > epsilon) return false;
+
+ diff = m21 - m1.m21;
+ if((diff<0?-diff:diff) > epsilon) return false;
+
+ diff = m22 - m1.m22;
+ if((diff<0?-diff:diff) > epsilon) return false;
+
+ return true;
+ }
+
+
+ /**
+ * Returns a hash code value based on the data values in this
+ * object. Two different Matrix3d objects with identical data values
+ * (i.e., Matrix3d.equals returns true) will return the same hash
+ * code value. Two objects with different data members may return the
+ * same hash value, although this is not likely.
+ * @return the integer hash code value
+ */
+ @Override
+ public int hashCode() {
+ long bits = 1L;
+ bits = VecMathUtil.hashDoubleBits(bits, m00);
+ bits = VecMathUtil.hashDoubleBits(bits, m01);
+ bits = VecMathUtil.hashDoubleBits(bits, m02);
+ bits = VecMathUtil.hashDoubleBits(bits, m10);
+ bits = VecMathUtil.hashDoubleBits(bits, m11);
+ bits = VecMathUtil.hashDoubleBits(bits, m12);
+ bits = VecMathUtil.hashDoubleBits(bits, m20);
+ bits = VecMathUtil.hashDoubleBits(bits, m21);
+ bits = VecMathUtil.hashDoubleBits(bits, m22);
+ return VecMathUtil.hashFinish(bits);
+ }
+
+
+ /**
+ * Sets this matrix to all zeros.
+ */
+ public final void setZero()
+ {
+ m00 = 0.0;
+ m01 = 0.0;
+ m02 = 0.0;
+
+ m10 = 0.0;
+ m11 = 0.0;
+ m12 = 0.0;
+
+ m20 = 0.0;
+ m21 = 0.0;
+ m22 = 0.0;
+
+ }
+
+ /**
+ * Negates the value of this matrix: this = -this.
+ */
+ public final void negate()
+ {
+ this.m00 = -this.m00;
+ this.m01 = -this.m01;
+ this.m02 = -this.m02;
+
+ this.m10 = -this.m10;
+ this.m11 = -this.m11;
+ this.m12 = -this.m12;
+
+ this.m20 = -this.m20;
+ this.m21 = -this.m21;
+ this.m22 = -this.m22;
+
+ }
+
+ /**
+ * Sets the value of this matrix equal to the negation of
+ * of the Matrix3d parameter.
+ * @param m1 the source matrix
+ */
+ public final void negate(Matrix3d m1)
+ {
+ this.m00 = -m1.m00;
+ this.m01 = -m1.m01;
+ this.m02 = -m1.m02;
+
+ this.m10 = -m1.m10;
+ this.m11 = -m1.m11;
+ this.m12 = -m1.m12;
+
+ this.m20 = -m1.m20;
+ this.m21 = -m1.m21;
+ this.m22 = -m1.m22;
+
+ }
+
+ /**
+ * Multiply this matrix by the tuple t and place the result
+ * back into the tuple (t = this*t).
+ * @param t the tuple to be multiplied by this matrix and then replaced
+ */
+ public final void transform(Tuple3d t) {
+ double x,y,z;
+ x = m00* t.x + m01*t.y + m02*t.z;
+ y = m10* t.x + m11*t.y + m12*t.z;
+ z = m20* t.x + m21*t.y + m22*t.z;
+ t.set(x,y,z);
+ }
+
+ /**
+ * Multiply this matrix by the tuple t and and place the result
+ * into the tuple "result" (result = this*t).
+ * @param t the tuple to be multiplied by this matrix
+ * @param result the tuple into which the product is placed
+ */
+ public final void transform(Tuple3d t, Tuple3d result) {
+ double x,y,z;
+ x = m00* t.x + m01*t.y + m02*t.z;
+ y = m10* t.x + m11*t.y + m12*t.z;
+ result.z = m20* t.x + m21*t.y + m22*t.z;
+ result.x = x;
+ result.y = y;
+ }
+
+ /**
+ * perform SVD (if necessary to get rotational component
+ */
+ final void getScaleRotate(double scales[], double rots[]) {
+
+ double[] tmp = new double[9]; // scratch matrix
+
+ tmp[0] = m00;
+ tmp[1] = m01;
+ tmp[2] = m02;
+
+ tmp[3] = m10;
+ tmp[4] = m11;
+ tmp[5] = m12;
+
+ tmp[6] = m20;
+ tmp[7] = m21;
+ tmp[8] = m22;
+ compute_svd( tmp, scales, rots);
+
+ return;
+ }
+
+ static void compute_svd( double[] m, double[] outScale, double[] outRot) {
+ int i,j;
+ double g,scale;
+ double[] u1 = new double[9];
+ double[] v1 = new double[9];
+ double[] t1 = new double[9];
+ double[] t2 = new double[9];
+
+ double[] tmp = t1;
+ double[] single_values = t2;
+
+ double[] rot = new double[9];
+ double[] e = new double[3];
+ double[] scales = new double[3];
+
+ int converged, negCnt=0;
+ double cs,sn;
+ double c1,c2,c3,c4;
+ double s1,s2,s3,s4;
+ double cl1,cl2,cl3;
+
+
+ for(i=0; i<9; i++)
+ rot[i] = m[i];
+
+ // u1
+
+ if( m[3]*m[3] < EPS ) {
+ u1[0] = 1.0; u1[1] = 0.0; u1[2] = 0.0;
+ u1[3] = 0.0; u1[4] = 1.0; u1[5] = 0.0;
+ u1[6] = 0.0; u1[7] = 0.0; u1[8] = 1.0;
+ } else if( m[0]*m[0] < EPS ) {
+ tmp[0] = m[0];
+ tmp[1] = m[1];
+ tmp[2] = m[2];
+ m[0] = m[3];
+ m[1] = m[4];
+ m[2] = m[5];
+
+ m[3] = -tmp[0]; // zero
+ m[4] = -tmp[1];
+ m[5] = -tmp[2];
+
+ u1[0] = 0.0; u1[1] = 1.0; u1[2] = 0.0;
+ u1[3] = -1.0; u1[4] = 0.0; u1[5] = 0.0;
+ u1[6] = 0.0; u1[7] = 0.0; u1[8] = 1.0;
+ } else {
+ g = 1.0/Math.sqrt(m[0]*m[0] + m[3]*m[3]);
+ c1 = m[0]*g;
+ s1 = m[3]*g;
+ tmp[0] = c1*m[0] + s1*m[3];
+ tmp[1] = c1*m[1] + s1*m[4];
+ tmp[2] = c1*m[2] + s1*m[5];
+
+ m[3] = -s1*m[0] + c1*m[3]; // zero
+ m[4] = -s1*m[1] + c1*m[4];
+ m[5] = -s1*m[2] + c1*m[5];
+
+ m[0] = tmp[0];
+ m[1] = tmp[1];
+ m[2] = tmp[2];
+ u1[0] = c1; u1[1] = s1; u1[2] = 0.0;
+ u1[3] = -s1; u1[4] = c1; u1[5] = 0.0;
+ u1[6] = 0.0; u1[7] = 0.0; u1[8] = 1.0;
+ }
+
+ // u2
+
+ if( m[6]*m[6] < EPS ) {
+ } else if( m[0]*m[0] < EPS ){
+ tmp[0] = m[0];
+ tmp[1] = m[1];
+ tmp[2] = m[2];
+ m[0] = m[6];
+ m[1] = m[7];
+ m[2] = m[8];
+
+ m[6] = -tmp[0]; // zero
+ m[7] = -tmp[1];
+ m[8] = -tmp[2];
+
+ tmp[0] = u1[0];
+ tmp[1] = u1[1];
+ tmp[2] = u1[2];
+ u1[0] = u1[6];
+ u1[1] = u1[7];
+ u1[2] = u1[8];
+
+ u1[6] = -tmp[0]; // zero
+ u1[7] = -tmp[1];
+ u1[8] = -tmp[2];
+ } else {
+ g = 1.0/Math.sqrt(m[0]*m[0] + m[6]*m[6]);
+ c2 = m[0]*g;
+ s2 = m[6]*g;
+ tmp[0] = c2*m[0] + s2*m[6];
+ tmp[1] = c2*m[1] + s2*m[7];
+ tmp[2] = c2*m[2] + s2*m[8];
+
+ m[6] = -s2*m[0] + c2*m[6];
+ m[7] = -s2*m[1] + c2*m[7];
+ m[8] = -s2*m[2] + c2*m[8];
+ m[0] = tmp[0];
+ m[1] = tmp[1];
+ m[2] = tmp[2];
+
+ tmp[0] = c2*u1[0];
+ tmp[1] = c2*u1[1];
+ u1[2] = s2;
+
+ tmp[6] = -u1[0]*s2;
+ tmp[7] = -u1[1]*s2;
+ u1[8] = c2;
+ u1[0] = tmp[0];
+ u1[1] = tmp[1];
+ u1[6] = tmp[6];
+ u1[7] = tmp[7];
+ }
+
+ // v1
+
+ if( m[2]*m[2] < EPS ) {
+ v1[0] = 1.0; v1[1] = 0.0; v1[2] = 0.0;
+ v1[3] = 0.0; v1[4] = 1.0; v1[5] = 0.0;
+ v1[6] = 0.0; v1[7] = 0.0; v1[8] = 1.0;
+ } else if( m[1]*m[1] < EPS ) {
+ tmp[2] = m[2];
+ tmp[5] = m[5];
+ tmp[8] = m[8];
+ m[2] = -m[1];
+ m[5] = -m[4];
+ m[8] = -m[7];
+
+ m[1] = tmp[2]; // zero
+ m[4] = tmp[5];
+ m[7] = tmp[8];
+
+ v1[0] = 1.0; v1[1] = 0.0; v1[2] = 0.0;
+ v1[3] = 0.0; v1[4] = 0.0; v1[5] =-1.0;
+ v1[6] = 0.0; v1[7] = 1.0; v1[8] = 0.0;
+ } else {
+ g = 1.0/Math.sqrt(m[1]*m[1] + m[2]*m[2]);
+ c3 = m[1]*g;
+ s3 = m[2]*g;
+ tmp[1] = c3*m[1] + s3*m[2]; // can assign to m[1]?
+ m[2] =-s3*m[1] + c3*m[2]; // zero
+ m[1] = tmp[1];
+
+ tmp[4] = c3*m[4] + s3*m[5];
+ m[5] =-s3*m[4] + c3*m[5];
+ m[4] = tmp[4];
+
+ tmp[7] = c3*m[7] + s3*m[8];
+ m[8] =-s3*m[7] + c3*m[8];
+ m[7] = tmp[7];
+
+ v1[0] = 1.0; v1[1] = 0.0; v1[2] = 0.0;
+ v1[3] = 0.0; v1[4] = c3; v1[5] = -s3;
+ v1[6] = 0.0; v1[7] = s3; v1[8] = c3;
+ }
+
+ // u3
+
+ if( m[7]*m[7] < EPS ) {
+ } else if( m[4]*m[4] < EPS ) {
+ tmp[3] = m[3];
+ tmp[4] = m[4];
+ tmp[5] = m[5];
+ m[3] = m[6]; // zero
+ m[4] = m[7];
+ m[5] = m[8];
+
+ m[6] = -tmp[3]; // zero
+ m[7] = -tmp[4]; // zero
+ m[8] = -tmp[5];
+
+ tmp[3] = u1[3];
+ tmp[4] = u1[4];
+ tmp[5] = u1[5];
+ u1[3] = u1[6];
+ u1[4] = u1[7];
+ u1[5] = u1[8];
+
+ u1[6] = -tmp[3]; // zero
+ u1[7] = -tmp[4];
+ u1[8] = -tmp[5];
+
+ } else {
+ g = 1.0/Math.sqrt(m[4]*m[4] + m[7]*m[7]);
+ c4 = m[4]*g;
+ s4 = m[7]*g;
+ tmp[3] = c4*m[3] + s4*m[6];
+ m[6] =-s4*m[3] + c4*m[6]; // zero
+ m[3] = tmp[3];
+
+ tmp[4] = c4*m[4] + s4*m[7];
+ m[7] =-s4*m[4] + c4*m[7];
+ m[4] = tmp[4];
+
+ tmp[5] = c4*m[5] + s4*m[8];
+ m[8] =-s4*m[5] + c4*m[8];
+ m[5] = tmp[5];
+
+ tmp[3] = c4*u1[3] + s4*u1[6];
+ u1[6] =-s4*u1[3] + c4*u1[6];
+ u1[3] = tmp[3];
+
+ tmp[4] = c4*u1[4] + s4*u1[7];
+ u1[7] =-s4*u1[4] + c4*u1[7];
+ u1[4] = tmp[4];
+
+ tmp[5] = c4*u1[5] + s4*u1[8];
+ u1[8] =-s4*u1[5] + c4*u1[8];
+ u1[5] = tmp[5];
+ }
+
+ single_values[0] = m[0];
+ single_values[1] = m[4];
+ single_values[2] = m[8];
+ e[0] = m[1];
+ e[1] = m[5];
+
+ if( e[0]*e[0]<EPS && e[1]*e[1]<EPS ) {
+
+ } else {
+ compute_qr( single_values, e, u1, v1);
+ }
+
+ scales[0] = single_values[0];
+ scales[1] = single_values[1];
+ scales[2] = single_values[2];
+
+
+ // Do some optimization here. If scale is unity, simply return the rotation matric.
+ if(almostEqual(Math.abs(scales[0]), 1.0) &&
+ almostEqual(Math.abs(scales[1]), 1.0) &&
+ almostEqual(Math.abs(scales[2]), 1.0)) {
+ // System.out.println("Scale components almost to 1.0");
+
+ for(i=0;i<3;i++)
+ if(scales[i]<0.0)
+ negCnt++;
+
+ if((negCnt==0)||(negCnt==2)) {
+ //System.out.println("Optimize!!");
+ outScale[0] = outScale[1] = outScale[2] = 1.0;
+ for(i=0;i<9;i++)
+ outRot[i] = rot[i];
+
+ return;
+ }
+ }
+
+
+ transpose_mat(u1, t1);
+ transpose_mat(v1, t2);
+
+ /*
+ System.out.println("t1 is \n" + t1);
+ System.out.println("t1="+t1[0]+" "+t1[1]+" "+t1[2]);
+ System.out.println("t1="+t1[3]+" "+t1[4]+" "+t1[5]);
+ System.out.println("t1="+t1[6]+" "+t1[7]+" "+t1[8]);
+
+ System.out.println("t2 is \n" + t2);
+ System.out.println("t2="+t2[0]+" "+t2[1]+" "+t2[2]);
+ System.out.println("t2="+t2[3]+" "+t2[4]+" "+t2[5]);
+ System.out.println("t2="+t2[6]+" "+t2[7]+" "+t2[8]);
+ */
+
+ svdReorder( m, t1, t2, scales, outRot, outScale);
+
+ }
+
+ static void svdReorder( double[] m, double[] t1, double[] t2, double[] scales,
+ double[] outRot, double[] outScale) {
+
+ int[] out = new int[3];
+ int[] in = new int[3];
+ int in0, in1, in2, index, i;
+ double[] mag = new double[3];
+ double[] rot = new double[9];
+
+
+ // check for rotation information in the scales
+ if(scales[0] < 0.0 ) { // move the rotation info to rotation matrix
+ scales[0] = -scales[0];
+ t2[0] = -t2[0];
+ t2[1] = -t2[1];
+ t2[2] = -t2[2];
+ }
+ if(scales[1] < 0.0 ) { // move the rotation info to rotation matrix
+ scales[1] = -scales[1];
+ t2[3] = -t2[3];
+ t2[4] = -t2[4];
+ t2[5] = -t2[5];
+ }
+ if(scales[2] < 0.0 ) { // move the rotation info to rotation matrix
+ scales[2] = -scales[2];
+ t2[6] = -t2[6];
+ t2[7] = -t2[7];
+ t2[8] = -t2[8];
+ }
+
+ mat_mul(t1,t2,rot);
+
+ // check for equal scales case and do not reorder
+ if(almostEqual(Math.abs(scales[0]), Math.abs(scales[1])) &&
+ almostEqual(Math.abs(scales[1]), Math.abs(scales[2])) ){
+ for(i=0;i<9;i++){
+ outRot[i] = rot[i];
+ }
+ for(i=0;i<3;i++){
+ outScale[i] = scales[i];
+ }
+
+ }else {
+
+ // sort the order of the results of SVD
+ if( scales[0] > scales[1]) {
+ if( scales[0] > scales[2] ) {
+ if( scales[2] > scales[1] ) {
+ out[0] = 0; out[1] = 2; out[2] = 1; // xzy
+ } else {
+ out[0] = 0; out[1] = 1; out[2] = 2; // xyz
+ }
+ } else {
+ out[0] = 2; out[1] = 0; out[2] = 1; // zxy
+ }
+ } else { // y > x
+ if( scales[1] > scales[2] ) {
+ if( scales[2] > scales[0] ) {
+ out[0] = 1; out[1] = 2; out[2] = 0; // yzx
+ } else {
+ out[0] = 1; out[1] = 0; out[2] = 2; // yxz
+ }
+ } else {
+ out[0] = 2; out[1] = 1; out[2] = 0; // zyx
+ }
+ }
+
+ /*
+ System.out.println("\nscales="+scales[0]+" "+scales[1]+" "+scales[2]);
+ System.out.println("\nrot="+rot[0]+" "+rot[1]+" "+rot[2]);
+ System.out.println("rot="+rot[3]+" "+rot[4]+" "+rot[5]);
+ System.out.println("rot="+rot[6]+" "+rot[7]+" "+rot[8]);
+ */
+
+ // sort the order of the input matrix
+ mag[0] = (m[0]*m[0] + m[1]*m[1] + m[2]*m[2]);
+ mag[1] = (m[3]*m[3] + m[4]*m[4] + m[5]*m[5]);
+ mag[2] = (m[6]*m[6] + m[7]*m[7] + m[8]*m[8]);
+
+ if( mag[0] > mag[1]) {
+ if( mag[0] > mag[2] ) {
+ if( mag[2] > mag[1] ) {
+ // 0 - 2 - 1
+ in0 = 0; in2 = 1; in1 = 2;// xzy
+ } else {
+ // 0 - 1 - 2
+ in0 = 0; in1 = 1; in2 = 2; // xyz
+ }
+ } else {
+ // 2 - 0 - 1
+ in2 = 0; in0 = 1; in1 = 2; // zxy
+ }
+ } else { // y > x 1>0
+ if( mag[1] > mag[2] ) {
+ if( mag[2] > mag[0] ) {
+ // 1 - 2 - 0
+ in1 = 0; in2 = 1; in0 = 2; // yzx
+ } else {
+ // 1 - 0 - 2
+ in1 = 0; in0 = 1; in2 = 2; // yxz
+ }
+ } else {
+ // 2 - 1 - 0
+ in2 = 0; in1 = 1; in0 = 2; // zyx
+ }
+ }
+
+
+ index = out[in0];
+ outScale[0] = scales[index];
+
+ index = out[in1];
+ outScale[1] = scales[index];
+
+ index = out[in2];
+ outScale[2] = scales[index];
+
+
+ index = out[in0];
+ outRot[0] = rot[index];
+
+ index = out[in0]+3;
+ outRot[0+3] = rot[index];
+
+ index = out[in0]+6;
+ outRot[0+6] = rot[index];
+
+ index = out[in1];
+ outRot[1] = rot[index];
+
+ index = out[in1]+3;
+ outRot[1+3] = rot[index];
+
+ index = out[in1]+6;
+ outRot[1+6] = rot[index];
+
+ index = out[in2];
+ outRot[2] = rot[index];
+
+ index = out[in2]+3;
+ outRot[2+3] = rot[index];
+
+ index = out[in2]+6;
+ outRot[2+6] = rot[index];
+ }
+ }
+
+ static int compute_qr( double[] s, double[] e, double[] u, double[] v) {
+
+ int i,j,k;
+ boolean converged;
+ double shift,ssmin,ssmax,r;
+ double[] cosl = new double[2];
+ double[] cosr = new double[2];
+ double[] sinl = new double[2];
+ double[] sinr = new double[2];
+ double[] m = new double[9];
+
+ double utemp,vtemp;
+ double f,g;
+
+ final int MAX_INTERATIONS = 10;
+ final double CONVERGE_TOL = 4.89E-15;
+
+ double c_b48 = 1.;
+ double c_b71 = -1.;
+ int first;
+ converged = false;
+
+
+ first = 1;
+
+ if( Math.abs(e[1]) < CONVERGE_TOL || Math.abs(e[0]) < CONVERGE_TOL) converged = true;
+
+ for(k=0;k<MAX_INTERATIONS && !converged;k++) {
+ shift = compute_shift( s[1], e[1], s[2]);
+ f = (Math.abs(s[0]) - shift) * (d_sign(c_b48, s[0]) + shift/s[0]);
+ g = e[0];
+ r = compute_rot(f, g, sinr, cosr, 0, first);
+ f = cosr[0] * s[0] + sinr[0] * e[0];
+ e[0] = cosr[0] * e[0] - sinr[0] * s[0];
+ g = sinr[0] * s[1];
+ s[1] = cosr[0] * s[1];
+
+ r = compute_rot(f, g, sinl, cosl, 0, first);
+ first = 0;
+ s[0] = r;
+ f = cosl[0] * e[0] + sinl[0] * s[1];
+ s[1] = cosl[0] * s[1] - sinl[0] * e[0];
+ g = sinl[0] * e[1];
+ e[1] = cosl[0] * e[1];
+
+ r = compute_rot(f, g, sinr, cosr, 1, first);
+ e[0] = r;
+ f = cosr[1] * s[1] + sinr[1] * e[1];
+ e[1] = cosr[1] * e[1] - sinr[1] * s[1];
+ g = sinr[1] * s[2];
+ s[2] = cosr[1] * s[2];
+
+ r = compute_rot(f, g, sinl, cosl, 1, first);
+ s[1] = r;
+ f = cosl[1] * e[1] + sinl[1] * s[2];
+ s[2] = cosl[1] * s[2] - sinl[1] * e[1];
+ e[1] = f;
+
+ // update u matrices
+ utemp = u[0];
+ u[0] = cosl[0]*utemp + sinl[0]*u[3];
+ u[3] = -sinl[0]*utemp + cosl[0]*u[3];
+ utemp = u[1];
+ u[1] = cosl[0]*utemp + sinl[0]*u[4];
+ u[4] = -sinl[0]*utemp + cosl[0]*u[4];
+ utemp = u[2];
+ u[2] = cosl[0]*utemp + sinl[0]*u[5];
+ u[5] = -sinl[0]*utemp + cosl[0]*u[5];
+
+ utemp = u[3];
+ u[3] = cosl[1]*utemp + sinl[1]*u[6];
+ u[6] = -sinl[1]*utemp + cosl[1]*u[6];
+ utemp = u[4];
+ u[4] = cosl[1]*utemp + sinl[1]*u[7];
+ u[7] = -sinl[1]*utemp + cosl[1]*u[7];
+ utemp = u[5];
+ u[5] = cosl[1]*utemp + sinl[1]*u[8];
+ u[8] = -sinl[1]*utemp + cosl[1]*u[8];
+
+ // update v matrices
+
+ vtemp = v[0];
+ v[0] = cosr[0]*vtemp + sinr[0]*v[1];
+ v[1] = -sinr[0]*vtemp + cosr[0]*v[1];
+ vtemp = v[3];
+ v[3] = cosr[0]*vtemp + sinr[0]*v[4];
+ v[4] = -sinr[0]*vtemp + cosr[0]*v[4];
+ vtemp = v[6];
+ v[6] = cosr[0]*vtemp + sinr[0]*v[7];
+ v[7] = -sinr[0]*vtemp + cosr[0]*v[7];
+
+ vtemp = v[1];
+ v[1] = cosr[1]*vtemp + sinr[1]*v[2];
+ v[2] = -sinr[1]*vtemp + cosr[1]*v[2];
+ vtemp = v[4];
+ v[4] = cosr[1]*vtemp + sinr[1]*v[5];
+ v[5] = -sinr[1]*vtemp + cosr[1]*v[5];
+ vtemp = v[7];
+ v[7] = cosr[1]*vtemp + sinr[1]*v[8];
+ v[8] = -sinr[1]*vtemp + cosr[1]*v[8];
+
+
+ m[0] = s[0]; m[1] = e[0]; m[2] = 0.0;
+ m[3] = 0.0; m[4] = s[1]; m[5] =e[1];
+ m[6] = 0.0; m[7] = 0.0; m[8] =s[2];
+
+ if( Math.abs(e[1]) < CONVERGE_TOL || Math.abs(e[0]) < CONVERGE_TOL) converged = true;
+ }
+
+ if( Math.abs(e[1]) < CONVERGE_TOL ) {
+ compute_2X2( s[0],e[0],s[1],s,sinl,cosl,sinr,cosr, 0);
+
+ utemp = u[0];
+ u[0] = cosl[0]*utemp + sinl[0]*u[3];
+ u[3] = -sinl[0]*utemp + cosl[0]*u[3];
+ utemp = u[1];
+ u[1] = cosl[0]*utemp + sinl[0]*u[4];
+ u[4] = -sinl[0]*utemp + cosl[0]*u[4];
+ utemp = u[2];
+ u[2] = cosl[0]*utemp + sinl[0]*u[5];
+ u[5] = -sinl[0]*utemp + cosl[0]*u[5];
+
+ // update v matrices
+
+ vtemp = v[0];
+ v[0] = cosr[0]*vtemp + sinr[0]*v[1];
+ v[1] = -sinr[0]*vtemp + cosr[0]*v[1];
+ vtemp = v[3];
+ v[3] = cosr[0]*vtemp + sinr[0]*v[4];
+ v[4] = -sinr[0]*vtemp + cosr[0]*v[4];
+ vtemp = v[6];
+ v[6] = cosr[0]*vtemp + sinr[0]*v[7];
+ v[7] = -sinr[0]*vtemp + cosr[0]*v[7];
+ } else {
+ compute_2X2( s[1],e[1],s[2],s,sinl,cosl,sinr,cosr,1);
+
+ utemp = u[3];
+ u[3] = cosl[0]*utemp + sinl[0]*u[6];
+ u[6] = -sinl[0]*utemp + cosl[0]*u[6];
+ utemp = u[4];
+ u[4] = cosl[0]*utemp + sinl[0]*u[7];
+ u[7] = -sinl[0]*utemp + cosl[0]*u[7];
+ utemp = u[5];
+ u[5] = cosl[0]*utemp + sinl[0]*u[8];
+ u[8] = -sinl[0]*utemp + cosl[0]*u[8];
+
+ // update v matrices
+
+ vtemp = v[1];
+ v[1] = cosr[0]*vtemp + sinr[0]*v[2];
+ v[2] = -sinr[0]*vtemp + cosr[0]*v[2];
+ vtemp = v[4];
+ v[4] = cosr[0]*vtemp + sinr[0]*v[5];
+ v[5] = -sinr[0]*vtemp + cosr[0]*v[5];
+ vtemp = v[7];
+ v[7] = cosr[0]*vtemp + sinr[0]*v[8];
+ v[8] = -sinr[0]*vtemp + cosr[0]*v[8];
+ }
+
+ return(0);
+}
+static double max( double a, double b) {
+ if( a > b)
+ return( a);
+ else
+ return( b);
+}
+static double min( double a, double b) {
+ if( a < b)
+ return( a);
+ else
+ return( b);
+}
+static double d_sign(double a, double b) {
+double x;
+x = (a >= 0 ? a : - a);
+return( b >= 0 ? x : -x);
+}
+
+static double compute_shift( double f, double g, double h) {
+ double d__1, d__2;
+ double fhmn, fhmx, c, fa, ga, ha, as, at, au;
+ double ssmin;
+
+ fa = Math.abs(f);
+ ga = Math.abs(g);
+ ha = Math.abs(h);
+ fhmn = min(fa,ha);
+ fhmx = max(fa,ha);
+ if (fhmn == 0.) {
+ ssmin = 0.;
+ if (fhmx == 0.) {
+ } else {
+ d__1 = min(fhmx,ga) / max(fhmx,ga);
+ }
+ } else {
+ if (ga < fhmx) {
+ as = fhmn / fhmx + 1.;
+ at = (fhmx - fhmn) / fhmx;
+ d__1 = ga / fhmx;
+ au = d__1 * d__1;
+ c = 2. / (Math.sqrt(as * as + au) + Math.sqrt(at * at + au));
+ ssmin = fhmn * c;
+ } else {
+ au = fhmx / ga;
+ if (au == 0.) {
+ ssmin = fhmn * fhmx / ga;
+ } else {
+ as = fhmn / fhmx + 1.;
+ at = (fhmx - fhmn) / fhmx;
+ d__1 = as * au;
+ d__2 = at * au;
+ c = 1. / (Math.sqrt(d__1 * d__1 + 1.) + Math.sqrt(d__2 * d__2 + 1.));
+ ssmin = fhmn * c * au;
+ ssmin += ssmin;
+ }
+ }
+ }
+
+ return(ssmin);
+}
+static int compute_2X2( double f, double g, double h, double[] single_values,
+ double[] snl, double[] csl, double[] snr, double[] csr, int index) {
+
+ double c_b3 = 2.;
+ double c_b4 = 1.;
+
+ double d__1;
+ int pmax;
+ double temp;
+ boolean swap;
+ double a, d, l, m, r, s, t, tsign, fa, ga, ha;
+ double ft, gt, ht, mm;
+ boolean gasmal;
+ double tt, clt, crt, slt, srt;
+ double ssmin,ssmax;
+
+ ssmax = single_values[0];
+ ssmin = single_values[1];
+ clt = 0.0;
+ crt = 0.0;
+ slt = 0.0;
+ srt = 0.0;
+ tsign = 0.0;
+
+ ft = f;
+ fa = Math.abs(ft);
+ ht = h;
+ ha = Math.abs(h);
+
+ pmax = 1;
+ if( ha > fa)
+ swap = true;
+ else
+ swap = false;
+
+ if (swap) {
+ pmax = 3;
+ temp = ft;
+ ft = ht;
+ ht = temp;
+ temp = fa;
+ fa = ha;
+ ha = temp;
+
+ }
+ gt = g;
+ ga = Math.abs(gt);
+ if (ga == 0.) {
+
+ single_values[1] = ha;
+ single_values[0] = fa;
+ clt = 1.;
+ crt = 1.;
+ slt = 0.;
+ srt = 0.;
+ } else {
+ gasmal = true;
+
+ if (ga > fa) {
+ pmax = 2;
+ if (fa / ga < EPS) {
+
+ gasmal = false;
+ ssmax = ga;
+ if (ha > 1.) {
+ ssmin = fa / (ga / ha);
+ } else {
+ ssmin = fa / ga * ha;
+ }
+ clt = 1.;
+ slt = ht / gt;
+ srt = 1.;
+ crt = ft / gt;
+ }
+ }
+ if (gasmal) {
+
+ d = fa - ha;
+ if (d == fa) {
+
+ l = 1.;
+ } else {
+ l = d / fa;
+ }
+
+ m = gt / ft;
+
+ t = 2. - l;
+
+ mm = m * m;
+ tt = t * t;
+ s = Math.sqrt(tt + mm);
+
+ if (l == 0.) {
+ r = Math.abs(m);
+ } else {
+ r = Math.sqrt(l * l + mm);
+ }
+
+ a = (s + r) * .5;
+
+ if (ga > fa) {
+ pmax = 2;
+ if (fa / ga < EPS) {
+
+ gasmal = false;
+ ssmax = ga;
+ if (ha > 1.) {
+ ssmin = fa / (ga / ha);
+ } else {
+ ssmin = fa / ga * ha;
+ }
+ clt = 1.;
+ slt = ht / gt;
+ srt = 1.;
+ crt = ft / gt;
+ }
+ }
+ if (gasmal) {
+
+ d = fa - ha;
+ if (d == fa) {
+
+ l = 1.;
+ } else {
+ l = d / fa;
+ }
+
+ m = gt / ft;
+
+ t = 2. - l;
+
+ mm = m * m;
+ tt = t * t;
+ s = Math.sqrt(tt + mm);
+
+ if (l == 0.) {
+ r = Math.abs(m);
+ } else {
+ r = Math.sqrt(l * l + mm);
+ }
+
+ a = (s + r) * .5;
+
+
+ ssmin = ha / a;
+ ssmax = fa * a;
+ if (mm == 0.) {
+
+ if (l == 0.) {
+ t = d_sign(c_b3, ft) * d_sign(c_b4, gt);
+ } else {
+ t = gt / d_sign(d, ft) + m / t;
+ }
+ } else {
+ t = (m / (s + t) + m / (r + l)) * (a + 1.);
+ }
+ l = Math.sqrt(t * t + 4.);
+ crt = 2. / l;
+ srt = t / l;
+ clt = (crt + srt * m) / a;
+ slt = ht / ft * srt / a;
+ }
+ }
+ if (swap) {
+ csl[0] = srt;
+ snl[0] = crt;
+ csr[0] = slt;
+ snr[0] = clt;
+ } else {
+ csl[0] = clt;
+ snl[0] = slt;
+ csr[0] = crt;
+ snr[0] = srt;
+ }
+
+ if (pmax == 1) {
+ tsign = d_sign(c_b4, csr[0]) * d_sign(c_b4, csl[0]) * d_sign(c_b4, f);
+ }
+ if (pmax == 2) {
+ tsign = d_sign(c_b4, snr[0]) * d_sign(c_b4, csl[0]) * d_sign(c_b4, g);
+ }
+ if (pmax == 3) {
+ tsign = d_sign(c_b4, snr[0]) * d_sign(c_b4, snl[0]) * d_sign(c_b4, h);
+ }
+ single_values[index] = d_sign(ssmax, tsign);
+ d__1 = tsign * d_sign(c_b4, f) * d_sign(c_b4, h);
+ single_values[index+1] = d_sign(ssmin, d__1);
+
+
+ }
+ return 0;
+ }
+ static double compute_rot( double f, double g, double[] sin, double[] cos, int index, int first) {
+ int i__1;
+ double d__1, d__2;
+ double cs,sn;
+ int i;
+ double scale;
+ int count;
+ double f1, g1;
+ double r;
+ final double safmn2 = 2.002083095183101E-146;
+ final double safmx2 = 4.994797680505588E+145;
+
+ if (g == 0.) {
+ cs = 1.;
+ sn = 0.;
+ r = f;
+ } else if (f == 0.) {
+ cs = 0.;
+ sn = 1.;
+ r = g;
+ } else {
+ f1 = f;
+ g1 = g;
+ scale = max(Math.abs(f1),Math.abs(g1));
+ if (scale >= safmx2) {
+ count = 0;
+ while(scale >= safmx2) {
+ ++count;
+ f1 *= safmn2;
+ g1 *= safmn2;
+ scale = max(Math.abs(f1),Math.abs(g1));
+ }
+ r = Math.sqrt(f1*f1 + g1*g1);
+ cs = f1 / r;
+ sn = g1 / r;
+ i__1 = count;
+ for (i = 1; i <= count; ++i) {
+ r *= safmx2;
+ }
+ } else if (scale <= safmn2) {
+ count = 0;
+ while(scale <= safmn2) {
+ ++count;
+ f1 *= safmx2;
+ g1 *= safmx2;
+ scale = max(Math.abs(f1),Math.abs(g1));
+ }
+ r = Math.sqrt(f1*f1 + g1*g1);
+ cs = f1 / r;
+ sn = g1 / r;
+ i__1 = count;
+ for (i = 1; i <= count; ++i) {
+ r *= safmn2;
+ }
+ } else {
+ r = Math.sqrt(f1*f1 + g1*g1);
+ cs = f1 / r;
+ sn = g1 / r;
+ }
+ if (Math.abs(f) > Math.abs(g) && cs < 0.) {
+ cs = -cs;
+ sn = -sn;
+ r = -r;
+ }
+ }
+ sin[index] = sn;
+ cos[index] = cs;
+ return r;
+
+ }
+static void print_mat( double[] mat) {
+int i;
+ for(i=0;i<3;i++){
+ System.out.println(mat[i*3+0]+" "+mat[i*3+1]+" "+mat[i*3+2]+"\n");
+ }
+
+}
+static void print_det( double[] mat) {
+double det;
+
+ det = mat[0]*mat[4]*mat[8] +
+ mat[1]*mat[5]*mat[6] +
+ mat[2]*mat[3]*mat[7] -
+ mat[2]*mat[4]*mat[6] -
+ mat[0]*mat[5]*mat[7] -
+ mat[1]*mat[3]*mat[8];
+ System.out.println("det= "+det);
+}
+static void mat_mul(double[] m1, double[] m2, double[] m3) {
+ int i;
+ double[] tmp = new double[9];
+
+ tmp[0] = m1[0]*m2[0] + m1[1]*m2[3] + m1[2]*m2[6];
+ tmp[1] = m1[0]*m2[1] + m1[1]*m2[4] + m1[2]*m2[7];
+ tmp[2] = m1[0]*m2[2] + m1[1]*m2[5] + m1[2]*m2[8];
+
+ tmp[3] = m1[3]*m2[0] + m1[4]*m2[3] + m1[5]*m2[6];
+ tmp[4] = m1[3]*m2[1] + m1[4]*m2[4] + m1[5]*m2[7];
+ tmp[5] = m1[3]*m2[2] + m1[4]*m2[5] + m1[5]*m2[8];
+
+ tmp[6] = m1[6]*m2[0] + m1[7]*m2[3] + m1[8]*m2[6];
+ tmp[7] = m1[6]*m2[1] + m1[7]*m2[4] + m1[8]*m2[7];
+ tmp[8] = m1[6]*m2[2] + m1[7]*m2[5] + m1[8]*m2[8];
+
+ for(i=0;i<9;i++) {
+ m3[i] = tmp[i];
+ }
+}
+static void transpose_mat(double[] in, double[] out) {
+ out[0] = in[0];
+ out[1] = in[3];
+ out[2] = in[6];
+
+ out[3] = in[1];
+ out[4] = in[4];
+ out[5] = in[7];
+
+ out[6] = in[2];
+ out[7] = in[5];
+ out[8] = in[8];
+}
+static double max3( double[] values) {
+ if( values[0] > values[1] ) {
+ if( values[0] > values[2] )
+ return(values[0]);
+ else
+ return(values[2]);
+ } else {
+ if( values[1] > values[2] )
+ return(values[1]);
+ else
+ return(values[2]);
+ }
+ }
+
+ private static final boolean almostEqual(double a, double b) {
+ if (a == b)
+ return true;
+
+ final double EPSILON_ABSOLUTE = 1.0e-6;
+ final double EPSILON_RELATIVE = 1.0e-4;
+ double diff = Math.abs(a-b);
+ double absA = Math.abs(a);
+ double absB = Math.abs(b);
+ double max = (absA >= absB) ? absA : absB;
+
+ if (diff < EPSILON_ABSOLUTE)
+ return true;
+
+ if ((diff / max) < EPSILON_RELATIVE)
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Creates a new object of the same class as this object.
+ *
+ * @return a clone of this instance.
+ * @exception OutOfMemoryError if there is not enough memory.
+ * @see java.lang.Cloneable
+ * @since vecmath 1.3
+ */
+ @Override
+ public Object clone() {
+ Matrix3d m1 = null;
+ try {
+ m1 = (Matrix3d)super.clone();
+ } catch (CloneNotSupportedException e) {
+ // this shouldn't happen, since we are Cloneable
+ throw new InternalError();
+ }
+
+ // Also need to create new tmp arrays (no need to actually clone them)
+ return m1;
+ }
+
+ /**
+ * Get the first matrix element in the first row.
+ * @return Returns the m00.
+ * @since vecmath 1.5
+ */
+ public final double getM00() {
+ return m00;
+ }
+
+ /**
+ * Set the first matrix element in the first row.
+ *
+ * @param m00 The m00 to set.
+ *
+ * @since vecmath 1.5
+ */
+ public final void setM00(double m00) {
+ this.m00 = m00;
+ }
+
+ /**
+ * Get the second matrix element in the first row.
+ *
+ * @return Returns the m01.
+ *
+ * @since vecmath 1.5
+ */
+ public final double getM01() {
+ return m01;
+ }
+
+ /**
+ * Set the second matrix element in the first row.
+ *
+ * @param m01 The m01 to set.
+ *
+ * @since vecmath 1.5
+ */
+ public final void setM01(double m01) {
+ this.m01 = m01;
+ }
+
+ /**
+ * Get the third matrix element in the first row.
+ *
+ * @return Returns the m02.
+ *
+ * @since vecmath 1.5
+ */
+ public final double getM02() {
+ return m02;
+ }
+
+ /**
+ * Set the third matrix element in the first row.
+ *
+ * @param m02 The m02 to set.
+ *
+ * @since vecmath 1.5
+ */
+ public final void setM02(double m02) {
+ this.m02 = m02;
+ }
+
+ /**
+ * Get first matrix element in the second row.
+ *
+ * @return Returns the m10.
+ *
+ * @since vecmath 1.5
+ */
+ public final double getM10() {
+ return m10;
+ }
+
+ /**
+ * Set first matrix element in the second row.
+ *
+ * @param m10 The m10 to set.
+ *
+ * @since vecmath 1.5
+ */
+ public final void setM10(double m10) {
+ this.m10 = m10;
+ }
+
+ /**
+ * Get second matrix element in the second row.
+ *
+ * @return Returns the m11.
+ *
+ * @since vecmath 1.5
+ */
+ public final double getM11() {
+ return m11;
+ }
+
+ /**
+ * Set the second matrix element in the second row.
+ *
+ * @param m11 The m11 to set.
+ *
+ * @since vecmath 1.5
+ */
+ public final void setM11(double m11) {
+ this.m11 = m11;
+ }
+
+ /**
+ * Get the third matrix element in the second row.
+ *
+ * @return Returns the m12.
+ *
+ * @since vecmath 1.5
+ */
+ public final double getM12() {
+ return m12;
+ }
+
+ /**
+ * Set the third matrix element in the second row.
+ *
+ * @param m12 The m12 to set.
+ *
+ * @since vecmath 1.5
+ */
+ public final void setM12(double m12) {
+ this.m12 = m12;
+ }
+
+ /**
+ * Get the first matrix element in the third row.
+ *
+ * @return Returns the m20.
+ *
+ * @since vecmath 1.5
+ */
+ public final double getM20() {
+ return m20;
+ }
+
+ /**
+ * Set the first matrix element in the third row.
+ *
+ * @param m20 The m20 to set.
+ *
+ * @since vecmath 1.5
+ */
+ public final void setM20(double m20) {
+ this.m20 = m20;
+ }
+
+ /**
+ * Get the second matrix element in the third row.
+ *
+ * @return Returns the m21.
+ *
+ * @since vecmath 1.5
+ */
+ public final double getM21() {
+ return m21;
+ }
+
+ /**
+ * Set the second matrix element in the third row.
+ *
+ * @param m21 The m21 to set.
+ *
+ * @since vecmath 1.5
+ */
+ public final void setM21(double m21) {
+ this.m21 = m21;
+ }
+
+ /**
+ * Get the third matrix element in the third row .
+ *
+ * @return Returns the m22.
+ *
+ * @since vecmath 1.5
+ */
+ public final double getM22() {
+ return m22;
+ }
+
+ /**
+ * Set the third matrix element in the third row.
+ *
+ * @param m22 The m22 to set.
+ *
+ * @since vecmath 1.5
+ */
+ public final void setM22(double m22) {
+ this.m22 = m22;
+ }
+
+}