
package Graphics;
import java.lang.*;


public class Matrix
{
  private double elm[];

  
  
  public Matrix()
  {
    elm = new double[16];
    identity();
  }  // constructor, creates identity matrix



  public Matrix(Matrix src)
  {
    elm = new double[16];
    set(src);
  }  // copy constructor
  
  

  public void set(Matrix src)
  {
    for(int i=0; i<16; i++)
      elm[i] = src.elm[i];
  }  // set, Matrix source



  public void set(Vector a, Vector b, Vector c)
  {
    elm[0] = a.elm[0];
    elm[1] = a.elm[1];
    elm[2] = a.elm[2];
    elm[3] = 0;
    elm[4] = b.elm[0];
    elm[5] = b.elm[1];
    elm[6] = b.elm[2];
    elm[7] = 0;
    elm[8] = c.elm[0];
    elm[9] = c.elm[1];
    elm[10] = c.elm[2];
    elm[11] = 0;
    elm[12] = 0;
    elm[13] = 0;
    elm[14] = 0;
    elm[15] = 1;
  }  // set, with three vectors
  


  public void set(int index, double value)
  {
    elm[index] = value;
  }  // set an element
  

  
  public double get(int index)
  {
    return elm[index];
  }  // get an element


  
  public void print()
  {
    for(int i=0; i<4; i++)
    {
      System.out.print("(");
      for(int j=0; j<4; j++)
      {
        System.out.print(elm[i*4+j]);
        if (j<3) System.out.print(", ");
      }
      System.out.println(")");
    }  // for, each row
  }  // print
  
  
      
  public void identity()
  {
    for(int i=0; i<16; i++) elm[i] = 0;
    elm[0] = 1;
    elm[5] = 1;
    elm[10] = 1;
    elm[15] = 1;
  }  // identity
  
  
  
  public Vector vec_premultiply(Vector V)
  {
    Vector result =
      new Vector(V.elm[0] * this.elm[0] +
                 V.elm[1] * this.elm[4] +
                 V.elm[2] * this.elm[8] +
                 V.elm[3] * this.elm[12],
                 V.elm[0] * this.elm[1] +
                 V.elm[1] * this.elm[5] +
                 V.elm[2] * this.elm[9] +
                 V.elm[3] * this.elm[13],
                 V.elm[0] * this.elm[2] +
                 V.elm[1] * this.elm[6] +
                 V.elm[2] * this.elm[10] +
                 V.elm[3] * this.elm[14],
                 V.elm[0] * this.elm[3] +
                 V.elm[1] * this.elm[7] +
                 V.elm[2] * this.elm[11] +
                 V.elm[3] * this.elm[15]);
    return result;
  }  // vec_premultiply
  
    
    
  public Vector vec_postmultiply(Vector V)
  {
    Vector result =
      new Vector(V.elm[0] * this.elm[0] +
                 V.elm[1] * this.elm[1] +
                 V.elm[2] * this.elm[2] +
                 V.elm[3] * this.elm[3],
                 V.elm[0] * this.elm[4] +
                 V.elm[1] * this.elm[5] +
                 V.elm[2] * this.elm[6] +
                 V.elm[3] * this.elm[7],
                 V.elm[0] * this.elm[8] +
                 V.elm[1] * this.elm[9] +
                 V.elm[2] * this.elm[10] +
                 V.elm[3] * this.elm[11],
                 V.elm[0] * this.elm[12] +
                 V.elm[1] * this.elm[13] +
                 V.elm[2] * this.elm[14] +
                 V.elm[3] * this.elm[15]);
    return result;
  }  // vec_postmultiply
  
  
  
  public Matrix matrix_multiply(Matrix M)
  {
    Matrix result = new Matrix();
    
    result.elm[0] = this.elm[0] * M.elm[0] +
                    this.elm[1] * M.elm[4] +
                    this.elm[2] * M.elm[8] +
                    this.elm[3] * M.elm[12];

    result.elm[1] = this.elm[0] * M.elm[1] +
                    this.elm[1] * M.elm[5] +
                    this.elm[2] * M.elm[9] +
                    this.elm[3] * M.elm[13];

    result.elm[2] = this.elm[0] * M.elm[2] +
                    this.elm[1] * M.elm[6] +
                    this.elm[2] * M.elm[10] +
                    this.elm[3] * M.elm[14];

    result.elm[3] = this.elm[0] * M.elm[3] +
                    this.elm[1] * M.elm[7] +
                    this.elm[2] * M.elm[11] +
                    this.elm[3] * M.elm[15];

    result.elm[4] = this.elm[4] * M.elm[0] +
                    this.elm[5] * M.elm[4] +
                    this.elm[6] * M.elm[8] +
                    this.elm[7] * M.elm[12];

    result.elm[5] = this.elm[4] * M.elm[1] +
                    this.elm[5] * M.elm[5] +
                    this.elm[6] * M.elm[9] +
                    this.elm[7] * M.elm[13];

    result.elm[6] = this.elm[4] * M.elm[2] +
                    this.elm[5] * M.elm[6] +
                    this.elm[6] * M.elm[10] +
                    this.elm[7] * M.elm[14];

    result.elm[7] = this.elm[4] * M.elm[3] +
                    this.elm[5] * M.elm[7] +
                    this.elm[6] * M.elm[11] +
                    this.elm[7] * M.elm[15];

    result.elm[8] = this.elm[8] * M.elm[0] +
                    this.elm[9] * M.elm[4] +
                    this.elm[10] * M.elm[8] +
                    this.elm[11] * M.elm[12];

    result.elm[9] = this.elm[8] * M.elm[1] +
                    this.elm[9] * M.elm[5] +
                    this.elm[10] * M.elm[9] +
                    this.elm[11] * M.elm[13];

    result.elm[10] = this.elm[8] * M.elm[2] +
                     this.elm[9] * M.elm[6] +
                     this.elm[10] * M.elm[10] +
                     this.elm[11] * M.elm[14];

    result.elm[11] = this.elm[8] * M.elm[3] +
                     this.elm[9] * M.elm[7] +
                     this.elm[10] * M.elm[11] +
                     this.elm[11] * M.elm[15];

    result.elm[12] = this.elm[12] * M.elm[0] +
                     this.elm[13] * M.elm[4] +
                     this.elm[14] * M.elm[8] +
                     this.elm[15] * M.elm[12];

    result.elm[13] = this.elm[12] * M.elm[1] +
                     this.elm[13] * M.elm[5] +
                     this.elm[14] * M.elm[9] +
                     this.elm[15] * M.elm[13];

    result.elm[14] = this.elm[12] * M.elm[2] +
                     this.elm[13] * M.elm[6] +
                     this.elm[14] * M.elm[10] +
                     this.elm[15] * M.elm[14];

    result.elm[15] = this.elm[12] * M.elm[3] +
                     this.elm[13] * M.elm[7] +
                     this.elm[14] * M.elm[11] +
                     this.elm[15] * M.elm[15];
    return result;
  }  // matrix_multiply



  public Matrix add(Matrix M)
  {
    Matrix result = new Matrix();

    for(int i=0; i<16; i++)
      result.elm[i] = this.elm[i] + M.elm[i];
      
    return result;
  }  // add



  public Matrix scalar_multiply(double scalar)
  {
    Matrix result = new Matrix();
    
    for(int i=0; i<16; i++)
      result.elm[i] = scalar * this.elm[i];
      
    return result;
  }  // scalar_multiply
  
  
  
  public Matrix transpose()
  {
    Matrix result = new Matrix();

    result.elm[0] = elm[0];
    result.elm[1] = elm[4];
    result.elm[2] = elm[8];
    result.elm[3] = elm[12];
    result.elm[4] = elm[1];
    result.elm[5] = elm[5];
    result.elm[6] = elm[9];
    result.elm[7] = elm[13];
    result.elm[8] = elm[2];
    result.elm[9] = elm[6];
    result.elm[10] = elm[10];
    result.elm[11] = elm[14];
    result.elm[12] = elm[3];
    result.elm[13] = elm[7];
    result.elm[14] = elm[11];
    result.elm[15] = elm[15];

    return result;
  }  // transpose



  public void translate(double dx, double dy, double dz)
  {
    identity();
    elm[3] = dx;
    elm[7] = dy;
    elm[11] = dz;
  }  // translate
  

  public void perspectiveview(double z)
  {
    identity();
    elm[10]=0;

    elm[14]=-1.0/z;
    

  }

  public void viewtransform(Vector N, Vector V)
  {

    Vector n=N.vclone();
    n.normalize();

    Vector u=V.cross_product(N);
    u.normalize();

    Vector v=n.cross_product(u);

    set(u,v,n);

  }

  
  public void translate(Vector V)
  {
    identity();
    elm[3] = V.elm[0];
    elm[7] = V.elm[1];
    elm[11] = V.elm[2];
  }  // translate with Vector par.
  
  
  
  public void rotate_x(double angle)
  {
    identity();
    
    elm[5] = Math.cos(angle);
    elm[6] = -Math.sin(angle);
    elm[9] = -elm[6];
    elm[10] = elm[5];
  }  // rotate_x

    
  public void rotate_xr(double angle)
  {
    identity();
    
    elm[5] = angle;
    elm[6] = -angle;
    elm[9] = -elm[6];
    elm[10] = elm[5];
  }  // rotate_x
  
  
  public void rotate_y(double angle)
  {
    identity();

    elm[0] = Math.cos(angle);
    elm[2] = -Math.sin(angle);
    elm[8] = -elm[2];
    elm[10] = elm[0];
  }  // rotate_y

  public void rotate_yr(double angle)
  {
    identity();

    elm[0] = angle;
    elm[2] = -angle;
    elm[8] = -elm[2];
    elm[10] = elm[0];
  }  // rotate_y
  
  
  
  public void rotate_z(double angle)
  {
    identity();
    
    elm[0] = Math.cos(angle);
    elm[1] = -Math.sin(angle);
    elm[4] = -elm[1];
    elm[5] = elm[0];
  }  // rotate_z

    public void rotate_xl(Vector location,double angle)
  {

    identity();
    Matrix m=new Matrix();



    location.negate();
    translate(location);

    m.rotate_x(angle);
    set(m.matrix_multiply(this));

    location.negate();
    m.translate(location);

    set(m.matrix_multiply(this));
  }

  public void rotate_yl(Vector location,double angle)
  {

    identity();
    Matrix m=new Matrix();
    location.negate();
    translate(location);

    m.rotate_y(angle);
    set(m.matrix_multiply(this));

    location.negate();
    m.translate(location);

    set(m.matrix_multiply(this));
  }

  public void rotate_zl(Vector location,double angle)
  {

    identity();
    Matrix m=new Matrix();

    location.negate();
    translate(location);

    m.rotate_z(angle);
    set(m.matrix_multiply(this));

    location.negate();
    m.translate(location);

   set(m.matrix_multiply(this));
  }

  public void scale(double sx, double sy, double sz)
  {
    identity();
    
    elm[0] = sx;
    elm[5] = sy;
    elm[10] = sz;
  }  // scale



  public void display()
  {

    for(int i=0;i<16;i++)
    {
      System.out.print("  " + elm[i]);
      if((i+1)%4==0)
        System.out.println();
      }
      System.out.flush();
  }


}  // class Matrix

