UNPKG

@tubular/astronomy

Version:

Astronomical calculations for planetary positions, moon phases, eclipses, rise, transit, and set times, and more.

241 lines 9.38 kB
import { floor, max, min, sqrt } from '@tubular/math'; import { clone, extendDelimited } from '@tubular/util'; import { FIRST_JUPITER_MOON, NO_MATCH } from './astro-constants'; import { SolarSystem } from './solar-system'; import { utToTdt } from '@tubular/time'; export const AS_SEEN_FROM_EARTH = false; export const AS_SEEN_FROM_SUN = true; export const MOON_ITSELF = false; export const MOON_SHADOW = true; export var MoonEvent; (function (MoonEvent) { MoonEvent[MoonEvent["TR_I"] = 1] = "TR_I"; MoonEvent[MoonEvent["TR_E"] = 2] = "TR_E"; MoonEvent[MoonEvent["OC_D"] = 3] = "OC_D"; MoonEvent[MoonEvent["OC_R"] = 4] = "OC_R"; MoonEvent[MoonEvent["EC_D"] = 5] = "EC_D"; MoonEvent[MoonEvent["EC_R"] = 6] = "EC_R"; MoonEvent[MoonEvent["SH_I"] = 7] = "SH_I"; MoonEvent[MoonEvent["SH_E"] = 8] = "SH_E"; // Shadow Egress - shadow of moon ends })(MoonEvent || (MoonEvent = {})); const moonNumbers = ['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII', 'XIII', 'XIV', 'XV', 'XVI', 'XVII', 'XVIII', 'XIX', 'XX']; const moonEvents = ['{0} Tr.I.', '{0} Tr.E.', '{0} Oc.D.', '{0} Oc.R.', '{0} Ec.D.', '{0} Ec.R.', '{0} Sh.I.', '{0} Sh.E.']; const moonEventsLong = ['{0} begins transit', '{0} ends transit', '{0} becomes occulted', '{0} emerges from occultation', '{0} becomes eclipsed', '{0} emerges from eclipse', 'Shadow of {0} appears', 'Shadow of {0} ends']; const CACHE_SIZE = 6; export class MoonEvents { constructor() { this.count = 0; this.text = ''; this.searchΔT = 1; // In minutes } } export class PlanetaryMoons { constructor() { this.cachedTimes = []; this.cachedMoons = []; this.solarSystem = new SolarSystem(); this.cachedTimes[0] = []; this.cachedTimes[1] = []; this.cachedMoons[0] = []; this.cachedMoons[1] = []; } getMoonPosition(moonIndex, time_JDE, sunPerspective = false) { const moons = this.getMoonPositions(time_JDE, sunPerspective, false); for (const moon of moons) { if (moon.moonIndex === moonIndex) return clone(moon); } return undefined; } getMoonPositions(time_JDE, sunPerspective = false, makeClones = true) { const index = (sunPerspective ? 1 : 0); let moons; for (let i = 0; i < CACHE_SIZE; ++i) { if (time_JDE === this.cachedTimes[index][i] && this.cachedMoons[index][i] != null) { moons = this.cachedMoons[index][i]; break; } } if (!moons) { moons = this.getMoonPositionsAux(time_JDE, sunPerspective); // Shuffle cache for (let i = 0; i < CACHE_SIZE - 1; ++i) { this.cachedTimes[index][i] = this.cachedTimes[index][i + 1]; this.cachedMoons[index][i] = this.cachedMoons[index][i + 1]; } this.cachedTimes[index][CACHE_SIZE - 1] = time_JDE; this.cachedMoons[index][CACHE_SIZE - 1] = moons; } if (!makeClones) return moons; const result = []; for (const moon of moons) result.push(clone(moon)); return result; } // Note: The span considered is +/- 30 seconds of the specified time *in Universal Time*. // getMoonEventsForOneMinuteSpan(time_JDU, longFormat = false) { const events = new MoonEvents(); const t0 = utToTdt(time_JDU - 0.5 / 1440); const t1 = utToTdt(time_JDU + 0.5 / 1440); const pos0 = this.getMoonPositions(t0); const pos1 = this.getMoonPositions(t1); const sunPos0 = this.getMoonPositions(t0, AS_SEEN_FROM_SUN); const sunPos1 = this.getMoonPositions(t1, AS_SEEN_FROM_SUN); const nmoons = pos0.length; events.events = []; events.shadowEvents = []; events.searchΔT = (!this.v_max ? 1 : 120); // At the very most, put off more event checking for two hours. events.t0 = t0; events.t1 = t1; if (this.v_max) { let Y1; let d; let ΔT; findSearchTime: for (let i = 0; i < nmoons; ++i) { for (let j = 0; j < 4; ++j) { let pos; switch (j) { case 0: pos = pos0; break; case 1: pos = pos1; break; case 2: pos = sunPos0; break; case 3: default: pos = sunPos1; break; } Y1 = pos[i].Y * this.flattening; d = sqrt(pos[i].X * pos[i].X + Y1 ** 2); if (d > 1) d -= 1; else d = 1 - d; ΔT = max(floor(d / this.v_max[i] * 0.75), 1); events.searchΔT = min(ΔT, events.searchΔT); if (ΔT === 1) break findSearchTime; } } } for (let i = 0; i < nmoons; ++i) { const tr0 = pos0[i].inFrontOfDisc; const tr1 = pos1[i].inFrontOfDisc; const oc0 = pos0[i].behindDisc; const oc1 = pos1[i].behindDisc; const ec0 = sunPos0[i].behindDisc; const ec1 = sunPos1[i].behindDisc; const sh0 = sunPos0[i].inFrontOfDisc; const sh1 = sunPos1[i].inFrontOfDisc; if (!tr0 && tr1) { ++events.count; events.events[i] = MoonEvent.TR_I; } else if (tr0 && !tr1) { ++events.count; events.events[i] = MoonEvent.TR_E; } else if (!oc0 && oc1 && !ec0) { ++events.count; events.events[i] = MoonEvent.OC_D; } else if (oc0 && !oc1 && !ec1) { ++events.count; events.events[i] = MoonEvent.OC_R; } else if (!ec0 && ec1 && !oc0) { ++events.count; events.events[i] = MoonEvent.EC_D; } else if (ec0 && !ec1 && !oc1) { ++events.count; events.events[i] = MoonEvent.EC_R; } if (!sh0 && sh1) { ++events.count; events.shadowEvents[i] = MoonEvent.SH_I; } else if (sh0 && !sh1) { ++events.count; events.shadowEvents[i] = MoonEvent.SH_E; } } if (events.count > 0) { let eventNames; const pad = []; let maxNumLen = 0; let eventText; if (longFormat) eventNames = moonEventsLong; else eventNames = moonEvents; for (let i = 0; i < nmoons; ++i) maxNumLen = max(moonNumbers[i + 1].length, maxNumLen); if (!longFormat) { for (let i = 0; i < nmoons; ++i) pad.push(' '.repeat(maxNumLen - moonNumbers[i + 1].length)); } for (let i = 0; i < nmoons; ++i) { let moonName; if (longFormat) moonName = PlanetaryMoons.getMoonName(FIRST_JUPITER_MOON + i); else moonName = pad[i] + moonNumbers[i + 1]; for (let j = 0; j < 2; ++j) { const list = (j === 0 ? events.events : events.shadowEvents); if (list[i]) { eventText = eventNames[list[i] - 1]; eventText = eventText.replace('{0}', moonName); events.text = extendDelimited(events.text, eventText); } } } } return events; } static getMoonName(moonIndex, getShadow = MOON_ITSELF) { for (const mni of PlanetaryMoons.namesList) { if (mni.first <= moonIndex && moonIndex <= mni.last) { moonIndex -= mni.first; return (getShadow ? mni.shadowNames[moonIndex] : mni.names[moonIndex]); } } return undefined; } static getMoonNumber(moonIndex) { moonIndex %= 1000; if (moonIndex <= 0 || moonIndex >= moonNumbers.length) return String(moonIndex); else return moonNumbers[moonIndex]; } static getMoonByName(moonName) { moonName = moonName.toLowerCase(); for (const mni of this.namesList) { for (let j = 0; j < mni.names.length; ++j) { if (mni.names[j].toLowerCase() === moonName) return mni.first + j; } } return NO_MATCH; } static registerMoonNames(first, last, names, shadowNames) { const mni = {}; mni.first = first; mni.last = last; mni.names = names; mni.shadowNames = shadowNames; this.namesList.push(mni); } } PlanetaryMoons.namesList = []; //# sourceMappingURL=planetary-moons.js.map