/// <summary> /// Creates new instance /// </summary> public LunarEclipseLocalCircumstancesContactPoint(InstantLunarEclipseElements e, CrdsGeographical g) { CrdsEquatorial eq = new CrdsEquatorial(e.Alpha, e.Delta); // Nutation elements var nutation = Nutation.NutationElements(e.JulianDay); // True obliquity var epsilon = Date.TrueObliquity(e.JulianDay, nutation.deltaEpsilon); // Greenwich apparent sidereal time double siderealTime = Date.ApparentSiderealTime(e.JulianDay, nutation.deltaPsi, epsilon); // Geocenric distance to the Moon, in km double dist = 358473400.0 / (e.F3 * 3600); // Horizontal parallax of the Moon double parallax = LunarEphem.Parallax(dist); // Topocentrical equatorial coordinates var eqTopo = eq.ToTopocentric(g, siderealTime, parallax); // Horizontal coordinates var h = eqTopo.ToHorizontal(g, siderealTime); // Hour angle double H = Coordinates.HourAngle(siderealTime, g.Longitude, eqTopo.Alpha); // Position angles // Parallactic angle - AA(II), p.98, formula 14.1 double qAngle = ToDegrees(Atan2(Sin(ToRadians(H)), Tan(ToRadians(g.Latitude)) * Cos(ToRadians(eqTopo.Delta)) - Sin(ToRadians(eqTopo.Delta)) * Cos(ToRadians(H)))); // Position angle, measured from North to East (CCW) double pAngle = To360(ToDegrees(Atan2(e.X, e.Y))); // Position angle, measured from Zenith CCW double zAngle = To360(pAngle - qAngle); JulianDay = e.JulianDay; LunarAltitude = h.Altitude; QAngle = qAngle; PAngle = pAngle; ZAngle = zAngle; X = e.X; Y = e.Y; F1 = e.F1; F2 = e.F2; F3 = e.F3; }
/// <summary> /// Finds horizon circle point for a given geographical longitude /// for an instant of lunar eclipse, where Moon has zero altitude. /// </summary> /// <param name="e">Besselian elements of the Moon for the given instant.</param> /// <param name="L">Geographical longitude, positive west, negative east, from -180 to +180 degrees.</param> /// <returns> /// Geographical coordinates for the point. /// </returns> /// <remarks> /// The method core is based on formulae from the book: /// Seidelmann, P. K.: Explanatory Supplement to The Astronomical Almanac, /// University Science Book, Mill Valley (California), 1992, /// Chapter 8 "Eclipses of the Sun and Moon" /// https://archive.org/download/131123ExplanatorySupplementAstronomicalAlmanac/131123-explanatory-supplement-astronomical-almanac.pdf /// </remarks> private static CrdsGeographical Project(InstantLunarEclipseElements e, double L) { CrdsGeographical g = null; // Nutation elements var nutation = Nutation.NutationElements(e.JulianDay); // True obliquity var epsilon = Date.TrueObliquity(e.JulianDay, nutation.deltaEpsilon); // Greenwich apparent sidereal time double siderealTime = Date.ApparentSiderealTime(e.JulianDay, nutation.deltaPsi, epsilon); // Geocenric distance to the Moon, in km double dist = 358473400.0 / (e.F3 * 3600); // Horizontal parallax of the Moon double parallax = LunarEphem.Parallax(dist); // Equatorial coordinates of the Moon, initial value is geocentric CrdsEquatorial eq = new CrdsEquatorial(e.Alpha, e.Delta); // two iterations: // 1st: find geo location needed to perform topocentric correction // 2nd: correct sublunar point with topocentric position and find true geoposition for (int i = 0; i < 2; i++) { // sublunar point latitude, preserve sign! double phi0 = Sign(e.Delta) * Abs(eq.Delta); // sublunar point longitude (formula 8.426-1) double lambda0 = siderealTime - eq.Alpha; // sublunar point latitude (formula 8.426-2) double tanPhi = -1.0 / Tan(ToRadians(phi0)) * Cos(ToRadians(lambda0 - L)); double phi = ToDegrees(Atan(tanPhi)); g = new CrdsGeographical(L, phi); if (i == 0) { // correct to topocentric eq = eq.ToTopocentric(g, siderealTime, parallax); } } return(g); }
public static PolynomialLunarEclipseElements BesselianElements(double jdMaximum, SunMoonPosition[] positions) { if (positions.Length != 5) { throw new ArgumentException("Five positions are required", nameof(positions)); } double step = positions[1].JulianDay - positions[0].JulianDay; if (!positions.Zip(positions.Skip(1), (a, b) => new { a, b }) .All(p => Abs(p.b.JulianDay - p.a.JulianDay - step) <= 1e-6)) { throw new ArgumentException("Positions should be sorted ascending by JulianDay value, and have same JulianDay step.", nameof(positions)); } // 5 time instants required InstantLunarEclipseElements[] elements = new InstantLunarEclipseElements[5]; PointF[] points = new PointF[5]; for (int i = 0; i < 5; i++) { elements[i] = BesselianElements(positions[i]); points[i].X = i - 2; } // Alpha expressed in degrees and can cross zero point (360 -> 0). // Values must be aligned in order to avoid crossing. double[] Alpha = Align(elements.Select(e => e.Alpha).ToArray()); return(new PolynomialLunarEclipseElements() { JulianDay0 = positions[2].JulianDay, JulianDayMaximum = jdMaximum, DeltaT = Date.DeltaT(positions[2].JulianDay), Step = step, X = LeastSquares.FindCoeffs(points.Select((p, i) => new PointF(p.X, (float)elements[i].X)), 3), Y = LeastSquares.FindCoeffs(points.Select((p, i) => new PointF(p.X, (float)elements[i].Y)), 3), F1 = LeastSquares.FindCoeffs(points.Select((p, i) => new PointF(p.X, (float)elements[i].F1)), 3), F2 = LeastSquares.FindCoeffs(points.Select((p, i) => new PointF(p.X, (float)elements[i].F2)), 3), F3 = LeastSquares.FindCoeffs(points.Select((p, i) => new PointF(p.X, (float)elements[i].F3)), 3), Alpha = LeastSquares.FindCoeffs(points.Select((p, i) => new PointF(p.X, (float)Alpha[i])), 3), Delta = LeastSquares.FindCoeffs(points.Select((p, i) => new PointF(p.X, (float)elements[i].Delta)), 3), }); }
private static IList <CrdsGeographical> FindCurvePoints(InstantLunarEclipseElements e) { var curve = new List <CrdsGeographical>(); var p0 = Project(e, -180); curve.Add(new CrdsGeographical(p0.Longitude, -88 * Sign(e.Delta))); for (int i = -180; i <= 180; i++) { var p = Project(e, i); curve.Add(p); } var p1 = Project(e, 180); curve.Add(new CrdsGeographical(p1.Longitude, -88 * Sign(e.Delta))); return(curve); }