home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume5
/
mapper
< prev
next >
Wrap
Text File
|
1989-02-03
|
21KB
|
803 lines
Path: xanth!nic.MR.NET!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