home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 353.lha / drawmap_v2.0 / drawmap.c < prev    next >
C/C++ Source or Header  |  1990-03-10  |  67KB  |  2,050 lines

  1. /*  File drawmap.c  */
  2.  
  3. #include "intuition/intuition.h"
  4. #include "graphics/gfxmacros.h"
  5. #include "exec/memory.h"
  6. #include <stdio.h>
  7. #include <fcntl.h>
  8. #include <math.h>
  9. #include <popmenu.h>
  10. #include <drawmap.h>
  11. #include <drawmap-req.h>
  12. #include <drawmap-menu.h>
  13.  
  14. short *map, *map_trig;                 /* workspaces for map  */
  15. short *td, *td_trig;
  16.  
  17. struct Screen *s;                      /* pointer to screen   */
  18. struct Window *w;                      /* pointer to Window   */
  19. struct RastPort *rp;                   /* pointer to RastPort */
  20. struct ViewPort *vp;                   /* pointer to ViewPort */
  21. struct AreaInfo mapAreaInfo;
  22. struct TmpRas mapTmpRas;
  23. struct Library *GfxBase;
  24. struct Library *IntuitionBase;
  25. short areaArray[5*NUMPTS];             /* 5 words per point for drawing    */
  26. short area[2*NUMPTS];                  /* storage for each individual area */
  27.  
  28. unsigned short *arrow, *cross;         /* storage for mouse pointers */
  29. unsigned short *waiter, *transparent;
  30.  
  31. UBYTE *bp[DEPTH];                      /* bitplane pointers         */
  32. short ytable[WHEIGHT];                 /* offsets from beginning of */
  33.                                        /*   each screen row         */
  34. short rowoffset;
  35.  
  36. struct Requester req;
  37.  
  38. /* ============================================================= */
  39.  
  40. main ()
  41.  
  42. {
  43.  
  44.    struct IntuiMessage *msg;
  45.    PLANEPTR workspace;
  46.    extern void free_svector(), InitTextRequest();
  47.    extern int readmap();
  48.    extern int HandleEvent();
  49.    extern short *svector();
  50.    int ix;
  51.  
  52.    if ((GfxBase = OpenLibrary ("graphics.library",0)) == NULL)  {
  53.       printf ("Can't open graphics library\n");
  54.       exit (10);
  55.    }
  56.    if ((IntuitionBase = OpenLibrary ("intuition.library",0)) == NULL)  {
  57.       printf ("Can't open intuition library\n");
  58.       goto end1;
  59.    }
  60.    if ((s = OpenScreen (&mapscreen)) == NULL)  {
  61.       printf ("Can't open screen\n");
  62.       goto end2;
  63.    }
  64.    mapWindow.Screen = s;
  65.    if ((w = OpenWindow (&mapWindow)) == NULL)  {
  66.       printf ("Can't open window\n");
  67.       goto end3;
  68.    }
  69.    vp = &(s->ViewPort);                /* pointer to viewport */
  70.    LoadRGB4 (vp, &mapcolors[0], 4);    /* init. color values  */
  71.                                        /* init. mouse pointers */
  72.    arrow = (UWORD *) AllocMem (arrow_size, MEMF_CHIP);
  73.    for (ix=0; ix<arrow_size/2; ++ix)
  74.       arrow[ix] = arrow_data[ix];
  75.    SetPointer (w, arrow, arrow_size/4-2, 16, arrow_x_offset, arrow_y_offset);
  76.    
  77.    cross = (UWORD *) AllocMem (cross_size, MEMF_CHIP);
  78.    for (ix=0; ix<cross_size/2; ++ix)
  79.       cross[ix] = cross_data[ix];
  80.    
  81.    waiter = (UWORD *) AllocMem (waiter_size, MEMF_CHIP);
  82.    for (ix=0; ix<waiter_size/2; ++ix)
  83.       waiter[ix] = waiter_data[ix];
  84.    
  85.    transparent = (UWORD *) AllocMem (transparent_size, MEMF_CHIP);
  86.    for (ix=0; ix<transparent_size/2; ++ix)
  87.       transparent[ix] = transparent_data[ix];
  88.  
  89.    rp = w->RPort;
  90.    if ((workspace = (PLANEPTR) AllocRaster (WWIDTH,WHEIGHT)) == NULL)  {
  91.       printf ("No space for Temporary Raster\n");
  92.       goto end4;
  93.    }
  94.    InitTmpRas (&mapTmpRas, workspace, RASSIZE(WWIDTH,WHEIGHT));
  95.    rp->TmpRas = &mapTmpRas;            /* link it to the RastPort */
  96.    InitArea (&mapAreaInfo, &areaArray[0], NUMPTS);
  97.    rp->AreaInfo = &mapAreaInfo;        /* link it to the RastPort */
  98.  
  99.    SetPointer (w, waiter, waiter_size/4-2, 16,
  100.                waiter_x_offset, waiter_y_offset);
  101.    if ((map = svector (0, MAXVAL-1)) == NULL)  {
  102.       printf ("Can't get space for map\n");
  103.       goto end5;
  104.    }
  105.    if ((ix = readmap (map, mapname, MAXVAL)) != OK)  { /* read map file */
  106.       printf ("Error reading map file\n");
  107.       goto end6;
  108.    }
  109.    if ((map_trig = svector (0, MAXVAL-1)) == NULL)  {
  110.       printf ("Can't get space for map_trig\n");
  111.       goto end6;
  112.    }
  113.    if ((ix = readmap (map_trig, mapname_trig, MAXVAL)) != OK)  { /* read map_trig file */
  114.       printf ("Error reading map-trig file\n");
  115.       goto end7;
  116.    }
  117.    if ((td = svector (0, MAXTIDY-1)) == NULL)  {
  118.       printf ("Can't get space for td\n");
  119.       goto end7;
  120.    }
  121.    if ((ix = readmap (td, tdname, MAXTIDY)) != OK)  {  /* read td file */
  122.       printf ("Error reading td file\n");
  123.       goto end8;
  124.    }
  125.    if ((td_trig = svector (0, MAXTIDY-1)) == NULL)  {
  126.       printf ("Can't get space for td_trig\n");
  127.       goto end8;
  128.    }
  129.    if ((ix = readmap (td_trig, tdname_trig, MAXTIDY)) != OK)  { /* read td_trig file */
  130.       printf ("Error reading td_trig file\n");
  131.       goto end9;
  132.    }
  133.    SetPointer (w, arrow, arrow_size/4-2, 16, arrow_x_offset, arrow_y_offset);
  134.  
  135.    SetAPen (rp,ORANGE);                /* land  */
  136.    SetBPen (rp,BLUE);                  /* water */
  137.    SetDrMd (rp,JAM2);
  138.  
  139.    InitTextRequest ();                 /* initialize the string requester */
  140.  
  141.    pi2 = pi/2.;                        /* initialize constants */
  142.    twopi = 2.*pi;
  143.    rad = pi/180.;
  144.    
  145.    view_height = VIEW_HEIGHT;          /* constants for globe view */
  146.    eta = view_height/RE;
  147.    facp = 1. + eta;
  148.    etap = 1./facp;
  149.    
  150.    for (ix=0; ix<DEPTH; ++ix)          /* initialize bitplane pointers */
  151.       bp[ix] = w->RPort->BitMap->Planes[ix];
  152.    ytable[0] = 0;                      /* initialize screen offsets */
  153.    rowoffset = WWIDTH/8;
  154.    for (ix=1; ix<WHEIGHT; ++ix)
  155.       ytable[ix] = ytable[ix-1] + rowoffset;
  156.    
  157.    WaitPort ( w->UserPort );           /* wait for message from */
  158.                                        /*   Intuition           */
  159.    while (1)  {
  160.       msg = (struct IntuiMessage *)GetMsg (w->UserPort);
  161.       if (msg==NULL)
  162.          WaitPort (w->UserPort);
  163.       else
  164.          if (HandleEvent (msg) != OK)
  165.             break;
  166.    }
  167.    
  168. end9:
  169.    free_svector (td_trig, 0, MAXTIDY-1); /* done, so clean up */
  170. end8:
  171.    free_svector (td, 0, MAXTIDY-1);
  172. end7:
  173.    free_svector (map_trig, 0, MAXVAL-1);
  174. end6:
  175.    free_svector (map, 0, MAXVAL-1);
  176. end5:
  177.    FreeRaster (workspace, WWIDTH, WHEIGHT);
  178. end4:
  179.    FreeMem (transparent, transparent_size);
  180.    FreeMem (cross, cross_size);
  181.    FreeMem (arrow, arrow_size);
  182.    FreeMem (waiter, waiter_size);
  183.    ClearPointer (w);
  184.    CloseWindow (w);
  185. end3:
  186.    CloseScreen (s);
  187. end2:
  188.    CloseLibrary (IntuitionBase);
  189. end1:
  190.    CloseLibrary (GfxBase);
  191. }
  192.  
  193. /* ============================================================= */
  194.  
  195. int readmap (ws, fname, num)                /* reads map files into memory */
  196.  
  197. short *ws;
  198. char *fname;
  199. int num;
  200.  
  201. {
  202.  
  203.    int ibin, disp, numrd;
  204.    
  205.    if ((ibin = open (fname, O_RDONLY)) == -1)
  206.       return (NOT_OK);
  207.    disp = 0;
  208.    while (1)  {
  209.       if ((numrd = read (ibin, (char*) &ws[disp], 4000)) <= 0)
  210.          break;
  211.       disp += numrd / sizeof(short);
  212.    }
  213.    close (ibin);
  214.    if (disp!=num)
  215.       return (NOT_OK);
  216.    return (OK);
  217. }
  218.  
  219. /* ============================================================= */
  220.  
  221. void InitTextRequest ()                /* initializes a string requester */
  222.  
  223. {
  224.    char *s, *t;   
  225.  
  226.    InitRequester (&req);               /* initialize the requester */
  227.    req.LeftEdge = TLEFT;
  228.    req.TopEdge = TTOP;
  229.    req.Width = TWIDTH;
  230.    req.Height = THEIGHT;
  231.    req.ReqGadget = &gad;
  232.    req.ReqText = &rtext;
  233.    req.BackFill = ORANGE;
  234.    req.Flags = 0;
  235.    req.ReqBorder = &border_top;
  236.  
  237.    s = &userinput[0];                  /* copy default text string */
  238.    t = &defaulttext[0];
  239.    while ((*s++ = *t++) != '\0')  ;
  240. }
  241.  
  242. /* ============================================================= */
  243.  
  244. int HandleEvent (msg)                  /* processes main Intuition events */
  245.  
  246. struct IntuiMessage *msg;
  247.  
  248. {
  249.  
  250.    struct IntuiMessage *msgf;
  251.    extern long PopChoose();
  252.    extern void fullmap(), globe(), stars(), floodfill(), getcoord();
  253.    extern void box(), grid(), shadow(), do_text();
  254.    extern int getbox();
  255.    static char title_FLAT[]     = "Flat Map";
  256.    static char title_MERCATOR[] = "Mercator";
  257.    static char title_GLOBE[]    = "Globe...view from infinitely far away";
  258.    static char title_ORBITAL[]  = "                                        "
  259.                                   "                                        ";
  260.    static char title_zoom[]     = "                                        "
  261.                                   "                                        ";
  262.    static char title_GRID[]     = "Grid";
  263.    static char title_FLOOD[]    = "Flood Fill";
  264.    static char title_SHADOW[]   = "Shadow";
  265.    static char title_BOX[]      = "Box";
  266.    static char title_COLORS[]   = "Colors";
  267.    static char title_TEXT[]     = "Text";
  268.    static char title_CLEARS[]   = "Clear Screen";
  269.    static char press_prompt[]   = "Press left button to select center point";
  270.    static char drag_prompt[]    = "Press and drag left button to select box";
  271.    static char flood_wait[]     = "Flood fill...press left button to select "
  272.                                   "area to fill";
  273.    static char box_error[]      = "Box of zero size not allowed";
  274.    static char grid_error[]     = "Invalid map displayed for Grid option";
  275.    static char fmt_ORBITAL[]    = "Orbital...view from %.2lf kilometers";
  276.    static char fmt_ZOOM_IN[]    = "Zoom In...view from %.2lf kilometers";
  277.    static char fmt_ZOOM_OUT[]   = "Zoom Out...view from %.2lf kilometers";
  278.    long val;
  279.    static long oldval = -1L;
  280.    static int fill = FILL;
  281.    static int color_offset = 0;
  282.    int i, x, y, x0, y0, result;
  283.    double lat[2], lam[2];
  284.    static double lamg, latg;
  285.    
  286.    switch (msg->Class) {
  287.    case CLOSEWINDOW:
  288.       return (NOT_OK);
  289.       break;
  290.    case MOUSEBUTTONS:
  291.       switch (msg->Code)  {
  292.       case MENUDOWN:
  293.          val = PopChoose (&map_menu, NULL);
  294.          switch (val)  {
  295.          case COLOR_F:                 /* toggle color-fill flag */
  296.             if (map_COLOR_F.Flags & CHECKED)
  297.                fill = FILL;
  298.             else
  299.                fill = NOFILL;
  300.             break;
  301.          case FLAT:                    /* flat map */
  302.             SetWindowTitles (w, title_FLAT, -1);
  303.             ModifyIDCMP (w, CLOSEWINDOW);
  304.             SetPointer (w, waiter, waiter_size/4-2, 16,
  305.                         waiter_x_offset, waiter_y_offset);
  306.             fullmap (map, FLAT, fill);
  307.             SetPointer (w, arrow, arrow_size/4-2, 16,
  308.                         arrow_x_offset, arrow_y_offset);
  309.             ModifyIDCMP (w, IDCMPFLAGS);
  310.             oldval = val;
  311.             break;
  312.          case MERCATOR:                /* Mercator map */
  313.             SetWindowTitles (w, title_MERCATOR, -1);
  314.             ModifyIDCMP (w, CLOSEWINDOW);
  315.             SetPointer (w, waiter, waiter_size/4-2, 16,
  316.                         waiter_x_offset, waiter_y_offset);
  317.             fullmap (map, MERCATOR, fill);
  318.             SetPointer (w, arrow, arrow_size/4-2, 16,
  319.                         arrow_x_offset, arrow_y_offset);
  320.             ModifyIDCMP (w, IDCMPFLAGS);
  321.             oldval = val;
  322.             break;
  323.          case GRID:
  324.             if (oldval!=FLAT     && oldval!=MERCATOR &&
  325.                 oldval!=GLOBE    && oldval!=ORBITAL  &&
  326.                 oldval!=ZOOM_IN  && oldval!=ZOOM_OUT)
  327.                SetWindowTitles (w, grid_error, -1);
  328.             else  {
  329.                SetWindowTitles (w, title_GRID, -1);
  330.                ModifyIDCMP (w, CLOSEWINDOW);
  331.                SetPointer (w, waiter, waiter_size/4-2, 16,
  332.                            waiter_x_offset, waiter_y_offset);
  333.                grid (oldval, latg, lamg);
  334.                SetPointer (w, arrow, arrow_size/4-2, 16,
  335.                         arrow_x_offset, arrow_y_offset);
  336.                ModifyIDCMP (w, IDCMPFLAGS);
  337.             }
  338.             break;
  339.          case ZOOM_IN:                 /* zoom views */
  340.          case ZOOM_OUT:
  341.             if (val==ZOOM_IN)  {
  342.                view_height /= 2.;
  343.                if (view_height<MIN_HEIGHT)
  344.                   view_height = MIN_HEIGHT;
  345.                sprintf (title_zoom, fmt_ZOOM_IN, view_height);
  346.             }
  347.             else  {
  348.                view_height *= 2.;
  349.                sprintf (title_zoom, fmt_ZOOM_OUT, view_height);
  350.             }
  351.             eta = view_height/RE;
  352.             facp = 1. + eta;
  353.             etap = 1./facp;
  354.          case GLOBE:                 /* globe views */
  355.          case ORBITAL:
  356.             if ( (val!=ZOOM_IN && val!=ZOOM_OUT) ||
  357.              (oldval!=ZOOM_IN && oldval!=ZOOM_OUT &&
  358.               oldval!=GLOBE   && oldval!=ORBITAL) )  {
  359.                SetWindowTitles (w, press_prompt, -1); /* wait for mouse button */
  360.                if (oldval!=FLAT && oldval!=MERCATOR)  {
  361.                   ModifyIDCMP (w, CLOSEWINDOW);
  362.                   SetPointer (w, waiter, waiter_size/4-2, 16,
  363.                               waiter_x_offset, waiter_y_offset);
  364.                   fullmap (map, FLAT, fill);
  365.                   ModifyIDCMP (w, IDCMPFLAGS);
  366.                   oldval = FLAT;
  367.                }
  368.                SetPointer (w, cross, cross_size/4-2, 16, 
  369.                            cross_x_offset, cross_y_offset);
  370.                WaitPort (w->UserPort);
  371.                while (1)  {
  372.                   msgf = (struct IntuiMessage *) GetMsg (w->UserPort);
  373.                   if (msgf==NULL)
  374.                      WaitPort (w->UserPort);
  375.                   else
  376.                      if (msgf->Code==SELECTDOWN)
  377.                         break;
  378.                }
  379.                x = msgf->MouseX;          /* get mouse position */
  380.                y = msgf->MouseY;
  381.                getcoord (x, y, oldval, &latg, &lamg);
  382.             }
  383.             if (val==ORBITAL)  {       /* re-initialize values for */
  384.                view_height = VIEW_HEIGHT; /* orbital view          */
  385.                eta = view_height/RE;
  386.                facp = 1. + eta;
  387.                etap = 1./facp;
  388.                sprintf (title_ORBITAL, fmt_ORBITAL, view_height);
  389.                SetWindowTitles (w, title_ORBITAL, -1);
  390.             }
  391.             else if (val==GLOBE)
  392.                SetWindowTitles (w, title_GLOBE, -1);
  393.             else
  394.                SetWindowTitles (w, title_zoom, -1);
  395.             ModifyIDCMP (w, CLOSEWINDOW);
  396.             SetPointer (w, waiter, waiter_size/4-2, 16,
  397.                         waiter_x_offset, waiter_y_offset);
  398.             Move (rp, 0, 0);
  399.             SetBPen (rp, BLACK);       /* black background */
  400.             ClearScreen (rp);
  401.             SetAPen (rp, BLUE);        /* blue globe */
  402.             DrawEllipse (rp, CENTERX, CENTERY, HRADIUS, VRADIUS);
  403.             Flood (rp, 1, CENTERX, CENTERY);
  404.             SetAPen (rp, ORANGE);      /* reset colors */
  405.             SetBPen (rp, BLUE);
  406.             globe (map, map_trig, latg, lamg, val, fill); /* draw map */
  407.             stars();
  408.             SetPointer (w, arrow, arrow_size/4-2, 16,
  409.                         arrow_x_offset, arrow_y_offset);
  410.             ModifyIDCMP (w, IDCMPFLAGS);
  411.             oldval = val;
  412.             break;
  413.          case FLOOD:                   /* flood fill */
  414.             SetWindowTitles (w, flood_wait, -1);
  415.             SetPointer (w, cross, cross_size/4-2, 16,
  416.                         cross_x_offset, cross_y_offset);
  417.             floodfill ();
  418.             SetPointer (w, arrow, arrow_size/4-2, 16,
  419.                         arrow_x_offset, arrow_y_offset);
  420.             SetWindowTitles (w, title_FLOOD, -1);
  421.             break;
  422.          case SHADOW:                  /* make shadows */
  423.             SetWindowTitles (w, title_SHADOW, -1);
  424.             ModifyIDCMP (w, CLOSEWINDOW);
  425.             SetPointer (w, waiter, waiter_size/4-2, 16,
  426.                         waiter_x_offset, waiter_y_offset);
  427.             shadow ();
  428.             SetPointer (w, arrow, arrow_size/4-2, 16,
  429.                         arrow_x_offset, arrow_y_offset);
  430.             ModifyIDCMP (w, IDCMPFLAGS);
  431.             break;
  432.          case BOX:                     /* box */
  433.             SetWindowTitles (w, drag_prompt, -1);
  434.             if (oldval!=FLAT && oldval!=MERCATOR)  {
  435.                ModifyIDCMP (w, CLOSEWINDOW);
  436.                SetPointer (w, waiter, waiter_size/4-2, 16,
  437.                            waiter_x_offset, waiter_y_offset);
  438.                fullmap (map, FLAT, fill);
  439.                ModifyIDCMP (w, IDCMPFLAGS);
  440.                oldval = FLAT;
  441.             }
  442.             SetPointer (w, cross, cross_size/4-2, 16,
  443.                         cross_x_offset, cross_y_offset);
  444.             result = getbox (&x0, &y0, &x, &y);
  445.             SetPointer (w, arrow, arrow_size/4-2, 16,
  446.                         arrow_x_offset, arrow_y_offset);
  447.             if (result!=OK)  {
  448.                SetWindowTitles (w, box_error, -1);
  449.                break;
  450.             }
  451.             SetWindowTitles (w, title_BOX, -1);
  452.             ModifyIDCMP (w, CLOSEWINDOW);
  453.             SetPointer (w, waiter, waiter_size/4-2, 16,
  454.                         waiter_x_offset, waiter_y_offset);
  455.             getcoord (x0, y0, oldval, &lat[0], &lam[0]);
  456.             getcoord (x, y, oldval, &lat[1], &lam[1]);
  457.             Move (rp, 0, 0);
  458.             ClearScreen (rp);
  459.             box (map, lat, lam, fill);
  460.             SetPointer (w, arrow, arrow_size/4-2, 16,
  461.                         arrow_x_offset, arrow_y_offset);
  462.             ModifyIDCMP (w, IDCMPFLAGS);
  463.             oldval = val;
  464.             break;
  465.          case COLORS:                  /* modify color table */
  466.             SetWindowTitles (w, title_COLORS, -1);
  467.             color_offset += 4;
  468.             if (color_offset>=num_colors)
  469.                color_offset = 0;
  470.             LoadRGB4 (vp, &mapcolors[color_offset], 4);
  471.             break;
  472.          case TEXT:                    /* get user text */
  473.             SetWindowTitles (w, title_TEXT, -1);
  474.             do_text (msg, val);
  475.             SetWindowTitles (w, title_TEXT, -1);
  476.             break;
  477.          case CLEARS:                  /* clear screen */
  478.             SetWindowTitles (w, title_CLEARS, -1);
  479.             Move (rp, 0, 0);
  480.             ClearScreen (rp);
  481.             oldval = val;
  482.             break;
  483.          default:
  484.             if (map_COLOR_F.Flags & CHECKED)
  485.                fill = FILL;
  486.             else
  487.                fill = NOFILL;
  488.             break;
  489.          }
  490.          break;
  491.       default:
  492.          break;
  493.       }
  494.    default:
  495.       break;
  496.    }
  497.    return (OK);
  498. }
  499.  
  500. /* ============================================================= */
  501.  
  502. void fullmap (ws, type, fill)          /* draws flat map projections */
  503.  
  504. short *ws;
  505. int type, fill;
  506.  
  507. {
  508.  
  509.    extern void afill(), adraw(), plotpoint();
  510.    int i, j, k, h1, h2, narea;
  511.    double t;
  512.    long pen;
  513.    short np, xs, ys;
  514.    
  515.    Move (rp, 0, 0);                    /* clear screen */
  516.    ClearScreen (rp);
  517.    j = 0;
  518.    np = 0;
  519.    narea = 0;
  520.    pen = ORANGE;
  521.    SetAPen (rp, pen);
  522.    for (i=0; i<MAXVAL; i+=2)  {
  523.       if (ws[i]==0 && ws[i+1]==0)  {   /* check for end of area */
  524.          ++narea;
  525.          pen = ORANGE;
  526.          for (k=0; k<num_lakes; ++k)  {
  527.             if (narea==lakes[k])  {
  528.                pen = BLUE;
  529.                break;
  530.             }
  531.          }
  532.          SetAPen (rp, pen);
  533.          if (np<=1)  {
  534.             xs = CENTERX + area[j-2];
  535.             ys = CENTERY + area[j-1];
  536.             plotpoint (xs, ys);
  537.          }
  538.          else  {
  539.             if (fill==FILL)
  540.                afill (np, pen);
  541.             else
  542.                adraw (np);
  543.          }
  544.          j = 0;
  545.          np = 0;
  546.          area[0] = 0;
  547.          area[1] = 0;
  548.          pen = ORANGE;
  549.          SetAPen (rp, pen);
  550.       }
  551.       else  {                          /* get coords of new point */
  552.          t = ws[i];                    /* y = latitude */
  553.          if (type==FLAT)
  554.             t = (t/100.) * VFACTOR;
  555.          else if (type==MERCATOR)  {
  556.             t = (t/200. + 45.) * rad;
  557.             t = log (tan (t)) * M_VFACTOR;
  558.          }
  559.          if (t<0.)
  560.             t -= 0.5;
  561.          else
  562.             t += 0.5;
  563.          h2 = -t;
  564.          t = ws[i+1];                  /* x = longitude */
  565.          t = (t/100.) * HFACTOR;
  566.          if (t<0.)
  567.             t -= 0.5;
  568.          else
  569.             t += 0.5;
  570.          h1 = t;
  571.          if (np!=0)  {                 /* disallow identical adjacent pts */
  572.             if (h1==area[j-2] && h2==area[j-1])
  573.                continue;
  574.          }
  575.          xs = CENTERX + h1;
  576.          ys = CENTERY + h2;
  577.          plotpoint (xs, ys);
  578.          area[j] = h1;
  579.          area[j+1] = h2;
  580.          j += 2;
  581.          ++np;
  582.       }
  583.    }
  584.    if (np>0)  {                        /* check for last area */
  585.       pen = ORANGE;
  586.       SetAPen (rp, pen);
  587.       if (np==1)  {
  588.          xs = CENTERX + area[j-2];
  589.          ys = CENTERY + area[j-1];
  590.          plotpoint (xs, ys);
  591.       }
  592.       else  {
  593.          if (fill==FILL)
  594.             afill (np, pen);
  595.          else
  596.             adraw (np);
  597.       }
  598.    }
  599.    SetAPen (rp, ORANGE);
  600. }
  601.  
  602. /* ============================================================= */
  603.  
  604. void grid (val, lat0, lam0)            /* controls drawing of grids */
  605.  
  606. long val;
  607. double lat0, lam0;
  608.  
  609. {
  610.  
  611.    extern void globe_grid();
  612.    long oldpen, h1;
  613.    double lam, lat, temp;
  614.    static double lat_interval = 20.;
  615.    static double lam_interval = 30.;
  616.  
  617.    oldpen = rp->FgPen;                 /* save original pen color */
  618.    if (val!=FLAT && val!=MERCATOR)     /* draw grid for globe     */
  619.       globe_grid (val, lat0, lam0);
  620.    else  {                             /* otherwise grid for flat */
  621.                                        /*   or Mercator map       */
  622.       SetAPen (rp, BLACK);             /* set grid color to black */
  623.       for (lam=-180.; lam<=+180.; lam += lam_interval)  {
  624.          h1 = lam*HFACTOR + CENTERX;
  625.          Move (rp, h1, 0);
  626.          Draw (rp, h1, WHEIGHT-1);
  627.       }
  628.       for (lat=80.; lat>=-80.; lat -= lat_interval)  {
  629.          if (val==FLAT)
  630.             h1 = -lat*VFACTOR;
  631.          else
  632.             h1 = -log (tan((lat/2.+45.)*rad)) * M_VFACTOR;
  633.          h1 += CENTERY;
  634.          Move (rp, 0, h1);
  635.          Draw (rp, WWIDTH-1, h1);
  636.       }
  637.       SetAPen (rp, WHITE);             /* draw coordinate axes in white */
  638.       Move (rp, CENTERX, 0);
  639.       Draw (rp, CENTERX, WHEIGHT-1);
  640.       Move (rp, 0, CENTERY);
  641.       Draw (rp, WWIDTH-1, CENTERY);
  642.    }
  643.    SetAPen (rp, oldpen);               /* restore pen color */
  644. }
  645.  
  646. /* ============================================================= */
  647.  
  648. void globe_grid (val, lat0, lam0)      /* controls drawing globe grid */
  649.  
  650. double lat0, lam0;
  651. long val;
  652.  
  653. {
  654.  
  655.    extern void globe_grid_plot();
  656.    extern int limit_lam(), limit_lat();
  657.    double lat, lam, c0, s0, c1, s1, c2, s2, rlam, rlat;
  658.    double hp, scale, fac3, dlat, dlam, ddelt;
  659.    double lamp[2], latp[2];
  660.    int k;
  661.    long oldpen;
  662.    char first;
  663.    static double lat_interval = 20.;
  664.    static double lam_interval = 30.;
  665.    static double delta = 5.;
  666.    
  667.    lat0 *= rad;
  668.    c0 = cos (lat0);
  669.    s0 = sin (lat0);
  670.    dlat = lat_interval;
  671.    dlam = lam_interval;
  672.    ddelt = delta;
  673.    if (val==GLOBE)  {                  /* ordinary globe view */
  674.       hp = 0.;
  675.       scale = 1.;
  676.       fac3 = 1.;
  677.    }
  678.    else  {                             /* orbital view */
  679.       hp = etap;
  680.       scale = sqrt (1.-etap*etap);
  681.       fac3 = (facp/(facp-hp)) * scale;
  682.       if (view_height<=1200.)  {
  683.          dlat /= 4.;
  684.          dlam /= 4.;
  685.          ddelt /= 5.;
  686.       }
  687.    }
  688.    SetAPen (rp, BLACK);                /* grid lines in black */
  689.    for (lat=80.; lat>=-80.; lat-=dlat)  {  /* lines of equal latitude */
  690.       rlat = lat*rad;
  691.       if ((k=limit_lam (&lamp[0], rlat, lat0, hp))!=OK)
  692.          continue;                     /* skip if entirely out of view */
  693.       lamp[0] += lam0;
  694.       lamp[1] += lam0;
  695.       k = lamp[0]/ddelt - 1.;          /* express limits as multiple */
  696.       lamp[0] = k*ddelt;               /*   of ddelt                 */
  697.       k = lamp[1]/ddelt + 1.;
  698.       lamp[1] = k*ddelt;
  699.       c1 = cos (rlat);
  700.       s1 = sin (rlat);
  701.       first = TRUE;
  702.       if (lat==0.)
  703.          SetAPen (rp, WHITE);          /* draw equator in white */
  704.       for (lam=lamp[0]; lam<=lamp[1]; lam+=ddelt)  {
  705.          rlam = (lam-lam0)*rad;
  706.          if (rlam<-pi)
  707.             rlam += twopi;
  708.          if (rlam>+pi)
  709.             rlam -= twopi;
  710.          c2 = cos (rlam);
  711.          s2 = sin (rlam);
  712.          globe_grid_plot (rlat, rlam, c0, s0, c1, s1, c2, s2,
  713.                           val, hp, scale, fac3, &first);
  714.       }
  715.       if (lat==0.)
  716.          SetAPen (rp, BLACK);          /* reset pen to black */
  717.    }
  718.    for (lam=-180.; lam<+180.; lam+=dlam)  {  /* meridian circles */
  719.       rlam = (lam-lam0)*rad;
  720.       if (rlam<-pi)
  721.          rlam += twopi;
  722.       if (rlam>+pi)
  723.          rlam -= twopi;
  724.       if ((k=limit_lat (&latp[0], lat0, rlam, hp))!=OK)
  725.          continue;                     /* skip if entirely out of view */
  726.       k = latp[0]/ddelt + 1.;          /* express limits as multiple */
  727.       latp[0] = k*ddelt;               /*   of ddelt                 */
  728.       k = latp[1]/ddelt - 1;
  729.       latp[1] = k*ddelt;
  730.       if (latp[0]>=90.)                /* exclude North polar point */
  731.          latp[0] = 90. - ddelt;
  732.       if (latp[1]<=-90.)               /* exclude South polar point */
  733.          latp[1] = -90. + ddelt;
  734.       c2 = cos (rlam);
  735.       s2 = sin (rlam);
  736.       first = TRUE;
  737.       if (lam==0. || lam==-180.)       /* prime meridian in white */
  738.          SetAPen (rp, WHITE);
  739.       for (lat=latp[0]; lat>=latp[1]; lat-=ddelt)  {
  740.          rlat = lat*rad;
  741.          c1 = cos (rlat);
  742.          s1 = sin (rlat);
  743.          globe_grid_plot (rlat, rlam, c0, s0, c1, s1, c2, s2,
  744.                           val, hp, scale, fac3, &first);
  745.       }
  746.       if (lam==0. || lam==-180.)
  747.          SetAPen (rp, BLACK);          /* reset pen to black */
  748.    }
  749. }
  750.  
  751. /* ============================================================= */
  752.  
  753. void globe_grid_plot (lat, lam, c0, s0, c1, s1, c2, s2,
  754.                       val, hp, scale, fac3, first)
  755.  
  756. double lat, lam, c0, s0, c1, s1, c2, s2;   /* draws globe grids */
  757. long val;
  758. double hp, scale, fac3;
  759. char *first;
  760.  
  761. {
  762.  
  763.    extern void plotpoint(), globe_rim_fix();
  764.    char in_view;
  765.    short h1, h1c;                      /* x-dist. (pix) from center */
  766.    short h2, h2c;                      /* y-dist. (pix) from center */
  767.    short xs, ys;
  768.    long x, y;
  769.    double lamc, dlam;                  /* longitude */
  770.    double latc, dlat;                  /* latitude  */
  771.    double zp, facz, h1d, h2d, fac2;
  772.    static char prev_in_view;
  773.    static short h1prev, h2prev;
  774.    static double latprev, lamprev, zpprev;
  775.    
  776.    in_view = FALSE;                    /* get status of current point */
  777.    zp = s1*s0 + c1*c0*c2;
  778.    if (zp>=hp)  {                      /* zp > hp => in view */
  779.       in_view = TRUE;
  780.       h1d = HRADIUS * c1 * s2;
  781.       h2d = -VRADIUS * (s1*c0 - c1*s0*c2);
  782.       if (val!=GLOBE)  {
  783.          fac2 = (facp/(facp-zp))*scale;
  784.          h1d *= fac2;
  785.          h2d *= fac2;
  786.       }
  787.       h1 = h1d;
  788.       h2 = h2d;
  789.    }
  790.    if (*first==TRUE)  {                /* get status of first point */
  791.       *first = FALSE;
  792.       if (in_view==TRUE)  {            /* if first point is in view, */
  793.          x = h1 + CENTERX;             /*   move pen to first point  */
  794.          y = h2 + CENTERY;             /*   and plot it              */
  795.          Move (rp, x, y);
  796.          xs = x;
  797.          ys = y;
  798.          plotpoint (xs, ys);
  799.          h1prev = h1;
  800.          h2prev = h2;
  801.       }
  802.       prev_in_view = in_view;          /* save status of first point */
  803.       latprev = lat;
  804.       lamprev = lam;
  805.       zpprev = zp;
  806.       return;
  807.    }
  808.    if (in_view==TRUE)  {               /* if current point is in view, */
  809.       if (prev_in_view==FALSE)  {      /*   but previous point was not */
  810.          facz = zp / (zpprev-zp);      /*   in view, get rim point by  */
  811.          latc = lat - (latprev-lat)*facz; /* linear interpolation      */
  812.          lamc = lam - (lamprev-lam)*facz;
  813.          dlat = fabs (lat-latprev);
  814.          dlam = fabs (lam-lamprev);
  815.          if ( fabs (latc-latprev)> dlat || /* if rim point not between */
  816.               fabs (latc-lat)    > dlat)   /*   current and previous   */
  817.             latc = (lat+latprev)/2.;       /*   points, use midpoint   */
  818.          if ( fabs (lamc-lamprev)> dlam ||
  819.               fabs (lamc-lam)    > dlam )
  820.             lamc = (lam+lamprev)/2.;
  821.          c1 = cos (latc);
  822.          h1d = HRADIUS * c1 * sin (lamc);
  823.          h2d = -VRADIUS * (sin (latc)*c0 - c1*s0*cos (lamc));
  824.          if (val!=GLOBE)  {
  825.             h1d *= fac3;
  826.             h2d *= fac3;
  827.          }
  828.          h1c = h1d;
  829.          h2c = h2d;
  830.          globe_rim_fix (&h1c, &h2c);
  831.          x = h1c + CENTERX;            /* move to rim point & plot it */
  832.          y = h2c + CENTERY;
  833.          Move (rp, x, y);
  834.          xs = x;
  835.          ys = y;
  836.          plotpoint (xs, ys);
  837.          h1prev = h1c;
  838.          h2prev = h2c;
  839.       }
  840.       if (h1!=h1prev || h2!=h2prev)  {
  841.          x = h1 + CENTERX;             /* draw to current point */
  842.          y = h2 + CENTERY;
  843.          Draw (rp, x, y);
  844.          Move (rp, x, y);
  845.       }
  846.       h1prev = h1;
  847.       h2prev = h2;
  848.    }
  849.    else  {                             /* current point is out of view   */
  850.       if (prev_in_view==TRUE)  {       /* if previous point was in view, */
  851.          facz = zp / (zpprev-zp);      /*   get rim point by linear      */
  852.          latc = lat - (latprev-lat)*facz; /* interpolation               */
  853.          lamc = lam - (lamprev-lam)*facz;
  854.          dlat = fabs (lat-latprev);
  855.          dlam = fabs (lam-lamprev);
  856.          if ( fabs (latc-latprev)> dlat || /* if rim point not between */
  857.               fabs (latc-lat)    > dlat)   /*   current and previous   */
  858.             latc = (lat+latprev)/2.;       /*   points, use midpoint   */
  859.          if ( fabs (lamc-lamprev)> dlam ||
  860.               fabs (lamc-lam)    > dlam )
  861.             lamc = (lam+lamprev)/2.;
  862.          c1 = cos (latc);         
  863.          h1d = HRADIUS * c1 * sin (lamc);
  864.          h2d = -VRADIUS * (c0*sin (latc) - c1*s0 * cos (lamc));
  865.          if (val!=GLOBE)  {
  866.             h1d *= fac3;
  867.             h2d *= fac3;
  868.          }
  869.          h1c = h1d;
  870.          h2c = h2d;
  871.          globe_rim_fix (&h1c, &h2c);
  872.          x = h1c + CENTERX;            /* draw to rim point */
  873.          y = h2c + CENTERY;
  874.          Draw (rp, x, y);
  875.          Move (rp, x, y);
  876.       }
  877.    }
  878.    prev_in_view = in_view;             /* save status of current point */
  879.    latprev = lat;
  880.    lamprev = lam;
  881.    zpprev = zp;
  882. }
  883.  
  884. /* ============================================================= */
  885.  
  886. int limit_lam (lam, lat, lat0, etap)   /* computes limits on longitude */
  887.                                        /*   for constant latitude      */
  888. double *lam, lat, lat0, etap;
  889.  
  890. {
  891.    double alpha;
  892.    
  893.    alpha = (etap-sin(lat)*sin(lat0)) / (cos(lat)*cos(lat0));
  894.    if (alpha<=-1.)  {                  /* negative => lamda covers */
  895.       lam[0] = -180.;                  /*   entire hemisphere      */
  896.       lam[1] = +180.;
  897.       return (OK);
  898.    }
  899.    else if (alpha>=+1.)                /* positive => nothing in view */
  900.       return (NOT_OK);
  901.    else  {                             /* otherwise, compute limits */
  902.       lam[0] = -acos (alpha)/rad;
  903.       lam[1] = -lam[0];
  904.       return (OK);
  905.    }
  906. }
  907.  
  908. /* ============================================================= */
  909.  
  910. int limit_lat (lat, lat0, lam, etap)   /* computes limits on latitude */
  911.                                        /*   for constant longitude    */
  912. double *lat, lat0, lam, etap;
  913.  
  914. {
  915.    double radical, a, b, sum, fac1;
  916.    
  917.    a = sin (lat0);
  918.    b = cos (lat0) * cos (lam);
  919.    sum = a*a + b*b;
  920.    radical = sum - etap*etap;
  921.    if (radical<=0.)                    /* no real solutions */
  922.       return (NOT_OK);
  923.    else  {                             /* two real solutions      */
  924.       radical = sqrt (radical);        /* solve quadrtic equation */
  925.       fac1 = (a*etap + b*radical)/sum;
  926.       lat[0] = asin (fac1)/rad;
  927.       fac1 = (a*etap - b*radical)/sum;
  928.       lat[1] = asin (fac1)/rad;
  929.       if (lat[0]<lat[1])  {            /* put in correct order */
  930.          b = lat[0];
  931.          lat[0] = lat[1];
  932.          lat[1] = b;
  933.       }
  934.       if (a>etap)                      /* check North pole */
  935.          lat[0] = 90.;
  936.       if (a<-etap)                     /* check South pole */
  937.          lat[1] = -90.;
  938.       return (OK);
  939.    }
  940. }
  941.  
  942. /* ============================================================= */
  943.  
  944. void getcoord (x, y, val, lat, lam)    /* converts screen coordinates   */
  945.                                        /*   into latitude and longitude */
  946. int x, y;
  947. long val;
  948. double *lat, *lam;
  949.  
  950. {
  951.  
  952.    (*lam) = (x - CENTERX) / HFACTOR;
  953.    if (val==FLAT)
  954.       (*lat) = (CENTERY - y) / VFACTOR;
  955.    else
  956.       (*lat) = -90. + 2.*atan(exp((CENTERY-y)/M_VFACTOR))/rad;
  957. }
  958.  
  959. /* ============================================================= */
  960.  
  961. void globe (ws, ws_trig, lat0, lam0, val, fill) /* draws globe projections */
  962.  
  963. short *ws, *ws_trig;
  964. double lat0, lam0;
  965. long val;
  966. int fill;
  967.  
  968. {
  969.  
  970.    extern void plotpoint(), globe_fill(), globe_rim_fix(), globe_tidy();
  971.    char first, prev_in_view, in_view, latzero;
  972.    short h1, h1c, h1prev;              /* x-dist. (pix) from center */
  973.    short h2, h2c, h2prev;              /* y-dist. (pix) from center */
  974.    short np, narea, nrim_in, nrim_out;
  975.    short xs, ys;
  976.    int i, j;
  977.    long x, y, pen, first_color;
  978.    double lam, lamc, lamprev;          /* longitude */
  979.    double lat, latc, latprev;          /* latitude  */
  980.    double c0, s0, c1, s1, c2, zp, zpprev;
  981.    double hp, fac2, fac3, facz, scale;
  982.    double h1d, h2d, dlat, dlam, lat0p;
  983.    static double fac = 1./32767.0;
  984.  
  985.    latzero = FALSE;
  986.    if (val==GLOBE)  {                  /* ordinary globe view */
  987.       hp = 0.;
  988.       scale = 1.;
  989.       fac3 = 1.;
  990.    }
  991.    else  {                             /* orbital globe view */
  992.       hp = etap;
  993.       scale = sqrt (1.-etap*etap);
  994.       fac3 = (facp/(facp-hp)) * scale;
  995.    }
  996.    if (lat0==0.)  {
  997.       c0 = 1.;
  998.       s0 = 0.;
  999.       if (val==GLOBE)
  1000.          latzero = TRUE;               /* equatorial, ordinary globe view */
  1001.    }
  1002.    else  {
  1003.       lat0p = lat0 * rad;
  1004.       c0 = cos (lat0p);
  1005.       s0 = sin (lat0p);
  1006.    }
  1007.    first = TRUE;
  1008.    pen = ORANGE;
  1009.    SetAPen (rp, pen);
  1010.    first_color = BLACK;
  1011.    j = 0;
  1012.    np = 0;
  1013.    narea = 0;
  1014.    nrim_in = 0;
  1015.    nrim_out = 0;
  1016.    for (i=0; i<MAXVAL; i+=2)  {
  1017.       if (ws[i]==0 && ws[i+1]==0)  {   /* if end of area, then     */
  1018.          ++narea;                      /*   color-fill and skip to */
  1019.          first = TRUE;                 /*    next area             */
  1020.          if (np>0 && fill==FILL)
  1021.             globe_fill (np, narea, nrim_in, nrim_out, first_color);
  1022.          j = 0;
  1023.          np = 0;
  1024.          nrim_in = 0;
  1025.          nrim_out = 0;
  1026.          first_color = BLACK;
  1027.          continue;
  1028.       }
  1029.       lat = ws[i];                     /* latitude */
  1030.       lat = (lat/100.) * rad;
  1031.       lam = ws[i+1];                   /* longitude */
  1032.       lam = (lam/100. - lam0) * rad;
  1033.       if (lam<-pi)
  1034.          lam += twopi;
  1035.       if (lam>pi)
  1036.          lam -= twopi;
  1037.       c1 = ws_trig[i];                 /* cosine of latitude */
  1038.       c1 *= fac;
  1039.       s1 = ws_trig[i+1];               /* sine of latitude */
  1040.       s1 *= fac;
  1041.       in_view = FALSE;                 /* get status of current point */
  1042.       if (latzero==TRUE)  {            /* equatorial globe view */
  1043.          zp = c1*cos (lam);
  1044.          if (lam>=-pi2 && lam<=+pi2)  {
  1045.             in_view = TRUE;
  1046.             h1 = HRADIUS * c1 * sin (lam);
  1047.             h2 = -VRADIUS * s1;
  1048.          }
  1049.       }
  1050.       else  {                          /* oblique earth view */
  1051.          c2 = cos (lam);
  1052.          zp = s1*s0 + c1*c0*c2;
  1053.          if (zp>=hp)  {                /* zp > hp => in view */
  1054.             in_view = TRUE;
  1055.             h1d = HRADIUS * c1 * sin (lam);
  1056.             h2d = -VRADIUS * (s1*c0 -c1*s0*c2);
  1057.             if (val!=GLOBE)  {
  1058.                fac2 = (facp/(facp-zp)) * scale;
  1059.                h1d *= fac2;
  1060.                h2d *= fac2;
  1061.             }
  1062.             h1 = h1d;
  1063.             h2 = h2d;
  1064.          }
  1065.       }
  1066.       if (first==TRUE)  {              /* get status of first point */
  1067.          first = FALSE;
  1068.          if (in_view==TRUE)  {         /* if first point is in view, */
  1069.             x = h1 + CENTERX;          /*   move pen to first point  */
  1070.             y = h2 + CENTERY;          /*   and plot it              */
  1071.             Move (rp, x, y);
  1072.             first_color = ReadPixel (rp, x, y);
  1073.             xs = x;
  1074.             ys = y;
  1075.             plotpoint (xs, ys);
  1076.             h1prev = h1;
  1077.             h2prev = h2;
  1078.             area[0] = h1;              /* save first point for later use */
  1079.             area[1] = h2;
  1080.             j = 2;
  1081.             np = 1;
  1082.          }
  1083.          prev_in_view = in_view;       /* save status of first point */
  1084.          latprev = lat;
  1085.          lamprev = lam;
  1086.          zpprev = zp;
  1087.          continue;
  1088.       }
  1089.       if (in_view==TRUE)  {            /* if current point is in view, */
  1090.          if (prev_in_view==FALSE)  {   /*   but previous point was not */
  1091.             facz = zp / (zpprev-zp);   /*   in view, get rim point by  */
  1092.             latc = lat - (latprev-lat)*facz; /* linear interpolation   */
  1093.             lamc = lam - (lamprev-lam)*facz;
  1094.             dlat = fabs (lat-latprev);
  1095.             dlam = fabs (lam-lamprev);
  1096.             if ( fabs (latc-latprev)> dlat || /* if rim point not between */
  1097.                  fabs (latc-lat)    > dlat)   /*   current and previous   */
  1098.                latc = (lat+latprev)/2.;       /*   point, use midpoint    */
  1099.             if ( fabs (lamc-lamprev)> dlam ||
  1100.                  fabs (lamc-lam)    > dlam )
  1101.                lamc = (lam+lamprev)/2.;
  1102.             if (latzero==TRUE)  {
  1103.                h1c = HRADIUS * cos (latc) * sin (lamc);
  1104.                h2c = -VRADIUS * sin (latc);
  1105.             }
  1106.             else  {
  1107.                c1 = cos (latc);
  1108.                h1d = HRADIUS * c1 * sin (lamc);
  1109.                h2d = -VRADIUS * (sin (latc)*c0 - c1*s0*cos (lamc));
  1110.                if (val!=GLOBE)  {
  1111.                   h1d *= fac3;
  1112.                   h2d *= fac3;
  1113.                }
  1114.                h1c = h1d;
  1115.                h2c = h2d;
  1116.             }
  1117.             globe_rim_fix (&h1c, &h2c); /* correct the computed rim point */
  1118.             x = h1c + CENTERX;         /* move to rim point & plot it */
  1119.             y = h2c + CENTERY;
  1120.             Move (rp, x, y);
  1121.             xs = x;
  1122.             ys = y;
  1123.             plotpoint (xs, ys);
  1124.             h1prev = h1c;
  1125.             h2prev = h2c;
  1126.             area[j] = h1;              /* save coords of rim point */
  1127.             area[j+1] = h2;
  1128.             j += 2;
  1129.             ++nrim_in;
  1130.             ++np;
  1131.          }
  1132.          if (h1!=h1prev || h2!=h2prev)  {
  1133.             x = h1 + CENTERX;          /* draw to current point */
  1134.             y = h2 + CENTERY;
  1135.             Draw (rp, x, y);
  1136.             Move (rp, x, y);
  1137.             area[j] = h1;              /* save coords of current point */
  1138.             area[j+1] = h2;
  1139.             j += 2;
  1140.             ++np;
  1141.          }
  1142.          h1prev = h1;
  1143.          h2prev = h2;
  1144.       }
  1145.       else  {                          /* current point is out of view   */
  1146.          if (prev_in_view==TRUE)  {    /* if previous point was in view, */
  1147.             facz = zp / (zpprev-zp);   /*   get rim point by linear      */
  1148.             latc = lat - (latprev-lat)*facz; /* interpolation            */
  1149.             lamc = lam - (lamprev-lam)*facz;
  1150.             dlat = fabs (lat-latprev);
  1151.             dlam = fabs (lam-lamprev);
  1152.             if ( fabs (latc-latprev)> dlat || /* if rim point not between */
  1153.                  fabs (latc-lat)    > dlat)   /*   current and previous   */
  1154.                latc = (lat+latprev)/2.;       /*   point, use midpoint    */
  1155.             if ( fabs (lamc-lamprev)> dlam ||
  1156.                  fabs (lamc-lam)    > dlam )
  1157.                lamc = (lam+lamprev)/2.;
  1158.             if (latzero==TRUE)  {
  1159.                h1c = HRADIUS * cos (latc) * sin (lamc);
  1160.                h2c = -VRADIUS * sin (latc);
  1161.             }
  1162.             else  {
  1163.                c1 = cos (latc);
  1164.                h1d = HRADIUS * c1 * sin (lamc);
  1165.                h2d = -VRADIUS * (c0*sin(latc) - c1*s0 * cos(lamc));
  1166.                if (val!=GLOBE)  {
  1167.                   h1d *= fac3;
  1168.                   h2d *= fac3;
  1169.                }
  1170.                h1c = h1d;
  1171.                h2c = h2d;
  1172.             }
  1173.             globe_rim_fix (&h1c, &h2c); /* correct the computed rim point */ 
  1174.             x = h1c + CENTERX;         /* draw to rim point */
  1175.             y = h2c + CENTERY;
  1176.             Draw (rp, x, y);
  1177.             Move (rp, x, y);
  1178.             area[j] = h1;              /* save coords of rim point */
  1179.             area[j+1] = h2;
  1180.             j += 2;
  1181.             ++nrim_out;
  1182.             ++np;
  1183.          }
  1184.       }
  1185.       prev_in_view = in_view;          /* save status of current point */
  1186.       latprev = lat;
  1187.       lamprev = lam;
  1188.       zpprev = zp;
  1189.    }
  1190.    if (fill == FILL)
  1191.       globe_tidy (td, td_trig, lat0, lam0, val);
  1192. }
  1193.  
  1194. /* ============================================================= */
  1195.  
  1196. void globe_fill (np, narea, nrim_in, nrim_out, first_color)
  1197.                                        /* fills area on globe */
  1198.  
  1199. short np, narea, nrim_in, nrim_out;
  1200. long first_color;
  1201.  
  1202. {
  1203.  
  1204.    extern void plotpoint ();
  1205.    int k;
  1206.    long x, y;
  1207.    short xs, ys;
  1208.    char is_lake;
  1209.    static long pen = ORANGE;
  1210.  
  1211.    if (nrim_in!=nrim_out)
  1212.       return;
  1213.    if (nrim_in==0)  {                  /* fill areas with no rim points */
  1214.       is_lake = FALSE;
  1215.       for (k=0; k<num_lakes; ++k)      /* check for lake */
  1216.          if (narea==lakes[k])  {
  1217.             if (first_color==ORANGE)  {
  1218.                pen = BLUE;             /* make lake blue if drawn */
  1219.                is_lake = TRUE;         /*   into orange           */
  1220.                break;
  1221.             }
  1222.             else                       /* don't color-fill if drawn */
  1223.                return;                 /*   into blue               */
  1224.          }
  1225.       xs = CENTERX + area[0];
  1226.       ys = CENTERY + area[1];
  1227.       if (np==1)
  1228.          plotpoint (xs, ys);
  1229.       else if (np>=GLOBE_FILL_MIN)
  1230.          afill (np, pen);
  1231.       if (is_lake==TRUE)
  1232.          pen = ORANGE;
  1233.    }
  1234. }
  1235.  
  1236. /* ============================================================= */
  1237.  
  1238. void globe_rim_fix (h1, h2)            /* find nearest actual rim point */
  1239.  
  1240. short *h1, *h2;
  1241.  
  1242. {
  1243.  
  1244.    short inc1, inc2;
  1245.    int i;
  1246.    long x, y, color;
  1247.    static int itmax = 20;
  1248.    
  1249.    if ((*h1)>=0)                       /* right half */
  1250.       inc1 = +1;
  1251.    else                                /* left half */
  1252.       inc1 = -1;
  1253.    if ((*h2)>=0)                       /* bottom half */
  1254.       inc2 = +1;
  1255.    else                                /* top half */
  1256.       inc2 = -1;
  1257.    x = (*h1) + CENTERX + 5*inc1;       /* coords of test pixel */
  1258.    y = (*h2) + CENTERY + 5*inc2;
  1259.    for (i=0; i<itmax; ++i)  {          /* look for nearest black pixel */
  1260.       if ((color = ReadPixel (rp, x, y))==BLACK)
  1261.          break;
  1262.       x += inc1;
  1263.       y += inc2;
  1264.    }
  1265.    x -= inc1;
  1266.    y -= inc2;
  1267.    for (i=0; i<itmax; ++i)  {          /* look back for previous blue one */
  1268.       if ((color = ReadPixel (rp, x, y))==BLUE || color==ORANGE)
  1269.          break;
  1270.       x -= inc1;
  1271.       y -= inc2;
  1272.    }
  1273.    (*h1) = x - CENTERX;
  1274.    (*h2) = y - CENTERY;
  1275. }
  1276.  
  1277. /* ============================================================= */
  1278.  
  1279. void globe_tidy (td, td_trig, lat0, lam0, val)
  1280.  
  1281. short *td, *td_trig;                   /* color-fills partially-drawn */
  1282. double lat0, lam0;                     /*   regions                    */
  1283. long val;
  1284.  
  1285. {
  1286.  
  1287.    int i;
  1288.    double lat, lam, c0, s0, c1, s1, c2;
  1289.    double zp, hp, scale, fac2, fac3, h1d, h2d;
  1290.    short h1, h2;
  1291.    long x, y, color;
  1292.    static double fac = 1./32767.0;
  1293.    
  1294.    if (val==GLOBE)  {                  /* ordinary globe view */
  1295.       hp = 0.;
  1296.       scale = 1.;
  1297.       fac3 = 1.;
  1298.    }
  1299.    else  {                             /* orbital globe view */
  1300.       hp = etap;
  1301.       scale = sqrt (1.-etap*etap);
  1302.       fac3 = (facp/(facp-hp)) * scale;
  1303.    }
  1304.    lat0 *= rad;
  1305.    c0 = cos (lat0);
  1306.    s0 = sin (lat0);
  1307.    i = 0;
  1308.    while (1)  {
  1309.       if (td[i]==0 && td[i+1]==0)      /* check for end of array */
  1310.          break;
  1311.       lat = td[i];                     /* latitude */
  1312.       lat = (lat/100.) * rad;
  1313.       lam = td[i+1];                   /* longitude */
  1314.       lam = (lam/100.-lam0) * rad;
  1315.       if (lam<-pi)
  1316.          lam += twopi;
  1317.       if (lam>pi)
  1318.          lam -= twopi;
  1319.       c1 = td_trig[i];
  1320.       c1 *= fac;
  1321.       s1 = td_trig[i+1];
  1322.       s1 *= fac;
  1323.       c2 = cos (lam);
  1324.       zp = s1*s0 + c1*c0*c2;
  1325.       if (zp>=hp)  {                   /* in view, so get screen coords */
  1326.          h1d = HRADIUS * c1 * sin (lam);
  1327.          h2d = -VRADIUS * (s1*c0-c1*s0*c2);
  1328.          if (val!=GLOBE)  {            /* orbital view */
  1329.             fac2 = (facp/(facp-zp)) * scale;
  1330.             h1d *= fac2;
  1331.             h2d *= fac2;
  1332.          }
  1333.          h1 = h1d;                     /* flood fill */
  1334.          h2 = h2d;
  1335.          x = h1 + CENTERX;
  1336.          y = h2 + CENTERY;
  1337.          if ((color = ReadPixel (rp, x, y)) == BLUE)
  1338.             Flood (rp, 1, x, y);
  1339.       }
  1340.       i += 2;
  1341.    }
  1342. }
  1343.  
  1344. /* ============================================================= */
  1345.  
  1346. void stars ()                          /* draws stars into black background */
  1347.  
  1348. {
  1349.  
  1350.    extern double ran();
  1351.    static int nmax = 150;
  1352.    double t;
  1353.    short x, y;
  1354.    int i, nstars;
  1355.    long oldpen, color;
  1356.   
  1357.    oldpen = rp->FgPen;
  1358.    SetAPen (rp, WHITE);
  1359.    nstars = 0;
  1360.    for (i=0; ; ++i)  {
  1361.       t = ran();
  1362.       x = t * WWIDTH + 0.5;
  1363.       t = ran();
  1364.       y = t * WHEIGHT + 0.5;
  1365.       if (x<0)
  1366.          x = 0;
  1367.       if (x>WWIDTH-1)
  1368.          x = WWIDTH-1;
  1369.       if (y<0)
  1370.          y = 0;
  1371.       if (y>WHEIGHT-1)
  1372.          y = WHEIGHT-1;
  1373.       if ((color = ReadPixel (rp, x, y)) == BLACK)  {
  1374.          WritePixel (rp, x, y);
  1375.          ++nstars;
  1376.          if (nstars>=nmax)
  1377.             break;
  1378.       }
  1379.    }
  1380.    SetAPen (rp, oldpen);
  1381. }
  1382.  
  1383. /* ============================================================= */
  1384.  
  1385. void floodfill ()                      /* flood fills an area based */
  1386.                                        /*   on mouse position       */
  1387. {
  1388.    struct IntuiMessage *msgf;
  1389.    short x, y;
  1390.    long color;
  1391.    
  1392.    WaitPort (w->UserPort);             /* wait for message */
  1393.    while (1)  {
  1394.       msgf = (struct IntuiMessage *) GetMsg (w->UserPort);
  1395.       if (msgf==NULL)
  1396.          WaitPort (w->UserPort);
  1397.       else
  1398.          if (msgf->Code==SELECTDOWN)
  1399.             break;
  1400.    }
  1401.    x = msgf->MouseX;                   /*  get mouse coordinates  */
  1402.    y = msgf->MouseY;                   /*    and flood fill       */
  1403.    if ((color = ReadPixel (rp, x, y))==BLUE)
  1404.       Flood (rp, 1, x, y);
  1405. }
  1406.  
  1407. /* ============================================================= */
  1408.  
  1409. void shadow ()                         /* makes shadowed screens */
  1410.  
  1411. {
  1412.    int modb0, modb1, color0, color1;
  1413.    int acolor0, acolor1, bcolor0, bcolor1;
  1414.    int j, k, k1, k2, m, bitlast;
  1415.    unsigned int byte0, byte1;
  1416.    unsigned int byte0b0, byte1b0, byte0b1, byte1b1;
  1417.    long color;
  1418.    static int blackcolor0, blackcolor1, disp;
  1419.    static int bluecolor0, bluecolor1, Ocolor0, Ocolor1;
  1420.    static unsigned int bitval[] = {1, 2, 4, 8, 16, 32, 64, 128};
  1421.    static char first = NOT_OK;
  1422.  
  1423.    if (first==NOT_OK)  {               /* initialize color values once */
  1424.       first = OK;
  1425.       color = BLACK;
  1426.       blackcolor0 = color&1L;
  1427.       blackcolor1 = (color&2L)>>1;
  1428.       color = BLUE;
  1429.       bluecolor0 = color&1L;
  1430.       bluecolor1 = (color&2L)>>1;
  1431.       color = ORANGE;
  1432.       Ocolor0 = color&1L;
  1433.       Ocolor1 = (color&2L)>>1;
  1434.       disp = SHADOW_DISP * rowoffset;  /* offset to shadowed row */
  1435.    }
  1436.    for (k=ytable[10]; k<ytable[WHEIGHT-SHADOW_DISP-1]; k+=rowoffset)  {
  1437.                                        /* do each row                  */
  1438.       k2 = k + disp;                   /* displacement to shadowed row */
  1439.       for (j=0; j<rowoffset; ++j)  {   /* do each byte in row          */
  1440.          byte0 = bp[0][k+j];           /* current row, planes 0 and 1  */
  1441.          byte1 = bp[1][k+j];
  1442.          byte0b0 = bp[0][k2+j];        /* shadowed row, planes 0 and 1 */
  1443.          byte1b0 = bp[1][k2+j];
  1444.          byte0b1 = bp[0][k2+j+1];      /* shadowed row, adjacent byte, */
  1445.          byte1b1 = bp[1][k2+j+1];      /*   planes 0 and 1             */
  1446.                                        /* if last byte in row, don't   */
  1447.                                        /*   need adjacent bytes        */
  1448.          ((j<rowoffset-1) ? (bitlast=0) : (bitlast=SHADOW_DISP));
  1449.          modb0 = NOT_OK;
  1450.          modb1 = NOT_OK;
  1451.          for (m=7; m>=bitlast; --m)  { /* check each bit, left to right */
  1452.             color0 = BITVAL(byte0,m);  /* current pixel color           */
  1453.             color1 = BITVAL(byte1,m);
  1454.             if (color0==Ocolor0 && color1==Ocolor1)  {
  1455.                if (m>SHADOW_DISP-1)  {           /* get color of pixel in   */
  1456.                   bcolor0 = BITVAL(byte0b0,m-SHADOW_DISP);  /* shadowed row */
  1457.                   bcolor1 = BITVAL(byte1b0,m-SHADOW_DISP);
  1458.                }
  1459.                else  {                 /* use adjacent byte */
  1460.                   bcolor0 = BITVAL(byte0b1,m+8-SHADOW_DISP);
  1461.                   bcolor1 = BITVAL(byte1b1,m+8-SHADOW_DISP);
  1462.                }
  1463.                if (bcolor0==bluecolor0 && bcolor1==bluecolor1)  {
  1464.                   if (m>SHADOW_DISP-1)  {  /* if blue, set color to black */
  1465.                      BITSTORE(byte0b0,m-SHADOW_DISP,blackcolor0);
  1466.                      BITSTORE(byte1b0,m-SHADOW_DISP,blackcolor1);
  1467.                      modb0 = OK;
  1468.                   }
  1469.                   else  {              /* use adjacent byte */
  1470.                      BITSTORE(byte0b1,m+8-SHADOW_DISP,blackcolor0);
  1471.                      BITSTORE(byte1b1,m+8-SHADOW_DISP,blackcolor1);
  1472.                      modb1 = OK;
  1473.                   }
  1474.                }
  1475.             }
  1476.          }                             /* end bit test */
  1477.          if (modb0==OK)  {             /* restore only modified bytes */
  1478.             bp[0][k2+j] = byte0b0;
  1479.             bp[1][k2+j] = byte1b0;
  1480.          }
  1481.          if (modb1==OK)  {
  1482.             bp[0][k2+j+1] = byte0b1;
  1483.             bp[1][k2+j+1] = byte1b1;
  1484.          }
  1485.       }                                /* end of row */
  1486.    }                                   /* last row   */
  1487. }
  1488.  
  1489. /* ============================================================= */
  1490.  
  1491. int getbox (x0, y0, x, y)              /* selects a region to draw to */
  1492.                                        /*   larger scale              */
  1493. int *x0, *y0, *x, *y;
  1494.  
  1495. {
  1496.  
  1497.    extern void drawbox();
  1498.    struct IntuiMessage *msgf;
  1499.    int xd, yd, x1, x2, y1, y2;
  1500.    char selectbutton;
  1501.    
  1502.    selectbutton = FALSE;
  1503.    SetDrMd (rp, JAM2 | COMPLEMENT);    /* turn on complement mode and */
  1504.    ModifyIDCMP (w, IDCMPFLAGS | MOUSEMOVE); /* enable mouse events    */
  1505.    WaitPort (w->UserPort);
  1506.    while (1)  {
  1507.       msgf = (struct IntuiMessage *) GetMsg (w->UserPort);
  1508.       if (msgf==NULL)
  1509.          WaitPort (w->UserPort);
  1510.       else if (msgf->Code==SELECTDOWN)  { /* if user pressed left button, */
  1511.          x1 = msgf->MouseX;               /*   get initial mouse position */
  1512.          y1 = msgf->MouseY;
  1513.          xd = x1;
  1514.          yd = y1;
  1515.          selectbutton = TRUE;
  1516.       }
  1517.       else if (selectbutton==TRUE && msgf->Class==MOUSEMOVE)  {
  1518.          x2 = msgf->MouseX;
  1519.          y2 = msgf->MouseY;
  1520.          drawbox (x1, y1, xd, yd);     /* erase old box */
  1521.          xd = x2;
  1522.          yd = y2;
  1523.          drawbox (x1, y1, xd, yd);     /* draw new box */
  1524.       }
  1525.       else if (selectbutton==TRUE && msgf->Code==SELECTUP)
  1526.          break;
  1527.    }
  1528.    x2 = msgf->MouseX;                  /* erase current box */
  1529.    y2 = msgf->MouseY;
  1530.    drawbox (x1, y1, xd, yd);
  1531.    SetDrMd (rp, JAM2);                 /* restore original drawing mode */
  1532.    ModifyIDCMP (w, IDCMPFLAGS);        /*   and disable mouse events    */
  1533.    *x0 = x1;
  1534.    *y0 = y1;
  1535.    *x = x2;
  1536.    *y = y2;
  1537.    if (x1==x2 || y1==y2)               /* error if box is of zero area */
  1538.       return (NOT_OK);
  1539.    if (x1>x2 && y1>y2)  {              /* ensure that the vertices of */
  1540.       *x0 = x2;                        /*   the box are in the proper */
  1541.       *y0 = y2;                        /*   order                     */
  1542.       *x = x1;
  1543.       *y = y1;
  1544.    }
  1545.    else if (x1<x2 && y1>y2)  {
  1546.       *x0 = x1;
  1547.       *y0 = y2;
  1548.       *x = x2;
  1549.       *y = y1;
  1550.    }
  1551.    else if (x1>x2 && y1<y2)  {
  1552.       *x0 = x2;
  1553.       *y0 = y1;
  1554.       *x = x1;
  1555.       *y = y2;
  1556.    }
  1557.    return (OK);
  1558. }
  1559.  
  1560. /* ============================================================= */
  1561.  
  1562. void drawbox (x1, y1, x2, y2)          /* draws a box */
  1563.  
  1564. int x1, y1, x2, y2;
  1565.  
  1566. {
  1567.  
  1568.    Move (rp, x1, y1);
  1569.    Draw (rp, x2, y1);
  1570.    Move (rp, x2, y1);
  1571.    Draw (rp, x2, y2);
  1572.    Move (rp, x2, y2);
  1573.    Draw (rp, x1, y2);
  1574.    Move (rp, x1, y2);
  1575.    Draw (rp, x1, y1);
  1576.    Move (rp, x1, y1);
  1577. }
  1578.  
  1579. /* ============================================================= */
  1580.  
  1581. void box (ws, latp, lamp, fill)        /* draws areas contained within */
  1582.                                        /*   a rectangular region       */
  1583. short *ws;
  1584. double *latp, *lamp;
  1585. int fill;
  1586.  
  1587. {
  1588.  
  1589.    extern void plotpoint(), drawbox(), box_tidy();
  1590.    char first, prev_in_view, in_view, is_lake;
  1591.    short h1, h1c, h1prev;              /* x-dist. (pix) from center */
  1592.    short h2, h2c, h2prev;              /* y-dist. (pix) from center */
  1593.    short np, xs, ys, nrim_in, nrim_out;
  1594.    int i, j, k, narea;
  1595.    long x, y, pen, first_color;
  1596.    double lam, lamc, lamprev;          /* longitude */
  1597.    double lat, latc, latprev;          /* latitude  */
  1598.    double bwidth, bheight, bcx, bcy, xscale, yscale;
  1599.    double lat1, lat2, lam1, lam2;
  1600.  
  1601.    lat1 = latp[0];                     /* store values for box corners */
  1602.    lat2 = latp[1];                     /*   locally                    */
  1603.    lam1 = lamp[0];
  1604.    lam2 = lamp[1];
  1605.    bwidth = lam2 - lam1;               /* box width (degrees)         */
  1606.    bheight = lat1 - lat2;              /* box height (degrees)        */
  1607.    bcx = (lam1 + lam2)/2.;             /* x-coord of box center (deg) */
  1608.    bcy = (lat1 + lat2)/2.;             /* y-coord of box center (deg) */
  1609.    xscale = WWIDTH / bwidth;           /* horizontal scale (pix/deg)  */
  1610.    yscale = (WHEIGHT-10) / bheight;    /* vertical scale (pix/deg)    */
  1611.    j = 0;
  1612.    np= 0;
  1613.    narea = 0;
  1614.    first = TRUE;
  1615.    pen = ORANGE;
  1616.    SetAPen (rp, pen);
  1617.    first_color = BLACK;
  1618.  
  1619.    drawbox (0, 0, WWIDTH-1, WHEIGHT-10); /* outline the box */
  1620.  
  1621.    for (i=0; i<MAXVAL; i+=2)  {
  1622.       if (ws[i]==0 && ws[i+1]==0)  {   /* if end of area, then */
  1623.          ++narea;
  1624.          if (np>0 && fill==FILL)  {    /* color-fill if requested */
  1625.             if (nrim_in==0)  {
  1626.                is_lake = FALSE;
  1627.                for (k=0; k<num_lakes; ++k)
  1628.                   if (narea==lakes[k])  {
  1629.                      is_lake = TRUE;
  1630.                      if (first_color==ORANGE)
  1631.                         pen = BLUE;
  1632.                      break;
  1633.                   }
  1634.                if (is_lake==FALSE || (is_lake==TRUE && pen==BLUE))  {
  1635.                   xs = CENTERX + area[0];
  1636.                   ys = CENTERY + area[1];
  1637.                   if (np==1)
  1638.                      plotpoint (xs, ys);
  1639.                   else
  1640.                      afill (np, pen);
  1641.                }
  1642.             }
  1643.          }
  1644.          j = 0;
  1645.          np = 0;
  1646.          nrim_in = 0;
  1647.          nrim_out = 0;
  1648.          pen = ORANGE;
  1649.          first_color = BLACK;
  1650.          first = TRUE;
  1651.          continue;                     /* skip to next point */
  1652.       }
  1653.       lat = ws[i];                     /* latitude */
  1654.       lat = lat/100.;
  1655.       lam = ws[i+1];                   /* longitude */
  1656.       lam = lam/100.;
  1657.       in_view = FALSE;                 /* get status of current point */
  1658.       if ( (lat<=lat1 && lat>=lat2)
  1659.         && (lam>=lam1 && lam<=lam2))  {
  1660.          in_view = TRUE;
  1661.          h1 = (lam-bcx) * xscale;
  1662.          h2 = - (lat-bcy) * yscale;
  1663.       }
  1664.       if (first==TRUE)  {              /* check first point */
  1665.          first = FALSE;
  1666.          if (in_view==TRUE)  {         /* if first point is in view, */
  1667.             x = h1 + CENTERX;          /*   move pen to first point  */
  1668.             y = h2 + CENTERY;          /*   and plot it              */
  1669.             Move (rp, x, y);
  1670.             first_color = ReadPixel (rp, x, y);
  1671.             xs = x;
  1672.             ys = y;
  1673.             plotpoint (xs, ys);
  1674.             h1prev = h1;
  1675.             h2prev = h2;
  1676.             area[0] = h1;
  1677.             area[1] = h2;
  1678.             j = 2;
  1679.             np = 1;
  1680.          }
  1681.          prev_in_view = in_view;       /* save status of first point */
  1682.          latprev = lat;
  1683.          lamprev = lam;
  1684.          continue;
  1685.       }
  1686.       if (in_view==TRUE)  {
  1687.          if (prev_in_view==FALSE)  {   /* if prev. point was not in view, */
  1688.             if (lamprev<=lam1)  {      /*   find rim point                */
  1689.                lamc = lam1;
  1690.                if (latprev<=lat2)      /* lower left */
  1691.                   latc = lat2;
  1692.                else if (latprev>=lat1) /* upper left */
  1693.                   latc = lat1;
  1694.                else                    /* left center */
  1695.                   latc = lat + (latprev-lat)*(lamc-lam)/(lamprev-lam);
  1696.             }
  1697.             else if (lamprev>=lam2)  {
  1698.                lamc = lam2;
  1699.                if (latprev>=lat1)      /* upper right */
  1700.                   latc = lat1;
  1701.                else if (latprev<=lat2) /* lower right */
  1702.                   latc = lat2;
  1703.                else                    /* right center */
  1704.                   latc = lat + (latprev-lat)*(lamc-lam)/(lamprev-lam);
  1705.             }
  1706.             else  {
  1707.                if (latprev>=lat1)      /* top center */
  1708.                   latc = lat1;
  1709.                else                    /* bottom center */
  1710.                   latc = lat2;
  1711.                lamc = lam + (lamprev-lam)*(latc-lat)/(latprev-lat);
  1712.             }
  1713.             h1c = (lamc-bcx) * xscale;
  1714.             h2c = - (latc-bcy) * yscale;
  1715.             x = h1c + CENTERX;         /* move to rim point & plot it */
  1716.             y = h2c + CENTERY;
  1717.             Move (rp, x, y);
  1718.             xs = x;
  1719.             ys = y;
  1720.             plotpoint (xs, ys);
  1721.             h1prev = h1c;
  1722.             h2prev = h2c;
  1723.             area[j] = h1;
  1724.             area[j+1] = h2;
  1725.             j += 2;
  1726.             ++nrim_in;
  1727.             ++np;
  1728.          }
  1729.          if (h1!=h1prev || h2!=h2prev)  {
  1730.             x = h1 + CENTERX;          /* draw to current point */
  1731.             y = h2 + CENTERY;
  1732.             Draw (rp, x, y);
  1733.             Move (rp, x, y);
  1734.             area[j] = h1;
  1735.             area[j+1] = h2;
  1736.             j += 2;
  1737.             ++np;
  1738.          }
  1739.          h1prev = h1;
  1740.          h2prev = h2;
  1741.       }
  1742.       else  {                          /* else out of view */
  1743.          if (prev_in_view==TRUE)  {    /* if previous point was in view, */
  1744.             if (lam<=lam1)  {          /*   find rim point                */
  1745.                lamc = lam1;
  1746.                if (lat<=lat2)          /* lower left */
  1747.                   latc = lat2;
  1748.                else if (lat>=lat1)     /* upper left */
  1749.                   latc = lat1;
  1750.                else                    /* left center */
  1751.                   latc = lat + (latprev-lat)*(lamc-lam)/(lamprev-lam);
  1752.             }
  1753.             else if (lam>=lam2)  {
  1754.                lamc = lam2;
  1755.                if (lat>=lat1)          /* upper right */
  1756.                   latc = lat1;
  1757.                else if (lat<=lat2)     /* lower right */
  1758.                   latc = lat2;
  1759.                else                    /* right center */
  1760.                   latc = lat + (latprev-lat)*(lamc-lam)/(lamprev-lam);
  1761.             }
  1762.             else  {
  1763.                if (lat>=lat1)          /* top center */
  1764.                   latc = lat1;
  1765.                else                    /* bottom center */
  1766.                   latc = lat2;
  1767.                lamc = lam + (lamprev-lam)*(latc-lat)/(latprev-lat);
  1768.             }
  1769.             h1c = (lamc-bcx) * xscale;
  1770.             h2c = - (latc-bcy) * yscale;
  1771.             x = h1c + CENTERX;         /* draw to rim point */
  1772.             y = h2c + CENTERY;
  1773.             Draw (rp, x, y);
  1774.             Move (rp, x, y);
  1775.             area[j] = h1;
  1776.             area[j+1] = h2;
  1777.             j += 2;
  1778.             ++nrim_out;
  1779.             ++np;
  1780.          }
  1781.       }
  1782.       prev_in_view = in_view;          /* save status of current point */
  1783.       latprev = lat;
  1784.       lamprev = lam;
  1785.    }
  1786.    if (fill==FILL)
  1787.       box_tidy (lat1, lam1, lat2, lam2, /* fill partial areas */
  1788.                 bcx, bcy, xscale, yscale);
  1789. }
  1790.  
  1791. /* ============================================================= */
  1792.  
  1793. void box_tidy (lat1, lam1, lat2, lam2, bcx, bcy, xscale, yscale)
  1794.                                        /* color-fills partially-drawn */
  1795.                                        /*   areas in box-view         */
  1796. double lat1, lam1, lat2, lam2, bcx, bcy, xscale, yscale;
  1797.  
  1798. {
  1799.    double lat, lam;
  1800.    int i;
  1801.    short h1, h2;
  1802.    long x, y, color;
  1803.    
  1804.    i = 0;
  1805.    while (1)  {                        /* check each special point */
  1806.       if (td[i]==0 && td[i+1]==0)      /* if end of special points, */
  1807.          break;                        /*   then all done           */
  1808.       lat = td[i];
  1809.       lat /= 100.;
  1810.       lam = td[i+1];
  1811.       lam /= 100.;
  1812.       if ((lat<=lat1 && lat>=lat2) &&  /* if point is in view,  */
  1813.           (lam>=lam1 && lam<=lam2))  { /*   then get its screen */
  1814.          h1 = (lam-bcx) * xscale;      /*   coordinates         */
  1815.          h2 = -(lat-bcy) * yscale;
  1816.          x = h1 + CENTERX;             /* color-fill if current color */
  1817.          y = h2 + CENTERY;             /*   is blue                   */
  1818.          if ((color = ReadPixel (rp, x, y)) == BLUE)
  1819.             Flood (rp, 1, x, y);
  1820.       }
  1821.       i += 2;
  1822.    }
  1823. }
  1824.  
  1825. /* ============================================================= */
  1826.  
  1827. void do_text (msgin, val)              /* get user text input */
  1828.  
  1829. struct IntuiMessage *msgin;
  1830. long val;
  1831.  
  1832. {
  1833.    extern void drawbox();
  1834.    struct IntuiMessage *msg, *msg1;
  1835.    struct Gadget *g;
  1836.    static char title_setdown[] = "Press Select button to position text";
  1837.    int x, y, xold, yold, pixlength;
  1838.    long oldpen;
  1839.    
  1840.    x = msgin->MouseX - GAD_LEFT-8;     /* position the requester */
  1841.    y = msgin->MouseY - GAD_TOP-12 + 10*val + POPTITLEHEIGHT;
  1842.    if ((x+TWIDTH) >= WWIDTH)
  1843.       x = WWIDTH-TWIDTH-15;
  1844.    if (x < 10)
  1845.       x =10;
  1846.    if ((y+THEIGHT) >= WHEIGHT)
  1847.       y = WHEIGHT-THEIGHT-15;
  1848.    if (y<5)
  1849.       y = 5;
  1850.    req.LeftEdge = x;
  1851.    req.TopEdge = y;
  1852.    Request (&req, w);                  /* issue the request */
  1853.    ModifyIDCMP (w, GADGETUP);          /* disable all but gadgetup event */
  1854.    ActivateGadget (&gad, w, &req);
  1855.    WaitPort (w->UserPort);             /* wait for gadgetup event */
  1856.    while (1)  {
  1857.       msg = (struct IntuiMessage *) GetMsg (w->UserPort);
  1858.       if (msg == NULL)
  1859.          WaitPort (w->UserPort);
  1860.       else if (msg->Class == GADGETUP)  { /* check for correct gadget */
  1861.          g = (struct Gadget *) (msg->IAddress);
  1862.          if (g->GadgetID != GAD_FIRST)
  1863.             continue;
  1864.          pixlength = TextLength (rp, userinput, strlen(userinput));
  1865.          SetWindowTitles (w, title_setdown, -1);
  1866.          SetDrMd (rp, JAM2 | COMPLEMENT);
  1867.          SetPointer (w, transparent, transparent_size/4-2, 16,
  1868.                      transparent_x_offset, transparent_y_offset);
  1869.          xold = msg->MouseX;           /* current mouse position */
  1870.          yold = msg->MouseY;
  1871.          drawbox (xold, yold, xold+pixlength, yold-10);
  1872.          ModifyIDCMP (w, IDCMPFLAGS | MOUSEMOVE);
  1873.          WaitPort (w->UserPort);       /* wait for mouse button  */
  1874.          while (1)  {
  1875.             msg1 = (struct IntuiMessage *) GetMsg (w->UserPort);
  1876.             if (msg1 == NULL)
  1877.                WaitPort (w->UserPort);
  1878.             else  {
  1879.                x = msg1->MouseX;       /* get current mouse position */
  1880.                y = msg1->MouseY;       /*   and erase old box        */
  1881.                if (msg1->Code == SELECTDOWN)  {
  1882.                   drawbox (xold, yold, xold+pixlength, yold-10);
  1883.                   break;               /* done if select button pressed */
  1884.                }
  1885.                else if (msg1->Class == MOUSEMOVE)  {
  1886.                   ReplyMsg (msg1);     /* else draw box at current position */
  1887.                   drawbox (xold, yold, xold+pixlength, yold-10);
  1888.                   drawbox (x, y, x+pixlength, y-10);
  1889.                   xold = x;
  1890.                   yold = y;
  1891.                }
  1892.             }
  1893.          }
  1894.          ReplyMsg (msg1);
  1895.          Move (rp, x, y);              /* move to current mouse position */
  1896.          SetDrMd (rp, JAM1);
  1897.          oldpen = rp->FgPen;
  1898.          SetAPen (rp, WHITE);          /* draw text in WHITE */
  1899.          Text (rp, userinput, strlen(userinput));
  1900.          SetAPen (rp, oldpen);
  1901.          SetDrMd (rp, JAM2);
  1902.          ModifyIDCMP (w, IDCMPFLAGS);  /* enable original event types */
  1903.          SetPointer (w, arrow, arrow_size/4-2, 16,
  1904.                      arrow_x_offset, arrow_y_offset);
  1905.          break;
  1906.       }
  1907.    }
  1908.    ReplyMsg (msg);
  1909. }
  1910.  
  1911. /* ================================================================ */
  1912.  
  1913. void afill (pairs, pen)                /* draws and fills a region  */
  1914.                                        /*   using AreaDraw function */
  1915. short pairs;                            /* how many pairs of words */
  1916. long pen;                              /* pen number to use       */
  1917.  
  1918. {
  1919.  
  1920.    short i, j;
  1921.    long x, y, oldpen;
  1922.  
  1923.    oldpen = rp->FgPen;
  1924.    SetAPen (rp, pen);
  1925.    x = area[0] + CENTERX;
  1926.    y = area[1] + CENTERY;
  1927.    if (x<0)
  1928.       x = 0;
  1929.    if (x>WWIDTH-1)
  1930.       x = WWIDTH-1;
  1931.    if (y<0)
  1932.       y = 0;
  1933.    if (y>WHEIGHT-1)
  1934.       y = WHEIGHT-1;
  1935.    AreaMove (rp, x, y);
  1936.    j = 2;
  1937.    for (i=1; i<pairs; i++)  {
  1938.       if (area[j]==0 && area[j+1]==0)
  1939.          break;
  1940.       x = area[j] + CENTERX;
  1941.       y = area[j+1] + CENTERY;
  1942.       if (x<0)
  1943.          x = 0;
  1944.       if (x>WWIDTH-1)
  1945.          x = WWIDTH-1;
  1946.       if (y<0)
  1947.          y = 0;
  1948.       if (y>WHEIGHT-1)
  1949.          y = WHEIGHT-1;
  1950.       AreaDraw (rp, x, y);
  1951.       j += 2;
  1952.    }   
  1953.    AreaEnd (rp);
  1954.    SetAPen (rp, oldpen);
  1955. }
  1956.  
  1957. /* ============================================================= */
  1958.  
  1959. void adraw (pairs)                     /* draws area outlines */
  1960.  
  1961. short pairs;
  1962.  
  1963. {
  1964.  
  1965.    short i, j;
  1966.    long x, y, oldpen;
  1967.    
  1968.    oldpen = rp->FgPen;
  1969.    SetAPen (rp, ORANGE);
  1970.    x = area[0] + CENTERX;
  1971.    y = area[1] + CENTERY;
  1972.    if (x<0)
  1973.       x = 0;
  1974.    if (x>WWIDTH-1)
  1975.       x = WWIDTH-1;
  1976.    if (y<0)
  1977.       y = 0;
  1978.    if (y>WHEIGHT-1)
  1979.       y = WHEIGHT-1;
  1980.    Move (rp, x, y);
  1981.    j = 2;
  1982.    for (i=1; i<pairs; ++i)  {
  1983.       if (area[j]==0 && area[j+1]==0)
  1984.          break;
  1985.       x = area[j] + CENTERX;
  1986.       y = area[j+1] + CENTERY;
  1987.       if (x<0)
  1988.          x = 0;
  1989.       if (x>WWIDTH-1)
  1990.          x = WWIDTH-1;
  1991.       if (y<0)
  1992.          y = 0;
  1993.       if (y>WHEIGHT-1)
  1994.          y = WHEIGHT-1;
  1995.       Draw (rp, x, y);
  1996.       Move (rp, x, y);
  1997.       j += 2;
  1998.    }
  1999.    SetAPen (rp, oldpen);
  2000. }
  2001.  
  2002. /* ============================================================= */
  2003.  
  2004. void plotpoint (x, y)                  /* plots a single point */
  2005.  
  2006. short x, y;
  2007.  
  2008. {
  2009.  
  2010.    if (x<0)
  2011.       x = 0;
  2012.    if (x>WWIDTH-1)
  2013.       x = WWIDTH-1;
  2014.    if (y<0)
  2015.       y = 0;
  2016.    if (y>WHEIGHT-1)
  2017.       y = WHEIGHT-1;
  2018.    WritePixel (rp, x, y);
  2019. }
  2020.  
  2021. /* ============================================================= */
  2022.  
  2023. short *svector (nl,nh)                 /* Allocates a short vector */
  2024.                                        /*   with range [nl..nh]    */
  2025. int nl, nh;
  2026.  
  2027. {
  2028.    extern char *calloc();
  2029.    extern void errors();
  2030.    short *v;
  2031.  
  2032.    v = (short*) calloc (1, (unsigned) (nh-nl+1)*sizeof(short));
  2033.    if (v==NULL)
  2034.       return (NULL);
  2035.    else
  2036.       return v-nl;
  2037. }
  2038.  
  2039. /* ============================================================= */
  2040.  
  2041. void free_svector (v,nl,nh)            /* Frees a short vector   */
  2042.                                        /*   allocated by svector */
  2043. short *v;
  2044. int nl, nh;
  2045.  
  2046. {
  2047.  
  2048.    free ((char*) (v+nl));
  2049. }
  2050.