/******************************************************************************* * 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 2D vector. Allows chaining methods by returning a reference to itself * * @author badlogicgames@gmail.com */ public class Vector2 implements Serializable { private static final long serialVersionUID = 913902788239530931L; /** * Static temporary vector. Use with care! Use only when sure other code will not also use this. * * @see #tmp() **/ public final static Vector2 tmp = new Vector2(), tmp2 = new Vector2(), tmp3 = new Vector2(); public final static Vector2 X = new Vector2(1, 0); public final static Vector2 Y = new Vector2(0, 1); public final static Vector2 Zero = new Vector2(0, 0); /** the x-component of this vector **/ public float x; /** the y-component of this vector **/ public float y; /** Constructs a new vector at (0,0) */ public Vector2() { } /** * Constructs a vector with the given components * * @param x * The x-component * @param y * The y-component */ public Vector2(float x, float y) { this.x = x; this.y = y; } /** * Constructs a vector from the given vector * * @param v * The vector */ public Vector2(Vector2 v) { set(v); } /** @return a copy of this vector */ public Vector2 cpy() { return new Vector2(this); } /** @return The euclidian length */ public float len() { return (float) Math.sqrt(x * x + y * y); } /** @return The squared euclidian length */ public float len2() { return x * x + y * y; } /** * Sets this vector from the given vector * * @param v * The vector * @return This vector for chaining */ public Vector2 set(Vector2 v) { x = v.x; y = v.y; return this; } /** * Sets the components of this vector * * @param x * The x-component * @param y * The y-component * @return This vector for chaining */ public Vector2 set(float x, float y) { this.x = x; this.y = y; return this; } /** * Substracts the given vector from this vector. * * @param v * The vector * @return This vector for chaining */ public Vector2 sub(Vector2 v) { x -= v.x; y -= v.y; return this; } /** * Normalizes this vector * * @return This vector for chaining */ public Vector2 nor() { float len = len(); if (len != 0) { x /= len; y /= len; } return this; } /** * Adds the given vector to this vector * * @param v * The vector * @return This vector for chaining */ public Vector2 add(Vector2 v) { x += v.x; y += v.y; return this; } /** * Adds the given components to this vector * * @param x * The x-component * @param y * The y-component * @return This vector for chaining */ public Vector2 add(float x, float y) { this.x += x; this.y += y; return this; } /** * @param v * The other vector * @return The dot product between this and the other vector */ public float dot(Vector2 v) { return x * v.x + y * v.y; } /** * Multiplies this vector by a scalar * * @param scalar * The scalar * @return This vector for chaining */ public Vector2 mul(float scalar) { x *= scalar; y *= scalar; return this; } /** * Multiplies this vector by a scalar * * @return This vector for chaining */ public Vector2 mul(float x, float y) { this.x *= x; this.y *= y; return this; } public Vector2 div(float value) { return this.mul(1 / value); } public Vector2 div(float vx, float vy) { return this.mul(1 / vx, 1 / vy); } public Vector2 div(Vector2 other) { return this.mul(1 / other.x, 1 / other.y); } /** * @param v * The other vector * @return the distance between this and the other vector */ public float dst(Vector2 v) { final float x_d = v.x - x; final float y_d = v.y - y; return (float) Math.sqrt(x_d * x_d + y_d * y_d); } /** * @param x * The x-component of the other vector * @param y * The y-component of the other vector * @return the distance between this and the other vector */ public float dst(float x, float y) { final float x_d = x - this.x; final float y_d = y - this.y; return (float) Math.sqrt(x_d * x_d + y_d * y_d); } /** * @param v * The other vector * @return the squared distance between this and the other vector */ public float dst2(Vector2 v) { final float x_d = v.x - x; final float y_d = v.y - y; return x_d * x_d + y_d * y_d; } /** * @param x * The x-component of the other vector * @param y * The y-component of the other vector * @return the squared distance between this and the other vector */ public float dst2(float x, float y) { final float x_d = x - this.x; final float y_d = y - this.y; return x_d * x_d + y_d * y_d; } public String toString() { return "[" + x + ":" + y + "]"; } /** * Substracts the other vector from this vector. * * @param x * The x-component of the other vector * @param y * The y-component of the other vector * @return This vector for chaining */ public Vector2 sub(float x, float y) { this.x -= x; this.y -= y; return 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. Use with care as this is backed by a single static Vector2 instance. * v1.tmp().add( v2.tmp() ) will not work! */ public Vector2 tmp() { return tmp.set(this); } /** * Multiplies this vector by the given matrix * * @param mat * the matrix * @return this vector */ public Vector2 mul(Matrix3 mat) { float x = this.x * mat.val[0] + this.y * mat.val[3] + mat.val[6]; float y = this.x * mat.val[1] + this.y * mat.val[4] + mat.val[7]; this.x = x; this.y = y; return this; } /** * Calculates the 2D cross product between this and the given vector. * * @param v * the other vector * @return the cross product */ public float crs(Vector2 v) { return this.x * v.y - this.y * v.x; } /** * Calculates the 2D cross product between this and the given vector. * * @param x * the x-coordinate of the other vector * @param y * the y-coordinate of the other vector * @return the cross product */ public float crs(float x, float y) { return this.x * y - this.y * x; } /** * @return the angle in degrees of this vector (point) relative to the x-axis. Angles are counter-clockwise and * between 0 and 360. */ public float angle() { float angle = (float) Math.atan2(y, x) * MathUtils.radiansToDegrees; if (angle < 0) angle += 360; return angle; } /** * Sets the angle of the vector. * * @param angle * The angle to set. */ public void setAngle(float angle) { this.set(len(), 0f); this.rotate(angle); } /** * Rotates the Vector2 by the given angle, counter-clockwise. * * @param degrees * the angle in degrees */ public Vector2 rotate(float degrees) { float rad = degrees * MathUtils.degreesToRadians; float cos = (float) Math.cos(rad); float sin = (float) Math.sin(rad); float newX = this.x * cos - this.y * sin; float newY = this.x * sin + this.y * cos; this.x = newX; this.y = newY; return this; } /** * 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 Vector2 lerp(Vector2 target, float alpha) { Vector2 r = this.mul(1.0f - alpha); r.add(target.tmp().mul(alpha)); return r; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + NumberUtils.floatToIntBits(x); result = prime * result + NumberUtils.floatToIntBits(y); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Vector2 other = (Vector2) obj; if (NumberUtils.floatToIntBits(x) != NumberUtils.floatToIntBits(other.x)) return false; if (NumberUtils.floatToIntBits(y) != NumberUtils.floatToIntBits(other.y)) 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(Vector2 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; return true; } }