#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
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");
}
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
);
}
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);
}
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);
}

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);
}
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);
}