//package noc;

/**
 * A class to describe a two or three dimensional vector.
 * <br>
 * Created for use in examples from the Nature of Code course at ITP.
 * <p>
 * <a href="http://www.shiffman.net">http://www.shiffman.net/</a>
 * <br>
 * <a href="http://www.shiffman.net/teaching/the-nature-of-code">http://www.shiffman.net/teaching/the-nature-of-code</a>
 */

public class Vector3D {
    public float x;
    public float y;
    public float z;

    public Vector3D(float x_, float y_, float z_) {
        x = x_; y = y_; z = z_;
    }

    public Vector3D(float x_, float y_) {
        x = x_; y = y_; z = 0f;
    }
    
    public Vector3D() {
        x = 0f; y = 0f; z = 0f;
    }

    public void setX(float x_) {
        x = x_;
    }

    public void setY(float y_) {
        y = y_;
    }

    public void setZ(float z_) {
        z = z_;
    }

    public void setXYZ(float x_, float y_, float z_) {
        x = x_;
        y = y_;
        z = z_;
    }

    public void setXYZ(Vector3D v) {
        x = v.x;
        y = v.y;
        z = v.z;
    }

    public float magnitude() {
        return (float) Math.sqrt(x*x + y*y + z*z);
    }

    public Vector3D copy() {
        return new Vector3D(x,y,z);
    }

    public static Vector3D copy(Vector3D v) {
        return new Vector3D(v.x, v.y,v.z);
    }

    public void add(Vector3D v) {
        x += v.x;
        y += v.y;
        z += v.z;
    }

    public void sub(Vector3D v) {
        x -= v.x;
        y -= v.y;
        z -= v.z;
    }

    public void mult(float n) {
        x *= n;
        y *= n;
        z *= n;
    }

    public void div(float n) {
        x /= n;
        y /= n;
        z /= n;
    }

    public float dot(Vector3D v) {
        float dot = x*v.x + y*v.y;
        return dot;
    }

    public Vector3D cross(Vector3D v) {
        float crossX = y * v.z - v.y * z;
        float crossY = z * v.x - v.z * x;
        float crossZ = x * v.y - v.x * y;
        return(new Vector3D(crossX,crossY,crossZ));
    }

    public void normalize() {
        float m = magnitude();
        if (m > 0) {
            div(m);
        }
    }

    public void limit(float max) {
        if (magnitude() > max) {
            normalize();
            mult(max);
        }
    }
    public void setMagnitude(float m) {
      normalize();
      mult(m);
    }
      
    public void checkmin(float minimum) {
      if (magnitude() == 0) {
        setXYZ(1,1,0);
      } else if(magnitude() < minimum) {
        normalize();
        mult(minimum);
      }
    }
    
    public float heading2D() {
        float angle = (float) Math.atan2(-y, x);
        return -1*angle;
    }
    
    public void rotate2D(float a) {
      float an = heading2D() + a;
      float m = magnitude();
      x = m * cos(an);
      y = m * sin(an);
      z = 0;
    }
    
    float cos(float a) {
      return (float) Math.cos(a);
    }
    float sin(float a) {
      return (float) Math.sin(a);
    }

    public static Vector3D add(Vector3D v1, Vector3D v2) {
        Vector3D v = new Vector3D(v1.x + v2.x,v1.y + v2.y, v1.z + v2.z);
        return v;
    }

    public static Vector3D sub(Vector3D v1, Vector3D v2) {
        Vector3D v = new Vector3D(v1.x - v2.x,v1.y - v2.y,v1.z - v2.z);
        return v;
    }
    

    public static Vector3D div(Vector3D v1, float n) {
        Vector3D v = new Vector3D(v1.x/n,v1.y/n,v1.z/n);
        return v;
    }

    public static Vector3D mult(Vector3D v1, float n) {
        Vector3D v = new Vector3D(v1.x*n,v1.y*n,v1.z*n);
        return v;
    }

    public static float distance (Vector3D v1, Vector3D v2) {
        float dx = v1.x - v2.x;
        float dy = v1.y - v2.y;
        float dz = v1.z - v2.z;
        return (float) Math.sqrt(dx*dx + dy*dy + dz*dz);
    }

    public static float angleBetween(Vector3D v1, Vector3D v2) {
        float dot = v1.dot(v2);
        float theta = (float) Math.acos(dot / (v1.magnitude() * v2.magnitude()));
        return theta;
    }
    
}


