// $Id$ // // = FILENAME // NavigationVisComp.java // // = AUTHOR // Seth Widoff (core functionality) // Michael Kircher (mk1@cs.wustl.edu) // // = DESCRIPTION // This is a Visualization Component for displaying navigation. // // ============================================================================ import java.awt.*; import java.io.*; public class NavigationVisComp extends Panel implements VisComp { private Alt_Horizon alt_hor_ = new Alt_Horizon (); private Position pos_ = new Position (); public NavigationVisComp () { setLayout (new BorderLayout (0, 2)); add ("Center", alt_hor_); add ("South", pos_); } public void setName (String title) { } public int getProperty () { return Properties.NAVIGATION; } public void update (java.util.Observable observable, java.lang.Object obj) { Navigation navigation_ = null; try { navigation_ = (Navigation) obj; } catch (Exception excp) { System.out.println (excp); System.out.println ("Visualization Component received wrong data type!"); } if (navigation_ != null) { // make sure all the values are in the proper range. navigation_.roll = (navigation_.roll > 180 || navigation_.roll < -180) ? 0 : navigation_.roll; navigation_.pitch = (navigation_.pitch > 90 || navigation_.pitch < -90) ? 0 : navigation_.pitch; // update the artificial horizon alt_hor_.update_display (navigation_.roll, navigation_.pitch); navigation_.pitch = (navigation_.position_latitude > 90 || navigation_.position_latitude < -90) ? 0 : navigation_.position_latitude; navigation_.pitch = (navigation_.position_longitude > 100 || navigation_.position_longitude < 00) ? 0 : navigation_.position_longitude; navigation_.pitch = (navigation_.altitude > 90 || navigation_.altitude < -90) ? 0 : navigation_.altitude; navigation_.pitch = (navigation_.heading > 180 || navigation_.heading < -180) ? 0 : navigation_.heading; // update the position display pos_.update_display (navigation_.position_latitude, navigation_.position_longitude, navigation_.altitude, navigation_.heading); } } } class Alt_Horizon extends Canvas { private final static Color GREEN = new Color (0, 100, 0), BLUE = new Color (30, 144, 255); private Graphics offgraphics_; private Image offscreen_; private Dimension offscreensize_; private int roll_ = 0, pitch_ = 0; public void update_display (int roll, int pitch) { roll_ = roll; pitch_ = pitch; repaint (); } public Dimension getPreferredSize () { return new Dimension (180, 180); } public Dimension getMinimumSize () { return new Dimension (80, 80); } public void paint (Graphics g) { update (g); } public void update (Graphics g) { Dimension d = getSize (); int rad, angles[] = { 180, 0 }; Point center; if ((offscreen_ == null) || (d.width != offscreensize_.width) || (d.height != offscreensize_.height)) { offscreen_ = createImage (d.width, d.height); offscreensize_ = new Dimension (d.width, d.height); offgraphics_ = offscreen_.getGraphics (); offgraphics_.setFont (getFont()); // g.setColor (Color.lightGray); // g.draw3DRect (0, 0, d.width - 1, d.height - 1, true); // g.draw3DRect (1, 1, d.width - 3, d.height - 3, true); // g.draw3DRect (2, 2, d.width - 5, d.height - 5, true); } offgraphics_.setColor (getBackground()); offgraphics_.fillRect (0, 0, d.width, d.height); offgraphics_.setColor (BLUE); // Calculate from the dimensions, the largest square. center = new Point (d.width / 2, d.height / 2); rad = ((center.x < center.y) ? center.x : center.y); // Draw a circle of blue offgraphics_.fillOval (center.x - rad, center.y - rad, 2*rad, 2*rad); // Roll the horizon based on the roll angle if (roll_ != 0) roll_horizon (rad, angles); // Pitch the horizon based on the pitch angle if (pitch_ != 0) pitch_horizon (rad, angles); // Draw the resulting terrain draw_horizon (rad, center, angles); // Draw the plotted Image. g.drawImage (offscreen_, 0, 0, null); } private void draw_horizon (int rad, Point center, int[] angles) { // Draw an arc int arc_angle = ((angles[0] > angles[1]) ? (360 - angles[0]) + angles[1] : (angles[1] - angles[0])); Polygon remainder = new Polygon (); offgraphics_.setColor (GREEN); offgraphics_.fillArc (center.x - rad, center.y - rad, 2*rad, 2*rad, angles[0], arc_angle); if (pitch_ != 0) { if ((pitch_ > 0 && Math.abs (roll_) < 90) || (pitch_ < 0 && Math.abs (roll_) >= 90)) offgraphics_.setColor (BLUE); int cover_angle = (angles[0] + arc_angle/2 + ((arc_angle < 180) ? 180 : 0)) % 360; // System.out.println (points[0] + " " + points[1]); // System.out.println (accepted_point); remainder.addPoint (center.x + polar_to_rect_x (rad, cover_angle), center.y - polar_to_rect_y (rad, cover_angle)); remainder.addPoint (center.x + polar_to_rect_x (rad, angles[0]), center.y - polar_to_rect_y (rad, angles[0])); remainder.addPoint (center.x + polar_to_rect_x (rad, angles[1]), center.y - polar_to_rect_y (rad, angles[1])); offgraphics_.fillPolygon (remainder); //offgraphics_.setColor (getBackground ()); //offgraphics_.drawPolygon (remainder); } } private void pitch_horizon (int rad, int[] angles) { boolean upside_down = Math.abs (roll_) >= 90; int angle_shift = (int) Math.round ((double)(90 - (Math.abs (roll_) % 180)) / 90.0 * pitch_); // System.out.println ("angle_shift " + angle_shift); angles[0] += angle_shift; angles[1] -= angle_shift; } private void roll_horizon (int rad, int[] angles) { // Roll the left and right points of the terrain. angles[0] += roll_; angles[1] += roll_; if (angles[0] < 0) angles[0] += 360; if (angles[1] < 0) angles[1] += 360; } private int polar_to_rect_x (int rad, int angle) { return (int) Math.round (rad * Math.cos ((double)angle * Math.PI/180.0)); } private int polar_to_rect_y (int rad, int angle) { return (int) Math.round (rad * Math.sin ((double)angle * Math.PI/180.0)); } private double caclulate_slope (int rad, int[] angles) { int x1 = polar_to_rect_x (rad, angles[0]), x2 = polar_to_rect_x (rad, angles[1]), y1 = polar_to_rect_y (rad, angles[0]), y2 = polar_to_rect_y (rad, angles[1]); return ((double) (y2 - y1)) / ((double) (x2 - x1)); } private Point[] line_circle_intesect (int rad, double y_intercept, double slope) { double r_2 = (double)(rad * rad), s_2 = slope * slope, a_x = s_2 + 1, b_x = 2.0 * slope * y_intercept, c_x = y_intercept * y_intercept - r_2; int[] x_roots = quad_eq (a_x, b_x, c_x), y_roots = { (int) Math.round ((double)((double) x_roots[0])*slope + y_intercept), (int) Math.round ((double)((double) x_roots[1])*slope + y_intercept) }; Point[] points = new Point [2]; points[0] = new Point (x_roots[0], y_roots[0]); points[1] = new Point (x_roots[1], y_roots[1]); return points; } private int calculate_angle (int rad, int x, int y) { /* double angle = 0, sin_value = Math.asin ((double)y / (double)rad), tan_value = Math.atan ((double)y / (double)x); if (x >= 0) angle = (x != 0) ? tan_value : sin_value + ((y < 0) ? 2*Math.PI : 0); else angle = Math.PI + tan_value; return (int) Math.round (angle * 180.0 / Math.PI); */ double angle = 0.0, sin_value = Math.asin ((double)Math.abs (y) / (double)rad); if (x >= 0 && y >= 0) angle = sin_value; else if (x < 0 && y >= 0) angle = sin_value + Math.PI/2.0; else if (x < 0 && y < 0) angle = sin_value + Math.PI; else if (x >= 0 && y < 0) angle = sin_value + 3.0*Math.PI/2.0; return (int) Math.round (angle * 180.0 / Math.PI); } private int[] quad_eq (double a, double b, double c) { int[] roots = new int [2]; double body = Math.sqrt (b*b - 4.0*a*c); roots[0] = (int) Math.round ((-b + body) / (2.0 * a)); roots[1] = (int) Math.round ((-b - body) / (2.0 * a)); return roots; } private int distance (Point point1, Point point2) { double xdiff = point1.x - point2.x, ydiff = point1.y - point2.y; return (int) Math.round (Math.sqrt (xdiff*xdiff + ydiff*ydiff)); } } class Position extends Panel { private final static Font FONT = new Font ("Dialog", Font.BOLD, 12); private final static char DEGREE = '\u00B0'; private Label lat_ = new Label ("0" + DEGREE + " N", Label.RIGHT), long_ = new Label ("0" + DEGREE + " S", Label.RIGHT), alt_ = new Label ("0 Kft", Label.RIGHT), heading_ = new Label ("0" + DEGREE + " ", Label.RIGHT); public Position () { Panel grid_panel = new Panel (); lat_.setFont (FONT); long_.setFont (FONT); alt_.setFont (FONT); heading_.setFont (FONT); setLayout (new GridLayout (1, 4)); add (lat_); add (long_); add (heading_); add (alt_); } public void update_display (int lat, int lon, int alt, int heading) { String lat_str = Math.abs (lat) + "" + DEGREE + ((lat > 0) ? " N" : " S"); String long_str = Math.abs (lon) + "" + DEGREE + ((lon > 0) ? " E" : " W"); lat_.setText (lat_str); long_.setText (long_str); alt_.setText (alt + " Kft"); heading_.setText (heading + "" + DEGREE + " "); } }