home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume19 / xephem / part18 / skyviewmenu.c.3 < prev   
Text File  |  1993-05-15  |  21KB  |  827 lines

  1.     } else {
  2.         label = (pu.op->o_flags ^= OBJF_LABEL) & OBJF_LABEL;
  3.         if (label) {
  4.         sv_getcircle (&w, &h, &r, &xb, &yb);
  5.         (void) sv_dbobjloc (pu.op, r, &x, &y);
  6.         name = pu.op->o_name;
  7.         }
  8.     }
  9.  
  10.     if (label) {
  11.         /* label is being turned on so draw it */
  12.         Display *dsp = XtDisplay(svda_w);
  13.         Window win = sv_pm;
  14.         GC gc;
  15.         x += xb;
  16.         y += yb;
  17.         obj_pickgc (pu.op, svda_w, &gc);
  18.         draw_label (dsp, win, gc, name, x, y);
  19.         sv_copy_sky();
  20.     } else {
  21.         /* label is being turned off so redraw */
  22.         sv_all (mm_get_now(), 1);
  23.     }
  24. }
  25.  
  26. /* remove trails no longer wanted. */
  27. static void
  28. tobj_rmoff()
  29. {
  30.     TrailObj **topp;    /* address to be changed if we decide to 
  31.                  * remove *topp
  32.                  */
  33.     TrailObj *top;        /* handy *topp */
  34.  
  35.     for (topp = &trailobj; (top = *topp) != NULL; ) {
  36.         if (top->on) {
  37.         topp = &top->ntop;
  38.         } else {
  39.         *topp = top->ntop;
  40.         XtFree ((char *)top);
  41.         }
  42.     }
  43. }
  44.  
  45. /* remove the trailobj list that contains the given pointer.
  46.  * we have to search each trail list to find the one with this pointer.
  47.  * it might be the one on TrailObj itself or one of the older ones on
  48.  *    the TSky list.
  49.  */
  50. static void
  51. tobj_rmobj (op)
  52. Obj *op;
  53. {
  54.     TrailObj **topp;    /* address to be changed if we decide to 
  55.                  * remove *topp
  56.                  */
  57.     TrailObj *top;        /* handy *topp */
  58.  
  59.     for (topp = &trailobj; (top = *topp) != NULL; ) {
  60.         int i;
  61.         if (top->op == op)
  62.         goto out;
  63.         for (i = 0; i < top->nsky; i++)
  64.         if (&top->sky[i].o == op)
  65.             goto out;
  66.         topp = &top->ntop;
  67.     }
  68.  
  69.     out:
  70.  
  71.     if (!top)
  72.         return;    /* oh well */
  73.  
  74.     *topp = top->ntop;
  75.     XtFree ((char *)top);
  76. }
  77.  
  78. /* add a new empty entry to the trailobj list for db object op.
  79.  * return a pointer to the new TrailObj.
  80.  */
  81. static TrailObj *
  82. tobj_addobj (op)
  83. Obj *op;
  84. {
  85.     TrailObj *top;
  86.  
  87.     /* don't forget there is inherently room for one TSky in a TrailObj */
  88.     top = (TrailObj *)
  89.         XtMalloc (sizeof(TrailObj) + (TRAILCHUNKS-1)*sizeof(TSky));
  90.     top->nskymem = TRAILCHUNKS; /* there is room for TRAILCHUNKS TSkys .. */
  91.     top->nsky = 0;      /* though none are in use in our new one */
  92.     top->op = op;
  93.     top->on = 1;
  94.  
  95.     /* link directly off trailobj -- order is unimportant */
  96.     top->ntop = trailobj;
  97.     trailobj = top;
  98.  
  99.     return (top);
  100. }
  101.  
  102. /* increase the number of Sky's top can hold.
  103.  * since we may have to move top to do it, return the new pointer.
  104.  */
  105. static TrailObj *
  106. tobj_growsky (top)
  107. TrailObj *top;
  108. {
  109.     TrailObj *ltop;
  110.     TrailObj *newtop;
  111.     int newn;
  112.  
  113.     /* set ltop to the TrailObj in the list just before top */
  114.     if (trailobj == top)
  115.         ltop = NULL;
  116.     else {
  117.         for (ltop=trailobj; ltop; ltop=ltop->ntop)
  118.         if (ltop->ntop == top)
  119.             break;
  120.         if (!ltop) {
  121.         printf ("tobj_growsky(): top not found!\n");
  122.         exit (1);
  123.         }
  124.     }
  125.  
  126.     /* don't forget there is already one TSky within a TrailObj. */
  127.     newn = top->nskymem + TRAILCHUNKS;
  128.     newtop = (TrailObj *) XtRealloc ((char *)top,
  129.                 sizeof(TrailObj) + (newn-1)*sizeof(TSky));
  130.     if (ltop)
  131.         ltop->ntop = newtop;
  132.     else
  133.         trailobj = newtop;
  134.     newtop->nskymem = newn;
  135.     return (newtop);
  136. }
  137.  
  138. /* empty the trailobj list and reclaim all space.
  139.  */
  140. static void
  141. tobj_reset()
  142. {
  143.     TrailObj *top, *ntop;
  144.  
  145.     for (top = trailobj; top; top = ntop) {
  146.         ntop = top->ntop;
  147.         XtFree ((char *)top);
  148.     }
  149.  
  150.     trailobj = NULL;
  151. }
  152.  
  153. /* find the TrailObj that contains op */
  154. static TrailObj *
  155. tobj_find (op)
  156. Obj *op;
  157. {
  158.     TrailObj *top;
  159.  
  160.     for (top = trailobj; top; top = top->ntop) {
  161.         int i;
  162.         if (top->op == op)
  163.         return (top);
  164.         for (i = 0; i < top->nsky; i++)
  165.         if (&top->sky[i].o == op)
  166.             return (top);
  167.     }
  168.  
  169.     return (NULL);
  170. }
  171.  
  172. /* add an Obj to the given trailobj, top.
  173.  * mark it as being valid as of jd (which is really an mjd).
  174.  * these are maintained in increasing order of time, ie, the first is the
  175.  * earliest. we take care not to add one for an identical time already in
  176.  * the list. since we might have to move top to grow it, we return a (possibly
  177.  * different) pointer.
  178.  */
  179. static TrailObj *
  180. tobj_addsky (top, jd, op)
  181. TrailObj *top;
  182. double jd;
  183. Obj *op;
  184. {
  185.     int i;
  186.  
  187.     /* make sure there is room for one more */
  188.     if (top->nsky == top->nskymem)
  189.         top = tobj_growsky (top);
  190.  
  191.     /* add op to top->sky in ascending time order.
  192.      * exit loop with i as the index of the cell to use.
  193.      */
  194.     for (i = top->nsky; i > 0; --i)
  195.         if (top->sky[i-1].ts_mjd < jd)
  196.         break;
  197.         else if (top->sky[i-1].ts_mjd == jd)
  198.         return (top);    /* don't add a dup */
  199.         else
  200.         top->sky[i] = top->sky[i-1];
  201.  
  202.     top->sky[i].flags = 0;
  203.     top->sky[i].ts_mjd = jd;
  204.     top->sky[i].o = *op;
  205.     top->nsky++;
  206.  
  207.     return (top);
  208. }
  209.  
  210. /* display everything in the trailobj list that is marked on onto sv_pm
  211.  * clipped to a circle of radius r, offset by xb and yb borders.
  212.  */
  213. static void
  214. tobj_display_all(r, xb, yb)
  215. unsigned r, xb, yb;
  216. {
  217.     Display *dsp = XtDisplay(svda_w);
  218.     Window win = sv_pm;
  219.     TrailObj *top;
  220.  
  221.     for (top = trailobj; top; top = top->ntop) {
  222.         int x1, y1, x2, y2;
  223.         int before;
  224.         Obj *op;
  225.         GC gc;
  226.         int i;
  227.  
  228.         if (!top->on)
  229.         continue;
  230.  
  231.         obj_pickgc(top->op, svda_w, &gc);
  232.         before = 0;
  233.  
  234.         for (i = 0; i < top->nsky; i++) {
  235.         op = &top->sky[i].o;
  236.         if (sv_trailobjloc (&top->sky[i], r, &x2, &y2)) {
  237.             sv_draw_obj (dsp, win, gc, op, x2+xb, y2+yb,
  238.                 magdiam(op->s_mag/MAGSCALE), justdots);
  239.             if (all_labels || (top->sky[i].flags & OBJF_LABEL))
  240.             draw_label (dsp, win, gc, op->o_name, x2+xb, y2+yb);
  241.         }
  242.         if (before++) {
  243.             int sx1, sy1, sx2, sy2;
  244.             if (lc(0,0,r*2,x1,y1,x2,y2,&sx1,&sy1,&sx2,&sy2) == 0)
  245.             XDrawLine (dsp, win, gc, sx1+xb, sy1+yb, sx2+xb,sy2+yb);
  246.         }
  247.         x1 = x2;
  248.         y1 = y2;
  249.         }
  250.  
  251.     }
  252.  
  253.     sv_draw_obj (dsp, win, (GC)0, NULL, 0, 0, 0, 0);    /* flush */
  254. }
  255.  
  256. /* determine if the given object is visible and within a circle of radius r
  257.  * pixels. if so, return 1 and compute the location in *xp/*yp, else return 0.
  258.  * N.B. only call this for bona fide db objects -- *not* for objects in the
  259.  *   TrailObj lists -- it will destroy their history.
  260.  */
  261. static
  262. sv_dbobjloc (op, r, xp, yp)
  263. Obj *op;
  264. int r;
  265. int *xp, *yp;
  266. {
  267.     double altdec, azra;
  268.  
  269.     if (!sv_precheck(op))
  270.         return (0);
  271.  
  272.     /* remaining things need accurate s_* fields */
  273.     db_update(op);
  274.  
  275.     if (aa_mode && op->s_alt < 0.0)
  276.         return(0);    /* it's below horizon and we're in alt-az mode */
  277.  
  278.     if (op->s_mag/MAGSCALE > fmag || op->s_mag/MAGSCALE < bmag)
  279.         return(0);    /* it's not within mag range after all */
  280.  
  281.     altdec = aa_mode ? op->s_alt : op->s_dec;
  282.     azra   = aa_mode ? op->s_az  : op->s_ra;
  283.     if (!sv_loc (r, altdec, azra, xp, yp))
  284.         return(0);     /* it's outside the fov after all */
  285.  
  286.     return (1);    /* yup, really within r */
  287. }
  288.  
  289. /* given a TSky find its location in a circle of radius r, all in pixels.
  290.  * return 1 if the resulting x/y is in fact within the circle, else 0 if it is
  291.  *   outside or otherwise should not be shown now (but return the x/y anyway).
  292.  * N.B. we take care to not change the tsp->o in any way.
  293.  */
  294. static
  295. sv_trailobjloc (tsp, r, xp, yp)
  296. TSky *tsp;
  297. int r;
  298. int *xp, *yp;
  299. {
  300.     Obj *op = &tsp->o;
  301.     double altdec, azra;
  302.     int infov;
  303.  
  304.     altdec = aa_mode ? op->s_alt : op->s_dec;
  305.     azra   = aa_mode ? op->s_az  : op->s_ra;
  306.     infov = sv_loc (r, altdec, azra, xp, yp);
  307.     return (infov && (!aa_mode || op->s_alt >= 0.0) && sv_precheck(op)?1:0);
  308. }
  309.  
  310. /* do as much as possible to pre-check whether op is on screen now
  311.  * WITHOUT computing it's actual coordinates. put another way, we are not to
  312.  * use and s_* fields in these tests.
  313.  * return 0 if we know it's definitely not on screen, or 1 if it might be.
  314.  */
  315. static
  316. sv_precheck (op)
  317. Obj *op;
  318. {
  319.     if (op->type == UNDEFOBJ)
  320.         return(0);
  321.  
  322.     if (!svf_filter_ok(op) || !sv_bright_ok(op) || !sv_infov(op))
  323.         return(0);    /* wrong type, wrong brightness or outside for sure */
  324.     
  325.     return (1);
  326. }
  327.  
  328. /* return 1 if db object is ever possibly within the fmag/bmag range; else 0.
  329.  */
  330. static
  331. sv_bright_ok(op)
  332. Obj *op;
  333. {
  334.     switch (op->type) {
  335.     case PLANET:
  336.         /* always go for the planets for now but ..
  337.          * TODO: work up a table of extreme planet magnitudes.
  338.          */
  339.         return (1);
  340.         /* break; */
  341.     case HYPERBOLIC: return (1);    /* and interlopers */
  342.     case PARABOLIC: return (1);
  343.     case ELLIPTICAL: {
  344.         double mag;        /* magnitude */
  345.         double per, aph;    /* perihelion and aphelion distance */
  346.  
  347.         per = op->e_a*(1.0 - op->e_e);
  348.         aph = op->e_a*(1.0 + op->e_e);
  349.         if (per <= 1.1 && aph >= 0.9)
  350.         return (1); /* might be blazing in the back yard some day */
  351.         if (op->e_mag.whichm == MAG_HG)
  352.          mag = op->e_mag.m1 + 5*log10(per*fabs(per-1.0));
  353.         else
  354.          gk_mag(op->e_mag.m1, op->e_mag.m2,
  355.                         per, fabs(per-1.0), &mag);
  356.         return (mag <= fmag && mag >= bmag);
  357.         /* break; */
  358.         }
  359.     case FIXED:
  360.         return (op->f_mag/MAGSCALE <= fmag && op->f_mag/MAGSCALE >= bmag);
  361.         /* break; */
  362.     default: 
  363.         printf ("sv_bright_ok(): bad type: %d\n", op->type);
  364.         exit (1);
  365.         return (0);    /* for lint */
  366.     }
  367. }
  368.  
  369. /* return 1 if the object can potentially be within the current sv_fov, else 0.
  370.  * N.B. this is meant to be cheap - we only do fixed objects and we don't
  371.  *      precess. most importantly, we don't use any s_* fields.
  372.  */
  373. static
  374. sv_infov (op)
  375. Obj *op;
  376. {
  377. #define    DELEP    100        /* maximum epoch difference we dare go without
  378.                  * precessing, years
  379.                  */
  380. #define    MARGIN    degrad(3.0)    /* border around fov still considered "in"
  381.                  * in spite of having not precessed.
  382.                  */
  383.     double ra0, dec0;    /* ra/dec of our center of view */
  384.     double a, sa, ca;    /* angle from viewpoint to pole */
  385.     double b, sb, cb;    /* angle from object to pole */
  386.     double c, cc;        /* diff of polar angles of obj and viewpoint */
  387.     double d;        /* angular separation of object and viewpoint */
  388.     Now *np = mm_get_now();
  389.  
  390.     if (op->type != FIXED)
  391.         return (1);
  392.     if (fabs (mjd - op->f_epoch) > DELEP)
  393.         return (1);
  394.  
  395.     if (aa_mode) {
  396.         /* TODO: cache this -- it's the same for each obj! */
  397.         double ha, lst;
  398.         aa_hadec (lat, sv_altdec, sv_azra, &ha, &dec0);
  399.         now_lst (np, &lst);
  400.         ra0 = hrrad(lst) - ha;
  401.         range (&ra0, 2*PI);
  402.     } else {
  403.         ra0 = sv_azra;
  404.         dec0 = sv_altdec;
  405.     }
  406.  
  407.     a = PI/2 - dec0;
  408.     sa = sin(a);
  409.     ca = cos(a);
  410.     b = PI/2 - op->f_dec;
  411.     sb = sin(b);
  412.     cb = cos(b);
  413.     c = ra0 - op->f_RA;
  414.     cc = cos(c);
  415.     d = acos(ca*cb + sa*sb*cc);
  416.     return (d < sv_fov/2 + MARGIN);
  417. }
  418.  
  419. /* compute x/y loc of a point at azra/altdec on a circle of radius rad pixels
  420.  *   as viewed from sv_azra/sv_altdec with sv_fov.
  421.  * return 1 if fits on screen, else 0 (but still return x/y).
  422.  */
  423. static
  424. sv_loc (rad, altdec, azra, xp, yp)
  425. int rad;    /* radius of target display, pixels */
  426. double altdec;    /* angle up from spherical equator, such as alt or dec; rad */
  427. double azra;    /* angle around spherical pole, such as az or ra; rad */
  428. int *xp, *yp;    /* return X coords within circle */
  429. {
  430. #define    LOCEPS    (1e-5)    /* an angle too small to see on screen, rads */
  431.     double a,sa,ca;    /* angle from viewpoint to pole */
  432.     double b,sb,cb;    /* angle from object to pole */
  433.     double c,sc,cc;    /* difference in polar angles of obj and viewpoint */
  434.     double d,sd,cd;    /* angular separation of object and viewpoint */
  435.     double r;    /* proportion of d to desired field of view */
  436.     double se, ce;    /* angle between (viewpoint,pole) and (viewpoint,obj) */
  437.  
  438.     a = PI/2 - sv_altdec;
  439.     sa = sin(a);
  440.     ca = cos(a);
  441.     b = PI/2 - altdec;
  442.     sb = sin(b);
  443.     cb = cos(b);
  444.     if (aa_mode)
  445.         c = azra - sv_azra;
  446.     else
  447.         c = sv_azra - azra;
  448.     cc = cos(c);
  449.     d = acos(ca*cb + sa*sb*cc);
  450.     if (d < LOCEPS) {
  451.         *xp = *yp = rad;
  452.         return (1);
  453.     }
  454.  
  455.     r = d/(sv_fov/2.0);
  456.  
  457.     sc = sin(c);
  458.     sd = sin(d);
  459.     se = sc*sb/sd;
  460.     *xp = rad*(1 + r*se) + 0.5;
  461.     if (a < LOCEPS) {
  462.         /* as viewpoint approaches N pole, e approaches PI - c */
  463.         ce = -cc;
  464.     } else if (a > PI - LOCEPS) {
  465.         /* as viewpoint approaches S pole, e approaches c */
  466.         ce = cc;
  467.     } else {
  468.         cd = cos(d);
  469.         ce = (cb - cd*ca)/(sd*sa);
  470.     }
  471.     *yp = rad*(1 - r*ce) + 0.5;
  472.  
  473.     return (r >= 1.0 ? 0 : 1);
  474. }
  475.  
  476. /* compute azra/altdec loc of a point at x/y on a circle of radius rad pixels
  477.  *   as viewed from sv_azra/sv_altdec with sv_fov.
  478.  * return 1 if x/y are within the circle, else 0.
  479.  */
  480. static
  481. sv_unloc (rad, x, y, altdecp, azrap)
  482. int rad;    /* radius of target display, pixels */
  483. int x, y;    /* X coords within circle */
  484. double *altdecp;/* angle up from spherical equator, such as alt or dec; rad */
  485. double *azrap;    /* angle around spherical pole, such as az or ra; rad */
  486. {
  487. #define    UNLOCEPS (1e-4)    /* sufficiently close to pole to not know az/ra; rads */
  488.     double a,sa,ca;    /* angle from viewpoint to pole */
  489.     double r;    /* distance from center to object, pixels */
  490.     double d,sd,cd;    /* angular separation of object and viewpoint */
  491.     double e,se,ce;    /* angle between (viewpoint,pole) and (viewpoint,obj) */
  492.     double b,sb,cb;    /* angle from object to pole */
  493.     double c,sc,cc;    /* difference in polar angles of obj and viewpoint */
  494.  
  495.     if (x == rad && y == rad) {
  496.         /* at the center -- avoids cases where r == 0 */
  497.         *altdecp = sv_altdec;
  498.         *azrap = sv_azra;
  499.         return (1);
  500.     }
  501.  
  502.     a = PI/2 - sv_altdec;
  503.     sa = sin(a);
  504.     ca = cos(a);
  505.  
  506.     r = sqrt ((double)((x-rad)*(x-rad) + (y-rad)*(y-rad)));
  507.     if (r > rad)
  508.         return(0); /* outside the circle */
  509.  
  510.     d = r/rad*(sv_fov/2.0);
  511.     sd = sin(d);
  512.     cd = cos(d);
  513.     ce = (rad - y)/r;
  514.     se = (x - rad)/r;
  515.     cb = ca*cd + sa*sd*ce;
  516.     b = acos(cb);
  517.     *altdecp = PI/2 - b;
  518.  
  519.     /* find c, the polar angle between viewpoint and object */
  520.     if (a < UNLOCEPS) {
  521.         /* as viewpoint approaches N pole, c approaches PI - e */
  522.         c = acos(-ce);
  523.     } else if (a > PI - UNLOCEPS) {
  524.         /* as viewpoint approaches S pole, c approaches e */
  525.         c = acos(ce);
  526.     } else if (b < UNLOCEPS || b > PI - UNLOCEPS) {
  527.         /* as object approaches either pole, c becomes arbitary */
  528.         c = 0.0;
  529.     } else {
  530.         sb = sin(b);
  531.         cc = (cd - ca*cb)/(sa*sb);
  532.         if (cc < -1.0) cc = -1.0;    /* heh, it happens ... */
  533.         if (cc >  1.0) cc =  1.0;    /* heh, it happens ... */
  534.         c = acos (cc);        /* 0 .. PI; next step checks if c
  535.                      * should be > PI
  536.                      */
  537.     }
  538.     if (se < 0.0)         /* if e > PI */
  539.         c = PI + (PI - c);    /*     so is c */
  540.  
  541.     if (aa_mode)
  542.         *azrap = sv_azra + c;
  543.     else
  544.         *azrap = sv_azra - c;
  545.     range (azrap, 2*PI);
  546.  
  547.     return (1);
  548. }
  549.  
  550. /* draw a nice grid on a circle of radius r, x and y borders xb and yb.
  551.  */
  552. static void
  553. draw_grid(dsp, win, gc, r, xb, yb)
  554. Display *dsp;
  555. Window win;
  556. GC gc;
  557. unsigned int r;
  558. unsigned int xb, yb;
  559. {
  560.     double vticks[NGRID], hticks[NGRID];
  561.     double vmin, vmax, hmin, hmax;
  562.     XSegment xsegments[NGRID*NSEGS], *xs;
  563.     char msg[64];
  564.     int nvt, nht;
  565.     int i, j;
  566.     int pole;
  567.  
  568.     /* set vertical min and max, and detect whether pole is within fov.
  569.      * since display is in degrees, use that unit for finding ticks.
  570.      */
  571.     pole = 0;
  572.     vmin = sv_altdec-sv_fov/2;
  573.     if (vmin < 0 && aa_mode)
  574.         vmin = 0.0;
  575.     if (vmin <= -PI/2) {
  576.         /* clamp at pole */
  577.         vmin = -PI/2;
  578.         pole = 1;
  579.     }
  580.     vmax = sv_altdec+sv_fov/2;
  581.     if (vmax >= PI/2) {
  582.         /* clamp at pole */
  583.         vmax = PI/2;
  584.         pole = 1;
  585.     }
  586.     vmin = raddeg(vmin);
  587.     vmax = raddeg(vmax);
  588.  
  589.     /* set horizontal min and max.
  590.      * if pole is visible, we go all the way around.
  591.      * else compute spherical angle spanned by fov "del" from pole.
  592.      * again, compute ticks in the units we display in.
  593.      */
  594.     if (pole) {
  595.         /* pole is visible */
  596.         hmin = 0.0;
  597.         hmax = 2*PI;
  598.     } else {
  599.         double del = PI/2 - fabs(sv_altdec);
  600.         double a= acos((cos(sv_fov) - cos(del)*cos(del))/sin(del)/sin(del));
  601.         hmin = sv_azra-a/2;
  602.         hmax = sv_azra+a/2;
  603.     }
  604.     hmin = aa_mode ? raddeg(hmin) : radhr(hmin);
  605.     hmax = aa_mode ? raddeg(hmax) : radhr(hmax);
  606.  
  607.     /* find tick marks.
  608.      * generally get less than half the max, so insure it to be consistent.
  609.      * N.B. remember that tickmarks() can return up to 2 more than asked.
  610.      */
  611.     nvt = tickmarks(vmin, vmax, NGRID-2, vticks);
  612.     nht = tickmarks(hmin, hmax, NGRID-2, hticks);
  613.  
  614.     /* report the spacing */
  615.     (void) sprintf (msg, "%s: %g Degs", aa_mode ? "Alt" : "Dec",
  616.                         (vticks[nvt-1]-vticks[0])/(nvt-1));
  617.     f_showit (vgrid_w, msg);
  618.     (void) sprintf (msg, " %s: %g %s", aa_mode ? "Az" : "RA",
  619.         (hticks[nht-1]-hticks[0])/(nht-1), aa_mode ? "Degs" : "Hrs");
  620.     f_showit (hgrid_w, msg);
  621.  
  622.     /* convert back to rads */
  623.     for (i = 0; i < nvt; i++)
  624.         vticks[i] = degrad(vticks[i]);
  625.     for (i = 0; i < nht; i++)
  626.         hticks[i] = aa_mode ? degrad(hticks[i]) : hrrad(hticks[i]);
  627.  
  628.     /* for each horizontal tick mark
  629.      *   for each vertical tick mark
  630.      *     compute coord on screen
  631.      *     if we've at least 2 pts now
  632.      *       connect the points with what is visible within the circle.
  633.      */
  634.     for (i = 0; i < nht; i += 1) {
  635.         double h = hticks[i];
  636.         int before = 0;
  637.         int vis1, vis2;
  638.         int x1, y1, x2, y2;
  639.         xs = xsegments;
  640.         for (j = 0; j < nvt; j++) {
  641.         double v = vticks[j];
  642.         vis2 = sv_loc(r, v, h, &x2, &y2);
  643.         if (before++ && (vis1 || vis2)) {
  644.             int sx1, sy1, sx2, sy2;
  645.             if (lc(0,0,r*2,x1,y1,x2,y2,&sx1,&sy1,&sx2,&sy2) == 0) {
  646.             xs->x1 = sx1+xb; xs->y1 = sy1+yb;
  647.             xs->x2 = sx2+xb; xs->y2 = sy2+yb;
  648.             xs++;
  649.             }
  650.         }
  651.         x1 = x2;
  652.         y1 = y2;
  653.         vis1 = vis2;
  654.         }
  655.         XDrawSegments (dsp, win, gc, xsegments, xs - xsegments);
  656.     }
  657.  
  658.     /* for each vertical tick mark
  659.      *   for each horizontal tick mark
  660.      *     compute coord on screen
  661.      *     if we've at least 2 pts now
  662.      *       connect the points with what is visible within the circle.
  663.      *     (break into smaller pieces because these lines tend to curve)
  664.      */
  665.     for (i = 0; i < nvt; i+=1) {
  666.         double v = vticks[i];
  667.         double h1;
  668.         int before = 0;
  669.         int vis1, vis2;
  670.         int x1, y1, x2, y2;
  671.         xs = xsegments;
  672.         for (j = 0; j < nht; j++) {
  673.         double h = hticks[j];
  674.         vis2 = sv_loc(r, v, h, &x2, &y2);
  675.         if (before++ && (vis1 || vis2)) {
  676.             /* last point is at (x1,y1) == (h1,v);
  677.              * this point is at (x2,y2) == (h, v);
  678.              * connect with NSEGS segments.
  679.              */
  680.             int sx1, sy1, sx2, sy2;
  681.             int xt, yt;
  682.             int vist, k;
  683.             for (k = 1; k <= NSEGS; k++) {
  684.             if (k == NSEGS) {
  685.                 xt = x2;
  686.                 yt = y2;
  687.                 vist = vis2;
  688.             } else
  689.                 vist = sv_loc(r, v, h1+k*(h-h1)/NSEGS, &xt, &yt);
  690.             if ((vis1 || vist) &&
  691.                 lc(0,0,r*2,x1,y1,xt,yt,&sx1,&sy1,&sx2,&sy2)==0){
  692.                 xs->x1 = sx1+xb; xs->y1 = sy1+yb;
  693.                 xs->x2 = sx2+xb; xs->y2 = sy2+yb;
  694.                 xs++;
  695.             }
  696.             x1 = xt;
  697.             y1 = yt;
  698.             vis1 = vist;
  699.             }
  700.         }
  701.         x1 = x2;
  702.         y1 = y2;
  703.         h1 = h;
  704.         vis1 = vis2;
  705.         }
  706.         XDrawSegments (dsp, win, gc, xsegments, xs - xsegments);
  707.     }
  708. }
  709.  
  710.  
  711. /* draw the ecliptic on a circle of radius r, x and y borders xb and yb.
  712.  * special thanks to Uwe Bonnes <bon@LTE.E-TECHNIK.uni-erlangen.de>
  713.  */
  714. static void
  715. draw_ecliptic(dsp, win, gc, r, xb, yb)
  716. Display *dsp;
  717. Window win;
  718. GC gc;
  719. unsigned int r;
  720. unsigned int xb, yb;
  721. {
  722. #define    ECL_CACHE_SZ    100
  723.     XPoint point_cache[ECL_CACHE_SZ];
  724.     double elat0, elng0;    /* ecliptic lat and long at center of fov */
  725.     double elngmin, elngmax;/* ecliptic long limits */
  726.     double ra, dec;
  727.     double elng;
  728.     double lst;
  729.     int ncache;
  730.     Now *np;
  731.  
  732.     np = mm_get_now();
  733.     now_lst (np, &lst);
  734.  
  735.     /* find ecliptic coords of center of view */
  736.     if (aa_mode) {
  737.         double ha0;        /* local hour angle */
  738.         aa_hadec (lat, sv_altdec, sv_azra, &ha0, &dec);
  739.         ra = hrrad(lst) - ha0;
  740.     } else {
  741.         ra = sv_azra;
  742.         dec = sv_altdec;
  743.     }
  744.     eq_ecl (mjd, ra, dec, &elat0, &elng0);
  745.  
  746.     /* no ecliptic visible if ecliptic latitude at center of view 
  747.      * is not less than fov/2
  748.      */
  749.     if (fabs(elat0) >= sv_fov/2.0)
  750.         return;
  751.  
  752.     /* worst-case elong limits is center elong += half fov */
  753.     elngmin = elng0 - sv_fov/2.0;
  754.     elngmax = elng0 + sv_fov/2.0;
  755.  
  756.     /* put a mark at every ECL_TICS pixels */
  757.     ncache = 0;
  758.     for (elng = elngmin; elng <= elngmax; elng += sv_fov/(2.0*r/ECL_TICS)) {
  759.         int x, y;
  760.         double altdec, azra;
  761.  
  762.         /* convert longitude along the ecliptic to ra/dec */
  763.         ecl_eq (mjd, 0.0, elng, &azra, &altdec);
  764.  
  765.         /* if in aa mode, we need it in alt/az */
  766.         if (aa_mode) {
  767.         hadec_aa (lat, hrrad(lst) - azra, altdec, &altdec, &azra);
  768.         refract (pressure, temp, altdec, &altdec);
  769.         }
  770.  
  771.         /* if visible, display point */
  772.         if ((!aa_mode || altdec >= 0) && sv_loc (r, altdec, azra, &x, &y)) {
  773.         XPoint *xp = &point_cache[ncache++];
  774.         xp->x = x + xb;
  775.         xp->y = y + yb;
  776.         if (ncache == XtNumber(point_cache)) {
  777.             XDrawPoints (dsp,win,gc,point_cache,ncache,CoordModeOrigin);
  778.             ncache = 0;
  779.         }
  780.         }
  781.     }
  782.  
  783.     if (ncache > 0)
  784.         XDrawPoints (dsp, win, gc, point_cache, ncache, CoordModeOrigin);
  785. }
  786.  
  787. /* given the magnitude of an object, return its desired diameter, in pixels.
  788.  * N.B. we assume it is at least as bright as fmag.
  789.  */
  790. static
  791. magdiam(m)
  792. double m;
  793. {
  794.     return (((int)(fmag-m)+3)/2);
  795. }
  796.  
  797. /* make the general purpose sv_gc and learn the three colors.
  798.  */
  799. static void
  800. sv_mk_gcs(dsp, win)
  801. Display *dsp;
  802. Window win;
  803. {
  804.     XGCValues gcv;
  805.     unsigned gcm = 0;
  806.  
  807.     get_something (svda_w, XmNforeground, (char *)&fg_p);
  808.     get_something (svda_w, XmNbackground, (char *)&sky_p);
  809.     get_something (svform_w, XmNbackground, (char *)&bg_p);
  810.     set_something (svda_w, XmNbackground, (char *)bg_p);
  811.  
  812.     sv_gc = XCreateGC (dsp, win, gcm, &gcv);
  813. }
  814.  
  815. /* draw a label for an object that is located at [x,y]
  816.  */
  817. static void
  818. draw_label (dsp, win, gc, label, x, y)
  819. Display *dsp;
  820. Window win;
  821. GC gc;
  822. char label[];
  823. int x, y;
  824. {
  825.     XDrawString (dsp, win, gc, x+4, y-4, label, strlen(label));
  826. }
  827.