home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Resource Library: Graphics
/
graphics-16000.iso
/
amiga
/
mapping
/
drawmap.lha
/
DrawMap
/
source.lha
/
source
/
drawmap.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-06
|
96KB
|
2,584 lines
/* File drawmap.c */
#include <functions.h>
#include <devices/printer.h>
#include <errno.h>
#include <exec/io.h>
#include <exec/libraries.h>
#include <exec/memory.h>
#include <fcntl.h>
#include <graphics/gfxmacros.h>
#include <intuition/intuition.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "reqbase.h"
#include "ILBM_lib.h"
#include "drawmap-menu.h"
#include "drawmap.h"
#include "drawmap-req.h"
#include "drawmap-help.h"
#include "drawmap-proto.h"
struct Screen *s; /* pointer to screen */
struct Window *w; /* pointer to Window */
struct RastPort *rp; /* pointer to RastPort */
struct ViewPort *vp; /* pointer to ViewPort */
struct TmpRas mapTmpRas; /* temp raster for flood fill */
struct Library *GfxBase;
struct Library *IntuitionBase;
struct Remember *rememberkey; /* pointer for cleaning up */
struct ReqLib *ReqBase; /* address of requester library */
struct ExtendedColorRequester colorstruct;
struct ReqFileRequester filereq;
char filename[FCHARS]; /* space for save file and */
char directoryname[DSIZE]; /* dir name */
char pathname[DSIZE+FCHARS]; /* full path and file name */
struct ILBMBase *ILBMBase; /* address of ILBM library */
ILBMFrame IlbmFrame;
unsigned short *arrow, *cross; /* storage for mouse pointers */
unsigned short *waiter, *transparent;
unsigned char *bp[DEPTH]; /* bitplane pointers */
struct Requester req;
struct BitMap map_bitmap; /* holding area for initial flat map */
struct RastPort map_rp; /* rastport for initial flat map */
char got_flat_map;
static long title_toggle = FALSE;
/* ============================================================= */
main (void)
{
struct IntuiMessage *msg;
PLANEPTR workspace;
int ix;
FILE *config;
rememberkey = NULL; /* initialize rememberkey */
if ((GfxBase = (struct Library *) OpenLibrary ("graphics.library", 0L))
== NULL) {
printf ("Can't open graphics library\n");
exit (10);
}
if ((IntuitionBase=(struct Library *) OpenLibrary ("intuition.library",0L))
== NULL) {
printf ("Can't open intuition library\n");
goto end1;
}
if ((ReqBase = (struct ReqLib *) OpenLibrary ("req.library", 0L))
== NULL) {
printf ("Can't open req.library\n");
goto end2;
}
if ((ILBMBase = (struct ILBMBase *) OpenLibrary ("ilbm.library", 0L))
== NULL) {
printf ("Can't open ilbm.library\n");
goto end3;
}
if ((s = (struct Screen *) OpenScreen (&mapscreen)) == NULL) {
printf ("Can't open screen\n");
goto end4;
}
mapWindow.Screen = s;
newhelpw.Screen = s;
if ((w = (struct Window *) OpenWindow (&mapWindow)) == NULL) {
printf ("Can't open window\n");
goto end5;
}
/* load default color table */
CopyMem ((char *) mapcolors, (char *) configcolors,
sizeof(mapcolors));
if ((config = fopen (configfile, "rb")) != NULL) {
if ((ix = fread ((char *) &configcolors[0], sizeof (char),
sizeof(configcolors), config))
!= sizeof(configcolors)) {
CopyMem ((char *) mapcolors, (char *) configcolors,
sizeof(mapcolors));
}
fclose (config);
}
vp = &(s->ViewPort); /* pointer to viewport */
LoadRGB4 (vp, &configcolors[0], NUM_COLORS); /* init. color values */
/* init. mouse pointers */
arrow = (UWORD *) AllocRemember (&rememberkey, ARROW_SIZE, MEMF_CHIP);
CopyMem ((char *) arrow_data, (char *) arrow, ARROW_SIZE);
cross = (UWORD *) AllocRemember (&rememberkey, CROSS_SIZE, MEMF_CHIP);
CopyMem ((char *) cross_data, (char *) cross, CROSS_SIZE);
waiter = (UWORD *) AllocRemember (&rememberkey, WAITER_SIZE, MEMF_CHIP);
CopyMem ((char *) waiter_data, (char *) waiter, WAITER_SIZE);
transparent = (UWORD *) AllocRemember (&rememberkey, TRANSPARENT_SIZE,
MEMF_CHIP);
CopyMem ((char *) transparent_data, (char *) transparent,
TRANSPARENT_SIZE);
SetPointer (w, waiter, WAITER_SIZE/4-2, 16, WAITER_X_OFFSET,
WAITER_Y_OFFSET);
rp = w->RPort;
if ((workspace = (PLANEPTR) AllocRaster (WWIDTH,WHEIGHT)) == NULL) {
printf ("No space for Temporary Raster\n");
goto end6;
}
InitBitMap (&map_bitmap, DEPTH, WWIDTH, WHEIGHT);
InitRastPort (&map_rp);
map_rp.BitMap = &map_bitmap;
for (ix=0; ix<DEPTH; ++ix) /* initialize flat map storage area */
map_bitmap.Planes[ix] = NULL;
for (ix=0; ix<DEPTH; ++ix) {
map_bitmap.Planes[ix] = (PLANEPTR) AllocRaster (WWIDTH, WHEIGHT);
if (map_bitmap.Planes[ix] == NULL) {
printf ("No space for bitmap workspace\n");
goto end7;
}
} /* temp raster for flood fill */
InitTmpRas (&mapTmpRas, workspace, RASSIZE(WWIDTH,WHEIGHT));
rp->TmpRas = &mapTmpRas; /* link it to the RastPort */
if ((ix = readmap ()) != OK) { /* read map files */
printf ("Error reading map files\n");
goto end7;
}
if ((ix = get_min_max ()) != OK) {
printf ("Map files are corrupted\n");
goto end7;
}
if ((ix = init_helpitems ()) != OK)
printf ("\nUnable to initialize help information, but continuing\n");
loadmappic(); /* load initial flat map */
for (ix=0; ix<DEPTH; ++ix) /* initialize bitplane pointers */
bp[ix] = rp->BitMap->Planes[ix];
init_requesters (); /* initialize the requesters */
SetMenuStrip (w, &menu[0]); /* bring up the menus */
SetAPen (rp, ORANGE); /* set initial drawing pens */
SetBPen (rp, BLUE);
SetDrMd (rp, JAM2);
view_height = VIEW_HEIGHT; /* constants for globe view */
eta = view_height/RE;
facp = 1. + eta;
etap = 1./facp;
SetPointer (w, arrow, ARROW_SIZE/4-2, 16, ARROW_X_OFFSET, ARROW_Y_OFFSET);
while (1) { /* wait for message from */
WaitPort ( w->UserPort ); /* Intuition */
if ((msg = (struct IntuiMessage *) GetMsg (w->UserPort)) == NULL)
continue;
else if ((ix = handle_event (msg)) != OK)
break;
else
ReplyMsg (msg);
}
ReplyMsg (msg);
if (helpbuffer != NULL)
free (helpbuffer);
PurgeFiles (&filereq); /* clean up after file requester */
end7:
for (ix=0; ix<DEPTH; ++ix)
if (map_bitmap.Planes[ix] != NULL)
FreeRaster (map_bitmap.Planes[ix], WWIDTH, WHEIGHT);
FreeRaster (workspace, WWIDTH, WHEIGHT);
end6:
FreeRemember (&rememberkey, TRUE); /* clean up */
ClearPointer (w);
ClearMenuStrip (w);
Forbid (); /* strip remaining messages */
while (1) {
if ((msg = (struct IntuiMessage *) GetMsg (w->UserPort)) == NULL)
break;
else
ReplyMsg (msg);
}
ModifyIDCMP (w, NULL);
Permit ();
CloseWindow (w);
end5:
CloseScreen (s);
end4:
CloseLibrary (ILBMBase);
end3:
CloseLibrary (ReqBase);
end2:
CloseLibrary (IntuitionBase);
end1:
CloseLibrary (GfxBase);
}
/* ============================================================= */
int handle_event (struct IntuiMessage *msg)
/* processes main Intuition events */
{
static char box_error[] = "Box of zero size not allowed";
static char *dlevels[] = { "High", "Medium high",
"Medium", "Medium low",
"Low" };
static char drag_prompt[] = "Press and drag left button to "
"select box, right button to "
"abort";
static char expandbox_error[] = "Invalid map displayed for Box "
"Zoom Out option";
static char flood_wait[] = "Press left button to select area "
"to fill, right button to abort";
static char fmt_DETAIL_LEVEL_TYPE[] = "%s detail level";
static char fmt_ORBITAL_TYPE[] = "Orbital...view from %.2lf "
"kilometers";
static char fmt_ZOOM_IN_TYPE[] = "Zoom In...view from %.2lf "
"kilometers";
static char fmt_ZOOM_OUT_TYPE[] = "Zoom Out...view from %.2lf "
"kilometers";
static char grid_error[] = "Invalid map displayed for Grid "
"option";
static char lines_wait[] = "Press left button to draw lines, "
"right button to abort";
static char press_prompt[] = "Press left button to select "
"center point, right button to "
"abort";
static char print_abort[] = "Printing aborted";
static char print_error[] = "Printer error";
static char print_wait[] = "Printing...press right button to "
"abort";
static char smallbox_error[] = "Invalid map displayed for Box "
"Zoom In option";
static char title_BOX_TYPE[] = "Box";
static char title_BOX_ZOOM_IN_TYPE[] = "Box Zoom In";
static char title_BOX_ZOOM_OUT_TYPE[] = "Box Zoom Out";
static char title_CLEARS_TYPE[] = "Clear Screen";
static char title_COAST_COLOR_TYPE[] = "Color for Coastlines";
static char title_COUNTRY_COLOR_TYPE[] = "Color for Countries";
static char title_DRAW_LINE_TYPE[] = "Draw Lines";
static char title_FLAT_TYPE[] = "Flat Map";
static char title_FLOOD_COLOR_TYPE[] = "Color for Flood Fill";
static char title_FLOOD_TYPE[] = "Flood Fill";
static char title_GLOBE_TYPE[] = "Globe...view from infinitely far "
"away";
static char title_HELP_TYPE[] = "Display help file";
static char title_HELP_TYPE_error[] = "Error displaying help information";
static char title_ISLAND_COLOR_TYPE[] = "Color for Islands";
static char title_LAKE_COLOR_TYPE[] = "Color for Lakes";
static char title_LINE_COLOR_TYPE[] = "Color for lines";
static char title_MERCATOR_TYPE[] = "Mercator";
static char title_PALETTE_TYPE[] = "Modify Color Palette";
static char title_PRINT_TYPE[] = "Print Screen";
static char title_REDRAW_TYPE[] = "Redraw";
static char title_REDRAW_TYPE_error[] = "Invalid map displayed for Redraw "
"option";
static char title_RESET_COLOR_TYPE[] = "Reset Colors";
static char title_RIVER_COLOR_TYPE[] = "Color for Rivers";
static char title_SHADOW_TYPE[] = "Shadow";
static char title_STATE_COLOR_TYPE[] = "Color for States";
static char title_TEXT_COLOR_TYPE[] = "Color for text";
static char title_TEXT_TYPE[] = "Text";
static char title_abort[] = "Selection aborted";
static char title_buffer[] = " "
" ";
static char title_config_not_saved[] = "Configuration not saved";
static char title_config_saved[] = "Configuration saved to disk";
static char title_not_saved[] = "Screen not saved";
static char title_saved[] = "Screen saved to disk";
static char first_time = TRUE;
static long oldtype = -1L;
static long flood_color = DK_GRN;
static long line_color = LT_YEL;
static long text_color = WHITE;
static double lamg, latg;
static double lat[2], lam[2];
struct IntuiMessage *msgf;
FILE *config;
char abort;
unsigned short select;
long x, y, x0, y0;
int i, result;
long menunum, itemnum, subnum, type;
double latb[2], lamb[2], del, av;
disable_menus (IDCMPFLAGS); /* disable menus while do this event */
abort = FALSE;
if (first_time == TRUE) {
first_time = FALSE;
if (got_flat_map == OK)
oldtype = FLAT_TYPE;
}
switch (msg->Class) {
case MENUPICK:
select = msg->Code;
if (select == MENUNULL) /* no extended selections */
break;
menunum = MENUNUM (select);
itemnum = ITEMNUM (select);
subnum = SUBNUM (select);
type = (long) (100*menunum+itemnum)*100+subnum; /* menu selection */
switch (menunum) {
case PROJECT:
switch (itemnum) {
case HELP:
SetWindowTitles (w, 0, title_HELP_TYPE);
ShowTitle (s, TRUE);
title_toggle = TRUE;
ModifyIDCMP (w, CLOSEWINDOW);
SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
WAITER_X_OFFSET, WAITER_Y_OFFSET);
if ((result = displayhelp ()) != OK) {
SetWindowTitles (w, 0, title_HELP_TYPE_error);
DisplayBeep (0);
}
SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
ARROW_X_OFFSET, ARROW_Y_OFFSET);
ModifyIDCMP (w, IDCMPFLAGS);
break;
case SAVEIT:
ModifyIDCMP (w, CLOSEWINDOW);
if ((result = save_to_disk ()) != OK) {
SetWindowTitles (w, 0, title_not_saved);
DisplayBeep (0);
}
else
SetWindowTitles (w, 0, title_saved);
ShowTitle (s, TRUE);
title_toggle = TRUE;
ModifyIDCMP (w, IDCMPFLAGS);
break;
case SAVE_CONFIG:
ModifyIDCMP (w, CLOSEWINDOW);
SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
WAITER_X_OFFSET, WAITER_Y_OFFSET);
if ((config = fopen (configfile, "wb")) != NULL) {
if ((i = fwrite ((char *) &configcolors[0], sizeof (char),
sizeof(configcolors), config))
== sizeof(configcolors))
SetWindowTitles (w, 0, title_config_saved);
else {
SetWindowTitles (w, 0, title_config_not_saved);
DisplayBeep (0);
}
fclose (config);
}
else {
SetWindowTitles (w, 0, title_config_not_saved);
DisplayBeep (0);
}
SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
ARROW_X_OFFSET, ARROW_Y_OFFSET);
ModifyIDCMP (w, IDCMPFLAGS);
ShowTitle (s, TRUE);
title_toggle = TRUE;
break;
case PRINT:
SetWindowTitles (w, 0, print_wait);
SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
WAITER_X_OFFSET, WAITER_Y_OFFSET);
if ((result = printmap (w)) == OK)
SetWindowTitles (w, 0, title_PRINT_TYPE);
else {
if (result == NOT_OK)
SetWindowTitles (w, 0, print_error);
else
SetWindowTitles (w, 0, print_abort);
DisplayBeep (0);
}
SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
ARROW_X_OFFSET, ARROW_Y_OFFSET);
break;
case CLEARS:
SetWindowTitles (w, 0, title_CLEARS_TYPE);
ShowTitle (s, TRUE);
title_toggle = TRUE;
SetRast (rp, BLUE);
oldtype = type;
break;
case QUIT:
enable_menus ();
return (NOT_OK);
break;
default:
break;
}
break;
case BOUNDARIES:
switch (itemnum) {
case COASTLINES:
map[COASTLINES].plot ^= 1;
break;
case COUNTRIES:
map[COUNTRIES].plot ^= 1;
break;
case STATES:
map[STATES].plot ^= 1;
break;
case ISLANDS:
map[ISLANDS].plot ^= 1;
break;
case LAKES:
map[LAKES].plot ^= 1;
break;
case RIVERS:
map[RIVERS].plot ^= 1;
break;
case DETAIL_LEVEL:
detail_level = subnum + 1;
sprintf (title_buffer, fmt_DETAIL_LEVEL_TYPE,
dlevels[subnum]);
SetWindowTitles (w, 0, title_buffer);
break;
default:
break;
}
break;
case MAPS:
switch (itemnum) {
case PLANE:
switch (subnum) {
case FLAT:
SetWindowTitles (w, 0, title_FLAT_TYPE);
ShowTitle (s, TRUE);
title_toggle = TRUE;
ModifyIDCMP (w, CLOSEWINDOW);
SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
WAITER_X_OFFSET, WAITER_Y_OFFSET);
fullmap (FLAT_TYPE);
SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
ARROW_X_OFFSET, ARROW_Y_OFFSET);
ModifyIDCMP (w, IDCMPFLAGS);
oldtype = type;
break;
case MERCATOR:
SetWindowTitles (w, 0, title_MERCATOR_TYPE);
ShowTitle (s, TRUE);
title_toggle = TRUE;
ModifyIDCMP (w, CLOSEWINDOW);
SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
WAITER_X_OFFSET, WAITER_Y_OFFSET);
fullmap (MERCATOR_TYPE);
SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
ARROW_X_OFFSET, ARROW_Y_OFFSET);
ModifyIDCMP (w, IDCMPFLAGS);
oldtype = type;
break;
default:
break;
}
break;
case SPHERE:
switch (subnum) {
case ZOOM_IN: /* zoom views */
case ZOOM_OUT:
if (type==ZOOM_IN_TYPE) {
view_height /= 2.;
if (view_height<MIN_HEIGHT)
view_height = MIN_HEIGHT;
sprintf (title_buffer, fmt_ZOOM_IN_TYPE, view_height);
}
else {
view_height *= 2.;
sprintf (title_buffer, fmt_ZOOM_OUT_TYPE, view_height);
}
eta = view_height/RE;
facp = 1. + eta;
etap = 1./facp;
case GLOBE: /* globe views */
case ORBITAL:
if ( (type!=ZOOM_IN_TYPE && type!=ZOOM_OUT_TYPE) ||
(oldtype!=ZOOM_IN_TYPE && oldtype!=ZOOM_OUT_TYPE &&
oldtype!=GLOBE_TYPE && oldtype!=ORBITAL_TYPE) ) {
SetWindowTitles (w, 0, press_prompt);
/* wait for mouse button */
if (oldtype!=FLAT_TYPE && oldtype!=MERCATOR_TYPE) {
ModifyIDCMP (w, CLOSEWINDOW);
SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
WAITER_X_OFFSET, WAITER_Y_OFFSET);
showmappic ();
ModifyIDCMP (w, IDCMPFLAGS);
oldtype = FLAT_TYPE;
}
ShowTitle (s, TRUE);
title_toggle = TRUE;
SetPointer (w, cross, CROSS_SIZE/4-2, 16,
CROSS_X_OFFSET, CROSS_Y_OFFSET);
while (1) {
WaitPort (w->UserPort);
if ((msgf = (struct IntuiMessage *) GetMsg (w->UserPort))
==NULL)
continue;
else if (msgf->Code==SELECTDOWN)
break;
else if (msgf->Code == MENUDOWN) {
abort = TRUE;
ReplyMsg (msgf);
SetWindowTitles (w, 0, title_abort);
SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
ARROW_X_OFFSET, ARROW_Y_OFFSET);
DisplayBeep (0);
break;
}
else
ReplyMsg (msgf);
}
if (abort == TRUE)
break;
x = msgf->MouseX; /* get mouse position */
y = msgf->MouseY;
ReplyMsg (msgf);
getcoord (x, y, oldtype, &latg, &lamg);
}
if (type==ORBITAL_TYPE) {
get_user_input (ORBITAL_TYPE, x, y, &view_height,
&x0, &y0);
eta = view_height/RE; /* initialize values for */
facp = 1. + eta; /* orbital view */
etap = 1./facp;
sprintf (title_buffer, fmt_ORBITAL_TYPE, view_height);
SetWindowTitles (w, 0, title_buffer);
}
else if (type==GLOBE_TYPE)
SetWindowTitles (w, 0, title_GLOBE_TYPE);
else
SetWindowTitles (w, 0, title_buffer);
ShowTitle (s, TRUE);
title_toggle = TRUE;
ModifyIDCMP (w, CLOSEWINDOW);
SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
WAITER_X_OFFSET, WAITER_Y_OFFSET);
globe (latg, lamg, type); /* draw map */
stars ();
SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
ARROW_X_OFFSET, ARROW_Y_OFFSET);
ModifyIDCMP (w, IDCMPFLAGS);
oldtype = type;
break;
default:
break;
}
break;
case BOXES:
switch (subnum) {
case BOX_ZOOM_IN: /* box zoom in */
if (oldtype != BOX_TYPE && oldtype != BOX_ZOOM_IN_TYPE &&
oldtype != BOX_ZOOM_OUT_TYPE) {
SetWindowTitles (w, 0, smallbox_error);
ShowTitle (s, TRUE);
title_toggle = TRUE;
DisplayBeep (0);
break;
} /* and fall through to */
case BOX: /* ordinary box request */
SetWindowTitles (w, 0, drag_prompt);
ShowTitle (s, TRUE);
title_toggle = TRUE;
if (type == BOX_TYPE && (oldtype!=FLAT_TYPE &&
oldtype!=MERCATOR_TYPE)) {
ModifyIDCMP (w, CLOSEWINDOW);
SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
WAITER_X_OFFSET, WAITER_Y_OFFSET);
showmappic ();
ModifyIDCMP (w, IDCMPFLAGS);
oldtype = FLAT_TYPE;
}
SetPointer (w, cross, CROSS_SIZE/4-2, 16,
CROSS_X_OFFSET, CROSS_Y_OFFSET);
if ((result = getbox (&x0, &y0, &x, &y)) != OK) {
SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
ARROW_X_OFFSET, ARROW_Y_OFFSET);
if (result == ABORT)
SetWindowTitles (w, 0, title_abort);
else
SetWindowTitles (w, 0, box_error);
DisplayBeep (0);
break;
}
if (type == BOX_TYPE)
SetWindowTitles (w, 0, title_BOX_TYPE);
else
SetWindowTitles (w, 0, title_BOX_ZOOM_IN_TYPE);
ModifyIDCMP (w, CLOSEWINDOW);
SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
WAITER_X_OFFSET, WAITER_Y_OFFSET);
if (type == BOX_TYPE) {
getcoord (x0, y0, oldtype, &lat[0], &lam[0]);
getcoord (x, y, oldtype, &lat[1], &lam[1]);
}
else {
getcoord_box (x0, y0, lat, lam, &latb[0], &lamb[0]);
getcoord_box (x, y, lat, lam, &latb[1], &lamb[1]);
lat[0] = latb[0];
lat[1] = latb[1];
lam[0] = lamb[0];
lam[1] = lamb[1];
}
box (lat, lam);
SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
ARROW_X_OFFSET, ARROW_Y_OFFSET);
ModifyIDCMP (w, IDCMPFLAGS);
oldtype = type;
break;
case BOX_ZOOM_OUT: /* box zoom out */
if (oldtype != BOX_TYPE && oldtype != BOX_ZOOM_IN_TYPE &&
oldtype != BOX_ZOOM_OUT_TYPE) {
SetWindowTitles (w, 0, expandbox_error);
ShowTitle (s, TRUE);
title_toggle = TRUE;
DisplayBeep (0);
break;
}
SetWindowTitles (w, 0, title_BOX_ZOOM_OUT_TYPE);
ModifyIDCMP (w, CLOSEWINDOW);
SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
WAITER_X_OFFSET, WAITER_Y_OFFSET);
del = EXPAND_SCALE_FACTOR * (lat[0] - lat[1])/2.;
av = (lat[0] + lat[1])/2.;
lat[0] = av + del;
lat[1] = av - del;
if (lat[0] > 90.)
lat[0] = 90.;
if (lat[1] < -90.)
lat[1] = -90.;
del = EXPAND_SCALE_FACTOR * (lam[1] - lam[0])/2.;
av = (lam[0] + lam[1])/2.;
lam[0] = av - del;
lam[1] = av + del;
if (lam[0] < -180.)
lam[0] = -180.;
if (lam[1] > 180.)
lam[1] = 180.;
box (lat, lam);
SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
ARROW_X_OFFSET, ARROW_Y_OFFSET);
ModifyIDCMP (w, IDCMPFLAGS);
oldtype = type;
break;
default:
break;
}
break;
case REDRAW: /* redraw previous map */
if (oldtype != FLAT_TYPE && oldtype != MERCATOR_TYPE &&
oldtype != GLOBE_TYPE && oldtype != ORBITAL_TYPE &&
oldtype != ZOOM_IN_TYPE && oldtype != ZOOM_OUT_TYPE &&
oldtype != BOX_TYPE && oldtype != BOX_ZOOM_IN_TYPE &&
oldtype != BOX_ZOOM_OUT_TYPE) {
SetWindowTitles (w, 0, title_REDRAW_TYPE_error);
ShowTitle (s, TRUE);
title_toggle = TRUE;
DisplayBeep (0);
break;
}
SetWindowTitles (w, 0, title_REDRAW_TYPE);
ModifyIDCMP (w, CLOSEWINDOW);
SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
WAITER_X_OFFSET, WAITER_Y_OFFSET);
if (oldtype == FLAT_TYPE || oldtype == MERCATOR_TYPE)
fullmap (oldtype);
else if (oldtype == ZOOM_IN_TYPE || oldtype == ZOOM_OUT_TYPE ||
oldtype == GLOBE_TYPE || oldtype == ORBITAL_TYPE) {
globe (latg, lamg, oldtype);
stars ();
}
else
box (lat, lam);
SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
ARROW_X_OFFSET, ARROW_Y_OFFSET);
ModifyIDCMP (w, IDCMPFLAGS);
break;
default:
break;
}
break;
case COLORS:
switch (itemnum) {
case PALETTE:
SetWindowTitles (w, 0, title_PALETTE_TYPE);
ShowTitle (s, TRUE);
title_toggle = TRUE;
ModifyIDCMP (w, CLOSEWINDOW);
SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
WAITER_X_OFFSET, WAITER_Y_OFFSET);
result = ExtendedColorRequester (&colorstruct);
for (i=0; i<NUM_COLORS; ++i)
configcolors[i] = GetRGB4 (vp->ColorMap, i);
SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
ARROW_X_OFFSET, ARROW_Y_OFFSET);
ModifyIDCMP (w, IDCMPFLAGS);
break;
case RESET_COLOR:
SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
WAITER_X_OFFSET, WAITER_Y_OFFSET);
LoadRGB4 (vp, &mapcolors[0], NUM_COLORS);
CopyMem ((char *) mapcolors, (char *) configcolors,
sizeof(mapcolors));
SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
ARROW_X_OFFSET, ARROW_Y_OFFSET);
SetWindowTitles (w, 0, title_RESET_COLOR_TYPE);
break;
case FLOOD_COLOR:
flood_color = subnum;
SetWindowTitles (w, 0, title_FLOOD_COLOR_TYPE);
ShowTitle (s, TRUE);
title_toggle = TRUE;
break;
case LINE_COLOR:
line_color = subnum;
SetWindowTitles (w, 0, title_LINE_COLOR_TYPE);
ShowTitle (s, TRUE);
title_toggle = TRUE;
break;
case TEXT_COLOR:
text_color = subnum;
SetWindowTitles (w, 0, title_TEXT_COLOR_TYPE);
ShowTitle (s, TRUE);
title_toggle = TRUE;
break;
case COAST_COLOR:
map[COASTLINES].color = subnum;
SetWindowTitles (w, 0, title_COAST_COLOR_TYPE);
ShowTitle (s, TRUE);
title_toggle = TRUE;
break;
case COUNTRY_COLOR:
map[COUNTRIES].color = subnum;
SetWindowTitles (w, 0, title_COUNTRY_COLOR_TYPE);
ShowTitle (s, TRUE);
title_toggle = TRUE;
break;
case STATE_COLOR:
map[STATES].color = subnum;
SetWindowTitles (w, 0, title_STATE_COLOR_TYPE);
ShowTitle (s, TRUE);
title_toggle = TRUE;
break;
case ISLAND_COLOR:
map[ISLANDS].color = subnum;
SetWindowTitles (w, 0, title_ISLAND_COLOR_TYPE);
ShowTitle (s, TRUE);
title_toggle = TRUE;
break;
case LAKE_COLOR:
map[LAKES].color = subnum;
SetWindowTitles (w, 0, title_LAKE_COLOR_TYPE);
ShowTitle (s, TRUE);
title_toggle = TRUE;
break;
case RIVER_COLOR:
map[RIVERS].color = subnum;
SetWindowTitles (w, 0, title_RIVER_COLOR_TYPE);
ShowTitle (s, TRUE);
title_toggle = TRUE;
break;
default:
break;
}
break;
case EDIT:
switch (itemnum) {
case GRID:
if (oldtype!=FLAT_TYPE && oldtype!=MERCATOR_TYPE &&
oldtype!=GLOBE_TYPE && oldtype!=ORBITAL_TYPE &&
oldtype!=ZOOM_IN_TYPE && oldtype!=ZOOM_OUT_TYPE) {
SetWindowTitles (w, 0, grid_error);
ShowTitle (s, TRUE);
title_toggle = TRUE;
DisplayBeep (0);
}
else {
ModifyIDCMP (w, CLOSEWINDOW);
SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
WAITER_X_OFFSET, WAITER_Y_OFFSET);
grid (oldtype, latg, lamg);
SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
ARROW_X_OFFSET, ARROW_Y_OFFSET);
ModifyIDCMP (w, IDCMPFLAGS);
}
break;
case FLOOD:
SetWindowTitles (w, 0, flood_wait);
ShowTitle (s, TRUE);
title_toggle = TRUE;
SetPointer (w, cross, CROSS_SIZE/4-2, 16,
CROSS_X_OFFSET, CROSS_Y_OFFSET);
if ((result = floodfill (flood_color)) == OK)
SetWindowTitles (w, 0, title_FLOOD_TYPE);
else {
SetWindowTitles (w, 0, title_abort);
DisplayBeep (0);
}
SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
ARROW_X_OFFSET, ARROW_Y_OFFSET);
break;
case DRAW_LINE:
SetWindowTitles (w, 0, lines_wait);
ShowTitle (s, TRUE);
title_toggle = TRUE;
SetPointer (w, cross, CROSS_SIZE/4-2, 16,
CROSS_X_OFFSET, CROSS_Y_OFFSET);
if ((result = draw_line (line_color)) == OK)
SetWindowTitles (w, 0, title_DRAW_LINE_TYPE);
else {
SetWindowTitles (w, 0, title_abort);
DisplayBeep (0);
}
SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
ARROW_X_OFFSET, ARROW_Y_OFFSET);
break;
case SHADOW:
ModifyIDCMP (w, CLOSEWINDOW);
ShowTitle (s, FALSE); /* don't shadow the title */
SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
WAITER_X_OFFSET, WAITER_Y_OFFSET);
shadow ();
SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
ARROW_X_OFFSET, ARROW_Y_OFFSET);
SetWindowTitles (w, 0, title_SHADOW_TYPE);
ShowTitle (s, TRUE);
title_toggle = TRUE;
ModifyIDCMP (w, IDCMPFLAGS);
break;
case TEXT:
x = msg->MouseX;
y = msg->MouseY;
if ((result = do_text (x, y, text_color)) == ABORT) {
SetWindowTitles (w, 0, title_abort);
DisplayBeep (0);
}
else
SetWindowTitles (w, 0, title_TEXT_TYPE);
ShowTitle (s, TRUE);
title_toggle = TRUE;
break;
case TTOGGLE:
title_toggle ^= 1L;
ShowTitle (s, title_toggle);
break;
default:
break;
}
break;
default:
break;
}
break;
default:
break;
}
enable_menus (); /* re-enable menu events */
return (OK);
}
/* ================================================================ */
void box (double *latp, double *lamp) /* draws areas contained within */
/* a rectangular region */
{
char first, prev_in_view, in_view;
short h1, h1c, h1prev; /* x-dist. (pix) from center */
short h2, h2c, h2prev; /* y-dist. (pix) from center */
long x, y;
int i, na, nc;
int lat1i, lat2i, lam1i, lam2i;
double lam, lamc, lamprev; /* longitude */
double lat, latc, latprev; /* latitude */
double bwidth, bheight, bcx, bcy, xscale, yscale;
double lat1, lat2, lam1, lam2;
struct Arc *seg;
struct Pt *pt;
lat1 = latp[0]; /* store values for box corners */
lat2 = latp[1]; /* locally */
lam1 = lamp[0];
lam2 = lamp[1];
lat1i = 60.*lat1; /* convert to signed minutes */
lat2i = 60.*lat2;
lam1i = 60.*lam1;
lam2i = 60.*lam2;
bwidth = lam2 - lam1; /* box width (degrees) */
bheight = lat1 - lat2; /* box height (degrees) */
bcx = (lam1 + lam2)/2.; /* x-coord of box center (deg) */
bcy = (lat1 + lat2)/2.; /* y-coord of box center (deg) */
xscale = WWIDTH / bwidth; /* horizontal scale (pix/deg) */
yscale = WHEIGHT / bheight; /* vertical scale (pix/deg) */
first = TRUE;
SetRast (rp, BLUE); /* blue background */
SetAPen (rp, ORANGE); /* outline the box */
drawbox (0, 0, WWIDTH-1, WHEIGHT-1);
for (nc=0; nc<NUM_MAPS; ++nc) { /* do each map type */
if (map[nc].plot != TRUE) /* if not requested, skip */
continue;
SetAPen (rp, map[nc].color); /* initialize color */
seg = map[nc].seg;
pt = map[nc].pt; /* do each segment */
for (na=0; na<map[nc].nsegs; ++na) {
first = TRUE; /* skip if not in view */
if (seg[na].lat_min > lat1i || seg[na].lat_max < lat2i ||
seg[na].lam_min > lam2i || seg[na].lam_max < lam1i)
continue;
for (i=seg[na].first; i<=seg[na].last; ++i) {
if (pt[i].code < detail_level) /* filter by detail level */
continue;
lat = pt[i].lat; /* latitude */
lat /= 60.;
lam = pt[i].lam; /* longitude */
lam /= 60.;
in_view = FALSE; /* get status of current point */
if ( (lat<=lat1 && lat>=lat2)
&& (lam>=lam1 && lam<=lam2)) {
in_view = TRUE;
h1 = (lam-bcx) * xscale;
h2 = - (lat-bcy) * yscale;
}
if (first==TRUE) { /* check first point */
first = FALSE;
if (in_view==TRUE) { /* if first point is in view, */
x = h1 + CENTERX; /* move pen to first point */
y = h2 + CENTERY; /* and plot it */
WritePixel (rp, x, y);
Move (rp, x, y);
h1prev = h1;
h2prev = h2;
}
prev_in_view = in_view; /* save status of first point */
latprev = lat;
lamprev = lam;
continue;
}
if (in_view==TRUE) {
if (prev_in_view==FALSE) { /* prev. point was not in view */
box_rim_point (lat, lam, latprev, lamprev, lat1, lam1,
lat2, lam2, &latc, &lamc);
h1c = (lamc-bcx) * xscale;
h2c = - (latc-bcy) * yscale;
x = h1c + CENTERX; /* move to rim point & plot it */
y = h2c + CENTERY;
WritePixel (rp, x, y);
Move (rp, x, y);
h1prev = h1c;
h2prev = h2c;
}
if (h1!=h1prev || h2!=h2prev) {
x = h1 + CENTERX; /* draw to current point */
y = h2 + CENTERY;
if (ABS(h1-h1prev) > WWIDTH/2)
WritePixel (rp, x, y);
else
Draw (rp, x, y);
Move (rp, x, y);
}
h1prev = h1;
h2prev = h2;
}
else { /* else out of view */
if (prev_in_view==TRUE) { /* previous point was in view */
box_rim_point (lat, lam, latprev, lamprev, lat1, lam1,
lat2, lam2, &latc, &lamc);
h1c = (lamc-bcx) * xscale;
h2c = - (latc-bcy) * yscale;
x = h1c + CENTERX; /* draw to rim point */
y = h2c + CENTERY;
if (ABS(h1c-h1prev) > WWIDTH/2)
WritePixel (rp, x, y);
else
Draw (rp, x, y);
Move (rp, x, y);
}
}
prev_in_view = in_view; /* save status of current point */
latprev = lat;
lamprev = lam;
}
}
}
}
/* ================================================================ */
/* find rim points in box view */
void box_rim_point (double lat, double lam, double latprev,
double lamprev, double lat1, double lam1,
double lat2, double lam2, double *latc,
double *lamc)
{
double dlam, dlat, tlam1, tlam2, tlat1, tlat2;
dlam = lam - lamprev; /* use parametric linear */
dlat = lat - latprev; /* interpolation */
if (dlam == 0.) { /* same longitude */
tlam1 = tlam2 = -1.;
tlat1 = (lat1 - latprev) / dlat;
tlat2 = (lat2 - latprev) / dlat;
}
else if (dlat == 0.) { /* same latitude */
tlam1 = (lam1 - lamprev) / dlam;
tlam2 = (lam2 - lamprev) / dlam;
tlat1 = tlat2 = -1.;
}
else {
tlam1 = (lam1 - lamprev) / dlam;
tlam2 = (lam2 - lamprev) / dlam;
tlat1 = (lat1 - latprev) / dlat;
tlat2 = (lat2 - latprev) / dlat;
}
if (tlam1 >= 0. && tlam1 <= 1.) { /* now find rim point */
(*lamc) = lam1;
(*latc) = latprev + tlam1 * dlat;
}
else if (tlam2 >= 0. && tlam2 <= 1.) {
(*lamc) = lam2;
(*latc) = latprev + tlam2 * dlat;
}
else if (tlat1 >= 0. && tlat1 <= 1.) {
(*lamc) = lamprev + tlat1 * dlam;
(*latc) = lat1;
}
else {
(*lamc) = lamprev + tlat2 * dlam;
(*latc) = lat2;
}
}
/* ============================================================= */
void disable_menus (long flags) /* disables menus */
{
ModifyIDCMP (w, flags);
Forbid ();
w->Flags |= RMBTRAP;
Permit ();
}
/* ============================================================= */
int displayhelp (void) /* displays help information */
{
struct IntuiMessage *msg;
int gadgetnum;
if (helpbuffer == NULL)
return (NOT_OK);
if ((hw = (struct Window *) OpenWindow (&newhelpw)) == NULL)
return (NOT_OK);
SetPointer (hw, arrow, ARROW_SIZE/4-2, 16, ARROW_X_OFFSET,
ARROW_Y_OFFSET);
DrawBorder (hw->RPort, &border1, 0, 0);
while (1) {
WaitPort (hw->UserPort);
if ((msg = (struct IntuiMessage * ) GetMsg (hw->UserPort)) == NULL)
continue;
gadgetnum = ((struct Gadget *) (msg->IAddress))->GadgetID;
ReplyMsg (msg);
if (gadgetnum < NUMGADGETS-1) {
SetPointer (hw, waiter, WAITER_SIZE/4-2, 16, WAITER_X_OFFSET,
WAITER_Y_OFFSET);
ModifyIDCMP (hw, NULL);
dohelpitem (gadgetnum);
ModifyIDCMP (hw, GADGETUP);
SetPointer (hw, arrow, ARROW_SIZE/4-2, 16, ARROW_X_OFFSET,
ARROW_Y_OFFSET);
}
if (gadgetnum == NUMGADGETS-1)
break;
}
ClearPointer (hw);
CloseWindow (hw);
return (OK);
}
/* ============================================================= */
void dohelpitem (int num)
{
static char defaulttext[] = "No help information to display";
char *txt;
short result;
int disp;
if ((disp = gadgetlist[num].disp) < 0)
txt = defaulttext;
else
txt = &(helpbuffer[disp]);
trs.Text = txt;
trs.Window = hw;
trs.Title = gadgetlist[num].text;
result = TextRequest (&trs);
}
/* ============================================================= */
int do_text (long xin, long yin, long color) /* get user text input */
{
struct IntuiMessage *msg1;
static char title_setdown[] = "Press left button to position text,"
" right button to cancel";
long x, y, xold, yold;
int pixlength;
double t;
/* get user text */
get_user_input (TEXT_TYPE, xin, yin, &t, &xold, &yold);
pixlength = TextLength (rp, user_text_input, strlen(user_text_input));
SetWindowTitles (w, 0, title_setdown);
ShowTitle (s, TRUE);
title_toggle = TRUE;
SetDrMd (rp, JAM2 | COMPLEMENT); /* turn on complement mode */
SetPointer (w, transparent, TRANSPARENT_SIZE/4-2, 16,
TRANSPARENT_X_OFFSET, TRANSPARENT_Y_OFFSET);
drawbox (xold, yold, xold+pixlength-1, yold-9);
ModifyIDCMP (w, IDCMPFLAGS | MOUSEMOVE);
while (1) {
WaitPort (w->UserPort); /* wait for mouse button */
if ((msg1 = (struct IntuiMessage *) GetMsg (w->UserPort)) == NULL)
continue;
else {
x = msg1->MouseX; /* get current mouse position */
y = msg1->MouseY; /* and erase old box */
if (msg1->Code == SELECTDOWN) {
ReplyMsg (msg1); /* done if select button pressed */
drawbox (xold, yold, xold+pixlength-1, yold-9);
break;
}
else if (msg1->Class == MOUSEMOVE) {
/* else draw box at current position */
drawbox (xold, yold, xold+pixlength-1, yold-9);
drawbox (x, y, x+pixlength-1, y-9);
xold = x;
yold = y;
}
else if (msg1->Code == MENUDOWN) {
ReplyMsg (msg1);
ModifyIDCMP (w, IDCMPFLAGS);
drawbox (xold, yold, xold+pixlength-1, yold-9);
SetDrMd (rp, JAM2);
SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
ARROW_X_OFFSET, ARROW_Y_OFFSET);
return (ABORT);
}
ReplyMsg (msg1);
}
}
Move (rp, x, y-2); /* move to current mouse position */
SetDrMd (rp, JAM1); /* (-2 to allow for font baseline) */
SetAPen (rp, color); /* draw text */
Text (rp, user_text_input, strlen(user_text_input));
SetDrMd (rp, JAM2);
ModifyIDCMP (w, IDCMPFLAGS); /* enable original event types */
SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
ARROW_X_OFFSET, ARROW_Y_OFFSET);
return (OK);
}
/* ============================================================= */
void drawbox (long x1, long y1, long x2, long y2) /* draws a box */
{
box_border.LeftEdge = x1;
box_border.TopEdge = y1;
box_borderpts[2] = box_borderpts[4] = x2-x1;
box_borderpts[5] = box_borderpts[7] = y2-y1;
DrawBorder (rp, (struct Border *) &box_border, 0, 0);
}
/* ============================================================= */
int draw_line (long color) /* draws a line based on */
/* mouse positions */
{
struct IntuiMessage *msg;
char selectbutton;
long x, y;
selectbutton = FALSE;
SetAPen (rp, color);
SetDrMd (rp, JAM2);
ModifyIDCMP (w, IDCMPFLAGS | MOUSEMOVE); /* enable mouse move events */
while (1) {
WaitPort (w->UserPort);
if ((msg = (struct IntuiMessage *) GetMsg (w->UserPort)) == NULL)
continue;
else if (msg->Code == MENUDOWN) { /* stop if press menu button */
ReplyMsg (msg);
ModifyIDCMP (w, IDCMPFLAGS); /* disable mouse move events */
return (ABORT);
}
else if (msg->Code == SELECTDOWN) {
x = msg->MouseX; /* get current mouse position */
y = msg->MouseY;
WritePixel (rp, x, y);
Move (rp, x, y);
selectbutton = TRUE;
}
else if (selectbutton == TRUE && msg->Class == MOUSEMOVE) {
x = msg->MouseX; /* get current mouse position */
y = msg->MouseY;
Draw (rp, x, y); /* draw to current position */
Move (rp, x, y);
}
else if (selectbutton == TRUE && msg->Code == SELECTUP)
break;
ReplyMsg (msg);
}
ReplyMsg (msg);
ModifyIDCMP (w, IDCMPFLAGS); /* enable original event types */
return (OK);
}
/* ============================================================= */
void enable_menus (void) /* enables menus */
{
ModifyIDCMP (w, IDCMPFLAGS);
Forbid ();
w->Flags &= ~RMBTRAP;
Permit ();
}
/* ============================================================= */
int floodfill (long flood_color) /* flood fills an area based */
/* on mouse position */
{
struct IntuiMessage *msgf;
long x, y;
while (1) {
WaitPort (w->UserPort); /* wait for message */
if ((msgf = (struct IntuiMessage *) GetMsg (w->UserPort)) == NULL)
continue;
else if (msgf->Code==SELECTDOWN)
break;
else if (msgf->Code == MENUDOWN) {
ReplyMsg (msgf);
return (ABORT);
}
else
ReplyMsg (msgf);
}
x = msgf->MouseX; /* get mouse coordinates */
y = msgf->MouseY;
ReplyMsg (msgf);
SetAPen (rp, flood_color);
Flood (rp, 1, x, y); /* flood fill the region */
return (OK);
}
/* ============================================================= */
void fullmap (long type) /* draws flat and mercator */
/* map projections */
{
short h1, h2, h1old, h2old;
long x, y;
int i, na, nc, np;
double t;
struct Arc *seg;
struct Pt *pt;
SetRast (rp, BLUE); /* clear screen */
for (nc=0; nc<NUM_MAPS; ++nc) { /* do each map type */
if (map[nc].plot != TRUE) /* if not requested, skip */
continue;
SetAPen (rp, map[nc].color); /* initialize color */
seg = map[nc].seg;
pt = map[nc].pt; /* do each segment */
for (na=0; na<map[nc].nsegs; ++na) {
np = 0;
for (i=seg[na].first; i<=seg[na].last; ++i) {
if (pt[i].code < detail_level) /* filter by detail level */
continue;
t = pt[i].lat; /* y = latitude */
if (type==FLAT_TYPE)
t *= (VFACTOR/60.);
else if (type==MERCATOR_TYPE) {
t = (t/120. + 45.) * RAD;
t = log (tan (t)) * M_VFACTOR;
}
if (t<0.) /* round to nearest pixel */
t -= 0.5;
else
t += 0.5;
h2 = -t;
t = pt[i].lam; /* x = longitude */
t *= (HFACTOR/60.);
if (t<0.) /* round to nearest pixel */
t -= 0.5;
else
t += 0.5;
h1 = t;
x = h1 + CENTERX;
y = h2 + CENTERY;
if (np!=0) { /* disallow identical adjacent pts */
if (h1==h1old && h2==h2old)
continue;
else if (ABS (h1-h1old) > WWIDTH/2)
WritePixel (rp, x, y);
else
Draw (rp, x, y);
}
else
WritePixel (rp, x, y);
Move (rp, x, y);
h1old = h1;
h2old = h2;
++np;
}
}
}
if (got_flat_map != OK && type == FLAT_TYPE) {
savemappic (); /* save map in save area */
got_flat_map = OK;
}
}
/* ============================================================= */
int getbox (long *x0, long *y0, long *x, long *y)
/* selects a region to draw to */
/* larger scale */
{
struct IntuiMessage *msgf;
char selectbutton;
long xd, yd, x1, x2, y1, y2;
selectbutton = FALSE;
SetDrMd (rp, JAM2 | COMPLEMENT); /* turn on complement mode and */
ModifyIDCMP (w, IDCMPFLAGS | MOUSEMOVE); /* enable mouse move events */
while (1) {
WaitPort (w->UserPort);
if ((msgf = (struct IntuiMessage *) GetMsg (w->UserPort)) == NULL)
continue;
else if (msgf->Code == MENUDOWN) { /* abort if user pressed */
ReplyMsg (msgf); /* menu button */
ModifyIDCMP (w, IDCMPFLAGS);
SetDrMd (rp, JAM2);
return (ABORT);
}
else if (msgf->Code==SELECTDOWN) { /* if user pressed left button, */
xd = x1 = msgf->MouseX; /* get initial mouse position */
yd = y1 = msgf->MouseY;
drawbox (x1, y1, xd, yd); /* draw initial box */
selectbutton = TRUE;
}
else if (selectbutton==TRUE && msgf->Class==MOUSEMOVE) {
x2 = msgf->MouseX;
y2 = msgf->MouseY;
drawbox (x1, y1, xd, yd); /* erase old box */
xd = x2;
yd = y2;
drawbox (x1, y1, xd, yd); /* draw new box */
}
else if (selectbutton==TRUE && msgf->Code==SELECTUP)
break;
ReplyMsg (msgf);
}
ModifyIDCMP (w, IDCMPFLAGS); /* disable mouse events and */
x2 = msgf->MouseX; /* erase current box */
y2 = msgf->MouseY;
ReplyMsg (msgf);
drawbox (x1, y1, xd, yd);
SetDrMd (rp, JAM2); /* restore original drawing mode */
*x0 = x1;
*y0 = y1;
*x = x2;
*y = y2;
if (x1==x2 || y1==y2) /* error if box is of zero area */
return (NOT_OK);
if (x1>x2 && y1>y2) { /* ensure that the vertices of */
*x0 = x2; /* the box are in the proper */
*y0 = y2; /* order */
*x = x1;
*y = y1;
}
else if (x1<x2 && y1>y2) {
*x0 = x1;
*y0 = y2;
*x = x2;
*y = y1;
}
else if (x1>x2 && y1<y2) {
*x0 = x2;
*y0 = y1;
*x = x1;
*y = y2;
}
return (OK);
}
/* ============================================================= */
void getcoord (long x, long y, long type, double *lat, double *lam)
/* converts screen coordinates */
/* into latitude and longitude */
/* for flat and Mercator maps */
{
(*lam) = (x - CENTERX) / HFACTOR;
if (type==FLAT_TYPE)
(*lat) = (CENTERY - y) / VFACTOR;
else
(*lat) = -90. + 2.*atan(exp((CENTERY-y)/M_VFACTOR))/RAD;
}
/* ============================================================= */
/* get latitude and longitude */
/* for Box Zoom In option */
void getcoord_box (long x, long y, double latin[2], double lamin[2],
double *latout, double *lamout)
{
(*lamout) = (((double) (x)) / WWIDTH) * (lamin[1]-lamin[0]) + lamin[0];
(*latout) = (((double) (y)) / WHEIGHT) * (latin[1]-latin[0]) + latin[0];
}
/* ============================================================= */
int get_min_max (void) /* find limits of each segment */
{
FILE *fin;
struct Arc *seg, *tseg;
struct Pt *pt;
int na, i, j, ix, first_seg;
if ((seg = (struct Arc *) AllocRemember (&rememberkey,
NSEGS*sizeof(struct Arc),
MEMF_PUBLIC | MEMF_CLEAR)) == NULL) {
printf ("Unable to get space for limits array\n");
return (NOT_OK);
}
for (i=0; i<NUM_MAPS; ++i) { /* link segment array to maps */
first_seg = map[i].first_seg;
map[i].seg = (struct Arc *) &(seg[first_seg].lat_min);
}
if ((fin = fopen (limitsfile, "rb")) != NULL) {
ix = fread (seg, sizeof(struct Arc), NSEGS, fin);
fclose (fin);
if (ix == NSEGS)
return (OK);
else
printf ("Limits file corrupted, building it afresh\n");
}
for (i=0; i<NUM_MAPS; ++i) { /* build limits array in units */
pt = map[i].pt; /* address of map points */
tseg = map[i].seg; /* address of segments for map */
for (j=0, na=-1; j<map[i].numpts; ++j) {
if (pt[j].code > MAX_DETAIL_LEVEL) {
++na;
if (na >= map[i].nsegs)
break;
tseg[na].first = tseg[na].last = j;
tseg[na].lat_min = tseg[na].lat_max = pt[j].lat;
tseg[na].lam_min = tseg[na].lam_max = pt[j].lam;
continue;
}
if (pt[j].lat < tseg[na].lat_min)
tseg[na].lat_min = pt[j].lat;
if (pt[j].lat > tseg[na].lat_max)
tseg[na].lat_max = pt[j].lat;
if (pt[j].lam < tseg[na].lam_min)
tseg[na].lam_min = pt[j].lam;
if (pt[j].lam > tseg[na].lam_max)
tseg[na].lam_max = pt[j].lam;
tseg[na].last = j;
}
}
ix = 0; /* save limits to disk */
if ((fin = fopen (limitsfile, "wb")) != NULL) {
ix = fwrite (seg, sizeof(struct Arc), NSEGS, fin);
fclose (fin);
}
if (ix != NSEGS) /* error in saving to disk */
printf ("Unable to save limits to disk, continuing anyway\n");
return (OK);
}
/* ============================================================= */
void get_user_input (long type, long xin, long yin, double *d,
long *xout, long *yout)
/* prompts for user input */
/* (text or doubleword) */
{
struct IntuiMessage *msg;
struct Gadget *g;
long x, y;
/* position the requester */
x = xin - GAD_LEFT - 8*(NUM_CHAR-2);
y = yin - GAD_TOP - 2;
if ((x+TWIDTH) >= WWIDTH)
x = WWIDTH - TWIDTH - 15;
if (x < 10)
x = 10;
if ((y+THEIGHT) >= WHEIGHT)
y = WHEIGHT - THEIGHT - 15;
if (y < 5)
y = 5;
req.LeftEdge = x;
req.TopEdge = y;
if (type == ORBITAL_TYPE) { /* initialize for doubleword input */
req.ReqText = &dtext;
gadgetinput.Buffer = &user_double_input[0];
}
else { /* initialize for text input */
req.ReqText = &rtext;
gadgetinput.Buffer = &user_text_input[0];
}
Request (&req, w); /* issue the requester */
ModifyIDCMP (w, GADGETUP); /* disable other events */
ActivateGadget (&gad, w, &req);
while (1) {
WaitPort (w->UserPort);
if ((msg = (struct IntuiMessage *) GetMsg (w->UserPort)) == NULL)
continue;
else if (msg->Class == GADGETUP) {
g = (struct Gadget *) (msg->IAddress);
if (g->GadgetID != GAD_FIRST) {
ReplyMsg (msg);
continue;
}
*xout = msg->MouseX; /* get mouse coordinates */
*yout = msg->MouseY;
ReplyMsg (msg);
if (type == ORBITAL_TYPE) { /* get user value */
*d = atof (&user_double_input[0]);
if (errno == ERANGE) { /* trap erroneous input */
*d = VIEW_HEIGHT; /* store default value */
sprintf (user_double_input, "%.2lf", *d);
DisplayBeep (0);
}
else if ((*d) < MIN_HEIGHT) {
*d = MIN_HEIGHT; /* store minimum value */
sprintf (user_double_input, "%.2lf", *d);
DisplayBeep (0);
}
}
break;
}
else /* ignore inappropriate events */
ReplyMsg (msg);
}
ModifyIDCMP (w, IDCMPFLAGS);
}
/* ============================================================= */
void globe (double lat0, double lam0, long type)
/* draws globe projections */
{
char first, prev_in_view, in_view, latzero;
short h1, h1c, h1prev; /* x-dist. (pix) from center */
short h2, h2c, h2prev; /* y-dist. (pix) from center */
long x, y;
int i, na, nc;
double lam, lamc, lamprev; /* longitude */
double lat, latc, latprev; /* latitude */
double c0, s0, c1, s1, c2, zp, zpprev;
double hp, fac2, fac3, scale;
double h1d, h2d, lat0p;
double latmin, latmax, lammin, lammax;
struct Arc *seg;
struct Pt *pt;
latzero = FALSE;
if (type==GLOBE_TYPE) { /* ordinary globe view */
hp = 0.;
scale = 1.;
fac3 = 1.;
}
else { /* orbital globe view */
hp = etap;
scale = sqrt (1.-etap*etap);
fac3 = (facp/(facp-hp)) * scale;
}
if (lat0==0.) {
c0 = 1.;
s0 = 0.;
if (type==GLOBE_TYPE)
latzero = TRUE; /* equatorial, ordinary globe view */
}
else {
lat0p = lat0 * RAD;
c0 = cos (lat0p);
s0 = sin (lat0p);
}
SetRast (rp, BLACK); /* black background */
SetAPen (rp, BLUE); /* blue globe */
DrawEllipse (rp, (long) CENTERX, (long) CENTERY, (long) HRADIUS,
(long) VRADIUS);
Flood (rp, 1, CENTERX, CENTERY);
for (nc=0; nc<NUM_MAPS; ++nc) { /* do each map type */
if (map[nc].plot != TRUE) /* if not requested, skip */
continue;
SetAPen (rp, map[nc].color);
seg = map[nc].seg;
pt = map[nc].pt; /* do each segment */
for (na=0; na<map[nc].nsegs; ++na) {
latmin = ((double) (seg[na].lat_min)) / 60.;
latmax = ((double) (seg[na].lat_max)) / 60.;
lammin = ((double) (seg[na].lam_min)) / 60.;
lammax = ((double) (seg[na].lam_max)) / 60.;
if ((i = globe_in_view (latmax, lammin, latmin, lammax, lat0, lam0,
hp)) != OK)
continue;
first = TRUE;
for (i=seg[na].first; i<=seg[na].last; ++i) {
if (pt[i].code < detail_level) /* filter by detail level */
continue;
lat = pt[i].lat; /* latitude */
lat *= (RAD/60.);
lam = pt[i].lam; /* longitude */
lam = (lam/60. - lam0) * RAD;
if (lam<-PI)
lam += TWOPI;
if (lam>PI)
lam -= TWOPI;
c1 = cos(lat); /* cosine of latitude */
s1 = sin(lat); /* sine of latitude */
in_view = FALSE; /* get status of current point */
if (latzero==TRUE) { /* equatorial globe view */
zp = c1*cos (lam);
if (lam>=-PI2 && lam<=+PI2) {
in_view = TRUE;
h1 = HRADIUS * c1 * sin (lam);
h2 = -VRADIUS * s1;
}
}
else { /* oblique earth view */
c2 = cos (lam);
zp = s1*s0 + c1*c0*c2;
if (zp>=hp) { /* zp > hp => in view */
in_view = TRUE;
h1d = HRADIUS * c1 * sin (lam);
h2d = -VRADIUS * (s1*c0 -c1*s0*c2);
if (type!=GLOBE_TYPE) {
fac2 = (facp/(facp-zp)) * scale;
h1d *= fac2;
h2d *= fac2;
}
h1 = h1d;
h2 = h2d;
}
}
if (first==TRUE) { /* get status of first point */
first = FALSE;
if (in_view==TRUE) { /* if first point is in view, */
x = h1 + CENTERX; /* move pen to first point */
y = h2 + CENTERY; /* and plot it */
Move (rp, x, y);
WritePixel (rp, x, y);
h1prev = h1;
h2prev = h2;
}
prev_in_view = in_view; /* save status of first point */
latprev = lat;
lamprev = lam;
zpprev = zp;
continue;
}
if (in_view==TRUE) { /* current point is in view, */
if (prev_in_view==FALSE) { /* previous point was not */
globe_rim_point (lat, lam, latprev, lamprev, zp, zpprev,
c0, s0, fac3, type, latzero,
&latc, &lamc, &h1c, &h2c);
x = h1c + CENTERX; /* move to rim point & plot it */
y = h2c + CENTERY;
Move (rp, x, y);
WritePixel (rp, x, y);
h1prev = h1c;
h2prev = h2c;
}
if (h1!=h1prev || h2!=h2prev) {
x = h1 + CENTERX; /* draw to current point */
y = h2 + CENTERY;
Draw (rp, x, y);
Move (rp, x, y);
}
h1prev = h1;
h2prev = h2;
}
else { /* current point out of view, */
if (prev_in_view==TRUE) { /* previous point in view */
globe_rim_point (lat, lam, latprev, lamprev, zp, zpprev,
c0, s0, fac3, type, latzero,
&latc, &lamc, &h1c, &h2c);
x = h1c + CENTERX; /* draw to rim point */
y = h2c + CENTERY;
Draw (rp, x, y);
Move (rp, x, y);
}
}
prev_in_view = in_view; /* save status of current point */
latprev = lat;
lamprev = lam;
zpprev = zp;
}
}
}
}
/* ============================================================= */
void globe_grid (long type, double lat0, double lam0)
/* controls drawing globe grid */
{
static double lat_interval = 20.;
static double lam_interval = 30.;
static double delta = 5.;
char first;
int k;
double lat, lam, c0, s0, c1, s1, c2, s2, rlam, rlat;
double hp, scale, fac3, dlat, dlam, ddelt;
double lamp[2], latp[2];
lat0 *= RAD;
c0 = cos (lat0);
s0 = sin (lat0);
dlat = lat_interval;
dlam = lam_interval;
ddelt = delta;
if (type==GLOBE_TYPE) { /* ordinary globe view */
hp = 0.;
scale = 1.;
fac3 = 1.;
}
else { /* orbital view */
hp = etap;
scale = sqrt (1.-etap*etap);
fac3 = (facp/(facp-hp)) * scale;
if (view_height<=1200.) {
dlat /= 4.;
dlam /= 4.;
ddelt /= 5.;
}
}
SetAPen (rp, BLACK); /* grid lines in black */
for (lat=80.; lat>=-80.; lat-=dlat) { /* lines of equal latitude */
rlat = lat*RAD;
if ((k=limit_lam (&lamp[0], rlat, lat0, hp))!=OK)
continue; /* skip if entirely out of view */
lamp[0] += lam0;
lamp[1] += lam0;
k = lamp[0]/ddelt - 1.; /* express limits as multiple */
lamp[0] = k*ddelt; /* of ddelt */
k = lamp[1]/ddelt + 1.;
lamp[1] = k*ddelt;
c1 = cos (rlat);
s1 = sin (rlat);
first = TRUE;
if (lat==0.)
SetAPen (rp, WHITE); /* draw equator in white */
for (lam=lamp[0]; lam<=lamp[1]; lam+=ddelt) {
rlam = (lam-lam0)*RAD;
if (rlam<-PI)
rlam += TWOPI;
if (rlam>+PI)
rlam -= TWOPI;
c2 = cos (rlam);
s2 = sin (rlam);
globe_grid_plot (rlat, rlam, c0, s0, c1, s1, c2, s2,
type, hp, scale, fac3, &first);
}
if (lat==0.)
SetAPen (rp, BLACK); /* reset pen to black */
}
for (lam=-180.; lam<+180.; lam+=dlam) { /* meridian circles */
rlam = (lam-lam0)*RAD;
if (rlam<-PI)
rlam += TWOPI;
if (rlam>+PI)
rlam -= TWOPI;
if ((k=limit_lat (&latp[0], lat0, rlam, hp))!=OK)
continue; /* skip if entirely out of view */
k = latp[0]/ddelt + 1.; /* express limits as multiple */
latp[0] = k*ddelt; /* of ddelt */
k = latp[1]/ddelt - 1.;
latp[1] = k*ddelt;
if (latp[0]>=90.) /* exclude North polar point */
latp[0] = 90. - ddelt;
if (latp[1]<=-90.) /* exclude South polar point */
latp[1] = -90. + ddelt;
c2 = cos (rlam);
s2 = sin (rlam);
first = TRUE;
if (lam==0. || lam==-180.) /* prime meridian in white */
SetAPen (rp, WHITE);
for (lat=latp[0]; lat>=latp[1]; lat-=ddelt) {
rlat = lat*RAD;
c1 = cos (rlat);
s1 = sin (rlat);
globe_grid_plot (rlat, rlam, c0, s0, c1, s1, c2, s2,
type, hp, scale, fac3, &first);
}
if (lam==0. || lam==-180.)
SetAPen (rp, BLACK); /* reset pen to black */
}
}
/* ============================================================= */
void globe_grid_plot (double lat, double lam, double c0, double s0,
double c1, double s1, double c2, double s2,
long type, double hp, double scale, double fac3,
char *first)
/* draws globe grids */
{
static char latzero = FALSE;
static char prev_in_view;
static short h1prev, h2prev;
static double latprev, lamprev, zpprev;
char in_view;
short h1, h1c; /* x-dist. (pix) from center */
short h2, h2c; /* y-dist. (pix) from center */
long x, y;
double lamc; /* longitude */
double latc; /* latitude */
double zp, h1d, h2d, fac2;
in_view = FALSE; /* get status of current point */
zp = s1*s0 + c1*c0*c2;
if (zp>=hp) { /* zp > hp => in view */
in_view = TRUE;
h1d = HRADIUS * c1 * s2;
h2d = -VRADIUS * (s1*c0 - c1*s0*c2);
if (type!=GLOBE_TYPE) {
fac2 = (facp/(facp-zp))*scale;
h1d *= fac2;
h2d *= fac2;
}
h1 = h1d;
h2 = h2d;
}
if (*first==TRUE) { /* get status of first point */
*first = FALSE;
if (in_view==TRUE) { /* if first point is in view, */
x = h1 + CENTERX; /* move pen to first point */
y = h2 + CENTERY; /* and plot it */
WritePixel (rp, x, y);
Move (rp, x, y);
h1prev = h1;
h2prev = h2;
}
prev_in_view = in_view; /* save status of first point */
latprev = lat;
lamprev = lam;
zpprev = zp;
return;
}
if (in_view==TRUE) { /* if current point is in view, */
if (prev_in_view==FALSE) { /* but previous point was not */
globe_rim_point (lat, lam, latprev, lamprev, zp, zpprev,
c0, s0, fac3, type, latzero,
&latc, &lamc, &h1c, &h2c);
x = h1c + CENTERX; /* move to rim point & plot it */
y = h2c + CENTERY;
WritePixel (rp, x, y);
Move (rp, x, y);
h1prev = h1c;
h2prev = h2c;
}
if (h1!=h1prev || h2!=h2prev) {
x = h1 + CENTERX; /* draw to current point */
y = h2 + CENTERY;
Draw (rp, x, y);
Move (rp, x, y);
}
h1prev = h1;
h2prev = h2;
}
else { /* current point is out of view */
if (prev_in_view==TRUE) { /* if previous point was in view, */
globe_rim_point (lat, lam, latprev, lamprev, zp, zpprev,
c0, s0, fac3, type, latzero,
&latc, &lamc, &h1c, &h2c);
x = h1c + CENTERX; /* draw to rim point */
y = h2c + CENTERY;
Draw (rp, x, y);
Move (rp, x, y);
}
}
prev_in_view = in_view; /* save status of current point */
latprev = lat;
lamprev = lam;
zpprev = zp;
}
/* ============================================================= */
int globe_in_view (double lat0, double lam0, double lat1, double lam1,
double latv, double lamv, double hp)
/* checks if a segment is visible */
/* in a globe view */
/* lat0, lam0 = coords of upper */
/* left corner of segment (deg) */
/* lat1, lam1 = coords of lower */
/* right corner of segment (deg) */
/* latv, lamv = coords of viewpoint */
/* (deg) */
/* hp = modified view height */
{
int k;
double lat[2], lam[2], latt, lamt, del1, del2, eps;
double lat0p, lam0p, lat1p, lam1p, latvp, lamvp, lamtp;
lat0p = lat0 * RAD; /* convert to radians */
lat1p = lat1 * RAD;
lam0p = lam0 * RAD;
lam1p = lam1 * RAD;
latvp = latv * RAD;
lamvp = lamv * RAD;
del1 = (lat0p-lat1p)/10.; /* divide into horizontal strips */
if (del1 > 0.) {
eps = del1/10.;
for (latt=lat0p; latt>=lat1p-eps; latt-=del1) {
if ((k = limit_lam (lam, latt, latvp, hp)) == OK) {
lam[0] += lamv;
lam[1] += lamv;
if (lam[0] < -PI)
lam[0] += TWOPI;
if (lam[0] > +PI)
lam[0] -= TWOPI;
if (lam[1] < -PI)
lam[1] += TWOPI;
if (lam[1] > +PI)
lam[1] -= TWOPI;
if (lam[0] <= lam1 && lam[1] >= lam0)
return (OK);
}
}
}
del2 = (lam1p-lam0p)/10.; /* divide into vertical strips */
if (del2 > 0.) {
eps = del2/10.;
for (lamt=lam0p-lamvp; lamt<=lam1p-lamvp+eps; lamt+=del2) {
if ((lamtp = lamt) < -PI)
lamtp += TWOPI;
if (lamtp > +PI)
lamtp -= TWOPI;
if ((k = limit_lat (lat, latvp, lamtp, hp)) == OK) {
if (lat[0] >= lat1 && lat[1] <= lat0)
return (OK);
}
}
}
if (del1 > 0. || del2 > 0.)
return (NOT_OK);
return (OK); /* let globe() do degenerate case */
}
/* ============================================================= */
/* get rim points for globe */
void globe_rim_point (double lat, double lam, double latprev,
double lamprev, double zp, double zpprev,
double c0, double s0, double fac3, long type,
char latzero, double *latc, double *lamc,
short *h1c, short *h2c)
{
static int itmax = 20;
double facz, dlat, dlam, c1, h1d, h2d;
long x, y ,color;
int i;
short inc1, inc2;
facz = zp / (zpprev-zp); /* get rim point by linear */
(*latc) = lat - (latprev-lat)*facz; /* interpolation */
(*lamc) = lam - (lamprev-lam)*facz;
dlat = fabs (lat-latprev);
dlam = fabs (lam-lamprev);
if ( fabs ((*latc)-latprev)> dlat || /* if rim point not between */
fabs ((*latc)-lat) > dlat) /* current and previous */
(*latc) = (lat+latprev)/2.; /* point, use midpoint */
if ( fabs ((*lamc)-lamprev)> dlam ||
fabs ((*lamc)-lam) > dlam )
(*lamc) = (lam+lamprev)/2.;
if (latzero==TRUE) {
(*h1c) = HRADIUS * cos ((*latc)) * sin ((*lamc));
(*h2c) = -VRADIUS * sin ((*latc));
}
else {
c1 = cos ((*latc));
h1d = HRADIUS * c1 * sin ((*lamc));
h2d = -VRADIUS * (sin ((*latc))*c0 - c1*s0*cos ((*lamc)));
if (type!=GLOBE_TYPE) {
h1d *= fac3;
h2d *= fac3;
}
(*h1c) = h1d;
(*h2c) = h2d;
} /* find nearest actual rim point */
if ((*h1c)>=0) /* right half */
inc1 = +1;
else /* left half */
inc1 = -1;
if ((*h2c)>=0) /* bottom half */
inc2 = +1;
else /* top half */
inc2 = -1;
x = (*h1c) + CENTERX + 5*inc1; /* coordinates of test pixel */
y = (*h2c) + CENTERY + 5*inc2;
for (i=0; i<itmax; ++i) { /* look for nearest black pixel */
if ((color = ReadPixel (rp, x, y))==BLACK)
break;
x += inc1;
y += inc2;
}
x -= inc1;
y -= inc2;
for (i=0; i<itmax; ++i) { /* look back for non-black one */
if ((color = ReadPixel (rp, x, y)) != BLACK)
break;
x -= inc1;
y -= inc2;
}
(*h1c) = x - CENTERX;
(*h2c) = y - CENTERY;
}
/* ============================================================= */
void grid (long type, double lat0, double lam0)
/* controls drawing of grids */
{
static double lat_interval = 20.;
static double lam_interval = 30.;
long h1;
double lam, lat;
if (type!=FLAT_TYPE && type!=MERCATOR_TYPE)
globe_grid (type, lat0, lam0); /* draw grid for globe */
else { /* otherwise grid for flat */
/* or Mercator map */
SetAPen (rp, BLACK); /* set grid color to black */
for (lam=-180.; lam<=+180.; lam += lam_interval) {
h1 = lam*HFACTOR + CENTERX;
Move (rp, h1, 0);
Draw (rp, h1, WHEIGHT-1);
}
for (lat=80.; lat>=-80.; lat -= lat_interval) {
if (type==FLAT_TYPE)
h1 = -lat*VFACTOR;
else
h1 = -log (tan((lat/2.+45.)*RAD)) * M_VFACTOR;
h1 += CENTERY;
Move (rp, 0, h1);
Draw (rp, WWIDTH-1, h1);
}
SetAPen (rp, WHITE); /* draw coordinate axes in white */
Move (rp, CENTERX, 0);
Draw (rp, CENTERX, WHEIGHT-1);
Move (rp, 0, CENTERY);
Draw (rp, WWIDTH-1, CENTERY);
}
}
/* ============================================================= */
int init_helpitems (void) /* initializes help info */
{
FILE *helpfile;
struct Gadget *gadgetpointer;
long x, y;
int gadgetnum;
int ix, numrd, i;
if ((helpbuffer = (char *) calloc (1, (unsigned) HELPBUFSIZE)) == NULL)
return (NOT_OK);
if ((helpfile = fopen (helpfilename, "rb")) == NULL) {
free (helpbuffer);
helpbuffer = NULL;
return (NOT_OK);
}
if ((numrd = fread (helpbuffer, sizeof(char), HELPBUFSIZE, helpfile))
<= 0) {
fclose (helpfile);
free (helpbuffer);
helpbuffer = NULL;
return (NOT_OK);
}
fclose (helpfile);
ix = 1;
gadgetlist[0].disp = 0;
for (i=0; i<numrd-1; ++i) { /* get disp to each help entry */
if (helpbuffer[i] == '\f') { /* replace formfeed with eol to */
helpbuffer[i] = '\0'; /* facilitate text display */
gadgetlist[ix].disp = i+1;
++ix;
if (ix > NUMGADGETS)
break;
}
} /* now link the gadgets */
for (gadgetnum=0; gadgetnum<NUMGADGETS; ++gadgetnum) {
x = HGADGETSTARTX + (gadgetnum&1) * (HWIDTH/2);
y = HGADGETSTARTY + s->Font->ta_YSize + (gadgetnum/2) *
(HGAD_HEIGHT+HGAP);
LinkGadget (&gadgetblocks[gadgetnum],
gadgetlist[gadgetnum].text,
&newhelpw, (long) x, (long) y);
gadgetblocks[gadgetnum].Gadget.GadgetID = gadgetnum;
} /* put exit gadget at top */
gadgetpointer = &gadgetblocks[NUMGADGETS-1].Gadget;
gadgetpointer->TopEdge = HTOP_MARGIN;
gadgetpointer->LeftEdge = (HWIDTH-gadgetpointer->Width) / 2;
return (OK);
}
/* ============================================================= */
void init_requesters (void) /* initializes the requesters */
{
static char title_file[] = "Select save file name:";
unsigned char *s, *t;
InitRequester (&req); /* initialize the requester */
req.LeftEdge = TLEFT;
req.TopEdge = TTOP;
req.Width = TWIDTH;
req.Height = THEIGHT;
req.ReqGadget = &gad;
req.ReqText = &rtext; /* assume text input */
req.BackFill = ORANGE;
req.Flags = 0;
req.ReqBorder = &border_top;
s = &user_text_input[0]; /* copy default text string */
t = &default_text[0];
while ((*s++ = *t++) != '\0')
;
s = &user_double_input[0]; /* copy default orbital height */
sprintf (default_double, "%.2lf", VIEW_HEIGHT);
t = &default_double[0];
while ((*s++ = *t++) != '\0')
;
colorstruct.window = w; /* window id for color requester */
pathname[0] = 0; /* initialize file requester */
filereq.Title = title_file; /* window title */
filereq.Dir = directoryname; /* space for dir name */
filereq.File = filename; /* space for file name */
filereq.PathName = pathname; /* space for path name */
filereq.Window = w; /* display on map window */
filereq.Flags = FRQCACHINGM; /* cache the filenames */
filereq.Flags |= FRQSAVINGM; /* saving files */
filereq.dirnamescolor = ORANGE; /* dir names */
filereq.filenamescolor = LT_YEL; /* file names */
filereq.devicenamescolor = BLACK; /* device names */
filereq.detailcolor = BLUE; /* window gadgets */
filereq.blockcolor = DK_YEL; /* title bar */
filereq.gadgettextcolor = DK_YEL; /* text in gadgets */
filereq.textmessagecolor = DK_YEL; /* text in title */
filereq.stringnamecolor = DK_YEL; /* prompts */
filereq.stringgadgetcolor= LT_BL; /* borders */
filereq.boxbordercolor = LT_BL;
filereq.gadgetboxcolor = LT_BL;
trs.MiddleText = "OK"; /* initialize items in */
trs.PositiveText = 0; /* help requester */
trs.NegativeText = 0;
trs.KeyMask = 0;
trs.textcolor = ORANGE;
trs.detailcolor = BLUE;
trs.blockcolor = DK_YEL;
trs.versionnumber = REQVERSION;
trs.Timeout = 0;
trs.AbortMask = 0;
trs.rfu1 = 0;
}
/* ============================================================= */
int limit_lam (double *lam, double lat, double lat0, double etap)
/* computes limits on longitude */
/* for constant latitude */
{
double alpha;
alpha = (etap-sin(lat)*sin(lat0)) / (cos(lat)*cos(lat0));
if (alpha<=-1.) { /* negative => lamda covers */
lam[0] = -180.; /* entire hemisphere */
lam[1] = +180.;
return (OK);
}
else if (alpha>=+1.) /* positive => nothing in view */
return (NOT_OK);
else { /* otherwise, compute limits */
lam[0] = -acos (alpha)/RAD;
lam[1] = -lam[0];
return (OK);
}
}
/* ============================================================= */
int limit_lat (double *lat, double lat0, double lam, double etap)
/* computes limits on latitude */
/* for constant longitude */
{
double radical, a, b, sum, fac1;
a = sin (lat0);
b = cos (lat0) * cos (lam);
sum = a*a + b*b;
if ((radical = sum - etap*etap) <= 0.) /* no real solutions */
return (NOT_OK);
else { /* two real solutions */
radical = sqrt (radical); /* solve quadratic equation */
fac1 = (a*etap + b*radical)/sum;
lat[0] = asin (fac1)/RAD;
fac1 = (a*etap - b*radical)/sum;
lat[1] = asin (fac1)/RAD;
if (lat[0]<lat[1]) { /* put in correct order */
b = lat[0];
lat[0] = lat[1];
lat[1] = b;
}
if (a>etap) /* check North pole */
lat[0] = 90.;
if (a<-etap) /* check South pole */
lat[1] = -90.;
return (OK);
}
}
/* ================================================================ */
void loadmappic (void) /* loads initial flat map */
{
IFFP Iresult;
IlbmFrame.iWindow = w;
IlbmFrame.iScreen = s;
IlbmFrame.iUserFlags = 0;
got_flat_map = NOT_OK;
if ((Iresult = LoadIFFToWindow (flatmapfile, &IlbmFrame)) == IFF_OKAY) {
got_flat_map = OK;
savemappic ();
ShowTitle (s, TRUE);
title_toggle = TRUE;
}
}
/* ================================================================ */
int printmap (struct Window *win) /* prints displayed map */
{
struct IODRPReq *ioreq;
struct MsgPort *printerport;
struct IntuiMessage *msg;
static char printerportname[] = "drmapdump";
static char printerdevice[] = "printer.device";
static char print_canx[] = "Printing canceled. Please wait ...";
static char print_error[] = "Printer error ... printing aborted";
char abort;
int returncode;
unsigned long signal, winsig, printsig;
abort = NULL;
ModifyIDCMP (win, MOUSEBUTTONS); /* disable all but mousebuttons */
if ((printerport = CreatePort (printerportname, 0)) != NULL) {
if ((ioreq = (struct IODRPReq *) CreateExtIO (printerport,
sizeof (struct IODRPReq))) != NULL) {
if ( ! (OpenDevice (printerdevice, 0,
(struct IORequest *) ioreq, 0))) {
ioreq->io_Command = CMD_FLUSH;
DoIO ((struct IORequest *) ioreq);
if (ioreq->io_Error == PDERR_NOERR) {
winsig = 1 << win->UserPort->mp_SigBit;
printsig = 1 << printerport->mp_SigBit;
ioreq->io_Command = PRD_DUMPRPORT;
ioreq->io_RastPort = rp;
ioreq->io_ColorMap = vp->ColorMap;
ioreq->io_Modes = VMODE; /* vp->Modes;*/
ioreq->io_SrcX = 0;
ioreq->io_SrcY = 0;
ioreq->io_SrcWidth = WWIDTH;
ioreq->io_SrcHeight = WHEIGHT;
ioreq->io_DestCols = 0;
ioreq->io_DestRows = 0;
ioreq->io_Special = SPECIAL_ASPECT|SPECIAL_FULLROWS;
SendIO ((struct IORequest *) ioreq);
while (abort == NULL) {
signal = Wait (printsig | winsig);
if (signal & winsig) {
while ((msg = (struct IntuiMessage *)
GetMsg (win->UserPort)) != NULL) {
if (msg->Code == MENUDOWN) {
returncode = ABORT;
SetWindowTitles (w, 0, print_canx);
abort |= U_ABORT;
}
ReplyMsg ((struct IntuiMessage *) msg);
}
}
if (signal & printsig) {
if (ioreq->io_Error != PDERR_NOERR) {
returncode = NOT_OK;
SetWindowTitles (w, 0, print_error);
abort |= P_ABORT;
}
else
abort |= NOABORT; /* ahem, not aborted, but ended OK */
}
}
if (abort == U_ABORT) { /* WAIT A MOMENT, crashes if */
/* printer.device is being */
/* loaded and printing is */
/* canceled */
DisplayBeep (0);
Delay (8 * TICKS_PER_SECOND);
AbortIO ((struct IORequest *)ioreq);
WaitIO ((struct IORequest *)ioreq);
}
else if (abort & NOABORT)
returncode = OK;
while ((struct MsgPort *) GetMsg (printerport))
;
}
CloseDevice ((struct IORequest *) ioreq);
}
DeleteExtIO ((struct IORequest *) ioreq);
}
DeletePort (printerport);
}
ModifyIDCMP (win, IDCMPFLAGS); /* restore normal events */
return (returncode);
}
/* ============================================================= */
int readmap (void) /* reads map files into memory */
{
FILE *fin;
int i, num_read, num_to_read;
struct Pt *pt;
for (i=0; i<NUM_MAPS; ++i) {
num_to_read = (map[i].numpts) * sizeof (struct Pt);
if ((pt = (struct Pt *) AllocRemember (&rememberkey, num_to_read,
MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
return (NOT_OK);
if ((fin = fopen (map[i].mapname, "rb")) == NULL)
return (NOT_OK);
if ((num_read = fread (pt, sizeof (char), num_to_read, fin))
!= num_to_read) {
fclose (fin);
return (NOT_OK);
}
fclose (fin);
map[i].pt = pt;
}
return (OK);
}
/* ============================================================= */
void savemappic (void) /* moves map from screen to */
/* temporary bitmap */
{
ShowTitle (s, FALSE); /* don't save window title bar */
BltBitMapRastPort (rp->BitMap, 0, 0, &map_rp, 0, 0, WWIDTH, WHEIGHT,
0xc0);
ShowTitle (s, title_toggle);
}
/* ================================================================ */
int save_to_disk (void) /* saves map to disk */
{
int result;
IFFP iffresult;
if ( (result = FileRequester (&filereq)) != TRUE) /* get file name */
return (NOT_OK);
ShowTitle (s, FALSE); /* turn off title in saved file */
SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
WAITER_X_OFFSET, WAITER_Y_OFFSET);
iffresult = SaveWindowToIFF (pathname, w); /* save map to disk */
SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
ARROW_X_OFFSET, ARROW_Y_OFFSET);
ShowTitle (s, title_toggle);
if (iffresult != IFF_OKAY) /* set return code */
return (NOT_OK);
else
return (OK);
}
/* ============================================================= */
void shadow (void) /* makes shadowed screens */
/* shadows all colors except */
/* blue and black */
{
static char first = NOT_OK;
static int blackcolor[DEPTH], disp;
static int bluecolor[DEPTH];
static unsigned int bitval[] = {1, 2, 4, 8, 16, 32, 64, 128};
static short ytable[WHEIGHT]; /* offsets from beginning of */
/* each screen row */
int modb0, modb1, color[DEPTH];
int bcolor[DEPTH];
int j, k, k1, k2, m, bitlast;
int test, t;
unsigned int byte[DEPTH];
unsigned int byteb0[DEPTH], byteb1[DEPTH];
if (first==NOT_OK) { /* initialize color values once */
first = OK;
test = BLACK;
blackcolor[0] = test&bitval[0];
for (k=1; k<DEPTH; ++k)
blackcolor[k] = (test&bitval[k]) >> k;
test = BLUE;
bluecolor[0] = test&bitval[0];
for (k=1; k<DEPTH; ++k)
bluecolor[k] = (test&bitval[k]) >> k;
ytable[0] = 0; /* initialize screen offsets */
for (k=1; k<WHEIGHT; ++k)
ytable[k] = ytable[k-1] + ROWOFFSET;
disp = SHADOW_DISP * ROWOFFSET; /* offset to shadowed row */
}
for (k=ytable[0]; k<ytable[WHEIGHT-SHADOW_DISP-1]; k+=ROWOFFSET) {
/* do each row */
k2 = k + disp; /* displacement to shadowed row */
for (j=0; j<ROWOFFSET; ++j) { /* do each byte in row */
for (k1=0; k1<DEPTH; ++k1) {
byte[k1] = bp[k1][k+j]; /* current row */
byteb0[k1] = bp[k1][k2+j]; /* shadowed row */
byteb1[k1] = bp[k1][k2+j+1]; /* shadowed row, adjacent byte */
} /* if last byte in row, don't */
/* need adjacent bytes */
((j<ROWOFFSET-1) ? (bitlast=0) : (bitlast=SHADOW_DISP));
modb0 = NOT_OK;
modb1 = NOT_OK;
for (m=7; m>=bitlast; --m) { /* check each bit, left to right */
for (k1=0; k1<DEPTH; ++k1) {
t = byte[k1];
color[k1] = BITVAL(t, m); /* current pixel color */
}
test = color[DEPTH-1]; /* build color value */
for (k1=DEPTH-2; k1>=0; --k1)
test = (test<<1) | color[k1];
if (test != BLACK && test != BLUE) {
if (m>SHADOW_DISP-1) { /* get color of pixel */
for (k1=0; k1<DEPTH; ++k1) { /* in shadowed row */
t = byteb0[k1];
bcolor[k1] = BITVAL(t, m-SHADOW_DISP);
}
}
else { /* use adjacent byte */
for (k1=0; k1<DEPTH; ++k1) {
t = byteb1[k1];
bcolor[k1] = BITVAL(t, m+8-SHADOW_DISP);
}
}
test = OK;
for (k1=0; k1<DEPTH; ++k1) { /* check if it is blue */
if (bcolor[k1] != bluecolor[k1]) {
test = NOT_OK;
break;
}
}
if (test == OK) { /* if blue, set color to black */
if (m>SHADOW_DISP-1) {
for (k1=0; k1<DEPTH; ++k1) {
t = byteb0[k1];
BITSTORE(t, m-SHADOW_DISP, blackcolor[k1]);
byteb0[k1] = t;
}
modb0 = OK;
}
else { /* use adjacent byte */
for (k1=0; k1<DEPTH; ++k1) {
t = byteb1[k1];
BITSTORE(t, m+8-SHADOW_DISP, blackcolor[k1]);
byteb1[k1] = t;
}
modb1 = OK;
}
}
}
} /* end bit test */
if (modb0==OK) { /* restore only modified bytes */
for (k1=0; k1<DEPTH; ++k1)
bp[k1][k2+j] = byteb0[k1];
}
if (modb1==OK) {
for (k1=0; k1<DEPTH; ++k1)
bp[k1][k2+j+1] = byteb1[k1];
}
} /* end of row */
} /* last row */
}
/* ============================================================= */
void showmappic (void) /* moves map from temporary */
/* bitmap to screen */
{
if (got_flat_map != OK) /* check if have already */
fullmap (FLAT_TYPE); /* saved a flat map */
else
BltBitMapRastPort (&map_bitmap, 0, 0, rp, 0, 0, WWIDTH, WHEIGHT, 0xc0);
}
/* ============================================================= */
void stars (void) /* draws stars into black background */
{
static char init = FALSE;
static int nmax = 150; /* max number of stars */
time_t systime;
unsigned int t;
int nstars;
long x, y, color;
if (init == FALSE) { /* initialize seed value */
init = TRUE; /* with system time */
t = (int) time (&systime);
srand (t);
}
SetAPen (rp, WHITE);
nstars = 0;
while (nstars < nmax) {
t = rand();
x = t % WWIDTH + 1;
t = rand();
y = t % WHEIGHT + 1;
if ((color = ReadPixel (rp, x, y)) == BLACK) {
WritePixel (rp, x, y);
++nstars;
}
}
}