DELAYS.C
/*********************************************************************
(c) 1984-2003 by Scientific Endeavors Corporation.
All rights reserved.
This program plots air traffic performance for
airport departures using the data file BOSDEP.DAT.
This program illustrates several useful GraphiC techniques:
1) How to create your own nonlinear polar grid.
2) How to generate a "clock" plot.
3) How to use circtext() and pltfnt().
4) How to make filled characters with a different color outline.
5) How to access stdprn in protected mode (GraphiC-286).
*********************************************************************/
#include <graphic.h>
#define TWOPI (float)TWO_PI
#define PI2 (float)PI_OVER_TWO
#if TCQ /* Set stack for Borland (Turbo) C */
extern unsigned _stklen = 0x3000;
#endif
FILE *ifptr = NULL, *stdp = NULL;
char lab[10]; /* The labels */
/**********************************************************************/
float rmap(float rin);
void GPC_MAIN(int argc, char *argv[])
{
float rmin = 0.0f, rmax = 15.0f, r0 = 10.0f, rinner = 5.0f, dr;
float r[241], theta[241], dth, x1, y1, xc, yc;
float r2[2], th2[2], rw, temp, th;
int i, j, nth = 240;
int ntick = 24;
char tkfname[20], name[6], str[100];
char *cp;
int type;
float actftime, oagdz, dz, az, estftime, oagaz;
char flight[10], from[10], to[10], depflight[12], equip[6];
float airdelay, grnddelay, arrivedelay;
int hour, tenth;
char datname[20];
if(argc < 2)
strcpy(datname, "bosdep.dat");
else
strcpy(datname, argv[1]);
ifptr = gfopen(datname, "r", 0);
/* Looks in the GPC(286) directory for the file */
if(ifptr==NULL) {
GPC_PUTS("\nUnable to open input data file.");
goto EndOfApp;
}
/*
Using GraphiC-286 in protected mode, stdprn is not opened by default. If you
debug by sending messages to stdprn, here is how to open a file handle
that can be used for that purpose.
*/
#if (1-GPC_WIN)
stdp = fopen("LPT1", "w"); /* The printer is not actually used */
#endif
/* TOSS THE ONE-LINE HEADER IN INPUT DATA */
/*
HEADER FORMAT:
DepFlight DZType Flight Equip From To DZ EstArr OAGDep OAGArr AZ
*/
while(fgetc(ifptr) != '\n');
/* CREATE A CONTEXT-DEPENDENT TKF FILE NAME AND TITLE */
strcpy(tkfname, datname);
cp = tkfname+3;
strcpy(cp, "DELAY.TKF");
strncpy(name, datname, 3);
name[3] = '\0';
cp = (char *)strupr(name);
bgnplot(1, 'g', tkfname); /* Start GraphiC */
font(4,"simplex.fnt",'\310',"swiss.fnt",'\311',"compgrma.fnt",'\312',
"swissitl.fnt", '\313'); /* Load fonts */
fillfont(1); /* Fill them */
startplot(230); /* Background is white */
metricunits(0); /* Ensure scaling in inch units */
color(BLACK); /* Scales are black */
rotate(1); /* Portrait mode */
page((float)6.844, (float)9.0);
area2d((float)6.0, (float)6.0);
physor((float)0.4, (float)1.5); /* Shift the plot down the page */
/* MAKE A LEGEND */
legpos(3, (float)0.2, (float)1.0, 1);
legend(2,"\311before takeoff = DZ time - OAG departure time", -2, .15f, 2);
legend(2,"\311in air = actual flight time - estimated flight time", -1, .15f, 1);
legend(2,"\311on arrival = AZ time - OAG arrival time", -4, .15f, 4);
/* PROCEDURE FOR OUTLINING A FONT IN ANOTHER COLOR */
tmargin((float)0.0);
color(RED); /* Do the filled string in red */
sprintf(str, "\313Departure Performance at %s", cp);
ctline(str, (float).3); /* ctline() gives more control of position */
tmargin((float)0.0); /* than using heading() */
color(BLACK); /* The outline color is black */
fillfont(0); /* Turn off filling for the outline */
ctline(str, (float).3);
fillfont(1);
axesoff(AXESOFF); /* We want to draw our own axes */
/* The plot will be an annulus from */
/* rinner to rmax */
polgrid(rmax, rmin, 1, NULL, 0, 0, 0); /* Set up polar coordinates */
dth = TWOPI/(float)nth;
/* DRAW BASE CIRCLE */
for (i = 0; i < nth + 1; i++) {
r[i] = r0; /* The location of our "zero delay" axis */
/* Time goes clockwise from the top */
theta[i] = PI2 - (float)i * dth;
}
tcurve(8); /* Thicken the zero delay line */
polcurve(r, theta, nth+1, 0); /* Draw it with no symbols */
tcurve(1);
dashf(2); /* Dotted lines for the grid */
/* DRAW CIRCLES */
for (j = -5; j <= 5; j++) {
if(j == 0)
continue;
/* DO NONLINEAR R SCALE */
rw = rmap((float)j) + 10.0f;
for (i = 0; i < nth + 1; i++) {
r[i] = rw;
}
polcurve(r, theta, nth+1, 0);
}
/* DRAW THE RADIAL LINES */
dth = TWOPI/(float)ntick;
dr = (float).3333333 * (rmax - rmin);
r2[0] = r0 - dr;
r2[1] = r0 + dr;
for (i = 0; i < ntick; i++) {
temp = PI2 - (float)i * dth ;
th2[0] = th2[1] = temp;
polcurve(r2, th2, 2, 0);
}
dashf(1); /* Return to solid lines */
color(BLUE);
/* LABEL THE CLOCK HOURS */
dth = TWOPI/(float)ntick;
/* FIND CENTER OF CIRCLE */
usertoinch((float)0.0, (float)0.0, &xc, &yc);
/* FIND THE RADIUS (= x1 - xc) */
usertoinch(rmax - (float).7, (float)0.0, &x1, &y1);
for (i = 0; i < ntick; i ++) {
th = PI2 - (float)i * dth; /* Clock angle */
sprintf(lab, "\311%d:00", i);
circtxt(xc, yc, x1 - xc, lab, (float).1,
(th*(float)360./TWOPI) + (float)2.5);
}
/* Add a curved axis label. Note the font change to get an arrow */
circtxt(xc, yc, x1 - xc + (float).25, "\311Greenwich Mean Time \312:\311",
(float).12, (float)90.0);
/* RADIAL LABELS */
tline(6);
color(GREEN);
/* MAKE TWO RADIAL ARROWS - DON'T CROSS THE ZERO DELAY LINE */
temp = (float)(.875 * (double)TWOPI); /* 315 degrees */
uvector(r0 - (float).1, temp, rinner - (float)1.0,
temp, (float)2.5, (float).1, "01");
pltfnt(rinner - (float)4.5, temp, "\311Early", (float).2, -45);
color(RED);
uvector(r0 + (float).1, temp, rmax + (float)0.5,
(float)(.875*(double)TWOPI), (float)2.5, (float).1, "01");
pltfnt(rmax + (float)1.5, temp, "\311Late", (float).2, -45);
tline(2);
color(BLUE);
temp = (float)(.885 * (double)TWOPI);
pltfnt(rinner + (float)2.0, temp, "\311hours", (float).1, -45);
/* THE PLOT IS SET UP. LOOP THROUGH THE DATA AND PLOT EACH POINT */
for(;;) {
/* GET FIRST DATA */
if(fscanf(ifptr, "%s%d%s%s%s%s%f%f%f%f%f",
&depflight, &type, &flight, &equip, &from, & to,
&dz, &estftime, &oagdz, &oagaz, &az) == EOF)
break;
/* Get nearest 6-minute interval (= .1 hour) */
i = (int)(dz * 100.f);
hour = i/100;
tenth = (i%100)/10;
j = 10 * hour + tenth;
temp = theta[j] * (float)360./TWOPI; /* Need degrees for the call */
/* CALCULATE AIR DELAY */
/* The difference between the estimated flight time in the dz message and (az - dz) */
if( az == (float)-1.0 || dz == (float)-1.0 || estftime == (float)-1.0)
airdelay = (float)-100.0; /* Check for NULL data */
else {
if(az < dz)
actftime = (float)24.0 + az - dz; /* Adjust for midnight */
else
actftime = az - dz;
if(estftime < dz)
estftime += (float)24.f;
estftime = estftime - dz;
airdelay = actftime - estftime;
}
/* CALCULATE GROUND DELAY BEFORE TAKEOFF */
/* THE TIME BETWEEN ACTUAL TAKEOFF AND OAG START */
if(oagdz == (float)-1.0 || dz == (float)-1.0)
grnddelay = (float)-100.0;
else {
if(fabs(oagdz - dz) > (float)12.0) {/* Across 24-hour boundary */
if(dz < oagdz)
dz += (float)24.0;
else
oagdz += (float)24.0;
}
grnddelay = dz - oagdz;
}
/* CALCULATE ARRIVAL DELAYS */
if(oagaz == (float)-1.0 || az == (float)-1.0)
arrivedelay = (float)-100.0;
else {
if(fabs(oagaz - az) > (float)12.0) {/* Across 24-hour boundary */
if(az < oagaz)
az += (float)24.0;
else
oagaz += (float)24.0;
}
arrivedelay = az - oagaz;
}
/* GRAPH THE ITEMS */
if(grnddelay != (float)-100.0) {
/* Get the correct position on the nonlinear scale */
rw = rmap(grnddelay) + (float)10.;
color(GREEN); /* Plot each data point as a small angular wedge */
wedge(rw - (float).03, rw + (float).03, temp-(float).6,
temp +(float).6, -2, 1);
}
if(airdelay != (float)-100.) {
rw = rmap(airdelay) + (float)10.0;
color(BLUE);
wedge(rw - (float).03, rw + (float).03, temp-(float).6,
temp +(float).6, -1, 1);
}
if(arrivedelay != (float)-100.0) {
rw = rmap(arrivedelay) + (float)10.;
color(RED);
wedge(rw - (float).03, rw + (float).03, temp-(float).6,
temp +(float).6, -4, 1);
}
}
gfclose(ifptr);
color(BLACK);
dateit((Uchar)'\310');
endplot();
stopplot();
EndOfApp:
if (stdp != NULL)
fclose(stdp);
}
/***********************************************************************/
/*
Make a nonlinear logarithmic radial scale to expand the first hours.
rout = 5 * sgn(rin) * log10(|rin|+1)/log10(6)
*/
float rmap(float rin)
{
float temp;
if(rin < 0) {
temp = (float)-5.0 * (float)log10((double)-(rin - (float)1.0))/(float)log10((double)6.0);
}
else {
temp = (float)5.0 * (float)log10((double)(rin + (float)1.0))/(float)log10((double)6.0);
}
return(temp);
}