package uulm.teamname.marvelous.gamelibrary; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import uulm.teamname.marvelous.gamelibrary.json.ingame.IntVector2Deserializer; import java.io.Serializable; import java.util.Objects; /** Represents a 2d vector of integers. */ @JsonDeserialize(using = IntVector2Deserializer.class) public class IntVector2 implements Serializable { private int x; private int y; public final static IntVector2 X = new IntVector2(1, 0); public final static IntVector2 Y = new IntVector2(0, 1); public final static IntVector2 Zero = new IntVector2(0, 0); public final static IntVector2[] CardinalDirections = { new IntVector2(1, 0), new IntVector2(0, 1), new IntVector2(1, 1), new IntVector2(-1, 0), new IntVector2(0, -1), new IntVector2(-1, -1), new IntVector2(1, -1), new IntVector2(-1, 1), }; private final static float nearZero = 0.000000001f; public IntVector2(int x, int y) { set(x, y); } public IntVector2(IntVector2 v) { set(v); } public IntVector2 copy() { return new IntVector2(this); } public int getX() { return x; } public int getY() { return y; } public static float length(int x, int y) { return (float)Math.sqrt(x * x + y * y); } public float length() { return IntVector2.length(this.x, this.y); } public static float length2(int x, int y) { return x * x + y * y; } public float length2 () { return IntVector2.length2(this.x, this.y); } public IntVector2 set(int x, int y) { this.x = x; this.y = y; return this; } public IntVector2 set(IntVector2 v) { return set(v.x, v.y); } public IntVector2 sub(int x, int y) { this.x -= x; this.y -= y; return this; } public IntVector2 sub(IntVector2 v) { return sub(v.x, v.y); } public IntVector2 add(int x, int y) { this.x += x; this.y += y; return this; } public IntVector2 add(IntVector2 v) { return add(v.x, v.y); } public static float dot(float x1, float y1, float x2, float y2) { return x1 * x2 + y1 * y2; } public float dot(float ox, float oy) { return IntVector2.dot(this.x, this.y, ox, oy); } public float dot(IntVector2 v) { return dot(v.x, v.y); } public IntVector2 scale(float x, float y) { this.x *= x; this.y *= y; return this; } public IntVector2 scale(float scalar) { return scale(scalar, scalar); } public IntVector2 scale(IntVector2 v) { return scale(v.x, v.y); } public static float distance(int x1, int y1, int x2, int y2) { final float x_d = x2 - x1; final float y_d = y2 - y1; return (float)Math.sqrt(x_d * x_d + y_d * y_d); } public float distance(int x, int y) { return IntVector2.distance(this.x, this.y, x, y); } public float distance(IntVector2 v) { return distance(v.x, v.y); } /** Equivalent to the minimum amount of king moves to go from A to B in chess */ public static float distanceChebyshev(int x1, int y1, int x2, int y2) { final float x_d = x2 - x1; final float y_d = y2 - y1; return Math.max(Math.abs(x_d), Math.abs(y_d)); } /** Equivalent to the minimum amount of king moves to go from A to B in chess */ public float distanceChebyshev(int x, int y) { return IntVector2.distanceChebyshev(this.x, this.y, x, y); } /** Equivalent to the minimum amount of king moves to go from A to B in chess */ public float distanceChebyshev(IntVector2 v) { return distanceChebyshev(v.x, v.y); } public static float distanceManhattan(int x1, int y1, int x2, int y2) { final float x_d = x2 - x1; final float y_d = y2 - y1; return Math.abs(x_d) + Math.abs(y_d); } public float distanceManhattan(int x, int y) { return IntVector2.distanceManhattan(this.x, this.y, x, y); } public float distanceManhattan(IntVector2 v) { return distanceManhattan(v.x, v.y); } public static float distance2(int x1, int y1, int x2, int y2) { final float x_d = x2 - x1; final float y_d = y2 - y1; return x_d * x_d + y_d * y_d; } public float distance2(int x, int y) { return IntVector2.distance2(this.x, this.y, x, y); } public float distance2(IntVector2 v) { return distance2(v.x, v.y); } public IntVector2 setLength(float len) { return setLength2(len * len); } public IntVector2 setLength2(float len2) { float oldLen2 = length2(); return (oldLen2 == 0 || oldLen2 == len2) ? this : scale((float)Math.sqrt(len2 / oldLen2)); } public String toString() { return "(" + x + "," + y + ")"; } public IntVector2 fromString(String v) throws NumberFormatException { int s = v.indexOf(',', 1); if (s != -1 && v.charAt(0) == '(' && v.charAt(v.length() - 1) == ')') { try { int x = Integer.parseInt(v.substring(1, s)); int y = Integer.parseInt(v.substring(s + 1, v.length() - 1)); return this.set(x, y); }catch (NumberFormatException ex) { //ok } } throw new NumberFormatException("Malformed IntVector2: " + v); } public float cross(float x, float y) { return this.x * y - this.y * x; } public float cross(IntVector2 v) { return cross(v.x, v.y); } public boolean isUnit(final float margin) { return Math.abs(length2() - 1f) < margin; } public boolean isUnit() { return isUnit(nearZero); } public boolean isZero() { return x == 0 && y == 0; } public boolean isZero(final float margin) { return length2() < margin; } public boolean isOnLine(IntVector2 other, float epsilon) { return Math.abs(x * other.y - y * other.x) <= epsilon; } public boolean isOnLine(IntVector2 other) { return isOnLine(other, nearZero); } public boolean isCollinear(IntVector2 other, float epsilon) { return isOnLine(other, epsilon) && dot(other) > 0f; } public boolean isCollinear(IntVector2 other) { return isOnLine(other) && dot(other) > 0f; } public boolean isCollinearOpposite(IntVector2 other, float epsilon) { return isOnLine(other, epsilon) && dot(other) < 0f; } public boolean isCollinearOpposite(IntVector2 other) { return isOnLine(other) && dot(other) < 0f; } public boolean isPerpendicular(IntVector2 vector) { return isPerpendicular(vector,nearZero); } public boolean isPerpendicular(IntVector2 vector, float epsilon) { return Math.abs(dot(vector)) <= epsilon; } public boolean hasSameDirection(IntVector2 vector) { return dot(vector) > 0; } public boolean hasOppositeDirection(IntVector2 vector) { return dot(vector) < 0; } public IntVector2 setZero() { this.x = 0; this.y = 0; return this; } @Override public boolean equals(Object o) { if(this == o) return true; if(o == null || getClass() != o.getClass()) return false; IntVector2 that = (IntVector2) o; return x == that.x && y == that.y; } @Override public int hashCode() { return Objects.hash(x, y); } }