<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">/*
 * pMatrix.java		v0.01	May 16th, 1998
 *
 * A general purpose (rotation and translation) matrix.
 * (05/16/1998,05/17/1998,4/2005)
 *
 * Copyright(c) 1998, Alex S, Particle
 */

import java.lang.String;
import java.util.Vector;

/**
 * pMatrix class, to handle all the matrix thingies.
 * the class represents a 4x4 matrix, with some 
 * useful operations defined on it.
 *
 * Note: This thing is Right Handed!; just like OpenGL :-)
 */
public class pMatrix {

    /**
     * the matrix stored as 2D array.
     */
    protected double[] matrix;

    /**
     * the stack to hold working matrices.
     */
    protected static Vector stack;

    /**
     * get the stack going...
     */
    static{
        stack = new Vector();
    }

    /**
     * default constructor, initializes the matrix, 
     * and makes sure it's an "intentity" matrix.
     */
    public pMatrix(){
        matrix = new double[16];
        ident();
    }

    /**
     * create a matrix from a 16 element array
     */
    public pMatrix(double[] m){
        matrix = new double[16];
        System.arraycopy(m,0,matrix, 0, 16);
    }

    /**
     * a copy constructor.
     *
     * @param m The matrix to copy.
     */
    public pMatrix(pMatrix m){
        matrix = new double[16];
        System.arraycopy(m.matrix, 0, matrix, 0, 16);
    }

    /**
     * pushes the current matrix onto the stack, 
     * (the current matrix is still there though)
     */
    public void push(){
        pMatrix tmp = new pMatrix(this);
        stack.addElement(tmp.matrix);
    }

    /**
     * pops the last pushed matrix from the stack,
     * and makes it current. (the previous one is 
     * erased)
     * &lt;p&gt;
     * NOTE: no error checking is performed, you WILL
     * get a NoSuchElementException if you're not careful
     * and try to pop an empty stack.
     *
     * @return The freshly poped matrix.
     */
    public pMatrix pop(){
        matrix = (double[])stack.lastElement();
        stack.removeElement(matrix);
        return this;
    }

    /**
     * makes this matrix into an identity matrix.
     * (current info of the matrix is erased)
     *
     * @return Current identity matrix.
     */
    public pMatrix ident(){
        for (int i=0;i&lt;4;i++)
            for (int j=0;j&lt;4;j++)
                matrix[(i&lt;&lt;2)+j] = i == j ? 1:0;
        return this;
    }

    /**
     * add another matrix to this one.
     * (changes current matrix)
     *
     * @param m The matrix to add.
     * @return The current changed matrix.
     */
    public pMatrix add(pMatrix m){
        for (int i=0;i&lt;16;i++)
            matrix[i] += m.matrix[i];
        return this;
    }

    /**
     * subtract a matrix from this one
     * (changes the current matrix)
     *
     * @param m The matrix to subtract.
     * @return The current changed matrix.
     */
    public pMatrix sub(pMatrix m){
        for (int i=0;i&lt;16;i++)
            matrix[i] -= m.matrix[i];    
        return this;
    }

    /**
     * get function to the rest of the world.
     *
     * @param i The column.
     * @param j The row.
     * @return The location of that row and column.
     */
    public double get(int i,int j){
        return matrix[(i&lt;&lt;2)+j];
    }

    /**
     * set function for the rest of the world.
     *
     * @param i The column.
     * @param j The row.
     * @param v The value of the new location.
     */
    public void set(int i,int j,double v){
        matrix[(i&lt;&lt;2)+j] = v;
    }

    /**
     * function to multiply this matrix by another.
     * (the result is a cross multiply of this matrix
     * by the parameter matrix.)
     * (current matrix changes!)
     *
     * @param m The matrix to multiply by.
     * @return The current changed matrix.
     */
    public pMatrix mult(pMatrix m){
        pMatrix tmp = new pMatrix(this);
        for (int i=0;i&lt;4;i++)
            for (int j=0;j&lt;4;j++) {
                matrix[(i&lt;&lt;2)+j] = 0;
                for (int k=0;k&lt;4;k++)
                    matrix[(i&lt;&lt;2)+j] += tmp.matrix[(i&lt;&lt;2)+k] * m.matrix[(k&lt;&lt;2)+j];
            }
        return this;
    }

    /**
     * function to transform a vector, 
     * (a vector consists of a 4 element array of doubles,
     * the last element of the array is reserved)
     * 
     * @param v The vector to transform.
     * @return The transformed vector.
     */
    public double[] mult(double[] v){
        double[] tmp = new double[4];
        int i;
        for (i=0;i&lt;4;i++)
            tmp[i] = v[i];
        for (i=0;i&lt;4;i++) {
            v[i] = 0;
            for (int j=0;j&lt;4;j++)
                v[i] += matrix[(i&lt;&lt;2)+j] * tmp[j];
        }
        return v;
    }

    /**
     * function to transform an array of vectors...
     *
     * @param a The array of arrays of vectors.
     * @return The transformed array...
     */
    public double[][] mult(double[][] a){
        for (int i=0;i&lt;a.length;i++)
            mult(a[i]);
        return a;
    }

    /**
     * rotate this matrix around the X axis.
     * (chances current matrix)
     * Note: change sin term signs to change handedness.
     *
     * @param a The angle to rotate by.
     * @return The new rotated matrix.
     */
    public pMatrix rotatex(double a){
        pMatrix tmp = new pMatrix();
        double cos = (double)Math.cos(a);
        double sin = (double)Math.sin(a);
        tmp.matrix[(1&lt;&lt;2)+1] = cos;
        tmp.matrix[(1&lt;&lt;2)+2] = sin;
        tmp.matrix[(2&lt;&lt;2)+1] = -sin;
        tmp.matrix[(2&lt;&lt;2)+2] = cos;
        return mult(tmp);
    }

    /**
     * rotate this matrix around the Y axis.
     * (chances current matrix)
     *
     * @param a The angle to rotate by.
     * @return The new rotated matrix.
     */
    public pMatrix rotatey(double a){
        pMatrix tmp = new pMatrix();
        double cos = (double)Math.cos(a);
        double sin = (double)Math.sin(a);
        tmp.matrix[(0&lt;&lt;2)+0] = cos;
        tmp.matrix[(0&lt;&lt;2)+2] = sin;
        tmp.matrix[(2&lt;&lt;2)+0] = -sin;
        tmp.matrix[(2&lt;&lt;2)+2] = cos;
        return mult(tmp);
    }

    /**
     * rotate this matrix around the Z axis.
     * (chances current matrix)
     *
     * @param a The angle to rotate by.
     * @return The new rotated matrix.
     */
    public pMatrix rotatez(double a){
        pMatrix tmp = new pMatrix();
        double cos = (double)Math.cos(a);
        double sin = (double)Math.sin(a);
        tmp.matrix[(0&lt;&lt;2)+0] = cos;
        tmp.matrix[(0&lt;&lt;2)+1] = -sin;
        tmp.matrix[(1&lt;&lt;2)+0] = sin;
        tmp.matrix[(1&lt;&lt;2)+1] = cos;
        return mult(tmp);
    }

    /**
     * translate the current matrix by that amount.
     * (changes the current matrix)
     *
     * @param x The x value to translate.
     * @param y The y value to translate.
     * @param z The z value to translate.
     * @return The translated matrix.
     */
    public pMatrix translate(double x,double y,double z){
        pMatrix tmp = new pMatrix();
        tmp.matrix[(0&lt;&lt;2)+3] = x;
        tmp.matrix[(1&lt;&lt;2)+3] = y;
        tmp.matrix[(2&lt;&lt;2)+3] = z;
        return mult(tmp);
    }

    /**
     * translate the current matrix by a 4 element vector.
     * (changes the current matrix)
     *
     * @param v The 4 element vector to translate by.
     * @return The translated matrix.
     */
    public pMatrix translate(double[] v){
        pMatrix tmp = new pMatrix();
        tmp.matrix[(0&lt;&lt;2)+3] = v[0];
        tmp.matrix[(1&lt;&lt;2)+3] = v[1];
        tmp.matrix[(2&lt;&lt;2)+3] = v[2];
        return mult(tmp);
    }

    /**
     * scales the matrix.
     * (changes the current matrix)
     *
     * @param s The scale to apply.
     * @return The scaled matrix.
     */
    public pMatrix scale(double s){
        pMatrix tmp = new pMatrix();
        tmp.matrix[(0&lt;&lt;2)+0] = s;
        tmp.matrix[(1&lt;&lt;2)+1] = s;
        tmp.matrix[(2&lt;&lt;2)+2] = s;
        return mult(tmp);
    }


    /**
     * scales the matrix.
     * (changes the current matrix)
     *
     * @param s The scale to apply.
     * @return The scaled matrix.
     */
    public pMatrix scale(double x,double y,double z){
        pMatrix tmp = new pMatrix();
        tmp.matrix[(0&lt;&lt;2)+0] = x;
        tmp.matrix[(1&lt;&lt;2)+1] = y;
        tmp.matrix[(2&lt;&lt;2)+2] = z;
        return mult(tmp);
    }


    /**
     * scales a matrix in relation to a point
     * (changes the curernt matrix)
     *
     * @param s The scale.
     * @param v The center of point where to scale.
     * @return The scaled matrrix.
     */
    public pMatrix scale(double s,double[] v){
        pMatrix tmp = new pMatrix();
        tmp.matrix[(0&lt;&lt;2)+0] = s;
        tmp.matrix[(0&lt;&lt;2)+3] = (1 - s) * v[0];
        tmp.matrix[(1&lt;&lt;2)+1] = s;
        tmp.matrix[(1&lt;&lt;2)+3] = (1 - s) * v[1];
        tmp.matrix[(2&lt;&lt;2)+2] = s;
        tmp.matrix[(2&lt;&lt;2)+3] = (1 - s) * v[2];
        return mult(tmp);
    }

    /**
     * scales a matrix in relation to a point
     * (changes the curernt matrix)
     *
     * @param s The scales (one for each coord).
     * @param v The center of point where to scale.
     * @return The scaled matrrix.
     */
    public pMatrix scale(double[] s,double[] v){
        pMatrix tmp = new pMatrix();
        tmp.matrix[(0&lt;&lt;2)+0] = s[0];
        tmp.matrix[(0&lt;&lt;2)+3] = (1 - s[0]) * v[0];
        tmp.matrix[(1&lt;&lt;2)+1] = s[1];
        tmp.matrix[(1&lt;&lt;2)+3] = (1 - s[1]) * v[1];
        tmp.matrix[(2&lt;&lt;2)+2] = s[2];
        tmp.matrix[(2&lt;&lt;2)+3] = (1 - s[2]) * v[2];
        return mult(tmp);
    }

    /**
     * reflect in the X axis.
     *
     * @return The refelected matrix.
     */
    public pMatrix reflectx(){
        pMatrix tmp = new pMatrix();
        tmp.matrix[(0&lt;&lt;2)+0] = -tmp.matrix[(0&lt;&lt;2)+0];
        return mult(tmp);
    }

    /**
     * reflect in the Y axis.
     *
     * @return The refelected matrix.
     */
    public pMatrix reflecty(){
        pMatrix tmp = new pMatrix();
        tmp.matrix[(1&lt;&lt;2)+1] = -tmp.matrix[(1&lt;&lt;2)+1];
        return mult(tmp);
    }

    /**
     * reflect in the Z axis.
     *
     * also known as conversion from right handled
     * to left handled coord system, or vice versa.
     *
     * @return The refelected matrix.
     */
    public pMatrix reflectz(){
        pMatrix tmp = new pMatrix();
        tmp.matrix[(2&lt;&lt;2)+2] = -tmp.matrix[(2&lt;&lt;2)+2];
        return mult(tmp);
    }


    /** 
     * create perspective matrix; turns current matrix into 
     * perspective matrix.
     *
     * @param zrpr at what z is the eye?
     * @param zvp at what z is the view plane?
     */
    public pMatrix perspective(double zprp,double zvp){
        double t2,t3;
        double d1 = zprp - zvp;
        double a = -zvp/d1;
        double b = -1/d1;
        double c = zvp*(zprp/d1);
        double d = zvp/d1;
        for (int i=0;i&lt;4;i++) {
            t2 = matrix[(i&lt;&lt;2)+2];
            t3 = matrix[(i&lt;&lt;2)+3];
            matrix[(i&lt;&lt;2)+2] = t2*a + t3*b;
            matrix[(i&lt;&lt;2)+3] = t2*c + t3*d;
        }
        return this;
    }

    /**
     * standard toString method to allow for 
     * conherent printing of this object.
     *
     * @return The String object representing this matrix.
     */
    public String toString(){
        String s = new String("pMatrix:\n");
        for (int i=0;i&lt;4;i++) {
            for (int j=0;j&lt;4;j++) {
                s += matrix[(i&lt;&lt;2)+j]+", ";
            }
            s += "\n";
        }
        return s;
    }

    /**
     * returns the inverse of the current matrix
     */
    public pMatrix inverse(){
        pMatrix n = new pMatrix();
        if(m4_inverse(n.matrix,matrix)){
            return n;
        }
        return new pMatrix();
    }


    /**
     * various matrix operations (inverse). taken from:
     * http://skal.planet-d.net/demo/matrixfaq.htm
     */

    /**
     * compute determinant of a 3x3 matrix
     */
    private static double m3_det(double[] mat){
        double det;
        det = mat[0] * ( mat[4]*mat[8] - mat[7]*mat[5] )
                - mat[1] * ( mat[3]*mat[8] - mat[6]*mat[5] )
                + mat[2] * ( mat[3]*mat[7] - mat[6]*mat[4] );
        return det;
    }

    private static boolean m3_inverse(double[] mr,double[] ma){
        double det = m3_det( ma );
        if ( Math.abs( det ) &lt; (double)0.0005 ) {            
            //m3_identity( mr );
            return false;
        }
        mr[0] =    ma[4]*ma[8] - ma[5]*ma[7]   / det;
        mr[1] = -( ma[1]*ma[8] - ma[7]*ma[2] ) / det;
        mr[2] =    ma[1]*ma[5] - ma[4]*ma[2]   / det;
        mr[3] = -( ma[3]*ma[8] - ma[5]*ma[6] ) / det;
        mr[4] =    ma[0]*ma[8] - ma[6]*ma[2]   / det;
        mr[5] = -( ma[0]*ma[5] - ma[3]*ma[2] ) / det;
        mr[6] =    ma[3]*ma[7] - ma[6]*ma[4]   / det;
        mr[7] = -( ma[0]*ma[7] - ma[6]*ma[1] ) / det;
        mr[8] =    ma[0]*ma[4] - ma[1]*ma[3]   / det;
        return true;
    }

    /**
     * mr is 4x4, mb is 3x4
     */
    private static void m4_submat(double[] mr,double[] mb, int i, int j ) {
        int di, dj, si, sj;
        // loop through 3x3 submatrix
        for( di = 0; di &lt; 3; di ++ ) {
            for( dj = 0; dj &lt; 3; dj ++ ) {
                // map 3x3 element (destination) to 4x4 element (source)
                si = di + ( ( di &gt;= i ) ? 1 : 0 );
                sj = dj + ( ( dj &gt;= j ) ? 1 : 0 );
                // copy element
                mb[di * 3 + dj] = mr[si * 4 + sj];
            }
        }
    }

    private static double m4_det(double[] mr) {
        double det, result = 0, i = 1;
        double[] msub3 = new double[3*3];
        int     n;
        for ( n = 0; n &lt; 4; n++, i *= -1 ){
            m4_submat( mr, msub3, 0, n );
            det     = m3_det( msub3 );
            result += mr[n] * det * i;
        }
        return result;
    }

    private static boolean m4_inverse(double[] mr, double[] ma ){
        double mdet = m4_det( ma );
        double[] mtemp = new double[3*3];
        int     i, j, sign;
        if (Math.abs( mdet ) &lt; (double)0.0005 ){
            // m4_identity( mr );
            return false;
        }
        for ( i = 0; i &lt; 4; i++ )
            for ( j = 0; j &lt; 4; j++ ){
                sign = 1 - ( (i +j) % 2 ) * 2;
                m4_submat( ma, mtemp, i, j );
                mr[i+j*4] = ( m3_det( mtemp ) * sign ) / mdet;
            }
        return true;
    }

}


</pre></body></html>