/**
 * Represents homogeneous coords point in 3D, plus algebra.
 *<p>
 * For CSU540 Computer Graphics class, Spring 2005
 * CCIS, Northeastern University
 *<p>
 * Consists of a single 4-element double vector, vec, and various static methods.
 *<br>
 * Method names ending with "Same" alter the vector argument.
 * Others return a copy.
 * @author Bob Futrelle
 * @version 26 January 2005
 */


public class Vec  {

    /**
     * The only (non-static) field, a 4-element array.
     */
    public double[] vec;
    
    /**
     * Tests and prints results of all methods (all are static)
     */
     public static void main(String[] args) {
	Vec p = new Vec();
	System.out.println("\nEmpty vector is: " + p);
	Vec v1 = new Vec(1.0,0.0,1.0);
	System.out.println("\nv1 is: " + v1);
	Vec v2 = new Vec(0.0,1.0,0.0);
	System.out.println("v2 is: " + v2);
	System.out.println("\nInner product of v1, v2:");
	System.out.println(Vec.innerProd(v1,v2));
	System.out.println("\nOuter product of v1, v2:");
	System.out.println(Vec.outerProd(v1,v2));
	System.out.println("\nOuter product of v2, v1 (other order):");
	System.out.println(Vec.outerProd(v2,v1));
	Vec v3 = new Vec(3.0,4.0,0.0);
	System.out.println("\nv3: " + v3);
	System.out.println("\nLength of v3: " + Vec.length(v3));
	System.out.println("\nNormalized copy of v3:");
	System.out.println(Vec.normalize(v3));
	System.out.println("\nv3 itself normalized. Not a copy:");
        Vec.normalizeSame(v3);
	System.out.println(v3 + "\n");
    }

    /**
     * Lists the x, y, and z elements of vec.
     */
    public String toString(){
	return "[" + vec[0] + "," + vec[1] + "," + vec[2] + "]";
    }

    /**
     * Creates 0.0 vector with homogeneous, vec[3], coord = 1.0.
     */
    public Vec () {
      	vec = new double[] {0.0,0.0,0.0,1.0};
      }

    /**
     * Creates vector with the three argument values and vec[3] = 1.0.
     */
    public Vec (double x, double y, double z) {
      	vec = new double[4];
	vec[0] = x;
	vec[1] = y;
	vec[2] = z;
	vec[3] = 1.0;
      }


    /**
     * Inner product using the x, y, z components.
     */
    public static double innerProd(Vec v1, Vec v2){
	double sum = 0.0;
	for(int i = 0 ; i < 3; i++)
	    sum = sum + v1.vec[i]*v2.vec[i];
	return sum;
    }

    /**
     * Outer, or vector,  product using the x, y, z components.
     * @return A new Vec object containing the product in the vec field.
     *<br>
     * Can be viewed as the value of this determinant:
     * <pre>
     * | i  j  k |
     * | x  y  z |
     * | x' y' z'|
     * </pre>
     * where i, j, and k are the unit vectors along the three axes.
     */

    public static Vec outerProd(Vec v1, Vec v2){
	Vec product = new Vec();
	product.vec[0] = 
	    v1.vec[1]*v2.vec[2] +
	    - v1.vec[2]*v2.vec[1];
	product.vec[1] = 
	    v1.vec[2]*v2.vec[0] +
	    - v1.vec[0]*v2.vec[2];
	product.vec[2] = 
	    v1.vec[0]*v2.vec[1] +
	    - v1.vec[1]*v2.vec[0];
	product.vec[3] = 1.0;
	return product;
    }


    /**
     * Sum of two vectors, a static method.
     * Homogeneous coordinate remains at 1.0
     * <br>
     * TO BE COMPLETED
     * @return Vector sum of two arguments.
     */
    public static Vec vecSum(Vec v1, Vec v2){
	Vec sum = new Vec();
	// INSERT LOOP CODE
	return sum;
    }

    /**
     * Difference of two vectors, a static method.
     * Homogeneous coordinate remains at 1.0
     * <br>
     * TO BE COMPLETED
     * @return Vector difference of v1 minus v2
     */
    public static Vec vecDiff(Vec v1, Vec v2){
	Vec diff = new Vec();
	// INSERT LOOP CODE
	return diff;
    }

    /**
     * Computes vector length.
     * @return length of arg (ignores homogeneous coordinate).
     */
    public static double length(Vec v) {
	return Math.sqrt(v.vec[0]*v.vec[0] + v.vec[1]*v.vec[1] + v.vec[2]*v.vec[2]); 
    }

    /**
     * Creates a normalized, unit length,  copy of a Vec.
     * @return normalized copy of arg.
     */
    public static Vec normalize(Vec v){
	double len = Vec.length(v);
	return new Vec(v.vec[0]/len, v.vec[1]/len, v.vec[2]/len);
    }

    /**
     * Normalizes (alters) a Vec to unit length.
     * @param v The vector to be scaled to unit length.
     */
    public static void normalizeSame(Vec v){
	double len = Vec.length(v);
	for(int m=0; m < 3; m++)
	    v.vec[m] = v.vec[m]/len;
    }

} // end class Vec

