1 const paMacros = require('./pa-macros.js'); 2 const paTypes = require('./pa-types.js'); 3 const paUtils = require('./pa-utils.js'); 4 5 /** 6 * Calculate approximate position of the Moon. 7 */ 8 function approximatePositionOfMoon(lctHour, lctMin, lctSec, isDaylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear) { 9 var daylightSaving = (isDaylightSaving) ? 1 : 0; 10 11 var l0 = 91.9293359879052; 12 var p0 = 130.143076320618; 13 var n0 = 291.682546643194; 14 var i = 5.145396; 15 16 var gdateDay = paMacros.localCivilTimeGreenwichDay(lctHour, lctMin, lctSec, daylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear); 17 var gdateMonth = paMacros.localCivilTimeGreenwichMonth(lctHour, lctMin, lctSec, daylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear); 18 var gdateYear = paMacros.localCivilTimeGreenwichYear(lctHour, lctMin, lctSec, daylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear); 19 20 var utHours = paMacros.localCivilTimeToUniversalTime(lctHour, lctMin, lctSec, daylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear); 21 var dDays = paMacros.civilDateToJulianDate(gdateDay, gdateMonth, gdateYear) - paMacros.civilDateToJulianDate(0.0, 1, 2010) + utHours / 24; 22 var sunLongDeg = paMacros.sunLong(lctHour, lctMin, lctSec, daylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear); 23 var sunMeanAnomalyRad = paMacros.sunMeanAnomaly(lctHour, lctMin, lctSec, daylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear); 24 var lmDeg = paMacros.unwindDeg(13.1763966 * dDays + l0); 25 var mmDeg = paMacros.unwindDeg(lmDeg - 0.1114041 * dDays - p0); 26 var nDeg = paMacros.unwindDeg(n0 - (0.0529539 * dDays)); 27 var evDeg = 1.2739 * Math.sin(paUtils.degreesToRadians(2.0 * (lmDeg - sunLongDeg) - mmDeg)); 28 var aeDeg = 0.1858 * Math.sin(sunMeanAnomalyRad); 29 var a3Deg = 0.37 * Math.sin(sunMeanAnomalyRad); 30 var mmdDeg = mmDeg + evDeg - aeDeg - a3Deg; 31 var ecDeg = 6.2886 * Math.sin(paUtils.degreesToRadians(mmdDeg)); 32 var a4Deg = 0.214 * Math.sin(2.0 * paUtils.degreesToRadians(mmdDeg)); 33 var ldDeg = lmDeg + evDeg + ecDeg - aeDeg + a4Deg; 34 var vDeg = 0.6583 * Math.sin(2.0 * paUtils.degreesToRadians(ldDeg - sunLongDeg)); 35 var lddDeg = ldDeg + vDeg; 36 var ndDeg = nDeg - 0.16 * Math.sin(sunMeanAnomalyRad); 37 var y = Math.sin(paUtils.degreesToRadians(lddDeg - ndDeg)) * Math.cos(paUtils.degreesToRadians(i)); 38 var x = Math.cos(paUtils.degreesToRadians(lddDeg - ndDeg)); 39 40 var moonLongDeg = paMacros.unwindDeg(paMacros.degrees(Math.atan2(y, x)) + ndDeg); 41 var moonLatDeg = paMacros.degrees(Math.asin(Math.sin(paUtils.degreesToRadians(lddDeg - ndDeg)) * Math.sin(paUtils.degreesToRadians(i)))); 42 var moonRAHours1 = paMacros.decimalDegreesToDegreeHours(paMacros.ecRA(moonLongDeg, 0, 0, moonLatDeg, 0, 0, gdateDay, gdateMonth, gdateYear)); 43 var moonDecDeg1 = paMacros.ecDec(moonLongDeg, 0, 0, moonLatDeg, 0, 0, gdateDay, gdateMonth, gdateYear); 44 45 var moonRAHour = paMacros.decimalHoursHour(moonRAHours1); 46 var moonRAMin = paMacros.decimalHoursMinute(moonRAHours1); 47 var moonRASec = paMacros.decimalHoursSecond(moonRAHours1); 48 var moonDecDeg = paMacros.decimalDegreesDegrees(moonDecDeg1); 49 var moonDecMin = paMacros.decimalDegreesMinutes(moonDecDeg1); 50 var moonDecSec = paMacros.decimalDegreesSeconds(moonDecDeg1); 51 52 return [moonRAHour, moonRAMin, moonRASec, moonDecDeg, moonDecMin, moonDecSec]; 53 } 54 55 /** 56 * Calculate precise position of the Moon. 57 */ 58 function precisePositionOfMoon(lctHour, lctMin, lctSec, isDaylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear) { 59 var daylightSaving = (isDaylightSaving) ? 1 : 0; 60 61 var gdateDay = paMacros.localCivilTimeGreenwichDay(lctHour, lctMin, lctSec, daylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear); 62 var gdateMonth = paMacros.localCivilTimeGreenwichMonth(lctHour, lctMin, lctSec, daylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear); 63 var gdateYear = paMacros.localCivilTimeGreenwichYear(lctHour, lctMin, lctSec, daylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear); 64 65 var [moonLongDeg, moonLatDeg, moonHorPara] = paMacros.moonLongLatHP(lctHour, lctMin, lctSec, daylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear); 66 67 var nutationInLongitudeDeg = paMacros.nutatLong(gdateDay, gdateMonth, gdateYear); 68 var correctedLongDeg = moonLongDeg + nutationInLongitudeDeg; 69 var earthMoonDistanceKM = 6378.14 / Math.sin(paUtils.degreesToRadians(moonHorPara)); 70 var moonRAHours1 = paMacros.decimalDegreesToDegreeHours(paMacros.ecRA(correctedLongDeg, 0, 0, moonLatDeg, 0, 0, gdateDay, gdateMonth, gdateYear)); 71 var moonDecDeg1 = paMacros.ecDec(correctedLongDeg, 0, 0, moonLatDeg, 0, 0, gdateDay, gdateMonth, gdateYear); 72 73 var moonRAHour = paMacros.decimalHoursHour(moonRAHours1); 74 var moonRAMin = paMacros.decimalHoursMinute(moonRAHours1); 75 var moonRASec = paMacros.decimalHoursSecond(moonRAHours1); 76 var moonDecDeg = paMacros.decimalDegreesDegrees(moonDecDeg1); 77 var moonDecMin = paMacros.decimalDegreesMinutes(moonDecDeg1); 78 var moonDecSec = paMacros.decimalDegreesSeconds(moonDecDeg1); 79 var earthMoonDistKM = paUtils.round(earthMoonDistanceKM, 0); 80 var moonHorParallaxDeg = paUtils.round(moonHorPara, 6); 81 82 return [moonRAHour, moonRAMin, moonRASec, moonDecDeg, moonDecMin, moonDecSec, earthMoonDistKM, moonHorParallaxDeg]; 83 } 84 85 /** 86 * Calculate Moon phase and position angle of bright limb. 87 */ 88 function moonPhase(lctHour, lctMin, lctSec, isDaylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear, accuracyLevel) { 89 var daylightSaving = (isDaylightSaving) ? 1 : 0; 90 91 var gdateDay = paMacros.localCivilTimeGreenwichDay(lctHour, lctMin, lctSec, daylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear); 92 var gdateMonth = paMacros.localCivilTimeGreenwichMonth(lctHour, lctMin, lctSec, daylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear); 93 var gdateYear = paMacros.localCivilTimeGreenwichYear(lctHour, lctMin, lctSec, daylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear); 94 95 var sunLongDeg = paMacros.sunLong(lctHour, lctMin, lctSec, daylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear); 96 var [moonLongDeg, moonLatDeg, moonHorPara] = paMacros.moonLongLatHP(lctHour, lctMin, lctSec, daylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear); 97 var dRad = paUtils.degreesToRadians(moonLongDeg - sunLongDeg); 98 99 var moonPhase1 = (accuracyLevel == paTypes.AccuracyLevel.Precise) ? paMacros.moonPhase(lctHour, lctMin, lctSec, daylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear) : (1.0 - Math.cos(dRad)) / 2.0; 100 101 var sunRARad = paUtils.degreesToRadians(paMacros.ecRA(sunLongDeg, 0, 0, 0, 0, 0, gdateDay, gdateMonth, gdateYear)); 102 var moonRARad = paUtils.degreesToRadians(paMacros.ecRA(moonLongDeg, 0, 0, moonLatDeg, 0, 0, gdateDay, gdateMonth, gdateYear)); 103 var sunDecRad = paUtils.degreesToRadians(paMacros.ecDec(sunLongDeg, 0, 0, 0, 0, 0, gdateDay, gdateMonth, gdateYear)); 104 var moonDecRad = paUtils.degreesToRadians(paMacros.ecDec(moonLongDeg, 0, 0, moonLatDeg, 0, 0, gdateDay, gdateMonth, gdateYear)); 105 106 var y = Math.cos(sunDecRad) * Math.sin(sunRARad - moonRARad); 107 var x = Math.cos(moonDecRad) * Math.sin(sunDecRad) - Math.sin(moonDecRad) * Math.cos(sunDecRad) * Math.cos(sunRARad - moonRARad); 108 109 var chiDeg = paMacros.degrees(Math.atan2(y, x)); 110 111 var moonPhase = paUtils.round(moonPhase1, 2); 112 var paBrightLimbDeg = paUtils.round(chiDeg, 2); 113 114 return [moonPhase, paBrightLimbDeg]; 115 } 116 117 /** 118 * Calculate new moon and full moon instances. 119 */ 120 function timesOfNewMoonAndFullMoon(isDaylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear) { 121 var daylightSaving = (isDaylightSaving) ? 1 : 0; 122 123 var jdOfNewMoonDays = paMacros.newMoon(daylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear); 124 var jdOfFullMoonDays = paMacros.fullMoon(3, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear); 125 126 var gDateOfNewMoonDay = paMacros.julianDateDay(jdOfNewMoonDays); 127 var integerDay1 = Math.floor(gDateOfNewMoonDay); 128 var gDateOfNewMoonMonth = paMacros.julianDateMonth(jdOfNewMoonDays); 129 var gDateOfNewMoonYear = paMacros.julianDateYear(jdOfNewMoonDays); 130 131 var gDateOfFullMoonDay = paMacros.julianDateDay(jdOfFullMoonDays); 132 var integerDay2 = Math.floor(gDateOfFullMoonDay); 133 var gDateOfFullMoonMonth = paMacros.julianDateMonth(jdOfFullMoonDays); 134 var gDateOfFullMoonYear = paMacros.julianDateYear(jdOfFullMoonDays); 135 136 var utOfNewMoonHours = 24.0 * (gDateOfNewMoonDay - integerDay1); 137 var utOfFullMoonHours = 24.0 * (gDateOfFullMoonDay - integerDay2); 138 var lctOfNewMoonHours = paMacros.universalTimeToLocalCivilTime(utOfNewMoonHours + 0.008333, 0, 0, daylightSaving, zoneCorrectionHours, integerDay1, gDateOfNewMoonMonth, gDateOfNewMoonYear); 139 var lctOfFullMoonHours = paMacros.universalTimeToLocalCivilTime(utOfFullMoonHours + 0.008333, 0, 0, daylightSaving, zoneCorrectionHours, integerDay2, gDateOfFullMoonMonth, gDateOfFullMoonYear); 140 141 var nmLocalTimeHour = paMacros.decimalHoursHour(lctOfNewMoonHours); 142 var nmLocalTimeMin = paMacros.decimalHoursMinute(lctOfNewMoonHours); 143 var nmLocalDateDay = paMacros.universalTime_LocalCivilDay(utOfNewMoonHours, 0, 0, daylightSaving, zoneCorrectionHours, integerDay1, gDateOfNewMoonMonth, gDateOfNewMoonYear); 144 var nmLocalDateMonth = paMacros.universalTime_LocalCivilMonth(utOfNewMoonHours, 0, 0, daylightSaving, zoneCorrectionHours, integerDay1, gDateOfNewMoonMonth, gDateOfNewMoonYear); 145 var nmLocalDateYear = paMacros.universalTime_LocalCivilYear(utOfNewMoonHours, 0, 0, daylightSaving, zoneCorrectionHours, integerDay1, gDateOfNewMoonMonth, gDateOfNewMoonYear); 146 var fmLocalTimeHour = paMacros.decimalHoursHour(lctOfFullMoonHours); 147 var fmLocalTimeMin = paMacros.decimalHoursMinute(lctOfFullMoonHours); 148 var fmLocalDateDay = paMacros.universalTime_LocalCivilDay(utOfFullMoonHours, 0, 0, daylightSaving, zoneCorrectionHours, integerDay2, gDateOfFullMoonMonth, gDateOfFullMoonYear); 149 var fmLocalDateMonth = paMacros.universalTime_LocalCivilMonth(utOfFullMoonHours, 0, 0, daylightSaving, zoneCorrectionHours, integerDay2, gDateOfFullMoonMonth, gDateOfFullMoonYear); 150 var fmLocalDateYear = paMacros.universalTime_LocalCivilYear(utOfFullMoonHours, 0, 0, daylightSaving, zoneCorrectionHours, integerDay2, gDateOfFullMoonMonth, gDateOfFullMoonYear); 151 152 return [nmLocalTimeHour, nmLocalTimeMin, nmLocalDateDay, nmLocalDateMonth, nmLocalDateYear, fmLocalTimeHour, fmLocalTimeMin, fmLocalDateDay, fmLocalDateMonth, fmLocalDateYear]; 153 } 154 155 /** 156 * Calculate Moon's distance, angular diameter, and horizontal parallax. 157 */ 158 function moonDistAngDiamHorParallax(lctHour, lctMin, lctSec, isDaylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear) { 159 var daylightSaving = (isDaylightSaving) ? 1 : 0; 160 161 var moonDistance = paMacros.moonDist(lctHour, lctMin, lctSec, daylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear); 162 var moonAngularDiameter = paMacros.moonSize(lctHour, lctMin, lctSec, daylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear); 163 var moonHorizontalParallax = paMacros.moonHP(lctHour, lctMin, lctSec, daylightSaving, zoneCorrectionHours, localDateDay, localDateMonth, localDateYear); 164 165 var earthMoonDist = paUtils.round(moonDistance, 0); 166 var angDiameterDeg = paMacros.decimalDegreesDegrees(moonAngularDiameter + 0.008333); 167 var angDiameterMin = paMacros.decimalDegreesMinutes(moonAngularDiameter + 0.008333); 168 var horParallaxDeg = paMacros.decimalDegreesDegrees(moonHorizontalParallax); 169 var horParallaxMin = paMacros.decimalDegreesMinutes(moonHorizontalParallax); 170 var horParallaxSec = paMacros.decimalDegreesSeconds(moonHorizontalParallax); 171 172 return [earthMoonDist, angDiameterDeg, angDiameterMin, horParallaxDeg, horParallaxMin, horParallaxSec]; 173 } 174 175 /** 176 * Calculate date/time of local moonrise and moonset. 177 */ 178 function moonriseAndMoonset(localDateDay, localDateMonth, localDateYear, isDaylightSaving, zoneCorrectionHours, geogLongDeg, geogLatDeg) { 179 var daylightSaving = (isDaylightSaving) ? 1 : 0; 180 181 var localTimeOfMoonriseHours = paMacros.moonRiseLCT(localDateDay, localDateMonth, localDateYear, daylightSaving, zoneCorrectionHours, geogLongDeg, geogLatDeg); 182 var [moonRiseLCResult_dy1, moonRiseLCResult_mn1, moonRiseLCResult_yr1] = paMacros.moonRiseLcDMY(localDateDay, localDateMonth, localDateYear, daylightSaving, zoneCorrectionHours, geogLongDeg, geogLatDeg); 183 var localAzimuthDeg1 = paMacros.moonRiseAz(localDateDay, localDateMonth, localDateYear, daylightSaving, zoneCorrectionHours, geogLongDeg, geogLatDeg); 184 185 var localTimeOfMoonsetHours = paMacros.moonSetLCT(localDateDay, localDateMonth, localDateYear, daylightSaving, zoneCorrectionHours, geogLongDeg, geogLatDeg); 186 var [moonSetLCResult_dy1, moonSetLCResult_mn1, moonSetLCResult_yr1] = paMacros.moonSetLcDMY(localDateDay, localDateMonth, localDateYear, daylightSaving, zoneCorrectionHours, geogLongDeg, geogLatDeg); 187 var localAzimuthDeg2 = paMacros.moonSetAz(localDateDay, localDateMonth, localDateYear, daylightSaving, zoneCorrectionHours, geogLongDeg, geogLatDeg); 188 189 var mrLTHour = paMacros.decimalHoursHour(localTimeOfMoonriseHours + 0.008333); 190 var mrLTMin = paMacros.decimalHoursMinute(localTimeOfMoonriseHours + 0.008333); 191 var mrLocalDateDay = moonRiseLCResult_dy1; 192 var mrLocalDateMonth = moonRiseLCResult_mn1; 193 var mrLocalDateYear = moonRiseLCResult_yr1; 194 var mrAzimuthDeg = paUtils.round(localAzimuthDeg1, 2); 195 var msLTHour = paMacros.decimalHoursHour(localTimeOfMoonsetHours + 0.008333); 196 var msLTMin = paMacros.decimalHoursMinute(localTimeOfMoonsetHours + 0.008333); 197 var msLocalDateDay = moonSetLCResult_dy1; 198 var msLocalDateMonth = moonSetLCResult_mn1; 199 var msLocalDateYear = moonSetLCResult_yr1; 200 var msAzimuthDeg = paUtils.round(localAzimuthDeg2, 2); 201 202 return [mrLTHour, mrLTMin, mrLocalDateDay, mrLocalDateMonth, mrLocalDateYear, mrAzimuthDeg, msLTHour, msLTMin, msLocalDateDay, msLocalDateMonth, msLocalDateYear, msAzimuthDeg]; 203 } 204 205 206 module.exports = { 207 approximatePositionOfMoon, 208 precisePositionOfMoon, 209 moonPhase, 210 timesOfNewMoonAndFullMoon, 211 moonDistAngDiamHorParallax, 212 moonriseAndMoonset 213 };