From 3ce32f88193b9cbd4fc9531d91700ca23e225785 Mon Sep 17 00:00:00 2001 From: Don Cross Date: Fri, 22 Apr 2022 16:36:14 -0400 Subject: [PATCH] Kotlin: lunar libration. Fixes for other languages. The existing lunar libration functions in the other languages (C, C#, Python, JavaScript) were calculating the Moon's ecliptic latitude and longitude in radians, not degrees as intended. They have been fixed. Implemented the libration function for Kotlin. --- README.md | 2 +- demo/browser/astronomy.browser.js | 6 +- demo/nodejs/astronomy.js | 6 +- demo/nodejs/calendar/astronomy.ts | 6 +- demo/python/astronomy.py | 6 +- generate/ctest.c | 10 ++ generate/dotnet/csharp_test/csharp_test.cs | 11 ++ generate/template/astronomy.c | 12 +- generate/template/astronomy.cs | 14 +- generate/template/astronomy.kt | 147 +++++++++++++++-- generate/template/astronomy.py | 6 +- generate/template/astronomy.ts | 6 +- generate/test.js | 16 +- generate/test.py | 17 +- source/c/README.md | 4 +- source/c/astronomy.c | 12 +- source/c/astronomy.h | 4 +- source/csharp/README.md | 4 +- source/csharp/astronomy.cs | 14 +- source/js/README.md | 4 +- source/js/astronomy.browser.js | 6 +- source/js/astronomy.browser.min.js | 150 +++++++++--------- source/js/astronomy.d.ts | 4 +- source/js/astronomy.js | 6 +- source/js/astronomy.min.js | 3 +- source/js/astronomy.ts | 6 +- source/js/esm/astronomy.js | 6 +- source/kotlin/README.md | 3 +- source/kotlin/doc/-libration-info/index.md | 2 +- source/kotlin/doc/index.md | 3 +- source/kotlin/doc/libration.md | 26 +++ .../github/cosinekitty/astronomy/astronomy.kt | 147 +++++++++++++++-- .../io/github/cosinekitty/astronomy/Tests.kt | 46 ++++++ source/python/README.md | 4 +- source/python/astronomy/astronomy.py | 6 +- 35 files changed, 553 insertions(+), 172 deletions(-) create mode 100644 source/kotlin/doc/libration.md diff --git a/README.md b/README.md index 79811759..81a04ace 100644 --- a/README.md +++ b/README.md @@ -168,7 +168,7 @@ of complexity. So I decided to create Astronomy Engine with the following engine - Support JavaScript, C, C#, and Python with the same algorithms, and verify them to produce identical results. - No external dependencies! The code must not require anything outside the standard library for each language. -- Minified JavaScript code less than 120K. (The current size is 108911 bytes.) +- Minified JavaScript code less than 120K. (The current size is 108931 bytes.) - Accuracy always within 1 arcminute of results from NOVAS. - It would be well documented, relatively easy to use, and support a wide variety of common use cases. diff --git a/demo/browser/astronomy.browser.js b/demo/browser/astronomy.browser.js index 55eb9de4..c122c4d1 100644 --- a/demo/browser/astronomy.browser.js +++ b/demo/browser/astronomy.browser.js @@ -1623,9 +1623,9 @@ function CalcMoon(time) { * @property {number} elon * Sub-Earth libration ecliptic longitude angle, in degrees. * @property {number} mlat - * Moon's geocentric ecliptic latitude. + * Moon's geocentric ecliptic latitude, in degrees. * @property {number} mlon - * Moon's geocentric ecliptic longitude. + * Moon's geocentric ecliptic longitude, in degrees. * @property {number} dist_km * Distance between the centers of the Earth and Moon in kilometers. * @property {number} diam_deg @@ -1742,7 +1742,7 @@ function Libration(date) { const ldash2 = -tau + (rho * Math.cos(a) + sigma * Math.sin(a)) * Math.tan(bdash); const bdash2 = sigma * Math.cos(a) - rho * Math.sin(a); const diam_deg = 2.0 * exports.RAD2DEG * Math.atan(MOON_MEAN_RADIUS_KM / Math.sqrt(dist_km * dist_km - MOON_MEAN_RADIUS_KM * MOON_MEAN_RADIUS_KM)); - return new LibrationInfo(exports.RAD2DEG * bdash + bdash2, ldash + ldash2, mlat, mlon, dist_km, diam_deg); + return new LibrationInfo(exports.RAD2DEG * bdash + bdash2, ldash + ldash2, exports.RAD2DEG * mlat, exports.RAD2DEG * mlon, dist_km, diam_deg); } exports.Libration = Libration; function rotate(rot, vec) { diff --git a/demo/nodejs/astronomy.js b/demo/nodejs/astronomy.js index 264f1041..72208cf8 100644 --- a/demo/nodejs/astronomy.js +++ b/demo/nodejs/astronomy.js @@ -1622,9 +1622,9 @@ function CalcMoon(time) { * @property {number} elon * Sub-Earth libration ecliptic longitude angle, in degrees. * @property {number} mlat - * Moon's geocentric ecliptic latitude. + * Moon's geocentric ecliptic latitude, in degrees. * @property {number} mlon - * Moon's geocentric ecliptic longitude. + * Moon's geocentric ecliptic longitude, in degrees. * @property {number} dist_km * Distance between the centers of the Earth and Moon in kilometers. * @property {number} diam_deg @@ -1741,7 +1741,7 @@ function Libration(date) { const ldash2 = -tau + (rho * Math.cos(a) + sigma * Math.sin(a)) * Math.tan(bdash); const bdash2 = sigma * Math.cos(a) - rho * Math.sin(a); const diam_deg = 2.0 * exports.RAD2DEG * Math.atan(MOON_MEAN_RADIUS_KM / Math.sqrt(dist_km * dist_km - MOON_MEAN_RADIUS_KM * MOON_MEAN_RADIUS_KM)); - return new LibrationInfo(exports.RAD2DEG * bdash + bdash2, ldash + ldash2, mlat, mlon, dist_km, diam_deg); + return new LibrationInfo(exports.RAD2DEG * bdash + bdash2, ldash + ldash2, exports.RAD2DEG * mlat, exports.RAD2DEG * mlon, dist_km, diam_deg); } exports.Libration = Libration; function rotate(rot, vec) { diff --git a/demo/nodejs/calendar/astronomy.ts b/demo/nodejs/calendar/astronomy.ts index b8e20305..ba1e6583 100644 --- a/demo/nodejs/calendar/astronomy.ts +++ b/demo/nodejs/calendar/astronomy.ts @@ -1729,9 +1729,9 @@ function CalcMoon(time: AstroTime) { * @property {number} elon * Sub-Earth libration ecliptic longitude angle, in degrees. * @property {number} mlat - * Moon's geocentric ecliptic latitude. + * Moon's geocentric ecliptic latitude, in degrees. * @property {number} mlon - * Moon's geocentric ecliptic longitude. + * Moon's geocentric ecliptic longitude, in degrees. * @property {number} dist_km * Distance between the centers of the Earth and Moon in kilometers. * @property {number} diam_deg @@ -1867,7 +1867,7 @@ export function Libration(date: FlexibleDateTime): LibrationInfo { const ldash2 = -tau + (rho*Math.cos(a) + sigma*Math.sin(a))*Math.tan(bdash); const bdash2 = sigma*Math.cos(a) - rho*Math.sin(a); const diam_deg = 2.0 * RAD2DEG * Math.atan(MOON_MEAN_RADIUS_KM / Math.sqrt(dist_km*dist_km - MOON_MEAN_RADIUS_KM*MOON_MEAN_RADIUS_KM)); - return new LibrationInfo(RAD2DEG*bdash + bdash2, ldash + ldash2, mlat, mlon, dist_km, diam_deg); + return new LibrationInfo(RAD2DEG*bdash + bdash2, ldash + ldash2, RAD2DEG*mlat, RAD2DEG*mlon, dist_km, diam_deg); } function rotate(rot: RotationMatrix, vec: ArrayVector): ArrayVector { diff --git a/demo/python/astronomy.py b/demo/python/astronomy.py index 651f9c99..e42b4cea 100644 --- a/demo/python/astronomy.py +++ b/demo/python/astronomy.py @@ -9136,9 +9136,9 @@ class LibrationInfo: elon : float Sub-Earth libration ecliptic longitude angle, in degrees. mlat : float - Moon's geocentric ecliptic latitude. + Moon's geocentric ecliptic latitude, in degrees. mlon : float - Moon's geocentric ecliptic longitude. + Moon's geocentric ecliptic longitude, in degrees. dist_km : float Distance between the centers of the Earth and Moon in kilometers. diam_deg : float @@ -9284,7 +9284,7 @@ def Libration(time): ldash2 = -tau + (rho*math.cos(a) + sigma*math.sin(a))*math.tan(bdash) bdash = math.degrees(bdash) bdash2 = sigma*math.cos(a) - rho*math.sin(a) - return LibrationInfo(bdash + bdash2, ldash + ldash2, mlat, mlon, dist_km, diam_deg) + return LibrationInfo(bdash + bdash2, ldash + ldash2, math.degrees(mlat), math.degrees(mlon), dist_km, diam_deg) class AxisInfo: diff --git a/generate/ctest.c b/generate/ctest.c index 1a0f2a3b..a9dae933 100644 --- a/generate/ctest.c +++ b/generate/ctest.c @@ -5753,6 +5753,7 @@ static int Libration(const char *filename, int *ndata, double *var_lon, double * astro_libration_t lib; double diff_elon, diff_elat, diff_distance, diff_diam; double max_diff_elon = 0.0, max_diff_elat = 0.0, max_diff_distance = 0.0, max_diff_diam = 0.0; + double max_eclip_lon = -900.0; infile = fopen(filename, "rt"); if (infile == NULL) @@ -5802,6 +5803,9 @@ static int Libration(const char *filename, int *ndata, double *var_lon, double * if (diff_diam > max_diff_diam) max_diff_diam = diff_diam; + if (lib.mlon > max_eclip_lon) + max_eclip_lon = lib.mlon; + if (diff_elon > 0.1304) FAIL("C Libration(%s line %d): EXCESSIVE diff_elon = %0.4lf arcmin\n", filename, lnum, diff_elon); @@ -5811,6 +5815,9 @@ static int Libration(const char *filename, int *ndata, double *var_lon, double * if (diff_distance > 54.377) FAIL("C Libration(%s line %d): EXCESSIVE diff_distance = %0.3lf km\n", filename, lnum, diff_distance); + if (diff_diam > 0.00009) + FAIL("C Libration(%s line %d): EXCESSIVE diff_diam = %0.3le degrees\n", filename, lnum, diff_diam); + /* Update sum-of-squared-errors. */ *var_lon += diff_elon * diff_elon; *var_lat += diff_elat * diff_elat; @@ -5819,6 +5826,9 @@ static int Libration(const char *filename, int *ndata, double *var_lon, double * } } + if (max_eclip_lon < 359.0 || max_eclip_lon > 360.0) + FAIL("C Libration(%s): INVALID max ecliptic longitude %0.3lf degrees.\n", filename, max_eclip_lon); + printf("C Libration(%s): PASS (%d test cases, max_diff_elon = %0.4lf arcmin, max_diff_elat = %0.4lf arcmin, max_diff_distance = %0.3lf km, max_diff_diam = %0.12lf deg)\n", filename, count, max_diff_elon, max_diff_elat, max_diff_distance, max_diff_diam); diff --git a/generate/dotnet/csharp_test/csharp_test.cs b/generate/dotnet/csharp_test/csharp_test.cs index 68777e87..b441d24f 100644 --- a/generate/dotnet/csharp_test/csharp_test.cs +++ b/generate/dotnet/csharp_test/csharp_test.cs @@ -3217,6 +3217,7 @@ namespace csharp_test double max_diff_elat = 0.0; double max_diff_distance = 0.0; double max_diff_diam = 0.0; + double max_eclip_lon = -900.0; string line; while (null != (line = infile.ReadLine())) { @@ -3294,10 +3295,20 @@ namespace csharp_test Console.WriteLine($"C# Libration({filename} line {lnum}): EXCESSIVE diff_distance = {diff_distance} km"); return 1; } + + if (lib.mlon > max_eclip_lon) + max_eclip_lon = lib.mlon; + ++count; } } + if (max_eclip_lon < 359.0 || max_eclip_lon > 360.0) + { + Console.WriteLine($"C# Libration({filename}): INVALID max ecliptic longitude {max_eclip_lon:F3} degrees."); + return 1; + } + Console.WriteLine($"C# Libration({filename}): PASS ({count} test cases, max_diff_elon = {max_diff_elon} arcmin, max_diff_elat = {max_diff_elat} arcmin, max_diff_distance = {max_diff_distance} km, max_diff_diam = {max_diff_diam} deg)"); return 0; } diff --git a/generate/template/astronomy.c b/generate/template/astronomy.c index 66a433ad..2d545f9c 100644 --- a/generate/template/astronomy.c +++ b/generate/template/astronomy.c @@ -2099,7 +2099,11 @@ astro_libration_t Astronomy_Libration(astro_time_t time) t3 = t2 * t; t4 = t2 * t2; - CalcMoon(t, &lib.mlon, &lib.mlat, &lib.dist_km); + double mlon; /* Moon's ecliptic longitude in radians. */ + double mlat; /* Moon's ecliptic latitude in radians. */ + CalcMoon(t, &mlon, &mlat, &lib.dist_km); + lib.mlon = RAD2DEG * mlon; + lib.mlat = RAD2DEG * mlat; lib.dist_km *= KM_PER_AU; lib.diam_deg = (2.0 * RAD2DEG) * atan(MOON_MEAN_RADIUS_KM / sqrt(lib.dist_km*lib.dist_km - MOON_MEAN_RADIUS_KM*MOON_MEAN_RADIUS_KM)); @@ -2122,10 +2126,10 @@ astro_libration_t Astronomy_Libration(astro_time_t time) e = 1.0 - 0.002516*t - 0.0000074*t2; /* Optical librations */ - w = lib.mlon - omega; - a = atan2(sin(w)*cos(lib.mlat)*cos_I - sin(lib.mlat)*sin_I, cos(w)*cos(lib.mlat)); + w = mlon - omega; + a = atan2(sin(w)*cos(mlat)*cos_I - sin(mlat)*sin_I, cos(w)*cos(mlat)); ldash = LongitudeOffset(RAD2DEG * (a - f)); - bdash = asin(-sin(w)*cos(lib.mlat)*sin_I - sin(lib.mlat)*cos_I); + bdash = asin(-sin(w)*cos(mlat)*sin_I - sin(mlat)*cos_I); /* Physical librations */ k1 = DEG2RAD*(119.75 + 131.849*t); diff --git a/generate/template/astronomy.cs b/generate/template/astronomy.cs index 6c07cb96..a6004d10 100644 --- a/generate/template/astronomy.cs +++ b/generate/template/astronomy.cs @@ -1016,10 +1016,10 @@ namespace CosineKitty /// Sub-Earth libration ecliptic longitude angle, in degrees. public double elon; - /// Moon's geocentric ecliptic latitude. + /// Moon's geocentric ecliptic latitude in degrees. public double mlat; - /// Moon's geocentric ecliptic longitude. + /// Moon's geocentric ecliptic longitude in degrees. public double mlon; /// Distance between the centers of the Earth and Moon in kilometers. @@ -3699,8 +3699,8 @@ $ASTRO_IAU_DATA() MoonResult moon = context.CalcMoon(); LibrationInfo lib; - lib.mlon = moon.geo_eclip_lon; - lib.mlat = moon.geo_eclip_lat; + lib.mlon = RAD2DEG * moon.geo_eclip_lon; + lib.mlat = RAD2DEG * moon.geo_eclip_lat; lib.dist_km = moon.distance_au * KM_PER_AU; lib.diam_deg = (2.0 * RAD2DEG) * Math.Atan(MOON_MEAN_RADIUS_KM / Math.Sqrt(lib.dist_km*lib.dist_km - MOON_MEAN_RADIUS_KM*MOON_MEAN_RADIUS_KM)); @@ -3726,10 +3726,10 @@ $ASTRO_IAU_DATA() double e = 1.0 - 0.002516*t - 0.0000074*t2; // Optical librations - double w = lib.mlon - omega; - double a = Math.Atan2(Math.Sin(w)*Math.Cos(lib.mlat)*Math.Cos(I) - Math.Sin(lib.mlat)*Math.Sin(I), Math.Cos(w)*Math.Cos(lib.mlat)); + double w = moon.geo_eclip_lon - omega; + double a = Math.Atan2(Math.Sin(w)*Math.Cos(moon.geo_eclip_lat)*Math.Cos(I) - Math.Sin(moon.geo_eclip_lat)*Math.Sin(I), Math.Cos(w)*Math.Cos(moon.geo_eclip_lat)); double ldash = LongitudeOffset(RAD2DEG * (a - f)); - double bdash = Math.Asin(-Math.Sin(w)*Math.Cos(lib.mlat)*Math.Sin(I) - Math.Sin(lib.mlat)*Math.Cos(I)); + double bdash = Math.Asin(-Math.Sin(w)*Math.Cos(moon.geo_eclip_lat)*Math.Sin(I) - Math.Sin(moon.geo_eclip_lat)*Math.Cos(I)); // Physical librations double k1 = DEG2RAD*(119.75 + 131.849*t); diff --git a/generate/template/astronomy.kt b/generate/template/astronomy.kt index 0ae7b35f..89293385 100644 --- a/generate/template/astronomy.kt +++ b/generate/template/astronomy.kt @@ -76,6 +76,8 @@ fun Double.degreesToRadians() = this * DEG2RAD internal fun dsin(degrees: Double) = sin(degrees.degreesToRadians()) internal fun dcos(degrees: Double) = cos(degrees.degreesToRadians()) internal fun dtan(degrees: Double) = tan(degrees.degreesToRadians()) +internal fun datan(slope: Double) = atan(slope).radiansToDegrees() +internal fun datan2(y: Double, x: Double) = atan2(y, x).radiansToDegrees() /** * The factor to convert radians to degrees = 180/pi. @@ -783,8 +785,8 @@ data class Vector( lon = 0.0 lat = if (z < 0.0) -90.0 else +90.0 } else { - lon = atan2(y, x).radiansToDegrees().withMinDegreeValue(0.0) - lat = atan2(z, sqrt(xyproj)).radiansToDegrees() + lon = datan2(y, x).withMinDegreeValue(0.0) + lat = datan2(z, sqrt(xyproj)) } return Spherical(lat, lon, dist) } @@ -2325,12 +2327,12 @@ internal fun geoidIntersect(shadow: ShadowInfo): GlobalSolarEclipseInfo { latitude = if (proj == 0.0) ( if (pz > 0.0) +90.0 else -90.0 ) else ( - atan(pz / proj).radiansToDegrees() + datan(pz / proj) ) // Adjust longitude for Earth's rotation at the given time. val gast = siderealTime(shadow.time) - longitude = ((atan2(py,px).radiansToDegrees() - (15.0 * gast)) % 360.0).withMaxDegreeValue(180.0) + longitude = ((datan2(py,px) - (15.0 * gast)) % 360.0).withMaxDegreeValue(180.0) // We want to determine whether the observer sees a total eclipse or an annular eclipse. // We need to perform a series of vector calculations. @@ -4895,7 +4897,7 @@ fun horizon( if (projHor > 0.0) ( // If the body is not exactly straight up/down, it has an azimuth. // Invert the angle to produce degrees eastward from north. - (-atan2(pw, pn)).radiansToDegrees().withMinDegreeValue(0.0) + (-datan2(pw, pn)).withMinDegreeValue(0.0) ) else ( // The body is straight up/down, so it does not have an azimuth. // Report an arbitrary but reasonable value. @@ -4904,7 +4906,7 @@ fun horizon( ) // zd = the angle of the body away from the observer's zenith, in degrees. - var zd = atan2(projHor, pz).radiansToDegrees() + var zd = datan2(projHor, pz) var horRa = ra var horDec = dec @@ -4928,11 +4930,11 @@ fun horizon( horRa = if (projEqu > 0.0) - atan2(pry, prx).radiansToDegrees().withMinDegreeValue(0.0) / 15.0 + datan2(pry, prx).withMinDegreeValue(0.0) / 15.0 else 0.0 - horDec = atan2(prz, projEqu).radiansToDegrees() + horDec = datan2(prz, projEqu) } } @@ -5410,10 +5412,10 @@ private fun rotateEquatorialToEcliptic(pos: Vector, obliqRadians: Double): Eclip val xyproj = hypot(ex, ey) val elon = if (xyproj > 0.0) - atan2(ey, ex).radiansToDegrees().withMinDegreeValue(0.0) + datan2(ey, ex).withMinDegreeValue(0.0) else 0.0 - val elat = atan2(ez, xyproj).radiansToDegrees() + val elat = datan2(ez, xyproj) val vec = Vector(ex, ey, ez, pos.t) return Ecliptic(vec, elat, elon) } @@ -6829,6 +6831,131 @@ fun lagrangePointFast( } +/** + * Calculates the Moon's libration angles at a given moment in time. + * + * Libration is an observed back-and-forth wobble of the portion of the + * Moon visible from the Earth. It is caused by the imperfect tidal locking + * of the Moon's fixed rotation rate, compared to its variable angular speed + * of orbit around the Earth. + * + * This function calculates a pair of perpendicular libration angles, + * one representing rotation of the Moon in eclitpic longitude `elon`, the other + * in ecliptic latitude `elat`, both relative to the Moon's mean Earth-facing position. + * + * This function also returns the geocentric position of the Moon + * expressed in ecliptic longitude `mlon`, ecliptic latitude `mlat`, the + * distance `dist_km` between the centers of the Earth and Moon expressed in kilometers, + * and the apparent angular diameter of the Moon `diam_deg`. + * + * @param time + * The date and time for which to calculate lunar libration. + * + * @return + * The Moon's ecliptic position and libration angles as seen from the Earth. + */ +fun libration(time: Time): LibrationInfo { + val t = time.julianCenturies() + val t2 = t * t + val t3 = t2 * t + val t4 = t2 * t2 + + val moon = eclipticGeoMoon(time) + + val mlon = moon.lon.degreesToRadians() + val mlat = moon.lat.degreesToRadians() + val distKm = moon.dist * KM_PER_AU + val diamDeg = 2.0 * datan(MOON_MEAN_RADIUS_KM / sqrt(distKm*distKm - MOON_MEAN_RADIUS_KM*MOON_MEAN_RADIUS_KM)) + + // Inclination angle in radians = 0.026930430358272504 + val cosIncl = 0.99963739787586170 + val sinIncl = 0.02692717526916351 + + // Moon's argument of latitude in radians. + val f = normalizeLongitude(93.2720950 + 483202.0175233*t - 0.0036539*t2 - t3/3526000 + t4/863310000).degreesToRadians() + + // Moon's ascending node's mean longitude in radians. + val omega = normalizeLongitude(125.0445479 - 1934.1362891*t + 0.0020754*t2 + t3/467441 - t4/60616000).degreesToRadians() + + // Sun's mean anomaly in radians. + val m = normalizeLongitude(357.5291092 + 35999.0502909*t - 0.0001536*t2 + t3/24490000).degreesToRadians() + + // Moon's mean anomaly in radians. + val mdash = normalizeLongitude(134.9633964 + 477198.8675055*t + 0.0087414*t2 + t3/69699 - t4/14712000).degreesToRadians() + + // Moon's mean elongation in radians. + val d = normalizeLongitude(297.8501921 + 445267.1114034*t - 0.0018819*t2 + t3/545868 - t4/113065000).degreesToRadians() + + // Eccentricity of the Earth's orbit. + val e = 1.0 - 0.002516*t - 0.0000074*t2 + + // Optical librations + val w = mlon - omega; + val a = atan2(sin(w)*cos(mlat)*cosIncl - sin(mlat)*sinIncl, cos(w)*cos(mlat)) + val ldash = longitudeOffset((a - f).radiansToDegrees()) + val bdash = asin(-sin(w)*cos(mlat)*sinIncl - sin(mlat)*cosIncl) + + // Physical librations + val k1 = (119.75 + 131.849*t).degreesToRadians() + val k2 = (72.56 + 20.186*t).degreesToRadians() + + val rho = ( + -0.02752*cos(mdash) + + -0.02245*sin(f) + + +0.00684*cos(mdash - 2*f) + + -0.00293*cos(2*f) + + -0.00085*cos(2*f - 2*d) + + -0.00054*cos(mdash - 2*d) + + -0.00020*sin(mdash + f) + + -0.00020*cos(mdash + 2*f) + + -0.00020*cos(mdash - f) + + +0.00014*cos(mdash + 2*f - 2*d) + ) + + val sigma = ( + -0.02816*sin(mdash) + + +0.02244*cos(f) + + -0.00682*sin(mdash - 2*f) + + -0.00279*sin(2*f) + + -0.00083*sin(2*f - 2*d) + + +0.00069*sin(mdash - 2*d) + + +0.00040*cos(mdash + f) + + -0.00025*sin(2*mdash) + + -0.00023*sin(mdash + 2*f) + + +0.00020*cos(mdash - f) + + +0.00019*sin(mdash - f) + + +0.00013*sin(mdash + 2*f - 2*d) + + -0.00010*cos(mdash - 3*f) + ) + + val tau = ( + +0.02520*e*sin(m) + + +0.00473*sin(2*mdash - 2*f) + + -0.00467*sin(mdash) + + +0.00396*sin(k1) + + +0.00276*sin(2*mdash - 2*d) + + +0.00196*sin(omega) + + -0.00183*cos(mdash - f) + + +0.00115*sin(mdash - 2*d) + + -0.00096*sin(mdash - d) + + +0.00046*sin(2*f - 2*d) + + -0.00039*sin(mdash - f) + + -0.00032*sin(mdash - m - d) + + +0.00027*sin(2*mdash - m - 2*d) + + +0.00023*sin(k2) + + -0.00014*sin(2*d) + + +0.00014*cos(2*mdash - 2*f) + + -0.00012*sin(mdash - 2*f) + + -0.00012*sin(2*mdash) + + +0.00011*sin(2*mdash - 2*m - 2*d) + ) + + val elon = ldash - tau + (rho*cos(a) + sigma*sin(a))*tan(bdash) + val elat = bdash.radiansToDegrees() + sigma*cos(a) - rho*sin(a) + return LibrationInfo(elat, elon, moon.lon, moon.lat, distKm, diamDeg) +} + + /** * Calculates a rotation matrix from equatorial J2000 (EQJ) to ecliptic J2000 (ECL). * diff --git a/generate/template/astronomy.py b/generate/template/astronomy.py index e9bacc8d..82794623 100644 --- a/generate/template/astronomy.py +++ b/generate/template/astronomy.py @@ -6643,9 +6643,9 @@ class LibrationInfo: elon : float Sub-Earth libration ecliptic longitude angle, in degrees. mlat : float - Moon's geocentric ecliptic latitude. + Moon's geocentric ecliptic latitude, in degrees. mlon : float - Moon's geocentric ecliptic longitude. + Moon's geocentric ecliptic longitude, in degrees. dist_km : float Distance between the centers of the Earth and Moon in kilometers. diam_deg : float @@ -6791,7 +6791,7 @@ def Libration(time): ldash2 = -tau + (rho*math.cos(a) + sigma*math.sin(a))*math.tan(bdash) bdash = math.degrees(bdash) bdash2 = sigma*math.cos(a) - rho*math.sin(a) - return LibrationInfo(bdash + bdash2, ldash + ldash2, mlat, mlon, dist_km, diam_deg) + return LibrationInfo(bdash + bdash2, ldash + ldash2, math.degrees(mlat), math.degrees(mlon), dist_km, diam_deg) class AxisInfo: diff --git a/generate/template/astronomy.ts b/generate/template/astronomy.ts index 9e9ed725..6aff9e2b 100644 --- a/generate/template/astronomy.ts +++ b/generate/template/astronomy.ts @@ -918,9 +918,9 @@ $ASTRO_ADDSOL() * @property {number} elon * Sub-Earth libration ecliptic longitude angle, in degrees. * @property {number} mlat - * Moon's geocentric ecliptic latitude. + * Moon's geocentric ecliptic latitude, in degrees. * @property {number} mlon - * Moon's geocentric ecliptic longitude. + * Moon's geocentric ecliptic longitude, in degrees. * @property {number} dist_km * Distance between the centers of the Earth and Moon in kilometers. * @property {number} diam_deg @@ -1056,7 +1056,7 @@ export function Libration(date: FlexibleDateTime): LibrationInfo { const ldash2 = -tau + (rho*Math.cos(a) + sigma*Math.sin(a))*Math.tan(bdash); const bdash2 = sigma*Math.cos(a) - rho*Math.sin(a); const diam_deg = 2.0 * RAD2DEG * Math.atan(MOON_MEAN_RADIUS_KM / Math.sqrt(dist_km*dist_km - MOON_MEAN_RADIUS_KM*MOON_MEAN_RADIUS_KM)); - return new LibrationInfo(RAD2DEG*bdash + bdash2, ldash + ldash2, mlat, mlon, dist_km, diam_deg); + return new LibrationInfo(RAD2DEG*bdash + bdash2, ldash + ldash2, RAD2DEG*mlat, RAD2DEG*mlon, dist_km, diam_deg); } function rotate(rot: RotationMatrix, vec: ArrayVector): ArrayVector { diff --git a/generate/test.js b/generate/test.js index ace0d6a8..34f44b67 100644 --- a/generate/test.js +++ b/generate/test.js @@ -2451,6 +2451,7 @@ function Libration(filename) { let max_diff_elat = 0.0; let max_diff_distance = 0.0; let max_diff_diam = 0.0; + let max_eclip_lon = -900.0; let count = 0; let lnum = 0; for (let line of lines) { @@ -2502,6 +2503,9 @@ function Libration(filename) { if (diff_diam > max_diff_diam) max_diff_diam = diff_diam; + if (lib.mlon > max_eclip_lon) + max_eclip_lon = lib.mlon; + if (diff_elon > 0.1304) { console.error(`JS Libration(${filename} line ${lnum}): EXCESSIVE diff_elon = ${diff_elon} arcmin`); return 1; @@ -2516,9 +2520,18 @@ function Libration(filename) { console.error(`JS Libration(${filename} line ${lnum}): EXCESSIVE diff_distance = ${diff_distance} km`); return 1; } + + if (diff_diam > 0.00009) { + console.error(`JS Libration(${filename}): EXCESSIVE diff_diam = ${diff_diam} degrees.`); + return 1; + } ++count; } } + if (max_eclip_lon < 359.0 || max_eclip_lon > 360.0) { + console.error(`JS Libration(${filename}): INVALID max ecliptic longitude = ${max_eclip_lon.toFixed(3)} degrees.`); + return 1; + } console.log(`JS Libration(${filename}): PASS (${count} test cases, max_diff_elon = ${max_diff_elon} arcmin, max_diff_elat = ${max_diff_elat} arcmin, max_diff_distance = ${max_diff_distance} km, max_diff_diam = ${max_diff_diam} deg)`); return 0; } @@ -2528,8 +2541,7 @@ function LibrationTest() { return ( Libration("libration/mooninfo_2020.txt") || Libration("libration/mooninfo_2021.txt") || - Libration("libration/mooninfo_2022.txt") || - 0 + Libration("libration/mooninfo_2022.txt") ); } diff --git a/generate/test.py b/generate/test.py index f7d6546b..cc66e5ac 100755 --- a/generate/test.py +++ b/generate/test.py @@ -2201,6 +2201,7 @@ def LibrationFile(filename): max_diff_elat = 0.0 max_diff_distance = 0.0 max_diff_diam = 0.0 + max_eclip_lon = -900.0 count = 0 with open(filename, 'rt') as infile: lnum = 0 @@ -2247,6 +2248,9 @@ def LibrationFile(filename): if diff_diam > max_diff_diam: max_diff_diam = diff_diam + if lib.mlon > max_eclip_lon: + max_eclip_lon = lib.mlon + if diff_elon > 0.1304: print('PY LibrationFile({} line {}): EXCESSIVE diff_elon = {}'.format(filename, lnum, diff_elon)) return 1 @@ -2259,9 +2263,17 @@ def LibrationFile(filename): print('PY LibrationFile({} line {}): EXCESSIVE diff_distance = {}'.format(filename, lnum, diff_distance)) return 1 + if diff_diam > 0.00009: + print('PY LibrationFile({} line {}): EXCESSIVE diff_diam = {}'.format(filename, lnum, diff_diam)) + return 1 + count += 1 - print('PY Libration({}): PASS ({} test cases, max_diff_elon = {} arcmin, max_diff_elat = {} arcmin, max_diff_distance = {} km, max_diff_diam = {} deg)'.format( + if not (359.0 < max_eclip_lon < 360.0): + print('PY LibrationFile({}): INVALID max ecliptic longitude = {:0.3f}'.format(filename, max_eclip_lon)) + return 1 + + print('PY LibrationFile({}): PASS ({} test cases, max_diff_elon = {} arcmin, max_diff_elat = {} arcmin, max_diff_distance = {} km, max_diff_diam = {} deg)'.format( filename, count, max_diff_elon, max_diff_elat, max_diff_distance, max_diff_diam )) return 0 @@ -2270,8 +2282,7 @@ def Libration(): return ( LibrationFile('libration/mooninfo_2020.txt') or LibrationFile('libration/mooninfo_2021.txt') or - LibrationFile('libration/mooninfo_2022.txt') or - 0 + LibrationFile('libration/mooninfo_2022.txt') ) #----------------------------------------------------------------------------------------------------------- diff --git a/source/c/README.md b/source/c/README.md index 1bbb4bc3..d2b7ebc0 100644 --- a/source/c/README.md +++ b/source/c/README.md @@ -3915,8 +3915,8 @@ The following integer constants may be useful for indexing into the `moon` array | ---- | ------ | ----------- | | `double` | `elat` | Sub-Earth libration ecliptic latitude angle, in degrees. | | `double` | `elon` | Sub-Earth libration ecliptic longitude angle, in degrees. | -| `double` | `mlat` | Moon's geocentric ecliptic latitude. | -| `double` | `mlon` | Moon's geocentric ecliptic longitude. | +| `double` | `mlat` | Moon's geocentric ecliptic latitude, in degrees. | +| `double` | `mlon` | Moon's geocentric ecliptic longitude, in degrees. | | `double` | `dist_km` | Distance between the centers of the Earth and Moon in kilometers. | | `double` | `diam_deg` | The apparent angular diameter of the Moon, in degrees, as seen from the center of the Earth. | diff --git a/source/c/astronomy.c b/source/c/astronomy.c index ff9f89cc..cf67dccf 100644 --- a/source/c/astronomy.c +++ b/source/c/astronomy.c @@ -2288,7 +2288,11 @@ astro_libration_t Astronomy_Libration(astro_time_t time) t3 = t2 * t; t4 = t2 * t2; - CalcMoon(t, &lib.mlon, &lib.mlat, &lib.dist_km); + double mlon; /* Moon's ecliptic longitude in radians. */ + double mlat; /* Moon's ecliptic latitude in radians. */ + CalcMoon(t, &mlon, &mlat, &lib.dist_km); + lib.mlon = RAD2DEG * mlon; + lib.mlat = RAD2DEG * mlat; lib.dist_km *= KM_PER_AU; lib.diam_deg = (2.0 * RAD2DEG) * atan(MOON_MEAN_RADIUS_KM / sqrt(lib.dist_km*lib.dist_km - MOON_MEAN_RADIUS_KM*MOON_MEAN_RADIUS_KM)); @@ -2311,10 +2315,10 @@ astro_libration_t Astronomy_Libration(astro_time_t time) e = 1.0 - 0.002516*t - 0.0000074*t2; /* Optical librations */ - w = lib.mlon - omega; - a = atan2(sin(w)*cos(lib.mlat)*cos_I - sin(lib.mlat)*sin_I, cos(w)*cos(lib.mlat)); + w = mlon - omega; + a = atan2(sin(w)*cos(mlat)*cos_I - sin(mlat)*sin_I, cos(w)*cos(mlat)); ldash = LongitudeOffset(RAD2DEG * (a - f)); - bdash = asin(-sin(w)*cos(lib.mlat)*sin_I - sin(lib.mlat)*cos_I); + bdash = asin(-sin(w)*cos(mlat)*sin_I - sin(mlat)*cos_I); /* Physical librations */ k1 = DEG2RAD*(119.75 + 131.849*t); diff --git a/source/c/astronomy.h b/source/c/astronomy.h index 8c7f9331..50e0de02 100644 --- a/source/c/astronomy.h +++ b/source/c/astronomy.h @@ -997,8 +997,8 @@ typedef struct { double elat; /**< Sub-Earth libration ecliptic latitude angle, in degrees. */ double elon; /**< Sub-Earth libration ecliptic longitude angle, in degrees. */ - double mlat; /**< Moon's geocentric ecliptic latitude. */ - double mlon; /**< Moon's geocentric ecliptic longitude. */ + double mlat; /**< Moon's geocentric ecliptic latitude, in degrees. */ + double mlon; /**< Moon's geocentric ecliptic longitude, in degrees. */ double dist_km; /**< Distance between the centers of the Earth and Moon in kilometers. */ double diam_deg; /**< The apparent angular diameter of the Moon, in degrees, as seen from the center of the Earth. */ } diff --git a/source/csharp/README.md b/source/csharp/README.md index 1c1cb936..d53df841 100644 --- a/source/csharp/README.md +++ b/source/csharp/README.md @@ -2571,8 +2571,8 @@ and the velocities in AU/day. | --- | --- | --- | | `double` | `elat` | Sub-Earth libration ecliptic latitude angle, in degrees. | | `double` | `elon` | Sub-Earth libration ecliptic longitude angle, in degrees. | -| `double` | `mlat` | Moon's geocentric ecliptic latitude. | -| `double` | `mlon` | Moon's geocentric ecliptic longitude. | +| `double` | `mlat` | Moon's geocentric ecliptic latitude in degrees. | +| `double` | `mlon` | Moon's geocentric ecliptic longitude in degrees. | | `double` | `dist_km` | Distance between the centers of the Earth and Moon in kilometers. | | `double` | `diam_deg` | The apparent angular diameter of the Moon, in degrees, as seen from the center of the Earth. | diff --git a/source/csharp/astronomy.cs b/source/csharp/astronomy.cs index 3bffe06b..3ee620a8 100644 --- a/source/csharp/astronomy.cs +++ b/source/csharp/astronomy.cs @@ -1016,10 +1016,10 @@ namespace CosineKitty /// Sub-Earth libration ecliptic longitude angle, in degrees. public double elon; - /// Moon's geocentric ecliptic latitude. + /// Moon's geocentric ecliptic latitude in degrees. public double mlat; - /// Moon's geocentric ecliptic longitude. + /// Moon's geocentric ecliptic longitude in degrees. public double mlon; /// Distance between the centers of the Earth and Moon in kilometers. @@ -4911,8 +4911,8 @@ namespace CosineKitty MoonResult moon = context.CalcMoon(); LibrationInfo lib; - lib.mlon = moon.geo_eclip_lon; - lib.mlat = moon.geo_eclip_lat; + lib.mlon = RAD2DEG * moon.geo_eclip_lon; + lib.mlat = RAD2DEG * moon.geo_eclip_lat; lib.dist_km = moon.distance_au * KM_PER_AU; lib.diam_deg = (2.0 * RAD2DEG) * Math.Atan(MOON_MEAN_RADIUS_KM / Math.Sqrt(lib.dist_km*lib.dist_km - MOON_MEAN_RADIUS_KM*MOON_MEAN_RADIUS_KM)); @@ -4938,10 +4938,10 @@ namespace CosineKitty double e = 1.0 - 0.002516*t - 0.0000074*t2; // Optical librations - double w = lib.mlon - omega; - double a = Math.Atan2(Math.Sin(w)*Math.Cos(lib.mlat)*Math.Cos(I) - Math.Sin(lib.mlat)*Math.Sin(I), Math.Cos(w)*Math.Cos(lib.mlat)); + double w = moon.geo_eclip_lon - omega; + double a = Math.Atan2(Math.Sin(w)*Math.Cos(moon.geo_eclip_lat)*Math.Cos(I) - Math.Sin(moon.geo_eclip_lat)*Math.Sin(I), Math.Cos(w)*Math.Cos(moon.geo_eclip_lat)); double ldash = LongitudeOffset(RAD2DEG * (a - f)); - double bdash = Math.Asin(-Math.Sin(w)*Math.Cos(lib.mlat)*Math.Sin(I) - Math.Sin(lib.mlat)*Math.Cos(I)); + double bdash = Math.Asin(-Math.Sin(w)*Math.Cos(moon.geo_eclip_lat)*Math.Sin(I) - Math.Sin(moon.geo_eclip_lat)*Math.Cos(I)); // Physical librations double k1 = DEG2RAD*(119.75 + 131.849*t); diff --git a/source/js/README.md b/source/js/README.md index 30610a60..e9c1b5dd 100644 --- a/source/js/README.md +++ b/source/js/README.md @@ -247,8 +247,8 @@ an `AstroTime` value that can be passed to Astronomy Engine functions. | --- | --- | --- | | elat | number | Sub-Earth libration ecliptic latitude angle, in degrees. | | elon | number | Sub-Earth libration ecliptic longitude angle, in degrees. | -| mlat | number | Moon's geocentric ecliptic latitude. | -| mlon | number | Moon's geocentric ecliptic longitude. | +| mlat | number | Moon's geocentric ecliptic latitude, in degrees. | +| mlon | number | Moon's geocentric ecliptic longitude, in degrees. | | dist_km | number | Distance between the centers of the Earth and Moon in kilometers. | | diam_deg | number | The apparent angular diameter of the Moon, in degrees, as seen from the center of the Earth. | diff --git a/source/js/astronomy.browser.js b/source/js/astronomy.browser.js index 55eb9de4..c122c4d1 100644 --- a/source/js/astronomy.browser.js +++ b/source/js/astronomy.browser.js @@ -1623,9 +1623,9 @@ function CalcMoon(time) { * @property {number} elon * Sub-Earth libration ecliptic longitude angle, in degrees. * @property {number} mlat - * Moon's geocentric ecliptic latitude. + * Moon's geocentric ecliptic latitude, in degrees. * @property {number} mlon - * Moon's geocentric ecliptic longitude. + * Moon's geocentric ecliptic longitude, in degrees. * @property {number} dist_km * Distance between the centers of the Earth and Moon in kilometers. * @property {number} diam_deg @@ -1742,7 +1742,7 @@ function Libration(date) { const ldash2 = -tau + (rho * Math.cos(a) + sigma * Math.sin(a)) * Math.tan(bdash); const bdash2 = sigma * Math.cos(a) - rho * Math.sin(a); const diam_deg = 2.0 * exports.RAD2DEG * Math.atan(MOON_MEAN_RADIUS_KM / Math.sqrt(dist_km * dist_km - MOON_MEAN_RADIUS_KM * MOON_MEAN_RADIUS_KM)); - return new LibrationInfo(exports.RAD2DEG * bdash + bdash2, ldash + ldash2, mlat, mlon, dist_km, diam_deg); + return new LibrationInfo(exports.RAD2DEG * bdash + bdash2, ldash + ldash2, exports.RAD2DEG * mlat, exports.RAD2DEG * mlon, dist_km, diam_deg); } exports.Libration = Libration; function rotate(rot, vec) { diff --git a/source/js/astronomy.browser.min.js b/source/js/astronomy.browser.min.js index b60d92d4..3bb60e53 100644 --- a/source/js/astronomy.browser.min.js +++ b/source/js/astronomy.browser.min.js @@ -166,78 +166,78 @@ var qb=new Date("2000-01-01T12:00:00Z"),R=2*Math.PI,ba=180/Math.PI*3600,$c=-.17- Qc;e.Libration=function(a){var b=w(a);a=b.tt/36525;var c=a*a,d=c*a,f=c*c,h=Y(b);b=h.geo_eclip_lon;var l=h.geo_eclip_lat;h=h.distance_au*e.KM_PER_AU;var k=1.543*e.DEG2RAD,g=e.DEG2RAD*ta(93.272095+483202.0175233*a-.0036539*c-d/3526E3+f/86331E4),m=e.DEG2RAD*ta(125.0445479-1934.1362891*a+.0020754*c+d/467441-f/60616E3),n=e.DEG2RAD*ta(357.5291092+35999.0502909*a-1.536E-4*c+d/2449E4),p=e.DEG2RAD*ta(134.9633964+477198.8675055*a+.0087414*c+d/69699-f/14712E3);d=e.DEG2RAD*ta(297.8501921+445267.1114034*a-.0018819* c+d/545868-f/113065E3);c=1-.002516*a-7.4E-6*c;var t=b-m;f=Math.atan2(Math.sin(t)*Math.cos(l)*Math.cos(k)-Math.sin(l)*Math.sin(k),Math.cos(t)*Math.cos(l));var x=sa(e.RAD2DEG*(f-g));k=Math.asin(-Math.sin(t)*Math.cos(l)*Math.sin(k)-Math.sin(l)*Math.cos(k));t=-.02752*Math.cos(p)+-.02245*Math.sin(g)+.00684*Math.cos(p-2*g)+-.00293*Math.cos(2*g)+-8.5E-4*Math.cos(2*g-2*d)+-5.4E-4*Math.cos(p-2*d)+-2E-4*Math.sin(p+g)+-2E-4*Math.cos(p+2*g)+-2E-4*Math.cos(p-g)+1.4E-4*Math.cos(p+2*g-2*d);var v=-.02816*Math.sin(p)+ .02244*Math.cos(g)+-.00682*Math.sin(p-2*g)+-.00279*Math.sin(2*g)+-8.3E-4*Math.sin(2*g-2*d)+6.9E-4*Math.sin(p-2*d)+4E-4*Math.cos(p+g)+-2.5E-4*Math.sin(2*p)+-2.3E-4*Math.sin(p+2*g)+2E-4*Math.cos(p-g)+1.9E-4*Math.sin(p-g)+1.3E-4*Math.sin(p+2*g-2*d)+-1E-4*Math.cos(p-3*g);return new Qc(e.RAD2DEG*k+(v*Math.cos(f)-t*Math.sin(f)),x+(-(.0252*c*Math.sin(n)+.00473*Math.sin(2*p-2*g)+-.00467*Math.sin(p)+.00396*Math.sin(e.DEG2RAD*(119.75+131.849*a))+.00276*Math.sin(2*p-2*d)+.00196*Math.sin(m)+-.00183*Math.cos(p- -g)+.00115*Math.sin(p-2*d)+-9.6E-4*Math.sin(p-d)+4.6E-4*Math.sin(2*g-2*d)+-3.9E-4*Math.sin(p-g)+-3.2E-4*Math.sin(p-n-d)+2.7E-4*Math.sin(2*p-n-2*d)+2.3E-4*Math.sin(e.DEG2RAD*(72.56+20.186*a))+-1.4E-4*Math.sin(2*d)+1.4E-4*Math.cos(2*p-2*g)+-1.2E-4*Math.sin(p-2*g)+-1.2E-4*Math.sin(2*p)+1.1E-4*Math.sin(2*p-2*n-2*d))+(t*Math.cos(f)+v*Math.sin(f))*Math.tan(k)),l,b,h,2*e.RAD2DEG*Math.atan(1737.4/Math.sqrt(h*h-1737.4*1737.4)))};var Ya;e.SiderealTime=function(a){a=w(a);return X(a)};var D=function(a,b,c,d){this.x= -a;this.y=b;this.z=c;this.t=d};D.prototype.Length=function(){return Math.hypot(this.x,this.y,this.z)};e.Vector=D;var K=function(a,b,c,d,f,h,l){this.x=a;this.y=b;this.z=c;this.vx=d;this.vy=f;this.vz=h;this.t=l};e.StateVector=K;var Ia=function(a,b,c){this.lat=y(a);this.lon=y(b);this.dist=y(c)};e.Spherical=Ia;var ab=function(a,b,c,d){this.ra=y(a);this.dec=y(b);this.dist=y(c);this.vec=d};e.EquatorialCoordinates=ab;var L=function(a){this.rot=a};e.RotationMatrix=L;e.MakeRotation=function(a){if(!Yc(a))throw"Argument must be a [3][3] array of numbers"; -return new L(a)};var Vb=function(a,b,c,d){this.azimuth=y(a);this.altitude=y(b);this.ra=y(c);this.dec=y(d)};e.HorizontalCoordinates=Vb;var Yb=function(a,b,c){this.vec=a;this.elat=y(b);this.elon=y(c)};e.EclipticCoordinates=Yb;e.Horizon=Ea;var pb=function(a,b,c){this.latitude=a;this.longitude=b;this.height=c;pa(this)};e.Observer=pb;e.SunPosition=Wb;e.Equator=Ga;e.ObserverVector=function(a,b,c){a=w(a);var d=X(a);b=ob(b,d).pos;c||(b=$a(b,a,F.Into2000));return new D(b[0],b[1],b[2],a)};e.ObserverState=function(a, -b,c){a=w(a);var d=X(a);b=ob(b,d);b=new K(b.pos[0],b.pos[1],b.pos[2],b.vel[0],b.vel[1],b.vel[2],a);return c?b:(c=F.Into2000,c===F.Into2000?(d=Da(a,c),b=ya(d,b),a=Ca(a,c),a=ya(a,b)):(d=Ca(a,c),b=ya(d,b),a=Da(a,c),a=ya(a,b)),a)};e.VectorObserver=function(a,b){var c=X(a.t),d=[a.x,a.y,a.z];b||(d=Ba(d,a.t,F.From2000),d=Za(d,a.t,F.From2000));b=d[0]*e.KM_PER_AU;var f=d[1]*e.KM_PER_AU;d=d[2]*e.KM_PER_AU;a=Math.hypot(b,f);if(1E-6>a){c=0;var h=0=c;)c+=360;for(;180Math.abs(n))break;h-=n/(-42.69778487239616*((k-g)/l-g*k*-.006694397995865464/(-42.69778487239616*m))+d*f+a*b)}h*=e.RAD2DEG;l=6378.1366/l;d=Math.abs(f)>Math.abs(b)?d/f-.9933056020041345*l:a/b-l}return new pb(h,c,1E3*d)};e.ObserverGravity=function(a,b){a=Math.sin(a*e.DEG2RAD);a*=a;return 9.7803253359* -(1+.00193185265241*a)/Math.sqrt(1-.00669437999013*a)*(1-(3.15704E-7-2.10269E-9*a)*b+7.37452E-14*b*b)};e.Ecliptic=Ha;e.GeoMoon=V;e.EclipticGeoMoon=cb;e.GeoMoonState=Ja;e.GeoEmbState=rb;var ia=[[-73E4,[-26.118207232108,-14.376168177825,3.384402515299],[.0016339372163656,-.0027861699588508,-.0013585880229445]],[-700800,[41.974905202127,-.448502952929,-12.770351505989],[7.3458569351457E-4,.0022785014891658,4.8619778602049E-4]],[-671600,[14.706930780744,44.269110540027,9.353698474772],[-.00210001479998, -2.2295915939915E-4,7.0143443551414E-4]],[-642400,[-29.441003929957,-6.43016153057,6.858481011305],[8.4495803960544E-4,-.0030783914758711,-.0012106305981192]],[-613200,[39.444396946234,-6.557989760571,-13.913760296463],[.0011480029005873,.0022400006880665,3.5168075922288E-4]],[-584E3,[20.2303809507,43.266966657189,7.382966091923],[-.0019754081700585,5.3457141292226E-4,7.5929169129793E-4]],[-554800,[-30.65832536462,2.093818874552,9.880531138071],[6.1010603013347E-5,-.0031326500935382,-9.9346125151067E-4]], -[-525600,[35.737703251673,-12.587706024764,-14.677847247563],[.0015802939375649,.0021347678412429,1.9074436384343E-4]],[-496400,[25.466295188546,41.367478338417,5.216476873382],[-.0018054401046468,8.328308359951E-4,8.0260156912107E-4]],[-467200,[-29.847174904071,10.636426313081,12.297904180106],[-6.3257063052907E-4,-.0029969577578221,-7.4476074151596E-4]],[-438E3,[30.774692107687,-18.236637015304,-14.945535879896],[.0020113162005465,.0019353827024189,-2.0937793168297E-6]],[-408800,[30.243153324028, -38.656267888503,2.938501750218],[-.0016052508674468,.0011183495337525,8.3333973416824E-4]],[-379600,[-27.288984772533,18.643162147874,14.023633623329],[-.0011856388898191,-.0027170609282181,-4.9015526126399E-4]],[-350400,[24.519605196774,-23.245756064727,-14.626862367368],[.0024322321483154,.0016062008146048,-2.3369181613312E-4]],[-321200,[34.505274805875,35.125338586954,.557361475637],[-.0013824391637782,.0013833397561817,8.4823598806262E-4]],[-292E3,[-23.275363915119,25.818514298769,15.055381588598], -[-.0016062295460975,-.0023395961498533,-2.4377362639479E-4]],[-262800,[17.050384798092,-27.180376290126,-13.608963321694],[.0028175521080578,.0011358749093955,-4.9548725258825E-4]],[-233600,[38.093671910285,30.880588383337,-1.843688067413],[-.0011317697153459,.0016128814698472,8.4177586176055E-4]],[-204400,[-18.197852930878,31.932869934309,15.438294826279],[-.0019117272501813,-.0019146495909842,-1.9657304369835E-5]],[-175200,[8.528924039997,-29.618422200048,-11.805400994258],[.0031034370787005,5.139363329243E-4, --7.7293066202546E-4]],[-146E3,[40.94685725864,25.904973592021,-4.256336240499],[-8.3652705194051E-4,.0018129497136404,8.156422827306E-4]],[-116800,[-12.326958895325,36.881883446292,15.217158258711],[-.0021166103705038,-.001481442003599,1.7401209844705E-4]],[-87600,[-.633258375909,-30.018759794709,-9.17193287495],[.0032016994581737,-2.5279858672148E-4,-.0010411088271861]],[-58400,[42.936048423883,20.344685584452,-6.588027007912],[-5.0525450073192E-4,.0019910074335507,7.7440196540269E-4]],[-29200,[-5.975910552974, -40.61180995846,14.470131723673],[-.0022184202156107,-.0010562361130164,3.3652250216211E-4]],[0,[-9.875369580774,-27.978926224737,-5.753711824704],[.0030287533248818,-.0011276087003636,-.0012651326732361]],[29200,[43.958831986165,14.214147973292,-8.808306227163],[-1.4717608981871E-4,.0021404187242141,7.1486567806614E-4]],[58400,[.67813676352,43.094461639362,13.243238780721],[-.0022358226110718,-6.3233636090933E-4,4.7664798895648E-4]],[87600,[-18.282602096834,-23.30503958666,-1.766620508028],[.0025567245263557, --.0019902940754171,-.0013943491701082]],[116800,[43.873338744526,7.700705617215,-10.814273666425],[2.3174803055677E-4,.0022402163127924,6.2988756452032E-4]],[146E3,[7.392949027906,44.382678951534,11.629500214854],[-.002193281545383,-2.1751799585364E-4,5.9556516201114E-4]],[175200,[-24.981690229261,-16.204012851426,2.466457544298],[.001819398914958,-.0026765419531201,-.0013848283502247]],[204400,[42.530187039511,.845935508021,-12.554907527683],[6.5059779150669E-4,.0022725657282262,5.1133743202822E-4]], -[233600,[13.999526486822,44.462363044894,9.669418486465],[-.0021079296569252,1.7533423831993E-4,6.9128485798076E-4]],[262800,[-29.184024803031,-7.371243995762,6.493275957928],[9.3581363109681E-4,-.0030610357109184,-.0012364201089345]],[292E3,[39.831980671753,-6.078405766765,-13.909815358656],[.0011117769689167,.0022362097830152,3.6230548231153E-4]],[321200,[20.294955108476,43.417190420251,7.450091985932],[-.0019742157451535,5.3102050468554E-4,7.5938408813008E-4]],[350400,[-30.66999230216,2.318743558955, -9.973480913858],[4.5605107450676E-5,-.0031308219926928,-9.9066533301924E-4]],[379600,[35.626122155983,-12.897647509224,-14.777586508444],[.0016015684949743,.0021171931182284,1.8002516202204E-4]],[408800,[26.133186148561,41.232139187599,5.00640132622],[-.0017857704419579,8.6046232702817E-4,8.0614690298954E-4]],[438E3,[-29.57674022923,11.863535943587,12.631323039872],[-7.2292830060955E-4,-.0029587820140709,-7.08242964503E-4]],[467200,[29.910805787391,-19.159019294,-15.013363865194],[.0020871080437997, -.0018848372554514,-3.8528655083926E-5]],[496400,[31.375957451819,38.050372720763,2.433138343754],[-.0015546055556611,.0011699815465629,8.3565439266001E-4]],[525600,[-26.360071336928,20.662505904952,14.414696258958],[-.0013142373118349,-.0026236647854842,-4.2542017598193E-4]],[554800,[22.599441488648,-24.508879898306,-14.484045731468],[.0025454108304806,.0014917058755191,-3.0243665086079E-4]],[584E3,[35.877864013014,33.894226366071,-.224524636277],[-.0012941245730845,.0014560427668319,8.4762160640137E-4]], -[613200,[-21.538149762417,28.204068269761,15.321973799534],[-.001731211740901,-.0021939631314577,-1.631691327518E-4]],[642400,[13.971521374415,-28.339941764789,-13.083792871886],[.0029334630526035,9.1860931752944E-4,-5.9939422488627E-4]],[671600,[39.526942044143,28.93989736011,-2.872799527539],[-.0010068481658095,.001702113288809,8.3578230511981E-4]],[700800,[-15.576200701394,34.399412961275,15.466033737854],[-.0020098814612884,-.0017191109825989,7.0414782780416E-5]],[73E4,[4.24325283709,-30.118201690825, --10.707441231349],[.0031725847067411,1.609846120227E-4,-9.0672150593868E-4]]],G=function(a,b,c){this.x=a;this.y=b;this.z=c};G.prototype.ToAstroVector=function(a){return new D(this.x,this.y,this.z,a)};G.prototype.quadrature=function(){return this.x*this.x+this.y*this.y+this.z*this.z};G.prototype.add=function(a){return new G(this.x+a.x,this.y+a.y,this.z+a.z)};G.prototype.sub=function(a){return new G(this.x-a.x,this.y-a.y,this.z-a.z)};G.prototype.incr=function(a){this.x+=a.x;this.y+=a.y;this.z+=a.z}; -G.prototype.decr=function(a){this.x-=a.x;this.y-=a.y;this.z-=a.z};G.prototype.mul=function(a){return new G(a*this.x,a*this.y,a*this.z)};G.prototype.div=function(a){return new G(this.x/a,this.y/a,this.z/a)};G.prototype.mean=function(a){return new G((this.x+a.x)/2,(this.y+a.y)/2,(this.z+a.z)/2)};var db=function(a,b,c){this.tt=a;this.r=b;this.v=c},qa=function(a){var b=new db(a,new G(0,0,0),new G(0,0,0));this.Jupiter=fb(b,a,q.Jupiter,2.825345909524226E-7);this.Saturn=fb(b,a,q.Saturn,8.459715185680659E-8); -this.Uranus=fb(b,a,q.Uranus,1.292024916781969E-8);this.Neptune=fb(b,a,q.Neptune,1.524358900784276E-8);this.Jupiter.r.decr(b.r);this.Jupiter.v.decr(b.v);this.Saturn.r.decr(b.r);this.Saturn.v.decr(b.v);this.Uranus.r.decr(b.r);this.Uranus.v.decr(b.v);this.Neptune.r.decr(b.r);this.Neptune.v.decr(b.v);this.Sun=new db(a,b.r.mul(-1),b.v.mul(-1))};qa.prototype.Acceleration=function(a){var b=La(a,2.959122082855911E-4,this.Sun.r);b.incr(La(a,2.825345909524226E-7,this.Jupiter.r));b.incr(La(a,8.459715185680659E-8, -this.Saturn.r));b.incr(La(a,1.292024916781969E-8,this.Uranus.r));b.incr(La(a,1.524358900784276E-8,this.Neptune.r));return b};var cc=function(a,b,c,d){this.tt=a;this.r=b;this.v=c;this.a=d},dc=function(a,b){this.bary=a;this.grav=b},xb=[],jd=new L([[.999432765338654,-.0336771074697641,0],[.0303959428906285,.902057912352809,.430543388542295],[-.0144994559663353,-.430299169409101,.902569881273754]]),kd=[{mu:2.82489428433814E-7,al:[1.446213296021224,3.5515522861824],a:[[.0028210960212903,0,0]],l:[[-1.925258348666E-4, -4.9369589722645,.01358483658305],[-9.70803596076E-5,4.3188796477322,.01303413843243],[-8.988174165E-5,1.9080016428617,.00305064867158],[-5.53101050262E-5,1.4936156681569,.01293892891155]],z:[[.0041510849668155,4.089939635545,-.01290686414666],[6.260521444113E-4,1.446188898627,3.5515522949802],[3.52747346169E-5,2.1256287034578,1.2727416567E-4]],zeta:[[3.142172466014E-4,2.7964219722923,-.002315096098],[9.04169207946E-5,1.0477061879627,-5.6920638196E-4]]},{mu:2.82483274392893E-7,al:[-.3735263437471362, -1.76932271112347],a:[[.0044871037804314,0,0],[4.324367498E-7,1.819645606291,1.7822295777568]],l:[[8.576433172936E-4,4.3188693178264,.01303413830805],[4.549582875086E-4,1.4936531751079,.01293892881962],[3.248939825174E-4,1.8196494533458,1.7822295777568],[-3.074250079334E-4,4.9377037005911,.01358483286724],[1.982386144784E-4,1.907986905476,.00305101212869],[1.834063551804E-4,2.1402853388529,.00145009789338],[-1.434383188452E-4,5.622214036663,.89111478887838],[-7.71939140944E-5,4.300272437235,2.6733443704266]], -z:[[-.0093589104136341,4.0899396509039,-.01290686414666],[2.988994545555E-4,5.9097265185595,1.7693227079462],[2.13903639035E-4,2.1256289300016,1.2727418407E-4],[1.980963564781E-4,2.743516829265,6.7797343009E-4],[1.210388158965E-4,5.5839943711203,3.20566149E-5],[8.37042048393E-5,1.6094538368039,-.90402165808846],[8.23525166369E-5,1.4461887708689,3.5515522949802]],zeta:[[.0040404917832303,1.0477063169425,-5.692064054E-4],[2.200421034564E-4,3.3368857864364,-1.2491307307E-4],[1.662544744719E-4,2.4134862374711, -0],[5.90282470983E-5,5.9719930968366,-3.056160225E-5]]},{mu:2.82498184184723E-7,al:[.2874089391143348,.878207923589328],a:[[.0071566594572575,0,0],[1.393029911E-6,1.1586745884981,2.6733443704266]],l:[[2.310797886226E-4,2.1402987195942,.00145009784384],[-1.828635964118E-4,4.3188672736968,.01303413828263],[1.512378778204E-4,4.9373102372298,.01358483481252],[-1.163720969778E-4,4.300265986149,2.6733443704266],[-9.55478069846E-5,1.4936612842567,.01293892879857],[8.15246854464E-5,5.6222137132535,.89111478887838], -[-8.01219679602E-5,1.2995922951532,1.0034433456729],[-6.07017260182E-5,.64978769669238,.50172167043264]],z:[[.0014289811307319,2.1256295942739,1.2727413029E-4],[7.71093122676E-4,5.5836330003496,3.20643411E-5],[5.925911780766E-4,4.0899396636448,-.01290686414666],[2.045597496146E-4,5.2713683670372,-.12523544076106],[1.785118648258E-4,.28743156721063,.8782079244252],[1.131999784893E-4,1.4462127277818,3.5515522949802],[-6.5877816921E-5,2.2702423990985,-1.7951364394537],[4.97058888328E-5,5.9096792204858, -1.7693227129285]],zeta:[[.0015932721570848,3.3368862796665,-1.2491307058E-4],[8.533093128905E-4,2.4133881688166,0],[3.513347911037E-4,5.9720789850127,-3.056101771E-5],[-1.441929255483E-4,1.0477061764435,-5.6920632124E-4]]},{mu:2.82492144889909E-7,al:[-.3620341291375704,.376486233433828],a:[[.0125879701715314,0,0],[3.595204947E-6,.64965776007116,.50172168165034],[2.7580210652E-6,1.808423578151,3.1750660413359]],l:[[5.586040123824E-4,2.1404207189815,.00145009793231],[-3.805813868176E-4,2.7358844897853, -2.972965062E-5],[2.205152863262E-4,.649796525964,.5017216724358],[1.877895151158E-4,1.8084787604005,3.1750660413359],[7.66916975242E-5,6.2720114319755,1.3928364636651],[7.47056855106E-5,1.2995916202344,1.0034433456729]],z:[[.0073755808467977,5.5836071576084,3.206509914E-5],[2.065924169942E-4,5.9209831565786,.37648624194703],[1.589869764021E-4,.28744006242623,.8782079244252],[-1.561131605348E-4,2.1257397865089,1.2727441285E-4],[1.486043380971E-4,1.4462134301023,3.5515522949802],[6.35073108731E-5,5.9096803285954, -1.7693227129285],[5.99351698525E-5,4.1125517584798,-2.7985797954589],[5.40660842731E-5,5.5390350845569,.00286834082283],[-4.89596900866E-5,4.6218149483338,-.62695712529519]],zeta:[[.0038422977898495,2.4133922085557,0],[.0022453891791894,5.9721736773277,-3.056125525E-5],[-2.604479450559E-4,3.3368746306409,-1.2491309972E-4],[3.3211214323E-5,5.5604137742337,.00290037688507]]}],Rc=function(a){this.moon=a};e.JupiterMoonsInfo=Rc;e.JupiterMoons=function(a){a=new P(a);for(var b=[],c=$jscomp.makeIterator(kd), -d=c.next();!d.done;d=c.next()){var f=b,h=f.push;d=d.value;for(var l=a.tt+18262.5,k=[0,d.al[0]+l*d.al[1],0,0,0,0],g=$jscomp.makeIterator(d.a),m=g.next();!m.done;m=g.next()){var n=$jscomp.makeIterator(m.value);m=n.next().value;var p=n.next().value;n=n.next().value;k[0]+=m*Math.cos(p+l*n)}g=$jscomp.makeIterator(d.l);for(m=g.next();!m.done;m=g.next())n=$jscomp.makeIterator(m.value),m=n.next().value,p=n.next().value,n=n.next().value,k[1]+=m*Math.sin(p+l*n);k[1]%=R;0>k[1]&&(k[1]+=R);g=$jscomp.makeIterator(d.z); -for(m=g.next();!m.done;m=g.next())n=$jscomp.makeIterator(m.value),m=n.next().value,p=n.next().value,n=n.next().value,p+=l*n,k[2]+=m*Math.cos(p),k[3]+=m*Math.sin(p);g=$jscomp.makeIterator(d.zeta);for(m=g.next();!m.done;m=g.next())n=$jscomp.makeIterator(m.value),m=n.next().value,p=n.next().value,n=n.next().value,p+=l*n,k[4]+=m*Math.cos(p),k[5]+=m*Math.sin(p);g=k[0];n=k[1];m=k[2];p=k[3];l=k[4];k=k[5];var t=Math.sqrt(d.mu/(g*g*g));d=n+m*Math.sin(n)-p*Math.cos(n);do{var x=Math.cos(d);var v=Math.sin(d); -x=(n-d+m*v-p*x)/(1-m*x-p*v);d+=x}while(1E-12<=Math.abs(x));x=Math.cos(d);v=Math.sin(d);n=p*x-m*v;var z=-m*x-p*v,ea=1/(1+z),S=1/(1+Math.sqrt(1-m*m-p*p));d=g*(x-m-S*p*n);n=g*(v-p+S*m*n);p=t*ea*g*(-v-S*p*z);g=t*ea*g*(+x+S*m*z);m=2*Math.sqrt(1-l*l-k*k);t=1-2*k*k;x=1-2*l*l;v=2*k*l;d=new K(d*t+n*v,d*v+n*x,(l*n-d*k)*m,p*t+g*v,p*v+g*x,(l*g-p*k)*m,a);d=ya(jd,d);h.call(f,d)}return new Rc(b)};e.HelioVector=Ma;e.HelioDistance=ja;e.GeoVector=ca;e.BaryState=function(a,b){b=w(b);if(a===q.SSB)return new K(0,0,0, -0,0,0,b);if(a===q.Pluto)return wb(b,!1);var c=new qa(b.tt);switch(a){case q.Sun:return ra(c.Sun,b);case q.Jupiter:return ra(c.Jupiter,b);case q.Saturn:return ra(c.Saturn,b);case q.Uranus:return ra(c.Uranus,b);case q.Neptune:return ra(c.Neptune,b);case q.Moon:case q.EMB:var d=Ka(H[q.Earth],b.tt);a=a===q.Moon?Ja(b):rb(b);return new K(a.x+c.Sun.r.x+d.r.x,a.y+c.Sun.r.y+d.r.y,a.z+c.Sun.r.z+d.r.z,a.vx+c.Sun.v.x+d.v.x,a.vy+c.Sun.v.y+d.v.y,a.vz+c.Sun.v.z+d.v.z,b)}if(a in H)return a=Ka(H[a],b.tt),new K(c.Sun.r.x+ -a.r.x,c.Sun.r.y+a.r.y,c.Sun.r.z+a.r.z,c.Sun.v.x+a.v.x,c.Sun.v.y+a.v.y,c.Sun.v.z+a.v.z,b);throw'BaryState: Unsupported body "'+a+'"';};e.HelioState=yb;e.Search=I;e.SearchSunLongitude=gc;e.PairLongitude=zb;e.AngleFromSun=ua;e.EclipticLongitude=ka;var hc=function(a,b,c,d,f,h,l,k){this.time=a;this.mag=b;this.phase_angle=c;this.helio_dist=d;this.geo_dist=f;this.gc=h;this.hc=l;this.ring_tilt=k;this.phase_fraction=(1+Math.cos(e.DEG2RAD*c))/2};e.IlluminationInfo=hc;e.Illumination=hb;e.SearchRelativeLongitude= -va;e.MoonPhase=Ab;e.SearchMoonPhase=Oa;var jc=function(a,b){this.quarter=a;this.time=b};e.MoonQuarter=jc;e.SearchMoonQuarter=ic;e.NextMoonQuarter=function(a){a=new Date(a.time.date.getTime()+5184E5);return ic(a)};e.SearchRiseSet=function(a,b,c,d,f){a:switch(a){case q.Sun:var h=gd;break a;case q.Moon:h=hd;break a;default:h=0}return kc(a,b,c,d,f,function(l){var k=Ga(a,l,b,!0,!0);l=Ea(l,b,k.ra,k.dec).altitude+h/k.dist*e.RAD2DEG+id;return c*l})};e.SearchAltitude=function(a,b,c,d,f,h){if(!Number.isFinite(h)|| --90>h||90=++f;){var h=ka(a,b),l=ka(q.Earth,b),k=sa(h-l),g=h=l=void 0;k>=-d.s1&&k<+d.s1?(g=0,l=+d.s1,h=+d.s2):k>=+d.s2||k<-d.s2?(g=0,l=-d.s2,h=-d.s1):0<=k?(g=-Na(a)/4,l=+d.s1,h=+d.s2):(g=-Na(a)/4,l=-d.s2,h=-d.s1);k=b.AddDays(g);l=va(a,l,k);h=va(a,h,l);k=c(l);if(0<=k)throw"SearchMaxElongation: internal error: m1 = "+k;g=c(h);if(0>=g)throw"SearchMaxElongation: internal error: m2 = "+ -g;k=I(c,l,h,{init_f1:k,init_f2:g,dt_tolerance_seconds:10});if(!k)throw"SearchMaxElongation: failed search iter "+f+" (t1="+l.toString()+", t2="+h.toString()+")";if(k.tt>=b.tt)return mc(a,k);b=h.AddDays(1)}throw"SearchMaxElongation: failed to find event after 2 tries.";};e.SearchPeakMagnitude=function(a,b){function c(g){var m=g.AddDays(-.005);g=g.AddDays(.005);m=hb(a,m).mag;return(hb(a,g).mag-m)/.01}if(a!==q.Venus)throw"SearchPeakMagnitude currently works for Venus only.";b=w(b);for(var d=0;2>=++d;){var f= -ka(a,b),h=ka(q.Earth,b),l=sa(f-h),k=f=h=void 0;-10<=l&&10>l?(k=0,h=10,f=30):30<=l||-30>l?(k=0,h=-30,f=-10):0<=l?(k=-Na(a)/4,h=10,f=30):(k=-Na(a)/4,h=-30,f=-10);l=b.AddDays(k);h=va(a,h,l);f=va(a,f,h);l=c(h);if(0<=l)throw"SearchPeakMagnitude: internal error: m1 = "+l;k=c(f);if(0>=k)throw"SearchPeakMagnitude: internal error: m2 = "+k;l=I(c,h,f,{init_f1:l,init_f2:k,dt_tolerance_seconds:10});if(!l)throw"SearchPeakMagnitude: failed search iter "+d+" (t1="+h.toString()+", t2="+f.toString()+")";if(l.tt>= -b.tt)return hb(a,l);b=f.AddDays(1)}throw"SearchPeakMagnitude: failed to find event after 2 tries.";};var Qa=function(a,b,c){this.time=a;this.kind=b;this.dist_au=c;this.dist_km=c*e.KM_PER_AU};e.Apsis=Qa;e.SearchLunarApsis=oc;e.NextLunarApsis=function(a){var b=oc(a.time.AddDays(11));if(1!==b.kind+a.kind)throw"NextLunarApsis INTERNAL ERROR: did not find alternating apogee/perigee: prev="+a.kind+" @ "+a.time.toString()+", next="+b.kind+" @ "+b.time.toString();return b};e.SearchPlanetApsis=qc;e.NextPlanetApsis= -function(a,b){if(0!==b.kind&&1!==b.kind)throw"Invalid apsis kind: "+b.kind;var c=b.time.AddDays(.25*da[a].OrbitalPeriod);a=qc(a,c);if(1!==a.kind+b.kind)throw"Internal error: previous apsis was "+b.kind+", but found "+a.kind+" for next apsis.";return a};e.InverseRotation=wa;e.CombineRotation=xa;e.IdentityMatrix=function(){return new L([[1,0,0],[0,1,0],[0,0,1]])};e.Pivot=function(a,b,c){if(0!==b&&1!==b&&2!==b)throw"Invalid axis "+b+". Must be [0, 1, 2].";var d=y(c)*e.DEG2RAD;c=Math.cos(d);d=Math.sin(d); -var f=(b+1)%3,h=(b+2)%3,l=[[0,0,0],[0,0,0],[0,0,0]];l[f][f]=c*a.rot[f][f]-d*a.rot[f][h];l[f][h]=d*a.rot[f][f]+c*a.rot[f][h];l[f][b]=a.rot[f][b];l[h][f]=c*a.rot[h][f]-d*a.rot[h][h];l[h][h]=d*a.rot[h][f]+c*a.rot[h][h];l[h][b]=a.rot[h][b];l[b][f]=c*a.rot[b][f]-d*a.rot[b][h];l[b][h]=d*a.rot[b][f]+c*a.rot[b][h];l[b][b]=a.rot[b][b];return new L(l)};e.VectorFromSphere=Bb;e.EquatorFromVector=Cb;e.SphereFromVector=Db;e.HorizonFromVector=function(a,b){a=Db(a);a.lon=rc(a.lon);a.lat+=Fa(b,a.lat);return a};e.VectorFromHorizon= -function(a,b,c){b=w(b);var d=rc(a.lon);c=a.lat+sc(c,a.lat);a=new Ia(c,d,a.dist);return Bb(a,b)};e.Refraction=Fa;e.InverseRefraction=sc;e.RotateVector=Ra;e.RotateState=ya;e.Rotation_EQJ_ECL=tc;e.Rotation_ECL_EQJ=function(){return new L([[1,0,0],[0,.9174821430670688,.3977769691083922],[0,-.3977769691083922,.9174821430670688]])};e.Rotation_EQJ_EQD=Eb;e.Rotation_EQD_EQJ=Fb;e.Rotation_EQD_HOR=Gb;e.Rotation_HOR_EQD=uc;e.Rotation_HOR_EQJ=vc;e.Rotation_EQJ_HOR=function(a,b){a=vc(a,b);return wa(a)};e.Rotation_EQD_ECL= -wc;e.Rotation_ECL_EQD=xc;e.Rotation_ECL_HOR=yc;e.Rotation_HOR_ECL=function(a,b){a=yc(a,b);return wa(a)};e.Rotation_EQJ_GAL=function(){return new L([[-.0548624779711344,.4941095946388765,-.8676668813529025],[-.8734572784246782,-.4447938112296831,-.1980677870294097],[-.483800052994852,.7470034631630423,.4559861124470794]])};e.Rotation_GAL_EQJ=function(){return new L([[-.0548624779711344,-.8734572784246782,-.483800052994852],[.4941095946388765,-.4447938112296831,.7470034631630423],[-.8676668813529025, --.1980677870294097,.4559861124470794]])};var ld=[["And","Andromeda"],["Ant","Antila"],["Aps","Apus"],["Aql","Aquila"],["Aqr","Aquarius"],["Ara","Ara"],["Ari","Aries"],["Aur","Auriga"],["Boo","Bootes"],["Cae","Caelum"],["Cam","Camelopardis"],["Cap","Capricornus"],["Car","Carina"],["Cas","Cassiopeia"],["Cen","Centaurus"],["Cep","Cepheus"],["Cet","Cetus"],["Cha","Chamaeleon"],["Cir","Circinus"],["CMa","Canis Major"],["CMi","Canis Minor"],["Cnc","Cancer"],["Col","Columba"],["Com","Coma Berenices"],["CrA", -"Corona Australis"],["CrB","Corona Borealis"],["Crt","Crater"],["Cru","Crux"],["Crv","Corvus"],["CVn","Canes Venatici"],["Cyg","Cygnus"],["Del","Delphinus"],["Dor","Dorado"],["Dra","Draco"],["Equ","Equuleus"],["Eri","Eridanus"],["For","Fornax"],["Gem","Gemini"],["Gru","Grus"],["Her","Hercules"],["Hor","Horologium"],["Hya","Hydra"],["Hyi","Hydrus"],["Ind","Indus"],["Lac","Lacerta"],["Leo","Leo"],["Lep","Lepus"],["Lib","Libra"],["LMi","Leo Minor"],["Lup","Lupus"],["Lyn","Lynx"],["Lyr","Lyra"],["Men", -"Mensa"],["Mic","Microscopium"],["Mon","Monoceros"],["Mus","Musca"],["Nor","Norma"],["Oct","Octans"],["Oph","Ophiuchus"],["Ori","Orion"],["Pav","Pavo"],["Peg","Pegasus"],["Per","Perseus"],["Phe","Phoenix"],["Pic","Pictor"],["PsA","Pisces Austrinus"],["Psc","Pisces"],["Pup","Puppis"],["Pyx","Pyxis"],["Ret","Reticulum"],["Scl","Sculptor"],["Sco","Scorpius"],["Sct","Scutum"],["Ser","Serpens"],["Sex","Sextans"],["Sge","Sagitta"],["Sgr","Sagittarius"],["Tau","Taurus"],["Tel","Telescopium"],["TrA","Triangulum Australe"], -["Tri","Triangulum"],["Tuc","Tucana"],["UMa","Ursa Major"],["UMi","Ursa Minor"],["Vel","Vela"],["Vir","Virgo"],["Vol","Volans"],["Vul","Vulpecula"]],md=[[83,0,8640,2112],[83,2880,5220,2076],[83,7560,8280,2068],[83,6480,7560,2064],[15,0,2880,2040],[10,3300,3840,1968],[15,0,1800,1920],[10,3840,5220,1920],[83,6300,6480,1920],[33,7260,7560,1920],[15,0,1263,1848],[10,4140,4890,1848],[83,5952,6300,1800],[15,7260,7440,1800],[10,2868,3300,1764],[33,3300,4080,1764],[83,4680,5952,1680],[13,1116,1230,1632], -[33,7350,7440,1608],[33,4080,4320,1596],[15,0,120,1584],[83,5040,5640,1584],[15,8490,8640,1584],[33,4320,4860,1536],[33,4860,5190,1512],[15,8340,8490,1512],[10,2196,2520,1488],[33,7200,7350,1476],[15,7393.2,7416,1462],[10,2520,2868,1440],[82,2868,3030,1440],[33,7116,7200,1428],[15,7200,7393.2,1428],[15,8232,8340,1418],[13,0,876,1404],[33,6990,7116,1392],[13,612,687,1380],[13,876,1116,1368],[10,1116,1140,1368],[15,8034,8232,1350],[10,1800,2196,1344],[82,5052,5190,1332],[33,5190,6990,1332],[10,1140, -1200,1320],[15,7968,8034,1320],[15,7416,7908,1316],[13,0,612,1296],[50,2196,2340,1296],[82,4350,4860,1272],[33,5490,5670,1272],[15,7908,7968,1266],[10,1200,1800,1260],[13,8232,8400,1260],[33,5670,6120,1236],[62,735,906,1212],[33,6120,6564,1212],[13,0,492,1200],[62,492,600,1200],[50,2340,2448,1200],[13,8400,8640,1200],[82,4860,5052,1164],[13,0,402,1152],[13,8490,8640,1152],[39,6543,6564,1140],[33,6564,6870,1140],[30,6870,6900,1140],[62,600,735,1128],[82,3030,3300,1128],[13,60,312,1104],[82,4320,4350, -1080],[50,2448,2652,1068],[30,7887,7908,1056],[30,7875,7887,1050],[30,6900,6984,1044],[82,3300,3660,1008],[82,3660,3882,960],[8,5556,5670,960],[39,5670,5880,960],[50,3330,3450,954],[0,0,906,882],[62,906,924,882],[51,6969,6984,876],[62,1620,1689,864],[30,7824,7875,864],[44,7875,7920,864],[7,2352,2652,852],[50,2652,2790,852],[0,0,720,840],[44,7920,8214,840],[44,8214,8232,828],[0,8232,8460,828],[62,924,978,816],[82,3882,3960,816],[29,4320,4440,816],[50,2790,3330,804],[48,3330,3558,804],[0,258,507,792], -[8,5466,5556,792],[0,8460,8550,770],[29,4440,4770,768],[0,8550,8640,752],[29,5025,5052,738],[80,870,978,736],[62,978,1620,736],[7,1620,1710,720],[51,6543,6969,720],[82,3960,4320,696],[30,7080,7530,696],[7,1710,2118,684],[48,3558,3780,684],[29,4770,5025,684],[0,0,24,672],[80,507,600,672],[7,2118,2352,672],[37,2838,2880,672],[30,7530,7824,672],[30,6933,7080,660],[80,690,870,654],[25,5820,5880,648],[8,5430,5466,624],[25,5466,5820,624],[51,6612,6792,624],[48,3870,3960,612],[51,6792,6933,612],[80,600, -690,600],[66,258,306,570],[48,3780,3870,564],[87,7650,7710,564],[77,2052,2118,548],[0,24,51,528],[73,5730,5772,528],[37,2118,2238,516],[87,7140,7290,510],[87,6792,6930,506],[0,51,306,504],[87,7290,7404,492],[37,2811,2838,480],[87,7404,7650,468],[87,6930,7140,460],[6,1182,1212,456],[75,6792,6840,444],[59,2052,2076,432],[37,2238,2271,420],[75,6840,7140,388],[77,1788,1920,384],[39,5730,5790,384],[75,7140,7290,378],[77,1662,1788,372],[77,1920,2016,372],[23,4620,4860,360],[39,6210,6570,344],[23,4272,4620, -336],[37,2700,2811,324],[39,6030,6210,308],[61,0,51,300],[77,2016,2076,300],[37,2520,2700,300],[61,7602,7680,300],[37,2271,2496,288],[39,6570,6792,288],[31,7515,7578,284],[61,7578,7602,284],[45,4146,4272,264],[59,2247,2271,240],[37,2496,2520,240],[21,2811,2853,240],[61,8580,8640,240],[6,600,1182,238],[31,7251,7308,204],[8,4860,5430,192],[61,8190,8580,180],[21,2853,3330,168],[45,3330,3870,168],[58,6570,6718.4,150],[3,6718.4,6792,150],[31,7500,7515,144],[20,2520,2526,132],[73,6570,6633,108],[39,5790, -6030,96],[58,6570,6633,72],[61,7728,7800,66],[66,0,720,48],[73,6690,6792,48],[31,7308,7500,48],[34,7500,7680,48],[61,7680,7728,48],[61,7920,8190,48],[61,7800,7920,42],[20,2526,2592,36],[77,1290,1662,0],[59,1662,1680,0],[20,2592,2910,0],[85,5280,5430,0],[58,6420,6570,0],[16,954,1182,-42],[77,1182,1290,-42],[73,5430,5856,-78],[59,1680,1830,-96],[59,2100,2247,-96],[73,6420,6468,-96],[73,6570,6690,-96],[3,6690,6792,-96],[66,8190,8580,-96],[45,3870,4146,-144],[85,4146,4260,-144],[66,0,120,-168],[66,8580, -8640,-168],[85,5130,5280,-192],[58,5730,5856,-192],[3,7200,7392,-216],[4,7680,7872,-216],[58,6180,6468,-240],[54,2100,2910,-264],[35,1770,1830,-264],[59,1830,2100,-264],[41,2910,3012,-264],[74,3450,3870,-264],[85,4260,4620,-264],[58,6330,6360,-280],[3,6792,7200,-288.8],[35,1740,1770,-348],[4,7392,7680,-360],[73,6180,6570,-384],[72,6570,6792,-384],[41,3012,3090,-408],[58,5856,5895,-438],[41,3090,3270,-456],[26,3870,3900,-456],[71,5856,5895,-462],[47,5640,5730,-480],[28,4530,4620,-528],[85,4620,5130, --528],[41,3270,3510,-576],[16,600,954,-585.2],[35,954,1350,-585.2],[26,3900,4260,-588],[28,4260,4530,-588],[47,5130,5370,-588],[58,5856,6030,-590],[16,0,600,-612],[11,7680,7872,-612],[4,7872,8580,-612],[16,8580,8640,-612],[41,3510,3690,-636],[35,1692,1740,-654],[46,1740,2202,-654],[11,7200,7680,-672],[41,3690,3810,-700],[41,4530,5370,-708],[47,5370,5640,-708],[71,5640,5760,-708],[35,1650,1692,-720],[58,6030,6336,-720],[76,6336,6420,-720],[41,3810,3900,-748],[19,2202,2652,-792],[41,4410,4530,-792], -[41,3900,4410,-840],[36,1260,1350,-864],[68,3012,3372,-882],[35,1536,1650,-888],[76,6420,6900,-888],[65,7680,8280,-888],[70,8280,8400,-888],[36,1080,1260,-950],[1,3372,3960,-954],[70,0,600,-960],[36,600,1080,-960],[35,1392,1536,-960],[70,8400,8640,-960],[14,5100,5370,-1008],[49,5640,5760,-1008],[71,5760,5911.5,-1008],[9,1740,1800,-1032],[22,1800,2370,-1032],[67,2880,3012,-1032],[35,1230,1392,-1056],[71,5911.5,6420,-1092],[24,6420,6900,-1092],[76,6900,7320,-1092],[53,7320,7680,-1092],[35,1080,1230, --1104],[9,1620,1740,-1116],[49,5520,5640,-1152],[63,0,840,-1156],[35,960,1080,-1176],[40,1470,1536,-1176],[9,1536,1620,-1176],[38,7680,7920,-1200],[67,2160,2880,-1218],[84,2880,2940,-1218],[35,870,960,-1224],[40,1380,1470,-1224],[63,0,660,-1236],[12,2160,2220,-1260],[84,2940,3042,-1272],[40,1260,1380,-1276],[32,1380,1440,-1276],[63,0,570,-1284],[35,780,870,-1296],[64,1620,1800,-1296],[49,5418,5520,-1296],[84,3042,3180,-1308],[12,2220,2340,-1320],[14,4260,4620,-1320],[49,5100,5418,-1320],[56,5418, -5520,-1320],[32,1440,1560,-1356],[84,3180,3960,-1356],[14,3960,4050,-1356],[5,6300,6480,-1368],[78,6480,7320,-1368],[38,7920,8400,-1368],[40,1152,1260,-1380],[64,1800,1980,-1380],[12,2340,2460,-1392],[63,0,480,-1404],[35,480,780,-1404],[63,8400,8640,-1404],[32,1560,1650,-1416],[56,5520,5911.5,-1440],[43,7320,7680,-1440],[64,1980,2160,-1464],[18,5460,5520,-1464],[5,5911.5,5970,-1464],[18,5370,5460,-1526],[5,5970,6030,-1526],[64,2160,2460,-1536],[12,2460,3252,-1536],[14,4050,4260,-1536],[27,4260,4620, --1536],[14,4620,5232,-1536],[18,4860,4920,-1560],[5,6030,6060,-1560],[40,780,1152,-1620],[69,1152,1650,-1620],[18,5310,5370,-1620],[5,6060,6300,-1620],[60,6300,6480,-1620],[81,7920,8400,-1620],[32,1650,2370,-1680],[18,4920,5310,-1680],[79,5310,6120,-1680],[81,0,480,-1800],[42,1260,1650,-1800],[86,2370,3252,-1800],[12,3252,4050,-1800],[55,4050,4920,-1800],[60,6480,7680,-1800],[43,7680,8400,-1800],[81,8400,8640,-1800],[81,270,480,-1824],[42,0,1260,-1980],[17,2760,4920,-1980],[2,4920,6480,-1980],[52, -1260,2760,-2040],[57,0,8640,-2160]],Lb,Tc,Uc=function(a,b,c,d){this.symbol=a;this.name=b;this.ra1875=c;this.dec1875=d};e.ConstellationInfo=Uc;e.Constellation=function(a,b){y(a);y(b);if(-90>b||90a&&(a+=24);Lb||(Lb=Eb(new P(-45655.74141261017)),Tc=new P(0));a=new Ia(b,15*a,1);a=Bb(a,Tc);a=Ra(Lb,a);a=Cb(a);b=10/240;for(var c=b/15,d=$jscomp.makeIterator(md),f=d.next();!f.done;f=d.next()){f=f.value;var h=f[1]*c,l=f[2]*c;if(f[3]*b<=a.dec&&h<= -a.ra&&a.ra +a){c=0;var h=0=c;)c+=360;for(;180Math.abs(n))break;h-=n/(-42.69778487239616*((k-g)/l-g*k*-.006694397995865464/(-42.69778487239616*m))+d*f+a*b)}h*=e.RAD2DEG;l=6378.1366/l;d=Math.abs(f)>Math.abs(b)?d/f-.9933056020041345*l:a/b-l}return new pb(h, +c,1E3*d)};e.ObserverGravity=function(a,b){a=Math.sin(a*e.DEG2RAD);a*=a;return 9.7803253359*(1+.00193185265241*a)/Math.sqrt(1-.00669437999013*a)*(1-(3.15704E-7-2.10269E-9*a)*b+7.37452E-14*b*b)};e.Ecliptic=Ha;e.GeoMoon=V;e.EclipticGeoMoon=cb;e.GeoMoonState=Ja;e.GeoEmbState=rb;var ia=[[-73E4,[-26.118207232108,-14.376168177825,3.384402515299],[.0016339372163656,-.0027861699588508,-.0013585880229445]],[-700800,[41.974905202127,-.448502952929,-12.770351505989],[7.3458569351457E-4,.0022785014891658,4.8619778602049E-4]], +[-671600,[14.706930780744,44.269110540027,9.353698474772],[-.00210001479998,2.2295915939915E-4,7.0143443551414E-4]],[-642400,[-29.441003929957,-6.43016153057,6.858481011305],[8.4495803960544E-4,-.0030783914758711,-.0012106305981192]],[-613200,[39.444396946234,-6.557989760571,-13.913760296463],[.0011480029005873,.0022400006880665,3.5168075922288E-4]],[-584E3,[20.2303809507,43.266966657189,7.382966091923],[-.0019754081700585,5.3457141292226E-4,7.5929169129793E-4]],[-554800,[-30.65832536462,2.093818874552, +9.880531138071],[6.1010603013347E-5,-.0031326500935382,-9.9346125151067E-4]],[-525600,[35.737703251673,-12.587706024764,-14.677847247563],[.0015802939375649,.0021347678412429,1.9074436384343E-4]],[-496400,[25.466295188546,41.367478338417,5.216476873382],[-.0018054401046468,8.328308359951E-4,8.0260156912107E-4]],[-467200,[-29.847174904071,10.636426313081,12.297904180106],[-6.3257063052907E-4,-.0029969577578221,-7.4476074151596E-4]],[-438E3,[30.774692107687,-18.236637015304,-14.945535879896],[.0020113162005465, +.0019353827024189,-2.0937793168297E-6]],[-408800,[30.243153324028,38.656267888503,2.938501750218],[-.0016052508674468,.0011183495337525,8.3333973416824E-4]],[-379600,[-27.288984772533,18.643162147874,14.023633623329],[-.0011856388898191,-.0027170609282181,-4.9015526126399E-4]],[-350400,[24.519605196774,-23.245756064727,-14.626862367368],[.0024322321483154,.0016062008146048,-2.3369181613312E-4]],[-321200,[34.505274805875,35.125338586954,.557361475637],[-.0013824391637782,.0013833397561817,8.4823598806262E-4]], +[-292E3,[-23.275363915119,25.818514298769,15.055381588598],[-.0016062295460975,-.0023395961498533,-2.4377362639479E-4]],[-262800,[17.050384798092,-27.180376290126,-13.608963321694],[.0028175521080578,.0011358749093955,-4.9548725258825E-4]],[-233600,[38.093671910285,30.880588383337,-1.843688067413],[-.0011317697153459,.0016128814698472,8.4177586176055E-4]],[-204400,[-18.197852930878,31.932869934309,15.438294826279],[-.0019117272501813,-.0019146495909842,-1.9657304369835E-5]],[-175200,[8.528924039997, +-29.618422200048,-11.805400994258],[.0031034370787005,5.139363329243E-4,-7.7293066202546E-4]],[-146E3,[40.94685725864,25.904973592021,-4.256336240499],[-8.3652705194051E-4,.0018129497136404,8.156422827306E-4]],[-116800,[-12.326958895325,36.881883446292,15.217158258711],[-.0021166103705038,-.001481442003599,1.7401209844705E-4]],[-87600,[-.633258375909,-30.018759794709,-9.17193287495],[.0032016994581737,-2.5279858672148E-4,-.0010411088271861]],[-58400,[42.936048423883,20.344685584452,-6.588027007912], +[-5.0525450073192E-4,.0019910074335507,7.7440196540269E-4]],[-29200,[-5.975910552974,40.61180995846,14.470131723673],[-.0022184202156107,-.0010562361130164,3.3652250216211E-4]],[0,[-9.875369580774,-27.978926224737,-5.753711824704],[.0030287533248818,-.0011276087003636,-.0012651326732361]],[29200,[43.958831986165,14.214147973292,-8.808306227163],[-1.4717608981871E-4,.0021404187242141,7.1486567806614E-4]],[58400,[.67813676352,43.094461639362,13.243238780721],[-.0022358226110718,-6.3233636090933E-4, +4.7664798895648E-4]],[87600,[-18.282602096834,-23.30503958666,-1.766620508028],[.0025567245263557,-.0019902940754171,-.0013943491701082]],[116800,[43.873338744526,7.700705617215,-10.814273666425],[2.3174803055677E-4,.0022402163127924,6.2988756452032E-4]],[146E3,[7.392949027906,44.382678951534,11.629500214854],[-.002193281545383,-2.1751799585364E-4,5.9556516201114E-4]],[175200,[-24.981690229261,-16.204012851426,2.466457544298],[.001819398914958,-.0026765419531201,-.0013848283502247]],[204400,[42.530187039511, +.845935508021,-12.554907527683],[6.5059779150669E-4,.0022725657282262,5.1133743202822E-4]],[233600,[13.999526486822,44.462363044894,9.669418486465],[-.0021079296569252,1.7533423831993E-4,6.9128485798076E-4]],[262800,[-29.184024803031,-7.371243995762,6.493275957928],[9.3581363109681E-4,-.0030610357109184,-.0012364201089345]],[292E3,[39.831980671753,-6.078405766765,-13.909815358656],[.0011117769689167,.0022362097830152,3.6230548231153E-4]],[321200,[20.294955108476,43.417190420251,7.450091985932],[-.0019742157451535, +5.3102050468554E-4,7.5938408813008E-4]],[350400,[-30.66999230216,2.318743558955,9.973480913858],[4.5605107450676E-5,-.0031308219926928,-9.9066533301924E-4]],[379600,[35.626122155983,-12.897647509224,-14.777586508444],[.0016015684949743,.0021171931182284,1.8002516202204E-4]],[408800,[26.133186148561,41.232139187599,5.00640132622],[-.0017857704419579,8.6046232702817E-4,8.0614690298954E-4]],[438E3,[-29.57674022923,11.863535943587,12.631323039872],[-7.2292830060955E-4,-.0029587820140709,-7.08242964503E-4]], +[467200,[29.910805787391,-19.159019294,-15.013363865194],[.0020871080437997,.0018848372554514,-3.8528655083926E-5]],[496400,[31.375957451819,38.050372720763,2.433138343754],[-.0015546055556611,.0011699815465629,8.3565439266001E-4]],[525600,[-26.360071336928,20.662505904952,14.414696258958],[-.0013142373118349,-.0026236647854842,-4.2542017598193E-4]],[554800,[22.599441488648,-24.508879898306,-14.484045731468],[.0025454108304806,.0014917058755191,-3.0243665086079E-4]],[584E3,[35.877864013014,33.894226366071, +-.224524636277],[-.0012941245730845,.0014560427668319,8.4762160640137E-4]],[613200,[-21.538149762417,28.204068269761,15.321973799534],[-.001731211740901,-.0021939631314577,-1.631691327518E-4]],[642400,[13.971521374415,-28.339941764789,-13.083792871886],[.0029334630526035,9.1860931752944E-4,-5.9939422488627E-4]],[671600,[39.526942044143,28.93989736011,-2.872799527539],[-.0010068481658095,.001702113288809,8.3578230511981E-4]],[700800,[-15.576200701394,34.399412961275,15.466033737854],[-.0020098814612884, +-.0017191109825989,7.0414782780416E-5]],[73E4,[4.24325283709,-30.118201690825,-10.707441231349],[.0031725847067411,1.609846120227E-4,-9.0672150593868E-4]]],G=function(a,b,c){this.x=a;this.y=b;this.z=c};G.prototype.ToAstroVector=function(a){return new D(this.x,this.y,this.z,a)};G.prototype.quadrature=function(){return this.x*this.x+this.y*this.y+this.z*this.z};G.prototype.add=function(a){return new G(this.x+a.x,this.y+a.y,this.z+a.z)};G.prototype.sub=function(a){return new G(this.x-a.x,this.y-a.y, +this.z-a.z)};G.prototype.incr=function(a){this.x+=a.x;this.y+=a.y;this.z+=a.z};G.prototype.decr=function(a){this.x-=a.x;this.y-=a.y;this.z-=a.z};G.prototype.mul=function(a){return new G(a*this.x,a*this.y,a*this.z)};G.prototype.div=function(a){return new G(this.x/a,this.y/a,this.z/a)};G.prototype.mean=function(a){return new G((this.x+a.x)/2,(this.y+a.y)/2,(this.z+a.z)/2)};var db=function(a,b,c){this.tt=a;this.r=b;this.v=c},qa=function(a){var b=new db(a,new G(0,0,0),new G(0,0,0));this.Jupiter=fb(b, +a,q.Jupiter,2.825345909524226E-7);this.Saturn=fb(b,a,q.Saturn,8.459715185680659E-8);this.Uranus=fb(b,a,q.Uranus,1.292024916781969E-8);this.Neptune=fb(b,a,q.Neptune,1.524358900784276E-8);this.Jupiter.r.decr(b.r);this.Jupiter.v.decr(b.v);this.Saturn.r.decr(b.r);this.Saturn.v.decr(b.v);this.Uranus.r.decr(b.r);this.Uranus.v.decr(b.v);this.Neptune.r.decr(b.r);this.Neptune.v.decr(b.v);this.Sun=new db(a,b.r.mul(-1),b.v.mul(-1))};qa.prototype.Acceleration=function(a){var b=La(a,2.959122082855911E-4,this.Sun.r); +b.incr(La(a,2.825345909524226E-7,this.Jupiter.r));b.incr(La(a,8.459715185680659E-8,this.Saturn.r));b.incr(La(a,1.292024916781969E-8,this.Uranus.r));b.incr(La(a,1.524358900784276E-8,this.Neptune.r));return b};var cc=function(a,b,c,d){this.tt=a;this.r=b;this.v=c;this.a=d},dc=function(a,b){this.bary=a;this.grav=b},xb=[],jd=new L([[.999432765338654,-.0336771074697641,0],[.0303959428906285,.902057912352809,.430543388542295],[-.0144994559663353,-.430299169409101,.902569881273754]]),kd=[{mu:2.82489428433814E-7, +al:[1.446213296021224,3.5515522861824],a:[[.0028210960212903,0,0]],l:[[-1.925258348666E-4,4.9369589722645,.01358483658305],[-9.70803596076E-5,4.3188796477322,.01303413843243],[-8.988174165E-5,1.9080016428617,.00305064867158],[-5.53101050262E-5,1.4936156681569,.01293892891155]],z:[[.0041510849668155,4.089939635545,-.01290686414666],[6.260521444113E-4,1.446188898627,3.5515522949802],[3.52747346169E-5,2.1256287034578,1.2727416567E-4]],zeta:[[3.142172466014E-4,2.7964219722923,-.002315096098],[9.04169207946E-5, +1.0477061879627,-5.6920638196E-4]]},{mu:2.82483274392893E-7,al:[-.3735263437471362,1.76932271112347],a:[[.0044871037804314,0,0],[4.324367498E-7,1.819645606291,1.7822295777568]],l:[[8.576433172936E-4,4.3188693178264,.01303413830805],[4.549582875086E-4,1.4936531751079,.01293892881962],[3.248939825174E-4,1.8196494533458,1.7822295777568],[-3.074250079334E-4,4.9377037005911,.01358483286724],[1.982386144784E-4,1.907986905476,.00305101212869],[1.834063551804E-4,2.1402853388529,.00145009789338],[-1.434383188452E-4, +5.622214036663,.89111478887838],[-7.71939140944E-5,4.300272437235,2.6733443704266]],z:[[-.0093589104136341,4.0899396509039,-.01290686414666],[2.988994545555E-4,5.9097265185595,1.7693227079462],[2.13903639035E-4,2.1256289300016,1.2727418407E-4],[1.980963564781E-4,2.743516829265,6.7797343009E-4],[1.210388158965E-4,5.5839943711203,3.20566149E-5],[8.37042048393E-5,1.6094538368039,-.90402165808846],[8.23525166369E-5,1.4461887708689,3.5515522949802]],zeta:[[.0040404917832303,1.0477063169425,-5.692064054E-4], +[2.200421034564E-4,3.3368857864364,-1.2491307307E-4],[1.662544744719E-4,2.4134862374711,0],[5.90282470983E-5,5.9719930968366,-3.056160225E-5]]},{mu:2.82498184184723E-7,al:[.2874089391143348,.878207923589328],a:[[.0071566594572575,0,0],[1.393029911E-6,1.1586745884981,2.6733443704266]],l:[[2.310797886226E-4,2.1402987195942,.00145009784384],[-1.828635964118E-4,4.3188672736968,.01303413828263],[1.512378778204E-4,4.9373102372298,.01358483481252],[-1.163720969778E-4,4.300265986149,2.6733443704266],[-9.55478069846E-5, +1.4936612842567,.01293892879857],[8.15246854464E-5,5.6222137132535,.89111478887838],[-8.01219679602E-5,1.2995922951532,1.0034433456729],[-6.07017260182E-5,.64978769669238,.50172167043264]],z:[[.0014289811307319,2.1256295942739,1.2727413029E-4],[7.71093122676E-4,5.5836330003496,3.20643411E-5],[5.925911780766E-4,4.0899396636448,-.01290686414666],[2.045597496146E-4,5.2713683670372,-.12523544076106],[1.785118648258E-4,.28743156721063,.8782079244252],[1.131999784893E-4,1.4462127277818,3.5515522949802], +[-6.5877816921E-5,2.2702423990985,-1.7951364394537],[4.97058888328E-5,5.9096792204858,1.7693227129285]],zeta:[[.0015932721570848,3.3368862796665,-1.2491307058E-4],[8.533093128905E-4,2.4133881688166,0],[3.513347911037E-4,5.9720789850127,-3.056101771E-5],[-1.441929255483E-4,1.0477061764435,-5.6920632124E-4]]},{mu:2.82492144889909E-7,al:[-.3620341291375704,.376486233433828],a:[[.0125879701715314,0,0],[3.595204947E-6,.64965776007116,.50172168165034],[2.7580210652E-6,1.808423578151,3.1750660413359]],l:[[5.586040123824E-4, +2.1404207189815,.00145009793231],[-3.805813868176E-4,2.7358844897853,2.972965062E-5],[2.205152863262E-4,.649796525964,.5017216724358],[1.877895151158E-4,1.8084787604005,3.1750660413359],[7.66916975242E-5,6.2720114319755,1.3928364636651],[7.47056855106E-5,1.2995916202344,1.0034433456729]],z:[[.0073755808467977,5.5836071576084,3.206509914E-5],[2.065924169942E-4,5.9209831565786,.37648624194703],[1.589869764021E-4,.28744006242623,.8782079244252],[-1.561131605348E-4,2.1257397865089,1.2727441285E-4],[1.486043380971E-4, +1.4462134301023,3.5515522949802],[6.35073108731E-5,5.9096803285954,1.7693227129285],[5.99351698525E-5,4.1125517584798,-2.7985797954589],[5.40660842731E-5,5.5390350845569,.00286834082283],[-4.89596900866E-5,4.6218149483338,-.62695712529519]],zeta:[[.0038422977898495,2.4133922085557,0],[.0022453891791894,5.9721736773277,-3.056125525E-5],[-2.604479450559E-4,3.3368746306409,-1.2491309972E-4],[3.3211214323E-5,5.5604137742337,.00290037688507]]}],Rc=function(a){this.moon=a};e.JupiterMoonsInfo=Rc;e.JupiterMoons= +function(a){a=new P(a);for(var b=[],c=$jscomp.makeIterator(kd),d=c.next();!d.done;d=c.next()){var f=b,h=f.push;d=d.value;for(var l=a.tt+18262.5,k=[0,d.al[0]+l*d.al[1],0,0,0,0],g=$jscomp.makeIterator(d.a),m=g.next();!m.done;m=g.next()){var n=$jscomp.makeIterator(m.value);m=n.next().value;var p=n.next().value;n=n.next().value;k[0]+=m*Math.cos(p+l*n)}g=$jscomp.makeIterator(d.l);for(m=g.next();!m.done;m=g.next())n=$jscomp.makeIterator(m.value),m=n.next().value,p=n.next().value,n=n.next().value,k[1]+= +m*Math.sin(p+l*n);k[1]%=R;0>k[1]&&(k[1]+=R);g=$jscomp.makeIterator(d.z);for(m=g.next();!m.done;m=g.next())n=$jscomp.makeIterator(m.value),m=n.next().value,p=n.next().value,n=n.next().value,p+=l*n,k[2]+=m*Math.cos(p),k[3]+=m*Math.sin(p);g=$jscomp.makeIterator(d.zeta);for(m=g.next();!m.done;m=g.next())n=$jscomp.makeIterator(m.value),m=n.next().value,p=n.next().value,n=n.next().value,p+=l*n,k[4]+=m*Math.cos(p),k[5]+=m*Math.sin(p);g=k[0];n=k[1];m=k[2];p=k[3];l=k[4];k=k[5];var t=Math.sqrt(d.mu/(g*g*g)); +d=n+m*Math.sin(n)-p*Math.cos(n);do{var x=Math.cos(d);var v=Math.sin(d);x=(n-d+m*v-p*x)/(1-m*x-p*v);d+=x}while(1E-12<=Math.abs(x));x=Math.cos(d);v=Math.sin(d);n=p*x-m*v;var z=-m*x-p*v,ea=1/(1+z),S=1/(1+Math.sqrt(1-m*m-p*p));d=g*(x-m-S*p*n);n=g*(v-p+S*m*n);p=t*ea*g*(-v-S*p*z);g=t*ea*g*(+x+S*m*z);m=2*Math.sqrt(1-l*l-k*k);t=1-2*k*k;x=1-2*l*l;v=2*k*l;d=new K(d*t+n*v,d*v+n*x,(l*n-d*k)*m,p*t+g*v,p*v+g*x,(l*g-p*k)*m,a);d=ya(jd,d);h.call(f,d)}return new Rc(b)};e.HelioVector=Ma;e.HelioDistance=ja;e.GeoVector= +ca;e.BaryState=function(a,b){b=w(b);if(a===q.SSB)return new K(0,0,0,0,0,0,b);if(a===q.Pluto)return wb(b,!1);var c=new qa(b.tt);switch(a){case q.Sun:return ra(c.Sun,b);case q.Jupiter:return ra(c.Jupiter,b);case q.Saturn:return ra(c.Saturn,b);case q.Uranus:return ra(c.Uranus,b);case q.Neptune:return ra(c.Neptune,b);case q.Moon:case q.EMB:var d=Ka(H[q.Earth],b.tt);a=a===q.Moon?Ja(b):rb(b);return new K(a.x+c.Sun.r.x+d.r.x,a.y+c.Sun.r.y+d.r.y,a.z+c.Sun.r.z+d.r.z,a.vx+c.Sun.v.x+d.v.x,a.vy+c.Sun.v.y+d.v.y, +a.vz+c.Sun.v.z+d.v.z,b)}if(a in H)return a=Ka(H[a],b.tt),new K(c.Sun.r.x+a.r.x,c.Sun.r.y+a.r.y,c.Sun.r.z+a.r.z,c.Sun.v.x+a.v.x,c.Sun.v.y+a.v.y,c.Sun.v.z+a.v.z,b);throw'BaryState: Unsupported body "'+a+'"';};e.HelioState=yb;e.Search=I;e.SearchSunLongitude=gc;e.PairLongitude=zb;e.AngleFromSun=ua;e.EclipticLongitude=ka;var hc=function(a,b,c,d,f,h,l,k){this.time=a;this.mag=b;this.phase_angle=c;this.helio_dist=d;this.geo_dist=f;this.gc=h;this.hc=l;this.ring_tilt=k;this.phase_fraction=(1+Math.cos(e.DEG2RAD* +c))/2};e.IlluminationInfo=hc;e.Illumination=hb;e.SearchRelativeLongitude=va;e.MoonPhase=Ab;e.SearchMoonPhase=Oa;var jc=function(a,b){this.quarter=a;this.time=b};e.MoonQuarter=jc;e.SearchMoonQuarter=ic;e.NextMoonQuarter=function(a){a=new Date(a.time.date.getTime()+5184E5);return ic(a)};e.SearchRiseSet=function(a,b,c,d,f){a:switch(a){case q.Sun:var h=gd;break a;case q.Moon:h=hd;break a;default:h=0}return kc(a,b,c,d,f,function(l){var k=Ga(a,l,b,!0,!0);l=Ea(l,b,k.ra,k.dec).altitude+h/k.dist*e.RAD2DEG+ +id;return c*l})};e.SearchAltitude=function(a,b,c,d,f,h){if(!Number.isFinite(h)||-90>h||90=++f;){var h=ka(a,b),l=ka(q.Earth,b),k=sa(h-l),g=h=l=void 0;k>=-d.s1&&k<+d.s1?(g=0,l=+d.s1,h=+d.s2):k>=+d.s2||k<-d.s2?(g=0,l=-d.s2,h=-d.s1):0<=k?(g=-Na(a)/4,l=+d.s1,h=+d.s2):(g=-Na(a)/4,l=-d.s2,h=-d.s1);k=b.AddDays(g);l=va(a,l,k);h=va(a, +h,l);k=c(l);if(0<=k)throw"SearchMaxElongation: internal error: m1 = "+k;g=c(h);if(0>=g)throw"SearchMaxElongation: internal error: m2 = "+g;k=I(c,l,h,{init_f1:k,init_f2:g,dt_tolerance_seconds:10});if(!k)throw"SearchMaxElongation: failed search iter "+f+" (t1="+l.toString()+", t2="+h.toString()+")";if(k.tt>=b.tt)return mc(a,k);b=h.AddDays(1)}throw"SearchMaxElongation: failed to find event after 2 tries.";};e.SearchPeakMagnitude=function(a,b){function c(g){var m=g.AddDays(-.005);g=g.AddDays(.005);m= +hb(a,m).mag;return(hb(a,g).mag-m)/.01}if(a!==q.Venus)throw"SearchPeakMagnitude currently works for Venus only.";b=w(b);for(var d=0;2>=++d;){var f=ka(a,b),h=ka(q.Earth,b),l=sa(f-h),k=f=h=void 0;-10<=l&&10>l?(k=0,h=10,f=30):30<=l||-30>l?(k=0,h=-30,f=-10):0<=l?(k=-Na(a)/4,h=10,f=30):(k=-Na(a)/4,h=-30,f=-10);l=b.AddDays(k);h=va(a,h,l);f=va(a,f,h);l=c(h);if(0<=l)throw"SearchPeakMagnitude: internal error: m1 = "+l;k=c(f);if(0>=k)throw"SearchPeakMagnitude: internal error: m2 = "+k;l=I(c,h,f,{init_f1:l,init_f2:k, +dt_tolerance_seconds:10});if(!l)throw"SearchPeakMagnitude: failed search iter "+d+" (t1="+h.toString()+", t2="+f.toString()+")";if(l.tt>=b.tt)return hb(a,l);b=f.AddDays(1)}throw"SearchPeakMagnitude: failed to find event after 2 tries.";};var Qa=function(a,b,c){this.time=a;this.kind=b;this.dist_au=c;this.dist_km=c*e.KM_PER_AU};e.Apsis=Qa;e.SearchLunarApsis=oc;e.NextLunarApsis=function(a){var b=oc(a.time.AddDays(11));if(1!==b.kind+a.kind)throw"NextLunarApsis INTERNAL ERROR: did not find alternating apogee/perigee: prev="+ +a.kind+" @ "+a.time.toString()+", next="+b.kind+" @ "+b.time.toString();return b};e.SearchPlanetApsis=qc;e.NextPlanetApsis=function(a,b){if(0!==b.kind&&1!==b.kind)throw"Invalid apsis kind: "+b.kind;var c=b.time.AddDays(.25*da[a].OrbitalPeriod);a=qc(a,c);if(1!==a.kind+b.kind)throw"Internal error: previous apsis was "+b.kind+", but found "+a.kind+" for next apsis.";return a};e.InverseRotation=wa;e.CombineRotation=xa;e.IdentityMatrix=function(){return new L([[1,0,0],[0,1,0],[0,0,1]])};e.Pivot=function(a, +b,c){if(0!==b&&1!==b&&2!==b)throw"Invalid axis "+b+". Must be [0, 1, 2].";var d=y(c)*e.DEG2RAD;c=Math.cos(d);d=Math.sin(d);var f=(b+1)%3,h=(b+2)%3,l=[[0,0,0],[0,0,0],[0,0,0]];l[f][f]=c*a.rot[f][f]-d*a.rot[f][h];l[f][h]=d*a.rot[f][f]+c*a.rot[f][h];l[f][b]=a.rot[f][b];l[h][f]=c*a.rot[h][f]-d*a.rot[h][h];l[h][h]=d*a.rot[h][f]+c*a.rot[h][h];l[h][b]=a.rot[h][b];l[b][f]=c*a.rot[b][f]-d*a.rot[b][h];l[b][h]=d*a.rot[b][f]+c*a.rot[b][h];l[b][b]=a.rot[b][b];return new L(l)};e.VectorFromSphere=Bb;e.EquatorFromVector= +Cb;e.SphereFromVector=Db;e.HorizonFromVector=function(a,b){a=Db(a);a.lon=rc(a.lon);a.lat+=Fa(b,a.lat);return a};e.VectorFromHorizon=function(a,b,c){b=w(b);var d=rc(a.lon);c=a.lat+sc(c,a.lat);a=new Ia(c,d,a.dist);return Bb(a,b)};e.Refraction=Fa;e.InverseRefraction=sc;e.RotateVector=Ra;e.RotateState=ya;e.Rotation_EQJ_ECL=tc;e.Rotation_ECL_EQJ=function(){return new L([[1,0,0],[0,.9174821430670688,.3977769691083922],[0,-.3977769691083922,.9174821430670688]])};e.Rotation_EQJ_EQD=Eb;e.Rotation_EQD_EQJ= +Fb;e.Rotation_EQD_HOR=Gb;e.Rotation_HOR_EQD=uc;e.Rotation_HOR_EQJ=vc;e.Rotation_EQJ_HOR=function(a,b){a=vc(a,b);return wa(a)};e.Rotation_EQD_ECL=wc;e.Rotation_ECL_EQD=xc;e.Rotation_ECL_HOR=yc;e.Rotation_HOR_ECL=function(a,b){a=yc(a,b);return wa(a)};e.Rotation_EQJ_GAL=function(){return new L([[-.0548624779711344,.4941095946388765,-.8676668813529025],[-.8734572784246782,-.4447938112296831,-.1980677870294097],[-.483800052994852,.7470034631630423,.4559861124470794]])};e.Rotation_GAL_EQJ=function(){return new L([[-.0548624779711344, +-.8734572784246782,-.483800052994852],[.4941095946388765,-.4447938112296831,.7470034631630423],[-.8676668813529025,-.1980677870294097,.4559861124470794]])};var ld=[["And","Andromeda"],["Ant","Antila"],["Aps","Apus"],["Aql","Aquila"],["Aqr","Aquarius"],["Ara","Ara"],["Ari","Aries"],["Aur","Auriga"],["Boo","Bootes"],["Cae","Caelum"],["Cam","Camelopardis"],["Cap","Capricornus"],["Car","Carina"],["Cas","Cassiopeia"],["Cen","Centaurus"],["Cep","Cepheus"],["Cet","Cetus"],["Cha","Chamaeleon"],["Cir","Circinus"], +["CMa","Canis Major"],["CMi","Canis Minor"],["Cnc","Cancer"],["Col","Columba"],["Com","Coma Berenices"],["CrA","Corona Australis"],["CrB","Corona Borealis"],["Crt","Crater"],["Cru","Crux"],["Crv","Corvus"],["CVn","Canes Venatici"],["Cyg","Cygnus"],["Del","Delphinus"],["Dor","Dorado"],["Dra","Draco"],["Equ","Equuleus"],["Eri","Eridanus"],["For","Fornax"],["Gem","Gemini"],["Gru","Grus"],["Her","Hercules"],["Hor","Horologium"],["Hya","Hydra"],["Hyi","Hydrus"],["Ind","Indus"],["Lac","Lacerta"],["Leo", +"Leo"],["Lep","Lepus"],["Lib","Libra"],["LMi","Leo Minor"],["Lup","Lupus"],["Lyn","Lynx"],["Lyr","Lyra"],["Men","Mensa"],["Mic","Microscopium"],["Mon","Monoceros"],["Mus","Musca"],["Nor","Norma"],["Oct","Octans"],["Oph","Ophiuchus"],["Ori","Orion"],["Pav","Pavo"],["Peg","Pegasus"],["Per","Perseus"],["Phe","Phoenix"],["Pic","Pictor"],["PsA","Pisces Austrinus"],["Psc","Pisces"],["Pup","Puppis"],["Pyx","Pyxis"],["Ret","Reticulum"],["Scl","Sculptor"],["Sco","Scorpius"],["Sct","Scutum"],["Ser","Serpens"], +["Sex","Sextans"],["Sge","Sagitta"],["Sgr","Sagittarius"],["Tau","Taurus"],["Tel","Telescopium"],["TrA","Triangulum Australe"],["Tri","Triangulum"],["Tuc","Tucana"],["UMa","Ursa Major"],["UMi","Ursa Minor"],["Vel","Vela"],["Vir","Virgo"],["Vol","Volans"],["Vul","Vulpecula"]],md=[[83,0,8640,2112],[83,2880,5220,2076],[83,7560,8280,2068],[83,6480,7560,2064],[15,0,2880,2040],[10,3300,3840,1968],[15,0,1800,1920],[10,3840,5220,1920],[83,6300,6480,1920],[33,7260,7560,1920],[15,0,1263,1848],[10,4140,4890, +1848],[83,5952,6300,1800],[15,7260,7440,1800],[10,2868,3300,1764],[33,3300,4080,1764],[83,4680,5952,1680],[13,1116,1230,1632],[33,7350,7440,1608],[33,4080,4320,1596],[15,0,120,1584],[83,5040,5640,1584],[15,8490,8640,1584],[33,4320,4860,1536],[33,4860,5190,1512],[15,8340,8490,1512],[10,2196,2520,1488],[33,7200,7350,1476],[15,7393.2,7416,1462],[10,2520,2868,1440],[82,2868,3030,1440],[33,7116,7200,1428],[15,7200,7393.2,1428],[15,8232,8340,1418],[13,0,876,1404],[33,6990,7116,1392],[13,612,687,1380],[13, +876,1116,1368],[10,1116,1140,1368],[15,8034,8232,1350],[10,1800,2196,1344],[82,5052,5190,1332],[33,5190,6990,1332],[10,1140,1200,1320],[15,7968,8034,1320],[15,7416,7908,1316],[13,0,612,1296],[50,2196,2340,1296],[82,4350,4860,1272],[33,5490,5670,1272],[15,7908,7968,1266],[10,1200,1800,1260],[13,8232,8400,1260],[33,5670,6120,1236],[62,735,906,1212],[33,6120,6564,1212],[13,0,492,1200],[62,492,600,1200],[50,2340,2448,1200],[13,8400,8640,1200],[82,4860,5052,1164],[13,0,402,1152],[13,8490,8640,1152],[39, +6543,6564,1140],[33,6564,6870,1140],[30,6870,6900,1140],[62,600,735,1128],[82,3030,3300,1128],[13,60,312,1104],[82,4320,4350,1080],[50,2448,2652,1068],[30,7887,7908,1056],[30,7875,7887,1050],[30,6900,6984,1044],[82,3300,3660,1008],[82,3660,3882,960],[8,5556,5670,960],[39,5670,5880,960],[50,3330,3450,954],[0,0,906,882],[62,906,924,882],[51,6969,6984,876],[62,1620,1689,864],[30,7824,7875,864],[44,7875,7920,864],[7,2352,2652,852],[50,2652,2790,852],[0,0,720,840],[44,7920,8214,840],[44,8214,8232,828], +[0,8232,8460,828],[62,924,978,816],[82,3882,3960,816],[29,4320,4440,816],[50,2790,3330,804],[48,3330,3558,804],[0,258,507,792],[8,5466,5556,792],[0,8460,8550,770],[29,4440,4770,768],[0,8550,8640,752],[29,5025,5052,738],[80,870,978,736],[62,978,1620,736],[7,1620,1710,720],[51,6543,6969,720],[82,3960,4320,696],[30,7080,7530,696],[7,1710,2118,684],[48,3558,3780,684],[29,4770,5025,684],[0,0,24,672],[80,507,600,672],[7,2118,2352,672],[37,2838,2880,672],[30,7530,7824,672],[30,6933,7080,660],[80,690,870, +654],[25,5820,5880,648],[8,5430,5466,624],[25,5466,5820,624],[51,6612,6792,624],[48,3870,3960,612],[51,6792,6933,612],[80,600,690,600],[66,258,306,570],[48,3780,3870,564],[87,7650,7710,564],[77,2052,2118,548],[0,24,51,528],[73,5730,5772,528],[37,2118,2238,516],[87,7140,7290,510],[87,6792,6930,506],[0,51,306,504],[87,7290,7404,492],[37,2811,2838,480],[87,7404,7650,468],[87,6930,7140,460],[6,1182,1212,456],[75,6792,6840,444],[59,2052,2076,432],[37,2238,2271,420],[75,6840,7140,388],[77,1788,1920,384], +[39,5730,5790,384],[75,7140,7290,378],[77,1662,1788,372],[77,1920,2016,372],[23,4620,4860,360],[39,6210,6570,344],[23,4272,4620,336],[37,2700,2811,324],[39,6030,6210,308],[61,0,51,300],[77,2016,2076,300],[37,2520,2700,300],[61,7602,7680,300],[37,2271,2496,288],[39,6570,6792,288],[31,7515,7578,284],[61,7578,7602,284],[45,4146,4272,264],[59,2247,2271,240],[37,2496,2520,240],[21,2811,2853,240],[61,8580,8640,240],[6,600,1182,238],[31,7251,7308,204],[8,4860,5430,192],[61,8190,8580,180],[21,2853,3330,168], +[45,3330,3870,168],[58,6570,6718.4,150],[3,6718.4,6792,150],[31,7500,7515,144],[20,2520,2526,132],[73,6570,6633,108],[39,5790,6030,96],[58,6570,6633,72],[61,7728,7800,66],[66,0,720,48],[73,6690,6792,48],[31,7308,7500,48],[34,7500,7680,48],[61,7680,7728,48],[61,7920,8190,48],[61,7800,7920,42],[20,2526,2592,36],[77,1290,1662,0],[59,1662,1680,0],[20,2592,2910,0],[85,5280,5430,0],[58,6420,6570,0],[16,954,1182,-42],[77,1182,1290,-42],[73,5430,5856,-78],[59,1680,1830,-96],[59,2100,2247,-96],[73,6420,6468, +-96],[73,6570,6690,-96],[3,6690,6792,-96],[66,8190,8580,-96],[45,3870,4146,-144],[85,4146,4260,-144],[66,0,120,-168],[66,8580,8640,-168],[85,5130,5280,-192],[58,5730,5856,-192],[3,7200,7392,-216],[4,7680,7872,-216],[58,6180,6468,-240],[54,2100,2910,-264],[35,1770,1830,-264],[59,1830,2100,-264],[41,2910,3012,-264],[74,3450,3870,-264],[85,4260,4620,-264],[58,6330,6360,-280],[3,6792,7200,-288.8],[35,1740,1770,-348],[4,7392,7680,-360],[73,6180,6570,-384],[72,6570,6792,-384],[41,3012,3090,-408],[58,5856, +5895,-438],[41,3090,3270,-456],[26,3870,3900,-456],[71,5856,5895,-462],[47,5640,5730,-480],[28,4530,4620,-528],[85,4620,5130,-528],[41,3270,3510,-576],[16,600,954,-585.2],[35,954,1350,-585.2],[26,3900,4260,-588],[28,4260,4530,-588],[47,5130,5370,-588],[58,5856,6030,-590],[16,0,600,-612],[11,7680,7872,-612],[4,7872,8580,-612],[16,8580,8640,-612],[41,3510,3690,-636],[35,1692,1740,-654],[46,1740,2202,-654],[11,7200,7680,-672],[41,3690,3810,-700],[41,4530,5370,-708],[47,5370,5640,-708],[71,5640,5760, +-708],[35,1650,1692,-720],[58,6030,6336,-720],[76,6336,6420,-720],[41,3810,3900,-748],[19,2202,2652,-792],[41,4410,4530,-792],[41,3900,4410,-840],[36,1260,1350,-864],[68,3012,3372,-882],[35,1536,1650,-888],[76,6420,6900,-888],[65,7680,8280,-888],[70,8280,8400,-888],[36,1080,1260,-950],[1,3372,3960,-954],[70,0,600,-960],[36,600,1080,-960],[35,1392,1536,-960],[70,8400,8640,-960],[14,5100,5370,-1008],[49,5640,5760,-1008],[71,5760,5911.5,-1008],[9,1740,1800,-1032],[22,1800,2370,-1032],[67,2880,3012,-1032], +[35,1230,1392,-1056],[71,5911.5,6420,-1092],[24,6420,6900,-1092],[76,6900,7320,-1092],[53,7320,7680,-1092],[35,1080,1230,-1104],[9,1620,1740,-1116],[49,5520,5640,-1152],[63,0,840,-1156],[35,960,1080,-1176],[40,1470,1536,-1176],[9,1536,1620,-1176],[38,7680,7920,-1200],[67,2160,2880,-1218],[84,2880,2940,-1218],[35,870,960,-1224],[40,1380,1470,-1224],[63,0,660,-1236],[12,2160,2220,-1260],[84,2940,3042,-1272],[40,1260,1380,-1276],[32,1380,1440,-1276],[63,0,570,-1284],[35,780,870,-1296],[64,1620,1800, +-1296],[49,5418,5520,-1296],[84,3042,3180,-1308],[12,2220,2340,-1320],[14,4260,4620,-1320],[49,5100,5418,-1320],[56,5418,5520,-1320],[32,1440,1560,-1356],[84,3180,3960,-1356],[14,3960,4050,-1356],[5,6300,6480,-1368],[78,6480,7320,-1368],[38,7920,8400,-1368],[40,1152,1260,-1380],[64,1800,1980,-1380],[12,2340,2460,-1392],[63,0,480,-1404],[35,480,780,-1404],[63,8400,8640,-1404],[32,1560,1650,-1416],[56,5520,5911.5,-1440],[43,7320,7680,-1440],[64,1980,2160,-1464],[18,5460,5520,-1464],[5,5911.5,5970,-1464], +[18,5370,5460,-1526],[5,5970,6030,-1526],[64,2160,2460,-1536],[12,2460,3252,-1536],[14,4050,4260,-1536],[27,4260,4620,-1536],[14,4620,5232,-1536],[18,4860,4920,-1560],[5,6030,6060,-1560],[40,780,1152,-1620],[69,1152,1650,-1620],[18,5310,5370,-1620],[5,6060,6300,-1620],[60,6300,6480,-1620],[81,7920,8400,-1620],[32,1650,2370,-1680],[18,4920,5310,-1680],[79,5310,6120,-1680],[81,0,480,-1800],[42,1260,1650,-1800],[86,2370,3252,-1800],[12,3252,4050,-1800],[55,4050,4920,-1800],[60,6480,7680,-1800],[43,7680, +8400,-1800],[81,8400,8640,-1800],[81,270,480,-1824],[42,0,1260,-1980],[17,2760,4920,-1980],[2,4920,6480,-1980],[52,1260,2760,-2040],[57,0,8640,-2160]],Lb,Tc,Uc=function(a,b,c,d){this.symbol=a;this.name=b;this.ra1875=c;this.dec1875=d};e.ConstellationInfo=Uc;e.Constellation=function(a,b){y(a);y(b);if(-90>b||90a&&(a+=24);Lb||(Lb=Eb(new P(-45655.74141261017)),Tc=new P(0));a=new Ia(b,15*a,1);a=Bb(a,Tc);a=Ra(Lb,a);a=Cb(a);b=10/240;for(var c= +b/15,d=$jscomp.makeIterator(md),f=d.next();!f.done;f=d.next()){f=f.value;var h=f[1]*c,l=f[2]*c;if(f[3]*b<=a.dec&&h<=a.ra&&a.raa&&(a+=360);return a}var sidereal_time_cache; function sidereal_time(a){if(!sidereal_time_cache||sidereal_time_cache.tt!==a.tt){var b=a.tt/36525,c=15*e_tilt(a).ee,d=era(a);b=((c+.014506+((((-3.68E-8*b-2.9956E-5)*b-4.4E-7)*b+1.3915817)*b+4612.156534)*b)/3600+d)%360/15;0>b&&(b+=24);sidereal_time_cache={tt:a.tt,st:b}}return sidereal_time_cache.st}function SiderealTime(a){a=MakeTime(a);return sidereal_time(a)}exports.SiderealTime=SiderealTime; diff --git a/source/js/astronomy.ts b/source/js/astronomy.ts index b8e20305..ba1e6583 100644 --- a/source/js/astronomy.ts +++ b/source/js/astronomy.ts @@ -1729,9 +1729,9 @@ function CalcMoon(time: AstroTime) { * @property {number} elon * Sub-Earth libration ecliptic longitude angle, in degrees. * @property {number} mlat - * Moon's geocentric ecliptic latitude. + * Moon's geocentric ecliptic latitude, in degrees. * @property {number} mlon - * Moon's geocentric ecliptic longitude. + * Moon's geocentric ecliptic longitude, in degrees. * @property {number} dist_km * Distance between the centers of the Earth and Moon in kilometers. * @property {number} diam_deg @@ -1867,7 +1867,7 @@ export function Libration(date: FlexibleDateTime): LibrationInfo { const ldash2 = -tau + (rho*Math.cos(a) + sigma*Math.sin(a))*Math.tan(bdash); const bdash2 = sigma*Math.cos(a) - rho*Math.sin(a); const diam_deg = 2.0 * RAD2DEG * Math.atan(MOON_MEAN_RADIUS_KM / Math.sqrt(dist_km*dist_km - MOON_MEAN_RADIUS_KM*MOON_MEAN_RADIUS_KM)); - return new LibrationInfo(RAD2DEG*bdash + bdash2, ldash + ldash2, mlat, mlon, dist_km, diam_deg); + return new LibrationInfo(RAD2DEG*bdash + bdash2, ldash + ldash2, RAD2DEG*mlat, RAD2DEG*mlon, dist_km, diam_deg); } function rotate(rot: RotationMatrix, vec: ArrayVector): ArrayVector { diff --git a/source/js/esm/astronomy.js b/source/js/esm/astronomy.js index 6377a71e..afbc0a10 100644 --- a/source/js/esm/astronomy.js +++ b/source/js/esm/astronomy.js @@ -1611,9 +1611,9 @@ function CalcMoon(time) { * @property {number} elon * Sub-Earth libration ecliptic longitude angle, in degrees. * @property {number} mlat - * Moon's geocentric ecliptic latitude. + * Moon's geocentric ecliptic latitude, in degrees. * @property {number} mlon - * Moon's geocentric ecliptic longitude. + * Moon's geocentric ecliptic longitude, in degrees. * @property {number} dist_km * Distance between the centers of the Earth and Moon in kilometers. * @property {number} diam_deg @@ -1729,7 +1729,7 @@ export function Libration(date) { const ldash2 = -tau + (rho * Math.cos(a) + sigma * Math.sin(a)) * Math.tan(bdash); const bdash2 = sigma * Math.cos(a) - rho * Math.sin(a); const diam_deg = 2.0 * RAD2DEG * Math.atan(MOON_MEAN_RADIUS_KM / Math.sqrt(dist_km * dist_km - MOON_MEAN_RADIUS_KM * MOON_MEAN_RADIUS_KM)); - return new LibrationInfo(RAD2DEG * bdash + bdash2, ldash + ldash2, mlat, mlon, dist_km, diam_deg); + return new LibrationInfo(RAD2DEG * bdash + bdash2, ldash + ldash2, RAD2DEG * mlat, RAD2DEG * mlon, dist_km, diam_deg); } function rotate(rot, vec) { return [ diff --git a/source/kotlin/README.md b/source/kotlin/README.md index 810761bc..7a095345 100644 --- a/source/kotlin/README.md +++ b/source/kotlin/README.md @@ -82,7 +82,7 @@ these are used in function and type names. | [InternalError](doc/-internal-error/index.md) | [jvm]
class [InternalError](doc/-internal-error/index.md)(message: [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)) : [Exception](https://docs.oracle.com/javase/8/docs/api/java/lang/Exception.html)
An unexpected internal error occurred in Astronomy Engine | | [InvalidBodyException](doc/-invalid-body-exception/index.md) | [jvm]
class [InvalidBodyException](doc/-invalid-body-exception/index.md)(body: [Body](doc/-body/index.md)) : [Exception](https://docs.oracle.com/javase/8/docs/api/java/lang/Exception.html)
An invalid body was specified for the given function. | | [JupiterMoonsInfo](doc/-jupiter-moons-info/index.md) | [jvm]
class [JupiterMoonsInfo](doc/-jupiter-moons-info/index.md)(moon: [Array](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-array/index.html)<[StateVector](doc/-state-vector/index.md)>)
Holds the positions and velocities of Jupiter's major 4 moons. | -| [LibrationInfo](doc/-libration-info/index.md) | [jvm]
data class [LibrationInfo](doc/-libration-info/index.md)(elat: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), elon: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), mlat: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), mlon: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), distKm: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), diamDeg: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html))
Lunar libration angles, returned by libration. | +| [LibrationInfo](doc/-libration-info/index.md) | [jvm]
data class [LibrationInfo](doc/-libration-info/index.md)(elat: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), elon: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), mlat: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), mlon: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), distKm: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), diamDeg: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html))
Lunar libration angles, returned by [libration](doc/libration.md). | | [LocalSolarEclipseInfo](doc/-local-solar-eclipse-info/index.md) | [jvm]
class [LocalSolarEclipseInfo](doc/-local-solar-eclipse-info/index.md)(kind: [EclipseKind](doc/-eclipse-kind/index.md), partialBegin: [EclipseEvent](doc/-eclipse-event/index.md), totalBegin: [EclipseEvent](doc/-eclipse-event/index.md)?, peak: [EclipseEvent](doc/-eclipse-event/index.md), totalEnd: [EclipseEvent](doc/-eclipse-event/index.md)?, partialEnd: [EclipseEvent](doc/-eclipse-event/index.md))
Information about a solar eclipse as seen by an observer at a given time and geographic location. | | [LunarEclipseInfo](doc/-lunar-eclipse-info/index.md) | [jvm]
class [LunarEclipseInfo](doc/-lunar-eclipse-info/index.md)(kind: [EclipseKind](doc/-eclipse-kind/index.md), peak: [Time](doc/-time/index.md), sdPenum: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), sdPartial: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), sdTotal: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html))
Information about a lunar eclipse. | | [MoonQuarterInfo](doc/-moon-quarter-info/index.md) | [jvm]
class [MoonQuarterInfo](doc/-moon-quarter-info/index.md)(quarter: [Int](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html), time: [Time](doc/-time/index.md))
A lunar quarter event (new moon, first quarter, full moon, or third quarter) along with its date and time. | @@ -127,6 +127,7 @@ these are used in function and type names. | [jupiterMoons](doc/jupiter-moons.md) | [jvm]
fun [jupiterMoons](doc/jupiter-moons.md)(time: [Time](doc/-time/index.md)): [JupiterMoonsInfo](doc/-jupiter-moons-info/index.md)
Calculates jovicentric positions and velocities of Jupiter's largest 4 moons. | | [lagrangePoint](doc/lagrange-point.md) | [jvm]
fun [lagrangePoint](doc/lagrange-point.md)(point: [Int](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html), time: [Time](doc/-time/index.md), majorBody: [Body](doc/-body/index.md), minorBody: [Body](doc/-body/index.md)): [StateVector](doc/-state-vector/index.md)
Calculates one of the 5 Lagrange points for a pair of co-orbiting bodies. | | [lagrangePointFast](doc/lagrange-point-fast.md) | [jvm]
fun [lagrangePointFast](doc/lagrange-point-fast.md)(point: [Int](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html), majorState: [StateVector](doc/-state-vector/index.md), majorMass: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), minorState: [StateVector](doc/-state-vector/index.md), minorMass: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html)): [StateVector](doc/-state-vector/index.md)
Calculates one of the 5 Lagrange points from body masses and state vectors. | +| [libration](doc/libration.md) | [jvm]
fun [libration](doc/libration.md)(time: [Time](doc/-time/index.md)): [LibrationInfo](doc/-libration-info/index.md)
Calculates the Moon's libration angles at a given moment in time. | | [massProduct](doc/mass-product.md) | [jvm]
fun [massProduct](doc/mass-product.md)(body: [Body](doc/-body/index.md)): [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html)
Returns the product of mass and universal gravitational constant of a Solar System body. | | [moonPhase](doc/moon-phase.md) | [jvm]
fun [moonPhase](doc/moon-phase.md)(time: [Time](doc/-time/index.md)): [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html)
Returns the Moon's phase as an angle from 0 to 360 degrees. | | [nextGlobalSolarEclipse](doc/next-global-solar-eclipse.md) | [jvm]
fun [nextGlobalSolarEclipse](doc/next-global-solar-eclipse.md)(prevEclipseTime: [Time](doc/-time/index.md)): [GlobalSolarEclipseInfo](doc/-global-solar-eclipse-info/index.md)
Searches for the next global solar eclipse in a series. | diff --git a/source/kotlin/doc/-libration-info/index.md b/source/kotlin/doc/-libration-info/index.md index 2e313785..8c80290e 100644 --- a/source/kotlin/doc/-libration-info/index.md +++ b/source/kotlin/doc/-libration-info/index.md @@ -5,7 +5,7 @@ [jvm]\ data class [LibrationInfo](index.md)(elat: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), elon: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), mlat: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), mlon: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), distKm: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), diamDeg: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html)) -Lunar libration angles, returned by libration. +Lunar libration angles, returned by [libration](../libration.md). ## Constructors diff --git a/source/kotlin/doc/index.md b/source/kotlin/doc/index.md index c78d9d07..138fedf4 100644 --- a/source/kotlin/doc/index.md +++ b/source/kotlin/doc/index.md @@ -27,7 +27,7 @@ | [InternalError](-internal-error/index.md) | [jvm]
class [InternalError](-internal-error/index.md)(message: [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)) : [Exception](https://docs.oracle.com/javase/8/docs/api/java/lang/Exception.html)
An unexpected internal error occurred in Astronomy Engine | | [InvalidBodyException](-invalid-body-exception/index.md) | [jvm]
class [InvalidBodyException](-invalid-body-exception/index.md)(body: [Body](-body/index.md)) : [Exception](https://docs.oracle.com/javase/8/docs/api/java/lang/Exception.html)
An invalid body was specified for the given function. | | [JupiterMoonsInfo](-jupiter-moons-info/index.md) | [jvm]
class [JupiterMoonsInfo](-jupiter-moons-info/index.md)(moon: [Array](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-array/index.html)<[StateVector](-state-vector/index.md)>)
Holds the positions and velocities of Jupiter's major 4 moons. | -| [LibrationInfo](-libration-info/index.md) | [jvm]
data class [LibrationInfo](-libration-info/index.md)(elat: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), elon: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), mlat: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), mlon: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), distKm: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), diamDeg: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html))
Lunar libration angles, returned by libration. | +| [LibrationInfo](-libration-info/index.md) | [jvm]
data class [LibrationInfo](-libration-info/index.md)(elat: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), elon: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), mlat: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), mlon: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), distKm: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), diamDeg: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html))
Lunar libration angles, returned by [libration](libration.md). | | [LocalSolarEclipseInfo](-local-solar-eclipse-info/index.md) | [jvm]
class [LocalSolarEclipseInfo](-local-solar-eclipse-info/index.md)(kind: [EclipseKind](-eclipse-kind/index.md), partialBegin: [EclipseEvent](-eclipse-event/index.md), totalBegin: [EclipseEvent](-eclipse-event/index.md)?, peak: [EclipseEvent](-eclipse-event/index.md), totalEnd: [EclipseEvent](-eclipse-event/index.md)?, partialEnd: [EclipseEvent](-eclipse-event/index.md))
Information about a solar eclipse as seen by an observer at a given time and geographic location. | | [LunarEclipseInfo](-lunar-eclipse-info/index.md) | [jvm]
class [LunarEclipseInfo](-lunar-eclipse-info/index.md)(kind: [EclipseKind](-eclipse-kind/index.md), peak: [Time](-time/index.md), sdPenum: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), sdPartial: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), sdTotal: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html))
Information about a lunar eclipse. | | [MoonQuarterInfo](-moon-quarter-info/index.md) | [jvm]
class [MoonQuarterInfo](-moon-quarter-info/index.md)(quarter: [Int](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html), time: [Time](-time/index.md))
A lunar quarter event (new moon, first quarter, full moon, or third quarter) along with its date and time. | @@ -72,6 +72,7 @@ | [jupiterMoons](jupiter-moons.md) | [jvm]
fun [jupiterMoons](jupiter-moons.md)(time: [Time](-time/index.md)): [JupiterMoonsInfo](-jupiter-moons-info/index.md)
Calculates jovicentric positions and velocities of Jupiter's largest 4 moons. | | [lagrangePoint](lagrange-point.md) | [jvm]
fun [lagrangePoint](lagrange-point.md)(point: [Int](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html), time: [Time](-time/index.md), majorBody: [Body](-body/index.md), minorBody: [Body](-body/index.md)): [StateVector](-state-vector/index.md)
Calculates one of the 5 Lagrange points for a pair of co-orbiting bodies. | | [lagrangePointFast](lagrange-point-fast.md) | [jvm]
fun [lagrangePointFast](lagrange-point-fast.md)(point: [Int](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/index.html), majorState: [StateVector](-state-vector/index.md), majorMass: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), minorState: [StateVector](-state-vector/index.md), minorMass: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html)): [StateVector](-state-vector/index.md)
Calculates one of the 5 Lagrange points from body masses and state vectors. | +| [libration](libration.md) | [jvm]
fun [libration](libration.md)(time: [Time](-time/index.md)): [LibrationInfo](-libration-info/index.md)
Calculates the Moon's libration angles at a given moment in time. | | [massProduct](mass-product.md) | [jvm]
fun [massProduct](mass-product.md)(body: [Body](-body/index.md)): [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html)
Returns the product of mass and universal gravitational constant of a Solar System body. | | [moonPhase](moon-phase.md) | [jvm]
fun [moonPhase](moon-phase.md)(time: [Time](-time/index.md)): [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html)
Returns the Moon's phase as an angle from 0 to 360 degrees. | | [nextGlobalSolarEclipse](next-global-solar-eclipse.md) | [jvm]
fun [nextGlobalSolarEclipse](next-global-solar-eclipse.md)(prevEclipseTime: [Time](-time/index.md)): [GlobalSolarEclipseInfo](-global-solar-eclipse-info/index.md)
Searches for the next global solar eclipse in a series. | diff --git a/source/kotlin/doc/libration.md b/source/kotlin/doc/libration.md new file mode 100644 index 00000000..8c33aa09 --- /dev/null +++ b/source/kotlin/doc/libration.md @@ -0,0 +1,26 @@ +//[astronomy](../../index.md)/[io.github.cosinekitty.astronomy](index.md)/[libration](libration.md) + +# libration + +[jvm]\ +fun [libration](libration.md)(time: [Time](-time/index.md)): [LibrationInfo](-libration-info/index.md) + +Calculates the Moon's libration angles at a given moment in time. + +Libration is an observed back-and-forth wobble of the portion of the Moon visible from the Earth. It is caused by the imperfect tidal locking of the Moon's fixed rotation rate, compared to its variable angular speed of orbit around the Earth. + +This function calculates a pair of perpendicular libration angles, one representing rotation of the Moon in eclitpic longitude elon, the other in ecliptic latitude elat, both relative to the Moon's mean Earth-facing position. + +This function also returns the geocentric position of the Moon expressed in ecliptic longitude mlon, ecliptic latitude mlat, the distance dist_km between the centers of the Earth and Moon expressed in kilometers, and the apparent angular diameter of the Moon diam_deg. + +#### Return + +The Moon's ecliptic position and libration angles as seen from the Earth. + +## Parameters + +jvm + +| | | +|---|---| +| time | The date and time for which to calculate lunar libration. | diff --git a/source/kotlin/src/main/kotlin/io/github/cosinekitty/astronomy/astronomy.kt b/source/kotlin/src/main/kotlin/io/github/cosinekitty/astronomy/astronomy.kt index 3b77b09b..2480b37a 100644 --- a/source/kotlin/src/main/kotlin/io/github/cosinekitty/astronomy/astronomy.kt +++ b/source/kotlin/src/main/kotlin/io/github/cosinekitty/astronomy/astronomy.kt @@ -76,6 +76,8 @@ fun Double.degreesToRadians() = this * DEG2RAD internal fun dsin(degrees: Double) = sin(degrees.degreesToRadians()) internal fun dcos(degrees: Double) = cos(degrees.degreesToRadians()) internal fun dtan(degrees: Double) = tan(degrees.degreesToRadians()) +internal fun datan(slope: Double) = atan(slope).radiansToDegrees() +internal fun datan2(y: Double, x: Double) = atan2(y, x).radiansToDegrees() /** * The factor to convert radians to degrees = 180/pi. @@ -783,8 +785,8 @@ data class Vector( lon = 0.0 lat = if (z < 0.0) -90.0 else +90.0 } else { - lon = atan2(y, x).radiansToDegrees().withMinDegreeValue(0.0) - lat = atan2(z, sqrt(xyproj)).radiansToDegrees() + lon = datan2(y, x).withMinDegreeValue(0.0) + lat = datan2(z, sqrt(xyproj)) } return Spherical(lat, lon, dist) } @@ -2325,12 +2327,12 @@ internal fun geoidIntersect(shadow: ShadowInfo): GlobalSolarEclipseInfo { latitude = if (proj == 0.0) ( if (pz > 0.0) +90.0 else -90.0 ) else ( - atan(pz / proj).radiansToDegrees() + datan(pz / proj) ) // Adjust longitude for Earth's rotation at the given time. val gast = siderealTime(shadow.time) - longitude = ((atan2(py,px).radiansToDegrees() - (15.0 * gast)) % 360.0).withMaxDegreeValue(180.0) + longitude = ((datan2(py,px) - (15.0 * gast)) % 360.0).withMaxDegreeValue(180.0) // We want to determine whether the observer sees a total eclipse or an annular eclipse. // We need to perform a series of vector calculations. @@ -4895,7 +4897,7 @@ fun horizon( if (projHor > 0.0) ( // If the body is not exactly straight up/down, it has an azimuth. // Invert the angle to produce degrees eastward from north. - (-atan2(pw, pn)).radiansToDegrees().withMinDegreeValue(0.0) + (-datan2(pw, pn)).withMinDegreeValue(0.0) ) else ( // The body is straight up/down, so it does not have an azimuth. // Report an arbitrary but reasonable value. @@ -4904,7 +4906,7 @@ fun horizon( ) // zd = the angle of the body away from the observer's zenith, in degrees. - var zd = atan2(projHor, pz).radiansToDegrees() + var zd = datan2(projHor, pz) var horRa = ra var horDec = dec @@ -4928,11 +4930,11 @@ fun horizon( horRa = if (projEqu > 0.0) - atan2(pry, prx).radiansToDegrees().withMinDegreeValue(0.0) / 15.0 + datan2(pry, prx).withMinDegreeValue(0.0) / 15.0 else 0.0 - horDec = atan2(prz, projEqu).radiansToDegrees() + horDec = datan2(prz, projEqu) } } @@ -5410,10 +5412,10 @@ private fun rotateEquatorialToEcliptic(pos: Vector, obliqRadians: Double): Eclip val xyproj = hypot(ex, ey) val elon = if (xyproj > 0.0) - atan2(ey, ex).radiansToDegrees().withMinDegreeValue(0.0) + datan2(ey, ex).withMinDegreeValue(0.0) else 0.0 - val elat = atan2(ez, xyproj).radiansToDegrees() + val elat = datan2(ez, xyproj) val vec = Vector(ex, ey, ez, pos.t) return Ecliptic(vec, elat, elon) } @@ -6829,6 +6831,131 @@ fun lagrangePointFast( } +/** + * Calculates the Moon's libration angles at a given moment in time. + * + * Libration is an observed back-and-forth wobble of the portion of the + * Moon visible from the Earth. It is caused by the imperfect tidal locking + * of the Moon's fixed rotation rate, compared to its variable angular speed + * of orbit around the Earth. + * + * This function calculates a pair of perpendicular libration angles, + * one representing rotation of the Moon in eclitpic longitude `elon`, the other + * in ecliptic latitude `elat`, both relative to the Moon's mean Earth-facing position. + * + * This function also returns the geocentric position of the Moon + * expressed in ecliptic longitude `mlon`, ecliptic latitude `mlat`, the + * distance `dist_km` between the centers of the Earth and Moon expressed in kilometers, + * and the apparent angular diameter of the Moon `diam_deg`. + * + * @param time + * The date and time for which to calculate lunar libration. + * + * @return + * The Moon's ecliptic position and libration angles as seen from the Earth. + */ +fun libration(time: Time): LibrationInfo { + val t = time.julianCenturies() + val t2 = t * t + val t3 = t2 * t + val t4 = t2 * t2 + + val moon = eclipticGeoMoon(time) + + val mlon = moon.lon.degreesToRadians() + val mlat = moon.lat.degreesToRadians() + val distKm = moon.dist * KM_PER_AU + val diamDeg = 2.0 * datan(MOON_MEAN_RADIUS_KM / sqrt(distKm*distKm - MOON_MEAN_RADIUS_KM*MOON_MEAN_RADIUS_KM)) + + // Inclination angle in radians = 0.026930430358272504 + val cosIncl = 0.99963739787586170 + val sinIncl = 0.02692717526916351 + + // Moon's argument of latitude in radians. + val f = normalizeLongitude(93.2720950 + 483202.0175233*t - 0.0036539*t2 - t3/3526000 + t4/863310000).degreesToRadians() + + // Moon's ascending node's mean longitude in radians. + val omega = normalizeLongitude(125.0445479 - 1934.1362891*t + 0.0020754*t2 + t3/467441 - t4/60616000).degreesToRadians() + + // Sun's mean anomaly in radians. + val m = normalizeLongitude(357.5291092 + 35999.0502909*t - 0.0001536*t2 + t3/24490000).degreesToRadians() + + // Moon's mean anomaly in radians. + val mdash = normalizeLongitude(134.9633964 + 477198.8675055*t + 0.0087414*t2 + t3/69699 - t4/14712000).degreesToRadians() + + // Moon's mean elongation in radians. + val d = normalizeLongitude(297.8501921 + 445267.1114034*t - 0.0018819*t2 + t3/545868 - t4/113065000).degreesToRadians() + + // Eccentricity of the Earth's orbit. + val e = 1.0 - 0.002516*t - 0.0000074*t2 + + // Optical librations + val w = mlon - omega; + val a = atan2(sin(w)*cos(mlat)*cosIncl - sin(mlat)*sinIncl, cos(w)*cos(mlat)) + val ldash = longitudeOffset((a - f).radiansToDegrees()) + val bdash = asin(-sin(w)*cos(mlat)*sinIncl - sin(mlat)*cosIncl) + + // Physical librations + val k1 = (119.75 + 131.849*t).degreesToRadians() + val k2 = (72.56 + 20.186*t).degreesToRadians() + + val rho = ( + -0.02752*cos(mdash) + + -0.02245*sin(f) + + +0.00684*cos(mdash - 2*f) + + -0.00293*cos(2*f) + + -0.00085*cos(2*f - 2*d) + + -0.00054*cos(mdash - 2*d) + + -0.00020*sin(mdash + f) + + -0.00020*cos(mdash + 2*f) + + -0.00020*cos(mdash - f) + + +0.00014*cos(mdash + 2*f - 2*d) + ) + + val sigma = ( + -0.02816*sin(mdash) + + +0.02244*cos(f) + + -0.00682*sin(mdash - 2*f) + + -0.00279*sin(2*f) + + -0.00083*sin(2*f - 2*d) + + +0.00069*sin(mdash - 2*d) + + +0.00040*cos(mdash + f) + + -0.00025*sin(2*mdash) + + -0.00023*sin(mdash + 2*f) + + +0.00020*cos(mdash - f) + + +0.00019*sin(mdash - f) + + +0.00013*sin(mdash + 2*f - 2*d) + + -0.00010*cos(mdash - 3*f) + ) + + val tau = ( + +0.02520*e*sin(m) + + +0.00473*sin(2*mdash - 2*f) + + -0.00467*sin(mdash) + + +0.00396*sin(k1) + + +0.00276*sin(2*mdash - 2*d) + + +0.00196*sin(omega) + + -0.00183*cos(mdash - f) + + +0.00115*sin(mdash - 2*d) + + -0.00096*sin(mdash - d) + + +0.00046*sin(2*f - 2*d) + + -0.00039*sin(mdash - f) + + -0.00032*sin(mdash - m - d) + + +0.00027*sin(2*mdash - m - 2*d) + + +0.00023*sin(k2) + + -0.00014*sin(2*d) + + +0.00014*cos(2*mdash - 2*f) + + -0.00012*sin(mdash - 2*f) + + -0.00012*sin(2*mdash) + + +0.00011*sin(2*mdash - 2*m - 2*d) + ) + + val elon = ldash - tau + (rho*cos(a) + sigma*sin(a))*tan(bdash) + val elat = bdash.radiansToDegrees() + sigma*cos(a) - rho*sin(a) + return LibrationInfo(elat, elon, moon.lon, moon.lat, distKm, diamDeg) +} + + /** * Calculates a rotation matrix from equatorial J2000 (EQJ) to ecliptic J2000 (ECL). * diff --git a/source/kotlin/src/test/kotlin/io/github/cosinekitty/astronomy/Tests.kt b/source/kotlin/src/test/kotlin/io/github/cosinekitty/astronomy/Tests.kt index fb4fb5cb..d13085ac 100644 --- a/source/kotlin/src/test/kotlin/io/github/cosinekitty/astronomy/Tests.kt +++ b/source/kotlin/src/test/kotlin/io/github/cosinekitty/astronomy/Tests.kt @@ -2067,4 +2067,50 @@ class Tests { } //---------------------------------------------------------------------------------------- + + @Test + fun `Lunar libration`() { + for (year in 2020..2022) { + verifyLibration(year) + } + } + + private fun verifyLibration(fileYear: Int) { + val filename = dataRootDir + "libration/mooninfo_$fileYear.txt" + var infile = File(filename) + var lnum = 0 + for (line in infile.readLines()) { + ++lnum + if (lnum == 1) { + assertTrue(line == " Date Time Phase Age Diam Dist RA Dec Slon Slat Elon Elat AxisA") + } else { + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + // 01 Jan 2020 00:00 UT 29.95 5.783 1774.5 403898 23.2609 -10.0824 114.557 -0.045 0.773 6.360 336.353 + val token = tokenize(line, 16, filename, lnum) + val day = token[0].toInt() + val month = monthNumber(token[1]) + val year = token[2].toInt() + assertTrue(token[3].length == 5 && token[3][2] == ':', "$filename line $lnum: invalid time string '${token[3]}'") + val hour = token[3].substring(0, 2).toInt() + val minute = token[3].substring(3).toInt() + val time = Time(year, month, day, hour, minute, 0.0) + val diam = token[7].toDouble() / 3600.0 + val dist = token[8].toDouble() + val elon = token[13].toDouble() + val elat = token[14].toDouble() + val lib: LibrationInfo = libration(time) + val diffElon = 60.0 * abs(lib.elon - elon) + val diffElat = 60.0 * abs(lib.elat - elat) + val diffDistance = abs(lib.distKm - dist) + val diffDiam = abs(lib.diamDeg - diam) + + assertTrue(diffElon < 0.1304, "$filename line $lnum: excessive libration longitude error = $diffElon arcmin.") + assertTrue(diffElat < 1.6476, "$filename line $lnum: excessive libration latitude error = $diffElat arcmin.") + assertTrue(diffDistance < 54.377, "$filename line $lnum: excessive distance error = $diffDistance km.") + assertTrue(diffDiam < 0.00009, "$filename line $lnum: excessive angular diameter error = $diffDiam degrees.") + } + } + } + + //---------------------------------------------------------------------------------------- } diff --git a/source/python/README.md b/source/python/README.md index d4a72d43..5f589eba 100644 --- a/source/python/README.md +++ b/source/python/README.md @@ -523,8 +523,8 @@ for a given moment in time. See [`Libration`](#Libration) for more details. | --- | --- | --- | | `float` | `elat` | Sub-Earth libration ecliptic latitude angle, in degrees. | | `float` | `elon` | Sub-Earth libration ecliptic longitude angle, in degrees. | -| `float` | `mlat` | Moon's geocentric ecliptic latitude. | -| `float` | `mlon` | Moon's geocentric ecliptic longitude. | +| `float` | `mlat` | Moon's geocentric ecliptic latitude, in degrees. | +| `float` | `mlon` | Moon's geocentric ecliptic longitude, in degrees. | | `float` | `dist_km` | Distance between the centers of the Earth and Moon in kilometers. | | `float` | `diam_deg` | The apparent angular diameter of the Moon as seen from the center of the Earth. | diff --git a/source/python/astronomy/astronomy.py b/source/python/astronomy/astronomy.py index 651f9c99..e42b4cea 100644 --- a/source/python/astronomy/astronomy.py +++ b/source/python/astronomy/astronomy.py @@ -9136,9 +9136,9 @@ class LibrationInfo: elon : float Sub-Earth libration ecliptic longitude angle, in degrees. mlat : float - Moon's geocentric ecliptic latitude. + Moon's geocentric ecliptic latitude, in degrees. mlon : float - Moon's geocentric ecliptic longitude. + Moon's geocentric ecliptic longitude, in degrees. dist_km : float Distance between the centers of the Earth and Moon in kilometers. diam_deg : float @@ -9284,7 +9284,7 @@ def Libration(time): ldash2 = -tau + (rho*math.cos(a) + sigma*math.sin(a))*math.tan(bdash) bdash = math.degrees(bdash) bdash2 = sigma*math.cos(a) - rho*math.sin(a) - return LibrationInfo(bdash + bdash2, ldash + ldash2, mlat, mlon, dist_km, diam_deg) + return LibrationInfo(bdash + bdash2, ldash + ldash2, math.degrees(mlat), math.degrees(mlon), dist_km, diam_deg) class AxisInfo: