package graphics; public class Quadratic extends Shape { public Matrix3D coefficients; //coefficients //ax^2 + by^2 + cz^2 + dxy + eyz + fzx + gx + hy + iz + j public double a, b, c, d, e, f, g, h, i, j; public Quadratic(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j) { this.a = a; this.b = b; this.c = c; this.d = d; this.e = e; this.f = f; this.g = g; this.h = h; this.i = i; this.j = j; double[][] data = new double[4][4]; data[0][0] = a; data[1][1] = b; data[2][2] = c; data[0][1] = d; data[1][2] = e; data[0][2] = f; data[0][3] = g; data[1][3] = h; data[2][3] = i; data[3][3] = j; this.coefficients = new Matrix3D(data); this.matrix = new Matrix3D(); } public double equation(double x, double y, double z) { return a*x*x + b*y*y + c*z*z + d*x*y + e*y*z + f*x*z + g*x + h*y + i*z + j; } //returns array of t values (roots) or void if no intersection //sets point of intersection and normal there public double[] testRay(Vector3 v, Vector3 w, Vector3 pos, Vector3 normal) { //for convenience double vx = v.get(0), vy = v.get(1), vz = v.get(2); double wx = w.get(0), wy = w.get(1), wz = w.get(2); //quadratic coefficients - (A B C) dot (t2 t 1) double A = a*wx*wx + b*wy*wy + c*wz*wz + d*wx*wy + e*wy*wz + f*wx*wz; double B = 2*a*vx*wx + 2*b*vy*wy + 2*c*vz*wz + d*vx*wy + d*vy*wx + e*vy*wz + e*vz*wy + f*vx*wz + f*vz*wx + g*wx + h*wy + i*wz; double C = equation(vx, vy, vz); //System.err.println("a,b,c: ("+A+", "+B+", "+C+")"); double[] roots = getRoots(A, B, C); if (roots == null) return null; //pick smaller (nearer) root double t = Math.min(roots[0], roots[1]); //we don't care about intersections behind the origin if (t < 0.001) return null; //calculate intersection point and normal setIntersectionPoint(v, w, t, pos); //for convenience double x = pos.get(0), y = pos.get(1), z = pos.get(2); normal.set(0, 2*a*x + d*y + f*z + g); normal.set(1, 2*b*y + d*x + e*z + h); normal.set(2, 2*c*z + e*y + f*x + i); normal.normalize(); return roots; } //quadratic equation protected double[] getRoots(double A, double B, double C) { double disc = B*B - 4*A*C; if (disc < 0) return null; double discRt = Math.sqrt(disc); double[] roots = new double[2]; roots[0] = (0-B - discRt)/2*A; roots[1] = (0-B + discRt)/2*A; return roots; } public void transform() { if (this.matrix == null) { System.err.println("Warning: transformation matrix is null. Cannot transform Quadratic."); return; } Matrix3D m = new Matrix3D(this.matrix); m.invert(); Matrix3D m2 = new Matrix3D(m); //save copy of inverted matrix m.transpose(); //System.err.println("m = " + m); m.multiply(this.coefficients); //multiply by coefficient matrix m.multiply(m2); //multiply by matrix inverse this.coefficients.copy(m); fixMatrix(); a = this.coefficients.get(0, 0); b = this.coefficients.get(1, 1); c = this.coefficients.get(2, 2); d = this.coefficients.get(0, 1); e = this.coefficients.get(1, 2); f = this.coefficients.get(0, 2); g = this.coefficients.get(0, 3); h = this.coefficients.get(1, 3); i = this.coefficients.get(2, 3); j = this.coefficients.get(3, 3); } //some transformations mess up coefficients matrix //this function restores them private void fixMatrix() { for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) { if (i < j) { double ij = this.coefficients.get(i, j); double ji = this.coefficients.get(j, i); this.coefficients.set(i, j, ij + ji); this.coefficients.set(j, i, 0); } } } public Quadratic deepCopy() { return new Quadratic(a, b, c, d, e, f, g, h, i, j); } public void dump() { System.err.println("(a, b, c), (d, e, f), (g, h, i, j) = (" + a + ", " + b + ", " + c + "), (" + d + ", " + e + ", " + f + "), (" + g + ", " + h + ", " + i + ", " + j + ")"); } }