/*- * #%L * Fiji distribution of ImageJ for the life sciences. * %% * Copyright (C) 2007 - 2017 Fiji developers. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. * * This program 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 for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-2.0.html>. * #L% */ package spim.vecmath; /* * 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. * */ /** * 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; 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; double g; 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 negCnt = 0; double c1, c2, c3, c4; double s1, s2, s3, s4; 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 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 k; boolean converged; double shift, 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.; 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 ) { 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; 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; 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; } }