[1457] | 1 | /* misc handy functions.
|
---|
| 2 | * every system has such, no?
|
---|
| 3 | * 4/20/98 now_lst() always just returns apparent time
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | #include <stdio.h>
|
---|
| 7 | #include <math.h>
|
---|
| 8 |
|
---|
| 9 | #if defined(__STDC__)
|
---|
| 10 | #include <stdlib.h>
|
---|
| 11 | #include <string.h>
|
---|
| 12 | #else
|
---|
| 13 | extern double atof();
|
---|
| 14 | #endif
|
---|
| 15 |
|
---|
| 16 | #include "P_.h"
|
---|
| 17 | #include "astro.h"
|
---|
| 18 | #include "circum.h"
|
---|
| 19 |
|
---|
| 20 | /* zero from loc for len bytes */
|
---|
| 21 | void
|
---|
| 22 | zero_mem (loc, len)
|
---|
| 23 | void *loc;
|
---|
| 24 | unsigned len;
|
---|
| 25 | {
|
---|
| 26 | (void) memset (loc, 0, len);
|
---|
| 27 | }
|
---|
| 28 |
|
---|
| 29 | /* given min and max and an approximate number of divisions desired,
|
---|
| 30 | * fill in ticks[] with nicely spaced values and return how many.
|
---|
| 31 | * N.B. return value, and hence number of entries to ticks[], might be as
|
---|
| 32 | * much as 2 more than numdiv.
|
---|
| 33 | */
|
---|
| 34 | int
|
---|
| 35 | tickmarks (min, max, numdiv, ticks)
|
---|
| 36 | double min, max;
|
---|
| 37 | int numdiv;
|
---|
| 38 | double ticks[];
|
---|
| 39 | {
|
---|
| 40 | static int factor[] = { 1, 2, 5 };
|
---|
| 41 | double minscale;
|
---|
| 42 | double delta;
|
---|
| 43 | double lo;
|
---|
| 44 | double v;
|
---|
| 45 | int n;
|
---|
| 46 |
|
---|
| 47 | minscale = fabs(max - min);
|
---|
| 48 | delta = minscale/numdiv;
|
---|
| 49 | for (n=0; n < sizeof(factor)/sizeof(factor[0]); n++) {
|
---|
| 50 | double scale;
|
---|
| 51 | double x = delta/factor[n];
|
---|
| 52 | if ((scale = (pow(10.0, ceil(log10(x)))*factor[n])) < minscale)
|
---|
| 53 | minscale = scale;
|
---|
| 54 | }
|
---|
| 55 | delta = minscale;
|
---|
| 56 |
|
---|
| 57 | lo = floor(min/delta);
|
---|
| 58 | for (n = 0; (v = delta*(lo+n)) < max+delta; )
|
---|
| 59 | ticks[n++] = v;
|
---|
| 60 |
|
---|
| 61 | return (n);
|
---|
| 62 | }
|
---|
| 63 |
|
---|
| 64 | /* given an Obj *, return its type as a descriptive string.
|
---|
| 65 | * if it's of type fixed then return its class description.
|
---|
| 66 | * N.B. we return the address of static storage -- do not free or change.
|
---|
| 67 | */
|
---|
| 68 | char *
|
---|
| 69 | obj_description (op)
|
---|
| 70 | Obj *op;
|
---|
| 71 | {
|
---|
| 72 | static struct {
|
---|
| 73 | char class;
|
---|
| 74 | char *desc;
|
---|
| 75 | } fixed_class_map[] = {
|
---|
| 76 | {'A', "Cluster of Galaxies"},
|
---|
| 77 | {'B', "Binary Star"},
|
---|
| 78 | {'C', "Globular Cluster"},
|
---|
| 79 | {'D', "Double Star"},
|
---|
| 80 | {'F', "Diffuse Nebula"},
|
---|
| 81 | {'G', "Spiral Galaxy"},
|
---|
| 82 | {'H', "Spherical Galaxy"},
|
---|
| 83 | {'J', "Radio"},
|
---|
| 84 | {'K', "Dark Nebula"},
|
---|
| 85 | {'L', "Pulsar"},
|
---|
| 86 | {'M', "Multiple Star"},
|
---|
| 87 | {'N', "Bright Nebula"},
|
---|
| 88 | {'O', "Open Cluster"},
|
---|
| 89 | {'P', "Planetary Nebula"},
|
---|
| 90 | {'Q', "Quasar"},
|
---|
| 91 | {'R', "Supernova Remnant"},
|
---|
| 92 | {'S', "Star"},
|
---|
| 93 | {'T', "Star-like Object"},
|
---|
| 94 | {'U', "Cluster, with nebulosity"},
|
---|
| 95 | {'V', "Variable Star"},
|
---|
| 96 | };
|
---|
| 97 | #define NFCM (sizeof(fixed_class_map)/sizeof(fixed_class_map[0]))
|
---|
| 98 |
|
---|
| 99 | switch (op->o_type) {
|
---|
| 100 | case FIXED:
|
---|
| 101 | if (op->f_class) {
|
---|
| 102 | int i;
|
---|
| 103 | for (i = 0; i < NFCM; i++)
|
---|
| 104 | if (fixed_class_map[i].class == op->f_class)
|
---|
| 105 | return (fixed_class_map[i].desc);
|
---|
| 106 | }
|
---|
| 107 | return (op->o_type == FIXED ? "Fixed" : "Field Star");
|
---|
| 108 | case PARABOLIC:
|
---|
| 109 | return ("Solar - Parabolic");
|
---|
| 110 | case HYPERBOLIC:
|
---|
| 111 | return ("Solar - Hyperbolic");
|
---|
| 112 | case ELLIPTICAL:
|
---|
| 113 | return ("Solar - Elliptical");
|
---|
| 114 | case PLANET:
|
---|
| 115 | return ("Planet");
|
---|
| 116 | case EARTHSAT:
|
---|
| 117 | return ("Earth Sat");
|
---|
| 118 | default:
|
---|
| 119 | printf ("obj_description: unknown type: 0x%x\n", op->o_type);
|
---|
| 120 | exit (1);
|
---|
| 121 | return (NULL); /* for lint */
|
---|
| 122 | }
|
---|
| 123 | }
|
---|
| 124 |
|
---|
| 125 | /* given a Now *, find the local apparent sidereal time, in hours.
|
---|
| 126 | */
|
---|
| 127 | void
|
---|
| 128 | now_lst (np, lstp)
|
---|
| 129 | Now *np;
|
---|
| 130 | double *lstp;
|
---|
| 131 | {
|
---|
| 132 | static double last_mjd = -23243, last_lng = 121212, last_lst;
|
---|
| 133 | double eps, lst, deps, dpsi;
|
---|
| 134 |
|
---|
| 135 | if (last_mjd == mjd && last_lng == lng) {
|
---|
| 136 | *lstp = last_lst;
|
---|
| 137 | return;
|
---|
| 138 | }
|
---|
| 139 |
|
---|
| 140 | utc_gst (mjd_day(mjd), mjd_hr(mjd), &lst);
|
---|
| 141 | lst += radhr(lng);
|
---|
| 142 |
|
---|
| 143 | obliquity(mjd, &eps);
|
---|
| 144 | nutation(mjd, &deps, &dpsi);
|
---|
| 145 | lst += radhr(dpsi*cos(eps+deps));
|
---|
| 146 |
|
---|
| 147 | range (&lst, 24.0);
|
---|
| 148 |
|
---|
| 149 | last_mjd = mjd;
|
---|
| 150 | last_lng = lng;
|
---|
| 151 | *lstp = last_lst = lst;
|
---|
| 152 | }
|
---|
| 153 |
|
---|
| 154 | /* convert ra to ha, in range -PI .. PI.
|
---|
| 155 | * need dec too if not already apparent.
|
---|
| 156 | */
|
---|
| 157 | void
|
---|
| 158 | radec2ha (np, ra, dec, hap)
|
---|
| 159 | Now *np;
|
---|
| 160 | double ra, dec;
|
---|
| 161 | double *hap;
|
---|
| 162 | {
|
---|
| 163 | double ha, lst;
|
---|
| 164 |
|
---|
| 165 | if (epoch != EOD)
|
---|
| 166 | as_ap (np, epoch, &ra, &dec);
|
---|
| 167 | now_lst (np, &lst);
|
---|
| 168 | ha = hrrad(lst) - ra;
|
---|
| 169 | if (ha < -PI) ha += 2*PI;
|
---|
| 170 | if (ha > PI) ha -= 2*PI;
|
---|
| 171 | *hap = ha;
|
---|
| 172 | }
|
---|
| 173 |
|
---|
| 174 | /* given a circle and a line segment, find a segment of the line inside the
|
---|
| 175 | * circle.
|
---|
| 176 | * return 0 and the segment end points if one exists, else -1.
|
---|
| 177 | * We use a parametric representation of the line:
|
---|
| 178 | * x = x1 + (x2-x1)*t and y = y1 + (y2-y1)*t, 0 < t < 1
|
---|
| 179 | * and a centered representation of the circle:
|
---|
| 180 | * (x - xc)**2 + (y - yc)**2 = r**2
|
---|
| 181 | * and solve for the t's that work, checking for usual conditions.
|
---|
| 182 | */
|
---|
| 183 | int
|
---|
| 184 | lc (cx, cy, cw, x1, y1, x2, y2, sx1, sy1, sx2, sy2)
|
---|
| 185 | int cx, cy, cw; /* circle bounding box corner and width */
|
---|
| 186 | int x1, y1, x2, y2; /* line segment endpoints */
|
---|
| 187 | int *sx1, *sy1, *sx2, *sy2; /* segment inside the circle */
|
---|
| 188 | {
|
---|
| 189 | int dx = x2 - x1;
|
---|
| 190 | int dy = y2 - y1;
|
---|
| 191 | int r = cw/2;
|
---|
| 192 | int xc = cx + r;
|
---|
| 193 | int yc = cy + r;
|
---|
| 194 | int A = x1 - xc;
|
---|
| 195 | int B = y1 - yc;
|
---|
| 196 | double a = dx*dx + dy*dy; /* O(2 * 2**16 * 2**16) */
|
---|
| 197 | double b = 2*(dx*A + dy*B); /* O(4 * 2**16 * 2**16) */
|
---|
| 198 | double c = A*A + B*B - r*r; /* O(2 * 2**16 * 2**16) */
|
---|
| 199 | double d = b*b - 4*a*c; /* O(2**32 * 2**32) */
|
---|
| 200 | double sqrtd;
|
---|
| 201 | double t1, t2;
|
---|
| 202 |
|
---|
| 203 | if (d <= 0)
|
---|
| 204 | return (-1); /* containing line is purely outside circle */
|
---|
| 205 |
|
---|
| 206 | sqrtd = sqrt(d);
|
---|
| 207 | t1 = (-b - sqrtd)/(2.0*a);
|
---|
| 208 | t2 = (-b + sqrtd)/(2.0*a);
|
---|
| 209 |
|
---|
| 210 | if (t1 >= 1.0 || t2 <= 0.0)
|
---|
| 211 | return (-1); /* segment is purely outside circle */
|
---|
| 212 |
|
---|
| 213 | /* we know now that some part of the segment is inside,
|
---|
| 214 | * ie, t1 < 1 && t2 > 0
|
---|
| 215 | */
|
---|
| 216 |
|
---|
| 217 | if (t1 <= 0.0) {
|
---|
| 218 | /* (x1,y1) is inside circle */
|
---|
| 219 | *sx1 = x1;
|
---|
| 220 | *sy1 = y1;
|
---|
| 221 | } else {
|
---|
| 222 | *sx1 = (int)(x1 + dx*t1);
|
---|
| 223 | *sy1 = (int)(y1 + dy*t1);
|
---|
| 224 | }
|
---|
| 225 |
|
---|
| 226 | if (t2 >= 1.0) {
|
---|
| 227 | /* (x2,y2) is inside circle */
|
---|
| 228 | *sx2 = x2;
|
---|
| 229 | *sy2 = y2;
|
---|
| 230 | } else {
|
---|
| 231 | *sx2 = (int)(x1 + dx*t2);
|
---|
| 232 | *sy2 = (int)(y1 + dy*t2);
|
---|
| 233 | }
|
---|
| 234 |
|
---|
| 235 | return (0);
|
---|
| 236 | }
|
---|
| 237 |
|
---|
| 238 | /* compute visual magnitude using the H/G parameters used in the Astro Almanac.
|
---|
| 239 | * these are commonly used for asteroids.
|
---|
| 240 | */
|
---|
| 241 | void
|
---|
| 242 | hg_mag (h, g, rp, rho, rsn, mp)
|
---|
| 243 | double h, g;
|
---|
| 244 | double rp; /* sun-obj dist, AU */
|
---|
| 245 | double rho; /* earth-obj dist, AU */
|
---|
| 246 | double rsn; /* sun-earth dist, AU */
|
---|
| 247 | double *mp;
|
---|
| 248 | {
|
---|
| 249 | double psi_t, Psi_1, Psi_2, beta;
|
---|
| 250 | double c;
|
---|
| 251 | double tb2;
|
---|
| 252 |
|
---|
| 253 | c = (rp*rp + rho*rho - rsn*rsn)/(2*rp*rho);
|
---|
| 254 | if (c <= -1)
|
---|
| 255 | beta = PI;
|
---|
| 256 | else if (c >= 1)
|
---|
| 257 | beta = 0;
|
---|
| 258 | else
|
---|
| 259 | beta = acos(c);;
|
---|
| 260 | tb2 = tan(beta/2.0);
|
---|
| 261 | /* psi_t = exp(log(tan(beta/2.0))*0.63); */
|
---|
| 262 | psi_t = pow (tb2, 0.63);
|
---|
| 263 | Psi_1 = exp(-3.33*psi_t);
|
---|
| 264 | /* psi_t = exp(log(tan(beta/2.0))*1.22); */
|
---|
| 265 | psi_t = pow (tb2, 1.22);
|
---|
| 266 | Psi_2 = exp(-1.87*psi_t);
|
---|
| 267 | *mp = h + 5.0*log10(rp*rho) - 2.5*log10((1-g)*Psi_1 + g*Psi_2);
|
---|
| 268 | }
|
---|
| 269 |
|
---|
| 270 | /* given faintest desired mag, mag step magstp, image scale and object
|
---|
| 271 | * magnitude and size, return diameter to draw object, in pixels, or 0 if
|
---|
| 272 | * dimmer than fmag.
|
---|
| 273 | */
|
---|
| 274 | int
|
---|
| 275 | magdiam (fmag, magstp, scale, mag, size)
|
---|
| 276 | int fmag; /* faintest mag */
|
---|
| 277 | int magstp; /* mag range per dot size */
|
---|
| 278 | double scale; /* rads per pixel */
|
---|
| 279 | double mag; /* magnitude */
|
---|
| 280 | double size; /* rads, or 0 */
|
---|
| 281 | {
|
---|
| 282 | int diam, sized;
|
---|
| 283 |
|
---|
| 284 | if (mag > fmag)
|
---|
| 285 | return (0);
|
---|
| 286 | diam = (int)((fmag - mag)/magstp + 1);
|
---|
| 287 | sized = (int)(size/scale + 0.5);
|
---|
| 288 | if (sized > diam)
|
---|
| 289 | diam = sized;
|
---|
| 290 |
|
---|
| 291 | return (diam);
|
---|
| 292 | }
|
---|
| 293 |
|
---|
| 294 | /* computer visual magnitude using the g/k parameters commonly used for comets.
|
---|
| 295 | */
|
---|
| 296 | void
|
---|
| 297 | gk_mag (g, k, rp, rho, mp)
|
---|
| 298 | double g, k;
|
---|
| 299 | double rp; /* sun-obj dist, AU */
|
---|
| 300 | double rho; /* earth-obj dist, AU */
|
---|
| 301 | double *mp;
|
---|
| 302 | {
|
---|
| 303 | *mp = g + 5.0*log10(rho) + 2.5*k*log10(rp);
|
---|
| 304 | }
|
---|
| 305 |
|
---|
| 306 | /* given a string convert to floating point and return it as a double.
|
---|
| 307 | * this is to isolate possible unportabilities associated with declaring atof().
|
---|
| 308 | * it's worth it because atof() is often some 50% faster than sscanf ("%lf");
|
---|
| 309 | */
|
---|
| 310 | double
|
---|
| 311 | atod (buf)
|
---|
| 312 | char *buf;
|
---|
| 313 | {
|
---|
| 314 | return (atof (buf));
|
---|
| 315 | }
|
---|
| 316 |
|
---|
| 317 | /* solve a spherical triangle:
|
---|
| 318 | * A
|
---|
| 319 | * / \
|
---|
| 320 | * / \
|
---|
| 321 | * c / \ b
|
---|
| 322 | * / \
|
---|
| 323 | * / \
|
---|
| 324 | * B ____________ C
|
---|
| 325 | * a
|
---|
| 326 | *
|
---|
| 327 | * given A, b, c find B and a in range 0..B..2PI and 0..a..PI, respectively..
|
---|
| 328 | * cap and Bp may be NULL if not interested in either one.
|
---|
| 329 | * N.B. we pass in cos(c) and sin(c) because in many problems one of the sides
|
---|
| 330 | * remains constant for many values of A and b.
|
---|
| 331 | */
|
---|
| 332 | void
|
---|
| 333 | solve_sphere (A, b, cc, sc, cap, Bp)
|
---|
| 334 | double A, b;
|
---|
| 335 | double cc, sc;
|
---|
| 336 | double *cap, *Bp;
|
---|
| 337 | {
|
---|
| 338 | double cb = cos(b), sb = sin(b);
|
---|
| 339 | double cA = cos(A);
|
---|
| 340 | double ca;
|
---|
| 341 | double B;
|
---|
| 342 |
|
---|
| 343 | ca = cb*cc + sb*sc*cA;
|
---|
| 344 | if (ca > 1.0) ca = 1.0;
|
---|
| 345 | if (ca < -1.0) ca = -1.0;
|
---|
| 346 | if (cap)
|
---|
| 347 | *cap = ca;
|
---|
| 348 |
|
---|
| 349 | if (!Bp)
|
---|
| 350 | return;
|
---|
| 351 |
|
---|
| 352 | if (cc > .99999) {
|
---|
| 353 | /* as c approaches 0, B approaches pi - A */
|
---|
| 354 | B = PI - A;
|
---|
| 355 | } else if (cc < -.99999) {
|
---|
| 356 | /* as c approaches PI, B approaches A */
|
---|
| 357 | B = A;
|
---|
| 358 | } else {
|
---|
| 359 | /* compute cB and sB and remove common factor of sa from quotient.
|
---|
| 360 | * be careful where B causes atan to blow.
|
---|
| 361 | */
|
---|
| 362 | double sA = sin(A);
|
---|
| 363 | double x, y;
|
---|
| 364 |
|
---|
| 365 | y = sA*sb*sc;
|
---|
| 366 | x = cb - ca*cc;
|
---|
| 367 |
|
---|
| 368 | if (fabs(x) < 1e-5)
|
---|
| 369 | B = y < 0 ? 3*PI/2 : PI/2;
|
---|
| 370 | else
|
---|
| 371 | B = atan2 (y, x);
|
---|
| 372 | }
|
---|
| 373 |
|
---|
| 374 | *Bp = B;
|
---|
| 375 | range (Bp, 2*PI);
|
---|
| 376 | }
|
---|
| 377 |
|
---|
| 378 | /* #define WANT_MATHERR if your system supports it. it gives SGI fits.
|
---|
| 379 | */
|
---|
| 380 | #undef WANT_MATHERR
|
---|
| 381 | #if defined(WANT_MATHERR)
|
---|
| 382 | /* attempt to do *something* reasonable when a math function blows.
|
---|
| 383 | */
|
---|
| 384 | matherr (xp)
|
---|
| 385 | struct exception *xp;
|
---|
| 386 | {
|
---|
| 387 | static char *names[8] = {
|
---|
| 388 | "acos", "asin", "atan2", "pow",
|
---|
| 389 | "exp", "log", "log10", "sqrt"
|
---|
| 390 | };
|
---|
| 391 | int i;
|
---|
| 392 |
|
---|
| 393 | /* catch-all */
|
---|
| 394 | xp->retval = 0.0;
|
---|
| 395 |
|
---|
| 396 | for (i = 0; i < sizeof(names)/sizeof(names[0]); i++)
|
---|
| 397 | if (strcmp (xp->name, names[i]) == 0)
|
---|
| 398 | switch (i) {
|
---|
| 399 | case 0: /* acos */
|
---|
| 400 | xp->retval = xp->arg1 >= 1.0 ? 0.0 : -PI;
|
---|
| 401 | break;
|
---|
| 402 | case 1: /* asin */
|
---|
| 403 | xp->retval = xp->arg1 >= 1.0 ? PI/2 : -PI/2;
|
---|
| 404 | break;
|
---|
| 405 | case 2: /* atan2 */
|
---|
| 406 | if (xp->arg1 == 0.0)
|
---|
| 407 | xp->retval = xp->arg2 < 0.0 ? PI : 0.0;
|
---|
| 408 | else if (xp->arg2 == 0.0)
|
---|
| 409 | xp->retval = xp->arg1 < 0.0 ? -PI/2 : PI/2;
|
---|
| 410 | else
|
---|
| 411 | xp->retval = 0.0;
|
---|
| 412 | break;
|
---|
| 413 | case 3: /* pow */
|
---|
| 414 | /* FALLTHRU */
|
---|
| 415 | case 4: /* exp */
|
---|
| 416 | xp->retval = xp->o_type == OVERFLOW ? 1e308 : 0.0;
|
---|
| 417 | break;
|
---|
| 418 | case 5: /* log */
|
---|
| 419 | /* FALLTHRU */
|
---|
| 420 | case 6: /* log10 */
|
---|
| 421 | xp->retval = xp->arg1 <= 0.0 ? -1e308 : 0;
|
---|
| 422 | break;
|
---|
| 423 | case 7: /* sqrt */
|
---|
| 424 | xp->retval = 0.0;
|
---|
| 425 | break;
|
---|
| 426 | }
|
---|
| 427 |
|
---|
| 428 | return (1); /* suppress default error handling */
|
---|
| 429 | }
|
---|
| 430 | #endif
|
---|
| 431 |
|
---|
| 432 | /* given the difference in two RA's, in rads, return their difference,
|
---|
| 433 | * accounting for wrap at 2*PI. caller need *not* first force it into the
|
---|
| 434 | * range 0..2*PI.
|
---|
| 435 | */
|
---|
| 436 | double
|
---|
| 437 | delra (dra)
|
---|
| 438 | double dra;
|
---|
| 439 | {
|
---|
| 440 | double fdra = fmod(fabs(dra), 2*PI);
|
---|
| 441 |
|
---|
| 442 | if (fdra > PI)
|
---|
| 443 | fdra = 2*PI - fdra;
|
---|
| 444 | return (fdra);
|
---|
| 445 | }
|
---|
| 446 |
|
---|
| 447 | /* return 1 if object is considered to be "deep sky", else 0.
|
---|
| 448 | * The only things deep-sky are fixed objects other than stars.
|
---|
| 449 | */
|
---|
| 450 | int
|
---|
| 451 | is_deepsky (op)
|
---|
| 452 | Obj *op;
|
---|
| 453 | {
|
---|
| 454 | int deepsky = 0;
|
---|
| 455 |
|
---|
| 456 | if (is_type(op, FIXEDM)) {
|
---|
| 457 | switch (op->f_class) {
|
---|
| 458 | case 'T':
|
---|
| 459 | case 'B':
|
---|
| 460 | case 'D':
|
---|
| 461 | case 'M':
|
---|
| 462 | case 'S':
|
---|
| 463 | case 'V':
|
---|
| 464 | break;
|
---|
| 465 | default:
|
---|
| 466 | deepsky = 1;
|
---|
| 467 | break;
|
---|
| 468 | }
|
---|
| 469 | }
|
---|
| 470 |
|
---|
| 471 | return (deepsky);
|
---|
| 472 | }
|
---|
| 473 |
|
---|
| 474 | /* For RCS Only -- Do Not Edit */
|
---|
[1719] | 475 | static char *rcsid[2] = {(char *)rcsid, "@(#) $RCSfile: misc.c,v $ $Date: 2001-10-22 12:08:27 $ $Revision: 1.2 $ $Name: not supported by cvs2svn $"};
|
---|