import java.text.DecimalFormat;

/**
 * Matrix transforms and composites for  homogeneous coords points in 3D.
 *<p>
 * For CSU540 Computer Graphics class, Spring 2005
 * CCIS, Northeastern University
 *<p>
 * Consists of a single 4x4 double matrix, mat, and various static methods.
 *<br>
 * Method names ending with "Same" alter the matrix argument.
 * Others return a copy.
 * @author Bob Futrelle
 * @version 26 January 2005
 */

public class Mat  {

    /**
     * The only (non-static) field, a 4x4 array.
     */
    public double[][] mat;
    
    /**
     * Tests and prints results of all methods (all are static)
     */
     public static void main(String[] args) {
	 Mat mat1 = new Mat();
	 System.out.println("Unit matrix is: " + mat1);
	 Mat trans = Mat.transMat(1.0, 2.0, 3.0); // could omit "Mat." in this context
	 System.out.println("Translation matrix: " + trans);
	 Vec vec = new Vec();
	 vec.vec[0] = 5.0;
	 vec.vec[1] = 5.0;
	 vec.vec[2] = 5.0;
	 System.out.println("Vector to be translated is: " + vec);
	 Vec translated = Mat.matrixXvector(trans, vec);
	 System.out.println("Translated vec is: " + translated);
	 Mat trans2 = Mat.transMat(7.0, 11.0, 15.0); // could omit "Mat." in this context
	 System.out.println("Second translation matrix: " + trans2);
	 Mat transProduct = Mat.matrixXmatrix(trans,trans2);
	 System.out.println("Product of two translations, should be additive:" + transProduct);	 
    }


    /**
     * Lists all 16  elements of the matrix.
     */
    public String toString(){
	String str = "";
	// there's no way to format with aligned leading blanks  :-(
	DecimalFormat nnnn = new DecimalFormat( "0.0000");
	// outer loop over rows
	for (int j=0; j < 4; j++)
	    {str += "\n| ";	
	    // inner loop over columns
	    for(int k=0; k < 4; k++)
		str += " " + nnnn.format(mat[j][k]) + " ";
	    str += "|";
	    }
	return str;
    } // toString() for Mat

    /**
     * Creates unit matrix with homogeneous 4th row, column elements
     */
    public Mat () {
      	mat = new double[][] 
	    {{1.0,0.0,0.0,0.0},
	     {0.0,1.0,0.0,0.0},
	     {0.0,0.0,1.0,0.0},
	     {0.0,0.0,0.0,1.0}};
    }
    /**
     * Creates an empty matrix with 1.0 in 3,3 lower corner
     */
    public static Mat emptyMat() {
      	Mat emptyMat = new Mat();
	for(int diag=0; diag < 3; diag++) // zero  out diagonals of unit matrix
	    emptyMat.mat[diag][diag] = 0.0;
	return emptyMat;
    }

    /**
     * Creates a translation matrix with displacements tx, ty, tz.
     */
    public static Mat transMat(double tx, double ty, double tz) {
      	Mat trans = new Mat();
	trans.mat[0][3] = tx;
	trans.mat[1][3] = ty;
	trans.mat[2][3] = tz;
	return trans;
      }

    /**
     * Creates a rotation matrix around x axis.
     * TO BE COMPLETED
     */
    public static Mat rotxMat(double theta) {
      	Mat rotX = new Mat();
	// TO BE COMPLETED
		return rotX;
      }

    /**
     * Creates a rotation matrix around y axis.
     * TO BE COMPLETED
     */
    public static Mat rotyMat(double theta) {
      	Mat rotY = new Mat();
	// TO BE COMPLETED
		return rotY;
      }

    /**
     * Creates a rotation matrix around z axis.
     * TO BE COMPLETED
     */
    public static Mat rotzMat(double theta) {
      	Mat rotZ = new Mat();
	// TO BE COMPLETED
		return rotZ;
      }

    /**
     * Creates a scaling matrix.
     * TO BE COMPLETED
     */
    public static Mat scaleMat(double s1, double s2, double s3) {
      	Mat scaleMat = new Mat();
	// TO BE COMPLETED
		return scaleMat;
      }
      
    /**
     * Matrix x vector ==> vector
     * @return The resulting vector
     */
    public static Vec matrixXvector(Mat mat, Vec v){
	Vec vecResult = new Vec();
	for(int m  = 0 ; m  < 3; m++) // 4th element will remain 1.0
	    for(int n=0; n < 4; n++)
		vecResult.vec[m] += mat.mat[m][n]*v.vec[n];
	return vecResult;
    }

    /**
     * Matrix product
     * @return The product of the two matrices
     */
    public static Mat matrixXmatrix(Mat m1, Mat m2){
	Mat matResult =  Mat.emptyMat();
	for(int row  = 0 ; row  < 3; row++) // last row will not change
	    for(int col=0; col < 4; col++)
		for(int tmp=0; tmp < 4;tmp++)
		    matResult.mat[row][col] += m1.mat[row][tmp]*m2.mat[tmp][col];
	return matResult;
    }

} // end class Mat

