/**************************************************************************** ** COPYRIGHT (C): 1997 Cay S. Horstmann. 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; }