The MapWin.C File 07 JUNE 1991


#include <graph.h>
#include <math.h>
#include <malloc.h>

/* Define ERESCOLOR raster's true aspect ratio on an IBM 8513 
VGA screen: */ #define ASPECTRATIO .6834532737

/* Define the number of kilometres equivalent to one Great 
Circle radian: */ #define KMPERRADIAN 6366.197723857773

/* Define the number of radians/second equivalent to one 
kilometre/hour */ #define KMH_RADS .4363323129861111E-7

/* Define the number of degrees/minute equivalent to one 
radian/second: */ #define RADS_DEGM 3437.74677

#define X_DIAM 100 //Diameter of scale square on map in Xpixels
#define X_SQUR 200 //Diameter of scale square on map in Xpixels

extern char *RadDeg(double c);

double Y_DIAM = X_DIAM * ASPECTRATIO,
       Y_SQUR = X_SQUR * ASPECTRATIO;

extern double           //All measured in radians
  ObsLat, ObsLng,       //Observer's lat/long
  DstLat, DstLng,       //Destination lat/long
  ObsHdg, ObsVel,       //Observer's direction and velocity

  Range,     //Distance of feature (eg city) from Observer
  Bearing,   //Bearing of the feature as viewed by Observer
  ObsRot,    //Observer's rate of rotation (radians/sec)
  ReqHdg,    //Commanded heading to bring vehicle on to Radial
  Radial;    //Destination radial on which observer must travel
Set up an area of memory to hold:

If compiling with CL, a static array char far Graph[2156] can be used. However, QC does not support far static data, so we must use malloc() to allocate an area of memory dynamically.

char
  far *GraphBuf,  //Pointer to `city blob' image
  far *Letters;   //Pointer to letter images

The MapBox( ) Function

Display the basic map screen on the currently-active page.
MapBox() {
  _settextcolor(6); _settextposition(1,1);
  _outtext("EBS VEHICLE NAVIGATION SYSTEM");
  _moveto(-X_DIAM, Y_SQUR + 17);
  _lineto( X_DIAM, Y_SQUR + 17);
  _settextposition(24, 53); _outtext("100km");
  _settextcolor(3);
  _settextposition(4,1); _outtext("NEXT WAY POINT");
  _settextposition(5,1); _outtext("LATITUDE");
  _settextposition(6,1); _outtext("LONGITUDE");
  _settextposition(7,1); _outtext("DISTANCE TO GO       km");
  _settextposition(8,1); _outtext("INBOUND RADIAL");
  _settextposition(10,1); _outtext("VEHICLE");
  _settextposition(11,1); _outtext("LATITUDE");
  _settextposition(12,1); _outtext("LONGITUDE");
  _settextposition(13,1); _outtext("HEADING");
  _settextposition(14,1); _outtext("SPEED                km/hr");
  _settextposition(16,1); _outtext("REQ'D HEADING");
  _settextposition(17,1); _outtext("RATE OF TURN         ø/min");
}

The MapIni( ) Function

Set up the graphics images necessary for displaying annotated map features (such as cities) within the map window:
MapIni() {
  int a, ox, oy;              //Logical origin of Map Window
  char far *Letter;
  struct videoconfig config;  //Defines CGA, EGA, VGA etc.
  _setvideomode(_ERESCOLOR);  //Mode to 16-colour 640 x 350
  _setactivepage(1);          //Set Page 1 active while
  _setvisualpage(0);          //displaying Page 0

  /* Allocate 2156 bytes of buffer and put its start address 
     in the far char pointer 'GraphBuf'. 76 bytes are for the 
     city blob, the rest is for the captured text characters 
     at 40 bytes per character. */

  GraphBuf = (char far *)malloc((unsigned int) 2156);
  Letters = GraphBuf + 76;

  /* Form the blob to represent a city and store its image in 
     the graphics image buffer pointed to by `graphbuf' this 
     image occupies first 76 bytes of the buffer */ 

  _setcolor(9);
  _moveto(4,0); _lineto( 8,0);
  _moveto(2,1); _lineto(10,1);
  _moveto(1,2); _lineto(11,2);
  _moveto(0,3); _lineto(12,3);
  _moveto(0,4); _lineto(12,4);
  _moveto(0,5); _lineto(12,5);
  _moveto(1,6); _lineto(11,6);
  _moveto(2,7); _lineto(10,7);
  _moveto(4,8); _lineto( 8,8);
  _getimage(0,0,12,8,GraphBuf);

  /* Display the alphabet on the screen, then capture each 
     letter as a graphics image and store it in the graphics 
     buffer from byte 76 onwards. The image of each letter 
     occupies 40 bytes of buffer */

  _settextcolor(7);
  _settextposition(1,1);
  _outtext(
    "'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  );
  for(a = 0, Letter = Letters; a < 416; a += 8, Letter += 40)
    _getimage(0 + a, 2, 7 + a, 10, Letter);
  _clearscreen(_GCLEARSCREEN);

  /* Set the logical co-ordinates origin to the centre of the 
     map display window. (Effective for both video pages.) */ 

  _getvideoconfig(&config);
  ox = config.numxpixels / 2 + 115;
  oy = config.numypixels / 2;
  _setlogorg(ox, oy);

  // Set up the main screen format on both video pages 0 and 1
  MapBox(); _setactivepage(0); _setvisualpage(1); MapBox();
  _settextcolor(7);

  /* Limit graphics area to window. Effective on BOTH video 
     pages. */
  _setcliprgn(
    ox - X_SQUR, oy - Y_SQUR + 1, ox + X_SQUR, oy + Y_SQUR
  );
}

The RBtoXY( ) Function

Compute X,Y screen co-ordinates from the range & bearing in radians. Assumes logical co-ordinates are at centre of 640 by 350 pixel VGA screen. If scale <= 1 nautical mile per pixel, curvature of screen ÷ that of the Earth so the actual range on the Earth's surface is used to compute the x,y screen co-ordinates. If scale > 1 nautical mile per pixel the surface range is projected onto the Earth's tangential plane at the observer point (centre-screen) before x,y are computed. Returns zero co-ordinates if observed is out of screen range.
int *RBtoXY(float s) {
  static int a[2];              //array for screen co-ordinates
  double x, y, z,
    d = Range * KMPERRADIAN,    //in km (20,000/pi km/radian)
    b = Bearing - ObsHdg;       //bearing in radians + heading

  // If scale > 2km/pixel, project range onto tangential plane.
  if(s > 2) d *= sin(Range);

  if(s > 0) d /= (z = s);           //Re-scale from km to pixels
  x = d * sin(b);                   //screen x-pixel
  y = d * cos(b);                   //screen y-pixel
  if(x > 0) x += .5; else x -= .5;  //Do appropriate negative
  if(y > 0) y += .5; else y -= .5;  //or positive rounding.
  if(x > 185 || x < -185 ||         //safe screen x-range limit
    y > 185 || y < -185) {          //safe screen y-range limit
    x = 1000; y = 1000;             //set zero co-ordinates
  }                                 //if target is off screen

  /* Store the x-displacement as is, and the y-displacement
     scaled to the MRES screen aspect ratio. Then return the 
     pointer to the co-ordinates array. */

  *a = x; *(a + 1) = -y * ASPECTRATIO; return(a);
}

The ShowNode( ) Function

Display a city or way point on the Earth's surface as a small annotated circle or ellipse.
ShowNode (
  int *q,     //Pointer to city's SCREEN co-ordinates array.
  char *n     //Pointer to city's name string.
) {
  int x = *q, y = *(q + 1), //x-y co-ordinates of city
  i,                        //Letter Nº within City Name
  l,                        //Nº of characters in annotation
  m;                        //repeat of l

  _putimage(x-6, y-4, GraphBuf, _GPSET);  //Display the city
  for(l = 0; *n != ' '; l++, n++);  //Find length of its name
  n -= l;

  //PUT CITY'S NAME LEFT, RIGHT, ABOVE, BELOW THE CITY ITSELF
  m = l;
  switch(*(n + 15)) {
    case 'L': x -= (8 + (m <<= 3)); break;    //annotate left
    case 'R': x += 10; break;                 //annotate right
    case 'A': x -= (m <<= 2); y -= 13; break; //annotate above
    case 'B': x -= (m <<= 2); y += 13;        //annotate below
  }

  /* Display the name of the city by displaying in sequence at 
     the city's screen co-ordinates the letters of its name as 
     graphics images of the normal text letters . */

  for(i = 0; i < l; i++, x += 8)  //For each letter of the name
  _putimage(x, y - 4, Letters + (*(n + i) - 39) * 40, _GPSET);
}

The RadKm( ) Function

Converts a 'double' in Earth-radians or Earth-radians/second to a 5-byte string showing km or km/hr respectively:
char *RadKm(double d, int e) {
  int a, b, c, latch = 0, x = ' ';
  char *s = "      ", *t = s, *o = "OVFLOW";
  if(e == 0) d *= KMPERRADIAN;
  else if (e == 1) d /= KMH_RADS;
  else if (e == 2) d *= RADS_DEGM;
  if(d > 32767 || d < -32767) s = o;
  else {
    b = d;
    if(b < 0) { b = -b; x = '-'; }
    for(a = 10000; a > 1; a /= 10, t++) {
      for(c = 0; b >= a; b -= a, c++);
      if(!latch) {          //If latch not yet set,
        if(c == 0)          //if digit value is zero
          *t = ' ';         //store a leading space
        else {              //else if first non-zero digit
          latch = 1;        //set the latch
          *t++ = x;         //store the sign
          *t = c + 48;      //store character, including zeros.
        } 
      } else *t = c + 48;   //store character, including zeros.
    }
    if(!latch) *t++ = x;    //store the sign
    *t = b + 48;
  }
  return(s);
}

The ShowData( ) Function

Updates the text-based navigation data on the screen:
ShowData() {
  static int pg;
  _setcolor(7);              //Set to display in white 
  _moveto(-X_DIAM,-Y_DIAM);  //Re-display the inner square
  _lineto(X_DIAM,-Y_DIAM);  _lineto(X_DIAM,Y_DIAM); 
  _lineto(-X_DIAM,Y_DIAM);  _lineto(-X_DIAM,-Y_DIAM);
  //Re-display the cross-hairs at the centre of the map window
  _moveto(-14,  0); _lineto( 14,  0); 
  _moveto(  0, 10); _lineto(  0,-10);
  _settextposition( 5,16); _outtext(RadDeg(DstLat));
  _settextposition( 6,16); _outtext(RadDeg(DstLng));
  _settextposition( 7,16); _outtext(RadKm(Range,0));
  _settextposition( 8,16); _outtext(RadDeg(Radial));
  _settextposition(11,16); _outtext(RadDeg(ObsLat));
  _settextposition(12,16); _outtext(RadDeg(ObsLng));
  _settextposition(13,16); _outtext(RadDeg(ObsHdg));
  _settextposition(14,16); _outtext(RadKm(ObsVel,1));
  _settextposition(16,16); _outtext(RadDeg(ReqHdg));
  _settextposition(17,16); _outtext(RadKm(ObsRot,2));
  _setvisualpage(pg);    //Display completed graphics page
  pg ^= 1;               //Flip video page: 0 -> 1; 1 -> 0
  _setactivepage(pg);    //Set old display page for updating
  _setcolor(8);
  _rectangle(_GFILLINTERIOR, -X_SQUR, -Y_SQUR, X_SQUR, Y_SQUR);
}

This page's parent within this Web Site. About this Web Site. Its home page. Email its Author.