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