/****************************************************************************
** COPYRIGHT (C): 1997. All Rights Reserved.
** PROJECT: David Bellin's CRC Card Book
** FILE: Intersection.java
** PURPOSE: Simulation of traffic lights at intersection
** VERSION 1.0
** PROGRAMMERS: Cay Horstmann (CSH)
** RELEASE DATE: 3-15-97 (CSH)
** UPDATE HISTORY:
****************************************************************************/
import java.awt.*;
import java.applet.*;
import java.util.*;
public class Intersection extends Applet implements Timed
{ public void init()
{ ts = new TrafficStream[7];
// wasting 0 entry to stay with terminology on paper
ts[1] = new TrafficStream(XCENTER - WIDTH / 2,
YCENTER - WIDTH / 2 - YSTREAM, XSTREAM, YSTREAM, SignalFace.LEFT);
ts[2] = new TrafficStream(XCENTER + WIDTH / 2 - XSTREAM,
YCENTER + WIDTH / 2, XSTREAM, YSTREAM, SignalFace.RIGHT);
ts[3] = new TrafficStream(XCENTER - WIDTH / 2 - XSTREAM,
YCENTER + WIDTH / 2 - YSTREAM, XSTREAM, YSTREAM, SignalFace.RIGHT);
ts[4] = new TrafficStream(XCENTER + WIDTH / 2,
YCENTER - WIDTH / 2, XSTREAM, YSTREAM, SignalFace.LEFT);
ts[5] = new TrafficStream(XCENTER - WIDTH / 2 - XSTREAM,
YCENTER + WIDTH / 2 - 2 * YSTREAM, XSTREAM, YSTREAM, SignalFace.RIGHT);
ts[6] = new TrafficStream(XCENTER + WIDTH / 2,
YCENTER - WIDTH / 2 + YSTREAM, XSTREAM, YSTREAM, SignalFace.LEFT);
phases = new Phase[5];
// wasting 0 entry to stay with terminology on paper
phases[1] = new Phase(30, 10);
phases[1].addStream(ts[1]).addStream(ts[2]);
phases[2] = new Phase(40, 10);
phases[2].addStream(ts[3]).addStream(ts[4]);
phases[3] = new Phase(40, 10);
phases[3].addStream(ts[3]).addStream(ts[5]);
phases[4] = new Phase(40, 10);
phases[4].addStream(ts[4]).addStream(ts[6]);
setColor(2, SignalFace.GREEN);
appletThreadGroup = Thread.currentThread().getThreadGroup();
}
public void paint(Graphics g)
{ g.drawLine(0, YCENTER - WIDTH / 2, XCENTER - WIDTH / 2, YCENTER - WIDTH / 2);
g.drawLine(XCENTER - WIDTH / 2, YCENTER - WIDTH / 2, XCENTER - WIDTH / 2, 0);
g.drawLine(0, YCENTER + WIDTH / 2, XCENTER - WIDTH / 2, YCENTER + WIDTH / 2);
g.drawLine(XCENTER - WIDTH / 2, YCENTER + WIDTH / 2, XCENTER - WIDTH / 2, 2 * YCENTER);
g.drawLine(XCENTER + WIDTH / 2, 0, XCENTER + WIDTH / 2, YCENTER - WIDTH / 2);
g.drawLine(XCENTER + WIDTH / 2, YCENTER - WIDTH / 2, 2 * XCENTER, YCENTER - WIDTH / 2);
g.drawLine(XCENTER + WIDTH / 2, YCENTER + WIDTH / 2, 2 * XCENTER, YCENTER + WIDTH / 2);
g.drawLine(XCENTER + WIDTH / 2, YCENTER + WIDTH / 2, XCENTER + WIDTH / 2, 2 * YCENTER);
for (int i = 1; i < ts.length; i++)
ts[i].paint(g);
}
public boolean mouseDown(Event evt, int x, int y)
{ for (int i = 1; i < phases.length; i++)
if (phases[i].mouseDown(x, y))
{ if (currentState == GREEN)
setColor(currentPhase, SignalFace.YELLOW);
else
repaint();
return true;
}
return false;
}
public void elapsed(Timer t)
{ if (currentState == GREEN_MIN) // end of minimum green phase
{ boolean found = false;
int j = currentPhase + 1;
while (!found && j != currentPhase)
{ j = j % phases.length;
if (j == 0) j = 1;
if (phases[j].needsServicing()) found = true;
else j++;
}
if (found)
setColor(currentPhase, SignalFace.YELLOW);
else
currentState = GREEN;
}
else if (currentState == YELLOW) // end of yellow phase
{ setColor(currentPhase, SignalFace.RED);
boolean found = false;
int j = currentPhase + 1;
while (!found)
{ j = j % phases.length;
if (j == 0) j = 1;
if (phases[j].needsServicing()) found = true;
else j++;
}
setColor(j, SignalFace.GREEN);
}
}
private void setColor(int i, int color)
{ int time = phases[i].setColor(color);
if (color == SignalFace.GREEN)
{ currentPhase = i;
currentState = GREEN_MIN;
}
else if (color == SignalFace.YELLOW)
currentState = YELLOW;
repaint();
if (time > 0)
new Timer(this, time * 1000 / 10).start();
}
private Phase[] phases;
private TrafficStream[] ts;
private int currentPhase;
private int currentState;
private static int XCENTER = 160;
private static int YCENTER = 160;
private static int WIDTH = 120; // width of intersection
private static int XSTREAM = 4 * SignalFace.RADIUS;
private static int YSTREAM = 4 * SignalFace.RADIUS;
private static int GREEN_MIN = 1;
private static int GREEN = 2;
private static int YELLOW = 3;
static ThreadGroup appletThreadGroup;
}
class Phase
{ public Phase(int theGreenTime, int theYellowTime)
{ greenTime = theGreenTime;
yellowTime = theYellowTime;
tstreams = new Vector();
needsSvc = false;
}
public Phase addStream(TrafficStream ts)
{ tstreams.addElement(ts);
return this;
}
public int setColor(int color) // returns the minimum time in that color
{ for (int i = 0; i < tstreams.size(); i++)
((TrafficStream)tstreams.elementAt(i)).setColor(color);
if (color == SignalFace.GREEN)
{ needsSvc = false;
return greenTime;
}
else if (color == SignalFace.YELLOW) return yellowTime;
else return 0;
}
public boolean needsServicing() { return needsSvc; }
public boolean mouseDown(int x, int y)
{ for (int i = 0; i < tstreams.size(); i++)
if (((TrafficStream)tstreams.elementAt(i)).mouseDown(x, y))
{ needsSvc = true;
return true;
}
return false;
}
private int greenTime;
private int yellowTime;
private boolean needsSvc;
private Vector tstreams;
}
class TrafficStream
{ public TrafficStream(int x, int y, int width, int height, int sensorOrientation)
{ if (sensorOrientation == SignalFace.LEFT)
{ detector = new Detector(new Point(x + width / 2, y + height / 2 - SignalFace.RADIUS / 2),
SignalFace.RADIUS, SignalFace.RADIUS);
signalFace = new SignalFace(new Point(x, y), SignalFace.RADIUS);
}
else
{ detector = new Detector(new Point(x, y + height / 2 - SignalFace.RADIUS / 2),
SignalFace.RADIUS, SignalFace.RADIUS);
signalFace = new SignalFace(new Point(x + width / 2, y), SignalFace.RADIUS);
}
}
public void setColor(int color)
{ signalFace.setColor(color);
if (color == SignalFace.GREEN) detector.reset();
}
public boolean mouseDown(int x, int y)
{ if (signalFace.getColor() != SignalFace.GREEN && detector.mouseDown(x, y))
{ return true;
}
return false;
}
public void paint(Graphics g)
{ detector.paint(g);
signalFace.paint(g);
}
private Detector detector;
private SignalFace signalFace;
}
class Detector
{ public Detector(Point s, int w, int h)
{ start = s;
width = w;
height = h;
activated = false;
}
public boolean mouseDown(int x, int y)
{ if (activated) return false;
if (start.x <= x && x <= start.x + width && start.y <= y && y <= start.y + height)
{ activated = true;
return true;
}
return false;
}
public void reset()
{ activated = false;
}
public void paint(Graphics g)
{ g.drawRect(start.x, start.y, height, width);
if (activated) g.fillRect(start.x, start.y, height, width);
}
private Point start;
int width;
int height;
boolean activated;
}
class SignalFace
{ public SignalFace(Point s, int w)
{ start = s;
width = w;
color = RED;
}
public void paint(Graphics g)
{ Color c = Color.red;
int y = 0;
if (color == YELLOW)
{ c = Color.yellow;
y = width;
}
else if (color == GREEN)
{ c = Color.green;
y = 2 * width;
}
g.setColor(c);
g.fillOval(start.x, start.y + y, width, width);
g.setColor(Color.black);
for (int i = 0; i < 3; i++)
g.drawOval(start.x, start.y + i * width, width, width);
}
public int getColor() { return color; }
public void setColor(int c) { color = c; }
public static int RED = 0;
public static int YELLOW = 1;
public static int GREEN = 2;
public static int RADIUS = 8;
public static int RIGHT = 1;
public static int LEFT = -1;
private int color;
private Point start;
private int width;
}
interface Timed
{ public void elapsed(Timer t);
}
class Timer extends Thread
{ public Timer(Timed t, int i)
{ super(Intersection.appletThreadGroup, "Timer");
target = t; interval = i;
setDaemon(true);
}
public void run()
{ try { sleep(interval); }
catch(InterruptedException e) {}
target.elapsed(this);
}
private Timed target;
private int interval;
}