import java.applet.Applet; import java.awt.*; import java.util.Calendar; import go.*; import goText.*; public class clock extends Applet { GoClockDemo clock; public void init() { // // Fonts will be found relative to the html document // that includes this applet. // GoFont.path(getDocumentBase()); // // Create Clock. // setLayout(new GridLayout(1, 1)); add(clock = new GoClockDemo()); } public void start() { clock.runClock = true; clock.rerender(); } public void stop() { clock.runClock = false; } } class GoClockDemo extends GoInterface { static final int ROTATE_TYPE_X_Y = 0; static final int ROTATE_TYPE_Z = 1; // clock numbers GoText[] number = new GoText[12]; // clock hands GoLines hourHand; double hourHandLength; GoLines minuteHand; double minuteHandLength; GoLines secondHand; double secondHandLength; // clock body GoTorus body; // clock orientation GoMatrix modelview = new GoMatrix(); GoMatrix currentModelview = new GoMatrix(); int xStart; int yStart; double angleStart; double rX, rY, rZ; int rotateType; // center point of clock double centerX, centerY, centerZ; // Used to "start" and "stop" applet animation. boolean runClock = true; GoClockDemo() { // // Initialize clock numbers. // double angle = 2 * Math.PI / 12; for(int i = 0; i < 12; i++) { String str = new String(Integer.toString(i + 1)); double r = 0.8; double x = r * Math.sin(angle); double y = r * Math.cos(angle); number[i] = new GoText(x, y, 0.0, // position 1.0, 0.0, 0.0, // path 0.0, 1.0, 0.0, // up 0.2, 0.2, // scale GoText.CENTER_CENTER, // alignment new GoHershey("hersheyFonts/futura.l"), // font str); // text angle += 2 * Math.PI / 12; } // // Initialize clock hands. // hourHandLength = 0.40; hourHand = new GoLines(2); hourHand.xyz(0, 0, 0, 0); minuteHandLength = 0.55; minuteHand = new GoLines(2); minuteHand.xyz(0, 0, 0, 0); secondHandLength = 0.65; secondHand = new GoLines(2); secondHand.xyz(0, 0, 0, 0); // // Initialize clock body. // body = new GoTorus(1.05, 12, 0.1, 12); // // Set center coordinate of clock. // centerX = centerY = centerZ = 0; // // Turn on LIGHT_0 // go.light(Go.LIGHT_0, true); go.light(Go.LIGHT_0, Go.DIRECTIONAL, 1.0, 1.0, 1.0); // // Clock background color. // go.background(0.2, 0.2, 0.2); } public void render() { // // Clear. // go.clear(Go.IMAGE); // // Setup clock hands. // setHourHand(); setMinuteHand(); setSecondHand(); // // Draw clock. // // clock numbers go.color(1, 1, 0); // yellow for(int i = 0; i < 12; i++) { number[i].render(go); } // clock hands go.color(1, 1, 1); // white go.render(hourHand); go.render(minuteHand); go.render(secondHand); // clock body go.color(0, 0, 1); // blue body.renderSolid(go); go.color(1.0, 0.5, 0.1); // salmon body.renderWireSlices(go); // // Display. // swap(); // // Post render event to update clock time. // if(runClock) { rerender(); } } public void mousePressed(int x, int y) { int width = go.width(); int height = go.height(); // // Rotate about X-Y axiz or Z axis? // int zRotSensitivity = 10; // NOTE: A smaller number makes the z-axis // rotation more sensitive. I.e. you // can be more sloppy to make it rotate // about the z-axis with a smaller number. rotateType = x > width / zRotSensitivity && x < width * (zRotSensitivity - 1) / zRotSensitivity && y > height / zRotSensitivity && y < height * (zRotSensitivity - 1) / zRotSensitivity ? ROTATE_TYPE_X_Y : ROTATE_TYPE_Z; switch(rotateType) { case ROTATE_TYPE_X_Y: { // // Init mouse info. // xStart = x; yStart = y; go.getModelview(currentModelview); } break; case ROTATE_TYPE_Z: { // // Init mouse info. // xStart = x; yStart = y; angleStart = Math.atan2(height / 2.0 - yStart, xStart - width / 2.0); // // Save the current modelview matrix so that // it can be restored as the mouse is moved. // go.getModelview(currentModelview); // // Calc the rotation vector // double x0 = 0.0; double y0 = 0.0; double z0 = 0.0; double x1; double y1; double z1; x1 = 0.0; y1 = 0.0; z1 = 1.0; go.push(Go.MODELVIEW); go.inverse(); go.getModelview(modelview); go.pop(Go.MODELVIEW); double[] m = modelview.m; double w = m[3] * x0 + m[7] * y0 + m[11] * z0 + m[15]; double x0N = (m[0] * x0 + m[4] * y0 + m[8] * z0 + m[12]) / w; double y0N = (m[1] * x0 + m[5] * y0 + m[9] * z0 + m[13]) / w; double z0N = (m[2] * x0 + m[6] * y0 + m[10] * z0 + m[14]) / w; w = m[3] * x1 + m[7] * y1 + m[11] * z1 + m[15]; double x1N = (m[0] * x1 + m[4] * y1 + m[8] * z1 + m[12]) / w; double y1N = (m[1] * x1 + m[5] * y1 + m[9] * z1 + m[13]) / w; double z1N = (m[2] * x1 + m[6] * y1 + m[10] * z1 + m[14]) / w; rX = x1N - x0N; rY = y1N - y0N; rZ = z1N - z0N; } break; } } public void mouseDragged(int x, int y) { int xEnd = x; int yEnd = y; switch(rotateType) { case ROTATE_TYPE_X_Y: { go.identity(); double xTheta = (yEnd - yStart) / 2; double yTheta = (xEnd - xStart) / 2; go.rotate(xTheta, 1, 0, 0); go.rotate(yTheta, 0, 1, 0); go.multiply(currentModelview); } break; case ROTATE_TYPE_Z: { int width = go.width(); int height = go.height(); go.load(currentModelview); double angleEnd = Math.atan2(height / 2.0 - yEnd, xEnd - width / 2.0); double delta = (angleEnd - angleStart) * 180.0 / Math.PI; go.translate(centerX, centerY, centerZ); go.rotate(delta, rX, rY, rZ); go.translate(-centerX, -centerY, -centerZ); } break; } } public void resized(int width, int height) { // // Setup projection matrix. // go.push(Go.MATRIX_MODE); go.matrixMode(Go.PROJECTION); go.identity(); if(width > height) { go.ortho(-1.2 * width / height, 1.2 * width / height, -1.2, 1.2, -1.2, 1.2); } else { go.ortho(-1.2, 1.2, -1.2 * height / width, 1.2 * height / width, -1.2, 1.2); } go.pop(Go.MATRIX_MODE); } // // Returns the current hour. // int hour() { return Calendar.getInstance().get(Calendar.HOUR_OF_DAY); } // // Returns the current minute. // int minute() { return Calendar.getInstance().get(Calendar.MINUTE); } // // Returns the current second. // int second() { return Calendar.getInstance().get(Calendar.SECOND); } // // Setup the clock's hour hand. // void setHourHand() { int hoursPassed = hour(); int minutesPassed = minute(); double angle = 2 * Math.PI / 12 * hoursPassed + 2 * Math.PI / 12 / 60 * minutesPassed; double x = hourHandLength * Math.sin(angle); double y = hourHandLength * Math.cos(angle); hourHand.xyz(1, x, y, 0); } // // Setup the clock's minute hand. // void setMinuteHand() { int minutesPassed = minute(); double angle = 2 * Math.PI / 60 * minutesPassed; double x = minuteHandLength * Math.sin(angle); double y = minuteHandLength * Math.cos(angle); minuteHand.xyz(1, x, y, 0); } // // Setup the clock's second hand. // void setSecondHand() { int secondsPassed = second(); double angle = 2 * Math.PI / 60 * secondsPassed; double x = secondHandLength * Math.sin(angle); double y = secondHandLength * Math.cos(angle); secondHand.xyz(1, x, y, 0); } }