home *** CD-ROM | disk | FTP | other *** search
- From decwrl!labrea!rutgers!tut.cis.ohio-state.edu!cwjcc!hal!ncoast!allbery Sun Dec 11 17:12:00 PST 1988
- Article 747 of comp.sources.misc:
- Path: granite!decwrl!labrea!rutgers!tut.cis.ohio-state.edu!cwjcc!hal!ncoast!allbery
- From: sampson@killer.DALLAS.TX.US (Steve Sampson)
- Newsgroups: comp.sources.misc
- Subject: v05i072: CGA/EGA Perspective Map Program
- Keywords: Source, Doc
- Message-ID: <6335@killer.DALLAS.TX.US>
- Date: 7 Dec 88 00:30:44 GMT
- Sender: allbery@ncoast.UUCP
- Reply-To: sampson@killer.DALLAS.TX.US (Steve Sampson)
- Organization: The Unix(R) Connection, Dallas, Texas
- Lines: 789
- Approved: allbery@ncoast.UUCP
-
- Posting-number: Volume 5, Issue 72
- Submitted-by: "Steve Sampson" <sampson@killer.DALLAS.TX.US>
- Archive-name: mapper
-
- This is for Turbo-C users, no binaries included. Easily modified for
- other compilers.
-
-
- #! /bin/sh
- # Contents: mapper.doc mapper.c
- # Wrapped by sampson on Mon Dec 05 15:07:18 1988
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f mapper.doc -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"mapper.doc\"
- else
- echo shar: Extracting \"mapper.doc\" \(4532 characters\)
- sed "s/^X//" >mapper.doc <<'END_OF_mapper.doc'
- X
- X The Mapper Program
- X
- X Version 1.7
- X
- X 22 November 1988
- X
- X
- X I was interested in techniques for producing maps, and found
- X the article by William D. Johnston in the May and June 1979 Byte
- X Magazine. This two part article provided an excellent
- X introduction and source code in Basic Language. His code was
- X restricted to the algorithms and did not get involved with user
- X interface. To evaluate his algorithms and try out the displays I
- X coded the program and a simple interface in Turbo-C Version 1.5.
- X The program in its current form is highly based on Mr. Johnston's
- X algorithms and provides no significant additional capabilities.
- X
- X I also found a high resolution database called the Micro World
- X Data Bank II (MWDBII). This database was 1 megabyte in length
- X and good down to minutes of a degree. See the C source code
- X comments for availability.
- X
- X To run the program and receive help you use the DOS common
- X method of the question option "/?". Just type "mapper/?" and the
- X following usage help will be displayed:
- X
- X Usage: mapper [/bcdgilmrsx]
- X
- X /b Boundaries Off
- X /c Countries On
- X /dn Database ('MWDBII' Default)
- X /g Grid lines On
- X /i Islands Off
- X /l Lakes Off
- X /mn Map Resolution (5 Default)
- X /r Rivers On
- X /s States On
- X /x Colors On
- X
- X Defaults to Boundaries and Islands On
- X
- X The defaults are what I thought should be fairly common. The map
- X database has 5 resolutions, and can be selected with the 'm'
- X option. 5 is the lowest resolution and 1 is the greatest. If
- X you have several different databases you can use the 'd' option
- X and provide the path and filename (128 Characters max). The 'm'
- X and 'd' options should be placed at the end. They can be put
- X anywhere but it's a little easier at the end. Example:
- X mapper/glrsm1. If you use the option in the middle you will need
- X to put a space between it and the remaining options. Example:
- X mapper/glddata /rs. These are the most foolproof methods. Note:
- X The level 5 database included doesn't really use the options yet.
- X The program works as advertised on level 1. There are some errors
- X with the database as you'll see. I've converted the database to
- X ASCII, and am working on cleaning up the errors and redundancies.
- X
- X A little about the speed of the result. The program is quite
- X slow on an 8088 without a math coprocessor, and speed is getting
- X acceptable on an 80286. The C language standard uses double
- X precision math. This is a waste with the current database
- X resolution. An integer version of the math routines would sure
- X speed up the program quite a bit. The mapper program uses
- X Turbo-C auto detect of a math coprocessor and graphics device
- X type (CGA, EGA, and VGA).
- X
- X If you want to quit the plotting on the screen, just hit any
- X key and the bell will sound and exit you back to DOS. You can
- X also use Control-C to get out.
- X
- X The C program lists three sources for the Micro World Data
- X Bank II database. The database is 1 Megabyte (800K Compressed)
- X and is just too much data for reasonable downloading. To see if
- X the program would be useful for you I included a level 5
- X resolution map (the lowest resolution). This particular database
- X has all the data thrown together so the command line options
- X aren't fully functional. They become functional at about level
- X 3 I believe.
- X
- X This program was tested on a PC XT Clone, 640K, and NSI EGA
- X board. Also a Zenith Z-248 with 512k and CGA was tested. Other
- X configurations will need to be tested.
- X
- X Due to the grid method used, it shouldn't be used with an
- X Azimuthal Equidistant map. You can try it once to see what I
- X mean. There's lots of room for improvements, "Handle It!".
- X
- X Thanks to Mr. Johnston for his article and algorithms.
- X
- X USMail: Steve R. Sampson, Box 45668, Tinker AFB, Oklahoma, 73145
- X Compuserve: 75136,626 Unix: sampson@killer.dallas.tx
- END_OF_mapper.doc
- if test 4532 -ne `wc -c <mapper.doc`; then
- echo shar: \"mapper.doc\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f mapper.c -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"mapper.c\"
- else
- echo shar: Extracting \"mapper.c\" \(13949 characters\)
- sed "s/^X//" >mapper.c <<'END_OF_mapper.c'
- X/*
- X * mapper.c
- X *
- X * Version 1.7 by Steven R. Sampson, November 1988
- X *
- X * Based on a program and article by William D. Johnston
- X * Copyright (c) May-June 1979 BYTE, All Rights Reserved
- X *
- X * This program draws three types of map projections:
- X * Perspective, Modified Perspective, and Azimuthal Equidistant.
- X *
- X * Compiled with Turbo-C V1.5
- X */
- X
- X#include <dos.h>
- X#include <math.h>
- X#include <stdio.h>
- X#include <conio.h>
- X#include <string.h>
- X#include <stdlib.h>
- X#include <graphics.h>
- X
- Xtypedef int bool;
- X
- X/* Program Constants */
- X
- X#define FALSE (bool) 0
- X#define TRUE (bool) ~FALSE
- X
- X#define PI (3.141593F)
- X#define HALFPI (1.570796F)
- X#define TWOPI (2.0F * PI) /* Two Pi alias 360 Degrees */
- X
- X#define RADIAN (180.0F / PI ) /* One radian */
- X#define TWO (2.0F / RADIAN) /* 2 degrees in radians */
- X#define TEN (10.0F / RADIAN) /* 10 degrees in radians */
- X#define EIGHTY (80.0F / RADIAN) /* 80 degrees in radians */
- X#define EARTH (6378.0F) /* Mean radius of earth (Kilometers) */
- X
- X/* Program Globals */
- X
- XFILE *fp;
- X
- Xfloat angle, maxplot, center_lat, center_lon, lat, lon, distance,
- X sin_of_distance, cos_of_distance, sin_of_center_lat, cos_of_center_lat,
- X scale, g, h2, facing_azimuth, aspect;
- X
- Xint option, center_x, center_y, grid_color, level = 5;
- Xint GraphDriver = DETECT, GraphMode;
- X
- Xchar optstring[] = "bcd:gilm:rsx?";
- Xchar database[128] = "mwdbii"; /* default name 'MWDBII' */
- X /* leave room for pathname! */
- Xbool boundaries = TRUE, /* defaults to Boundaries, Islands */
- X countries = FALSE,
- X grids = FALSE,
- X islands = TRUE,
- X lakes = FALSE,
- X rivers = FALSE,
- X states = FALSE,
- X colors = FALSE;
- X
- X/* Forward Declarations, Prototypes */
- X
- Xextern int getopt(int, char **, char *);
- Xextern int optind, opterr;
- Xextern char *optarg;
- X
- Xfloat parse(char *);
- Xvoid grid(void), plotmap(void), prompts(void), quit(void);
- Xbool compute(float *, float *, int *, int *);
- X
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar *argv[];
- X{
- X register int i;
- X int err, xasp, yasp;
- X
- X registerbgidriver(EGAVGA_driver);
- X registerbgidriver(CGA_driver);
- X
- X setcbrk(TRUE); /* Allow Control-C checking */
- X ctrlbrk(quit); /* Execute quit() if Control-C detected */
- X
- X while ((i = getopt(argc, argv, optstring)) != -1) {
- X switch (i) {
- X case 'b':
- X boundaries = FALSE;
- X break;
- X case 'c':
- X countries = TRUE;
- X break;
- X case 'd':
- X strcpy(database, optarg);
- X break;
- X case 'g':
- X grids = TRUE;
- X break;
- X case 'i':
- X islands = FALSE;
- X break;
- X case 'l':
- X lakes = TRUE;
- X break;
- X case 'm':
- X level = atoi(optarg);
- X break;
- X case 'r':
- X rivers = TRUE;
- X break;
- X case 's':
- X states = TRUE;
- X break;
- X case 'x':
- X colors = FALSE;
- X break;
- X case '?':
- X default:
- X printf("Usage: mapper [/bcdgilmrsx]\n\n");
- X printf(" /b Boundaries Off\n");
- X printf(" /c Countries On\n");
- X printf(" /dn Database ('MWDBII' Default)\n");
- X printf(" /g Grid lines On\n");
- X printf(" /i Islands Off\n");
- X printf(" /l Lakes On\n");
- X printf(" /mn Map Resolution (5 Default)\n");
- X printf(" /r Rivers On\n");
- X printf(" /s States On\n");
- X printf(" /x Colors On\n\n");
- X printf("Defaults to Boundaries and Islands On\n");
- X exit(0);
- X }
- X }
- X
- X if ((fp = fopen(database, "rb")) == (FILE *)NULL) {
- X printf("\007Error: Can't locate Database '%s'\n", database);
- X exit(1);
- X }
- X
- X initgraph(&GraphDriver, &GraphMode, "");/* initialize graphics */
- X err = graphresult();
- X
- X restorecrtmode(); /* get back to text mode */
- X
- X if (err < 0) {
- X printf("Graphics Error - %s\n", grapherrormsg(err));
- X exit(-1);
- X }
- X
- X center_x = getmaxx() / 2; /* get screen size for x, y */
- X center_y = getmaxy() / 2;
- X getaspectratio(&xasp, &yasp); /* squish factor for y axis */
- X aspect = (float)xasp / (float)yasp;
- X
- X prompts(); /* get the basic map info */
- X setgraphmode(GraphMode); /* and go to graphics mode */
- X
- X if (GraphMode != CGAHI) {
- X setbkcolor(BLACK); /* must be EGA or VGA then */
- X if (colors)
- X grid_color = EGA_LIGHTRED;
- X else
- X grid_color = EGA_LIGHTGRAY;
- X } else
- X grid_color = LIGHTGRAY; /* CGA only has two colors */
- X
- X setcolor(LIGHTGRAY);
- X
- X /*
- X * See if data plotting is even needed
- X */
- X
- X if (boundaries || countries || islands || lakes || rivers || states)
- X plotmap(); /* display map on screen */
- X
- X if (grids)
- X grid(); /* draw lat & long ref lines */
- X
- X if (print)
- X printscreen(); /* relay screen to printer */
- X
- X sound(800); /* 800 Hz for 1/4 a second */
- X delay(125);
- X nosound();
- X
- X getch(); /* pause until key pressed */
- X closegraph(); /* graphics off */
- X fclose(fp); /* close database file */
- X
- X exit(0);
- X}
- X
- X/*
- X * Return to operator following Control-C
- X */
- X
- Xvoid quit()
- X{
- X closegraph();
- X fclose(fp);
- X
- X exit(0);
- X}
- X
- X/*
- X * Operator prompts and input.
- X */
- X
- Xvoid prompts()
- X{
- X char temp[16];
- X float ret, altitude;
- X
- X printf("West Longitudes and South Lattitudes are negative\n");
- X
- X /* input the world Lat & Long that is to be centered on */
- X /* then convert the human notation to radians */
- X
- X do {
- X printf("\nLatitude of the map center [+-]dd.mm : ");
- X scanf("%s", temp);
- X ret = parse(temp);
- X } while (ret > 90.0F || ret < -90.0F);
- X
- X /* the arcosine function has trouble at 90 degrees */
- X
- X if (ret == 90.0F)
- X ret = 89.9F;
- X
- X if (ret == -90.0F)
- X ret = -89.9F;
- X
- X center_lat = ret / RADIAN;
- X sin_of_center_lat = sin(center_lat);
- X cos_of_center_lat = cos(center_lat);
- X
- X do {
- X printf("Longitude of the map center [+-]ddd.mm : ");
- X scanf("%s", temp);
- X ret = parse(temp);
- X } while (ret > 180.0F || ret < -180.0F);
- X
- X center_lon = ret / RADIAN;
- X
- X do {
- X printf("\nSelect from the following options:\n\n");
- X printf(" 1 - Perspective Projection\n");
- X printf(" 2 - Modified Perspective Projection\n");
- X printf(" 3 - Azimuthal Equidistant Projection\n\n");
- X printf("Choice : ");
- X scanf("%d", &option);
- X } while (option < 1 || option > 3);
- X
- X if (option == 3) {
- X maxplot = PI; /* use HALFPI for less area */
- X scale = (float)center_y / maxplot;
- X return;
- X }
- X
- X /* input the height above the terrain */
- X
- X printf("\nObserver altitude (km) : ");
- X scanf("%f", &altitude);
- X
- X h2 = EARTH + altitude;
- X maxplot = acos(EARTH / h2);
- X
- X /* the operator can orient the world upside down if they want */
- X
- X do {
- X printf("Observer facing azimuth (0 - 359 degrees) : ");
- X scanf("%f", &facing_azimuth);
- X } while (facing_azimuth < 0.0F || facing_azimuth > 360.0F);
- X
- X facing_azimuth = -facing_azimuth / RADIAN;
- X
- X /* calculate the scale for the polar coordinates */
- X
- X scale = (float)center_y / (EARTH * sin(maxplot));
- X
- X /* for the perspective projection */
- X
- X g = EARTH * (h2 - EARTH * cos(maxplot));
- X}
- X
- X
- X/*
- X * Convert the database to the desired projection by computation.
- X *
- X * This code is a hand translation from BASIC to C based on Mr. Johnstons
- X * code. It is a non-mathematicians idea of what he meant.
- X *
- X * Return TRUE if offscale else FALSE.
- X */
- X
- Xbool compute(lat, lon, x, y)
- Xregister float *lat, *lon;
- Xregister int *x, *y;
- X{
- X float sin_of_lat,
- X cos_of_lat,
- X abs_delta_lon, /* absolute value */
- X delta_lon, /* x distance from center */
- X delta_lat, /* y distance from center */
- X temp; /* temporary storage */
- X
- X /* normalize the longitude to +/- PI */
- X
- X delta_lon = *lon - center_lon;
- X
- X if (delta_lon < -PI)
- X delta_lon = delta_lon + TWOPI;
- X
- X if (delta_lon > PI)
- X delta_lon = delta_lon - TWOPI;
- X
- X abs_delta_lon = fabs(delta_lon);
- X
- X /*
- X * If the delta_lon is within .00015 radians of 0 then
- X * the difference is considered exactly zero.
- X *
- X * This also simplifys the great circle bearing calculation.
- X */
- X
- X if (abs_delta_lon <= 0.00015F) {
- X delta_lat = fabs(center_lat - *lat);
- X
- X if (delta_lat > maxplot)
- X return TRUE; /* offscale */
- X
- X if (*lat < center_lat)
- X angle = PI;
- X else
- X angle = 0.0F;
- X
- X sin_of_distance = sin(delta_lat);
- X cos_of_distance = cos(delta_lat);
- X }
- X
- X /*
- X * Check if delta_lon is within .00015 radians of PI.
- X */
- X
- X else if (fabs(PI - abs_delta_lon) <= 0.00015F) {
- X delta_lat = PI - center_lat - *lat;
- X
- X if (delta_lat > PI) {
- X delta_lat = TWOPI - delta_lat;
- X angle = PI;
- X } else
- X angle = 0.0F;
- X
- X if (delta_lat > maxplot)
- X return TRUE; /* offscale */
- X
- X sin_of_distance = sin(delta_lat);
- X cos_of_distance = cos(delta_lat);
- X }
- X
- X /*
- X * Simple calculations are out, now get cosmic.
- X */
- X
- X else {
- X sin_of_lat = sin(*lat);
- X cos_of_lat = cos(*lat);
- X
- X cos_of_distance = sin_of_center_lat * sin_of_lat +
- X cos_of_center_lat * cos_of_lat *
- X cos(delta_lon);
- X
- X distance = acos(cos_of_distance);
- X
- X if (distance > maxplot)
- X return TRUE; /* offscale */
- X
- X sin_of_distance = sin(distance);
- X
- X temp = (sin_of_lat - sin_of_center_lat * cos_of_distance) /
- X (cos_of_center_lat * sin_of_distance);
- X
- X if (temp < -1.0F || temp > 1.0F)
- X return TRUE; /* offscale */
- X
- X angle = acos(temp);
- X
- X if (delta_lon < 0.0F)
- X angle = TWOPI - angle;
- X }
- X
- X if (facing_azimuth != 0.0F) {
- X angle = angle - facing_azimuth;
- X if (angle < 0.0F)
- X angle = TWOPI + angle;
- X }
- X
- X angle = HALFPI - angle;
- X
- X if (angle < -PI)
- X angle = angle + TWOPI;
- X
- X switch (option) {
- X case 1:
- X temp = (scale * (g * sin_of_distance)) /
- X (h2 - EARTH * cos_of_distance);
- X break;
- X case 2:
- X temp = scale * EARTH * sin_of_distance;
- X break;
- X case 3:
- X temp = scale * distance;
- X }
- X
- X /* convert polar to rectangular, correct for screen aspect */
- X
- X *x = center_x + (int)(temp * cos(angle));
- X *y = center_y - (int)(temp * sin(angle) * aspect);
- X
- X return FALSE;
- X}
- X
- X/*
- X * Read the database and plot points or lines.
- X *
- X * The database is Micro World Data Bank II. It's based on the
- X * CIA WDB-II tape available from NTIS. Micro WDB-II was created
- X * by Micro Doc. Placed in the public domain by Fred Pospeschil
- X * and Antonio Riveria. Check on availability at:
- X * 1-402-291-0795 (6-9 PM Central)
- X *
- X * Austin Code Works has something called: The World Digitized
- X * that sounds like the same thing ($30.00), 1-512-258-0785
- X *
- X * Lone Star Software has something called: The World Digitized
- X * that sounds like the same thing ($6.00), 1-800-445-6172.
- X *
- X * Database is in Intel word order:
- X * code_lsb, code_msb, lat_lsb, lat_msb, lon_lsb, lon_msb
- X *
- X * Code: Integer, two meanings:
- X * 1. Detail Level (1 Highest - 5 Lowest)
- X *
- X * 2. Header (1xxx - 7xxx) Command Line Options
- X *
- X * 1xxx Boundaries /b
- X * 2xxx Countries /c
- X * (decimal) 4xxx States /s
- X * 5xxx Islands /i
- X * 6xxx Lakes /l
- X * 7xxx Rivers /r
- X *
- X * Lat & Long: Integer
- X * Representing Minutes of degree
- X */
- X
- Xvoid plotmap()
- X{
- X struct { short code, lat, lon; } coord;
- X float lat, lon;
- X int x, y;
- X bool point;
- X
- X point = TRUE;
- X while (fread(&coord, sizeof coord, 1, fp) > 0) {
- X
- X if (kbhit()) {
- X grids = print = FALSE;
- X getch();
- X return;
- X }
- X
- X /*
- X * Skip data that has been optioned out.
- X */
- X
- X if (coord.code < level)
- X continue;
- X
- X if (coord.code > 5) { /* must be a header */
- X
- X point = TRUE;
- X
- X switch (coord.code / 1000) {
- X case 1:
- X if (boundaries) {
- X if (colors)
- X setcolor(EGA_LIGHTGRAY);
- X break;
- X }
- X else
- X continue;
- X case 2:
- X if (countries) {
- X if (colors)
- X setcolor(EGA_BROWN);
- X break;
- X }
- X else
- X continue;
- X case 4:
- X if (states) {
- X if (colors)
- X setcolor(EGA_BROWN);
- X break;
- X }
- X else
- X continue;
- X case 5:
- X if (islands) {
- X if (colors)
- X setcolor(EGA_LIGHTGRAY);
- X break;
- X }
- X else
- X continue;
- X case 6:
- X if (lakes) {
- X if (colors)
- X setcolor(EGA_BLUE);
- X break;
- X }
- X else
- X continue;
- X case 7:
- X if (rivers) {
- X if (colors)
- X setcolor(EGA_GREEN);
- X break;
- X }
- X else
- X continue;
- X }
- X }
- X
- X /* Convert database minutes of a degree to radians */
- X
- X lat = (float) coord.lat / 60.0F / RADIAN;
- X lon = (float) coord.lon / 60.0F / RADIAN;
- X
- X if (compute(&lat, &lon, &x, &y)) {
- X point = TRUE; /* offscale */
- X continue;
- X }
- X
- X if (point) {
- X putpixel(x, y, getcolor());/* put down a dot */
- X moveto(x, y);
- X point = FALSE;
- X }
- X else
- X lineto(x, y); /* connect the dots */
- X }
- X}
- X
- X/*
- X * parse +-ddd.mm
- X *
- X * Change human degrees, and minutes to computer decimal.
- X * Probably designed a monster for a simple solution here...
- X */
- X
- Xfloat parse(string)
- Xchar *string;
- X{
- X char *ptr, degrees[8], minutes[8];
- X float num;
- X
- X strcpy(degrees, " "); /* pre-load with blanks */
- X strcpy(minutes, " ");
- X
- X /* if no decimal point we assume a whole number */
- X
- X if ( (ptr = strchr(string, '.')) == (char *)NULL )
- X return atof(string);
- X
- X /* else use the decimal point to offset */
- X
- X *ptr++ = '\0';
- X
- X strcpy(degrees, string);
- X num = atof(degrees);
- X
- X switch (strlen(ptr)) {
- X case 0:
- X return atof(string);
- X case 1:
- X case 2:
- X strcpy(minutes, ptr);
- X break;
- X default:
- X return 361.0F; /* This will produce an error */
- X }
- X
- X if (num >= 0.0F)
- X num += atof(minutes) / 60.0F;
- X else
- X num -= atof(minutes) / 60.0F;
- X
- X return num;
- X}
- X
- X
- X/*
- X * Draw grid lines from -180 to +180 Degrees (Longitude Lines),
- X * as well as +80 to -80 Degrees (Lattitude Lines).
- X */
- X
- Xvoid grid()
- X{
- X float lat, lon;
- X int x, y, pass1;
- X
- X setcolor(grid_color);
- X
- X for (lon = -PI; lon <= PI; lon += TEN) {
- X pass1 = TRUE;
- X for (lat = EIGHTY; lat > -EIGHTY; lat -= TEN) {
- X if (!compute(&lat, &lon, &x, &y)) {
- X if (pass1) {
- X putpixel(x, y, grid_color);
- X moveto(x, y);
- X pass1 = FALSE;
- X } else
- X lineto(x, y);
- X } else
- X pass1 = TRUE;
- X }
- X
- X if (kbhit()) {
- X print = FALSE;
- X getch();
- X return;
- X }
- X }
- X
- X for (lat = EIGHTY; lat > -EIGHTY; lat -= TEN) {
- X pass1 = TRUE;
- X for (lon = -PI; lon <= PI; lon += TEN) {
- X if (!compute(&lat, &lon, &x, &y)) {
- X if (pass1) {
- X putpixel(x, y, grid_color);
- X moveto(x, y);
- X pass1 = FALSE;
- X } else
- X lineto(x, y);
- X } else
- X pass1 = TRUE;
- X
- X }
- X
- X if (kbhit()) {
- X print = FALSE;
- X getch();
- X return;
- X }
- X }
- X}
- X
- X/* EOF */
- END_OF_mapper.c
- if test 13949 -ne `wc -c <mapper.c`; then
- echo shar: \"mapper.c\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- echo shar: End of shell archive.
- exit 0
-
-
-