This class creates and updates the navigational information panel at the top left of the applet window. Its paint() method first draws the headings and field names for the items of information displayed. Then, every time the aircraft's position is updated by the navigational classes, update() displays the numerical value corresponding to each field name.
Aeronautical distance is still normally given in nautical miles and speed is given in knots. However, most people throughout the world, and all those who are concerned with science and engineering went metric a long time ago. In the interests of general familiarity, therefore, distances are given in kilometres and speeds in kilometres per hour. Aeronaughts, please forgive.
The rate of turn figure may not be quite what it seems. It is of course the rate at which the aircraft is turning, that it, its azimuthal angular velocity. However, the displayed figure includes another element. The shortest distance between two points (waypoints) on the Earth's surface is a great circle. As one flies a great circle, one's compass heading steadily changes. [If one were to fly a constant heading, one would spiral round the Earth in ever-decreasing circles until one ended up at one of the Earth's poles.] The displayed rate of turn figure includes by default this rate of change of heading due to great circle flight.
Finally, bearings are given in degrees (1/360 of a complete circle). The latitudes and longitudes are given in degrees and minutes (1/60 degree). Please note that the two digits after the decimal point are hundredths of a minute as seems to have become the preference after the advent of GPS . They are not seconds or arc as given in the older 'C' version of this software.
/**
* Navigation Information Display Panel for Moving Map package
* @author Robert J Morton
* @version 16 December 1997
*/
import java.awt.*;
class navpanel extends Panel implements navconst {
private static navpanel np; //reference to this nav panel's own object
private Graphics g; //graphics context of the nav panel
private Font font; //reference to a text font (or typeface)
private FontMetrics fm; //type-face dimensions etc.
private int fh; //font height (height of a line of text)
private int fa; //font ascent (height of letters above base line)
private int nw = 0; //width in pixels of longest field name
private int ne; //end position of numeric field (excluding sign)
private int vw; //width in pixels of standard value string
private int sw; //width of '+' sign
private int rw; //width of wiper rectangle
private int VY = 10; //top margin for start of text
private int vy; //start height of first numeric value
private int FI = 10; //field names inset from left side of applet window
private String FN[] = { //names of the numeric fields
"Name", "Latitude", "Longitude", "Distance (km)", "Bearing", "Radial",
"Latitude", "Longitude", "Speed (kph)", "Heading", "Req Hdg", "Turn Rate"
};
private int fn; //field number index for the above array
private double LTV[]; //array for previous 'double' values of display fields
private String LTS[]; //array to hold previous display string versions
private boolean FTT = true; //set to indicate first time through
private String wpname = ""; //waypoint name buffer
private String sign = ""; //sign of the displayed field value
navpanel(Font f, FontMetrics m) { //CONSTRUCT THE NAV PANEL
np = this; //reference to nav panel object
font = f; fm = m; //capture font and fontmetrics references
setFont(font);
int j;
nw = 0;
for(int i = 0; i < 12 ; i++) //find width (nw) of widest field name
if((j = fm.stringWidth(FN[i])) > nw)
nw = j;
nw += 30; //start position of numeric fields excluding sign
vw = fm.stringWidth("000:00.00"); //width of numeric display string
sw = fm.stringWidth("+"); //width of + sign (assumed wider than - sign)
rw = 180 - nw; //width of wiper rectangle
ne = nw + vw; //end position of numeric fields excluding sign
fh = fm.getHeight(); //get the full height of a line of text
fh = 14; //problem with Netscape Navigator
fa = fm.getAscent(); //get the font's ascent (height above baseline)
fa = 10; //problem with Netscape Navigator
LTV = new double[11]; //for last time's numeric values
LTS = new String[11]; //for last time's display strings
}
public void paint(Graphics G) { //DISPLAY THE FIELD NAMES & VALUES
g = G; //copy graphics context to local class variable
vy = VY; //go to top line of the nav panel text
g.setFont(font); //activate the required font
g.drawString("WAYPOINT", 0, vy); //display waypoint block heading
for(int i = 0; i < 6 ; i++) //display the 6 waypoint field names
g.drawString(FN[i], FI, vy += fh);
vy += 2; //skip a line
g.drawString("AIRCRAFT", 0, vy += fh); //display aircraft block heading
for(int i = 6; i < 12 ; i++) //display the 6 aircraft field names
g.drawString(FN[i], FI, vy += fh);
FTT = true; //set the 'first time through' flag
ShowFields(); //display the corresponding field values
}
public void update(Graphics G) { //Re-draw the panel in the event of it being
g = G; ShowFields(); //uneclipsed by another window or of it being
} //scrolled into view within the browser window.
private void ShowFields() { //RE-DISPLAY THE FIELD VALUES
g.setFont(font); //activate the required font
waypnt wp = waypnt.getCurrent(); //get reference of current waypoint object
vy = VY + fh; fn = 0; //go to line height of first field value
if(!wpname.equals(wp.getName()) || FTT) { //re-display waypoint name if it has changed
g.setColor(Color.lightGray); //set text background colour
g.fillRect(nw, vy - fa, rw, fh); //wipe the name field's display area
g.setColor(Color.black); //set text colour
g.drawString(wpname = wp.getName(), nw, vy); //display the name of the current waypoint
}
vy += fh; //advance down a line
ShowField(wp.getLat(), true); //waypoint latitude
ShowField(wp.getLng(), true); //waypoint longitude
ShowField(wp.getDst(), false); //waypoint distance
ShowField(wp.getrBrg(), false); //waypoint bearing
ShowField(wp.getOutRad(), false); //selected outbound radial
vy += fh + 2; //miss two lines
aircraft ac = aircraft.getCurrent(); //get reference to current aircraft object
ShowField(ac.getLat(), true); //aircraft latitude
ShowField(ac.getLng(), true); //aircraft longitude
ShowField(ac.getSpd(), false); //aircraft speed
ShowField(ac.getHdg(), false); //aircraft heading
ShowField(ac.getRqH(), false); //required heading
ShowField(ac.getROT(), false); //rate of turn radians per minute
FTT = false; //set to indicate not first time through
}
private void ShowField(double c, boolean flag) { //DISPLAY AN UPDATED NUMERIC FIELD
if(c != LTV[fn] || FTT) { //if value changed since last time through
LTV[fn] = c; //store new value for testing next time
String v = ""; //display string
if(fn == 2) v = getDist(c); //field #2 is 'waypoint distance'
else if(fn == 7) v = getSpeed(c); //field #7 is 'aircraft speed'
else if(flag) v = getLatLng(c, fn); //if flag set it is a latitude or longitude
else v = getBrg(c, fn); //else it must be a 'bearing' value
String s = v + sign; //tack on the sign
if(!s.equals(LTS[fn]) || FTT) { //if display string changed since last time
g.setColor(Color.lightGray); //set text background colour
g.fillRect(nw, vy - fa, rw, fh); //wipe the numeric field's display area
g.setColor(Color.black); //set text foreground colour
g.drawString(LTS[fn] = s, //Display the number and its sign
ne - fm.stringWidth(v), vy); // right justified in the numeric field.
}
}
vy += fh; fn++; //advance downwards to the next line
}
private String getSpeed(double s) { //convert aircraft speed from double to display string
sign = ""; //speed is always positive
return "" + (int)Math.floor(s * KphRps); //find the number of whole kilometres per hour
}
private String getDist(double c) { //convert waypoint distance from double to string
double x;
if(wpenc.getCurrent().getToFlag()) { //if aircraft is receding from the waypoint
x = -c; sign = "-"; //reverse the sign of the distance
} else { //else if aircraft is receding from the waypoint
x = +c; sign = "+"; //display the distance as positive
}
LTV[2] = x; //store new value for testing next time
int d = (int)Math.floor(c); //find the number of whole kilometres
return "" + d + "." //form it into a display string and
+ (int)Math.floor(10 * (c - d)); //tack on the tenths of a kilometre
}
private String getLatLng(double c, int fn) { //CONVERT A LATITUDE OR LONGITUDE INTO A DISPLAY STRING
boolean sc = true; //the sign of c
if(c < 0) {sc = false; c = -c;} //if c negative make it positive and set sign negative
int d = (int)Math.floor(c *= DPR); //find the integral number of units
if(fn == 0 || fn == 5) //if it is a latitude
if(sc) sign = "N"; else sign = "S"; //then if it is positive it is north
else //else it is a longitude
if(sc) sign = "E"; else sign = "W"; //positive is east, negative is west
int m = (int)Math.floor(c = 60 * (c - d)); //then find number of whole minutes
String ms = ms = ":" + m; //assume initially that it fits without padding
if(m < 10) ms = ":0" + m; //pad it with a 0 if it's less than 10
int f = (int)Math.floor(100 * (c - m)); //hundredths of a minute of arc
String fs = "." + f;
if(f < 10) fs = ".0" + f; //pad it with a 0 if it's less than 10
return "" + d + ms + fs; //form it all into a string
}
private String getBrg(double c, int fn) { //STRING OF A BEARING FIELD
if(fn == 10) { //if displaying rate of turn
c *= 60; //convert to degrees per minute
if(c < 0) { //if c is negative
sign = "-"; c = -c; //make sign a '-' and make 'c' positive
} else sign = "+"; //else make the sign a '+'
} else sign = ""; //all other bearings have no sign (0-360)
int d = (int)Math.floor(c *= DPR); //find the integral number of units
return "" + d + "." //form it all into a string
+ (int)Math.floor(10 * (c - d)); //tack on the tenths of a degree
}
static navpanel getCurrent() {return np;} //return the panel's object reference
}
/* Robert J Morton, the author of this program,
is a poor but Right Honourable Member of the
Ancient and Noble Order of the Long-term Unemployed.
Offers of work please to: robmorton@clara.net */