You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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);
}
}
}
}
}