package nxm.sys.lib;


import nxm.sys.inc.InternalUseOnly;

/** Utility methos for 3D Vectors
 *
 *  @author Jeanette McCall
 *
 */
@InternalUseOnly
public final class Vector3D {

  private Vector3D () { } // prevent instantiation since all methods are static

  /** compute dot product
   *
   *  @param vector1 first vector
   *  @param vector2 second vector
   *  @return dot product
   */
  @InternalUseOnly
  public static double dotProduct(double[] vector1, double[] vector2) {
    return vector1[0]*vector2[0] + vector1[1]*vector2[1] + vector1[2]*vector2[2];
  }

  /** compute magnitude of vector
   *
   *  @param vector vector
   *  @return magnitude of vector
   */
  @InternalUseOnly
  public static double mag (double[] vector) {
    return Math.sqrt(vector[0]*vector[0] + vector[1]*vector[1] + vector[2]*vector[2]);
  }

  /** normalize vector
   *
   *  @param vector vector
   *  @return normalized vector
   */
  @InternalUseOnly
  public static double[] norm (double[] vector) {
    return norm(vector,mag(vector));
  }

  /** normalize vector
  *
  *  @param vector vector
  *  @param magnitude magnitude of vector
  *  @return normalized vector
  */
  @InternalUseOnly
  public static double[] norm (double[] vector, double magnitude) {
    double inverseMagnitude = 1/magnitude;
    double[] normalizedVector = new double[vector.length];
    for (int i=0; i < normalizedVector.length; i++) {
      normalizedVector[i] = vector[i]*inverseMagnitude;
    }
    return normalizedVector;
  }

  /** subtract vector 2 from vector 1
  *
  *  @param vector1 first vector
  *  @param vector2 second vector
  *  @return (vector 1 - vector 2)
  */
 @InternalUseOnly
  public static double[] subtract (double[] vector1, double[] vector2) {
    return new double[] {vector1[0] - vector2[0], vector1[1] - vector2[1], vector1[2] - vector2[2]};
  }

 /** add vector 2 to vector 1
   *
   *  @param vector1 first vector
   *  @param vector2 second vector
   *  @return (vector 1 + vector 2)
   */
  @InternalUseOnly
  public static double[] add (double[] vector1, double[] vector2) {
    return new double[] {vector1[0] + vector2[0], vector1[1] + vector2[1], vector1[2] + vector2[2]};
  }

  /** Get the angle between vectors<br>
   *  <pre>
   *  the following formula was used:
   *                /              (x1x2 + y1y2 + z1z2)                     \
   *  angle = acos ( ------------------------------------------------------- )
   *                \ Math.sqrt((x1^2 + y1^2 + z1^2) * (x2^2 + y2^2 + z2^2) /
   *  </pre>
   *  @param vector1 {x1,y1,z1} vector
   *  @param vector2 {x2,y2,z2} vector
   *  @return angle in radians
   */
  @InternalUseOnly
  public static double angleBetween (double[] vector1, double[] vector2) {
    return Math.acos(dotProduct(vector1,vector2) / (mag(vector1) * mag(vector2)));
  }

  /** Get the angle, given a common point and another point along each ray
   *
   *  @param commonPoint vertex
   *  @param point1      first point
   *  @param point2      second point
   *  @return angle in radians
   */
  @InternalUseOnly
  public static double angleBetween (double[] commonPoint, double[] point1, double[] point2) {
    double[] vector1 = {point1[0]-commonPoint[0],point1[1]-commonPoint[1],point1[2]-commonPoint[2]};
    double[] vector2 = {point2[0]-commonPoint[0],point2[1]-commonPoint[1],point2[2]-commonPoint[2]};
    return angleBetween(vector1, vector2);
  }

  /** multiply vector by scalar
   *
   *  @param vector vector
   *  @param scalar scalar
   *  @return vector multiplied by scalar
   */
  @InternalUseOnly
  public static double[] multByScalar (double[] vector, double scalar) {
    return new double[] {vector[0] * scalar,vector[1] * scalar,vector[2] * scalar};
  }

  /** compute cross product of two vectors
   *
   *  @param vector1 first vector
   *  @param vector2 second vector
   *  @return cross product
   */
  @InternalUseOnly
  public static double[] crossProduct (double[] vector1, double[] vector2) {
    double[] crossProduct = new double[3];
    crossProduct[0] = vector1[1] * vector2[2] - vector1[2] * vector2[1];
    crossProduct[1] = vector1[2] * vector2[0] - vector1[0] * vector2[2];
    crossProduct[2] = vector1[0] * vector2[1] - vector1[1] * vector2[0];
    return crossProduct;
  }
}
