mirror of
https://github.com/acamarata/pray-calc.git
synced 2026-06-30 19:04:26 +00:00
added getMoon functions
This commit is contained in:
parent
aacc8ff81b
commit
c1814c2783
9 changed files with 172 additions and 63 deletions
|
|
@ -14,3 +14,7 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
- Moved timezone to main args and changed default behavior (major)
|
||||
- Updated test cases and readme to reflect new usage (minor)
|
||||
|
||||
## [1.3.0] - 2013-11-13
|
||||
|
||||
- Major updates to getMoon with own functions
|
||||
|
|
|
|||
86
getMoon.js
86
getMoon.js
|
|
@ -1,65 +1,35 @@
|
|||
const { getEarthSunDistance } = require('./getEarthSunDistance');
|
||||
const { getMoonPhase } = require('./getMoonPhase');
|
||||
const { getMoonPosition } = require('./getMoonPosition');
|
||||
const { getMoonIllumination } = require('./getMoonIllumination');
|
||||
const { getMoonVisibility } = require('./getMoonVisibility');
|
||||
|
||||
function getMoon(date, accurate = true) {
|
||||
const PI = Math.PI;
|
||||
const rad = PI / 180;
|
||||
const e = rad * 23.4397; // obliquity of the Earth
|
||||
/**
|
||||
* Calculates detailed moon visibility information.
|
||||
*
|
||||
* @param {Date} date - The date for which to calculate moon data.
|
||||
* @param {number} [latitude=0] - Observer's latitude in decimal degrees.
|
||||
* @param {number} [longitude=0] - Observer's longitude in decimal degrees.
|
||||
* @param {number} [elevation=50] - Observer's elevation in meters above sea level. Default is 50 meters.
|
||||
* @param {number} [temp=15] - Ambient temperature in degrees Celsius. Default is 15°C.
|
||||
* @param {number} [pressure=1013.25] - Atmospheric pressure in hPa. Default is 1013.25 hPa (average sea level pressure).
|
||||
* @param {number} [humidity=50] - Humidity in percentage. Default is 50%.
|
||||
* @param {number} [clouds=0] - Cloudiness in percentage. Default is 0% (clear sky).
|
||||
* @returns {Object} An object containing moon details: phase, position, illumination, and visibility.
|
||||
*/
|
||||
function getMoon(date, latitude = 0, longitude = 0, elevation = 50, temp = 15, pressure = 1013.25, humidity = 50, clouds = 0) {
|
||||
const phase = getMoonPhase(date);
|
||||
const position = getMoonPosition(date, latitude, longitude);
|
||||
const illumination = getMoonIllumination(date);
|
||||
|
||||
function toDays(date) {
|
||||
return (date - new Date(2000, 0, 1)) / 86400000;
|
||||
}
|
||||
|
||||
function rightAscension(l, b) {
|
||||
return Math.atan2(Math.sin(l) * Math.cos(e) - Math.tan(b) * Math.sin(e), Math.cos(l));
|
||||
}
|
||||
|
||||
function declination(l, b) {
|
||||
return Math.asin(Math.sin(b) * Math.cos(e) + Math.cos(b) * Math.sin(e) * Math.sin(l));
|
||||
}
|
||||
|
||||
function sunCoords(d) {
|
||||
const M = rad * (357.5291 + 0.98560028 * d);
|
||||
const L = rad * (280.1470 + 360.9856235 * d) + (1.9148 - 0.004817 * d / 36525) * Math.sin(M) + 0.019993 - 0.000101 * d / 36525 * Math.cos(M);
|
||||
return {
|
||||
dec: declination(L, 0),
|
||||
ra: rightAscension(L, 0)
|
||||
};
|
||||
}
|
||||
|
||||
function moonCoords(d) {
|
||||
const L = rad * (218.316 + 13.176396 * d);
|
||||
const M = rad * (134.963 + 13.064993 * d);
|
||||
const F = rad * (93.272 + 13.229350 * d);
|
||||
|
||||
const l = L + rad * 6.289 * Math.sin(M); // Moon's mean longitude
|
||||
const b = rad * 5.128 * Math.sin(F); // Moon's mean latitude
|
||||
const dt = 385001 - 20905 * Math.cos(M); // Distance to the moon in km
|
||||
|
||||
return {
|
||||
ra: rightAscension(l, b),
|
||||
dec: declination(l, b),
|
||||
dist: dt
|
||||
};
|
||||
}
|
||||
|
||||
const d = toDays(date);
|
||||
const s = sunCoords(d);
|
||||
const m = moonCoords(d);
|
||||
|
||||
// distance from Earth to Sun in km
|
||||
const sdist = accurate ? getEarthSunDistance(date) : 149598000;
|
||||
|
||||
const phi = Math.acos(Math.sin(s.dec) * Math.sin(m.dec) + Math.cos(s.dec) * Math.cos(m.dec) * Math.cos(s.ra - m.ra));
|
||||
const inc = Math.atan2(sdist * Math.sin(phi), m.dist - sdist * Math.cos(phi));
|
||||
const angle = Math.atan2(Math.cos(s.dec) * Math.sin(s.ra - m.ra), Math.sin(s.dec) * Math.cos(m.dec) - Math.cos(s.dec) * Math.sin(m.dec) * Math.cos(s.ra - m.ra));
|
||||
// Calculate visibility considering all factors
|
||||
const visibility = getMoonVisibility(phase, position, illumination, elevation, temp, pressure, humidity, clouds);
|
||||
|
||||
return {
|
||||
fraction: (1 + Math.cos(inc)) / 2,
|
||||
phase: 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math.PI,
|
||||
angle: angle
|
||||
phase,
|
||||
position,
|
||||
illumination,
|
||||
visibility
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getMoon
|
||||
};
|
||||
module.exports = { getMoon };
|
||||
|
|
|
|||
19
getMoonIllumination.js
Normal file
19
getMoonIllumination.js
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// Import the SunCalc library
|
||||
const suncalc = require('suncalc');
|
||||
|
||||
/**
|
||||
* Calculates the moon's illumination for a given phase.
|
||||
* @param {number} phase - The phase of the moon, from 0 (new moon) to 1 (full moon).
|
||||
* @returns {Object} The moon's illumination details.
|
||||
*/
|
||||
function getMoonIllumination(date) {
|
||||
const illuminationDetails = suncalc.getMoonIllumination(date);
|
||||
|
||||
return {
|
||||
fraction: illuminationDetails.fraction, // Illuminated fraction of the moon; 0 = new moon, 1 = full moon
|
||||
phase: illuminationDetails.phase, // Moon phase (0 to 1)
|
||||
angle: illuminationDetails.angle // Angle in radians of the moon's bright limb
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = { getMoonIllumination };
|
||||
23
getMoonPhase.js
Normal file
23
getMoonPhase.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* Calculates the current phase of the moon as a fraction.
|
||||
* @param {Date} date - The date for which to calculate the moon phase.
|
||||
* @returns {number} The moon phase as a fraction from 0 (new moon) to just under 1 (end of lunar cycle).
|
||||
*/
|
||||
function getMoonPhase(date) {
|
||||
const synodicMonth = 29.530588861; // Average length of a synodic month in days
|
||||
// Most recent known new moon: November 13, 2023, 03:27 AM
|
||||
const knownNewMoon = new Date(Date.UTC(2023, 10, 13, 3, 27, 0));
|
||||
|
||||
// Convert both dates to the number of milliseconds since Unix Epoch and find the difference
|
||||
const diffInMilliseconds = date - knownNewMoon;
|
||||
|
||||
// Convert the difference to days
|
||||
const diffInDays = diffInMilliseconds / 1000 / 60 / 60 / 24;
|
||||
|
||||
// Calculate the phase as a fraction of the synodic month
|
||||
const phase = (diffInDays % synodicMonth) / synodicMonth;
|
||||
|
||||
return phase;
|
||||
}
|
||||
|
||||
module.exports = { getMoonPhase };
|
||||
26
getMoonPosition.js
Normal file
26
getMoonPosition.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Import the SunCalc library
|
||||
const suncalc = require('suncalc');
|
||||
|
||||
/**
|
||||
* Calculates detailed moon position information.
|
||||
* @param {Date} date - The date and time for which to calculate the position.
|
||||
* @param {number} latitude - Observer's latitude in decimal degrees.
|
||||
* @param {number} longitude - Observer's longitude in decimal degrees.
|
||||
* @returns {Object} The moon's position (azimuth, altitude), distance, and parallactic angle.
|
||||
*/
|
||||
function getMoonPosition(date, latitude, longitude) {
|
||||
const moonPosition = suncalc.getMoonPosition(date, latitude, longitude);
|
||||
|
||||
// Convert azimuth and altitude from radians to degrees
|
||||
const azimuth = moonPosition.azimuth * 180 / Math.PI;
|
||||
const altitude = moonPosition.altitude * 180 / Math.PI;
|
||||
|
||||
return {
|
||||
azimuth,
|
||||
altitude,
|
||||
distance: moonPosition.distance, // distance to moon in kilometers
|
||||
parallacticAngle: moonPosition.parallacticAngle // parallactic angle in radians
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = { getMoonPosition };
|
||||
39
getMoonVisibility.js
Normal file
39
getMoonVisibility.js
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* Calculates detailed moon visibility information.
|
||||
*
|
||||
* @param {number} phase - The phase of the moon, from 0 (new moon) to 1 (next full moon).
|
||||
* @param {Object} position - { azimuth, altitude, distance (km), parallacticAngle (radians) }
|
||||
* @param {Object} illumination - { fraction, phase, angle }
|
||||
* @param {number} [elevation=50] - Observer's elevation in meters above sea level. Default is 50 meters.
|
||||
* @param {number} [temp=15] - Ambient temperature in degrees Celsius. Default is 15°C.
|
||||
* @param {number} [pressure=1013.25] - Atmospheric pressure in hPa. Default is 1013.25 hPa (average sea level pressure).
|
||||
* @param {number} [humidity=50] - Humidity in percentage. Default is 50%.
|
||||
* @param {number} [clouds=0] - Cloudiness in percentage. Default is 0% (clear sky).
|
||||
* @returns {Object} An object containing moon details: phase, position, illumination, and visibility.
|
||||
*/
|
||||
|
||||
function getMoonVisibility(phase, position, illumination, elevation = 50, temp = 15, pressure = 1013.25, humidity = 50, clouds = 0) {
|
||||
|
||||
/** Placeholder Simplified Algorithm...
|
||||
* This is a very simplified algorithm that is not intended to be precise or accurate.
|
||||
* It is loosely based on average observations from astronomy journals and other sources.
|
||||
* Using a window of earliest general visibility until near definite visibility is reached.
|
||||
*/
|
||||
|
||||
const sMonth = 29.530588861;
|
||||
const phaseHour = 1 / 24 / sMonth; // ~ 0.001410966333
|
||||
const startVis = phaseHour * 15; // ~ 0.02116449584
|
||||
const endofVis = phaseHour * 30; // ~ 0.04232899168
|
||||
const visWindow = endofVis - startVis;
|
||||
|
||||
let visibility = 0;
|
||||
if (phase > endofVis) {
|
||||
visibility = 1;
|
||||
} else if (phase > startVis) {
|
||||
visibility = (phase - startVis) / visWindow;
|
||||
}
|
||||
|
||||
return visibility;
|
||||
}
|
||||
|
||||
module.exports = { getMoonVisibility };
|
||||
12
package-lock.json
generated
12
package-lock.json
generated
|
|
@ -1,21 +1,27 @@
|
|||
{
|
||||
"name": "praycalc",
|
||||
"version": "1.2.2",
|
||||
"version": "1.3.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "praycalc",
|
||||
"version": "1.2.2",
|
||||
"version": "1.3.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"nrel-spa": "^1.2.2"
|
||||
"nrel-spa": "^1.2.2",
|
||||
"suncalc": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nrel-spa": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/nrel-spa/-/nrel-spa-1.2.2.tgz",
|
||||
"integrity": "sha512-2mycHd7PP0l+pPjPvrT6vr+PRHufCFOxsPcpaIOQ9GwhhfzgyTvSsLKPsqC6ZENNU65yq4PetT5XlWj3CoLjiQ=="
|
||||
},
|
||||
"node_modules/suncalc": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/suncalc/-/suncalc-1.9.0.tgz",
|
||||
"integrity": "sha512-vMJ8Byp1uIPoj+wb9c1AdK4jpkSKVAywgHX0lqY7zt6+EWRRC3Z+0Ucfjy/0yxTVO1hwwchZe4uoFNqrIC24+A=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "praycalc",
|
||||
"version": "1.2.3",
|
||||
"version": "1.3.0",
|
||||
"description": "Prayer times calculator using nrel-spa and custom formula for Fajr and Isha angles (as well as traditional static angle methods in the All function)",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
"author": "USF",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"nrel-spa": "^1.2.2"
|
||||
"nrel-spa": "^1.2.2",
|
||||
"suncalc": "^1.9.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
21
test-moon.js
Normal file
21
test-moon.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
const { getMoon } = require('./index');
|
||||
|
||||
const date = new Date();
|
||||
|
||||
/* NYC - minimum params
|
||||
const city = "New York"
|
||||
const lat = 40.7128;
|
||||
const lng = -74.006;
|
||||
*/
|
||||
|
||||
// Jakarta - all params
|
||||
const city = "Jakarta"
|
||||
const lat = -6.2088
|
||||
const lng = 106.8456
|
||||
|
||||
// Get results
|
||||
const get = getMoon(date, lat, lng);
|
||||
|
||||
// Print results
|
||||
console.log(`\nTest: ${city} with current Date():\n`)
|
||||
console.log("getMoon =", get, "\n");
|
||||
Loading…
Reference in a new issue