Skip to content

Instantly share code, notes, and snippets.

@avanderw
Created December 2, 2020 08:36
Show Gist options
  • Save avanderw/2a8ee8f479fff0d31c8eb97b83f898bc to your computer and use it in GitHub Desktop.
Save avanderw/2a8ee8f479fff0d31c8eb97b83f898bc to your computer and use it in GitHub Desktop.
Single class immutable 2D vector.
package net.avdw;
/**
* Single class immutable 2D vector.
*
* @version 2020-12-02 Copied from Vector2D
*/
public class Vector2DConst {
protected static final Double EPSILON = 0.0000001;
protected static final Double EPSILON_SQR = EPSILON * EPSILON;
public final double x;
public final double y;
/**
* @param args empty, Vector2DConst, [ x, y ]
*/
public Vector2DConst(Object... args) {
switch (args.length) {
case 0:
x = 0D;
y = 0D;
break;
case 1:
if (args[0] instanceof Vector2DConst) {
Vector2DConst that = (Vector2DConst) args[0];
this.x = that.x;
this.y = that.y;
break;
}
case 2:
if (args[0] instanceof Number && args[1] instanceof Number) {
x = ((Number) args[0]).doubleValue();
y = ((Number) args[1]).doubleValue();
break;
}
default:
throw new RuntimeException();
}
}
public Vector2DConst add(Object... args) {
Vector2DConst newVector = null;
switch (args.length) {
case 1:
if (args[0] instanceof Vector2DConst) {
Vector2DConst that = (Vector2DConst) args[0];
newVector = new Vector2DConst(this.x + that.x, this.y + that.y);
}
break;
case 2:
if (args[0] instanceof Number && args[1] instanceof Number) {
newVector = new Vector2DConst(this.x + ((Number) args[0]).doubleValue(), this.y + ((Number) args[1]).doubleValue());
}
break;
default:
throw new RuntimeException();
}
return newVector;
}
public Vector2DConst subtract(Object... args) {
Vector2DConst newVector = null;
switch (args.length) {
case 1:
if (args[0] instanceof Vector2DConst) {
Vector2DConst that = (Vector2DConst) args[0];
newVector = new Vector2DConst(this.x - that.x, this.y - that.y);
}
break;
case 2:
if (args[0] instanceof Number && args[1] instanceof Number) {
newVector = new Vector2DConst(this.x - ((Number) args[0]).doubleValue(), this.y - ((Number) args[1]).doubleValue());
}
break;
default:
throw new RuntimeException();
}
return newVector;
}
public Vector2DConst multiply(Object... args) {
Vector2DConst newVector = null;
switch (args.length) {
case 1:
if (args[0] instanceof Vector2DConst) {
Vector2DConst that = (Vector2DConst) args[0];
newVector = new Vector2DConst(this.x * that.x, this.y * that.y);
}
break;
case 2:
if (args[0] instanceof Number && args[1] instanceof Number) {
newVector = new Vector2DConst(this.x * ((Number) args[0]).doubleValue(), this.y * ((Number) args[1]).doubleValue());
}
break;
default:
throw new RuntimeException();
}
return newVector;
}
public Vector2DConst divide(Object... args) {
Vector2DConst newVector = null;
switch (args.length) {
case 1:
if (args[0] instanceof Vector2DConst) {
Vector2DConst that = (Vector2DConst) args[0];
newVector = new Vector2DConst(this.x / that.x, this.y / that.y);
}
break;
case 2:
if (args[0] instanceof Number && args[1] instanceof Number) {
newVector = new Vector2DConst(this.x / ((Number) args[0]).doubleValue(), this.y / ((Number) args[1]).doubleValue());
}
break;
default:
throw new RuntimeException();
}
return newVector;
}
public Vector2DConst scale(Double scale) {
return multiply(scale, scale);
}
public Double length() {
return Math.sqrt(x * x + y * y);
}
public Double lengthSqr() {
return x * x + y * y;
}
public Vector2DConst length(Double length) {
if (isZero()) {
if (Math.abs(length) < EPSILON) {
return this;
} else {
throw new RuntimeException("don't have a direction to scale in");
}
} else {
return scale(length / length());
}
}
public Vector2DConst normalise() {
return length(1D);
}
public Double distance(Object... args) {
double xd = 0D, yd = 0D;
switch (args.length) {
case 1:
if (args[0] instanceof Vector2DConst) {
Vector2DConst that = (Vector2DConst) args[0];
xd = this.x - that.x;
yd = this.y - that.y;
}
break;
case 2:
if (args[0] instanceof Number && args[1] instanceof Number) {
xd = x - ((Number) args[0]).doubleValue();
yd = y - ((Number) args[1]).doubleValue();
}
break;
default:
throw new RuntimeException();
}
return Math.sqrt(xd * xd + yd * yd);
}
public Double distanceSqr(Object... args) {
double xd = 0D, yd = 0D;
switch (args.length) {
case 1:
if (args[0] instanceof Vector2DConst) {
Vector2DConst that = (Vector2DConst) args[0];
xd = this.x - that.x;
yd = this.y - that.y;
}
break;
case 2:
if (args[0] instanceof Number && args[1] instanceof Number) {
xd = x - ((Number) args[0]).doubleValue();
yd = y - ((Number) args[1]).doubleValue();
}
break;
default:
throw new RuntimeException();
}
return xd * xd + yd * yd;
}
public Boolean equals(Object... args) {
boolean equal = true;
switch (args.length) {
case 1:
if (args[0] instanceof Vector2DConst) {
Vector2DConst that = (Vector2DConst) args[0];
equal = equal && Math.abs(this.x - that.x) > EPSILON;
equal = equal && Math.abs(this.y - that.y) > EPSILON;
}
break;
case 2:
if (args[0] instanceof Number && args[1] instanceof Number) {
equal = equal && Math.abs(x - ((Number) args[0]).doubleValue()) > EPSILON;
equal = equal && Math.abs(y - ((Number) args[1]).doubleValue()) > EPSILON;
}
break;
default:
throw new RuntimeException();
}
return equal;
}
public Boolean isNormalized() {
return Math.abs(length() - 1) < EPSILON;
}
public Boolean isZero() {
return Math.abs(x) < EPSILON && Math.abs(y) < EPSILON;
}
public Boolean isNear(Object... args) {
return distanceSqr(args) < EPSILON_SQR;
}
public Boolean isWithin(Double epsilon, Object... args) {
return distanceSqr(args) < epsilon * epsilon;
}
public Boolean isValid() {
return !Double.isNaN(x) && !Double.isNaN(y) && Double.isFinite(x) && Double.isFinite(y);
}
public Double dot(Object... args) {
double dot = Double.NaN;
switch (args.length) {
case 1:
if (args[0] instanceof Vector2DConst) {
Vector2DConst that = (Vector2DConst) args[0];
dot = this.x * that.x + this.y * that.y;
}
break;
case 2:
if (args[0] instanceof Number && args[1] instanceof Number) {
dot = x * ((Number) args[0]).doubleValue() + y * ((Number) args[1]).doubleValue();
}
break;
default:
throw new RuntimeException();
}
return dot;
}
public Double cross(Object... args) {
double cross = Double.NaN;
switch (args.length) {
case 1:
if (args[0] instanceof Vector2DConst) {
Vector2DConst that = (Vector2DConst) args[0];
cross = this.x * that.y - this.y * that.x;
}
break;
case 2:
if (args[0] instanceof Number && args[1] instanceof Number) {
cross = x * ((Number) args[1]).doubleValue() - y * ((Number) args[0]).doubleValue();
}
break;
default:
throw new RuntimeException();
}
return cross;
}
public Boolean isNormalTo(Object... args) {
return dot(args) < EPSILON;
}
public Double angle() {
double ang = Math.atan2(y, x);
if (ang < 0) {
ang += Math.PI + Math.PI;
}
return ang;
}
public Vector2DConst angle(Double radians) {
final Double len = length();
return new Vector2DConst(len * Math.cos(radians), len * Math.sin(radians));
}
public Double angleBetween(Object... args) {
double angle = Double.NaN;
switch (args.length) {
case 1:
if (args[0] instanceof Vector2DConst) {
Vector2DConst that = (Vector2DConst) args[0];
angle = that.angle() - this.angle();
}
break;
case 2:
if (args[0] instanceof Number && args[1] instanceof Number) {
angle = new Vector2DConst(((Number) args[0]).doubleValue(), ((Number) args[1]).doubleValue()).angle() - this.angle();
}
break;
default:
throw new RuntimeException();
}
if (angle > Math.PI) {
angle -= 2 * Math.PI;
} else if (angle < -Math.PI) {
angle += 2 * Math.PI;
}
return angle;
}
public Vector2DConst rotate(Double radians) {
final double s = Math.sin(radians);
final double c = Math.cos(radians);
double newX = x * c - y * s;
double newY = x * s + y * c;
return new Vector2DConst(newX, newY);
}
public Vector2DConst normalRight() {
return new Vector2DConst(-y, x);
}
public Vector2DConst normalLeft() {
return new Vector2DConst(y, -x);
}
public Vector2DConst negate() {
return new Vector2DConst(-x, -y);
}
public Vector2DConst lerp(Double t, Object... args) {
Vector2DConst newVector = null;
switch (args.length) {
case 1:
if (args[0] instanceof Vector2DConst) {
Vector2DConst that = (Vector2DConst) args[0];
newVector = new Vector2DConst(x + t * (that.x - x), y + t * (that.y - y));
}
break;
case 2:
if (args[0] instanceof Number && args[1] instanceof Number) {
newVector = new Vector2DConst(x + t * (((Number) args[0]).doubleValue() - x), y + t * (((Number) args[1]).doubleValue() - y));
}
break;
default:
throw new RuntimeException();
}
return newVector;
}
public Vector2DConst slerp(Double t, Object... args) {
final Double cosTheta = dot(args);
final double theta = Math.acos(cosTheta);
final double sinTheta = Math.sin(theta);
final Double w1 = Math.sin((1 - t) * theta) / sinTheta;
final Double w2 = Math.sin(t * theta) / sinTheta;
final Vector2DConst to = new Vector2DConst(args);
return scale(w1).add(to.scale(w2));
}
public Vector2DConst reflect(Object... args) {
Vector2DConst newVector = null;
double d;
switch (args.length) {
case 1:
if (args[0] instanceof Vector2DConst) {
Vector2DConst that = (Vector2DConst) args[0];
d = 2 * (x * that.x + y * that.y);
newVector = subtract(d * that.x, d * that.y);
}
break;
case 2:
if (args[0] instanceof Number && args[1] instanceof Number) {
d = 2 * (x * ((Number) args[0]).doubleValue() + y * ((Number) args[1]).doubleValue());
newVector = subtract(d * ((Number) args[0]).doubleValue(), d * ((Number) args[1]).doubleValue());
}
break;
default:
throw new RuntimeException();
}
return newVector;
}
public Vector2DConst project(Object... args) {
double scalar = Double.NaN;
Vector2DConst projVector = null;
switch (args.length) {
case 1:
if (args[0] instanceof Vector2DConst) {
projVector = (Vector2DConst) args[0];
scalar = dot(projVector) / projVector.lengthSqr();
}
break;
case 2:
if (args[0] instanceof Number && args[1] instanceof Number) {
projVector = new Vector2DConst(args[0], args[1]);
scalar = dot(projVector) / projVector.lengthSqr();
}
break;
default:
throw new RuntimeException();
}
return projVector.scale(scalar);
}
public Vector2DConst offsetPolar(Double radius, Double angle) {
return new Vector2DConst(x + radius * Math.cos(angle), y + radius * Math.sin(angle));
}
public Vector2DConst copy() {
return new Vector2DConst(this);
}
@Override
public String toString() {
return "[" + x + "," + y + "]";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment