/*
* Copyright (C) 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package interactivespaces.util.geometry;
import interactivespaces.util.math.MathUtils;
/**
* A 3D vector.
*
* @author Keith M. Hughes
*/
public class Vector3 {
/**
* Create a vector which represents the X axis.
*
* @return the vector for the X axis
*/
public static Vector3 newXAxis() {
return new Vector3(1.0f, 0.0f, 0.0f);
}
/**
* Create a vector which represents the Y axis.
*
* @return the vector for the Y axis
*/
public static Vector3 newYAxis() {
return new Vector3(0.0f, 1.0f, 0.0f);
}
/**
* Create a vector which represents the Z axis.
*
* @return the vector for the Z axis
*/
public static Vector3 newZAxis() {
return new Vector3(0.0f, 0.0f, 1.0f);
}
/**
* Intepolate along the line between {@code v0} and {@code v1}.
*
* <ul>
* <li>If {@code amount} is {@code 0}, the value will be {@code v0}.</li>
* <li>If {@code amount} is {@code 1}, the value will be {@code v1}.</li>
* </ul>
*
* @param v1
* the origin point
* @param v2
* the direction point
* @param amount
* the percentage between the origin and the direction
* @param answer
* where to place the answer
*
* @return the answer
*/
public static Vector3 interpolate(Vector3 v1, Vector3 v2, double amount, Vector3 answer) {
answer.v0 = (v2.v0 - v1.v0) * amount + v1.v0;
answer.v1 = (v2.v1 - v1.v1) * amount + v1.v1;
answer.v2 = (v2.v2 - v1.v2) * amount + v1.v2;
return answer;
}
/**
* Intepolate along the line between {@code v0} and {@code v1}.
*
* <ul>
* <li>If {@code amount} is {@code 0}, the value will be {@code v0}.</li>
* <li>If {@code amount} is {@code 1}, the value will be {@code v1}.</li>
* </ul>
*
* @param v1
* the origin point
* @param v2
* the direction point
* @param amount
* the percentage between the origin and the direction
*
* @return a new vector containing the answer
*/
public static Vector3 interpolate(Vector3 v1, Vector3 v2, double amount) {
return interpolate(v1, v2, amount, new Vector3());
}
/**
* The first component of the vector.
*/
double v0;
/**
* The second component of the vector.
*/
double v1;
/**
* The third component of the vector.
*/
double v2;
/**
* Construct a new vector with components all equal to 0.
*/
public Vector3() {
this(0.0, 0.0, 0.0);
}
/**
* Construct a new vector with the supplied components where the 3rd component
* is 0.
*
* @param v0
* the first component
* @param v1
* the second component
*/
public Vector3(double v0, double v1) {
this(v0, v1, 0.0f);
}
/**
* Construct a new vector with the suppliec components.
*
* @param v0
* the first component
* @param v1
* the second component
* @param v2
* the third component
*/
public Vector3(double v0, double v1, double v2) {
this.v0 = v0;
this.v1 = v1;
this.v2 = v2;
}
/**
* Construct a vector whose components are the same as the supplied vector.
*
* @param v
* the supplied vector
*/
public Vector3(Vector3 v) {
this.v0 = v.v0;
this.v1 = v.v1;
this.v2 = v.v2;
}
/**
* Get the first component of the vector.
*
* @return first component
*/
public double getV0() {
return v0;
}
/**
* Set the first component of the vector.
*
* @param v
* the new component value
*
* @return this vector
*/
public Vector3 setV0(double v) {
this.v0 = v;
return this;
}
/**
* Get the second component of the vector.
*
* @return the second component
*/
public double getV1() {
return v1;
}
/**
* Set the second component of the vector.
*
* @param v
* the new component value
*
* @return this vector
*/
public Vector3 setV1(double v) {
this.v1 = v;
return this;
}
/**
* Get the third component of the vector.
*
* @return the third component
*/
public double getV2() {
return v2;
}
/**
* Set the third component of the vector.
*
* @param v
* the new component value
*
* @return this vector
*/
public Vector3 setV2(double v) {
this.v2 = v;
return this;
}
/**
* Set the components of the vector.
*
* @param v0
* the first component value
* @param v1
* the second component value
* @param v2
* the third component value
*
* @return this vector
*/
public Vector3 set(double v0, double v1, double v2) {
this.v0 = v0;
this.v1 = v1;
this.v2 = v2;
return this;
}
/**
* Set the components of the vector.
*
* @param v
* the vector to get the components from
*
* @return this vector
*/
public Vector3 set(Vector3 v) {
return set(v.v0, v.v1, v.v2);
}
/**
* Normalize the current vector.
*
* @return a new vector with the normalized components
*/
public Vector3 normalize() {
return new Vector3(this).normalizeSelf();
}
/**
* Normalize the current vector.
*
* @return this vector with the normalized components
*/
public Vector3 normalizeSelf() {
double length = getLength();
v0 /= length;
v1 /= length;
v2 /= length;
return this;
}
/**
* Get the length of the vector.
*
* @return the length of the vector
*/
public double getLength() {
return Math.sqrt(v0 * v0 + v1 * v1 + v2 * v2);
}
/**
* Multiply the current vector by the matrix.
*
* @param m
* the matrix to multiply by
*
* @return a new vector whose components are result of the multiplication
*/
public Vector3 multiply(Matrix4 m) {
return new Vector3(this).multiplySelf(m);
}
/**
* Multiple the current vector in homogeneous space, setting the current
* vector to the result.
*
* @param m
* the vector to multiply by
*
* @return this vector whose components are result of the multiplication
*/
public Vector3 multiplySelf(Matrix4 m) {
double tv0 = v0 * m.matrix[0][0] + v1 * m.matrix[0][1] + v2 * m.matrix[0][2] + m.matrix[0][3];
double tv1 = v0 * m.matrix[1][0] + v1 * m.matrix[1][1] + v2 * m.matrix[1][2] + m.matrix[1][3];
double tv2 = v0 * m.matrix[2][0] + v1 * m.matrix[2][1] + v2 * m.matrix[2][2] + m.matrix[2][3];
double w = v0 * m.matrix[3][0] + v1 * m.matrix[3][1] + v2 * m.matrix[3][2] + m.matrix[3][3];
v0 = tv0 / w;
v1 = tv1 / w;
v2 = tv2 / w;
return this;
}
/**
* Add the supplied vector to this vector.
*
* @param v
* the supplied vector
*
* @return a new vector with components are the result of the addition
*/
public Vector3 add(Vector3 v) {
return new Vector3(this).addSelf(v);
}
/**
* Add the supplied vector to this vector.
*
* @param v
* the supplied vector
*
* @return this vector with components are the result of the addition
*/
public Vector3 addSelf(Vector3 v) {
v0 += v.v0;
v1 += v.v1;
v2 += v.v2;
return this;
}
/**
* Subtract the supplied vector from this vector.
*
* @param v
* the supplied vector
*
* @return a new vector with components are the result of the subtraction
*/
public Vector3 subtract(Vector3 v) {
return new Vector3(this).subtractSelf(v);
}
/**
* Subtract the supplied vector from this vector.
*
* @param v
* the supplied vector
*
* @return this vector with components are the result of the subtraction
*/
public Vector3 subtractSelf(Vector3 v) {
v0 -= v.v0;
v1 -= v.v1;
v2 -= v.v2;
return this;
}
/**
* Get a vector which has every component multiplied by a factor.
*
* @param factor
* the factor
*
* @return a new vector with components that are scaled
*/
public Vector3 scale(double factor) {
return new Vector3(this).scaleSelf(factor);
}
/**
* Get a vector which has every component multiplied by a factor.
*
* @param factor
* the factor
*
* @return this vector with components that are scaled
*/
public Vector3 scaleSelf(double factor) {
v0 *= factor;
v1 *= factor;
v2 *= factor;
return this;
}
/**
* Divide all components of the current vector by a factor.
*
* @param factor
* the factor by which to divide the components
*
* @return a new vector with components equal to the division
*/
public Vector3 divide(double factor) {
return new Vector3(this).divideSelf(factor);
}
/**
* Divide all components of the current vector by a factor.
*
* @param factor
* the factor by which to divide the components
*
* @return this vector with components equal to the division
*/
public Vector3 divideSelf(double factor) {
v0 /= factor;
v1 /= factor;
v2 /= factor;
return this;
}
/**
* Limit the vector to a given magnitude. If the magnitude is less the vector
* is left alone, if the magnitude is greater, it will be scaled to have a
* length of the given magnitude.
*
* @param magnitude
* the magnitude limit
*
* @return a new vector with components that are limited
*/
public Vector3 limit(double magnitude) {
return new Vector3(this).limitSelf(magnitude);
}
/**
* Limit the vector to a given magnitude. If the magnitude is less the vector
* is left alone, if the magnitude is greater, it will be scaled to have a
* length of the given magnitude.
*
* @param magnitude
* the magnitude limit
*
* @return this vector with components that are limited
*/
public Vector3 limitSelf(double magnitude) {
double length = getLength();
if (length > magnitude) {
double factor = magnitude / length;
v0 *= factor;
v1 *= factor;
v2 *= factor;
}
return this;
}
/**
* Calculate the dot product between this vector and the supplied vector.
*
* @param v
* the supplied vector
*
* @return the dot product
*/
public double dot(Vector3 v) {
return v0 * v.v0 + v1 * v.v1 + v2 * v.v2;
}
/**
* Calculate the cross product of this vector with the supplied vector.
*
* @param v
* the supplied vector
*
* @return a new vector with components are the result of the cross product
*/
public Vector3 cross(Vector3 v) {
return new Vector3(this).crossSelf(v);
}
/**
* Calculate the cross product of this vector with the supplied vector.
*
* @param v
* the supplied vector
*
* @return this vector with components are the result of the cross product
*/
public Vector3 crossSelf(Vector3 v) {
double tv0 = v1 * v.v2 - v2 * v.v1;
double tv1 = v2 * v.v0 - v0 * v.v2;
double tv2 = v0 * v.v1 - v1 * v.v0;
v0 = tv0;
v1 = tv1;
v2 = tv2;
return this;
}
/**
* Calculate the square of the Euclidean distance between this vector and the
* other using all 3 coordinates.
*
* @param v
* the second vector
*
* @return the Euclidean distance
*/
public double euclideanDistanceSquared(Vector3 v) {
double xDiff = v0 - v.v0;
double yDiff = v1 - v.v1;
double zDiff = v2 - v.v2;
return xDiff * xDiff + yDiff * yDiff + zDiff * zDiff;
}
/**
* Calculate the Euclidean distance between this vector and the other using
* all 3 coordinates.
*
* @param v
* the second vector
*
* @return the Euclidean distance
*/
public double euclideanDistance(Vector3 v) {
return Math.sqrt(euclideanDistanceSquared(v));
}
/**
* Calculate the square of the Euclidean distance between this vector and the
* other.
*
* @param v
* the second vector
*
* @return the Euclidean distance
*/
public double euclideanDistanceSquared2(Vector3 v) {
double xDiff = v0 - v.v0;
double yDiff = v1 - v.v1;
return xDiff * xDiff + yDiff * yDiff;
}
/**
* Calculate the Euclidean distance between this vector and the second using
* the first 2 coordinates.
*
* @param v
* the second vector
*
* @return the Euclidean distance
*/
public double euclideanDistance2(Vector3 v) {
return Math.sqrt(euclideanDistanceSquared2(v));
}
/**
* Is this vector equal to the other?
*
* @param v
* the second vector
*
* @return {@code true} if each component is equal to the corresponding
* component.
*/
public boolean equal(Vector3 v) {
return v0 == v.v0 && v1 == v.v1 && v2 == v.v2;
}
/**
* Is this vectors equal to the other within some tolerance factor?.
*
* @param v
* the second vector
* @param tolerance
* the tolerance for equality
*
* @return {@code true} if each component is equal to the corresponding
* component within the tolerance factor
*/
public boolean equal(Vector3 v, double tolerance) {
return MathUtils.equals(v0, v.v0, tolerance) && MathUtils.equals(v1, v.v1, tolerance)
&& MathUtils.equals(v2, v.v2, tolerance);
}
@Override
public String toString() {
return "Vector3 [v0=" + v0 + ", v1=" + v1 + ", v2=" + v2 + "]";
}
}