2021-04-29 14:45:18 +00:00
|
|
|
package uulm.teamname.marvelous.gamelibrary;
|
2021-04-29 14:39:10 +00:00
|
|
|
|
2021-05-11 18:26:57 +00:00
|
|
|
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
2021-05-30 15:00:59 +00:00
|
|
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
2021-05-31 21:38:22 +00:00
|
|
|
import uulm.teamname.marvelous.gamelibrary.json.ingame.deserialize.IntVector2Deserializer;
|
|
|
|
import uulm.teamname.marvelous.gamelibrary.json.ingame.serialize.IntVector2Serializer;
|
2021-05-11 18:26:57 +00:00
|
|
|
|
2021-04-29 14:39:10 +00:00
|
|
|
import java.io.Serializable;
|
|
|
|
import java.util.Objects;
|
|
|
|
|
2021-04-30 21:19:58 +00:00
|
|
|
/** Represents a 2d vector of integers. */
|
2021-05-11 18:26:57 +00:00
|
|
|
@JsonDeserialize(using = IntVector2Deserializer.class)
|
2021-05-30 15:00:59 +00:00
|
|
|
@JsonSerialize(using = IntVector2Serializer.class)
|
2021-04-29 14:39:10 +00:00
|
|
|
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);
|
|
|
|
|
2021-05-27 15:08:08 +00:00
|
|
|
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),
|
|
|
|
};
|
|
|
|
|
2021-04-29 14:39:10 +00:00
|
|
|
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) {
|
2021-06-04 11:47:16 +00:00
|
|
|
return (float)Math.sqrt((double) x * x + y * y);
|
2021-04-29 14:39:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public float length() {
|
|
|
|
return IntVector2.length(this.x, this.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static float length2(int x, int y) {
|
2021-06-04 11:47:16 +00:00
|
|
|
return (float) x * x + y * y;
|
2021-04-29 14:39:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2021-06-04 03:13:37 +00:00
|
|
|
return new IntVector2(this.x - x, this.y - y);
|
2021-04-29 14:39:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public IntVector2 sub(IntVector2 v) {
|
|
|
|
return sub(v.x, v.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
public IntVector2 add(int x, int y) {
|
2021-06-04 03:13:37 +00:00
|
|
|
return new IntVector2(this.x + x, this.y + y);
|
2021-04-29 14:39:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2021-06-04 03:13:37 +00:00
|
|
|
return new IntVector2((int)(this.x * x), (int)(this.y * y));
|
2021-04-29 14:39:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2021-06-04 11:47:16 +00:00
|
|
|
final float x_d = (float) x2 - x1;
|
|
|
|
final float y_d = (float) y2 - y1;
|
2021-04-29 14:39:10 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2021-05-11 01:50:24 +00:00
|
|
|
/** 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) {
|
2021-06-04 11:47:16 +00:00
|
|
|
final float x_d = (float) x2 - x1;
|
|
|
|
final float y_d = (float) y2 - y1;
|
2021-05-11 01:50:24 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2021-05-02 13:34:42 +00:00
|
|
|
public static float distanceManhattan(int x1, int y1, int x2, int y2) {
|
2021-06-04 11:47:16 +00:00
|
|
|
final float x_d = (float) x2 - x1;
|
|
|
|
final float y_d = (float) y2 - y1;
|
2021-05-02 13:34:42 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2021-04-29 14:39:10 +00:00
|
|
|
public static float distance2(int x1, int y1, int x2, int y2) {
|
2021-06-04 11:47:16 +00:00
|
|
|
final float x_d = (float) x2 - x1;
|
|
|
|
final float y_d = (float) y2 - y1;
|
2021-04-29 14:39:10 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|