/** Air Navigation Waypoint Intercept Demonstrator by Robert J Morton 21 Oct 1997 */ /* A demonstrator applet for the Waypoint Encounter class: NavEncPG.class which in turn uses the classes: Aircraft.class and Waypoint.class */ import java.awt.*; import javax.swing.*; import java.awt.image.BufferedImage; public class wpapplet extends JPanel implements Runnable { private int XE, // horizontal extent of window and JFrame. YE, // vertical extent of window and JFrame. SelRad = -44, // Selected Radial in angular degrees XM = 190, // x margin between left edge and start of tracking area fh, // font height (height of a line of text) fa, // font ascent (height of letters above base line) nw, // width in pixels of longest field name vw, // width in pixels of standard value string NY, // top margin for start of text VY, // start height of first numeric value vy, // start height of first numeric value X = 520, // window and image buffer dimensions Y = 200; // window and image buffer dimensions private int[] OldVal = { // values from previous pass of update() 999,999,999,999,999,999,999 }; private long tf = 50, // inter-plot time frame (milliseconds) t; // system time at which a new plot will be due to begin private String // Field names Names[] = { "WAYPOINT ENCOUNTER","","Waypoint Name","","Selected Radial", "Aircraft Bearing","Radial Deviation","","Station Bearing", "Steering Offset","Required Heading","","Distance" }, Zeros[] = { "","0","00","000" // leading zeros for displaying numeric values }; private Color TFC = Color.white; // text foreground colour private Font // set font for text in this applet font = new Font("Dialog",Font.PLAIN,12); private FontMetrics fm; // reference to font's dimensions etc. private BufferedImage I = null; // reference for an off-screen image buffer private Graphics2D gi = null; // graphics context for the off-screen image private Thread T; // declare a program thread reference private aircraft ac; // reference to an aircraft object private waypoint wp; // reference to a waypoint object private wpencpg en; // reference to an encounter object private wpcolour ca; // reference to a colour array object public wpapplet(int XE, int YE) { this.XE = XE; // horizontal [X] dimension of the JPanel this.YE = YE; // vertical [Y] dimension of the JPanel setBounds(0,0,XE,YE); // the JPanel fills the whole of the JFrame area setLayout(null); // JPanel has free-form layout [for graph] I = new BufferedImage(X,Y,BufferedImage.TYPE_INT_RGB); gi = I.createGraphics(); gi.setColor(Color.black); // set background colour for off-screen image gi.fillRect(0,0,X,Y); // paint background colour of off-screen image ac = new aircraft(); // create an aircraft object wp = new waypoint(); // create a waypoint object en = new wpencpg(); // create an encounter object ca = new wpcolour(); // create a colour array object fm = getFontMetrics(font); // get the dimensions etc for this font fh = fm.getHeight(); // get the full height of a line of text fh = 14; // Netscape Navigator problem fa = fm.getAscent(); // get the font's ascent (ht above baseline) fa = 10; // Netscape Navigator problem // width of the longest field name + 10pixels nw = fm.stringWidth(Names[10]) + 20; // width of numeric value readout string vw = fm.stringWidth("000+"); NY = 5; // top 'margin' for text VY = NY+fh+fh+fh+fh; // starting height of first numeric field T = new Thread(this); // by creating the thread object T.start(); // and starting it running by // Set system time at which the first plot time-frame will end t = System.currentTimeMillis() + tf; } private void reset(){ // PAINT THE SUPERSTRUCTURE FOR A NEW RUN gi.setColor(Color.black); // set background colour for the text area gi.fillRect(0,0,XM,ca.YH); // clear the text area gi.setFont(font); // activate the chosen font gi.setColor(Color.white); // set colour for displaying text int y = NY; // vertical start position for text for(int i = 0; i < 13; i++) { // display the field names gi.drawString(Names[i],10,y += fh); // show a field name if(i == 2) gi.drawString(wp.N,nw,y); // show the waypoint name } for(y = 0; y < ca.YH; y++) { // for each line of pixels of tracking area int X = 0; // starting dot of next single-colour stretch of line int x = 0; // to find next pixel in current line of different colour Color c = ca.C[X][y]; // make colour of first dot the reference colour while(++x < ca.XW) { // while not yet reached end of current line // if this dot is a different colour from the previous dot... if(c != ca.C[x][y]) { gi.setColor(c); // set colour to colour of previous dot // draw a line from the start dot to the 'previous' dot gi.drawLine(XM + X,ca.YH - y - 1,XM + x - 1,ca.YH - y - 1); c = ca.C[X = x][y]; // make new reference colour that of this dot } } gi.setColor(c); // set colour for final stretch of current line // draw the last stretch of the current line gi.drawLine(XM + X,ca.YH - y - 1,XM + x - 1,ca.YH - y - 1); } repaint(); // re-display the off-screen image } public void paint(Graphics g) { // PAINT THE INITIAL IMAGE g.drawImage(I,10,15,null); // draw from the off-screen image buffer } // DISPLAY A NUMERIC VALUE FOR A FIELD IN THE OFF-SCREEN IMAGE void ShowNum(Graphics g,double a,int n) { if(n < 6) // if displaying an angle, a *= en.DegRad; // convert IT from radians to degrees String sign = "+"; // means number to be displayed is positive if(a < 0) { // If the number is negative, a = -a; // reverse it sign = "-"; // and make it's sign a minus } int i = (int)a; // convert it to an integer if((a -= i) > .5) // and round it i++; vy += fh; // advance downwards to new text line if(i != OldVal[n]) { // if this value has changed since last update OldVal[n] = i; // note this time's (changed) value for next time String s = String.valueOf(i); // convert integer to a string i = 3 - s.length(); // Compute the number of if(i < 0) i = 0; // leading zeros needed. gi.setColor(Color.black); // set text background colour gi.fillRect(nw,vy-fa,vw,fh); // wipe numeric field's display area gi.setColor(Color.white); // set text foreground colour gi.drawString(Zeros[i] + s + sign,nw,vy); // display the string } } void advance(){ // ADVANCE THE AIRCRAFT ALONG THE TRACK int x = (int)(ac.x + XM), // current 'window co-ordinates' y = (int)(ca.YH - ac.y); // of aircraft gi.setColor(ca.ATC); // set colour of aircraft track gi.drawLine(x,y,x,y); // Draw the next bit of the aircraft track vy = VY; // set the vertical start position of the first numeric field gi.setFont(font); // activate the chosen font ShowNum(gi,en.OSR,0); // display outbound selected radial ShowNum(gi,en.tBrg,1); // display bearing of aircraft from waypoint // Display the aircraft's deviation from the selected outbound radial ShowNum(gi,en.RadDev,2); vy += fh; // miss a line ShowNum(gi,en.rBrg,3); // display bearing of waypoint from aircraft ShowNum(gi,en.StrOff,4); // display steering offset ShowNum(gi,en.ReqHdg,5); // display required heading vy += fh; // miss a line double a = en.Dst; if(en.approach) // show distance 'to' as negative a =- a; // and 'from' as positive ShowNum(gi,a,6); // display distance to/from waypoint repaint(); // re-display the off-screen image } public void run() { // RUN THE WAYPOINT ENCOUNTER PROGRAM THREAD while(true) { // permanent loop broken only by an external event if(en.outofRange(ac,wp)) { // if aircraft has just passed out of range if((SelRad += 44) > 359) // if selected radial has come full circle, SelRad -= 360; // then start over en.SetRadial(ac,wp,SelRad); // set up the new selected radial ca.InitC(ac,wp,en.OSR); // initialise the colour array reset(); // begin a new fly-past of the waypoint } else ca.PlotPosn(ac); // plot aircraft's new position on display raster advance(); // advance the aircraft along its track // get time left in this plot's time frame long s = t - System.currentTimeMillis(); if(s < 5) s = 5; // in case machine isn't fast enough try{Thread.currentThread().sleep(s);} // sleep for the time remaining catch(InterruptedException e) {} // catch interrupt from GUI // Set the system time at which the next plot's time frame will end. t = System.currentTimeMillis() + tf; } } }