/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* 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 com.badlogic.gdx.math;
import java.io.Serializable;
import com.badlogic.gdx.utils.NumberUtils;
/**
* Encapsulates a 3D vector. Allows chaining operations by returning a reference to itself in all modification methods.
*
* @author badlogicgames@gmail.com
*/
public class Vector3 implements Serializable {
private static final long serialVersionUID = 3840054589595372522L;
/** the x-component of this vector **/
public float x;
/** the x-component of this vector **/
public float y;
/** the x-component of this vector **/
public float z;
/**
* Static temporary vector. Use with care! Use only when sure other code will not also use this.
*
* @see #tmp()
**/
public final static Vector3 tmp = new Vector3();
/**
* Static temporary vector. Use with care! Use only when sure other code will not also use this.
*
* @see #tmp()
**/
public final static Vector3 tmp2 = new Vector3();
/**
* Static temporary vector. Use with care! Use only when sure other code will not also use this.
*
* @see #tmp()
**/
public final static Vector3 tmp3 = new Vector3();
public final static Vector3 X = new Vector3(1, 0, 0);
public final static Vector3 Y = new Vector3(0, 1, 0);
public final static Vector3 Z = new Vector3(0, 0, 1);
public final static Vector3 Zero = new Vector3(0, 0, 0);
private final static Matrix4 tmpMat = new Matrix4();
/** Constructs a vector at (0,0,0) */
public Vector3() {
}
/**
* Creates a vector with the given components
*
* @param x
* The x-component
* @param y
* The y-component
* @param z
* The z-component
*/
public Vector3(float x, float y, float z) {
this.set(x, y, z);
}
/**
* Creates a vector from the given vector
*
* @param vector
* The vector
*/
public Vector3(Vector3 vector) {
this.set(vector);
}
/**
* Creates a vector from the given array. The array must have at least 3 elements.
*
* @param values
* The array
*/
public Vector3(float[] values) {
this.set(values[0], values[1], values[2]);
}
/**
* Sets the vector to the given components
*
* @param x
* The x-component
* @param y
* The y-component
* @param z
* The z-component
* @return this vector for chaining
*/
public Vector3 set(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
return this;
}
/**
* Sets the components of the given vector
*
* @param vector
* The vector
* @return This vector for chaining
*/
public Vector3 set(Vector3 vector) {
return this.set(vector.x, vector.y, vector.z);
}
/**
* Sets the components from the array. The array must have at least 3 elements
*
* @param values
* The array
* @return this vector for chaining
*/
public Vector3 set(float[] values) {
return this.set(values[0], values[1], values[2]);
}
/** @return a copy of this vector */
public Vector3 cpy() {
return new Vector3(this);
}
/**
* NEVER EVER SAVE THIS REFERENCE! Do not use this unless you are aware of the side-effects, e.g. other methods
* might call this as well.
*
* @return a temporary copy of this vector
*/
public Vector3 tmp() {
return tmp.set(this);
}
/**
* NEVER EVER SAVE THIS REFERENCE! Do not use this unless you are aware of the side-effects, e.g. other methods
* might call this as well.
*
* @return a temporary copy of this vector
*/
public Vector3 tmp2() {
return tmp2.set(this);
}
/**
* NEVER EVER SAVE THIS REFERENCE! Do not use this unless you are aware of the side-effects, e.g. other methods
* might call this as well.
*
* @return a temporary copy of this vector
*/
Vector3 tmp3() {
return tmp3.set(this);
}
/**
* Adds the given vector to this vector
*
* @param vector
* The other vector
* @return This vector for chaining
*/
public Vector3 add(Vector3 vector) {
return this.add(vector.x, vector.y, vector.z);
}
/**
* Adds the given vector to this component
*
* @param x
* The x-component of the other vector
* @param y
* The y-component of the other vector
* @param z
* The z-component of the other vector
* @return This vector for chaining.
*/
public Vector3 add(float x, float y, float z) {
return this.set(this.x + x, this.y + y, this.z + z);
}
/**
* Adds the given value to all three components of the vector.
*
* @param values
* The value
* @return This vector for chaining
*/
public Vector3 add(float values) {
return this.set(this.x + values, this.y + values, this.z + values);
}
/**
* Subtracts the given vector from this vector
*
* @param a_vec
* The other vector
* @return This vector for chaining
*/
public Vector3 sub(Vector3 a_vec) {
return this.sub(a_vec.x, a_vec.y, a_vec.z);
}
/**
* Subtracts the other vector from this vector.
*
* @param x
* The x-component of the other vector
* @param y
* The y-component of the other vector
* @param z
* The z-component of the other vector
* @return This vector for chaining
*/
public Vector3 sub(float x, float y, float z) {
return this.set(this.x - x, this.y - y, this.z - z);
}
/**
* Subtracts the given value from all components of this vector
*
* @param value
* The value
* @return This vector for chaining
*/
public Vector3 sub(float value) {
return this.set(this.x - value, this.y - value, this.z - value);
}
/**
* Multiplies all components of this vector by the given value
*
* @param value
* The value
* @return This vector for chaining
*/
public Vector3 mul(float value) {
return this.set(this.x * value, this.y * value, this.z * value);
}
/**
* Multiplies all components of this vector by the given vector3's values
*
* @param other
* The vector3 to multiply by
* @return This vector for chaining
*/
public Vector3 mul(Vector3 other) {
return this.mul(other.x, other.y, other.z);
}
/**
* Multiplies all components of this vector by the given values
*
* @param vx
* X value
* @param vy
* Y value
* @param vz
* Z value
* @return This vector for chaining
*/
public Vector3 mul(float vx, float vy, float vz) {
return this.set(this.x * vx, this.y * vy, this.z * vz);
}
/**
* Divides all components of this vector by the given value
*
* @param value
* The value
* @return This vector for chaining
*/
public Vector3 div(float value) {
return this.mul(1 / value);
}
public Vector3 div(float vx, float vy, float vz) {
return this.mul(1 / vx, 1 / vy, 1 / vz);
}
public Vector3 div(Vector3 other) {
return this.mul(1 / other.x, 1 / other.y, 1 / other.z);
}
/** @return The euclidian length */
public float len() {
return (float) Math.sqrt(x * x + y * y + z * z);
}
/** @return The squared euclidian length */
public float len2() {
return x * x + y * y + z * z;
}
/**
* @param vector
* The other vector
* @return Wether this and the other vector are equal
*/
public boolean idt(Vector3 vector) {
return x == vector.x && y == vector.y && z == vector.z;
}
/**
* @param vector
* The other vector
* @return The euclidian distance between this and the other vector
*/
public float dst(Vector3 vector) {
float a = vector.x - x;
float b = vector.y - y;
float c = vector.z - z;
a *= a;
b *= b;
c *= c;
return (float) Math.sqrt(a + b + c);
}
/**
* Normalizes this vector to unit length
*
* @return This vector for chaining
*/
public Vector3 nor() {
float len = this.len();
if (len == 0) {
return this;
} else {
return this.div(len);
}
}
/**
* @param vector
* The other vector
* @return The dot product between this and the other vector
*/
public float dot(Vector3 vector) {
return x * vector.x + y * vector.y + z * vector.z;
}
/**
* Sets this vector to the cross product between it and the other vector.
*
* @param vector
* The other vector
* @return This vector for chaining
*/
public Vector3 crs(Vector3 vector) {
return this.set(y * vector.z - z * vector.y, z * vector.x - x * vector.z, x * vector.y - y * vector.x);
}
/**
* Sets this vector to the cross product between it and the other vector.
*
* @param x
* The x-component of the other vector
* @param y
* The y-component of the other vector
* @param z
* The z-component of the other vector
* @return This vector for chaining
*/
public Vector3 crs(float x, float y, float z) {
return this.set(this.y * z - this.z * y, this.z * x - this.x * z, this.x * y - this.y * x);
}
/**
* Multiplies the vector by the given matrix.
*
* @param matrix
* The matrix
* @return This vector for chaining
*/
public Vector3 mul(Matrix4 matrix) {
float l_mat[] = matrix.val;
return this.set(x * l_mat[Matrix4.M00] + y * l_mat[Matrix4.M01] + z * l_mat[Matrix4.M02] + l_mat[Matrix4.M03],
x * l_mat[Matrix4.M10] + y * l_mat[Matrix4.M11] + z * l_mat[Matrix4.M12] + l_mat[Matrix4.M13], x
* l_mat[Matrix4.M20] + y * l_mat[Matrix4.M21] + z * l_mat[Matrix4.M22] + l_mat[Matrix4.M23]);
}
/**
* Multiplies this vector by the given matrix dividing by w. This is mostly used to project/unproject vectors via a
* perspective projection matrix.
*
* @param matrix
* The matrix.
* @return This vector for chaining
*/
public Vector3 prj(Matrix4 matrix) {
float l_mat[] = matrix.val;
float l_w = x * l_mat[Matrix4.M30] + y * l_mat[Matrix4.M31] + z * l_mat[Matrix4.M32] + l_mat[Matrix4.M33];
return this.set((x * l_mat[Matrix4.M00] + y * l_mat[Matrix4.M01] + z * l_mat[Matrix4.M02] + l_mat[Matrix4.M03])
/ l_w, (x * l_mat[Matrix4.M10] + y * l_mat[Matrix4.M11] + z * l_mat[Matrix4.M12] + l_mat[Matrix4.M13])
/ l_w, (x * l_mat[Matrix4.M20] + y * l_mat[Matrix4.M21] + z * l_mat[Matrix4.M22] + l_mat[Matrix4.M23])
/ l_w);
}
/**
* Multiplies this vector by the first three columns of the matrix, essentially only applying rotation and scaling.
*
* @param matrix
* The matrix
* @return This vector for chaining
*/
public Vector3 rot(Matrix4 matrix) {
float l_mat[] = matrix.val;
return this.set(x * l_mat[Matrix4.M00] + y * l_mat[Matrix4.M01] + z * l_mat[Matrix4.M02], x
* l_mat[Matrix4.M10] + y * l_mat[Matrix4.M11] + z * l_mat[Matrix4.M12], x * l_mat[Matrix4.M20] + y
* l_mat[Matrix4.M21] + z * l_mat[Matrix4.M22]);
}
/**
* Rotates this vector by the given angle around the given axis.
*
* @param axisX
* the x-component of the axis
* @param axisY
* the y-component of the axis
* @param axisZ
* the z-component of the axis
* @return This vector for chaining
*/
public Vector3 rotate(float angle, float axisX, float axisY, float axisZ) {
return rotate(tmp.set(axisX, axisY, axisZ), angle);
}
/**
* Rotates this vector by the given angle around the given axis.
*
* @param axis
* @param angle
* the angle
* @return This vector for chaining
*/
public Vector3 rotate(Vector3 axis, float angle) {
tmpMat.setToRotation(axis, angle);
return this.mul(tmpMat);
}
/** @return Whether this vector is a unit length vector */
public boolean isUnit() {
return this.len() == 1;
}
/** @return Whether this vector is a zero vector */
public boolean isZero() {
return x == 0 && y == 0 && z == 0;
}
/**
* Linearly interpolates between this vector and the target vector by alpha which is in the range [0,1]. The result
* is stored in this vector.
*
* @param target
* The target vector
* @param alpha
* The interpolation coefficient
* @return This vector for chaining.
*/
public Vector3 lerp(Vector3 target, float alpha) {
Vector3 r = this.mul(1.0f - alpha);
r.add(target.tmp().mul(alpha));
return r;
}
/**
* Spherically interpolates between this vector and the target vector by alpha which is in the range [0,1]. The
* result is stored in this vector.
*
* @param target
* The target vector
* @param alpha
* The interpolation coefficient
* @return This vector for chaining.
*/
public Vector3 slerp(Vector3 target, float alpha) {
float dot = dot(target);
if (dot > 0.99995 || dot < 0.9995) {
this.add(target.tmp().sub(this).mul(alpha));
this.nor();
return this;
}
if (dot > 1)
dot = 1;
if (dot < -1)
dot = -1;
float theta0 = (float) Math.acos(dot);
float theta = theta0 * alpha;
Vector3 v2 = target.tmp().sub(x * dot, y * dot, z * dot);
v2.nor();
return this.mul((float) Math.cos(theta)).add(v2.mul((float) Math.sin(theta))).nor();
}
/** {@inheritDoc} */
public String toString() {
return x + "," + y + "," + z;
}
/**
* Returns the dot product between this and the given vector.
*
* @param x
* The x-component of the other vector
* @param y
* The y-component of the other vector
* @param z
* The z-component of the other vector
* @return The dot product
*/
public float dot(float x, float y, float z) {
return this.x * x + this.y * y + this.z * z;
}
/**
* Returns the squared distance between this point and the given point
*
* @param point
* The other point
* @return The squared distance
*/
public float dst2(Vector3 point) {
float a = point.x - x;
float b = point.y - y;
float c = point.z - z;
a *= a;
b *= b;
c *= c;
return a + b + c;
}
/**
* Returns the squared distance between this point and the given point
*
* @param x
* The x-component of the other point
* @param y
* The y-component of the other point
* @param z
* The z-component of the other point
* @return The squared distance
*/
public float dst2(float x, float y, float z) {
float a = x - this.x;
float b = y - this.y;
float c = z - this.z;
a *= a;
b *= b;
c *= c;
return a + b + c;
}
public float dst(float x, float y, float z) {
return (float) Math.sqrt(dst2(x, y, z));
}
/** {@inheritDoc} */
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + NumberUtils.floatToIntBits(x);
result = prime * result + NumberUtils.floatToIntBits(y);
result = prime * result + NumberUtils.floatToIntBits(z);
return result;
}
/** {@inheritDoc} */
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Vector3 other = (Vector3) obj;
if (NumberUtils.floatToIntBits(x) != NumberUtils.floatToIntBits(other.x))
return false;
if (NumberUtils.floatToIntBits(y) != NumberUtils.floatToIntBits(other.y))
return false;
if (NumberUtils.floatToIntBits(z) != NumberUtils.floatToIntBits(other.z))
return false;
return true;
}
/**
* Compares this vector with the other vector, using the supplied epsilon for fuzzy equality testing.
*
* @param obj
* @param epsilon
* @return whether the vectors are the same.
*/
public boolean epsilonEquals(Vector3 obj, float epsilon) {
if (obj == null)
return false;
if (Math.abs(obj.x - x) > epsilon)
return false;
if (Math.abs(obj.y - y) > epsilon)
return false;
if (Math.abs(obj.z - z) > epsilon)
return false;
return true;
}
/**
* Compares this vector with the other vector, using the supplied epsilon for fuzzy equality testing.
*
* @return whether the vectors are the same.
*/
public boolean epsilonEquals(float x, float y, float z, float epsilon) {
if (Math.abs(x - this.x) > epsilon)
return false;
if (Math.abs(y - this.y) > epsilon)
return false;
if (Math.abs(z - this.z) > epsilon)
return false;
return true;
}
/**
* Scales the vector components by the given scalars.
*
* @param scalarX
* @param scalarY
* @param scalarZ
*/
public Vector3 scale(float scalarX, float scalarY, float scalarZ) {
x *= scalarX;
y *= scalarY;
z *= scalarZ;
return this;
}
}