import java.util.*; import java.awt.*; import java.lang.*; public class Sphere implements Item { private int centerx, centery, centerz; private double radius; private World world; private Color baseColor; public Sphere() { centerx = centery = centerz = 0; radius = 50.0; } public Sphere(World w) { centerx = centery = centerz = 0; radius = 50.0; world = w; } public Sphere(int cx, int cy, int cz, double r) { centerx = cx; centery = cy; centerz = cz; radius = r; } public Sphere(int cx, int cy, int cz, double r, World w) { centerx = cx; centery = cy; centerz = cz; radius = r; world = w; } public Sphere(long seed, World w) { Random random = new Random(seed); baseColor = new Color(random.nextFloat(), random.nextFloat(), random.nextFloat()); centerx = random.nextInt() % 200; centery = random.nextInt() % 150; centerz = random.nextInt() % 50 - 50; radius = (random.nextDouble() + random.nextDouble() + random.nextDouble()) * 32.0; world = w; } public Sphere(long seed, World w, int width, int height) { Random random = new Random(seed); baseColor = new Color(random.nextFloat(), random.nextFloat(), random.nextFloat()); centerx = random.nextInt() % width/2; centery = random.nextInt() % height/2; centerz = random.nextInt() % 50 - 50; radius = (random.nextDouble() + random.nextDouble() + random.nextDouble()) * 32.0; world = w; } public void setWorld(World w) { world = w; } public boolean contains(int x, int y) { double distance = Math.sqrt((double) (x-centerx)*(x-centerx) + (y-centery)*(y-centery)); return (distance <= radius); } public boolean almostContains(int x, int y) { double distance = Math.sqrt((double) (x-centerx)*(x-centerx) + (y-centery)*(y-centery)); return (distance-1.0 <= radius); } public String toString() { String str = "Sphere: "; str = str + "center = " + centerx + ", " + centery + ", " + centerz + "; radius = " + radius + "; color = " + baseColor; return str; } public double zIntersectCalc(int x, int y, boolean VERBOSE) throws ItemException { // Note that this algorithm returns only the greater of two intersections. if (!almostContains(x, y)) { throw new ItemException("Use contains before trying zIntersect!"); } // else if (!contains(x, y)) // { // } double xsq = (double)(x-centerx)*(x-centerx); double ysq = (double)(y-centery)*(y-centery); double zret = (radius * radius) - (xsq + ysq); if (zret < 0) { System.out.println("r^2 - x^2 - y^2 = " + zret + ". Using zero"); zret = centerz; } else zret = centerz + Math.sqrt(zret); return zret; } public double zIntersectVerbose(int x, int y) throws ItemException { return zIntersectCalc(x, y, true); } public double zIntersect(int x, int y) throws ItemException { return zIntersectCalc(x, y, false); } public Color getNiftyColorAt(int x, int y, double z) { double x_y = (double) ((x-centerx) - (y-centery)); double x_z = (double) ((x-centerx) - (z-centerz)); double y_z = (double) ((y-centery) - (z-centerz)); double r = x_y / (4.0 * radius) + .5; double g = x_z / (4.0 * radius) + .5; double b = y_z / (4.0 * radius) + .5; // double r = ((x_y > 0) ? x_y : -x_y); // r /= (2.0 * radius); // r = 1.0 - r; // double g = ((x_z > 0) ? x_z : -x_z); // g /= (2.0 * radius); // g = 1.0 - g; // double b = ((y_z > 0) ? y_z : -y_z); // b /= (2.0 * radius); // b = 1.0 - b; return new Color((float) r, (float) g, (float) b); // double r = Math.abs(x-centerx)/radius; // double g = Math.abs(y-centery)/radius; // double b = Math.abs(z-centerz)/radius; // return new Color((float) r, (float) g, (float) b); // return baseColor; } public Color getColorAt(int x, int y, double z) { XYZVector V, L, H, N; double r, g, b; double a, d, s; V = new XYZVector(0.0, 0.0, 1.0); // L = new XYZVector((double) world.lightx, (double) world.lighty, (double) world.lightz, // (double) x, (double) y, z); N = new XYZVector((double) centerx, (double) centery, (double) centerz, (double) x, (double) y, z); L = new XYZVector((double) x, (double) y, z, (double) world.lightx, (double) world.lighty, (double) world.lightz); V.normalize(); L.normalize(); N.normalize(); H = XYZVector.plus(L, V); H.normalize(); d = XYZVector.dotProduct(N, L); if (d<0) d = 0; a = world.kambient; d *= world.kdiffuse; s = XYZVector.dotProduct(N, H); if (s < 0) s = 0; else s = world.kspecular * Math.pow(s, world.specularExponent); r = (double) baseColor.getRed() / 255.0; g = (double) baseColor.getGreen() / 255.0; b = (double) baseColor.getBlue() / 255.0; r *= (a + d); if (r > 1.0) r = 1.0; g *= (a + d); if (g > 1.0) g = 1.0; b *= (a + d); if (b > 1.0) b = 1.0; r = s + r*(1-s); g = s + g*(1-s); b = s + b*(1-s); return new Color((float) r, (float) g, (float) b); } public Color getColorAt(double x, double y, double z) { return baseColor; } public double maxZ() throws ItemException { return (double) centerz + radius; } public void translate(int dx, int dy, int dz) { centerx += dx; centery += dy; centerz += dz; } }