Logo Search packages:      
Sourcecode: ibp version File versions  Download package

xdisp.c

/*  IBP - show which beacon of the International Beacon Project is active now
 *
 *  Parts copyright (C) 2000, Pieter-Tjerk de Boer -- pa3fwm@amsat.org
 *  Other copyrights are mentioned in the course of this file.
 *
 *  Distributed on the conditions of the Gnu Public Licence, version 2.
 *
 *  This file (xdisp.c) contains all code related to the X11 windows
 *  support.
 */

/* Note: this file consists of several files from the sunclock program
 * concatenated together, so everything except for the bitmap data is
 * in one file.
 * Some copyright and author notices appear around line 223 in this file, at
 * the beginning of the former sunclock.c.
 * Lots of code that were not needed for ibp have been removed, although
 * bits and pieces of unused code may still remain; new code has been
 * added at the end.
 */


#define large_map_width 640
#define large_map_height 320
const char large_map_bits[]
#include "large.bits.h"

/*
 * $Id: sunclock.h,v 1.2 1999/04/07 14:00:57 wg Exp $
 * Sun clock definitions.
 */

#include <X11/Xlib.h>
#include <X11/Xutil.h>

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <assert.h>



#define abs(x) ((x) < 0 ? (-(x)) : x)                   /* Absolute value */
#define sgn(x) (((x) < 0) ? -1 : ((x) > 0 ? 1 : 0))     /* Extract sign */
#define dtr(x) ((x) * (PI / 180.0))               /* Degree->Radian */
#define rtd(x) ((x) * (180.0 / PI))               /* Radian->Degree */
#define fixangle(a) ((a) - 360.0 * (floor((a) / 360.0)))  /* Fix angle    */

#define PI 3.14159265358979323846

#define TERMINC  100             /* Circle segments for terminator */

#define PROJINT  (60 * 10)       /* Frequency of seasonal recalculation
                              in seconds. */




/*
 * Sun clock - astronomical routines.  (formerly astro.c)
 */

/*  JDATE  --  Convert internal GMT date and time to Julian day
             and fraction.  */

long
jdate(t)
struct tm *t;
{
      long c, m, y;

      y = t->tm_year + 1900;
      m = t->tm_mon + 1;
      if (m > 2)
         m = m - 3;
      else {
         m = m + 9;
         y--;
      }
      c = y / 100L;              /* Compute century */
      y -= 100L * c;
      return t->tm_mday + (c * 146097L) / 4 + (y * 1461L) / 4 +
          (m * 153L + 2) / 5 + 1721119L;
}

/* JTIME --    Convert internal GMT  date  and  time  to  astronomical
             Julian  time  (i.e.   Julian  date  plus  day fraction,
             expressed as a double).      */

double
jtime(t)
struct tm *t;
{
      return (jdate(t) - 0.5) + 
         (((long) t->tm_sec) +
           60L * (t->tm_min + 60L * t->tm_hour)) / 86400.0;
}

/*  KEPLER  --    Solve the equation of Kepler.  */

double
kepler(m, ecc)
double m, ecc;
{
      double e, delta;
#define EPSILON 1E-6

      e = m = dtr(m);
      do {
         delta = e - ecc * sin(e) - m;
         e -= delta / (1 - ecc * cos(e));
      } while (abs(delta) > EPSILON);
      return e;
}

/*  SUNPOS  --    Calculate position of the Sun.      JD is the Julian  date
            of  the  instant for which the position is desired and
            APPARENT should be nonzero if  the  apparent  position
            (corrected  for  nutation  and aberration) is desired.
                The Sun's co-ordinates are returned  in  RA  and  DEC,
            both  specified  in degrees (divide RA by 15 to obtain
            hours).  The radius vector to the Sun in  astronomical
                units  is returned in RV and the Sun's longitude (true
            or apparent, as desired) is  returned  as  degrees  in
            SLONG.      */

void
sunpos(jd, apparent, ra, dec, rv, slong)
double jd;
int apparent;
double *ra, *dec, *rv, *slong;
{
      double t, t2, t3, l, m, e, ea, v, theta, omega,
             eps;

      /* Time, in Julian centuries of 36525 ephemeris days,
         measured from the epoch 1900 January 0.5 ET. */

      t = (jd - 2415020.0) / 36525.0;
      t2 = t * t;
      t3 = t2 * t;

      /* Geometric mean longitude of the Sun, referred to the
         mean equinox of the date. */

      l = fixangle(279.69668 + 36000.76892 * t + 0.0003025 * t2);

        /* Sun's mean anomaly. */

      m = fixangle(358.47583 + 35999.04975*t - 0.000150*t2 - 0.0000033*t3);

        /* Eccentricity of the Earth's orbit. */

      e = 0.01675104 - 0.0000418 * t - 0.000000126 * t2;

      /* Eccentric anomaly. */

      ea = kepler(m, e);

      /* True anomaly */

      v = fixangle(2 * rtd(atan(sqrt((1 + e) / (1 - e))  * tan(ea / 2))));

        /* Sun's true longitude. */

      theta = l + v - m;

      /* Obliquity of the ecliptic. */

      eps = 23.452294 - 0.0130125 * t - 0.00000164 * t2 + 0.000000503 * t3;

        /* Corrections for Sun's apparent longitude, if desired. */

      if (apparent) {
         omega = fixangle(259.18 - 1934.142 * t);
         theta = theta - 0.00569 - 0.00479 * sin(dtr(omega));
         eps += 0.00256 * cos(dtr(omega));
      }

        /* Return Sun's longitude and radius vector */

      *slong = theta;
      *rv = (1.0000002 * (1 - e * e)) / (1 + e * cos(dtr(v)));

      /* Determine solar co-ordinates. */

      *ra =
      fixangle(rtd(atan2(cos(dtr(eps)) * sin(dtr(theta)), cos(dtr(theta)))));
      *dec = rtd(asin(sin(dtr(eps)) * sin(dtr(theta))));
}

/*  GMST  --  Calculate Greenwich Mean Siderial Time for a given
            instant expressed as a Julian date and fraction.      */

double
gmst(jd)
double jd;
{
      double t, theta0;


      /* Time, in Julian centuries of 36525 ephemeris days,
         measured from the epoch 1900 January 0.5 ET. */

      t = ((floor(jd + 0.5) - 0.5) - 2415020.0) / 36525.0;

      theta0 = 6.6460656 + 2400.051262 * t + 0.00002581 * t * t;

      t = (jd + 0.5) - (floor(jd + 0.5));

      theta0 += (t * 24.0) * 1.002737908;

      theta0 = (theta0 - 24.0 * (floor(theta0 / 24.0)));

      return theta0;
}




/*
 * $Id: sunclock.c,v 1.2 1999/04/07 14:00:49 wg Exp $
 * Sun clock.  X11 version by John Mackin.
 *
 * This program was derived from, and is still in part identical with, the
 * Suntools Sun clock program whose author's comment appears immediately
 * below.  Please preserve both notices.
 *
 * The X11R3/4 version of this program was written by John Mackin, at the
 * Basser Department of Computer Science, University of Sydney, Sydney,
 * New South Wales, Australia; <john@cs.su.oz.AU>.  This program, like
 * the one it was derived from, is in the public domain: `Love is the
 * law, love under will.'
 */

/*

      Sun clock

      Designed and implemented by John Walker in November of 1988.

      Version for the Sun Workstation.

    The algorithm used to calculate the position of the Sun is given in
    Chapter 18 of:

    "Astronomical  Formulae for Calculators" by Jean Meeus, Third Edition,
    Richmond: Willmann-Bell, 1985.  This book can be obtained from:

       Willmann-Bell
       P.O. Box 35025
       Richmond, VA  23235
       USA
       Phone: (804) 320-7016

    This program was written by:

       John Walker
       Autodesk, Inc.
       2320 Marinship Way
       Sausalito, CA  94965
       USA
       Fax:   (415) 389-9418
       Voice: (415) 332-2344 Ext. 2829
       Usenet: {sun,well,uunet}!acad!kelvin
         or: kelvin@acad.uu.net

    modified for interactive maps by

      Stephen Martin
      Fujitsu Systems Business of Canada
      smartin@fujitsu.ca

    icon animation and miscellaneous minor fixes by

      Wolfram Gloger
      wmglo@dent.med.uni-muenchen.de

    This  program is in the public domain: "Do what thou wilt shall be the
    whole of the law".  I'd appreciate  receiving  any  bug  fixes  and/or
    enhancements,  which  I'll  incorporate  in  future  versions  of  the
    program.  Please leave the original attribution information intact  so
    that credit and blame may be properly apportioned.

    Revision history:

      1.0  12/21/89  Initial version.
            8/24/89  Finally got around to submitting.

      1.1   8/31/94  Version with interactive map.
      1.2  10/12/94  Fixes for HP and Solaris, new icon bitmap
      1.3  11/01/94  Timezone now shown in icon
      1.4  03/29/98  Fixed city drawing, added icon animation
      1.5  04/07/99  Colors changeable thanks to Michael Richmond,
                   window/icon update should now always work

*/

#define     FAILFONT    "fixed"

#define     VERSION           "1.5"

#include <sys/types.h>
#include <sys/timeb.h>
#include <string.h>
#include <unistd.h>

#ifdef __STDC__
#define CONST     const
#else
#define CONST
#endif

struct sunclock {
      int         s_width;    /* size of pixmap */
      int         s_height;
      Window            s_window;   /* associated window */
      Pixmap            s_pixmap;   /* and pixmap (this is a 1-bpp pixmap in which only the map and the day/night is drawn) */
      Pixmap            s_backg;    /* second pixmap, which serves as the background (and only content, eliminating refresh complexities) for the window */
      int         s_flags;    /* see below */
      int         s_noon;           /* position of noon */
      short *           s_wtab1;    /* current width table (?) */
      short *           s_wtab;           /* previous width table (?) */
      long        s_time;           /* time - real */
      long        s_projtime; /* last time we projected illumination */
      int         s_timeout;  /* time until next image update */
      struct sunclock * s_next;     /* pointer to next clock context */
};


/*
 * bits in s_flags
 */

#define     S_DIRTY           04          /* pixmap -> window copy required */

#ifdef NEED_SYSTEM_DECLARATIONS
char *                        strdup();
char *                        strrchr();
char *                        strtok();
char *                        malloc();
long                    time();
#ifdef NEW_CTIME
char *                        timezone();
#endif
#endif


/*
 * External Functions
 */

double                        jtime();
double                        gmst();
char *                        salloc();
struct sunclock *       makeClockContext();
void                    getColors();
void                    fixGeometry();
void                    makePixmaps();
void                    makeWindows();
void                    makeGCs();
void                    setAllHints();
void                    makeClockContexts();
void                    shutDown();
void                    updimage();
void                    showImage();
void                    sunpos();
void                    moveterm();
void                    projillum();

CONST char * CONST            Wdayname[] = {
      "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
CONST char * CONST            Monname[] = {
      "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
      "Aug", "Sep", "Oct", "Nov", "Dec"
};

struct geom {
      int               mask;
      int               x;
      int               y;
};

CONST char *                  Display_name = "";
Display *               dpy;
int                     scr;
unsigned long                 Black;
unsigned long                 White;
unsigned long                 Beaconcolour[5];
GC                      GC_store;
GC                      GC_invert;
GC                      GC_bigf;
GC                      GC_smallf;
GC                      GC_xor;
GC                      GC_beacon[5];
Pixmap                        Mappix;
Window                        Clock;
struct sunclock *       S_list = 0; /* NULL-terminated */
struct geom             Geom = { 0, 0, 0 };
char *                        fg = "Black";
char *                        bg = "White";


/*
 * Free resources.
 */

void
shutDown()
{
      XFreeGC(dpy, GC_store);
      XFreeGC(dpy, GC_invert);
      XFreeGC(dpy, GC_bigf);
      XFreeGC(dpy, GC_smallf);
      XFreeGC(dpy, GC_xor);
      XFreePixmap(dpy, Mappix);
      XDestroyWindow(dpy, Clock);
      XCloseDisplay(dpy);
}


/*
 * Set up stuff the window manager will want to know.  Must be done
 * before mapping window, but after creating it.
 */

void
setAllHints(void)
{
      XClassHint        xch;
      XSizeHints        xsh;

      xch.res_name = "ibp";
      xch.res_class = "ibp";
      XSetClassHint(dpy, Clock, &xch);
      XStoreName(dpy, Clock, "ibp");

      xsh.flags = PSize | PMinSize | PMaxSize;
      if (Geom.mask & (XValue | YValue)) {
            xsh.x = Geom.x;
            xsh.y = Geom.y;
            xsh.flags |= USPosition;
      }
      xsh.width = xsh.min_width = xsh.max_width = large_map_width;
      xsh.height = xsh.min_height = xsh.max_height = large_map_height;
      XSetNormalHints(dpy, Clock, &xsh);
}

void
makeWindows()
{
      XSetWindowAttributes    xswa;
      register int            mask;

      xswa.background_pixel = White;
      xswa.border_pixel = Black;
      xswa.backing_store = WhenMapped;
      mask = CWBackPixel | CWBorderPixel | CWBackingStore;

      fixGeometry(&Geom, large_map_width, large_map_height);
      Clock = XCreateWindow(dpy, RootWindow(dpy, scr), Geom.x, Geom.y,
                        large_map_width, large_map_height, 3, CopyFromParent,
                        InputOutput, CopyFromParent, mask, &xswa);
}

void
fixGeometry(g, w, h)
register struct geom *        g;
register int                  w;
register int                  h;
{
      if (g->mask & XNegative)
            g->x = DisplayWidth(dpy, scr) - w + g->x;
      if (g->mask & YNegative)
            g->y = DisplayHeight(dpy, scr) - h + g->y;
}

void
makeGCs(w, p)
register Window               w;
register Pixmap               p;
{
      XGCValues         gcv;
      int i;

      gcv.foreground = Black;
      gcv.background = White;
      GC_store = XCreateGC(dpy, w, GCForeground | GCBackground, &gcv);
      gcv.function = GXinvert;
      gcv.fill_style = FillSolid;
      GC_invert = XCreateGC(dpy, p, GCForeground | GCBackground | GCFunction | GCFillStyle, &gcv);

      gcv.function = GXcopyInverted;
      GC_xor = XCreateGC(dpy, p, GCForeground | GCBackground | GCFunction, &gcv);

      for (i=0;i<5;i++) {
                gcv.line_width = 0;
            gcv.foreground = Beaconcolour[i];
            GC_beacon[i] = XCreateGC(dpy, w, GCForeground | GCLineWidth , &gcv);
      }
}


unsigned long getColor(char *name,int black)
{
      XColor                  c;
      XColor                  e;
      register Status         s;

      s = XAllocNamedColor(dpy, DefaultColormap(dpy, scr), name, &c, &e);
      if (s != (Status)1) {
            fprintf(stderr, "ibps: warning: can't allocate color `%s'\n",
                  fg);
            return black ? BlackPixel(dpy, scr) : WhitePixel(dpy, scr);
      }
      return c.pixel;
}

void
getColors()
{
      Black = getColor(fg,1);
      White = getColor(bg,0);
      Beaconcolour[0] = getColor("red",1);
      Beaconcolour[1] = getColor("yellow",1);
      Beaconcolour[2] = getColor("green",1);
      Beaconcolour[3] = getColor("cyan",1);
      Beaconcolour[4] = getColor("blue",1);
}


void
makePixmaps()
{
      Mappix = XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, scr),
                         (char *)large_map_bits, large_map_width,
                         large_map_height, 0, 1, 1);
}

void
makeClockContexts()
{
      register struct sunclock * s;

      s = makeClockContext(large_map_width, large_map_height, Clock, Mappix );
}


struct sunclock *
makeClockContext(wid, ht, win, pix, gc)
int                     wid;
int                     ht;
Window                        win;
Pixmap                        pix;
{
      register struct sunclock * s;

      s = (struct sunclock *)salloc(sizeof (struct sunclock));
      s->s_width = wid;
      s->s_height = ht;
      s->s_window = win;
      s->s_pixmap = pix;
      s->s_flags = S_DIRTY;
      s->s_noon = -1;
      s->s_wtab = (short *)salloc((int)(ht * sizeof (short *)));
      s->s_wtab1 = (short *)salloc((int)(ht * sizeof (short *)));
      s->s_time = 0L;
      s->s_timeout = 0;
      s->s_projtime = -1L;
      s->s_next = S_list;
      S_list = s;

      return (s);
}     




void
showImage(s)
register struct sunclock *    s;
{
      XCopyPlane(dpy, s->s_pixmap, s->s_backg, GC_store,
               0, 0, s->s_width, s->s_height, 0, 0, 1);
      s->s_flags &= ~S_DIRTY;
}


/* --- */
/*  UPDIMAGE  --  Update current displayed image.  */

void
updimage(s)
register struct sunclock *    s;
{
      register int            i;
      int               xl;
      struct tm *       ct;
      double                  jt;
      double                  sunra;
      double                  sundec;
      double                  sunrv;
      double                  sunlong;
      double                  gt;
      short *                 wtab_swap;

      /* If this is a full repaint of the window, force complete
         recalculation. */

      if (s->s_noon < 0) {
            s->s_projtime = 0;
            for (i = 0; i < s->s_height; i++) {
                  s->s_wtab1[i] = -1;
            }
      }

      time(&s->s_time);
      ct = gmtime(&s->s_time);

      jt = jtime(ct);
      sunpos(jt, False, &sunra, &sundec, &sunrv, &sunlong);
      gt = gmst(jt);

      /* Projecting the illumination curve  for the current seasonal
         instant is costly.  Only  do it every PROJINT seconds.  */
        if (s->s_projtime < 0
            || (s->s_time - s->s_projtime) > PROJINT) {
                projillum(s->s_wtab, s->s_width, s->s_height, sundec);
                wtab_swap = s->s_wtab;
                s->s_wtab = s->s_wtab1;
                s->s_wtab1 = wtab_swap;
                s->s_projtime = s->s_time;
        }

      sunlong = fixangle(180.0 + (sunra - (gt * 15)));
      xl = sunlong * (s->s_width / 360.0);

      /* If the subsolar point has moved at least one pixel, update
         the illuminated area on the screen.    */

      if (s->s_noon != xl) {
            moveterm(s->s_wtab1, xl, s->s_wtab, s->s_noon, s->s_width,
                   s->s_height, s->s_pixmap);
            s->s_noon = xl;
            s->s_flags |= S_DIRTY;
      }
}

/*  PROJILLUM  --  Project illuminated area on the map.  */

void
projillum(wtab, xdots, ydots, dec)
short *wtab;
int xdots, ydots;
double dec;
{
      int i, ftf = True, ilon, ilat, lilon, lilat, xt;
      double m, x, y, z, th, lon, lat, s, c, s_th;

      /* Clear unoccupied cells in width table */

      for (i = 0; i < ydots; i++)
            wtab[i] = -1;

      /* Build transformation for declination */

      s = sin(-dtr(dec));
      c = cos(-dtr(dec));

      /* Increment over a semicircle of illumination */

      for (th = -(PI / 2); th <= PI / 2 + 0.001;
          th += PI / TERMINC) {

            /* Transform the point through the declination rotation. */

            s_th = sin(th);
            x = -s * s_th;
            y = cos(th);
            z = c * s_th;

            /* Transform the resulting co-ordinate through the
               map projection to obtain screen co-ordinates. */

            lon = (y == 0.0 && x == 0.0) ? 0.0 : rtd(atan2(y, x));
            lat = rtd(asin(z));

            ilat = ydots - (lat + 90.0) * (ydots / 180.0);
            ilon = lon * (xdots / 360.0);

            if (ftf) {

                  /* First time.  Just save start co-ordinate. */

                  lilon = ilon;
                  lilat = ilat;
                  ftf = False;
            } else {

                  /* Trace out the line and set the width table. */

                  if (lilat == ilat) {
                        wtab[(ydots - 1) - ilat] = ilon == 0 ? 1 : ilon;
                  } else {
                        m = ((double) (ilon - lilon)) / (ilat - lilat);
                        for (i = lilat; i != ilat; i += sgn(ilat - lilat)) {
                              xt = lilon + floor((m * (i - lilat)) + 0.5);
                              wtab[(ydots - 1) - i] = xt == 0 ? 1 : xt;
                        }
                  }
                  lilon = ilon;
                  lilat = ilat;
            }
      }

      /* Now tweak the widths to generate full illumination for
         the correct pole. */

      if (dec < 0.0) {
            ilat = ydots - 1;
            lilat = -1;
      } else {
            ilat = 0;
            lilat = 1;
      }

      for (i = ilat; i != ydots / 2; i += lilat) {
            if (wtab[i] != -1) {
                  while (True) {
                        wtab[i] = xdots / 2;
                        if (i == ilat)
                              break;
                        i -= lilat;
                  }
                  break;
            }
      }
}

/*  XSPAN  --  Complement a span of pixels.  Called with line in which
             pixels are contained, leftmost pixel in the  line,  and
             the   number   of   pixels   to     complement.   Handles
             wrap-around at the right edge of the screen.  */

void
xspan(pline, leftp, npix, xdots, p)
register int                  pline;
register int                  leftp;
register int                  npix;
register int                  xdots;
register Pixmap               p;
{
      leftp = leftp % xdots;

      if (leftp + npix > xdots) {
            XDrawLine(dpy, p, GC_invert, leftp, pline, xdots - 1, pline);
            XDrawLine(dpy, p, GC_invert, 0, pline,
                    (leftp + npix) - (xdots + 1), pline);
      }
      else
            XDrawLine(dpy, p, GC_invert, leftp, pline,
                    leftp + (npix - 1), pline);
}

/*  MOVETERM  --  Update illuminated portion of the globe.  */

void
moveterm(wtab, noon, otab, onoon, xdots, ydots, pixmap)
short *wtab, *otab;
int noon, onoon, xdots, ydots;
Pixmap pixmap;
{
      int i, ol, oh, nl, nh;

      for (i = 0; i < ydots; i++) {

            /* If line is off in new width table but is set in
               the old table, clear it. */

            if (wtab[i] < 0) {
                  if (otab[i] >= 0) {
                        xspan(i, ((onoon - otab[i]) + xdots) % xdots,
                            otab[i] * 2, xdots, pixmap);
                  }
            } else {

                  /* Line is on in new width table.  If it was off in
                     the old width table, just draw it. */

                  if (otab[i] < 0) {
                        xspan(i, ((noon - wtab[i]) + xdots) % xdots,
                            wtab[i] * 2, xdots, pixmap);
                  } else {

                        /* If both the old and new spans were the entire
                           screen, they're equivalent. */

                        if (otab[i] == wtab[i] && wtab[i] == (xdots / 2))
                              continue;

                        /* The line was on in both the old and new width
                           tables.  We must adjust the difference in the
                           span.  */

                        ol =  ((onoon - otab[i]) + xdots) % xdots;
                        oh = (ol + otab[i] * 2) - 1;
                        nl =  ((noon - wtab[i]) + xdots) % xdots;
                        nh = (nl + wtab[i] * 2) - 1;

                        /* If spans are disjoint, erase old span and set
                           new span. */

                        if (oh < nl || nh < ol) {
                              xspan(i, ol, (oh - ol) + 1, xdots, pixmap);
                              xspan(i, nl, (nh - nl) + 1, xdots, pixmap);
                        } else {
                              /* Clear portion(s) of old span that extend
                                 beyond end of new span. */
                              if (ol < nl) {
                                    xspan(i, ol, nl - ol, xdots, pixmap);
                                    ol = nl;
                              }
                              if (oh > nh) {
                                    xspan(i, nh + 1, oh - nh, xdots, pixmap);
                                    oh = nh;
                              }
                              /* Extend existing (possibly trimmed) span to
                                 correct new length. */
                              if (nl < ol) {
                                    xspan(i, nl, ol - nl, xdots, pixmap);
                              }
                              if (nh > oh) {
                                    xspan(i, oh + 1, nh - oh, xdots, pixmap);
                              }
                        }
                  }
            }
            otab[i] = wtab[i];
      }
}

char *
salloc(nbytes)
register int                  nbytes;
{
      register char *         p;

      p = malloc((unsigned)nbytes);
      if (p == (char *)NULL) {
            fprintf(stderr, "ibp: out of memory\n");
            exit(1);
      }
      return (p);
}






#define R1 3
#define R2 5


/*************************************************************************
  Below here are some new (i.e., non-sunclock) functions for display of
  beacons, RF paths, and glueing with the main program.
*************************************************************************/

#define NPOINTS 363    /* number of points on one "beacon path" (including the endpoints (= beacon location) and the observer's location) */

struct Beaconpath {
   int ilat[NPOINTS];
   int ilon[NPOINTS];
   int nshort;  /* number of points on the short path */
   /* the points in the above array are ordered as follows:
      - the first and last point are the beacon itself
      - point number 'nshort' is the at the listener's location
      - we first follow the short path, from beacon to listener,
        and then the long path, from listener to beacon.
   */
};

struct Beaconpath beaconpaths[18];

int x_myloc_ok=0;

#define lat2i(lat) ((int)(large_map_height - ((lat) + 90) * (large_map_height / 180.0)))
#define lon2i(lon) ((int)((180.0 + (lon)) * (large_map_width / 360.0)))

void x_storeBeacons(int myloc_ok, double mylat, double mylon, double *lat, double *lon)
{
   int cnt;
   struct Beaconpath *bp;
   int myilat=0,myilon=0;
   
   x_myloc_ok = myloc_ok;
   if (myloc_ok) {
      myilat=lat2i(mylat);
      myilon=lon2i(mylon);
   }
   bp=beaconpaths;
   for (cnt=0;cnt<18;cnt++,bp++,lat++,lon++) {
      int mark_beacon, mark_listener;
      bp->ilat[0] = bp->ilat[NPOINTS-1] = lat2i(*lat);
      bp->ilon[0] = bp->ilon[NPOINTS-1] = lon2i(*lon);
      if (!myloc_ok) continue;
      {
       double phi1,phi2,th1,th2;   /* coordinates in radians instead of degrees */
       double ecross;  /* longitude where the great-circle path crosses the equator */
       double elev;    /* "elevation" of the great circle; i.e., the angle its plane makes with the equatorial plane */
       double t;
         Pixmap tst;
         int ila[NPOINTS-2],ilo[NPOINTS-2];
         int i,j,inc;
         double prevx;

       tst = XCreatePixmap(dpy, RootWindow(dpy, scr), large_map_width, large_map_height, 1);

         phi1 = *lon*M_PI/180;  phi2 = mylon*M_PI/180;
         th1 = *lat*M_PI/180;   th2 = mylat*M_PI/180;
         if (tan(th1)==0 || tan(th2)==0) ecross=0;
       else ecross = atan2( sin(phi1)/tan(th1) - sin(phi2)/tan(th2) , cos(phi1)/tan(th1) - cos(phi2)/tan(th2) );
       if (phi1==ecross) elev=M_PI/2;
       else elev = atan( tan(th1) / sin(phi1-ecross) );

         prevx=ecross;
         mark_beacon = mark_listener = -1;
         for (t=0, i=0; t<=2*M_PI+0.000001; t+=2*M_PI/(NPOINTS-3), i++) {
            double x,y;

            x = ecross + atan2( sin(t)*cos(elev), cos(t) );
            if (x<-M_PI) x+=2*M_PI;
            else if (x>M_PI) x-=2*M_PI;
            y = asin(sin(t)*sin(elev));

            if (prevx<x) {
               if (prevx<=phi1 && phi1<x) mark_beacon=i;
               if (prevx<=phi2 && phi2<x) mark_listener=i;
            } else {
               if (prevx<=phi1 || phi1<x) mark_beacon=i;
               if (prevx<=phi2 || phi2<x) mark_listener=i;
            }

            ila[i] = lat2i(y*180/M_PI);
            ilo[i] = lon2i(x*180/M_PI);

            prevx=x;
         }
         assert(mark_beacon>=0);
         assert(mark_listener>=0);

         i=mark_beacon;
         if (abs(mark_beacon-mark_listener)<=(NPOINTS-3)/2) inc=+1; else inc=-1;
         if (mark_listener<mark_beacon) inc*=-1;
         j=1;
         do {
            if (i==mark_listener && inc<0) {
               bp->ilat[j]=myilat;
               bp->ilon[j]=myilon;
               bp->nshort=j;
               j++;
            }
            bp->ilat[j]=ila[i];
            bp->ilon[j]=ilo[i];
            j++;
            if (i==mark_listener && inc>0) {
               bp->ilat[j]=myilat;
               bp->ilon[j]=myilon;
               bp->nshort=j;
               j++;
            }
            i+=inc;
            if (i<0) i=NPOINTS-4;
            if (i>=NPOINTS-3) i=0;
         } while (i!=mark_beacon);
      }
   }
}


void
drawBeacons(Pixmap backg,int act[5])
/* based partially on sunclock's place_city() */
{
    int i;
    for (i=0;i<5;i++) {
        int ilat,ilon;
        struct Beaconpath *bp;
        int j;

        if (act[i]<0) continue;
        bp = beaconpaths+act[i];
        ilat = bp->ilat[0];
        ilon = bp->ilon[0];
        XFillArc(dpy, backg, GC_beacon[i], ilon-R1, ilat-R1, 2*R1, 2*R1, 0, 360*64);
        XDrawArc(dpy, backg, GC_beacon[i], ilon-R2, ilat-R2, 2*R2, 2*R2, 0, 360*64);
        if (!x_myloc_ok) continue;

        for (j=1;j<bp->nshort;j++)
            if (abs(bp->ilon[j]-bp->ilon[j-1])<large_map_width/2) 
                XDrawLine(dpy, backg, GC_beacon[i], bp->ilon[j-1], bp->ilat[j-1], bp->ilon[j], bp->ilat[j]);
        for (j=bp->nshort+2;j<NPOINTS;j+=2)
            XDrawPoint(dpy, backg, GC_beacon[i], bp->ilon[j], bp->ilat[j]);
    }
}




void x_update(int act[5])
/* based on sunclock's doTimeout() */
{
      struct sunclock * s;

      for(s = S_list; s; s = s->s_next) {
            updimage(s);
            showImage(s);
            drawBeacons(s->s_backg,act);
            XClearWindow(dpy, s->s_window);   /* = copy background pixmap to screen */
      }
      XFlush(dpy);
}


int x_getkeypress(void)
{
      XEvent ev;

      while (XCheckMaskEvent(dpy, -1L, &ev))
            if (ev.type==KeyPress)
                  return XKeycodeToKeysym(dpy, ev.xkey.keycode, 0);

      return 0;
}


int x_init(void)
/* based on sunclock's main() */
/* returns number of filedescriptor used for communication with Xserver */
{
      XWindowAttributes wa;

      dpy = XOpenDisplay(getenv("DISPLAY"));
      if (dpy == (Display *)NULL) {
            fprintf(stderr, "ibp: can't open display `%s'\n",
                  getenv("DISPLAY"));
            exit(1);
      }
      scr = DefaultScreen(dpy);

      getColors();
      makePixmaps();
      makeWindows();
      makeGCs(Clock, Mappix);
      setAllHints();
      makeClockContexts();

      XSelectInput(dpy, Clock, KeyPressMask);
      XMapWindow(dpy, Clock);

      XGetWindowAttributes(dpy, Clock, &wa);
      S_list->s_backg = XCreatePixmap(dpy, RootWindow(dpy, scr), wa.width, wa.height, wa.depth);
      XSetWindowBackgroundPixmap(dpy,Clock,S_list->s_backg);

      return ConnectionNumber(dpy);
}



Generated by  Doxygen 1.6.0   Back to index