better-suncalc
Version:
A tiny TypeScript library for calculating sun/moon positions and phases.
135 lines (134 loc) • 4.6 kB
JavaScript
/*
mooncalc.ts
Contains functions to calculate moon position, illumination, and rise/set times.
Depends on suncalc.ts, constants.ts, and utils.ts for shared functions and constants.
*/
import { acos, atan, cos, PI, rad, sin, tan } from "./constants";
import { altitude, astroRefraction, azimuth, declination, rightAscension, siderealTime, sunCoords, } from "./suncalc";
import { hoursLater, toDays } from "./utils";
/* ==================== Moon calculations ==================== */
/**
* Calculates moon coordinates for a given number of days since J2000.
* @param d - Days since J2000 epoch.
* @returns Object containing moon's right ascension, declination, and distance.
*/
export function moonCoords(d) {
var L = rad * (218.316 + 13.176396 * d);
var M = rad * (134.963 + 13.064993 * d);
var F = rad * (93.272 + 13.22935 * d);
var l = L + rad * 6.289 * sin(M);
var b = rad * 5.128 * sin(F);
var dt = 385001 - 20905 * cos(M);
return {
ra: rightAscension(l, b),
dec: declination(l, b),
dist: dt,
};
}
/**
* Calculates moon position for provided date and location.
* @param date - Date/time of observation.
* @param lat - Observer's latitude in degrees.
* @param lng - Observer's longitude in degrees.
* @returns Object containing moon position data.
*/
export function getMoonPosition(date, lat, lng) {
var lw = rad * -lng;
var phi = rad * lat;
var d = toDays(date);
var c = moonCoords(d);
var H = siderealTime(d, lw) - c.ra;
var h = altitude(H, phi, c.dec);
var pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H));
h += astroRefraction(h);
return {
azimuth: azimuth(H, phi, c.dec),
altitude: h,
distance: c.dist,
parallacticAngle: pa,
};
}
/**
* Calculates moon illumination parameters.
* @param date - Date/time of observation.
* @returns Object containing illumination data.
*/
export function getMoonIllumination(date) {
var d = toDays(date);
var s = sunCoords(d);
var m = moonCoords(d);
var sdist = 149598000;
var phi = acos(sin(s.dec) * sin(m.dec) + cos(s.dec) * cos(m.dec) * cos(s.ra - m.ra));
var inc = atan(sdist * sin(phi), m.dist - sdist * cos(phi));
var angle = atan(cos(s.dec) * sin(s.ra - m.ra), sin(s.dec) * cos(m.dec) - cos(s.dec) * sin(m.dec) * cos(s.ra - m.ra));
return {
fraction: (1 + cos(inc)) / 2,
phase: 0.5 + (0.5 * inc * (angle < 0 ? -1 : 1)) / PI,
angle: angle,
};
}
/**
* Calculates moon rise and set times for given date and location.
* @param date - Date of observation.
* @param lat - Observer's latitude in degrees.
* @param lng - Observer's longitude in degrees.
* @param inUTC - Whether to use UTC time.
* @returns Object containing moon times data.
*/
export function getMoonTimes(date, lat, lng, inUTC) {
var t = new Date(date);
if (inUTC)
t.setUTCHours(0, 0, 0, 0);
else
t.setHours(0, 0, 0, 0);
var hc = 0.133 * rad;
var h0 = getMoonPosition(t, lat, lng).altitude - hc;
var rise, set;
var ye = 0;
// Iterate through 2-hour increments to approximate sunrise/sunset.
for (var i = 1; i <= 24; i += 2) {
var h1 = getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc;
var h2 = getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc;
var a = (h0 + h2) / 2 - h1;
var b = (h2 - h0) / 2;
var xe = -b / (2 * a);
ye = (a * xe + b) * xe + h1;
var d = b * b - 4 * a * h1;
var roots = 0;
var x1 = 0, x2 = 0;
if (d >= 0) {
var dx = Math.sqrt(d) / (2 * Math.abs(a));
x1 = xe - dx;
x2 = xe + dx;
if (Math.abs(x1) <= 1)
roots++;
if (Math.abs(x2) <= 1)
roots++;
if (x1 < -1)
x1 = x2;
}
if (roots === 1) {
if (h0 < 0)
rise = i + x1;
else
set = i + x1;
}
else if (roots === 2) {
rise = i + (ye < 0 ? x2 : x1);
set = i + (ye < 0 ? x1 : x2);
}
if (rise !== undefined && set !== undefined)
break;
h0 = h2;
}
var result = {};
if (rise !== undefined)
result.rise = hoursLater(t, rise);
if (set !== undefined)
result.set = hoursLater(t, set);
if (rise === undefined && set === undefined) {
result[ye > 0 ? "alwaysUp" : "alwaysDown"] = true;
}
return result;
}
//# sourceMappingURL=mooncalc.js.map