//******** //* RUNWAY APPROACH SIMULATION - GRAPHICS AND USER INTERACTION //* //* a demonstration program for a simplistic simulation of //* aircraft arrivals to a single runway; //* simulation runs for one hour; //* the program uses concept of a simple queuing system with //* one implicit server (runway) and aircraft objects; //* the generator object generates the aircraft using random //* numbers, and determining if there is space for a new airplane //* //* when runway is busy the aircraft waits in an airborne queue; //* an airplane can be released from the airborne queue by clicking on it, //* //* originally written by A.J. Kornecki, CSD ERAU, January 1995 //* JAVA port by Robert Temple, http://www.db.erau.edu/~templer/ //* September 1995 //* //******************* //* Updated November 1995 //******************* import java.awt.*; import java.awt.image.*; import java.applet.Applet; import java.util.*; public class PatternSimulator extends Applet { SimCanvas canvas; public Label time_label; public Label number_label; Button pause_button; public void init() { canvas = new SimCanvas(); canvas.init(this); setLayout(new BorderLayout()); Panel p = new Panel(); p.setFont(new Font("TimesRoman", Font.BOLD, 12)); p.add(new Label("Simulation Time:", Label.RIGHT)); p.add(time_label = new Label("1000", Label.LEFT)); p.add(new Label("Airplanes in system:", Label.RIGHT)); p.add(number_label = new Label("0", Label.LEFT)); p.add(new Label(" ")); p.add(pause_button = new Button("Start Sim")); pause_button.disable(); add("North", p); add("Center", canvas); } public void start() { if (canvas.sim_thread == null) { canvas.sim_thread = new Thread(canvas); canvas.sim_thread.start(); } } public void stop() { canvas.sim_thread = null; } public boolean action(Event evt, Object arg) { if ("Start Sim".equals(arg)) { pause_button.setLabel("Pause"); canvas.startSim(); return true; } else if("Pause".equals(arg)) { canvas.paused = true; pause_button.setLabel("Resume"); return true; } else if("Resume".equals(arg)) { canvas.paused = false; pause_button.setLabel("Pause"); } return false; } } class SimCanvas extends Canvas implements Runnable { Applet app; public Thread sim_thread = null; Image background; Image hangar; Image double_buffer; Graphics double_buffer_graphics; int mouse_down_at_x; int mouse_down_at_y; public Vector airplanes; int simulation_units; final static double new_plane_frequency = 0.10; public boolean paused = true; public void init(Applet app) { resize(450, 450); setBackground(new Color(10, 70, 30)); this.app = app; background = app.getImage(app.getDocumentBase(), "backgrnd.gif"); hangar = app.getImage(app.getDocumentBase(), "hangar.gif"); CommercialAirplane.MakeImages(app.getImage(app.getDocumentBase(), "777.gif"), app); PropellerAirplane.MakeImages(app.getImage(app.getDocumentBase(), "propeller.gif"), app); double_buffer = app.createImage(450, 450); double_buffer_graphics = double_buffer.getGraphics(); double_buffer_graphics.setColor(new Color(10, 70, 30)); double_buffer_graphics.fillRect(0,0,450,450); double_buffer_graphics.setColor(Color.white); double_buffer_graphics.drawString("Loading Pattern Simulator...", 10, 425); airplanes = new Vector(20); } public void startSim() { airplanes.removeAllElements(); airplanes.addElement(new CommercialAirplane()); repaint(); simulation_units = 1000; paused = false; } public void paint(Graphics g) { double_buffer_graphics.drawImage(background, 0, 0, app); for (Enumeration e = airplanes.elements() ; e.hasMoreElements() ;) { Airplane plane = (Airplane)e.nextElement(); plane.Draw(double_buffer_graphics, app); } double_buffer_graphics.drawImage(hangar, 170, 292, app); g.drawImage(double_buffer, 0, 0, app); } public void update(Graphics g) { paint(g); } public void run() { //# Get the first image to the screen ASAP while((app.checkImage(background, app) & ImageObserver.ALLBITS) == 0) { repaint(); try { Thread.sleep(250); } catch (InterruptedException e) {} } ((PatternSimulator)getParent()).pause_button.enable(); while (true) { if(paused) { try { Thread.sleep(1500); } catch (InterruptedException e) {} } else { if(--simulation_units <= 0) { ((PatternSimulator)getParent()).pause_button.setLabel("Start Sim"); paused = true; } ((PatternSimulator)getParent()).time_label.setText(Integer.toString(simulation_units)); ((PatternSimulator)getParent()).number_label.setText(Integer.toString(airplanes.size())); try { Thread.sleep(100); } catch (InterruptedException e) {} DoUpdate(); try { paint(getGraphics()); } catch (Exception e){ sim_thread = null; } } } } protected void DoUpdate() { boolean CanAddAirplane = true; boolean CanLandAirplane = true; for (Enumeration e = airplanes.elements() ; e.hasMoreElements() ;) { Airplane plane = (Airplane)e.nextElement(); if(plane.InTheWayOfNewAirplane()) { CanAddAirplane = false; } if(plane.CurrentlyLanding()) { CanLandAirplane = false; } } for (Enumeration e = airplanes.elements() ; e.hasMoreElements() ;) { Airplane plane = (Airplane)e.nextElement(); if(CanLandAirplane) { if(plane.DoLandIfPossible()) { CanLandAirplane = false; } } if(mouse_down_at_x >= 0) { plane.Release(mouse_down_at_x, mouse_down_at_y); } plane.Fly(); if(plane.RemoveMe()) { airplanes.removeElement(plane); } } if(CanAddAirplane) { double random_number = Math.random(); if(random_number < new_plane_frequency / 2) { airplanes.addElement(new PropellerAirplane()); } else if(random_number < new_plane_frequency) { airplanes.addElement(new CommercialAirplane()); } } } public boolean mouseDown(java.awt.Event evt, int x, int y) { mouse_down_at_x = x; mouse_down_at_y = y; return true; } public boolean mouseUp(java.awt.Event evt, int x, int y) { mouse_down_at_x = -1; mouse_down_at_y = -1; return true; } public boolean mouseDrag(java.awt.Event evt, int x, int y) { mouse_down_at_x = x; mouse_down_at_y = y; return true; } } abstract class Airplane extends Object { public static final int NORTH = 0; public static final int NORTHEAST = 1; public static final int EAST = 2; public static final int SOUTHEAST = 3; public static final int SOUTH = 4; public static final int SOUTHWEST = 5; public static final int WEST = 6; public static final int NORTHWEST = 7; public static final int SPEED = 18; public static final int DIAGNAL_SPEED = 10; public static final int GROUND_SPEED = 5; public static final int DIAGNAL_GROUND_SPEED = 3; public static final int NORMAL = 0; public static final int LANDING = 1; public static final int LEAVING = 2; int x, y, w, h; int direction; int status; int random_course; Airplane() { this.x = 410; this.y = 0; direction = SOUTH; status = NORMAL; random_course = (int) (Math.random() * 20.0f); } public abstract void Draw(Graphics g, ImageObserver ob); public boolean InTheWayOfNewAirplane() { if(status == LANDING) return false; switch(direction) { case EAST : return (x > 265); case SOUTHEAST : return status != LANDING; case SOUTH : return (status != LANDING && y < 135); default : return false; } } public boolean CurrentlyLanding() { return (status == LANDING && direction <= SOUTH); } public boolean RemoveMe() { if(status == LANDING && direction == NORTH) return true; if(status == LEAVING &&(x < -40 || y < -40 || x > 450 || y > 450)) return true; return false; } public boolean DoLandIfPossible() { if(status == NORMAL && direction == EAST && x >= 250 && x <= 275) { status = LANDING; direction = SOUTHEAST; return true; } return false; } public void Fly() { if(status == LANDING) { switch(direction) { case SOUTHEAST : y += DIAGNAL_SPEED; x += DIAGNAL_SPEED; if(x >= 280) { x = 282; direction = SOUTH; } break; case SOUTH : int gradual_slow = y / 20; y += SPEED - gradual_slow; if(y >= 269) { direction = SOUTHWEST; } break; case SOUTHWEST : x -= DIAGNAL_GROUND_SPEED; y += DIAGNAL_GROUND_SPEED; if(y >= 292) { direction = WEST; } break; case WEST : x -= GROUND_SPEED; if(x <= 220) { direction = NORTH; } break; } } else { switch(direction) { case NORTH : y -= SPEED; if(y + random_course < 65 && status != LEAVING) { direction = NORTHEAST; random_course = (int) (Math.random() * 20.0f); } break; case NORTHEAST : y -= DIAGNAL_SPEED; x += DIAGNAL_SPEED; if(y + random_course < 35 && status != LEAVING) { direction = EAST; } break; case EAST : x += SPEED; if(x + random_course > 370 && status != LEAVING) { direction = SOUTHEAST; random_course = (int) (Math.random() * 20.0f); } break; case SOUTHEAST : x += DIAGNAL_SPEED; y += DIAGNAL_SPEED; if(x + random_course > 400 && status != LEAVING) { direction = SOUTH; } break; case SOUTH : y += SPEED; if(y + random_course > 358 && status != LEAVING) { direction = SOUTHWEST; random_course = (int) (Math.random() * 20.0f); } break; case SOUTHWEST : x -= DIAGNAL_SPEED; y += DIAGNAL_SPEED; if(y + random_course > 388 && status != LEAVING) { direction = WEST; } break; case WEST : x -= SPEED; if(x + random_course < 62 && status != LEAVING) { direction = NORTHWEST; random_course = (int) (Math.random() * 20.0f); } break; case NORTHWEST : x -= DIAGNAL_SPEED; y -= DIAGNAL_SPEED; if(x + random_course < 32 && status != LEAVING) { direction = NORTH; } break; } } } public void Release(int x_press, int y_press) { if( status == NORMAL && x_press >= x && x_press <= x + w && y_press >= y && y_press <= y + h) { status = LEAVING; } } } class CommercialAirplane extends Airplane { public static Image airplane_image[] = new Image[8]; public static void MakeImages(Image base_image, Component component) { for(int y = 0 ; y < 8 ; ++y) { ImageFilter crop = new CropImageFilter(0, 38 * y, 36, 38); airplane_image[y] = component.createImage( new FilteredImageSource(base_image.getSource(), crop)); component.prepareImage(airplane_image[y], component); } } public CommercialAirplane() { super(); w = 36; h = 38; } public void Draw(Graphics g, ImageObserver ob) { g.drawImage(airplane_image[direction], x, y, ob); } } class PropellerAirplane extends Airplane { public static Image airplane_image[] = new Image[8]; public static void MakeImages(Image base_image, Component component) { for(int y = 0 ; y < 8 ; ++y) { ImageFilter crop = new CropImageFilter(0, 31 * y, 31, 31); airplane_image[y] = component.createImage( new FilteredImageSource(base_image.getSource(), crop)); component.prepareImage(airplane_image[y], component); } } public PropellerAirplane() { super(); w = 31; h = 31; } public void Draw(Graphics g, ImageObserver ob) { g.drawImage(airplane_image[direction], x, y, ob); } }