Implements an Vector in 3D space. : Geometry « 2D Graphics GUI « Java






Implements an Vector in 3D space.

      

/* $Id: Vector3f.java,v 1.3 2005/08/20 10:15:55 joda Exp $
 * Created on 22.07.2004
 */
//package net.sourceforge.ftgl.util;

/**
 * Implements an Vector in 3D space.
 * 
 * @author Ralf Petring
 * @author funsheep
 */
public class Vector3f implements Cloneable
{

  /** The tolerance we accept when prooving length against a value (e.g. 1.0f). */
  public final static float TOLERANCE = 1E-6f;

  /** x component*/
  public float x;
  /** y component*/
  public float y;
  /** z component*/
  public float z;
  //public float dx, dy;    // tkoch: only for test purposes regarding inclusion of .3DS loader


  /**
   * Constructs a new vector.
   * 
   * @param x the first coordinate
   * @param y the second coordinate
   * @param z the third coordinate
   */
  public Vector3f(final float x, final float y, final float z)
  {
    this.x = x;
    this.y = y;
    this.z = z;
  }

  /**
   * Constructs a new vector.
   * @param vector new vector's coordinates
   */
  public Vector3f(final float[] vector)
  {
    this(vector[0], vector[1], vector[2]);
  }

  /**
   * Constructs a new vector whith (0,0,0) as coordinates.
   */
  public Vector3f()
  {
    this(0, 0, 0);
  }

  /**
   * Copyconstructor.
   * 
   * @param v the vector to be copied
   */
  public Vector3f(final Vector3f v)
  {
    this(v.x, v.y, v.z);
  }

  /**
   * {@inheritDoc}
   */
  public boolean equals(Object o)
  {
    if (o instanceof Vector3f)
      return this.equals((Vector3f)o);

    return false;
  }

  /**
   * Compares this vector with the given vector.
   * 
   * @param v the vector to be used for compare
   * @return <code>true</code> if this vector has the same components as the argument vector
   * <code>v</code>, false otherwise
   */
  public boolean equals(Vector3f v)
  {
    if (v == null)
      return false;

    return (this.x == v.x && this.y == v.y && this.z == v.z);
  }

  /**
   * Compares this vector with the given vector.
   * <p>Note: tolerance is applied per component, thus all vectors
   * which equal this vector will form a box.</p>
   * @param v the vector to be used for compare
   * @param tolerance accepted tolerance
   * @return <code>true</code> if this the components of this vector are equal to the argument vector
   * <code>v</code> with a tolerance of argument <code>tolerance</code>, false otherwise
   */
  public boolean equals(Vector3f v, float tolerance)
  {
    if (v == null)
      return false;

    return (Math.abs(this.x-v.x)<tolerance &&
        Math.abs(this.y-v.y)<tolerance &&
        Math.abs(this.z-v.z)<tolerance);
  }

  /**
   * {@inheritDoc}
   */
  public int hashCode()
  {
    int i1 = Float.floatToIntBits(this.x);
    int i2 = Float.floatToIntBits(this.y);
    int i3 = Float.floatToIntBits(this.z);

    return i1 ^ ((i2 << 8) | (i2 >>> 24)) ^ ((i3 << 16) | (i3 >>> 16));
  }

  /**
   * Calculates the (squared) distance between two Vectors.
   * 
   * @param v1
   * @param v2
   * @return the distance (squared)
   */
  public static float distanceSquared(Vector3f v1, Vector3f v2)
  {
    float x = v1.x - v2.x;
    float y = v1.y - v2.y;
    float z = v1.z - v2.z;
    return x*x + y*y + z*z;
  }

  /**
   * Calculates the distance between two Vectors.
   * 
   * @param v1
   * @param v2
   * @return the distance
   */
  public static float distance(Vector3f v1, Vector3f v2)
  {
    return (float)Math.sqrt(distanceSquared(v1, v2));
  }

  /**
   * Adds the given float values to the coordinates of this vector.
   * 
   * @param dx the value to be added to the x coordinate
   * @param dy the value to be added to the y coordinate
   * @param dz the value to be added to the z coordinate
   * @return this
   */
  public Vector3f add(final float dx, final float dy, final float dz)
  {
    this.x += dx;
    this.y += dy;
    this.z += dz;
    return this;
  }

  /**
   * Adds a given vector to this vector.
   * 
   * @param v the vector to be added
   * @return this
   */
  public Vector3f add(final Vector3f v)
  {
    return this.add(v.x, v.y, v.z);
  }

  /**
   * Adds to this vector the given one with the given scale.
   * @param v A vector to add.
   * @param d The length of the vector, to be added.
   * @return this
   */
  public Vector3f addScaled(final Vector3f v, final float d)
  {
    return this.add(v.x * d, v.y * d, v.z * d);
  }

  /**
   * Substracts a given vector from this vector.
   * 
   * @param v the vector to be substracted
   * @return this
   */
  public Vector3f sub(final Vector3f v)
  {
    return this.sub(v.x, v.y, v.z);
  }

  /**
   * Substracts the given float values from the coordinates of this vector.
   * 
   * @param dx the value to be substracted from the x coordinate
   * @param dy the value to be substracted from the y coordinate
   * @param dz the value to be substracted from the z coordinate
   * @return this
   */
  public Vector3f sub(final float dx, final float dy, final float dz)
  {
    this.x -= dx;
    this.y -= dy;
    this.z -= dz;
    return this;
  }

  /**
   * Multiplies the coordinates of this vector with the given float values.
   * 
   * @param dx the value to be multiplied the x coordinate
   * @param dy the value to be multiplied the y coordinate
   * @param dz the value to be multiplied the z coordinate
   * @return this
   */
  public Vector3f scale(final float dx, final float dy, final float dz)
  {
    this.x *= dx;
    this.y *= dy;
    this.z *= dz;
    return this;
  }

  /**
   * Multiplies all coordinates of this vector with the given float value.
   * 
   * @param d the value to be multiplied with all coordinates
   * @return this
   */
  public Vector3f scale(final float d)
  {
    return this.scale(d, d, d);
  }

  /**
   * Calculates the dotprodukt of this vector and the given vector.
   * 
   * @param v the vector to be used for calculation
   * @return the dotproduct
   */
  public float dot(final Vector3f v)
  {
    return this.x * v.x + this.y * v.y + this.z * v.z;
  }

  /**
   * Normalizes this vector.
   * 
   * @return this
   */
  public Vector3f normalize()
  {
    float l = this.length();
    if (l != 0)
    {
      this.x /= l;
      this.y /= l;
      this.z /= l;
    }
    return this;
  }

  //Daniel K. wanted this name
  /**
   * Improved version of {@link #normalize()} which also works for VERY short vectors,
   * or very large ones. This implementation is slighty slower than {@link #normalize()}.
   * @return this
   */
  public Vector3f normalize2()
  {
    if (this.isZero())
      throw new IllegalStateException("this is the zero vector");
    if (this.isInvalid())
      throw new IllegalStateException("invalid vector");

    while (x>-0.5f && x<0.5f && y>-0.5f && y<0.5f && z>-0.5f && z<0.5f)
    {
      x *= 2;
      y *= 2;
      z *= 2;
    }

    while (x<=-1.0f || x>=1.0f || y<=-1.0f || y>=1.0f || z<=-1.0f || z>=1.0f)
    {
      x /= 2;
      y /= 2;
      z /= 2;
    }

    float l = this.length();
    this.x /= l;
    this.y /= l;
    this.z /= l;

    return this;
  }

  /**
   * Returns <code>true</code> if vector is {@link Float#NEGATIVE_INFINITY},
   * {@link Float#POSITIVE_INFINITY} or {@link Float#NaN}
   * @return  <code>true</code> if vector is {@link Float#NEGATIVE_INFINITY},
   * {@link Float#POSITIVE_INFINITY} or {@link Float#NaN}.
   */
  public boolean isInvalid()
  {
    return Float.isInfinite(x) || Float.isInfinite(y) || Float.isInfinite(z)
      || Float.isNaN(x) || Float.isNaN(y) || Float.isNaN(z);
  }

  /**
   * Returns <code>true</code> iff x exactly zero (0,0,0).
   * @return <code>true</code> iff x exactly zero (0,0,0).
   */
  public boolean isZero()
  {
    return x==0f && y==0f && z==0f;
  }

  /**
   * Returns <code>true</code> if vector is nearly zero (0,0,0).
   * @param tolerance accepted tolerance
   * @return <code>true</code> if vector is nearly zero (0,0,0).
   */
  public boolean isZero(float tolerance)
  {
    return Math.abs(this.x)<tolerance &&
      Math.abs(this.y)<tolerance &&
      Math.abs(this.z)<tolerance;
  }

  /**
   * Calculates the angle between this vector and the given vector.
   * 
   * @param v the vector to be used for calculation
   * @return the angle between this and v
   */
  public float angle(final Vector3f v)
  {
    float dls = dot(v) / (this.length() * v.length());
    if (dls < -1.0f)
      dls = -1.0f;
    else if (dls > 1.0f)
      dls = 1.0f;
    return (float)Math.acos(dls);
  }

  /**
   * Sets all coordinates of this vector to zero.
   * 
   * @return this
   */
  public Vector3f setZero()
  {
    this.x = 0;
    this.y = 0;
    this.z = 0;
    return this;
  }

  /**
   * Copies all values from the given vector to this vector.
   * 
   * @param v the vector to be copied
   * @return this
   */
  public Vector3f set(final Vector3f v)
  {
    this.x = v.x;
    this.y = v.y;
    this.z = v.z;
    return this;
  }

  public Vector3f set(float x, float y, float z)
  {
    this.x = x;
    this.y = y;
    this.z = z;
    return this;
  }

  /**
   * Sets the vector's components to the first 3 values
   * in argument <code>array</code>.
   * @param array array which contains the new values
   * @return this
   */
  public Vector3f set(final float[] array)
  {
    this.x = array[0];
    this.y = array[1];
    this.z = array[2];
    return this;
  }

  /**
   * Negates all coordinates of this vector.
   * 
   * @return this
   */
  public Vector3f negate()
  {
    this.x = -this.x;
    this.y = -this.y;
    this.z = -this.z;
    return this;
  }


  /**
   * Returns the squared length of this vector.
   * 
   * @return the squared length of this vector
   */
  public float lengthSquared()
  {
    return (this.x * this.x + this.y * this.y + this.z * this.z);
  }

  /**
   * Returns the length of this vector.
   * 
   * @return the length of this vector
   */
  public float length()
  {
    return (float)Math.sqrt(this.lengthSquared());
  }

  /**
   * Calculates the vector cross product of this vector and the given vector.
   * 
   * @param v the second vector
   * @return this
   */
  public Vector3f cross(final Vector3f v)
  {
    final float a = this.y * v.z - this.z * v.y;
    final float b = this.z * v.x - this.x * v.z;
    final float c = this.x * v.y - this.y * v.x;

    this.x = a;
    this.y = b;
    this.z = c;

    return this;
  }

  /**
   * Calculates the vector cross product of the two given vectors.
   * <br><code>a x b = c</code> c is returned.
   * @param a The first vector.
   * @param b The second vector.
   * @return A new vector, holding the cross product of a x b.
   */
  public static Vector3f cross(final Vector3f a, final Vector3f b)
  {
    return new Vector3f(
        a.y * b.z - a.z * b.y,
        a.z * b.x - a.x * b.z,
        a.x * b.y - a.y * b.x);
  }

  /**
   * {@inheritDoc}
   */
  public Object clone()
  {
    try
    {
      return super.clone();
    }
    catch (CloneNotSupportedException e)
    {
      throw new RuntimeException("the roof is on fire", e);
    }
  }

  /**
   * {@inheritDoc}
   */
  public String toString()
  {
    return "[" + this.x + "," + this.y + "," + this.z + "]";
  }

  /**
   * Copies all components of this vector into the first 3 array components.
   * @param dest array to be filled - may be <code>null</code>
   * @return argument <code>dest</code> or a new array filled with this
   * instances components.
   */
  public float[] toArray(float[] dest)
  {
    if (dest==null)
      dest = new float[3];
    dest[0] = this.x;
    dest[1] = this.y;
    dest[2] = this.z;
    return dest;
  }

  /**
   * Returns <code>true</code> if this vector is normalized. If it's length is <code>1</code>.
   * @return <code>true</code> if this vector is normalized.
   */
  public boolean isNormalized()
  {
    return this.lengthSquared()==1;
  }

  /**
   * Returns <code>true</code> if this vector is normalized.
   * If it's length is <code>1</code> within a tolerance of argument <code>tolerance</code>.
   * @param tolerance amount of error to be ignores - must be positive!
   * <p>Note: the normal is computed by using {@link #lengthSquared()}, thus
   * the following equation approximated.
   * For a Vector3f <code>v</code>:
   * Correct:<pre>return {@link Math#sqrt(double) sqrt}({@link #lengthSquared()
   * v.lengthSquared()})>1f-tolerance;</pre>
   * 
   * Steps to a more numerical stable and faster test:
   * <pre>
   * v.lengthSquared()>(1f-tolerance)^2
   *  &lt;=&gt; v.lengthSquared()>1f-2f*tolerance+tolerance^2;</pre>
   * Optimized and approximated result:
   * <pre>return v.lengthSquared()>1f-2f*tolerance;</pre>
   * This test is infact less precise than the original test,
   * but seems to be reasonable, as a tolerance is assumed to be pretty small!
   * @return <code>true</code> if this vector is normalized.
   */
  public boolean isNormalized(float tolerance)
  {
    assert tolerance>=0:"tolerance must be positive or 0";
    float tmp1 = this.lengthSquared() - 1f;
    float tmp2 = 2f * tolerance + tolerance * tolerance;
    return tmp1 < tmp2 && -tmp1 < tmp2;
  }

  /**
   * Returns <code>true</code> if this vector is orthogonal to argument <code>other</code>.
   * @param other other vector
   * @return <code>true</code> if this vector is orthogonal to argument <code>other</code>.
   */
  public boolean isOrthogonal(Vector3f other)
  {
    return this.dot(other)==0;
  }

  /**
   * Returns <code>true</code> if this vector is orthogonal to argument <code>other</code>.
   * @param other other vector
   * @param tolerance amount of error to be ignores - must be positive!
   * @return <code>true</code> if this vector is orthogonal to argument <code>other</code>.
   */
  public boolean isOrthogonal(Vector3f other, float tolerance)
  {
    assert tolerance>=0:"tolerance must be positive or 0";
    return this.dot(other)>-tolerance;
  }
}

   
    
    
    
    
    
  








Related examples in the same category

1.Collection of geometry utility methods
2.Unions Rectangle2D
3.Interpolates points given in the 2D plane
4.Returns distance between two sets of coords
5.Returns distance between 3D set of coords
6.Returns closest point on segment to point
7.Calculate Angle From
8.Returns distance to segment
9.Hexagon demo
10.Implementation of the 4 dimensional vector.
11.Quaternion
12.Circle shape
13.Geometry Utilities
14.This is a Polygon that allows the user to flip and swap the points along it's axis.
15.Fast trigonometric operationsFast trigonometric operations
16.A class to represent a latitude and longitude
17.An undirected graph that keeps track of connected components (groups).
18.Generates n logarithmically-spaced points between d1 and d2 using the provided base.
19.Returns a dimension where width and height are inside the bounds of the maxWidth and maxHeight parameters