package ptjava;
import java.util.concurrent.ThreadLocalRandom;
import jdk.incubator.vector.DoubleVector;
import jdk.incubator.vector.VectorMask;
import jdk.incubator.vector.VectorOperators;
import jdk.incubator.vector.VectorShuffle;
import jdk.incubator.vector.VectorSpecies;
public class Vector {
private static final VectorSpecies SPECIES = DoubleVector.SPECIES_256;
private static final VectorMask XYZ_MASK = SPECIES.indexInRange(0, 3);
private static final VectorShuffle YZX = VectorShuffle.fromValues(SPECIES, 1, 2, 0, 3);
private static final VectorShuffle ZXY = VectorShuffle.fromValues(SPECIES, 2, 0, 1, 3);
public final DoubleVector vec;
public static final Vector ZERO = new Vector(0, 0, 0);
public static final Vector UP = new Vector(0, 1, 0);
public static final Vector RIGHT = new Vector(1, 0, 0);
public static final Vector FORWARD = new Vector(0, 0, 1);
public Vector() {
vec = DoubleVector.zero(SPECIES);
}
public double getX() {
return vec.lane(0);
}
public double getY() {
return vec.lane(1);
}
public double getZ() {
return vec.lane(2);
}
public Vector withX(double x) {
return new Vector(vec.withLane(0, x));
}
public Vector withY(double y) {
return new Vector(vec.withLane(1, y));
}
public Vector withZ(double z) {
return new Vector(vec.withLane(2, z));
}
private Vector(DoubleVector vec) {
this.vec = vec;
}
public Vector(double x, double y, double z) {
vec = DoubleVector.zero(SPECIES).withLane(0, x).withLane(1, y).withLane(2, z);
}
public static Vector RandomUnitVector(ThreadLocalRandom rnd) {
double z = rnd.nextDouble() * 2.0 - 1.0;
double a = rnd.nextDouble() * 2.0 * Math.PI;
double r = Math.sqrt(1.0 - z * z);
double x = Math.sin(a);
double y = Math.cos(a);
return new Vector(r * x, r * y, z);
}
public double Length() {
return Math.sqrt(this.vec.mul(this.vec).reduceLanes(VectorOperators.ADD, XYZ_MASK));
}
public double LengthN(double n) {
if (n == 2) {
return this.Length();
}
DoubleVector absVec = this.vec.abs();
double x = Math.pow(absVec.lane(0), n);
double y = Math.pow(absVec.lane(1), n);
double z = Math.pow(absVec.lane(2), n);
return Math.pow(x + y + z, 1.0 / n);
}
public double Dot(Vector b) {
return this.vec.mul(b.vec).reduceLanes(VectorOperators.ADD, XYZ_MASK);
}
public Vector Cross(Vector b) {
DoubleVector a_yzx = this.vec.rearrange(YZX);
DoubleVector b_zxy = b.vec.rearrange(ZXY);
DoubleVector a_zxy = this.vec.rearrange(ZXY);
DoubleVector b_yzx = b.vec.rearrange(YZX);
return new Vector(a_yzx.mul(b_zxy).sub(a_zxy.mul(b_yzx)));
}
public Vector Normalize() {
return new Vector(this.vec.div(this.Length()));
}
public Vector Negate() {
return new Vector(this.vec.neg());
}
public Vector Abs() {
return new Vector(this.vec.abs());
}
public Vector Add(Vector b) {
return new Vector(this.vec.add(b.vec));
}
public Vector Sub(Vector b) {
return new Vector(this.vec.sub(b.vec));
}
public Vector Mul(Vector b) {
return new Vector(this.vec.mul(b.vec));
}
public Vector Div(Vector b) {
return new Vector(this.vec.div(b.vec));
}
public Vector Mod(Vector b) {
double x = this.getX() % b.getX();
double y = this.getY() % b.getY();
double z = this.getZ() % b.getZ();
return new Vector(x, y, z);
}
public Vector AddScalar(double b) {
return new Vector(this.vec.add(DoubleVector.broadcast(SPECIES, b), XYZ_MASK));
}
public Vector SubScalar(double b) {
return new Vector(this.vec.sub(DoubleVector.broadcast(SPECIES, b), XYZ_MASK));
}
public Vector MulScalar(double b) {
return new Vector(this.vec.mul(b));
}
public Vector DivScalar(double b) {
return new Vector(this.vec.div(b));
}
public Vector Min(Vector b) {
return new Vector(this.vec.min(b.vec));
}
public static Vector Min(Vector a, Vector b) {
return new Vector(a.vec.min(b.vec));
}
public Vector Max(Vector b) {
return new Vector(this.vec.max(b.vec));
}
public static Vector Max(Vector a, Vector b) {
return new Vector(a.vec.max(b.vec));
}
public Vector MinAxis() {
double x = Math.abs(vec.lane(0));
double y = Math.abs(vec.lane(1));
double z = Math.abs(vec.lane(2));
if (x <= y && x <= z) {
return new Vector(1, 0, 0);
} else if (y <= x && y <= z) {
return new Vector(0, 1, 0);
}
return new Vector(0, 0, 1);
}
public double MinComponent() {
return Math.min(Math.min(vec.lane(0), vec.lane(1)), vec.lane(2));
}
public double MaxComponent() {
return Math.max(Math.max(vec.lane(0), vec.lane(1)), vec.lane(2));
}
public Vector Reflect(Vector i) {
return i.Sub(this.MulScalar(2 * this.Dot(i)));
}
public Vector Refract(Vector i, double n1, double n2) {
double nr = n1 / n2;
double cosI = -this.Dot(i);
double sinT2 = nr * nr * (1 - cosI * cosI);
if (sinT2 > 1) {
return new Vector();
}
double cosT = Math.sqrt(1 - sinT2);
return i.MulScalar(nr).Add(this.MulScalar(nr * cosI - cosT));
}
public double Reflectance(Vector i, double n1, double n2) {
double nr = n1 / n2;
double cosI = -this.Dot(i);
double sinT2 = nr * nr * (1 - cosI * cosI);
if (sinT2 > 1) {
return 1;
}
double cosT = Math.sqrt(1 - sinT2);
double rOrth = (n1 * cosI - n2 * cosT) / (n1 * cosI + n2 * cosT);
double rPar = (n2 * cosI - n1 * cosT) / (n2 * cosI + n1 * cosT);
return (rOrth * rOrth + rPar * rPar) / 2;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof Vector)) return false;
Vector other = (Vector) obj;
return Double.compare(getX(), other.getX()) == 0
&& Double.compare(getY(), other.getY()) == 0
&& Double.compare(getZ(), other.getZ()) == 0;
}
@Override
public int hashCode() {
long bits = Double.doubleToLongBits(getX());
bits = 31 * bits + Double.doubleToLongBits(getY());
bits = 31 * bits + Double.doubleToLongBits(getZ());
return (int)(bits ^ (bits >>> 32));
}
}