//
import java.awt.*;
public class AutoshutterApplet extends GenericApplet
{
int inch = 20; // scale an inch to be 20 applet pixels
int width, height;
int gapSize = 4 * inch;
int screenWidth = 10 * inch;
int shutterWidth = 27 * inch / 2;
int phase = 0;
int leftX, rightX, leftY, rightY;
int headX, headY, noseX, noseY, leftEyeX, leftEyeY, rightEyeX, rightEyeY;
int screenY, shutterY, screenLeft, screenRight, shutterLeft, shutterRight;
double theta = 0;
boolean isDamage = true, isPaused = true, isVisible = false;
public void init() {
super.init();
width = bounds().width;
height = bounds().height;
screenLeft = width/2 - screenWidth/2;
screenRight = width/2 + screenWidth/2;
shutterLeft = width/2 - shutterWidth/2;
shutterRight = width/2 + shutterWidth/2;
screenY = 50;
shutterY = screenY + gapSize;
setPosition(width/2, 20 * inch, 0);
}
void setPosition(int x, int y, double angle) {
double P = 0.75 * inch;
double r = 1.25 * inch;
double E = 2 * inch;
double N = 2.75 * inch;
double s = Math.sin(theta);
double c = Math.cos(theta);
y = (int)Math.max(y, shutterY+E+2*P+1);
theta = angle;
headX = x;
headY = y;
noseX = (int)(x + s * N);
noseY = (int)(y - c * N);
int eyeX = (int)(x + s * E);
int eyeY = (int)(y - c * E);
leftEyeX = (int)(eyeX - c * r);
rightEyeX = (int)(eyeX + c * r);
leftEyeY = (int)(eyeY - s * r);
rightEyeY = (int)(eyeY + s * r);
double phi = Math.atan((double)(noseX - width/2) / (noseY - screenY));
c = Math.cos(phi/2);
s = Math.sin(phi/2);
leftX = (int)(leftEyeX - s * P);
rightX = (int)(rightEyeX - s * P);
leftY = (int)(leftEyeY - c * P);
rightY = (int)(rightEyeY - c * P);
isDamage = true;
}
public boolean mouseDrag(Event e, int x, int y) {
if (y < shutterY)
return true;
setPosition(x, y, theta);
return true;
}
public boolean mouseUp(Event e, int x, int y) {
if (y < 20 && x < 50) {
phase = (phase + 1) % 3;
isDamage = true;
}
else if (y < 20 && x > width - 50) {
isPaused = ! isPaused;
isDamage = true;
}
else if (y < shutterY) {
setPosition(headX, headY, theta + (x < width/2 ? -.1 : .1));
isDamage = true;
}
return true;
}
int intercept(int ax, int ay, int bx, int by, int cy) {
return ax + (bx - ax) * (cy - ay) / (by - ay);
}
public void render(Graphics g) {
// determine which phase we're in now
if (!isPaused) {
isDamage = true;
phase = (phase + 1) % 3;
}
if (! isDamage)
return;
isDamage = false;
// draw distance ruling every inch
g.setColor(Color.white);
g.fillRect(0, 0, width, height);
g.setColor(Color.black);
for (int y = screenY ; y < height ; y += inch)
g.drawLine(0, y, width, y);
// draw head and eyes
g.setColor(Color.gray);
g.fillOval(headX - 3*inch, headY - 3*inch, 6*inch, 6*inch);
g.fillOval(noseX - inch*3/4, noseY - inch*3/4, inch*3/2, inch*3/2);
g.setColor(Color.white);
g.fillOval(leftEyeX - inch*3/4, leftEyeY - inch, inch*3/2, inch*3/2);
g.fillOval(rightEyeX - inch*3/4, rightEyeY - inch, inch*3/2, inch*3/2);
g.setColor(Color.black);
g.drawOval(leftEyeX - inch*3/4, leftEyeY - inch, inch*3/2, inch*3/2);
g.drawOval(rightEyeX - inch*3/4, rightEyeY - inch, inch*3/2, inch*3/2);
int pupilSize = inch * 2 / 3;
g.fillOval(leftX - pupilSize/2, leftY - pupilSize/2, pupilSize, pupilSize);
g.fillOval(rightX - pupilSize/2, rightY - pupilSize/2, pupilSize, pupilSize);
// print text labels
g.setColor(Color.magenta.darker());
g.drawString("Instructions: drag mouse to move head", width/2-105, 14);
g.drawString(isPaused ? "STEP" : "", 2, 14);
g.drawString(isPaused ? "CYCLE" : "PAUSE", width - 45, 14);
int clickY = (screenY + shutterY) / 2 + 3;
g.drawString("[Click here to turn left]", width/12, clickY);
g.drawString("[Click here to turn right]", width*2/3, clickY);
g.setColor(Color.yellow.darker().darker().darker());
g.drawString(" (display screen)", screenRight, screenY + 3);
g.setColor(Color.black);
g.drawString(" (active shutter)", shutterRight, shutterY + 3);
g.drawString("Viewer distance: " + (((leftY + rightY)/2 - screenY)/inch) + " inches",
2, shutterY + 45);
// display the interleaved screen and the autoshutter
g.fillRect(shutterLeft, shutterY-1, shutterRight-shutterLeft, 2);
int x, x1, x2;
cx = screenRight;
isVisible = true;
for (ax = bx = screenLeft ; isVisible && cx > bx ; ax = cx) {
computeIntercepts();
if (ax == screenLeft && phase > 0) {
ax += (phase - 3) * (cx - ax) / 3;
computeIntercepts();
}
isVisible = false;
g.setColor(Color.green);
x1 = Math.max(screenLeft , ax);
x2 = Math.min(screenRight, bx);
g.fillRect(x1, screenY-2, x2-x1, 4);
x = (ax + bx) / 2;
if (x >= screenLeft && x < screenRight) {
g.drawLine(x, screenY, leftX, leftY);
isVisible = true;
g.setColor(Color.yellow);
g.fillRect(aX + (bX-aX)/6, shutterY-1, (bX-aX)*2/3, 2);
}
g.setColor(Color.red);
x1 = Math.max(screenLeft , bx);
x2 = Math.min(screenRight, cx);
g.fillRect(x1, screenY-2, x2-x1, 4);
x = (bx + cx) / 2;
if (x >= screenLeft && x < screenRight) {
g.drawLine(x, screenY, rightX, rightY);
isVisible = true;
g.setColor(Color.yellow);
g.fillRect(cX + (dX-cX)/6, shutterY-1, (dX-cX)*2/3, 2);
}
}
}
int ax, bx, cx, aX, bX, cX, dX;
void computeIntercepts() {
aX = intercept(ax, screenY, leftX, leftY, shutterY);
bX = intercept(ax, screenY, rightX, rightY, shutterY);
bx = intercept(bX, shutterY, leftX, leftY, screenY);
cX = intercept(bx, screenY, rightX, rightY, shutterY);
cx = intercept(cX, shutterY, leftX, leftY, screenY);
dX = intercept(cx, screenY, rightX, rightY, shutterY);
}
}