/// <summary> /// Gets longitude of ascending node of Lunar orbit for given instant. /// </summary> /// <param name="jd">Julian Day</param> /// <param name="trueAscendingNode">True if position of true ascending node is needed, false for mean position</param> /// <returns>Longitude of ascending node of Lunar orbit, in degrees.</returns> private static double AscendingNode(double jd, bool trueAscendingNode) { double T = (jd - 2451545.0) / 36525.0; double T2 = T * T; double T3 = T2 * T; double T4 = T3 * T; double Omega = 125.0445479 - 1934.1362891 * T + 0.0020754 * T2 + T3 / 467441.0 - T4 / 60616000.0; if (trueAscendingNode) { // Mean elongation of the Moon double D = 297.8501921 + 445267.1114034 * T - 0.0018819 * T2 + T3 / 545868.0 - T4 / 113065000.0; // Sun's mean anomaly double M = 357.5291092 + 35999.0502909 * T - 0.0001536 * T2 + T3 / 24490000.0; // Moon's mean anomaly double M_ = 134.9633964 + 477198.8675055 * T + 0.0087414 * T2 + T3 / 69699.0 - T4 / 14712000.0; // Moon's argument of latitude (mean dinstance of the Moon from its ascending node) double F = 93.2720950 + 483202.0175233 * T - 0.0036539 * T2 - T3 / 3526000.0 + T4 / 863310000.0; Omega += -1.4979 * Math.Sin(Angle.ToRadians(2 * (D - F))) - 0.1500 * Math.Sin(Angle.ToRadians(M)) - 0.1226 * Math.Sin(Angle.ToRadians(2 * D)) + 0.1176 * Math.Sin(Angle.ToRadians(2 * F)) - 0.0801 * Math.Sin(Angle.ToRadians(2 * (M_ - F))); } return(Angle.To360(Omega)); }
public static CrdsHorizontal WithRefraction(this CrdsHorizontal h0) { //if (h0.Altitude < 0) return h0; double R = 1.02 / Math.Tan(Angle.ToRadians(h0.Altitude + 10.3 / (h0.Altitude + 5.11))); return(new CrdsHorizontal(h0.Azimuth, h0.Altitude + R / 60)); }
/// <summary> /// Performs reduction of equatorial coordinates from one epoch to another /// with using of precessional elements. /// </summary> /// <param name="eq0">Equatorial coordinates for initial epoch.</param> /// <param name="p">Precessional elements for reduction from initial epoch to target (final) epoch.</param> /// <returns>Equatorial coordinates for target (final) epoch.</returns> /// <remarks> /// This method is taken from AA(I), formula 20.4. /// </remarks> public static CrdsEquatorial GetEquatorialCoordinates(CrdsEquatorial eq0, PrecessionalElements p) { CrdsEquatorial eq = new CrdsEquatorial(); double sinDelta0 = Math.Sin(Angle.ToRadians(eq0.Delta)); double cosDelta0 = Math.Cos(Angle.ToRadians(eq0.Delta)); double sinTheta = Math.Sin(Angle.ToRadians(p.theta)); double cosTheta = Math.Cos(Angle.ToRadians(p.theta)); double sinAlpha0Zeta = Math.Sin(Angle.ToRadians(eq0.Alpha + p.zeta)); double cosAlpha0Zeta = Math.Cos(Angle.ToRadians(eq0.Alpha + p.zeta)); double A = cosDelta0 * sinAlpha0Zeta; double B = cosTheta * cosDelta0 * cosAlpha0Zeta - sinTheta * sinDelta0; double C = sinTheta * cosDelta0 * cosAlpha0Zeta + cosTheta * sinDelta0; eq.Alpha = Angle.ToDegrees(Math.Atan2(A, B)) + p.z; eq.Alpha = Angle.To360(eq.Alpha); if (Math.Abs(C) == 1) { eq.Delta = Angle.ToDegrees(Math.Acos(A * A + B * B)); } else { eq.Delta = Angle.ToDegrees(Math.Asin(C)); } return(eq); }
/// <summary> /// Calculates aberration elements for given instant. /// </summary> /// <param name="jde">Julian Ephemeris Day, corresponding to the given instant.</param> /// <returns>Aberration elements for the given instant.</returns> /// <remarks> /// AA(II), pp. 151, 163, 164 /// </remarks> public static AberrationElements AberrationElements(double jde) { double T = (jde - 2451545.0) / 36525.0; double T2 = T * T; double e = 0.016708634 - 0.000042037 * T - 0.0000001267 * T2; double pi = 102.93735 + 1.71946 * T + 0.00046 * T2; // geometric true longitude of the Sun double L0 = 280.46646 + 36000.76983 * T + 0.0003032 * T2; // mean anomaly of the Sun double M = 357.52911 + 35999.05029 * T - 0.0001537 * T2; M = Angle.ToRadians(M); // Sun's equation of the center double C = (1.914602 - 0.004817 * T - 0.000014 * T2) * Math.Sin(M) + (0.019993 - 0.000101 * T) * Math.Sin(2 * M) + 0.000289 * Math.Sin(3 * M); return(new AberrationElements() { e = e, pi = pi, lambda = Angle.To360(L0 + C) }); }
/// <summary> /// Converts heliocentrical coordinates to rectangular topocentrical coordinates. /// </summary> /// <param name="planet">Heliocentrical coordinates of a planet</param> /// <param name="earth">Heliocentrical coordinates of Earth</param> /// <returns>Rectangular topocentrical coordinates of a planet.</returns> public static CrdsRectangular ToRectangular(this CrdsHeliocentrical planet, CrdsHeliocentrical earth) { CrdsRectangular rect = new CrdsRectangular(); double B = Angle.ToRadians(planet.B); double L = Angle.ToRadians(planet.L); double R = planet.R; double B0 = Angle.ToRadians(earth.B); double L0 = Angle.ToRadians(earth.L); double R0 = earth.R; double cosL = Math.Cos(L); double sinL = Math.Sin(L); double cosB = Math.Cos(B); double sinB = Math.Sin(B); double cosL0 = Math.Cos(L0); double sinL0 = Math.Sin(L0); double cosB0 = Math.Cos(B0); double sinB0 = Math.Sin(B0); rect.X = R * cosB * cosL - R0 * cosB0 * cosL0; rect.Y = R * cosB * sinL - R0 * cosB0 * sinL0; rect.Z = R * sinB - R0 * sinB0; return(rect); }
/// <summary> /// Gets magnitude of the Moon by its phase angle. /// </summary> /// <param name="phaseAngle">Phase angle value, in degrees, from 0 to 180.</param> /// <returns>Moon magnitude</returns> /// <remarks> /// Formula is taken from <see href="https://astronomy.stackexchange.com/questions/10246/is-there-a-simple-analytical-formula-for-the-lunar-phase-brightness-curve"/> /// </remarks> public static double Magnitude(double phaseAngle) { double psi = Angle.ToRadians(phaseAngle); double psi4 = Math.Pow(psi, 4); return(-12.73 + 1.49 * Math.Abs(psi) + 0.043 * psi4); }
/// <summary> /// Gets geocentric elongation angle of the Moon from Sun /// </summary> /// <param name="sun">Ecliptical geocentrical coordinates of the Sun</param> /// <param name="moon">Ecliptical geocentrical coordinates of the Moon</param> /// <returns>Geocentric elongation angle, in degrees, from 0 to 180.</returns> /// <remarks> /// AA(II), formula 48.2 /// </remarks> public static double Elongation(CrdsEcliptical sun, CrdsEcliptical moon) { double beta = Angle.ToRadians(moon.Beta); double lambda = Angle.ToRadians(moon.Lambda); double lambda0 = Angle.ToRadians(sun.Lambda); return(Angle.ToDegrees(Math.Acos(Math.Cos(beta) * Math.Cos(lambda - lambda0)))); }
/// <summary> /// Calculates the aberration effect for a celestial body (star or planet) for given instant. /// </summary> /// <param name="ecl">Ecliptical coordinates of the body (not corrected).</param> /// <param name="ae">Aberration elements needed for calculation of aberration correction.</param> /// <returns>Returns aberration correction values for ecliptical coordinates.</returns> /// <remarks> /// AA(II), formula 23.2 /// </remarks> public static CrdsEcliptical AberrationEffect(CrdsEcliptical ecl, AberrationElements ae) { double thetaLambda = Angle.ToRadians(ae.lambda - ecl.Lambda); double piLambda = Angle.ToRadians(ae.pi - ecl.Lambda); double beta = Angle.ToRadians(ecl.Beta); double dLambda = (-k * Math.Cos(thetaLambda) + ae.e * k * Math.Cos(piLambda)) / Math.Cos(beta); double dBeta = -k *Math.Sin(beta) * (Math.Sin(thetaLambda) - ae.e * Math.Sin(piLambda)); return(new CrdsEcliptical(dLambda / 3600, dBeta / 3600)); }
/// <summary> /// Calculates phase angle of the Moon /// </summary> /// <param name="psi">Geocentric elongation of the Moon.</param> /// <param name="R">Distance Earth-Sun, in kilometers</param> /// <param name="Delta">Distance Earth-Moon, in kilometers</param> /// <returns>Phase angle, in degrees, from 0 to 180</returns> /// <remarks> /// AA(II), formula 48.3. /// </remarks> public static double PhaseAngle(double psi, double R, double Delta) { psi = Angle.ToRadians(Math.Abs(psi)); double phaseAngle = Angle.ToDegrees(Math.Atan(R * Math.Sin(psi) / (Delta - R * Math.Cos(psi)))); if (phaseAngle < 0) { phaseAngle += 180; } return(phaseAngle); }
/// <summary> /// Returns nutation corrections for equatorial coordiantes. /// </summary> /// <param name="eq">Initial (not corrected) equatorial coordiantes.</param> /// <param name="ne">Nutation elements for given instant.</param> /// <param name="epsilon">True obliquity of the ecliptic (ε), in degrees.</param> /// <returns>Nutation corrections for equatorial coordiantes.</returns> /// <remarks>AA(II), formula 23.1</remarks> public static CrdsEquatorial NutationEffect(CrdsEquatorial eq, NutationElements ne, double epsilon) { CrdsEquatorial correction = new CrdsEquatorial(); epsilon = Angle.ToRadians(epsilon); double alpha = Angle.ToRadians(eq.Alpha); double delta = Angle.ToRadians(eq.Delta); correction.Alpha = (Math.Cos(epsilon) + Math.Sin(epsilon) * Math.Sin(alpha) * Math.Tan(delta)) * ne.deltaPsi - (Math.Cos(alpha) * Math.Tan(delta)) * ne.deltaEpsilon; correction.Delta = Math.Sin(epsilon) * Math.Cos(alpha) * ne.deltaPsi + Math.Sin(alpha) * ne.deltaEpsilon; return(correction); }
/// <summary> /// Calculates appearance of Saturn rings /// </summary> /// <param name="jd">Julian date to calculate for</param> /// <param name="saturn">Heliocentric coordinates of Saturn.</param> /// <param name="earth">Heliocentric coordinates of Earth.</param> /// <param name="epsilon">True obliquity of ecliptic.</param> /// <returns> /// Appearance data for Saturn rings. /// </returns> /// <remarks> /// Method is taken from AA(II), chapter 45. /// </remarks> public static RingsAppearance SaturnRings(double jd, CrdsHeliocentrical saturn, CrdsHeliocentrical earth, double epsilon) { RingsAppearance rings = new RingsAppearance(); double T = (jd - 2451545.0) / 36525.0; double T2 = T * T; double i = 28.075216 - 0.012998 * T + 0.000004 * T2; double Omega = 169.508470 + 1.394681 * T + 0.000412 * T2; double lambda0 = Omega - 90; double beta0 = 90 - i; i = Angle.ToRadians(i); Omega = Angle.ToRadians(Omega); CrdsEcliptical ecl = saturn.ToRectangular(earth).ToEcliptical(); double beta = Angle.ToRadians(ecl.Beta); double lambda = Angle.ToRadians(ecl.Lambda); rings.B = Angle.ToDegrees(Math.Asin(Math.Sin(i) * Math.Cos(beta) * Math.Sin(lambda - Omega) - Math.Cos(i) * Math.Sin(beta))); rings.a = 375.35 / ecl.Distance; rings.b = rings.a * Math.Sin(Math.Abs(Angle.ToRadians(rings.B))); double N = 113.6655 + 0.8771 * T; double l_ = Angle.ToRadians(saturn.L - 0.01759 / saturn.R); double b_ = Angle.ToRadians(saturn.B - 0.000764 * Math.Cos(Angle.ToRadians(saturn.L - N)) / saturn.R); double U1 = Angle.ToDegrees(Math.Atan((Math.Sin(i) * Math.Sin(b_) + Math.Cos(i) * Math.Cos(b_) * Math.Sin(l_ - Omega)) / (Math.Cos(b_) * Math.Cos(l_ - Omega)))); double U2 = Angle.ToDegrees(Math.Atan((Math.Sin(i) * Math.Sin(beta) + Math.Cos(i) * Math.Cos(beta) * Math.Sin(lambda - Omega)) / (Math.Cos(beta) * Math.Cos(lambda - Omega)))); rings.DeltaU = Math.Abs(U1 - U2); CrdsEcliptical eclPole = new CrdsEcliptical(); eclPole.Set(lambda0, beta0); CrdsEquatorial eq = ecl.ToEquatorial(epsilon); CrdsEquatorial eqPole = eclPole.ToEquatorial(epsilon); double alpha = Angle.ToRadians(eq.Alpha); double delta = Angle.ToRadians(eq.Delta); double alpha0 = Angle.ToRadians(eqPole.Alpha); double delta0 = Angle.ToRadians(eqPole.Delta); double y = Math.Cos(delta0) * Math.Sin(alpha0 - alpha); double x = Math.Sin(delta0) * Math.Cos(delta) - Math.Cos(delta0) * Math.Sin(delta) * Math.Cos(alpha0 - alpha); rings.P = Angle.ToDegrees(Math.Atan2(y, x)); return(rings); }
/// <summary> /// Calculates visible appearance of planet for given date. /// </summary> /// <param name="jd">Julian day</param> /// <param name="planet">Planet number to calculate appearance, 1 = Mercury, 2 = Venus and etc.</param> /// <param name="eq">Equatorial coordinates of the planet</param> /// <param name="distance">Distance from the planet to the Earth</param> /// <returns>Appearance parameters of the planet</returns> /// <remarks> /// This method is based on book "Practical Ephemeris Calculations", Montenbruck. /// See topic 6.4, pp. 88-92. /// </remarks> public static PlanetAppearance PlanetAppearance(double jd, int planet, CrdsEquatorial eq, double distance) { PlanetAppearance a = new PlanetAppearance(); double d = jd - 2451545.0; double T = d / 36525.0; // coordinates of the point to which the north pole of the planet is pointing. CrdsEquatorial eq0 = new CrdsEquatorial(); eq0.Alpha = Angle.To360(cAlpha0[planet - 1][0] + cAlpha0[planet - 1][1] * T + cAlpha0[planet - 1][2] * T); eq0.Delta = cDelta0[planet - 1][0] + cDelta0[planet - 1][1] * T + cDelta0[planet - 1][2] * T; // take light time effect into account d -= PlanetPositions.LightTimeEffect(distance); T = d / 36525.0; // position of null meridian double W = Angle.To360(cW[planet - 1][0] + cW[planet - 1][1] * d + cW[planet - 1][2] * T); double delta = Angle.ToRadians(eq.Delta); double alpha = Angle.ToRadians(eq.Alpha); double delta0 = Angle.ToRadians(eq0.Delta); double dAlpha0 = Angle.ToRadians(eq0.Alpha - eq.Alpha); double sinD = -Math.Sin(delta0) * Math.Sin(delta) - Math.Cos(delta0) * Math.Cos(delta) * Math.Cos(dAlpha0); // planetographic latitude of the Earth a.D = Angle.ToDegrees(Math.Asin(sinD)); double cosD = Math.Cos(Angle.ToRadians(a.D)); double sinP = Math.Cos(delta0) * Math.Sin(dAlpha0) / cosD; double cosP = (Math.Sin(delta0) * Math.Cos(delta) - Math.Cos(delta0) * Math.Sin(delta) * Math.Cos(dAlpha0)) / cosD; // position angle of the axis a.P = Angle.To360(Angle.ToDegrees(Math.Atan2(sinP, cosP))); double sinK = (-Math.Cos(delta0) * Math.Sin(delta) + Math.Sin(delta0) * Math.Cos(delta) * Math.Cos(dAlpha0)) / cosD; double cosK = Math.Cos(delta) * Math.Sin(dAlpha0) / cosD; double K = Angle.ToDegrees(Math.Atan2(sinK, cosK)); // planetographic longitude of the central meridian a.CM = planet == 5 ? JupiterCM2(jd) : Angle.To360(Math.Sign(W) * (W - K)); return(a); }
/// <summary> /// Calculates longitude of Central Meridian of Jupiter in System II. /// </summary> /// <param name="jd">Julian Day</param> /// <returns>Longitude of Central Meridian of Jupiter in System II, in degrees.</returns> /// <remarks> /// This method is based on formula described here: <see href="https://www.projectpluto.com/grs_form.htm"/> /// </remarks> private static double JupiterCM2(double jd) { double jup_mean = (jd - 2455636.938) * 360.0 / 4332.89709; double eqn_center = 5.55 * Math.Sin(Angle.ToRadians(jup_mean)); double angle = (jd - 2451870.628) * 360.0 / 398.884 - eqn_center; double correction = 11 * Math.Sin(Angle.ToRadians(angle)) + 5 * Math.Cos(Angle.ToRadians(angle)) - 1.25 * Math.Cos(Angle.ToRadians(jup_mean)) - eqn_center; double cm = 181.62 + 870.1869147 * jd + correction; return(Angle.To360(cm)); }
/// <summary> /// Gets correction for ecliptical coordinates obtained by VSOP87 theory, /// needed for conversion to standard FK5 system. /// This correction should be used only for high-precision version of VSOP87. /// </summary> /// <param name="jde">Julian Ephemeris Day</param> /// <param name="ecl">Non-corrected ecliptical coordinates of the body.</param> /// <returns>Corrections values for longutude and latitude, in degrees.</returns> /// <remarks> /// AA(II), formula 32.3. /// </remarks> public static CrdsEcliptical CorrectionForFK5(double jde, CrdsEcliptical ecl) { double T = (jde - 2451545) / 36525.0; double L_ = Angle.ToRadians(ecl.Lambda - 1.397 * T - 0.00031 * T * T); double sinL_ = Math.Sin(L_); double cosL_ = Math.Cos(L_); double deltaL = -0.09033 + 0.03916 * (cosL_ + sinL_) * Math.Tan(Angle.ToRadians(ecl.Beta)); double deltaB = 0.03916 * (cosL_ - sinL_); return(new CrdsEcliptical(deltaL / 3600, deltaB / 3600)); }
/// <summary> /// Converts ecliptical coordinates to equatorial. /// </summary> /// <param name="ecl">Pair of ecliptical cooordinates.</param> /// <param name="epsilon">Obliquity of the ecliptic, in degrees.</param> /// <returns>Pair of equatorial coordinates.</returns> public static CrdsEquatorial ToEquatorial(this CrdsEcliptical ecl, double epsilon) { CrdsEquatorial eq = new CrdsEquatorial(); epsilon = Angle.ToRadians(epsilon); double lambda = Angle.ToRadians(ecl.Lambda); double beta = Angle.ToRadians(ecl.Beta); double Y = Math.Sin(lambda) * Math.Cos(epsilon) - Math.Tan(beta) * Math.Sin(epsilon); double X = Math.Cos(lambda); eq.Alpha = Angle.To360(Angle.ToDegrees(Math.Atan2(Y, X))); eq.Delta = Angle.ToDegrees(Math.Asin(Math.Sin(beta) * Math.Cos(epsilon) + Math.Cos(beta) * Math.Sin(epsilon) * Math.Sin(lambda))); return(eq); }
/// <summary> /// Converts equatorial coordinates (for equinox B1950.0) to galactical coordinates. /// </summary> /// <param name="eq">Equatorial coordinates for equinox B1950.0</param> /// <returns>Galactical coordinates.</returns> public static CrdsGalactical ToGalactical(this CrdsEquatorial eq) { CrdsGalactical gal = new CrdsGalactical(); double alpha0_alpha = Angle.ToRadians(192.25 - eq.Alpha); double delta = Angle.ToRadians(eq.Delta); double delta0 = Angle.ToRadians(27.4); double Y = Math.Sin(alpha0_alpha); double X = Math.Cos(alpha0_alpha) * Math.Sin(delta0) - Math.Tan(delta) * Math.Cos(delta0); double sinb = Math.Sin(delta) * Math.Sin(delta0) + Math.Cos(delta) * Math.Cos(delta0) * Math.Cos(alpha0_alpha); gal.l = Angle.To360(303 - Angle.ToDegrees(Math.Atan2(Y, X))); gal.b = Angle.ToDegrees(Math.Asin(sinb)); return(gal); }
/// <summary> /// Converts equatorial coordinates to ecliptical coordinates. /// </summary> /// <param name="eq">Pair of equatorial coordinates.</param> /// <param name="epsilon">Obliquity of the ecliptic, in degrees.</param> /// <returns></returns> public static CrdsEcliptical ToEcliptical(this CrdsEquatorial eq, double epsilon) { CrdsEcliptical ecl = new CrdsEcliptical(); epsilon = Angle.ToRadians(epsilon); double alpha = Angle.ToRadians(eq.Alpha); double delta = Angle.ToRadians(eq.Delta); double Y = Math.Sin(alpha) * Math.Cos(epsilon) + Math.Tan(delta) * Math.Sin(epsilon); double X = Math.Cos(alpha); ecl.Lambda = Angle.ToDegrees(Math.Atan2(Y, X)); ecl.Beta = Angle.ToDegrees(Math.Asin(Math.Sin(delta) * Math.Cos(epsilon) - Math.Cos(delta) * Math.Sin(epsilon) * Math.Sin(alpha))); return(ecl); }
/// <summary> /// Converts galactical coodinates to equatorial, for equinox B1950.0. /// </summary> /// <param name="gal">Galactical coodinates.</param> /// <returns>Equatorial coodinates, for equinox B1950.0.</returns> public static CrdsEquatorial ToEquatorial(this CrdsGalactical gal) { CrdsEquatorial eq = new CrdsEquatorial(); double l_l0 = Angle.ToRadians(gal.l - 123.0); double delta0 = Angle.ToRadians(27.4); double b = Angle.ToRadians(gal.b); double Y = Math.Sin(l_l0); double X = Math.Cos(l_l0) * Math.Sin(delta0) - Math.Tan(b) * Math.Cos(delta0); double sinDelta = Math.Sin(b) * Math.Sin(delta0) + Math.Cos(b) * Math.Cos(delta0) * Math.Cos(l_l0); eq.Alpha = Angle.To360(Angle.ToDegrees(Math.Atan2(Y, X)) + 12.25); eq.Delta = Angle.ToDegrees(Math.Asin(sinDelta)); return(eq); }
/// <summary> /// Converts local horizontal coordinates to equatorial coordinates. /// </summary> /// <param name="hor">Pair of local horizontal coordinates.</param> /// <param name="geo">Geographical of the observer</param> /// <param name="theta0">Local sidereal time.</param> /// <returns>Pair of equatorial coordinates</returns> public static CrdsEquatorial ToEquatorial(this CrdsHorizontal hor, CrdsGeographical geo, double theta0) { CrdsEquatorial eq = new CrdsEquatorial(); double A = Angle.ToRadians(hor.Azimuth); double h = Angle.ToRadians(hor.Altitude); double phi = Angle.ToRadians(geo.Latitude); double Y = Math.Sin(A); double X = Math.Cos(A) * Math.Sin(phi) + Math.Tan(h) * Math.Cos(phi); double H = Angle.ToDegrees(Math.Atan2(Y, X)); eq.Alpha = Angle.To360(theta0 - geo.Longitude - H); eq.Delta = Angle.ToDegrees(Math.Asin(Math.Sin(phi) * Math.Sin(h) - Math.Cos(phi) * Math.Cos(h) * Math.Cos(A))); return(eq); }
/// <summary> /// Converts equatorial coodinates to local horizontal /// </summary> /// <param name="eq">Pair of equatorial coodinates</param> /// <param name="geo">Geographical coordinates of the observer</param> /// <param name="theta0">Local sidereal time</param> /// <remarks> /// Implementation is taken from AA(I), formulae 12.5, 12.6. /// </remarks> public static CrdsHorizontal ToHorizontal(this CrdsEquatorial eq, CrdsGeographical geo, double theta0) { double H = Angle.ToRadians(HourAngle(theta0, geo.Longitude, eq.Alpha)); double phi = Angle.ToRadians(geo.Latitude); double delta = Angle.ToRadians(eq.Delta); CrdsHorizontal hor = new CrdsHorizontal(); double Y = Math.Sin(H); double X = Math.Cos(H) * Math.Sin(phi) - Math.Tan(delta) * Math.Cos(phi); hor.Altitude = Angle.ToDegrees(Math.Asin(Math.Sin(phi) * Math.Sin(delta) + Math.Cos(phi) * Math.Cos(delta) * Math.Cos(H))); hor.Azimuth = Angle.ToDegrees(Math.Atan2(Y, X)); hor.Azimuth = Angle.To360(hor.Azimuth); return(hor); }
/// <summary> /// Calculates topocentric equatorial coordinates of celestial body /// with taking into account correction for parallax. /// </summary> /// <param name="eq">Geocentric equatorial coordinates of the body</param> /// <param name="geo">Geographical coordinates of the body</param> /// <param name="theta0">Apparent sidereal time at Greenwich</param> /// <param name="pi">Parallax of a body</param> /// <returns>Topocentric equatorial coordinates of the celestial body</returns> /// <remarks> /// Method is taken from AA(II), formulae 40.6-40.7. /// </remarks> public static CrdsEquatorial ToTopocentric(this CrdsEquatorial eq, CrdsGeographical geo, double theta0, double pi) { double H = Angle.ToRadians(HourAngle(theta0, geo.Longitude, eq.Alpha)); double delta = Angle.ToRadians(eq.Delta); double sinPi = Math.Sin(Angle.ToRadians(pi)); double A = Math.Cos(delta) * Math.Sin(H); double B = Math.Cos(delta) * Math.Cos(H) - geo.RhoCosPhi * sinPi; double C = Math.Sin(delta) - geo.RhoSinPhi * sinPi; double q = Math.Sqrt(A * A + B * B + C * C); double H_ = Angle.ToDegrees(Math.Atan2(A, B)); double alpha_ = Angle.To360(theta0 - geo.Longitude - H_); double delta_ = Angle.ToDegrees(Math.Asin(C / q)); return(new CrdsEquatorial(alpha_, delta_)); }
/// <summary> /// Calculates the aberration effect for a celestial body (star or planet) for given instant. /// </summary> /// <param name="eq">Equatorial coordinates of the body (not corrected).</param> /// <param name="ae">Aberration elements needed for calculation of aberration correction.</param> /// <returns>Returns aberration correction values for equatorial coordinates.</returns> /// <remarks>AA(II), formula 23.3</remarks> public static CrdsEquatorial AberrationEffect(CrdsEquatorial eq, AberrationElements ae, double epsilon) { double a = Angle.ToRadians(eq.Alpha); double d = Angle.ToRadians(eq.Delta); double theta = Angle.ToRadians(ae.lambda); double pi = Angle.ToRadians(ae.pi); epsilon = Angle.ToRadians(epsilon); double da = -k * (Math.Cos(a) * Math.Cos(theta) * Math.Cos(epsilon) + Math.Sin(a) * Math.Sin(theta)) / Math.Cos(d) + epsilon * k * (Math.Cos(a) * Math.Cos(pi) * Math.Cos(epsilon) + Math.Sin(a) * Math.Sin(pi)) / Math.Cos(d); double m = Math.Tan(epsilon) * Math.Cos(d) - Math.Sin(a) * Math.Sin(d); double dd = -k * (Math.Cos(theta) * Math.Cos(epsilon) * m + Math.Cos(a) * Math.Sin(d) * Math.Sin(theta)) + epsilon * k * (Math.Cos(pi) * Math.Cos(epsilon) * m + Math.Cos(a) * Math.Sin(d) * Math.Sin(pi)); return(new CrdsEquatorial(da / 3600, dd / 3600)); }
public static CrdsEquatorial ToEquatorial(this CrdsRectangular m, CrdsEquatorial planet, double P, double semidiameter) { // convert to polar coordinates // radius-vector of moon, in planet's equatorial radii double r = Math.Sqrt(m.X * m.X + m.Y * m.Y); // rotation angle double theta = Angle.ToDegrees(Math.Atan2(m.Y, m.X)); // rotate with position angle of the planet theta += P; // convert back to rectangular coordinates, but rotated with P angle: double x = r * Math.Cos(Angle.ToRadians(theta)); double y = r * Math.Sin(Angle.ToRadians(theta)); double dAlpha = (1 / Math.Cos(Angle.ToRadians(planet.Delta))) * x * semidiameter / 3600; double dDelta = y * semidiameter / 3600; return(new CrdsEquatorial(planet.Alpha - dAlpha, planet.Delta + dDelta)); }
/// <summary> /// Converts ecliptical coordinates to rectangular coordinates. /// </summary> /// <param name="ecl">Ecliptical coordinates</param> /// <param name="epsilon">Obliquity of the ecliptic, in degrees.</param> /// <returns>Rectangular coordinates.</returns> public static CrdsRectangular ToRectangular(this CrdsEcliptical ecl, double epsilon) { CrdsRectangular rect = new CrdsRectangular(); double beta = Angle.ToRadians(ecl.Beta); double lambda = Angle.ToRadians(ecl.Lambda); double R = ecl.Distance; epsilon = Angle.ToRadians(epsilon); double cosBeta = Math.Cos(beta); double sinBeta = Math.Sin(beta); double sinLambda = Math.Sin(lambda); double cosLambda = Math.Cos(lambda); double sinEpsilon = Math.Sin(epsilon); double cosEpsilon = Math.Cos(epsilon); rect.X = R * cosBeta * cosLambda; rect.Y = R * (cosBeta * sinLambda * cosEpsilon - sinBeta * sinEpsilon); rect.Z = R * (cosBeta * sinLambda * sinEpsilon + sinBeta * cosEpsilon); return(rect); }
/// <summary> /// Gets geocentric elongation angle of the celestial body /// </summary> /// <param name="sun">Ecliptical geocentrical coordinates of the Sun</param> /// <param name="body">Ecliptical geocentrical coordinates of the body</param> /// <returns>Geocentric elongation angle, in degrees, from -180 to 180. /// Negative sign means western elongation, positive eastern. /// </returns> /// <remarks> /// AA(II), formula 48.2 /// </remarks> // TODO: tests public static double Elongation(CrdsEcliptical sun, CrdsEcliptical body) { double beta = Angle.ToRadians(body.Beta); double lambda = Angle.ToRadians(body.Lambda); double lambda0 = Angle.ToRadians(sun.Lambda); double s = sun.Lambda; double b = body.Lambda; if (Math.Abs(s - b) > 180) { if (s < b) { s += 360; } else { b += 360; } } return(Math.Sign(b - s) * Angle.ToDegrees(Math.Acos(Math.Cos(beta) * Math.Cos(lambda - lambda0)))); }
/// <summary> /// Calculates nutation elements for given instant. /// </summary> /// <param name="jd">Julian Day, corresponding to the given instant.</param> /// <returns>Aberration elements for the given instant.</returns> /// <remarks> /// The method is taken from AA(II), page 144. /// Accuracy of the method is 0.1" for Δε and 0.5" for Δψ. /// </remarks> public static NutationElements NutationElements(double jd) { double T = (jd - 2451545) / 36525.0; // Longitude of the ascending node of Moon's mean orbit on the ecliptic, // measured from the mean equinox of the date: double Omega = 125.04452 - 1934.136261 * T; // Mean longutude of Sun double L = 280.4665 + 36000.7698 * T; // Mean longitude of Moon double L_ = 218.3165 + 481267.8813 * T; double deltaEpsilon = 9.20 * Math.Cos(Angle.ToRadians(Omega)) + 0.57 * Math.Cos(Angle.ToRadians(2 * L)) + 0.10 * Math.Cos(Angle.ToRadians(2 * L_)) - 0.09 * Math.Cos(Angle.ToRadians(2 * Omega)); double deltaPsi = -17.20 * Math.Sin(Angle.ToRadians(Omega)) - 1.32 * Math.Sin(Angle.ToRadians(2 * L)) - 0.23 * Math.Sin(Angle.ToRadians(2 * L_)) + 0.21 * Math.Sin(Angle.ToRadians(2 * Omega)); return(new NutationElements() { deltaEpsilon = deltaEpsilon / 3600, deltaPsi = deltaPsi / 3600 }); }
/// <summary> /// Gets magnitude component of Saturn rings, that should be added to Saturn disk magnitude (see <see cref="PlanetEphem.Magnitude(int, double, double, double)"/>). /// </summary> /// <returns></returns> public float GetRingsMagnitude() { double sinB = Math.Sin(Angle.ToRadians(B)); return((float)(0.044 * Math.Abs(DeltaU) - 2.6 * Math.Sin(Angle.ToRadians(Math.Abs(B))) + 1.25 * sinB * sinB)); }
/// <summary> /// Calculates apparent sidereal time at Greenwich for given instant. /// </summary> /// <param name="jd">Julian Day</param> /// <returns>Apparent sidereal time at Greenwich, expressed in degrees.</returns> /// <remarks> /// AA(II), formula 12.4, with corrections for nutation (chapter 22). /// </remarks> public static double ApparentSiderealTime(double jd, double deltaPsi, double epsilon) { double cosEpsilon = Math.Cos(Angle.ToRadians(epsilon)); return(MeanSiderealTime(jd) + deltaPsi * cosEpsilon); }
/// <summary> /// Calculates instants of rising, transit and setting for non-stationary celestial body for the desired date. /// Non-stationary in this particular case means that body has fastly changing celestial coordinates during the day. /// </summary> /// <param name="eq">Array of three equatorial coordinates of the celestial body correspoding to local midnight, local noon, and local midnight of the following day after the desired date respectively.</param> /// <param name="location">Geographical location of the observation point.</param> /// <param name="theta0">Apparent sidereal time at Greenwich for local midnight of the desired date.</param> /// <param name="pi">Horizontal equatorial parallax of the body.</param> /// <param name="sd">Visible semidiameter of the body, expressed in degrees.</param> /// <returns>Instants of rising, transit and setting for the celestial body for the desired date.</returns> public static RTS RiseTransitSet(CrdsEquatorial[] eq, CrdsGeographical location, double theta0, double pi = 0, double sd = 0) { if (eq.Length != 3) { throw new ArgumentException("Number of equatorial coordinates in the array should be equal to 3."); } double[] alpha = new double[3]; double[] delta = new double[3]; for (int i = 0; i < 3; i++) { alpha[i] = eq[i].Alpha; delta[i] = eq[i].Delta; } Angle.Align(alpha); Angle.Align(delta); List <CrdsHorizontal> hor = new List <CrdsHorizontal>(); for (int i = 0; i <= 24; i++) { double n = i / 24.0; CrdsEquatorial eq0 = InterpolateEq(alpha, delta, n); var sidTime = InterpolateSiderialTime(theta0, n); hor.Add(eq0.ToTopocentric(location, sidTime, pi).ToHorizontal(location, sidTime)); } var result = new RTS(); for (int i = 0; i < 24; i++) { double n = (i + 0.5) / 24.0; CrdsEquatorial eq0 = InterpolateEq(alpha, delta, n); var sidTime = InterpolateSiderialTime(theta0, n); var hor0 = eq0.ToTopocentric(location, sidTime, pi).ToHorizontal(location, sidTime); if (double.IsNaN(result.Transit) && hor0.Altitude > 0) { double r = SolveParabola(Math.Sin(Angle.ToRadians(hor[i].Azimuth)), Math.Sin(Angle.ToRadians(hor0.Azimuth)), Math.Sin(Angle.ToRadians(hor[i + 1].Azimuth))); if (!double.IsNaN(r)) { double t = (i + r) / 24.0; eq0 = InterpolateEq(alpha, delta, t); sidTime = InterpolateSiderialTime(theta0, t); result.Transit = t; result.TransitAltitude = eq0.ToTopocentric(location, sidTime, pi).ToHorizontal(location, sidTime).Altitude; } } if (double.IsNaN(result.Rise) || double.IsNaN(result.Set)) { double r = SolveParabola(hor[i].Altitude + sd, hor0.Altitude + sd, hor[i + 1].Altitude + sd); if (!double.IsNaN(r)) { double t = (i + r) / 24.0; eq0 = InterpolateEq(alpha, delta, t); sidTime = InterpolateSiderialTime(theta0, t); if (double.IsNaN(result.Rise) && hor[i].Altitude + sd < 0 && hor[i + 1].Altitude + sd > 0) { result.Rise = t; result.RiseAzimuth = eq0.ToTopocentric(location, sidTime, pi).ToHorizontal(location, sidTime).Azimuth; } if (double.IsNaN(result.Set) && hor[i].Altitude + sd > 0 && hor[i + 1].Altitude + sd < 0) { result.Set = t; result.SetAzimuth = eq0.ToTopocentric(location, sidTime, pi).ToHorizontal(location, sidTime).Azimuth; } if (!double.IsNaN(result.Transit) && !double.IsNaN(result.Rise) && !double.IsNaN(result.Set)) { break; } } } } return(result); }
/// <summary> /// Gets phase value (illuminated fraction of the Moon disk). /// </summary> /// <param name="phaseAngle">Phase angle of the Moon, in degrees.</param> /// <returns>Illuminated fraction of the Moon disk, from 0 to 1.</returns> /// <remarks> /// AA(II), formula 48.1 /// </remarks> public static double Phase(double phaseAngle) { return((1 + Math.Cos(Angle.ToRadians(phaseAngle))) / 2); }