mirror of
https://github.com/acamarata/pray-calc.git
synced 2026-07-03 04:10:39 +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)
|
- Moved timezone to main args and changed default behavior (major)
|
||||||
- Updated test cases and readme to reflect new usage (minor)
|
- 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;
|
* Calculates detailed moon visibility information.
|
||||||
const rad = PI / 180;
|
*
|
||||||
const e = rad * 23.4397; // obliquity of the Earth
|
* @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) {
|
// Calculate visibility considering all factors
|
||||||
return (date - new Date(2000, 0, 1)) / 86400000;
|
const visibility = getMoonVisibility(phase, position, illumination, elevation, temp, pressure, humidity, clouds);
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
fraction: (1 + Math.cos(inc)) / 2,
|
phase,
|
||||||
phase: 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math.PI,
|
position,
|
||||||
angle: angle
|
illumination,
|
||||||
|
visibility
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = { getMoon };
|
||||||
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",
|
"name": "praycalc",
|
||||||
"version": "1.2.2",
|
"version": "1.3.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "praycalc",
|
"name": "praycalc",
|
||||||
"version": "1.2.2",
|
"version": "1.3.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nrel-spa": "^1.2.2"
|
"nrel-spa": "^1.2.2",
|
||||||
|
"suncalc": "^1.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/nrel-spa": {
|
"node_modules/nrel-spa": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/nrel-spa/-/nrel-spa-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/nrel-spa/-/nrel-spa-1.2.2.tgz",
|
||||||
"integrity": "sha512-2mycHd7PP0l+pPjPvrT6vr+PRHufCFOxsPcpaIOQ9GwhhfzgyTvSsLKPsqC6ZENNU65yq4PetT5XlWj3CoLjiQ=="
|
"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",
|
"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)",
|
"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",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
"author": "USF",
|
"author": "USF",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"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