GfxLab-2022-2023/src/xyz/marsavic/gfxlab/Vec3.java
2022-11-15 02:21:15 +01:00

458 lines
8.1 KiB
Java

package xyz.marsavic.gfxlab;
import xyz.marsavic.geometry.Vector;
import xyz.marsavic.gfxlab.elements.Immutable;
import xyz.marsavic.random.RNG;
import xyz.marsavic.utils.Numeric;
import java.util.function.DoubleBinaryOperator;
import java.util.function.DoubleUnaryOperator;
@Immutable
public class Vec3 {
public static final Vec3 ZERO = xyz(0, 0, 0);
public static final Vec3 ONES = xyz(1, 1, 1);
public static final Vec3 EX = xyz(1, 0, 0);
public static final Vec3 EY = xyz(0, 1, 0);
public static final Vec3 EZ = xyz(0, 0, 1);
public static final Vec3 EXY = xyz(1, 1, 0);
public static final Vec3 EYZ = xyz(0, 1, 1);
public static final Vec3 EZX = xyz(1, 0, 1);
public static final Vec3 EXYZ = xyz(1, 1, 1);
public static final Vec3[] E = {EX, EY, EZ};
public static final Vec3 P012 = xyz(0, 1, 2);
public static final Vec3 P021 = xyz(0, 2, 1);
public static final Vec3 P102 = xyz(1, 0, 2);
public static final Vec3 P120 = xyz(1, 2, 0);
public static final Vec3 P201 = xyz(2, 0, 1);
public static final Vec3 P210 = xyz(2, 1, 0);
public static final Vec3[] PERMUTATIONS = {P012, P021, P102, P120, P201, P210};
private final double x, y, z;
public Vec3(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public static Vec3 xyz(double x, double y, double z) {
return new Vec3(x, y, z);
}
public static Vec3 fromArray(int[] i) {
return xyz(i[0], i[1], i[2]);
}
public static Vec3 fromArray(double[] i) {
return xyz(i[0], i[1], i[2]);
}
public static Vec3 xp(double x, Vector p) {
return xyz(x, p.x(), p.y());
}
public static Vec3 yp(double y, Vector p) {
return xyz(p.x(), y, p.y());
}
public static Vec3 zp(double z, Vector p) {
return xyz(p.x(), p.y(), z);
}
public double x() {
return x;
}
public double y() {
return y;
}
public double z() {
return z;
}
public double get(int i) {
return switch (i) {
case 0 -> x();
case 1 -> y();
case 2 -> z();
default -> throw new IllegalArgumentException();
};
}
public double[] toArray() {
return new double[] { x(), y(), z() };
}
public int[] toArrayInt() {
return new int[] { (int) x(), (int) y(), (int) z() };
}
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (o instanceof Vec3 vec3) {
return
(vec3.x() == x()) &&
(vec3.y() == y()) &&
(vec3.z() == z())
;
} else {
return false;
}
}
@Override
public int hashCode() {
long temp =
Double.doubleToLongBits(x) +
31 * Double.doubleToLongBits(y) +
997 * Double.doubleToLongBits(z);
return (int) (temp ^ (temp >>> 32));
}
public Vec3 add(Vec3 o) {
return xyz(x() + o.x(), y() + o.y(), z() + o.z());
}
public Vec3 sub(Vec3 o) {
return xyz(x() - o.x(), y() - o.y(), z() - o.z());
}
public Vec3 mul(double k) {
return xyz(x() * k, y() * k, z() * k);
}
public Vec3 mul(Vec3 o) {
return xyz(x() * o.x(), y() * o.y(), z() * o.z());
}
public Vec3 div(double k) {
return xyz(x() / k, y() / k, z() / k);
}
public Vec3 div(Vec3 o) {
return xyz(x() / o.x(), y() / o.y(), z() / o.z());
}
public double lengthSquared() {
return x() * x() + y() * y() + z() * z();
}
public double length() {
return Math.sqrt(lengthSquared());
}
public Vec3 normalized_() {
return div(length());
}
public Vec3 normalizedTo(double l) {
return mul(l / length());
}
public Vec3 inverse() {
return xyz(-x(), -y(), -z());
}
public double dot(Vec3 o) {
return x() * o.x() + y() * o.y() + z() * o.z();
}
public Vec3 cross(Vec3 o) {
return xyz(
y() * o.z() - z() * o.y(),
z() * o.x() - x() * o.z(),
x() * o.y() - y() * o.x()
);
}
public Vec3 projection(Vec3 d) {
return d.mul(this.dot(d) / d.lengthSquared());
}
public Vec3 projectionN(Vec3 d_) {
return d_.mul(this.dot(d_));
}
public Vec3 rejection(Vec3 d) {
return this.sub(projection(d));
}
public Vec3 rejectionN(Vec3 d_) {
return this.sub(projectionN(d_));
}
public double min() {
return Math.min(Math.min(x(), y()), z());
}
public double max() {
return Math.max(Math.max(x(), y()), z());
}
public Vec3 minIndicator() {
if (x() < y()) {
return x() < z() ? Vec3.EX : Vec3.EZ;
} else {
return y() < z() ? Vec3.EY : Vec3.EZ;
}
}
public Vec3 maxIndicator() {
if (x() > y()) {
return x() > z() ? Vec3.EX : Vec3.EZ;
} else {
return y() > z() ? Vec3.EY : Vec3.EZ;
}
}
public int minIndex() {
if (x() < y()) {
return x() < z() ? 0 : 2;
} else {
return y() < z() ? 1 : 2;
}
}
public int maxIndex() {
if (x() > y()) {
return x() > z() ? 0 : 2;
} else {
return y() > z() ? 1 : 2;
}
}
public Vec3 ranks() {
if (x() < y()) {
if (y() < z()) {
return P012;
} else {
if (x() < z()) {
return P021;
} else {
return P201;
}
}
} else {
if (x() < z()) {
return P102;
} else {
if (y() < z()) {
return P120;
} else {
return P210;
}
}
}
}
public Vec3 sign() {
return xyz(Numeric.sign(x()), Numeric.sign(y()), Numeric.sign(z()));
}
public Vec3 abs() {
return xyz(Math.abs(x()), Math.abs(y()), Math.abs(z()));
}
public boolean allZero() {
return (x() == 0) && (y() == 0) && (z() == 0);
}
public boolean anyZero() {
return (x() == 0) || (y() == 0) || (z() == 0);
}
public Vec3 floor() {
return xyz(Math.floor(x()), Math.floor(y()), Math.floor(z()));
}
public Vec3 floor(Vec3 d) {
return this.div(d).floor().mul(d);
}
public Vec3 ceil() {
return xyz(Math.ceil(x()), Math.ceil(y()), Math.ceil(z()));
}
public Vec3 ceil(Vec3 d) {
return this.div(d).ceil().mul(d);
}
public Vec3 round() {
return xyz(Math.round(x()), Math.round(y()), Math.round(z()));
}
public Vec3 round(Vec3 d) {
return this.div(d).round().mul(d);
}
/** Snaps each component to floor or ceil, depending on whether the corresponding component of s is not one. */
public Vec3 snap(Vec3 s) {
return Vec3.xyz (
s.x() != 1 ? Math.floor(x()) : Math.ceil(x()),
s.y() != 1 ? Math.floor(y()) : Math.ceil(y()),
s.z() != 1 ? Math.floor(z()) : Math.ceil(z())
);
}
public double product() {
return x() * y() * z();
}
public Vec3 f(DoubleUnaryOperator f) {
return Vec3.f(f, this);
}
public Vec3 f(DoubleBinaryOperator f, Vec3 v) {
return Vec3.f(f, this, v);
}
public Vec3[] split() {
return new Vec3[] {
Vec3.xyz(x(), 0, 0),
Vec3.xyz(0, y(), 0),
Vec3.xyz(0, 0, z()),
};
}
public Vec3 only(int i) {
return switch (i) {
case 0 -> Vec3.xyz(x(), 0, 0);
case 1 -> Vec3.xyz(0, y(), 0);
case 2 -> Vec3.xyz(0, 0, z());
default -> throw new IllegalArgumentException();
};
}
public Vector p01() {
return Vector.xy(x(), y());
}
public Vector p12() {
return Vector.xy(y(), z());
}
/** The result is obtained by applying the affine transform that maps 0 to -1 and 1 to 1. */
public Vec3 ZOtoMP() {
return mul(2).sub(Vec3.EXYZ);
}
/** The result is obtained by applying the affine transform that maps -1 to 0 and 1 to 1. */
public Vec3 MPtoZO() {
return add(Vec3.EXYZ).mul(0.5);
}
@Override
public String toString() {
return String.format("(%6.2f, %6.2f, %6.2f)", x(), y(), z());
}
public static Vec3 f(DoubleUnaryOperator f, Vec3 u) {
return Vec3.xyz(
f.applyAsDouble(u.x()),
f.applyAsDouble(u.y()),
f.applyAsDouble(u.z())
);
}
public static Vec3 f(DoubleBinaryOperator f, Vec3 u, Vec3 v) {
return Vec3.xyz(
f.applyAsDouble(u.x(), v.x()),
f.applyAsDouble(u.y(), v.y()),
f.applyAsDouble(u.z(), v.z())
);
}
public static Vec3 min(Vec3 a, Vec3 b) {
return xyz(
Math.min(a.x(), b.x()),
Math.min(a.y(), b.y()),
Math.min(a.z(), b.z())
);
}
public static Vec3 max(Vec3 a, Vec3 b) {
return xyz(
Math.max(a.x(), b.x()),
Math.max(a.y(), b.y()),
Math.max(a.z(), b.z())
);
}
public static Vec3 lerp(Vec3 v0, Vec3 v1, double t) {
return v0.mul(1 - t).add(v1.mul(t));
}
public static Vec3 random(RNG rng) {
return Vec3.xyz(rng.nextDouble(), rng.nextDouble(), rng.nextDouble());
}
}