/*! * \fn void ln_get_ell_body_equ_coords (double JD, struct ln_ell_orbit * orbit, struct ln_equ_posn * posn) * \param JD Julian Day. * \param orbit Orbital parameters. * \param posn Pointer to hold asteroid position. * * Calculate a bodies equatorial coordinates for the given julian day. */ void ln_get_ell_body_equ_coords (double JD, struct ln_ell_orbit * orbit, struct ln_equ_posn * posn) { struct ln_rect_posn body_rect_posn, sol_rect_posn; double dist, t; double x,y,z; /* get solar and body rect coords */ ln_get_ell_helio_rect_posn (orbit, JD, &body_rect_posn); ln_get_solar_geo_coords (JD, &sol_rect_posn); /* calc distance and light time */ dist = ln_get_rect_distance (&body_rect_posn, &sol_rect_posn); t = ln_get_light_time (dist); /* repeat calculation with new time (i.e. JD - t) */ ln_get_ell_helio_rect_posn (orbit, JD - t, &body_rect_posn); /* calc equ coords equ 33.10 */ x = sol_rect_posn.X + body_rect_posn.X; y = sol_rect_posn.Y + body_rect_posn.Y; z = sol_rect_posn.Z + body_rect_posn.Z; posn->ra = ln_range_degrees(ln_rad_to_deg(atan2 (y,x))); posn->dec = ln_rad_to_deg(asin (z / sqrt (x * x + y * y + z * z))); }
/*! \fn double ln_solve_kepler (double E, double M); * \param E Orbital eccentricity * \param M Mean anomaly * \return Eccentric anomaly * * Calculate the eccentric anomaly. * This method was devised by Roger Sinnott. (Sky and Telescope, Vol 70, pg 159) */ double ln_solve_kepler (double e, double M) { double Eo = M_PI_2; double F, M1; double D = M_PI_4; int i; /* covert to radians */ M = ln_deg_to_rad (M); F = sgn (M); M = fabs (M) / (2.0 * M_PI); M = (M - (int)M) * 2.0 * M_PI * F; if (M < 0) M = M + 2.0 * M_PI; F = 1.0; if (M > M_PI) F = -1.0; if (M > M_PI) M = 2.0 * M_PI - M; for (i = 0; i < KEPLER_STEPS; i++) { M1 = Eo - e * sin (Eo); Eo = Eo + D * sgn (M - M1); D /= 2.0; } Eo *= F; /* back to degrees */ Eo = ln_rad_to_deg (Eo); return Eo; }
/*! \fn double ln_get_ell_body_elong (double JD, struct ln_ell_orbit * orbit); * \param JD Julian day * \param orbit Orbital parameters * \return Elongation to the Sun. * * Calculate the bodies elongation to the Sun.. */ double ln_get_ell_body_elong (double JD, struct ln_ell_orbit * orbit) { double r,R,d; double t; double elong; double E,M; /* time since perihelion */ t = JD - orbit->JD; /* get mean anomaly */ if (orbit->n == 0) orbit->n = ln_get_ell_mean_motion (orbit->a); M = ln_get_ell_mean_anomaly (orbit->n, t); /* get eccentric anomaly */ E = ln_solve_kepler (orbit->e, M); /* get radius vector */ r = ln_get_ell_radius_vector (orbit->a, orbit->e, E); /* get solar and Earth-Sun distances */ R = ln_get_earth_solar_dist (JD); d = ln_get_ell_body_solar_dist (JD, orbit); elong = (R * R + d * d - r * r) / ( 2.0 * R * d ); return ln_range_degrees (ln_rad_to_deg (acos (elong))); }
/* Equ 20.2, 20.4 pg 126 */ void ln_get_equ_prec2 (struct ln_equ_posn * mean_position, double fromJD, double toJD, struct ln_equ_posn * position) { long double t, t2, t3, A, B, C, zeta, eta, theta, ra, dec, mean_ra, mean_dec, T, T2; /* change original ra and dec to radians */ mean_ra = ln_deg_to_rad (mean_position->ra); mean_dec = ln_deg_to_rad (mean_position->dec); /* calc t, T, zeta, eta and theta Equ 20.2 */ T = ((long double) (fromJD - JD2000)) / 36525.0; T *= 1.0 / 3600.0; t = ((long double) (toJD - fromJD)) / 36525.0; t *= 1.0 / 3600.0; T2 = T * T; t2 = t * t; t3 = t2 *t; zeta = (2306.2181 + 1.39656 * T - 0.000139 * T2) * t + (0.30188 - 0.000344 * T) * t2 + 0.017998 * t3; eta = (2306.2181 + 1.39656 * T - 0.000139 * T2) * t + (1.09468 + 0.000066 * T) * t2 + 0.018203 * t3; theta = (2004.3109 - 0.85330 * T - 0.000217 * T2) * t - (0.42665 + 0.000217 * T) * t2 - 0.041833 * t3; zeta = ln_deg_to_rad (zeta); eta = ln_deg_to_rad (eta); theta = ln_deg_to_rad (theta); /* calc A,B,C equ 20.4 */ A = cosl (mean_dec) * sinl (mean_ra + zeta); B = cosl (theta) * cosl (mean_dec) * cosl (mean_ra + zeta) - sinl (theta) * sinl (mean_dec); C = sinl (theta) * cosl (mean_dec) * cosl (mean_ra + zeta) + cosl (theta) * sinl (mean_dec); ra = atan2l (A,B) + eta; /* check for object near celestial pole */ if (mean_dec > (0.4 * M_PI) || mean_dec < (-0.4 * M_PI)) { /* close to pole */ dec = acosl (sqrt(A * A + B * B)); if (mean_dec < 0.) dec *= -1; /* 0 <= acos() <= PI */ } else { /* not close to pole */ dec = asinl (C); } /* change to degrees */ position->ra = ln_range_degrees (ln_rad_to_deg (ra)); position->dec = ln_rad_to_deg (dec); }
/* convert radians to hh:mm:ss */ void ln_rad_to_hms (double radians, struct ln_hms * hms) { double degrees; radians = ln_range_radians(radians); degrees = ln_rad_to_deg(radians); ln_deg_to_hms(degrees, hms); }
/* equ 30.1 */ double ln_get_ell_true_anomaly (double e, double E) { double v; E = ln_deg_to_rad (E); v = sqrt ((1.0 + e) / (1.0 - e)) * tan (E / 2.0); v = 2.0 * atan (v); v = ln_range_degrees (ln_rad_to_deg (v)); return v; }
/* equ 30.1 */ double ln_get_par_true_anomaly (double q, double t) { double v; double s; s = ln_solve_barker (q,t); v = 2.0 * atan (s); return ln_range_degrees(ln_rad_to_deg(v)); }
/* Equ 20.3, 20.4 pg 126 */ void ln_get_equ_prec (struct ln_equ_posn * mean_position, double JD, struct ln_equ_posn * position) { long double t, t2, t3, A, B, C, zeta, eta, theta, ra, dec, mean_ra, mean_dec; /* change original ra and dec to radians */ mean_ra = ln_deg_to_rad (mean_position->ra); mean_dec = ln_deg_to_rad (mean_position->dec); /* calc t, zeta, eta and theta for J2000.0 Equ 20.3 */ t = (JD - JD2000) / 36525.0; t *= 1.0 / 3600.0; t2 = t * t; t3 = t2 *t; zeta = 2306.2181 * t + 0.30188 * t2 + 0.017998 * t3; eta = 2306.2181 * t + 1.09468 * t2 + 0.041833 * t3; theta = 2004.3109 * t - 0.42665 * t2 - 0.041833 * t3; zeta = ln_deg_to_rad (zeta); eta = ln_deg_to_rad (eta); theta = ln_deg_to_rad (theta); /* calc A,B,C equ 20.4 */ A = cosl (mean_dec) * sinl (mean_ra + zeta); B = cosl (theta) * cosl (mean_dec) * cosl (mean_ra + zeta) - sinl (theta) * sinl (mean_dec); C = sinl (theta) * cosl (mean_dec) * cosl (mean_ra + zeta) + cosl (theta) * sinl (mean_dec); ra = atan2l (A,B) + eta; /* check for object near celestial pole */ if (mean_dec > (0.4 * M_PI) || mean_dec < (-0.4 * M_PI)) { /* close to pole */ dec = acosl (sqrt(A * A + B * B)); if (mean_dec < 0.) dec *= -1; /* 0 <= acos() <= PI */ } else { /* not close to pole */ dec = asinl (C); } /* change to degrees */ position->ra = ln_range_degrees (ln_rad_to_deg (ra)); position->dec = ln_rad_to_deg (dec); }
/*! \fn double ln_get_par_body_elong (double JD, struct ln_par_orbit * orbit); * \param JD Julian day * \param orbit Orbital parameters * \return Elongation to the Sun. * * Calculate the bodies elongation to the Sun.. */ double ln_get_par_body_elong (double JD, struct ln_par_orbit * orbit) { double r,R,d; double t; double elong; /* time since perihelion */ t = JD - orbit->JD; /* get radius vector */ r = ln_get_par_radius_vector (orbit->q, t); /* get solar and Earth-Sun distances */ R = ln_get_earth_solar_dist (JD); d = ln_get_par_body_solar_dist (JD, orbit); elong = (R * R + d * d - r * r) / ( 2.0 * R * d ); return ln_range_degrees (ln_rad_to_deg (acos (elong))); }
/*! \fn double ln_get_par_body_phase_angle (double JD, struct ln_par_orbit * orbit); * \param JD Julian day * \param orbit Orbital parameters * \return Phase angle. * * Calculate the phase angle of the body. The angle Sun - body - Earth. */ double ln_get_par_body_phase_angle (double JD, struct ln_par_orbit * orbit) { double r,R,d; double t; double phase; /* time since perihelion */ t = JD - orbit->JD; /* get radius vector */ r = ln_get_par_radius_vector (orbit->q, t); /* get solar and Earth-Sun distances */ R = ln_get_earth_solar_dist (JD); d = ln_get_par_body_solar_dist (JD, orbit); phase = (r * r + d * d - R * R) / ( 2.0 * r * d ); return ln_range_degrees (ln_rad_to_deg (acos (phase))); }
int ln_get_object_rst_horizon_offset (double JD, struct ln_lnlat_posn * observer, struct ln_equ_posn * object, long double horizon, struct ln_rst_time * rst, double ut_offset) { int jd; long double O, JD_UT, H0, H1; double Hat, Har, Has, altr, alts; double mt, mr, ms, mst, msr, mss; double dmt, dmr, dms; int ret, i; if (isnan (ut_offset)) { JD_UT = JD; } else { /* convert local sidereal time into degrees for 0h of UT on day JD */ jd = (int)JD; JD_UT = jd + ut_offset; } O = ln_get_apparent_sidereal_time (JD_UT); O *= 15.0; /* equ 15.1 */ H0 = (sin (ln_deg_to_rad (horizon)) - sin (ln_deg_to_rad (observer->lat)) * sin (ln_deg_to_rad (object->dec))); H1 = (cos (ln_deg_to_rad (observer->lat)) * cos (ln_deg_to_rad (object->dec))); H1 = H0 / H1; ret = check_coords (observer, H1, horizon, object); if (ret) return ret; H0 = acos (H1); H0 = ln_rad_to_deg (H0); /* equ 15.2 */ mt = (object->ra - observer->lng - O) / 360.0; mr = mt - H0 / 360.0; ms = mt + H0 / 360.0; for (i = 0; i < 3; i++) { /* put in correct range */ if (mt > 1.0) mt--; else if (mt < 0) mt++; if (mr > 1.0) mr--; else if (mr < 0) mr++; if (ms > 1.0) ms--; else if (ms < 0) ms++; /* find sidereal time at Greenwich, in degrees, for each m */ mst = O + 360.985647 * mt; msr = O + 360.985647 * mr; mss = O + 360.985647 * ms; /* find local hour angle */ Hat = mst + observer->lng - object->ra; Har = msr + observer->lng - object->ra; Has = mss + observer->lng - object->ra; /* find altitude for rise and set */ altr = sin (ln_deg_to_rad (observer->lat)) * sin (ln_deg_to_rad (object->dec)) + cos (ln_deg_to_rad (observer->lat)) * cos (ln_deg_to_rad (object->dec)) * cos (ln_deg_to_rad (Har)); alts = sin (ln_deg_to_rad (observer->lat)) * sin (ln_deg_to_rad (object->dec)) + cos (ln_deg_to_rad (observer->lat)) * cos (ln_deg_to_rad (object->dec)) * cos (ln_deg_to_rad (Has)); /* must be in degrees */ altr = ln_rad_to_deg (altr); alts = ln_rad_to_deg (alts); /* corrections for m */ ln_range_degrees (Hat); if (Hat > 180.0) Hat -= 360; dmt = -(Hat / 360.0); dmr = (altr - horizon) / (360 * cos (ln_deg_to_rad (object->dec)) * cos (ln_deg_to_rad (observer->lat)) * sin (ln_deg_to_rad (Har))); dms = (alts - horizon) / (360 * cos (ln_deg_to_rad (object->dec)) * cos (ln_deg_to_rad (observer->lat)) * sin (ln_deg_to_rad (Has))); /* add corrections and change to JD */ mt += dmt; mr += dmr; ms += dms; if (mt <= 1 && mt >= 0 && mr <= 1 && mr >= 0 && ms <= 1 && ms >= 0) break; } rst->rise = JD_UT + mr; rst->transit = JD_UT + mt; rst->set = JD_UT + ms; /* not circumpolar */ return 0; }
int ln_get_motion_body_rst_horizon_offset (double JD, struct ln_lnlat_posn * observer, get_motion_body_coords_t get_motion_body_coords, void * orbit, double horizon, struct ln_rst_time * rst, double ut_offset) { int jd; double T, O, JD_UT, H0, H1; double Hat, Har, Has, altr, alts; double mt, mr, ms, mst, msr, mss, nt, nr, ns; struct ln_equ_posn sol1, sol2, sol3, post, posr, poss; double dmt, dmr, dms; int ret, i; /* dynamical time diff */ T = ln_get_dynamical_time_diff (JD); if (isnan (ut_offset)) { JD_UT = JD; } else { jd = (int)JD; JD_UT = jd + ut_offset; } O = ln_get_apparent_sidereal_time (JD_UT); O *= 15.0; /* get body coords for JD_UT -1, JD_UT and JD_UT + 1 */ get_motion_body_coords (JD_UT - 1.0, orbit, &sol1); get_motion_body_coords (JD_UT, orbit, &sol2); get_motion_body_coords (JD_UT + 1.0, orbit, &sol3); /* equ 15.1 */ H0 = (sin(ln_deg_to_rad (horizon)) - sin(ln_deg_to_rad(observer->lat)) * sin(ln_deg_to_rad(sol2.dec))); H1 = (cos(ln_deg_to_rad(observer->lat)) * cos(ln_deg_to_rad(sol2.dec))); H1 = H0 / H1; ret = check_coords (observer, H1, horizon, &sol2); if (ret) return ret; H0 = acos (H1); H0 = ln_rad_to_deg (H0); /* correct ra values for interpolation - put them to the same side of circle */ if ((sol1.ra - sol2.ra) > 180.0) sol2.ra += 360; if ((sol2.ra - sol3.ra) > 180.0) sol3.ra += 360; if ((sol3.ra - sol2.ra) > 180.0) sol3.ra -= 360; if ((sol2.ra - sol1.ra) > 180.0) sol3.ra -= 360; for (i = 0; i < 3; i++) { /* equ 15.2 */ mt = (sol2.ra - observer->lng - O) / 360.0; mr = mt - H0 / 360.0; ms = mt + H0 / 360.0; /* put in correct range */ if (mt > 1.0 ) mt--; else if (mt < 0.0) mt++; if (mr > 1.0 ) mr--; else if (mr < 0.0) mr++; if (ms > 1.0 ) ms--; else if (ms < 0.0) ms++; /* find sidereal time at Greenwich, in degrees, for each m*/ mst = O + 360.985647 * mt; msr = O + 360.985647 * mr; mss = O + 360.985647 * ms; nt = mt + T / 86400.0; nr = mr + T / 86400.0; ns = ms + T / 86400.0; /* interpolate ra and dec for each m, except for transit dec (dec2) */ posr.ra = ln_interpolate3 (nr, sol1.ra, sol2.ra, sol3.ra); posr.dec = ln_interpolate3 (nr, sol1.dec, sol2.dec, sol3.dec); post.ra = ln_interpolate3 (nt, sol1.ra, sol2.ra, sol3.ra); poss.ra = ln_interpolate3 (ns, sol1.ra, sol2.ra, sol3.ra); poss.dec = ln_interpolate3 (ns, sol1.dec, sol2.dec, sol3.dec); /* find local hour angle */ Hat = mst + observer->lng - post.ra; Har = msr + observer->lng - posr.ra; Has = mss + observer->lng - poss.ra; /* find altitude for rise and set */ altr = sin(ln_deg_to_rad(observer->lat)) * sin(ln_deg_to_rad(posr.dec)) + cos(ln_deg_to_rad(observer->lat)) * cos(ln_deg_to_rad(posr.dec)) * cos(ln_deg_to_rad (Har)); alts = sin(ln_deg_to_rad(observer->lat)) * sin(ln_deg_to_rad(poss.dec)) + cos(ln_deg_to_rad(observer->lat)) * cos(ln_deg_to_rad(poss.dec)) * cos(ln_deg_to_rad (Has)); /* corrections for m */ dmt = - (Hat / 360.0); dmr = (altr - horizon) / (360 * cos(ln_deg_to_rad(posr.dec)) * cos(ln_deg_to_rad(observer->lat)) * sin(ln_deg_to_rad(Har))); dms = (alts - horizon) / (360 * cos(ln_deg_to_rad(poss.dec)) * cos(ln_deg_to_rad(observer->lat)) * sin(ln_deg_to_rad(Has))); /* add corrections and change to JD */ mt += dmt; mr += dmr; ms += dms; if (mt <= 1 && mt >= 0 && mr <= 1 && mr >= 0 && ms <= 1 && ms >= 0) break; } rst->rise = JD_UT + mr; rst->transit = JD_UT + mt; rst->set = JD_UT + ms; /* not circumpolar */ return 0; }
/* convert radians to dms */ void ln_rad_to_dms (double radians, struct ln_dms * dms) { double degrees = ln_rad_to_deg(radians); ln_deg_to_dms(degrees, dms); }