00001
00062 package riverrat;
00063
00064 import java.awt.Font;
00065 import java.awt.Frame;
00066 import java.awt.Color;
00067 import java.awt.Graphics;
00068 import java.awt.Graphics2D;
00069 import java.awt.RenderingHints;
00070 import java.awt.Menu;
00071 import java.awt.MenuBar;
00072 import java.awt.MenuItem;
00073 import java.awt.event.WindowAdapter;
00074 import java.awt.event.WindowEvent;
00075 import java.awt.event.MouseListener;
00076 import java.awt.event.MouseMotionListener;
00077 import java.awt.event.MouseEvent;
00078 import java.awt.event.KeyListener;
00079 import java.awt.event.KeyEvent;
00080 import java.awt.event.ActionListener;
00081 import java.awt.event.ActionEvent;
00082 import java.util.Vector;
00083
00087 public class RiverRatDemo extends Frame implements RiverRatClient, MouseListener, MouseMotionListener, KeyListener, ActionListener {
00088 static final int TRACK_DOT_RADIUS = 10;
00089 static final int DOT_RADIUS = 10;
00090 static final int MARK_RADIUS = 15;
00091
00092 static final int MAX_DIMENSION = 500;
00093
00094 static final float NW_LAT = 42.3645f;
00095 static final float SE_LAT = 42.3505f;
00096 static final float NW_LON = -71.095f;
00097 static final float SE_LON = -71.075f;
00098 static final int GRID_DIVISIONS = 10;
00099
00100 static final boolean DEBUG = false;
00101 static final boolean ENABLE_TRACKS = true;
00102 static final boolean DRAW_BOAT_ICON = true;
00103
00104 static final Color BG_COLOR = Color.white;
00105 static final Color GRID_COLOR = Color.gray;
00106
00107 static String host = "localhost";
00108 static int port = 8080;
00109
00110 Map themap;
00111 Race therace;
00112 Color dotcolor;
00113 int boatid;
00114 int markid;
00115 int width = 1000;
00116 int height = 375;
00117
00118 int mouse_x, mouse_y;
00119 boolean isButtonPressed = false;
00120 boolean drawPointerLocation = false;
00121 boolean drawRaceStatus = true;
00122 boolean drawBoatStatus = true;
00123 boolean drawGrid = false;
00124 boolean drawHelp = false;
00125
00131 public RiverRatDemo() {
00132 super("River Rat: The coolest sailing you've ever seen.");
00133 this.addWindowListener(new WindowAdapter() {
00134 public void windowClosing(WindowEvent e) {
00135 System.exit(0);
00136 }
00137 });
00138
00139 ViewMenu viewMenu = new ViewMenu((ActionListener) this);
00140 MenuBar mb = new MenuBar();
00141 mb.add(viewMenu);
00142 setMenuBar(mb);
00143
00144 therace = new LiveRace(host, port);
00145 themap = new Map(new Fix(NW_LAT, NW_LON), new Fix(SE_LAT, SE_LON));
00146 setSize(width, height);
00147 setBackground(BG_COLOR);
00148 setVisible(true);
00149
00150 addKeyListener(this);
00151 addMouseListener(this);
00152 addMouseMotionListener(this);
00153 }
00154
00159 public void actionPerformed(ActionEvent e) {
00160 String item = e.getActionCommand();
00161 if(item.equals("Hide Race Status")) drawRaceStatus = !drawRaceStatus;
00162 else if(item.equals("Hide Boat Status")) drawBoatStatus = !drawBoatStatus;
00163 else if(item.equals("Draw Pointer Location")) drawPointerLocation = !drawPointerLocation;
00164 else if(item.equals("Draw Lat/Lon Grid")) drawGrid = !drawGrid;
00165 }
00166
00172 class ViewMenu extends Menu {
00179 public ViewMenu(ActionListener al) {
00180 super("View");
00181 MenuItem mi;
00182 add(mi = new MenuItem("Hide Race Status"));
00183 mi.addActionListener(al);
00184 add(mi = new MenuItem("Hide Boat Status"));
00185 mi.addActionListener(al);
00186 add(mi = new MenuItem("Draw Pointer Location"));
00187 mi.addActionListener(al);
00188 add(mi = new MenuItem("Draw Lat/Lon Grid"));
00189 mi.addActionListener(al);
00190 }
00191 }
00192
00196 public void mouseEntered(MouseEvent e) {}
00197 public void mouseExited(MouseEvent e) {}
00198 public void mouseClicked(MouseEvent e) {}
00199
00204 public void mousePressed(MouseEvent e) {
00205 isButtonPressed = true;
00206 repaint();
00207 e.consume();
00208 }
00209
00214 public void mouseReleased(MouseEvent e) {
00215 isButtonPressed = false;
00216 repaint();
00217 e.consume();
00218 }
00219
00226 public void mouseMoved(MouseEvent e) {
00227 mouse_x = e.getX();
00228 mouse_y = e.getY();
00229 repaint();
00230 e.consume();
00231 }
00232
00239 public void mouseDragged(MouseEvent e) {
00240 mouse_x = e.getX();
00241 mouse_y = e.getY();
00242 repaint();
00243 e.consume();
00244 }
00245
00253 public void drawArrows(Graphics g) {
00254 drawTriangle(g, 50, 450, (float) 0.0f);
00255 drawTriangle(g, 100, 450, (float) (Math.PI)/4.0f);
00256 drawTriangle(g, 150, 450, (float) (Math.PI)/2.0f);
00257 drawTriangle(g, 200, 450, (float) (3.0f*Math.PI)/4.0f);
00258 drawTriangle(g, 250, 450, (float) (1.0f*Math.PI));
00259 drawTriangle(g, 300, 450, (float) (5.0f*Math.PI)/4.0f);
00260 drawTriangle(g, 350, 450, (float) (3.0f*Math.PI)/2.0f);
00261 drawTriangle(g, 400, 450, (float) (7.0f*Math.PI)/4.0f);
00262 drawTriangle(g, 450, 450, (float) (2.0f*Math.PI));
00263 }
00264
00277 public void drawTriangle(Graphics g, int x, int y, float radians) {
00278 int[] xPoints = new int[3];
00279 int[] yPoints = new int[3];
00280 yPoints[0] = - (int) ((float) 2.0f*DOT_RADIUS*Math.cos(radians));
00281 yPoints[1] = - (int) ((float) DOT_RADIUS*Math.cos((radians)+(float) ((2.0f*Math.PI)/3.0f)));
00282 yPoints[2] = - (int) ((float) DOT_RADIUS*Math.cos((radians)+(float) ((4.0f*Math.PI)/3.0f)));
00283 xPoints[0] = (int) ((float) 2.0f*DOT_RADIUS*Math.sin(radians));
00284 xPoints[1] = (int) ((float) DOT_RADIUS*Math.sin((radians)+(float) ((2.0f*Math.PI)/3.0f)));
00285 xPoints[2] = (int) ((float) DOT_RADIUS*Math.sin((radians)+(float) ((4.0f*Math.PI)/3.0f)));
00286 for(int i = 0; i < 3; i++) {
00287 xPoints[i] += x;
00288 yPoints[i] += y;
00289 }
00290 g.fillPolygon(xPoints, yPoints, 3);
00291 }
00292
00306 public void drawBoatIcon(Graphics g, int x, int y, float radians) {
00307 int[] xPoints = new int[7];
00308 int[] yPoints = new int[7];
00309 yPoints[0] = - (int) ((float) 2.0f*DOT_RADIUS*Math.cos(radians));
00310 yPoints[1] = - (int) ((float) 1.2f*DOT_RADIUS*Math.cos((radians)+(float) (Math.PI)/3.0f));
00311 yPoints[2] = - (int) ((float) 1.2f*DOT_RADIUS*Math.cos((radians)+(float) (Math.PI)/2.0f));
00312 yPoints[3] = - (int) ((float) DOT_RADIUS*Math.cos((radians)+(float) ((2.0f*Math.PI)/3.0f)));
00313 yPoints[4] = - (int) ((float) DOT_RADIUS*Math.cos((radians)+(float) ((4.0f*Math.PI)/3.0f)));
00314 yPoints[5] = - (int) ((float) 1.2f*DOT_RADIUS*Math.cos((radians)+(float) ((3.0f*Math.PI)/2.0f)));
00315 yPoints[6] = - (int) ((float) 1.2f*DOT_RADIUS*Math.cos((radians)+(float) ((5.0f*Math.PI)/3.0f)));
00316
00317 xPoints[0] = (int) ((float) 2.0f*DOT_RADIUS*Math.sin(radians));
00318 xPoints[1] = (int) ((float) 1.2f*DOT_RADIUS*Math.sin((radians)+(float) (Math.PI)/3.0f));
00319 xPoints[2] = (int) ((float) 1.2f*DOT_RADIUS*Math.sin((radians)+(float) (Math.PI)/8.0f));
00320 xPoints[3] = (int) ((float) DOT_RADIUS*Math.sin((radians)+(float) ((2.0f*Math.PI)/3.0f)));
00321 xPoints[4] = (int) ((float) DOT_RADIUS*Math.sin((radians)+(float) ((4.0f*Math.PI)/3.0f)));
00322 xPoints[5] = (int) ((float) 1.2f*DOT_RADIUS*Math.sin((radians)+(float) ((11.0f*Math.PI)/8.0f)));
00323 xPoints[6] = (int) ((float) 1.2f*DOT_RADIUS*Math.sin((radians)+(float) ((3.0f*Math.PI)/2.0f)));
00324
00325 for(int i = 0; i < 7; i++) {
00326 xPoints[i] += x;
00327 yPoints[i] += y;
00328 }
00329 g.fillPolygon(xPoints, yPoints, 7);
00330 }
00331
00337 public void drawHelpMessage(Graphics g) {
00338 if(drawHelp) {
00339 g.setColor(Color.white);
00340 g.fill3DRect((width/2)-70,(height/2)-45,180,80,true);
00341 g.setColor(Color.red);
00342 g.drawString("P to toggle pointer location",(width/2)-60,(height/2)-30);
00343 g.drawString("G to toggle grid",(width/2)-60,(height/2)-15);
00344 g.drawString("B to toggle boat status",(width/2)-60,(height/2));
00345 g.drawString("R to toggle race status",(width/2)-60,(height/2)+15);
00346 g.drawString("H to toggle this message",(width/2)-60,(height/2)+30);
00347 }
00348 }
00349
00356 public void drawCursorLatLon(Graphics g) {
00357 g.drawString("Pointer at ("+themap.getLatFromY((float) mouse_y/(float) height)+", "+themap.getLonFromX((float) mouse_x/(float) width)+")",250,60);
00358 }
00359
00365 public void drawLatLonGrid(Graphics g) {
00366 g.setColor(GRID_COLOR);
00367
00368 int inc = 0;
00369 try {
00370 inc = width/(GRID_DIVISIONS*(int)themap.getAspect());
00371 } catch(ArithmeticException ae) {
00372 }
00373 for(int x = 1; x < width; x += inc) {
00374 g.drawLine(x,0,x,height);
00375 }
00376 for(int y = 1; y < height; y += inc) {
00377 g.drawLine(0,y,width,y);
00378 }
00379 }
00380
00387 public void drawMark(Graphics g, int markid) {
00388 try {
00389 if(DEBUG) System.out.println("drawMark(): "+therace.getMark(markid).markToString());
00390 switch(markid % 3) {
00391 case 0: dotcolor = Color.yellow; break;
00392 case 1: dotcolor = Color.orange; break;
00393 }
00394 g.setColor(dotcolor);
00395 g.fillOval( (int) (width*themap.getXFromLon(therace.getMark(markid).getLon()))-(DOT_RADIUS/2),
00396 (int) (height*themap.getYFromLat(therace.getMark(markid).getLat()))-(DOT_RADIUS/2),
00397 MARK_RADIUS,MARK_RADIUS);
00398 g.setColor(Color.black);
00399 g.drawOval( (int) (width*themap.getXFromLon(therace.getMark(markid).getLon()))-(DOT_RADIUS/2),
00400 (int) (height*themap.getYFromLat(therace.getMark(markid).getLat()))-(DOT_RADIUS/2),
00401 MARK_RADIUS,MARK_RADIUS);
00402 g.drawString(""+(markid+1),
00403 (int) (width*themap.getXFromLon(therace.getMark(markid).getLon())),
00404 (int) (height*themap.getYFromLat(therace.getMark(markid).getLat()))+(int) ((7.0f/10.f)*DOT_RADIUS));
00405 } catch(NoSuchObjectException ex) {
00406 System.err.println("NoSuchObjectException caught.");
00407 return;
00408 }
00409 }
00410
00417 public void drawBoat(Graphics g, int boatid) {
00418 try {
00419 Vector boattrack;
00420 float colorvals[];
00421 float alpha;
00422 Fix tempfix;
00423 if(DEBUG) System.out.println("drawBoat(): "+therace.getBoat(boatid).boatToString());
00424 switch(boatid % 5) {
00425 case 0: dotcolor = Color.green; break;
00426 case 1: dotcolor = Color.blue; break;
00427 case 2: dotcolor = Color.red; break;
00428 case 3: dotcolor = Color.pink; break;
00429 case 4: dotcolor = Color.green; break;
00430 }
00431 g.setColor(dotcolor);
00432 if(drawBoatStatus) g.drawString(therace.getBoat(boatid).boatToString(),20,60+(20*boatid));
00433 boattrack = therace.getBoat(boatid).getTrack();
00434 colorvals = dotcolor.getColorComponents(null);
00435 if((boattrack.size() > 1) && (ENABLE_TRACKS)) {
00436 if(DEBUG){
00437 System.out.println("paint(): painting track: ");
00438 }
00439 for(int i = 0; i < boattrack.size(); i++) {
00440 alpha = (float) (1.0-((1.0/boattrack.size())*(boattrack.size()-i)));
00441 tempfix = (Fix)boattrack.elementAt(i);
00442 if(DEBUG) {
00443 System.out.println("paint(): alpha is "+alpha+", painting track dot at");
00444 System.out.println("paint(): +"+tempfix.fixToString());
00445 }
00446 if(alpha > 255) alpha = 255;
00447 if(alpha < 0) alpha = 0;
00448 dotcolor = new Color(colorvals[0],colorvals[1],colorvals[2],alpha);
00449 g.setColor(dotcolor);
00450 g.fillOval( (int) (width*themap.getXFromLon(tempfix.getLon()))-(DOT_RADIUS/2),
00451 (int) (height*themap.getYFromLat(tempfix.getLat()))-(DOT_RADIUS/2),
00452 TRACK_DOT_RADIUS,TRACK_DOT_RADIUS);
00453 }
00454 }
00455 if(DRAW_BOAT_ICON) {
00456 drawTriangle( g,
00457 (int) (width*themap.getXFromLon(therace.getBoat(boatid).getLon())),
00458 (int) (height*themap.getYFromLat(therace.getBoat(boatid).getLat())),
00459 therace.getBoat(boatid).getHeading());
00460 } else {
00461 g.fillOval( (int) (width*themap.getXFromLon(therace.getBoat(boatid).getLon()))-(DOT_RADIUS/2),
00462 (int) (height*themap.getYFromLat(therace.getBoat(boatid).getLat()))-(DOT_RADIUS/2),
00463 DOT_RADIUS,DOT_RADIUS);
00464 }
00465 } catch(NoSuchObjectException ex) {
00466 System.err.println("NoSuchObjectException caught.");
00467 return;
00468 }
00469 }
00470
00478 public void paint(Graphics g) {
00479 if(DEBUG) System.out.println("paint(): called");
00480 height = getHeight();
00481 width = getWidth();
00482 themap.setAspect((float)width/(float)height);
00483 ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
00484 g.setFont(new Font("Helvetica",Font.PLAIN,12));
00485 if(therace == null) {
00486 g.setColor(Color.red);
00487 g.drawString("Race has not begun",250,40);
00488 return;
00489 } else {
00490 g.setColor(Color.blue);
00491 if(drawRaceStatus) g.drawString("Race has "+therace.numBoats()+" boats",250,40);
00492 }
00493 if(drawGrid) drawLatLonGrid(g);
00494 if(drawPointerLocation) drawCursorLatLon(g);
00495 for(markid = 0; markid < therace.numMarks(); markid++) {
00496 drawMark(g, markid);
00497 }
00498 for(boatid = 0; boatid < therace.numBoats(); boatid++) {
00499 drawBoat(g, boatid);
00500 }
00501 drawHelpMessage(g);
00502 }
00503
00513 public void keyTyped(KeyEvent e) {
00514 if(((String)"p").equals(""+e.getKeyChar())) {
00515 drawPointerLocation = !drawPointerLocation;
00516 System.out.println("Toggling pointer location.");
00517 }
00518 if(((String)"b").equals(""+e.getKeyChar())) {
00519 drawBoatStatus = !drawBoatStatus;
00520 System.out.println("Toggling boat status.");
00521 }
00522 if(((String)"r").equals(""+e.getKeyChar())) {
00523 drawRaceStatus = !drawRaceStatus;
00524 System.out.println("Toggling race status.");
00525 }
00526 if(((String)"g").equals(""+e.getKeyChar())) {
00527 drawGrid = !drawGrid;
00528 System.out.println("Toggling lat/lon grid.");
00529 }
00530 if(((String)"h").equals(""+e.getKeyChar())) {
00531 drawHelp = !drawHelp;
00532 System.out.println("Toggling help.");
00533 }
00534 }
00535
00536 public void keyReleased(KeyEvent e) {}
00537
00538 public void keyPressed(KeyEvent e) {}
00539
00545 public static void main(String args[]) {
00546 System.out.println("Starting RiverRatDemo...");
00547 RiverRatDemo rr = new RiverRatDemo();
00548
00549 while(true) {
00550 rr.repaint();
00551 try {
00552 Thread.sleep(500);
00553 } catch(InterruptedException ie) {
00554 }
00555 }
00556 }
00557 }