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 >
C/C++ Source or Header  |  1992-04-06  |  96KB  |  2,584 lines

  1. /*  File drawmap.c  */
  2.  
  3. #include <functions.h>
  4. #include <devices/printer.h>
  5. #include <errno.h>
  6. #include <exec/io.h>
  7. #include <exec/libraries.h>
  8. #include <exec/memory.h>
  9. #include <fcntl.h>
  10. #include <graphics/gfxmacros.h>
  11. #include <intuition/intuition.h>
  12. #include <libraries/dos.h>
  13. #include <libraries/dosextens.h>
  14. #include <math.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <time.h>
  19.  
  20. #include "reqbase.h"
  21. #include "ILBM_lib.h"
  22. #include "drawmap-menu.h"
  23. #include "drawmap.h"
  24. #include "drawmap-req.h"
  25. #include "drawmap-help.h"
  26. #include "drawmap-proto.h"
  27.  
  28. struct Screen *s;                      /* pointer to screen          */
  29. struct Window *w;                      /* pointer to Window          */
  30. struct RastPort *rp;                   /* pointer to RastPort        */
  31. struct ViewPort *vp;                   /* pointer to ViewPort        */
  32. struct TmpRas mapTmpRas;               /* temp raster for flood fill */
  33. struct Library *GfxBase;
  34. struct Library *IntuitionBase;
  35. struct Remember *rememberkey;          /* pointer for cleaning up */
  36.  
  37. struct ReqLib *ReqBase;                /* address of requester library */
  38. struct ExtendedColorRequester colorstruct;
  39. struct ReqFileRequester filereq;
  40. char filename[FCHARS];                 /* space for save file and */
  41. char directoryname[DSIZE];             /*   dir name              */
  42. char pathname[DSIZE+FCHARS];           /* full path and file name */
  43.  
  44. struct ILBMBase *ILBMBase;             /* address of ILBM library */
  45. ILBMFrame IlbmFrame;
  46.  
  47. unsigned short *arrow, *cross;         /* storage for mouse pointers */
  48. unsigned short *waiter, *transparent;
  49.  
  50. unsigned char *bp[DEPTH];              /* bitplane pointers */
  51.  
  52. struct Requester req;
  53.  
  54. struct BitMap map_bitmap;              /* holding area for initial flat map */
  55. struct RastPort map_rp;                /* rastport for initial flat map */ 
  56. char got_flat_map;
  57.  
  58. static long title_toggle = FALSE;
  59.  
  60. /* ============================================================= */
  61.  
  62. main (void)
  63.  
  64. {
  65.    struct IntuiMessage *msg;
  66.    PLANEPTR workspace;
  67.    int ix;
  68.    FILE *config;
  69.  
  70.    rememberkey = NULL;                 /* initialize rememberkey */
  71.    if ((GfxBase = (struct Library *) OpenLibrary ("graphics.library", 0L))
  72.         == NULL)  {
  73.       printf ("Can't open graphics library\n");
  74.       exit (10);
  75.    }
  76.    if ((IntuitionBase=(struct Library *) OpenLibrary ("intuition.library",0L))
  77.         == NULL)  {
  78.       printf ("Can't open intuition library\n");
  79.       goto end1;
  80.    }
  81.    if ((ReqBase = (struct ReqLib *) OpenLibrary ("req.library", 0L))
  82.         == NULL)  {
  83.       printf ("Can't open req.library\n");
  84.       goto end2;
  85.    }
  86.    if ((ILBMBase = (struct ILBMBase *) OpenLibrary ("ilbm.library", 0L))
  87.         == NULL)  {
  88.       printf ("Can't open ilbm.library\n");
  89.       goto end3;
  90.    }
  91.    if ((s = (struct Screen *) OpenScreen (&mapscreen)) == NULL)  {
  92.       printf ("Can't open screen\n");
  93.       goto end4;
  94.    }
  95.    mapWindow.Screen = s;
  96.    newhelpw.Screen = s;
  97.    if ((w = (struct Window *) OpenWindow (&mapWindow)) == NULL)  {
  98.       printf ("Can't open window\n");
  99.       goto end5;
  100.    }
  101.                                        /* load default color table */
  102.    CopyMem ((char *) mapcolors, (char *) configcolors,
  103.             sizeof(mapcolors));
  104.    if ((config = fopen (configfile, "rb")) != NULL)  {
  105.       if ((ix = fread ((char *) &configcolors[0], sizeof (char),
  106.                        sizeof(configcolors), config))
  107.                        != sizeof(configcolors))  {
  108.          CopyMem ((char *) mapcolors, (char *) configcolors,
  109.                   sizeof(mapcolors));
  110.       }
  111.       fclose (config);
  112.    }
  113.    vp = &(s->ViewPort);                /* pointer to viewport */
  114.    LoadRGB4 (vp, &configcolors[0], NUM_COLORS); /* init. color values  */
  115.                                        /* init. mouse pointers */
  116.    arrow = (UWORD *) AllocRemember (&rememberkey, ARROW_SIZE, MEMF_CHIP);
  117.    CopyMem ((char *) arrow_data, (char *) arrow, ARROW_SIZE);
  118.  
  119.    cross = (UWORD *) AllocRemember (&rememberkey, CROSS_SIZE, MEMF_CHIP);
  120.    CopyMem ((char *) cross_data, (char *) cross, CROSS_SIZE);
  121.    
  122.    waiter = (UWORD *) AllocRemember (&rememberkey, WAITER_SIZE, MEMF_CHIP);
  123.    CopyMem ((char *) waiter_data, (char *) waiter, WAITER_SIZE);
  124.    
  125.    transparent = (UWORD *) AllocRemember (&rememberkey, TRANSPARENT_SIZE,
  126.                                           MEMF_CHIP);
  127.    CopyMem ((char *) transparent_data, (char *) transparent,
  128.             TRANSPARENT_SIZE);
  129.  
  130.    SetPointer (w, waiter, WAITER_SIZE/4-2, 16, WAITER_X_OFFSET,
  131.                WAITER_Y_OFFSET);
  132.  
  133.    rp = w->RPort;
  134.    if ((workspace = (PLANEPTR) AllocRaster (WWIDTH,WHEIGHT)) == NULL)  {
  135.       printf ("No space for Temporary Raster\n");
  136.       goto end6;
  137.    }
  138.  
  139.    InitBitMap (&map_bitmap, DEPTH, WWIDTH, WHEIGHT);
  140.    InitRastPort (&map_rp);
  141.    map_rp.BitMap = &map_bitmap;
  142.  
  143.    for (ix=0; ix<DEPTH; ++ix)          /* initialize flat map storage area */
  144.       map_bitmap.Planes[ix] = NULL;
  145.    for (ix=0; ix<DEPTH; ++ix)  {
  146.       map_bitmap.Planes[ix] = (PLANEPTR) AllocRaster (WWIDTH, WHEIGHT);
  147.       if (map_bitmap.Planes[ix] == NULL)  {
  148.          printf ("No space for bitmap workspace\n");
  149.          goto end7;
  150.       }
  151.    }                                   /* temp raster for flood fill */
  152.    InitTmpRas (&mapTmpRas, workspace, RASSIZE(WWIDTH,WHEIGHT));
  153.    rp->TmpRas = &mapTmpRas;            /* link it to the RastPort */
  154.  
  155.    if ((ix = readmap ()) != OK)  {     /* read map files */
  156.       printf ("Error reading map files\n");
  157.       goto end7;
  158.    }
  159.    if ((ix = get_min_max ()) != OK)  {
  160.       printf ("Map files are corrupted\n");
  161.       goto end7;
  162.    }
  163.  
  164.    if ((ix = init_helpitems ()) != OK)
  165.       printf ("\nUnable to initialize help information, but continuing\n");
  166.  
  167.    loadmappic();                       /* load initial flat map */
  168.  
  169.    for (ix=0; ix<DEPTH; ++ix)          /* initialize bitplane pointers */
  170.       bp[ix] = rp->BitMap->Planes[ix];
  171.  
  172.    init_requesters ();                 /* initialize the requesters */
  173.  
  174.    SetMenuStrip (w, &menu[0]);         /* bring up the menus */
  175.  
  176.    SetAPen (rp, ORANGE);               /* set initial drawing pens */
  177.    SetBPen (rp, BLUE);
  178.    SetDrMd (rp, JAM2);
  179.  
  180.    view_height = VIEW_HEIGHT;          /* constants for globe view */
  181.    eta = view_height/RE;
  182.    facp = 1. + eta;
  183.    etap = 1./facp;
  184.  
  185.    SetPointer (w, arrow, ARROW_SIZE/4-2, 16, ARROW_X_OFFSET, ARROW_Y_OFFSET);
  186.  
  187.    while (1)  {                        /* wait for message from */
  188.       WaitPort ( w->UserPort );        /*   Intuition           */
  189.       if ((msg = (struct IntuiMessage *) GetMsg (w->UserPort)) == NULL)
  190.          continue;
  191.       else if ((ix = handle_event (msg)) != OK)
  192.          break;
  193.       else
  194.          ReplyMsg (msg);
  195.    }
  196.    ReplyMsg (msg);
  197.    if (helpbuffer != NULL)
  198.       free (helpbuffer);
  199.    PurgeFiles (&filereq);              /* clean up after file requester */
  200. end7:
  201.    for (ix=0; ix<DEPTH; ++ix)
  202.       if (map_bitmap.Planes[ix] != NULL)
  203.          FreeRaster (map_bitmap.Planes[ix], WWIDTH, WHEIGHT);
  204.    FreeRaster (workspace, WWIDTH, WHEIGHT);
  205. end6:
  206.    FreeRemember (&rememberkey, TRUE);  /* clean up */
  207.    ClearPointer (w);
  208.    ClearMenuStrip (w);
  209.    Forbid ();                          /* strip remaining messages */
  210.    while (1)  {
  211.       if ((msg = (struct IntuiMessage *) GetMsg (w->UserPort)) == NULL)
  212.          break;
  213.       else
  214.          ReplyMsg (msg);
  215.    }
  216.    ModifyIDCMP (w, NULL);
  217.    Permit ();
  218.    CloseWindow (w);
  219. end5:
  220.    CloseScreen (s);
  221. end4:
  222.    CloseLibrary (ILBMBase);
  223. end3:
  224.    CloseLibrary (ReqBase);
  225. end2:
  226.    CloseLibrary (IntuitionBase);
  227. end1:
  228.    CloseLibrary (GfxBase);
  229. }
  230.  
  231. /* ============================================================= */
  232.  
  233. int handle_event (struct IntuiMessage *msg)
  234.                                        /* processes main Intuition events */
  235. {
  236.    static char box_error[]               = "Box of zero size not allowed";
  237.    static char *dlevels[]                = { "High", "Medium high",
  238.                                              "Medium", "Medium low",
  239.                                              "Low" };
  240.    static char drag_prompt[]             = "Press and drag left button to "
  241.                                            "select box, right button to "
  242.                                            "abort";
  243.    static char expandbox_error[]         = "Invalid map displayed for Box "
  244.                                            "Zoom Out option";
  245.    static char flood_wait[]              = "Press left button to select area "
  246.                                            "to fill, right button to abort";
  247.    static char fmt_DETAIL_LEVEL_TYPE[]   = "%s detail level";
  248.    static char fmt_ORBITAL_TYPE[]        = "Orbital...view from %.2lf "
  249.                                            "kilometers";
  250.    static char fmt_ZOOM_IN_TYPE[]        = "Zoom In...view from %.2lf "
  251.                                            "kilometers";
  252.    static char fmt_ZOOM_OUT_TYPE[]       = "Zoom Out...view from %.2lf "
  253.                                            "kilometers";
  254.    static char grid_error[]              = "Invalid map displayed for Grid "
  255.                                            "option";
  256.    static char lines_wait[]              = "Press left button to draw lines, "
  257.                                            "right button to abort";
  258.    static char press_prompt[]            = "Press left button to select "
  259.                                            "center point, right button to "
  260.                                            "abort";
  261.    static char print_abort[]             = "Printing aborted";
  262.    static char print_error[]             = "Printer error";
  263.    static char print_wait[]              = "Printing...press right button to "
  264.                                            "abort";
  265.    static char smallbox_error[]          = "Invalid map displayed for Box "
  266.                                            "Zoom In option";
  267.    static char title_BOX_TYPE[]          = "Box";
  268.    static char title_BOX_ZOOM_IN_TYPE[]  = "Box Zoom In";
  269.    static char title_BOX_ZOOM_OUT_TYPE[] = "Box Zoom Out";
  270.    static char title_CLEARS_TYPE[]       = "Clear Screen";
  271.    static char title_COAST_COLOR_TYPE[]  = "Color for Coastlines";
  272.    static char title_COUNTRY_COLOR_TYPE[] = "Color for Countries";
  273.    static char title_DRAW_LINE_TYPE[]    = "Draw Lines";
  274.    static char title_FLAT_TYPE[]         = "Flat Map";
  275.    static char title_FLOOD_COLOR_TYPE[]  = "Color for Flood Fill";
  276.    static char title_FLOOD_TYPE[]        = "Flood Fill";
  277.    static char title_GLOBE_TYPE[]        = "Globe...view from infinitely far "
  278.                                            "away";
  279.    static char title_HELP_TYPE[]         = "Display help file";
  280.    static char title_HELP_TYPE_error[]   = "Error displaying help information";
  281.    static char title_ISLAND_COLOR_TYPE[] = "Color for Islands";
  282.    static char title_LAKE_COLOR_TYPE[]   = "Color for Lakes";
  283.    static char title_LINE_COLOR_TYPE[]   = "Color for lines";
  284.    static char title_MERCATOR_TYPE[]     = "Mercator";
  285.    static char title_PALETTE_TYPE[]      = "Modify Color Palette";
  286.    static char title_PRINT_TYPE[]        = "Print Screen";
  287.    static char title_REDRAW_TYPE[]       = "Redraw";
  288.    static char title_REDRAW_TYPE_error[] = "Invalid map displayed for Redraw "
  289.                                            "option";
  290.    static char title_RESET_COLOR_TYPE[]  = "Reset Colors";
  291.    static char title_RIVER_COLOR_TYPE[]  = "Color for Rivers";
  292.    static char title_SHADOW_TYPE[]       = "Shadow";
  293.    static char title_STATE_COLOR_TYPE[]  = "Color for States";
  294.    static char title_TEXT_COLOR_TYPE[]   = "Color for text";
  295.    static char title_TEXT_TYPE[]         = "Text";
  296.    static char title_abort[]             = "Selection aborted";
  297.    static char title_buffer[]            = "                                "
  298.                                            "                                ";
  299.    static char title_config_not_saved[]  = "Configuration not saved";
  300.    static char title_config_saved[]      = "Configuration saved to disk";
  301.    static char title_not_saved[]         = "Screen not saved";
  302.    static char title_saved[]             = "Screen saved to disk";
  303.    static char first_time = TRUE;
  304.    static long oldtype = -1L;
  305.    static long flood_color = DK_GRN;
  306.    static long line_color  = LT_YEL;
  307.    static long text_color  = WHITE;
  308.    static double lamg, latg;
  309.    static double lat[2], lam[2];
  310.    struct IntuiMessage *msgf;
  311.    FILE *config;
  312.    char abort;
  313.    unsigned short select;
  314.    long x, y, x0, y0;
  315.    int i, result;
  316.    long menunum, itemnum, subnum, type;
  317.    double latb[2], lamb[2], del, av;
  318.  
  319.    disable_menus (IDCMPFLAGS);         /* disable menus while do this event */
  320.    abort = FALSE;
  321.    if (first_time == TRUE)  {
  322.       first_time = FALSE;
  323.       if (got_flat_map == OK)
  324.          oldtype = FLAT_TYPE;
  325.    }
  326.    switch (msg->Class) {
  327.    case MENUPICK:
  328.       select = msg->Code;
  329.       if (select == MENUNULL)          /* no extended selections */
  330.          break;
  331.       menunum = MENUNUM (select);
  332.       itemnum = ITEMNUM (select);
  333.       subnum = SUBNUM (select);
  334.       type = (long) (100*menunum+itemnum)*100+subnum; /* menu selection */
  335.       switch (menunum)  {
  336.       case PROJECT:
  337.          switch (itemnum)  {
  338.          case HELP:
  339.             SetWindowTitles (w, 0, title_HELP_TYPE);
  340.             ShowTitle (s, TRUE);
  341.             title_toggle = TRUE;
  342.             ModifyIDCMP (w, CLOSEWINDOW);
  343.             SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
  344.                         WAITER_X_OFFSET, WAITER_Y_OFFSET);
  345.             if ((result = displayhelp ()) != OK)  {
  346.                SetWindowTitles (w, 0, title_HELP_TYPE_error);
  347.                DisplayBeep (0);
  348.             }
  349.             SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
  350.                         ARROW_X_OFFSET, ARROW_Y_OFFSET);
  351.             ModifyIDCMP (w, IDCMPFLAGS);
  352.             break;
  353.          case SAVEIT:
  354.             ModifyIDCMP (w, CLOSEWINDOW);
  355.             if ((result = save_to_disk ()) != OK)  {
  356.                SetWindowTitles (w, 0, title_not_saved);
  357.                DisplayBeep (0);
  358.             }
  359.             else
  360.                SetWindowTitles (w, 0, title_saved);
  361.             ShowTitle (s, TRUE);
  362.             title_toggle = TRUE;
  363.             ModifyIDCMP (w, IDCMPFLAGS);
  364.             break;
  365.          case SAVE_CONFIG:
  366.             ModifyIDCMP (w, CLOSEWINDOW);
  367.             SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
  368.                         WAITER_X_OFFSET, WAITER_Y_OFFSET);
  369.             if ((config = fopen (configfile, "wb")) != NULL)  {
  370.                if ((i = fwrite ((char *) &configcolors[0], sizeof (char),
  371.                         sizeof(configcolors), config))
  372.                     == sizeof(configcolors))
  373.                   SetWindowTitles (w, 0, title_config_saved);
  374.                else  {
  375.                   SetWindowTitles (w, 0, title_config_not_saved);
  376.                   DisplayBeep (0);
  377.                }
  378.                fclose (config);
  379.             }
  380.             else  {
  381.                SetWindowTitles (w, 0, title_config_not_saved);
  382.                DisplayBeep (0);
  383.             }
  384.             SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
  385.                         ARROW_X_OFFSET, ARROW_Y_OFFSET);
  386.             ModifyIDCMP (w, IDCMPFLAGS);
  387.             ShowTitle (s, TRUE);
  388.             title_toggle = TRUE;
  389.             break;
  390.          case PRINT:
  391.             SetWindowTitles (w, 0, print_wait);
  392.             SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
  393.                         WAITER_X_OFFSET, WAITER_Y_OFFSET);
  394.             if ((result = printmap (w)) == OK)
  395.                SetWindowTitles (w, 0, title_PRINT_TYPE);
  396.             else  {
  397.                if (result == NOT_OK)
  398.                   SetWindowTitles (w, 0, print_error);
  399.                else
  400.                   SetWindowTitles (w, 0, print_abort);
  401.                DisplayBeep (0);
  402.             }
  403.             SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
  404.                         ARROW_X_OFFSET, ARROW_Y_OFFSET);
  405.             break;
  406.          case CLEARS:
  407.             SetWindowTitles (w, 0, title_CLEARS_TYPE);
  408.             ShowTitle (s, TRUE);
  409.             title_toggle = TRUE;
  410.             SetRast (rp, BLUE);
  411.             oldtype = type;
  412.             break;
  413.          case QUIT:
  414.             enable_menus ();
  415.             return (NOT_OK);
  416.             break;
  417.          default:
  418.             break;
  419.          }
  420.          break;
  421.       case BOUNDARIES:
  422.          switch (itemnum)  {
  423.          case COASTLINES:
  424.             map[COASTLINES].plot ^= 1;
  425.             break;
  426.          case COUNTRIES:
  427.             map[COUNTRIES].plot ^= 1;
  428.             break;
  429.          case STATES:
  430.             map[STATES].plot ^= 1;
  431.             break;
  432.          case ISLANDS:
  433.             map[ISLANDS].plot ^= 1;
  434.             break;
  435.          case LAKES:
  436.             map[LAKES].plot ^= 1;
  437.             break;
  438.          case RIVERS:
  439.             map[RIVERS].plot ^= 1;
  440.             break;
  441.          case DETAIL_LEVEL:
  442.             detail_level = subnum + 1;
  443.             sprintf (title_buffer, fmt_DETAIL_LEVEL_TYPE,
  444.                dlevels[subnum]);
  445.             SetWindowTitles (w, 0, title_buffer);
  446.             break;
  447.          default:
  448.             break;
  449.          }
  450.          break;
  451.       case MAPS:
  452.          switch (itemnum)  {
  453.          case PLANE:
  454.             switch (subnum)  {
  455.             case FLAT:
  456.                SetWindowTitles (w, 0, title_FLAT_TYPE);
  457.                ShowTitle (s, TRUE);
  458.                title_toggle = TRUE;
  459.                ModifyIDCMP (w, CLOSEWINDOW);
  460.                SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
  461.                            WAITER_X_OFFSET, WAITER_Y_OFFSET);
  462.                fullmap (FLAT_TYPE);
  463.                SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
  464.                            ARROW_X_OFFSET, ARROW_Y_OFFSET);
  465.                ModifyIDCMP (w, IDCMPFLAGS);
  466.                oldtype = type;
  467.                break;
  468.             case MERCATOR:
  469.                SetWindowTitles (w, 0, title_MERCATOR_TYPE);
  470.                ShowTitle (s, TRUE);
  471.                title_toggle = TRUE;
  472.                ModifyIDCMP (w, CLOSEWINDOW);
  473.                SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
  474.                            WAITER_X_OFFSET, WAITER_Y_OFFSET);
  475.                fullmap (MERCATOR_TYPE);
  476.                SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
  477.                            ARROW_X_OFFSET, ARROW_Y_OFFSET);
  478.                ModifyIDCMP (w, IDCMPFLAGS);
  479.                oldtype = type;
  480.                break;
  481.             default:
  482.                break;
  483.             }
  484.             break;
  485.          case SPHERE:
  486.             switch (subnum)  {
  487.             case ZOOM_IN:              /* zoom views */
  488.             case ZOOM_OUT:
  489.                if (type==ZOOM_IN_TYPE)  {
  490.                   view_height /= 2.;
  491.                   if (view_height<MIN_HEIGHT)
  492.                      view_height = MIN_HEIGHT;
  493.                   sprintf (title_buffer, fmt_ZOOM_IN_TYPE, view_height);
  494.                }
  495.                else  {
  496.                   view_height *= 2.;
  497.                   sprintf (title_buffer, fmt_ZOOM_OUT_TYPE, view_height);
  498.                }
  499.                eta = view_height/RE;
  500.                facp = 1. + eta;
  501.                etap = 1./facp;
  502.             case GLOBE:                /* globe views */
  503.             case ORBITAL:
  504.                if ( (type!=ZOOM_IN_TYPE && type!=ZOOM_OUT_TYPE) ||
  505.                 (oldtype!=ZOOM_IN_TYPE && oldtype!=ZOOM_OUT_TYPE &&
  506.                  oldtype!=GLOBE_TYPE   && oldtype!=ORBITAL_TYPE) )  {
  507.                   SetWindowTitles (w, 0, press_prompt);
  508.                                        /* wait for mouse button */
  509.                   if (oldtype!=FLAT_TYPE && oldtype!=MERCATOR_TYPE)  {
  510.                      ModifyIDCMP (w, CLOSEWINDOW);
  511.                      SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
  512.                                  WAITER_X_OFFSET, WAITER_Y_OFFSET);
  513.                      showmappic ();
  514.                      ModifyIDCMP (w, IDCMPFLAGS);
  515.                      oldtype = FLAT_TYPE;
  516.                   }
  517.                   ShowTitle (s, TRUE);
  518.                   title_toggle = TRUE;
  519.                   SetPointer (w, cross, CROSS_SIZE/4-2, 16, 
  520.                               CROSS_X_OFFSET, CROSS_Y_OFFSET);
  521.                   while (1)  {
  522.                      WaitPort (w->UserPort);
  523.                      if ((msgf = (struct IntuiMessage *) GetMsg (w->UserPort))
  524.                           ==NULL)
  525.                         continue;
  526.                      else if (msgf->Code==SELECTDOWN)
  527.                         break;
  528.                      else if (msgf->Code == MENUDOWN)  {
  529.                         abort = TRUE;
  530.                         ReplyMsg (msgf);
  531.                         SetWindowTitles (w, 0, title_abort);
  532.                         SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
  533.                                     ARROW_X_OFFSET, ARROW_Y_OFFSET);
  534.                         DisplayBeep (0);
  535.                         break;
  536.                      }
  537.                      else
  538.                         ReplyMsg (msgf);
  539.                   }
  540.                   if (abort == TRUE)
  541.                      break;
  542.                   x = msgf->MouseX;    /* get mouse position */
  543.                   y = msgf->MouseY;
  544.                   ReplyMsg (msgf);
  545.                   getcoord (x, y, oldtype, &latg, &lamg);
  546.                }
  547.                if (type==ORBITAL_TYPE)  {
  548.                   get_user_input (ORBITAL_TYPE, x, y, &view_height,
  549.                                   &x0, &y0);
  550.                   eta = view_height/RE;   /* initialize values for */
  551.                   facp = 1. + eta;        /*   orbital view        */
  552.                   etap = 1./facp;
  553.                   sprintf (title_buffer, fmt_ORBITAL_TYPE, view_height);
  554.                   SetWindowTitles (w, 0, title_buffer);
  555.                }
  556.                else if (type==GLOBE_TYPE)
  557.                   SetWindowTitles (w, 0, title_GLOBE_TYPE);
  558.                else
  559.                   SetWindowTitles (w, 0, title_buffer);
  560.                ShowTitle (s, TRUE);
  561.                title_toggle = TRUE;
  562.                ModifyIDCMP (w, CLOSEWINDOW);
  563.                SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
  564.                            WAITER_X_OFFSET, WAITER_Y_OFFSET);
  565.                globe (latg, lamg, type); /* draw map */
  566.                stars ();
  567.                SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
  568.                            ARROW_X_OFFSET, ARROW_Y_OFFSET);
  569.                ModifyIDCMP (w, IDCMPFLAGS);
  570.                oldtype = type;
  571.                break;
  572.             default:
  573.                break;
  574.             }
  575.             break;
  576.          case BOXES:
  577.             switch (subnum)  {
  578.             case BOX_ZOOM_IN:          /* box zoom in */
  579.                if (oldtype != BOX_TYPE && oldtype != BOX_ZOOM_IN_TYPE &&
  580.                    oldtype != BOX_ZOOM_OUT_TYPE)  {
  581.                   SetWindowTitles (w, 0, smallbox_error);
  582.                   ShowTitle (s, TRUE);
  583.                   title_toggle = TRUE;
  584.                   DisplayBeep (0);
  585.                   break;
  586.                }                       /* and fall through to  */
  587.             case BOX:                  /* ordinary box request */
  588.                SetWindowTitles (w, 0, drag_prompt);
  589.                ShowTitle (s, TRUE);
  590.                title_toggle = TRUE;
  591.                if (type == BOX_TYPE && (oldtype!=FLAT_TYPE &&
  592.                    oldtype!=MERCATOR_TYPE))  {
  593.                   ModifyIDCMP (w, CLOSEWINDOW);
  594.                   SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
  595.                               WAITER_X_OFFSET, WAITER_Y_OFFSET);
  596.                   showmappic ();
  597.                   ModifyIDCMP (w, IDCMPFLAGS);
  598.                   oldtype = FLAT_TYPE;
  599.                }
  600.                SetPointer (w, cross, CROSS_SIZE/4-2, 16,
  601.                            CROSS_X_OFFSET, CROSS_Y_OFFSET);
  602.                if ((result = getbox (&x0, &y0, &x, &y)) != OK)  {
  603.                   SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
  604.                               ARROW_X_OFFSET, ARROW_Y_OFFSET);
  605.                   if (result == ABORT)
  606.                      SetWindowTitles (w, 0, title_abort);
  607.                   else
  608.                      SetWindowTitles (w, 0, box_error);
  609.                   DisplayBeep (0);
  610.                   break;
  611.                }
  612.                if (type == BOX_TYPE)
  613.                   SetWindowTitles (w, 0, title_BOX_TYPE);
  614.                else
  615.                   SetWindowTitles (w, 0, title_BOX_ZOOM_IN_TYPE);
  616.                ModifyIDCMP (w, CLOSEWINDOW);
  617.                SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
  618.                            WAITER_X_OFFSET, WAITER_Y_OFFSET);
  619.                if (type == BOX_TYPE)  {
  620.                   getcoord (x0, y0, oldtype, &lat[0], &lam[0]);
  621.                   getcoord (x, y, oldtype, &lat[1], &lam[1]);
  622.                }
  623.                else  {
  624.                   getcoord_box (x0, y0, lat, lam, &latb[0], &lamb[0]);
  625.                   getcoord_box (x, y, lat, lam, &latb[1], &lamb[1]);
  626.                   lat[0] = latb[0];
  627.                   lat[1] = latb[1];
  628.                   lam[0] = lamb[0];
  629.                   lam[1] = lamb[1];
  630.                }
  631.                box (lat, lam);
  632.                SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
  633.                            ARROW_X_OFFSET, ARROW_Y_OFFSET);
  634.                ModifyIDCMP (w, IDCMPFLAGS);
  635.                oldtype = type;
  636.                break;
  637.             case BOX_ZOOM_OUT:         /* box zoom out */
  638.                if (oldtype != BOX_TYPE && oldtype != BOX_ZOOM_IN_TYPE &&
  639.                    oldtype != BOX_ZOOM_OUT_TYPE)  {
  640.                   SetWindowTitles (w, 0, expandbox_error);
  641.                   ShowTitle (s, TRUE);
  642.                   title_toggle = TRUE;
  643.                   DisplayBeep (0);
  644.                   break;
  645.                }
  646.                SetWindowTitles (w, 0, title_BOX_ZOOM_OUT_TYPE);
  647.                ModifyIDCMP (w, CLOSEWINDOW);
  648.                SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
  649.                            WAITER_X_OFFSET, WAITER_Y_OFFSET);
  650.                del = EXPAND_SCALE_FACTOR * (lat[0] - lat[1])/2.;
  651.                av = (lat[0] + lat[1])/2.;
  652.                lat[0] = av + del;
  653.                lat[1] = av - del;
  654.                if (lat[0] > 90.)
  655.                   lat[0] = 90.;
  656.                if (lat[1] < -90.)
  657.                   lat[1] = -90.;
  658.                del = EXPAND_SCALE_FACTOR * (lam[1] - lam[0])/2.;
  659.                av = (lam[0] + lam[1])/2.;
  660.                lam[0] = av - del;
  661.                lam[1] = av + del;
  662.                if (lam[0] < -180.)
  663.                   lam[0] = -180.;
  664.                if (lam[1] > 180.)
  665.                   lam[1] = 180.;
  666.                box (lat, lam);
  667.                SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
  668.                            ARROW_X_OFFSET, ARROW_Y_OFFSET);
  669.                ModifyIDCMP (w, IDCMPFLAGS);
  670.                oldtype = type;
  671.                break;
  672.             default:
  673.                break;
  674.             }
  675.             break;
  676.          case REDRAW:                  /* redraw previous map */
  677.             if (oldtype != FLAT_TYPE    && oldtype != MERCATOR_TYPE    &&
  678.                 oldtype != GLOBE_TYPE   && oldtype != ORBITAL_TYPE     &&
  679.                 oldtype != ZOOM_IN_TYPE && oldtype != ZOOM_OUT_TYPE    &&
  680.                 oldtype != BOX_TYPE     && oldtype != BOX_ZOOM_IN_TYPE &&
  681.                 oldtype != BOX_ZOOM_OUT_TYPE)  {
  682.                SetWindowTitles (w, 0, title_REDRAW_TYPE_error);
  683.                ShowTitle (s, TRUE);
  684.                title_toggle = TRUE;
  685.                DisplayBeep (0);
  686.                break;
  687.             }
  688.             SetWindowTitles (w, 0, title_REDRAW_TYPE);
  689.             ModifyIDCMP (w, CLOSEWINDOW);
  690.             SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
  691.                         WAITER_X_OFFSET, WAITER_Y_OFFSET);
  692.             if (oldtype == FLAT_TYPE || oldtype == MERCATOR_TYPE)
  693.                fullmap (oldtype);
  694.             else if (oldtype == ZOOM_IN_TYPE || oldtype == ZOOM_OUT_TYPE ||
  695.                      oldtype == GLOBE_TYPE   || oldtype == ORBITAL_TYPE)  {
  696.                globe (latg, lamg, oldtype);
  697.                stars ();
  698.             }
  699.             else
  700.                box (lat, lam);
  701.             SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
  702.                         ARROW_X_OFFSET, ARROW_Y_OFFSET);
  703.             ModifyIDCMP (w, IDCMPFLAGS);
  704.             break;
  705.          default:
  706.             break;
  707.          }
  708.          break;
  709.       case COLORS:
  710.          switch (itemnum)  {
  711.          case PALETTE:
  712.             SetWindowTitles (w, 0, title_PALETTE_TYPE);
  713.             ShowTitle (s, TRUE);
  714.             title_toggle = TRUE;
  715.             ModifyIDCMP (w, CLOSEWINDOW);
  716.             SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
  717.                         WAITER_X_OFFSET, WAITER_Y_OFFSET);
  718.             result = ExtendedColorRequester (&colorstruct);
  719.             for (i=0; i<NUM_COLORS; ++i)
  720.                configcolors[i] = GetRGB4 (vp->ColorMap, i);
  721.             SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
  722.                         ARROW_X_OFFSET, ARROW_Y_OFFSET);
  723.             ModifyIDCMP (w, IDCMPFLAGS);
  724.             break;
  725.          case RESET_COLOR:
  726.             SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
  727.                         WAITER_X_OFFSET, WAITER_Y_OFFSET);
  728.             LoadRGB4 (vp, &mapcolors[0], NUM_COLORS);
  729.             CopyMem ((char *) mapcolors, (char *) configcolors,
  730.                      sizeof(mapcolors));
  731.             SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
  732.                         ARROW_X_OFFSET, ARROW_Y_OFFSET);
  733.             SetWindowTitles (w, 0, title_RESET_COLOR_TYPE);
  734.             break;
  735.          case FLOOD_COLOR:
  736.             flood_color = subnum;
  737.             SetWindowTitles (w, 0, title_FLOOD_COLOR_TYPE);
  738.             ShowTitle (s, TRUE);
  739.             title_toggle = TRUE;
  740.             break;
  741.          case LINE_COLOR:
  742.             line_color = subnum;
  743.             SetWindowTitles (w, 0, title_LINE_COLOR_TYPE);
  744.             ShowTitle (s, TRUE);
  745.             title_toggle = TRUE;
  746.             break;
  747.          case TEXT_COLOR:
  748.             text_color = subnum;
  749.             SetWindowTitles (w, 0, title_TEXT_COLOR_TYPE);
  750.             ShowTitle (s, TRUE);
  751.             title_toggle = TRUE;
  752.             break;
  753.          case COAST_COLOR:
  754.             map[COASTLINES].color = subnum;
  755.             SetWindowTitles (w, 0, title_COAST_COLOR_TYPE);
  756.             ShowTitle (s, TRUE);
  757.             title_toggle = TRUE;
  758.             break;
  759.          case COUNTRY_COLOR:
  760.             map[COUNTRIES].color = subnum;
  761.             SetWindowTitles (w, 0, title_COUNTRY_COLOR_TYPE);
  762.             ShowTitle (s, TRUE);
  763.             title_toggle = TRUE;
  764.             break;
  765.          case STATE_COLOR:
  766.             map[STATES].color = subnum;
  767.             SetWindowTitles (w, 0, title_STATE_COLOR_TYPE);
  768.             ShowTitle (s, TRUE);
  769.             title_toggle = TRUE;
  770.             break;
  771.          case ISLAND_COLOR:
  772.             map[ISLANDS].color = subnum;
  773.             SetWindowTitles (w, 0, title_ISLAND_COLOR_TYPE);
  774.             ShowTitle (s, TRUE);
  775.             title_toggle = TRUE;
  776.             break;
  777.          case LAKE_COLOR:
  778.             map[LAKES].color = subnum;
  779.             SetWindowTitles (w, 0, title_LAKE_COLOR_TYPE);
  780.             ShowTitle (s, TRUE);
  781.             title_toggle = TRUE;
  782.             break;
  783.          case RIVER_COLOR:
  784.             map[RIVERS].color = subnum;
  785.             SetWindowTitles (w, 0, title_RIVER_COLOR_TYPE);
  786.             ShowTitle (s, TRUE);
  787.             title_toggle = TRUE;
  788.             break;
  789.          default:
  790.             break;
  791.          }
  792.          break;
  793.       case EDIT:
  794.          switch (itemnum)  {
  795.          case GRID:
  796.             if (oldtype!=FLAT_TYPE     && oldtype!=MERCATOR_TYPE &&
  797.                 oldtype!=GLOBE_TYPE    && oldtype!=ORBITAL_TYPE  &&
  798.                 oldtype!=ZOOM_IN_TYPE  && oldtype!=ZOOM_OUT_TYPE)  {
  799.                SetWindowTitles (w, 0, grid_error);
  800.                ShowTitle (s, TRUE);
  801.                title_toggle = TRUE;
  802.                DisplayBeep (0);
  803.             }
  804.             else  {
  805.                ModifyIDCMP (w, CLOSEWINDOW);
  806.                SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
  807.                            WAITER_X_OFFSET, WAITER_Y_OFFSET);
  808.                grid (oldtype, latg, lamg);
  809.                SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
  810.                         ARROW_X_OFFSET, ARROW_Y_OFFSET);
  811.                ModifyIDCMP (w, IDCMPFLAGS);
  812.             }
  813.             break;
  814.          case FLOOD:
  815.             SetWindowTitles (w, 0, flood_wait);
  816.             ShowTitle (s, TRUE);
  817.             title_toggle = TRUE;
  818.             SetPointer (w, cross, CROSS_SIZE/4-2, 16,
  819.                         CROSS_X_OFFSET, CROSS_Y_OFFSET);
  820.             if ((result = floodfill (flood_color)) == OK)
  821.                SetWindowTitles (w, 0, title_FLOOD_TYPE);
  822.             else  {
  823.                SetWindowTitles (w, 0, title_abort);
  824.                DisplayBeep (0);
  825.             }
  826.             SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
  827.                         ARROW_X_OFFSET, ARROW_Y_OFFSET);
  828.             break;
  829.          case DRAW_LINE:
  830.             SetWindowTitles (w, 0, lines_wait);
  831.             ShowTitle (s, TRUE);
  832.             title_toggle = TRUE;
  833.             SetPointer (w, cross, CROSS_SIZE/4-2, 16,
  834.                         CROSS_X_OFFSET, CROSS_Y_OFFSET);
  835.             if ((result = draw_line (line_color)) == OK)
  836.                SetWindowTitles (w, 0, title_DRAW_LINE_TYPE);
  837.             else  {
  838.                SetWindowTitles (w, 0, title_abort);
  839.                DisplayBeep (0);
  840.             }
  841.             SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
  842.                         ARROW_X_OFFSET, ARROW_Y_OFFSET);
  843.             break;
  844.          case SHADOW:
  845.             ModifyIDCMP (w, CLOSEWINDOW);
  846.             ShowTitle (s, FALSE);      /* don't shadow the title */
  847.             SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
  848.                         WAITER_X_OFFSET, WAITER_Y_OFFSET);
  849.             shadow ();
  850.             SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
  851.                         ARROW_X_OFFSET, ARROW_Y_OFFSET);
  852.             SetWindowTitles (w, 0, title_SHADOW_TYPE);
  853.             ShowTitle (s, TRUE);
  854.             title_toggle = TRUE;
  855.             ModifyIDCMP (w, IDCMPFLAGS);
  856.             break;
  857.          case TEXT:
  858.             x = msg->MouseX;
  859.             y = msg->MouseY;
  860.             if ((result = do_text (x, y, text_color)) == ABORT)  {
  861.                SetWindowTitles (w, 0, title_abort);
  862.                DisplayBeep (0);
  863.             }
  864.             else
  865.                SetWindowTitles (w, 0, title_TEXT_TYPE);
  866.             ShowTitle (s, TRUE);
  867.             title_toggle = TRUE;
  868.             break;
  869.          case TTOGGLE:
  870.             title_toggle ^= 1L;
  871.             ShowTitle (s, title_toggle);
  872.             break;
  873.          default:
  874.             break;
  875.          }
  876.          break;
  877.       default:
  878.          break;
  879.       }
  880.       break;
  881.    default:
  882.       break;
  883.    }
  884.    enable_menus ();                    /* re-enable menu events */
  885.    return (OK);
  886. }
  887.  
  888. /* ================================================================ */
  889.  
  890. void box (double *latp, double *lamp)  /* draws areas contained within */
  891.                                        /*   a rectangular region       */
  892. {
  893.    char first, prev_in_view, in_view;
  894.    short h1, h1c, h1prev;              /* x-dist. (pix) from center */
  895.    short h2, h2c, h2prev;              /* y-dist. (pix) from center */
  896.    long x, y;
  897.    int i, na, nc;
  898.    int lat1i, lat2i, lam1i, lam2i;
  899.    double lam, lamc, lamprev;          /* longitude */
  900.    double lat, latc, latprev;          /* latitude  */
  901.    double bwidth, bheight, bcx, bcy, xscale, yscale;
  902.    double lat1, lat2, lam1, lam2;
  903.    struct Arc *seg;
  904.    struct Pt *pt;
  905.  
  906.    lat1 = latp[0];                     /* store values for box corners */
  907.    lat2 = latp[1];                     /*   locally                    */
  908.    lam1 = lamp[0];
  909.    lam2 = lamp[1];
  910.    lat1i = 60.*lat1;                   /* convert to signed minutes */
  911.    lat2i = 60.*lat2;
  912.    lam1i = 60.*lam1;
  913.    lam2i = 60.*lam2;
  914.    bwidth = lam2 - lam1;               /* box width (degrees)         */
  915.    bheight = lat1 - lat2;              /* box height (degrees)        */
  916.    bcx = (lam1 + lam2)/2.;             /* x-coord of box center (deg) */
  917.    bcy = (lat1 + lat2)/2.;             /* y-coord of box center (deg) */
  918.    xscale = WWIDTH / bwidth;           /* horizontal scale (pix/deg)  */
  919.    yscale = WHEIGHT / bheight;         /* vertical scale (pix/deg)    */
  920.    first = TRUE;
  921.    SetRast (rp, BLUE);                 /* blue background */
  922.    SetAPen (rp, ORANGE);               /* outline the box */
  923.    drawbox (0, 0, WWIDTH-1, WHEIGHT-1);
  924.    for (nc=0; nc<NUM_MAPS; ++nc)  {    /* do each map type */
  925.       if (map[nc].plot != TRUE)        /* if not requested, skip */
  926.          continue;
  927.       SetAPen (rp, map[nc].color);     /* initialize color */
  928.       seg = map[nc].seg;
  929.       pt = map[nc].pt;                 /* do each segment */
  930.       for (na=0; na<map[nc].nsegs; ++na)  {
  931.          first = TRUE;                 /* skip if not in view */
  932.          if (seg[na].lat_min > lat1i || seg[na].lat_max < lat2i ||
  933.              seg[na].lam_min > lam2i || seg[na].lam_max < lam1i)
  934.             continue;
  935.          for (i=seg[na].first; i<=seg[na].last; ++i)  {
  936.             if (pt[i].code < detail_level) /* filter by detail level */
  937.                continue;
  938.             lat = pt[i].lat;           /* latitude */
  939.             lat /= 60.;
  940.             lam = pt[i].lam;           /* longitude */
  941.             lam /= 60.;
  942.             in_view = FALSE;           /* get status of current point */
  943.             if ( (lat<=lat1 && lat>=lat2)
  944.               && (lam>=lam1 && lam<=lam2))  {
  945.                in_view = TRUE;
  946.                h1 = (lam-bcx) * xscale;
  947.                h2 = - (lat-bcy) * yscale;
  948.             }
  949.             if (first==TRUE)  {        /* check first point */
  950.                first = FALSE;
  951.                if (in_view==TRUE)  {   /* if first point is in view, */
  952.                   x = h1 + CENTERX;    /*   move pen to first point  */
  953.                   y = h2 + CENTERY;    /*   and plot it              */
  954.                   WritePixel (rp, x, y);
  955.                   Move (rp, x, y);
  956.                   h1prev = h1;
  957.                   h2prev = h2;
  958.                }
  959.                prev_in_view = in_view; /* save status of first point */
  960.                latprev = lat;
  961.                lamprev = lam;
  962.                continue;
  963.             }
  964.             if (in_view==TRUE)  {
  965.                if (prev_in_view==FALSE)  { /* prev. point was not in view */
  966.                   box_rim_point (lat, lam, latprev, lamprev, lat1, lam1,
  967.                                  lat2, lam2, &latc, &lamc);
  968.                   h1c = (lamc-bcx) * xscale;
  969.                   h2c = - (latc-bcy) * yscale;
  970.                   x = h1c + CENTERX;   /* move to rim point & plot it */
  971.                   y = h2c + CENTERY;
  972.                   WritePixel (rp, x, y);
  973.                   Move (rp, x, y);
  974.                   h1prev = h1c;
  975.                   h2prev = h2c;
  976.                }
  977.                if (h1!=h1prev || h2!=h2prev)  {
  978.                   x = h1 + CENTERX;    /* draw to current point */
  979.                   y = h2 + CENTERY;
  980.                   if (ABS(h1-h1prev) > WWIDTH/2)
  981.                      WritePixel (rp, x, y);
  982.                   else
  983.                      Draw (rp, x, y);
  984.                   Move (rp, x, y);
  985.                }
  986.                h1prev = h1;
  987.                h2prev = h2;
  988.             }
  989.             else  {                    /* else out of view */
  990.                if (prev_in_view==TRUE)  { /* previous point was in view */
  991.                   box_rim_point (lat, lam, latprev, lamprev, lat1, lam1,
  992.                                  lat2, lam2, &latc, &lamc);
  993.                   h1c = (lamc-bcx) * xscale;
  994.                   h2c = - (latc-bcy) * yscale;
  995.                   x = h1c + CENTERX;   /* draw to rim point */
  996.                   y = h2c + CENTERY;
  997.                   if (ABS(h1c-h1prev) > WWIDTH/2)
  998.                      WritePixel (rp, x, y);
  999.                   else
  1000.                      Draw (rp, x, y);
  1001.                   Move (rp, x, y);
  1002.                }
  1003.             }
  1004.             prev_in_view = in_view;    /* save status of current point */
  1005.             latprev = lat;
  1006.             lamprev = lam;
  1007.          }
  1008.       }
  1009.    }
  1010. }
  1011.  
  1012. /* ================================================================ */
  1013.  
  1014.                                        /* find rim points in box view */
  1015.  
  1016. void  box_rim_point (double lat, double lam, double latprev,
  1017.                      double lamprev, double lat1, double lam1,
  1018.                      double lat2, double lam2, double *latc,
  1019.                      double *lamc)
  1020. {
  1021.    double dlam, dlat, tlam1, tlam2, tlat1, tlat2;
  1022.  
  1023.    dlam = lam - lamprev;               /* use parametric linear */
  1024.    dlat = lat - latprev;               /*   interpolation       */
  1025.    if (dlam == 0.)  {                  /* same longitude */
  1026.       tlam1 = tlam2 = -1.;
  1027.       tlat1 = (lat1 - latprev) / dlat;
  1028.       tlat2 = (lat2 - latprev) / dlat;
  1029.    }
  1030.    else if (dlat == 0.)  {             /* same latitude */
  1031.       tlam1 = (lam1 - lamprev) / dlam;
  1032.       tlam2 = (lam2 - lamprev) / dlam;
  1033.       tlat1 = tlat2 = -1.;
  1034.    }
  1035.    else  {
  1036.       tlam1 = (lam1 - lamprev) / dlam;
  1037.       tlam2 = (lam2 - lamprev) / dlam;
  1038.       tlat1 = (lat1 - latprev) / dlat;
  1039.       tlat2 = (lat2 - latprev) / dlat;
  1040.    }
  1041.    if (tlam1 >= 0. && tlam1 <= 1.)  {  /* now find rim point */
  1042.       (*lamc) = lam1;
  1043.       (*latc) = latprev + tlam1 * dlat;
  1044.    }
  1045.    else if (tlam2 >= 0. && tlam2 <= 1.)  {
  1046.       (*lamc) = lam2;
  1047.       (*latc) = latprev + tlam2 * dlat;
  1048.    }
  1049.    else if (tlat1 >= 0. && tlat1 <= 1.)  {
  1050.       (*lamc) = lamprev + tlat1 * dlam;
  1051.       (*latc) = lat1;
  1052.    }
  1053.    else  {
  1054.       (*lamc) = lamprev + tlat2 * dlam;
  1055.       (*latc) = lat2;
  1056.    }
  1057. }
  1058.  
  1059. /* ============================================================= */
  1060.  
  1061. void disable_menus (long flags)        /* disables menus */
  1062.  
  1063. {
  1064.    ModifyIDCMP (w, flags);
  1065.    Forbid ();
  1066.    w->Flags |= RMBTRAP;
  1067.    Permit ();
  1068. }
  1069.  
  1070. /* ============================================================= */
  1071.  
  1072. int displayhelp (void)                 /* displays help information */
  1073.  
  1074. {
  1075.    struct IntuiMessage *msg;
  1076.    int gadgetnum;
  1077.  
  1078.    if (helpbuffer == NULL)
  1079.       return (NOT_OK);
  1080.    if ((hw = (struct Window *) OpenWindow (&newhelpw)) == NULL)
  1081.       return (NOT_OK);
  1082.    SetPointer (hw, arrow, ARROW_SIZE/4-2, 16, ARROW_X_OFFSET,
  1083.                ARROW_Y_OFFSET);
  1084.    DrawBorder (hw->RPort, &border1, 0, 0);
  1085.    while (1)  {
  1086.       WaitPort (hw->UserPort);
  1087.       if ((msg = (struct IntuiMessage * ) GetMsg (hw->UserPort)) == NULL)
  1088.          continue;
  1089.       gadgetnum = ((struct Gadget *) (msg->IAddress))->GadgetID;
  1090.       ReplyMsg (msg);
  1091.       if (gadgetnum < NUMGADGETS-1)  {
  1092.          SetPointer (hw, waiter, WAITER_SIZE/4-2, 16, WAITER_X_OFFSET,
  1093.                      WAITER_Y_OFFSET);
  1094.          ModifyIDCMP (hw, NULL);
  1095.          dohelpitem (gadgetnum);
  1096.          ModifyIDCMP (hw, GADGETUP);
  1097.          SetPointer (hw, arrow, ARROW_SIZE/4-2, 16, ARROW_X_OFFSET,
  1098.                      ARROW_Y_OFFSET);
  1099.       }
  1100.       if (gadgetnum == NUMGADGETS-1)
  1101.          break;
  1102.    }
  1103.    ClearPointer (hw);
  1104.    CloseWindow (hw);
  1105.    return (OK);
  1106. }
  1107.  
  1108. /* ============================================================= */
  1109.  
  1110. void dohelpitem (int num)
  1111.  
  1112. {
  1113.    static char defaulttext[] = "No help information to display";
  1114.    char *txt;
  1115.    short result;
  1116.    int disp;
  1117.  
  1118.    if ((disp = gadgetlist[num].disp) < 0)
  1119.       txt = defaulttext;
  1120.    else
  1121.       txt = &(helpbuffer[disp]);
  1122.    trs.Text = txt;
  1123.    trs.Window = hw;
  1124.    trs.Title = gadgetlist[num].text;
  1125.    result = TextRequest (&trs);
  1126. }
  1127.  
  1128. /* ============================================================= */
  1129.  
  1130. int do_text (long xin, long yin, long color) /* get user text input */
  1131.  
  1132. {
  1133.    struct IntuiMessage *msg1;
  1134.    static char title_setdown[] = "Press left button to position text,"
  1135.                                  " right button to cancel";
  1136.    long x, y, xold, yold;
  1137.    int pixlength;
  1138.    double t;
  1139.                                        /* get user text */
  1140.    get_user_input (TEXT_TYPE, xin, yin, &t, &xold, &yold);
  1141.    pixlength = TextLength (rp, user_text_input, strlen(user_text_input));
  1142.    SetWindowTitles (w, 0, title_setdown);
  1143.    ShowTitle (s, TRUE);
  1144.    title_toggle = TRUE;
  1145.    SetDrMd (rp, JAM2 | COMPLEMENT);    /* turn on complement mode */
  1146.    SetPointer (w, transparent, TRANSPARENT_SIZE/4-2, 16,
  1147.                TRANSPARENT_X_OFFSET, TRANSPARENT_Y_OFFSET);
  1148.    drawbox (xold, yold, xold+pixlength-1, yold-9);
  1149.    ModifyIDCMP (w, IDCMPFLAGS | MOUSEMOVE);
  1150.    while (1)  {
  1151.       WaitPort (w->UserPort);          /* wait for mouse button  */
  1152.       if ((msg1 = (struct IntuiMessage *) GetMsg (w->UserPort)) == NULL)
  1153.          continue;
  1154.       else  {
  1155.          x = msg1->MouseX;             /* get current mouse position */
  1156.          y = msg1->MouseY;             /*   and erase old box        */
  1157.          if (msg1->Code == SELECTDOWN)  {
  1158.             ReplyMsg (msg1);           /* done if select button pressed */
  1159.             drawbox (xold, yold, xold+pixlength-1, yold-9);
  1160.             break;
  1161.          }
  1162.          else if (msg1->Class == MOUSEMOVE)  {
  1163.                                        /* else draw box at current position */
  1164.             drawbox (xold, yold, xold+pixlength-1, yold-9);
  1165.             drawbox (x, y, x+pixlength-1, y-9);
  1166.             xold = x;
  1167.             yold = y;
  1168.          }
  1169.          else if (msg1->Code == MENUDOWN)  {
  1170.             ReplyMsg (msg1);
  1171.             ModifyIDCMP (w, IDCMPFLAGS);
  1172.             drawbox (xold, yold, xold+pixlength-1, yold-9);
  1173.             SetDrMd (rp, JAM2);
  1174.             SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
  1175.                         ARROW_X_OFFSET, ARROW_Y_OFFSET);
  1176.             return (ABORT);
  1177.          }
  1178.          ReplyMsg (msg1);
  1179.       }
  1180.    }
  1181.    Move (rp, x, y-2);                  /* move to current mouse position  */
  1182.    SetDrMd (rp, JAM1);                 /* (-2 to allow for font baseline) */
  1183.    SetAPen (rp, color);                /* draw text */
  1184.    Text (rp, user_text_input, strlen(user_text_input));
  1185.    SetDrMd (rp, JAM2);
  1186.    ModifyIDCMP (w, IDCMPFLAGS);        /* enable original event types */
  1187.    SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
  1188.                ARROW_X_OFFSET, ARROW_Y_OFFSET);
  1189.    return (OK);
  1190. }
  1191.  
  1192. /* ============================================================= */
  1193.  
  1194. void drawbox (long x1, long y1, long x2, long y2) /* draws a box */
  1195.  
  1196. {
  1197.    box_border.LeftEdge = x1;
  1198.    box_border.TopEdge  = y1;
  1199.    box_borderpts[2] = box_borderpts[4] = x2-x1;
  1200.    box_borderpts[5] = box_borderpts[7] = y2-y1;
  1201.    DrawBorder (rp, (struct Border *) &box_border, 0, 0);
  1202. }
  1203.  
  1204. /* ============================================================= */
  1205.  
  1206. int draw_line (long color)             /* draws a line based on */
  1207.                                        /*   mouse positions     */
  1208. {
  1209.    struct IntuiMessage *msg;
  1210.    char selectbutton;
  1211.    long x, y;
  1212.  
  1213.    selectbutton = FALSE;
  1214.    SetAPen (rp, color);
  1215.    SetDrMd (rp, JAM2);
  1216.    ModifyIDCMP (w, IDCMPFLAGS | MOUSEMOVE); /* enable mouse move events */
  1217.    while (1)  {
  1218.       WaitPort (w->UserPort);
  1219.       if ((msg = (struct IntuiMessage *) GetMsg (w->UserPort)) == NULL)
  1220.          continue;
  1221.       else if (msg->Code == MENUDOWN)  { /* stop if press menu button */
  1222.          ReplyMsg (msg);
  1223.          ModifyIDCMP (w, IDCMPFLAGS);  /* disable mouse move events */
  1224.          return (ABORT);
  1225.       }
  1226.       else if (msg->Code == SELECTDOWN)  {
  1227.          x = msg->MouseX;              /* get current mouse position */
  1228.          y = msg->MouseY;
  1229.          WritePixel (rp, x, y);
  1230.          Move (rp, x, y);
  1231.          selectbutton = TRUE;
  1232.       }
  1233.       else if (selectbutton == TRUE && msg->Class == MOUSEMOVE)  {
  1234.          x = msg->MouseX;              /* get current mouse position */
  1235.          y = msg->MouseY;
  1236.          Draw (rp, x, y);              /* draw to current position */
  1237.          Move (rp, x, y);
  1238.       }
  1239.       else if (selectbutton == TRUE && msg->Code == SELECTUP)
  1240.          break;
  1241.       ReplyMsg (msg);
  1242.    }
  1243.    ReplyMsg (msg);
  1244.    ModifyIDCMP (w, IDCMPFLAGS);        /* enable original event types */
  1245.    return (OK);
  1246. }
  1247.  
  1248. /* ============================================================= */
  1249.  
  1250. void enable_menus (void)               /* enables menus */
  1251.  
  1252. {
  1253.    ModifyIDCMP (w, IDCMPFLAGS);
  1254.    Forbid ();
  1255.    w->Flags &= ~RMBTRAP;
  1256.    Permit ();
  1257. }
  1258.  
  1259. /* ============================================================= */
  1260.  
  1261. int floodfill (long flood_color)       /* flood fills an area based */
  1262.                                        /*   on mouse position       */
  1263. {
  1264.    struct IntuiMessage *msgf;
  1265.    long x, y;
  1266.    
  1267.    while (1)  {
  1268.       WaitPort (w->UserPort);          /* wait for message */
  1269.       if ((msgf = (struct IntuiMessage *) GetMsg (w->UserPort)) == NULL)
  1270.          continue;
  1271.       else if (msgf->Code==SELECTDOWN)
  1272.          break;
  1273.       else if (msgf->Code == MENUDOWN)  {
  1274.          ReplyMsg (msgf);
  1275.          return (ABORT);
  1276.       }
  1277.       else
  1278.          ReplyMsg (msgf);
  1279.    }
  1280.    x = msgf->MouseX;                   /*  get mouse coordinates  */
  1281.    y = msgf->MouseY;
  1282.    ReplyMsg (msgf);
  1283.    SetAPen (rp, flood_color);
  1284.    Flood (rp, 1, x, y);                /* flood fill the region */
  1285.    return (OK);
  1286. }
  1287.  
  1288. /* ============================================================= */
  1289.  
  1290. void fullmap (long type)               /* draws flat and mercator */
  1291.                                        /*   map projections       */
  1292. {
  1293.    short h1, h2, h1old, h2old;
  1294.    long x, y;
  1295.    int i, na, nc, np;
  1296.    double t;
  1297.    struct Arc *seg;
  1298.    struct Pt *pt;
  1299.  
  1300.    SetRast (rp, BLUE);                 /* clear screen */
  1301.    for (nc=0; nc<NUM_MAPS; ++nc)  {    /* do each map type */
  1302.       if (map[nc].plot != TRUE)        /* if not requested, skip */
  1303.          continue;
  1304.       SetAPen (rp, map[nc].color);     /* initialize color */
  1305.       seg = map[nc].seg;
  1306.       pt = map[nc].pt;                 /* do each segment */
  1307.       for (na=0; na<map[nc].nsegs; ++na)  {
  1308.          np = 0;
  1309.          for (i=seg[na].first; i<=seg[na].last; ++i)  {
  1310.             if (pt[i].code < detail_level) /* filter by detail level */
  1311.                continue;
  1312.             t = pt[i].lat;             /* y = latitude */
  1313.             if (type==FLAT_TYPE)
  1314.                t *= (VFACTOR/60.);
  1315.             else if (type==MERCATOR_TYPE)  {
  1316.                t = (t/120. + 45.) * RAD;
  1317.                t = log (tan (t)) * M_VFACTOR;
  1318.             }
  1319.             if (t<0.)                  /* round to nearest pixel */
  1320.                t -= 0.5;
  1321.             else
  1322.                t += 0.5;
  1323.             h2 = -t;
  1324.             t = pt[i].lam;             /* x = longitude */
  1325.             t *= (HFACTOR/60.);
  1326.             if (t<0.)                  /* round to nearest pixel */
  1327.                t -= 0.5;
  1328.             else
  1329.                t += 0.5;
  1330.             h1 = t;
  1331.             x = h1 + CENTERX;
  1332.             y = h2 + CENTERY;
  1333.             if (np!=0)  {              /* disallow identical adjacent pts */
  1334.                if (h1==h1old  && h2==h2old)
  1335.                   continue;
  1336.                else if (ABS (h1-h1old) > WWIDTH/2)
  1337.                   WritePixel (rp, x, y);
  1338.                else
  1339.                   Draw (rp, x, y);
  1340.             }
  1341.             else
  1342.                WritePixel (rp, x, y);
  1343.             Move (rp, x, y);
  1344.             h1old = h1;
  1345.             h2old = h2;
  1346.             ++np;
  1347.          }
  1348.       }
  1349.    }
  1350.    if (got_flat_map != OK && type == FLAT_TYPE)  {
  1351.       savemappic ();                   /* save map in save area */
  1352.       got_flat_map = OK;
  1353.    }
  1354. }
  1355.  
  1356. /* ============================================================= */
  1357.  
  1358. int getbox (long *x0, long *y0, long *x, long *y)
  1359.                                        /* selects a region to draw to */
  1360.                                        /*   larger scale              */
  1361. {
  1362.    struct IntuiMessage *msgf;
  1363.    char selectbutton;
  1364.    long xd, yd, x1, x2, y1, y2;
  1365.  
  1366.    selectbutton = FALSE;
  1367.    SetDrMd (rp, JAM2 | COMPLEMENT);    /* turn on complement mode and */
  1368.    ModifyIDCMP (w, IDCMPFLAGS | MOUSEMOVE); /* enable mouse move events */
  1369.    while (1)  {
  1370.       WaitPort (w->UserPort);
  1371.       if ((msgf = (struct IntuiMessage *) GetMsg (w->UserPort)) == NULL)
  1372.          continue;
  1373.       else if (msgf->Code == MENUDOWN)  { /* abort if user pressed */
  1374.          ReplyMsg (msgf);                 /*   menu button         */
  1375.          ModifyIDCMP (w, IDCMPFLAGS);
  1376.          SetDrMd (rp, JAM2);
  1377.          return (ABORT);
  1378.       }
  1379.       else if (msgf->Code==SELECTDOWN)  { /* if user pressed left button, */
  1380.          xd = x1 = msgf->MouseX;          /*   get initial mouse position */
  1381.          yd = y1 = msgf->MouseY;
  1382.          drawbox (x1, y1, xd, yd);     /* draw initial box */
  1383.          selectbutton = TRUE;
  1384.       }
  1385.       else if (selectbutton==TRUE && msgf->Class==MOUSEMOVE)  {
  1386.          x2 = msgf->MouseX;
  1387.          y2 = msgf->MouseY;
  1388.          drawbox (x1, y1, xd, yd);     /* erase old box */
  1389.          xd = x2;
  1390.          yd = y2;
  1391.          drawbox (x1, y1, xd, yd);     /* draw new box */
  1392.       }
  1393.       else if (selectbutton==TRUE && msgf->Code==SELECTUP)
  1394.          break;
  1395.       ReplyMsg (msgf);
  1396.    }
  1397.    ModifyIDCMP (w, IDCMPFLAGS);        /* disable mouse events and */
  1398.    x2 = msgf->MouseX;                  /*    erase current box     */
  1399.    y2 = msgf->MouseY;
  1400.    ReplyMsg (msgf);
  1401.    drawbox (x1, y1, xd, yd);
  1402.    SetDrMd (rp, JAM2);                 /* restore original drawing mode */
  1403.    *x0 = x1;
  1404.    *y0 = y1;
  1405.    *x = x2;
  1406.    *y = y2;
  1407.    if (x1==x2 || y1==y2)               /* error if box is of zero area */
  1408.       return (NOT_OK);
  1409.    if (x1>x2 && y1>y2)  {              /* ensure that the vertices of */
  1410.       *x0 = x2;                        /*   the box are in the proper */
  1411.       *y0 = y2;                        /*   order                     */
  1412.       *x = x1;
  1413.       *y = y1;
  1414.    }
  1415.    else if (x1<x2 && y1>y2)  {
  1416.       *x0 = x1;
  1417.       *y0 = y2;
  1418.       *x = x2;
  1419.       *y = y1;
  1420.    }
  1421.    else if (x1>x2 && y1<y2)  {
  1422.       *x0 = x2;
  1423.       *y0 = y1;
  1424.       *x = x1;
  1425.       *y = y2;
  1426.    }
  1427.    return (OK);
  1428. }
  1429.  
  1430. /* ============================================================= */
  1431.  
  1432. void getcoord (long x, long y, long type, double *lat, double *lam)
  1433.                                        /* converts screen coordinates   */
  1434.                                        /*   into latitude and longitude */
  1435.                                        /*   for flat and Mercator maps  */
  1436. {
  1437.    (*lam) = (x - CENTERX) / HFACTOR;
  1438.    if (type==FLAT_TYPE)
  1439.       (*lat) = (CENTERY - y) / VFACTOR;
  1440.    else
  1441.       (*lat) = -90. + 2.*atan(exp((CENTERY-y)/M_VFACTOR))/RAD;
  1442. }
  1443.  
  1444. /* ============================================================= */
  1445.  
  1446.                                        /* get latitude and longitude */
  1447.                                        /*   for Box Zoom In option   */
  1448. void getcoord_box (long x, long y, double latin[2], double lamin[2],
  1449.                    double *latout, double *lamout)
  1450. {
  1451.    (*lamout) = (((double) (x)) / WWIDTH)  * (lamin[1]-lamin[0]) + lamin[0];
  1452.    (*latout) = (((double) (y)) / WHEIGHT) * (latin[1]-latin[0]) + latin[0];
  1453. }
  1454.  
  1455. /* ============================================================= */
  1456.  
  1457. int get_min_max (void)                 /* find limits of each segment */
  1458.  
  1459. {
  1460.    FILE *fin;
  1461.    struct Arc *seg, *tseg;
  1462.    struct Pt *pt;
  1463.    int na, i, j, ix, first_seg;
  1464.  
  1465.    if ((seg = (struct Arc *) AllocRemember (&rememberkey,
  1466.                              NSEGS*sizeof(struct Arc),
  1467.                              MEMF_PUBLIC | MEMF_CLEAR)) == NULL)  {
  1468.       printf ("Unable to get space for limits array\n");
  1469.       return (NOT_OK);
  1470.    }
  1471.    for (i=0; i<NUM_MAPS; ++i)  {       /* link segment array to maps */
  1472.       first_seg = map[i].first_seg;
  1473.       map[i].seg = (struct Arc *) &(seg[first_seg].lat_min);
  1474.    }
  1475.    if ((fin = fopen (limitsfile, "rb")) != NULL)  {
  1476.       ix = fread (seg, sizeof(struct Arc), NSEGS, fin);
  1477.       fclose (fin);
  1478.       if (ix == NSEGS)
  1479.          return (OK);
  1480.       else
  1481.          printf ("Limits file corrupted, building it afresh\n");
  1482.    }
  1483.    for (i=0; i<NUM_MAPS; ++i)  {       /* build limits array in units */
  1484.       pt = map[i].pt;                  /* address of map points */
  1485.       tseg = map[i].seg;               /* address of segments for map */
  1486.       for (j=0, na=-1; j<map[i].numpts; ++j)  {
  1487.          if (pt[j].code > MAX_DETAIL_LEVEL)  {
  1488.             ++na;
  1489.             if (na >= map[i].nsegs)
  1490.                break;
  1491.             tseg[na].first = tseg[na].last = j;
  1492.             tseg[na].lat_min = tseg[na].lat_max = pt[j].lat;
  1493.             tseg[na].lam_min = tseg[na].lam_max = pt[j].lam;
  1494.             continue;
  1495.          }
  1496.          if (pt[j].lat < tseg[na].lat_min)
  1497.             tseg[na].lat_min = pt[j].lat;
  1498.          if (pt[j].lat > tseg[na].lat_max)
  1499.             tseg[na].lat_max = pt[j].lat;
  1500.          if (pt[j].lam < tseg[na].lam_min)
  1501.             tseg[na].lam_min = pt[j].lam;
  1502.          if (pt[j].lam > tseg[na].lam_max)
  1503.             tseg[na].lam_max = pt[j].lam;
  1504.          tseg[na].last = j;
  1505.       }
  1506.    }
  1507.    ix = 0;                             /* save limits to disk */
  1508.    if ((fin = fopen (limitsfile, "wb")) != NULL)  {
  1509.       ix = fwrite (seg, sizeof(struct Arc), NSEGS, fin);
  1510.       fclose (fin);
  1511.    }
  1512.    if (ix != NSEGS)                    /* error in saving to disk */
  1513.       printf ("Unable to save limits to disk, continuing anyway\n");
  1514.    return (OK);
  1515. }
  1516.  
  1517. /* ============================================================= */
  1518.  
  1519. void get_user_input (long type, long xin, long yin, double *d,
  1520.                      long *xout, long *yout)
  1521.                                        /* prompts for user input */
  1522.                                        /*   (text or doubleword) */
  1523. {
  1524.    struct IntuiMessage *msg;
  1525.    struct Gadget *g;
  1526.    long x, y;
  1527.                                        /* position the requester */
  1528.    x = xin - GAD_LEFT - 8*(NUM_CHAR-2);
  1529.    y = yin - GAD_TOP - 2;
  1530.    if ((x+TWIDTH) >= WWIDTH)
  1531.       x = WWIDTH - TWIDTH - 15;
  1532.    if (x < 10)
  1533.       x = 10;
  1534.    if ((y+THEIGHT) >= WHEIGHT)
  1535.       y = WHEIGHT - THEIGHT - 15;
  1536.    if (y < 5)
  1537.       y = 5;
  1538.    req.LeftEdge = x;
  1539.    req.TopEdge = y;
  1540.    if (type == ORBITAL_TYPE)  {        /* initialize for doubleword input */
  1541.       req.ReqText = &dtext;
  1542.       gadgetinput.Buffer = &user_double_input[0];
  1543.    }
  1544.    else  {                             /* initialize for text input */
  1545.       req.ReqText = &rtext;
  1546.       gadgetinput.Buffer = &user_text_input[0];
  1547.    }
  1548.    Request (&req, w);                  /* issue the requester */
  1549.    ModifyIDCMP (w, GADGETUP);          /* disable other events */
  1550.    ActivateGadget (&gad, w, &req);
  1551.    while (1)  {
  1552.       WaitPort (w->UserPort);
  1553.       if ((msg = (struct IntuiMessage *) GetMsg (w->UserPort)) == NULL)
  1554.          continue;
  1555.       else if (msg->Class == GADGETUP)  {
  1556.          g = (struct Gadget *) (msg->IAddress);
  1557.          if (g->GadgetID != GAD_FIRST)  {
  1558.             ReplyMsg (msg);
  1559.             continue;
  1560.          }
  1561.          *xout = msg->MouseX;          /* get mouse coordinates */
  1562.          *yout = msg->MouseY;
  1563.          ReplyMsg (msg);
  1564.          if (type == ORBITAL_TYPE)  {  /* get user value */
  1565.             *d = atof (&user_double_input[0]);
  1566.             if (errno == ERANGE)  {    /* trap erroneous input */
  1567.                *d = VIEW_HEIGHT;       /* store default value */
  1568.                sprintf (user_double_input, "%.2lf", *d);
  1569.                DisplayBeep (0);
  1570.             }
  1571.             else if ((*d) < MIN_HEIGHT)  {
  1572.                *d = MIN_HEIGHT;        /* store minimum value */
  1573.                sprintf (user_double_input, "%.2lf", *d);
  1574.                DisplayBeep (0);
  1575.             }
  1576.          }
  1577.          break;
  1578.       }
  1579.       else                             /* ignore inappropriate events */
  1580.          ReplyMsg (msg);
  1581.    }
  1582.    ModifyIDCMP (w, IDCMPFLAGS);
  1583. }
  1584.  
  1585. /* ============================================================= */
  1586.  
  1587. void globe (double lat0, double lam0, long type)
  1588.                                        /* draws globe projections */
  1589. {
  1590.    char first, prev_in_view, in_view, latzero;
  1591.    short h1, h1c, h1prev;              /* x-dist. (pix) from center */
  1592.    short h2, h2c, h2prev;              /* y-dist. (pix) from center */
  1593.    long x, y;
  1594.    int i, na, nc;
  1595.    double lam, lamc, lamprev;          /* longitude */
  1596.    double lat, latc, latprev;          /* latitude  */
  1597.    double c0, s0, c1, s1, c2, zp, zpprev;
  1598.    double hp, fac2, fac3, scale;
  1599.    double h1d, h2d, lat0p;
  1600.    double latmin, latmax, lammin, lammax;
  1601.    struct Arc *seg;
  1602.    struct Pt *pt;
  1603.  
  1604.    latzero = FALSE;
  1605.    if (type==GLOBE_TYPE)  {            /* ordinary globe view */
  1606.       hp = 0.;
  1607.       scale = 1.;
  1608.       fac3 = 1.;
  1609.    }
  1610.    else  {                             /* orbital globe view */
  1611.       hp = etap;
  1612.       scale = sqrt (1.-etap*etap);
  1613.       fac3 = (facp/(facp-hp)) * scale;
  1614.    }
  1615.    if (lat0==0.)  {
  1616.       c0 = 1.;
  1617.       s0 = 0.;
  1618.       if (type==GLOBE_TYPE)
  1619.          latzero = TRUE;               /* equatorial, ordinary globe view */
  1620.    }
  1621.    else  {
  1622.       lat0p = lat0 * RAD;
  1623.       c0 = cos (lat0p);
  1624.       s0 = sin (lat0p);
  1625.    }
  1626.    SetRast (rp, BLACK);                /* black background */
  1627.    SetAPen (rp, BLUE);                 /* blue globe */
  1628.    DrawEllipse (rp, (long) CENTERX, (long) CENTERY, (long) HRADIUS,
  1629.                 (long) VRADIUS);
  1630.    Flood (rp, 1, CENTERX, CENTERY);
  1631.    for (nc=0; nc<NUM_MAPS; ++nc)  {    /* do each map type */
  1632.       if (map[nc].plot != TRUE)        /* if not requested, skip */
  1633.          continue;
  1634.       SetAPen (rp, map[nc].color);
  1635.       seg = map[nc].seg;
  1636.       pt = map[nc].pt;                 /* do each segment */
  1637.       for (na=0; na<map[nc].nsegs; ++na)  {
  1638.          latmin = ((double) (seg[na].lat_min)) / 60.;
  1639.          latmax = ((double) (seg[na].lat_max)) / 60.;
  1640.          lammin = ((double) (seg[na].lam_min)) / 60.;
  1641.          lammax = ((double) (seg[na].lam_max)) / 60.;
  1642.          if ((i = globe_in_view (latmax, lammin, latmin, lammax, lat0, lam0,
  1643.                                  hp)) != OK)
  1644.             continue;
  1645.          first = TRUE;
  1646.          for (i=seg[na].first; i<=seg[na].last; ++i)  {
  1647.             if (pt[i].code < detail_level) /* filter by detail level */
  1648.                continue;
  1649.             lat = pt[i].lat;           /* latitude */
  1650.             lat *= (RAD/60.);
  1651.             lam = pt[i].lam;           /* longitude */
  1652.             lam = (lam/60. - lam0) * RAD;
  1653.             if (lam<-PI)
  1654.                lam += TWOPI;
  1655.             if (lam>PI)
  1656.                lam -= TWOPI;
  1657.             c1 = cos(lat);             /* cosine of latitude */
  1658.             s1 = sin(lat);             /* sine of latitude */
  1659.             in_view = FALSE;           /* get status of current point */
  1660.             if (latzero==TRUE)  {      /* equatorial globe view */
  1661.                zp = c1*cos (lam);
  1662.                if (lam>=-PI2 && lam<=+PI2)  {
  1663.                   in_view = TRUE;
  1664.                   h1 = HRADIUS * c1 * sin (lam);
  1665.                   h2 = -VRADIUS * s1;
  1666.                }
  1667.             }
  1668.             else  {                    /* oblique earth view */
  1669.                c2 = cos (lam);
  1670.                zp = s1*s0 + c1*c0*c2;
  1671.                if (zp>=hp)  {          /* zp > hp => in view */
  1672.                   in_view = TRUE;
  1673.                   h1d = HRADIUS * c1 * sin (lam);
  1674.                   h2d = -VRADIUS * (s1*c0 -c1*s0*c2);
  1675.                   if (type!=GLOBE_TYPE)  {
  1676.                      fac2 = (facp/(facp-zp)) * scale;
  1677.                      h1d *= fac2;
  1678.                      h2d *= fac2;
  1679.                   }
  1680.                   h1 = h1d;
  1681.                   h2 = h2d;
  1682.                }
  1683.             }
  1684.             if (first==TRUE)  {        /* get status of first point */
  1685.                first = FALSE;
  1686.                if (in_view==TRUE)  {   /* if first point is in view, */
  1687.                   x = h1 + CENTERX;    /*   move pen to first point  */
  1688.                   y = h2 + CENTERY;    /*   and plot it              */
  1689.                   Move (rp, x, y);
  1690.                   WritePixel (rp, x, y);
  1691.                   h1prev = h1;
  1692.                   h2prev = h2;
  1693.                }
  1694.                prev_in_view = in_view; /* save status of first point */
  1695.                latprev = lat;
  1696.                lamprev = lam;
  1697.                zpprev = zp;
  1698.                continue;
  1699.             }
  1700.             if (in_view==TRUE)  {          /* current point is in view, */
  1701.                if (prev_in_view==FALSE)  { /*   previous point was not  */
  1702.                   globe_rim_point (lat, lam, latprev, lamprev, zp, zpprev,
  1703.                                    c0, s0, fac3, type, latzero,
  1704.                                    &latc, &lamc, &h1c, &h2c);
  1705.                   x = h1c + CENTERX;   /* move to rim point & plot it */
  1706.                   y = h2c + CENTERY;
  1707.                   Move (rp, x, y);
  1708.                   WritePixel (rp, x, y);
  1709.                   h1prev = h1c;
  1710.                   h2prev = h2c;
  1711.                }
  1712.                if (h1!=h1prev || h2!=h2prev)  {
  1713.                   x = h1 + CENTERX;    /* draw to current point */
  1714.                   y = h2 + CENTERY;
  1715.                   Draw (rp, x, y);
  1716.                   Move (rp, x, y);
  1717.                }
  1718.                h1prev = h1;
  1719.                h2prev = h2;
  1720.             }
  1721.             else  {                       /* current point out of view, */
  1722.                if (prev_in_view==TRUE)  { /*   previous point in view   */
  1723.                   globe_rim_point (lat, lam, latprev, lamprev, zp, zpprev,
  1724.                                    c0, s0, fac3, type, latzero,
  1725.                                    &latc, &lamc, &h1c, &h2c);
  1726.                   x = h1c + CENTERX;   /* draw to rim point */
  1727.                   y = h2c + CENTERY;
  1728.                   Draw (rp, x, y);
  1729.                   Move (rp, x, y);
  1730.                }
  1731.             }
  1732.             prev_in_view = in_view;    /* save status of current point */
  1733.             latprev = lat;
  1734.             lamprev = lam;
  1735.             zpprev = zp;
  1736.          }
  1737.       }
  1738.    }
  1739. }
  1740.  
  1741. /* ============================================================= */
  1742.  
  1743. void globe_grid (long type, double lat0, double lam0)
  1744.                                        /* controls drawing globe grid */
  1745. {
  1746.    static double lat_interval = 20.;
  1747.    static double lam_interval = 30.;
  1748.    static double delta = 5.;
  1749.    char first;
  1750.    int k;
  1751.    double lat, lam, c0, s0, c1, s1, c2, s2, rlam, rlat;
  1752.    double hp, scale, fac3, dlat, dlam, ddelt;
  1753.    double lamp[2], latp[2];
  1754.    
  1755.    lat0 *= RAD;
  1756.    c0 = cos (lat0);
  1757.    s0 = sin (lat0);
  1758.    dlat = lat_interval;
  1759.    dlam = lam_interval;
  1760.    ddelt = delta;
  1761.    if (type==GLOBE_TYPE)  {            /* ordinary globe view */
  1762.       hp = 0.;
  1763.       scale = 1.;
  1764.       fac3 = 1.;
  1765.    }
  1766.    else  {                             /* orbital view */
  1767.       hp = etap;
  1768.       scale = sqrt (1.-etap*etap);
  1769.       fac3 = (facp/(facp-hp)) * scale;
  1770.       if (view_height<=1200.)  {
  1771.          dlat /= 4.;
  1772.          dlam /= 4.;
  1773.          ddelt /= 5.;
  1774.       }
  1775.    }
  1776.    SetAPen (rp, BLACK);                /* grid lines in black */
  1777.    for (lat=80.; lat>=-80.; lat-=dlat)  { /* lines of equal latitude */
  1778.       rlat = lat*RAD;
  1779.       if ((k=limit_lam (&lamp[0], rlat, lat0, hp))!=OK)
  1780.          continue;                     /* skip if entirely out of view */
  1781.       lamp[0] += lam0;
  1782.       lamp[1] += lam0;
  1783.       k = lamp[0]/ddelt - 1.;          /* express limits as multiple */
  1784.       lamp[0] = k*ddelt;               /*   of ddelt                 */
  1785.       k = lamp[1]/ddelt + 1.;
  1786.       lamp[1] = k*ddelt;
  1787.       c1 = cos (rlat);
  1788.       s1 = sin (rlat);
  1789.       first = TRUE;
  1790.       if (lat==0.)
  1791.          SetAPen (rp, WHITE);          /* draw equator in white */
  1792.       for (lam=lamp[0]; lam<=lamp[1]; lam+=ddelt)  {
  1793.          rlam = (lam-lam0)*RAD;
  1794.          if (rlam<-PI)
  1795.             rlam += TWOPI;
  1796.          if (rlam>+PI)
  1797.             rlam -= TWOPI;
  1798.          c2 = cos (rlam);
  1799.          s2 = sin (rlam);
  1800.          globe_grid_plot (rlat, rlam, c0, s0, c1, s1, c2, s2,
  1801.                           type, hp, scale, fac3, &first);
  1802.       }
  1803.       if (lat==0.)
  1804.          SetAPen (rp, BLACK);          /* reset pen to black */
  1805.    }
  1806.    for (lam=-180.; lam<+180.; lam+=dlam)  { /* meridian circles */
  1807.       rlam = (lam-lam0)*RAD;
  1808.       if (rlam<-PI)
  1809.          rlam += TWOPI;
  1810.       if (rlam>+PI)
  1811.          rlam -= TWOPI;
  1812.       if ((k=limit_lat (&latp[0], lat0, rlam, hp))!=OK)
  1813.          continue;                     /* skip if entirely out of view */
  1814.       k = latp[0]/ddelt + 1.;          /* express limits as multiple */
  1815.       latp[0] = k*ddelt;               /*   of ddelt                 */
  1816.       k = latp[1]/ddelt - 1.;
  1817.       latp[1] = k*ddelt;
  1818.       if (latp[0]>=90.)                /* exclude North polar point */
  1819.          latp[0] = 90. - ddelt;
  1820.       if (latp[1]<=-90.)               /* exclude South polar point */
  1821.          latp[1] = -90. + ddelt;
  1822.       c2 = cos (rlam);
  1823.       s2 = sin (rlam);
  1824.       first = TRUE;
  1825.       if (lam==0. || lam==-180.)       /* prime meridian in white */
  1826.          SetAPen (rp, WHITE);
  1827.       for (lat=latp[0]; lat>=latp[1]; lat-=ddelt)  {
  1828.          rlat = lat*RAD;
  1829.          c1 = cos (rlat);
  1830.          s1 = sin (rlat);
  1831.          globe_grid_plot (rlat, rlam, c0, s0, c1, s1, c2, s2,
  1832.                           type, hp, scale, fac3, &first);
  1833.       }
  1834.       if (lam==0. || lam==-180.)
  1835.          SetAPen (rp, BLACK);          /* reset pen to black */
  1836.    }
  1837. }
  1838.  
  1839. /* ============================================================= */
  1840.  
  1841. void globe_grid_plot (double lat, double lam, double c0, double s0,
  1842.                       double c1, double s1, double c2, double s2,
  1843.                       long type, double hp, double scale, double fac3,
  1844.                       char *first)
  1845.                                        /* draws globe grids */
  1846. {
  1847.    static char latzero = FALSE;
  1848.    static char prev_in_view;
  1849.    static short h1prev, h2prev;
  1850.    static double latprev, lamprev, zpprev;
  1851.    char in_view;
  1852.    short h1, h1c;                      /* x-dist. (pix) from center */
  1853.    short h2, h2c;                      /* y-dist. (pix) from center */
  1854.    long x, y;
  1855.    double lamc;                        /* longitude */
  1856.    double latc;                        /* latitude  */
  1857.    double zp, h1d, h2d, fac2;
  1858.    
  1859.    in_view = FALSE;                    /* get status of current point */
  1860.    zp = s1*s0 + c1*c0*c2;
  1861.    if (zp>=hp)  {                      /* zp > hp => in view */
  1862.       in_view = TRUE;
  1863.       h1d = HRADIUS * c1 * s2;
  1864.       h2d = -VRADIUS * (s1*c0 - c1*s0*c2);
  1865.       if (type!=GLOBE_TYPE)  {
  1866.          fac2 = (facp/(facp-zp))*scale;
  1867.          h1d *= fac2;
  1868.          h2d *= fac2;
  1869.       }
  1870.       h1 = h1d;
  1871.       h2 = h2d;
  1872.    }
  1873.    if (*first==TRUE)  {                /* get status of first point */
  1874.       *first = FALSE;
  1875.       if (in_view==TRUE)  {            /* if first point is in view, */
  1876.          x = h1 + CENTERX;             /*   move pen to first point  */
  1877.          y = h2 + CENTERY;             /*   and plot it              */
  1878.          WritePixel (rp, x, y);
  1879.          Move (rp, x, y);
  1880.          h1prev = h1;
  1881.          h2prev = h2;
  1882.       }
  1883.       prev_in_view = in_view;          /* save status of first point */
  1884.       latprev = lat;
  1885.       lamprev = lam;
  1886.       zpprev = zp;
  1887.       return;
  1888.    }
  1889.    if (in_view==TRUE)  {               /* if current point is in view, */
  1890.       if (prev_in_view==FALSE)  {      /*   but previous point was not */
  1891.          globe_rim_point (lat, lam, latprev, lamprev, zp, zpprev,
  1892.                           c0, s0, fac3, type, latzero,
  1893.                           &latc, &lamc, &h1c, &h2c);
  1894.          x = h1c + CENTERX;            /* move to rim point & plot it */
  1895.          y = h2c + CENTERY;
  1896.          WritePixel (rp, x, y);
  1897.          Move (rp, x, y);
  1898.          h1prev = h1c;
  1899.          h2prev = h2c;
  1900.       }
  1901.       if (h1!=h1prev || h2!=h2prev)  {
  1902.          x = h1 + CENTERX;             /* draw to current point */
  1903.          y = h2 + CENTERY;
  1904.          Draw (rp, x, y);
  1905.          Move (rp, x, y);
  1906.       }
  1907.       h1prev = h1;
  1908.       h2prev = h2;
  1909.    }
  1910.    else  {                             /* current point is out of view   */
  1911.       if (prev_in_view==TRUE)  {       /* if previous point was in view, */
  1912.          globe_rim_point (lat, lam, latprev, lamprev, zp, zpprev,
  1913.                           c0, s0, fac3, type, latzero,
  1914.                           &latc, &lamc, &h1c, &h2c);
  1915.          x = h1c + CENTERX;            /* draw to rim point */
  1916.          y = h2c + CENTERY;
  1917.          Draw (rp, x, y);
  1918.          Move (rp, x, y);
  1919.       }
  1920.    }
  1921.    prev_in_view = in_view;             /* save status of current point */
  1922.    latprev = lat;
  1923.    lamprev = lam;
  1924.    zpprev = zp;
  1925. }
  1926.  
  1927. /* ============================================================= */
  1928.  
  1929. int globe_in_view (double lat0, double lam0, double lat1, double lam1,
  1930.                    double latv, double lamv, double hp)
  1931.  
  1932.                                        /* checks if a segment is visible   */
  1933.                                        /*   in a globe view                */
  1934.                                        /* lat0, lam0 = coords of upper     */
  1935.                                        /*   left corner of segment (deg)   */
  1936.                                        /* lat1, lam1 = coords of lower     */
  1937.                                        /*   right corner of segment (deg)  */
  1938.                                        /* latv, lamv = coords of viewpoint */
  1939.                                        /*   (deg)                          */
  1940.                                        /* hp = modified view height        */
  1941. {
  1942.    int k;
  1943.    double lat[2], lam[2], latt, lamt, del1, del2, eps;
  1944.    double lat0p, lam0p, lat1p, lam1p, latvp, lamvp, lamtp;
  1945.  
  1946.    lat0p = lat0 * RAD;                 /* convert to radians */
  1947.    lat1p = lat1 * RAD;
  1948.    lam0p = lam0 * RAD;
  1949.    lam1p = lam1 * RAD;
  1950.    latvp = latv * RAD;
  1951.    lamvp = lamv * RAD;
  1952.    del1 = (lat0p-lat1p)/10.;           /* divide into horizontal strips */
  1953.    if (del1 > 0.)  {
  1954.       eps = del1/10.;
  1955.       for (latt=lat0p; latt>=lat1p-eps; latt-=del1)  {
  1956.          if ((k = limit_lam (lam, latt, latvp, hp)) == OK)  {
  1957.             lam[0] += lamv;
  1958.             lam[1] += lamv;
  1959.             if (lam[0] < -PI)
  1960.                lam[0] += TWOPI;
  1961.             if (lam[0] > +PI)
  1962.                lam[0] -= TWOPI;
  1963.             if (lam[1] < -PI)
  1964.                lam[1] += TWOPI;
  1965.             if (lam[1] > +PI)
  1966.                lam[1] -= TWOPI;
  1967.             if (lam[0] <= lam1 && lam[1] >= lam0)
  1968.                return (OK);
  1969.          }
  1970.       }
  1971.    }
  1972.    del2 = (lam1p-lam0p)/10.;           /* divide into vertical strips */
  1973.    if (del2 > 0.)  {
  1974.       eps = del2/10.;
  1975.       for (lamt=lam0p-lamvp; lamt<=lam1p-lamvp+eps; lamt+=del2)  {
  1976.          if ((lamtp = lamt) < -PI)
  1977.             lamtp += TWOPI;
  1978.          if (lamtp > +PI)
  1979.             lamtp -= TWOPI;
  1980.          if ((k = limit_lat (lat, latvp, lamtp, hp)) == OK)  {
  1981.             if (lat[0] >= lat1 && lat[1] <= lat0)
  1982.                return (OK);
  1983.          }
  1984.       }
  1985.    }
  1986.    if (del1 > 0. || del2 > 0.)
  1987.       return (NOT_OK);
  1988.    return (OK);                        /* let globe() do degenerate case */
  1989. }
  1990.  
  1991. /* ============================================================= */
  1992.  
  1993.                                        /* get rim points for globe */
  1994.  
  1995. void globe_rim_point (double lat, double lam, double latprev,
  1996.                       double lamprev, double zp, double zpprev,
  1997.                       double c0, double s0, double fac3, long type,
  1998.                       char latzero, double *latc, double *lamc,
  1999.                       short *h1c, short *h2c)
  2000. {
  2001.    static int itmax = 20;
  2002.    double facz, dlat, dlam, c1, h1d, h2d;
  2003.    long x, y ,color;
  2004.    int i;
  2005.    short inc1, inc2;
  2006.  
  2007.    facz = zp / (zpprev-zp);            /* get rim point by linear */
  2008.    (*latc) = lat - (latprev-lat)*facz; /*   interpolation         */
  2009.    (*lamc) = lam - (lamprev-lam)*facz;
  2010.    dlat = fabs (lat-latprev);
  2011.    dlam = fabs (lam-lamprev);
  2012.    if ( fabs ((*latc)-latprev)> dlat || /* if rim point not between */
  2013.         fabs ((*latc)-lat)    > dlat)   /*   current and previous   */
  2014.       (*latc) = (lat+latprev)/2.;       /*   point, use midpoint    */
  2015.    if ( fabs ((*lamc)-lamprev)> dlam ||
  2016.         fabs ((*lamc)-lam)    > dlam )
  2017.       (*lamc) = (lam+lamprev)/2.;
  2018.    if (latzero==TRUE)  {
  2019.       (*h1c) = HRADIUS * cos ((*latc)) * sin ((*lamc));
  2020.       (*h2c) = -VRADIUS * sin ((*latc));
  2021.    }
  2022.    else  {
  2023.       c1 = cos ((*latc));
  2024.       h1d = HRADIUS * c1 * sin ((*lamc));
  2025.       h2d = -VRADIUS * (sin ((*latc))*c0 - c1*s0*cos ((*lamc)));
  2026.       if (type!=GLOBE_TYPE)  {
  2027.          h1d *= fac3;
  2028.          h2d *= fac3;
  2029.       }
  2030.       (*h1c) = h1d;
  2031.       (*h2c) = h2d;
  2032.    }                                   /* find nearest actual rim point */
  2033.    if ((*h1c)>=0)                      /* right half */
  2034.       inc1 = +1;
  2035.    else                                /* left half */
  2036.       inc1 = -1;
  2037.    if ((*h2c)>=0)                      /* bottom half */
  2038.       inc2 = +1;
  2039.    else                                /* top half */
  2040.       inc2 = -1;
  2041.    x = (*h1c) + CENTERX + 5*inc1;      /* coordinates of test pixel */
  2042.    y = (*h2c) + CENTERY + 5*inc2;
  2043.    for (i=0; i<itmax; ++i)  {          /* look for nearest black pixel */
  2044.       if ((color = ReadPixel (rp, x, y))==BLACK)
  2045.          break;
  2046.       x += inc1;
  2047.       y += inc2;
  2048.    }
  2049.    x -= inc1;
  2050.    y -= inc2;
  2051.    for (i=0; i<itmax; ++i)  {          /* look back for non-black one */
  2052.       if ((color = ReadPixel (rp, x, y)) != BLACK)
  2053.          break;
  2054.       x -= inc1;
  2055.       y -= inc2;
  2056.    }
  2057.    (*h1c) = x - CENTERX;
  2058.    (*h2c) = y - CENTERY;
  2059. }
  2060.  
  2061. /* ============================================================= */
  2062.  
  2063. void grid (long type, double lat0, double lam0)
  2064.                                        /* controls drawing of grids */
  2065. {
  2066.    static double lat_interval = 20.;
  2067.    static double lam_interval = 30.;
  2068.    long h1;
  2069.    double lam, lat;
  2070.  
  2071.    if (type!=FLAT_TYPE && type!=MERCATOR_TYPE)
  2072.       globe_grid (type, lat0, lam0);   /* draw grid for globe */
  2073.    else  {                             /* otherwise grid for flat */
  2074.                                        /*   or Mercator map       */
  2075.       SetAPen (rp, BLACK);             /* set grid color to black */
  2076.       for (lam=-180.; lam<=+180.; lam += lam_interval)  {
  2077.          h1 = lam*HFACTOR + CENTERX;
  2078.          Move (rp, h1, 0);
  2079.          Draw (rp, h1, WHEIGHT-1);
  2080.       }
  2081.       for (lat=80.; lat>=-80.; lat -= lat_interval)  {
  2082.          if (type==FLAT_TYPE)
  2083.             h1 = -lat*VFACTOR;
  2084.          else
  2085.             h1 = -log (tan((lat/2.+45.)*RAD)) * M_VFACTOR;
  2086.          h1 += CENTERY;
  2087.          Move (rp, 0, h1);
  2088.          Draw (rp, WWIDTH-1, h1);
  2089.       }
  2090.       SetAPen (rp, WHITE);             /* draw coordinate axes in white */
  2091.       Move (rp, CENTERX, 0);
  2092.       Draw (rp, CENTERX, WHEIGHT-1);
  2093.       Move (rp, 0, CENTERY);
  2094.       Draw (rp, WWIDTH-1, CENTERY);
  2095.    }
  2096. }
  2097.  
  2098. /* ============================================================= */
  2099.  
  2100. int init_helpitems (void)              /* initializes help info */
  2101.  
  2102. {
  2103.    FILE *helpfile;
  2104.    struct Gadget *gadgetpointer;
  2105.    long x, y;
  2106.    int gadgetnum;
  2107.    int ix, numrd, i;
  2108.  
  2109.    if ((helpbuffer = (char *) calloc (1, (unsigned) HELPBUFSIZE)) == NULL)
  2110.       return (NOT_OK);
  2111.    if ((helpfile = fopen (helpfilename, "rb")) == NULL)  {
  2112.       free (helpbuffer);
  2113.       helpbuffer = NULL;
  2114.       return (NOT_OK);
  2115.    }
  2116.    if ((numrd = fread (helpbuffer, sizeof(char), HELPBUFSIZE, helpfile))
  2117.        <= 0)  {
  2118.       fclose (helpfile);
  2119.       free (helpbuffer);
  2120.       helpbuffer = NULL;
  2121.       return (NOT_OK);
  2122.    }
  2123.    fclose (helpfile);
  2124.    ix = 1;
  2125.    gadgetlist[0].disp = 0;
  2126.    for (i=0; i<numrd-1; ++i)  {        /* get disp to each help entry */
  2127.       if (helpbuffer[i] == '\f')  {    /* replace formfeed with eol to */
  2128.          helpbuffer[i] = '\0';         /*   facilitate text display    */
  2129.          gadgetlist[ix].disp = i+1;
  2130.          ++ix;
  2131.          if (ix > NUMGADGETS)
  2132.             break;
  2133.       }
  2134.    }                                   /* now link the gadgets */
  2135.    for (gadgetnum=0; gadgetnum<NUMGADGETS; ++gadgetnum)  {
  2136.       x = HGADGETSTARTX + (gadgetnum&1) * (HWIDTH/2);
  2137.       y = HGADGETSTARTY + s->Font->ta_YSize + (gadgetnum/2) *
  2138.           (HGAD_HEIGHT+HGAP);
  2139.       LinkGadget (&gadgetblocks[gadgetnum],
  2140.                   gadgetlist[gadgetnum].text,
  2141.                   &newhelpw, (long) x, (long) y);
  2142.       gadgetblocks[gadgetnum].Gadget.GadgetID = gadgetnum;
  2143.    }                                   /* put exit gadget at top */
  2144.    gadgetpointer = &gadgetblocks[NUMGADGETS-1].Gadget;
  2145.    gadgetpointer->TopEdge = HTOP_MARGIN;
  2146.    gadgetpointer->LeftEdge = (HWIDTH-gadgetpointer->Width) / 2;
  2147.    return (OK);
  2148. }
  2149.  
  2150. /* ============================================================= */
  2151.  
  2152. void init_requesters (void)            /* initializes the requesters */
  2153.  
  2154. {
  2155.    static char title_file[] = "Select save file name:";
  2156.    unsigned char *s, *t;   
  2157.  
  2158.    InitRequester (&req);               /* initialize the requester */
  2159.    req.LeftEdge  = TLEFT;
  2160.    req.TopEdge   = TTOP;
  2161.    req.Width     = TWIDTH;
  2162.    req.Height    = THEIGHT;
  2163.    req.ReqGadget = &gad;
  2164.    req.ReqText   = &rtext;             /* assume text input */
  2165.    req.BackFill  = ORANGE;
  2166.    req.Flags     = 0;
  2167.    req.ReqBorder = &border_top;
  2168.    s = &user_text_input[0];            /* copy default text string */
  2169.    t = &default_text[0];
  2170.    while ((*s++ = *t++) != '\0')
  2171.             ;
  2172.    s = &user_double_input[0];          /* copy default orbital height */
  2173.    sprintf (default_double, "%.2lf", VIEW_HEIGHT);
  2174.    t = &default_double[0];
  2175.    while ((*s++ = *t++) != '\0')
  2176.             ;
  2177.  
  2178.    colorstruct.window = w;             /* window id for color requester */
  2179.  
  2180.    pathname[0]              = 0;       /* initialize file requester */
  2181.    filereq.Title            = title_file;  /* window title          */
  2182.    filereq.Dir              = directoryname;  /* space for dir name */
  2183.    filereq.File             = filename;    /* space for file name   */
  2184.    filereq.PathName         = pathname;    /* space for path name   */
  2185.    filereq.Window           = w;           /* display on map window */
  2186.    filereq.Flags            = FRQCACHINGM; /* cache the filenames   */
  2187.    filereq.Flags           |= FRQSAVINGM;  /* saving files          */
  2188.    filereq.dirnamescolor    = ORANGE;      /* dir names             */
  2189.    filereq.filenamescolor   = LT_YEL;      /* file names            */
  2190.    filereq.devicenamescolor = BLACK;       /* device names          */
  2191.    filereq.detailcolor      = BLUE;        /* window gadgets        */
  2192.    filereq.blockcolor       = DK_YEL;      /* title bar             */
  2193.    filereq.gadgettextcolor  = DK_YEL;      /* text in gadgets       */
  2194.    filereq.textmessagecolor = DK_YEL;      /* text in title         */
  2195.    filereq.stringnamecolor  = DK_YEL;      /* prompts               */
  2196.    filereq.stringgadgetcolor= LT_BL;       /* borders               */
  2197.    filereq.boxbordercolor   = LT_BL;
  2198.    filereq.gadgetboxcolor   = LT_BL;
  2199.  
  2200.    trs.MiddleText = "OK";              /* initialize items in */
  2201.    trs.PositiveText = 0;               /*   help requester    */
  2202.    trs.NegativeText = 0;
  2203.    trs.KeyMask = 0;
  2204.    trs.textcolor = ORANGE;
  2205.    trs.detailcolor = BLUE;
  2206.    trs.blockcolor = DK_YEL;
  2207.    trs.versionnumber = REQVERSION;
  2208.    trs.Timeout = 0;
  2209.    trs.AbortMask = 0;
  2210.    trs.rfu1 = 0;
  2211. }
  2212.  
  2213. /* ============================================================= */
  2214.  
  2215. int limit_lam (double *lam, double lat, double lat0, double etap)
  2216.                                        /* computes limits on longitude */
  2217.                                        /*   for constant latitude      */
  2218. {
  2219.    double alpha;
  2220.    
  2221.    alpha = (etap-sin(lat)*sin(lat0)) / (cos(lat)*cos(lat0));
  2222.    if (alpha<=-1.)  {                  /* negative => lamda covers */
  2223.       lam[0] = -180.;                  /*   entire hemisphere      */
  2224.       lam[1] = +180.;
  2225.       return (OK);
  2226.    }
  2227.    else if (alpha>=+1.)                /* positive => nothing in view */
  2228.       return (NOT_OK);
  2229.    else  {                             /* otherwise, compute limits */
  2230.       lam[0] = -acos (alpha)/RAD;
  2231.       lam[1] = -lam[0];
  2232.       return (OK);
  2233.    }
  2234. }
  2235.  
  2236. /* ============================================================= */
  2237.  
  2238. int limit_lat (double *lat, double lat0, double lam, double etap)
  2239.                                        /* computes limits on latitude */
  2240.                                        /*   for constant longitude    */
  2241. {
  2242.    double radical, a, b, sum, fac1;
  2243.    
  2244.    a = sin (lat0);
  2245.    b = cos (lat0) * cos (lam);
  2246.    sum = a*a + b*b;
  2247.    if ((radical = sum - etap*etap) <= 0.) /* no real solutions */
  2248.       return (NOT_OK);
  2249.    else  {                             /* two real solutions       */
  2250.       radical = sqrt (radical);        /* solve quadratic equation */
  2251.       fac1 = (a*etap + b*radical)/sum;
  2252.       lat[0] = asin (fac1)/RAD;
  2253.       fac1 = (a*etap - b*radical)/sum;
  2254.       lat[1] = asin (fac1)/RAD;
  2255.       if (lat[0]<lat[1])  {            /* put in correct order */
  2256.          b = lat[0];
  2257.          lat[0] = lat[1];
  2258.          lat[1] = b;
  2259.       }
  2260.       if (a>etap)                      /* check North pole */
  2261.          lat[0] = 90.;
  2262.       if (a<-etap)                     /* check South pole */
  2263.          lat[1] = -90.;
  2264.       return (OK);
  2265.    }
  2266. }
  2267.  
  2268. /* ================================================================ */
  2269.  
  2270. void loadmappic (void)                 /* loads initial flat map */
  2271.  
  2272. {
  2273.    IFFP Iresult;
  2274.  
  2275.    IlbmFrame.iWindow = w;
  2276.    IlbmFrame.iScreen = s;
  2277.    IlbmFrame.iUserFlags = 0;
  2278.    got_flat_map = NOT_OK;
  2279.    if ((Iresult = LoadIFFToWindow (flatmapfile, &IlbmFrame)) == IFF_OKAY)  {
  2280.       got_flat_map = OK;
  2281.       savemappic ();
  2282.       ShowTitle (s, TRUE);
  2283.       title_toggle = TRUE;
  2284.    }
  2285. }
  2286.  
  2287. /* ================================================================ */
  2288.  
  2289. int printmap (struct Window *win)      /* prints displayed map */
  2290.  
  2291. {
  2292.    struct IODRPReq *ioreq;
  2293.    struct MsgPort *printerport;
  2294.    struct IntuiMessage *msg;
  2295.    static char printerportname[] = "drmapdump";
  2296.    static char printerdevice[]   = "printer.device";
  2297.    static char print_canx[]      = "Printing canceled. Please wait ...";
  2298.    static char print_error[]     = "Printer error ... printing aborted";
  2299.    char abort;
  2300.    int returncode;
  2301.    unsigned long signal, winsig, printsig;
  2302.  
  2303.    abort = NULL;
  2304.    ModifyIDCMP (win, MOUSEBUTTONS);    /* disable all but mousebuttons */
  2305.    if ((printerport = CreatePort (printerportname, 0)) != NULL)  {
  2306.       if ((ioreq = (struct IODRPReq *) CreateExtIO (printerport,
  2307.                    sizeof (struct IODRPReq))) != NULL)  {
  2308.          if ( ! (OpenDevice (printerdevice, 0,
  2309.                              (struct IORequest *) ioreq, 0)))  {
  2310.             ioreq->io_Command = CMD_FLUSH;
  2311.             DoIO ((struct IORequest *) ioreq);
  2312.             if (ioreq->io_Error == PDERR_NOERR)  {
  2313.                winsig = 1 << win->UserPort->mp_SigBit;
  2314.                printsig = 1 << printerport->mp_SigBit;
  2315.                ioreq->io_Command = PRD_DUMPRPORT;
  2316.                ioreq->io_RastPort = rp;
  2317.                ioreq->io_ColorMap = vp->ColorMap;
  2318.                ioreq->io_Modes = VMODE; /* vp->Modes;*/
  2319.                ioreq->io_SrcX = 0;
  2320.                ioreq->io_SrcY = 0;
  2321.                ioreq->io_SrcWidth = WWIDTH;
  2322.                ioreq->io_SrcHeight = WHEIGHT;
  2323.                ioreq->io_DestCols = 0;
  2324.                ioreq->io_DestRows = 0;
  2325.                ioreq->io_Special = SPECIAL_ASPECT|SPECIAL_FULLROWS;
  2326.  
  2327.                SendIO ((struct IORequest *) ioreq);
  2328.                while (abort == NULL)  {
  2329.                   signal = Wait (printsig | winsig);
  2330.                   if (signal & winsig)  {
  2331.                      while ((msg = (struct IntuiMessage *)
  2332.                                    GetMsg (win->UserPort)) != NULL)  {
  2333.                         if (msg->Code == MENUDOWN)  {
  2334.                            returncode = ABORT;
  2335.                            SetWindowTitles (w, 0, print_canx);
  2336.                            abort |= U_ABORT;
  2337.                         }
  2338.                         ReplyMsg ((struct IntuiMessage *) msg);
  2339.                      }
  2340.                   }
  2341.                   if (signal & printsig)  {
  2342.                      if (ioreq->io_Error != PDERR_NOERR)  {
  2343.                         returncode = NOT_OK;
  2344.                         SetWindowTitles (w, 0, print_error);
  2345.                         abort |= P_ABORT;
  2346.                      }
  2347.                      else
  2348.                         abort |= NOABORT; /* ahem, not aborted, but ended OK */
  2349.                   }
  2350.                }
  2351.                if (abort == U_ABORT)  { /* WAIT A MOMENT, crashes if */
  2352.                                         /*   printer.device is being */
  2353.                                         /*   loaded and printing is  */
  2354.                                         /*   canceled                */
  2355.                   DisplayBeep (0);
  2356.                   Delay (8 * TICKS_PER_SECOND);
  2357.                   AbortIO ((struct IORequest *)ioreq);
  2358.                   WaitIO ((struct IORequest *)ioreq);
  2359.                }
  2360.                else if (abort & NOABORT)
  2361.                   returncode = OK;
  2362.                while ((struct MsgPort *) GetMsg (printerport))
  2363.                   ;
  2364.             }
  2365.             CloseDevice ((struct IORequest *) ioreq);
  2366.          }
  2367.          DeleteExtIO ((struct IORequest *) ioreq);
  2368.       }
  2369.       DeletePort (printerport);
  2370.    }
  2371.    ModifyIDCMP (win, IDCMPFLAGS);      /* restore normal events */
  2372.    return (returncode);
  2373. }
  2374.  
  2375. /* ============================================================= */
  2376.  
  2377. int readmap (void)                     /* reads map files into memory */
  2378.  
  2379. {
  2380.    FILE *fin;
  2381.    int i, num_read, num_to_read;
  2382.    struct Pt *pt;
  2383.  
  2384.    for (i=0; i<NUM_MAPS; ++i)  {
  2385.       num_to_read = (map[i].numpts) * sizeof (struct Pt);
  2386.       if ((pt = (struct Pt *) AllocRemember (&rememberkey, num_to_read,
  2387.                               MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
  2388.          return (NOT_OK);
  2389.       if ((fin = fopen (map[i].mapname, "rb")) == NULL)
  2390.          return (NOT_OK);
  2391.       if ((num_read = fread (pt, sizeof (char), num_to_read, fin))
  2392.            != num_to_read)  {
  2393.          fclose (fin);
  2394.          return (NOT_OK);
  2395.       }
  2396.       fclose (fin);
  2397.       map[i].pt = pt;
  2398.    }
  2399.    return (OK);
  2400. }
  2401.  
  2402. /* ============================================================= */
  2403.  
  2404. void savemappic (void)                 /* moves map from screen to */
  2405.                                        /*   temporary bitmap       */
  2406. {
  2407.    ShowTitle (s, FALSE);               /* don't save window title bar */
  2408.    BltBitMapRastPort (rp->BitMap, 0, 0, &map_rp, 0, 0, WWIDTH, WHEIGHT,
  2409.                       0xc0);
  2410.    ShowTitle (s, title_toggle);
  2411. }
  2412.  
  2413. /* ================================================================ */
  2414.  
  2415. int save_to_disk (void)                /* saves map to disk */
  2416.  
  2417. {
  2418.    int result;
  2419.    IFFP iffresult;
  2420.  
  2421.    if ( (result = FileRequester (&filereq)) != TRUE) /* get file name */
  2422.       return (NOT_OK);
  2423.    ShowTitle (s, FALSE);               /* turn off title in saved file */
  2424.    SetPointer (w, waiter, WAITER_SIZE/4-2, 16,
  2425.                WAITER_X_OFFSET, WAITER_Y_OFFSET);
  2426.    iffresult = SaveWindowToIFF (pathname, w); /* save map to disk */
  2427.    SetPointer (w, arrow, ARROW_SIZE/4-2, 16,
  2428.                ARROW_X_OFFSET, ARROW_Y_OFFSET);
  2429.    ShowTitle (s, title_toggle);
  2430.    if (iffresult != IFF_OKAY)          /* set return code */
  2431.       return (NOT_OK);
  2432.    else
  2433.      return (OK);
  2434. }
  2435.  
  2436. /* ============================================================= */
  2437.  
  2438. void shadow (void)                     /* makes shadowed screens */
  2439.                                        /* shadows all colors except */
  2440.                                        /*   blue and black          */
  2441. {
  2442.    static char first = NOT_OK;
  2443.    static int blackcolor[DEPTH], disp;
  2444.    static int bluecolor[DEPTH];
  2445.    static unsigned int bitval[] = {1, 2, 4, 8, 16, 32, 64, 128};
  2446.    static short ytable[WHEIGHT];       /* offsets from beginning of */
  2447.                                        /*   each screen row         */
  2448.    int modb0, modb1, color[DEPTH];
  2449.    int bcolor[DEPTH];
  2450.    int j, k, k1, k2, m, bitlast;
  2451.    int test, t;
  2452.    unsigned int byte[DEPTH];
  2453.    unsigned int byteb0[DEPTH], byteb1[DEPTH];
  2454.  
  2455.    if (first==NOT_OK)  {               /* initialize color values once */
  2456.       first = OK;
  2457.       test = BLACK;
  2458.       blackcolor[0] = test&bitval[0];
  2459.       for (k=1; k<DEPTH; ++k)
  2460.          blackcolor[k] = (test&bitval[k]) >> k;
  2461.       test = BLUE;
  2462.       bluecolor[0] = test&bitval[0];
  2463.       for (k=1; k<DEPTH; ++k)
  2464.          bluecolor[k] = (test&bitval[k]) >> k;
  2465.       ytable[0] = 0;                   /* initialize screen offsets */
  2466.       for (k=1; k<WHEIGHT; ++k)
  2467.          ytable[k] = ytable[k-1] + ROWOFFSET;
  2468.       disp = SHADOW_DISP * ROWOFFSET;  /* offset to shadowed row */
  2469.    }
  2470.    for (k=ytable[0]; k<ytable[WHEIGHT-SHADOW_DISP-1]; k+=ROWOFFSET)  {
  2471.                                        /* do each row                  */
  2472.       k2 = k + disp;                   /* displacement to shadowed row */
  2473.       for (j=0; j<ROWOFFSET; ++j)  {   /* do each byte in row          */
  2474.          for (k1=0; k1<DEPTH; ++k1)  {
  2475.             byte[k1] = bp[k1][k+j];    /* current row */
  2476.             byteb0[k1] = bp[k1][k2+j]; /* shadowed row */
  2477.             byteb1[k1] = bp[k1][k2+j+1]; /* shadowed row, adjacent byte */
  2478.          }                             /* if last byte in row, don't   */
  2479.                                        /*   need adjacent bytes        */
  2480.          ((j<ROWOFFSET-1) ? (bitlast=0) : (bitlast=SHADOW_DISP));
  2481.          modb0 = NOT_OK;
  2482.          modb1 = NOT_OK;
  2483.          for (m=7; m>=bitlast; --m)  { /* check each bit, left to right */
  2484.             for (k1=0; k1<DEPTH; ++k1)  {
  2485.                t = byte[k1];
  2486.                color[k1] = BITVAL(t, m); /* current pixel color */
  2487.             }
  2488.             test = color[DEPTH-1];     /* build color value */
  2489.             for (k1=DEPTH-2; k1>=0; --k1)
  2490.                test = (test<<1) | color[k1];
  2491.             if (test != BLACK && test != BLUE)  {
  2492.                if (m>SHADOW_DISP-1)  {          /* get color of pixel */
  2493.                   for (k1=0; k1<DEPTH; ++k1)  { /*   in shadowed row  */
  2494.                      t = byteb0[k1];
  2495.                      bcolor[k1] = BITVAL(t, m-SHADOW_DISP);
  2496.                   }
  2497.                }
  2498.                else  {                 /* use adjacent byte */
  2499.                   for (k1=0; k1<DEPTH; ++k1)  {
  2500.                      t = byteb1[k1];
  2501.                      bcolor[k1] = BITVAL(t, m+8-SHADOW_DISP);
  2502.                   }
  2503.                }
  2504.                test = OK;
  2505.                for (k1=0; k1<DEPTH; ++k1)  { /* check if it is blue */
  2506.                   if (bcolor[k1] != bluecolor[k1])  {
  2507.                      test = NOT_OK;
  2508.                      break;
  2509.                   }
  2510.                }
  2511.                if (test == OK)  {      /* if blue, set color to black */
  2512.                   if (m>SHADOW_DISP-1)  {
  2513.                      for (k1=0; k1<DEPTH; ++k1)  {
  2514.                         t = byteb0[k1];
  2515.                         BITSTORE(t, m-SHADOW_DISP, blackcolor[k1]);
  2516.                         byteb0[k1] = t;
  2517.                      }
  2518.                      modb0 = OK;
  2519.                   }
  2520.                   else  {              /* use adjacent byte */
  2521.                      for (k1=0; k1<DEPTH; ++k1)  {
  2522.                         t = byteb1[k1];
  2523.                         BITSTORE(t, m+8-SHADOW_DISP, blackcolor[k1]);
  2524.                         byteb1[k1] = t;
  2525.                      }
  2526.                      modb1 = OK;
  2527.                   }
  2528.                }
  2529.             }
  2530.          }                             /* end bit test */
  2531.          if (modb0==OK)  {             /* restore only modified bytes */
  2532.             for (k1=0; k1<DEPTH; ++k1)
  2533.                bp[k1][k2+j] = byteb0[k1];
  2534.          }
  2535.          if (modb1==OK)  {
  2536.             for (k1=0; k1<DEPTH; ++k1)
  2537.                bp[k1][k2+j+1] = byteb1[k1];
  2538.          }
  2539.       }                                /* end of row */
  2540.    }                                   /* last row   */
  2541. }
  2542.  
  2543. /* ============================================================= */
  2544.  
  2545. void showmappic (void)                 /* moves map from temporary */
  2546.                                        /*   bitmap to screen       */
  2547. {
  2548.    if (got_flat_map != OK)             /* check if have already */
  2549.       fullmap (FLAT_TYPE);             /*   saved a flat map    */
  2550.    else
  2551.       BltBitMapRastPort (&map_bitmap, 0, 0, rp, 0, 0, WWIDTH, WHEIGHT, 0xc0);
  2552. }
  2553.  
  2554. /* ============================================================= */
  2555.  
  2556. void stars (void)                      /* draws stars into black background */
  2557.  
  2558. {
  2559.    static char init = FALSE;
  2560.    static int nmax = 150;              /* max number of stars */
  2561.    time_t systime;
  2562.    unsigned int t;
  2563.    int nstars;
  2564.    long x, y, color;
  2565.  
  2566.    if (init == FALSE)  {               /* initialize seed value */
  2567.       init = TRUE;                     /*   with system time    */
  2568.       t = (int) time (&systime);
  2569.       srand (t);
  2570.    }
  2571.    SetAPen (rp, WHITE);
  2572.    nstars = 0;
  2573.    while (nstars < nmax)  {
  2574.       t = rand();
  2575.       x = t % WWIDTH + 1;
  2576.       t = rand();
  2577.       y = t % WHEIGHT + 1;
  2578.       if ((color = ReadPixel (rp, x, y)) == BLACK)  {
  2579.          WritePixel (rp, x, y);
  2580.          ++nstars;
  2581.       }
  2582.    }
  2583. }
  2584.