PatternSimulator
//********
//* 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);
}
}
Back to the PatternSimulator applet page
New on the Java Boutique:
New Review:
Time Management Made Easy with the Quartz Enterprise Job Scheduler
Why not just use the Java timer API? This open source scheduling
API boasts simplicity, ease-of-integration, a well-rounded feature
set, and it's free!
New Applet:
Reverse Complement
Reverse Complement is a simple applet that converts DNA or RNA
sequences into three useful formats.
Elsewhere on internet.com:
WebDeveloper Java
Lots of Java information on webdeveloper.com
WDVL Java
Thorough Java resource at the Web Developer's Virtual Library.
ScriptSearch Java
Hundreds of free Java code files to download.
jGuru: Your View of the Java Universe
Customizable portal with online training, FAQs, regular news updates, and tutorials.
|