source: Sophya/trunk/SophyaExt/XephemAstroLib/misc.c@ 2437

Last change on this file since 2437 was 1719, checked in by cmv, 24 years ago

Adapted to version 3.5 xephem cmv 22/10/2001

File size: 10.5 KB
Line 
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
13extern 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 */
21void
22zero_mem (loc, len)
23void *loc;
24unsigned 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 */
34int
35tickmarks (min, max, numdiv, ticks)
36double min, max;
37int numdiv;
38double 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 */
68char *
69obj_description (op)
70Obj *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 */
127void
128now_lst (np, lstp)
129Now *np;
130double *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 */
157void
158radec2ha (np, ra, dec, hap)
159Now *np;
160double ra, dec;
161double *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 */
183int
184lc (cx, cy, cw, x1, y1, x2, y2, sx1, sy1, sx2, sy2)
185int cx, cy, cw; /* circle bounding box corner and width */
186int x1, y1, x2, y2; /* line segment endpoints */
187int *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 */
241void
242hg_mag (h, g, rp, rho, rsn, mp)
243double h, g;
244double rp; /* sun-obj dist, AU */
245double rho; /* earth-obj dist, AU */
246double rsn; /* sun-earth dist, AU */
247double *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 */
274int
275magdiam (fmag, magstp, scale, mag, size)
276int fmag; /* faintest mag */
277int magstp; /* mag range per dot size */
278double scale; /* rads per pixel */
279double mag; /* magnitude */
280double 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 */
296void
297gk_mag (g, k, rp, rho, mp)
298double g, k;
299double rp; /* sun-obj dist, AU */
300double rho; /* earth-obj dist, AU */
301double *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 */
310double
311atod (buf)
312char *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 */
332void
333solve_sphere (A, b, cc, sc, cap, Bp)
334double A, b;
335double cc, sc;
336double *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 */
384matherr (xp)
385struct 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 */
436double
437delra (dra)
438double 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 */
450int
451is_deepsky (op)
452Obj *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 */
475static char *rcsid[2] = {(char *)rcsid, "@(#) $RCSfile: misc.c,v $ $Date: 2001-10-22 12:08:27 $ $Revision: 1.2 $ $Name: not supported by cvs2svn $"};
Note: See TracBrowser for help on using the repository browser.