/****************************************************************************

** 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;

}