package org.terasology.math; import javax.vecmath.Vector3d; import javax.vecmath.Vector3f; import java.io.Serializable; /** * Vector3i - integer vector class in the style of VecMath. * * @author Immortius <immortius@gmail.com> */ public class Vector3i extends javax.vecmath.Tuple3i implements Serializable { private static final long serialVersionUID = -1965792038041767639L; public static Vector3i zero() { return new Vector3i(0, 0, 0); } public static Vector3i unitX() { return new Vector3i(1, 0, 0); } public static Vector3i unitY() { return new Vector3i(0, 1, 0); } public static Vector3i unitZ() { return new Vector3i(0, 0, 1); } public static Vector3i unitXY() { return new Vector3i(1, 1, 0); } public static Vector3i unitXZ() { return new Vector3i(1, 0, 1); } public static Vector3i unitYZ() { return new Vector3i(0, 1, 1); } public static Vector3i one() { return new Vector3i(1, 1, 1); } public static Vector3i min() { return new Vector3i(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE); } public static Vector3i max() { return new Vector3i(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE); } public static Vector3i north() { return unitZ(); } public static Vector3i south() { return new Vector3i(0, 0, -1); } public static Vector3i west() { return unitX(); } public static Vector3i east() { return new Vector3i(-1, 0, 0); } public static Vector3i up() { return unitY(); } public static Vector3i down() { return new Vector3i(0, -1, 0); } /** * Constructor instantiates a new <code>Vector3i</code> with default * values of (0,0,0). */ public Vector3i() { x = y = z = 0; } /** * Constructs the integer version of a Vector3f, by flooring it * * @param other */ public Vector3i(Vector3f other) { this.x = TeraMath.floorToInt(other.x); this.y = TeraMath.floorToInt(other.y); this.z = TeraMath.floorToInt(other.z); } public Vector3i(float x, float y, float z) { this.x = TeraMath.floorToInt(x); this.y = TeraMath.floorToInt(y); this.z = TeraMath.floorToInt(z); } /** * Constructs the integer version of a Vector3f, by adding an offset and flooring it * * @param other */ public Vector3i(Vector3f other, float offset) { this.x = TeraMath.floorToInt(other.x + offset); this.y = TeraMath.floorToInt(other.y + offset); this.z = TeraMath.floorToInt(other.z + offset); } public Vector3i(float x, float y, float z, float offset) { this.x = TeraMath.floorToInt(x + offset); this.y = TeraMath.floorToInt(y + offset); this.z = TeraMath.floorToInt(z + offset); } /** * Constructor instantiates a new <code>Vector3i</code> with provides * values. * * @param x the x value of the vector. * @param y the y value of the vector. * @param z the z value of the vector. */ public Vector3i(int x, int y, int z) { this.x = x; this.y = y; this.z = z; } /** * Constructor instantiates a new <code>Vector3i</code> that is a copy * of the provided vector * * @param other The Vector3i to copy */ public Vector3i(Vector3i other) { this.x = other.x; this.y = other.y; this.z = other.z; } @Override public Vector3i clone() { return (Vector3i) super.clone(); } /** * Returns true if this vector is a unit vector (lengthSquared() == 1), * returns false otherwise. * * @return true if this vector is a unit vector (lengthSquared() == 1), * or false otherwise. */ public boolean isUnitVector() { return (Math.abs(x) + Math.abs(y) + Math.abs(z)) == 1; } /** * Calculates the total distance in axis-aligned steps between this and * other vector (manhattan distance). This is the distance that is traveled * if movement is restricted to adjacent vectors. * * @param other the other vector to test * @return the total distance in axis-aligned steps between this and * other vector (manhattan distance) */ public int gridDistance(Vector3i other) { return Math.abs(other.x - x) + Math.abs(other.y - y) + Math.abs(other.z - z); } /** * Calculates the total magnitude of the vector as a sum of its axis aligned * dimensions (manhattan distance) * * @return the total magnitude of the vector as a sum of its axis aligned * dimensions (manhattan distance) */ public int gridMagnitude() { return Math.abs(x) + Math.abs(y) + Math.abs(z); } /** * <code>lengthSquared</code> calculates the squared value of the * magnitude of the vector. * * @return the magnitude squared of the vector. */ public int lengthSquared() { return x * x + y * y + z * z; } /** * @return the magnitude of the vector. */ public float length() { return (float) Math.sqrt(lengthSquared()); } /** * <code>distanceSquared</code> calculates the distance squared between * this vector and vector v. * * @param v the second vector to determine the distance squared. * @return the distance squared between the two vectors. */ public int distanceSquared(Vector3i v) { int dx = x - v.x; int dy = y - v.y; int dz = z - v.z; return (dx * dx + dy * dy + dz * dz); } /** * <code>distance</code> calculates the distance between this vector and * vector v. * * @param v the second vector to determine the distance. * @return the distance between the two vectors. */ public float distance(Vector3i v) { return (float) Math.sqrt(distanceSquared(v)); } public void add(int x, int y, int z) { this.x += x; this.y += y; this.z += z; } public void sub(int x, int y, int z) { this.x -= x; this.y -= y; this.z -= z; } /** * <code>mult</code> multiplies this vector by a scalar. The resultant * vector is returned. * * @param scalar the value to multiply this vector by. */ public void mult(int scalar) { x *= scalar; y *= scalar; z *= scalar; } /** * <code>mult</code> pairwise multiplies this vector by the provided values. * * @param x * @param y * @param z */ public void mult(int x, int y, int z) { this.x *= x; this.y *= y; this.z *= z; } /** * <code>mult</code> pairwise multiplies this vector by <code>other</code>. * * @param other */ public void mult(Vector3i other) { mult(other.x, other.y, other.z); } /** * <code>divide</code> divides the values of this vector by a scalar. * * @param scalar the value to divide this vectors attributes by. */ public void divide(int scalar) { x /= scalar; y /= scalar; z /= scalar; } /** * <code>divide</code> pairwise divides the values of this vector. * * @param x * @param y * @param z */ public void divide(int x, int y, int z) { this.x /= x; this.y /= y; this.z /= z; } /** * <code>divide</code> pairwise divides the values of this vector by a <code>other</code>. * * @param other the value to divide this vectors attributes by. */ public void divide(Vector3i other) { divide(other.x, other.y, other.z); } /** * <code>min</code> sets each component to the min of this and <code>other</code> * * @param other */ public void min(Vector3i other) { x = Math.min(x, other.x); y = Math.min(y, other.y); z = Math.min(z, other.z); } /** * <code>max</code> sets each component to the max of this and <code>other</code> * * @param other */ public void max(Vector3i other) { x = Math.max(x, other.x); y = Math.max(y, other.y); z = Math.max(z, other.z); } /** * <code>reset</code> resets this vector's data to zero internally. */ public Vector3i reset() { x = y = z = 0; return this; } @Override public boolean equals(Object o) { if (!(o instanceof Vector3i)) { return false; } if (this == o) { return true; } Vector3i comp = (Vector3i) o; return x == comp.x && y == comp.y && z == comp.z; } /** * <code>hashCode</code> returns a unique code for this vector object based * on it's values. If two vectors are logically equivalent, they will return * the same hash code value. * * @return the hash code value of this vector. */ @Override public int hashCode() { // idea: use the 10 least significant bits of each dimension and merge // them next to each other into one 32 bit // its less likely that the cache contains chunks that are far away from // x and z use 11 instead of 10 bits int hash = 0; hash += (x - Integer.MIN_VALUE) & 0x07FF; hash <<= 10; hash += (y - Integer.MIN_VALUE) & 0x03FF; hash <<= 11; hash += (z - Integer.MIN_VALUE) & 0x07FF; return hash; } @Override public String toString() { return "(" + x + ", " + y + ", " + z + ")"; } /** * @return The equivalent Vector3f */ public Vector3f toVector3f() { return new Vector3f(x, y, z); } /** * @return The equivalent Vector3d */ public Vector3d toVector3d() { return new Vector3d(x, y, z); } }