diff options
author | Kevin Rushforth <[email protected]> | 2004-06-09 02:52:37 +0000 |
---|---|---|
committer | Kevin Rushforth <[email protected]> | 2004-06-09 02:52:37 +0000 |
commit | df69463d936326e3f44453e9b9987b96272ae5d9 (patch) | |
tree | c0aa5a160cd3a4e9bdbd201a0e6a2c35ce763e4f | |
parent | 8d04fe6c33678b770bbd5c7747ca21e565648222 (diff) |
Initial creation of vecmath sources in CVS repository
git-svn-id: https://svn.java.net/svn/vecmath~svn/trunk@5 dd45e54d-f42e-c781-df72-dca083a658b1
51 files changed, 27406 insertions, 0 deletions
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt new file mode 100644 index 0000000..23f8b5e --- /dev/null +++ b/COPYRIGHT.txt @@ -0,0 +1,77 @@ +Copyright (c) 2004 Sun Microsystems, Inc., 4150 Network Circle, Santa +Clara, California 95054, U.S.A. All rights reserved. + +Sun Microsystems, Inc. has intellectual property rights relating to +technology embodied in the product that is described in this +document. In particular, and without limitation, these intellectual +property rights may include one or more of the U.S. patents listed at +http://www.sun.com/patents and one or more additional patents or +pending patent applications in the U.S. and in other countries. + +U.S. Government Rights - Commercial software. Government users are +subject to the Sun Microsystems, Inc. standard license agreement and +applicable provisions of the FAR and its supplements. + +Use is subject to license terms. + +This distribution may include materials developed by third parties. + +Parts of the product may be derived from Berkeley BSD systems, +licensed from the University of California. UNIX is a registered +trademark in the U.S. and in other countries, exclusively licensed +through X/Open Company, Ltd. + +Sun, Sun Microsystems, the Sun logo, Java, Solaris, Java 3D, the 100% +Pure Java logo, the Duke logo and the Java Coffee Cup logo are +trademarks or registered trademarks of Sun Microsystems, Inc. in the +U.S. and other countries. + +This product is covered and controlled by U.S. Export Control laws and +may be subject to the export or import laws in other countries. +Nuclear, missile, chemical biological weapons or nuclear maritime end +uses or end users, whether direct or indirect, are strictly +prohibited. Export or reexport to countries subject to U.S. embargo or +to entities identified on U.S. export exclusion lists, including, but +not limited to, the denied persons and specially designated nationals +lists is strictly prohibited. + +Copyright (c) 2004 Sun Microsystems, Inc., 4150 Network Circle, Santa +Clara, California 95054, Etats-Unis. Tous droits r�serv�s. + +Sun Microsystems, Inc. d�tient les droits de propri�t� intellectuels +relatifs � la technologie incorpor�e dans le produit qui est d�crit +dans ce document. En particulier, et ce sans limitation, ces droits de +propri�t� intellectuelle peuvent inclure un ou plus des brevets +am�ricains list�s � l'adresse http://www.sun.com/patents et un ou les +brevets suppl�mentaires ou les applications de brevet en attente aux +Etats - Unis et dans les autres pays. + +L'utilisation est soumise aux termes de la Licence. + +Cette distribution peut comprendre des composants d�velopp�s par des +tierces parties. + +Des parties de ce produit pourront �tre d�riv�es des syst�mes Berkeley +BSD licenci�s par l'Universit� de Californie. UNIX est une marque +d�pos�e aux Etats-Unis et dans d'autres pays et licenci�e +exclusivement par X/Open Company, Ltd. + +Sun, Sun Microsystems, le logo Sun, Java, Solaris, Java 3D, le logo +100% Pure Java, le logo Duke et le logo Java Coffee Cup sont des +marques de fabrique ou des marques d�pos�es de Sun Microsystems, +Inc. aux Etats-Unis et dans d'autres pays. + +Ce produit est soumis � la l�gislation am�ricaine en mati�re de +contr�le des exportations et peut �tre soumis � la r�glementation en +vigueur dans d'autres pays dans le domaine des exportations et +importations. Les utilisations, ou utilisateurs finaux, pour des armes +nucl�aires,des missiles, des armes biologiques et chimiques ou du +nucl�aire maritime, directement ou indirectement, sont strictement +interdites. Les exportations ou r�exportations vers les pays sous +embargo am�ricain, ou vers des entit�s figurant sur les listes +d'exclusion d'exportation am�ricaines, y compris, mais de mani�re non +exhaustive, la liste de personnes qui font objet d'un ordre de ne pas +participer, d'une fa�on directe ou indirecte, aux exportations des +produits ou des services qui sont r�gis par la l�gislation am�ricaine +en mati�re de contr�le des exportations et la liste de ressortissants +sp�cifiquement d�sign�s, sont rigoureusement interdites. diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..4617b0b --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,16 @@ +===================================================================== +BEGIN LICENSE PLACEHOLDER +===================================================================== + +Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + +This software is licensed under terms that are yet to be disclosed. +Until such time as these terms are disclosed, you may not do anything +at all with the source code in this CVS repository. + +===================================================================== +END LICENSE PLACEHOLDER +===================================================================== + +TODO: remove the above placeholder and put the actual license, and/or +pointer (URL) to license, here. diff --git a/README-FIRST.txt b/README-FIRST.txt new file mode 100644 index 0000000..b143e92 --- /dev/null +++ b/README-FIRST.txt @@ -0,0 +1,9 @@ +The source code for the vecmath project project is copyrighted code +that is licensed to individuals or companies who download or otherwise +access the code. + +The copyright notice for this project is in COPYRIGHT.txt + +The source code license for this project is in LICENSE.txt + +Instructions for building this project are in README-build.html diff --git a/README-build.html b/README-build.html new file mode 100644 index 0000000..978c5f5 --- /dev/null +++ b/README-build.html @@ -0,0 +1,79 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> + +<!-- +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + --> + +<html> +<head> + <meta content="text/html; charset=ISO-8859-1" + http-equiv="content-type"> + <title>README-build</title> +</head> +<body> +<span style="font-weight: bold; text-decoration: underline;">Building +the +Vecmath Packages<br> +<br> +</span>To build the vecmath packages, you must first download the +vecmath +CVS repository:<br> +<br> +NOTE: this top-level directory must be named "vecmath".<span + style="font-weight: bold; text-decoration: underline;"><br> +<br> +System Requirements<br> +<br> +</span>Vecmath is 100% Java, so any operating environment that supports +J2SE should work. We have built vecmath on the following +operating environments:<br> +<ul> + <li>Solaris: Sparc (Ultra60 or better) running Solaris 9</li> + <li>Linux: i386/i586 running SuSE 9 or RedHat 9.0</li> + <li>Windows: Windows/XP (Windows +2000 should work, but is untested)<br> + </li> +</ul> +The following software must be installed:<br> +<ul> + <li><a href="http://java.sun.com/j2se">JDK 1.4.2 </a> <br> + </li> + <li><a href="http://jakarta.apache.org/ant">Apache Ant 1.6.1 </a> + <br> + </li> +</ul> +<span style="font-weight: bold; text-decoration: underline;">Building +Vecmath<br> +<br> +</span> Before you start building, please check that your PATH must +include the +following directories:<br> + . <ant-root-dir>/bin<br> + . <jdk-root_dir>/bin<br> +<br> +The default target, jar-opt, creates an optimized jar files.<br> +<br> +Steps:<br> +<br> + cd <java3d-root-dir>/vecmath<br> + ant<br> +<br> +This will build the javax.vecmath package. The build will be put +in vecmath/build/opt<br> +<br> +Other targets can be found by typing "ant -projecthelp". Note +that ant<br> +must be run from the top-level directory.<br> +<br> +</body> +</html> diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..2b0437c --- /dev/null +++ b/build.xml @@ -0,0 +1,206 @@ +<?xml version="1.0"?> + +<!-- +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + --> + +<project name="vecmath" default="jar-opt" basedir="."> + + <!-- Set global properties for this build --> + <property name="src" location="src"/> + <property name="build" location="build"/> + <property name="dist" location="dist"/> + <property name="version" value="1_3_2"/> + <property name="docname" value="vecmath-${version}-doc"/> + + <target name="echo"> + <echo message="user.name = ${user.name}"/> + <echo message="user.home = ${user.home}"/> + <echo message="java.home = ${java.home}"/> + <echo message="ant.home = ${ant.home}"/> + <echo message="O/S arch is ${os.arch}"/> + <echo message="O/S name is ${os.name}"/> + </target> + + + <target name="init"> + <!-- Create the time stamp --> + <tstamp> + <format property="buildtime" + pattern="yyyy-MM-dd'T'HH:mm:ss"/> + </tstamp> + + <!-- Create the base build directory --> + <mkdir dir="${build}"/> + </target> + + <target name="compile-debug" depends="init"> + + <!-- Create the debug build directory structure used for compile --> + <mkdir dir="${build}/debug/classes"/> + + <!-- Compile the java code from ${src} into ${build}/debug/classes --> + <javac srcdir="${src}" + destdir="${build}/debug/classes" + source="1.4" + target="1.4" + debug="yes" + deprecation="on" + /> + + <!-- Copy the I18N property files while retaining package location --> + <copy todir="${build}/debug/classes"> + <fileset dir="${src}" includes="**/*.properties"/> + </copy> + </target> + + <target name="compile-opt" depends="init"> + + <!-- Create the opt build directory structure used for compile --> + <mkdir dir="${build}/opt/classes"/> + + <!-- Compile the java code from ${src} into ${build}/opt/classes --> + <javac srcdir="${src}" + destdir="${build}/opt/classes" + source="1.4" + target="1.4" + debug="no" + deprecation="on" + /> + + <!-- Copy the I18N property files while retaining package location --> + <copy todir="${build}/opt/classes"> + <fileset dir="${src}" includes="**/*.properties"/> + </copy> + </target> + + <target name="compile" depends="compile-opt,compile-debug"/> + + <target name="jar-debug" depends="compile-debug"> + <!-- Create the jar directory --> + <mkdir dir="${build}/debug/lib/ext"/> + + <!-- Copy the copyright file and all license files --> + <copy todir="${build}/debug/classes"> + <fileset dir="." includes="COPYRIGHT.txt"/> + <fileset dir="." includes="*LICENSE*.txt"/> + </copy> + + <!-- Put everything in ${build}/debug/classes into the vecmath.jar file --> + <jar jarfile="${build}/debug/lib/ext/vecmath.jar" + manifest="${src}/VECMATH.MF" compress="false" update="yes"> + <fileset dir="${build}/debug/classes"/> + </jar> + </target> + + <target name="jar-opt" depends="compile-opt"> + <!-- Create the jar directory --> + <mkdir dir="${build}/opt/lib/ext"/> + + <!-- Copy the copyright file and all license files --> + <copy todir="${build}/opt/classes"> + <fileset dir="." includes="COPYRIGHT.txt"/> + <fileset dir="." includes="*LICENSE*.txt"/> + </copy> + + <!-- Put everything in ${build}/classes/opt into the vecmath.jar file --> + <jar jarfile="${build}/opt/lib/ext/vecmath.jar" + manifest="${src}/VECMATH.MF" compress="false" update="yes"> + <fileset dir="${build}/opt/classes"/> + </jar> + </target> + + <target name="jar" depends="jar-opt,jar-debug"/> + + <target name="docs" depends="init"> + <!-- Create the build directory structure used by docs --> + <mkdir dir="${build}/javadocs"/> + + <!-- Compile the javadoc from ${src} into ${build}/javadocs --> + <javadoc sourcepath="${src}" + packagenames="javax.vecmath.*" + maxmemory="128m" + destdir="${build}/javadocs" + windowtitle="Vecmath ${version}"> + </javadoc> + + <!-- Copy the copyright file --> + <copy todir="${build}/javadocs"> + <fileset dir="." includes="COPYRIGHT.txt"/> + </copy> + </target> + + <target name="dist" depends="jar-opt,docs"> + <!-- Create the distribution directory --> + <mkdir dir="${dist}/lib/ext"/> + + <!-- Copy the jar file --> + <copy file="${build}/opt/lib/ext/vecmath.jar" todir="${dist}/lib/ext"/> + + <!-- Create the docs distribution directory --> + <mkdir dir="${dist}/javadocs"/> + + <!-- Put everything in ${build}/javadocs into the zip docname file --> + <zip zipfile="${dist}/javadocs/${docname}.zip" basedir="${build}/javadocs"/> + </target> + + <target name="all" depends="jar-debug,dist"/> + + <target name="clean-dist"> + <!-- Delete the ${dist} directory tree --> + <delete dir="${dist}"/> + </target> + + <target name="clean"> + <!-- Delete the ${build}, and ${dist} directory trees --> + <delete dir="${build}"/> + <delete dir="${dist}"/> + </target> + + <description> +The following ant targets are available ("jar-opt" is the default): + + all - execute targets jar-debug and dist + + clean - removes WS/build/ and WS/dist/ + + clean-dist - removes WS/dist + + compile - execute targets compile-debug and compile-opt + + compile-debug - builds all classes in WS/src into class files + under WS/build/classes/debug + + compile-opt - builds all classes in WS/src/ into class files + under WS/build/classes/opt + + dist - creates WS/dist/lib/opt/ext/vecmath.jar + from class files under WS/build/classes/opt and + creates WS/dist/doc/vecmath-${version}-doc.zip from + javadoc under WS/build/javadocs + + docs - builds all classes in WS/src into javadoc under + WS/build/javadocs + + echo - echo some useful information, such as user.home, + ant.home and java.home + + jar - execute targets jar-debug and jar-opt + + jar-debug - creates WS/build/lib/debug/ext/vecmath.jar + from class files under WS/build/classes/debug + + jar-opt - creates WS/build/lib/opt/ext/vecmath.jar + from class files under WS/build/classes/opt + </description> +</project> diff --git a/src/VECMATH.MF b/src/VECMATH.MF new file mode 100644 index 0000000..32b4dad --- /dev/null +++ b/src/VECMATH.MF @@ -0,0 +1,9 @@ +Manifest-Version: 1.0 +Specification-Title: Java 3D API Specification +Specification-Version: 1.3 +Specification-Vendor: Sun Microsystems, Inc. +Implementation-Title: Java 3D Vecmath Runtime Environment +Implementation-Version: 1.3.2 +Implementation-Vendor: Sun Microsystems, Inc. +Extension-Name: javax.vecmath +Implementation-Vendor-Id: com.sun diff --git a/src/javax/vecmath/AxisAngle4d.java b/src/javax/vecmath/AxisAngle4d.java new file mode 100644 index 0000000..d856081 --- /dev/null +++ b/src/javax/vecmath/AxisAngle4d.java @@ -0,0 +1,536 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A four-element axis angle represented by double-precision floating point + * x,y,z,angle components. An axis angle is a rotation of angle (radians) + * about the vector (x,y,z). + * + */ +public class AxisAngle4d implements java.io.Serializable, Cloneable { + + + // Compatible with 1.1 + static final long serialVersionUID = 3644296204459140589L; + + /** + * The x coordinate. + */ + public double x; + + /** + * The y coordinate. + */ + public double y; + + /** + * The z coordinate. + */ + public double z; + + /** + * The angle of rotation in radians. + */ + public double angle; + + final static double EPS = 0.000001; + + /** + * Constructs and initializes an AxisAngle4d from the specified + * x, y, z, and angle. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param angle the angle of rotation in radians + */ + public AxisAngle4d(double x, double y, double z, double angle) + { + this.x = x; + this.y = y; + this.z = z; + this.angle = angle; + } + + + /** + * Constructs and initializes an AxisAngle4d from the components + * contained in the array. + * @param a the array of length 4 containing x,y,z,angle in order + */ + public AxisAngle4d(double[] a) + { + this.x = a[0]; + this.y = a[1]; + this.z = a[2]; + this.angle = a[3]; + } + /** + * Constructs and initializes an AxisAngle4d from the specified AxisAngle4d. + * @param a1 the AxisAngle4d containing the initialization x y z angle data + */ + public AxisAngle4d(AxisAngle4d a1) + { + this.x = a1.x; + this.y = a1.y; + this.z = a1.z; + this.angle = a1.angle; + } + + + /** + * Constructs and initializes an AxisAngle4d from the specified + * AxisAngle4f. + * @param a1 the AxisAngle4f containing the initialization x y z angle data + */ + public AxisAngle4d(AxisAngle4f a1) + { + this.x = a1.x; + this.y = a1.y; + this.z = a1.z; + this.angle = a1.angle; + } + + + /** + * Constructs and initializes an AxisAngle4d from the specified + * axis and angle. + * @param axis the axis + * @param angle the angle of rotation in radian + * + * @since Java 3D 1.2 + */ + public AxisAngle4d(Vector3d axis, double angle) { + this.x = axis.x; + this.y = axis.y; + this.z = axis.z; + this.angle = angle; + } + + + /** + * Constructs and initializes an AxisAngle4d to (0,0,1,0). + */ + public AxisAngle4d() + { + this.x = 0.0; + this.y = 0.0; + this.z = 1.0; + this.angle = 0.0; + } + + + /** + * Sets the value of this axis angle to the specified x,y,z,angle. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param angle the angle of rotation in radians + */ + public final void set(double x, double y, double z, double angle) + { + this.x = x; + this.y = y; + this.z = z; + this.angle = angle; + } + + + /** + * Sets the value of this axis angle to the specified x,y,z,angle. + * @param a the array of length 4 containing x,y,z,angle in order + */ + public final void set(double[] a) + { + this.x = a[0]; + this.y = a[1]; + this.z = a[2]; + this.angle = a[3]; + } + + + /** + * Sets the value of this axis angle to the value of axis angle a1. + * @param a1 the axis angle to be copied + */ + public final void set(AxisAngle4d a1) + { + this.x = a1.x; + this.y = a1.y; + this.z = a1.z; + this.angle = a1.angle; + } + + + /** + * Sets the value of this axis angle to the value of axis angle a1. + * @param a1 the axis angle to be copied + */ + public final void set(AxisAngle4f a1) + { + this.x = a1.x; + this.y = a1.y; + this.z = a1.z; + this.angle = a1.angle; + } + + + /** + * Sets the value of this AxisAngle4d to the specified + * axis and angle. + * @param axis the axis + * @param angle the angle of rotation in radians + * + * @since Java 3D 1.2 + */ + public final void set(Vector3d axis, double angle) { + this.x = axis.x; + this.y = axis.y; + this.z = axis.z; + this.angle = angle; + } + + + /** + * Gets the value of this axis angle and places it into the array a of + * length four in x,y,z,angle order. + * @param a the array of length four + */ + public final void get(double[] a) + { + a[0] = this.x; + a[1] = this.y; + a[2] = this.z; + a[3] = this.angle; + } + + + /** + * Sets the value of this axis-angle to the rotational component of + * the passed matrix. + * If the specified matrix has no rotational component, the value + * of this AxisAngle4d is set to an angle of 0 about an axis of (0,1,0). + * + * @param m1 the matrix4f + */ + public final void set(Matrix4f m1) + { + Matrix3d m3d = new Matrix3d(); + + m1.get(m3d); + + x = (float)(m3d.m21 - m3d.m12); + y = (float)(m3d.m02 - m3d.m20); + z = (float)(m3d.m10 - m3d.m01); + double mag = x*x + y*y + z*z; + + if (mag > EPS ) { + mag = Math.sqrt(mag); + double sin = 0.5*mag; + double cos = 0.5*(m3d.m00 + m3d.m11 + m3d.m22 - 1.0); + + angle = (float)Math.atan2(sin, cos); + + double invMag = 1.0/mag; + x = x*invMag; + y = y*invMag; + z = z*invMag; + } else { + x = 0.0f; + y = 1.0f; + z = 0.0f; + angle = 0.0f; + } + } + + + /** + * Sets the value of this axis-angle to the rotational component of + * the passed matrix. + * If the specified matrix has no rotational component, the value + * of this AxisAngle4d is set to an angle of 0 about an axis of (0,1,0). + * + * @param m1 the matrix4d + */ + public final void set(Matrix4d m1) + { + Matrix3d m3d = new Matrix3d(); + + m1.get(m3d); + + x = (float)(m3d.m21 - m3d.m12); + y = (float)(m3d.m02 - m3d.m20); + z = (float)(m3d.m10 - m3d.m01); + + double mag = x*x + y*y + z*z; + + if (mag > EPS ) { + mag = Math.sqrt(mag); + + double sin = 0.5*mag; + double cos = 0.5*(m3d.m00 + m3d.m11 + m3d.m22 - 1.0); + angle = (float)Math.atan2(sin, cos); + + double invMag = 1.0/mag; + x = x*invMag; + y = y*invMag; + z = z*invMag; + } else { + x = 0.0f; + y = 1.0f; + z = 0.0f; + angle = 0.0f; + } + } + + + /** + * Sets the value of this axis-angle to the rotational component of + * the passed matrix. + * If the specified matrix has no rotational component, the value + * of this AxisAngle4d is set to an angle of 0 about an axis of (0,1,0). + * @param m1 the matrix3f + */ + public final void set(Matrix3f m1) + { + x = (float)(m1.m21 - m1.m12); + y = (float)(m1.m02 - m1.m20); + z = (float)(m1.m10 - m1.m01); + double mag = x*x + y*y + z*z; + + if (mag > EPS ) { + mag = Math.sqrt(mag); + + double sin = 0.5*mag; + double cos = 0.5*(m1.m00 + m1.m11 + m1.m22 - 1.0); + angle = (float)Math.atan2(sin, cos); + + double invMag = 1.0/mag; + x = x*invMag; + y = y*invMag; + z = z*invMag; + } else { + x = 0.0f; + y = 1.0f; + z = 0.0f; + angle = 0.0f; + } + } + + + /** + * Sets the value of this axis-angle to the rotational component of + * the passed matrix. + * If the specified matrix has no rotational component, the value + * of this AxisAngle4d is set to an angle of 0 about an axis of (0,1,0). + * @param m1 the matrix3d + */ + public final void set(Matrix3d m1) + { + x = (float)(m1.m21 - m1.m12); + y = (float)(m1.m02 - m1.m20); + z = (float)(m1.m10 - m1.m01); + + double mag = x*x + y*y + z*z; + + if (mag > EPS ) { + mag = Math.sqrt(mag); + + double sin = 0.5*mag; + double cos = 0.5*(m1.m00 + m1.m11 + m1.m22 - 1.0); + + angle = (float)Math.atan2(sin, cos); + + double invMag = 1.0/mag; + x = x*invMag; + y = y*invMag; + z = z*invMag; + } else { + x = 0.0f; + y = 1.0f; + z = 0.0f; + angle = 0.0f; + } + + } + + + + /** + * Sets the value of this axis-angle to the rotational equivalent + * of the passed quaternion. + * If the specified quaternion has no rotational component, the value + * of this AxisAngle4d is set to an angle of 0 about an axis of (0,1,0). + * @param q1 the Quat4f + */ + public final void set(Quat4f q1) + { + double mag = q1.x*q1.x + q1.y*q1.y + q1.z*q1.z; + + if( mag > EPS ) { + mag = Math.sqrt(mag); + double invMag = 1.0/mag; + + x = q1.x*invMag; + y = q1.y*invMag; + z = q1.z*invMag; + angle = 2.0*Math.atan2(mag, q1.w); + } else { + x = 0.0f; + y = 1.0f; + z = 0.0f; + angle = 0.0f; + } + } + + + /** + * Sets the value of this axis-angle to the rotational equivalent + * of the passed quaternion. + * If the specified quaternion has no rotational component, the value + * of this AxisAngle4d is set to an angle of 0 about an axis of (0,1,0). + * @param q1 the Quat4d + */ + public final void set(Quat4d q1) + { + double mag = q1.x*q1.x + q1.y*q1.y + q1.z*q1.z; + + if ( mag > EPS ) { + mag = Math.sqrt(mag); + double invMag = 1.0/mag; + + x = q1.x*invMag; + y = q1.y*invMag; + z = q1.z*invMag; + angle = 2.0*Math.atan2(mag, q1.w); + } else { + x = 0.0f; + y = 1.0f; + z = 0.0f; + angle = 0f; + } + } + + + /** + * Returns a string that contains the values of this AxisAngle4d. + * The form is (x,y,z,angle). + * @return the String representation + */ + public String toString() { + return "(" + this.x + ", " + this.y + ", " + this.z + ", " + this.angle + ")"; + } + + + /** + * Returns true if all of the data members of AxisAngle4d a1 are + * equal to the corresponding data members in this AxisAngle4d. + * @param a1 the axis-angle with which the comparison is made + * @return true or false + */ + public boolean equals(AxisAngle4d a1) + { + try { + return(this.x == a1.x && this.y == a1.y && this.z == a1.z + && this.angle == a1.angle); + } + catch (NullPointerException e2) {return false;} + + } + /** + * Returns true if the Object o1 is of type AxisAngle4d and all of the + * data members of o1 are equal to the corresponding data members in + * this AxisAngle4d. + * @param o1 the object with which the comparison is made + * @return true or false + */ + public boolean equals(Object o1) + { + try { + AxisAngle4d a2 = (AxisAngle4d) o1; + return(this.x == a2.x && this.y == a2.y && this.z == a2.z + && this.angle == a2.angle); + } + catch (NullPointerException e2) {return false;} + catch (ClassCastException e1) {return false;} + + } + + + /** + * Returns true if the L-infinite distance between this axis-angle + * and axis-angle a1 is less than or equal to the epsilon parameter, + * otherwise returns false. The L-infinite + * distance is equal to + * MAX[abs(x1-x2), abs(y1-y2), abs(z1-z2), abs(angle1-angle2)]. + * @param a1 the axis-angle to be compared to this axis-angle + * @param epsilon the threshold value + */ + public boolean epsilonEquals(AxisAngle4d a1, double epsilon) + { + double diff; + + diff = x - a1.x; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = y - a1.y; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = z - a1.z; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = angle - a1.angle; + 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 AxisAngle4d objects with identical data values + * (i.e., AxisAngle4d.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 + */ + public int hashCode() { + long bits = 1L; + bits = 31L * bits + Double.doubleToLongBits(x); + bits = 31L * bits + Double.doubleToLongBits(y); + bits = 31L * bits + Double.doubleToLongBits(z); + bits = 31L * bits + Double.doubleToLongBits(angle); + return (int) (bits ^ (bits >> 32)); + } + + /** + * 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 Java 3D 1.3 + */ + public Object clone() { + // Since there are no arrays we can just use Object.clone() + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + } + +} diff --git a/src/javax/vecmath/AxisAngle4f.java b/src/javax/vecmath/AxisAngle4f.java new file mode 100644 index 0000000..7de19f9 --- /dev/null +++ b/src/javax/vecmath/AxisAngle4f.java @@ -0,0 +1,532 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A four-element axis angle represented by single-precision floating point + * x,y,z,angle components. An axis angle is a rotation of angle (radians) + * about the vector (x,y,z). + * + */ +public class AxisAngle4f implements java.io.Serializable, Cloneable { + + // Compatible with 1.1 + static final long serialVersionUID = -163246355858070601L; + + /** + * The x coordinate. + */ + public float x; + + /** + * The y coordinate. + */ + public float y; + + /** + * The z coordinate. + */ + public float z; + + /** + * The angle of rotation in radians. + */ + public float angle; + + final static double EPS = 0.000001; + + /** + * Constructs and initializes a AxisAngle4f from the specified xyzw coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param angle the angle of rotation in radians + */ + public AxisAngle4f(float x, float y, float z, float angle) + { + this.x = x; + this.y = y; + this.z = z; + this.angle = angle; + } + + + /** + * Constructs and initializes an AxisAngle4f from the array of length 4. + * @param a the array of length 4 containing x,y,z,angle in order + */ + public AxisAngle4f(float[] a) + { + this.x = a[0]; + this.y = a[1]; + this.z = a[2]; + this.angle = a[3]; + } + + + /** + * Constructs and initializes an AxisAngle4f from the specified + * AxisAngle4f. + * @param a1 the AxisAngle4f containing the initialization x y z angle data + */ + public AxisAngle4f(AxisAngle4f a1) + { + this.x = a1.x; + this.y = a1.y; + this.z = a1.z; + this.angle = a1.angle; + } + + + /** + * Constructs and initializes an AxisAngle4f from the specified AxisAngle4d. + * @param a1 the AxisAngle4d containing the initialization x y z angle data + */ + public AxisAngle4f(AxisAngle4d a1) + { + this.x = (float) a1.x; + this.y = (float) a1.y; + this.z = (float) a1.z; + this.angle = (float) a1.angle; + } + + + /** + * Constructs and initializes an AxisAngle4f from the specified + * axis and angle. + * @param axis the axis + * @param angle the angle of rotation in radians + * + * @since Java 3D 1.2 + */ + public AxisAngle4f(Vector3f axis, float angle) { + this.x = axis.x; + this.y = axis.y; + this.z = axis.z; + this.angle = angle; + } + + + /** + * Constructs and initializes an AxisAngle4f to (0,0,1,0). + */ + public AxisAngle4f() + { + this.x = 0.0f; + this.y = 0.0f; + this.z = 1.0f; + this.angle = 0.0f; + } + + + /** + * Sets the value of this axis-angle to the specified x,y,z,angle. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param angle the angle of rotation in radians + */ + public final void set(float x, float y, float z, float angle) + { + this.x = x; + this.y = y; + this.z = z; + this.angle = angle; + } + + + /** + * Sets the value of this axis-angle to the specified values in the + * array of length 4. + * @param a the array of length 4 containing x,y,z,angle in order + */ + public final void set(float[] a) + { + this.x = a[0]; + this.y = a[1]; + this.z = a[2]; + this.angle = a[3]; + } + + + /** + * Sets the value of this axis-angle to the value of axis-angle a1. + * @param a1 the axis-angle to be copied + */ + public final void set(AxisAngle4f a1) + { + this.x = a1.x; + this.y = a1.y; + this.z = a1.z; + this.angle = a1.angle; + } + + + /** + * Sets the value of this axis-angle to the value of axis-angle a1. + * @param a1 the axis-angle to be copied + */ + public final void set(AxisAngle4d a1) + { + this.x = (float) a1.x; + this.y = (float) a1.y; + this.z = (float) a1.z; + this.angle = (float) a1.angle; + } + + + /** + * Sets the value of this AxisAngle4f to the specified + * axis and angle. + * @param axis the axis + * @param angle the angle of rotation in radians + * + * @since Java 3D 1.2 + */ + public final void set(Vector3f axis, float angle) { + this.x = axis.x; + this.y = axis.y; + this.z = axis.z; + this.angle = angle; + } + + + /** + * Copies the value of this axis-angle into the array a. + * @param a the array + */ + public final void get(float[] a) + { + a[0] = this.x; + a[1] = this.y; + a[2] = this.z; + a[3] = this.angle; + } + + + /** + * Sets the value of this axis-angle to the rotational equivalent + * of the passed quaternion. + * If the specified quaternion has no rotational component, the value + * of this AxisAngle4f is set to an angle of 0 about an axis of (0,1,0). + * @param q1 the Quat4f + */ + public final void set(Quat4f q1) + { + double mag = q1.x*q1.x + q1.y*q1.y + q1.z*q1.z; + + if ( mag > EPS ) { + mag = Math.sqrt(mag); + double invMag = 1.0/mag; + + x = (float)(q1.x*invMag); + y = (float)(q1.y*invMag); + z = (float)(q1.z*invMag); + angle = (float)(2.0*Math.atan2(mag, q1.w)); + } else { + x = 0.0f; + y = 1.0f; + z = 0.0f; + angle = 0.0f; + } + } + + + /** + * Sets the value of this axis-angle to the rotational equivalent + * of the passed quaternion. + * If the specified quaternion has no rotational component, the value + * of this AxisAngle4f is set to an angle of 0 about an axis of (0,1,0). + * @param q1 the Quat4d + */ + public final void set(Quat4d q1) + { + double mag = q1.x*q1.x + q1.y*q1.y + q1.z*q1.z; + + if (mag > EPS) { + mag = Math.sqrt(mag); + double invMag = 1.0/mag; + + x = (float)(q1.x*invMag); + y = (float)(q1.y*invMag); + z = (float)(q1.z*invMag); + angle = (float)(2.0*Math.atan2(mag, q1.w)); + } else { + x = 0.0f; + y = 1.0f; + z = 0.0f; + angle = 0.0f; + } + } + + + /** + * Sets the value of this axis-angle to the rotational component of + * the passed matrix. + * If the specified matrix has no rotational component, the value + * of this AxisAngle4f is set to an angle of 0 about an axis of (0,1,0). + * @param m1 the matrix4f + */ + public final void set(Matrix4f m1) + { + Matrix3f m3f = new Matrix3f(); + + m1.get(m3f); + + x = m3f.m21 - m3f.m12; + y = m3f.m02 - m3f.m20; + z = m3f.m10 - m3f.m01; + double mag = x*x + y*y + z*z; + + if (mag > EPS) { + mag = Math.sqrt(mag); + double sin = 0.5*mag; + double cos = 0.5*(m3f.m00 + m3f.m11 + m3f.m22 - 1.0); + + angle = (float)Math.atan2(sin, cos); + double invMag = 1.0/mag; + x = (float)(x*invMag); + y = (float)(y*invMag); + z = (float)(z*invMag); + } else { + x = 0.0f; + y = 1.0f; + z = 0.0f; + angle = 0.0f; + } + + + } + + + /** + * Sets the value of this axis-angle to the rotational component of + * the passed matrix. + * If the specified matrix has no rotational component, the value + * of this AxisAngle4f is set to an angle of 0 about an axis of (0,1,0). + * @param m1 the matrix4d + */ + public final void set(Matrix4d m1) + { + Matrix3d m3d = new Matrix3d(); + + m1.get(m3d); + + + x = (float)(m3d.m21 - m3d.m12); + y = (float)(m3d.m02 - m3d.m20); + z = (float)(m3d.m10 - m3d.m01); + double mag = x*x + y*y + z*z; + + if (mag > EPS) { + mag = Math.sqrt(mag); + double sin = 0.5*mag; + double cos = 0.5*(m3d.m00 + m3d.m11 + m3d.m22 - 1.0); + angle = (float)Math.atan2(sin, cos); + + double invMag = 1.0/mag; + x = (float)(x*invMag); + y = (float)(y*invMag); + z = (float)(z*invMag); + } else { + x = 0.0f; + y = 1.0f; + z = 0.0f; + angle = 0.0f; + } + + } + + + /** + * Sets the value of this axis-angle to the rotational component of + * the passed matrix. + * If the specified matrix has no rotational component, the value + * of this AxisAngle4f is set to an angle of 0 about an axis of (0,1,0). + * @param m1 the matrix3f + */ + public final void set(Matrix3f m1) + { + x = (float)(m1.m21 - m1.m12); + y = (float)(m1.m02 - m1.m20); + z = (float)(m1.m10 - m1.m01); + double mag = x*x + y*y + z*z; + if (mag > EPS) { + mag = Math.sqrt(mag); + double sin = 0.5*mag; + double cos = 0.5*(m1.m00 + m1.m11 + m1.m22 - 1.0); + + angle = (float)Math.atan2(sin, cos); + + double invMag = 1.0/mag; + x = (float)(x*invMag); + y = (float)(y*invMag); + z = (float)(z*invMag); + } else { + x = 0.0f; + y = 1.0f; + z = 0.0f; + angle = 0.0f; + } + + } + + + /** + * Sets the value of this axis-angle to the rotational component of + * the passed matrix. + * If the specified matrix has no rotational component, the value + * of this AxisAngle4f is set to an angle of 0 about an axis of (0,1,0). + * @param m1 the matrix3d + */ + public final void set(Matrix3d m1) + { + + x = (float)(m1.m21 - m1.m12); + y = (float)(m1.m02 - m1.m20); + z = (float)(m1.m10 - m1.m01); + double mag = x*x + y*y + z*z; + + if (mag > EPS) { + mag = Math.sqrt(mag); + double sin = 0.5*mag; + double cos = 0.5*(m1.m00 + m1.m11 + m1.m22 - 1.0); + + angle = (float)Math.atan2(sin, cos); + + double invMag = 1.0/mag; + x = (float)(x*invMag); + y = (float)(y*invMag); + z = (float)(z*invMag); + } else { + x = 0.0f; + y = 1.0f; + z = 0.0f; + angle = 0.0f; + } + } + + + /** + * Returns a string that contains the values of this AxisAngle4f. + * The form is (x,y,z,angle). + * @return the String representation + */ + public String toString() { + return "(" + this.x + ", " + this.y + ", " + this.z + ", " + this.angle + ")"; + } + + + /** + * Returns true if all of the data members of AxisAngle4f a1 are + * equal to the corresponding data members in this AxisAngle4f. + * @param a1 the axis-angle with which the comparison is made + * @return true or false + */ + public boolean equals(AxisAngle4f a1) + { + try { + return(this.x == a1.x && this.y == a1.y && this.z == a1.z + && this.angle == a1.angle); + } + catch (NullPointerException e2) {return false;} + + } + + /** + * Returns true if the Object o1 is of type AxisAngle4f and all of the + * data members of o1 are equal to the corresponding data members in + * this AxisAngle4f. + * @param o1 the object with which the comparison is made + * @return true or false + */ + public boolean equals(Object o1) + { + try { + AxisAngle4f a2 = (AxisAngle4f) o1; + return(this.x == a2.x && this.y == a2.y && this.z == a2.z + && this.angle == a2.angle); + } + catch (NullPointerException e2) {return false;} + catch (ClassCastException e1) {return false;} + + } + + /** + * Returns true if the L-infinite distance between this axis-angle + * and axis-angle a1 is less than or equal to the epsilon parameter, + * otherwise returns false. The L-infinite + * distance is equal to + * MAX[abs(x1-x2), abs(y1-y2), abs(z1-z2), abs(angle1-angle2)]. + * @param a1 the axis-angle to be compared to this axis-angle + * @param epsilon the threshold value + */ + public boolean epsilonEquals(AxisAngle4f a1, float epsilon) + { + float diff; + + diff = x - a1.x; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = y - a1.y; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = z - a1.z; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = angle - a1.angle; + 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 AxisAngle4f objects with identical data values + * (i.e., AxisAngle4f.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 + */ + public int hashCode() { + long bits = 1L; + bits = 31L * bits + (long)Float.floatToIntBits(x); + bits = 31L * bits + (long)Float.floatToIntBits(y); + bits = 31L * bits + (long)Float.floatToIntBits(z); + bits = 31L * bits + (long)Float.floatToIntBits(angle); + return (int) (bits ^ (bits >> 32)); + } + + /** + * 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 Java 3D 1.3 + */ + public Object clone() { + // Since there are no arrays we can just use Object.clone() + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + } + +} diff --git a/src/javax/vecmath/Color3b.java b/src/javax/vecmath/Color3b.java new file mode 100644 index 0000000..4ad55d0 --- /dev/null +++ b/src/javax/vecmath/Color3b.java @@ -0,0 +1,135 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.awt.Color; + + +/** + * A three-byte color value represented by byte x, y, and z values. The + * x, y, and z values represent the red, green, and blue values, + * respectively. + * <p> + * Note that Java defines a byte as a signed integer in the range + * [-128, 127]. However, colors are more typically represented by values + * in the range [0, 255]. Java 3D recognizes this and for color + * treats the bytes as if the range were [0, 255]---in other words, as + * if the bytes were unsigned. + * <p> + * Java 3D assumes that a linear (gamma-corrected) visual is used for + * all colors. + * + */ +public class Color3b extends Tuple3b implements java.io.Serializable { + + // Compatible with 1.1 + static final long serialVersionUID = 6632576088353444794L; + + /** + * Constructs and initializes a Color3b from the specified three values. + * @param c1 the red color value + * @param c2 the green color value + * @param c3 the blue color value + */ + public Color3b(byte c1, byte c2, byte c3) { + super(c1,c2,c3); + } + + + /** + * Constructs and initializes a Color3b from input array of length 3. + * @param c the array of length 3 containing the r,g,b data in order + */ + public Color3b(byte[] c) { + super(c); + } + + + /** + * Constructs and initializes a Color3b from the specified Color3b. + * @param c1 the Color3b containing the initialization r,g,b data + */ + public Color3b(Color3b c1) { + super(c1); + } + + + /** + * Constructs and initializes a Color3b from the specified Tuple3b. + * @param t1 the Tuple3b containing the initialization r,g,b data + */ + public Color3b(Tuple3b t1) { + super(t1); + } + + + /** + * Constructs and initializes a Color3b from the specified AWT + * Color object. The alpha value of the AWT color is ignored. + * No conversion is done on the color to compensate for + * gamma correction. + * + * @param color the AWT color with which to initialize this + * Color3b object + * + * @since Java 3D 1.2 + */ + public Color3b(Color color) { + super((byte)color.getRed(), + (byte)color.getGreen(), + (byte)color.getBlue()); + } + + + /** + * Constructs and initializes a Color3b to (0,0,0). + */ + public Color3b() { + super(); + } + + + /** + * Sets the r,g,b values of this Color3b object to those of the + * specified AWT Color object. + * No conversion is done on the color to compensate for + * gamma correction. + * + * @param color the AWT color to copy into this Color3b object + * + * @since Java 3D 1.2 + */ + public final void set(Color color) { + x = (byte)color.getRed(); + y = (byte)color.getGreen(); + z = (byte)color.getBlue(); + } + + + /** + * Returns a new AWT color object initialized with the r,g,b + * values of this Color3b object. + * + * @return a new AWT Color object + * + * @since Java 3D 1.2 + */ + public final Color get() { + int r = (int)x & 0xff; + int g = (int)y & 0xff; + int b = (int)z & 0xff; + + return new Color(r, g, b); + } + +} diff --git a/src/javax/vecmath/Color3f.java b/src/javax/vecmath/Color3f.java new file mode 100644 index 0000000..f7ea10b --- /dev/null +++ b/src/javax/vecmath/Color3f.java @@ -0,0 +1,139 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.awt.Color; + + +/** + * A three-element color value represented by single precision floating + * point x,y,z values. The x,y,z values represent the red, green, and + * blue color values, respectively. Color components should be in the + * range of [0.0, 1.0]. + * <p> + * Java 3D assumes that a linear (gamma-corrected) visual is used for + * all colors. + * + */ +public class Color3f extends Tuple3f implements java.io.Serializable { + + // Compatible with 1.1 + static final long serialVersionUID = -1861792981817493659L; + + /** + * Constructs and initializes a Color3f from the three xyz values. + * @param x the red color value + * @param y the green color value + * @param z the blue color value + */ + public Color3f(float x, float y, float z) { + super(x,y,z); + } + + + /** + * Constructs and initializes a Color3f from the array of length 3. + * @param v the array of length 3 containing xyz in order + */ + public Color3f(float[] v) { + super(v); + } + + + /** + * Constructs and initializes a Color3f from the specified Color3f. + * @param v1 the Color3f containing the initialization x y z data + */ + public Color3f(Color3f v1) { + super(v1); + } + + + /** + * Constructs and initializes a Color3f from the specified Tuple3f. + * @param t1 the Tuple3f containing the initialization x y z data + */ + public Color3f(Tuple3f t1) { + super(t1); + } + + + /** + * Constructs and initializes a Color3f from the specified Tuple3d. + * @param t1 the Tuple3d containing the initialization x y z data + */ + public Color3f(Tuple3d t1) { + super(t1); + } + + + /** + * Constructs and initializes a Color3f from the specified AWT + * Color object. The alpha value of the AWT color is ignored. + * No conversion is done on the color to compensate for + * gamma correction. + * + * @param color the AWT color with which to initialize this + * Color3f object + * + * @since Java 3D 1.2 + */ + public Color3f(Color color) { + super((float)color.getRed() / 255.0f, + (float)color.getGreen() / 255.0f, + (float)color.getBlue() / 255.0f); + } + + + /** + * Constructs and initializes a Color3f to (0.0, 0.0, 0.0). + */ + public Color3f() { + super(); + } + + + /** + * Sets the r,g,b values of this Color3f object to those of the + * specified AWT Color object. + * No conversion is done on the color to compensate for + * gamma correction. + * + * @param color the AWT color to copy into this Color3f object + * + * @since Java 3D 1.2 + */ + public final void set(Color color) { + x = (float)color.getRed() / 255.0f; + y = (float)color.getGreen() / 255.0f; + z = (float)color.getBlue() / 255.0f; + } + + + /** + * Returns a new AWT color object initialized with the r,g,b + * values of this Color3f object. + * + * @return a new AWT Color object + * + * @since Java 3D 1.2 + */ + public final Color get() { + int r = Math.round(x * 255.0f); + int g = Math.round(y * 255.0f); + int b = Math.round(z * 255.0f); + + return new Color(r, g, b); + } + +} diff --git a/src/javax/vecmath/Color4b.java b/src/javax/vecmath/Color4b.java new file mode 100644 index 0000000..929821a --- /dev/null +++ b/src/javax/vecmath/Color4b.java @@ -0,0 +1,141 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.awt.Color; + + +/** + * A four-byte color value represented by byte x, y, z, and w values. + * The x, y, z, and w values represent the red, green, blue, and alpha + * values, respectively. + * <p> + * Note that Java defines a byte as a signed integer in the range + * [-128, 127]. However, colors are more typically represented by values + * in the range [0, 255]. Java 3D recognizes this and for color + * treats the bytes as if the range were [0, 255]---in other words, as + * if the bytes were unsigned. + * <p> + * Java 3D assumes that a linear (gamma-corrected) visual is used for + * all colors. + * + */ +public class Color4b extends Tuple4b implements java.io.Serializable { + + // Compatible with 1.1 + static final long serialVersionUID = -105080578052502155L; + + /** + * Constructs and initializes a Color4b from the four specified values. + * @param b1 the red color value + * @param b2 the green color value + * @param b3 the blue color value + * @param b4 the alpha value + */ + public Color4b(byte b1, byte b2, byte b3, byte b4) { + super(b1,b2,b3,b4); + } + + + /** + * Constructs and initializes a Color4b from the array of length 4. + * @param c the array of length 4 containing r, g, b, and alpha in order + */ + public Color4b(byte[] c) { + super(c); + } + + + /** + * Constructs and initializes a Color4b from the specified Color4b. + * @param c1 the Color4b containing the initialization r,g,b,a + * data + */ + public Color4b(Color4b c1) { + super(c1); + } + + + /** + * Constructs and initializes a Color4b from the specified Tuple4b. + * @param t1 the Tuple4b containing the initialization r,g,b,a + * data + */ + public Color4b(Tuple4b t1) { + super(t1); + } + + + /** + * Constructs and initializes a Color4b from the specified AWT + * Color object. + * No conversion is done on the color to compensate for + * gamma correction. + * + * @param color the AWT color with which to initialize this + * Color4b object + * + * @since Java 3D 1.2 + */ + public Color4b(Color color) { + super((byte)color.getRed(), + (byte)color.getGreen(), + (byte)color.getBlue(), + (byte)color.getAlpha()); + } + + + /** + * Constructs and initializes a Color4b to (0,0,0,0). + */ + public Color4b() { + super(); + } + + + /** + * Sets the r,g,b,a values of this Color4b object to those of the + * specified AWT Color object. + * No conversion is done on the color to compensate for + * gamma correction. + * + * @param color the AWT color to copy into this Color4b object + * + * @since Java 3D 1.2 + */ + public final void set(Color color) { + x = (byte)color.getRed(); + y = (byte)color.getGreen(); + z = (byte)color.getBlue(); + w = (byte)color.getAlpha(); + } + + + /** + * Returns a new AWT color object initialized with the r,g,b,a + * values of this Color4b object. + * + * @return a new AWT Color object + * + * @since Java 3D 1.2 + */ + public final Color get() { + int r = (int)x & 0xff; + int g = (int)y & 0xff; + int b = (int)z & 0xff; + int a = (int)w & 0xff; + + return new Color(r, g, b, a); + } + +} diff --git a/src/javax/vecmath/Color4f.java b/src/javax/vecmath/Color4f.java new file mode 100644 index 0000000..265086f --- /dev/null +++ b/src/javax/vecmath/Color4f.java @@ -0,0 +1,144 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.awt.Color; + + +/** + * A four-element color represented by single precision floating point + * x, y, z, and w values. The x, y, z, and w values represent the red, + * blue, green, and alpha color values, respectively. Color and alpha + * components should be in the range [0.0, 1.0]. + * <p> + * Java 3D assumes that a linear (gamma-corrected) visual is used for + * all colors. + * + */ +public class Color4f extends Tuple4f implements java.io.Serializable { + + // Compatible with 1.1 + static final long serialVersionUID = 8577680141580006740L; + + /** + * Constructs and initializes a Color4f from the specified xyzw + * coordinates. + * @param x the red color value + * @param y the green color value + * @param z the blue color value + * @param w the alpha value + */ + public Color4f(float x, float y, float z, float w) { + super(x,y,z,w); + } + + + /** + * Constructs and initializes a Color4f from the array of length 4. + * @param c the array of length 4 containing r,g,b,a in order + */ + public Color4f(float[] c) { + super(c); + } + + + /** + * Constructs and initializes a Color4f from the specified Color4f. + * @param c1 the Color4f containing the initialization r,g,b,a data + */ + public Color4f(Color4f c1) { + super(c1); + } + + + /** + * Constructs and initializes a Color4f from the specified Tuple4f. + * @param t1 the Tuple4f containing the initialization r,g,b,a data + */ + public Color4f(Tuple4f t1) { + super(t1); + } + + + /** + * Constructs and initializes a Color4f from the specified Tuple4d. + * @param t1 the Tuple4d containing the initialization r,g,b,a data + */ + public Color4f(Tuple4d t1) { + super(t1); + } + + + /** + * Constructs and initializes a Color4f from the specified AWT + * Color object. + * No conversion is done on the color to compensate for + * gamma correction. + * + * @param color the AWT color with which to initialize this + * Color4f object + * + * @since Java 3D 1.2 + */ + public Color4f(Color color) { + super((float)color.getRed() / 255.0f, + (float)color.getGreen() / 255.0f, + (float)color.getBlue() / 255.0f, + (float)color.getAlpha() / 255.0f); + } + + + /** + * Constructs and initializes a Color4f to (0.0, 0.0, 0.0, 0.0). + */ + public Color4f() { + super(); + } + + + /** + * Sets the r,g,b,a values of this Color4f object to those of the + * specified AWT Color object. + * No conversion is done on the color to compensate for + * gamma correction. + * + * @param color the AWT color to copy into this Color4f object + * + * @since Java 3D 1.2 + */ + public final void set(Color color) { + x = (float)color.getRed() / 255.0f; + y = (float)color.getGreen() / 255.0f; + z = (float)color.getBlue() / 255.0f; + w = (float)color.getAlpha() / 255.0f; + } + + + /** + * Returns a new AWT color object initialized with the r,g,b,a + * values of this Color4f object. + * + * @return a new AWT Color object + * + * @since Java 3D 1.2 + */ + public final Color get() { + int r = Math.round(x * 255.0f); + int g = Math.round(y * 255.0f); + int b = Math.round(z * 255.0f); + int a = Math.round(w * 255.0f); + + return new Color(r, g, b, a); + } + +} diff --git a/src/javax/vecmath/ExceptionStrings.properties b/src/javax/vecmath/ExceptionStrings.properties new file mode 100644 index 0000000..ca56746 --- /dev/null +++ b/src/javax/vecmath/ExceptionStrings.properties @@ -0,0 +1,86 @@ +Matrix3d0=Matrix3d setElement +Matrix3d1=Matrix3d getElement +Matrix3d2=Matrix3d getRow +Matrix3d4=Matrix3d getColumn +Matrix3d6=Matrix3d setRow +Matrix3d9=Matrix3d setColumn +Matrix3d12=cannot invert matrix +Matrix3d13=Logic error: imax < 0 +Matrix3f0=Matrix3f setElement +Matrix3f1=Matrix3d getRow +Matrix3f3=Matrix3d getColumn +Matrix3f5=Matrix3f getElement +Matrix3f6=Matrix3f setRow +Matrix3f9=Matrix3f setColumn +Matrix3f12=cannot invert matrix +Matrix3f13=Logic error: imax < 0 +Matrix4d0=Matrix4d setElement +Matrix4d1=Matrix4d getElement +Matrix4d2=Matrix4d getRow +Matrix4d3=Matrix4d getColumn +Matrix4d4=Matrix4d setRow +Matrix4d7=Matrix4d setColumn +Matrix4d10=cannot invert matrix +Matrix4d11=Logic error: imax < 0 +Matrix4f0=Matrix4f setElement +Matrix4f1=Matrix4f getElement +Matrix4f2=Matrix4f getRow +Matrix4f4=Matrix4f getColumn +Matrix4f6=Matrix4f setRow +Matrix4f9=Matrix4f setColumn +Matrix4f12=cannot invert matrix +Matrix4f13=Logic error: imax < 0 +GMatrix0=GMatrix.mul:array dimension mismatch +GMatrix1=GMatrix.mul(GMatrix, GMatrix) dimension mismatch +GMatrix2=GMatrix.mul(GVector, GVector): matrix does not have enough rows +GMatrix3=GMatrix.mul(GVector, GVector): matrix does not have enough columns +GMatrix4=GMatrix.add(GMatrix): row dimension mismatch +GMatrix5=GMatrix.add(GMatrix): column dimension mismatch +GMatrix6=GMatrix.add(GMatrix, GMatrix): row dimension mismatch +GMatrix7=GMatrix.add(GMatrix, GMatrix): column dimension mismatch +GMatrix8=GMatrix.add(GMatrix): input matrices dimensions do not match this matrix dimensions +GMatrix9=GMatrix.sub(GMatrix): row dimension mismatch +GMatrix10=GMatrix.sub(GMatrix, GMatrix): row dimension mismatch +GMatrix11=GMatrix.sub(GMatrix, GMatrix): column dimension mismatch +GMatrix12=GMatrix.sub(GMatrix, GMatrix): input matrix dimensions do not match dimensions for this matrix +GMatrix13=GMatrix.negate(GMatrix, GMatrix): input matrix dimensions do not match dimensions for this matrix +GMatrix14=GMatrix.mulTransposeBoth matrix dimension mismatch +GMatrix15=GMatrix.mulTransposeRight matrix dimension mismatch +GMatrix16=GMatrix.mulTransposeLeft matrix dimension mismatch +GMatrix17=GMatrix.transpose(GMatrix) mismatch in matrix dimensions +GMatrix18=GMatrix.SVD: dimension mismatch with V matrix +GMatrix19=cannot perform LU decomposition on a non square matrix +GMatrix20=row permutation must be same dimension as matrix +GMatrix21=cannot invert matrix +GMatrix22=cannot invert non square matrix +GMatrix24=Logic error: imax < 0 +GMatrix25=GMatrix.SVD: dimension mismatch with U matrix +GMatrix26=GMatrix.SVD: dimension mismatch with W matrix +GMatrix27=LU must have same dimensions as this matrix +GMatrix28=GMatrix.sub(GMatrix): column dimension mismatch +GVector0=GVector.normalize( GVector) input vector and this vector lengths not matched +GVector1=GVector.scale(double, GVector) input vector and this vector lengths not matched +GVector2=GVector.scaleAdd(GVector, GVector) input vector dimensions not matched +GVector3=GVector.scaleAdd(GVector, GVector) input vectors and this vector dimensions not matched +GVector4=GVector.add(GVector) input vectors and this vector dimensions not matched +GVector5=GVector.add(GVector, GVector) input vector dimensions not matched +GVector6=GVector.add(GVector, GVector) input vectors and this vector dimensions not matched +GVector7=GVector.sub(GVector) input vector and this vector dimensions not matched +GVector8=GVector.sub(GVector, GVector) input vector dimensions not matched +GVector9=GVector.sub(GMatrix, GVector) input vectors and this vector dimensions not matched +GVector10=GVector.mul(GMatrix, GVector) matrix and vector dimensions not matched +GVector11=GVector.mul(GMatrix, GVector) matrix this vector dimensions not matched +GVector12=GVector.mul(GVector, GMatrix) matrix and vector dimensions not matched +GVector13=GVector.mul(GVector, GMatrix) matrix this vector dimensions not matched +GVector14=GVector.dot(GVector) input vector and this vector have different sizes +GVector15=matrix dimensions are not compatible +GVector16=b vector does not match matrix dimension +GVector17=GVector.interpolate(GVector, GVector, float) input vectors have different lengths +GVector18=GVector.interpolate(GVector, GVector, float) input vectors and this vector have different lengths +GVector19=GVector.interpolate(GVector, float) input vector and this vector have different lengths +GVector20=GVector.interpolate(GVector, GVector, double) input vectors have different lengths +GVector21=GVector.interpolate(GVector, GVector, double) input vectors and this vector have different lengths +GVector22=GVector.interpolate(GVector, double) input vectors and this vector have different lengths +GVector23=matrix dimensions are not compatible +GVector24=permutation vector does not match matrix dimension +GVector25=LUDBackSolve non square matrix diff --git a/src/javax/vecmath/GMatrix.java b/src/javax/vecmath/GMatrix.java new file mode 100644 index 0000000..5ccdbb4 --- /dev/null +++ b/src/javax/vecmath/GMatrix.java @@ -0,0 +1,2989 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A double precision, general, dynamically-resizable, + * two-dimensional matrix class. Row and column numbering begins with + * zero. The representation is row major. + */ + +public class GMatrix implements java.io.Serializable, Cloneable { + + // Compatible with 1.1 + static final long serialVersionUID = 2777097312029690941L; + private static final boolean debug = false; + + int nRow; + int nCol; + + // double dereference is slow + double[][] values; + + private static final double EPS = 1.0E-10; + + /** + * Constructs an nRow by NCol identity matrix. + * Note that because row and column numbering begins with + * zero, nRow and nCol will be one larger than the maximum + * possible matrix index values. + * @param nRow number of rows in this matrix. + * @param nCol number of columns in this matrix. + */ + public GMatrix(int nRow, int nCol) + { + values = new double[nRow][nCol]; + this.nRow = nRow; + this.nCol = nCol; + + int i, j; + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + values[i][j] = 0.0; + } + } + + int l; + if (nRow < nCol) + l = nRow; + else + l = nCol; + + for (i = 0; i < l; i++) { + values[i][i] = 1.0; + } + } + + /** + * Constructs an nRow by nCol matrix initialized to the values + * in the matrix array. The array values are copied in one row at + * a time in row major fashion. The array should be at least + * nRow*nCol in length. + * Note that because row and column numbering begins with + * zero, nRow and nCol will be one larger than the maximum + * possible matrix index values. + * @param nRow number of rows in this matrix. + * @param nCol number of columns in this matrix. + * @param matrix a 1D array that specifies a matrix in row major fashion + */ + public GMatrix(int nRow, int nCol, double[] matrix) + { + values = new double[nRow][nCol]; + this.nRow = nRow; + this.nCol = nCol; + + int i, j; + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + values[i][j] = matrix[i*nCol+j]; + } + } + } + + /** + * Constructs a new GMatrix and copies the initial values + * from the parameter matrix. + * @param matrix the source of the initial values of the new GMatrix + */ + public GMatrix(GMatrix matrix) + { + nRow = matrix.nRow; + nCol = matrix.nCol; + values = new double[nRow][nCol]; + + int i, j; + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + values[i][j] = matrix.values[i][j]; + } + } + } + + /** + * Sets the value of this matrix to the result of multiplying itself + * with matrix m1 (this = this * m1). + * @param m1 the other matrix + */ + public final void mul(GMatrix m1) + { + int i, j, k; + + if (nCol != m1.nRow || nCol != m1.nCol) + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix0")); + + double [][] tmp = new double[nRow][nCol]; + + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + tmp[i][j] = 0.0; + for (k = 0; k < nCol; k++) { + tmp[i][j] += values[i][k]*m1.values[k][j]; + } + } + } + + values = tmp; + } + + /** + * Sets the value of this matrix to the result of multiplying + * the two argument matrices together (this = m1 * m2). + * @param m1 the first matrix + * @param m2 the second matrix + */ + public final void mul(GMatrix m1, GMatrix m2) + { + int i, j, k; + + if (m1.nCol != m2.nRow || nRow != m1.nRow || nCol != m2.nCol) + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix1")); + + double[][] tmp = new double[nRow][nCol]; + + for (i = 0; i < m1.nRow; i++) { + for (j = 0; j < m2.nCol; j++) { + tmp[i][j] = 0.0; + for (k = 0; k < m1.nCol; k++) { + tmp[i][j] += m1.values[i][k]*m2.values[k][j]; + } + } + } + + values = tmp; + } + + /** + * Computes the outer product of the two vectors; multiplies the + * the first vector by the transpose of the second vector and places + * the matrix result into this matrix. This matrix must be + * be as big or bigger than getSize(v1)xgetSize(v2). + * @param v1 the first vector, treated as a row vector + * @param v2 the second vector, treated as a column vector + */ + public final void mul(GVector v1, GVector v2) + { + int i, j; + + if (nRow < v1.getSize()) + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix2")); + + if (nCol < v2.getSize()) + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix3")); + + for (i = 0; i < v1.getSize(); i++ ) { + for (j = 0; j < v2.getSize(); j++ ) { + values[i][j] = v1.values[i]*v2.values[j]; + } + } + } + + /** + * Sets the value of this matrix to sum of itself and matrix m1. + * @param m1 the other matrix + */ + public final void add(GMatrix m1) + { + int i, j; + + if (nRow != m1.nRow) + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix4")); + + if (nCol != m1.nCol) + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix5")); + + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + values[i][j] = values[i][j] + m1.values[i][j]; + } + } + } + + /** + * 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(GMatrix m1, GMatrix m2) + { + int i, j; + + if (m2.nRow != m1.nRow) + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix6")); + + if (m2.nCol != m1.nCol) + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix7")); + + if (nCol != m1.nCol || nRow != m1.nRow) + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix8")); + + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + values[i][j] = m1.values[i][j] + m2.values[i][j]; + } + } + } + + /** + * 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(GMatrix m1) + { + int i, j; + if (nRow != m1.nRow) + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix9")); + + if (nCol != m1.nCol) + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix28")); + + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + values[i][j] = values[i][j] - m1.values[i][j]; + } + } + } + + /** + * Sets the value of this matrix to the matrix difference + * of matrices m1 and m2 (this = m1 - m2). + * @param m1 the first matrix + * @param m2 the second matrix + */ + public final void sub(GMatrix m1, GMatrix m2) + { + int i, j; + if (m2.nRow != m1.nRow) + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix10")); + + if (m2.nCol != m1.nCol) + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix11")); + + if (nRow != m1.nRow || nCol != m1.nCol) + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix12")); + + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + values[i][j] = m1.values[i][j] - m2.values[i][j]; + } + } + } + + /** + * Negates the value of this matrix: this = -this. + */ + public final void negate() + { + int i, j; + for (i = 0; i < nRow; i++) { + for (j = 0;j < nCol; j++) { + values[i][j] = -values[i][j]; + } + } + } + + /** + * Sets the value of this matrix equal to the negation of + * of the GMatrix parameter. + * @param m1 The source matrix + */ + public final void negate(GMatrix m1) + { + int i, j; + if (nRow != m1.nRow || nCol != m1.nCol) + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix13")); + + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + values[i][j] = -m1.values[i][j]; + } + } + } + + /** + * Sets this GMatrix to the identity matrix. + */ + public final void setIdentity() + { + int i, j; + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + values[i][j] = 0.0; + } + } + + int l; + if (nRow < nCol) + l = nRow; + else + l = nCol; + + for (i = 0; i < l; i++) { + values[i][i] = 1.0; + } + } + + /** + * Sets all the values in this matrix to zero. + */ + public final void setZero() + { + int i, j; + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + values[i][j] = 0.0; + } + } + } + + /** + * Subtracts this matrix from the identity matrix and puts the values + * back into this (this = I - this). + */ + public final void identityMinus() + { + int i, j; + + for(i = 0; i < nRow; i++) { + for(j = 0; j < nCol; j++) { + values[i][j] = -values[i][j]; + } + } + + int l; + if( nRow < nCol) + l = nRow; + else + l = nCol; + + for(i = 0; i < l; i++) { + values[i][i] += 1.0; + } + } + + + /** + * Inverts this matrix in place. + */ + public final void invert() + { + invertGeneral(this); + } + + /** + * Inverts matrix m1 and places the new values into this matrix. Matrix + * m1 is not modified. + * @param m1 the matrix to be inverted + */ + public final void invert(GMatrix m1) + { + invertGeneral(m1); + } + + /** + * Copies a sub-matrix derived from this matrix into the target matrix. + * The upper left of the sub-matrix is located at (rowSource, colSource); + * the lower right of the sub-matrix is located at + * (lastRowSource,lastColSource). The sub-matrix is copied into the + * the target matrix starting at (rowDest, colDest). + * @param rowSource the top-most row of the sub-matrix + * @param colSource the left-most column of the sub-matrix + * @param numRow the number of rows in the sub-matrix + * @param numCol the number of columns in the sub-matrix + * @param rowDest the top-most row of the position of the copied + * sub-matrix within the target matrix + * @param colDest the left-most column of the position of the copied + * sub-matrix within the target matrix + * @param target the matrix into which the sub-matrix will be copied + */ + public final void copySubMatrix(int rowSource, int colSource, + int numRow, int numCol, int rowDest, + int colDest, GMatrix target) + { + int i, j; + + if (this != target) { + for (i = 0; i < numRow; i++) { + for (j = 0; j < numCol; j++) { + target.values[rowDest+i][colDest+j] = + values[rowSource+i][colSource+j]; + } + } + } else { + double[][] tmp = new double[numRow][numCol]; + for (i = 0; i < numRow; i++) { + for (j = 0; j < numCol; j++) { + tmp[i][j] = values[rowSource+i][colSource+j]; + } + } + for (i = 0; i < numRow; i++) { + for (j = 0; j < numCol; j++) { + target.values[rowDest+i][colDest+j] = tmp[i][j]; + } + } + } + } + + /** + * Changes the size of this matrix dynamically. If the size is increased + * no data values will be lost. If the size is decreased, only those data + * values whose matrix positions were eliminated will be lost. + * @param nRow number of desired rows in this matrix + * @param nCol number of desired columns in this matrix + */ + public final void setSize(int nRow, int nCol) + { + double[][] tmp = new double[nRow][nCol]; + int i, j, maxRow, maxCol; + + if (this.nRow < nRow) + maxRow = this.nRow; + else + maxRow = nRow; + + if (this.nCol < nCol) + maxCol = this.nCol; + else + maxCol = nCol; + + for (i = 0; i < maxRow; i++) { + for (j = 0; j < maxCol; j++) { + tmp[i][j] = values[i][j]; + } + } + + this.nRow = nRow; + this.nCol = nCol; + + values = tmp; + } + + /** + * Sets the value of this matrix to the values found in the array parameter. + * The values are copied in one row at a time, in row major + * fashion. The array should be at least equal in length to + * the number of matrix rows times the number of matrix columns + * in this matrix. + * @param matrix the row major source array + */ + public final void set(double[] matrix) + { + int i, j; + + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + values[i][j] = matrix[nCol*i+j]; + } + } + } + + /** + * Sets the value of this matrix to that of the Matrix3f provided. + * @param m1 the matrix + */ + public final void set(Matrix3f m1) + { + int i, j; + + if (nCol < 3 || nRow < 3) { // expand matrix if too small + nCol = 3; + nRow = 3; + values = new double[nRow][nCol]; + } + + values[0][0] = m1.m00; + values[0][1] = m1.m01; + values[0][2] = m1.m02; + + values[1][0] = m1.m10; + values[1][1] = m1.m11; + values[1][2] = m1.m12; + + values[2][0] = m1.m20; + values[2][1] = m1.m21; + values[2][2] = m1.m22; + + for (i = 3; i < nRow; i++) { // pad rest or matrix with zeros + for (j = 3; j < nCol; j++) { + values[i][j] = 0.0; + } + } + } + + /** + * Sets the value of this matrix to that of the Matrix3d provided. + * @param m1 the matrix + */ + public final void set(Matrix3d m1) + { + if (nRow < 3 || nCol < 3) { + values = new double[3][3]; + nRow = 3; + nCol = 3; + } + + values[0][0] = m1.m00; + values[0][1] = m1.m01; + values[0][2] = m1.m02; + + values[1][0] = m1.m10; + values[1][1] = m1.m11; + values[1][2] = m1.m12; + + values[2][0] = m1.m20; + values[2][1] = m1.m21; + values[2][2] = m1.m22; + + for (int i = 3; i < nRow; i++) { // pad rest or matrix with zeros + for(int j = 3; j < nCol; j++) { + values[i][j] = 0.0; + } + } + + } + + /** + * Sets the value of this matrix to that of the Matrix4f provided. + * @param m1 the matrix + */ + public final void set(Matrix4f m1) + { + if (nRow < 4 || nCol < 4) { + values = new double[4][4]; + nRow = 4; + nCol = 4; + } + + values[0][0] = m1.m00; + values[0][1] = m1.m01; + values[0][2] = m1.m02; + values[0][3] = m1.m03; + + values[1][0] = m1.m10; + values[1][1] = m1.m11; + values[1][2] = m1.m12; + values[1][3] = m1.m13; + + values[2][0] = m1.m20; + values[2][1] = m1.m21; + values[2][2] = m1.m22; + values[2][3] = m1.m23; + + values[3][0] = m1.m30; + values[3][1] = m1.m31; + values[3][2] = m1.m32; + values[3][3] = m1.m33; + + for (int i = 4 ; i < nRow; i++) { // pad rest or matrix with zeros + for (int j = 4; j < nCol; j++) { + values[i][j] = 0.0; + } + } + } + + /** + * Sets the value of this matrix to that of the Matrix4d provided. + * @param m1 the matrix + */ + public final void set(Matrix4d m1) + { + if (nRow < 4 || nCol < 4) { + values = new double[4][4]; + nRow = 4; + nCol = 4; + } + + values[0][0] = m1.m00; + values[0][1] = m1.m01; + values[0][2] = m1.m02; + values[0][3] = m1.m03; + + values[1][0] = m1.m10; + values[1][1] = m1.m11; + values[1][2] = m1.m12; + values[1][3] = m1.m13; + + values[2][0] = m1.m20; + values[2][1] = m1.m21; + values[2][2] = m1.m22; + values[2][3] = m1.m23; + + values[3][0] = m1.m30; + values[3][1] = m1.m31; + values[3][2] = m1.m32; + values[3][3] = m1.m33; + + for (int i = 4; i < nRow; i++) { // pad rest or matrix with zeros + for (int j = 4; j < nCol; j++) { + values[i][j] = 0.0; + } + } + } + + /** + * Sets the value of this matrix to the values found in matrix m1. + * @param m1 the source matrix + */ + public final void set(GMatrix m1) + { + int i, j; + + if (nRow < m1.nRow || nCol < m1.nCol) { + nRow = m1.nRow; + nCol = m1.nCol; + values = new double[nRow][nCol]; + } + + for (i = 0; i < Math.min(nRow, m1.nRow); i++) { + for (j = 0; j < Math.min(nCol, m1.nCol); j++) { + values[i][j] = m1.values[i][j]; + } + } + + for (i = m1.nRow; i < nRow; i++) { // pad rest or matrix with zeros + for (j = m1.nCol; j < nCol; j++) { + values[i][j] = 0.0; + } + } + } + + /** + * Returns the number of rows in this matrix. + * @return number of rows in this matrix + */ + public final int getNumRow() + { + return(nRow); + } + + /** + * Returns the number of colmuns in this matrix. + * @return number of columns in this matrix + */ + public final int getNumCol() + { + return(nCol); + } + + /** + * Retrieves the value at the specified row and column of this 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) + { + return(values[row][column]); + } + + + /** + * Modifies the value at the specified row and column of this matrix. + * @param row the row number to be modified (zero indexed) + * @param column the column number to be modified (zero indexed) + * @param value the new matrix element value + */ + public final void setElement(int row, int column, double value) + { + values[row][column] = value; + } + + /** + * Places the values of the specified row into the array parameter. + * @param row the target row number + * @param array the array into which the row values will be placed + */ + public final void getRow(int row, double[] array) + { + for (int i = 0; i < nCol; i++) { + array[i] = values[row][i]; + } + } + + /** + * Places the values of the specified row into the vector parameter. + * @param row the target row number + * @param vector the vector into which the row values will be placed + */ + public final void getRow(int row, GVector vector) + { + if (vector.getSize() < nCol) + vector.setSize(nCol); + + for (int i = 0; i < nCol; i++) { + vector.values[i] = values[row][i]; + } + } + + /** + * Places the values of the specified column into the array parameter. + * @param col the target column number + * @param array the array into which the column values will be placed + */ + public final void getColumn(int col, double[] array) + { + for (int i = 0; i < nRow; i++) { + array[i] = values[i][col]; + } + + } + + /** + * Places the values of the specified column into the vector parameter. + * @param col the target column number + * @param vector the vector into which the column values will be placed + */ + public final void getColumn(int col, GVector vector) + { + if (vector.getSize() < nRow) + vector.setSize(nRow); + + for (int i = 0; i < nRow; i++) { + vector.values[i] = values[i][col]; + } + } + + /** + * Places the values in the upper 3x3 of this GMatrix into + * the matrix m1. + * @param m1 The matrix that will hold the new values + */ + public final void get(Matrix3d m1) + { + if (nRow < 3 || nCol < 3) { + m1.setZero(); + if (nCol > 0) { + if (nRow > 0){ + m1.m00 = values[0][0]; + if (nRow > 1){ + m1.m10 = values[1][0]; + if( nRow > 2 ){ + m1.m20= values[2][0]; + } + } + } + if (nCol > 1) { + if (nRow > 0) { + m1.m01 = values[0][1]; + if (nRow > 1){ + m1.m11 = values[1][1]; + if (nRow > 2){ + m1.m21 = values[2][1]; + } + } + } + if (nCol > 2) { + if (nRow > 0) { + m1.m02 = values[0][2]; + if (nRow > 1) { + m1.m12 = values[1][2]; + if (nRow > 2) { + m1.m22 = values[2][2]; + } + } + } + } + } + } + } else { + m1.m00 = values[0][0]; + m1.m01 = values[0][1]; + m1.m02 = values[0][2]; + + m1.m10 = values[1][0]; + m1.m11 = values[1][1]; + m1.m12 = values[1][2]; + + m1.m20 = values[2][0]; + m1.m21 = values[2][1]; + m1.m22 = values[2][2]; + } + } + + /** + * Places the values in the upper 3x3 of this GMatrix into + * the matrix m1. + * @param m1 The matrix that will hold the new values + */ + public final void get(Matrix3f m1) + { + + if (nRow < 3 || nCol < 3) { + m1.setZero(); + if (nCol > 0) { + if (nRow > 0) { + m1.m00 = (float)values[0][0]; + if (nRow > 1) { + m1.m10 = (float)values[1][0]; + if (nRow > 2) { + m1.m20 = (float)values[2][0]; + } + } + } + if (nCol > 1) { + if (nRow > 0) { + m1.m01 = (float)values[0][1]; + if (nRow > 1){ + m1.m11 = (float)values[1][1]; + if (nRow > 2){ + m1.m21 = (float)values[2][1]; + } + } + } + if (nCol > 2) { + if (nRow > 0) { + m1.m02 = (float)values[0][2]; + if (nRow > 1) { + m1.m12 = (float)values[1][2]; + if (nRow > 2) { + m1.m22 = (float)values[2][2]; + } + } + } + } + } + } + } else { + m1.m00 = (float)values[0][0]; + m1.m01 = (float)values[0][1]; + m1.m02 = (float)values[0][2]; + + m1.m10 = (float)values[1][0]; + m1.m11 = (float)values[1][1]; + m1.m12 = (float)values[1][2]; + + m1.m20 = (float)values[2][0]; + m1.m21 = (float)values[2][1]; + m1.m22 = (float)values[2][2]; + } + } + + /** + * Places the values in the upper 4x4 of this GMatrix into + * the matrix m1. + * @param m1 The matrix that will hold the new values + */ + public final void get(Matrix4d m1) + { + if (nRow < 4 || nCol < 4) { + m1.setZero(); + if (nCol > 0) { + if (nRow > 0) { + m1.m00 = values[0][0]; + if (nRow > 1) { + m1.m10 = values[1][0]; + if (nRow > 2) { + m1.m20 = values[2][0]; + if (nRow > 3) { + m1.m30 = values[3][0]; + } + } + } + } + if (nCol > 1) { + if (nRow > 0) { + m1.m01 = values[0][1]; + if (nRow > 1) { + m1.m11 = values[1][1]; + if (nRow > 2) { + m1.m21 = values[2][1]; + if (nRow > 3) { + m1.m31 = values[3][1]; + } + } + } + } + if (nCol > 2) { + if (nRow > 0) { + m1.m02 = values[0][2]; + if (nRow > 1) { + m1.m12 = values[1][2]; + if (nRow > 2) { + m1.m22 = values[2][2]; + if (nRow > 3) { + m1.m32 = values[3][2]; + } + } + } + } + if (nCol > 3) { + if (nRow > 0) { + m1.m03 = values[0][3]; + if (nRow > 1) { + m1.m13 = values[1][3]; + if (nRow > 2) { + m1.m23 = values[2][3]; + if (nRow > 3) { + m1.m33 = values[3][3]; + } + } + } + } + } + } + } + } + } else { + m1.m00 = values[0][0]; + m1.m01 = values[0][1]; + m1.m02 = values[0][2]; + m1.m03 = values[0][3]; + + m1.m10 = values[1][0]; + m1.m11 = values[1][1]; + m1.m12 = values[1][2]; + m1.m13 = values[1][3]; + + m1.m20 = values[2][0]; + m1.m21 = values[2][1]; + m1.m22 = values[2][2]; + m1.m23 = values[2][3]; + + m1.m30 = values[3][0]; + m1.m31 = values[3][1]; + m1.m32 = values[3][2]; + m1.m33 = values[3][3]; + } + + } + + /** + * Places the values in the upper 4x4 of this GMatrix into + * the matrix m1. + * @param m1 The matrix that will hold the new values + */ + public final void get(Matrix4f m1) + { + + if (nRow < 4 || nCol < 4) { + m1.setZero(); + if (nCol > 0) { + if (nRow > 0) { + m1.m00 = (float)values[0][0]; + if (nRow > 1) { + m1.m10 = (float)values[1][0]; + if (nRow > 2) { + m1.m20 = (float)values[2][0]; + if (nRow > 3) { + m1.m30 = (float)values[3][0]; + } + } + } + } + if (nCol > 1) { + if (nRow > 0) { + m1.m01 = (float)values[0][1]; + if (nRow > 1) { + m1.m11 = (float)values[1][1]; + if (nRow > 2) { + m1.m21 = (float)values[2][1]; + if (nRow > 3) { + m1.m31 = (float)values[3][1]; + } + } + } + } + if (nCol > 2) { + if (nRow > 0) { + m1.m02 = (float)values[0][2]; + if (nRow > 1) { + m1.m12 = (float)values[1][2]; + if (nRow > 2) { + m1.m22 = (float)values[2][2]; + if (nRow > 3) { + m1.m32 = (float)values[3][2]; + } + } + } + } + if (nCol > 3) { + if (nRow > 0) { + m1.m03 = (float)values[0][3]; + if (nRow > 1) { + m1.m13 = (float)values[1][3]; + if (nRow > 2) { + m1.m23 = (float)values[2][3]; + if (nRow > 3) { + m1.m33 = (float)values[3][3]; + } + } + } + } + } + } + } + } + } else { + m1.m00 = (float)values[0][0]; + m1.m01 = (float)values[0][1]; + m1.m02 = (float)values[0][2]; + m1.m03 = (float)values[0][3]; + + m1.m10 = (float)values[1][0]; + m1.m11 = (float)values[1][1]; + m1.m12 = (float)values[1][2]; + m1.m13 = (float)values[1][3]; + + m1.m20 = (float)values[2][0]; + m1.m21 = (float)values[2][1]; + m1.m22 = (float)values[2][2]; + m1.m23 = (float)values[2][3]; + + m1.m30 = (float)values[3][0]; + m1.m31 = (float)values[3][1]; + m1.m32 = (float)values[3][2]; + m1.m33 = (float)values[3][3]; + } + } + + /** + * Places the values in the this GMatrix into the matrix m1; + * m1 should be at least as large as this GMatrix. + * @param m1 The matrix that will hold the new values + */ + public final void get(GMatrix m1) + { + int i, j, nc, nr; + + if (nCol < m1.nCol) + nc = nCol; + else + nc = m1.nCol; + + if (nRow < m1.nRow) + nr = nRow; + else + nr = m1.nRow; + + for (i = 0; i < nr; i++) { + for (j = 0; j < nc; j++) { + m1.values[i][j] = values[i][j]; + } + } + for (i = nr; i < m1.nRow; i++) { + for (j = 0; j < m1.nCol; j++) { + m1.values[i][j] = 0.0; + } + } + for (j = nc; j < m1.nCol; j++) { + for (i = 0; i < nr; i++) { + m1.values[i][j] = 0.0; + } + } + } + + /** + * Copy the values from the array into the specified row of this + * matrix. + * @param row the row of this matrix into which the array values + * will be copied. + * @param array the source array + */ + public final void setRow(int row, double[] array) + { + for (int i = 0; i < nCol; i++) { + values[row][i] = array[i]; + } + } + + /** + * Copy the values from the vector into the specified row of this + * matrix. + * @param row the row of this matrix into which the array values + * will be copied + * @param vector the source vector + */ + public final void setRow(int row, GVector vector) + { + for(int i = 0; i < nCol; i++) { + values[row][i] = vector.values[i]; + } + } + + /** + * Copy the values from the array into the specified column of this + * matrix. + * @param col the column of this matrix into which the array values + * will be copied + * @param array the source array + */ + public final void setColumn(int col, double[] array) + { + for(int i = 0; i < nRow; i++) { + values[i][col] = array[i]; + } + } + + /** + * Copy the values from the vector into the specified column of this + * matrix. + * @param col the column of this matrix into which the array values + * will be copied + * @param vector the source vector + */ + public final void setColumn(int col, GVector vector) + { + for(int i = 0; i < nRow; i++) { + values[i][col] = vector.values[i]; + } + + } + + /** + * 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(GMatrix m1, GMatrix m2) + { + int i, j, k; + + if (m1.nRow != m2.nCol || nRow != m1.nCol || nCol != m2.nRow) + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix14")); + + if (m1 == this || m2 == this) { + double[][] tmp = new double[nRow][nCol]; + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + tmp[i][j] = 0.0; + for (k = 0; k < m1.nRow; k++) { + tmp[i][j] += m1.values[k][i]*m2.values[j][k]; + } + } + } + values = tmp; + } else { + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + values[i][j] = 0.0; + for (k = 0; k < m1.nRow; k++) { + values[i][j] += m1.values[k][i]*m2.values[j][k]; + } + } + } + } + } + + /** + * 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(GMatrix m1, GMatrix m2) + { + int i, j, k; + + if (m1.nCol != m2.nCol || nCol != m2.nRow || nRow != m1.nRow) + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix15")); + + if (m1 == this || m2 == this) { + double[][] tmp = new double[nRow][nCol]; + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + tmp[i][j] = 0.0; + for (k = 0; k < m1.nCol; k++) { + tmp[i][j] += m1.values[i][k]*m2.values[j][k]; + } + } + } + values = tmp; + } else { + for (i = 0; i < nRow; i++) { + for (j = 0;j < nCol; j++) { + values[i][j] = 0.0; + for (k = 0; k < m1.nCol; k++) { + values[i][j] += m1.values[i][k]*m2.values[j][k]; + } + } + } + } + + } + + + /** + * 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(GMatrix m1, GMatrix m2) + { + int i, j, k; + + if (m1.nRow != m2.nRow || nCol != m2.nCol || nRow != m1.nCol) + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix16")); + + if (m1 == this || m2 == this) { + double[][] tmp = new double[nRow][nCol]; + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + tmp[i][j] = 0.0; + for (k = 0; k < m1.nRow; k++) { + tmp[i][j] += m1.values[k][i]*m2.values[k][j]; + } + } + } + values = tmp; + } else { + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + values[i][j] = 0.0; + for (k = 0; k < m1.nRow; k++) { + values[i][j] += m1.values[k][i]*m2.values[k][j]; + } + } + } + } + } + + + /** + * Transposes this matrix in place. + */ + public final void transpose() + { + int i, j; + + if (nRow != nCol) { + double[][] tmp; + i=nRow; + nRow = nCol; + nCol = i; + tmp = new double[nRow][nCol]; + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + tmp[i][j] = values[j][i]; + } + } + values = tmp; + } else { + double swap; + for (i = 0; i < nRow; i++) { + for (j = 0; j < i; j++) { + swap = values[i][j]; + values[i][j] = values[j][i]; + values[j][i] = swap; + } + } + } + } + + /** + * Places the matrix values of the transpose of matrix m1 into this matrix. + * @param m1 the matrix to be transposed (but not modified) + */ + public final void transpose(GMatrix m1) + { + int i, j; + + if (nRow != m1.nCol || nCol != m1.nRow) + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix17")); + + if (m1 != this) { + for (i = 0; i < nRow; i++) { + for (j = 0;j < nCol; j++) { + values[i][j] = m1.values[j][i]; + } + } + } else { + transpose(); + } + } + + /** + * Returns a string that contains the values of this GMatrix. + * @return the String representation + */ + public String toString() + { + StringBuffer buffer = new StringBuffer(nRow*nCol*8); + + int i, j; + + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + buffer.append(values[i][j]).append(" "); + } + buffer.append("\n"); + } + + return buffer.toString(); + } + + private static void checkMatrix( GMatrix m) + { + int i, j; + + for (i = 0; i < m.nRow; i++) { + for (j = 0; j < m.nCol; j++) { + if (Math.abs(m.values[i][j]) < 0.0000000001) { + System.out.print(" 0.0 "); + } else { + System.out.print(" " + m.values[i][j]); + } + } + System.out.print("\n"); + } + } + + + /** + * Returns a hash code value based on the data values in this + * object. Two different GMatrix objects with identical data + * values (i.e., GMatrix.equals returns true) will return the + * same hash number. Two GMatrix objects with different data + * members may return the same hash value, although this is not + * likely. + * @return the integer hash code value + */ + public int hashCode() { + long bits = 1L; + + bits = 31L * bits + (long)nRow; + bits = 31L * bits + (long)nCol; + + for (int i = 0; i < nRow; i++) { + for (int j = 0; j < nCol; j++) { + bits = 31L * bits + Double.doubleToLongBits(values[i][j]); + } + } + + return (int) (bits ^ (bits >> 32)); + } + + + /** + * Returns true if all of the data members of GMatrix m1 are + * equal to the corresponding data members in this GMatrix. + * @param m1 The matrix with which the comparison is made. + * @return true or false + */ + public boolean equals(GMatrix m1) + { + try { + int i, j; + + if (nRow != m1.nRow || nCol != m1.nCol) + return false; + + for (i = 0;i < nRow; i++) { + for (j = 0; j < nCol; j++) { + if (values[i][j] != m1.values[i][j]) + return false; + } + } + return true; + } + catch (NullPointerException e2) { + return false; + } + } + + /** + * Returns true if the Object o1 is of type GMatrix and all of the + * data members of o1 are equal to the corresponding data members in + * this GMatrix. + * @param o1 The object with which the comparison is made. + * @return true or false + */ + public boolean equals(Object o1) + { + try { + GMatrix m2 = (GMatrix) o1; + int i, j; + if (nRow != m2.nRow || nCol != m2.nCol) + return false; + + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + if (values[i][j] != m2.values[i][j]) + return false; + } + } + return true; + } + catch (ClassCastException e1) { + return false; + } + catch (NullPointerException e2) { + return false; + } + } + + /** + * @deprecated Use epsilonEquals(GMatrix, double) instead + */ + public boolean epsilonEquals(GMatrix m1, float epsilon) { + return epsilonEquals(m1, (double)epsilon); + } + + /** + * 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, . . .n ; j=0,1,2, . . .n ; 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(GMatrix m1, double epsilon) + { + int i, j; + double diff; + if (nRow != m1.nRow || nCol != m1.nCol) + return false; + + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + diff = values[i][j] - m1.values[i][j]; + if ((diff < 0 ? -diff : diff) > epsilon) + return false; + } + } + return true; + } + + /** + * Returns the trace of this matrix. + * @return the trace of this matrix + */ + public final double trace() + { + int i, l; + double t; + + if (nRow < nCol) + l = nRow; + else + l = nCol; + + t = 0.0; + for (i = 0; i < l; i++) { + t += values[i][i]; + } + return t; + } + + /** + * Finds the singular value decomposition (SVD) of this matrix + * such that this = U*W*transpose(V); and returns the rank of + * this matrix; the values of U,W,V are all overwritten. Note + * that the matrix V is output as V, and + * not transpose(V). If this matrix is mxn, then U is mxm, W + * is a diagonal matrix that is mxn, and V is nxn. Using the + * notation W = diag(w), then the inverse of this matrix is: + * inverse(this) = V*diag(1/w)*tranpose(U), where diag(1/w) + * is the same matrix as W except that the reciprocal of each + * of the diagonal components is used. + * @param U The computed U matrix in the equation this = U*W*transpose(V) + * @param W The computed W matrix in the equation this = U*W*transpose(V) + * @param V The computed V matrix in the equation this = U*W*transpose(V) + * @return The rank of this matrix. + */ + public final int SVD(GMatrix U, GMatrix W, GMatrix V) + { + // check for consistancy in dimensions + if (nCol != V.nCol || nCol != V.nRow) { + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix18")); + } + + if (nRow != U.nRow || nRow != U.nCol) { + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix25")); + } + + if (nRow != W.nRow || nCol != W.nCol) { + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix26")); + } + + // Fix ArrayIndexOutOfBounds for 2x2 matrices, which partially + // addresses bug 4348562 for J3D 1.2.1. + // + // Does *not* fix the following problems reported in 4348562, + // which will wait for J3D 1.3: + // + // 1) no output of W + // 2) wrong transposition of U + // 3) wrong results for 4x4 matrices + // 4) slow performance + if (nRow == 2 && nCol == 2) { + if (values[1][0] == 0.0) { + U.setIdentity(); + V.setIdentity(); + + if (values[0][1] == 0.0) { + return 2; + } + + double[] sinl = new double[1]; + double[] sinr = new double[1]; + double[] cosl = new double[1]; + double[] cosr = new double[1]; + double[] single_values = new double[2]; + + single_values[0] = values[0][0]; + single_values[1] = values[1][1]; + + compute_2X2(values[0][0], values[0][1], values[1][1], + single_values, sinl, cosl, sinr, cosr, 0); + + update_u(0, U, cosl, sinl); + update_v(0, V, cosr, sinr); + + return 2; + } + // else call computeSVD() and check for 2x2 there + } + + return computeSVD(this, U, W, V); + } + + /** + * LU Decomposition: this matrix must be a square matrix and the + * LU GMatrix parameter must be the same size as this matrix. + * The matrix LU will be overwritten as the combination of a + * lower diagonal and upper diagonal matrix decompostion of this + * matrix; the diagonal + * elements of L (unity) are not stored. The GVector parameter + * records the row permutation effected by the partial pivoting, + * and is used as a parameter to the GVector method LUDBackSolve + * to solve sets of linear equations. + * This method returns +/- 1 depending on whether the number + * of row interchanges was even or odd, respectively. + * @param LU The matrix into which the lower and upper decompositions + * will be placed. + * @param permutation The row permutation effected by the partial + * pivoting + * @return +-1 depending on whether the number of row interchanges + * was even or odd respectively + */ + public final int LUD(GMatrix LU, GVector permutation) + { + int size = LU.nRow*LU.nCol; + double[] temp = new double[size]; + int[] even_row_exchange = new int[1]; + int[] row_perm = new int[LU.nRow]; + int i, j; + + if (nRow != nCol) { + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix19")); + } + + if (nRow != LU.nRow) { + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix27")); + } + + if (nCol != LU.nCol) { + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix27")); + } + + if (LU.nRow != permutation.getSize()) { + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix20")); + } + + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + temp[i*nCol+j] = values[i][j]; + } + } + + // Calculate LU decomposition: Is the matrix singular? + if (!luDecomposition(LU.nRow, temp, row_perm, even_row_exchange)) { + // Matrix has no inverse + throw new SingularMatrixException + (VecMathI18N.getString("GMatrix21")); + } + + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + LU.values[i][j] = temp[i*nCol+j]; + } + } + + for (i = 0; i < LU.nRow; i++){ + permutation.values[i] = (double)row_perm[i]; + } + + return even_row_exchange[0]; + } + + /** + * Sets this matrix to a uniform scale matrix; all of the + * values are reset. + * @param scale The new scale value + */ + public final void setScale(double scale) + { + int i, j, l; + + if (nRow < nCol) + l = nRow; + else + l = nCol; + + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + values[i][j] = 0.0; + } + } + + for (i = 0; i < l; i++) { + values[i][i] = scale; + } + } + + /** + * 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. + */ + final void invertGeneral(GMatrix m1) { + int size = m1.nRow*m1.nCol; + double temp[] = new double[size]; + double result[] = new double[size]; + int row_perm[] = new int[m1.nRow]; + int[] even_row_exchange = new int[1]; + int i, j; + + // Use LU decomposition and backsubstitution code specifically + // for floating-point nxn matrices. + if (m1.nRow != m1.nCol) { + // Matrix is either under or over determined + throw new MismatchedSizeException + (VecMathI18N.getString("GMatrix22")); + } + + // Copy source matrix to temp + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + temp[i*nCol+j] = m1.values[i][j]; + } + } + + // Calculate LU decomposition: Is the matrix singular? + if (!luDecomposition(m1.nRow, temp, row_perm, even_row_exchange)) { + // Matrix has no inverse + throw new SingularMatrixException + (VecMathI18N.getString("GMatrix21")); + } + + // Perform back substitution on the identity matrix + for (i = 0; i < size; i++) + result[i] = 0.0; + + for (i = 0; i < nCol; i++) + result[i+i*nCol] = 1.0; + + luBacksubstitution(m1.nRow, temp, row_perm, result); + + for (i = 0; i < nRow; i++) { + for (j = 0; j < nCol; j++) { + values[i][j] = result[i*nCol+j]; + } + } + } + + /** + * Given a nxn array "matrix0", this function replaces it with the + * LU decomposition of a row-wise permutation of itself. The input + * parameters are "matrix0" and "dim". The array "matrix0" is also + * an output parameter. The vector "row_perm[]" 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. + * + * @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(int dim, double[] matrix0, + int[] row_perm, int[] even_row_xchg) { + + double row_scale[] = new double[dim]; + + // Determine implicit scaling information by looping over rows + int i, j; + int ptr, rs, mtx; + double big, temp; + + ptr = 0; + rs = 0; + even_row_xchg[0] = 1; + + // For each row ... + i = dim; + while (i-- != 0) { + big = 0.0; + + // For each column, find the largest element in the row + j = dim; + 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; + } + + // For all columns, execute Crout's method + mtx = 0; + for (j = 0; j < dim; j++) { + int imax, k; + int target, p1, p2; + double sum; + + // Determine elements of upper diagonal matrix U + for (i = 0; i < j; i++) { + target = mtx + (dim*i) + j; + sum = matrix0[target]; + k = i; + p1 = mtx + (dim*i); + p2 = mtx + j; + while (k-- != 0) { + sum -= matrix0[p1] * matrix0[p2]; + p1++; + p2 += dim; + } + 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 < dim; i++) { + target = mtx + (dim*i) + j; + sum = matrix0[target]; + k = j; + p1 = mtx + (dim*i); + p2 = mtx + j; + while (k-- != 0) { + sum -= matrix0[p1] * matrix0[p2]; + p1++; + p2 += dim; + } + 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("GMatrix24")); + } + + // Is a row exchange necessary? + if (j != imax) { + // Yes: exchange rows + k = dim; + p1 = mtx + (dim*imax); + p2 = mtx + (dim*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]; + even_row_xchg[0] = -even_row_xchg[0]; // change exchange parity + } + + // Record row permutation + row_perm[j] = imax; + + // Is the matrix singular + if (matrix0[(mtx + (dim*j) + j)] == 0.0) { + return false; + } + + // Divide elements of lower diagonal matrix L by pivot + if (j != (dim-1)) { + temp = 1.0 / (matrix0[(mtx + (dim*j) + j)]); + target = mtx + (dim*(j+1)) + j; + i = (dim-1) - j; + while (i-- != 0) { + matrix0[target] *= temp; + target += dim; + } + } + + } + + return true; + } + + /** + * Solves a set of linear equations. The input parameters "matrix1", + * and "row_perm" come from luDecompostion and do not change + * here. The parameter "matrix2" is a set of column vectors assembled + * into a nxn 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(int dim, double[] matrix1, + int[] row_perm, + double[] matrix2) { + + int i, ii, ip, j, k; + int rp; + int cv, rv, ri; + double tt; + + // rp = row_perm; + rp = 0; + + // For each column vector of matrix2 ... + for (k = 0; k < dim; k++) { + // cv = &(matrix2[0][k]); + cv = k; + ii = -1; + + // Forward substitution + for (i = 0; i < dim; i++) { + double sum; + + ip = row_perm[rp+i]; + sum = matrix2[cv+dim*ip]; + matrix2[cv+dim*ip] = matrix2[cv+dim*i]; + if (ii >= 0) { + // rv = &(matrix1[i][0]); + rv = i*dim; + for (j = ii; j <= i-1; j++) { + sum -= matrix1[rv+j] * matrix2[cv+dim*j]; + } + } + else if (sum != 0.0) { + ii = i; + } + matrix2[cv+dim*i] = sum; + } + + // Backsubstitution + for (i = 0; i < dim; i++) { + ri = (dim-1-i); + rv = dim*(ri); + tt = 0.0; + for(j=1;j<=i;j++) { + tt += matrix1[rv+dim-j] * matrix2[cv+dim*(dim-j)]; + } + matrix2[cv+dim*ri]= (matrix2[cv+dim*ri] - tt) / matrix1[rv+ri]; + } + } + } + + static int computeSVD(GMatrix mat, GMatrix U, GMatrix W, GMatrix V) { + int i, j, k; + int nr, nc, si; + + int converged, rank; + double cs, sn, r, mag,scale, t; + int eLength, sLength, vecLength; + + GMatrix tmp = new GMatrix(mat.nRow, mat.nCol); + GMatrix u = new GMatrix(mat.nRow, mat.nCol); + GMatrix v = new GMatrix(mat.nRow, mat.nCol); + GMatrix m = new GMatrix(mat); + + // compute the number of singular values + if (m.nRow >= m.nCol) { + sLength = m.nCol; + eLength = m.nCol-1; + }else { + sLength = m.nRow; + eLength = m.nRow; + } + + if (m.nRow > m.nCol) + vecLength = m.nRow; + else + vecLength = m.nCol; + + double[] vec = new double[vecLength]; + double[] single_values = new double[sLength]; + double[] e = new double[eLength]; + + if(debug) { + System.out.println("input to compute_svd = \n"+m.toString()); + } + + rank = 0; + + U.setIdentity(); + V.setIdentity(); + + nr = m.nRow; + nc = m.nCol; + + // householder reduction + for (si = 0; si < sLength; si++) { + // for each singular value + + if (nr > 1) { + // zero out column + if (debug) + System.out.println + ("*********************** U ***********************\n"); + + // compute reflector + mag = 0.0; + for (i = 0; i < nr; i++) { + mag += m.values[i+si][si] * m.values[i+si][si]; + if (debug) + System.out.println + ("mag = " + mag + " matrix.dot = " + + m.values[i+si][si] * m.values[i+si][si]); + } + + mag = Math.sqrt(mag); + if (m.values[si][si] == 0.0) { + vec[0] = mag; + } else { + vec[0] = m.values[si][si] + d_sign(mag, m.values[si][si]); + } + + for (i = 1; i < nr; i++) { + vec[i] = m.values[si+i][si]; + } + + scale = 0.0; + for (i = 0; i < nr; i++) { + if (debug) + System.out.println("vec["+i+"]="+vec[i]); + + scale += vec[i]*vec[i]; + } + + scale = 2.0/scale; + if (debug) + System.out.println("scale = "+scale); + + for (j = si; j < m.nRow; j++) { + for (k = si; k < m.nRow; k++) { + u.values[j][k] = -scale * vec[j-si]*vec[k-si]; + } + } + + for (i = si; i < m.nRow; i++){ + u.values[i][i] += 1.0; + } + + // compute s + t = 0.0; + for (i = si; i < m.nRow; i++){ + t += u.values[si][i] * m.values[i][si]; + } + m.values[si][si] = t; + + // apply reflector + for (j = si; j < m.nRow; j++) { + for (k = si+1; k < m.nCol; k++) { + tmp.values[j][k] = 0.0; + for (i = si; i < m.nCol; i++) { + tmp.values[j][k] += u.values[j][i] * m.values[i][k]; + } + } + } + + for (j = si; j < m.nRow; j++) { + for (k = si+1; k < m.nCol; k++) { + m.values[j][k] = tmp.values[j][k]; + } + } + + if (debug) { + System.out.println("U =\n" + U.toString()); + System.out.println("u =\n" + u.toString()); + } + + // update U matrix + for (j = si; j < m.nRow; j++) { + for (k = 0; k < m.nCol; k++) { + tmp.values[j][k] = 0.0; + for (i = si; i < m.nCol; i++) { + tmp.values[j][k] += u.values[j][i] * U.values[i][k]; + } + } + } + + for (j = si; j < m.nRow; j++) { + for (k = 0; k < m.nCol; k++) { + U.values[j][k] = tmp.values[j][k]; + } + } + + if (debug) { + System.out.println("single_values["+si+"] =\n" + + single_values[si]); + System.out.println("m =\n" + m.toString()); + System.out.println("U =\n" + U.toString()); + } + + nr--; + } + + if( nc > 2 ) { + // zero out row + if (debug) + System.out.println + ("*********************** V ***********************\n"); + + mag = 0.0; + for (i = 1; i < nc; i++){ + mag += m.values[si][si+i] * m.values[si][si+i]; + } + + if (debug) + System.out.println("mag = " + mag); + + // generate the reflection vector, compute the first entry and + // copy the rest from the row to be zeroed + mag = Math.sqrt(mag); + if (m.values[si][si+1] == 0.0) { + vec[0] = mag; + } else { + vec[0] = m.values[si][si+1] + + d_sign(mag, m.values[si][si+1]); + } + + for (i = 1; i < nc - 1; i++){ + vec[i] = m.values[si][si+i+1]; + } + + // use reflection vector to compute v matrix + scale = 0.0; + for (i = 0; i < nc - 1; i++){ + if( debug )System.out.println("vec["+i+"]="+vec[i]); + scale += vec[i]*vec[i]; + } + + scale = 2.0/scale; + if (debug) + System.out.println("scale = "+scale); + + for (j = si + 1; j < nc; j++) { + for (k = si+1; k < m.nCol; k++) { + v.values[j][k] = -scale * vec[j-si-1]*vec[k-si-1]; + } + } + + for (i = si + 1; i < m.nCol; i++){ + v.values[i][i] += 1.0; + } + + t=0.0; + for (i = si; i < m.nCol; i++){ + t += v.values[i][si+1] * m.values[si][i]; + } + m.values[si][si+1]=t; + + // apply reflector + for (j = si + 1; j < m.nRow; j++) { + for (k = si + 1; k < m.nCol; k++) { + tmp.values[j][k] = 0.0; + for (i = si + 1; i < m.nCol; i++) { + tmp.values[j][k] += v.values[i][k] * m.values[j][i]; + } + } + } + + for (j = si + 1; j < m.nRow; j++) { + for (k = si + 1; k < m.nCol; k++) { + m.values[j][k] = tmp.values[j][k]; + } + } + + if (debug) { + System.out.println("V =\n" + V.toString()); + System.out.println("v =\n" + v.toString()); + System.out.println("tmp =\n" + tmp.toString()); + } + + // update V matrix + for (j = 0; j < m.nRow; j++) { + for (k = si + 1; k < m.nCol; k++) { + tmp.values[j][k] = 0.0; + for (i = si + 1; i < m.nCol; i++) { + tmp.values[j][k] += v.values[i][k] * V.values[j][i]; + } + } + } + + if (debug) + System.out.println("tmp =\n" + tmp.toString()); + + for (j = 0;j < m.nRow; j++) { + for (k = si + 1; k < m.nCol; k++) { + V.values[j][k] = tmp.values[j][k]; + } + } + + if (debug) { + System.out.println("m =\n" + m.toString()); + System.out.println("V =\n" + V.toString()); + } + + nc--; + } + } + + for (i = 0; i < sLength; i++){ + single_values[i] = m.values[i][i]; + } + + for (i = 0; i < eLength; i++){ + e[i] = m.values[i][i+1]; + } + + // Fix ArrayIndexOutOfBounds for 2x2 matrices, which partially + // addresses bug 4348562 for J3D 1.2.1. + // + // Does *not* fix the following problems reported in 4348562, + // which will wait for J3D 1.3: + // + // 1) no output of W + // 2) wrong transposition of U + // 3) wrong results for 4x4 matrices + // 4) slow performance + if (m.nRow == 2 && m.nCol == 2) { + double[] cosl = new double[1]; + double[] cosr = new double[1]; + double[] sinl = new double[1]; + double[] sinr = new double[1]; + + compute_2X2(single_values[0], e[0], single_values[1], + single_values, sinl, cosl, sinr, cosr, 0); + + update_u(0, U, cosl, sinl); + update_v(0, V, cosr, sinr); + + return 2; + } + + // compute_qr causes ArrayIndexOutOfBounds for 2x2 matrices + compute_qr (0, e.length-1, single_values, e, U, V); + + // compute rank = number of non zero singular values + rank = single_values.length; + + // sort by order of size of single values + // and check for zero's + return rank; + } + + static void compute_qr(int start, int end, double[] s, double[] e, + GMatrix u, GMatrix v) { + + int i, j, k, n, sl; + boolean converged; + double shift, r, utemp, vtemp, f, g; + double[] cosl = new double[1]; + double[] cosr = new double[1]; + double[] sinl = new double[1]; + double[] sinr = new double[1]; + GMatrix m = new GMatrix(u.nCol, v.nRow); + + final int MAX_INTERATIONS = 2; + final double CONVERGE_TOL = 4.89E-15; + + if (debug) { + System.out.println("start =" + start); + System.out.println("s =\n"); + for(i=0;i<s.length;i++) { + System.out.println(s[i]); + } + + System.out.println("\nes =\n"); + for (i = 0; i < e.length; i++) { + System.out.println(e[i]); + } + + for (i = 0; i < s.length; i++) { + m.values[i][i] = s[i]; + } + + for (i = 0; i < e.length; i++) { + m.values[i][i+1] = e[i]; + } + System.out.println("\nm =\n" + m.toString()); + } + + double c_b48 = 1.0; + double c_b71 = -1.0; + converged = false; + + if (debug) + print_svd(s, e, u, v); + + f = 0.0; + g = 0.0; + + for (k = 0; k < MAX_INTERATIONS && !converged;k++) { + for (i = start; i <= end; i++) { + + // if at start of iterfaction compute shift + if (i == start) { + if (e.length == s.length) + sl = end; + else + sl = end + 1; + + shift = compute_shift(s[sl-1], e[end], s[sl]); + + f = (Math.abs(s[i]) - shift) * + (d_sign(c_b48, s[i]) + shift/s[i]); + g = e[i]; + } + + r = compute_rot(f, g, sinr, cosr); + if (i != start) + e[i-1] = r; + + f = cosr[0] * s[i] + sinr[0] * e[i]; + e[i] = cosr[0] * e[i] - sinr[0] * s[i]; + g = sinr[0] * s[i+1]; + s[i+1] = cosr[0] * s[i+1]; + + // if (debug) print_se(s,e); + update_v (i, v, cosr, sinr); + if (debug) + print_m(m,u,v); + + r = compute_rot(f, g, sinl, cosl); + s[i] = r; + f = cosl[0] * e[i] + sinl[0] * s[i+1]; + s[i+1] = cosl[0] * s[i+1] - sinl[0] * e[i]; + + if( i < end) { + // if not last + g = sinl[0] * e[i+1]; + e[i+1] = cosl[0] * e[i+1]; + } + //if (debug) print_se(s,e); + + update_u(i, u, cosl, sinl); + if (debug) + print_m(m,u,v); + } + + // if extra off diagonal perform one more right side rotation + if (s.length == e.length) { + r = compute_rot(f, g, sinr, cosr); + f = cosr[0] * s[i] + sinr[0] * e[i]; + e[i] = cosr[0] * e[i] - sinr[0] * s[i]; + s[i+1] = cosr[0] * s[i+1]; + + update_v(i, v, cosr, sinr); + if (debug) + print_m(m,u,v); + } + + if (debug) { + System.out.println + ("\n*********************** iteration #" + k + + " ***********************\n"); + print_svd(s, e, u, v); + } + + // check for convergence on off diagonals and reduce + while ((end-start > 1) && (Math.abs(e[end]) < CONVERGE_TOL)) { + end--; + } + + // check if need to split + for (n = end - 2; n > start; n--) { + if (Math.abs(e[n]) < CONVERGE_TOL) { // split + compute_qr(n + 1, end, s, e, u, v); // do lower matrix + end = n - 1; // do upper matrix + + // check for convergence on off diagonals and reduce + while ((end - start > 1) && + (Math.abs(e[end]) < CONVERGE_TOL)) { + end--; + } + } + } + + if (debug) + System.out.println("start = " + start); + + if ((end - start <= 1) && (Math.abs(e[start+1]) < CONVERGE_TOL)) { + converged = true; + } else { + // check if zero on the diagonal + } + + } + + if (debug) + System.out.println("\n****call compute_2X2 ********************\n"); + + if (Math.abs(e[1]) < CONVERGE_TOL) { + compute_2X2(s[start], e[start], s[start+1], s, + sinl, cosl, sinr, cosr, 0); + e[start] = 0.0; + e[start+1] = 0.0; + } else { + } + + i = start; + update_u(i, u, cosl, sinl); + update_v(i, v, cosr, sinr); + + if(debug) { + System.out.println + ("\n*******after call compute_2X2 **********************\n"); + print_svd(s, e, u, v); + } + + return; + } + + private static void print_se(double[] s, double[] e) { + System.out.println("\ns =" + s[0] + " " + s[1] + " " + s[2]); + System.out.println("e =" + e[0] + " " + e[1]); + } + + private static void update_v(int index, GMatrix v, + double[] cosr, double[] sinr) { + int j; + double vtemp; + + for (j = 0; j < v.nRow; j++) { + vtemp = v.values[j][index]; + v.values[j][index] = + cosr[0]*vtemp + sinr[0]*v.values[j][index+1]; + v.values[j][index+1] = + -sinr[0]*vtemp + cosr[0]*v.values[j][index+1]; + } + } + + private static void chase_up(double[] s, double[] e, int k, GMatrix v) { + double f, g, r; + double[] cosr = new double[1]; + double[] sinr = new double[1]; + int i; + GMatrix t = new GMatrix(v.nRow, v.nCol); + GMatrix m = new GMatrix(v.nRow, v.nCol); + + if (debug) { + m.setIdentity(); + for (i = 0; i < s.length; i++) { + m.values[i][i] = s[i]; + } + for (i = 0; i < e.length; i++) { + m.values[i][i+1] = e[i]; + } + } + + f = e[k]; + g = s[k]; + + for (i = k; i > 0; i--) { + r = compute_rot(f, g, sinr, cosr); + f = -e[i-1] * sinr[0]; + g = s[i-1]; + s[i] = r; + e[i-1] = e[i-1] * cosr[0]; + update_v_split(i, k+1, v, cosr, sinr, t, m); + } + + s[i+1] = compute_rot(f, g, sinr, cosr); + update_v_split(i, k+1, v, cosr, sinr, t, m); + } + + private static void chase_across(double[] s, double[] e, int k, GMatrix u) { + double f, g, r; + double[] cosl = new double[1]; + double[] sinl = new double[1]; + int i; + GMatrix t = new GMatrix(u.nRow, u.nCol); + GMatrix m = new GMatrix(u.nRow, u.nCol); + + if (debug) { + m.setIdentity(); + for (i = 0; i < s.length; i++) { + m.values[i][i] = s[i]; + } + for (i = 0; i < e.length; i++) { + m.values[i][i+1] = e[i]; + } + } + + g = e[k]; + f = s[k+1]; + + for (i = k; i < u.nCol-2; i++){ + r = compute_rot(f, g, sinl, cosl); + g = -e[i+1] * sinl[0]; + f = s[i+2]; + s[i+1] = r; + e[i+1] = e[i+1] * cosl[0]; + update_u_split(k, i + 1, u, cosl, sinl, t, m); + } + + s[i+1] = compute_rot(f, g, sinl, cosl); + update_u_split(k, i + 1, u, cosl, sinl, t, m); + } + + private static void update_v_split(int topr, int bottomr, GMatrix v, + double[] cosr, double[] sinr, + GMatrix t, GMatrix m) { + int j; + double vtemp; + + for (j = 0; j < v.nRow; j++) { + vtemp = v.values[j][topr]; + v.values[j][topr] = cosr[0]*vtemp - sinr[0]*v.values[j][bottomr]; + v.values[j][bottomr] = sinr[0]*vtemp + cosr[0]*v.values[j][bottomr]; + } + + if (debug) { + t.setIdentity(); + for (j = 0; j < v.nRow; j++) { + vtemp = t.values[j][topr]; + t.values[j][topr] = + cosr[0]*vtemp - sinr[0]*t.values[j][bottomr]; + t.values[j][bottomr] = + sinr[0]*vtemp + cosr[0]*t.values[j][bottomr]; + } + } + + System.out.println("topr =" + topr); + System.out.println("bottomr =" + bottomr); + System.out.println("cosr =" + cosr[0]); + System.out.println("sinr =" + sinr[0]); + System.out.println("\nm ="); + checkMatrix(m); + System.out.println("\nv ="); + checkMatrix(t); + m.mul(m,t); + System.out.println("\nt*m ="); + checkMatrix(m); + } + + private static void update_u_split(int topr, int bottomr, GMatrix u, + double[] cosl, double[] sinl, + GMatrix t, GMatrix m) { + int j; + double utemp; + + for (j = 0; j < u.nCol; j++) { + utemp = u.values[topr][j]; + u.values[topr][j] = cosl[0]*utemp - sinl[0]*u.values[bottomr][j]; + u.values[bottomr][j] = sinl[0]*utemp + cosl[0]*u.values[bottomr][j]; + } + + if(debug) { + t.setIdentity(); + for (j = 0;j < u.nCol; j++) { + utemp = t.values[topr][j]; + t.values[topr][j] = + cosl[0]*utemp - sinl[0]*t.values[bottomr][j]; + t.values[bottomr][j] = + sinl[0]*utemp + cosl[0]*t.values[bottomr][j]; + } + } + System.out.println("\nm="); + checkMatrix(m); + System.out.println("\nu="); + checkMatrix(t); + m.mul(t,m); + System.out.println("\nt*m="); + checkMatrix(m); + } + + private static void update_u(int index, GMatrix u, + double[] cosl, double[] sinl) { + int j; + double utemp; + + for (j = 0; j < u.nCol; j++) { + utemp = u.values[index][j]; + u.values[index][j] = + cosl[0]*utemp + sinl[0]*u.values[index+1][j]; + u.values[index+1][j] = + -sinl[0]*utemp + cosl[0]*u.values[index+1][j]; + } + } + + private static void print_m(GMatrix m, GMatrix u, GMatrix v) { + GMatrix mtmp = new GMatrix(m.nCol, m.nRow); + + mtmp.mul(u, mtmp); + mtmp.mul(mtmp, v); + System.out.println("\n m = \n" + mtmp.toString(mtmp)); + + } + + private static String toString(GMatrix m) + { + StringBuffer buffer = new StringBuffer(m.nRow * m.nCol * 8); + int i, j; + + for (i = 0; i < m.nRow; i++) { + for(j = 0; j < m.nCol; j++) { + if (Math.abs(m.values[i][j]) < .000000001) { + buffer.append("0.0000 "); + } else { + buffer.append(m.values[i][j]).append(" "); + } + } + buffer.append("\n"); + } + return buffer.toString(); + } + + private static void print_svd(double[] s, double[] e, + GMatrix u, GMatrix v) { + int i; + GMatrix mtmp = new GMatrix(u.nCol, v.nRow); + + System.out.println(" \ns = "); + for (i = 0; i < s.length; i++) { + System.out.println(" " + s[i]); + } + + System.out.println(" \ne = "); + for (i = 0; i < e.length; i++) { + System.out.println(" " + e[i]); + } + + System.out.println(" \nu = \n" + u.toString()); + System.out.println(" \nv = \n" + v.toString()); + + mtmp.setIdentity(); + for (i = 0; i < s.length; i++) { + mtmp.values[i][i] = s[i]; + } + for (i = 0; i < e.length; i++) { + mtmp.values[i][i+1] = e[i]; + } + System.out.println(" \nm = \n"+mtmp.toString()); + + mtmp.mulTransposeLeft(u, mtmp); + mtmp.mulTransposeRight(mtmp, v); + + System.out.println(" \n u.transpose*m*v.transpose = \n" + + mtmp.toString()); + } + + 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 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.0) { + ssmin = 0.0; + if (fhmx == 0.0) { + } else { + d__1 = min(fhmx,ga) / max(fhmx,ga); + } + } else { + if (ga < fhmx) { + as = fhmn / fhmx + 1.0; + at = (fhmx - fhmn) / fhmx; + d__1 = ga / fhmx; + au = d__1 * d__1; + c = 2.0 / (Math.sqrt(as * as + au) + Math.sqrt(at * at + au)); + ssmin = fhmn * c; + } else { + au = fhmx / ga; + if (au == 0.0) { + ssmin = fhmn * fhmx / ga; + } else { + as = fhmn / fhmx + 1.0; + at = (fhmx - fhmn) / fhmx; + d__1 = as * au; + d__2 = at * au; + c = 1.0 / (Math.sqrt(d__1 * d__1 + 1.0) + + Math.sqrt(d__2 * d__2 + 1.0)); + 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.0; + double c_b4 = 1.0; + + 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.0) { + single_values[1] = ha; + single_values[0] = fa; + clt = 1.0; + crt = 1.0; + slt = 0.0; + srt = 0.0; + } else { + gasmal = true; + if (ga > fa) { + pmax = 2; + if (fa / ga < EPS) { + gasmal = false; + ssmax = ga; + + if (ha > 1.0) { + ssmin = fa / (ga / ha); + } else { + ssmin = fa / ga * ha; + } + clt = 1.0; + slt = ht / gt; + srt = 1.0; + crt = ft / gt; + } + } + if (gasmal) { + d = fa - ha; + if (d == fa) { + + l = 1.0; + } else { + l = d / fa; + } + + m = gt / ft; + t = 2.0 - l; + mm = m * m; + tt = t * t; + s = Math.sqrt(tt + mm); + + if (l == 0.0) { + r = Math.abs(m); + } else { + r = Math.sqrt(l * l + mm); + } + + a = (s + r) * 0.5; + if (ga > fa) { + pmax = 2; + if (fa / ga < EPS) { + gasmal = false; + ssmax = ga; + if (ha > 1.0) { + ssmin = fa / (ga / ha); + } else { + ssmin = fa / ga * ha; + } + clt = 1.0; + slt = ht / gt; + srt = 1.0; + crt = ft / gt; + } + } + if (gasmal) { + d = fa - ha; + if (d == fa) { + l = 1.0; + } else { + l = d / fa; + } + + m = gt / ft; + t = 2.0 - 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) * 0.5; + ssmin = ha / a; + ssmax = fa * a; + + if (mm == 0.0) { + if (l == 0.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.0); + } + + l = Math.sqrt(t * t + 4.0); + crt = 2.0 / 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 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.0) { + cs = 1.0; + sn = 0.0; + r = f; + } else if (f == 0.0) { + cs = 0.0; + sn = 1.0; + 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.0) { + cs = -cs; + sn = -sn; + r = -r; + } + } + sin[0] = sn; + cos[0] = cs; + return r; + } + + static double d_sign(double a, double b) { + double x; + x = (a >= 0 ? a : - a); + return (b >= 0 ? x : -x); + } + + /** + * 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 Java 3D 1.3 + */ + public Object clone() { + GMatrix m1 = null; + try { + m1 = (GMatrix)super.clone(); + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + + // Also need to clone array of values + m1.values = new double[nRow][nCol]; + for (int i = 0; i < nRow; i++) { + for(int j = 0; j < nCol; j++) { + m1.values[i][j] = values[i][j]; + } + } + + return m1; + } + +} diff --git a/src/javax/vecmath/GVector.java b/src/javax/vecmath/GVector.java new file mode 100644 index 0000000..89a9b37 --- /dev/null +++ b/src/javax/vecmath/GVector.java @@ -0,0 +1,914 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A double precision, general, dynamically-resizable, + * one-dimensional vector class. Index numbering begins with zero. + */ + +public class GVector implements java.io.Serializable, Cloneable { + + private int length; + double[] values; + + // Compatible with 1.1 + static final long serialVersionUID = 1398850036893875112L; + + /** + * Constructs a new GVector of the specified + * length with all vector elements initialized to 0. + * @param length the number of elements in this GVector. + */ + public GVector(int length) + { + int i; + + this.length = length; + values = new double[length]; + for(i = 0; i < length; i++) values[i] = 0.0; + } + + /** + * Constructs a new GVector from the specified array elements. + * The length of this GVector is set to the length of the + * specified array. The array elements are copied into this new + * GVector. + * @param vector the values for the new GVector. + */ + public GVector(double[] vector) + { + int i; + + length = vector.length; + values = new double[vector.length]; + for(i = 0; i < length; i++) values[i] = vector[i]; + } + + /** + * Constructs a new GVector from the specified vector. + * The vector elements are copied into this new GVector. + * @param vector the source GVector for this new GVector. + */ + public GVector(GVector vector) + { + int i; + + values = new double[vector.length]; + length = vector.length; + for(i = 0; i < length; i++) values[i] = vector.values[i]; + } + + /** + * Constructs a new GVector and copies the initial values + * from the specified tuple. + * @param tuple the source for the new GVector's initial values + */ + public GVector(Tuple2f tuple) + { + values = new double[2]; + values[0] = (double)tuple.x; + values[1] = (double)tuple.y; + length = 2; + } + + /** + * Constructs a new GVector and copies the initial values + * from the specified tuple. + * @param tuple the source for the new GVector's initial values + */ + public GVector(Tuple3f tuple) + { + values = new double[3]; + values[0] = (double)tuple.x; + values[1] = (double)tuple.y; + values[2] = (double)tuple.z; + length = 3; + } + + /** + * Constructs a new GVector and copies the initial values + * from the specified tuple. + * @param tuple the source for the new GVector's initial values + */ + public GVector(Tuple3d tuple) + { + values = new double[3]; + values[0] = tuple.x; + values[1] = tuple.y; + values[2] = tuple.z; + length = 3; + } + + /** + * Constructs a new GVector and copies the initial values + * from the specified tuple. + * @param tuple the source for the new GVector's initial values + */ + public GVector(Tuple4f tuple) + { + values = new double[4]; + values[0] = (double)tuple.x; + values[1] = (double)tuple.y; + values[2] = (double)tuple.z; + values[3] = (double)tuple.w; + length = 4; + } + + /** + * Constructs a new GVector and copies the initial values + * from the specified tuple. + * @param tuple the source for the new GVector's initial values + */ + public GVector(Tuple4d tuple) + { + values = new double[4]; + values[0] = tuple.x; + values[1] = tuple.y; + values[2] = tuple.z; + values[3] = tuple.w; + length = 4; + } + + /** + * Constructs a new GVector of the specified length and + * initializes it by copying the specified number of elements from + * the specified array. The array must contain at least + * <code>length</code> elements (i.e., <code>vector.length</code> >= + * <code>length</code>. The length of this new GVector is set to + * the specified length. + * @param vector The array from which the values will be copied. + * @param length The number of values copied from the array. + */ + public GVector(double vector[], int length) { + int i; + + this.length = length; + values = new double [length]; + for(i=0;i<length;i++) { + values[i] = vector[i]; + } + } + + /** + * Returns the square root of the sum of the squares of this + * vector (its length in n-dimensional space). + * @return length of this vector + */ + + public final double norm() + { + double sq = 0.0; + int i; + + for(i=0;i<length;i++) { + sq += values[i]*values[i]; + } + + return(Math.sqrt(sq)); + + } + + /** + * Returns the sum of the squares of this + * vector (its length squared in n-dimensional space). + * @return length squared of this vector + */ + public final double normSquared() + { + double sq = 0.0; + int i; + + for(i=0;i<length;i++) { + sq += values[i]*values[i]; + } + + return(sq); + } + + /** + * Sets the value of this vector to the normalization of vector v1. + * @param v1 the un-normalized vector + */ + public final void normalize(GVector v1) + { + double sq = 0.0; + int i; + + if( length != v1.length) + throw new MismatchedSizeException(VecMathI18N.getString("GVector0")); + + for(i=0;i<length;i++) { + sq += v1.values[i]*v1.values[i]; + } + + double invMag; + invMag = 1.0/Math.sqrt(sq); + + for(i=0;i<length;i++) { + values[i] = v1.values[i]*invMag; + } + } + + + /** + * Normalizes this vector in place. + */ + public final void normalize() + { + double sq = 0.0; + int i; + + for(i=0;i<length;i++) { + sq += values[i]*values[i]; + } + + double invMag; + invMag = 1.0/Math.sqrt(sq); + + for(i=0;i<length;i++) { + values[i] = values[i]*invMag; + } + + } + + /** + * Sets the value of this vector to the scalar multiplication + * of the scale factor with the vector v1. + * @param s the scalar value + * @param v1 the source vector + */ + public final void scale(double s, GVector v1) + { + int i; + if( length != v1.length) + throw new MismatchedSizeException(VecMathI18N.getString("GVector1")); + + for(i=0;i<length;i++) { + values[i] = v1.values[i]*s; + } + } + + /** + * Scales this vector by the scale factor s. + * @param s the scalar value + */ + public final void scale(double s) + { + int i; + + for(i=0;i<length;i++) { + values[i] = values[i]*s; + } + } + + /** + * Sets the value of this vector to the scalar multiplication by s + * of vector v1 plus vector v2 (this = s*v1 + v2). + * @param s the scalar value + * @param v1 the vector to be multiplied + * @param v2 the vector to be added + */ + public final void scaleAdd(double s, GVector v1, GVector v2) + { + + int i; + + if( v2.length != v1.length ) + throw new MismatchedSizeException(VecMathI18N.getString("GVector2")); + + if( length != v1.length ) + throw new MismatchedSizeException(VecMathI18N.getString("GVector3")); + + for(i=0;i<length;i++) { + values[i] = v1.values[i]*s + v2.values[i]; + } + } + + /** + * Sets the value of this vector to sum of itself and the specified + * vector + * @param vector the second vector + */ + public final void add(GVector vector) + { + int i; + + if( length != vector.length ) + throw new MismatchedSizeException(VecMathI18N.getString("GVector4")); + + for(i = 0; i < length; i++) { + this.values[i] += vector.values[i]; + } + } + + /** + * Sets the value of this vector to the vector sum of vectors vector1 + * and vector2. + * @param vector1 the first vector + * @param vector2 the second vector + */ + public final void add(GVector vector1, GVector vector2) + { + int i; + + if( vector1.length != vector2.length ) + throw new MismatchedSizeException(VecMathI18N.getString("GVector5")); + + if( length != vector1.length ) + throw new MismatchedSizeException(VecMathI18N.getString("GVector6")); + + for(i = 0; i < length; i++) + this.values[i] = vector1.values[i] + vector2.values[i]; + } + + /** + * Sets the value of this vector to the vector difference of itself + * and vector (this = this - vector). + * @param vector the other vector + */ + public final void sub(GVector vector) + { + int i; + + if( length != vector.length ) + throw new MismatchedSizeException(VecMathI18N.getString("GVector7")); + + for(i = 0; i < length; i++) { + this.values[i] -= vector.values[i]; + } + } + + /** + * Sets the value of this vector to the vector difference + * of vectors vector1 and vector2 (this = vector1 - vector2). + * @param vector1 the first vector + * @param vector2 the second vector + */ + public final void sub(GVector vector1, GVector vector2) + { + int i,l; + + + if( vector1.length != vector2.length ) + throw new MismatchedSizeException(VecMathI18N.getString("GVector8")); + + if( length != vector1.length ) + throw new MismatchedSizeException(VecMathI18N.getString("GVector9")); + + for(i = 0; i < length; i++) + this.values[i] = vector1.values[i] - vector2.values[i]; + } + + /** + * Multiplies matrix m1 times Vector v1 and places the result + * into this vector (this = m1*v1). + * @param m1 The matrix in the multiplication + * @param v1 The vector that is multiplied + */ + public final void mul(GMatrix m1, GVector v1) { + if (m1.getNumCol() != v1.length) + throw new MismatchedSizeException(VecMathI18N.getString("GVector10")); + + if (length != m1.getNumRow()) + throw new MismatchedSizeException(VecMathI18N.getString("GVector11")); + + double v[]; + if (v1 != this) { + v = v1.values; + } else { + v = (double []) values.clone(); + } + + for(int j=length-1; j>=0; j--){ + values[j] = 0.0; + for(int i=v1.length-1;i>=0; i--){ + values[j] += m1.values[j][i] * v[i]; + } + } + } + + /** + * Multiplies the transpose of vector v1 (ie, v1 becomes a row + * vector with respect to the multiplication) times matrix m1 + * and places the result into this vector + * (this = transpose(v1)*m1). The result is technically a + * row vector, but the GVector class only knows about column + * vectors, and so the result is stored as a column vector. + * @param m1 The matrix in the multiplication + * @param v1 The vector that is temporarily transposed + */ + public final void mul(GVector v1, GMatrix m1) { + if (m1.getNumRow() != v1.length) + throw new MismatchedSizeException(VecMathI18N.getString("GVector12")); + + if (length != m1.getNumCol()) + throw new MismatchedSizeException(VecMathI18N.getString("GVector13")); + + double v[]; + if (v1 != this) { + v = v1.values; + } else { + v = (double []) values.clone(); + } + + for (int j=length-1; j>=0; j--){ + values[j] = 0.0; + for(int i=v1.length-1; i>=0; i--){ + values[j] += m1.values[i][j] * v[i]; + } + } + } + + /** + * Negates the value of this vector: this = -this. + */ + public final void negate() { + for(int i=length-1; i>=0; i--) { + this.values[i] *= -1.0; + } + } + + /** + * Sets all the values in this vector to zero. + */ + public final void zero() { + for (int i=0; i < this.length; i++) { + this.values[i] = 0.0; + } + } + + /** + * Changes the size of this vector dynamically. If the size is increased + * no data values will be lost. If the size is decreased, only those data + * values whose vector positions were eliminated will be lost. + * @param length number of desired elements in this vector + */ + public final void setSize(int length) { + double[] tmp = new double[length]; + int i,max; + + if( this.length < length) + max = this.length; + else + max = length; + + for(i=0;i<max;i++) { + tmp[i] = values[i]; + } + this.length = length; + + values = tmp; + + } + + /** + * Sets the value of this vector to the values found in the array + * parameter. The array should be at least equal in length to + * the number of elements in the vector. + * @param vector the source array + */ + public final void set(double[] vector) { + for(int i = length-1; i >=0; i--) + values[i] = vector[i]; + } + + /** + * Sets the value of this vector to the values found in vector vector. + * @param vector the source vector + */ + public final void set(GVector vector) { + int i; + + if (length < vector.length) { + length = vector.length; + values = new double[length]; + for(i = 0; i < length; i++) + values[i] = vector.values[i]; + }else { + for(i = 0; i < vector.length; i++) + values[i] = vector.values[i]; + for(i = vector.length; i < length; i++) + values[i] = 0.0; + } + } + + /** + * Sets the value of this vector to the values in tuple + * @param tuple the source for the new GVector's new values + */ + public final void set(Tuple2f tuple) + { + if (length < 2) { + length = 2; + values = new double[2]; + } + values[0] = (double)tuple.x; + values[1] = (double)tuple.y; + for(int i = 2; i < length; i++) values[i] = 0.0; + + } + + /** + * Sets the value of this vector to the values in tuple + * @param tuple the source for the new GVector's new values + */ + public final void set(Tuple3f tuple) + { + if (length < 3) { + length = 3; + values = new double[3]; + } + values[0] = (double)tuple.x; + values[1] = (double)tuple.y; + values[2] = (double)tuple.z; + for(int i = 3; i < length; i++) values[i] = 0.0; + } + + /** + * Sets the value of this vector to the values in tuple + * @param tuple the source for the new GVector's new values + */ + public final void set(Tuple3d tuple) + { + if (length < 3) { + length = 3; + values = new double[3]; + } + values[0] = tuple.x; + values[1] = tuple.y; + values[2] = tuple.z; + for(int i = 3; i < length; i++) values[i] = 0.0; + } + + /** + * Sets the value of this vector to the values in tuple + * @param tuple the source for the new GVector's new values + */ + public final void set(Tuple4f tuple) + { + if (length < 4) { + length = 4; + values = new double[4]; + } + values[0] = (double)tuple.x; + values[1] = (double)tuple.y; + values[2] = (double)tuple.z; + values[3] = (double)tuple.w; + for(int i = 4; i < length; i++) values[i] = 0.0; + } + + /** + * Sets the value of this vector to the values in tuple + * @param tuple the source for the new GVector's new values + */ + public final void set(Tuple4d tuple) + { + if (length < 4) { + length = 4; + values = new double[4]; + } + values[0] = tuple.x; + values[1] = tuple.y; + values[2] = tuple.z; + values[3] = tuple.w; + for(int i = 4; i < length; i++) values[i] = 0.0; + } + + /** + * Returns the number of elements in this vector. + * @return number of elements in this vector + */ + public final int getSize() + { + return values.length; + } + + /** + * Retrieves the value at the specified index value of this vector. + * @param index the index of the element to retrieve (zero indexed) + * @return the value at the indexed element + */ + public final double getElement(int index) + { + return values[index]; + } + + + /** + * Modifies the value at the specified index of this vector. + * @param index the index if the element to modify (zero indexed) + * @param value the new vector element value + */ + public final void setElement(int index, double value) + { + values[index] = value; + } + + /** + * Returns a string that contains the values of this GVector. + * @return the String representation + */ + public String toString() { + StringBuffer buffer = new StringBuffer(length*8); + + int i; + + for(i=0;i<length;i++) { + buffer.append(values[i]).append(" "); + } + + return buffer.toString(); + + } + + + /** + * Returns a hash code value based on the data values in this + * object. Two different GVector objects with identical data + * values (i.e., GVector.equals returns true) will return the + * same hash number. Two GVector objects with different data + * members may return the same hash value, although this is not + * likely. + * @return the integer hash code value + */ + public int hashCode() { + long bits = 1L; + + for (int i = 0; i < length; i++) { + bits = 31L * bits + Double.doubleToLongBits(values[i]); + } + + return (int) (bits ^ (bits >> 32)); + } + + + /** + * Returns true if all of the data members of GVector vector1 are + * equal to the corresponding data members in this GVector. + * @param vector1 The vector with which the comparison is made. + * @return true or false + */ + public boolean equals(GVector vector1) + { + try { + if( length != vector1.length) return false; + + for(int i = 0;i<length;i++) { + if( values[i] != vector1.values[i]) return false; + } + + return true; + } + catch (NullPointerException e2) { return false; } + + } + /** + * Returns true if the Object o1 is of type GMatrix and all of the + * data members of o1 are equal to the corresponding data members in + * this GMatrix. + * @param o1 The object with which the comparison is made. + * @return true or false + */ + public boolean equals(Object o1) + { + try { + GVector v2 = (GVector) o1; + + if( length != v2.length) return false; + + for(int i = 0;i<length;i++) { + if( values[i] != v2.values[i]) return false; + } + return true; + } + catch (ClassCastException e1) { return false; } + catch (NullPointerException e2) { return false; } + + } + + /** + * Returns true if the L-infinite distance between this vector + * and vector v1 is less than or equal to the epsilon parameter, + * otherwise returns false. The L-infinite + * distance is equal to + * MAX[abs(x1-x2), abs(y1-y2), . . . ]. + * @param v1 The vector to be compared to this vector + * @param epsilon the threshold value + */ + public boolean epsilonEquals(GVector v1, double epsilon) + { + double diff; + + if( length != v1.length) return false; + + for(int i = 0;i<length;i++) { + diff = values[i] - v1.values[i]; + if( (diff<0?-diff:diff) > epsilon) return false; + } + return true; + } + + /** + * Returns the dot product of this vector and vector v1. + * @param v1 the other vector + * @return the dot product of this and v1 + */ + public final double dot(GVector v1) + { + if( length != v1.length) + throw new MismatchedSizeException(VecMathI18N.getString("GVector14")); + + double result = 0.0; + for(int i = 0;i<length;i++) { + result += values[i] * v1.values[i]; + } + return result; + } + + + /** + * Solves for x in Ax = b, where x is this vector (nx1), A is mxn, + * b is mx1, and A = U*W*transpose(V); U,W,V must + * be precomputed and can be found by taking the singular value + * decomposition (SVD) of A using the method SVD found in the + * GMatrix class. + * @param U The U matrix produced by the GMatrix method SVD + * @param W The W matrix produced by the GMatrix method SVD + * @param V The V matrix produced by the GMatrix method SVD + * @param b The b vector in the linear equation Ax = b + */ + public final void SVDBackSolve(GMatrix U, GMatrix W, GMatrix V, GVector b) + { + if( !(U.nRow == b.getSize() && + U.nRow == U.nCol && + U.nRow == W.nRow ) ) { + throw new MismatchedSizeException(VecMathI18N.getString("GVector15")); + } + + if( !(W.nCol == values.length && + W.nCol == V.nCol && + W.nCol == V.nRow ) ) { + throw new MismatchedSizeException(VecMathI18N.getString("GVector23")); + } + + GMatrix tmp = new GMatrix( U.nRow, W.nCol); + tmp.mul( U, V); + tmp.mulTransposeRight( U, W); + tmp.invert(); + mul(tmp, b); + + } + + /** + * LU Decomposition Back Solve; this method takes the LU matrix + * and the permutation vector produced by the GMatrix method LUD + * and solves the equation (LU)*x = b by placing the solution vector + * x into this vector. This vector should be the same length or + * longer than b. + * @param LU The matrix into which the lower and upper decompostions + * have been placed + * @param b The b vector in the equation (LU)*x = b + * @param permutation The row permuations that were necessary to + * produce the LU matrix parameter + */ + public final void LUDBackSolve(GMatrix LU, GVector b, GVector permutation) + { + int size = LU.nRow*LU.nCol; + + double[] temp = new double[size]; + double[] result = new double[size]; + int[] row_perm = new int[b.getSize()]; + int i,j; + + if( LU.nRow != b.getSize() ) { + throw new MismatchedSizeException(VecMathI18N.getString("GVector16")); + } + + if( LU.nRow != permutation.getSize() ) { + throw new MismatchedSizeException(VecMathI18N.getString("GVector24")); + } + + if (LU.nRow != LU.nCol) { + throw new MismatchedSizeException(VecMathI18N.getString("GVector25")); + } + + for(i=0;i<LU.nRow;i++) { + for(j=0;j<LU.nCol;j++) { + temp[i*LU.nCol+j] = LU.values[i][j]; + } + } + + for(i=0;i<size;i++) result[i] = 0.0; + for(i=0;i<LU.nRow;i++) result[i*LU.nCol] = b.values[i]; + for(i=0;i<LU.nCol;i++) row_perm[i] = (int)permutation.values[i]; + + GMatrix.luBacksubstitution(LU.nRow, temp, row_perm, result); + + for(i=0;i<LU.nRow;i++) this.values[i] = result[i*LU.nCol]; + } + + /** + * Returns the (n-space) angle in radians between this vector and + * the vector parameter; the return value is constrained to the + * range [0,PI]. + * @param v1 The other vector + * @return The angle in radians in the range [0,PI] + */ + public final double angle(GVector v1) + { + return( Math.acos( this.dot(v1) / ( this.norm()*v1.norm() ) ) ); + } + + + /** + * @deprecated Use interpolate(GVector, GVector, double) instead + */ + public final void interpolate(GVector v1, GVector v2, float alpha) { + interpolate(v1, v2, (double)alpha); + } + + + /** + * @deprecated Use interpolate(GVector, double) instead + */ + public final void interpolate(GVector v1, float alpha) { + interpolate(v1, (double)alpha); + } + + + /** + * Linearly interpolates between vectors v1 and v2 and places the + * result into this tuple: this = (1-alpha)*v1 + alpha*v2. + * @param v1 the first vector + * @param v2 the second vector + * @param alpha the alpha interpolation parameter + */ + public final void interpolate(GVector v1, GVector v2, double alpha) + { + if( v2.length != v1.length ) + throw new MismatchedSizeException(VecMathI18N.getString("GVector20")); + + if( length != v1.length ) + throw new MismatchedSizeException(VecMathI18N.getString("GVector21")); + + for(int i=0;i<length;i++) { + values[i] = (1-alpha)*v1.values[i] + alpha*v2.values[i]; + } + } + + /** + * Linearly interpolates between this vector and vector v1 and + * places the result into this tuple: this = (1-alpha)*this + alpha*v1. + * @param v1 the first vector + * @param alpha the alpha interpolation parameter + */ + public final void interpolate(GVector v1, double alpha) + { + if( v1.length != length ) + throw new MismatchedSizeException(VecMathI18N.getString("GVector22")); + + for(int i=0;i<length;i++) { + values[i] = (1-alpha)*values[i] + alpha*v1.values[i]; + } + } + + /** + * 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 Java 3D 1.3 + */ + public Object clone() { + GVector v1 = null; + try { + v1 = (GVector)super.clone(); + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + + // Also need to clone array of values + v1.values = new double[length]; + for (int i = 0; i < length; i++) { + v1.values[i] = values[i]; + } + + return v1; + } + +} diff --git a/src/javax/vecmath/Matrix3d.java b/src/javax/vecmath/Matrix3d.java new file mode 100644 index 0000000..eb696b8 --- /dev/null +++ b/src/javax/vecmath/Matrix3d.java @@ -0,0 +1,3106 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * 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; + private static final double ERR_EPS = 1.0E-8; + private static double xin,yin,zin,xout,yout,zout; + + /** + * 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 + */ + 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 = a1.x * a1.z; + double xy = a1.x * a1.y; + double yz = a1.y * a1.z; + + 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, r, c; + 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 + */ + 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 + */ + public int hashCode() { + long bits = 1L; + bits = 31L * bits + Double.doubleToLongBits(m00); + bits = 31L * bits + Double.doubleToLongBits(m01); + bits = 31L * bits + Double.doubleToLongBits(m02); + bits = 31L * bits + Double.doubleToLongBits(m10); + bits = 31L * bits + Double.doubleToLongBits(m11); + bits = 31L * bits + Double.doubleToLongBits(m12); + bits = 31L * bits + Double.doubleToLongBits(m20); + bits = 31L * bits + Double.doubleToLongBits(m21); + bits = 31L * bits + Double.doubleToLongBits(m22); + return (int) (bits ^ (bits >> 32)); + } + + + /** + * 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 Java 3D 1.3 + */ + 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; + } + +} diff --git a/src/javax/vecmath/Matrix3f.java b/src/javax/vecmath/Matrix3f.java new file mode 100644 index 0000000..155d5e1 --- /dev/null +++ b/src/javax/vecmath/Matrix3f.java @@ -0,0 +1,2096 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A single precision floating point 3 by 3 matrix. + * Primarily to support 3D rotations. + * + */ +public class Matrix3f implements java.io.Serializable, Cloneable { + + // Compatible with 1.1 + static final long serialVersionUID = 329697160112089834L; + + /** + * The first matrix element in the first row. + */ + public float m00; + + /** + * The second matrix element in the first row. + */ + public float m01; + + /** + * The third matrix element in the first row. + */ + public float m02; + + /** + * The first matrix element in the second row. + */ + public float m10; + + /** + * The second matrix element in the second row. + */ + public float m11; + + /** + * The third matrix element in the second row. + */ + public float m12; + + /** + * The first matrix element in the third row. + */ + public float m20; + + /** + * The second matrix element in the third row. + */ + public float m21; + + /** + * The third matrix element in the third row. + */ + public float 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.0E-8; + + + + /** + * Constructs and initializes a Matrix3f 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 Matrix3f(float m00, float m01, float m02, + float m10, float m11, float m12, + float m20, float m21, float 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 Matrix3f from the specified + * nine-element array. this.m00 =v[0], this.m01=v[1], etc. + * @param v the array of length 9 containing in order + */ + public Matrix3f(float[] 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 Matrix3f(Matrix3d m1) + { + this.m00 = (float)m1.m00; + this.m01 = (float)m1.m01; + this.m02 = (float)m1.m02; + + this.m10 = (float)m1.m10; + this.m11 = (float)m1.m11; + this.m12 = (float)m1.m12; + + this.m20 = (float)m1.m20; + this.m21 = (float)m1.m21; + this.m22 = (float)m1.m22; + + } + + + /** + * Constructs a new matrix with the same values as the + * Matrix3f parameter. + * @param m1 the source matrix + */ + public Matrix3f(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 Matrix3f to all zeros. + */ + public Matrix3f() + { + this.m00 = (float) 0.0; + this.m01 = (float) 0.0; + this.m02 = (float) 0.0; + + this.m10 = (float) 0.0; + this.m11 = (float) 0.0; + this.m12 = (float) 0.0; + + this.m20 = (float) 0.0; + this.m21 = (float) 0.0; + this.m22 = (float) 0.0; + + } + + /** + * Returns a string that contains the values of this Matrix3f. + * @return the String representation + */ + 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 Matrix3f to identity. + */ + public final void setIdentity() + { + this.m00 = (float) 1.0; + this.m01 = (float) 0.0; + this.m02 = (float) 0.0; + + this.m10 = (float) 0.0; + this.m11 = (float) 1.0; + this.m12 = (float) 0.0; + + this.m20 = (float) 0.0; + this.m21 = (float) 0.0; + this.m22 = (float) 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(float scale) + { + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + + getScaleRotate( tmp_scale, tmp_rot ); + + this.m00 = (float)(tmp_rot[0] * scale); + this.m01 = (float)(tmp_rot[1] * scale); + this.m02 = (float)(tmp_rot[2] * scale); + + this.m10 = (float)(tmp_rot[3] * scale); + this.m11 = (float)(tmp_rot[4] * scale); + this.m12 = (float)(tmp_rot[5] * scale); + + this.m20 = (float)(tmp_rot[6] * scale); + this.m21 = (float)(tmp_rot[7] * scale); + this.m22 = (float)(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, float 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("Matrix3f0")); + } + 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("Matrix3f0")); + } + 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("Matrix3f0")); + } + break; + + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix3f0")); + } + } + + /** + * 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, Vector3f 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("Matrix3f1")); + } + + } + + /** + * 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, float 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("Matrix3f1")); + } + + } + + /** + * 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, Vector3f 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("Matrix3f3")); + } + + } + + /** + * 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, float 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("Matrix3f3")); + } + } + + /** + * Retrieves the value at the specified row and column of this + * 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 float 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("Matrix3f5")); + } + + /** + * Sets the specified row of this matrix3f to the three 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, float x, float y, float 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("Matrix3f6")); + } + } + + /** + * Sets the specified row of this matrix3f 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, Vector3f 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("Matrix3f6")); + } + } + + /** + * Sets the specified row of this matrix3f 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, float 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("Matrix3f6")); + } + } + + /** + * Sets the specified column of this matrix3f 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, float x, float y, float 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("Matrix3f9")); + } + } + + /** + * Sets the specified column of this matrix3f 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, Vector3f 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("Matrix3f9")); + } + } + + /** + * Sets the specified column of this matrix3f 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, float 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("Matrix3f9")); + } + } + + /** + * 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 float getScale() + { + + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + getScaleRotate(tmp_scale, tmp_rot); + + return( (float)Matrix3d.max3(tmp_scale )); + + } + + /** + * Adds a scalar to each component of this matrix. + * @param scalar the scalar adder + */ + public final void add(float 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(float scalar, Matrix3f 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(Matrix3f m1, Matrix3f 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 sum of itself and + * matrix m1. + * @param m1 the other matrix + */ + public final void add(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 matrix difference + * of matrices m1 and m2. + * @param m1 the first matrix + * @param m2 the second matrix + */ + public final void sub(Matrix3f m1, Matrix3f 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(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 its transpose. + */ + public final void transpose() + { + float 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(Matrix3f 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 + * (single precision) quaternion argument. + * @param q1 the quaternion to be converted + */ + public final void set(Quat4f q1) + { + this.m00 = 1.0f - 2.0f*q1.y*q1.y - 2.0f*q1.z*q1.z; + this.m10 = 2.0f*(q1.x*q1.y + q1.w*q1.z); + this.m20 = 2.0f*(q1.x*q1.z - q1.w*q1.y); + + this.m01 = 2.0f*(q1.x*q1.y - q1.w*q1.z); + this.m11 = 1.0f - 2.0f*q1.x*q1.x - 2.0f*q1.z*q1.z; + this.m21 = 2.0f*(q1.y*q1.z + q1.w*q1.x); + + this.m02 = 2.0f*(q1.x*q1.z + q1.w*q1.y); + this.m12 = 2.0f*(q1.y*q1.z - q1.w*q1.x); + this.m22 = 1.0f - 2.0f*q1.x*q1.x - 2.0f*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) + { + float mag = (float)Math.sqrt( a1.x*a1.x + a1.y*a1.y + a1.z*a1.z); + if( mag < EPS ) { + m00 = 1.0f; + m01 = 0.0f; + m02 = 0.0f; + + m10 = 0.0f; + m11 = 1.0f; + m12 = 0.0f; + + m20 = 0.0f; + m21 = 0.0f; + m22 = 1.0f; + } else { + mag = 1.0f/mag; + float ax = a1.x*mag; + float ay = a1.y*mag; + float az = a1.z*mag; + + float sinTheta = (float)Math.sin((float)a1.angle); + float cosTheta = (float)Math.cos((float)a1.angle); + float t = (float)1.0 - cosTheta; + + float xz = ax * az; + float xy = ax * ay; + float 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 + * (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.0f; + m01 = 0.0f; + m02 = 0.0f; + + m10 = 0.0f; + m11 = 1.0f; + m12 = 0.0f; + + m20 = 0.0f; + m21 = 0.0f; + m22 = 1.0f; + } 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 = (float)(t * ax * ax + cosTheta); + m01 = (float)(t * xy - sinTheta * az); + m02 = (float)(t * xz + sinTheta * ay); + + m10 = (float)(t * xy + sinTheta * az); + m11 = (float)(t * ay * ay + cosTheta); + m12 = (float)(t * yz - sinTheta * ax); + + m20 = (float)(t * xz - sinTheta * ay); + m21 = (float)(t * yz + sinTheta * ax); + m22 = (float)(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(Quat4d q1) + { + this.m00 = (float) (1.0 - 2.0*q1.y*q1.y - 2.0*q1.z*q1.z); + this.m10 = (float) (2.0*(q1.x*q1.y + q1.w*q1.z)); + this.m20 = (float) (2.0*(q1.x*q1.z - q1.w*q1.y)); + + this.m01 = (float) (2.0*(q1.x*q1.y - q1.w*q1.z)); + this.m11 = (float) (1.0 - 2.0*q1.x*q1.x - 2.0*q1.z*q1.z); + this.m21 = (float) (2.0*(q1.y*q1.z + q1.w*q1.x)); + + this.m02 = (float) (2.0*(q1.x*q1.z + q1.w*q1.y)); + this.m12 = (float) (2.0*(q1.y*q1.z - q1.w*q1.x)); + this.m22 = (float) (1.0 - 2.0*q1.x*q1.x - 2.0*q1.y*q1.y); + } + + /** + * Sets the values in this Matrix3f 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 single precision array of length 9 + */ + public final void set(float[] 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 value of the Matrix3f + * argument. + * @param m1 the source matrix3f + */ + 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 float value of the Matrix3d + * argument. + * @param m1 the source matrix3d + */ + public final void set(Matrix3d m1) { + + this.m00 = (float)m1.m00; + this.m01 = (float)m1.m01; + this.m02 = (float)m1.m02; + + this.m10 = (float)m1.m10; + this.m11 = (float)m1.m11; + this.m12 = (float)m1.m12; + + this.m20 = (float)m1.m20; + this.m21 = (float)m1.m21; + this.m22 = (float)m1.m22; + + } + + + /** + * 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(Matrix3f 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(Matrix3f m1) { + double temp[] = new double[9]; + double result[] = new double[9]; + int row_perm[] = new int[3]; + int i, r, c; + + // Use LU decomposition and backsubstitution code specifically + // for floating-point 3x3 matrices. + + // Copy source matrix to t1tmp + temp[0] = (double)m1.m00; + temp[1] = (double)m1.m01; + temp[2] = (double)m1.m02; + + temp[3] = (double)m1.m10; + temp[4] = (double)m1.m11; + temp[5] = (double)m1.m12; + + temp[6] = (double)m1.m20; + temp[7] = (double)m1.m21; + temp[8] = (double)m1.m22; + + + // Calculate LU decomposition: Is the matrix singular? + if (!luDecomposition(temp, row_perm)) { + // Matrix has no inverse + throw new SingularMatrixException(VecMathI18N.getString("Matrix3f12")); + } + + // 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(temp, row_perm, result); + + this.m00 = (float)result[0]; + this.m01 = (float)result[1]; + this.m02 = (float)result[2]; + + this.m10 = (float)result[3]; + this.m11 = (float)result[4]; + this.m12 = (float)result[5]; + + this.m20 = (float)result[6]; + this.m21 = (float)result[7]; + this.m22 = (float)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("Matrix3f13")); + } + + // 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 this matrix + */ + public final float determinant() + { + float 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(float scale) + { + this.m00 = scale; + this.m01 = (float) 0.0; + this.m02 = (float) 0.0; + + this.m10 = (float) 0.0; + this.m11 = scale; + this.m12 = (float) 0.0; + + this.m20 = (float) 0.0; + this.m21 = (float) 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(float angle) + { + float sinAngle, cosAngle; + + sinAngle = (float) Math.sin((double) angle); + cosAngle = (float) Math.cos((double) angle); + + this.m00 = (float) 1.0; + this.m01 = (float) 0.0; + this.m02 = (float) 0.0; + + this.m10 = (float) 0.0; + this.m11 = cosAngle; + this.m12 = -sinAngle; + + this.m20 = (float) 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(float angle) + { + float sinAngle, cosAngle; + + sinAngle = (float) Math.sin((double) angle); + cosAngle = (float) Math.cos((double) angle); + + this.m00 = cosAngle; + this.m01 = (float) 0.0; + this.m02 = sinAngle; + + this.m10 = (float) 0.0; + this.m11 = (float) 1.0; + this.m12 = (float) 0.0; + + this.m20 = -sinAngle; + this.m21 = (float) 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(float angle) + { + float sinAngle, cosAngle; + + sinAngle = (float) Math.sin((double) angle); + cosAngle = (float) Math.cos((double) angle); + + this.m00 = cosAngle; + this.m01 = -sinAngle; + this.m02 = (float) 0.0; + + this.m10 = sinAngle; + this.m11 = cosAngle; + this.m12 = (float) 0.0; + + this.m20 = (float) 0.0; + this.m21 = (float) 0.0; + this.m22 = (float) 1.0; + } + + /** + * Multiplies each element of this matrix by a scalar. + * @param scalar the scalar multiplier + */ + public final void mul(float 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(float scalar, Matrix3f 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(Matrix3f m1) + { + float 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(Matrix3f m1, Matrix3f 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 { + float m00, m01, m02, + m10, m11, m12, + m20, m21, m22; + + 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(Matrix3f 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; + + Matrix3d.compute_svd( tmp, tmp_scale, tmp_rot); + + this.m00 = (float)(tmp_rot[0]); + this.m01 = (float)(tmp_rot[1]); + this.m02 = (float)(tmp_rot[2]); + + this.m10 = (float)(tmp_rot[3]); + this.m11 = (float)(tmp_rot[4]); + this.m12 = (float)(tmp_rot[5]); + + this.m20 = (float)(tmp_rot[6]); + this.m21 = (float)(tmp_rot[7]); + this.m22 = (float)(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(Matrix3f m1, Matrix3f 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; + + Matrix3d.compute_svd( tmp, tmp_scale, tmp_rot); + + this.m00 = (float)(tmp_rot[0]); + this.m01 = (float)(tmp_rot[1]); + this.m02 = (float)(tmp_rot[2]); + + this.m10 = (float)(tmp_rot[3]); + this.m11 = (float)(tmp_rot[4]); + this.m12 = (float)(tmp_rot[5]); + + this.m20 = (float)(tmp_rot[6]); + this.m21 = (float)(tmp_rot[7]); + this.m22 = (float)(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(Matrix3f m1, Matrix3f 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 { + float 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(Matrix3f m1, Matrix3f 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 { + float 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(Matrix3f m1, Matrix3f 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 { + float 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 = (float)tmp_rot[0]; + this.m01 = (float)tmp_rot[1]; + this.m02 = (float)tmp_rot[2]; + + this.m10 = (float)tmp_rot[3]; + this.m11 = (float)tmp_rot[4]; + this.m12 = (float)tmp_rot[5]; + + this.m20 = (float)tmp_rot[6]; + this.m21 = (float)tmp_rot[7]; + this.m22 = (float)tmp_rot[8]; + + } + + /** + * Perform singular value decomposition normalization of matrix m1 + * and place the normalized values into this. + * @param m1 the matrix values to be normalized + */ + public final void normalize(Matrix3f 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; + + Matrix3d.compute_svd( tmp, tmp_scale, tmp_rot ); + + this.m00 = (float)(tmp_rot[0]); + this.m01 = (float)(tmp_rot[1]); + this.m02 = (float)(tmp_rot[2]); + + this.m10 = (float)(tmp_rot[3]); + this.m11 = (float)(tmp_rot[4]); + this.m12 = (float)(tmp_rot[5]); + + this.m20 = (float)(tmp_rot[6]); + this.m21 = (float)(tmp_rot[7]); + this.m22 = (float)(tmp_rot[8]); + + } + + /** + * Perform cross product normalization of this matrix. + */ + public final void normalizeCP() + { + float mag = 1.0f/(float)Math.sqrt(m00*m00 + m10*m10 + m20*m20); + m00 = m00*mag; + m10 = m10*mag; + m20 = m20*mag; + + mag = 1.0f/(float)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(Matrix3f m1) + { + float mag = 1.0f/(float)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.0f/(float)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 Matrix3f m1 are + * equal to the corresponding data members in this Matrix3f. + * @param m1 the matrix with which the comparison is made + * @return true or false + */ + public boolean equals(Matrix3f 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 o1 is of type Matrix3f and all of the + * data members of o1 are equal to the corresponding data members in + * this Matrix3f. + * @param o1 the object with which the comparison is made + * @return true or false + */ + public boolean equals(Object o1) + { + try { + + Matrix3f m2 = (Matrix3f) o1; + 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(Matrix3f m1, float epsilon) + { + boolean status = true; + + if( Math.abs( this.m00 - m1.m00) > epsilon) status = false; + if( Math.abs( this.m01 - m1.m01) > epsilon) status = false; + if( Math.abs( this.m02 - m1.m02) > epsilon) status = false; + + if( Math.abs( this.m10 - m1.m10) > epsilon) status = false; + if( Math.abs( this.m11 - m1.m11) > epsilon) status = false; + if( Math.abs( this.m12 - m1.m12) > epsilon) status = false; + + if( Math.abs( this.m20 - m1.m20) > epsilon) status = false; + if( Math.abs( this.m21 - m1.m21) > epsilon) status = false; + if( Math.abs( this.m22 - m1.m22) > epsilon) status = false; + + return( status ); + + } + + + /** + * Returns a hash code value based on the data values in this + * object. Two different Matrix3f objects with identical data values + * (i.e., Matrix3f.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 + */ + public int hashCode() { + long bits = 1L; + bits = 31L * bits + (long)Float.floatToIntBits(m00); + bits = 31L * bits + (long)Float.floatToIntBits(m01); + bits = 31L * bits + (long)Float.floatToIntBits(m02); + bits = 31L * bits + (long)Float.floatToIntBits(m10); + bits = 31L * bits + (long)Float.floatToIntBits(m11); + bits = 31L * bits + (long)Float.floatToIntBits(m12); + bits = 31L * bits + (long)Float.floatToIntBits(m20); + bits = 31L * bits + (long)Float.floatToIntBits(m21); + bits = 31L * bits + (long)Float.floatToIntBits(m22); + return (int) (bits ^ (bits >> 32)); + } + + + /** + * Sets this matrix to all zeros. + */ + public final void setZero() + { + m00 = 0.0f; + m01 = 0.0f; + m02 = 0.0f; + + m10 = 0.0f; + m11 = 0.0f; + m12 = 0.0f; + + m20 = 0.0f; + m21 = 0.0f; + m22 = 0.0f; + + } + + /** + * 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 Matrix3f parameter. + * @param m1 the source matrix + */ + public final void negate(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; + + } + + /** + * 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(Tuple3f t) { + float 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(Tuple3f t, Tuple3f result) { + float 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 + */ + void getScaleRotate( double[] scales, double[] rot ) { + + 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; + Matrix3d.compute_svd(tmp, scales, rot); + + return; + + } + + /** + * 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 Java 3D 1.3 + */ + public Object clone() { + Matrix3f m1 = null; + try { + m1 = (Matrix3f)super.clone(); + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + return m1; + } + +} diff --git a/src/javax/vecmath/Matrix4d.java b/src/javax/vecmath/Matrix4d.java new file mode 100644 index 0000000..0aa353b --- /dev/null +++ b/src/javax/vecmath/Matrix4d.java @@ -0,0 +1,3585 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A double precision floating point 4 by 4 matrix. + * Primarily to support 3D rotations. + * + */ +public class Matrix4d implements java.io.Serializable, Cloneable { + + // Compatible with 1.1 + static final long serialVersionUID = 8223903484171633710L; + + /** + * The first element of the first row. + */ + public double m00; + + /** + * The second element of the first row. + */ + public double m01; + + /** + * The third element of the first row. + */ + public double m02; + + /** + * The fourth element of the first row. + */ + public double m03; + + /** + * The first element of the second row. + */ + public double m10; + + /** + * The second element of the second row. + */ + public double m11; + + /** + * The third element of the second row. + */ + public double m12; + + /** + * The fourth element of the second row. + */ + public double m13; + + /** + * The first element of the third row. + */ + public double m20; + + /** + * The second element of the third row. + */ + public double m21; + + /** + * The third element of the third row. + */ + public double m22; + + /** + * The fourth element of the third row. + */ + public double m23; + + /** + * The first element of the fourth row. + */ + public double m30; + + /** + * The second element of the fourth row. + */ + public double m31; + + /** + * The third element of the fourth row. + */ + public double m32; + + /** + * The fourth element of the fourth row. + */ + public double m33; + /* + double[] tmp = new double[16]; + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + */ + private static final double EPS = 1.0E-10; + + + /** + * Constructs and initializes a Matrix4d from the specified 16 values. + * @param m00 the [0][0] element + * @param m01 the [0][1] element + * @param m02 the [0][2] element + * @param m03 the [0][3] element + * @param m10 the [1][0] element + * @param m11 the [1][1] element + * @param m12 the [1][2] element + * @param m13 the [1][3] element + * @param m20 the [2][0] element + * @param m21 the [2][1] element + * @param m22 the [2][2] element + * @param m23 the [2][3] element + * @param m30 the [3][0] element + * @param m31 the [3][1] element + * @param m32 the [3][2] element + * @param m33 the [3][3] element + */ + public Matrix4d(double m00, double m01, double m02, double m03, + double m10, double m11, double m12, double m13, + double m20, double m21, double m22, double m23, + double m30, double m31, double m32, double m33) + { + this.m00 = m00; + this.m01 = m01; + this.m02 = m02; + this.m03 = m03; + + this.m10 = m10; + this.m11 = m11; + this.m12 = m12; + this.m13 = m13; + + this.m20 = m20; + this.m21 = m21; + this.m22 = m22; + this.m23 = m23; + + this.m30 = m30; + this.m31 = m31; + this.m32 = m32; + this.m33 = m33; + + } + + /** + * Constructs and initializes a Matrix4d from the specified 16 + * element array. this.m00 =v[0], this.m01=v[1], etc. + * @param v the array of length 16 containing in order + */ + public Matrix4d(double[] v) + { + this.m00 = v[ 0]; + this.m01 = v[ 1]; + this.m02 = v[ 2]; + this.m03 = v[ 3]; + + this.m10 = v[ 4]; + this.m11 = v[ 5]; + this.m12 = v[ 6]; + this.m13 = v[ 7]; + + this.m20 = v[ 8]; + this.m21 = v[ 9]; + this.m22 = v[10]; + this.m23 = v[11]; + + this.m30 = v[12]; + this.m31 = v[13]; + this.m32 = v[14]; + this.m33 = v[15]; + + } + + /** + * Constructs and initializes a Matrix4d from the quaternion, + * translation, and scale values; the scale is applied only to the + * rotational components of the matrix (upper 3x3) and not to the + * translational components. + * @param q1 the quaternion value representing the rotational component + * @param t1 the translational component of the matrix + * @param s the scale value applied to the rotational components + */ + public Matrix4d(Quat4d q1, Vector3d t1, double s) + { + m00 = s*(1.0 - 2.0*q1.y*q1.y - 2.0*q1.z*q1.z); + m10 = s*(2.0*(q1.x*q1.y + q1.w*q1.z)); + m20 = s*(2.0*(q1.x*q1.z - q1.w*q1.y)); + + m01 = s*(2.0*(q1.x*q1.y - q1.w*q1.z)); + m11 = s*(1.0 - 2.0*q1.x*q1.x - 2.0*q1.z*q1.z); + m21 = s*(2.0*(q1.y*q1.z + q1.w*q1.x)); + + m02 = s*(2.0*(q1.x*q1.z + q1.w*q1.y)); + m12 = s*(2.0*(q1.y*q1.z - q1.w*q1.x)); + m22 = s*(1.0 - 2.0*q1.x*q1.x - 2.0*q1.y*q1.y); + + m03 = t1.x; + m13 = t1.y; + m23 = t1.z; + + m30 = 0.0; + m31 = 0.0; + m32 = 0.0; + m33 = 1.0; + + } + + /** + * Constructs and initializes a Matrix4d from the quaternion, + * translation, and scale values; the scale is applied only to the + * rotational components of the matrix (upper 3x3) and not to the + * translational components. + * @param q1 the quaternion value representing the rotational component + * @param t1 the translational component of the matrix + * @param s the scale value applied to the rotational components + */ + public Matrix4d(Quat4f q1, Vector3d t1, double s) + { + m00 = s*(1.0 - 2.0*q1.y*q1.y - 2.0*q1.z*q1.z); + m10 = s*(2.0*(q1.x*q1.y + q1.w*q1.z)); + m20 = s*(2.0*(q1.x*q1.z - q1.w*q1.y)); + + m01 = s*(2.0*(q1.x*q1.y - q1.w*q1.z)); + m11 = s*(1.0 - 2.0*q1.x*q1.x - 2.0*q1.z*q1.z); + m21 = s*(2.0*(q1.y*q1.z + q1.w*q1.x)); + + m02 = s*(2.0*(q1.x*q1.z + q1.w*q1.y)); + m12 = s*(2.0*(q1.y*q1.z - q1.w*q1.x)); + m22 = s*(1.0 - 2.0*q1.x*q1.x - 2.0*q1.y*q1.y); + + m03 = t1.x; + m13 = t1.y; + m23 = t1.z; + + m30 = 0.0; + m31 = 0.0; + m32 = 0.0; + m33 = 1.0; + + } + + /** + * Constructs a new matrix with the same values as the + * Matrix4d parameter. + * @param m1 the source matrix + */ + public Matrix4d(Matrix4d m1) + { + this.m00 = m1.m00; + this.m01 = m1.m01; + this.m02 = m1.m02; + this.m03 = m1.m03; + + this.m10 = m1.m10; + this.m11 = m1.m11; + this.m12 = m1.m12; + this.m13 = m1.m13; + + this.m20 = m1.m20; + this.m21 = m1.m21; + this.m22 = m1.m22; + this.m23 = m1.m23; + + this.m30 = m1.m30; + this.m31 = m1.m31; + this.m32 = m1.m32; + this.m33 = m1.m33; + + } + + /** + * Constructs a new matrix with the same values as the + * Matrix4f parameter. + * @param m1 the source matrix + */ + public Matrix4d(Matrix4f m1) + { + this.m00 = m1.m00; + this.m01 = m1.m01; + this.m02 = m1.m02; + this.m03 = m1.m03; + + this.m10 = m1.m10; + this.m11 = m1.m11; + this.m12 = m1.m12; + this.m13 = m1.m13; + + this.m20 = m1.m20; + this.m21 = m1.m21; + this.m22 = m1.m22; + this.m23 = m1.m23; + + this.m30 = m1.m30; + this.m31 = m1.m31; + this.m32 = m1.m32; + this.m33 = m1.m33; + + } + + /** + * Constructs and initializes a Matrix4d from the rotation matrix, + * translation, and scale values; the scale is applied only to the + * rotational components of the matrix (upper 3x3) and not to the + * translational components of the matrix. + * @param m1 the rotation matrix representing the rotational components + * @param t1 the translational components of the matrix + * @param s the scale value applied to the rotational components + */ + public Matrix4d(Matrix3f m1, Vector3d t1, double s) + { + this.m00 = m1.m00*s; + this.m01 = m1.m01*s; + this.m02 = m1.m02*s; + this.m03 = t1.x; + + this.m10 = m1.m10*s; + this.m11 = m1.m11*s; + this.m12 = m1.m12*s; + this.m13 = t1.y; + + this.m20 = m1.m20*s; + this.m21 = m1.m21*s; + this.m22 = m1.m22*s; + this.m23 = t1.z; + + this.m30 = 0.0; + this.m31 = 0.0; + this.m32 = 0.0; + this.m33 = 1.0; + + } + + /** + * Constructs and initializes a Matrix4f from the rotation matrix, + * translation, and scale values; the scale is applied only to the + * rotational components of the matrix (upper 3x3) and not to the + * translational components of the matrix. + * @param m1 the rotation matrix representing the rotational components + * @param t1 the translational components of the matrix + * @param s the scale value applied to the rotational components + */ + public Matrix4d(Matrix3d m1, Vector3d t1, double s) + { + this.m00 = m1.m00*s; + this.m01 = m1.m01*s; + this.m02 = m1.m02*s; + this.m03 = t1.x; + + this.m10 = m1.m10*s; + this.m11 = m1.m11*s; + this.m12 = m1.m12*s; + this.m13 = t1.y; + + this.m20 = m1.m20*s; + this.m21 = m1.m21*s; + this.m22 = m1.m22*s; + this.m23 = t1.z; + + this.m30 = 0.0; + this.m31 = 0.0; + this.m32 = 0.0; + this.m33 = 1.0; + + } + + /** + * Constructs and initializes a Matrix4d to all zeros. + */ + public Matrix4d() + { + this.m00 = 0.0; + this.m01 = 0.0; + this.m02 = 0.0; + this.m03 = 0.0; + + this.m10 = 0.0; + this.m11 = 0.0; + this.m12 = 0.0; + this.m13 = 0.0; + + this.m20 = 0.0; + this.m21 = 0.0; + this.m22 = 0.0; + this.m23 = 0.0; + + this.m30 = 0.0; + this.m31 = 0.0; + this.m32 = 0.0; + this.m33 = 0.0; + + } + + /** + * Returns a string that contains the values of this Matrix4d. + * @return the String representation + */ + public String toString() { + return + this.m00 + ", " + this.m01 + ", " + this.m02 + ", " + this.m03 + "\n" + + this.m10 + ", " + this.m11 + ", " + this.m12 + ", " + this.m13 + "\n" + + this.m20 + ", " + this.m21 + ", " + this.m22 + ", " + this.m23 + "\n" + + this.m30 + ", " + this.m31 + ", " + this.m32 + ", " + this.m33 + "\n"; + } + + /** + * Sets this Matrix4d to identity. + */ + public final void setIdentity() + { + this.m00 = 1.0; + this.m01 = 0.0; + this.m02 = 0.0; + this.m03 = 0.0; + + this.m10 = 0.0; + this.m11 = 1.0; + this.m12 = 0.0; + this.m13 = 0.0; + + this.m20 = 0.0; + this.m21 = 0.0; + this.m22 = 1.0; + this.m23 = 0.0; + + this.m30 = 0.0; + this.m31 = 0.0; + this.m32 = 0.0; + this.m33 = 1.0; + } + + /** + * Sets the specified element of this matrix4f 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; + case 3: + this.m03 = value; + break; + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4d0")); + } + break; + + case 1: + switch(column) + { + case 0: + this.m10 = value; + break; + case 1: + this.m11 = value; + break; + case 2: + this.m12 = value; + break; + case 3: + this.m13 = value; + break; + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4d0")); + } + break; + + case 2: + switch(column) + { + case 0: + this.m20 = value; + break; + case 1: + this.m21 = value; + break; + case 2: + this.m22 = value; + break; + case 3: + this.m23 = value; + break; + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4d0")); + } + break; + + case 3: + switch(column) + { + case 0: + this.m30 = value; + break; + case 1: + this.m31 = value; + break; + case 2: + this.m32 = value; + break; + case 3: + this.m33 = value; + break; + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4d0")); + } + break; + + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4d0")); + } + } + + /** + * Retrieves the value at the specified row and column of this 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); + case 3: + return(this.m03); + default: + break; + } + break; + case 1: + switch(column) + { + case 0: + return(this.m10); + case 1: + return(this.m11); + case 2: + return(this.m12); + case 3: + return(this.m13); + default: + break; + } + break; + + case 2: + switch(column) + { + case 0: + return(this.m20); + case 1: + return(this.m21); + case 2: + return(this.m22); + case 3: + return(this.m23); + default: + break; + } + break; + + case 3: + switch(column) + { + case 0: + return(this.m30); + case 1: + return(this.m31); + case 2: + return(this.m32); + case 3: + return(this.m33); + default: + break; + } + break; + + default: + break; + } + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4d1")); + } + + /** + * 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, Vector4d v) { + if( row == 0 ) { + v.x = m00; + v.y = m01; + v.z = m02; + v.w = m03; + } else if(row == 1) { + v.x = m10; + v.y = m11; + v.z = m12; + v.w = m13; + } else if(row == 2) { + v.x = m20; + v.y = m21; + v.z = m22; + v.w = m23; + } else if(row == 3) { + v.x = m30; + v.y = m31; + v.z = m32; + v.w = m33; + } else { + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4d2")); + } + } + + + /** + * 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; + v[3] = m03; + } else if(row == 1) { + v[0] = m10; + v[1] = m11; + v[2] = m12; + v[3] = m13; + } else if(row == 2) { + v[0] = m20; + v[1] = m21; + v[2] = m22; + v[3] = m23; + } else if(row == 3) { + v[0] = m30; + v[1] = m31; + v[2] = m32; + v[3] = m33; + } else { + + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4d2")); + } + } + + + + /** + * 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 column values will be copied + */ + public final void getColumn(int column, Vector4d v) { + if( column == 0 ) { + v.x = m00; + v.y = m10; + v.z = m20; + v.w = m30; + } else if(column == 1) { + v.x = m01; + v.y = m11; + v.z = m21; + v.w = m31; + } else if(column == 2) { + v.x = m02; + v.y = m12; + v.z = m22; + v.w = m32; + } else if(column == 3) { + v.x = m03; + v.y = m13; + v.z = m23; + v.w = m33; + } else { + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4d3")); + + } + + } + + + + /** + * 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 column values will be copied + */ + public final void getColumn(int column, double v[]) { + if( column == 0 ) { + v[0] = m00; + v[1] = m10; + v[2] = m20; + v[3] = m30; + } else if(column == 1) { + v[0] = m01; + v[1] = m11; + v[2] = m21; + v[3] = m31; + } else if(column == 2) { + v[0] = m02; + v[1] = m12; + v[2] = m22; + v[3] = m32; + } else if(column == 3) { + v[0] = m03; + v[1] = m13; + v[2] = m23; + v[3] = m33; + } else { + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4d3")); + + } + + } + + + /** + * Performs an SVD normalization of this matrix in order to acquire + * the normalized rotational component; the values are placed into + * the Matrix3d parameter. + * @param m1 the matrix into which the rotational component is placed + */ + public final void get(Matrix3d m1) + { + + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + getScaleRotate( tmp_scale, tmp_rot ); + + m1.m00 = tmp_rot[0]; + m1.m01 = tmp_rot[1]; + m1.m02 = tmp_rot[2]; + + m1.m10 = tmp_rot[3]; + m1.m11 = tmp_rot[4]; + m1.m12 = tmp_rot[5]; + + m1.m20 = tmp_rot[6]; + m1.m21 = tmp_rot[7]; + m1.m22 = tmp_rot[8]; + + } + + + /** + * Performs an SVD normalization of this matrix in order to acquire + * the normalized rotational component; the values are placed into + * the Matrix3f parameter. + * @param m1 the matrix into which the rotational component is placed + */ + public final void get(Matrix3f m1) + { + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + + getScaleRotate( tmp_scale, tmp_rot ); + + m1.m00 = (float)tmp_rot[0]; + m1.m01 = (float)tmp_rot[1]; + m1.m02 = (float)tmp_rot[2]; + + m1.m10 = (float)tmp_rot[3]; + m1.m11 = (float)tmp_rot[4]; + m1.m12 = (float)tmp_rot[5]; + + m1.m20 = (float)tmp_rot[6]; + m1.m21 = (float)tmp_rot[7]; + m1.m22 = (float)tmp_rot[8]; + } + + /** + * Performs an SVD normalization of this matrix to calculate + * the rotation as a 3x3 matrix, the translation, and the scale. + * None of the matrix values are modified. + * @param m1 the normalized matrix representing the rotation + * @param t1 the translation component + * @return the scale component of this transform + */ + public final double get(Matrix3d m1, Vector3d t1) + { + + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + getScaleRotate( tmp_scale, tmp_rot ); + + m1.m00 = tmp_rot[0]; + m1.m01 = tmp_rot[1]; + m1.m02 = tmp_rot[2]; + + m1.m10 = tmp_rot[3]; + m1.m11 = tmp_rot[4]; + m1.m12 = tmp_rot[5]; + + m1.m20 = tmp_rot[6]; + m1.m21 = tmp_rot[7]; + m1.m22 = tmp_rot[8]; + + t1.x = m03; + t1.y = m13; + t1.z = m23; + + return( Matrix3d.max3( tmp_scale )); + + } + + /** + * Performs an SVD normalization of this matrix to calculate + * the rotation as a 3x3 matrix, the translation, and the scale. + * None of the matrix values are modified. + * @param m1 the normalized matrix representing the rotation + * @param t1 the translation component + * @return the scale component of this transform + */ + public final double get(Matrix3f m1, Vector3d t1){ + + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + getScaleRotate( tmp_scale, tmp_rot ); + + m1.m00 = (float)tmp_rot[0]; + m1.m01 = (float)tmp_rot[1]; + m1.m02 = (float)tmp_rot[2]; + + m1.m10 = (float)tmp_rot[3]; + m1.m11 = (float)tmp_rot[4]; + m1.m12 = (float)tmp_rot[5]; + + m1.m20 = (float)tmp_rot[6]; + m1.m21 = (float)tmp_rot[7]; + m1.m22 = (float)tmp_rot[8]; + + t1.x = m03; + t1.y = m13; + t1.z = m23; + + return( Matrix3d.max3( tmp_scale )); + + } + + /** + * Performs an SVD normalization of this matrix in order to acquire + * the normalized rotational component; the values are placed into + * the Quat4f parameter. + * @param q1 quaternion into which the rotation component is placed + */ + public final void get(Quat4f q1) + { + + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + getScaleRotate( tmp_scale, tmp_rot ); + + double ww; + + ww = 0.25*(1.0 + tmp_rot[0] + tmp_rot[4] + tmp_rot[8]); + if(!((ww<0?-ww:ww) < 1.0e-30)) { + q1.w = (float)Math.sqrt(ww); + ww = 0.25/q1.w; + q1.x = (float)((tmp_rot[7] - tmp_rot[5])*ww); + q1.y = (float)((tmp_rot[2] - tmp_rot[6])*ww); + q1.z = (float)((tmp_rot[3] - tmp_rot[1])*ww); + return; + } + + q1.w = 0.0f; + ww = -0.5*(tmp_rot[4] + tmp_rot[8]); + if(!((ww<0?-ww:ww) < 1.0e-30)) { + q1.x = (float)Math.sqrt(ww); + ww = 0.5/q1.x; + q1.y = (float)(tmp_rot[3]*ww); + q1.z = (float)(tmp_rot[6]*ww); + return; + } + + q1.x = 0.0f; + ww = 0.5*(1.0 - tmp_rot[8]); + if(!((ww<0?-ww:ww) < 1.0e-30)) { + q1.y = (float)(Math.sqrt(ww)); + q1.z = (float)(tmp_rot[7]/(2.0*q1.y)); + return; + } + + q1.y = 0.0f; + q1.z = 1.0f; + + } + + /** + * Performs an SVD normalization of q1 matrix in order to acquire + * the normalized rotational component; the values are placed into + * the Quat4d parameter. + * @param q1 the quaternion into which the rotation component is placed + */ + public final void get(Quat4d q1) + { + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + + getScaleRotate( tmp_scale, tmp_rot ); + + double ww; + + ww = 0.25*(1.0 + tmp_rot[0] + tmp_rot[4] + tmp_rot[8]); + if(!((ww<0?-ww:ww) < 1.0e-30)) { + q1.w = Math.sqrt(ww); + ww = 0.25/q1.w; + q1.x = (tmp_rot[7] - tmp_rot[5])*ww; + q1.y = (tmp_rot[2] - tmp_rot[6])*ww; + q1.z = (tmp_rot[3] - tmp_rot[1])*ww; + return; + } + + q1.w = 0.0f; + ww = -0.5*(tmp_rot[4] + tmp_rot[8]); + if(!((ww<0?-ww:ww) < 1.0e-30)) { + q1.x = Math.sqrt(ww); + ww = 0.5/q1.x; + q1.y = tmp_rot[3]*ww; + q1.z = tmp_rot[6]*ww; + return; + } + + q1.x = 0.0; + ww = 0.5*(1.0 - tmp_rot[8]); + if(!((ww<0?-ww:ww) < 1.0e-30)) { + q1.y = Math.sqrt(ww); + q1.z = tmp_rot[7]/(2.0*q1.y); + return; + } + + q1.y = 0.0; + q1.z = 1.0; + } + + /** + * Retrieves the translational components of this matrix. + * @param trans the vector that will receive the translational component + */ + public final void get(Vector3d trans) + { + trans.x = m03; + trans.y = m13; + trans.z = m23; + } + + /** + * Gets the upper 3x3 values of this matrix and places them into + * the matrix m1. + * @param m1 the matrix that will hold the values + */ + public final void getRotationScale(Matrix3f m1) + { + m1.m00 = (float)m00; m1.m01 = (float)m01; m1.m02 = (float)m02; + m1.m10 = (float)m10; m1.m11 = (float)m11; m1.m12 = (float)m12; + m1.m20 = (float)m20; m1.m21 = (float)m21; m1.m22 = (float)m22; + } + + /** + * Gets the upper 3x3 values of this matrix and places them into + * the matrix m1. + * @param m1 the matrix that will hold the values + */ + public final void getRotationScale(Matrix3d m1) + { + m1.m00 = m00; m1.m01 = m01; m1.m02 = m02; + m1.m10 = m10; m1.m11 = m11; m1.m12 = m12; + m1.m20 = m20; m1.m21 = m21; m1.m22 = m22; + } + + /** + * 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_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + getScaleRotate( tmp_scale, tmp_rot ); + + return( Matrix3d.max3( tmp_scale )); + + } + + /** + * Replaces the upper 3x3 matrix values of this matrix with the + * values in the matrix m1. + * @param m1 the matrix that will be the new upper 3x3 + */ + public final void setRotationScale(Matrix3d m1) + { + m00 = m1.m00; m01 = m1.m01; m02 = m1.m02; + m10 = m1.m10; m11 = m1.m11; m12 = m1.m12; + m20 = m1.m20; m21 = m1.m21; m22 = m1.m22; + } + + /** + * Replaces the upper 3x3 matrix values of this matrix with the + * values in the matrix m1. + * @param m1 the matrix that will be the new upper 3x3 + */ + public final void setRotationScale(Matrix3f m1) + { + m00 = m1.m00; m01 = m1.m01; m02 = m1.m02; + m10 = m1.m10; m11 = m1.m11; m12 = m1.m12; + m20 = m1.m20; m21 = m1.m21; m22 = m1.m22; + } + + /** + * Sets the scale component of the current matrix by factoring + * out the current scale (by doing an SVD) from the rotational + * component 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 ); + + m00 = tmp_rot[0]*scale; + m01 = tmp_rot[1]*scale; + m02 = tmp_rot[2]*scale; + + m10 = tmp_rot[3]*scale; + m11 = tmp_rot[4]*scale; + m12 = tmp_rot[5]*scale; + + m20 = tmp_rot[6]*scale; + m21 = tmp_rot[7]*scale; + m22 = tmp_rot[8]*scale; + + } + + /** + * Sets the specified row of this matrix4d to the four 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 + * @param w the fourth column element + */ + public final void setRow(int row, double x, double y, double z, double w) + { + switch (row) { + case 0: + this.m00 = x; + this.m01 = y; + this.m02 = z; + this.m03 = w; + break; + + case 1: + this.m10 = x; + this.m11 = y; + this.m12 = z; + this.m13 = w; + break; + + case 2: + this.m20 = x; + this.m21 = y; + this.m22 = z; + this.m23 = w; + break; + + case 3: + this.m30 = x; + this.m31 = y; + this.m32 = z; + this.m33 = w; + break; + + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4d4")); + + } + } + + /** + * Sets the specified row of this matrix4d 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, Vector4d v) + { + switch (row) { + case 0: + this.m00 = v.x; + this.m01 = v.y; + this.m02 = v.z; + this.m03 = v.w; + break; + + case 1: + this.m10 = v.x; + this.m11 = v.y; + this.m12 = v.z; + this.m13 = v.w; + break; + + case 2: + this.m20 = v.x; + this.m21 = v.y; + this.m22 = v.z; + this.m23 = v.w; + break; + + case 3: + this.m30 = v.x; + this.m31 = v.y; + this.m32 = v.z; + this.m33 = v.w; + break; + + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4d4")); + } + } + + /** + * Sets the specified row of this matrix4d to the four 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]; + this.m03 = v[3]; + break; + + case 1: + this.m10 = v[0]; + this.m11 = v[1]; + this.m12 = v[2]; + this.m13 = v[3]; + break; + + case 2: + this.m20 = v[0]; + this.m21 = v[1]; + this.m22 = v[2]; + this.m23 = v[3]; + break; + + case 3: + this.m30 = v[0]; + this.m31 = v[1]; + this.m32 = v[2]; + this.m33 = v[3]; + break; + + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4d4")); + } + } + + /** + * Sets the specified column of this matrix4d to the four 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 + * @param w the fourth row element + */ + public final void setColumn(int column, double x, double y, double z, double w) + { + switch (column) { + case 0: + this.m00 = x; + this.m10 = y; + this.m20 = z; + this.m30 = w; + break; + + case 1: + this.m01 = x; + this.m11 = y; + this.m21 = z; + this.m31 = w; + break; + + case 2: + this.m02 = x; + this.m12 = y; + this.m22 = z; + this.m32 = w; + break; + + case 3: + this.m03 = x; + this.m13 = y; + this.m23 = z; + this.m33 = w; + break; + + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4d7")); + } + } + + /** + * Sets the specified column of this matrix4d 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, Vector4d v) + { + switch (column) { + case 0: + this.m00 = v.x; + this.m10 = v.y; + this.m20 = v.z; + this.m30 = v.w; + break; + + case 1: + this.m01 = v.x; + this.m11 = v.y; + this.m21 = v.z; + this.m31 = v.w; + break; + + case 2: + this.m02 = v.x; + this.m12 = v.y; + this.m22 = v.z; + this.m32 = v.w; + break; + + case 3: + this.m03 = v.x; + this.m13 = v.y; + this.m23 = v.z; + this.m33 = v.w; + break; + + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4d7")); + } + } + + /** + * Sets the specified column of this matrix4d to the four 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]; + this.m30 = v[3]; + break; + + case 1: + this.m01 = v[0]; + this.m11 = v[1]; + this.m21 = v[2]; + this.m31 = v[3]; + break; + + case 2: + this.m02 = v[0]; + this.m12 = v[1]; + this.m22 = v[2]; + this.m32 = v[3]; + break; + + case 3: + this.m03 = v[0]; + this.m13 = v[1]; + this.m23 = v[2]; + this.m33 = v[3]; + break; + + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4d7")); + } + } + + /** + * 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; + m03 += scalar; + m10 += scalar; + m11 += scalar; + m12 += scalar; + m13 += scalar; + m20 += scalar; + m21 += scalar; + m22 += scalar; + m23 += scalar; + m30 += scalar; + m31 += scalar; + m32 += scalar; + m33 += 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, Matrix4d m1) + { + this.m00 = m1.m00 + scalar; + this.m01 = m1.m01 + scalar; + this.m02 = m1.m02 + scalar; + this.m03 = m1.m03 + scalar; + this.m10 = m1.m10 + scalar; + this.m11 = m1.m11 + scalar; + this.m12 = m1.m12 + scalar; + this.m13 = m1.m13 + scalar; + this.m20 = m1.m20 + scalar; + this.m21 = m1.m21 + scalar; + this.m22 = m1.m22 + scalar; + this.m23 = m1.m23 + scalar; + this.m30 = m1.m30 + scalar; + this.m31 = m1.m31 + scalar; + this.m32 = m1.m32 + scalar; + this.m33 = m1.m33 + 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(Matrix4d m1, Matrix4d m2) + { + this.m00 = m1.m00 + m2.m00; + this.m01 = m1.m01 + m2.m01; + this.m02 = m1.m02 + m2.m02; + this.m03 = m1.m03 + m2.m03; + + this.m10 = m1.m10 + m2.m10; + this.m11 = m1.m11 + m2.m11; + this.m12 = m1.m12 + m2.m12; + this.m13 = m1.m13 + m2.m13; + + this.m20 = m1.m20 + m2.m20; + this.m21 = m1.m21 + m2.m21; + this.m22 = m1.m22 + m2.m22; + this.m23 = m1.m23 + m2.m23; + + this.m30 = m1.m30 + m2.m30; + this.m31 = m1.m31 + m2.m31; + this.m32 = m1.m32 + m2.m32; + this.m33 = m1.m33 + m2.m33; + } + + /** + * Sets the value of this matrix to sum of itself and matrix m1. + * @param m1 the other matrix + */ + public final void add(Matrix4d m1) + { + this.m00 += m1.m00; + this.m01 += m1.m01; + this.m02 += m1.m02; + this.m03 += m1.m03; + + this.m10 += m1.m10; + this.m11 += m1.m11; + this.m12 += m1.m12; + this.m13 += m1.m13; + + this.m20 += m1.m20; + this.m21 += m1.m21; + this.m22 += m1.m22; + this.m23 += m1.m23; + + this.m30 += m1.m30; + this.m31 += m1.m31; + this.m32 += m1.m32; + this.m33 += m1.m33; + } + + /** + * 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(Matrix4d m1, Matrix4d m2) + { + this.m00 = m1.m00 - m2.m00; + this.m01 = m1.m01 - m2.m01; + this.m02 = m1.m02 - m2.m02; + this.m03 = m1.m03 - m2.m03; + + this.m10 = m1.m10 - m2.m10; + this.m11 = m1.m11 - m2.m11; + this.m12 = m1.m12 - m2.m12; + this.m13 = m1.m13 - m2.m13; + + this.m20 = m1.m20 - m2.m20; + this.m21 = m1.m21 - m2.m21; + this.m22 = m1.m22 - m2.m22; + this.m23 = m1.m23 - m2.m23; + + this.m30 = m1.m30 - m2.m30; + this.m31 = m1.m31 - m2.m31; + this.m32 = m1.m32 - m2.m32; + this.m33 = m1.m33 - m2.m33; + } + + + /** + * 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(Matrix4d m1) + { + this.m00 -= m1.m00; + this.m01 -= m1.m01; + this.m02 -= m1.m02; + this.m03 -= m1.m03; + + this.m10 -= m1.m10; + this.m11 -= m1.m11; + this.m12 -= m1.m12; + this.m13 -= m1.m13; + + this.m20 -= m1.m20; + this.m21 -= m1.m21; + this.m22 -= m1.m22; + this.m23 -= m1.m23; + + this.m30 -= m1.m30; + this.m31 -= m1.m31; + this.m32 -= m1.m32; + this.m33 -= m1.m33; + } + + /** + * 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.m30; + this.m30 = this.m03; + this.m03 = temp; + + temp = this.m21; + this.m21 = this.m12; + this.m12 = temp; + + temp = this.m31; + this.m31 = this.m13; + this.m13 = temp; + + temp = this.m32; + this.m32 = this.m23; + this.m23 = 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(Matrix4d m1) + { + if (this != m1) { + this.m00 = m1.m00; + this.m01 = m1.m10; + this.m02 = m1.m20; + this.m03 = m1.m30; + + this.m10 = m1.m01; + this.m11 = m1.m11; + this.m12 = m1.m21; + this.m13 = m1.m31; + + this.m20 = m1.m02; + this.m21 = m1.m12; + this.m22 = m1.m22; + this.m23 = m1.m32; + + this.m30 = m1.m03; + this.m31 = m1.m13; + this.m32 = m1.m23; + this.m33 = m1.m33; + } else + this.transpose(); + } + + /** + * Sets the values in this Matrix4d equal to the row-major + * array parameter (ie, the first four elements of the + * array will be copied into the first row of this matrix, etc.). + * @param m the double precision array of length 16 + */ + public final void set(double[] m) + { + m00 = m[0]; + m01 = m[1]; + m02 = m[2]; + m03 = m[3]; + m10 = m[4]; + m11 = m[5]; + m12 = m[6]; + m13 = m[7]; + m20 = m[8]; + m21 = m[9]; + m22 = m[10]; + m23 = m[11]; + m30 = m[12]; + m31 = m[13]; + m32 = m[14]; + m33 = m[15]; + } + + /** + * Sets the rotational component (upper 3x3) of this matrix to the + * matrix values in the single precision Matrix3f argument; the other + * elements of this matrix are initialized as if this were an identity + * matrix (i.e., affine matrix with no translational component). + * @param m1 the double precision 3x3 matrix + */ + public final void set(Matrix3f m1) + { + m00 = m1.m00; m01 = m1.m01; m02 = m1.m02; m03 = 0.0; + m10 = m1.m10; m11 = m1.m11; m12 = m1.m12; m13 = 0.0; + m20 = m1.m20; m21 = m1.m21; m22 = m1.m22; m23 = 0.0; + m30 = 0.0; m31 = 0.0 ; m32 = 0.0 ; m33 = 1.0; + } + + /** + * Sets the rotational component (upper 3x3) of this matrix to the + * matrix values in the double precision Matrix3d argument; the other + * elements of this matrix are initialized as if this were an identity + * matrix (i.e., affine matrix with no translational component). + * @param m1 the double precision 3x3 matrix + */ + public final void set(Matrix3d m1) + { + m00 = m1.m00; m01 = m1.m01; m02 = m1.m02; m03 = 0.0; + m10 = m1.m10; m11 = m1.m11; m12 = m1.m12; m13 = 0.0; + m20 = m1.m20; m21 = m1.m21; m22 = m1.m22; m23 = 0.0; + m30 = 0.0; m31 = 0.0 ; m32 = 0.0 ; m33 = 1.0; + } + + /** + * 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); + + this.m03 = 0.0; + this.m13 = 0.0; + this.m23 = 0.0; + + this.m30 = 0.0; + this.m31 = 0.0; + this.m32 = 0.0; + this.m33 = 1.0; + } + + /** + * 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; + } + + m03 = 0.0; + m13 = 0.0; + m23 = 0.0; + + m30 = 0.0; + m31 = 0.0; + m32 = 0.0; + m33 = 1.0; + } + + /** + * 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); + + this.m03 = 0.0; + this.m13 = 0.0; + this.m23 = 0.0; + + this.m30 = 0.0; + this.m31 = 0.0; + this.m32 = 0.0; + this.m33 = 1.0; + } + + /** + * 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((double)a1.angle); + double cosTheta = Math.cos((double)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; + } + m03 = 0.0; + m13 = 0.0; + m23 = 0.0; + + m30 = 0.0; + m31 = 0.0; + m32 = 0.0; + m33 = 1.0; + } + + /** + * Sets the value of this matrix from the rotation expressed + * by the quaternion q1, the translation t1, and the scale s. + * @param q1 the rotation expressed as a quaternion + * @param t1 the translation + * @param s the scale value + */ + public final void set(Quat4d q1, Vector3d t1, double s) + { + this.m00 = s*(1.0 - 2.0*q1.y*q1.y - 2.0*q1.z*q1.z); + this.m10 = s*(2.0*(q1.x*q1.y + q1.w*q1.z)); + this.m20 = s*(2.0*(q1.x*q1.z - q1.w*q1.y)); + + this.m01 = s*(2.0*(q1.x*q1.y - q1.w*q1.z)); + this.m11 = s*(1.0 - 2.0*q1.x*q1.x - 2.0*q1.z*q1.z); + this.m21 = s*(2.0*(q1.y*q1.z + q1.w*q1.x)); + + this.m02 = s*(2.0*(q1.x*q1.z + q1.w*q1.y)); + this.m12 = s*(2.0*(q1.y*q1.z - q1.w*q1.x)); + this.m22 = s*(1.0 - 2.0*q1.x*q1.x - 2.0*q1.y*q1.y); + + this.m03 = t1.x; + this.m13 = t1.y; + this.m23 = t1.z; + + this.m30 = 0.0; + this.m31 = 0.0; + this.m32 = 0.0; + this.m33 = 1.0; + } + + /** + * Sets the value of this matrix from the rotation expressed + * by the quaternion q1, the translation t1, and the scale s. + * @param q1 the rotation expressed as a quaternion + * @param t1 the translation + * @param s the scale value + */ + public final void set(Quat4f q1, Vector3d t1, double s) + { + this.m00 = s*(1.0 - 2.0*q1.y*q1.y - 2.0*q1.z*q1.z); + this.m10 = s*(2.0*(q1.x*q1.y + q1.w*q1.z)); + this.m20 = s*(2.0*(q1.x*q1.z - q1.w*q1.y)); + + this.m01 = s*(2.0*(q1.x*q1.y - q1.w*q1.z)); + this.m11 = s*(1.0 - 2.0*q1.x*q1.x - 2.0*q1.z*q1.z); + this.m21 = s*(2.0*(q1.y*q1.z + q1.w*q1.x)); + + this.m02 = s*(2.0*(q1.x*q1.z + q1.w*q1.y)); + this.m12 = s*(2.0*(q1.y*q1.z - q1.w*q1.x)); + this.m22 = s*(1.0 - 2.0*q1.x*q1.x - 2.0*q1.y*q1.y); + + this.m03 = t1.x; + this.m13 = t1.y; + this.m23 = t1.z; + + this.m30 = 0.0; + this.m31 = 0.0; + this.m32 = 0.0; + this.m33 = 1.0; + } + + /** + * Sets the value of this matrix from the rotation expressed + * by the quaternion q1, the translation t1, and the scale s. + * @param q1 the rotation expressed as a quaternion + * @param t1 the translation + * @param s the scale value + */ + public final void set(Quat4f q1, Vector3f t1, float s) + { + this.m00 = s*(1.0 - 2.0*q1.y*q1.y - 2.0*q1.z*q1.z); + this.m10 = s*(2.0*(q1.x*q1.y + q1.w*q1.z)); + this.m20 = s*(2.0*(q1.x*q1.z - q1.w*q1.y)); + + this.m01 = s*(2.0*(q1.x*q1.y - q1.w*q1.z)); + this.m11 = s*(1.0 - 2.0*q1.x*q1.x - 2.0*q1.z*q1.z); + this.m21 = s*(2.0*(q1.y*q1.z + q1.w*q1.x)); + + this.m02 = s*(2.0*(q1.x*q1.z + q1.w*q1.y)); + this.m12 = s*(2.0*(q1.y*q1.z - q1.w*q1.x)); + this.m22 = s*(1.0 - 2.0*q1.x*q1.x - 2.0*q1.y*q1.y); + + this.m03 = t1.x; + this.m13 = t1.y; + this.m23 = t1.z; + + this.m30 = 0.0; + this.m31 = 0.0; + this.m32 = 0.0; + this.m33 = 1.0; + } + + /** + * Sets the value of this matrix to a copy of the + * passed matrix m1. + * @param m1 the matrix4f + */ + public final void set(Matrix4f m1) + { + this.m00 = m1.m00; + this.m01 = m1.m01; + this.m02 = m1.m02; + this.m03 = m1.m03; + + this.m10 = m1.m10; + this.m11 = m1.m11; + this.m12 = m1.m12; + this.m13 = m1.m13; + + this.m20 = m1.m20; + this.m21 = m1.m21; + this.m22 = m1.m22; + this.m23 = m1.m23; + + this.m30 = m1.m30; + this.m31 = m1.m31; + this.m32 = m1.m32; + this.m33 = m1.m33; + } + + /** + * Sets the value of this matrix to a copy of the + * passed matrix m1. + * @param m1 the matrix to be copied + */ + public final void set(Matrix4d m1) + { + this.m00 = m1.m00; + this.m01 = m1.m01; + this.m02 = m1.m02; + this.m03 = m1.m03; + + this.m10 = m1.m10; + this.m11 = m1.m11; + this.m12 = m1.m12; + this.m13 = m1.m13; + + this.m20 = m1.m20; + this.m21 = m1.m21; + this.m22 = m1.m22; + this.m23 = m1.m23; + + this.m30 = m1.m30; + this.m31 = m1.m31; + this.m32 = m1.m32; + this.m33 = m1.m33; + } + + /** + * Sets the value of this matrix to the matrix inverse + * of the passed (user declared) matrix m1. + * @param m1 the matrix to be inverted + */ + public final void invert(Matrix4d 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. + */ + final void invertGeneral(Matrix4d m1) { + double result[] = new double[16]; + int row_perm[] = new int[4]; + int i, r, c; + + // Use LU decomposition and backsubstitution code specifically + // for floating-point 4x4 matrices. + double[] tmp = new double[16]; // scratch matrix + // Copy source matrix to t1tmp + tmp[0] = m1.m00; + tmp[1] = m1.m01; + tmp[2] = m1.m02; + tmp[3] = m1.m03; + + tmp[4] = m1.m10; + tmp[5] = m1.m11; + tmp[6] = m1.m12; + tmp[7] = m1.m13; + + tmp[8] = m1.m20; + tmp[9] = m1.m21; + tmp[10] = m1.m22; + tmp[11] = m1.m23; + + tmp[12] = m1.m30; + tmp[13] = m1.m31; + tmp[14] = m1.m32; + tmp[15] = m1.m33; + + // Calculate LU decomposition: Is the matrix singular? + if (!luDecomposition(tmp, row_perm)) { + // Matrix has no inverse + throw new SingularMatrixException(VecMathI18N.getString("Matrix4d10")); + } + + // Perform back substitution on the identity matrix + for(i=0;i<16;i++) result[i] = 0.0; + result[0] = 1.0; result[5] = 1.0; result[10] = 1.0; result[15] = 1.0; + luBacksubstitution(tmp, row_perm, result); + + this.m00 = result[0]; + this.m01 = result[1]; + this.m02 = result[2]; + this.m03 = result[3]; + + this.m10 = result[4]; + this.m11 = result[5]; + this.m12 = result[6]; + this.m13 = result[7]; + + this.m20 = result[8]; + this.m21 = result[9]; + this.m22 = result[10]; + this.m23 = result[11]; + + this.m30 = result[12]; + this.m31 = result[13]; + this.m32 = result[14]; + this.m33 = result[15]; + + } + + /** + * Given a 4x4 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[4]" 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 4x4 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[4]; + + // 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 = 4; + while (i-- != 0) { + big = 0.0; + + // For each column, find the largest element in the row + j = 4; + 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 < 4; 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 + (4*i) + j; + sum = matrix0[target]; + k = i; + p1 = mtx + (4*i); + p2 = mtx + j; + while (k-- != 0) { + sum -= matrix0[p1] * matrix0[p2]; + p1++; + p2 += 4; + } + 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 < 4; i++) { + target = mtx + (4*i) + j; + sum = matrix0[target]; + k = j; + p1 = mtx + (4*i); + p2 = mtx + j; + while (k-- != 0) { + sum -= matrix0[p1] * matrix0[p2]; + p1++; + p2 += 4; + } + 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("Matrix4d11")); + } + + // Is a row exchange necessary? + if (j != imax) { + // Yes: exchange rows + k = 4; + p1 = mtx + (4*imax); + p2 = mtx + (4*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 + (4*j) + j)] == 0.0) { + return false; + } + + // Divide elements of lower diagonal matrix L by pivot + if (j != (4-1)) { + temp = 1.0 / (matrix0[(mtx + (4*j) + j)]); + target = mtx + (4*(j+1)) + j; + i = 3 - j; + while (i-- != 0) { + matrix0[target] *= temp; + target += 4; + } + } + } + } + + return true; + } + + /** + * Solves a set of linear equations. The input parameters "matrix1", + * and "row_perm" come from luDecompostionD4x4 and do not change + * here. The parameter "matrix2" is a set of column vectors assembled + * into a 4x4 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 < 4; k++) { + // cv = &(matrix2[0][k]); + cv = k; + ii = -1; + + // Forward substitution + for (i = 0; i < 4; i++) { + double sum; + + ip = row_perm[rp+i]; + sum = matrix2[cv+4*ip]; + matrix2[cv+4*ip] = matrix2[cv+4*i]; + if (ii >= 0) { + // rv = &(matrix1[i][0]); + rv = i*4; + for (j = ii; j <= i-1; j++) { + sum -= matrix1[rv+j] * matrix2[cv+4*j]; + } + } + else if (sum != 0.0) { + ii = i; + } + matrix2[cv+4*i] = sum; + } + + // Backsubstitution + // rv = &(matrix1[3][0]); + rv = 3*4; + matrix2[cv+4*3] /= matrix1[rv+3]; + + rv -= 4; + matrix2[cv+4*2] = (matrix2[cv+4*2] - + matrix1[rv+3] * matrix2[cv+4*3]) / matrix1[rv+2]; + + rv -= 4; + matrix2[cv+4*1] = (matrix2[cv+4*1] - + matrix1[rv+2] * matrix2[cv+4*2] - + matrix1[rv+3] * matrix2[cv+4*3]) / matrix1[rv+1]; + + rv -= 4; + matrix2[cv+4*0] = (matrix2[cv+4*0] - + matrix1[rv+1] * matrix2[cv+4*1] - + matrix1[rv+2] * matrix2[cv+4*2] - + matrix1[rv+3] * matrix2[cv+4*3]) / matrix1[rv+0]; + } + } + + /** + * Computes the determinant of this matrix. + * @return the determinant of the matrix + */ + public final double determinant() + { + double det; + + // cofactor exapainsion along first row + + det = m00*(m11*m22*m33+ m12*m23*m31 + m13*m21*m32 + - m13*m22*m31 -m11*m23*m32 - m12*m21*m33); + det -= m01*(m10*m22*m33+ m12*m23*m30 + m13*m20*m32 + - m13*m22*m30 -m10*m23*m32 - m12*m20*m33); + det += m02*(m10*m21*m33+ m11*m23*m30 + m13*m20*m31 + - m13*m21*m30 -m10*m23*m31 - m11*m20*m33); + det -= m03*(m10*m21*m32+ m11*m22*m30 + m12*m20*m31 + - m12*m21*m30 -m10*m22*m31 - m11*m20*m32); + + return( det ); + } + + /** + * 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.m03 = 0.0; + + this.m10 = 0.0; + this.m11 = scale; + this.m12 = 0.0; + this.m13 = 0.0; + + this.m20 = 0.0; + this.m21 = 0.0; + this.m22 = scale; + this.m23 = 0.0; + + this.m30 = 0.0; + this.m31 = 0.0; + this.m32 = 0.0; + this.m33 = 1.0; + } + + /** + * Sets the value of this matrix to a translate matrix by the + * passed translation value. + * @param v1 the translation amount + */ + public final void set(Vector3d v1) + { + this.m00 = 1.0; + this.m01 = 0.0; + this.m02 = 0.0; + this.m03 = v1.x; + + this.m10 = 0.0; + this.m11 = 1.0; + this.m12 = 0.0; + this.m13 = v1.y; + + this.m20 = 0.0; + this.m21 = 0.0; + this.m22 = 1.0; + this.m23 = v1.z; + + this.m30 = 0.0; + this.m31 = 0.0; + this.m32 = 0.0; + this.m33 = 1.0; + } + + /** + * Sets the value of this transform to a scale and translation matrix; + * the scale is not applied to the translation and all of the matrix + * values are modified. + * @param scale the scale factor for the matrix + * @param v1 the translation amount + */ + public final void set(double scale, Vector3d v1) + { + this.m00 = scale; + this.m01 = 0.0; + this.m02 = 0.0; + this.m03 = v1.x; + + this.m10 = 0.0; + this.m11 = scale; + this.m12 = 0.0; + this.m13 = v1.y; + + this.m20 = 0.0; + this.m21 = 0.0; + this.m22 = scale; + this.m23 = v1.z; + + this.m30 = 0.0; + this.m31 = 0.0; + this.m32 = 0.0; + this.m33 = 1.0; + } + + /** + * Sets the value of this transform to a scale and translation matrix; + * the translation is scaled by the scale factor and all of the matrix + * values are modified. + * @param v1 the translation amount + * @param scale the scale factor for the matrix + */ + public final void set(Vector3d v1, double scale) + { + this.m00 = scale; + this.m01 = 0.0; + this.m02 = 0.0; + this.m03 = scale*v1.x; + + this.m10 = 0.0; + this.m11 = scale; + this.m12 = 0.0; + this.m13 = scale*v1.y; + + this.m20 = 0.0; + this.m21 = 0.0; + this.m22 = scale; + this.m23 = scale*v1.z; + + this.m30 = 0.0; + this.m31 = 0.0; + this.m32 = 0.0; + this.m33 = 1.0; + } + + /** + * Sets the value of this matrix from the rotation expressed by + * the rotation matrix m1, the translation t1, and the scale factor. + * The translation is not modified by the scale. + * @param m1 the rotation component + * @param t1 the translation component + * @param scale the scale component + */ + public final void set(Matrix3f m1, Vector3f t1, float scale) + { + this.m00 = m1.m00*scale; + this.m01 = m1.m01*scale; + this.m02 = m1.m02*scale; + this.m03 = t1.x; + + this.m10 = m1.m10*scale; + this.m11 = m1.m11*scale; + this.m12 = m1.m12*scale; + this.m13 = t1.y; + + this.m20 = m1.m20*scale; + this.m21 = m1.m21*scale; + this.m22 = m1.m22*scale; + this.m23 = t1.z; + + this.m30 = 0.0; + this.m31 = 0.0; + this.m32 = 0.0; + this.m33 = 1.0; + } + + + /** + * Sets the value of this matrix from the rotation expressed by + * the rotation matrix m1, the translation t1, and the scale factor. + * The translation is not modified by the scale. + * @param m1 the rotation component + * @param t1 the translation component + * @param scale the scale component + */ + public final void set(Matrix3d m1, Vector3d t1, double scale) + { + this.m00 = m1.m00*scale; + this.m01 = m1.m01*scale; + this.m02 = m1.m02*scale; + this.m03 = t1.x; + + this.m10 = m1.m10*scale; + this.m11 = m1.m11*scale; + this.m12 = m1.m12*scale; + this.m13 = t1.y; + + this.m20 = m1.m20*scale; + this.m21 = m1.m21*scale; + this.m22 = m1.m22*scale; + this.m23 = t1.z; + + this.m30 = 0.0; + this.m31 = 0.0; + this.m32 = 0.0; + this.m33 = 1.0; + } + + /** + * Modifies the translational components of this matrix to the values + * of the Vector3d argument; the other values of this matrix are not + * modified. + * @param trans the translational component + */ + public final void setTranslation(Vector3d trans) + { + m03 = trans.x; + m13 = trans.y; + m23 = trans.z; + } + + /** + * 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.m03 = 0.0; + + this.m10 = 0.0; + this.m11 = cosAngle; + this.m12 = -sinAngle; + this.m13 = 0.0; + + this.m20 = 0.0; + this.m21 = sinAngle; + this.m22 = cosAngle; + this.m23 = 0.0; + + this.m30 = 0.0; + this.m31 = 0.0; + this.m32 = 0.0; + this.m33 = 1.0; + } + + /** + * 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.m03 = 0.0; + + this.m10 = 0.0; + this.m11 = 1.0; + this.m12 = 0.0; + this.m13 = 0.0; + + this.m20 = -sinAngle; + this.m21 = 0.0; + this.m22 = cosAngle; + this.m23 = 0.0; + + this.m30 = 0.0; + this.m31 = 0.0; + this.m32 = 0.0; + this.m33 = 1.0; + } + + /** + * 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.m03 = 0.0; + + this.m10 = sinAngle; + this.m11 = cosAngle; + this.m12 = 0.0; + this.m13 = 0.0; + + this.m20 = 0.0; + this.m21 = 0.0; + this.m22 = 1.0; + this.m23 = 0.0; + + this.m30 = 0.0; + this.m31 = 0.0; + this.m32 = 0.0; + this.m33 = 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; + m03 *= scalar; + m10 *= scalar; + m11 *= scalar; + m12 *= scalar; + m13 *= scalar; + m20 *= scalar; + m21 *= scalar; + m22 *= scalar; + m23 *= scalar; + m30 *= scalar; + m31 *= scalar; + m32 *= scalar; + m33 *= 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, Matrix4d m1) + { + this.m00 = m1.m00 * scalar; + this.m01 = m1.m01 * scalar; + this.m02 = m1.m02 * scalar; + this.m03 = m1.m03 * scalar; + this.m10 = m1.m10 * scalar; + this.m11 = m1.m11 * scalar; + this.m12 = m1.m12 * scalar; + this.m13 = m1.m13 * scalar; + this.m20 = m1.m20 * scalar; + this.m21 = m1.m21 * scalar; + this.m22 = m1.m22 * scalar; + this.m23 = m1.m23 * scalar; + this.m30 = m1.m30 * scalar; + this.m31 = m1.m31 * scalar; + this.m32 = m1.m32 * scalar; + this.m33 = m1.m33 * scalar; + } + + /** + * Sets the value of this matrix to the result of multiplying itself + * with matrix m1. + * @param m1 the other matrix + */ + public final void mul(Matrix4d m1) + { + double m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33; // vars for temp result matrix + + m00 = this.m00*m1.m00 + this.m01*m1.m10 + + this.m02*m1.m20 + this.m03*m1.m30; + m01 = this.m00*m1.m01 + this.m01*m1.m11 + + this.m02*m1.m21 + this.m03*m1.m31; + m02 = this.m00*m1.m02 + this.m01*m1.m12 + + this.m02*m1.m22 + this.m03*m1.m32; + m03 = this.m00*m1.m03 + this.m01*m1.m13 + + this.m02*m1.m23 + this.m03*m1.m33; + + m10 = this.m10*m1.m00 + this.m11*m1.m10 + + this.m12*m1.m20 + this.m13*m1.m30; + m11 = this.m10*m1.m01 + this.m11*m1.m11 + + this.m12*m1.m21 + this.m13*m1.m31; + m12 = this.m10*m1.m02 + this.m11*m1.m12 + + this.m12*m1.m22 + this.m13*m1.m32; + m13 = this.m10*m1.m03 + this.m11*m1.m13 + + this.m12*m1.m23 + this.m13*m1.m33; + + m20 = this.m20*m1.m00 + this.m21*m1.m10 + + this.m22*m1.m20 + this.m23*m1.m30; + m21 = this.m20*m1.m01 + this.m21*m1.m11 + + this.m22*m1.m21 + this.m23*m1.m31; + m22 = this.m20*m1.m02 + this.m21*m1.m12 + + this.m22*m1.m22 + this.m23*m1.m32; + m23 = this.m20*m1.m03 + this.m21*m1.m13 + + this.m22*m1.m23 + this.m23*m1.m33; + + m30 = this.m30*m1.m00 + this.m31*m1.m10 + + this.m32*m1.m20 + this.m33*m1.m30; + m31 = this.m30*m1.m01 + this.m31*m1.m11 + + this.m32*m1.m21 + this.m33*m1.m31; + m32 = this.m30*m1.m02 + this.m31*m1.m12 + + this.m32*m1.m22 + this.m33*m1.m32; + m33 = this.m30*m1.m03 + this.m31*m1.m13 + + this.m32*m1.m23 + this.m33*m1.m33; + + this.m00 = m00; this.m01 = m01; this.m02 = m02; this.m03 = m03; + this.m10 = m10; this.m11 = m11; this.m12 = m12; this.m13 = m13; + this.m20 = m20; this.m21 = m21; this.m22 = m22; this.m23 = m23; + this.m30 = m30; this.m31 = m31; this.m32 = m32; this.m33 = m33; + } + + /** + * 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(Matrix4d m1, Matrix4d m2) + { + if (this != m1 && this != m2) { + // code for mat mul + this.m00 = m1.m00*m2.m00 + m1.m01*m2.m10 + + m1.m02*m2.m20 + m1.m03*m2.m30; + this.m01 = m1.m00*m2.m01 + m1.m01*m2.m11 + + m1.m02*m2.m21 + m1.m03*m2.m31; + this.m02 = m1.m00*m2.m02 + m1.m01*m2.m12 + + m1.m02*m2.m22 + m1.m03*m2.m32; + this.m03 = m1.m00*m2.m03 + m1.m01*m2.m13 + + m1.m02*m2.m23 + m1.m03*m2.m33; + + this.m10 = m1.m10*m2.m00 + m1.m11*m2.m10 + + m1.m12*m2.m20 + m1.m13*m2.m30; + this.m11 = m1.m10*m2.m01 + m1.m11*m2.m11 + + m1.m12*m2.m21 + m1.m13*m2.m31; + this.m12 = m1.m10*m2.m02 + m1.m11*m2.m12 + + m1.m12*m2.m22 + m1.m13*m2.m32; + this.m13 = m1.m10*m2.m03 + m1.m11*m2.m13 + + m1.m12*m2.m23 + m1.m13*m2.m33; + + this.m20 = m1.m20*m2.m00 + m1.m21*m2.m10 + + m1.m22*m2.m20 + m1.m23*m2.m30; + this.m21 = m1.m20*m2.m01 + m1.m21*m2.m11 + + m1.m22*m2.m21 + m1.m23*m2.m31; + this.m22 = m1.m20*m2.m02 + m1.m21*m2.m12 + + m1.m22*m2.m22 + m1.m23*m2.m32; + this.m23 = m1.m20*m2.m03 + m1.m21*m2.m13 + + m1.m22*m2.m23 + m1.m23*m2.m33; + + this.m30 = m1.m30*m2.m00 + m1.m31*m2.m10 + + m1.m32*m2.m20 + m1.m33*m2.m30; + this.m31 = m1.m30*m2.m01 + m1.m31*m2.m11 + + m1.m32*m2.m21 + m1.m33*m2.m31; + this.m32 = m1.m30*m2.m02 + m1.m31*m2.m12 + + m1.m32*m2.m22 + m1.m33*m2.m32; + this.m33 = m1.m30*m2.m03 + m1.m31*m2.m13 + + m1.m32*m2.m23 + m1.m33*m2.m33; + } else { + double m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33; // vars for temp result matrix + + // code for mat mul + m00 = m1.m00*m2.m00 + m1.m01*m2.m10 + m1.m02*m2.m20 + m1.m03*m2.m30; + m01 = m1.m00*m2.m01 + m1.m01*m2.m11 + m1.m02*m2.m21 + m1.m03*m2.m31; + m02 = m1.m00*m2.m02 + m1.m01*m2.m12 + m1.m02*m2.m22 + m1.m03*m2.m32; + m03 = m1.m00*m2.m03 + m1.m01*m2.m13 + m1.m02*m2.m23 + m1.m03*m2.m33; + + m10 = m1.m10*m2.m00 + m1.m11*m2.m10 + m1.m12*m2.m20 + m1.m13*m2.m30; + m11 = m1.m10*m2.m01 + m1.m11*m2.m11 + m1.m12*m2.m21 + m1.m13*m2.m31; + m12 = m1.m10*m2.m02 + m1.m11*m2.m12 + m1.m12*m2.m22 + m1.m13*m2.m32; + m13 = m1.m10*m2.m03 + m1.m11*m2.m13 + m1.m12*m2.m23 + m1.m13*m2.m33; + + m20 = m1.m20*m2.m00 + m1.m21*m2.m10 + m1.m22*m2.m20 + m1.m23*m2.m30; + m21 = m1.m20*m2.m01 + m1.m21*m2.m11 + m1.m22*m2.m21 + m1.m23*m2.m31; + m22 = m1.m20*m2.m02 + m1.m21*m2.m12 + m1.m22*m2.m22 + m1.m23*m2.m32; + m23 = m1.m20*m2.m03 + m1.m21*m2.m13 + m1.m22*m2.m23 + m1.m23*m2.m33; + + m30 = m1.m30*m2.m00 + m1.m31*m2.m10 + m1.m32*m2.m20 + m1.m33*m2.m30; + m31 = m1.m30*m2.m01 + m1.m31*m2.m11 + m1.m32*m2.m21 + m1.m33*m2.m31; + m32 = m1.m30*m2.m02 + m1.m31*m2.m12 + m1.m32*m2.m22 + m1.m33*m2.m32; + m33 = m1.m30*m2.m03 + m1.m31*m2.m13 + m1.m32*m2.m23 + m1.m33*m2.m33; + + this.m00 = m00; this.m01 = m01; this.m02 = m02; this.m03 = m03; + this.m10 = m10; this.m11 = m11; this.m12 = m12; this.m13 = m13; + this.m20 = m20; this.m21 = m21; this.m22 = m22; this.m23 = m23; + this.m30 = m30; this.m31 = m31; this.m32 = m32; this.m33 = m33; + + } + } + + /** + * 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(Matrix4d m1, Matrix4d m2) + { + if (this != m1 && this != m2) { + this.m00 = m1.m00*m2.m00 + m1.m10*m2.m01 + m1.m20*m2.m02 + m1.m30*m2.m03; + this.m01 = m1.m00*m2.m10 + m1.m10*m2.m11 + m1.m20*m2.m12 + m1.m30*m2.m13; + this.m02 = m1.m00*m2.m20 + m1.m10*m2.m21 + m1.m20*m2.m22 + m1.m30*m2.m23; + this.m03 = m1.m00*m2.m30 + m1.m10*m2.m31 + m1.m20*m2.m32 + m1.m30*m2.m33; + + this.m10 = m1.m01*m2.m00 + m1.m11*m2.m01 + m1.m21*m2.m02 + m1.m31*m2.m03; + this.m11 = m1.m01*m2.m10 + m1.m11*m2.m11 + m1.m21*m2.m12 + m1.m31*m2.m13; + this.m12 = m1.m01*m2.m20 + m1.m11*m2.m21 + m1.m21*m2.m22 + m1.m31*m2.m23; + this.m13 = m1.m01*m2.m30 + m1.m11*m2.m31 + m1.m21*m2.m32 + m1.m31*m2.m33; + + this.m20 = m1.m02*m2.m00 + m1.m12*m2.m01 + m1.m22*m2.m02 + m1.m32*m2.m03; + this.m21 = m1.m02*m2.m10 + m1.m12*m2.m11 + m1.m22*m2.m12 + m1.m32*m2.m13; + this.m22 = m1.m02*m2.m20 + m1.m12*m2.m21 + m1.m22*m2.m22 + m1.m32*m2.m23; + this.m23 = m1.m02*m2.m30 + m1.m12*m2.m31 + m1.m22*m2.m32 + m1.m32*m2.m33; + + this.m30 = m1.m03*m2.m00 + m1.m13*m2.m01 + m1.m23*m2.m02 + m1.m33*m2.m03; + this.m31 = m1.m03*m2.m10 + m1.m13*m2.m11 + m1.m23*m2.m12 + m1.m33*m2.m13; + this.m32 = m1.m03*m2.m20 + m1.m13*m2.m21 + m1.m23*m2.m22 + m1.m33*m2.m23; + this.m33 = m1.m03*m2.m30 + m1.m13*m2.m31 + m1.m23*m2.m32 + m1.m33*m2.m33; + } else { + double m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, // vars for temp result matrix + m30, m31, m32, m33; + + m00 = m1.m00*m2.m00 + m1.m10*m2.m01 + m1.m20*m2.m02 + m1.m30*m2.m03; + m01 = m1.m00*m2.m10 + m1.m10*m2.m11 + m1.m20*m2.m12 + m1.m30*m2.m13; + m02 = m1.m00*m2.m20 + m1.m10*m2.m21 + m1.m20*m2.m22 + m1.m30*m2.m23; + m03 = m1.m00*m2.m30 + m1.m10*m2.m31 + m1.m20*m2.m32 + m1.m30*m2.m33; + + m10 = m1.m01*m2.m00 + m1.m11*m2.m01 + m1.m21*m2.m02 + m1.m31*m2.m03; + m11 = m1.m01*m2.m10 + m1.m11*m2.m11 + m1.m21*m2.m12 + m1.m31*m2.m13; + m12 = m1.m01*m2.m20 + m1.m11*m2.m21 + m1.m21*m2.m22 + m1.m31*m2.m23; + m13 = m1.m01*m2.m30 + m1.m11*m2.m31 + m1.m21*m2.m32 + m1.m31*m2.m33; + + m20 = m1.m02*m2.m00 + m1.m12*m2.m01 + m1.m22*m2.m02 + m1.m32*m2.m03; + m21 = m1.m02*m2.m10 + m1.m12*m2.m11 + m1.m22*m2.m12 + m1.m32*m2.m13; + m22 = m1.m02*m2.m20 + m1.m12*m2.m21 + m1.m22*m2.m22 + m1.m32*m2.m23; + m23 = m1.m02*m2.m30 + m1.m12*m2.m31 + m1.m22*m2.m32 + m1.m32*m2.m33; + + m30 = m1.m03*m2.m00 + m1.m13*m2.m01 + m1.m23*m2.m02 + m1.m33*m2.m03; + m31 = m1.m03*m2.m10 + m1.m13*m2.m11 + m1.m23*m2.m12 + m1.m33*m2.m13; + m32 = m1.m03*m2.m20 + m1.m13*m2.m21 + m1.m23*m2.m22 + m1.m33*m2.m23; + m33 = m1.m03*m2.m30 + m1.m13*m2.m31 + m1.m23*m2.m32 + m1.m33*m2.m33; + + this.m00 = m00; this.m01 = m01; this.m02 = m02; this.m03 = m03; + this.m10 = m10; this.m11 = m11; this.m12 = m12; this.m13 = m13; + this.m20 = m20; this.m21 = m21; this.m22 = m22; this.m23 = m23; + this.m30 = m30; this.m31 = m31; this.m32 = m32; this.m33 = m33; + } + + } + + + + /** + * 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(Matrix4d m1, Matrix4d m2) + { + if (this != m1 && this != m2) { + this.m00 = m1.m00*m2.m00 + m1.m01*m2.m01 + m1.m02*m2.m02 + m1.m03*m2.m03; + this.m01 = m1.m00*m2.m10 + m1.m01*m2.m11 + m1.m02*m2.m12 + m1.m03*m2.m13; + this.m02 = m1.m00*m2.m20 + m1.m01*m2.m21 + m1.m02*m2.m22 + m1.m03*m2.m23; + this.m03 = m1.m00*m2.m30 + m1.m01*m2.m31 + m1.m02*m2.m32 + m1.m03*m2.m33; + + this.m10 = m1.m10*m2.m00 + m1.m11*m2.m01 + m1.m12*m2.m02 + m1.m13*m2.m03; + this.m11 = m1.m10*m2.m10 + m1.m11*m2.m11 + m1.m12*m2.m12 + m1.m13*m2.m13; + this.m12 = m1.m10*m2.m20 + m1.m11*m2.m21 + m1.m12*m2.m22 + m1.m13*m2.m23; + this.m13 = m1.m10*m2.m30 + m1.m11*m2.m31 + m1.m12*m2.m32 + m1.m13*m2.m33; + + this.m20 = m1.m20*m2.m00 + m1.m21*m2.m01 + m1.m22*m2.m02 + m1.m23*m2.m03; + this.m21 = m1.m20*m2.m10 + m1.m21*m2.m11 + m1.m22*m2.m12 + m1.m23*m2.m13; + this.m22 = m1.m20*m2.m20 + m1.m21*m2.m21 + m1.m22*m2.m22 + m1.m23*m2.m23; + this.m23 = m1.m20*m2.m30 + m1.m21*m2.m31 + m1.m22*m2.m32 + m1.m23*m2.m33; + + this.m30 = m1.m30*m2.m00 + m1.m31*m2.m01 + m1.m32*m2.m02 + m1.m33*m2.m03; + this.m31 = m1.m30*m2.m10 + m1.m31*m2.m11 + m1.m32*m2.m12 + m1.m33*m2.m13; + this.m32 = m1.m30*m2.m20 + m1.m31*m2.m21 + m1.m32*m2.m22 + m1.m33*m2.m23; + this.m33 = m1.m30*m2.m30 + m1.m31*m2.m31 + m1.m32*m2.m32 + m1.m33*m2.m33; + } else { + double m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, // vars for temp result matrix + m30, m31, m32, m33; + + m00 = m1.m00*m2.m00 + m1.m01*m2.m01 + m1.m02*m2.m02 + m1.m03*m2.m03; + m01 = m1.m00*m2.m10 + m1.m01*m2.m11 + m1.m02*m2.m12 + m1.m03*m2.m13; + m02 = m1.m00*m2.m20 + m1.m01*m2.m21 + m1.m02*m2.m22 + m1.m03*m2.m23; + m03 = m1.m00*m2.m30 + m1.m01*m2.m31 + m1.m02*m2.m32 + m1.m03*m2.m33; + + m10 = m1.m10*m2.m00 + m1.m11*m2.m01 + m1.m12*m2.m02 + m1.m13*m2.m03; + m11 = m1.m10*m2.m10 + m1.m11*m2.m11 + m1.m12*m2.m12 + m1.m13*m2.m13; + m12 = m1.m10*m2.m20 + m1.m11*m2.m21 + m1.m12*m2.m22 + m1.m13*m2.m23; + m13 = m1.m10*m2.m30 + m1.m11*m2.m31 + m1.m12*m2.m32 + m1.m13*m2.m33; + + m20 = m1.m20*m2.m00 + m1.m21*m2.m01 + m1.m22*m2.m02 + m1.m23*m2.m03; + m21 = m1.m20*m2.m10 + m1.m21*m2.m11 + m1.m22*m2.m12 + m1.m23*m2.m13; + m22 = m1.m20*m2.m20 + m1.m21*m2.m21 + m1.m22*m2.m22 + m1.m23*m2.m23; + m23 = m1.m20*m2.m30 + m1.m21*m2.m31 + m1.m22*m2.m32 + m1.m23*m2.m33; + + m30 = m1.m30*m2.m00 + m1.m31*m2.m01 + m1.m32*m2.m02 + m1.m33*m2.m03; + m31 = m1.m30*m2.m10 + m1.m31*m2.m11 + m1.m32*m2.m12 + m1.m33*m2.m13; + m32 = m1.m30*m2.m20 + m1.m31*m2.m21 + m1.m32*m2.m22 + m1.m33*m2.m23; + m33 = m1.m30*m2.m30 + m1.m31*m2.m31 + m1.m32*m2.m32 + m1.m33*m2.m33; + + this.m00 = m00; this.m01 = m01; this.m02 = m02; this.m03 = m03; + this.m10 = m10; this.m11 = m11; this.m12 = m12; this.m13 = m13; + this.m20 = m20; this.m21 = m21; this.m22 = m22; this.m23 = m23; + this.m30 = m30; this.m31 = m31; this.m32 = m32; this.m33 = m33; + } +} + + + /** + * 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(Matrix4d m1, Matrix4d m2) + { + if (this != m1 && this != m2) { + this.m00 = m1.m00*m2.m00 + m1.m10*m2.m10 + m1.m20*m2.m20 + m1.m30*m2.m30; + this.m01 = m1.m00*m2.m01 + m1.m10*m2.m11 + m1.m20*m2.m21 + m1.m30*m2.m31; + this.m02 = m1.m00*m2.m02 + m1.m10*m2.m12 + m1.m20*m2.m22 + m1.m30*m2.m32; + this.m03 = m1.m00*m2.m03 + m1.m10*m2.m13 + m1.m20*m2.m23 + m1.m30*m2.m33; + + this.m10 = m1.m01*m2.m00 + m1.m11*m2.m10 + m1.m21*m2.m20 + m1.m31*m2.m30; + this.m11 = m1.m01*m2.m01 + m1.m11*m2.m11 + m1.m21*m2.m21 + m1.m31*m2.m31; + this.m12 = m1.m01*m2.m02 + m1.m11*m2.m12 + m1.m21*m2.m22 + m1.m31*m2.m32; + this.m13 = m1.m01*m2.m03 + m1.m11*m2.m13 + m1.m21*m2.m23 + m1.m31*m2.m33; + + this.m20 = m1.m02*m2.m00 + m1.m12*m2.m10 + m1.m22*m2.m20 + m1.m32*m2.m30; + this.m21 = m1.m02*m2.m01 + m1.m12*m2.m11 + m1.m22*m2.m21 + m1.m32*m2.m31; + this.m22 = m1.m02*m2.m02 + m1.m12*m2.m12 + m1.m22*m2.m22 + m1.m32*m2.m32; + this.m23 = m1.m02*m2.m03 + m1.m12*m2.m13 + m1.m22*m2.m23 + m1.m32*m2.m33; + + this.m30 = m1.m03*m2.m00 + m1.m13*m2.m10 + m1.m23*m2.m20 + m1.m33*m2.m30; + this.m31 = m1.m03*m2.m01 + m1.m13*m2.m11 + m1.m23*m2.m21 + m1.m33*m2.m31; + this.m32 = m1.m03*m2.m02 + m1.m13*m2.m12 + m1.m23*m2.m22 + m1.m33*m2.m32; + this.m33 = m1.m03*m2.m03 + m1.m13*m2.m13 + m1.m23*m2.m23 + m1.m33*m2.m33; + } else { + double m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, // vars for temp result matrix + m30, m31, m32, m33; + + + + m00 = m1.m00*m2.m00 + m1.m10*m2.m10 + m1.m20*m2.m20 + m1.m30*m2.m30; + m01 = m1.m00*m2.m01 + m1.m10*m2.m11 + m1.m20*m2.m21 + m1.m30*m2.m31; + m02 = m1.m00*m2.m02 + m1.m10*m2.m12 + m1.m20*m2.m22 + m1.m30*m2.m32; + m03 = m1.m00*m2.m03 + m1.m10*m2.m13 + m1.m20*m2.m23 + m1.m30*m2.m33; + + m10 = m1.m01*m2.m00 + m1.m11*m2.m10 + m1.m21*m2.m20 + m1.m31*m2.m30; + m11 = m1.m01*m2.m01 + m1.m11*m2.m11 + m1.m21*m2.m21 + m1.m31*m2.m31; + m12 = m1.m01*m2.m02 + m1.m11*m2.m12 + m1.m21*m2.m22 + m1.m31*m2.m32; + m13 = m1.m01*m2.m03 + m1.m11*m2.m13 + m1.m21*m2.m23 + m1.m31*m2.m33; + + m20 = m1.m02*m2.m00 + m1.m12*m2.m10 + m1.m22*m2.m20 + m1.m32*m2.m30; + m21 = m1.m02*m2.m01 + m1.m12*m2.m11 + m1.m22*m2.m21 + m1.m32*m2.m31; + m22 = m1.m02*m2.m02 + m1.m12*m2.m12 + m1.m22*m2.m22 + m1.m32*m2.m32; + m23 = m1.m02*m2.m03 + m1.m12*m2.m13 + m1.m22*m2.m23 + m1.m32*m2.m33; + + m30 = m1.m03*m2.m00 + m1.m13*m2.m10 + m1.m23*m2.m20 + m1.m33*m2.m30; + m31 = m1.m03*m2.m01 + m1.m13*m2.m11 + m1.m23*m2.m21 + m1.m33*m2.m31; + m32 = m1.m03*m2.m02 + m1.m13*m2.m12 + m1.m23*m2.m22 + m1.m33*m2.m32; + m33 = m1.m03*m2.m03 + m1.m13*m2.m13 + m1.m23*m2.m23 + m1.m33*m2.m33; + + this.m00 = m00; this.m01 = m01; this.m02 = m02; this.m03 = m03; + this.m10 = m10; this.m11 = m11; this.m12 = m12; this.m13 = m13; + this.m20 = m20; this.m21 = m21; this.m22 = m22; this.m23 = m23; + this.m30 = m30; this.m31 = m31; this.m32 = m32; this.m33 = m33; + } + + } + + + /** + * Returns true if all of the data members of Matrix4d m1 are + * equal to the corresponding data members in this Matrix4d. + * @param m1 the matrix with which the comparison is made + * @return true or false + */ + public boolean equals(Matrix4d m1) + { + try { + return(this.m00 == m1.m00 && this.m01 == m1.m01 && this.m02 == m1.m02 + && this.m03 == m1.m03 && this.m10 == m1.m10 && this.m11 == m1.m11 + && this.m12 == m1.m12 && this.m13 == m1.m13 && this.m20 == m1.m20 + && this.m21 == m1.m21 && this.m22 == m1.m22 && this.m23 == m1.m23 + && this.m30 == m1.m30 && this.m31 == m1.m31 && this.m32 == m1.m32 + && this.m33 == m1.m33); + } + catch (NullPointerException e2) { return false; } + + } + + /** + * Returns true if the Object t1 is of type Matrix4d and all of the + * data members of t1 are equal to the corresponding data members in + * this Matrix4d. + * @param t1 the matrix with which the comparison is made + * @return true or false + */ + public boolean equals(Object t1) + { + try { + Matrix4d m2 = (Matrix4d) t1; + return(this.m00 == m2.m00 && this.m01 == m2.m01 && this.m02 == m2.m02 + && this.m03 == m2.m03 && this.m10 == m2.m10 && this.m11 == m2.m11 + && this.m12 == m2.m12 && this.m13 == m2.m13 && this.m20 == m2.m20 + && this.m21 == m2.m21 && this.m22 == m2.m22 && this.m23 == m2.m23 + && this.m30 == m2.m30 && this.m31 == m2.m31 && this.m32 == m2.m32 + && this.m33 == m2.m33); + } + catch (ClassCastException e1) { return false; } + catch (NullPointerException e2) { return false; } + } + + /** + * @deprecated Use epsilonEquals(Matrix4d,double) instead + */ + public boolean epsilonEquals(Matrix4d m1, float epsilon) { + return epsilonEquals(m1, (double)epsilon); + } + + /** + * 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,3 ; j=0,1,2,3 ; 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(Matrix4d 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 = m03 - m1.m03; + 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 = m13 - m1.m13; + 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; + + diff = m23 - m1.m23; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = m30 - m1.m30; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = m31 - m1.m31; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = m32 - m1.m32; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = m33 - m1.m33; + 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 Matrix4d objects with identical data values + * (i.e., Matrix4d.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 + */ + public int hashCode() { + long bits = 1L; + bits = 31L * bits + Double.doubleToLongBits(m00); + bits = 31L * bits + Double.doubleToLongBits(m01); + bits = 31L * bits + Double.doubleToLongBits(m02); + bits = 31L * bits + Double.doubleToLongBits(m03); + bits = 31L * bits + Double.doubleToLongBits(m10); + bits = 31L * bits + Double.doubleToLongBits(m11); + bits = 31L * bits + Double.doubleToLongBits(m12); + bits = 31L * bits + Double.doubleToLongBits(m13); + bits = 31L * bits + Double.doubleToLongBits(m20); + bits = 31L * bits + Double.doubleToLongBits(m21); + bits = 31L * bits + Double.doubleToLongBits(m22); + bits = 31L * bits + Double.doubleToLongBits(m23); + bits = 31L * bits + Double.doubleToLongBits(m30); + bits = 31L * bits + Double.doubleToLongBits(m31); + bits = 31L * bits + Double.doubleToLongBits(m32); + bits = 31L * bits + Double.doubleToLongBits(m33); + return (int) (bits ^ (bits >> 32)); + } + + + /** + * Transform the vector vec using this Matrix4d and place the + * result into vecOut. + * @param vec the double precision vector to be transformed + * @param vecOut the vector into which the transformed values are placed + */ + public final void transform(Tuple4d vec, Tuple4d vecOut) + { + double x,y,z,w; + x = (m00*vec.x + m01*vec.y + + m02*vec.z + m03*vec.w); + y = (m10*vec.x + m11*vec.y + + m12*vec.z + m13*vec.w); + z = (m20*vec.x + m21*vec.y + + m22*vec.z + m23*vec.w); + vecOut.w = (m30*vec.x + m31*vec.y + + m32*vec.z + m33*vec.w); + vecOut.x = x; + vecOut.y = y; + vecOut.z = z; + } + + /** + * Transform the vector vec using this Matrix4d and place the + * result back into vec. + * @param vec the double precision vector to be transformed + */ + public final void transform(Tuple4d vec) + { + double x,y,z; + + x = (m00*vec.x + m01*vec.y + + m02*vec.z + m03*vec.w); + y = (m10*vec.x + m11*vec.y + + m12*vec.z + m13*vec.w); + z = (m20*vec.x + m21*vec.y + + m22*vec.z + m23*vec.w); + vec.w = (m30*vec.x + m31*vec.y + + m32*vec.z + m33*vec.w); + vec.x = x; + vec.y = y; + vec.z = z; + } + + /** + * Transform the vector vec using this Matrix4d and place the + * result into vecOut. + * @param vec the single precision vector to be transformed + * @param vecOut the vector into which the transformed values are placed + */ + public final void transform(Tuple4f vec, Tuple4f vecOut) + { + float x,y,z; + x = (float) (m00*vec.x + m01*vec.y + + m02*vec.z + m03*vec.w); + y = (float) (m10*vec.x + m11*vec.y + + m12*vec.z + m13*vec.w); + z = (float) (m20*vec.x + m21*vec.y + + m22*vec.z + m23*vec.w); + vecOut.w = (float) (m30*vec.x + m31*vec.y + + m32*vec.z + m33*vec.w); + vecOut.x = x; + vecOut.y = y; + vecOut.z = z; + } + + /** + * Transform the vector vec using this Transform and place the + * result back into vec. + * @param vec the single precision vector to be transformed + */ + public final void transform(Tuple4f vec) + { + float x,y,z; + + x = (float) (m00*vec.x + m01*vec.y + + m02*vec.z + m03*vec.w); + y = (float) (m10*vec.x + m11*vec.y + + m12*vec.z + m13*vec.w); + z = (float) (m20*vec.x + m21*vec.y + + m22*vec.z + m23*vec.w); + vec.w = (float) (m30*vec.x + m31*vec.y + + m32*vec.z + m33*vec.w); + vec.x = x; + vec.y = y; + vec.z = z; + } + + + /** + * Transforms the point parameter with this Matrix4d and + * places the result into pointOut. The fourth element of the + * point input parameter is assumed to be one. + * @param point the input point to be transformed. + * @param pointOut the transformed point + */ + public final void transform(Point3d point, Point3d pointOut) + { + double x,y; + x = m00*point.x + m01*point.y + m02*point.z + m03; + y = m10*point.x + m11*point.y + m12*point.z + m13; + pointOut.z = m20*point.x + m21*point.y + m22*point.z + m23; + pointOut.x = x; + pointOut.y = y; + + } + + + /** + * Transforms the point parameter with this Matrix4d and + * places the result back into point. The fourth element of the + * point input parameter is assumed to be one. + * @param point the input point to be transformed. + */ + public final void transform(Point3d point) + { + double x, y; + x = m00*point.x + m01*point.y + m02*point.z + m03; + y = m10*point.x + m11*point.y + m12*point.z + m13; + point.z = m20*point.x + m21*point.y + m22*point.z + m23; + point.x = x; + point.y = y; + } + + + /** + * Transforms the point parameter with this Matrix4d and + * places the result into pointOut. The fourth element of the + * point input parameter is assumed to be one. + * @param point the input point to be transformed. + * @param pointOut the transformed point + */ + public final void transform(Point3f point, Point3f pointOut) + { + float x,y; + + x = (float) (m00*point.x + m01*point.y + m02*point.z + m03); + y = (float) (m10*point.x + m11*point.y + m12*point.z + m13); + pointOut.z = (float) (m20*point.x + m21*point.y + m22*point.z + m23); + pointOut.x = x; + pointOut.y = y; + } + + + /** + * Transforms the point parameter with this Matrix4d and + * places the result back into point. The fourth element of the + * point input parameter is assumed to be one. + * @param point the input point to be transformed. + */ + public final void transform(Point3f point) + { + float x, y; + x = (float) (m00*point.x + m01*point.y + m02*point.z + m03); + y = (float) (m10*point.x + m11*point.y + m12*point.z + m13); + point.z = (float) (m20*point.x + m21*point.y + m22*point.z + m23); + point.x = x; + point.y = y; + } + + + /** + * Transforms the normal parameter by this Matrix4d and places the value + * into normalOut. The fourth element of the normal is assumed to be zero. + * @param normal the input normal to be transformed. + * @param normalOut the transformed normal + */ + public final void transform(Vector3d normal, Vector3d normalOut) + { + double x,y; + x = m00*normal.x + m01*normal.y + m02*normal.z; + y = m10*normal.x + m11*normal.y + m12*normal.z; + normalOut.z = m20*normal.x + m21*normal.y + m22*normal.z; + normalOut.x = x; + normalOut.y = y; + } + + + /** + * Transforms the normal parameter by this transform and places the value + * back into normal. The fourth element of the normal is assumed to be zero. + * @param normal the input normal to be transformed. + */ + public final void transform(Vector3d normal) + { + double x, y; + + x = m00*normal.x + m01*normal.y + m02*normal.z; + y = m10*normal.x + m11*normal.y + m12*normal.z; + normal.z = m20*normal.x + m21*normal.y + m22*normal.z; + normal.x = x; + normal.y = y; + } + + + /** + * Transforms the normal parameter by this Matrix4d and places the value + * into normalOut. The fourth element of the normal is assumed to be zero. + * @param normal the input normal to be transformed. + * @param normalOut the transformed normal + */ + public final void transform(Vector3f normal, Vector3f normalOut) + { + float x,y; + x = (float) (m00*normal.x + m01*normal.y + m02*normal.z); + y = (float) (m10*normal.x + m11*normal.y + m12*normal.z); + normalOut.z = (float) (m20*normal.x + m21*normal.y + m22*normal.z); + normalOut.x = x; + normalOut.y = y; + } + + + /** + * Transforms the normal parameter by this transform and places the value + * back into normal. The fourth element of the normal is assumed to be zero. + * @param normal the input normal to be transformed. + */ + public final void transform(Vector3f normal) + { + float x, y; + + x = (float) (m00*normal.x + m01*normal.y + m02*normal.z); + y = (float) (m10*normal.x + m11*normal.y + m12*normal.z); + normal.z = (float) (m20*normal.x + m21*normal.y + m22*normal.z); + normal.x = x; + normal.y = y; + } + + /** + * Sets the rotational component (upper 3x3) of this matrix to the + * matrix values in the double precision Matrix3d argument; the other + * elements of this matrix are unchanged; a singular value + * decomposition is performed on this object's upper 3x3 matrix to + * factor out the scale, then this object's upper 3x3 matrix components + * are replaced by the passed rotation components, + * and then the scale is reapplied to the rotational components. + * @param m1 double precision 3x3 matrix + */ + public final void setRotation( Matrix3d m1){ + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + + getScaleRotate( tmp_scale, tmp_rot ); + + m00 = m1.m00*tmp_scale[0]; + m01 = m1.m01*tmp_scale[1]; + m02 = m1.m02*tmp_scale[2]; + + m10 = m1.m10*tmp_scale[0]; + m11 = m1.m11*tmp_scale[1]; + m12 = m1.m12*tmp_scale[2]; + + m20 = m1.m20*tmp_scale[0]; + m21 = m1.m21*tmp_scale[1]; + m22 = m1.m22*tmp_scale[2]; + + } + + + /** + * Sets the rotational component (upper 3x3) of this matrix to the + * matrix values in the single precision Matrix3f argument; the other + * elements of this matrix are unchanged; a singular value + * decomposition is performed on this object's upper 3x3 matrix to + * factor out the scale, then this object's upper 3x3 matrix components + * are replaced by the passed rotation components, + * and then the scale is reapplied to the rotational components. + * @param m1 single precision 3x3 matrix + */ + public final void setRotation( Matrix3f m1) + { + + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + getScaleRotate( tmp_scale, tmp_rot ); + + m00 = m1.m00*tmp_scale[0]; + m01 = m1.m01*tmp_scale[1]; + m02 = m1.m02*tmp_scale[2]; + + m10 = m1.m10*tmp_scale[0]; + m11 = m1.m11*tmp_scale[1]; + m12 = m1.m12*tmp_scale[2]; + + m20 = m1.m20*tmp_scale[0]; + m21 = m1.m21*tmp_scale[1]; + m22 = m1.m22*tmp_scale[2]; + } + + /** + * Sets the rotational component (upper 3x3) of this matrix to the + * matrix equivalent values of the quaternion argument; the other + * elements of this matrix are unchanged; a singular value + * decomposition is performed on this object's upper 3x3 matrix to + * factor out the scale, then this object's upper 3x3 matrix components + * are replaced by the matrix equivalent of the quaternion, + * and then the scale is reapplied to the rotational components. + * @param q1 the quaternion that specifies the rotation + */ + public final void setRotation(Quat4f q1){ + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + getScaleRotate( tmp_scale, tmp_rot ); + + m00 = (1.0 - 2.0f*q1.y*q1.y - 2.0f*q1.z*q1.z)*tmp_scale[0]; + m10 = (2.0*(q1.x*q1.y + q1.w*q1.z))*tmp_scale[0]; + m20 = (2.0*(q1.x*q1.z - q1.w*q1.y))*tmp_scale[0]; + + m01 = (2.0*(q1.x*q1.y - q1.w*q1.z))*tmp_scale[1]; + m11 = (1.0 - 2.0f*q1.x*q1.x - 2.0f*q1.z*q1.z)*tmp_scale[1]; + m21 = (2.0*(q1.y*q1.z + q1.w*q1.x))*tmp_scale[1]; + + m02 = (2.0*(q1.x*q1.z + q1.w*q1.y))*tmp_scale[2]; + m12 = (2.0*(q1.y*q1.z - q1.w*q1.x))*tmp_scale[2]; + m22 = (1.0 - 2.0f*q1.x*q1.x - 2.0f*q1.y*q1.y)*tmp_scale[2]; + + } + + + /** + * Sets the rotational component (upper 3x3) of this matrix to the + * matrix equivalent values of the quaternion argument; the other + * elements of this matrix are unchanged; a singular value + * decomposition is performed on this object's upper 3x3 matrix to + * factor out the scale, then this object's upper 3x3 matrix components + * are replaced by the matrix equivalent of the quaternion, + * and then the scale is reapplied to the rotational components. + * @param q1 the quaternion that specifies the rotation + */ + public final void setRotation(Quat4d q1){ + + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + getScaleRotate( tmp_scale, tmp_rot ); + + m00 = (1.0 - 2.0f*q1.y*q1.y - 2.0f*q1.z*q1.z)*tmp_scale[0]; + m10 = (2.0*(q1.x*q1.y + q1.w*q1.z))*tmp_scale[0]; + m20 = (2.0*(q1.x*q1.z - q1.w*q1.y))*tmp_scale[0]; + + m01 = (2.0*(q1.x*q1.y - q1.w*q1.z))*tmp_scale[1]; + m11 = (1.0 - 2.0f*q1.x*q1.x - 2.0f*q1.z*q1.z)*tmp_scale[1]; + m21 = (2.0*(q1.y*q1.z + q1.w*q1.x))*tmp_scale[1]; + + m02 = (2.0*(q1.x*q1.z + q1.w*q1.y))*tmp_scale[2]; + m12 = (2.0*(q1.y*q1.z - q1.w*q1.x))*tmp_scale[2]; + m22 = (1.0 - 2.0f*q1.x*q1.x - 2.0f*q1.y*q1.y)*tmp_scale[2]; + + } + + /** + * Sets the rotational component (upper 3x3) of this matrix to the + * matrix equivalent values of the axis-angle argument; the other + * elements of this matrix are unchanged; a singular value + * decomposition is performed on this object's upper 3x3 matrix to + * factor out the scale, then this object's upper 3x3 matrix components + * are replaced by the matrix equivalent of the axis-angle, + * and then the scale is reapplied to the rotational components. + * @param a1 the axis-angle to be converted (x, y, z, angle) + */ + public final void setRotation(AxisAngle4d a1) + { + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + + getScaleRotate( tmp_scale, tmp_rot ); + + double mag = 1.0/Math.sqrt( a1.x*a1.x + a1.y*a1.y + a1.z*a1.z); + 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 = a1.x * a1.z; + double xy = a1.x * a1.y; + double yz = a1.y * a1.z; + + m00 = (t * ax * ax + cosTheta)*tmp_scale[0]; + m01 = (t * xy - sinTheta * az)*tmp_scale[1]; + m02 = (t * xz + sinTheta * ay)*tmp_scale[2]; + + m10 = (t * xy + sinTheta * az)*tmp_scale[0]; + m11 = (t * ay * ay + cosTheta)*tmp_scale[1]; + m12 = (t * yz - sinTheta * ax)*tmp_scale[2]; + + m20 = (t * xz - sinTheta * ay)*tmp_scale[0]; + m21 = (t * yz + sinTheta * ax)*tmp_scale[1]; + m22 = (t * az * az + cosTheta)*tmp_scale[2]; + + } + + /** + * Sets this matrix to all zeros. + */ + public final void setZero() + { + m00 = 0.0; + m01 = 0.0; + m02 = 0.0; + m03 = 0.0; + m10 = 0.0; + m11 = 0.0; + m12 = 0.0; + m13 = 0.0; + m20 = 0.0; + m21 = 0.0; + m22 = 0.0; + m23 = 0.0; + m30 = 0.0; + m31 = 0.0; + m32 = 0.0; + m33 = 0.0; + } + + /** + * Negates the value of this matrix: this = -this. + */ + public final void negate() + { + m00 = -m00; + m01 = -m01; + m02 = -m02; + m03 = -m03; + m10 = -m10; + m11 = -m11; + m12 = -m12; + m13 = -m13; + m20 = -m20; + m21 = -m21; + m22 = -m22; + m23 = -m23; + m30 = -m30; + m31 = -m31; + m32 = -m32; + m33 = -m33; + } + + /** + * Sets the value of this matrix equal to the negation of + * of the Matrix4d parameter. + * @param m1 the source matrix + */ + public final void negate(Matrix4d m1) + { + this.m00 = -m1.m00; + this.m01 = -m1.m01; + this.m02 = -m1.m02; + this.m03 = -m1.m03; + this.m10 = -m1.m10; + this.m11 = -m1.m11; + this.m12 = -m1.m12; + this.m13 = -m1.m13; + this.m20 = -m1.m20; + this.m21 = -m1.m21; + this.m22 = -m1.m22; + this.m23 = -m1.m23; + this.m30 = -m1.m30; + this.m31 = -m1.m31; + this.m32 = -m1.m32; + this.m33 = -m1.m33; + } + private 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; + + Matrix3d.compute_svd( tmp, scales, rots); + + return; + } + + /** + * 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 Java 3D 1.3 + */ + public Object clone() { + Matrix4d m1 = null; + try { + m1 = (Matrix4d)super.clone(); + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + + return m1; + } + +} diff --git a/src/javax/vecmath/Matrix4f.java b/src/javax/vecmath/Matrix4f.java new file mode 100644 index 0000000..395d209 --- /dev/null +++ b/src/javax/vecmath/Matrix4f.java @@ -0,0 +1,3245 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A single precision floating point 4 by 4 matrix. + * Primarily to support 3D rotations. + * + */ +public class Matrix4f implements java.io.Serializable, Cloneable { + + // Compatible with 1.1 + static final long serialVersionUID = -8405036035410109353L; + + /** + * The first element of the first row. + */ + public float m00; + + /** + * The second element of the first row. + */ + public float m01; + + /** + * The third element of the first row. + */ + public float m02; + + /** + * The fourth element of the first row. + */ + public float m03; + + /** + * The first element of the second row. + */ + public float m10; + + /** + * The second element of the second row. + */ + public float m11; + + /** + * The third element of the second row. + */ + public float m12; + + /** + * The fourth element of the second row. + */ + public float m13; + + /** + * The first element of the third row. + */ + public float m20; + + /** + * The second element of the third row. + */ + public float m21; + + /** + * The third element of the third row. + */ + public float m22; + + /** + * The fourth element of the third row. + */ + public float m23; + + /** + * The first element of the fourth row. + */ + public float m30; + + /** + * The second element of the fourth row. + */ + public float m31; + + /** + * The third element of the fourth row. + */ + public float m32; + + /** + * The fourth element of the fourth row. + */ + public float m33; + /* + double[] tmp = new double[9]; + double[] tmp_scale = new double[3]; + double[] tmp_rot = new double[9]; + */ + private static final double EPS = 1.0E-8; + + /** + * Constructs and initializes a Matrix4f from the specified 16 values. + * @param m00 the [0][0] element + * @param m01 the [0][1] element + * @param m02 the [0][2] element + * @param m03 the [0][3] element + * @param m10 the [1][0] element + * @param m11 the [1][1] element + * @param m12 the [1][2] element + * @param m13 the [1][3] element + * @param m20 the [2][0] element + * @param m21 the [2][1] element + * @param m22 the [2][2] element + * @param m23 the [2][3] element + * @param m30 the [3][0] element + * @param m31 the [3][1] element + * @param m32 the [3][2] element + * @param m33 the [3][3] element + */ + public Matrix4f(float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23, + float m30, float m31, float m32, float m33) + { + this.m00 = m00; + this.m01 = m01; + this.m02 = m02; + this.m03 = m03; + + this.m10 = m10; + this.m11 = m11; + this.m12 = m12; + this.m13 = m13; + + this.m20 = m20; + this.m21 = m21; + this.m22 = m22; + this.m23 = m23; + + this.m30 = m30; + this.m31 = m31; + this.m32 = m32; + this.m33 = m33; + + } + + /** + * Constructs and initializes a Matrix4f from the specified 16 + * element array. this.m00 =v[0], this.m01=v[1], etc. + * @param v the array of length 16 containing in order + */ + public Matrix4f(float[] v) + { + this.m00 = v[ 0]; + this.m01 = v[ 1]; + this.m02 = v[ 2]; + this.m03 = v[ 3]; + + this.m10 = v[ 4]; + this.m11 = v[ 5]; + this.m12 = v[ 6]; + this.m13 = v[ 7]; + + this.m20 = v[ 8]; + this.m21 = v[ 9]; + this.m22 = v[10]; + this.m23 = v[11]; + + this.m30 = v[12]; + this.m31 = v[13]; + this.m32 = v[14]; + this.m33 = v[15]; + + } + + /** + * Constructs and initializes a Matrix4f from the quaternion, + * translation, and scale values; the scale is applied only to the + * rotational components of the matrix (upper 3x3) and not to the + * translational components. + * @param q1 the quaternion value representing the rotational component + * @param t1 the translational component of the matrix + * @param s the scale value applied to the rotational components + */ + public Matrix4f(Quat4f q1, Vector3f t1, float s) + { + m00 = (float)(s*(1.0 - 2.0*q1.y*q1.y - 2.0*q1.z*q1.z)); + m10 = (float)(s*(2.0*(q1.x*q1.y + q1.w*q1.z))); + m20 = (float)(s*(2.0*(q1.x*q1.z - q1.w*q1.y))); + + m01 = (float)(s*(2.0*(q1.x*q1.y - q1.w*q1.z))); + m11 = (float)(s*(1.0 - 2.0*q1.x*q1.x - 2.0*q1.z*q1.z)); + m21 = (float)(s*(2.0*(q1.y*q1.z + q1.w*q1.x))); + + m02 = (float)(s*(2.0*(q1.x*q1.z + q1.w*q1.y))); + m12 = (float)(s*(2.0*(q1.y*q1.z - q1.w*q1.x))); + m22 = (float)(s*(1.0 - 2.0*q1.x*q1.x - 2.0*q1.y*q1.y)); + + m03 = t1.x; + m13 = t1.y; + m23 = t1.z; + + m30 = 0.0f; + m31 = 0.0f; + m32 = 0.0f; + m33 = 1.0f; + + } + + /** + * Constructs a new matrix with the same values as the + * Matrix4d parameter. + * @param m1 the source matrix + */ + public Matrix4f(Matrix4d m1) + { + this.m00 = (float)m1.m00; + this.m01 = (float)m1.m01; + this.m02 = (float)m1.m02; + this.m03 = (float)m1.m03; + + this.m10 = (float)m1.m10; + this.m11 = (float)m1.m11; + this.m12 = (float)m1.m12; + this.m13 = (float)m1.m13; + + this.m20 = (float)m1.m20; + this.m21 = (float)m1.m21; + this.m22 = (float)m1.m22; + this.m23 = (float)m1.m23; + + this.m30 = (float)m1.m30; + this.m31 = (float)m1.m31; + this.m32 = (float)m1.m32; + this.m33 = (float)m1.m33; + + } + + + /** + * Constructs a new matrix with the same values as the + * Matrix4f parameter. + * @param m1 the source matrix + */ + public Matrix4f(Matrix4f m1) + { + this.m00 = m1.m00; + this.m01 = m1.m01; + this.m02 = m1.m02; + this.m03 = m1.m03; + + this.m10 = m1.m10; + this.m11 = m1.m11; + this.m12 = m1.m12; + this.m13 = m1.m13; + + this.m20 = m1.m20; + this.m21 = m1.m21; + this.m22 = m1.m22; + this.m23 = m1.m23; + + this.m30 = m1.m30; + this.m31 = m1.m31; + this.m32 = m1.m32; + this.m33 = m1.m33; + + } + + + /** + * Constructs and initializes a Matrix4f from the rotation matrix, + * translation, and scale values; the scale is applied only to the + * rotational components of the matrix (upper 3x3) and not to the + * translational components of the matrix. + * @param m1 the rotation matrix representing the rotational components + * @param t1 the translational components of the matrix + * @param s the scale value applied to the rotational components + */ + public Matrix4f(Matrix3f m1, Vector3f t1, float s) + { + this.m00 = m1.m00*s; + this.m01 = m1.m01*s; + this.m02 = m1.m02*s; + this.m03 = t1.x; + + this.m10 = m1.m10*s; + this.m11 = m1.m11*s; + this.m12 = m1.m12*s; + this.m13 = t1.y; + + this.m20 = m1.m20*s; + this.m21 = m1.m21*s; + this.m22 = m1.m22*s; + this.m23 = t1.z; + + this.m30 = 0.0f; + this.m31 = 0.0f; + this.m32 = 0.0f; + this.m33 = 1.0f; + + } + + + /** + * Constructs and initializes a Matrix4f to all zeros. + */ + public Matrix4f() + { + this.m00 = (float) 0.0; + this.m01 = (float) 0.0; + this.m02 = (float) 0.0; + this.m03 = (float) 0.0; + + this.m10 = (float) 0.0; + this.m11 = (float) 0.0; + this.m12 = (float) 0.0; + this.m13 = (float) 0.0; + + this.m20 = (float) 0.0; + this.m21 = (float) 0.0; + this.m22 = (float) 0.0; + this.m23 = (float) 0.0; + + this.m30 = (float) 0.0; + this.m31 = (float) 0.0; + this.m32 = (float) 0.0; + this.m33 = (float) 0.0; + + } + + /** + * Returns a string that contains the values of this Matrix4f. + * @return the String representation + */ + public String toString() { + return + this.m00 + ", " + this.m01 + ", " + this.m02 + ", " + this.m03 + "\n" + + this.m10 + ", " + this.m11 + ", " + this.m12 + ", " + this.m13 + "\n" + + this.m20 + ", " + this.m21 + ", " + this.m22 + ", " + this.m23 + "\n" + + this.m30 + ", " + this.m31 + ", " + this.m32 + ", " + this.m33 + "\n"; + } + + /** + * Sets this Matrix4f to identity. + */ + public final void setIdentity() + { + this.m00 = (float) 1.0; + this.m01 = (float) 0.0; + this.m02 = (float) 0.0; + this.m03 = (float) 0.0; + + this.m10 = (float) 0.0; + this.m11 = (float) 1.0; + this.m12 = (float) 0.0; + this.m13 = (float) 0.0; + + this.m20 = (float) 0.0; + this.m21 = (float) 0.0; + this.m22 = (float) 1.0; + this.m23 = (float) 0.0; + + this.m30 = (float) 0.0; + this.m31 = (float) 0.0; + this.m32 = (float) 0.0; + this.m33 = (float) 1.0; + } + + /** + * Sets the specified element of this matrix4f 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, float 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; + case 3: + this.m03 = value; + break; + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4f0")); + } + break; + + case 1: + switch(column) + { + case 0: + this.m10 = value; + break; + case 1: + this.m11 = value; + break; + case 2: + this.m12 = value; + break; + case 3: + this.m13 = value; + break; + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4f0")); + } + break; + + case 2: + switch(column) + { + case 0: + this.m20 = value; + break; + case 1: + this.m21 = value; + break; + case 2: + this.m22 = value; + break; + case 3: + this.m23 = value; + break; + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4f0")); + } + break; + + case 3: + switch(column) + { + case 0: + this.m30 = value; + break; + case 1: + this.m31 = value; + break; + case 2: + this.m32 = value; + break; + case 3: + this.m33 = value; + break; + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4f0")); + } + break; + + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4f0")); + } + } + + /** + * Retrieves the value at the specified row and column of this 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 float 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); + case 3: + return(this.m03); + default: + break; + } + break; + case 1: + switch(column) + { + case 0: + return(this.m10); + case 1: + return(this.m11); + case 2: + return(this.m12); + case 3: + return(this.m13); + default: + break; + } + break; + + case 2: + switch(column) + { + case 0: + return(this.m20); + case 1: + return(this.m21); + case 2: + return(this.m22); + case 3: + return(this.m23); + default: + break; + } + break; + + case 3: + switch(column) + { + case 0: + return(this.m30); + case 1: + return(this.m31); + case 2: + return(this.m32); + case 3: + return(this.m33); + default: + break; + } + break; + + default: + break; + } + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4f1")); + } + + /** + * 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, Vector4f v) { + if( row == 0 ) { + v.x = m00; + v.y = m01; + v.z = m02; + v.w = m03; + } else if(row == 1) { + v.x = m10; + v.y = m11; + v.z = m12; + v.w = m13; + } else if(row == 2) { + v.x = m20; + v.y = m21; + v.z = m22; + v.w = m23; + } else if(row == 3) { + v.x = m30; + v.y = m31; + v.z = m32; + v.w = m33; + } else { + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4f2")); + } + + } + + /** + * 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, float v[]) { + if( row == 0 ) { + v[0] = m00; + v[1] = m01; + v[2] = m02; + v[3] = m03; + } else if(row == 1) { + v[0] = m10; + v[1] = m11; + v[2] = m12; + v[3] = m13; + } else if(row == 2) { + v[0] = m20; + v[1] = m21; + v[2] = m22; + v[3] = m23; + } else if(row == 3) { + v[0] = m30; + v[1] = m31; + v[2] = m32; + v[3] = m33; + } else { + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4f2")); + } + + } + + /** + * 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, Vector4f v) { + if( column == 0 ) { + v.x = m00; + v.y = m10; + v.z = m20; + v.w = m30; + } else if(column == 1) { + v.x = m01; + v.y = m11; + v.z = m21; + v.w = m31; + } else if(column == 2) { + v.x = m02; + v.y = m12; + v.z = m22; + v.w = m32; + } else if(column == 3) { + v.x = m03; + v.y = m13; + v.z = m23; + v.w = m33; + } else { + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4f4")); + } + + } + + /** + * 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, float v[]) { + if( column == 0 ) { + v[0] = m00; + v[1] = m10; + v[2] = m20; + v[3] = m30; + } else if(column == 1) { + v[0] = m01; + v[1] = m11; + v[2] = m21; + v[3] = m31; + } else if(column == 2) { + v[0] = m02; + v[1] = m12; + v[2] = m22; + v[3] = m32; + } else if(column == 3) { + v[0] = m03; + v[1] = m13; + v[2] = m23; + v[3] = m33; + } else { + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4f4")); + } + + } + + + /** + * Sets the scale component of the current matrix by factoring + * out the current scale (by doing an SVD) from the rotational + * component and multiplying by the new scale. + * @param scale the new scale amount + */ + public final void setScale(float scale){ + + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + getScaleRotate( tmp_scale, tmp_rot ); + + m00 = (float)(tmp_rot[0]*scale); + m01 = (float)(tmp_rot[1]*scale); + m02 = (float)(tmp_rot[2]*scale); + + m10 = (float)(tmp_rot[3]*scale); + m11 = (float)(tmp_rot[4]*scale); + m12 = (float)(tmp_rot[5]*scale); + + m20 = (float)(tmp_rot[6]*scale); + m21 = (float)(tmp_rot[7]*scale); + m22 = (float)(tmp_rot[8]*scale); + + } + + /** + * Performs an SVD normalization of this matrix in order to acquire + * the normalized rotational component; the values are placed into + * the Matrix3d parameter. + * @param m1 matrix into which the rotational component is placed + */ + public final void get(Matrix3d m1){ + + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + + getScaleRotate( tmp_scale, tmp_rot ); + + m1.m00 = tmp_rot[0]; + m1.m01 = tmp_rot[1]; + m1.m02 = tmp_rot[2]; + + m1.m10 = tmp_rot[3]; + m1.m11 = tmp_rot[4]; + m1.m12 = tmp_rot[5]; + + m1.m20 = tmp_rot[6]; + m1.m21 = tmp_rot[7]; + m1.m22 = tmp_rot[8]; + + } + + /** + * Performs an SVD normalization of this matrix in order to acquire + * the normalized rotational component; the values are placed into + * the Matrix3f parameter. + * @param m1 matrix into which the rotational component is placed + */ + public final void get(Matrix3f m1) + { + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + + getScaleRotate( tmp_scale, tmp_rot ); + + m1.m00 = (float)tmp_rot[0]; + m1.m01 = (float)tmp_rot[1]; + m1.m02 = (float)tmp_rot[2]; + + m1.m10 = (float)tmp_rot[3]; + m1.m11 = (float)tmp_rot[4]; + m1.m12 = (float)tmp_rot[5]; + + m1.m20 = (float)tmp_rot[6]; + m1.m21 = (float)tmp_rot[7]; + m1.m22 = (float)tmp_rot[8]; + + } + + + /** + * Performs an SVD normalization of this matrix to calculate + * the rotation as a 3x3 matrix, the translation, and the scale. + * None of the matrix values are modified. + * @param m1 the normalized matrix representing the rotation + * @param t1 the translation component + * @return the scale component of this transform + */ + public final float get(Matrix3f m1, Vector3f t1) + { + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + + getScaleRotate( tmp_scale, tmp_rot ); + + m1.m00 = (float)tmp_rot[0]; + m1.m01 = (float)tmp_rot[1]; + m1.m02 = (float)tmp_rot[2]; + + m1.m10 = (float)tmp_rot[3]; + m1.m11 = (float)tmp_rot[4]; + m1.m12 = (float)tmp_rot[5]; + + m1.m20 = (float)tmp_rot[6]; + m1.m21 = (float)tmp_rot[7]; + m1.m22 = (float)tmp_rot[8]; + + t1.x = m03; + t1.y = m13; + t1.z = m23; + + return( (float)Matrix3d.max3( tmp_scale )); + + } + + + /** + * Performs an SVD normalization of this matrix in order to acquire + * the normalized rotational component; the values are placed into + * the Quat4f parameter. + * @param q1 quaternion into which the rotation component is placed + */ + public final void get(Quat4f q1){ + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + getScaleRotate( tmp_scale, tmp_rot ); + + double ww; + + ww = 0.25*(1.0 + tmp_rot[0] + tmp_rot[4] + tmp_rot[8]); + if(!((ww<0?-ww:ww) < 1.0e-30)) { + q1.w = (float)Math.sqrt(ww); + ww = 0.25/q1.w; + q1.x = (float)((tmp_rot[7] - tmp_rot[5])*ww); + q1.y = (float)((tmp_rot[2] - tmp_rot[6])*ww); + q1.z = (float)((tmp_rot[3] - tmp_rot[1])*ww); + return; + } + + q1.w = 0.0f; + ww = -0.5*(tmp_rot[4] + tmp_rot[8]); + if(!((ww<0?-ww:ww) < 1.0e-30)) { + q1.x = (float)Math.sqrt(ww); + ww = 0.5/q1.x; + q1.y = (float)(tmp_rot[3]*ww); + q1.z = (float)(tmp_rot[6]*ww); + return; + } + + q1.x = 0.0f; + ww = 0.5*(1.0 - tmp_rot[8]); + if(!((ww<0?-ww:ww) < 1.0e-30)) { + q1.y = (float)(Math.sqrt(ww)); + q1.z = (float)(tmp_rot[7]/(2.0*q1.y)); + return; + } + + q1.y = 0.0f; + q1.z = 1.0f; + + } + + + /** + * Retrieves the translational components of this matrix. + * @param trans the vector that will receive the translational component + */ + public final void get(Vector3f trans) + { + trans.x = m03; + trans.y = m13; + trans.z = m23; + } + + /** + * Gets the upper 3x3 values of this matrix and places them into + * the matrix m1. + * @param m1 the matrix that will hold the values + */ + public final void getRotationScale(Matrix3f m1) + { + m1.m00 = m00; m1.m01 = m01; m1.m02 = m02; + m1.m10 = m10; m1.m11 = m11; m1.m12 = m12; + m1.m20 = m20; m1.m21 = m21; m1.m22 = m22; + } + + /** + * 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 float getScale() + { + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + + getScaleRotate( tmp_scale, tmp_rot ); + + return( (float)Matrix3d.max3( tmp_scale )); + + } + + + /** + * Replaces the upper 3x3 matrix values of this matrix with the + * values in the matrix m1. + * @param m1 the matrix that will be the new upper 3x3 + */ + public final void setRotationScale(Matrix3f m1) + { + m00 = m1.m00; m01 = m1.m01; m02 = m1.m02; + m10 = m1.m10; m11 = m1.m11; m12 = m1.m12; + m20 = m1.m20; m21 = m1.m21; m22 = m1.m22; + } + + + /** + * Sets the specified row of this matrix4f to the four 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 + * @param w the fourth column element + */ + public final void setRow(int row, float x, float y, float z, float w) + { + switch (row) { + case 0: + this.m00 = x; + this.m01 = y; + this.m02 = z; + this.m03 = w; + break; + + case 1: + this.m10 = x; + this.m11 = y; + this.m12 = z; + this.m13 = w; + break; + + case 2: + this.m20 = x; + this.m21 = y; + this.m22 = z; + this.m23 = w; + break; + + case 3: + this.m30 = x; + this.m31 = y; + this.m32 = z; + this.m33 = w; + break; + + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4f6")); + } + } + + /** + * Sets the specified row of this matrix4f 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, Vector4f v) + { + switch (row) { + case 0: + this.m00 = v.x; + this.m01 = v.y; + this.m02 = v.z; + this.m03 = v.w; + break; + + case 1: + this.m10 = v.x; + this.m11 = v.y; + this.m12 = v.z; + this.m13 = v.w; + break; + + case 2: + this.m20 = v.x; + this.m21 = v.y; + this.m22 = v.z; + this.m23 = v.w; + break; + + case 3: + this.m30 = v.x; + this.m31 = v.y; + this.m32 = v.z; + this.m33 = v.w; + break; + + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4f6")); + } + } + + /** + * Sets the specified row of this matrix4f to the four values provided + * in the passed array. + * @param row the row number to be modified (zero indexed) + * @param v the replacement row + */ + public final void setRow(int row, float v[]) + { + switch (row) { + case 0: + this.m00 = v[0]; + this.m01 = v[1]; + this.m02 = v[2]; + this.m03 = v[3]; + break; + + case 1: + this.m10 = v[0]; + this.m11 = v[1]; + this.m12 = v[2]; + this.m13 = v[3]; + break; + + case 2: + this.m20 = v[0]; + this.m21 = v[1]; + this.m22 = v[2]; + this.m23 = v[3]; + break; + + case 3: + this.m30 = v[0]; + this.m31 = v[1]; + this.m32 = v[2]; + this.m33 = v[3]; + break; + + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4f6")); + } + } + + /** + * Sets the specified column of this matrix4f to the four 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 + * @param w the fourth row element + */ + public final void setColumn(int column, float x, float y, float z, float w) + { + switch (column) { + case 0: + this.m00 = x; + this.m10 = y; + this.m20 = z; + this.m30 = w; + break; + + case 1: + this.m01 = x; + this.m11 = y; + this.m21 = z; + this.m31 = w; + break; + + case 2: + this.m02 = x; + this.m12 = y; + this.m22 = z; + this.m32 = w; + break; + + case 3: + this.m03 = x; + this.m13 = y; + this.m23 = z; + this.m33 = w; + break; + + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4f9")); + } + } + + /** + * Sets the specified column of this matrix4f 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, Vector4f v) + { + switch (column) { + case 0: + this.m00 = v.x; + this.m10 = v.y; + this.m20 = v.z; + this.m30 = v.w; + break; + + case 1: + this.m01 = v.x; + this.m11 = v.y; + this.m21 = v.z; + this.m31 = v.w; + break; + + case 2: + this.m02 = v.x; + this.m12 = v.y; + this.m22 = v.z; + this.m32 = v.w; + break; + + case 3: + this.m03 = v.x; + this.m13 = v.y; + this.m23 = v.z; + this.m33 = v.w; + break; + + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4f9")); + } + } + + /** + * Sets the specified column of this matrix4f to the four values provided. + * @param column the column number to be modified (zero indexed) + * @param v the replacement column + */ + public final void setColumn(int column, float v[]) + { + switch (column) { + case 0: + this.m00 = v[0]; + this.m10 = v[1]; + this.m20 = v[2]; + this.m30 = v[3]; + break; + + case 1: + this.m01 = v[0]; + this.m11 = v[1]; + this.m21 = v[2]; + this.m31 = v[3]; + break; + + case 2: + this.m02 = v[0]; + this.m12 = v[1]; + this.m22 = v[2]; + this.m32 = v[3]; + break; + + case 3: + this.m03 = v[0]; + this.m13 = v[1]; + this.m23 = v[2]; + this.m33 = v[3]; + break; + + default: + throw new ArrayIndexOutOfBoundsException(VecMathI18N.getString("Matrix4f9")); + } + } + + /** + * Adds a scalar to each component of this matrix. + * @param scalar the scalar adder + */ + public final void add(float scalar) + { + m00 += scalar; + m01 += scalar; + m02 += scalar; + m03 += scalar; + m10 += scalar; + m11 += scalar; + m12 += scalar; + m13 += scalar; + m20 += scalar; + m21 += scalar; + m22 += scalar; + m23 += scalar; + m30 += scalar; + m31 += scalar; + m32 += scalar; + m33 += 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(float scalar, Matrix4f m1) + { + this.m00 = m1.m00 + scalar; + this.m01 = m1.m01 + scalar; + this.m02 = m1.m02 + scalar; + this.m03 = m1.m03 + scalar; + this.m10 = m1.m10 + scalar; + this.m11 = m1.m11 + scalar; + this.m12 = m1.m12 + scalar; + this.m13 = m1.m13 + scalar; + this.m20 = m1.m20 + scalar; + this.m21 = m1.m21 + scalar; + this.m22 = m1.m22 + scalar; + this.m23 = m1.m23 + scalar; + this.m30 = m1.m30 + scalar; + this.m31 = m1.m31 + scalar; + this.m32 = m1.m32 + scalar; + this.m33 = m1.m33 + 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(Matrix4f m1, Matrix4f m2) + { + this.m00 = m1.m00 + m2.m00; + this.m01 = m1.m01 + m2.m01; + this.m02 = m1.m02 + m2.m02; + this.m03 = m1.m03 + m2.m03; + + this.m10 = m1.m10 + m2.m10; + this.m11 = m1.m11 + m2.m11; + this.m12 = m1.m12 + m2.m12; + this.m13 = m1.m13 + m2.m13; + + this.m20 = m1.m20 + m2.m20; + this.m21 = m1.m21 + m2.m21; + this.m22 = m1.m22 + m2.m22; + this.m23 = m1.m23 + m2.m23; + + this.m30 = m1.m30 + m2.m30; + this.m31 = m1.m31 + m2.m31; + this.m32 = m1.m32 + m2.m32; + this.m33 = m1.m33 + m2.m33; + } + + + /** + * Sets the value of this matrix to the sum of itself and matrix m1. + * @param m1 the other matrix + */ + public final void add(Matrix4f m1) + { + this.m00 += m1.m00; + this.m01 += m1.m01; + this.m02 += m1.m02; + this.m03 += m1.m03; + + this.m10 += m1.m10; + this.m11 += m1.m11; + this.m12 += m1.m12; + this.m13 += m1.m13; + + this.m20 += m1.m20; + this.m21 += m1.m21; + this.m22 += m1.m22; + this.m23 += m1.m23; + + this.m30 += m1.m30; + this.m31 += m1.m31; + this.m32 += m1.m32; + this.m33 += m1.m33; + } + + /** + * Performs an element-by-element subtraction of matrix m2 from + * matrix m1 and places the result into matrix this (this = + * m2 - m1). + * @param m1 the first matrix + * @param m2 the second matrix + */ + public final void sub(Matrix4f m1, Matrix4f m2) + { + this.m00 = m1.m00 - m2.m00; + this.m01 = m1.m01 - m2.m01; + this.m02 = m1.m02 - m2.m02; + this.m03 = m1.m03 - m2.m03; + + this.m10 = m1.m10 - m2.m10; + this.m11 = m1.m11 - m2.m11; + this.m12 = m1.m12 - m2.m12; + this.m13 = m1.m13 - m2.m13; + + this.m20 = m1.m20 - m2.m20; + this.m21 = m1.m21 - m2.m21; + this.m22 = m1.m22 - m2.m22; + this.m23 = m1.m23 - m2.m23; + + this.m30 = m1.m30 - m2.m30; + this.m31 = m1.m31 - m2.m31; + this.m32 = m1.m32 - m2.m32; + this.m33 = m1.m33 - m2.m33; + } + + /** + * Sets this matrix to the matrix difference of itself and + * matrix m1 (this = this - m1). + * @param m1 the other matrix + */ + public final void sub(Matrix4f m1) + { + this.m00 -= m1.m00; + this.m01 -= m1.m01; + this.m02 -= m1.m02; + this.m03 -= m1.m03; + + this.m10 -= m1.m10; + this.m11 -= m1.m11; + this.m12 -= m1.m12; + this.m13 -= m1.m13; + + this.m20 -= m1.m20; + this.m21 -= m1.m21; + this.m22 -= m1.m22; + this.m23 -= m1.m23; + + this.m30 -= m1.m30; + this.m31 -= m1.m31; + this.m32 -= m1.m32; + this.m33 -= m1.m33; + } + + /** + * Sets the value of this matrix to its transpose in place. + */ + public final void transpose() + { + float temp; + + temp = this.m10; + this.m10 = this.m01; + this.m01 = temp; + + temp = this.m20; + this.m20 = this.m02; + this.m02 = temp; + + temp = this.m30; + this.m30 = this.m03; + this.m03 = temp; + + temp = this.m21; + this.m21 = this.m12; + this.m12 = temp; + + temp = this.m31; + this.m31 = this.m13; + this.m13 = temp; + + temp = this.m32; + this.m32 = this.m23; + this.m23 = 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(Matrix4f m1) + { + if (this != m1) { + this.m00 = m1.m00; + this.m01 = m1.m10; + this.m02 = m1.m20; + this.m03 = m1.m30; + + this.m10 = m1.m01; + this.m11 = m1.m11; + this.m12 = m1.m21; + this.m13 = m1.m31; + + this.m20 = m1.m02; + this.m21 = m1.m12; + this.m22 = m1.m22; + this.m23 = m1.m32; + + this.m30 = m1.m03; + this.m31 = m1.m13; + this.m32 = m1.m23; + this.m33 = m1.m33; + } else + this.transpose(); + } + + /** + * 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.0f - 2.0f*q1.y*q1.y - 2.0f*q1.z*q1.z); + this.m10 = (2.0f*(q1.x*q1.y + q1.w*q1.z)); + this.m20 = (2.0f*(q1.x*q1.z - q1.w*q1.y)); + + this.m01 = (2.0f*(q1.x*q1.y - q1.w*q1.z)); + this.m11 = (1.0f - 2.0f*q1.x*q1.x - 2.0f*q1.z*q1.z); + this.m21 = (2.0f*(q1.y*q1.z + q1.w*q1.x)); + + this.m02 = (2.0f*(q1.x*q1.z + q1.w*q1.y)); + this.m12 = (2.0f*(q1.y*q1.z - q1.w*q1.x)); + this.m22 = (1.0f - 2.0f*q1.x*q1.x - 2.0f*q1.y*q1.y); + + this.m03 = (float) 0.0; + this.m13 = (float) 0.0; + this.m23 = (float) 0.0; + + this.m30 = (float) 0.0; + this.m31 = (float) 0.0; + this.m32 = (float) 0.0; + this.m33 = (float) 1.0; + } + + /** + * 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) + { + float mag = (float)Math.sqrt( a1.x*a1.x + a1.y*a1.y + a1.z*a1.z); + if( mag < EPS ) { + m00 = 1.0f; + m01 = 0.0f; + m02 = 0.0f; + + m10 = 0.0f; + m11 = 1.0f; + m12 = 0.0f; + + m20 = 0.0f; + m21 = 0.0f; + m22 = 1.0f; + } else { + mag = 1.0f/mag; + float ax = a1.x*mag; + float ay = a1.y*mag; + float az = a1.z*mag; + + float sinTheta = (float)Math.sin((double)a1.angle); + float cosTheta = (float)Math.cos((double)a1.angle); + float t = 1.0f - cosTheta; + + float xz = ax * az; + float xy = ax * ay; + float 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; + } + m03 = 0.0f; + m13 = 0.0f; + m23 = 0.0f; + + m30 = 0.0f; + m31 = 0.0f; + m32 = 0.0f; + m33 = 1.0f; + } + + /** + * 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 = (float) (1.0 - 2.0*q1.y*q1.y - 2.0*q1.z*q1.z); + this.m10 = (float) (2.0*(q1.x*q1.y + q1.w*q1.z)); + this.m20 = (float) (2.0*(q1.x*q1.z - q1.w*q1.y)); + + this.m01 = (float) (2.0*(q1.x*q1.y - q1.w*q1.z)); + this.m11 = (float) (1.0 - 2.0*q1.x*q1.x - 2.0*q1.z*q1.z); + this.m21 = (float) (2.0*(q1.y*q1.z + q1.w*q1.x)); + + this.m02 = (float) (2.0*(q1.x*q1.z + q1.w*q1.y)); + this.m12 = (float) (2.0*(q1.y*q1.z - q1.w*q1.x)); + this.m22 = (float) (1.0 - 2.0*q1.x*q1.x - 2.0*q1.y*q1.y); + + this.m03 = (float) 0.0; + this.m13 = (float) 0.0; + this.m23 = (float) 0.0; + + this.m30 = (float) 0.0; + this.m31 = (float) 0.0; + this.m32 = (float) 0.0; + this.m33 = (float) 1.0; + } + + /** + * 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.0f; + m01 = 0.0f; + m02 = 0.0f; + + m10 = 0.0f; + m11 = 1.0f; + m12 = 0.0f; + + m20 = 0.0f; + m21 = 0.0f; + m22 = 1.0f; + } else { + mag = 1.0/mag; + double ax = a1.x*mag; + double ay = a1.y*mag; + double az = a1.z*mag; + + float sinTheta = (float) Math.sin(a1.angle); + float cosTheta = (float) Math.cos(a1.angle); + float t = 1.0f - cosTheta; + + float xz = (float) (ax * az); + float xy = (float) (ax * ay); + float yz = (float) (ay * az); + + this.m00 = t * (float)(ax * ax) + cosTheta; + this.m01 = t * xy - sinTheta * (float)az; + this.m02 = t * xz + sinTheta * (float)ay; + + this.m10 = t * xy + sinTheta * (float)az; + this.m11 = t * (float)(ay * ay) + cosTheta; + this.m12 = t * yz - sinTheta * (float)ax; + + this.m20 = t * xz - sinTheta * (float)ay; + this.m21 = t * yz + sinTheta * (float)ax; + this.m22 = t * (float)(az * az) + cosTheta; + } + this.m03 = 0.0f; + this.m13 = 0.0f; + this.m23 = 0.0f; + + this.m30 = 0.0f; + this.m31 = 0.0f; + this.m32 = 0.0f; + this.m33 = 1.0f; + } + + /** + * Sets the value of this matrix from the rotation expressed + * by the quaternion q1, the translation t1, and the scale s. + * @param q1 the rotation expressed as a quaternion + * @param t1 the translation + * @param s the scale value + */ + public final void set(Quat4d q1, Vector3d t1, double s) + { + this.m00 = (float) (s*(1.0 - 2.0*q1.y*q1.y -2.0*q1.z*q1.z)); + this.m10 = (float) (s*(2.0*(q1.x*q1.y + q1.w*q1.z))); + this.m20 = (float) (s*(2.0*(q1.x*q1.z - q1.w*q1.y))); + + this.m01 = (float) (s*(2.0*(q1.x*q1.y - q1.w*q1.z))); + this.m11 = (float) (s*(1.0 - 2.0*q1.x*q1.x -2.0*q1.z*q1.z)); + this.m21 = (float) (s*(2.0*(q1.y*q1.z + q1.w*q1.x))); + + this.m02 = (float) (s*(2.0*(q1.x*q1.z + q1.w*q1.y))); + this.m12 = (float) (s*(2.0*(q1.y*q1.z - q1.w*q1.x))); + this.m22 = (float) (s*(1.0 - 2.0*q1.x*q1.x -2.0*q1.y*q1.y)); + + this.m03 = (float) t1.x; + this.m13 = (float) t1.y; + this.m23 = (float) t1.z; + + this.m30 = (float) 0.0; + this.m31 = (float) 0.0; + this.m32 = (float) 0.0; + this.m33 = (float) 1.0; + } + + /** + * Sets the value of this matrix from the rotation expressed + * by the quaternion q1, the translation t1, and the scale s. + * @param q1 the rotation expressed as a quaternion + * @param t1 the translation + * @param s the scale value + */ + public final void set(Quat4f q1, Vector3f t1, float s) + { + this.m00 = (s*(1.0f - 2.0f*q1.y*q1.y -2.0f*q1.z*q1.z)); + this.m10 = (s*(2.0f*(q1.x*q1.y + q1.w*q1.z))); + this.m20 = (s*(2.0f*(q1.x*q1.z - q1.w*q1.y))); + + this.m01 = (s*(2.0f*(q1.x*q1.y - q1.w*q1.z))); + this.m11 = (s*(1.0f - 2.0f*q1.x*q1.x -2.0f*q1.z*q1.z)); + this.m21 = (s*(2.0f*(q1.y*q1.z + q1.w*q1.x))); + + this.m02 = (s*(2.0f*(q1.x*q1.z + q1.w*q1.y))); + this.m12 = (s*(2.0f*(q1.y*q1.z - q1.w*q1.x))); + this.m22 = (s*(1.0f - 2.0f*q1.x*q1.x - 2.0f*q1.y*q1.y)); + + this.m03 = t1.x; + this.m13 = t1.y; + this.m23 = t1.z; + + this.m30 = (float) 0.0; + this.m31 = (float) 0.0; + this.m32 = (float) 0.0; + this.m33 = (float) 1.0; + } + + /** + * Sets the value of this matrix to the float value of the + * passed matrix4d m1. + * @param m1 the matrix4d to be converted to float + */ + public final void set(Matrix4d m1) + { + this.m00 = (float) m1.m00; + this.m01 = (float) m1.m01; + this.m02 = (float) m1.m02; + this.m03 = (float) m1.m03; + + this.m10 = (float) m1.m10; + this.m11 = (float) m1.m11; + this.m12 = (float) m1.m12; + this.m13 = (float) m1.m13; + + this.m20 = (float) m1.m20; + this.m21 = (float) m1.m21; + this.m22 = (float) m1.m22; + this.m23 = (float) m1.m23; + + this.m30 = (float) m1.m30; + this.m31 = (float) m1.m31; + this.m32 = (float) m1.m32; + this.m33 = (float) m1.m33; + } + + /** + * Sets the value of this matrix to a copy of the + * passed matrix m1. + * @param m1 the matrix to be copied + */ + public final void set(Matrix4f m1) + { + this.m00 = m1.m00; + this.m01 = m1.m01; + this.m02 = m1.m02; + this.m03 = m1.m03; + + this.m10 = m1.m10; + this.m11 = m1.m11; + this.m12 = m1.m12; + this.m13 = m1.m13; + + this.m20 = m1.m20; + this.m21 = m1.m21; + this.m22 = m1.m22; + this.m23 = m1.m23; + + this.m30 = m1.m30; + this.m31 = m1.m31; + this.m32 = m1.m32; + this.m33 = m1.m33; + } + + /** + * Sets the value of this matrix to the matrix inverse + * of the passed (user declared) matrix m1. + * @param m1 the matrix to be inverted + */ + public final void invert(Matrix4f 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. + */ + final void invertGeneral(Matrix4f m1) { + double temp[] = new double[16]; + double result[] = new double[16]; + int row_perm[] = new int[4]; + int i, r, c; + + // Use LU decomposition and backsubstitution code specifically + // for floating-point 4x4 matrices. + + // Copy source matrix to t1tmp + temp[0] = m1.m00; + temp[1] = m1.m01; + temp[2] = m1.m02; + temp[3] = m1.m03; + + temp[4] = m1.m10; + temp[5] = m1.m11; + temp[6] = m1.m12; + temp[7] = m1.m13; + + temp[8] = m1.m20; + temp[9] = m1.m21; + temp[10] = m1.m22; + temp[11] = m1.m23; + + temp[12] = m1.m30; + temp[13] = m1.m31; + temp[14] = m1.m32; + temp[15] = m1.m33; + + // Calculate LU decomposition: Is the matrix singular? + if (!luDecomposition(temp, row_perm)) { + // Matrix has no inverse + throw new SingularMatrixException(VecMathI18N.getString("Matrix4f12")); + } + + // Perform back substitution on the identity matrix + for(i=0;i<16;i++) result[i] = 0.0; + result[0] = 1.0; result[5] = 1.0; result[10] = 1.0; result[15] = 1.0; + luBacksubstitution(temp, row_perm, result); + + this.m00 = (float)result[0]; + this.m01 = (float)result[1]; + this.m02 = (float)result[2]; + this.m03 = (float)result[3]; + + this.m10 = (float)result[4]; + this.m11 = (float)result[5]; + this.m12 = (float)result[6]; + this.m13 = (float)result[7]; + + this.m20 = (float)result[8]; + this.m21 = (float)result[9]; + this.m22 = (float)result[10]; + this.m23 = (float)result[11]; + + this.m30 = (float)result[12]; + this.m31 = (float)result[13]; + this.m32 = (float)result[14]; + this.m33 = (float)result[15]; + + } + + /** + * Given a 4x4 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[4]" 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 4x4 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[4]; + + // 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 = 4; + while (i-- != 0) { + big = 0.0; + + // For each column, find the largest element in the row + j = 4; + 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 < 4; 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 + (4*i) + j; + sum = matrix0[target]; + k = i; + p1 = mtx + (4*i); + p2 = mtx + j; + while (k-- != 0) { + sum -= matrix0[p1] * matrix0[p2]; + p1++; + p2 += 4; + } + 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 < 4; i++) { + target = mtx + (4*i) + j; + sum = matrix0[target]; + k = j; + p1 = mtx + (4*i); + p2 = mtx + j; + while (k-- != 0) { + sum -= matrix0[p1] * matrix0[p2]; + p1++; + p2 += 4; + } + 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("Matrix4f13")); + } + + // Is a row exchange necessary? + if (j != imax) { + // Yes: exchange rows + k = 4; + p1 = mtx + (4*imax); + p2 = mtx + (4*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 + (4*j) + j)] == 0.0) { + return false; + } + + // Divide elements of lower diagonal matrix L by pivot + if (j != (4-1)) { + temp = 1.0 / (matrix0[(mtx + (4*j) + j)]); + target = mtx + (4*(j+1)) + j; + i = 3 - j; + while (i-- != 0) { + matrix0[target] *= temp; + target += 4; + } + } + } + } + + return true; + } + + /** + * Solves a set of linear equations. The input parameters "matrix1", + * and "row_perm" come from luDecompostionD4x4 and do not change + * here. The parameter "matrix2" is a set of column vectors assembled + * into a 4x4 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 < 4; k++) { + // cv = &(matrix2[0][k]); + cv = k; + ii = -1; + + // Forward substitution + for (i = 0; i < 4; i++) { + double sum; + + ip = row_perm[rp+i]; + sum = matrix2[cv+4*ip]; + matrix2[cv+4*ip] = matrix2[cv+4*i]; + if (ii >= 0) { + // rv = &(matrix1[i][0]); + rv = i*4; + for (j = ii; j <= i-1; j++) { + sum -= matrix1[rv+j] * matrix2[cv+4*j]; + } + } + else if (sum != 0.0) { + ii = i; + } + matrix2[cv+4*i] = sum; + } + + // Backsubstitution + // rv = &(matrix1[3][0]); + rv = 3*4; + matrix2[cv+4*3] /= matrix1[rv+3]; + + rv -= 4; + matrix2[cv+4*2] = (matrix2[cv+4*2] - + matrix1[rv+3] * matrix2[cv+4*3]) / matrix1[rv+2]; + + rv -= 4; + matrix2[cv+4*1] = (matrix2[cv+4*1] - + matrix1[rv+2] * matrix2[cv+4*2] - + matrix1[rv+3] * matrix2[cv+4*3]) / matrix1[rv+1]; + + rv -= 4; + matrix2[cv+4*0] = (matrix2[cv+4*0] - + matrix1[rv+1] * matrix2[cv+4*1] - + matrix1[rv+2] * matrix2[cv+4*2] - + matrix1[rv+3] * matrix2[cv+4*3]) / matrix1[rv+0]; + } + } + + /** + * Computes the determinate of this matrix. + * @return the determinate of the matrix + */ + public final float determinant() + { + float det; + + // cofactor exapainsion along first row + + det = m00*(m11*m22*m33+ m12*m23*m31 + m13*m21*m32 + - m13*m22*m31 -m11*m23*m32 - m12*m21*m33); + det -= m01*(m10*m22*m33+ m12*m23*m30 + m13*m20*m32 + - m13*m22*m30 -m10*m23*m32 - m12*m20*m33); + det += m02*(m10*m21*m33+ m11*m23*m30 + m13*m20*m31 + - m13*m21*m30 -m10*m23*m31 - m11*m20*m33); + det -= m03*(m10*m21*m32+ m11*m22*m30 + m12*m20*m31 + - m12*m21*m30 -m10*m22*m31 - m11*m20*m32); + + return( det ); + } + + /** + * Sets the rotational component (upper 3x3) of this matrix to the + * matrix values in the single precision Matrix3f argument; the other + * elements of this matrix are initialized as if this were an identity + * matrix (i.e., affine matrix with no translational component). + * @param m1 the single-precision 3x3 matrix + */ + public final void set(Matrix3f m1) + { + m00 = m1.m00; m01 = m1.m01; m02 = m1.m02; m03 = 0.0f; + m10 = m1.m10; m11 = m1.m11; m12 = m1.m12; m13 = 0.0f; + m20 = m1.m20; m21 = m1.m21; m22 = m1.m22; m23 = 0.0f; + m30 = 0.0f; m31 = 0.0f ; m32 = 0.0f ; m33 = 1.0f; + } + + /** + * Sets the rotational component (upper 3x3) of this matrix to the + * matrix values in the double precision Matrix3d argument; the other + * elements of this matrix are initialized as if this were an identity + * matrix (i.e., affine matrix with no translational component). + * @param m1 the double-precision 3x3 matrix + */ + public final void set(Matrix3d m1) + { + m00 = (float)m1.m00; m01 = (float)m1.m01; m02 = (float)m1.m02; m03 = 0.0f; + m10 = (float)m1.m10; m11 = (float)m1.m11; m12 = (float)m1.m12; m13 = 0.0f; + m20 = (float)m1.m20; m21 = (float)m1.m21; m22 = (float)m1.m22; m23 = 0.0f; + m30 = 0.0f; m31 = 0.0f ; m32 = 0.0f ; m33 = 1.0f; + } + + /** + * Sets the value of this matrix to a scale matrix with the + * the passed scale amount. + * @param scale the scale factor for the matrix + */ + public final void set(float scale) + { + this.m00 = scale; + this.m01 = (float) 0.0; + this.m02 = (float) 0.0; + this.m03 = (float) 0.0; + + this.m10 = (float) 0.0; + this.m11 = scale; + this.m12 = (float) 0.0; + this.m13 = (float) 0.0; + + this.m20 = (float) 0.0; + this.m21 = (float) 0.0; + this.m22 = scale; + this.m23 = (float) 0.0; + + this.m30 = (float) 0.0; + this.m31 = (float) 0.0; + this.m32 = (float) 0.0; + this.m33 = (float) 1.0; + } + + /** + * Sets the values in this Matrix4f equal to the row-major + * array parameter (ie, the first four elements of the + * array will be copied into the first row of this matrix, etc.). + * @param m the single precision array of length 16 + */ + public final void set(float[] m) + { + m00 = m[0]; + m01 = m[1]; + m02 = m[2]; + m03 = m[3]; + m10 = m[4]; + m11 = m[5]; + m12 = m[6]; + m13 = m[7]; + m20 = m[8]; + m21 = m[9]; + m22 = m[10]; + m23 = m[11]; + m30 = m[12]; + m31 = m[13]; + m32 = m[14]; + m33 = m[15]; + } + + /** + * Sets the value of this matrix to a translate matrix with + * the passed translation value. + * @param v1 the translation amount + */ + public final void set(Vector3f v1) + { + this.m00 = (float) 1.0; + this.m01 = (float) 0.0; + this.m02 = (float) 0.0; + this.m03 = v1.x; + + this.m10 = (float) 0.0; + this.m11 = (float) 1.0; + this.m12 = (float) 0.0; + this.m13 = v1.y; + + this.m20 = (float) 0.0; + this.m21 = (float) 0.0; + this.m22 = (float) 1.0; + this.m23 = v1.z; + + this.m30 = (float) 0.0; + this.m31 = (float) 0.0; + this.m32 = (float) 0.0; + this.m33 = (float) 1.0; + } + + /** + * Sets the value of this transform to a scale and translation matrix; + * the scale is not applied to the translation and all of the matrix + * values are modified. + * @param scale the scale factor for the matrix + * @param t1 the translation amount + */ + public final void set(float scale, Vector3f t1) + { + this.m00 = scale; + this.m01 = (float) 0.0; + this.m02 = (float) 0.0; + this.m03 = t1.x; + + this.m10 = (float) 0.0; + this.m11 = scale; + this.m12 = (float) 0.0; + this.m13 = t1.y; + + this.m20 = (float) 0.0; + this.m21 = (float) 0.0; + this.m22 = scale; + this.m23 = t1.z; + + this.m30 = (float) 0.0; + this.m31 = (float) 0.0; + this.m32 = (float) 0.0; + this.m33 = (float) 1.0; + } + + /** + * Sets the value of this transform to a scale and translation matrix; + * the translation is scaled by the scale factor and all of the matrix + * values are modified. + * @param t1 the translation amount + * @param scale the scale factor for the matrix + */ + public final void set(Vector3f t1, float scale) + { + this.m00 = scale; + this.m01 = (float) 0.0; + this.m02 = (float) 0.0; + this.m03 = scale*t1.x; + + this.m10 = (float) 0.0; + this.m11 = scale; + this.m12 = (float) 0.0; + this.m13 = scale*t1.y; + + this.m20 = (float) 0.0; + this.m21 = (float) 0.0; + this.m22 = scale; + this.m23 = scale*t1.z; + + this.m30 = (float) 0.0; + this.m31 = (float) 0.0; + this.m32 = (float) 0.0; + this.m33 = (float) 1.0; + } + + /** + * Sets the value of this matrix from the rotation expressed by + * the rotation matrix m1, the translation t1, and the scale factor. + * The translation is not modified by the scale. + * @param m1 the rotation component + * @param t1 the translation component + * @param scale the scale component + */ + public final void set(Matrix3f m1, Vector3f t1, float scale) + { + this.m00 = m1.m00*scale; + this.m01 = m1.m01*scale; + this.m02 = m1.m02*scale; + this.m03 = t1.x; + + this.m10 = m1.m10*scale; + this.m11 = m1.m11*scale; + this.m12 = m1.m12*scale; + this.m13 = t1.y; + + this.m20 = m1.m20*scale; + this.m21 = m1.m21*scale; + this.m22 = m1.m22*scale; + this.m23 = t1.z; + + this.m30 = 0.0f; + this.m31 = 0.0f; + this.m32 = 0.0f; + this.m33 = 1.0f; + } + + /** + * Sets the value of this matrix from the rotation expressed by + * the rotation matrix m1, the translation t1, and the scale factor. + * The translation is not modified by the scale. + * @param m1 the rotation component + * @param t1 the translation component + * @param scale the scale factor + */ + public final void set(Matrix3d m1, Vector3d t1, double scale) + { + this.m00 = (float)(m1.m00*scale); + this.m01 = (float)(m1.m01*scale); + this.m02 = (float)(m1.m02*scale); + this.m03 = (float)t1.x; + + this.m10 = (float)(m1.m10*scale); + this.m11 = (float)(m1.m11*scale); + this.m12 = (float)(m1.m12*scale); + this.m13 = (float)t1.y; + + this.m20 = (float)(m1.m20*scale); + this.m21 = (float)(m1.m21*scale); + this.m22 = (float)(m1.m22*scale); + this.m23 = (float)t1.z; + + this.m30 = 0.0f; + this.m31 = 0.0f; + this.m32 = 0.0f; + this.m33 = 1.0f; + } + + /** + * Modifies the translational components of this matrix to the values + * of the Vector3f argument; the other values of this matrix are not + * modified. + * @param trans the translational component + */ + public final void setTranslation(Vector3f trans) + { + m03 = trans.x; + m13 = trans.y; + m23 = trans.z; + } + + + /** + * 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(float angle) + { + float sinAngle, cosAngle; + + sinAngle = (float) Math.sin((double) angle); + cosAngle = (float) Math.cos((double) angle); + + this.m00 = (float) 1.0; + this.m01 = (float) 0.0; + this.m02 = (float) 0.0; + this.m03 = (float) 0.0; + + this.m10 = (float) 0.0; + this.m11 = cosAngle; + this.m12 = -sinAngle; + this.m13 = (float) 0.0; + + this.m20 = (float) 0.0; + this.m21 = sinAngle; + this.m22 = cosAngle; + this.m23 = (float) 0.0; + + this.m30 = (float) 0.0; + this.m31 = (float) 0.0; + this.m32 = (float) 0.0; + this.m33 = (float) 1.0; + } + + /** + * 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(float angle) + { + float sinAngle, cosAngle; + + sinAngle = (float) Math.sin((double) angle); + cosAngle = (float) Math.cos((double) angle); + + this.m00 = cosAngle; + this.m01 = (float) 0.0; + this.m02 = sinAngle; + this.m03 = (float) 0.0; + + this.m10 = (float) 0.0; + this.m11 = (float) 1.0; + this.m12 = (float) 0.0; + this.m13 = (float) 0.0; + + this.m20 = -sinAngle; + this.m21 = (float) 0.0; + this.m22 = cosAngle; + this.m23 = (float) 0.0; + + this.m30 = (float) 0.0; + this.m31 = (float) 0.0; + this.m32 = (float) 0.0; + this.m33 = (float) 1.0; + } + + /** + * 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(float angle) + { + float sinAngle, cosAngle; + + sinAngle = (float) Math.sin((double) angle); + cosAngle = (float) Math.cos((double) angle); + + this.m00 = cosAngle; + this.m01 = -sinAngle; + this.m02 = (float) 0.0; + this.m03 = (float) 0.0; + + this.m10 = sinAngle; + this.m11 = cosAngle; + this.m12 = (float) 0.0; + this.m13 = (float) 0.0; + + this.m20 = (float) 0.0; + this.m21 = (float) 0.0; + this.m22 = (float) 1.0; + this.m23 = (float) 0.0; + + this.m30 = (float) 0.0; + this.m31 = (float) 0.0; + this.m32 = (float) 0.0; + this.m33 = (float) 1.0; + } + + /** + * Multiplies each element of this matrix by a scalar. + * @param scalar the scalar multiplier. + */ + public final void mul(float scalar) + { + m00 *= scalar; + m01 *= scalar; + m02 *= scalar; + m03 *= scalar; + m10 *= scalar; + m11 *= scalar; + m12 *= scalar; + m13 *= scalar; + m20 *= scalar; + m21 *= scalar; + m22 *= scalar; + m23 *= scalar; + m30 *= scalar; + m31 *= scalar; + m32 *= scalar; + m33 *= 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(float scalar, Matrix4f m1) + { + this.m00 = m1.m00 * scalar; + this.m01 = m1.m01 * scalar; + this.m02 = m1.m02 * scalar; + this.m03 = m1.m03 * scalar; + this.m10 = m1.m10 * scalar; + this.m11 = m1.m11 * scalar; + this.m12 = m1.m12 * scalar; + this.m13 = m1.m13 * scalar; + this.m20 = m1.m20 * scalar; + this.m21 = m1.m21 * scalar; + this.m22 = m1.m22 * scalar; + this.m23 = m1.m23 * scalar; + this.m30 = m1.m30 * scalar; + this.m31 = m1.m31 * scalar; + this.m32 = m1.m32 * scalar; + this.m33 = m1.m33 * scalar; + } + + /** + * Sets the value of this matrix to the result of multiplying itself + * with matrix m1. + * @param m1 the other matrix + */ + public final void mul(Matrix4f m1) + { + float m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33; // vars for temp result matrix + + m00 = this.m00*m1.m00 + this.m01*m1.m10 + + this.m02*m1.m20 + this.m03*m1.m30; + m01 = this.m00*m1.m01 + this.m01*m1.m11 + + this.m02*m1.m21 + this.m03*m1.m31; + m02 = this.m00*m1.m02 + this.m01*m1.m12 + + this.m02*m1.m22 + this.m03*m1.m32; + m03 = this.m00*m1.m03 + this.m01*m1.m13 + + this.m02*m1.m23 + this.m03*m1.m33; + + m10 = this.m10*m1.m00 + this.m11*m1.m10 + + this.m12*m1.m20 + this.m13*m1.m30; + m11 = this.m10*m1.m01 + this.m11*m1.m11 + + this.m12*m1.m21 + this.m13*m1.m31; + m12 = this.m10*m1.m02 + this.m11*m1.m12 + + this.m12*m1.m22 + this.m13*m1.m32; + m13 = this.m10*m1.m03 + this.m11*m1.m13 + + this.m12*m1.m23 + this.m13*m1.m33; + + m20 = this.m20*m1.m00 + this.m21*m1.m10 + + this.m22*m1.m20 + this.m23*m1.m30; + m21 = this.m20*m1.m01 + this.m21*m1.m11 + + this.m22*m1.m21 + this.m23*m1.m31; + m22 = this.m20*m1.m02 + this.m21*m1.m12 + + this.m22*m1.m22 + this.m23*m1.m32; + m23 = this.m20*m1.m03 + this.m21*m1.m13 + + this.m22*m1.m23 + this.m23*m1.m33; + + m30 = this.m30*m1.m00 + this.m31*m1.m10 + + this.m32*m1.m20 + this.m33*m1.m30; + m31 = this.m30*m1.m01 + this.m31*m1.m11 + + this.m32*m1.m21 + this.m33*m1.m31; + m32 = this.m30*m1.m02 + this.m31*m1.m12 + + this.m32*m1.m22 + this.m33*m1.m32; + m33 = this.m30*m1.m03 + this.m31*m1.m13 + + this.m32*m1.m23 + this.m33*m1.m33; + + this.m00 = m00; this.m01 = m01; this.m02 = m02; this.m03 = m03; + this.m10 = m10; this.m11 = m11; this.m12 = m12; this.m13 = m13; + this.m20 = m20; this.m21 = m21; this.m22 = m22; this.m23 = m23; + this.m30 = m30; this.m31 = m31; this.m32 = m32; this.m33 = m33; + } + + /** + * 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(Matrix4f m1, Matrix4f m2) + { + if (this != m1 && this != m2) { + + this.m00 = m1.m00*m2.m00 + m1.m01*m2.m10 + + m1.m02*m2.m20 + m1.m03*m2.m30; + this.m01 = m1.m00*m2.m01 + m1.m01*m2.m11 + + m1.m02*m2.m21 + m1.m03*m2.m31; + this.m02 = m1.m00*m2.m02 + m1.m01*m2.m12 + + m1.m02*m2.m22 + m1.m03*m2.m32; + this.m03 = m1.m00*m2.m03 + m1.m01*m2.m13 + + m1.m02*m2.m23 + m1.m03*m2.m33; + + this.m10 = m1.m10*m2.m00 + m1.m11*m2.m10 + + m1.m12*m2.m20 + m1.m13*m2.m30; + this.m11 = m1.m10*m2.m01 + m1.m11*m2.m11 + + m1.m12*m2.m21 + m1.m13*m2.m31; + this.m12 = m1.m10*m2.m02 + m1.m11*m2.m12 + + m1.m12*m2.m22 + m1.m13*m2.m32; + this.m13 = m1.m10*m2.m03 + m1.m11*m2.m13 + + m1.m12*m2.m23 + m1.m13*m2.m33; + + this.m20 = m1.m20*m2.m00 + m1.m21*m2.m10 + + m1.m22*m2.m20 + m1.m23*m2.m30; + this.m21 = m1.m20*m2.m01 + m1.m21*m2.m11 + + m1.m22*m2.m21 + m1.m23*m2.m31; + this.m22 = m1.m20*m2.m02 + m1.m21*m2.m12 + + m1.m22*m2.m22 + m1.m23*m2.m32; + this.m23 = m1.m20*m2.m03 + m1.m21*m2.m13 + + m1.m22*m2.m23 + m1.m23*m2.m33; + + this.m30 = m1.m30*m2.m00 + m1.m31*m2.m10 + + m1.m32*m2.m20 + m1.m33*m2.m30; + this.m31 = m1.m30*m2.m01 + m1.m31*m2.m11 + + m1.m32*m2.m21 + m1.m33*m2.m31; + this.m32 = m1.m30*m2.m02 + m1.m31*m2.m12 + + m1.m32*m2.m22 + m1.m33*m2.m32; + this.m33 = m1.m30*m2.m03 + m1.m31*m2.m13 + + m1.m32*m2.m23 + m1.m33*m2.m33; + } else { + float m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33; // vars for temp result matrix + m00 = m1.m00*m2.m00 + m1.m01*m2.m10 + m1.m02*m2.m20 + m1.m03*m2.m30; + m01 = m1.m00*m2.m01 + m1.m01*m2.m11 + m1.m02*m2.m21 + m1.m03*m2.m31; + m02 = m1.m00*m2.m02 + m1.m01*m2.m12 + m1.m02*m2.m22 + m1.m03*m2.m32; + m03 = m1.m00*m2.m03 + m1.m01*m2.m13 + m1.m02*m2.m23 + m1.m03*m2.m33; + + m10 = m1.m10*m2.m00 + m1.m11*m2.m10 + m1.m12*m2.m20 + m1.m13*m2.m30; + m11 = m1.m10*m2.m01 + m1.m11*m2.m11 + m1.m12*m2.m21 + m1.m13*m2.m31; + m12 = m1.m10*m2.m02 + m1.m11*m2.m12 + m1.m12*m2.m22 + m1.m13*m2.m32; + m13 = m1.m10*m2.m03 + m1.m11*m2.m13 + m1.m12*m2.m23 + m1.m13*m2.m33; + + m20 = m1.m20*m2.m00 + m1.m21*m2.m10 + m1.m22*m2.m20 + m1.m23*m2.m30; + m21 = m1.m20*m2.m01 + m1.m21*m2.m11 + m1.m22*m2.m21 + m1.m23*m2.m31; + m22 = m1.m20*m2.m02 + m1.m21*m2.m12 + m1.m22*m2.m22 + m1.m23*m2.m32; + m23 = m1.m20*m2.m03 + m1.m21*m2.m13 + m1.m22*m2.m23 + m1.m23*m2.m33; + + m30 = m1.m30*m2.m00 + m1.m31*m2.m10 + m1.m32*m2.m20 + m1.m33*m2.m30; + m31 = m1.m30*m2.m01 + m1.m31*m2.m11 + m1.m32*m2.m21 + m1.m33*m2.m31; + m32 = m1.m30*m2.m02 + m1.m31*m2.m12 + m1.m32*m2.m22 + m1.m33*m2.m32; + m33 = m1.m30*m2.m03 + m1.m31*m2.m13 + m1.m32*m2.m23 + m1.m33*m2.m33; + + this.m00 = m00; this.m01 = m01; this.m02 = m02; this.m03 = m03; + this.m10 = m10; this.m11 = m11; this.m12 = m12; this.m13 = m13; + this.m20 = m20; this.m21 = m21; this.m22 = m22; this.m23 = m23; + this.m30 = m30; this.m31 = m31; this.m32 = m32; this.m33 = m33; + } + } + + /** + * 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(Matrix4f m1, Matrix4f m2) + { + if (this != m1 && this != m2) { + this.m00 = m1.m00*m2.m00 + m1.m10*m2.m01 + m1.m20*m2.m02 + m1.m30*m2.m03; + this.m01 = m1.m00*m2.m10 + m1.m10*m2.m11 + m1.m20*m2.m12 + m1.m30*m2.m13; + this.m02 = m1.m00*m2.m20 + m1.m10*m2.m21 + m1.m20*m2.m22 + m1.m30*m2.m23; + this.m03 = m1.m00*m2.m30 + m1.m10*m2.m31 + m1.m20*m2.m32 + m1.m30*m2.m33; + + this.m10 = m1.m01*m2.m00 + m1.m11*m2.m01 + m1.m21*m2.m02 + m1.m31*m2.m03; + this.m11 = m1.m01*m2.m10 + m1.m11*m2.m11 + m1.m21*m2.m12 + m1.m31*m2.m13; + this.m12 = m1.m01*m2.m20 + m1.m11*m2.m21 + m1.m21*m2.m22 + m1.m31*m2.m23; + this.m13 = m1.m01*m2.m30 + m1.m11*m2.m31 + m1.m21*m2.m32 + m1.m31*m2.m33; + + this.m20 = m1.m02*m2.m00 + m1.m12*m2.m01 + m1.m22*m2.m02 + m1.m32*m2.m03; + this.m21 = m1.m02*m2.m10 + m1.m12*m2.m11 + m1.m22*m2.m12 + m1.m32*m2.m13; + this.m22 = m1.m02*m2.m20 + m1.m12*m2.m21 + m1.m22*m2.m22 + m1.m32*m2.m23; + this.m23 = m1.m02*m2.m30 + m1.m12*m2.m31 + m1.m22*m2.m32 + m1.m32*m2.m33; + + this.m30 = m1.m03*m2.m00 + m1.m13*m2.m01 + m1.m23*m2.m02 + m1.m33*m2.m03; + this.m31 = m1.m03*m2.m10 + m1.m13*m2.m11 + m1.m23*m2.m12 + m1.m33*m2.m13; + this.m32 = m1.m03*m2.m20 + m1.m13*m2.m21 + m1.m23*m2.m22 + m1.m33*m2.m23; + this.m33 = m1.m03*m2.m30 + m1.m13*m2.m31 + m1.m23*m2.m32 + m1.m33*m2.m33; + } else { + float m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, // vars for temp result matrix + m30, m31, m32, m33; + + m00 = m1.m00*m2.m00 + m1.m10*m2.m01 + m1.m20*m2.m02 + m1.m30*m2.m03; + m01 = m1.m00*m2.m10 + m1.m10*m2.m11 + m1.m20*m2.m12 + m1.m30*m2.m13; + m02 = m1.m00*m2.m20 + m1.m10*m2.m21 + m1.m20*m2.m22 + m1.m30*m2.m23; + m03 = m1.m00*m2.m30 + m1.m10*m2.m31 + m1.m20*m2.m32 + m1.m30*m2.m33; + + m10 = m1.m01*m2.m00 + m1.m11*m2.m01 + m1.m21*m2.m02 + m1.m31*m2.m03; + m11 = m1.m01*m2.m10 + m1.m11*m2.m11 + m1.m21*m2.m12 + m1.m31*m2.m13; + m12 = m1.m01*m2.m20 + m1.m11*m2.m21 + m1.m21*m2.m22 + m1.m31*m2.m23; + m13 = m1.m01*m2.m30 + m1.m11*m2.m31 + m1.m21*m2.m32 + m1.m31*m2.m33; + + m20 = m1.m02*m2.m00 + m1.m12*m2.m01 + m1.m22*m2.m02 + m1.m32*m2.m03; + m21 = m1.m02*m2.m10 + m1.m12*m2.m11 + m1.m22*m2.m12 + m1.m32*m2.m13; + m22 = m1.m02*m2.m20 + m1.m12*m2.m21 + m1.m22*m2.m22 + m1.m32*m2.m23; + m23 = m1.m02*m2.m30 + m1.m12*m2.m31 + m1.m22*m2.m32 + m1.m32*m2.m33; + + m30 = m1.m03*m2.m00 + m1.m13*m2.m01 + m1.m23*m2.m02 + m1.m33*m2.m03; + m31 = m1.m03*m2.m10 + m1.m13*m2.m11 + m1.m23*m2.m12 + m1.m33*m2.m13; + m32 = m1.m03*m2.m20 + m1.m13*m2.m21 + m1.m23*m2.m22 + m1.m33*m2.m23; + m33 = m1.m03*m2.m30 + m1.m13*m2.m31 + m1.m23*m2.m32 + m1.m33*m2.m33; + + this.m00 = m00; this.m01 = m01; this.m02 = m02; this.m03 = m03; + this.m10 = m10; this.m11 = m11; this.m12 = m12; this.m13 = m13; + this.m20 = m20; this.m21 = m21; this.m22 = m22; this.m23 = m23; + this.m30 = m30; this.m31 = m31; this.m32 = m32; this.m33 = m33; + } + + } + + /** + * 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(Matrix4f m1, Matrix4f m2) + { + if (this != m1 && this != m2) { + this.m00 = m1.m00*m2.m00 + m1.m01*m2.m01 + m1.m02*m2.m02 + m1.m03*m2.m03; + this.m01 = m1.m00*m2.m10 + m1.m01*m2.m11 + m1.m02*m2.m12 + m1.m03*m2.m13; + this.m02 = m1.m00*m2.m20 + m1.m01*m2.m21 + m1.m02*m2.m22 + m1.m03*m2.m23; + this.m03 = m1.m00*m2.m30 + m1.m01*m2.m31 + m1.m02*m2.m32 + m1.m03*m2.m33; + + this.m10 = m1.m10*m2.m00 + m1.m11*m2.m01 + m1.m12*m2.m02 + m1.m13*m2.m03; + this.m11 = m1.m10*m2.m10 + m1.m11*m2.m11 + m1.m12*m2.m12 + m1.m13*m2.m13; + this.m12 = m1.m10*m2.m20 + m1.m11*m2.m21 + m1.m12*m2.m22 + m1.m13*m2.m23; + this.m13 = m1.m10*m2.m30 + m1.m11*m2.m31 + m1.m12*m2.m32 + m1.m13*m2.m33; + + this.m20 = m1.m20*m2.m00 + m1.m21*m2.m01 + m1.m22*m2.m02 + m1.m23*m2.m03; + this.m21 = m1.m20*m2.m10 + m1.m21*m2.m11 + m1.m22*m2.m12 + m1.m23*m2.m13; + this.m22 = m1.m20*m2.m20 + m1.m21*m2.m21 + m1.m22*m2.m22 + m1.m23*m2.m23; + this.m23 = m1.m20*m2.m30 + m1.m21*m2.m31 + m1.m22*m2.m32 + m1.m23*m2.m33; + + this.m30 = m1.m30*m2.m00 + m1.m31*m2.m01 + m1.m32*m2.m02 + m1.m33*m2.m03; + this.m31 = m1.m30*m2.m10 + m1.m31*m2.m11 + m1.m32*m2.m12 + m1.m33*m2.m13; + this.m32 = m1.m30*m2.m20 + m1.m31*m2.m21 + m1.m32*m2.m22 + m1.m33*m2.m23; + this.m33 = m1.m30*m2.m30 + m1.m31*m2.m31 + m1.m32*m2.m32 + m1.m33*m2.m33; + } else { + float m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, // vars for temp result matrix + m30, m31, m32, m33; + + m00 = m1.m00*m2.m00 + m1.m01*m2.m01 + m1.m02*m2.m02 + m1.m03*m2.m03; + m01 = m1.m00*m2.m10 + m1.m01*m2.m11 + m1.m02*m2.m12 + m1.m03*m2.m13; + m02 = m1.m00*m2.m20 + m1.m01*m2.m21 + m1.m02*m2.m22 + m1.m03*m2.m23; + m03 = m1.m00*m2.m30 + m1.m01*m2.m31 + m1.m02*m2.m32 + m1.m03*m2.m33; + + m10 = m1.m10*m2.m00 + m1.m11*m2.m01 + m1.m12*m2.m02 + m1.m13*m2.m03; + m11 = m1.m10*m2.m10 + m1.m11*m2.m11 + m1.m12*m2.m12 + m1.m13*m2.m13; + m12 = m1.m10*m2.m20 + m1.m11*m2.m21 + m1.m12*m2.m22 + m1.m13*m2.m23; + m13 = m1.m10*m2.m30 + m1.m11*m2.m31 + m1.m12*m2.m32 + m1.m13*m2.m33; + + m20 = m1.m20*m2.m00 + m1.m21*m2.m01 + m1.m22*m2.m02 + m1.m23*m2.m03; + m21 = m1.m20*m2.m10 + m1.m21*m2.m11 + m1.m22*m2.m12 + m1.m23*m2.m13; + m22 = m1.m20*m2.m20 + m1.m21*m2.m21 + m1.m22*m2.m22 + m1.m23*m2.m23; + m23 = m1.m20*m2.m30 + m1.m21*m2.m31 + m1.m22*m2.m32 + m1.m23*m2.m33; + + m30 = m1.m30*m2.m00 + m1.m31*m2.m01 + m1.m32*m2.m02 + m1.m33*m2.m03; + m31 = m1.m30*m2.m10 + m1.m31*m2.m11 + m1.m32*m2.m12 + m1.m33*m2.m13; + m32 = m1.m30*m2.m20 + m1.m31*m2.m21 + m1.m32*m2.m22 + m1.m33*m2.m23; + m33 = m1.m30*m2.m30 + m1.m31*m2.m31 + m1.m32*m2.m32 + m1.m33*m2.m33; + + this.m00 = m00; this.m01 = m01; this.m02 = m02; this.m03 = m03; + this.m10 = m10; this.m11 = m11; this.m12 = m12; this.m13 = m13; + this.m20 = m20; this.m21 = m21; this.m22 = m22; this.m23 = m23; + this.m30 = m30; this.m31 = m31; this.m32 = m32; this.m33 = m33; + } + + } + + + /** + * 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(Matrix4f m1, Matrix4f m2) + { + if (this != m1 && this != m2) { + this.m00 = m1.m00*m2.m00 + m1.m10*m2.m10 + m1.m20*m2.m20 + m1.m30*m2.m30; + this.m01 = m1.m00*m2.m01 + m1.m10*m2.m11 + m1.m20*m2.m21 + m1.m30*m2.m31; + this.m02 = m1.m00*m2.m02 + m1.m10*m2.m12 + m1.m20*m2.m22 + m1.m30*m2.m32; + this.m03 = m1.m00*m2.m03 + m1.m10*m2.m13 + m1.m20*m2.m23 + m1.m30*m2.m33; + + this.m10 = m1.m01*m2.m00 + m1.m11*m2.m10 + m1.m21*m2.m20 + m1.m31*m2.m30; + this.m11 = m1.m01*m2.m01 + m1.m11*m2.m11 + m1.m21*m2.m21 + m1.m31*m2.m31; + this.m12 = m1.m01*m2.m02 + m1.m11*m2.m12 + m1.m21*m2.m22 + m1.m31*m2.m32; + this.m13 = m1.m01*m2.m03 + m1.m11*m2.m13 + m1.m21*m2.m23 + m1.m31*m2.m33; + + this.m20 = m1.m02*m2.m00 + m1.m12*m2.m10 + m1.m22*m2.m20 + m1.m32*m2.m30; + this.m21 = m1.m02*m2.m01 + m1.m12*m2.m11 + m1.m22*m2.m21 + m1.m32*m2.m31; + this.m22 = m1.m02*m2.m02 + m1.m12*m2.m12 + m1.m22*m2.m22 + m1.m32*m2.m32; + this.m23 = m1.m02*m2.m03 + m1.m12*m2.m13 + m1.m22*m2.m23 + m1.m32*m2.m33; + + this.m30 = m1.m03*m2.m00 + m1.m13*m2.m10 + m1.m23*m2.m20 + m1.m33*m2.m30; + this.m31 = m1.m03*m2.m01 + m1.m13*m2.m11 + m1.m23*m2.m21 + m1.m33*m2.m31; + this.m32 = m1.m03*m2.m02 + m1.m13*m2.m12 + m1.m23*m2.m22 + m1.m33*m2.m32; + this.m33 = m1.m03*m2.m03 + m1.m13*m2.m13 + m1.m23*m2.m23 + m1.m33*m2.m33; + } else { + float m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, // vars for temp result matrix + m30, m31, m32, m33; + + + + m00 = m1.m00*m2.m00 + m1.m10*m2.m10 + m1.m20*m2.m20 + m1.m30*m2.m30; + m01 = m1.m00*m2.m01 + m1.m10*m2.m11 + m1.m20*m2.m21 + m1.m30*m2.m31; + m02 = m1.m00*m2.m02 + m1.m10*m2.m12 + m1.m20*m2.m22 + m1.m30*m2.m32; + m03 = m1.m00*m2.m03 + m1.m10*m2.m13 + m1.m20*m2.m23 + m1.m30*m2.m33; + + m10 = m1.m01*m2.m00 + m1.m11*m2.m10 + m1.m21*m2.m20 + m1.m31*m2.m30; + m11 = m1.m01*m2.m01 + m1.m11*m2.m11 + m1.m21*m2.m21 + m1.m31*m2.m31; + m12 = m1.m01*m2.m02 + m1.m11*m2.m12 + m1.m21*m2.m22 + m1.m31*m2.m32; + m13 = m1.m01*m2.m03 + m1.m11*m2.m13 + m1.m21*m2.m23 + m1.m31*m2.m33; + + m20 = m1.m02*m2.m00 + m1.m12*m2.m10 + m1.m22*m2.m20 + m1.m32*m2.m30; + m21 = m1.m02*m2.m01 + m1.m12*m2.m11 + m1.m22*m2.m21 + m1.m32*m2.m31; + m22 = m1.m02*m2.m02 + m1.m12*m2.m12 + m1.m22*m2.m22 + m1.m32*m2.m32; + m23 = m1.m02*m2.m03 + m1.m12*m2.m13 + m1.m22*m2.m23 + m1.m32*m2.m33; + + m30 = m1.m03*m2.m00 + m1.m13*m2.m10 + m1.m23*m2.m20 + m1.m33*m2.m30; + m31 = m1.m03*m2.m01 + m1.m13*m2.m11 + m1.m23*m2.m21 + m1.m33*m2.m31; + m32 = m1.m03*m2.m02 + m1.m13*m2.m12 + m1.m23*m2.m22 + m1.m33*m2.m32; + m33 = m1.m03*m2.m03 + m1.m13*m2.m13 + m1.m23*m2.m23 + m1.m33*m2.m33; + + this.m00 = m00; this.m01 = m01; this.m02 = m02; this.m03 = m03; + this.m10 = m10; this.m11 = m11; this.m12 = m12; this.m13 = m13; + this.m20 = m20; this.m21 = m21; this.m22 = m22; this.m23 = m23; + this.m30 = m30; this.m31 = m31; this.m32 = m32; this.m33 = m33; + } + + } + + + /** + * Returns true if all of the data members of Matrix4f m1 are + * equal to the corresponding data members in this Matrix4f. + * @param m1 the matrix with which the comparison is made. + * @return true or false + */ + public boolean equals(Matrix4f m1) + { + try { + return(this.m00 == m1.m00 && this.m01 == m1.m01 && this.m02 == m1.m02 + && this.m03 == m1.m03 && this.m10 == m1.m10 && this.m11 == m1.m11 + && this.m12 == m1.m12 && this.m13 == m1.m13 && this.m20 == m1.m20 + && this.m21 == m1.m21 && this.m22 == m1.m22 && this.m23 == m1.m23 + && this.m30 == m1.m30 && this.m31 == m1.m31 && this.m32 == m1.m32 + && this.m33 == m1.m33); + } + catch (NullPointerException e2) { return false; } + + } + + /** + * Returns true if the Object t1 is of type Matrix4f and all of the + * data members of t1 are equal to the corresponding data members in + * this Matrix4f. + * @param t1 the matrix with which the comparison is made. + * @return true or false + */ + public boolean equals(Object t1) + { + try { + Matrix4f m2 = (Matrix4f) t1; + return(this.m00 == m2.m00 && this.m01 == m2.m01 && this.m02 == m2.m02 + && this.m03 == m2.m03 && this.m10 == m2.m10 && this.m11 == m2.m11 + && this.m12 == m2.m12 && this.m13 == m2.m13 && this.m20 == m2.m20 + && this.m21 == m2.m21 && this.m22 == m2.m22 && this.m23 == m2.m23 + && this.m30 == m2.m30 && this.m31 == m2.m31 && this.m32 == m2.m32 + && this.m33 == m2.m33); + } + 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,3 ; j=0,1,2,3 ; 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(Matrix4f m1, float epsilon) + { + + boolean status = true; + + if( Math.abs( this.m00 - m1.m00) > epsilon) status = false; + if( Math.abs( this.m01 - m1.m01) > epsilon) status = false; + if( Math.abs( this.m02 - m1.m02) > epsilon) status = false; + if( Math.abs( this.m03 - m1.m03) > epsilon) status = false; + + if( Math.abs( this.m10 - m1.m10) > epsilon) status = false; + if( Math.abs( this.m11 - m1.m11) > epsilon) status = false; + if( Math.abs( this.m12 - m1.m12) > epsilon) status = false; + if( Math.abs( this.m13 - m1.m13) > epsilon) status = false; + + if( Math.abs( this.m20 - m1.m20) > epsilon) status = false; + if( Math.abs( this.m21 - m1.m21) > epsilon) status = false; + if( Math.abs( this.m22 - m1.m22) > epsilon) status = false; + if( Math.abs( this.m23 - m1.m23) > epsilon) status = false; + + if( Math.abs( this.m30 - m1.m30) > epsilon) status = false; + if( Math.abs( this.m31 - m1.m31) > epsilon) status = false; + if( Math.abs( this.m32 - m1.m32) > epsilon) status = false; + if( Math.abs( this.m33 - m1.m33) > epsilon) status = false; + + return( status ); + + } + + + /** + * Returns a hash code value based on the data values in this + * object. Two different Matrix4f objects with identical data values + * (i.e., Matrix4f.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 + */ + public int hashCode() { + long bits = 1L; + bits = 31L * bits + (long)Float.floatToIntBits(m00); + bits = 31L * bits + (long)Float.floatToIntBits(m01); + bits = 31L * bits + (long)Float.floatToIntBits(m02); + bits = 31L * bits + (long)Float.floatToIntBits(m03); + bits = 31L * bits + (long)Float.floatToIntBits(m10); + bits = 31L * bits + (long)Float.floatToIntBits(m11); + bits = 31L * bits + (long)Float.floatToIntBits(m12); + bits = 31L * bits + (long)Float.floatToIntBits(m13); + bits = 31L * bits + (long)Float.floatToIntBits(m20); + bits = 31L * bits + (long)Float.floatToIntBits(m21); + bits = 31L * bits + (long)Float.floatToIntBits(m22); + bits = 31L * bits + (long)Float.floatToIntBits(m23); + bits = 31L * bits + (long)Float.floatToIntBits(m30); + bits = 31L * bits + (long)Float.floatToIntBits(m31); + bits = 31L * bits + (long)Float.floatToIntBits(m32); + bits = 31L * bits + (long)Float.floatToIntBits(m33); + return (int) (bits ^ (bits >> 32)); + } + + + /** + * Transform the vector vec using this Matrix4f and place the + * result into vecOut. + * @param vec the single precision vector to be transformed + * @param vecOut the vector into which the transformed values are placed + */ + public final void transform(Tuple4f vec, Tuple4f vecOut) + { + float x,y,z; + x = m00*vec.x + m01*vec.y + + m02*vec.z + m03*vec.w; + y = m10*vec.x + m11*vec.y + + m12*vec.z + m13*vec.w; + z = m20*vec.x + m21*vec.y + + m22*vec.z + m23*vec.w; + vecOut.w = m30*vec.x + m31*vec.y + + m32*vec.z + m33*vec.w; + vecOut.x = x; + vecOut.y = y; + vecOut.z = z; + } + + + /** + * Transform the vector vec using this Transform and place the + * result back into vec. + * @param vec the single precision vector to be transformed + */ + public final void transform(Tuple4f vec) + { + float x,y,z; + + x = m00*vec.x + m01*vec.y + + m02*vec.z + m03*vec.w; + y = m10*vec.x + m11*vec.y + + m12*vec.z + m13*vec.w; + z = m20*vec.x + m21*vec.y + + m22*vec.z + m23*vec.w; + vec.w = m30*vec.x + m31*vec.y + + m32*vec.z + m33*vec.w; + vec.x = x; + vec.y = y; + vec.z = z; + } + + /** + * Transforms the point parameter with this Matrix4f and + * places the result into pointOut. The fourth element of the + * point input paramter is assumed to be one. + * @param point the input point to be transformed. + * @param pointOut the transformed point + */ + public final void transform(Point3f point, Point3f pointOut) + { + float x,y; + x = m00*point.x + m01*point.y + m02*point.z + m03; + y = m10*point.x + m11*point.y + m12*point.z + m13; + pointOut.z = m20*point.x + m21*point.y + m22*point.z + m23; + pointOut.x = x; + pointOut.y = y; + } + + + /** + * Transforms the point parameter with this Matrix4f and + * places the result back into point. The fourth element of the + * point input paramter is assumed to be one. + * @param point the input point to be transformed. + */ + public final void transform(Point3f point) + { + float x, y; + x = m00*point.x + m01*point.y + m02*point.z + m03; + y = m10*point.x + m11*point.y + m12*point.z + m13; + point.z = m20*point.x + m21*point.y + m22*point.z + m23; + point.x = x; + point.y = y; + } + + + /** + * Transforms the normal parameter by this Matrix4f and places the value + * into normalOut. The fourth element of the normal is assumed to be zero. + * @param normal the input normal to be transformed. + * @param normalOut the transformed normal + */ + public final void transform(Vector3f normal, Vector3f normalOut) + { + float x,y; + x = m00*normal.x + m01*normal.y + m02*normal.z; + y = m10*normal.x + m11*normal.y + m12*normal.z; + normalOut.z = m20*normal.x + m21*normal.y + m22*normal.z; + normalOut.x = x; + normalOut.y = y; + } + + + /** + * Transforms the normal parameter by this transform and places the value + * back into normal. The fourth element of the normal is assumed to be zero. + * @param normal the input normal to be transformed. + */ + public final void transform(Vector3f normal) + { + float x, y; + + x = m00*normal.x + m01*normal.y + m02*normal.z; + y = m10*normal.x + m11*normal.y + m12*normal.z; + normal.z = m20*normal.x + m21*normal.y + m22*normal.z; + normal.x = x; + normal.y = y; + } + + + /** + * Sets the rotational component (upper 3x3) of this matrix to the + * matrix values in the double precision Matrix3d argument; the other + * elements of this matrix are unchanged; a singular value + * decomposition is performed on this object's upper 3x3 matrix to + * factor out the scale, then this object's upper 3x3 matrix components + * are replaced by the passed rotation components, + * and then the scale is reapplied to the rotational components. + * @param m1 double precision 3x3 matrix + */ + public final void setRotation( Matrix3d m1) + { + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + + getScaleRotate( tmp_scale, tmp_rot ); + + m00 = (float)(m1.m00*tmp_scale[0]); + m01 = (float)(m1.m01*tmp_scale[1]); + m02 = (float)(m1.m02*tmp_scale[2]); + + m10 = (float)(m1.m10*tmp_scale[0]); + m11 = (float)(m1.m11*tmp_scale[1]); + m12 = (float)(m1.m12*tmp_scale[2]); + + m20 = (float)(m1.m20*tmp_scale[0]); + m21 = (float)(m1.m21*tmp_scale[1]); + m22 = (float)(m1.m22*tmp_scale[2]); + + } + + /** + * Sets the rotational component (upper 3x3) of this matrix to the + * matrix values in the single precision Matrix3f argument; the other + * elements of this matrix are unchanged; a singular value + * decomposition is performed on this object's upper 3x3 matrix to + * factor out the scale, then this object's upper 3x3 matrix components + * are replaced by the passed rotation components, + * and then the scale is reapplied to the rotational components. + * @param m1 single precision 3x3 matrix + */ + public final void setRotation( Matrix3f m1){ + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + + getScaleRotate( tmp_scale, tmp_rot ); + + m00 = (float)(m1.m00*tmp_scale[0]); + m01 = (float)(m1.m01*tmp_scale[1]); + m02 = (float)(m1.m02*tmp_scale[2]); + + m10 = (float)(m1.m10*tmp_scale[0]); + m11 = (float)(m1.m11*tmp_scale[1]); + m12 = (float)(m1.m12*tmp_scale[2]); + + m20 = (float)(m1.m20*tmp_scale[0]); + m21 = (float)(m1.m21*tmp_scale[1]); + m22 = (float)(m1.m22*tmp_scale[2]); + } + + /** + * Sets the rotational component (upper 3x3) of this matrix to the + * matrix equivalent values of the quaternion argument; the other + * elements of this matrix are unchanged; a singular value + * decomposition is performed on this object's upper 3x3 matrix to + * factor out the scale, then this object's upper 3x3 matrix components + * are replaced by the matrix equivalent of the quaternion, + * and then the scale is reapplied to the rotational components. + * @param q1 the quaternion that specifies the rotation + */ + public final void setRotation(Quat4f q1){ + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + getScaleRotate( tmp_scale, tmp_rot ); + + m00 = (float)((1.0f - 2.0f*q1.y*q1.y - 2.0f*q1.z*q1.z)*tmp_scale[0]); + m10 = (float)((2.0f*(q1.x*q1.y + q1.w*q1.z))*tmp_scale[0]); + m20 = (float)((2.0f*(q1.x*q1.z - q1.w*q1.y))*tmp_scale[0]); + + m01 = (float)((2.0f*(q1.x*q1.y - q1.w*q1.z))*tmp_scale[1]); + m11 = (float)((1.0f - 2.0f*q1.x*q1.x - 2.0f*q1.z*q1.z)*tmp_scale[1]); + m21 = (float)((2.0f*(q1.y*q1.z + q1.w*q1.x))*tmp_scale[1]); + + m02 = (float)((2.0f*(q1.x*q1.z + q1.w*q1.y))*tmp_scale[2]); + m12 = (float)((2.0f*(q1.y*q1.z - q1.w*q1.x))*tmp_scale[2]); + m22 = (float)((1.0f - 2.0f*q1.x*q1.x - 2.0f*q1.y*q1.y)*tmp_scale[2]); + + } + + + /** + * Sets the rotational component (upper 3x3) of this matrix to the + * matrix equivalent values of the quaternion argument; the other + * elements of this matrix are unchanged; a singular value + * decomposition is performed on this object's upper 3x3 matrix to + * factor out the scale, then this object's upper 3x3 matrix components + * are replaced by the matrix equivalent of the quaternion, + * and then the scale is reapplied to the rotational components. + * @param q1 the quaternion that specifies the rotation + */ + public final void setRotation(Quat4d q1){ + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + + getScaleRotate( tmp_scale, tmp_rot ); + + m00 = (float)((1.0f - 2.0f*q1.y*q1.y - 2.0f*q1.z*q1.z)*tmp_scale[0]); + m10 = (float)((2.0f*(q1.x*q1.y + q1.w*q1.z))*tmp_scale[0]); + m20 = (float)((2.0f*(q1.x*q1.z - q1.w*q1.y))*tmp_scale[0]); + + m01 = (float)((2.0f*(q1.x*q1.y - q1.w*q1.z))*tmp_scale[1]); + m11 = (float)((1.0f - 2.0f*q1.x*q1.x - 2.0f*q1.z*q1.z)*tmp_scale[1]); + m21 = (float)((2.0f*(q1.y*q1.z + q1.w*q1.x))*tmp_scale[1]); + + m02 = (float)((2.0f*(q1.x*q1.z + q1.w*q1.y))*tmp_scale[2]); + m12 = (float)((2.0f*(q1.y*q1.z - q1.w*q1.x))*tmp_scale[2]); + m22 = (float)((1.0f - 2.0f*q1.x*q1.x - 2.0f*q1.y*q1.y)*tmp_scale[2]); + } + + /** + * Sets the rotational component (upper 3x3) of this matrix to the + * matrix equivalent values of the axis-angle argument; the other + * elements of this matrix are unchanged; a singular value + * decomposition is performed on this object's upper 3x3 matrix to + * factor out the scale, then this object's upper 3x3 matrix components + * are replaced by the matrix equivalent of the axis-angle, + * and then the scale is reapplied to the rotational components. + * @param a1 the axis-angle to be converted (x, y, z, angle) + */ + public final void setRotation(AxisAngle4f a1){ + double[] tmp_rot = new double[9]; // scratch matrix + double[] tmp_scale = new double[3]; // scratch matrix + + getScaleRotate( tmp_scale, tmp_rot ); + + double mag = Math.sqrt( a1.x*a1.x + a1.y*a1.y + a1.z*a1.z); + if( mag < EPS ) { + m00 = 1.0f; + m01 = 0.0f; + m02 = 0.0f; + + m10 = 0.0f; + m11 = 1.0f; + m12 = 0.0f; + + m20 = 0.0f; + m21 = 0.0f; + m22 = 1.0f; + } 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 = a1.x * a1.z; + double xy = a1.x * a1.y; + double yz = a1.y * a1.z; + + m00 = (float)((t * ax * ax + cosTheta)*tmp_scale[0]); + m01 = (float)((t * xy - sinTheta * az)*tmp_scale[1]); + m02 = (float)((t * xz + sinTheta * ay)*tmp_scale[2]); + + m10 = (float)((t * xy + sinTheta * az)*tmp_scale[0]); + m11 = (float)((t * ay * ay + cosTheta)*tmp_scale[1]); + m12 = (float)((t * yz - sinTheta * ax)*tmp_scale[2]); + + m20 = (float)((t * xz - sinTheta * ay)*tmp_scale[0]); + m21 = (float)((t * yz + sinTheta * ax)*tmp_scale[1]); + m22 = (float)((t * az * az + cosTheta)*tmp_scale[2]); + } + + + } + + /** + * Sets this matrix to all zeros. + */ + public final void setZero() + { + m00 = 0.0f; + m01 = 0.0f; + m02 = 0.0f; + m03 = 0.0f; + m10 = 0.0f; + m11 = 0.0f; + m12 = 0.0f; + m13 = 0.0f; + m20 = 0.0f; + m21 = 0.0f; + m22 = 0.0f; + m23 = 0.0f; + m30 = 0.0f; + m31 = 0.0f; + m32 = 0.0f; + m33 = 0.0f; + } + + /** + * Negates the value of this matrix: this = -this. + */ + public final void negate() + { + m00 = -m00; + m01 = -m01; + m02 = -m02; + m03 = -m03; + m10 = -m10; + m11 = -m11; + m12 = -m12; + m13 = -m13; + m20 = -m20; + m21 = -m21; + m22 = -m22; + m23 = -m23; + m30 = -m30; + m31 = -m31; + m32 = -m32; + m33 = -m33; + } + + /** + * Sets the value of this matrix equal to the negation of + * of the Matrix4f parameter. + * @param m1 the source matrix + */ + public final void negate(Matrix4f m1) + { + this.m00 = -m1.m00; + this.m01 = -m1.m01; + this.m02 = -m1.m02; + this.m03 = -m1.m03; + this.m10 = -m1.m10; + this.m11 = -m1.m11; + this.m12 = -m1.m12; + this.m13 = -m1.m13; + this.m20 = -m1.m20; + this.m21 = -m1.m21; + this.m22 = -m1.m22; + this.m23 = -m1.m23; + this.m30 = -m1.m30; + this.m31 = -m1.m31; + this.m32 = -m1.m32; + this.m33 = -m1.m33; + } + private 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; + + Matrix3d.compute_svd( tmp, scales, rots); + + return; + } + + /** + * 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 Java 3D 1.3 + */ + public Object clone() { + Matrix4f m1 = null; + try { + m1 = (Matrix4f)super.clone(); + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + + return m1; + } + +} diff --git a/src/javax/vecmath/MismatchedSizeException.java b/src/javax/vecmath/MismatchedSizeException.java new file mode 100644 index 0000000..062194c --- /dev/null +++ b/src/javax/vecmath/MismatchedSizeException.java @@ -0,0 +1,38 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +/** + * Indicates that an operation cannot be completed properly because + * of a mismatch in the sizes of object attributes. + */ +public class MismatchedSizeException extends RuntimeException{ + + +/** + * Create the exception object with default values. + */ + public MismatchedSizeException(){ + } + +/** + * Create the exception object that outputs a message. + * @param str the message string to be output. + */ + public MismatchedSizeException(String str){ + + super(str); + } + +} + diff --git a/src/javax/vecmath/Point2d.java b/src/javax/vecmath/Point2d.java new file mode 100644 index 0000000..0e819d3 --- /dev/null +++ b/src/javax/vecmath/Point2d.java @@ -0,0 +1,144 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 2 element point that is represented by double precision floating + * point x,y coordinates. + * + */ +public class Point2d extends Tuple2d implements java.io.Serializable { + + // Compatible with 1.1 + static final long serialVersionUID = 1133748791492571954L; + + /** + * Constructs and initializes a Point2d from the specified xy coordinates. + * @param x the x coordinate + * @param y the y coordinate + */ + public Point2d(double x, double y) + { + super(x,y); + } + + + /** + * Constructs and initializes a Point2d from the specified array. + * @param p the array of length 2 containing xy in order + */ + public Point2d(double[] p) + { + super(p); + } + + + /** + * Constructs and initializes a Point2d from the specified Point2d. + * @param p1 the Point2d containing the initialization x y data + */ + public Point2d(Point2d p1) + { + super(p1); + } + + + /** + * Constructs and initializes a Point2d from the specified Point2f. + * @param p1 the Point2f containing the initialization x y data + */ + public Point2d(Point2f p1) + { + super(p1); + } + + + /** + * Constructs and initializes a Point2d from the specified Tuple2d. + * @param t1 the Tuple2d containing the initialization x y data + */ + public Point2d(Tuple2d t1) + { + super(t1); + } + + + /** + * Constructs and initializes a Point2d from the specified Tuple2f. + * @param t1 the Tuple2f containing the initialization x y data + */ + public Point2d(Tuple2f t1) + { + super(t1); + } + + + /** + * Constructs and initializes a Point2d to (0,0). + */ + public Point2d() + { + super(); + } + + /** + * Computes the square of the distance between this point and point p1. + * @param p1 the other point + */ + public final double distanceSquared(Point2d p1) + { + double dx, dy; + + dx = this.x-p1.x; + dy = this.y-p1.y; + return dx*dx+dy*dy; + } + + /** + * Computes the distance between this point and point p1. + * @param p1 the other point + */ + public final double distance(Point2d p1) + { + double dx, dy; + + dx = this.x-p1.x; + dy = this.y-p1.y; + return Math.sqrt(dx*dx+dy*dy); + } + + + /** + * Computes the L-1 (Manhattan) distance between this point and + * point p1. The L-1 distance is equal to abs(x1-x2) + abs(y1-y2). + * @param p1 the other point + */ + public final double distanceL1(Point2d p1) + { + return( Math.abs(this.x-p1.x) + Math.abs(this.y-p1.y)); + } + + /** + * Computes the L-infinite distance between this point and + * point p1. The L-infinite distance is equal to + * MAX[abs(x1-x2), abs(y1-y2)]. + * @param p1 the other point + */ + public final double distanceLinf(Point2d p1) + { + return(Math.max( Math.abs(this.x-p1.x), Math.abs(this.y-p1.y))); + } + +} diff --git a/src/javax/vecmath/Point2f.java b/src/javax/vecmath/Point2f.java new file mode 100644 index 0000000..acb3243 --- /dev/null +++ b/src/javax/vecmath/Point2f.java @@ -0,0 +1,145 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 2 element point that is represented by single precision floating + * point x,y coordinates. + * + */ +public class Point2f extends Tuple2f implements java.io.Serializable { + + // Compatible with 1.1 + static final long serialVersionUID = -4801347926528714435L; + + /** + * Constructs and initializes a Point2f from the specified xy coordinates. + * @param x the x coordinate + * @param y the y coordinate + */ + public Point2f(float x, float y) + { + super(x,y); + } + + + /** + * Constructs and initializes a Point2f from the specified array. + * @param p the array of length 2 containing xy in order + */ + public Point2f(float[] p) + { + super(p); + } + + + /** + * Constructs and initializes a Point2f from the specified Point2f. + * @param p1 the Point2f containing the initialization x y data + */ + public Point2f(Point2f p1) + { + super(p1); + } + + /** + * Constructs and initializes a Point2f from the specified Point2d. + * @param p1 the Point2d containing the initialization x y z data + */ + public Point2f(Point2d p1) + { + super(p1); + } + + + + /** + * Constructs and initializes a Point2f from the specified Tuple2d. + * @param t1 the Tuple2d containing the initialization x y z data + */ + public Point2f(Tuple2d t1) + { + super(t1); + } + + + + /** + * Constructs and initializes a Point2f from the specified Tuple2f. + * @param t1 the Tuple2f containing the initialization x y data + */ + public Point2f(Tuple2f t1) + { + super(t1); + } + + + /** + * Constructs and initializes a Point2f to (0,0). + */ + public Point2f() + { + super(); + } + + /** + * Computes the square of the distance between this point and point p1. + * @param p1 the other point + */ + public final float distanceSquared(Point2f p1) + { + float dx, dy; + + dx = this.x-p1.x; + dy = this.y-p1.y; + return dx*dx+dy*dy; + } + + /** + * Computes the distance between this point and point p1. + * @param p1 the other point + */ + public final float distance(Point2f p1) + { + float dx, dy; + + dx = this.x-p1.x; + dy = this.y-p1.y; + return (float) Math.sqrt(dx*dx+dy*dy); + } + + + /** + * Computes the L-1 (Manhattan) distance between this point and + * point p1. The L-1 distance is equal to abs(x1-x2) + abs(y1-y2). + * @param p1 the other point + */ + public final float distanceL1(Point2f p1) + { + return( Math.abs(this.x-p1.x) + Math.abs(this.y-p1.y)); + } + + /** + * Computes the L-infinite distance between this point and + * point p1. The L-infinite distance is equal to + * MAX[abs(x1-x2), abs(y1-y2)]. + * @param p1 the other point + */ + public final float distanceLinf(Point2f p1) + { + return(Math.max( Math.abs(this.x-p1.x), Math.abs(this.y-p1.y))); + } + +} diff --git a/src/javax/vecmath/Point3d.java b/src/javax/vecmath/Point3d.java new file mode 100644 index 0000000..3acf542 --- /dev/null +++ b/src/javax/vecmath/Point3d.java @@ -0,0 +1,175 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 3 element point that is represented by double precision floating point + * x,y,z coordinates. + * + */ +public class Point3d extends Tuple3d implements java.io.Serializable { + + // Compatible with 1.1 + static final long serialVersionUID = 5718062286069042927L; + + /** + * Constructs and initializes a Point3d from the specified xyz coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + */ + public Point3d(double x, double y, double z) + { + super(x,y,z); + } + + + /** + * Constructs and initializes a Point3d from the array of length 3. + * @param p the array of length 3 containing xyz in order + */ + public Point3d(double[] p) + { + super(p); + } + + + /** + * Constructs and initializes a Point3d from the specified Point3d. + * @param p1 the Point3d containing the initialization x y z data + */ + public Point3d(Point3d p1) + { + super(p1); + } + + + /** + * Constructs and initializes a Point3d from the specified Point3f. + * @param p1 the Point3f containing the initialization x y z data + */ + public Point3d(Point3f p1) + { + super(p1); + } + + + /** + * Constructs and initializes a Point3d from the specified Tuple3f. + * @param t1 the Tuple3f containing the initialization x y z data + */ + public Point3d(Tuple3f t1) + { + super(t1); + } + + + /** + * Constructs and initializes a Point3d from the specified Tuple3d. + * @param t1 the Tuple3d containing the initialization x y z data + */ + public Point3d(Tuple3d t1) + { + super(t1); + } + + + /** + * Constructs and initializes a Point3d to (0,0,0). + */ + public Point3d() + { + super(); + } + + + /** + * Returns the square of the distance between this point and point p1. + * @param p1 the other point + * @return the square of the distance + */ + public final double distanceSquared(Point3d p1) + { + double dx, dy, dz; + + dx = this.x-p1.x; + dy = this.y-p1.y; + dz = this.z-p1.z; + return (dx*dx+dy*dy+dz*dz); + } + + + /** + * Returns the distance between this point and point p1. + * @param p1 the other point + * @return the distance + */ + public final double distance(Point3d p1) + { + double dx, dy, dz; + + dx = this.x-p1.x; + dy = this.y-p1.y; + dz = this.z-p1.z; + return Math.sqrt(dx*dx+dy*dy+dz*dz); + } + + + /** + * Computes the L-1 (Manhattan) distance between this point and + * point p1. The L-1 distance is equal to: + * abs(x1-x2) + abs(y1-y2) + abs(z1-z2). + * @param p1 the other point + * @return the L-1 distance + */ + public final double distanceL1(Point3d p1) { + return Math.abs(this.x-p1.x) + Math.abs(this.y-p1.y) + + Math.abs(this.z-p1.z); + } + + + /** + * Computes the L-infinite distance between this point and + * point p1. The L-infinite distance is equal to + * MAX[abs(x1-x2), abs(y1-y2), abs(z1-z2)]. + * @param p1 the other point + * @return the L-infinite distance + */ + public final double distanceLinf(Point3d p1) { + double tmp; + tmp = Math.max( Math.abs(this.x-p1.x), Math.abs(this.y-p1.y)); + + return Math.max(tmp,Math.abs(this.z-p1.z)); + } + + + /** + * Multiplies each of the x,y,z components of the Point4d parameter + * by 1/w and places the projected values into this point. + * @param p1 the source Point4d, which is not modified + */ + public final void project(Point4d p1) + { + double oneOw; + + oneOw = 1/p1.w; + x = p1.x*oneOw; + y = p1.y*oneOw; + z = p1.z*oneOw; + + } + + +} diff --git a/src/javax/vecmath/Point3f.java b/src/javax/vecmath/Point3f.java new file mode 100644 index 0000000..1b0a372 --- /dev/null +++ b/src/javax/vecmath/Point3f.java @@ -0,0 +1,178 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 3 element point that is represented by single precision floating point + * x,y,z coordinates. + * + */ +public class Point3f extends Tuple3f implements java.io.Serializable { + + + // Compatible with 1.1 + static final long serialVersionUID = -8689337816398030143L; + + /** + * Constructs and initializes a Point3f from the specified xyz coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + */ + public Point3f(float x, float y, float z) + { + super(x,y,z); + } + + + /** + * Constructs and initializes a Point3f from the array of length 3. + * @param p the array of length 3 containing xyz in order + */ + public Point3f(float[] p) + { + super(p); + } + + + /** + * Constructs and initializes a Point3f from the specified Point3f. + * @param p1 the Point3f containing the initialization x y z data + */ + public Point3f(Point3f p1) + { + super(p1); + } + + + /** + * Constructs and initializes a Point3f from the specified Point3d. + * @param p1 the Point3d containing the initialization x y z data + */ + public Point3f(Point3d p1) + { + super(p1); + } + + + /** + * Constructs and initializes a Point3f from the specified Tuple3f. + * @param t1 the Tuple3f containing the initialization x y z data + */ + public Point3f(Tuple3f t1) + { + super(t1); + } + + + /** + * Constructs and initializes a Point3f from the specified Tuple3d. + * @param t1 the Tuple3d containing the initialization x y z data + */ + public Point3f(Tuple3d t1) + { + super(t1); + } + + + /** + * Constructs and initializes a Point3f to (0,0,0). + */ + public Point3f() + { + super(); + } + + + /** + * Computes the square of the distance between this point and + * point p1. + * @param p1 the other point + * @return the square of the distance + */ + public final float distanceSquared(Point3f p1) + { + float dx, dy, dz; + + dx = this.x-p1.x; + dy = this.y-p1.y; + dz = this.z-p1.z; + return dx*dx+dy*dy+dz*dz; + } + + + /** + * Computes the distance between this point and point p1. + * @param p1 the other point + * @return the distance + */ + public final float distance(Point3f p1) + { + float dx, dy, dz; + + dx = this.x-p1.x; + dy = this.y-p1.y; + dz = this.z-p1.z; + return (float) Math.sqrt(dx*dx+dy*dy+dz*dz); + } + + + /** + * Computes the L-1 (Manhattan) distance between this point and + * point p1. The L-1 distance is equal to: + * abs(x1-x2) + abs(y1-y2) + abs(z1-z2). + * @param p1 the other point + * @return the L-1 distance + */ + public final float distanceL1(Point3f p1) + { + return( Math.abs(this.x-p1.x) + Math.abs(this.y-p1.y) + Math.abs(this.z-p1.z)); + } + + + /** + * Computes the L-infinite distance between this point and + * point p1. The L-infinite distance is equal to + * MAX[abs(x1-x2), abs(y1-y2), abs(z1-z2)]. + * @param p1 the other point + * @return the L-infinite distance + */ + public final float distanceLinf(Point3f p1) + { + float tmp; + tmp = Math.max( Math.abs(this.x-p1.x), Math.abs(this.y-p1.y)); + return(Math.max(tmp,Math.abs(this.z-p1.z))); + + } + + + /** + * Multiplies each of the x,y,z components of the Point4f parameter + * by 1/w and places the projected values into this point. + * @param p1 the source Point4f, which is not modified + */ + public final void project(Point4f p1) + { + float oneOw; + + oneOw = 1/p1.w; + x = p1.x*oneOw; + y = p1.y*oneOw; + z = p1.z*oneOw; + + } + + +} diff --git a/src/javax/vecmath/Point3i.java b/src/javax/vecmath/Point3i.java new file mode 100644 index 0000000..a84c35f --- /dev/null +++ b/src/javax/vecmath/Point3i.java @@ -0,0 +1,66 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 3 element point represented by signed integer x,y,z + * coordinates. + * + * @since Java 3D 1.2 + */ +public class Point3i extends Tuple3i implements java.io.Serializable { + + // Compatible with 1.2 + static final long serialVersionUID = 6149289077348153921L; + + /** + * Constructs and initializes a Point3i from the specified + * x, y, and z coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + */ + public Point3i(int x, int y, int z) { + super(x, y, z); + } + + + /** + * Constructs and initializes a Point3i from the array of length 3. + * @param t the array of length 3 containing x, y, and z in order. + */ + public Point3i(int[] t) { + super(t); + } + + + /** + * Constructs and initializes a Point3i from the specified Tuple3i. + * @param t1 the Tuple3i containing the initialization x, y, and z + * data. + */ + public Point3i(Tuple3i t1) { + super(t1); + } + + + /** + * Constructs and initializes a Point3i to (0,0,0). + */ + public Point3i() { + super(); + } + +} diff --git a/src/javax/vecmath/Point4d.java b/src/javax/vecmath/Point4d.java new file mode 100644 index 0000000..218b4d2 --- /dev/null +++ b/src/javax/vecmath/Point4d.java @@ -0,0 +1,210 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 4 element vector represented by double precision floating point + * x,y,z,w coordinates. + * + */ +public class Point4d extends Tuple4d implements java.io.Serializable { + + // Compatible with 1.1 + static final long serialVersionUID = 1733471895962736949L; + + + /** + * Constructs and initializes a Point4d from the specified xyzw coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param w the w coordinate + */ + public Point4d(double x, double y, double z, double w) + { + super(x,y,z,w); + } + + /** + * Constructs and initializes a Point4d from the coordinates contained + * in the array. + * @param p the array of length 4 containing xyzw in order + */ + public Point4d(double[] p) + { + super(p); + } + + + /** + * Constructs and initializes a Point4d from the specified Point4d. + * @param p1 the Point4d containing the initialization x y z w data + */ + public Point4d(Point4d p1) + { + super(p1); + } + + + /** + * Constructs and initializes a Point4d from the specified Point4f. + * @param p1 the Point4f containing the initialization x y z w data + */ + public Point4d(Point4f p1) + { + super(p1); + } + + + /** + * Constructs and initializes a Point4d from the specified Tuple4f. + * @param t1 the Tuple4f containing the initialization x y z w data + */ + public Point4d(Tuple4f t1) + { + super(t1); + } + + + /** + * Constructs and initializes a Point4d from the specified Tuple4d. + * @param t1 the Tuple4d containing the initialization x y z w data + */ + public Point4d(Tuple4d t1) + { + super(t1); + } + + + /** + * Constructs and initializes a Point4d from the specified Tuple3d. + * The x,y,z components of this point are set to the corresponding + * components of tuple t1. The w component of this point + * is set to 1. + * @param t1 the tuple to be copied + * + * @since Java 3D 1.2 + */ + public Point4d(Tuple3d t1) { + super(t1.x, t1.y, t1.z, 1.0); + } + + + /** + * Constructs and initializes a Point4d to (0,0,0,0). + */ + public Point4d() + { + super(); + } + + + /** + * Sets the x,y,z components of this point to the corresponding + * components of tuple t1. The w component of this point + * is set to 1. + * @param t1 the tuple to be copied + * + * @since Java 3D 1.2 + */ + public final void set(Tuple3d t1) { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + this.w = 1.0; + } + + + /** + * Returns the square of the distance between this point and point p1. + * @param p1 the first point + * @return the square of distance between this point and point p1 + */ + public final double distanceSquared(Point4d p1) + { + double dx, dy, dz, dw; + + dx = this.x-p1.x; + dy = this.y-p1.y; + dz = this.z-p1.z; + dw = this.w-p1.w; + return (dx*dx+dy*dy+dz*dz+dw*dw); + } + + + /** + * Returns the distance between this point and point p1. + * @param p1 the first point + * @return the distance between these this point and point p1. + */ + public final double distance(Point4d p1) + { + double dx, dy, dz, dw; + + dx = this.x-p1.x; + dy = this.y-p1.y; + dz = this.z-p1.z; + dw = this.w-p1.w; + return Math.sqrt(dx*dx+dy*dy+dz*dz+dw*dw); + } + + + /** + * Computes the L-1 (Manhattan) distance between this point and + * point p1. The L-1 distance is equal to: + * abs(x1-x2) + abs(y1-y2) + abs(z1-z2) + abs(w1-w2). + * @param p1 the other point + * @return the L-1 distance + */ + public final double distanceL1(Point4d p1) { + return Math.abs(this.x-p1.x) + Math.abs(this.y-p1.y) + + Math.abs(this.z-p1.z) + Math.abs(this.w-p1.w); + } + + /** + * Computes the L-infinite distance between this point and + * point p1. The L-infinite distance is equal to + * MAX[abs(x1-x2), abs(y1-y2), abs(z1-z2), abs(w1-w2)]. + * @param p1 the other point + * @return the L-infinite distance + */ + public final double distanceLinf(Point4d p1) { + double t1, t2; + t1 = Math.max( Math.abs(this.x-p1.x), Math.abs(this.y-p1.y)); + t2 = Math.max( Math.abs(this.z-p1.z), Math.abs(this.w-p1.w)); + + return Math.max(t1,t2); + } + + /** + * Multiplies each of the x,y,z components of the Point4d parameter + * by 1/w, places the projected values into this point, and places + * a 1 as the w parameter of this point. + * @param p1 the source Point4d, which is not modified + */ + public final void project(Point4d p1) + { + double oneOw; + + oneOw = 1/p1.w; + x = p1.x*oneOw; + y = p1.y*oneOw; + z = p1.z*oneOw; + w = 1.0; + + } + + +} diff --git a/src/javax/vecmath/Point4f.java b/src/javax/vecmath/Point4f.java new file mode 100644 index 0000000..8c7be5e --- /dev/null +++ b/src/javax/vecmath/Point4f.java @@ -0,0 +1,212 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 4 element point represented by single precision floating point x,y,z,w + * coordinates. + * + */ +public class Point4f extends Tuple4f implements java.io.Serializable { + + + // Compatible with 1.1 + static final long serialVersionUID = 4643134103185764459L; + + /** + * Constructs and initializes a Point4f from the specified xyzw coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param w the w coordinate + */ + public Point4f(float x, float y, float z, float w) + { + super(x,y,z,w); + } + + + /** + * Constructs and initializes a Point4f from the array of length 4. + * @param p the array of length 4 containing xyzw in order + */ + public Point4f(float[] p) + { + super(p); + } + + + /** + * Constructs and initializes a Point4f from the specified Point4f. + * @param p1 the Point4f containing the initialization x y z w data + */ + public Point4f(Point4f p1) + { + super(p1); + } + + + /** + * Constructs and initializes a Point4f from the specified Point4d. + * @param p1 the Point4d containing the initialization x y z w data + */ + public Point4f(Point4d p1) + { + super(p1); + } + + + /** + * Constructs and initializes a Point4f from the specified Tuple4f. + * @param t1 the Tuple4f containing the initialization x y z w data + */ + public Point4f(Tuple4f t1) + { + super(t1); + } + + + /** + * Constructs and initializes a Point4f from the specified Tuple4d. + * @param t1 the Tuple4d containing the initialization x y z w data + */ + public Point4f(Tuple4d t1) + { + super(t1); + } + + + /** + * Constructs and initializes a Point4f from the specified Tuple3f. + * The x,y,z components of this point are set to the corresponding + * components of tuple t1. The w component of this point + * is set to 1. + * @param t1 the tuple to be copied + * + * @since Java 3D 1.2 + */ + public Point4f(Tuple3f t1) { + super(t1.x, t1.y, t1.z, 1.0f); + } + + + /** + * Constructs and initializes a Point4f to (0,0,0,0). + */ + public Point4f() + { + super(); + } + + + /** + * Sets the x,y,z components of this point to the corresponding + * components of tuple t1. The w component of this point + * is set to 1. + * @param t1 the tuple to be copied + * + * @since Java 3D 1.2 + */ + public final void set(Tuple3f t1) { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + this.w = 1.0f; + } + + + /** + * Computes the square of the distance between this point and point p1. + * @param p1 the other point + * @return the square of distance between these two points as a float + */ + public final float distanceSquared(Point4f p1) + { + float dx, dy, dz, dw; + + dx = this.x-p1.x; + dy = this.y-p1.y; + dz = this.z-p1.z; + dw = this.w-p1.w; + return (dx*dx+dy*dy+dz*dz+dw*dw); + } + + + /** + * Computes the distance between this point and point p1. + * @param p1 the other point + * @return the distance between the two points + */ + public final float distance(Point4f p1) + { + float dx, dy, dz, dw; + + dx = this.x-p1.x; + dy = this.y-p1.y; + dz = this.z-p1.z; + dw = this.w-p1.w; + return (float) Math.sqrt(dx*dx+dy*dy+dz*dz+dw*dw); + } + + + /** + * Computes the L-1 (Manhattan) distance between this point and + * point p1. The L-1 distance is equal to: + * abs(x1-x2) + abs(y1-y2) + abs(z1-z2) + abs(w1-w2). + * @param p1 the other point + * @return the L-1 distance + */ + public final float distanceL1(Point4f p1) + { + return( Math.abs(this.x-p1.x) + Math.abs(this.y-p1.y) + Math.abs(this.z-p1.z) + Math.abs(this.w-p1.w)); + } + + + /** + * Computes the L-infinite distance between this point and + * point p1. The L-infinite distance is equal to + * MAX[abs(x1-x2), abs(y1-y2), abs(z1-z2), abs(w1-w2)]. + * @param p1 the other point + * @return the L-infinite distance + */ + public final float distanceLinf(Point4f p1) + { + float t1, t2; + t1 = Math.max( Math.abs(this.x-p1.x), Math.abs(this.y-p1.y)); + t2 = Math.max( Math.abs(this.z-p1.z), Math.abs(this.w-p1.w)); + + return(Math.max(t1,t2)); + + } + + /** + * Multiplies each of the x,y,z components of the Point4f parameter + * by 1/w, places the projected values into this point, and places + * a 1 as the w parameter of this point. + * @param p1 the source Point4f, which is not modified + */ + public final void project(Point4f p1) + { + float oneOw; + + oneOw = 1/p1.w; + x = p1.x*oneOw; + y = p1.y*oneOw; + z = p1.z*oneOw; + w = 1.0f; + + } + +} diff --git a/src/javax/vecmath/Point4i.java b/src/javax/vecmath/Point4i.java new file mode 100644 index 0000000..13c6962 --- /dev/null +++ b/src/javax/vecmath/Point4i.java @@ -0,0 +1,67 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 4 element point represented by signed integer x,y,z,w + * coordinates. + * + * @since Java 3D 1.2 + */ +public class Point4i extends Tuple4i implements java.io.Serializable { + + // Combatible with 1.2 + static final long serialVersionUID = 620124780244617983L; + + /** + * Constructs and initializes a Point4i from the specified + * x, y, z, and w coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param w the w coordinate + */ + public Point4i(int x, int y, int z, int w) { + super(x, y, z, w); + } + + + /** + * Constructs and initializes a Point4i from the array of length 4. + * @param t the array of length 4 containing x, y, z, and w in order. + */ + public Point4i(int[] t) { + super(t); + } + + + /** + * Constructs and initializes a Point4i from the specified Tuple4i. + * @param t1 the Tuple4i containing the initialization x, y, z, + * and w data. + */ + public Point4i(Tuple4i t1) { + super(t1); + } + + + /** + * Constructs and initializes a Point4i to (0,0,0,0). + */ + public Point4i() { + super(); + } + +} diff --git a/src/javax/vecmath/Quat4d.java b/src/javax/vecmath/Quat4d.java new file mode 100644 index 0000000..c6232f6 --- /dev/null +++ b/src/javax/vecmath/Quat4d.java @@ -0,0 +1,662 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 4-element quaternion represented by double precision floating + * point x,y,z,w coordinates. The quaternion is always normalized. + * + */ +public class Quat4d extends Tuple4d implements java.io.Serializable { + + // Combatible with 1.1 + static final long serialVersionUID = 7577479888820201099L; + + final static double EPS = 0.000001; + final static double EPS2 = 1.0e-30; + final static double PIO2 = 1.57079632679; + + /** + * Constructs and initializes a Quat4d from the specified xyzw coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param w the w scalar component + */ + public Quat4d(double x, double y, double z, double w) + { + double mag; + mag = 1.0/Math.sqrt( x*x + y*y + z*z + w*w ); + this.x = x*mag; + this.y = y*mag; + this.z = z*mag; + this.w = w*mag; + + } + + /** + * Constructs and initializes a Quat4d from the array of length 4. + * @param q the array of length 4 containing xyzw in order + */ + public Quat4d(double[] q) + { + double mag; + mag = 1.0/Math.sqrt( q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3] ); + x = q[0]*mag; + y = q[1]*mag; + z = q[2]*mag; + w = q[3]*mag; + + } + + /** + * Constructs and initializes a Quat4d from the specified Quat4d. + * @param q1 the Quat4d containing the initialization x y z w data + */ + public Quat4d(Quat4d q1) + { + super(q1); + } + + /** + * Constructs and initializes a Quat4d from the specified Quat4f. + * @param q1 the Quat4f containing the initialization x y z w data + */ + public Quat4d(Quat4f q1) + { + super(q1); + } + + + /** + * Constructs and initializes a Quat4d from the specified Tuple4f. + * @param t1 the Tuple4f containing the initialization x y z w data + */ + public Quat4d(Tuple4f t1) + { + double mag; + mag = 1.0/Math.sqrt( t1.x*t1.x + t1.y*t1.y + t1.z*t1.z + t1.w*t1.w ); + x = t1.x*mag; + y = t1.y*mag; + z = t1.z*mag; + w = t1.w*mag; + + } + + + /** + * Constructs and initializes a Quat4d from the specified Tuple4d. + * @param t1 the Tuple4d containing the initialization x y z w data + */ + public Quat4d(Tuple4d t1) + { + double mag; + mag = 1.0/Math.sqrt( t1.x*t1.x + t1.y*t1.y + t1.z*t1.z + t1.w*t1.w ); + x = t1.x*mag; + y = t1.y*mag; + z = t1.z*mag; + w = t1.w*mag; + } + + + /** + * Constructs and initializes a Quat4d to (0,0,0,0). + */ + public Quat4d() + { + super(); + } + + + /** + * Sets the value of this quaternion to the conjugate of quaternion q1. + * @param q1 the source vector + */ + public final void conjugate(Quat4d q1) + { + this.x = -q1.x; + this.y = -q1.y; + this.z = -q1.z; + this.w = q1.w; + } + + + /** + * Negate the value of of each of this quaternion's x,y,z coordinates + * in place. + */ + public final void conjugate() + { + this.x = -this.x; + this.y = -this.y; + this.z = -this.z; + } + + + /** + * Sets the value of this quaternion to the quaternion product of + * quaternions q1 and q2 (this = q1 * q2). + * Note that this is safe for aliasing (e.g. this can be q1 or q2). + * @param q1 the first quaternion + * @param q2 the second quaternion + */ + public final void mul(Quat4d q1, Quat4d q2) + { + if (this != q1 && this != q2) { + this.w = q1.w*q2.w - q1.x*q2.x - q1.y*q2.y - q1.z*q2.z; + this.x = q1.w*q2.x + q2.w*q1.x + q1.y*q2.z - q1.z*q2.y; + this.y = q1.w*q2.y + q2.w*q1.y - q1.x*q2.z + q1.z*q2.x; + this.z = q1.w*q2.z + q2.w*q1.z + q1.x*q2.y - q1.y*q2.x; + } else { + double x, y, w; + + w = q1.w*q2.w - q1.x*q2.x - q1.y*q2.y - q1.z*q2.z; + x = q1.w*q2.x + q2.w*q1.x + q1.y*q2.z - q1.z*q2.y; + y = q1.w*q2.y + q2.w*q1.y - q1.x*q2.z + q1.z*q2.x; + this.z = q1.w*q2.z + q2.w*q1.z + q1.x*q2.y - q1.y*q2.x; + this.w = w; + this.x = x; + this.y = y; + } + } + + + /** + * Sets the value of this quaternion to the quaternion product of + * itself and q1 (this = this * q1). + * @param q1 the other quaternion + */ + public final void mul(Quat4d q1) + { + double x, y, w; + + w = this.w*q1.w - this.x*q1.x - this.y*q1.y - this.z*q1.z; + x = this.w*q1.x + q1.w*this.x + this.y*q1.z - this.z*q1.y; + y = this.w*q1.y + q1.w*this.y - this.x*q1.z + this.z*q1.x; + this.z = this.w*q1.z + q1.w*this.z + this.x*q1.y - this.y*q1.x; + this.w = w; + this.x = x; + this.y = y; + } + + + /** + * Multiplies quaternion q1 by the inverse of quaternion q2 and places + * the value into this quaternion. The value of both argument quaternions + * is preservered (this = q1 * q2^-1). + * @param q1 the first quaternion + * @param q2 the second quaternion + */ + public final void mulInverse(Quat4d q1, Quat4d q2) + { + Quat4d tempQuat = new Quat4d(q2); + + tempQuat.inverse(); + this.mul(q1, tempQuat); + } + + + + /** + * Multiplies this quaternion by the inverse of quaternion q1 and places + * the value into this quaternion. The value of the argument quaternion + * is preserved (this = this * q^-1). + * @param q1 the other quaternion + */ + public final void mulInverse(Quat4d q1) + { + Quat4d tempQuat = new Quat4d(q1); + + tempQuat.inverse(); + this.mul(tempQuat); + } + + + /** + * Sets the value of this quaternion to quaternion inverse of quaternion q1. + * @param q1 the quaternion to be inverted + */ + public final void inverse(Quat4d q1) + { + double norm; + + norm = 1.0/(q1.w*q1.w + q1.x*q1.x + q1.y*q1.y + q1.z*q1.z); + this.w = norm*q1.w; + this.x = -norm*q1.x; + this.y = -norm*q1.y; + this.z = -norm*q1.z; + } + + + /** + * Sets the value of this quaternion to the quaternion inverse of itself. + */ + public final void inverse() + { + double norm; + + norm = 1.0/(this.w*this.w + this.x*this.x + this.y*this.y + this.z*this.z); + this.w *= norm; + this.x *= -norm; + this.y *= -norm; + this.z *= -norm; + } + + + /** + * Sets the value of this quaternion to the normalized value + * of quaternion q1. + * @param q1 the quaternion to be normalized. + */ + public final void normalize(Quat4d q1) + { + double norm; + + norm = (q1.x*q1.x + q1.y*q1.y + q1.z*q1.z + q1.w*q1.w); + + if (norm > 0.0) { + norm = 1.0/Math.sqrt(norm); + this.x = norm*q1.x; + this.y = norm*q1.y; + this.z = norm*q1.z; + this.w = norm*q1.w; + } else { + this.x = 0.0; + this.y = 0.0; + this.z = 0.0; + this.w = 0.0; + } + } + + + /** + * Normalizes the value of this quaternion in place. + */ + public final void normalize() + { + double norm; + + norm = (this.x*this.x + this.y*this.y + this.z*this.z + this.w*this.w); + + if (norm > 0.0) { + norm = 1.0 / Math.sqrt(norm); + this.x *= norm; + this.y *= norm; + this.z *= norm; + this.w *= norm; + } else { + this.x = 0.0; + this.y = 0.0; + this.z = 0.0; + this.w = 0.0; + } + } + + + /** + * Sets the value of this quaternion to the rotational component of + * the passed matrix. + * @param m1 the matrix4f + */ + public final void set(Matrix4f m1) + { + double ww = 0.25*(m1.m00 + m1.m11 + m1.m22 + m1.m33); + + if (ww >= 0) { + if (ww >= EPS2) { + this.w = Math.sqrt(ww); + ww = 0.25/this.w; + this.x = ((m1.m21 - m1.m12)*ww); + this.y = ((m1.m02 - m1.m20)*ww); + this.z = ((m1.m10 - m1.m01)*ww); + return; + } + } else { + this.w = 0; + this.x = 0; + this.y = 0; + this.z = 1; + return; + } + + this.w = 0; + ww = -0.5*(m1.m11 + m1.m22); + if (ww >= 0) { + if (ww >= EPS2) { + this.x = Math.sqrt(ww); + ww = 1.0/(2.0*this.x); + this.y = (m1.m10*ww); + this.z = (m1.m20*ww); + return; + } + } else { + this.x = 0; + this.y = 0; + this.z = 1; + return; + } + + this.x = 0; + ww = 0.5*(1.0 - m1.m22); + if (ww >= EPS2) { + this.y = Math.sqrt(ww); + this.z = (m1.m21)/(2.0*this.y); + return; + } + + this.y = 0; + this.z = 1; + } + + + /** + * Sets the value of this quaternion to the rotational component of + * the passed matrix. + * @param m1 the matrix4d + */ + public final void set(Matrix4d m1) + { + double ww = 0.25*(m1.m00 + m1.m11 + m1.m22 + m1.m33); + + if (ww >= 0) { + if (ww >= EPS2) { + this.w = Math.sqrt(ww); + ww = 0.25/this.w; + this.x = (m1.m21 - m1.m12)*ww; + this.y = (m1.m02 - m1.m20)*ww; + this.z = (m1.m10 - m1.m01)*ww; + return; + } + } else { + this.w = 0; + this.x = 0; + this.y = 0; + this.z = 1; + return; + } + + this.w = 0; + ww = -0.5*(m1.m11 + m1.m22); + if (ww >= 0) { + if (ww >= EPS2){ + this.x = Math.sqrt(ww); + ww = 0.5/this.x; + this.y = m1.m10*ww; + this.z = m1.m20*ww; + return; + } + } else { + this.x = 0; + this.y = 0; + this.z = 1; + return; + } + + this.x = 0.0; + ww = 0.5*(1.0 - m1.m22); + if (ww >= EPS2) { + this.y = Math.sqrt(ww); + this.z = m1.m21/(2.0*this.y); + return; + } + + this.y = 0; + this.z = 1; + } + + + /** + * Sets the value of this quaternion to the rotational component of + * the passed matrix. + * @param m1 the matrix3f + */ + public final void set(Matrix3f m1) + { + double ww = 0.25*(m1.m00 + m1.m11 + m1.m22 + 1.0); + + if (ww >= 0) { + if (ww >= EPS2) { + this.w = Math.sqrt(ww); + ww = 0.25/this.w; + this.x = ((m1.m21 - m1.m12)*ww); + this.y = ((m1.m02 - m1.m20)*ww); + this.z = ((m1.m10 - m1.m01)*ww); + return; + } + } else { + this.w = 0; + this.x = 0; + this.y = 0; + this.z = 1; + return; + } + + this.w = 0; + ww = -0.5*(m1.m11 + m1.m22); + if (ww >= 0) { + if (ww >= EPS2) { + this.x = Math.sqrt(ww); + ww = 0.5/this.x; + this.y = (m1.m10*ww); + this.z = (m1.m20*ww); + return; + } + } else { + this.x = 0; + this.y = 0; + this.z = 1; + return; + } + + this.x = 0; + ww = 0.5*(1.0 - m1.m22); + if (ww >= EPS2) { + this.y = Math.sqrt(ww); + this.z = (m1.m21/(2.0*this.y)); + } + + this.y = 0; + this.z = 1; + } + + + /** + * Sets the value of this quaternion to the rotational component of + * the passed matrix. + * @param m1 the matrix3d + */ + public final void set(Matrix3d m1) + { + double ww = 0.25*(m1.m00 + m1.m11 + m1.m22 + 1.0); + + if (ww >= 0) { + if (ww >= EPS2) { + this.w = Math.sqrt(ww); + ww = 0.25/this.w; + this.x = (m1.m21 - m1.m12)*ww; + this.y = (m1.m02 - m1.m20)*ww; + this.z = (m1.m10 - m1.m01)*ww; + return; + } + } else { + this.w = 0; + this.x = 0; + this.y = 0; + this.z = 1; + return; + } + + this.w = 0; + ww = -0.5*(m1.m11 + m1.m22); + if (ww >= 0) { + if (ww >= EPS2) { + this.x = Math.sqrt(ww); + ww = 0.5/this.x; + this.y = m1.m10*ww; + this.z = m1.m20*ww; + return; + } + } else { + this.x = 0; + this.y = 0; + this.z = 1; + return; + } + + this.x = 0; + ww = 0.5*(1.0 - m1.m22); + if (ww >= EPS2) { + this.y = Math.sqrt(ww); + this.z = m1.m21/(2.0*this.y); + return; + } + + this.y = 0; + this.z = 1; + } + + + /** + * Sets the value of this quaternion to the equivalent rotation + * of the AxisAngle argument. + * @param a the AxisAngle to be emulated + */ + public final void set(AxisAngle4f a) + { + double mag,amag; + // Quat = cos(theta/2) + sin(theta/2)(roation_axis) + + amag = Math.sqrt( a.x*a.x + a.y*a.y + a.z*a.z); + if( amag < EPS ) { + w = 0.0; + x = 0.0; + y = 0.0; + z = 0.0; + } else { + mag = Math.sin(a.angle/2.0); + amag = 1.0/amag; + w = Math.cos(a.angle/2.0); + x = a.x*amag*mag; + y = a.y*amag*mag; + z = a.z*amag*mag; + } + + } + + /** + * Sets the value of this quaternion to the equivalent rotation + * of the AxisAngle argument. + * @param a the AxisAngle to be emulated + */ + public final void set(AxisAngle4d a) + { + double mag,amag; + // Quat = cos(theta/2) + sin(theta/2)(roation_axis) + + amag = Math.sqrt( a.x*a.x + a.y*a.y + a.z*a.z); + if( amag < EPS ) { + w = 0.0; + x = 0.0; + y = 0.0; + z = 0.0; + } else { + amag = 1.0/amag; + mag = Math.sin(a.angle/2.0); + w = Math.cos(a.angle/2.0); + x = a.x*amag*mag; + y = a.y*amag*mag; + z = a.z*amag*mag; + } + + } + + /** + * Performs a great circle interpolation between this quaternion + * and the quaternion parameter and places the result into this + * quaternion. + * @param q1 the other quaternion + * @param alpha the alpha interpolation parameter + */ + public final void interpolate(Quat4d q1, double alpha) { + // From "Advanced Animation and Rendering Techniques" + // by Watt and Watt pg. 364, function as implemented appeared to be + // incorrect. Fails to choose the same quaternion for the double + // covering. Resulting in change of direction for rotations. + // Fixed function to negate the first quaternion in the case that the + // dot product of q1 and this is negative. Second case was not needed. + double dot,s1,s2,om,sinom; + + dot = x*q1.x + y*q1.y + z*q1.z + w*q1.w; + + if ( dot < 0 ) { + // switch the quaterion values + q1.x = -q1.x; q1.y = -q1.y; q1.z = -q1.z; q1.w = -q1.w; + } + + if ( (1.0 - Math.abs(dot) ) > EPS ) { + om = Math.acos(dot); + sinom = Math.sin(om); + s1 = Math.sin((1.0-alpha)*om)/sinom; + s2 = Math.sin( alpha*om)/sinom; + } else{ + s1 = 1.0 - alpha; + s2 = alpha; + } + + w = s1*w + s2*q1.w; + x = s1*x + s2*q1.x; + y = s1*y + s2*q1.y; + z = s1*z + s2*q1.z; + } + +/** + * Performs a great circle interpolation between quaternion q1 + * and quaternion q2 and places the result into this quaternion. + * @param q1 the first quaternion + * @param q2 the second quaternion + * @param alpha the alpha interpolation parameter + */ + public final void interpolate(Quat4d q1, Quat4d q2, double alpha) { + // From "Advanced Animation and Rendering Techniques" + // by Watt and Watt pg. 364, function as implemented appeared to be + // incorrect. Fails to choose the same quaternion for the double + // covering. Resulting in change of direction for rotations. + // Fixed function to negate the first quaternion in the case that the + // dot product of q1 and this is negative. Second case was not needed. + double dot,s1,s2,om,sinom; + + dot = q2.x*q1.x + q2.y*q1.y + q2.z*q1.z + q2.w*q1.w; + + if ( dot < 0 ) { + // switch the quaterion values + q1.x = -q1.x; q1.y = -q1.y; q1.z = -q1.z; q1.w = -q1.w; + } + + if ( (1.0 - Math.abs(dot) ) > EPS ) { + om = Math.acos(dot); + sinom = Math.sin(om); + s1 = Math.sin((1.0-alpha)*om)/sinom; + s2 = Math.sin( alpha*om)/sinom; + } else{ + s1 = 1.0 - alpha; + s2 = alpha; + } + w = s1*q1.w + s2*q2.w; + x = s1*q1.x + s2*q2.x; + y = s1*q1.y + s2*q2.y; + z = s1*q1.z + s2*q2.z; + } + +} diff --git a/src/javax/vecmath/Quat4f.java b/src/javax/vecmath/Quat4f.java new file mode 100644 index 0000000..f4fecfa --- /dev/null +++ b/src/javax/vecmath/Quat4f.java @@ -0,0 +1,674 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 4 element unit quaternion represented by single precision floating + * point x,y,z,w coordinates. The quaternion is always normalized. + * + */ +public class Quat4f extends Tuple4f implements java.io.Serializable { + + // Combatible with 1.1 + static final long serialVersionUID = 2675933778405442383L; + + final static double EPS = 0.000001; + final static double EPS2 = 1.0e-30; + final static double PIO2 = 1.57079632679; + + /** + * Constructs and initializes a Quat4f from the specified xyzw coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param w the w scalar component + */ + public Quat4f(float x, float y, float z, float w) + { + float mag; + mag = (float)(1.0/Math.sqrt( x*x + y*y + z*z + w*w )); + this.x = x*mag; + this.y = y*mag; + this.z = z*mag; + this.w = w*mag; + + } + + /** + * Constructs and initializes a Quat4f from the array of length 4. + * @param q the array of length 4 containing xyzw in order + */ + public Quat4f(float[] q) + { + float mag; + mag = (float)(1.0/Math.sqrt( q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3] )); + x = q[0]*mag; + y = q[1]*mag; + z = q[2]*mag; + w = q[3]*mag; + + } + + + /** + * Constructs and initializes a Quat4f from the specified Quat4f. + * @param q1 the Quat4f containing the initialization x y z w data + */ + public Quat4f(Quat4f q1) + { + super(q1); + } + + /** + * Constructs and initializes a Quat4f from the specified Quat4d. + * @param q1 the Quat4d containing the initialization x y z w data + */ + public Quat4f(Quat4d q1) + { + super(q1); + } + + + /** + * Constructs and initializes a Quat4f from the specified Tuple4f. + * @param t1 the Tuple4f containing the initialization x y z w data + */ + public Quat4f(Tuple4f t1) + { + float mag; + mag = (float)(1.0/Math.sqrt( t1.x*t1.x + t1.y*t1.y + t1.z*t1.z + t1.w*t1.w )); + x = t1.x*mag; + y = t1.y*mag; + z = t1.z*mag; + w = t1.w*mag; + + } + + + /** + * Constructs and initializes a Quat4f from the specified Tuple4d. + * @param t1 the Tuple4d containing the initialization x y z w data + */ + public Quat4f(Tuple4d t1) + { + double mag; + mag = 1.0/Math.sqrt( t1.x*t1.x + t1.y*t1.y + t1.z*t1.z + t1.w*t1.w ); + x = (float)(t1.x*mag); + y = (float)(t1.y*mag); + z = (float)(t1.z*mag); + w = (float)(t1.w*mag); + } + + + /** + * Constructs and initializes a Quat4f to (0.0,0.0,0.0,0.0). + */ + public Quat4f() + { + super(); + } + + + /** + * Sets the value of this quaternion to the conjugate of quaternion q1. + * @param q1 the source vector + */ + public final void conjugate(Quat4f q1) + { + this.x = -q1.x; + this.y = -q1.y; + this.z = -q1.z; + this.w = q1.w; + } + + /** + * Sets the value of this quaternion to the conjugate of itself. + */ + public final void conjugate() + { + this.x = -this.x; + this.y = -this.y; + this.z = -this.z; + } + + + /** + * Sets the value of this quaternion to the quaternion product of + * quaternions q1 and q2 (this = q1 * q2). + * Note that this is safe for aliasing (e.g. this can be q1 or q2). + * @param q1 the first quaternion + * @param q2 the second quaternion + */ + public final void mul(Quat4f q1, Quat4f q2) + { + if (this != q1 && this != q2) { + this.w = q1.w*q2.w - q1.x*q2.x - q1.y*q2.y - q1.z*q2.z; + this.x = q1.w*q2.x + q2.w*q1.x + q1.y*q2.z - q1.z*q2.y; + this.y = q1.w*q2.y + q2.w*q1.y - q1.x*q2.z + q1.z*q2.x; + this.z = q1.w*q2.z + q2.w*q1.z + q1.x*q2.y - q1.y*q2.x; + } else { + float x, y, w; + + w = q1.w*q2.w - q1.x*q2.x - q1.y*q2.y - q1.z*q2.z; + x = q1.w*q2.x + q2.w*q1.x + q1.y*q2.z - q1.z*q2.y; + y = q1.w*q2.y + q2.w*q1.y - q1.x*q2.z + q1.z*q2.x; + this.z = q1.w*q2.z + q2.w*q1.z + q1.x*q2.y - q1.y*q2.x; + this.w = w; + this.x = x; + this.y = y; + } + } + + + /** + * Sets the value of this quaternion to the quaternion product of + * itself and q1 (this = this * q1). + * @param q1 the other quaternion + */ + public final void mul(Quat4f q1) + { + float x, y, w; + + w = this.w*q1.w - this.x*q1.x - this.y*q1.y - this.z*q1.z; + x = this.w*q1.x + q1.w*this.x + this.y*q1.z - this.z*q1.y; + y = this.w*q1.y + q1.w*this.y - this.x*q1.z + this.z*q1.x; + this.z = this.w*q1.z + q1.w*this.z + this.x*q1.y - this.y*q1.x; + this.w = w; + this.x = x; + this.y = y; + } + + + /** + * Multiplies quaternion q1 by the inverse of quaternion q2 and places + * the value into this quaternion. The value of both argument quaternions + * is preservered (this = q1 * q2^-1). + * @param q1 the first quaternion + * @param q2 the second quaternion + */ + public final void mulInverse(Quat4f q1, Quat4f q2) + { + Quat4f tempQuat = new Quat4f(q2); + + tempQuat.inverse(); + this.mul(q1, tempQuat); + } + + + + /** + * Multiplies this quaternion by the inverse of quaternion q1 and places + * the value into this quaternion. The value of the argument quaternion + * is preserved (this = this * q^-1). + * @param q1 the other quaternion + */ + public final void mulInverse(Quat4f q1) + { + Quat4f tempQuat = new Quat4f(q1); + + tempQuat.inverse(); + this.mul(tempQuat); + } + + + + /** + * Sets the value of this quaternion to quaternion inverse of quaternion q1. + * @param q1 the quaternion to be inverted + */ + public final void inverse(Quat4f q1) + { + float norm; + + norm = 1.0f/(q1.w*q1.w + q1.x*q1.x + q1.y*q1.y + q1.z*q1.z); + this.w = norm*q1.w; + this.x = -norm*q1.x; + this.y = -norm*q1.y; + this.z = -norm*q1.z; + } + + + /** + * Sets the value of this quaternion to the quaternion inverse of itself. + */ + public final void inverse() + { + float norm; + + norm = 1.0f/(this.w*this.w + this.x*this.x + this.y*this.y + this.z*this.z); + this.w *= norm; + this.x *= -norm; + this.y *= -norm; + this.z *= -norm; + } + + + /** + * Sets the value of this quaternion to the normalized value + * of quaternion q1. + * @param q1 the quaternion to be normalized. + */ + public final void normalize(Quat4f q1) + { + float norm; + + norm = (q1.x*q1.x + q1.y*q1.y + q1.z*q1.z + q1.w*q1.w); + + if (norm > 0.0f) { + norm = 1.0f/(float)Math.sqrt(norm); + this.x = norm*q1.x; + this.y = norm*q1.y; + this.z = norm*q1.z; + this.w = norm*q1.w; + } else { + this.x = (float) 0.0; + this.y = (float) 0.0; + this.z = (float) 0.0; + this.w = (float) 0.0; + } + } + + + /** + * Normalizes the value of this quaternion in place. + */ + public final void normalize() + { + float norm; + + norm = (this.x*this.x + this.y*this.y + this.z*this.z + this.w*this.w); + + if (norm > 0.0f) { + norm = 1.0f / (float)Math.sqrt(norm); + this.x *= norm; + this.y *= norm; + this.z *= norm; + this.w *= norm; + } else { + this.x = (float) 0.0; + this.y = (float) 0.0; + this.z = (float) 0.0; + this.w = (float) 0.0; + } + } + + + /** + * Sets the value of this quaternion to the rotational component of + * the passed matrix. + * @param m1 the Matrix4f + */ + public final void set(Matrix4f m1) + { + float ww = 0.25f*(m1.m00 + m1.m11 + m1.m22 + m1.m33); + + if (ww >= 0) { + if (ww >= EPS2) { + this.w = (float) Math.sqrt((double)ww); + ww = 0.25f/this.w; + this.x = (m1.m21 - m1.m12)*ww; + this.y = (m1.m02 - m1.m20)*ww; + this.z = (m1.m10 - m1.m01)*ww; + return; + } + } else { + this.w = 0; + this.x = 0; + this.y = 0; + this.z = 1; + return; + } + + this.w = 0; + ww = -0.5f*(m1.m11 + m1.m22); + + if (ww >= 0) { + if (ww >= EPS2) { + this.x = (float) Math.sqrt((double) ww); + ww = 1.0f/(2.0f*this.x); + this.y = m1.m10*ww; + this.z = m1.m20*ww; + return; + } + } else { + this.x = 0; + this.y = 0; + this.z = 1; + return; + } + + this.x = 0; + ww = 0.5f*(1.0f - m1.m22); + + if (ww >= EPS2) { + this.y = (float) Math.sqrt((double) ww); + this.z = m1.m21/(2.0f*this.y); + return; + } + + this.y = 0; + this.z = 1; + } + + + /** + * Sets the value of this quaternion to the rotational component of + * the passed matrix. + * @param m1 the Matrix4d + */ + public final void set(Matrix4d m1) + { + double ww = 0.25*(m1.m00 + m1.m11 + m1.m22 + m1.m33); + + if (ww >= 0) { + if (ww >= EPS2) { + this.w = (float) Math.sqrt(ww); + ww = 0.25/this.w; + this.x = (float) ((m1.m21 - m1.m12)*ww); + this.y = (float) ((m1.m02 - m1.m20)*ww); + this.z = (float) ((m1.m10 - m1.m01)*ww); + return; + } + } else { + this.w = 0; + this.x = 0; + this.y = 0; + this.z = 1; + return; + } + + this.w = 0; + ww = -0.5*(m1.m11 + m1.m22); + if (ww >= 0) { + if (ww >= EPS2) { + this.x = (float) Math.sqrt(ww); + ww = 0.5/this.x; + this.y = (float)(m1.m10*ww); + this.z = (float)(m1.m20*ww); + return; + } + } else { + this.x = 0; + this.y = 0; + this.z = 1; + return; + } + + this.x = 0; + ww = 0.5*(1.0 - m1.m22); + if (ww >= EPS2) { + this.y = (float) Math.sqrt(ww); + this.z = (float) (m1.m21/(2.0*(double)(this.y))); + return; + } + + this.y = 0; + this.z = 1; + } + + + /** + * Sets the value of this quaternion to the rotational component of + * the passed matrix. + * @param m1 the Matrix3f + */ + public final void set(Matrix3f m1) + { + float ww = 0.25f*(m1.m00 + m1.m11 + m1.m22 + 1.0f); + + if (ww >= 0) { + if (ww >= EPS2) { + this.w = (float) Math.sqrt((double) ww); + ww = 0.25f/this.w; + this.x = (m1.m21 - m1.m12)*ww; + this.y = (m1.m02 - m1.m20)*ww; + this.z = (m1.m10 - m1.m01)*ww; + return; + } + } else { + this.w = 0; + this.x = 0; + this.y = 0; + this.z = 1; + return; + } + + this.w = 0; + ww = -0.5f*(m1.m11 + m1.m22); + if (ww >= 0) { + if (ww >= EPS2) { + this.x = (float) Math.sqrt((double) ww); + ww = 0.5f/this.x; + this.y = m1.m10*ww; + this.z = m1.m20*ww; + return; + } + } else { + this.x = 0; + this.y = 0; + this.z = 1; + return; + } + + this.x = 0; + ww = 0.5f*(1.0f - m1.m22); + if (ww >= EPS2) { + this.y = (float) Math.sqrt((double) ww); + this.z = m1.m21/(2.0f*this.y); + return; + } + + this.y = 0; + this.z = 1; + } + + + /** + * Sets the value of this quaternion to the rotational component of + * the passed matrix. + * @param m1 the Matrix3d + */ + public final void set(Matrix3d m1) + { + double ww = 0.25*(m1.m00 + m1.m11 + m1.m22 + 1.0f); + + if (ww >= 0) { + if (ww >= EPS2) { + this.w = (float) Math.sqrt(ww); + ww = 0.25/this.w; + this.x = (float) ((m1.m21 - m1.m12)*ww); + this.y = (float) ((m1.m02 - m1.m20)*ww); + this.z = (float) ((m1.m10 - m1.m01)*ww); + return; + } + } else { + this.w = 0; + this.x = 0; + this.y = 0; + this.z = 1; + return; + } + + this.w = 0; + ww = -0.5*(m1.m11 + m1.m22); + if (ww >= 0) { + if (ww >= EPS2) { + this.x = (float) Math.sqrt(ww); + ww = 0.5/this.x; + this.y = (float) (m1.m10*ww); + this.z = (float) (m1.m20*ww); + return; + } + } else { + this.x = 0; + this.y = 0; + this.z = 1; + return; + } + + this.x = 0; + ww = 0.5*(1.0 - m1.m22); + if (ww >= EPS2) { + this.y = (float) Math.sqrt(ww); + this.z = (float) (m1.m21/(2.0*(double)(this.y))); + return; + } + + this.y = 0; + this.z = 1; + } + + + /** + * Sets the value of this quaternion to the equivalent rotation + * of the AxisAngle argument. + * @param a the AxisAngle to be emulated + */ + public final void set(AxisAngle4f a) + { + float mag,amag; + // Quat = cos(theta/2) + sin(theta/2)(roation_axis) + amag = (float)Math.sqrt( a.x*a.x + a.y*a.y + a.z*a.z); + if (amag < EPS ) { + w = 0.0f; + x = 0.0f; + y = 0.0f; + z = 0.0f; + } else { + amag = 1.0f/amag; + mag = (float)Math.sin(a.angle/2.0); + w = (float)Math.cos(a.angle/2.0); + x = a.x*amag*mag; + y = a.y*amag*mag; + z = a.z*amag*mag; + } + } + + + /** + * Sets the value of this quaternion to the equivalent rotation + * of the AxisAngle argument. + * @param a the AxisAngle to be emulated + */ + public final void set(AxisAngle4d a) + { + float mag,amag; + // Quat = cos(theta/2) + sin(theta/2)(roation_axis) + + amag = (float)(1.0/Math.sqrt( a.x*a.x + a.y*a.y + a.z*a.z)); + + if (amag < EPS ) { + w = 0.0f; + x = 0.0f; + y = 0.0f; + z = 0.0f; + } else { + amag = 1.0f/amag; + mag = (float)Math.sin(a.angle/2.0); + w = (float)Math.cos(a.angle/2.0); + x = (float)a.x*amag*mag; + y = (float)a.y*amag*mag; + z = (float)a.z*amag*mag; + } + + } + + + /** + * Performs a great circle interpolation between this quaternion + * and the quaternion parameter and places the result into this + * quaternion. + * @param q1 the other quaternion + * @param alpha the alpha interpolation parameter + */ + public final void interpolate(Quat4f q1, float alpha) { + // From "Advanced Animation and Rendering Techniques" + // by Watt and Watt pg. 364, function as implemented appeared to be + // incorrect. Fails to choose the same quaternion for the double + // covering. Resulting in change of direction for rotations. + // Fixed function to negate the first quaternion in the case that the + // dot product of q1 and this is negative. Second case was not needed. + + double dot,s1,s2,om,sinom; + + dot = x*q1.x + y*q1.y + z*q1.z + w*q1.w; + + if ( dot < 0 ) { + // switch the quaterion values + q1.x = -q1.x; q1.y = -q1.y; q1.z = -q1.z; q1.w = -q1.w; + } + + if ( (1.0 - Math.abs(dot) ) > EPS ) { + om = Math.acos(dot); + sinom = Math.sin(om); + s1 = Math.sin((1.0-alpha)*om)/sinom; + s2 = Math.sin( alpha*om)/sinom; + } else{ + s1 = 1.0 - alpha; + s2 = alpha; + } + + w = (float)(s1*w + s2*q1.w); + x = (float)(s1*x + s2*q1.x); + y = (float)(s1*y + s2*q1.y); + z = (float)(s1*z + s2*q1.z); + } + + + + /** + * Performs a great circle interpolation between quaternion q1 + * and quaternion q2 and places the result into this quaternion. + * @param q1 the first quaternion + * @param q2 the second quaternion + * @param alpha the alpha interpolation parameter + */ + public final void interpolate(Quat4f q1, Quat4f q2, float alpha) { + // From "Advanced Animation and Rendering Techniques" + // by Watt and Watt pg. 364, function as implemented appeared to be + // incorrect. Fails to choose the same quaternion for the double + // covering. Resulting in change of direction for rotations. + // Fixed function to negate the first quaternion in the case that the + // dot product of q1 and this is negative. Second case was not needed. + + double dot,s1,s2,om,sinom; + + dot = q2.x*q1.x + q2.y*q1.y + q2.z*q1.z + q2.w*q1.w; + + if ( dot < 0 ) { + // switch the quaterion values + q1.x = -q1.x; q1.y = -q1.y; q1.z = -q1.z; q1.w = -q1.w; + } + + if ( (1.0 - Math.abs(dot) ) > EPS ) { + om = Math.acos(dot); + sinom = Math.sin(om); + s1 = Math.sin((1.0-alpha)*om)/sinom; + s2 = Math.sin( alpha*om)/sinom; + } else{ + s1 = 1.0 - alpha; + s2 = alpha; + } + w = (float)(s1*q1.w + s2*q2.w); + x = (float)(s1*q1.x + s2*q2.x); + y = (float)(s1*q1.y + s2*q2.y); + z = (float)(s1*q1.z + s2*q2.z); + } + +} + + + + diff --git a/src/javax/vecmath/SingularMatrixException.java b/src/javax/vecmath/SingularMatrixException.java new file mode 100644 index 0000000..339ba31 --- /dev/null +++ b/src/javax/vecmath/SingularMatrixException.java @@ -0,0 +1,35 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +/** + * Indicates that inverse of a matrix can not be computed. + */ +public class SingularMatrixException extends RuntimeException{ + +/** + * Create the exception object with default values. + */ + public SingularMatrixException(){ + } + +/** + * Create the exception object that outputs message. + * @param str the message string to be output. + */ + public SingularMatrixException(String str){ + + super(str); + } + +} diff --git a/src/javax/vecmath/TexCoord2f.java b/src/javax/vecmath/TexCoord2f.java new file mode 100644 index 0000000..7defa9f --- /dev/null +++ b/src/javax/vecmath/TexCoord2f.java @@ -0,0 +1,77 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 2-element vector that is represented by single-precision floating + * point x,y coordinates. + * + */ +public class TexCoord2f extends Tuple2f implements java.io.Serializable { + + // Combatible with 1.1 + static final long serialVersionUID = 7998248474800032487L; + + /** + * Constructs and initializes a TexCoord2f from the specified xy coordinates. + * @param x the x coordinate + * @param y the y coordinate + */ + public TexCoord2f(float x, float y) + { + super(x,y); + } + + + /** + * Constructs and initializes a TexCoord2f from the specified array. + * @param v the array of length 2 containing xy in order + */ + public TexCoord2f(float[] v) + { + super(v); + } + + + /** + * Constructs and initializes a TexCoord2f from the specified TexCoord2f. + * @param v1 the TexCoord2f containing the initialization x y data + */ + public TexCoord2f(TexCoord2f v1) + { + super(v1); + } + + + /** + * Constructs and initializes a TexCoord2f from the specified Tuple2f. + * @param t1 the Tuple2f containing the initialization x y data + */ + public TexCoord2f(Tuple2f t1) + { + super(t1); + } + + + /** + * Constructs and initializes a TexCoord2f to (0,0). + */ + public TexCoord2f() + { + super(); + } + + +} diff --git a/src/javax/vecmath/TexCoord3f.java b/src/javax/vecmath/TexCoord3f.java new file mode 100644 index 0000000..05268c8 --- /dev/null +++ b/src/javax/vecmath/TexCoord3f.java @@ -0,0 +1,88 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 3 element texture coordinate that is represented by single precision + * floating point x,y,z coordinates. + * + */ +public class TexCoord3f extends Tuple3f implements java.io.Serializable { + + // Combatible with 1.1 + static final long serialVersionUID = -3517736544731446513L; + + /** + * Constructs and initializes a TexCoord3f from the specified xyz + * coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + */ + public TexCoord3f(float x, float y, float z) + { + super(x,y,z); + } + + + /** + * Constructs and initializes a TexCoord3f from the array of length 3. + * @param v the array of length 3 containing xyz in order + */ + public TexCoord3f(float[] v) + { + super(v); + } + + + /** + * Constructs and initializes a TexCoord3f from the specified TexCoord3f. + * @param v1 the TexCoord3f containing the initialization x y z data + */ + public TexCoord3f(TexCoord3f v1) + { + super(v1); + } + + + /** + * Constructs and initializes a TexCoord3f from the specified Tuple3f. + * @param t1 the Tuple3f containing the initialization x y z data + */ + public TexCoord3f(Tuple3f t1) + { + super(t1); + } + + + /** + * Constructs and initializes a TexCoord3f from the specified Tuple3d. + * @param t1 the Tuple3d containing the initialization x y z data + */ + public TexCoord3f(Tuple3d t1) + { + super(t1); + } + + + /** + * Constructs and initializes a TexCoord3f to (0,0,0). + */ + public TexCoord3f() + { + super(); + } + +} diff --git a/src/javax/vecmath/TexCoord4f.java b/src/javax/vecmath/TexCoord4f.java new file mode 100644 index 0000000..845888f --- /dev/null +++ b/src/javax/vecmath/TexCoord4f.java @@ -0,0 +1,90 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 4 element texture coordinate that is represented by single precision + * floating point x,y,z,w coordinates. + * + * @since Java 3D 1.3 + */ +public class TexCoord4f extends Tuple4f implements java.io.Serializable { + + // Combatible with 1.1 + static final long serialVersionUID = -3517736544731446513L; + + /** + * Constructs and initializes a TexCoord4f from the specified xyzw + * coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param w the w coordinate + */ + public TexCoord4f(float x, float y, float z, float w) + { + super(x,y,z,w); + } + + + /** + * Constructs and initializes a TexCoord4f from the array of length 4. + * @param v the array of length w containing xyzw in order + */ + public TexCoord4f(float[] v) + { + super(v); + } + + + /** + * Constructs and initializes a TexCoord4f from the specified TexCoord4f. + * @param v1 the TexCoord4f containing the initialization x y z w data + */ + public TexCoord4f(TexCoord4f v1) + { + super(v1); + } + + + /** + * Constructs and initializes a TexCoord4f from the specified Tuple4f. + * @param t1 the Tuple4f containing the initialization x y z w data + */ + public TexCoord4f(Tuple4f t1) + { + super(t1); + } + + + /** + * Constructs and initializes a TexCoord4f from the specified Tuple4d. + * @param t1 the Tuple4d containing the initialization x y z w data + */ + public TexCoord4f(Tuple4d t1) + { + super(t1); + } + + + /** + * Constructs and initializes a TexCoord4f to (0,0,0,0). + */ + public TexCoord4f() + { + super(); + } + +} diff --git a/src/javax/vecmath/Tuple2d.java b/src/javax/vecmath/Tuple2d.java new file mode 100644 index 0000000..21f7da7 --- /dev/null +++ b/src/javax/vecmath/Tuple2d.java @@ -0,0 +1,537 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A generic 2-element tuple that is represented by double-precision + * floating point x,y coordinates. + * + */ +public abstract class Tuple2d implements java.io.Serializable, Cloneable { + + static final long serialVersionUID = 6205762482756093838L; + + /** + * The x coordinate. + */ + public double x; + + /** + * The y coordinate. + */ + public double y; + + + /** + * Constructs and initializes a Tuple2d from the specified xy coordinates. + * @param x the x coordinate + * @param y the y coordinate + */ + public Tuple2d(double x, double y) + { + this.x = x; + this.y = y; + } + + + /** + * Constructs and initializes a Tuple2d from the specified array. + * @param t the array of length 2 containing xy in order + */ + public Tuple2d(double[] t) + { + this.x = t[0]; + this.y = t[1]; + } + + + /** + * Constructs and initializes a Tuple2d from the specified Tuple2d. + * @param t1 the Tuple2d containing the initialization x y data + */ + public Tuple2d(Tuple2d t1) + { + this.x = t1.x; + this.y = t1.y; + } + + + /** + * Constructs and initializes a Tuple2d from the specified Tuple2f. + * @param t1 the Tuple2f containing the initialization x y data + */ + public Tuple2d(Tuple2f t1) + { + this.x = (double) t1.x; + this.y = (double) t1.y; + } + + /** + * Constructs and initializes a Tuple2d to (0,0). + */ + public Tuple2d() + { + this.x = 0.0; + this.y = 0.0; + } + + + /** + * Sets the value of this tuple to the specified xy coordinates. + * @param x the x coordinate + * @param y the y coordinate + */ + public final void set(double x, double y) + { + this.x = x; + this.y = y; + } + + + /** + * Sets the value of this tuple from the 2 values specified in + * the array. + * @param t the array of length 2 containing xy in order + */ + public final void set(double[] t) + { + this.x = t[0]; + this.y = t[1]; + } + + + /** + * Sets the value of this tuple to the value of the Tuple2d argument. + * @param t1 the tuple to be copied + */ + public final void set(Tuple2d t1) + { + this.x = t1.x; + this.y = t1.y; + } + + + /** + * Sets the value of this tuple to the value of Tuple2f t1. + * @param t1 the tuple to be copied + */ + public final void set(Tuple2f t1) + { + this.x = (double) t1.x; + this.y = (double) t1.y; + } + + /** + * Copies the value of the elements of this tuple into the array t. + * @param t the array that will contain the values of the vector + */ + public final void get(double[] t) + { + t[0] = this.x; + t[1] = this.y; + } + + + /** + * Sets the value of this tuple to the vector sum of tuples t1 and t2. + * @param t1 the first tuple + * @param t2 the second tuple + */ + public final void add(Tuple2d t1, Tuple2d t2) + { + this.x = t1.x + t2.x; + this.y = t1.y + t2.y; + } + + + /** + * Sets the value of this tuple to the vector sum of itself and tuple t1. + * @param t1 the other tuple + */ + public final void add(Tuple2d t1) + { + this.x += t1.x; + this.y += t1.y; + } + + + /** + * Sets the value of this tuple to the vector difference of + * tuple t1 and t2 (this = t1 - t2). + * @param t1 the first tuple + * @param t2 the second tuple + */ + public final void sub(Tuple2d t1, Tuple2d t2) + { + this.x = t1.x - t2.x; + this.y = t1.y - t2.y; + } + + + /** + * Sets the value of this tuple to the vector difference of + * itself and tuple t1 (this = this - t1). + * @param t1 the other vector + */ + public final void sub(Tuple2d t1) + { + this.x -= t1.x; + this.y -= t1.y; + } + + + /** + * Sets the value of this tuple to the negation of tuple t1. + * @param t1 the source vector + */ + public final void negate(Tuple2d t1) + { + this.x = -t1.x; + this.y = -t1.y; + } + + + /** + * Negates the value of this vector in place. + */ + public final void negate() + { + this.x = -this.x; + this.y = -this.y; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of tuple t1. + * @param s the scalar value + * @param t1 the source tuple + */ + public final void scale(double s, Tuple2d t1) + { + this.x = s*t1.x; + this.y = s*t1.y; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of itself. + * @param s the scalar value + */ + public final void scale(double s) + { + this.x *= s; + this.y *= s; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of tuple t1 and then adds tuple t2 (this = s*t1 + t2). + * @param s the scalar value + * @param t1 the tuple to be multipled + * @param t2 the tuple to be added + */ + public final void scaleAdd(double s, Tuple2d t1, Tuple2d t2) + { + this.x = s*t1.x + t2.x; + this.y = s*t1.y + t2.y; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of itself and then adds tuple t1 (this = s*this + t1). + * @param s the scalar value + * @param t1 the tuple to be added + */ + public final void scaleAdd(double s, Tuple2d t1) + { + this.x = s*this.x + t1.x; + this.y = s*this.y + t1.y; + } + + + + /** + * Returns a hash code value based on the data values in this + * object. Two different Tuple2d objects with identical data values + * (i.e., Tuple2d.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 + */ + public int hashCode() { + long bits = 1L; + bits = 31L * bits + Double.doubleToLongBits(x); + bits = 31L * bits + Double.doubleToLongBits(y); + return (int) (bits ^ (bits >> 32)); + } + + + /** + * Returns true if all of the data members of Tuple2d t1 are + * equal to the corresponding data members in this Tuple2d. + * @param t1 the vector with which the comparison is made + * @return true or false + */ + public boolean equals(Tuple2d t1) + { + try { + return(this.x == t1.x && this.y == t1.y); + } + catch (NullPointerException e2) {return false;} + + } + + /** + * Returns true if the Object t1 is of type Tuple2d and all of the + * data members of t1 are equal to the corresponding data members in + * this Tuple2d. + * @param t1 the object with which the comparison is made + * @return true or false + */ + public boolean equals(Object t1) + { + try { + Tuple2d t2 = (Tuple2d) t1; + return(this.x == t2.x && this.y == t2.y); + } + catch (NullPointerException e2) {return false;} + catch (ClassCastException e1) {return false;} + + } + + /** + * Returns true if the L-infinite distance between this tuple + * and tuple t1 is less than or equal to the epsilon parameter, + * otherwise returns false. The L-infinite + * distance is equal to MAX[abs(x1-x2), abs(y1-y2)]. + * @param t1 the tuple to be compared to this tuple + * @param epsilon the threshold value + * @return true or false + */ + public boolean epsilonEquals(Tuple2d t1, double epsilon) + { + double diff; + + diff = x - t1.x; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = y - t1.y; + if((diff<0?-diff:diff) > epsilon) return false; + + return true; + } + + /** + * Returns a string that contains the values of this Tuple2d. + * The form is (x,y). + * @return the String representation + */ + public String toString() + { + return("(" + this.x + ", " + this.y + ")"); + } + + + /** + * Clamps the tuple parameter to the range [low, high] and + * places the values into this tuple. + * @param min the lowest value in the tuple after clamping + * @param max the highest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clamp(double min, double max, Tuple2d t) + { + if( t.x > max ) { + x = max; + } else if( t.x < min ){ + x = min; + } else { + x = t.x; + } + + if( t.y > max ) { + y = max; + } else if( t.y < min ){ + y = min; + } else { + y = t.y; + } + + } + + + /** + * Clamps the minimum value of the tuple parameter to the min + * parameter and places the values into this tuple. + * @param min the lowest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clampMin(double min, Tuple2d t) + { + if( t.x < min ) { + x = min; + } else { + x = t.x; + } + + if( t.y < min ) { + y = min; + } else { + y = t.y; + } + + } + + + /** + * Clamps the maximum value of the tuple parameter to the max + * parameter and places the values into this tuple. + * @param max the highest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clampMax(double max, Tuple2d t) + { + if( t.x > max ) { + x = max; + } else { + x = t.x; + } + + if( t.y > max ) { + y = max; + } else { + y = t.y; + } + + } + + + /** + * Sets each component of the tuple parameter to its absolute + * value and places the modified values into this tuple. + * @param t the source tuple, which will not be modified + */ + public final void absolute(Tuple2d t) + { + x = Math.abs(t.x); + y = Math.abs(t.y); + } + + + + /** + * Clamps this tuple to the range [low, high]. + * @param min the lowest value in this tuple after clamping + * @param max the highest value in this tuple after clamping + */ + public final void clamp(double min, double max) + { + if( x > max ) { + x = max; + } else if( x < min ){ + x = min; + } + + if( y > max ) { + y = max; + } else if( y < min ){ + y = min; + } + + } + + + /** + * Clamps the minimum value of this tuple to the min parameter. + * @param min the lowest value in this tuple after clamping + */ + public final void clampMin(double min) + { + if( x < min ) x=min; + if( y < min ) y=min; + } + + + /** + * Clamps the maximum value of this tuple to the max parameter. + * @param max the highest value in the tuple after clamping + */ + public final void clampMax(double max) + { + if( x > max ) x=max; + if( y > max ) y=max; + } + + + /** + * Sets each component of this tuple to its absolute value. + */ + public final void absolute() + { + x = Math.abs(x); + y = Math.abs(y); + } + + + /** + * Linearly interpolates between tuples t1 and t2 and places the + * result into this tuple: this = (1-alpha)*t1 + alpha*t2. + * @param t1 the first tuple + * @param t2 the second tuple + * @param alpha the alpha interpolation parameter + */ + public final void interpolate(Tuple2d t1, Tuple2d t2, double alpha) + { + this.x = (1-alpha)*t1.x + alpha*t2.x; + this.y = (1-alpha)*t1.y + alpha*t2.y; + } + + + /** + * Linearly interpolates between this tuple and tuple t1 and + * places the result into this tuple: this = (1-alpha)*this + alpha*t1. + * @param t1 the first tuple + * @param alpha the alpha interpolation parameter + */ + public final void interpolate(Tuple2d t1, double alpha) + { + this.x = (1-alpha)*this.x + alpha*t1.x; + this.y = (1-alpha)*this.y + alpha*t1.y; + + } + + /** + * 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 Java 3D 1.3 + */ + public Object clone() { + // Since there are no arrays we can just use Object.clone() + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + } + +} diff --git a/src/javax/vecmath/Tuple2f.java b/src/javax/vecmath/Tuple2f.java new file mode 100644 index 0000000..b482d80 --- /dev/null +++ b/src/javax/vecmath/Tuple2f.java @@ -0,0 +1,541 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A generic 2-element tuple that is represented by single-precision + * floating point x,y coordinates. + * + */ +public abstract class Tuple2f implements java.io.Serializable, Cloneable { + + static final long serialVersionUID = 9011180388985266884L; + + /** + * The x coordinate. + */ + public float x; + + /** + * The y coordinate. + */ + public float y; + + + /** + * Constructs and initializes a Tuple2f from the specified xy coordinates. + * @param x the x coordinate + * @param y the y coordinate + */ + public Tuple2f(float x, float y) + { + this.x = x; + this.y = y; + } + + + /** + * Constructs and initializes a Tuple2f from the specified array. + * @param t the array of length 2 containing xy in order + */ + public Tuple2f(float[] t) + { + this.x = t[0]; + this.y = t[1]; + } + + + /** + * Constructs and initializes a Tuple2f from the specified Tuple2f. + * @param t1 the Tuple2f containing the initialization x y data + */ + public Tuple2f(Tuple2f t1) + { + this.x = t1.x; + this.y = t1.y; + } + + + /** + * Constructs and initializes a Tuple2f from the specified Tuple2d. + * @param t1 the Tuple2d containing the initialization x y data + */ + public Tuple2f(Tuple2d t1) + { + this.x = (float) t1.x; + this.y = (float) t1.y; + } + + + /** + * Constructs and initializes a Tuple2f to (0,0). + */ + public Tuple2f() + { + this.x = (float) 0.0; + this.y = (float) 0.0; + } + + + /** + * Sets the value of this tuple to the specified xy coordinates. + * @param x the x coordinate + * @param y the y coordinate + */ + public final void set(float x, float y) + { + this.x = x; + this.y = y; + } + + + /** + * Sets the value of this tuple from the 2 values specified in + * the array. + * @param t the array of length 2 containing xy in order + */ + public final void set(float[] t) + { + this.x = t[0]; + this.y = t[1]; + } + + + /** + * Sets the value of this tuple to the value of the Tuple2f argument. + * @param t1 the tuple to be copied + */ + public final void set(Tuple2f t1) + { + this.x = t1.x; + this.y = t1.y; + } + + + /** + * Sets the value of this tuple to the value of the Tuple2d argument. + * @param t1 the tuple to be copied + */ + public final void set(Tuple2d t1) + { + this.x = (float) t1.x; + this.y = (float) t1.y; + } + + + /** + * Copies the value of the elements of this tuple into the array t. + * @param t the array that will contain the values of the vector + */ + public final void get(float[] t) + { + t[0] = this.x; + t[1] = this.y; + } + + + /** + * Sets the value of this tuple to the vector sum of tuples t1 and t2. + * @param t1 the first tuple + * @param t2 the second tuple + */ + public final void add(Tuple2f t1, Tuple2f t2) + { + this.x = t1.x + t2.x; + this.y = t1.y + t2.y; + } + + + /** + * Sets the value of this tuple to the vector sum of itself and tuple t1. + * @param t1 the other tuple + */ + public final void add(Tuple2f t1) + { + this.x += t1.x; + this.y += t1.y; + } + + + /** + * Sets the value of this tuple to the vector difference of + * tuple t1 and t2 (this = t1 - t2). + * @param t1 the first tuple + * @param t2 the second tuple + */ + public final void sub(Tuple2f t1, Tuple2f t2) + { + this.x = t1.x - t2.x; + this.y = t1.y - t2.y; + } + + + /** + * Sets the value of this tuple to the vector difference of + * itself and tuple t1 (this = this - t1). + * @param t1 the other tuple + */ + public final void sub(Tuple2f t1) + { + this.x -= t1.x; + this.y -= t1.y; + } + + + /** + * Sets the value of this tuple to the negation of tuple t1. + * @param t1 the source tuple + */ + public final void negate(Tuple2f t1) + { + this.x = -t1.x; + this.y = -t1.y; + } + + + /** + * Negates the value of this vector in place. + */ + public final void negate() + { + this.x = -this.x; + this.y = -this.y; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of tuple t1. + * @param s the scalar value + * @param t1 the source tuple + */ + public final void scale(float s, Tuple2f t1) + { + this.x = s*t1.x; + this.y = s*t1.y; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of itself. + * @param s the scalar value + */ + public final void scale(float s) + { + this.x *= s; + this.y *= s; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of tuple t1 and then adds tuple t2 (this = s*t1 + t2). + * @param s the scalar value + * @param t1 the tuple to be multipled + * @param t2 the tuple to be added + */ + public final void scaleAdd(float s, Tuple2f t1, Tuple2f t2) + { + this.x = s*t1.x + t2.x; + this.y = s*t1.y + t2.y; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of itself and then adds tuple t1 (this = s*this + t1). + * @param s the scalar value + * @param t1 the tuple to be added + */ + public final void scaleAdd(float s, Tuple2f t1) + { + this.x = s*this.x + t1.x; + this.y = s*this.y + t1.y; + } + + + + /** + * Returns a hash code value based on the data values in this + * object. Two different Tuple2f objects with identical data values + * (i.e., Tuple2f.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 + */ + public int hashCode() { + long bits = 1L; + bits = 31L * bits + (long)Float.floatToIntBits(x); + bits = 31L * bits + (long)Float.floatToIntBits(y); + return (int) (bits ^ (bits >> 32)); + } + + + /** + * Returns true if all of the data members of Tuple2f t1 are + * equal to the corresponding data members in this Tuple2f. + * @param t1 the vector with which the comparison is made + * @return true or false + */ + public boolean equals(Tuple2f t1) + { + try { + return(this.x == t1.x && this.y == t1.y); + } + catch (NullPointerException e2) {return false;} + + } + + /** + * Returns true if the Object t1 is of type Tuple2f and all of the + * data members of t1 are equal to the corresponding data members in + * this Tuple2f. + * @param t1 the object with which the comparison is made + * @return true or false + */ + public boolean equals(Object t1) + { + try { + Tuple2f t2 = (Tuple2f) t1; + return(this.x == t2.x && this.y == t2.y); + } + catch (NullPointerException e2) {return false;} + catch (ClassCastException e1) {return false;} + + } + + /** + * Returns true if the L-infinite distance between this tuple + * and tuple t1 is less than or equal to the epsilon parameter, + * otherwise returns false. The L-infinite + * distance is equal to MAX[abs(x1-x2), abs(y1-y2)]. + * @param t1 the tuple to be compared to this tuple + * @param epsilon the threshold value + * @return true or false + */ + public boolean epsilonEquals(Tuple2f t1, float epsilon) + { + float diff; + + diff = x - t1.x; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = y - t1.y; + if((diff<0?-diff:diff) > epsilon) return false; + + return true; + } + + /** + * Returns a string that contains the values of this Tuple2f. + * The form is (x,y). + * @return the String representation + */ + public String toString() + { + return("(" + this.x + ", " + this.y + ")"); + } + + + /** + * Clamps the tuple parameter to the range [low, high] and + * places the values into this tuple. + * @param min the lowest value in the tuple after clamping + * @param max the highest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clamp(float min, float max, Tuple2f t) + { + if( t.x > max ) { + x = max; + } else if( t.x < min ){ + x = min; + } else { + x = t.x; + } + + if( t.y > max ) { + y = max; + } else if( t.y < min ){ + y = min; + } else { + y = t.y; + } + + } + + + /** + * Clamps the minimum value of the tuple parameter to the min + * parameter and places the values into this tuple. + * @param min the lowest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clampMin(float min, Tuple2f t) + { + if( t.x < min ) { + x = min; + } else { + x = t.x; + } + + if( t.y < min ) { + y = min; + } else { + y = t.y; + } + + } + + + /** + * Clamps the maximum value of the tuple parameter to the max + * parameter and places the values into this tuple. + * @param max the highest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clampMax(float max, Tuple2f t) + { + if( t.x > max ) { + x = max; + } else { + x = t.x; + } + + if( t.y > max ) { + y = max; + } else { + y = t.y; + } + + } + + + /** + * Sets each component of the tuple parameter to its absolute + * value and places the modified values into this tuple. + * @param t the source tuple, which will not be modified + */ + public final void absolute(Tuple2f t) + { + x = Math.abs(t.x); + y = Math.abs(t.y); + } + + + + /** + * Clamps this tuple to the range [low, high]. + * @param min the lowest value in this tuple after clamping + * @param max the highest value in this tuple after clamping + */ + public final void clamp(float min, float max) + { + if( x > max ) { + x = max; + } else if( x < min ){ + x = min; + } + + if( y > max ) { + y = max; + } else if( y < min ){ + y = min; + } + + } + + + /** + * Clamps the minimum value of this tuple to the min parameter. + * @param min the lowest value in this tuple after clamping + */ + public final void clampMin(float min) + { + if( x < min ) x=min; + if( y < min ) y=min; + } + + + /** + * Clamps the maximum value of this tuple to the max parameter. + * @param max the highest value in the tuple after clamping + */ + public final void clampMax(float max) + { + if( x > max ) x=max; + if( y > max ) y=max; + } + + + /** + * Sets each component of this tuple to its absolute value. + */ + public final void absolute() + { + x = Math.abs(x); + y = Math.abs(y); + } + + + /** + * Linearly interpolates between tuples t1 and t2 and places the + * result into this tuple: this = (1-alpha)*t1 + alpha*t2. + * @param t1 the first tuple + * @param t2 the second tuple + * @param alpha the alpha interpolation parameter + */ + public final void interpolate(Tuple2f t1, Tuple2f t2, float alpha) + { + this.x = (1-alpha)*t1.x + alpha*t2.x; + this.y = (1-alpha)*t1.y + alpha*t2.y; + + } + + + /** + * Linearly interpolates between this tuple and tuple t1 and + * places the result into this tuple: this = (1-alpha)*this + alpha*t1. + * @param t1 the first tuple + * @param alpha the alpha interpolation parameter + */ + public final void interpolate(Tuple2f t1, float alpha) + { + + this.x = (1-alpha)*this.x + alpha*t1.x; + this.y = (1-alpha)*this.y + alpha*t1.y; + + } + + /** + * 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 Java 3D 1.3 + */ + public Object clone() { + // Since there are no arrays we can just use Object.clone() + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + } + +} diff --git a/src/javax/vecmath/Tuple3b.java b/src/javax/vecmath/Tuple3b.java new file mode 100644 index 0000000..2615160 --- /dev/null +++ b/src/javax/vecmath/Tuple3b.java @@ -0,0 +1,229 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A three byte tuple. Note that Java defines a byte as a signed integer + * in the range [-128, 127]. However, colors are more typically + * represented by values in the range [0, 255]. Java 3D recognizes this + * and, in those cases where Tuple3b is used to represent color, treats + * the bytes as if the range were [0, 255]---in other words, as if the + * bytes were unsigned. + * Values greater than 127 can be assigned to a byte variable using a + * type cast. For example: + * <ul>byteVariable = (byte) intValue; // intValue can be > 127</ul> + * If intValue is greater than 127, then byteVariable will be negative. The + * correct value will be extracted when it is used (by masking off the upper + * bits). + */ +public abstract class Tuple3b implements java.io.Serializable, Cloneable { + + static final long serialVersionUID = -483782685323607044L; + + /** + * The first value. + */ + public byte x; + + /** + * The second value. + */ + public byte y; + + /** + * The third value. + */ + public byte z; + + + /** + * Constructs and initializes a Tuple3b from the specified three values. + * @param b1 the first value + * @param b2 the second value + * @param b3 the third value + */ + public Tuple3b(byte b1, byte b2, byte b3) + { + this.x = b1; + this.y = b2; + this.z = b3; + } + + + /** + * Constructs and initializes a Tuple3b from input array of length 3. + * @param t the array of length 3 containing b1 b2 b3 in order + */ + public Tuple3b(byte[] t) + { + this.x = t[0]; + this.y = t[1]; + this.z = t[2]; + } + + + /** + * Constructs and initializes a Tuple3b from the specified Tuple3b. + * @param t1 the Tuple3b containing the initialization x y z data + */ + public Tuple3b(Tuple3b t1) + { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + } + + + /** + * Constructs and initializes a Tuple3b to (0,0,0). + */ + public Tuple3b() + { + this.x = (byte) 0; + this.y = (byte) 0; + this.z = (byte) 0; + } + + + /** + * Returns a string that contains the values of this Tuple3b. + * @return a String with the values + */ + public String toString() + { + return("(" + ((int)this.x & 0xff) + + ", " + ((int)this.y & 0xff) + + ", " + ((int)this.z & 0xff) + ")"); + } + + + /** + * Places the value of the x,y,z components of this Tuple3b + * into the array of length 3. + * @param t array of length 3 into which the component values are copied + */ + public final void get(byte[] t) + { + + t[0] = this.x; + t[1] = this.y; + t[2] = this.z; + } + + + /** + * Places the value of the x,y,z components of this tuple into + * the tuple t1. + * @param t1 the tuple into which the values are placed + */ + public final void get(Tuple3b t1) + { + t1.x = this.x; + t1.y = this.y; + t1.z = this.z; + } + + + /** + * Sets the value of the data members of this tuple to the value + * of the argument tuple t1. + * @param t1 the source tuple for the memberwise copy + */ + public final void set(Tuple3b t1) + { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + } + + + /** + * Sets the value of the x,y,z, data members of this tuple to the + * values in the array t of length 3. + * @param t array of length 3 which is the source for the memberwise copy + */ + public final void set(byte[] t) + { + this.x = t[0]; + this.y = t[1]; + this.z = t[2]; + } + + + /** + * Returns true if all of the data members of tuple t1 are equal to + * the corresponding data members in this tuple. + * @param t1 the tuple with which the comparison is made + * @return true or false + */ + public boolean equals(Tuple3b t1) + { + try { + return(this.x == t1.x && this.y == t1.y && this.z == t1.z); + } + catch (NullPointerException e2) {return false;} + + } + + /** + * Returns true if the Object t1 is of type Tuple3b and all of the + * data members of t1 are equal to the corresponding data members in + * this Tuple3b. + * @param t1 the object with which the comparison is made + */ + public boolean equals(Object t1) + { + try { + Tuple3b t2 = (Tuple3b) t1; + return(this.x == t2.x && this.y == t2.y && this.z == t2.z); + } + catch (NullPointerException e2) {return false;} + catch (ClassCastException e1) {return false;} + + } + + /** + * Returns a hash code value based on the data values in this + * object. Two different Tuple3b objects with identical data values + * (i.e., Tuple3b.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 + */ + public int hashCode() { + return ((((int)x & 0xff) << 0) | + (((int)y & 0xff) << 8) | + (((int)z & 0xff) << 16)); + } + + /** + * 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 Java 3D 1.3 + */ + public Object clone() { + // Since there are no arrays we can just use Object.clone() + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + } + +} diff --git a/src/javax/vecmath/Tuple3d.java b/src/javax/vecmath/Tuple3d.java new file mode 100644 index 0000000..23d31dc --- /dev/null +++ b/src/javax/vecmath/Tuple3d.java @@ -0,0 +1,667 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A generic 3-element tuple that is represented by double-precision + * floating point x,y,z coordinates. + * + */ +public abstract class Tuple3d implements java.io.Serializable, Cloneable { + + static final long serialVersionUID = 5542096614926168415L; + + /** + * The x coordinate. + */ + public double x; + + /** + * The y coordinate. + */ + public double y; + + /** + * The z coordinate. + */ + public double z; + + + /** + * Constructs and initializes a Tuple3d from the specified xyz coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + */ + public Tuple3d(double x, double y, double z) + { + this.x = x; + this.y = y; + this.z = z; + } + + /** + * Constructs and initializes a Tuple3d from the array of length 3. + * @param t the array of length 3 containing xyz in order + */ + public Tuple3d(double[] t) + { + this.x = t[0]; + this.y = t[1]; + this.z = t[2]; + } + + /** + * Constructs and initializes a Tuple3d from the specified Tuple3d. + * @param t1 the Tuple3d containing the initialization x y z data + */ + public Tuple3d(Tuple3d t1) + { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + } + + /** + * Constructs and initializes a Tuple3d from the specified Tuple3f. + * @param t1 the Tuple3f containing the initialization x y z data + */ + public Tuple3d(Tuple3f t1) + { + this.x = (double) t1.x; + this.y = (double) t1.y; + this.z = (double) t1.z; + } + + /** + * Constructs and initializes a Tuple3d to (0,0,0). + */ + public Tuple3d() + { + this.x = (double) 0.0; + this.y = (double) 0.0; + this.z = (double) 0.0; + } + + /** + * Sets the value of this tuple to the specified xyz coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + */ + public final void set(double x, double y, double z) + { + this.x = x; + this.y = y; + this.z = z; + } + + /** + * Sets the value of this tuple to the value of the xyz coordinates + * located in the array of length 3. + * @param t the array of length 3 containing xyz in order + */ + public final void set(double[] t) + { + this.x = t[0]; + this.y = t[1]; + this.z = t[2]; + } + + /** + * Sets the value of this tuple to the value of tuple t1. + * @param t1 the tuple to be copied + */ + public final void set(Tuple3d t1) + { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + } + + /** + * Sets the value of this tuple to the value of tuple t1. + * @param t1 the tuple to be copied + */ + public final void set(Tuple3f t1) + { + this.x = (double) t1.x; + this.y = (double) t1.y; + this.z = (double) t1.z; + } + + /** + * Copies the x,y,z coordinates of this tuple into the array t + * of length 3. + * @param t the target array + */ + public final void get(double[] t) + { + t[0] = this.x; + t[1] = this.y; + t[2] = this.z; + } + + + /** + * Copies the x,y,z coordinates of this tuple into the tuple t. + * @param t the Tuple3d object into which the values of this object are copied + */ + public final void get(Tuple3d t) + { + t.x = this.x; + t.y = this.y; + t.z = this.z; + } + + + /** + * Sets the value of this tuple to the sum of tuples t1 and t2. + * @param t1 the first tuple + * @param t2 the second tuple + */ + public final void add(Tuple3d t1, Tuple3d t2) + { + this.x = t1.x + t2.x; + this.y = t1.y + t2.y; + this.z = t1.z + t2.z; + } + + + /** + * Sets the value of this tuple to the sum of itself and t1. + * @param t1 the other tuple + */ + public final void add(Tuple3d t1) + { + this.x += t1.x; + this.y += t1.y; + this.z += t1.z; + } + + /** + * Sets the value of this tuple to the difference of tuples + * t1 and t2 (this = t1 - t2). + * @param t1 the first tuple + * @param t2 the second tuple + */ + public final void sub(Tuple3d t1, Tuple3d t2) + { + this.x = t1.x - t2.x; + this.y = t1.y - t2.y; + this.z = t1.z - t2.z; + } + + /** + * Sets the value of this tuple to the difference + * of itself and t1 (this = this - t1). + * @param t1 the other tuple + */ + public final void sub(Tuple3d t1) + { + this.x -= t1.x; + this.y -= t1.y; + this.z -= t1.z; + } + + + /** + * Sets the value of this tuple to the negation of tuple t1. + * @param t1 the source tuple + */ + public final void negate(Tuple3d t1) + { + this.x = -t1.x; + this.y = -t1.y; + this.z = -t1.z; + } + + + /** + * Negates the value of this tuple in place. + */ + public final void negate() + { + this.x = -this.x; + this.y = -this.y; + this.z = -this.z; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of tuple t1. + * @param s the scalar value + * @param t1 the source tuple + */ + public final void scale(double s, Tuple3d t1) + { + this.x = s*t1.x; + this.y = s*t1.y; + this.z = s*t1.z; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of itself. + * @param s the scalar value + */ + public final void scale(double s) + { + this.x *= s; + this.y *= s; + this.z *= s; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of tuple t1 and then adds tuple t2 (this = s*t1 + t2). + * @param s the scalar value + * @param t1 the tuple to be multipled + * @param t2 the tuple to be added + */ + public final void scaleAdd(double s, Tuple3d t1, Tuple3d t2) + { + this.x = s*t1.x + t2.x; + this.y = s*t1.y + t2.y; + this.z = s*t1.z + t2.z; + } + + + /** + * @deprecated Use scaleAdd(double,Tuple3d) instead + */ + public final void scaleAdd(double s, Tuple3f t1) { + scaleAdd(s, new Point3d(t1)); + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of itself and then adds tuple t1 (this = s*this + t1). + * @param s the scalar value + * @param t1 the tuple to be added + */ + public final void scaleAdd(double s, Tuple3d t1) { + this.x = s*this.x + t1.x; + this.y = s*this.y + t1.y; + this.z = s*this.z + t1.z; + } + + + + /** + * Returns a string that contains the values of this Tuple3d. + * The form is (x,y,z). + * @return the String representation + */ + public String toString() { + return "(" + this.x + ", " + this.y + ", " + this.z + ")"; + } + + + /** + * Returns a hash code value based on the data values in this + * object. Two different Tuple3d objects with identical data values + * (i.e., Tuple3d.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 + */ + public int hashCode() { + long bits = 1L; + bits = 31L * bits + Double.doubleToLongBits(x); + bits = 31L * bits + Double.doubleToLongBits(y); + bits = 31L * bits + Double.doubleToLongBits(z); + return (int) (bits ^ (bits >> 32)); + } + + + /** + * Returns true if all of the data members of Tuple3d t1 are + * equal to the corresponding data members in this Tuple3d. + * @param t1 the tuple with which the comparison is made + * @return true or false + */ + public boolean equals(Tuple3d t1) + { + try { + return(this.x == t1.x && this.y == t1.y && this.z == t1.z); + } + catch (NullPointerException e2) {return false;} + } + + /** + * Returns true if the Object t1 is of type Tuple3d and all of the + * data members of t1 are equal to the corresponding data members in + * this Tuple3d. + * @param t1 the Object with which the comparison is made + * @return true or false + */ + public boolean equals(Object t1) + { + try { + Tuple3d t2 = (Tuple3d) t1; + return(this.x == t2.x && this.y == t2.y && this.z == t2.z); + } + catch (ClassCastException e1) {return false;} + catch (NullPointerException e2) {return false;} + + } + + /** + * Returns true if the L-infinite distance between this tuple + * and tuple t1 is less than or equal to the epsilon parameter, + * otherwise returns false. The L-infinite + * distance is equal to MAX[abs(x1-x2), abs(y1-y2), abs(z1-z2)]. + * @param t1 the tuple to be compared to this tuple + * @param epsilon the threshold value + * @return true or false + */ + public boolean epsilonEquals(Tuple3d t1, double epsilon) + { + double diff; + + diff = x - t1.x; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = y - t1.y; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = z - t1.z; + if((diff<0?-diff:diff) > epsilon) return false; + + return true; + + } + + + /** + * @deprecated Use clamp(double,double,Tuple3d) instead + */ + public final void clamp(float min, float max, Tuple3d t) { + clamp((double)min, (double)max, t); + } + + + /** + * Clamps the tuple parameter to the range [low, high] and + * places the values into this tuple. + * @param min the lowest value in the tuple after clamping + * @param max the highest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clamp(double min, double max, Tuple3d t) { + if( t.x > max ) { + x = max; + } else if( t.x < min ){ + x = min; + } else { + x = t.x; + } + + if( t.y > max ) { + y = max; + } else if( t.y < min ){ + y = min; + } else { + y = t.y; + } + + if( t.z > max ) { + z = max; + } else if( t.z < min ){ + z = min; + } else { + z = t.z; + } + + } + + + /** + * @deprecated Use clampMin(double,Tuple3d) instead + */ + public final void clampMin(float min, Tuple3d t) { + clampMin((double)min, t); + } + + + /** + * Clamps the minimum value of the tuple parameter to the min + * parameter and places the values into this tuple. + * @param min the lowest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clampMin(double min, Tuple3d t) { + if( t.x < min ) { + x = min; + } else { + x = t.x; + } + + if( t.y < min ) { + y = min; + } else { + y = t.y; + } + + if( t.z < min ) { + z = min; + } else { + z = t.z; + } + + } + + + /** + * @deprecated Use clampMax(double,Tuple3d) instead + */ + public final void clampMax(float max, Tuple3d t) { + clampMax((double)max, t); + } + + + /** + * Clamps the maximum value of the tuple parameter to the max + * parameter and places the values into this tuple. + * @param max the highest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clampMax(double max, Tuple3d t) { + if( t.x > max ) { + x = max; + } else { + x = t.x; + } + + if( t.y > max ) { + y = max; + } else { + y = t.y; + } + + if( t.z > max ) { + z = max; + } else { + z = t.z; + } + + } + + + /** + * Sets each component of the tuple parameter to its absolute + * value and places the modified values into this tuple. + * @param t the source tuple, which will not be modified + */ + public final void absolute(Tuple3d t) + { + x = Math.abs(t.x); + y = Math.abs(t.y); + z = Math.abs(t.z); + + } + + + /** + * @deprecated Use clamp(double,double) instead + */ + public final void clamp(float min, float max) { + clamp((double)min, (double)max); + } + + + /** + * Clamps this tuple to the range [low, high]. + * @param min the lowest value in this tuple after clamping + * @param max the highest value in this tuple after clamping + */ + public final void clamp(double min, double max) { + if( x > max ) { + x = max; + } else if( x < min ){ + x = min; + } + + if( y > max ) { + y = max; + } else if( y < min ){ + y = min; + } + + if( z > max ) { + z = max; + } else if( z < min ){ + z = min; + } + + } + + + /** + * @deprecated Use clampMin(double) instead + */ + public final void clampMin(float min) { + clampMin((double)min); + } + + + /** + * Clamps the minimum value of this tuple to the min parameter. + * @param min the lowest value in this tuple after clamping + */ + public final void clampMin(double min) { + if( x < min ) x=min; + if( y < min ) y=min; + if( z < min ) z=min; + + } + + + /** + * @deprecated Use clampMax(double) instead + */ + public final void clampMax(float max) { + clampMax((double)max); + } + + + /** + * Clamps the maximum value of this tuple to the max parameter. + * @param max the highest value in the tuple after clamping + */ + public final void clampMax(double max) { + if( x > max ) x=max; + if( y > max ) y=max; + if( z > max ) z=max; + } + + + /** + * Sets each component of this tuple to its absolute value. + */ + public final void absolute() + { + x = Math.abs(x); + y = Math.abs(y); + z = Math.abs(z); + } + + + /** + * @deprecated Use interpolate(Tuple3d,Tuple3d,double) instead + */ + public final void interpolate(Tuple3d t1, Tuple3d t2, float alpha) { + interpolate(t1, t2, (double)alpha); + } + + + /** + * Linearly interpolates between tuples t1 and t2 and places the + * result into this tuple: this = (1-alpha)*t1 + alpha*t2. + * @param t1 the first tuple + * @param t2 the second tuple + * @param alpha the alpha interpolation parameter + */ + public final void interpolate(Tuple3d t1, Tuple3d t2, double alpha) { + this.x = (1-alpha)*t1.x + alpha*t2.x; + this.y = (1-alpha)*t1.y + alpha*t2.y; + this.z = (1-alpha)*t1.z + alpha*t2.z; + } + + + /** + * @deprecated Use interpolate(Tuple3d,double) instead + */ + public final void interpolate(Tuple3d t1, float alpha) { + interpolate(t1, (double)alpha); + } + + + /** + * Linearly interpolates between this tuple and tuple t1 and + * places the result into this tuple: this = (1-alpha)*this + alpha*t1. + * @param t1 the first tuple + * @param alpha the alpha interpolation parameter + */ + public final void interpolate(Tuple3d t1, double alpha) { + this.x = (1-alpha)*this.x + alpha*t1.x; + this.y = (1-alpha)*this.y + alpha*t1.y; + this.z = (1-alpha)*this.z + alpha*t1.z; + } + + /** + * 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 Java 3D 1.3 + */ + public Object clone() { + // Since there are no arrays we can just use Object.clone() + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + } + +} diff --git a/src/javax/vecmath/Tuple3f.java b/src/javax/vecmath/Tuple3f.java new file mode 100644 index 0000000..4e96f4b --- /dev/null +++ b/src/javax/vecmath/Tuple3f.java @@ -0,0 +1,621 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A generic 3-element tuple that is represented by single precision-floating + * point x,y,z coordinates. + * + */ +public abstract class Tuple3f implements java.io.Serializable, Cloneable { + + static final long serialVersionUID=5019834619484343712L; + + /** + * The x coordinate. + */ + public float x; + + /** + * The y coordinate. + */ + public float y; + + /** + * The z coordinate. + */ + public float z; + + + /** + * Constructs and initializes a Tuple3f from the specified xyz coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + */ + public Tuple3f(float x, float y, float z) + { + this.x = x; + this.y = y; + this.z = z; + } + + + /** + * Constructs and initializes a Tuple3f from the array of length 3. + * @param t the array of length 3 containing xyz in order + */ + public Tuple3f(float[] t) + { + this.x = t[0]; + this.y = t[1]; + this.z = t[2]; + } + + + /** + * Constructs and initializes a Tuple3f from the specified Tuple3f. + * @param t1 the Tuple3f containing the initialization x y z data + */ + public Tuple3f(Tuple3f t1) + { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + } + + + /** + * Constructs and initializes a Tuple3f from the specified Tuple3d. + * @param t1 the Tuple3d containing the initialization x y z data + */ + public Tuple3f(Tuple3d t1) + { + this.x = (float) t1.x; + this.y = (float) t1.y; + this.z = (float) t1.z; + } + + + /** + * Constructs and initializes a Tuple3f to (0,0,0). + */ + public Tuple3f() + { + this.x = 0.0f; + this.y = 0.0f; + this.z = 0.0f; + } + + + /** + * Returns a string that contains the values of this Tuple3f. + * The form is (x,y,z). + * @return the String representation + */ + public String toString() { + return "(" + this.x + ", " + this.y + ", " + this.z + ")"; + } + + + /** + * Sets the value of this tuple to the specified xyz coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + */ + public final void set(float x, float y, float z) + { + this.x = x; + this.y = y; + this.z = z; + } + + + /** + * Sets the value of this tuple to the xyz coordinates specified in + * the array of length 3. + * @param t the array of length 3 containing xyz in order + */ + public final void set(float[] t) + { + this.x = t[0]; + this.y = t[1]; + this.z = t[2]; + } + + + /** + * Sets the value of this tuple to the value of tuple t1. + * @param t1 the tuple to be copied + */ + public final void set(Tuple3f t1) + { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + } + + + /** + * Sets the value of this tuple to the value of tuple t1. + * @param t1 the tuple to be copied + */ + public final void set(Tuple3d t1) + { + this.x = (float) t1.x; + this.y = (float) t1.y; + this.z = (float) t1.z; + } + + + /** + * Gets the value of this tuple and copies the values into t. + * @param t the array of length 3 into which the values are copied + */ + public final void get(float[] t) + { + t[0] = this.x; + t[1] = this.y; + t[2] = this.z; + } + + + /** + * Gets the value of this tuple and copies the values into t. + * @param t the Tuple3f object into which the values of this object are copied + */ + public final void get(Tuple3f t) + { + t.x = this.x; + t.y = this.y; + t.z = this.z; + } + + + /** + * Sets the value of this tuple to the vector sum of tuples t1 and t2. + * @param t1 the first tuple + * @param t2 the second tuple + */ + public final void add(Tuple3f t1, Tuple3f t2) + { + this.x = t1.x + t2.x; + this.y = t1.y + t2.y; + this.z = t1.z + t2.z; + } + + + /** + * Sets the value of this tuple to the vector sum of itself and tuple t1. + * @param t1 the other tuple + */ + public final void add(Tuple3f t1) + { + this.x += t1.x; + this.y += t1.y; + this.z += t1.z; + } + + + /** + * Sets the value of this tuple to the vector difference + * of tuples t1 and t2 (this = t1 - t2). + * @param t1 the first tuple + * @param t2 the second tuple + */ + public final void sub(Tuple3f t1, Tuple3f t2) + { + this.x = t1.x - t2.x; + this.y = t1.y - t2.y; + this.z = t1.z - t2.z; + } + + + /** + * Sets the value of this tuple to the vector difference of + * itself and tuple t1 (this = this - t1) . + * @param t1 the other tuple + */ + public final void sub(Tuple3f t1) + { + this.x -= t1.x; + this.y -= t1.y; + this.z -= t1.z; + } + + + /** + * Sets the value of this tuple to the negation of tuple t1. + * @param t1 the source tuple + */ + public final void negate(Tuple3f t1) + { + this.x = -t1.x; + this.y = -t1.y; + this.z = -t1.z; + } + + + /** + * Negates the value of this tuple in place. + */ + public final void negate() + { + this.x = -this.x; + this.y = -this.y; + this.z = -this.z; + } + + + /** + * Sets the value of this vector to the scalar multiplication + * of tuple t1. + * @param s the scalar value + * @param t1 the source tuple + */ + public final void scale(float s, Tuple3f t1) + { + this.x = s*t1.x; + this.y = s*t1.y; + this.z = s*t1.z; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of the scale factor with this. + * @param s the scalar value + */ + public final void scale(float s) + { + this.x *= s; + this.y *= s; + this.z *= s; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of tuple t1 and then adds tuple t2 (this = s*t1 + t2). + * @param s the scalar value + * @param t1 the tuple to be scaled and added + * @param t2 the tuple to be added without a scale + */ + public final void scaleAdd(float s, Tuple3f t1, Tuple3f t2) + { + this.x = s*t1.x + t2.x; + this.y = s*t1.y + t2.y; + this.z = s*t1.z + t2.z; + } + + + + /** + * Sets the value of this tuple to the scalar multiplication + * of itself and then adds tuple t1 (this = s*this + t1). + * @param s the scalar value + * @param t1 the tuple to be added + */ + public final void scaleAdd(float s, Tuple3f t1) + { + this.x = s*this.x + t1.x; + this.y = s*this.y + t1.y; + this.z = s*this.z + t1.z; + } + + + /** + * Returns true if the Object t1 is of type Tuple3f and all of the + * data members of t1 are equal to the corresponding data members in + * this Tuple3f. + * @param t1 the vector with which the comparison is made + * @return true or false + */ + public boolean equals(Tuple3f t1) + { + try { + return(this.x == t1.x && this.y == t1.y && this.z == t1.z); + } + catch (NullPointerException e2) {return false;} + } + /** + * Returns true if the Object t1 is of type Tuple3f and all of the + * data members of t1 are equal to the corresponding data members in + * this Tuple3f. + * @param t1 the Object with which the comparison is made + * @return true or false + */ + public boolean equals(Object t1) + { + try { + Tuple3f t2 = (Tuple3f) t1; + return(this.x == t2.x && this.y == t2.y && this.z == t2.z); + } + catch (NullPointerException e2) {return false;} + catch (ClassCastException e1) {return false;} + } + + + /** + * Returns true if the L-infinite distance between this tuple + * and tuple t1 is less than or equal to the epsilon parameter, + * otherwise returns false. The L-infinite + * distance is equal to MAX[abs(x1-x2), abs(y1-y2), abs(z1-z2)]. + * @param t1 the tuple to be compared to this tuple + * @param epsilon the threshold value + * @return true or false + */ + public boolean epsilonEquals(Tuple3f t1, float epsilon) + { + float diff; + + diff = x - t1.x; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = y - t1.y; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = z - t1.z; + 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 Tuple3f objects with identical data values + * (i.e., Tuple3f.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 + */ + public int hashCode() { + long bits = 1L; + bits = 31L * bits + (long)Float.floatToIntBits(x); + bits = 31L * bits + (long)Float.floatToIntBits(y); + bits = 31L * bits + (long)Float.floatToIntBits(z); + return (int) (bits ^ (bits >> 32)); + } + + + + /** + * Clamps the tuple parameter to the range [low, high] and + * places the values into this tuple. + * @param min the lowest value in the tuple after clamping + * @param max the highest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clamp(float min, float max, Tuple3f t) + { + if( t.x > max ) { + x = max; + } else if( t.x < min ){ + x = min; + } else { + x = t.x; + } + + if( t.y > max ) { + y = max; + } else if( t.y < min ){ + y = min; + } else { + y = t.y; + } + + if( t.z > max ) { + z = max; + } else if( t.z < min ){ + z = min; + } else { + z = t.z; + } + + } + + + /** + * Clamps the minimum value of the tuple parameter to the min + * parameter and places the values into this tuple. + * @param min the lowest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clampMin(float min, Tuple3f t) + { + if( t.x < min ) { + x = min; + } else { + x = t.x; + } + + if( t.y < min ) { + y = min; + } else { + y = t.y; + } + + if( t.z < min ) { + z = min; + } else { + z = t.z; + } + + } + + + /** + * Clamps the maximum value of the tuple parameter to the max + * parameter and places the values into this tuple. + * @param max the highest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clampMax(float max, Tuple3f t) + { + if( t.x > max ) { + x = max; + } else { + x = t.x; + } + + if( t.y > max ) { + y = max; + } else { + y = t.y; + } + + if( t.z > max ) { + z = max; + } else { + z = t.z; + } + + } + + + /** + * Sets each component of the tuple parameter to its absolute + * value and places the modified values into this tuple. + * @param t the source tuple, which will not be modified + */ + public final void absolute(Tuple3f t) + { + x = Math.abs(t.x); + y = Math.abs(t.y); + z = Math.abs(t.z); + } + + + + /** + * Clamps this tuple to the range [low, high]. + * @param min the lowest value in this tuple after clamping + * @param max the highest value in this tuple after clamping + */ + public final void clamp(float min, float max) + { + if( x > max ) { + x = max; + } else if( x < min ){ + x = min; + } + + if( y > max ) { + y = max; + } else if( y < min ){ + y = min; + } + + if( z > max ) { + z = max; + } else if( z < min ){ + z = min; + } + + } + + + /** + * Clamps the minimum value of this tuple to the min parameter. + * @param min the lowest value in this tuple after clamping + */ + public final void clampMin(float min) + { + if( x < min ) x=min; + if( y < min ) y=min; + if( z < min ) z=min; + + } + + + /** + * Clamps the maximum value of this tuple to the max parameter. + * @param max the highest value in the tuple after clamping + */ + public final void clampMax(float max) + { + if( x > max ) x=max; + if( y > max ) y=max; + if( z > max ) z=max; + + } + + + /** + * Sets each component of this tuple to its absolute value. + */ + public final void absolute() + { + x = Math.abs(x); + y = Math.abs(y); + z = Math.abs(z); + + } + + + /** + * Linearly interpolates between tuples t1 and t2 and places the + * result into this tuple: this = (1-alpha)*t1 + alpha*t2. + * @param t1 the first tuple + * @param t2 the second tuple + * @param alpha the alpha interpolation parameter + */ + public final void interpolate(Tuple3f t1, Tuple3f t2, float alpha) + { + this.x = (1-alpha)*t1.x + alpha*t2.x; + this.y = (1-alpha)*t1.y + alpha*t2.y; + this.z = (1-alpha)*t1.z + alpha*t2.z; + + + } + + + /** + * Linearly interpolates between this tuple and tuple t1 and + * places the result into this tuple: this = (1-alpha)*this + alpha*t1. + * @param t1 the first tuple + * @param alpha the alpha interpolation parameter + */ + public final void interpolate(Tuple3f t1, float alpha) + { + this.x = (1-alpha)*this.x + alpha*t1.x; + this.y = (1-alpha)*this.y + alpha*t1.y; + this.z = (1-alpha)*this.z + alpha*t1.z; + + + } + + /** + * 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 Java 3D 1.3 + */ + public Object clone() { + // Since there are no arrays we can just use Object.clone() + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + } + +} diff --git a/src/javax/vecmath/Tuple3i.java b/src/javax/vecmath/Tuple3i.java new file mode 100644 index 0000000..d0321a4 --- /dev/null +++ b/src/javax/vecmath/Tuple3i.java @@ -0,0 +1,502 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 3-element tuple represented by signed integer x,y,z + * coordinates. + * + * @since Java 3D 1.2 + */ +public abstract class Tuple3i implements java.io.Serializable, Cloneable { + + static final long serialVersionUID = -732740491767276200L; + + /** + * The x coordinate. + */ + public int x; + + /** + * The y coordinate. + */ + public int y; + + /** + * The z coordinate. + */ + public int z; + + + /** + * Constructs and initializes a Tuple3i from the specified + * x, y, and z coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + */ + public Tuple3i(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + + /** + * Constructs and initializes a Tuple3i from the array of length 3. + * @param t the array of length 3 containing x, y, and z in order. + */ + public Tuple3i(int[] t) { + this.x = t[0]; + this.y = t[1]; + this.z = t[2]; + } + + + /** + * Constructs and initializes a Tuple3i from the specified Tuple3i. + * @param t1 the Tuple3i containing the initialization x, y, and z + * data. + */ + public Tuple3i(Tuple3i t1) { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + } + + + /** + * Constructs and initializes a Tuple3i to (0,0,0). + */ + public Tuple3i() { + this.x = 0; + this.y = 0; + this.z = 0; + } + + + /** + * Sets the value of this tuple to the specified x, y, and z + * coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + */ + public final void set(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + + /** + * Sets the value of this tuple to the specified coordinates in the + * array of length 3. + * @param t the array of length 3 containing x, y, and z in order. + */ + public final void set(int[] t) { + this.x = t[0]; + this.y = t[1]; + this.z = t[2]; + } + + + /** + * Sets the value of this tuple to the value of tuple t1. + * @param t1 the tuple to be copied + */ + public final void set(Tuple3i t1) { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + } + + + /** + * Copies the values of this tuple into the array t. + * @param t is the array + */ + public final void get(int[] t) { + t[0] = this.x; + t[1] = this.y; + t[2] = this.z; + } + + + /** + * Copies the values of this tuple into the tuple t. + * @param t is the target tuple + */ + public final void get(Tuple3i t) { + t.x = this.x; + t.y = this.y; + t.z = this.z; + } + + + /** + * Sets the value of this tuple to the sum of tuples t1 and t2. + * @param t1 the first tuple + * @param t2 the second tuple + */ + public final void add(Tuple3i t1, Tuple3i t2) { + this.x = t1.x + t2.x; + this.y = t1.y + t2.y; + this.z = t1.z + t2.z; + } + + + /** + * Sets the value of this tuple to the sum of itself and t1. + * @param t1 the other tuple + */ + public final void add(Tuple3i t1) { + this.x += t1.x; + this.y += t1.y; + this.z += t1.z; + } + + + /** + * Sets the value of this tuple to the difference + * of tuples t1 and t2 (this = t1 - t2). + * @param t1 the first tuple + * @param t2 the second tuple + */ + public final void sub(Tuple3i t1, Tuple3i t2) { + this.x = t1.x - t2.x; + this.y = t1.y - t2.y; + this.z = t1.z - t2.z; + } + + + /** + * Sets the value of this tuple to the difference + * of itself and t1 (this = this - t1). + * @param t1 the other tuple + */ + public final void sub(Tuple3i t1) { + this.x -= t1.x; + this.y -= t1.y; + this.z -= t1.z; + } + + + /** + * Sets the value of this tuple to the negation of tuple t1. + * @param t1 the source tuple + */ + public final void negate(Tuple3i t1) { + this.x = -t1.x; + this.y = -t1.y; + this.z = -t1.z; + } + + + /** + * Negates the value of this tuple in place. + */ + public final void negate() { + this.x = -this.x; + this.y = -this.y; + this.z = -this.z; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of tuple t1. + * @param s the scalar value + * @param t1 the source tuple + */ + public final void scale(int s, Tuple3i t1) { + this.x = s*t1.x; + this.y = s*t1.y; + this.z = s*t1.z; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of the scale factor with this. + * @param s the scalar value + */ + public final void scale(int s) { + this.x *= s; + this.y *= s; + this.z *= s; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of tuple t1 plus tuple t2 (this = s*t1 + t2). + * @param s the scalar value + * @param t1 the tuple to be multipled + * @param t2 the tuple to be added + */ + public final void scaleAdd(int s, Tuple3i t1, Tuple3i t2) { + this.x = s*t1.x + t2.x; + this.y = s*t1.y + t2.y; + this.z = s*t1.z + t2.z; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of itself and then adds tuple t1 (this = s*this + t1). + * @param s the scalar value + * @param t1 the tuple to be added + */ + public final void scaleAdd(int s, Tuple3i t1) { + this.x = s*this.x + t1.x; + this.y = s*this.y + t1.y; + this.z = s*this.z + t1.z; + } + + + /** + * Returns a string that contains the values of this Tuple3i. + * The form is (x,y,z). + * @return the String representation + */ + public String toString() { + return "(" + this.x + ", " + this.y + ", " + this.z + ")"; + } + + + /** + * Returns true if the Object t1 is of type Tuple3i and all of the + * data members of t1 are equal to the corresponding data members in + * this Tuple3i. + * @param t1 the object with which the comparison is made + */ + public boolean equals(Object t1) { + try { + Tuple3i t2 = (Tuple3i) t1; + return(this.x == t2.x && this.y == t2.y && this.z == t2.z); + } + catch (NullPointerException e2) { + return false; + } + catch (ClassCastException e1) { + return false; + } + } + + + /** + * Returns a hash code value based on the data values in this + * object. Two different Tuple3i objects with identical data values + * (i.e., Tuple3i.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 + */ + public int hashCode() { + long bits = 1L; + bits = 31L * bits + (long)x; + bits = 31L * bits + (long)y; + bits = 31L * bits + (long)z; + return (int) (bits ^ (bits >> 32)); + } + + + /** + * Clamps the tuple parameter to the range [low, high] and + * places the values into this tuple. + * @param min the lowest value in the tuple after clamping + * @param max the highest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clamp(int min, int max, Tuple3i t) { + if( t.x > max ) { + x = max; + } else if( t.x < min ) { + x = min; + } else { + x = t.x; + } + + if( t.y > max ) { + y = max; + } else if( t.y < min ) { + y = min; + } else { + y = t.y; + } + + if( t.z > max ) { + z = max; + } else if( t.z < min ) { + z = min; + } else { + z = t.z; + } + } + + + /** + * Clamps the minimum value of the tuple parameter to the min + * parameter and places the values into this tuple. + * @param min the lowest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clampMin(int min, Tuple3i t) { + if( t.x < min ) { + x = min; + } else { + x = t.x; + } + + if( t.y < min ) { + y = min; + } else { + y = t.y; + } + + if( t.z < min ) { + z = min; + } else { + z = t.z; + } + } + + + /** + * Clamps the maximum value of the tuple parameter to the max + * parameter and places the values into this tuple. + * @param max the highest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clampMax(int max, Tuple3i t) { + if( t.x > max ) { + x = max; + } else { + x = t.x; + } + + if( t.y > max ) { + y = max; + } else { + y = t.y; + } + + if( t.z > max ) { + z = max; + } else { + z = t.z; + } + } + + + /** + * Sets each component of the tuple parameter to its absolute + * value and places the modified values into this tuple. + * @param t the source tuple, which will not be modified + */ + public final void absolute(Tuple3i t) { + x = Math.abs(t.x); + y = Math.abs(t.y); + z = Math.abs(t.z); + } + + + /** + * Clamps this tuple to the range [low, high]. + * @param min the lowest value in this tuple after clamping + * @param max the highest value in this tuple after clamping + */ + public final void clamp(int min, int max) { + if( x > max ) { + x = max; + } else if( x < min ) { + x = min; + } + + if( y > max ) { + y = max; + } else if( y < min ) { + y = min; + } + + if( z > max ) { + z = max; + } else if( z < min ) { + z = min; + } + } + + + /** + * Clamps the minimum value of this tuple to the min parameter. + * @param min the lowest value in this tuple after clamping + */ + public final void clampMin(int min) { + if (x < min) + x=min; + + if (y < min) + y = min; + + if (z < min) + z = min; + } + + + /** + * Clamps the maximum value of this tuple to the max parameter. + * @param max the highest value in the tuple after clamping + */ + public final void clampMax(int max) { + if (x > max) + x = max; + + if (y > max) + y = max; + + if (z > max) + z = max; + } + + + /** + * Sets each component of this tuple to its absolute value. + */ + public final void absolute() { + x = Math.abs(x); + y = Math.abs(y); + z = Math.abs(z); + } + + /** + * 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 Java 3D 1.3 + */ + public Object clone() { + // Since there are no arrays we can just use Object.clone() + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + } + +} diff --git a/src/javax/vecmath/Tuple4b.java b/src/javax/vecmath/Tuple4b.java new file mode 100644 index 0000000..8945665 --- /dev/null +++ b/src/javax/vecmath/Tuple4b.java @@ -0,0 +1,246 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A four byte tuple. Note that Java defines a byte as a signed integer + * in the range [-128, 127]. However, colors are more typically + * represented by values in the range [0, 255]. Java 3D recognizes this + * and, in those cases where Tuple4b is used to represent color, treats + * the bytes as if the range were [0, 255]---in other words, as if the + * bytes were unsigned. + * Values greater than 127 can be assigned to a byte variable using a + * type cast. For example: + * <ul>byteVariable = (byte) intValue; // intValue can be > 127</ul> + * If intValue is greater than 127, then byteVariable will be negative. The + * correct value will be extracted when it is used (by masking off the upper + * bits). + */ +public abstract class Tuple4b implements java.io.Serializable, Cloneable { + + static final long serialVersionUID = -8226727741811898211L; + + /** + * The first value. + */ + public byte x; + + /** + * The second value. + */ + public byte y; + + /** + * The third value. + */ + public byte z; + + /** + * The fourth value. + */ + public byte w; + + + /** + * Constructs and initializes a Tuple4b from the specified four values. + * @param b1 the first value + * @param b2 the second value + * @param b3 the third value + * @param b4 the fourth value + */ + public Tuple4b(byte b1, byte b2, byte b3, byte b4) + { + this.x = b1; + this.y = b2; + this.z = b3; + this.w = b4; + } + + + /** + * Constructs and initializes a Tuple4b from the array of length 4. + * @param t the array of length 4 containing b1 b2 b3 b4 in order + */ + public Tuple4b(byte[] t) + { + this.x = t[0]; + this.y = t[1]; + this.z = t[2]; + this.w = t[3]; + } + + + /** + * Constructs and initializes a Tuple4b from the specified Tuple4b. + * @param t1 the Tuple4b containing the initialization x y z w data + */ + public Tuple4b(Tuple4b t1) + { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + this.w = t1.w; + } + + + /** + * Constructs and initializes a Tuple4b to (0,0,0,0). + */ + public Tuple4b() + { + this.x = (byte) 0; + this.y = (byte) 0; + this.z = (byte) 0; + this.w = (byte) 0; + } + + + /** + * Returns a string that contains the values of this Tuple4b. + * @return the String representation + */ + public String toString() + { + return("(" + ((int)this.x & 0xff) + + ", " + ((int)this.y & 0xff) + + ", " + ((int)this.z & 0xff) + + ", " + ((int)this.w & 0xff) + ")"); + } + + + /** + * Places the value of the x,y,z,w components of this Tuple4b + * into the array of length 4. + * @param b array of length 4 into which the values are placed + */ + public final void get(byte[] b) + { + b[0] = this.x; + b[1] = this.y; + b[2] = this.z; + b[3] = this.w; + } + + + /** + * Places the value of the x,y,z,w components of this + * Tuple4b into the tuple t1. + * @param t1 tuple into which the values are placed + */ + public final void get(Tuple4b t1) + { + t1.x = this.x; + t1.y = this.y; + t1.z = this.z; + t1.w = this.w; + } + + + /** + * Sets the value of the data members of this tuple to the value + * of the argument tuple t1. + * @param t1 the source tuple + */ + public final void set(Tuple4b t1) + { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + this.w = t1.w; + } + + + /** + * Sets the value of the data members of this tuple to the value + * of the array b of length 4. + * @param b the source array of length 4 + */ + public final void set(byte[] b) + { + this.x = b[0]; + this.y = b[1]; + this.z = b[2]; + this.w = b[3]; + } + + + /** + * Returns true if all of the data members of tuple t1 are equal to + * the corresponding data members in this tuple. + * @param t1 the tuple with which the comparison is made + */ + public boolean equals(Tuple4b t1) + { + try { + return(this.x == t1.x && this.y == t1.y && + this.z == t1.z && this.w == t1.w); + } + catch (NullPointerException e2) {return false;} + + } + + /** + * Returns true if the Object t1 is of type Tuple4b and all of the + * data members of t1 are equal to the corresponding data members in + * this Tuple4b. + * @param t1 the object with which the comparison is made + */ + public boolean equals(Object t1) + { + try { + Tuple4b t2 = (Tuple4b) t1; + return(this.x == t2.x && this.y == t2.y && + this.z == t2.z && this.w == t2.w); + } + catch (NullPointerException e2) {return false;} + catch (ClassCastException e1) {return false;} + + } + + + /** + * Returns a hash code value based on the data values in this + * object. Two different Tuple4b objects with identical data values + * (i.e., Tuple4b.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 + */ + public int hashCode() { + return ((((int)x & 0xff) << 0) | + (((int)y & 0xff) << 8) | + (((int)z & 0xff) << 16) | + (((int)w & 0xff) << 24)); + } + + /** + * 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 Java 3D 1.3 + */ + public Object clone() { + // Since there are no arrays we can just use Object.clone() + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + } + +} diff --git a/src/javax/vecmath/Tuple4d.java b/src/javax/vecmath/Tuple4d.java new file mode 100644 index 0000000..063e130 --- /dev/null +++ b/src/javax/vecmath/Tuple4d.java @@ -0,0 +1,751 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 4 element tuple represented by double precision floating point + * x,y,z,w coordinates. + * + */ +public abstract class Tuple4d implements java.io.Serializable, Cloneable { + + static final long serialVersionUID = -4748953690425311052L; + + /** + * The x coordinate. + */ + public double x; + + /** + * The y coordinate. + */ + public double y; + + /** + * The z coordinate. + */ + public double z; + + /** + * The w coordinate. + */ + public double w; + + + /** + * Constructs and initializes a Tuple4d from the specified xyzw coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param w the w coordinate + */ + public Tuple4d(double x, double y, double z, double w) + { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + + /** + * Constructs and initializes a Tuple4d from the coordinates contained + * in the array. + * @param t the array of length 4 containing xyzw in order + */ + public Tuple4d(double[] t) + { + this.x = t[0]; + this.y = t[1]; + this.z = t[2]; + this.w = t[3]; + } + + + /** + * Constructs and initializes a Tuple4d from the specified Tuple4d. + * @param t1 the Tuple4d containing the initialization x y z w data + */ + public Tuple4d(Tuple4d t1) + { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + this.w = t1.w; + } + + + /** + * Constructs and initializes a Tuple4d from the specified Tuple4f. + * @param t1 the Tuple4f containing the initialization x y z w data + */ + public Tuple4d(Tuple4f t1) + { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + this.w = t1.w; + } + + + /** + * Constructs and initializes a Tuple4d to (0,0,0,0). + */ + public Tuple4d() + { + this.x = 0.0; + this.y = 0.0; + this.z = 0.0; + this.w = 0.0; + } + + + /** + * Sets the value of this tuple to the specified xyzw coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param w the w coordinate + */ + public final void set(double x, double y, double z, double w) + { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + + /** + * Sets the value of this tuple to the specified xyzw coordinates. + * @param t the array of length 4 containing xyzw in order + */ + public final void set(double[] t) + { + this.x = t[0]; + this.y = t[1]; + this.z = t[2]; + this.w = t[3]; + } + + + /** + * Sets the value of this tuple to the value of tuple t1. + * @param t1 the tuple to be copied + */ + public final void set(Tuple4d t1) + { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + this.w = t1.w; + } + + + /** + * Sets the value of this tuple to the value of tuple t1. + * @param t1 the tuple to be copied + */ + public final void set(Tuple4f t1) + { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + this.w = t1.w; + } + + + /** + * Gets the value of this tuple and places it into the array t of + * length four in x,y,z,w order. + * @param t the array of length four + */ + public final void get(double[] t) + { + t[0] = this.x; + t[1] = this.y; + t[2] = this.z; + t[3] = this.w; + } + + + /** + * Gets the value of this tuple and places it into the Tuple4d + * argument of + * length four in x,y,z,w order. + * @param t the Tuple into which the values will be copied + */ + public final void get(Tuple4d t) + { + t.x = this.x; + t.y = this.y; + t.z = this.z; + t.w = this.w; + } + + + /** + * Sets the value of this tuple to the tuple sum of tuples t1 and t2. + * @param t1 the first tuple + * @param t2 the second tuple + */ + public final void add(Tuple4d t1, Tuple4d t2) + { + this.x = t1.x + t2.x; + this.y = t1.y + t2.y; + this.z = t1.z + t2.z; + this.w = t1.w + t2.w; + } + + + /** + * Sets the value of this tuple to the sum of itself and tuple t1. + * @param t1 the other tuple + */ + public final void add(Tuple4d t1) + { + this.x += t1.x; + this.y += t1.y; + this.z += t1.z; + this.w += t1.w; + } + + + /** + * Sets the value of this tuple to the difference + * of tuples t1 and t2 (this = t1 - t2). + * @param t1 the first tuple + * @param t2 the second tuple + */ + public final void sub(Tuple4d t1, Tuple4d t2) + { + this.x = t1.x - t2.x; + this.y = t1.y - t2.y; + this.z = t1.z - t2.z; + this.w = t1.w - t2.w; + } + + + /** + * Sets the value of this tuple to the difference of itself + * and tuple t1 (this = this - t1). + * @param t1 the other tuple + */ + public final void sub(Tuple4d t1) + { + this.x -= t1.x; + this.y -= t1.y; + this.z -= t1.z; + this.w -= t1.w; + } + + + /** + * Sets the value of this tuple to the negation of tuple t1. + * @param t1 the source tuple + */ + public final void negate(Tuple4d t1) + { + this.x = -t1.x; + this.y = -t1.y; + this.z = -t1.z; + this.w = -t1.w; + } + + + /** + * Negates the value of this tuple in place. + */ + public final void negate() + { + this.x = -this.x; + this.y = -this.y; + this.z = -this.z; + this.w = -this.w; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of the scale factor with the tuple t1. + * @param s the scalar value + * @param t1 the source tuple + */ + public final void scale(double s, Tuple4d t1) + { + this.x = s*t1.x; + this.y = s*t1.y; + this.z = s*t1.z; + this.w = s*t1.w; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of the scale factor with this. + * @param s the scalar value + */ + public final void scale(double s) + { + this.x *= s; + this.y *= s; + this.z *= s; + this.w *= s; + } + + + /** + * Sets the value of this tuple to the scalar multiplication by s + * of tuple t1 plus tuple t2 (this = s*t1 + t2). + * @param s the scalar value + * @param t1 the tuple to be multipled + * @param t2 the tuple to be added + */ + public final void scaleAdd(double s, Tuple4d t1, Tuple4d t2) + { + this.x = s*t1.x + t2.x; + this.y = s*t1.y + t2.y; + this.z = s*t1.z + t2.z; + this.w = s*t1.w + t2.w; + } + + + + /** + * @deprecated Use scaleAdd(double,Tuple4d) instead + */ + public final void scaleAdd(float s, Tuple4d t1) { + scaleAdd((double)s, t1); + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of itself and then adds tuple t1 (this = s*this + t1). + * @param s the scalar value + * @param t1 the tuple to be added + */ + public final void scaleAdd(double s, Tuple4d t1) { + this.x = s*this.x + t1.x; + this.y = s*this.y + t1.y; + this.z = s*this.z + t1.z; + this.w = s*this.w + t1.w; + } + + + + /** + * Returns a string that contains the values of this Tuple4d. + * The form is (x,y,z,w). + * @return the String representation + */ + public String toString() { + return "(" + this.x + ", " + this.y + ", " + this.z + ", " + this.w + ")"; + } + + + /** + * Returns true if all of the data members of Tuple4d t1 are + * equal to the corresponding data members in this Tuple4d. + * @param t1 the tuple with which the comparison is made + * @return true or false + */ + public boolean equals(Tuple4d t1) + { + try { + return(this.x == t1.x && this.y == t1.y && this.z == t1.z + && this.w == t1.w); + } + catch (NullPointerException e2) {return false;} + } + + /** + * Returns true if the Object t1 is of type Tuple4d and all of the + * data members of t1 are equal to the corresponding data members in + * this Tuple4d. + * @param t1 the object with which the comparison is made + * @return true or false + */ + public boolean equals(Object t1) + { + try { + + Tuple4d t2 = (Tuple4d) t1; + return(this.x == t2.x && this.y == t2.y && + this.z == t2.z && this.w == t2.w); + } + catch (NullPointerException e2) {return false;} + catch (ClassCastException e1) {return false;} + } + + + /** + * Returns true if the L-infinite distance between this tuple + * and tuple t1 is less than or equal to the epsilon parameter, + * otherwise returns false. The L-infinite + * distance is equal to + * MAX[abs(x1-x2), abs(y1-y2), abs(z1-z2), abs(w1-w2)]. + * @param t1 the tuple to be compared to this tuple + * @param epsilon the threshold value + * @return true or false + */ + public boolean epsilonEquals(Tuple4d t1, double epsilon) + { + double diff; + + diff = x - t1.x; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = y - t1.y; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = z - t1.z; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = w - t1.w; + 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 Tuple4d objects with identical data values + * (i.e., Tuple4d.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 + */ + public int hashCode() { + long bits = 1L; + bits = 31L * bits + Double.doubleToLongBits(x); + bits = 31L * bits + Double.doubleToLongBits(y); + bits = 31L * bits + Double.doubleToLongBits(z); + bits = 31L * bits + Double.doubleToLongBits(w); + return (int) (bits ^ (bits >> 32)); + } + + + /** + * @deprecated Use clamp(double,double,Tuple4d) instead + */ + public final void clamp(float min, float max, Tuple4d t) { + clamp((double)min, (double)max, t); + } + + + /** + * Clamps the tuple parameter to the range [low, high] and + * places the values into this tuple. + * @param min the lowest value in the tuple after clamping + * @param max the highest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clamp(double min, double max, Tuple4d t) { + if( t.x > max ) { + x = max; + } else if( t.x < min ){ + x = min; + } else { + x = t.x; + } + + if( t.y > max ) { + y = max; + } else if( t.y < min ){ + y = min; + } else { + y = t.y; + } + + if( t.z > max ) { + z = max; + } else if( t.z < min ){ + z = min; + } else { + z = t.z; + } + + if( t.w > max ) { + w = max; + } else if( t.w < min ){ + w = min; + } else { + w = t.w; + } + + } + + + /** + * @deprecated Use clampMin(double,Tuple4d) instead + */ + public final void clampMin(float min, Tuple4d t) { + clampMin((double)min, t); + } + + + /** + * Clamps the minimum value of the tuple parameter to the min + * parameter and places the values into this tuple. + * @param min the lowest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clampMin(double min, Tuple4d t) { + if( t.x < min ) { + x = min; + } else { + x = t.x; + } + + if( t.y < min ) { + y = min; + } else { + y = t.y; + } + + if( t.z < min ) { + z = min; + } else { + z = t.z; + } + + if( t.w < min ) { + w = min; + } else { + w = t.w; + } + + } + + + /** + * @deprecated Use clampMax(double,Tuple4d) instead + */ + public final void clampMax(float max, Tuple4d t) { + clampMax((double)max, t); + } + + + /** + * Clamps the maximum value of the tuple parameter to the max + * parameter and places the values into this tuple. + * @param max the highest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clampMax(double max, Tuple4d t) { + if( t.x > max ) { + x = max; + } else { + x = t.x; + } + + if( t.y > max ) { + y = max; + } else { + y = t.y; + } + + if( t.z > max ) { + z = max; + } else { + z = t.z; + } + + if( t.w > max ) { + w = max; + } else { + w = t.z; + } + + } + + + /** + * Sets each component of the tuple parameter to its absolute + * value and places the modified values into this tuple. + * @param t the source tuple, which will not be modified + */ + public final void absolute(Tuple4d t) + { + x = Math.abs(t.x); + y = Math.abs(t.y); + z = Math.abs(t.z); + w = Math.abs(t.w); + + } + + + + /** + * @deprecated Use clamp(double,double) instead + */ + public final void clamp(float min, float max) { + clamp((double)min, (double)max); + } + + + /** + * Clamps this tuple to the range [low, high]. + * @param min the lowest value in this tuple after clamping + * @param max the highest value in this tuple after clamping + */ + public final void clamp(double min, double max) { + if( x > max ) { + x = max; + } else if( x < min ){ + x = min; + } + + if( y > max ) { + y = max; + } else if( y < min ){ + y = min; + } + + if( z > max ) { + z = max; + } else if( z < min ){ + z = min; + } + + if( w > max ) { + w = max; + } else if( w < min ){ + w = min; + } + + } + + + /** + * @deprecated Use clampMin(double) instead + */ + public final void clampMin(float min) { + clampMin((double)min); + } + + + /** + * Clamps the minimum value of this tuple to the min parameter. + * @param min the lowest value in this tuple after clamping + */ + public final void clampMin(double min) { + if( x < min ) x=min; + if( y < min ) y=min; + if( z < min ) z=min; + if( w < min ) w=min; + } + + + /** + * @deprecated Use clampMax(double) instead + */ + public final void clampMax(float max) { + clampMax((double)max); + } + + + /** + * Clamps the maximum value of this tuple to the max parameter. + * @param max the highest value in the tuple after clamping + */ + public final void clampMax(double max) { + if( x > max ) x=max; + if( y > max ) y=max; + if( z > max ) z=max; + if( w > max ) w=max; + + } + + + /** + * Sets each component of this tuple to its absolute value. + */ + public final void absolute() + { + x = Math.abs(x); + y = Math.abs(y); + z = Math.abs(z); + w = Math.abs(w); + + } + + + /** + * @deprecated Use interpolate(Tuple4d,Tuple4d,double) instead + */ + public void interpolate(Tuple4d t1, Tuple4d t2, float alpha) { + interpolate(t1, t2, (double)alpha); + } + + + /** + * Linearly interpolates between tuples t1 and t2 and places the + * result into this tuple: this = (1-alpha)*t1 + alpha*t2. + * @param t1 the first tuple + * @param t2 the second tuple + * @param alpha the alpha interpolation parameter + */ + public void interpolate(Tuple4d t1, Tuple4d t2, double alpha) { + this.x = (1-alpha)*t1.x + alpha*t2.x; + this.y = (1-alpha)*t1.y + alpha*t2.y; + this.z = (1-alpha)*t1.z + alpha*t2.z; + this.w = (1-alpha)*t1.w + alpha*t2.w; + } + + + /** + * @deprecated Use interpolate(Tuple4d,double) instead + */ + public void interpolate(Tuple4d t1, float alpha) { + interpolate(t1, (double)alpha); + } + + + /** + * Linearly interpolates between this tuple and tuple t1 and + * places the result into this tuple: this = (1-alpha)*this + alpha*t1. + * @param t1 the first tuple + * @param alpha the alpha interpolation parameter + */ + public void interpolate(Tuple4d t1, double alpha) { + this.x = (1-alpha)*this.x + alpha*t1.x; + this.y = (1-alpha)*this.y + alpha*t1.y; + this.z = (1-alpha)*this.z + alpha*t1.z; + this.w = (1-alpha)*this.w + alpha*t1.w; + } + + /** + * 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 Java 3D 1.3 + */ + public Object clone() { + // Since there are no arrays we can just use Object.clone() + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + } + +} diff --git a/src/javax/vecmath/Tuple4f.java b/src/javax/vecmath/Tuple4f.java new file mode 100644 index 0000000..fea4e31 --- /dev/null +++ b/src/javax/vecmath/Tuple4f.java @@ -0,0 +1,682 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 4-element tuple represented by single-precision floating point x,y,z,w + * coordinates. + * + */ +public abstract class Tuple4f implements java.io.Serializable, Cloneable { + + static final long serialVersionUID = 7068460319248845763L; + + /** + * The x coordinate. + */ + public float x; + + /** + * The y coordinate. + */ + public float y; + + /** + * The z coordinate. + */ + public float z; + + /** + * The w coordinate. + */ + public float w; + + + /** + * Constructs and initializes a Tuple4f from the specified xyzw coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param w the w coordinate + */ + public Tuple4f(float x, float y, float z, float w) + { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + + /** + * Constructs and initializes a Tuple4f from the array of length 4. + * @param t the array of length 4 containing xyzw in order + */ + public Tuple4f(float[] t) + { + this.x = t[0]; + this.y = t[1]; + this.z = t[2]; + this.w = t[3]; + } + + + /** + * Constructs and initializes a Tuple4f from the specified Tuple4f. + * @param t1 the Tuple4f containing the initialization x y z w data + */ + public Tuple4f(Tuple4f t1) + { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + this.w = t1.w; + } + + + /** + * Constructs and initializes a Tuple4f from the specified Tuple4d. + * @param t1 the Tuple4d containing the initialization x y z w data + */ + public Tuple4f(Tuple4d t1) + { + this.x = (float) t1.x; + this.y = (float) t1.y; + this.z = (float) t1.z; + this.w = (float) t1.w; + } + + + /** + * Constructs and initializes a Tuple4f to (0,0,0,0). + */ + public Tuple4f() + { + this.x = 0.0f; + this.y = 0.0f; + this.z = 0.0f; + this.w = 0.0f; + } + + + /** + * Sets the value of this tuple to the specified xyzw coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param w the w coordinate + */ + public final void set(float x, float y, float z, float w) + { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + + /** + * Sets the value of this tuple to the specified coordinates in the + * array of length 4. + * @param t the array of length 4 containing xyzw in order + */ + public final void set(float[] t) + { + this.x = t[0]; + this.y = t[1]; + this.z = t[2]; + this.w = t[3]; + } + + + /** + * Sets the value of this tuple to the value of tuple t1. + * @param t1 the tuple to be copied + */ + public final void set(Tuple4f t1) + { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + this.w = t1.w; + } + + + /** + * Sets the value of this tuple to the value of tuple t1. + * @param t1 the tuple to be copied + */ + public final void set(Tuple4d t1) + { + this.x = (float) t1.x; + this.y = (float) t1.y; + this.z = (float) t1.z; + this.w = (float) t1.w; + } + + + /** + * Copies the values of this tuple into the array t. + * @param t the array + */ + public final void get(float[] t) + { + t[0] = this.x; + t[1] = this.y; + t[2] = this.z; + t[3] = this.w; + } + + + /** + * Copies the values of this tuple into the tuple t. + * @param t the target tuple + */ + public final void get(Tuple4f t) + { + t.x = this.x; + t.y = this.y; + t.z = this.z; + t.w = this.w; + } + + + /** + * Sets the value of this tuple to the sum of tuples t1 and t2. + * @param t1 the first tuple + * @param t2 the second tuple + */ + public final void add(Tuple4f t1, Tuple4f t2) + { + this.x = t1.x + t2.x; + this.y = t1.y + t2.y; + this.z = t1.z + t2.z; + this.w = t1.w + t2.w; + } + + + /** + * Sets the value of this tuple to the sum of itself and t1. + * @param t1 the other tuple + */ + public final void add(Tuple4f t1) + { + this.x += t1.x; + this.y += t1.y; + this.z += t1.z; + this.w += t1.w; + } + + + /** + * Sets the value of this tuple to the difference + * of tuples t1 and t2 (this = t1 - t2). + * @param t1 the first tuple + * @param t2 the second tuple + */ + public final void sub(Tuple4f t1, Tuple4f t2) + { + this.x = t1.x - t2.x; + this.y = t1.y - t2.y; + this.z = t1.z - t2.z; + this.w = t1.w - t2.w; + } + + + /** + * Sets the value of this tuple to the difference + * of itself and t1 (this = this - t1). + * @param t1 the other tuple + */ + public final void sub(Tuple4f t1) + { + this.x -= t1.x; + this.y -= t1.y; + this.z -= t1.z; + this.w -= t1.w; + } + + + /** + * Sets the value of this tuple to the negation of tuple t1. + * @param t1 the source tuple + */ + public final void negate(Tuple4f t1) + { + this.x = -t1.x; + this.y = -t1.y; + this.z = -t1.z; + this.w = -t1.w; + } + + + /** + * Negates the value of this tuple in place. + */ + public final void negate() + { + this.x = -this.x; + this.y = -this.y; + this.z = -this.z; + this.w = -this.w; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of tuple t1. + * @param s the scalar value + * @param t1 the source tuple + */ + public final void scale(float s, Tuple4f t1) + { + this.x = s*t1.x; + this.y = s*t1.y; + this.z = s*t1.z; + this.w = s*t1.w; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of the scale factor with this. + * @param s the scalar value + */ + public final void scale(float s) + { + this.x *= s; + this.y *= s; + this.z *= s; + this.w *= s; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of tuple t1 plus tuple t2 (this = s*t1 + t2). + * @param s the scalar value + * @param t1 the tuple to be multipled + * @param t2 the tuple to be added + */ + public final void scaleAdd(float s, Tuple4f t1, Tuple4f t2) + { + this.x = s*t1.x + t2.x; + this.y = s*t1.y + t2.y; + this.z = s*t1.z + t2.z; + this.w = s*t1.w + t2.w; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of itself and then adds tuple t1 (this = s*this + t1). + * @param s the scalar value + * @param t1 the tuple to be added + */ + public final void scaleAdd(float s, Tuple4f t1) + { + this.x = s*this.x + t1.x; + this.y = s*this.y + t1.y; + this.z = s*this.z + t1.z; + this.w = s*this.w + t1.w; + } + + + + /** + * Returns a string that contains the values of this Tuple4f. + * The form is (x,y,z,w). + * @return the String representation + */ + public String toString() { + return "(" + this.x + ", " + this.y + ", " + this.z + ", " + this.w + ")"; + } + + /** + * Returns true if all of the data members of Tuple4f t1 are + * equal to the corresponding data members in this Tuple4f. + * @param t1 the vector with which the comparison is made + * @return true or false + */ + public boolean equals(Tuple4f t1) + { + try { + return(this.x == t1.x && this.y == t1.y && this.z == t1.z + && this.w == t1.w); + } + catch (NullPointerException e2) {return false;} + } + + /** + * Returns true if the Object t1 is of type Tuple4f and all of the + * data members of t1 are equal to the corresponding data members in + * this Tuple4f. + * @param t1 the object with which the comparison is made + * @return true or false + */ + public boolean equals(Object t1) + { + try { + Tuple4f t2 = (Tuple4f) t1; + return(this.x == t2.x && this.y == t2.y && + this.z == t2.z && this.w == t2.w); + } + catch (NullPointerException e2) {return false;} + catch (ClassCastException e1) {return false;} + } + + + /** + * Returns true if the L-infinite distance between this tuple + * and tuple t1 is less than or equal to the epsilon parameter, + * otherwise returns false. The L-infinite + * distance is equal to + * MAX[abs(x1-x2), abs(y1-y2), abs(z1-z2), abs(w1-w2)]. + * @param t1 the tuple to be compared to this tuple + * @param epsilon the threshold value + * @return true or false + */ + public boolean epsilonEquals(Tuple4f t1, float epsilon) + { + float diff; + + diff = x - t1.x; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = y - t1.y; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = z - t1.z; + if((diff<0?-diff:diff) > epsilon) return false; + + diff = w - t1.w; + 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 Tuple4f objects with identical data values + * (i.e., Tuple4f.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 + */ + public int hashCode() { + long bits = 1L; + bits = 31L * bits + (long)Float.floatToIntBits(x); + bits = 31L * bits + (long)Float.floatToIntBits(y); + bits = 31L * bits + (long)Float.floatToIntBits(z); + bits = 31L * bits + (long)Float.floatToIntBits(w); + return (int) (bits ^ (bits >> 32)); + } + + + /** + * Clamps the tuple parameter to the range [low, high] and + * places the values into this tuple. + * @param min the lowest value in the tuple after clamping + * @param max the highest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clamp(float min, float max, Tuple4f t) + { + if( t.x > max ) { + x = max; + } else if( t.x < min ){ + x = min; + } else { + x = t.x; + } + + if( t.y > max ) { + y = max; + } else if( t.y < min ){ + y = min; + } else { + y = t.y; + } + + if( t.z > max ) { + z = max; + } else if( t.z < min ){ + z = min; + } else { + z = t.z; + } + + if( t.w > max ) { + w = max; + } else if( t.w < min ){ + w = min; + } else { + w = t.w; + } + + } + + + /** + * Clamps the minimum value of the tuple parameter to the min + * parameter and places the values into this tuple. + * @param min the lowest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clampMin(float min, Tuple4f t) + { + if( t.x < min ) { + x = min; + } else { + x = t.x; + } + + if( t.y < min ) { + y = min; + } else { + y = t.y; + } + + if( t.z < min ) { + z = min; + } else { + z = t.z; + } + + if( t.w < min ) { + w = min; + } else { + w = t.w; + } + + + } + + + /** + * Clamps the maximum value of the tuple parameter to the max + * parameter and places the values into this tuple. + * @param max the highest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clampMax(float max, Tuple4f t) + { + if( t.x > max ) { + x = max; + } else { + x = t.x; + } + + if( t.y > max ) { + y = max; + } else { + y = t.y; + } + + if( t.z > max ) { + z = max; + } else { + z = t.z; + } + + if( t.w > max ) { + w = max; + } else { + w = t.z; + } + + } + + + /** + * Sets each component of the tuple parameter to its absolute + * value and places the modified values into this tuple. + * @param t the source tuple, which will not be modified + */ + public final void absolute(Tuple4f t) + { + x = Math.abs(t.x); + y = Math.abs(t.y); + z = Math.abs(t.z); + w = Math.abs(t.w); + } + + + /** + * Clamps this tuple to the range [low, high]. + * @param min the lowest value in this tuple after clamping + * @param max the highest value in this tuple after clamping + */ + public final void clamp(float min, float max) + { + if( x > max ) { + x = max; + } else if( x < min ){ + x = min; + } + + if( y > max ) { + y = max; + } else if( y < min ){ + y = min; + } + + if( z > max ) { + z = max; + } else if( z < min ){ + z = min; + } + + if( w > max ) { + w = max; + } else if( w < min ){ + w = min; + } + + } + + + /** + * Clamps the minimum value of this tuple to the min parameter. + * @param min the lowest value in this tuple after clamping + */ + public final void clampMin(float min) + { + if( x < min ) x=min; + if( y < min ) y=min; + if( z < min ) z=min; + if( w < min ) w=min; + + } + + + /** + * Clamps the maximum value of this tuple to the max parameter. + * @param max the highest value in the tuple after clamping + */ + public final void clampMax(float max) + { + if( x > max ) x=max; + if( y > max ) y=max; + if( z > max ) z=max; + if( w > max ) w=max; + + } + + + /** + * Sets each component of this tuple to its absolute value. + */ + public final void absolute() + { + x = Math.abs(x); + y = Math.abs(y); + z = Math.abs(z); + w = Math.abs(w); + } + + + /** + * Linearly interpolates between tuples t1 and t2 and places the + * result into this tuple: this = (1-alpha)*t1 + alpha*t2. + * @param t1 the first tuple + * @param t2 the second tuple + * @param alpha the alpha interpolation parameter + */ + public void interpolate(Tuple4f t1, Tuple4f t2, float alpha) + { + this.x = (1-alpha)*t1.x + alpha*t2.x; + this.y = (1-alpha)*t1.y + alpha*t2.y; + this.z = (1-alpha)*t1.z + alpha*t2.z; + this.w = (1-alpha)*t1.w + alpha*t2.w; + + } + + + /** + * Linearly interpolates between this tuple and tuple t1 and + * places the result into this tuple: this = (1-alpha)*this + alpha*t1. + * @param t1 the first tuple + * @param alpha the alpha interpolation parameter + */ + public void interpolate(Tuple4f t1, float alpha) + { + this.x = (1-alpha)*this.x + alpha*t1.x; + this.y = (1-alpha)*this.y + alpha*t1.y; + this.z = (1-alpha)*this.z + alpha*t1.z; + this.w = (1-alpha)*this.w + alpha*t1.w; + + } + + /** + * 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 Java 3D 1.3 + */ + public Object clone() { + // Since there are no arrays we can just use Object.clone() + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + } + +} diff --git a/src/javax/vecmath/Tuple4i.java b/src/javax/vecmath/Tuple4i.java new file mode 100644 index 0000000..a066ac9 --- /dev/null +++ b/src/javax/vecmath/Tuple4i.java @@ -0,0 +1,567 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 4-element tuple represented by signed integer x,y,z,w + * coordinates. + * + * @since Java 3D 1.2 + */ +public abstract class Tuple4i implements java.io.Serializable, Cloneable { + + static final long serialVersionUID = 8064614250942616720L; + + /** + * The x coordinate. + */ + public int x; + + /** + * The y coordinate. + */ + public int y; + + /** + * The z coordinate. + */ + public int z; + + /** + * The w coordinate. + */ + public int w; + + + /** + * Constructs and initializes a Tuple4i from the specified + * x, y, z, and w coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param w the w coordinate + */ + public Tuple4i(int x, int y, int z, int w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + + /** + * Constructs and initializes a Tuple4i from the array of length 4. + * @param t the array of length 4 containing x, y, z, and w in order. + */ + public Tuple4i(int[] t) { + this.x = t[0]; + this.y = t[1]; + this.z = t[2]; + this.w = t[3]; + } + + + /** + * Constructs and initializes a Tuple4i from the specified Tuple4i. + * @param t1 the Tuple4i containing the initialization x, y, z, + * and w data. + */ + public Tuple4i(Tuple4i t1) { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + this.w = t1.w; + } + + + /** + * Constructs and initializes a Tuple4i to (0,0,0,0). + */ + public Tuple4i() { + this.x = 0; + this.y = 0; + this.z = 0; + this.w = 0; + } + + + /** + * Sets the value of this tuple to the specified x, y, z, and w + * coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param w the w coordinate + */ + public final void set(int x, int y, int z, int w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + + /** + * Sets the value of this tuple to the specified coordinates in the + * array of length 4. + * @param t the array of length 4 containing x, y, z, and w in order. + */ + public final void set(int[] t) { + this.x = t[0]; + this.y = t[1]; + this.z = t[2]; + this.w = t[3]; + } + + + /** + * Sets the value of this tuple to the value of tuple t1. + * @param t1 the tuple to be copied + */ + public final void set(Tuple4i t1) { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + this.w = t1.w; + } + + + /** + * Copies the values of this tuple into the array t. + * @param t the array + */ + public final void get(int[] t) { + t[0] = this.x; + t[1] = this.y; + t[2] = this.z; + t[3] = this.w; + } + + + /** + * Copies the values of this tuple into the tuple t. + * @param t the target tuple + */ + public final void get(Tuple4i t) { + t.x = this.x; + t.y = this.y; + t.z = this.z; + t.w = this.w; + } + + + /** + * Sets the value of this tuple to the sum of tuples t1 and t2. + * @param t1 the first tuple + * @param t2 the second tuple + */ + public final void add(Tuple4i t1, Tuple4i t2) { + this.x = t1.x + t2.x; + this.y = t1.y + t2.y; + this.z = t1.z + t2.z; + this.w = t1.w + t2.w; + } + + + /** + * Sets the value of this tuple to the sum of itself and t1. + * @param t1 the other tuple + */ + public final void add(Tuple4i t1) { + this.x += t1.x; + this.y += t1.y; + this.z += t1.z; + this.w += t1.w; + } + + + /** + * Sets the value of this tuple to the difference + * of tuples t1 and t2 (this = t1 - t2). + * @param t1 the first tuple + * @param t2 the second tuple + */ + public final void sub(Tuple4i t1, Tuple4i t2) { + this.x = t1.x - t2.x; + this.y = t1.y - t2.y; + this.z = t1.z - t2.z; + this.w = t1.w - t2.w; + } + + + /** + * Sets the value of this tuple to the difference + * of itself and t1 (this = this - t1). + * @param t1 the other tuple + */ + public final void sub(Tuple4i t1) { + this.x -= t1.x; + this.y -= t1.y; + this.z -= t1.z; + this.w -= t1.w; + } + + + /** + * Sets the value of this tuple to the negation of tuple t1. + * @param t1 the source tuple + */ + public final void negate(Tuple4i t1) { + this.x = -t1.x; + this.y = -t1.y; + this.z = -t1.z; + this.w = -t1.w; + } + + + /** + * Negates the value of this tuple in place. + */ + public final void negate() { + this.x = -this.x; + this.y = -this.y; + this.z = -this.z; + this.w = -this.w; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of tuple t1. + * @param s the scalar value + * @param t1 the source tuple + */ + public final void scale(int s, Tuple4i t1) { + this.x = s*t1.x; + this.y = s*t1.y; + this.z = s*t1.z; + this.w = s*t1.w; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of the scale factor with this. + * @param s the scalar value + */ + public final void scale(int s) { + this.x *= s; + this.y *= s; + this.z *= s; + this.w *= s; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of tuple t1 plus tuple t2 (this = s*t1 + t2). + * @param s the scalar value + * @param t1 the tuple to be multipled + * @param t2 the tuple to be added + */ + public final void scaleAdd(int s, Tuple4i t1, Tuple4i t2) { + this.x = s*t1.x + t2.x; + this.y = s*t1.y + t2.y; + this.z = s*t1.z + t2.z; + this.w = s*t1.w + t2.w; + } + + + /** + * Sets the value of this tuple to the scalar multiplication + * of itself and then adds tuple t1 (this = s*this + t1). + * @param s the scalar value + * @param t1 the tuple to be added + */ + public final void scaleAdd(int s, Tuple4i t1) { + this.x = s*this.x + t1.x; + this.y = s*this.y + t1.y; + this.z = s*this.z + t1.z; + this.w = s*this.w + t1.w; + } + + + /** + * Returns a string that contains the values of this Tuple4i. + * The form is (x,y,z,w). + * @return the String representation + */ + public String toString() { + return "(" + this.x + ", " + this.y + ", " + this.z + ", " + this.w + ")"; + } + + + /** + * Returns true if the Object t1 is of type Tuple4i and all of the + * data members of t1 are equal to the corresponding data members in + * this Tuple4i. + * @param t1 the object with which the comparison is made + * @return true or false + */ + public boolean equals(Object t1) { + try { + Tuple4i t2 = (Tuple4i) t1; + return(this.x == t2.x && this.y == t2.y && + this.z == t2.z && this.w == t2.w); + } + catch (NullPointerException e2) { + return false; + } + catch (ClassCastException e1) { + return false; + } + } + + + /** + * Returns a hash code value based on the data values in this + * object. Two different Tuple4i objects with identical data values + * (i.e., Tuple4i.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 + */ + public int hashCode() { + long bits = 1L; + bits = 31L * bits + (long)x; + bits = 31L * bits + (long)y; + bits = 31L * bits + (long)z; + bits = 31L * bits + (long)w; + return (int) (bits ^ (bits >> 32)); + } + + + /** + * Clamps the tuple parameter to the range [low, high] and + * places the values into this tuple. + * @param min the lowest value in the tuple after clamping + * @param max the highest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clamp(int min, int max, Tuple4i t) { + if( t.x > max ) { + x = max; + } else if( t.x < min ) { + x = min; + } else { + x = t.x; + } + + if( t.y > max ) { + y = max; + } else if( t.y < min ) { + y = min; + } else { + y = t.y; + } + + if( t.z > max ) { + z = max; + } else if( t.z < min ) { + z = min; + } else { + z = t.z; + } + + if( t.w > max ) { + w = max; + } else if( t.w < min ) { + w = min; + } else { + w = t.w; + } + } + + + /** + * Clamps the minimum value of the tuple parameter to the min + * parameter and places the values into this tuple. + * @param min the lowest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clampMin(int min, Tuple4i t) { + if( t.x < min ) { + x = min; + } else { + x = t.x; + } + + if( t.y < min ) { + y = min; + } else { + y = t.y; + } + + if( t.z < min ) { + z = min; + } else { + z = t.z; + } + + if( t.w < min ) { + w = min; + } else { + w = t.w; + } + + + } + + + /** + * Clamps the maximum value of the tuple parameter to the max + * parameter and places the values into this tuple. + * @param max the highest value in the tuple after clamping + * @param t the source tuple, which will not be modified + */ + public final void clampMax(int max, Tuple4i t) { + if( t.x > max ) { + x = max; + } else { + x = t.x; + } + + if( t.y > max ) { + y = max; + } else { + y = t.y; + } + + if( t.z > max ) { + z = max; + } else { + z = t.z; + } + + if( t.w > max ) { + w = max; + } else { + w = t.z; + } + } + + + /** + * Sets each component of the tuple parameter to its absolute + * value and places the modified values into this tuple. + * @param t the source tuple, which will not be modified + */ + public final void absolute(Tuple4i t) { + x = Math.abs(t.x); + y = Math.abs(t.y); + z = Math.abs(t.z); + w = Math.abs(t.w); + } + + + /** + * Clamps this tuple to the range [low, high]. + * @param min the lowest value in this tuple after clamping + * @param max the highest value in this tuple after clamping + */ + public final void clamp(int min, int max) { + if( x > max ) { + x = max; + } else if( x < min ) { + x = min; + } + + if( y > max ) { + y = max; + } else if( y < min ) { + y = min; + } + + if( z > max ) { + z = max; + } else if( z < min ) { + z = min; + } + + if( w > max ) { + w = max; + } else if( w < min ) { + w = min; + } + } + + + /** + * Clamps the minimum value of this tuple to the min parameter. + * @param min the lowest value in this tuple after clamping + */ + public final void clampMin(int min) { + if (x < min) + x=min; + + if (y < min) + y = min; + + if (z < min) + z = min; + + if (w < min) + w = min; + } + + + /** + * Clamps the maximum value of this tuple to the max parameter. + * @param max the highest value in the tuple after clamping + */ + public final void clampMax(int max) { + if (x > max) + x = max; + + if (y > max) + y = max; + + if (z > max) + z = max; + + if (w > max) + w = max; + } + + + /** + * Sets each component of this tuple to its absolute value. + */ + public final void absolute() { + x = Math.abs(x); + y = Math.abs(y); + z = Math.abs(z); + w = Math.abs(w); + } + + /** + * 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 Java 3D 1.3 + */ + public Object clone() { + // Since there are no arrays we can just use Object.clone() + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + // this shouldn't happen, since we are Cloneable + throw new InternalError(); + } + } + +} diff --git a/src/javax/vecmath/VecMathI18N.java b/src/javax/vecmath/VecMathI18N.java new file mode 100644 index 0000000..d142325 --- /dev/null +++ b/src/javax/vecmath/VecMathI18N.java @@ -0,0 +1,31 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.io.*; +import java.util.*; + + +class VecMathI18N { + static String getString(String key) { + String s; + try { + s = (String) ResourceBundle.getBundle("javax.vecmath.ExceptionStrings").getString(key); + } + catch (MissingResourceException e) { + System.err.println("VecMathI18N: Error looking up: " + key); + s = key; + } + return s; + } +} diff --git a/src/javax/vecmath/Vector2d.java b/src/javax/vecmath/Vector2d.java new file mode 100644 index 0000000..1a5ca68 --- /dev/null +++ b/src/javax/vecmath/Vector2d.java @@ -0,0 +1,168 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 2-element vector that is represented by double-precision floating + * point x,y coordinates. + * + */ +public class Vector2d extends Tuple2d implements java.io.Serializable { + + // Combatible with 1.1 + static final long serialVersionUID = 8572646365302599857L; + + /** + * Constructs and initializes a Vector2d from the specified xy coordinates. + * @param x the x coordinate + * @param y the y coordinate + */ + public Vector2d(double x, double y) + { + super(x,y); + } + + + /** + * Constructs and initializes a Vector2d from the specified array. + * @param v the array of length 2 containing xy in order + */ + public Vector2d(double[] v) + { + super(v); + } + + + /** + * Constructs and initializes a Vector2d from the specified Vector2d. + * @param v1 the Vector2d containing the initialization x y data + */ + public Vector2d(Vector2d v1) + { + super(v1); + } + + + /** + * Constructs and initializes a Vector2d from the specified Vector2f. + * @param v1 the Vector2f containing the initialization x y data + */ + public Vector2d(Vector2f v1) + { + super(v1); + } + + + /** + * Constructs and initializes a Vector2d from the specified Tuple2d. + * @param t1 the Tuple2d containing the initialization x y data + */ + public Vector2d(Tuple2d t1) + { + super(t1); + } + + + /** + * Constructs and initializes a Vector2d from the specified Tuple2f. + * @param t1 the Tuple2f containing the initialization x y data + */ + public Vector2d(Tuple2f t1) + { + super(t1); + } + + + /** + * Constructs and initializes a Vector2d to (0,0). + */ + public Vector2d() + { + super(); + } + + + /** + * Computes the dot product of the this vector and vector v1. + * @param v1 the other vector + */ + public final double dot(Vector2d v1) + { + return (this.x*v1.x + this.y*v1.y); + } + + + /** + * Returns the length of this vector. + * @return the length of this vector + */ + public final double length() + { + return (double) Math.sqrt(this.x*this.x + this.y*this.y); + } + + /** + * Returns the squared length of this vector. + * @return the squared length of this vector + */ + public final double lengthSquared() + { + return (this.x*this.x + this.y*this.y); + } + + /** + * Sets the value of this vector to the normalization of vector v1. + * @param v1 the un-normalized vector + */ + public final void normalize(Vector2d v1) + { + double norm; + + norm = (double) (1.0/Math.sqrt(v1.x*v1.x + v1.y*v1.y)); + this.x = v1.x*norm; + this.y = v1.y*norm; + } + + /** + * Normalizes this vector in place. + */ + public final void normalize() + { + double norm; + + norm = (double) + (1.0/Math.sqrt(this.x*this.x + this.y*this.y)); + this.x *= norm; + this.y *= norm; + } + + + /** + * Returns the angle in radians between this vector and the vector + * parameter; the return value is constrained to the range [0,PI]. + * @param v1 the other vector + * @return the angle in radians in the range [0,PI] + */ + public final double angle(Vector2d v1) + { + double vDot = this.dot(v1) / ( this.length()*v1.length() ); + if( vDot < -1.0) vDot = -1.0; + if( vDot > 1.0) vDot = 1.0; + return((double) (Math.acos( vDot ))); + + } + + +} diff --git a/src/javax/vecmath/Vector2f.java b/src/javax/vecmath/Vector2f.java new file mode 100644 index 0000000..9ee8183 --- /dev/null +++ b/src/javax/vecmath/Vector2f.java @@ -0,0 +1,168 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 2-element vector that is represented by single-precision floating + * point x,y coordinates. + * + */ +public class Vector2f extends Tuple2f implements java.io.Serializable { + + // Combatible with 1.1 + static final long serialVersionUID = -2168194326883512320L; + + /** + * Constructs and initializes a Vector2f from the specified xy coordinates. + * @param x the x coordinate + * @param y the y coordinate + */ + public Vector2f(float x, float y) + { + super(x,y); + } + + + /** + * Constructs and initializes a Vector2f from the specified array. + * @param v the array of length 2 containing xy in order + */ + public Vector2f(float[] v) + { + super(v); + } + + + /** + * Constructs and initializes a Vector2f from the specified Vector2f. + * @param v1 the Vector2f containing the initialization x y data + */ + public Vector2f(Vector2f v1) + { + super(v1); + } + + + /** + * Constructs and initializes a Vector2f from the specified Vector2d. + * @param v1 the Vector2d containing the initialization x y data + */ + public Vector2f(Vector2d v1) + { + super(v1); + } + + + /** + * Constructs and initializes a Vector2f from the specified Tuple2f. + * @param t1 the Tuple2f containing the initialization x y data + */ + public Vector2f(Tuple2f t1) + { + super(t1); + } + + + /** + * Constructs and initializes a Vector2f from the specified Tuple2d. + * @param t1 the Tuple2d containing the initialization x y data + */ + public Vector2f(Tuple2d t1) + { + super(t1); + } + + + + /** + * Constructs and initializes a Vector2f to (0,0). + */ + public Vector2f() + { + super(); + } + + + /** + * Computes the dot product of the this vector and vector v1. + * @param v1 the other vector + */ + public final float dot(Vector2f v1) + { + return (this.x*v1.x + this.y*v1.y); + } + + + /** + * Returns the length of this vector. + * @return the length of this vector + */ + public final float length() + { + return (float) Math.sqrt(this.x*this.x + this.y*this.y); + } + + /** + * Returns the squared length of this vector. + * @return the squared length of this vector + */ + public final float lengthSquared() + { + return (this.x*this.x + this.y*this.y); + } + + /** + * Sets the value of this vector to the normalization of vector v1. + * @param v1 the un-normalized vector + */ + public final void normalize(Vector2f v1) + { + float norm; + + norm = (float) (1.0/Math.sqrt(v1.x*v1.x + v1.y*v1.y)); + this.x = v1.x*norm; + this.y = v1.y*norm; + } + + /** + * Normalizes this vector in place. + */ + public final void normalize() + { + float norm; + + norm = (float) + (1.0/Math.sqrt(this.x*this.x + this.y*this.y)); + this.x *= norm; + this.y *= norm; + } + + + /** + * Returns the angle in radians between this vector and the vector + * parameter; the return value is constrained to the range [0,PI]. + * @param v1 the other vector + * @return the angle in radians in the range [0,PI] + */ + public final float angle(Vector2f v1) + { + double vDot = this.dot(v1) / ( this.length()*v1.length() ); + if( vDot < -1.0) vDot = -1.0; + if( vDot > 1.0) vDot = 1.0; + return((float) (Math.acos( vDot ))); + } + + +} diff --git a/src/javax/vecmath/Vector3d.java b/src/javax/vecmath/Vector3d.java new file mode 100644 index 0000000..79a4dfd --- /dev/null +++ b/src/javax/vecmath/Vector3d.java @@ -0,0 +1,191 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 3-element vector that is represented by double-precision floating point + * x,y,z coordinates. If this value represents a normal, then it should + * be normalized. + * + */ +public class Vector3d extends Tuple3d implements java.io.Serializable { + + // Combatible with 1.1 + static final long serialVersionUID = 3761969948420550442L; + + /** + * Constructs and initializes a Vector3d from the specified xyz coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + */ + public Vector3d(double x, double y, double z) + { + super(x,y,z); + } + + + /** + * Constructs and initializes a Vector3d from the array of length 3. + * @param v the array of length 3 containing xyz in order + */ + public Vector3d(double[] v) + { + super(v); + } + + + /** + * Constructs and initializes a Vector3d from the specified Vector3d. + * @param v1 the Vector3d containing the initialization x y z data + */ + public Vector3d(Vector3d v1) + { + super(v1); + } + + + /** + * Constructs and initializes a Vector3d from the specified Vector3f. + * @param v1 the Vector3f containing the initialization x y z data + */ + public Vector3d(Vector3f v1) + { + super(v1); + } + + + /** + * Constructs and initializes a Vector3d from the specified Tuple3f. + * @param t1 the Tuple3f containing the initialization x y z data + */ + public Vector3d(Tuple3f t1) + { + super(t1); + } + + + /** + * Constructs and initializes a Vector3d from the specified Tuple3d. + * @param t1 the Tuple3d containing the initialization x y z data + */ + public Vector3d(Tuple3d t1) + { + super(t1); + } + + + /** + * Constructs and initializes a Vector3d to (0,0,0). + */ + public Vector3d() + { + super(); + } + + + /** + * Sets this vector to the vector cross product of vectors v1 and v2. + * @param v1 the first vector + * @param v2 the second vector + */ + public final void cross(Vector3d v1, Vector3d v2) + { + double x,y; + + x = v1.y*v2.z - v1.z*v2.y; + y = v2.x*v1.z - v2.z*v1.x; + this.z = v1.x*v2.y - v1.y*v2.x; + this.x = x; + this.y = y; + } + + + /** + * Sets the value of this vector to the normalization of vector v1. + * @param v1 the un-normalized vector + */ + public final void normalize(Vector3d v1) + { + double norm; + + norm = 1.0/Math.sqrt(v1.x*v1.x + v1.y*v1.y + v1.z*v1.z); + this.x = v1.x*norm; + this.y = v1.y*norm; + this.z = v1.z*norm; + } + + + /** + * Normalizes this vector in place. + */ + public final void normalize() + { + double norm; + + norm = 1.0/Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z); + this.x *= norm; + this.y *= norm; + this.z *= norm; + } + + + /** + * Returns the dot product of this vector and vector v1. + * @param v1 the other vector + * @return the dot product of this and v1 + */ + public final double dot(Vector3d v1) + { + return (this.x*v1.x + this.y*v1.y + this.z*v1.z); + } + + + /** + * Returns the squared length of this vector. + * @return the squared length of this vector + */ + public final double lengthSquared() + { + return (this.x*this.x + this.y*this.y + this.z*this.z); + } + + + /** + * Returns the length of this vector. + * @return the length of this vector + */ + public final double length() + { + return Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z); + } + + + /** + * Returns the angle in radians between this vector and the vector + * parameter; the return value is constrained to the range [0,PI]. + * @param v1 the other vector + * @return the angle in radians in the range [0,PI] + */ + public final double angle(Vector3d v1) + { + double vDot = this.dot(v1) / ( this.length()*v1.length() ); + if( vDot < -1.0) vDot = -1.0; + if( vDot > 1.0) vDot = 1.0; + return((double) (Math.acos( vDot ))); + } + + +} diff --git a/src/javax/vecmath/Vector3f.java b/src/javax/vecmath/Vector3f.java new file mode 100644 index 0000000..1b9a4fd --- /dev/null +++ b/src/javax/vecmath/Vector3f.java @@ -0,0 +1,186 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 3-element vector that is represented by single-precision floating point + * x,y,z coordinates. If this value represents a normal, then it should + * be normalized. + * + */ +public class Vector3f extends Tuple3f implements java.io.Serializable { + + // Combatible with 1.1 + static final long serialVersionUID = -7031930069184524614L; + + /** + * Constructs and initializes a Vector3f from the specified xyz coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + */ + public Vector3f(float x, float y, float z) + { + super(x,y,z); + } + + + /** + * Constructs and initializes a Vector3f from the array of length 3. + * @param v the array of length 3 containing xyz in order + */ + public Vector3f(float[] v) + { + super(v); + } + + + /** + * Constructs and initializes a Vector3f from the specified Vector3f. + * @param v1 the Vector3f containing the initialization x y z data + */ + public Vector3f(Vector3f v1) + { + super(v1); + } + + + /** + * Constructs and initializes a Vector3f from the specified Vector3d. + * @param v1 the Vector3d containing the initialization x y z data + */ + public Vector3f(Vector3d v1) + { + super(v1); + } + + + /** + * Constructs and initializes a Vector3f from the specified Tuple3f. + * @param t1 the Tuple3f containing the initialization x y z data + */ + public Vector3f(Tuple3f t1) { + super(t1); + } + + + /** + * Constructs and initializes a Vector3f from the specified Tuple3d. + * @param t1 the Tuple3d containing the initialization x y z data + */ + public Vector3f(Tuple3d t1) { + super(t1); + } + + + /** + * Constructs and initializes a Vector3f to (0,0,0). + */ + public Vector3f() + { + super(); + } + + + /** + * Returns the squared length of this vector. + * @return the squared length of this vector + */ + public final float lengthSquared() + { + return (this.x*this.x + this.y*this.y + this.z*this.z); + } + + /** + * Returns the length of this vector. + * @return the length of this vector + */ + public final float length() + { + return (float) + Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z); + } + + + /** + * Sets this vector to be the vector cross product of vectors v1 and v2. + * @param v1 the first vector + * @param v2 the second vector + */ + public final void cross(Vector3f v1, Vector3f v2) + { + float x,y; + + x = v1.y*v2.z - v1.z*v2.y; + y = v2.x*v1.z - v2.z*v1.x; + this.z = v1.x*v2.y - v1.y*v2.x; + this.x = x; + this.y = y; + } + + /** + * Computes the dot product of this vector and vector v1. + * @param v1 the other vector + * @return the dot product of this vector and v1 + */ + public final float dot(Vector3f v1) + { + return (this.x*v1.x + this.y*v1.y + this.z*v1.z); + } + + /** + * Sets the value of this vector to the normalization of vector v1. + * @param v1 the un-normalized vector + */ + public final void normalize(Vector3f v1) + { + float norm; + + norm = (float) (1.0/Math.sqrt(v1.x*v1.x + v1.y*v1.y + v1.z*v1.z)); + this.x = v1.x*norm; + this.y = v1.y*norm; + this.z = v1.z*norm; + } + + /** + * Normalizes this vector in place. + */ + public final void normalize() + { + float norm; + + norm = (float) + (1.0/Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z)); + this.x *= norm; + this.y *= norm; + this.z *= norm; + } + + + /** + * Returns the angle in radians between this vector and the vector + * parameter; the return value is constrained to the range [0,PI]. + * @param v1 the other vector + * @return the angle in radians in the range [0,PI] + */ + public final float angle(Vector3f v1) + { + double vDot = this.dot(v1) / ( this.length()*v1.length() ); + if( vDot < -1.0) vDot = -1.0; + if( vDot > 1.0) vDot = 1.0; + return((float) (Math.acos( vDot ))); + } + +} diff --git a/src/javax/vecmath/Vector4d.java b/src/javax/vecmath/Vector4d.java new file mode 100644 index 0000000..e56997d --- /dev/null +++ b/src/javax/vecmath/Vector4d.java @@ -0,0 +1,205 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 4-element vector represented by double-precision floating point + * x,y,z,w coordinates. + * + */ +public class Vector4d extends Tuple4d implements java.io.Serializable { + + // Compatible with 1.1 + static final long serialVersionUID = 3938123424117448700L; + + /** + * Constructs and initializes a Vector4d from the specified xyzw coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param w the w coordinate + */ + public Vector4d(double x, double y, double z, double w) + { + super(x,y,z,w); + } + + /** + * Constructs and initializes a Vector4d from the coordinates contained + * in the array. + * @param v the array of length 4 containing xyzw in order + */ + public Vector4d(double[] v) + { + super(v); + } + + /** + * Constructs and initializes a Vector4d from the specified Vector4d. + * @param v1 the Vector4d containing the initialization x y z w data + */ + public Vector4d(Vector4d v1) + { + super(v1); + } + + /** + * Constructs and initializes a Vector4d from the specified Vector4f. + * @param v1 the Vector4f containing the initialization x y z w data + */ + public Vector4d(Vector4f v1) + { + super(v1); + } + + /** + * Constructs and initializes a Vector4d from the specified Tuple4f. + * @param t1 the Tuple4f containing the initialization x y z w data + */ + public Vector4d(Tuple4f t1) + { + super(t1); + } + + /** + * Constructs and initializes a Vector4d from the specified Tuple4d. + * @param t1 the Tuple4d containing the initialization x y z w data + */ + public Vector4d(Tuple4d t1) + { + super(t1); + } + + + /** + * Constructs and initializes a Vector4d from the specified Tuple3d. + * The x,y,z components of this vector are set to the corresponding + * components of tuple t1. The w component of this vector + * is set to 0. + * @param t1 the tuple to be copied + * + * @since Java 3D 1.2 + */ + public Vector4d(Tuple3d t1) { + super(t1.x, t1.y, t1.z, 0.0); + } + + + /** + * Constructs and initializes a Vector4d to (0,0,0,0). + */ + public Vector4d() + { + super(); + } + + + /** + * Sets the x,y,z components of this vector to the corresponding + * components of tuple t1. The w component of this vector + * is set to 0. + * @param t1 the tuple to be copied + * + * @since Java 3D 1.2 + */ + public final void set(Tuple3d t1) { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + this.w = 0.0; + } + + + /** + * Returns the length of this vector. + * @return the length of this vector + */ + public final double length() + { + return Math.sqrt(this.x*this.x + this.y*this.y + + this.z*this.z + this.w*this.w); + } + + + /** + * Returns the squared length of this vector. + * @return the squared length of this vector + */ + public final double lengthSquared() + { + return (this.x*this.x + this.y*this.y + + this.z*this.z + this.w*this.w); + } + + + /** + * Returns the dot product of this vector and vector v1. + * @param v1 the other vector + * @return the dot product of this vector and vector v1 + */ + public final double dot(Vector4d v1) + { + return (this.x*v1.x + this.y*v1.y + this.z*v1.z + this.w*v1.w); + } + + + /** + * Sets the value of this vector to the normalization of vector v1. + * @param v1 the un-normalized vector + */ + public final void normalize(Vector4d v1) + { + double norm; + + norm = 1.0/Math.sqrt(v1.x*v1.x + v1.y*v1.y + v1.z*v1.z + v1.w*v1.w); + this.x = v1.x*norm; + this.y = v1.y*norm; + this.z = v1.z*norm; + this.w = v1.w*norm; + } + + + /** + * Normalizes this vector in place. + */ + public final void normalize() + { + double norm; + + norm = 1.0/Math.sqrt(this.x*this.x + this.y*this.y + + this.z*this.z + this.w*this.w); + this.x *= norm; + this.y *= norm; + this.z *= norm; + this.w *= norm; + } + + + /** + * Returns the (4-space) angle in radians between this vector and + * the vector parameter; the return value is constrained to the + * range [0,PI]. + * @param v1 the other vector + * @return the angle in radians in the range [0,PI] + */ + public final double angle(Vector4d v1) + { + double vDot = this.dot(v1) / ( this.length()*v1.length() ); + if( vDot < -1.0) vDot = -1.0; + if( vDot > 1.0) vDot = 1.0; + return((double) (Math.acos( vDot ))); + } + +} diff --git a/src/javax/vecmath/Vector4f.java b/src/javax/vecmath/Vector4f.java new file mode 100644 index 0000000..9ff885e --- /dev/null +++ b/src/javax/vecmath/Vector4f.java @@ -0,0 +1,209 @@ +/* + * $RCSfile$ + * + * Copyright (c) 2004 Sun Microsystems, Inc. All rights reserved. + * + * Use is subject to license terms. + * + * $Revision$ + * $Date$ + * $State$ + */ + +package javax.vecmath; + +import java.lang.Math; + +/** + * A 4-element vector represented by single-precision floating point x,y,z,w + * coordinates. + * + */ +public class Vector4f extends Tuple4f implements java.io.Serializable { + + // Compatible with 1.1 + static final long serialVersionUID = 8749319902347760659L; + + /** + * Constructs and initializes a Vector4f from the specified xyzw coordinates. + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param w the w coordinate + */ + public Vector4f(float x, float y, float z, float w) + { + super(x,y,z,w); + } + + + /** + * Constructs and initializes a Vector4f from the array of length 4. + * @param v the array of length 4 containing xyzw in order + */ + public Vector4f(float[] v) + { + super(v); + } + + + /** + * Constructs and initializes a Vector4f from the specified Vector4f. + * @param v1 the Vector4f containing the initialization x y z w data + */ + public Vector4f(Vector4f v1) + { + super(v1); + } + + + /** + * Constructs and initializes a Vector4f from the specified Vector4d. + * @param v1 the Vector4d containing the initialization x y z w data + */ + public Vector4f(Vector4d v1) + { + super(v1); + } + + + /** + * Constructs and initializes a Vector4f from the specified Tuple4f. + * @param t1 the Tuple4f containing the initialization x y z w data + */ + public Vector4f(Tuple4f t1) + { + super(t1); + } + + + /** + * Constructs and initializes a Vector4f from the specified Tuple4d. + * @param t1 the Tuple4d containing the initialization x y z w data + */ + public Vector4f(Tuple4d t1) + { + super(t1); + } + + + /** + * Constructs and initializes a Vector4f from the specified Tuple3f. + * The x,y,z components of this vector are set to the corresponding + * components of tuple t1. The w component of this vector + * is set to 0. + * @param t1 the tuple to be copied + * + * @since Java 3D 1.2 + */ + public Vector4f(Tuple3f t1) { + super(t1.x, t1.y, t1.z, 0.0f); + } + + + /** + * Constructs and initializes a Vector4f to (0,0,0,0). + */ + public Vector4f() + { + super(); + } + + + /** + * Sets the x,y,z components of this vector to the corresponding + * components of tuple t1. The w component of this vector + * is set to 0. + * @param t1 the tuple to be copied + * + * @since Java 3D 1.2 + */ + public final void set(Tuple3f t1) { + this.x = t1.x; + this.y = t1.y; + this.z = t1.z; + this.w = 0.0f; + } + + + /** + * Returns the length of this vector. + * @return the length of this vector as a float + */ + public final float length() + { + return + (float) Math.sqrt(this.x*this.x + this.y*this.y + + this.z*this.z + this.w*this.w); + } + + /** + * Returns the squared length of this vector + * @return the squared length of this vector as a float + */ + public final float lengthSquared() + { + return (this.x*this.x + this.y*this.y + + this.z*this.z + this.w*this.w); + } + + /** + * returns the dot product of this vector and v1 + * @param v1 the other vector + * @return the dot product of this vector and v1 + */ + public final float dot(Vector4f v1) + { + return (this.x*v1.x + this.y*v1.y + this.z*v1.z + this.w*v1.w); + } + + + /** + * Sets the value of this vector to the normalization of vector v1. + * @param v1 the un-normalized vector + */ + public final void normalize(Vector4f v1) + { + float norm; + + norm = (float) (1.0/Math.sqrt(v1.x*v1.x + v1.y*v1.y + + v1.z*v1.z + v1.w*v1.w)); + this.x = v1.x*norm; + this.y = v1.y*norm; + this.z = v1.z*norm; + this.w = v1.w*norm; + } + + + /** + * Normalizes this vector in place. + */ + public final void normalize() + { + float norm; + + norm = (float) (1.0/Math.sqrt(this.x*this.x + this.y*this.y + + this.z*this.z + this.w*this.w)); + this.x *= norm; + this.y *= norm; + this.z *= norm; + this.w *= norm; + } + + + /** + * Returns the (4-space) angle in radians between this vector and + * the vector parameter; the return value is constrained to the + * range [0,PI]. + * @param v1 the other vector + * @return the angle in radians in the range [0,PI] + */ + public final float angle(Vector4f v1) + { + double vDot = this.dot(v1) / ( this.length()*v1.length() ); + if( vDot < -1.0) vDot = -1.0; + if( vDot > 1.0) vDot = 1.0; + return((float) (Math.acos( vDot ))); + } + +} |