/*
* Copyright (c) 2012. HappyDroids LLC, All rights reserved.
*/
package com.happydroids.droidtowers.math;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Matrix3;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.io.Serializable;
import static com.happydroids.droidtowers.TowerConsts.GRID_UNIT_SIZE;
/**
* Encapsulates a 2D vector. Allows chaining methods by returning a reference to itself
* Copied from Vector2 which uses floats, I wanted integers so I didn't have to constantly cast and round
* for my grid points.
*
* @author badlogicgames@gmail.com
* @author phil@happydroids.com
*/
public class GridPoint implements Serializable {
/**
* Static temporary vector. Use with care! Use only when sure other code will not also use this.
*
* @see #tmp() *
*/
public final static GridPoint TMP = new GridPoint();
public final static GridPoint X = new GridPoint(1, 0);
public final static GridPoint Y = new GridPoint(0, 1);
public final static GridPoint ZERO = new GridPoint(0, 0);
/**
* the x-component of this vector *
*/
public int x;
/**
* the y-component of this vector *
*/
public int y;
/**
* Constructs a new vector at (0,0)
*/
public GridPoint() {
}
/**
* Constructs a vector with the given components
*
* @param x The x-component
* @param y The y-component
*/
public GridPoint(int x, int y) {
this.x = x;
this.y = y;
}
/**
* Constructs a vector from the given vector
*
* @param v The vector
*/
public GridPoint(GridPoint v) {
set(v);
}
/**
* @return a copy of this vector
*/
public GridPoint cpy() {
return new GridPoint(this);
}
/**
* @return The euclidian length
*/
public int len() {
return (int) Math.sqrt(x * x + y * y);
}
/**
* @return The squared euclidian length
*/
public int len2() {
return x * x + y * y;
}
/**
* Sets this vector from the given vector
*
* @param v The vector
* @return This vector for chaining
*/
public GridPoint set(GridPoint 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 GridPoint set(int x, int 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 GridPoint sub(GridPoint v) {
x -= v.x;
y -= v.y;
return this;
}
/**
* Normalizes this vector
*
* @return This vector for chaining
*/
public GridPoint nor() {
int 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 GridPoint add(GridPoint 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 GridPoint add(int x, int 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 int dot(GridPoint v) {
return x * v.x + y * v.y;
}
/**
* Multiplies this vector by a scalar
*
* @param scalar The scalar
* @return This vector for chaining
*/
public GridPoint mul(int scalar) {
x *= scalar;
y *= scalar;
return this;
}
/**
* @param v The other vector
* @return the distance between this and the other vector
*/
public int dst(GridPoint v) {
final int x_d = v.x - x;
final int y_d = v.y - y;
return (int) 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 int dst(int x, int y) {
final int x_d = x - this.x;
final int y_d = y - this.y;
return (int) 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 int dst2(GridPoint v) {
final int x_d = v.x - x;
final int 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 int dst2(int x, int y) {
final int x_d = x - this.x;
final int 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 GridPoint sub(int x, int 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 GridPoint tmp() {
return TMP.set(this);
}
/**
* Multiplies this vector by the given matrix
*
* @param mat the matrix
* @return this vector
*/
public GridPoint mul(Matrix3 mat) {
int x = (int) (this.x * mat.val[0] + this.y * mat.val[3] + mat.val[6]);
int y = (int) (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 int crs(GridPoint 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 int crs(int x, int 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 int angle() {
int angle = (int) (Math.atan2(y, x) * MathUtils.radiansToDegrees);
if (angle < 0) {
angle += 360;
}
return angle;
}
/**
* Rotates the Vector2 by the given angle, counter-clockwise.
*
* @param angle the angle in degrees
* @return the
*/
public GridPoint rotate(int angle) {
int rad = (int) (angle * MathUtils.degreesToRadians);
int cos = (int) Math.cos(rad);
int sin = (int) Math.sin(rad);
int newX = this.x * cos - this.y * sin;
int 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 GridPoint lerp(GridPoint target, int alpha) {
GridPoint r = this.mul(1 - alpha);
r.add(target.tmp().mul(alpha));
return r;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + 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;
}
GridPoint other = (GridPoint) obj;
return x == other.x && y == other.y;
}
/**
* 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(GridPoint obj, int epsilon) {
return obj != null && Math.abs(obj.x - x) <= epsilon && Math.abs(obj.y - y) <= epsilon;
}
@JsonIgnore
public float getWorldX() {
return GRID_UNIT_SIZE * x;
}
@JsonIgnore
public float getWorldY() {
return GRID_UNIT_SIZE * y;
}
}