UNPKG

@tubular/astronomy

Version:

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

654 lines 28.2 kB
import { ArrayBufferReader } from '@tubular/array-buffer-reader'; import { abs, cos, mod, PI, sign, sin, sin_deg, SphericalPosition, tan, to_radian, Unit } from '@tubular/math'; import { utToTdt } from '@tubular/time'; import { isFunction, isString } from '@tubular/util'; import { ABERRATION, JD_J2000, NO_PRECESSION, NUTATION, OBLIQUITY_J2000, UNKNOWN_MAGNITUDE } from './astro-constants'; import { Ecliptic, NMode } from './ecliptic'; let _Buffer; let _readFile; try { _Buffer = typeof Buffer !== undefined && Buffer; // eslint-disable-next-line no-new-func _readFile = !!_Buffer && (new Function('req', 'return req("fs").readFile'))(typeof require !== 'undefined' && require); } catch (_a) { } var READING; (function (READING) { READING[READING["FK5"] = 0] = "FK5"; READING[READING["BSC"] = 1] = "BSC"; READING[READING["HIP"] = 2] = "HIP"; })(READING || (READING = {})); var MARKER; (function (MARKER) { MARKER[MARKER["INC_FK5"] = 255] = "INC_FK5"; MARKER[MARKER["NEW_STATE"] = 254] = "NEW_STATE"; MARKER[MARKER["DBL_PREC"] = 253] = "DBL_PREC"; MARKER[MARKER["SNG_PREC"] = 252] = "SNG_PREC"; })(MARKER || (MARKER = {})); const CONSTELLATION_LINES = `And~Andromeda~Gam,Bet,Del,Alp,Pi,Mu,Xi,51 Ant~Antlia~Iot,Alp,The,Eps Aps~Apus~Bet,Gam,Del-1,Alp Aql~Aquila~12,Lam,Del,The,Bet,Alp,Gam,Zet,Del;Zet,Eps Aqr~Aquarius~88,Del,Tau-2,Lam,Phi,Eta,Zet,Gam,Alp,Bet,Mu,Eps;Iot,The,Alp Ara~Ara~Del,Gam,Bet,Alp,Eps-1,Zet,Eta;Gam,Zet;The,Alp Ari~Aries~41,Alp,Bet,Gam Aur~Auriga~Alp,Eps,Eta,Iot,Bet (Tau),The,Bet,Alp Boo~Boötes~Zet,Alp,Eps,Del,Bet,Gam,Rho,Alp,Eta Cae~Caelum~Alp,Bet Cam~Camelopardalis~7,Bet,Alp,Gam;Alp,36,43 Cap~Capricornus~Alp-1,Bet,Psi,Ome,24,Zet,Eps,Del,Gam,Iot,The,Bet Car~Carina~Ups,Bet,Ome,The,FK5:397,FK5:1264,Iot,Eps,Chi,Alp Cas~Cassiopeia~Eps,Del,Gam,Alp,Bet Cen~Centaurus~Kap,Eta,Nu,BSC:5089,Iot;The,Nu,Mu,Zet,Eps,Alp;Bet,Eps,Gam,Sig,Del,Rho,Pi,FK5:443,Lam Cep~Cepheus~Del,Eps,Zet,Iot,Gam,Bet,Alp,Zet;Alp,Eta,The Cet~Cetus~Gam,Alp,Lam,Mu,Xi-2,Nu,Gam,Del,Omi,Zet,Tau,Bet,Iot,Eta,The,Zet Cha~Chamaeleon~Bet,Gam,Alp,The,Del-2 Cir~Circinus~Gam,Alp,Bet CMa~Canis Major~Eta,Del,Omi-2,Alp,Bet;Eps,Sig,Alp CMi~Canis Minor~Alp,Bet Cnc~Cancer~Alp,Del,Iot;Del,Bet Col~Columba~Del,Kap,Gam,Bet,Eta;Bet,Alp,Eps Com~Coma Berenices~Alp,Bet,Gam CrA~Corona Australis~Zet,Del,Bet,Alp,Gam,Eps CrB~Corona Borealis~Iot,Eps,Del,Gam,Alp,Bet,The Crt~Crater~Eta,Zet,Gam,Del,Eps,The;Gam,Bet,Alp,Del Cru~Crux~Alp,Gam;Bet,Del Crv~Corvus~Alp,Eps,Gam,Del,Bet,Eps CVn~Canes Venatici~Alp,Bet Cyg~Cygnus~Alp,Gam,Bet;Zet,Eps,Gam,Del,Iot-2,Kap Del~Delphinus~Eps,Bet,Alp,Gam,Del,Bet Dor~Dorado~Del,Bet,Zet,Alp,Gam;BSC:2102,Bet Dra~Draco~Xi,Nu,Bet,Gam,Xi,Del,Eps,Tau,Chi,Psi,Zet,Eta,@The,Iot,Alp,Kap,Lam Equ~Equuleus~Alp,Bet,Del,Gam,Alp Eri~Eridanus~Lam,Bet,Ome,Mu,Nu,Omi-1,Gam,Pi,Del,Eps,Zet,Eta,@Tau-1,Tau-3,Tau-4,Tau-5,Tau-6,Tau-8,Tau-9,Ups-1,Ups-2,43,Ups-4,The,Iot,Kap,Phi,Chi,Alp For~Fornax~Alp,Bet,Nu Gem~Gemini~Xi,Gam,Nu,Mu,Eps,Tau,Rho,Alp,Sig,Bet,Kap,Del,Zet,Gam;Lam,Del;Eta,Mu Gru~Grus~Alp,Bet,Iot,The;Zet,Eps,Bet,Del-2,Mu-1,Lam,Gam Her~Hercules~Alp,Bet,Gam;Bet,Zet,Eta,Sig,Tau,Phi,Chi;Zet,Eps,Pi,Eta;Pi,Rho,The,Iot;Eps,Del,Lam,Mu,Xi,Omi Hor~Horologium~Alp,BSC:868,Zet,Mu,Bet Hya~Hydra~Pi,Gam,Bet,Xi,Nu,@Mu,Lam,Ups-1,Alp,Iot,The,Zet,Eta,Sig,Del,Eps,Zet Hyi~Hydrus~Alp,Bet,Gam,Alp Ind~Indus~Alp,The,Del;The,Bet Lac~Lacerta~1,FK5:1583,6,2,5,4,Alp,Bet Leo~Leo~Eps,Mu,Zet,Gam,Eta,Alp,The,Bet,Del,Gam Lep~Lepus~Del,Gam,Bet,Alp,Zet,Eta;Eps,Bet;Alp,Mu Lib~Libra~48,The,Gam,Bet,Sig,Ups,Tau;Sig,Alp-2,Bet LMi~Leo Minor~46,Bet,21 Lup~Lupus~The,Eta,Gam,Del,Phi-1,Chi Lyn~Lynx~Alp,38,FK5:339,31,21,15,2 Lyr~Lyra~Eps-2,Alp,Zet,Bet,Gam,Del-2,Zet Men~Mensa~Alp,Gam,Eta,Bet Mic~Microscopium~The-1,Eps,Gam,Alp Mon~Monoceros~Zet,Alp,Del,18,8 Eps,13;Del,Bet,Gam Mus~Musca~Bet,Alp,Gam;Del,Alp,Eps,Lam Nor~Norma~Eps,Gam-2,Eta Oct~Octans~Bet,Del,Nu,Bet Oph~Ophiuchus~45,The,44,Xi,Eta,Bet,Alp,Kap,Del,Eps,Ups,Zet,Eta;70,67,Gam,Bet;Gam,Nu Ori~Orion~Alp,Zet,Kap,Bet,Del,Gam,Lam,Alp,Mu,Xi,Nu,Chi-1;Xi,Chi-2;Pi-1,Pi-2,Pi-3,Gam;Pi-3,Pi-4,Pi-5,Pi-6 Pav~Pavo~Alp,Bet,Eps,Zet,Eta,Pi,Xi,Lam,Del,Bet,Gam Peg~Pegasus~Bet,Alp (And),Gam,Alp,Bet,Eta,Iot,Kap;Bet,Mu,Lam,9,1;Alp,Xi,Zet,The,Eps Per~Perseus~Omi,Zet,Xi,Eps,Del,Alp,Gam,Eta,Phi;Alp,Kap,Bet,Rho,16 Phe~Phoenix~Del,Gam,Bet,Alp,Eps,Eta,Zet,Bet Pic~Pictor~Alp,Gam,Bet PsA~Piscis Austrinus~Alp,Del,Gam,Bet,Mu,Iot,The,Lam,Eps,Alp Psc~Pisces~Tau,Ups,Phi,Eta,Omi,Alp,Nu,Mu,Eps,@Del,Ome,Iot,Lam,Kap,Gam,The,Iot Pup~Puppis~Zet,Sig,Tau,Nu,Pi,Xi,Rho,Zet Pyx~Pyxis~Bet,Alp,Gam Ret~Reticulum~Alp,Bet,Del,Eps,Alp Scl~Sculptor~Alp,Iot,Del,Gam,Bet Sco~Scorpius~Lam,Kap,Iot-1,The,Eta,Zet-2,Mu-1,Eps,Tau,Alp,Sig,Del,Bet,Nu;Del,Pi,Rho Sct~Scutum~Bet,Alp,Gam;Alp,Zet Ser~Serpens Caput~Mu,Eps,Alp,Del,Bet,Kap,Gam,Bet Ser~Serpens Cauda~The,Eta,Omi,Xi,Nu Sex~Sextans~Bet,Alp,Gam Sge~Sagitta~Eta,Gam,Zet,Alp;Zet,Bet Sgr~Sagittarius~Alp,Iot,The-1,62,52,Tau,Zet,Eps,Eta;Bet-2,Iot;Tau,Sig,Omi,Pi,Rho-1;Zet,Phi,Sig;Mu,Lam,Phi,Del,Gam-2,3;Lam,Del,Eps;Eps,Gam-2 Tau~Taurus~Bet,Tau,Eps,Del,Gam,Lam,Xi,Omi;Zet,Alp,The,Gam Tel~Telescopium~Zet,Alp,Eps TrA~Triangulum Australe~Alp,Bet,Gam,Alp Tri~Triangulum~Alp,Bet,Gam,Alp Tuc~Tucana~Del,Alp,Gam,Bet-1,Zet,Eps,Gam UMa~Ursa Major~Eta,Zet,Eps,Del,Alp,Bet,Gam,Del;Kap,Iot,The,Ups,Omi,23,Alp;Ups,Bet;Gam,Chi,Nu,Xi;Chi,Psi,Mu,Lam UMi~Ursa Minor~Alp,Del,Eps,Zet,Bet,Gam,Eta,Zet Vel~Vela~Gam,Del,Kap,Phi,Mu,BSC:4167,FK5:1273,FK5:382,Psi,Lam,BSC:3477,FK5:324,Gam Vir~Virgo~Mu,Iot,Kap,Alp,The,Gam,Del,Zet,Alp;109,Tau,Zet;Eps,Del;Gam,Eta,Bet Vol~Volans~Alp,Bet,Eps,Zet,Gam,Del,Eps Vul~Vulpecula~13,Alp,1`; export const LINE_BREAK = -1; export const LABEL_ANCHOR = -2; function toArrayBuffer(buf) { return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength); } export class StarCatalog { constructor(dataSource, readyCallback) { this.bscLookup = {}; this.cachedPositions = []; this.constellations = []; this.ecliptic = new Ecliptic(); this.fk5Lookup = {}; this.hipLookup = {}; this.messierLookup = {}; this.ngcIcLookup = {}; this.nameLookup = {}; this.properlyInitialized = false; this.starNames = {}; this.sunCacheTime = -1E10; this.sunLongitudeCache = -1; this.stars = []; if (_Buffer) { if (dataSource instanceof _Buffer) { this.readStarData(toArrayBuffer(dataSource)); if (readyCallback) readyCallback(this.properlyInitialized); return; } else if (_readFile && isString(dataSource)) { _readFile(dataSource, (err, data) => { if (err) throw err; this.readStarData(toArrayBuffer(data)); if (readyCallback) readyCallback(this.properlyInitialized); }); return; } } if (isFunction(dataSource.getStars)) { dataSource.getStars().then((data) => { this.readStarData(data); if (readyCallback) readyCallback(this.properlyInitialized); }); } else throw new Error('Invalid StarCatalog constructor data source'); } static createCodedName(star) { if (star.messierNum !== 0) return 'M' + star.messierNum; else if (star.ngcIcNum < 0) return 'IC ' + (-star.ngcIcNum); else if (star.ngcIcNum > 0) return 'NGC ' + star.ngcIcNum; let result = ''; if (star.flamsteed > 0) result += star.flamsteed + ' '; if (star.bayerRank > 0) result += StarCatalog.greekIndices[star.bayerRank - 1] + ' '; if (star.subIndex > 0) result = result.trim() + '-' + star.subIndex + ' '; if (star.constellation > 0) result += StarCatalog.constellationCodes[star.constellation - 1]; if (result === '') { if (star.fk5Num > 0) result = 'FK5 ' + star.fk5Num; else if (star.bscNum > 0) result = 'BSC ' + star.bscNum; else if (star.hipNum > 0) result = 'HC ' + star.hipNum; else return null; } return result; } readStarData(data) { const reader = new ArrayBufferReader(data); let state = READING.FK5; let doDouble = false; let fk5Num = 0; const namesInUse = {}; try { while (true) { const firstByte = reader.read(); // Can be marker, Flamsteed number, constellation number, or EOF. if (firstByte < 0) // EOF break; if (firstByte === MARKER.NEW_STATE) { ++state; continue; } else if (firstByte === MARKER.DBL_PREC) { doDouble = true; continue; } else if (firstByte === MARKER.SNG_PREC) { doDouble = false; continue; } else if (firstByte === MARKER.INC_FK5) { ++fk5Num; continue; } const star = {}; star.flamsteed = firstByte; star.bayerRank = reader.read(); star.subIndex = reader.read(); star.constellation = reader.read(); if (doDouble) { star.RA = reader.readDouble(); star.DE = reader.readDouble(); } else { star.RA = reader.readFloat(); star.DE = reader.readFloat(); } star.pmRA = reader.readFloat(); star.pmDE = reader.readFloat(); const vmag = reader.read(); if (vmag === 255) star.vmag = UNKNOWN_MAGNITUDE; else star.vmag = vmag / 10 - 2; if (state === READING.FK5) { star.fk5Num = ++fk5Num; star.bscNum = 0; star.hipNum = 0; star.ngcIcNum = 0; star.messierNum = 0; } else if (state === READING.BSC) { star.fk5Num = 0; star.bscNum = reader.readInt16(); star.hipNum = 0; star.ngcIcNum = 0; star.messierNum = 0; } else if (state === READING.HIP) { star.fk5Num = 0; star.bscNum = 0; star.hipNum = reader.read() * 0x10000 + (reader.readInt16() & 0xFFFF); star.ngcIcNum = 0; star.messierNum = 0; } else { star.fk5Num = 0; star.bscNum = 0; star.hipNum = 0; star.ngcIcNum = reader.readInt16(); star.messierNum = reader.read(); } star.name = reader.readShortUtf8String(); star.name = star.name || null; if (star.name != null) { if (!namesInUse[star.name]) { namesInUse[star.name] = true; star.duplicateName = false; } else star.duplicateName = true; } else star.duplicateName = false; star.codedName = StarCatalog.createCodedName(star); this.stars.push(star); if (star.name) this.nameLookup[star.name.toLowerCase()] = star; if (star.bscNum) this.bscLookup[star.bscNum] = star; if (star.fk5Num) this.fk5Lookup[star.fk5Num] = star; if (star.hipNum) this.hipLookup[star.hipNum] = star; if (star.messierNum) this.messierLookup[star.messierNum] = star; if (star.ngcIcNum) this.ngcIcLookup[star.ngcIcNum] = star; } } catch (e) { console.error(e); this.properlyInitialized = false; return; } this.stars.sort((a, b) => { // The top priority is sorting stars by magnitude, dimmest (highest vmag) first. // The rest of the comparison, if vmags match, is to impose a consistent sort order. if (a.vmag > b.vmag) return -1; else if (a.vmag < b.vmag) return 1; else if (a.fk5Num !== 0 || b.fk5Num !== 0) return sign(a.fk5Num - b.fk5Num); else if (a.bscNum !== 0 || b.bscNum !== 0) return sign(a.bscNum - b.bscNum); else if (a.hipNum !== 0 || b.hipNum !== 0) return sign(a.hipNum - b.hipNum); else if (a.ngcIcNum !== 0 || b.ngcIcNum !== 0) return sign(a.ngcIcNum - b.ngcIcNum); return sign(a.messierNum - b.messierNum); }); this.cachedPositions = []; this.cachedPositions.length = this.stars.length; // Create look-up tables for star indices. for (let i = 0; i < this.stars.length; ++i) { this.cachedPositions[i] = {}; const star = this.stars[i]; star.catalogIndex = i; Object.freeze(star); if (star.name) this.starNames[star.name] = i; if (star.codedName) { this.starNames[star.codedName] = i; // For coded names such as 47 Lam Peg, we'll make an additional // shortened look-up entry, i.e. Lam Peg. const match = /^(\d+\s*)(.+)$/.exec(star.codedName); if (match && !this.starNames[match[2]]) this.starNames[match[2]] = i; } } // Parse constellation data. const lines = CONSTELLATION_LINES.split('\n'); for (let line of lines) { line = line.trim(); if (!line) continue; const parts = line.split('~'); if (parts.length !== 3) continue; const constCode = parts[0]; const constName = parts[1]; const paths = parts[2].split(';'); const starList = []; for (const path of paths) { if (starList.length > 0) starList.push(LINE_BREAK); const starIndices = path.split(','); for (let codedIndex of starIndices) { if (codedIndex.startsWith('@')) { starList.push(LABEL_ANCHOR); codedIndex = codedIndex.substring(1); } if (codedIndex.startsWith('FK5:')) { fk5Num = Number(codedIndex.substring(4)); if (this.fk5Lookup[fk5Num]) starList.push(this.fk5Lookup[fk5Num].catalogIndex); else console.error(codedIndex + ' not found'); } else if (codedIndex.startsWith('BSC:')) { const bscNum = Number(codedIndex.substring(4)); if (this.bscLookup[bscNum]) starList.push(this.bscLookup[bscNum].catalogIndex); else console.error(codedIndex + ' not found'); } else { let pos; let constCode2; let starNum; if ((pos = codedIndex.lastIndexOf('(')) >= 0) { constCode2 = codedIndex.substring(pos + 1, codedIndex.length - 1); codedIndex = codedIndex.substring(0, pos).trim(); } else constCode2 = constCode; const codedName = codedIndex + ' ' + constCode2; // If a first match is not found on, say, Gam And, try Gam-1 And. if (!(starNum = this.starNames[codedName])) { const codedNameAlt = codedIndex + '-1 ' + constCode2; if (!(starNum = this.starNames[codedNameAlt])) console.error(codedName + ' not found'); } if (starNum) starList.push(starNum); } } } this.constellations.push({ index: this.constellations.length + 1, name: constName, code: constCode, starList }); } this.properlyInitialized = true; } isProperlyInitialized() { return this.properlyInitialized; } getStarCount() { return (this.stars ? this.stars.length : 0); } getStarInfo(starIndex) { return this.stars[starIndex]; } getStarByName(name) { return this.nameLookup[(name === null || name === void 0 ? void 0 : name.toLowerCase()) || '']; } getBrightStarCatalogStar(num) { return this.bscLookup[num]; } getFk5Star(num) { return this.fk5Lookup[num]; } getHipparcosStar(num) { return this.hipLookup[num]; } getName(starIndex, skipDuplicates = false) { var _a; if (starIndex < 0 || starIndex >= this.stars.length || (skipDuplicates && this.stars[starIndex].duplicateName)) return null; return (_a = this.stars[starIndex]) === null || _a === void 0 ? void 0 : _a.name; } getCodedName(starIndex) { var _a; if (starIndex < 0 || starIndex >= this.stars.length) return null; return (_a = this.stars[starIndex]) === null || _a === void 0 ? void 0 : _a.codedName; } getExpandedName(starIndex) { let name; const codedName = this.getCodedName(starIndex); if (this.isDeepSkyObject(starIndex)) name = codedName; const fullName = this.getName(starIndex, true); if (fullName) { if (!name) { name = fullName; if (codedName) name += ' (' + codedName + ')'; } else name += ' - ' + fullName; } return name; } getMagnitude(starIndex) { if (starIndex < 0 || starIndex >= this.stars.length) return -1.0E6; return this.stars[starIndex].vmag; } getFK5Number(starIndex) { if (starIndex < 0 || starIndex >= this.stars.length) return 0; return this.stars[starIndex].fk5Num; } getBSCNumber(starIndex) { if (starIndex < 0 || starIndex >= this.stars.length) return 0; return this.stars[starIndex].bscNum; } forEach(callback) { for (const star of this.stars) { if (callback(star, star.catalogIndex) === false) break; } } isDeepSkyObject(starIndex) { if (starIndex < 0 || starIndex >= this.stars.length) return false; const star = this.stars[starIndex]; return (star.messierNum !== 0 || star.ngcIcNum !== 0); } getMessierNumber(starIndex) { if (starIndex < 0 || starIndex >= this.stars.length) return 0; return this.stars[starIndex].messierNum; } getDsoByMessierNumber(mn) { return this.messierLookup[mn]; } // noinspection JSUnusedGlobalSymbols /** @deprecated */ getNGCNumber(n) { return this.getNgcNumber(n); } getNgcNumber(starIndex) { if (starIndex < 0 || starIndex >= this.stars.length || this.stars[starIndex].ngcIcNum <= 0) return 0; return this.stars[starIndex].ngcIcNum; } getDsoByNgcNumber(ngc) { return this.ngcIcLookup[ngc]; } // noinspection JSUnusedGlobalSymbols /** @deprecated */ getICNumber(n) { return this.getIcNumber(n); } getIcNumber(starIndex) { if (starIndex < 0 || starIndex >= this.stars.length || this.stars[starIndex].ngcIcNum >= 0) return 0; return -this.stars[starIndex].ngcIcNum; } getDsoByIcNumber(ic) { return this.ngcIcLookup[-ic]; } getBayerRank(starIndex) { if (starIndex < 0 || starIndex >= this.stars.length) return 0; return this.stars[starIndex].bayerRank; } getConstellationOfStar(starIndex) { if (starIndex < 0 || starIndex >= this.stars.length) return 0; return this.stars[starIndex].constellation; } getConstellationCount() { return this.constellations.length; } // noinspection JSUnusedGlobalSymbols /** * @deprecated - Uses 0-based indexing, inconsistent with 1-based constellation codes * */ getConstellationName(constellationIndex) { return this.constellations[constellationIndex].name; } constellationName(constellationIndex) { return this.constellations[constellationIndex - 1].name; } // noinspection JSUnusedGlobalSymbols /** * @deprecated - Uses 0-based indexing, inconsistent with 1-based constellation codes * */ getConstellationCode(constellationIndex) { return this.constellations[constellationIndex].code; } constellationCode(constellationIndex) { return this.constellations[constellationIndex - 1].code; } // noinspection JSUnusedGlobalSymbols /** * @deprecated - Uses 0-based indexing, inconsistent with 1-based constellation codes * */ getConstellationDrawingStars(constellationIndex) { return this.constellations[constellationIndex].starList; } constellationDrawingStars(constellationIndex) { return this.constellations[constellationIndex - 1].starList; } forEachConstellation(callback) { for (const constellation of this.constellations) { if (callback(constellation, constellation.index) === false) break; } } // Note: The calculation for aberration used here can misbehave for coordinates very close // to either pole, but no stars in the star catalogs that I'm using get close enough // to cause a problem over the time period of years -5999 to 9999. // getEquatorialPosition(starIndex, time_JDE, cacheTolerance = 0, flags = 0) { if (starIndex < 0 || starIndex >= this.stars.length) return null; if (this.cachedPositions[starIndex].pos && this.cachedPositions[starIndex].flags === flags && abs(this.cachedPositions[starIndex].time - time_JDE) <= cacheTolerance) return this.cachedPositions[starIndex].pos; const star = this.stars[starIndex]; const T = (time_JDE - JD_J2000) / 36525; let pos = new SphericalPosition(star.RA + star.pmRA * T / 3600, star.DE + star.pmDE * T / 3600, Unit.HOURS, Unit.DEGREES); if ((flags & NO_PRECESSION) === 0) pos = Ecliptic.precessEquatorial(pos, time_JDE); if ((flags & NUTATION) !== 0) pos = this.ecliptic.nutateEquatorialPosition(pos, time_JDE); if ((flags & ABERRATION) !== 0) { // Low-precision formulae for the Sun's longitude and the obliquity of the // ecliptic are quite enough here, given that the greatest effect of stellar // aberration is only 20.5". const T2 = T ** 2; const e = 0.016708634 - 0.000042037 * T - 0.0000001267 * T2; const pi = to_radian(102.93735 + 1.71946 * T + 0.00046 * T2); const e0 = to_radian(OBLIQUITY_J2000 - (46.8150 * T - 0.00059 * T2 + 0.001813 * T2 * T) / 3600); if (time_JDE !== this.sunCacheTime) { const L0 = 280.46646 + 36000.76983 * T + 0.0003032 * T2; const M = 357.52911 + 35999.05029 * T - 0.0001537 * T2; const C = (1.914602 - 0.004817 * T - 0.000014 * T2) * sin_deg(M) + (0.019993 - 0.000101 * T) * sin_deg(2 * M) + 0.000289 * sin_deg(3 * M); this.sunLongitudeCache = to_radian(mod(L0 + C, 360)); } const LS = this.sunLongitudeCache; const RA = pos.rightAscension.radians; const dec = pos.declination.radians; const cosd = cos(dec); let dRA = 0; if (cosd !== 0) dRA = -StarCatalog.kappa * ((cos(RA) * cos(LS) * cos(e0) + sin(RA) * sin(LS)) - e * (cos(RA) * cos(pi) * cos(e0) + sin(RA) * sin(pi))) / cosd; const dDec = -StarCatalog.kappa * (cos(LS) * cos(e0) * (tan(e0) * cosd - sin(RA) * sin(dec)) + cos(RA) * sin(dec) * sin(LS) - e * (cos(pi) * cos(e0) * (tan(e0) * cosd - sin(RA) * sin(dec)) + cos(RA) * sin(dec) * sin(pi))); pos = new SphericalPosition(RA + dRA, dec + dDec); } this.cachedPositions[starIndex].pos = pos; this.cachedPositions[starIndex].flags = flags; this.cachedPositions[starIndex].time = time_JDE; return pos; } getEclipticPosition(starIndex, time_JDE, cacheTolerance = 0, flags = 0) { if (starIndex < 0 || starIndex >= this.stars.length) return null; flags |= StarCatalog.ECLIPTIC; if (this.cachedPositions[starIndex].pos !== null && this.cachedPositions[starIndex].flags === flags && abs(this.cachedPositions[starIndex].time - time_JDE) <= cacheTolerance) return this.cachedPositions[starIndex].pos; // Don't compute nutation twice -- it's much more efficient to apply // nutation to ecliptic coordinates. const eqPos = this.getEquatorialPosition(starIndex, time_JDE, flags & ~NUTATION); let nutationMode; if ((flags & NUTATION) !== 0) nutationMode = NMode.NUTATED; else nutationMode = NMode.J2000; let pos = this.ecliptic.equatorialToEcliptic(eqPos, time_JDE, nutationMode); pos = this.ecliptic.nutateEclipticPosition(pos, time_JDE, nutationMode); this.cachedPositions[starIndex].pos = pos; this.cachedPositions[starIndex].flags = flags; this.cachedPositions[starIndex].time = time_JDE; return pos; } // Note: cacheTolerance applies to the equatorial position of a star. Horizontal coordinates // themselves are not cached. // getHorizontalPosition(starIndex, time_JDU, observer, cacheTolerance = 0, flags = 0) { if (starIndex < 0 || starIndex >= this.stars.length) return null; flags &= ~NUTATION; const pos = this.getEquatorialPosition(starIndex, utToTdt(time_JDU), cacheTolerance, flags); return observer.equatorialToHorizontal(pos, time_JDU, flags); } } StarCatalog.greekIndices = 'Alp Bet Gam Del Eps Zet Eta The Iot Kap Lam Mu Nu Xi Omi Pi Rho Sig Tau Ups Phi Chi Psi Ome' .split(/\s+/); StarCatalog.constellationCodes = ('And Ant Aps Aql Aqr Ara Ari Aur Boo Cae Cam Cap Car Cas Cen Cep Cet Cha Cir CMa CMi Cnc Col Com ' + 'CrA CrB Crt Cru Crv CVn Cyg Del Dor Dra Equ Eri For Gem Gru Her Hor Hya Hyi Ind Lac Leo Lep Lib ' + 'LMi Lup Lyn Lyr Men Mic Mon Mus Nor Oct Oph Ori Pav Peg Per Phe Pic PsA Psc Pup Pyx Ret Scl Sco ' + 'Sct Ser Sex Sge Sgr Tau Tel TrA Tri Tuc UMa UMi Vel Vir Vol Vul') .split(/\s+/); StarCatalog.ECLIPTIC = 0x80000000; // Flag used in cache // Constant of aberration, converted to radians. StarCatalog.kappa = 20.49552 / 648000 * PI; //# sourceMappingURL=star-catalog.js.map