158 lines
3.4 KiB
Java
158 lines
3.4 KiB
Java
public class RayIntersections {
|
|
static final double eps = 1e-9;
|
|
|
|
public static class Ray {
|
|
Vector org;
|
|
Vector dir;
|
|
}
|
|
|
|
public static class Sphere {
|
|
Vector center;
|
|
double r;
|
|
}
|
|
|
|
public static class Plane {
|
|
Vector n;
|
|
double d;
|
|
}
|
|
|
|
public static double sqr(double x) {
|
|
return x * x;
|
|
}
|
|
|
|
// algebraic solution
|
|
public static double raySphereIntersection(Ray ray, Sphere s) {
|
|
Vector CO = ray.org.sub(s.center);
|
|
double b = ray.dir.dot(CO);
|
|
double c = ray.org.len2() - s.r * s.r;
|
|
double d = b * b - c;
|
|
|
|
if (d < eps)
|
|
return Double.NaN;
|
|
|
|
d = Math.sqrt(d < 0 ? 0 : d);
|
|
|
|
double t1 = -b - d;
|
|
double t2 = -b + d;
|
|
return t2 < eps ? Double.NaN : (t1 > eps ? t1 : t2);
|
|
}
|
|
|
|
// geometric solution
|
|
public static double raySphereIntersection2(Ray ray, Sphere s) {
|
|
Vector OC = s.center.sub(ray.org);
|
|
double t0 = OC.dot(ray.dir); // point, closest to center
|
|
double d = s.r * s.r - (OC.len2() - t0 * t0);
|
|
|
|
if (d < -eps)
|
|
return Double.NaN;
|
|
|
|
d = Math.sqrt(d < 0 ? 0 : d);
|
|
double t1, t2;
|
|
|
|
if (t0 < d) { // we are inside
|
|
t1 = t0 + d;
|
|
t2 = t0 - d;
|
|
} else { // we are outside
|
|
t1 = t0 - d;
|
|
t2 = t0 + d;
|
|
}
|
|
|
|
if (Math.abs(t1) < eps)
|
|
t1 = t2;
|
|
|
|
return t1 > eps ? t1 : Double.NaN;
|
|
}
|
|
|
|
// algebraic solution
|
|
public static double rayPlaneIntersection(Ray ray, Plane p) {
|
|
double b = p.n.dot(ray.dir);
|
|
if (Math.abs(b) < eps)
|
|
return Double.NaN;
|
|
double a = -(p.n.dot(ray.org) + p.d);
|
|
double t = a / b;
|
|
return t < eps ? Double.NaN : t;
|
|
}
|
|
|
|
public static class Vector {
|
|
double x, y, z;
|
|
|
|
public Vector(double x, double y, double z) {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.z = z;
|
|
}
|
|
|
|
public Vector sub(Vector b) {
|
|
return new Vector(x - b.x, y - b.y, z - b.z);
|
|
}
|
|
|
|
public Vector add(Vector b) {
|
|
return new Vector(x + b.x, y + b.y, z + b.z);
|
|
}
|
|
|
|
public static double det(double a, double b, double c, double d) {
|
|
return a * d - b * c;
|
|
}
|
|
|
|
public Vector mul(Vector b) {
|
|
return new Vector(det(y, b.y, z, b.z), -det(x, b.x, z, b.z), det(x, b.x, y, b.y));
|
|
}
|
|
|
|
public Vector mul(double b) {
|
|
return new Vector(x * b, y * b, z * b);
|
|
}
|
|
|
|
double len2() {
|
|
return x * x + y * y + z * z;
|
|
}
|
|
|
|
double len() {
|
|
return Math.sqrt(x * x + y * y + z * z);
|
|
}
|
|
|
|
public Vector norm() {
|
|
return len() == 0 ? new Vector(0, 0, 0) : mul(1 / len());
|
|
}
|
|
|
|
public double dot(Vector b) {
|
|
return x * b.x + y * b.y + z * b.z;
|
|
}
|
|
|
|
public double proj(Vector p) {
|
|
return dot(p) / len();
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return "Vector2d [x=" + x + ", y=" + y + ", z=" + z + "]";
|
|
}
|
|
}
|
|
|
|
// usage example
|
|
public static void main(String[] args) {
|
|
Sphere s = new Sphere();
|
|
s.center = new Vector(0, 0, 0);
|
|
Ray ray = new Ray();
|
|
for (int x1 = -4; x1 <= 4; x1++)
|
|
for (int y1 = -4; y1 <= 4; y1++)
|
|
for (int z1 = -4; z1 <= 4; z1++)
|
|
for (int x2 = -4; x2 <= 4; x2++)
|
|
for (int y2 = -4; y2 <= 4; y2++)
|
|
for (int z2 = -4; z2 <= 4; z2++) {
|
|
if (x2 == 0 && y2 == 0 && z2 == 0)
|
|
continue;
|
|
ray.org = new Vector(x1, y1, z1);
|
|
ray.dir = new Vector(x2, y2, z2).norm();
|
|
|
|
for (int r = 0; r <= 4; r++) {
|
|
s.r = r;
|
|
double t1 = raySphereIntersection(ray, s);
|
|
double t2 = raySphereIntersection(ray, s);
|
|
if (!(Double.isNaN(t1) && Double.isNaN(t2) || !(Math.abs(t1 - t2) > eps))) {
|
|
System.out.println(t1 + " " + t2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|