home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 555a.lha / DrawMap_v3.1_src&libs / sources.LZH / sources / drawmap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-14  |  93.2 KB  |  2,604 lines

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