1 const paMacros = require('./pa-macros.js'); 2 const paTypes = require('./pa-types.js'); 3 const paUtils = require('./pa-utils.js'); 4 5 /** 6 * Convert an Angle (degrees, minutes, and seconds) to Decimal Degrees 7 */ 8 function angleToDecimalDegrees(degrees, minutes, seconds) { 9 var a = Math.abs(seconds) / 60; 10 var b = (Math.abs(minutes) + a) / 60; 11 var c = Math.abs(degrees) + b; 12 var d = (degrees < 0 || minutes < 0 || seconds < 0) ? -c : c; 13 14 return d; 15 } 16 17 /** 18 * Convert Decimal Degrees to an Angle (degrees, minutes, and seconds) 19 */ 20 function decimalDegreesToAngle(decimalDegrees) { 21 var unsignedDecimal = Math.abs(decimalDegrees); 22 var totalSeconds = unsignedDecimal * 3600; 23 var seconds2DP = paUtils.round(totalSeconds % 60, 2); 24 var correctedSeconds = (seconds2DP == 60) ? 0 : seconds2DP; 25 var correctedRemainder = (seconds2DP == 60) ? totalSeconds + 60 : totalSeconds; 26 var minutes = Math.floor(correctedRemainder / 60) % 60; 27 var unsignedDegrees = Math.floor(correctedRemainder / 3600); 28 var signedDegrees = (decimalDegrees < 0) ? -1 * unsignedDegrees : unsignedDegrees; 29 30 return [signedDegrees, minutes, Math.floor(correctedSeconds)]; 31 } 32 33 /** 34 * Convert Right Ascension to Hour Angle 35 */ 36 function rightAscensionToHourAngle(raHours, raMinutes, raSeconds, lctHours, lctMinutes, lctSeconds, isDaylightSavings, zoneCorrection, localDay, localMonth, localYear, geographicalLongitude) { 37 var daylightSaving = (isDaylightSavings) ? 1 : 0; 38 39 var hourAngle = paMacros.rightAscensionToHourAngle(raHours, raMinutes, raSeconds, lctHours, lctMinutes, lctSeconds, daylightSaving, zoneCorrection, localDay, localMonth, localYear, geographicalLongitude); 40 41 var hourAngleHours = paMacros.decimalHoursHour(hourAngle); 42 var hourAngleMinutes = paMacros.decimalHoursMinute(hourAngle); 43 var hourAngleSeconds = paMacros.decimalHoursSecond(hourAngle); 44 45 return [hourAngleHours, hourAngleMinutes, hourAngleSeconds]; 46 } 47 48 /** 49 * Convert Hour Angle to Right Ascension 50 */ 51 function hourAngleToRightAscension(hourAngleHours, hourAngleMinutes, hourAngleSeconds, lctHours, lctMinutes, lctSeconds, isDaylightSaving, zoneCorrection, localDay, localMonth, localYear, geographicalLongitude) { 52 var daylightSaving = (isDaylightSaving) ? 1 : 0; 53 54 var rightAscension = paMacros.hourAngleToRightAscension(hourAngleHours, hourAngleMinutes, hourAngleSeconds, lctHours, lctMinutes, lctSeconds, daylightSaving, zoneCorrection, localDay, localMonth, localYear, geographicalLongitude); 55 56 var rightAscensionHours = paMacros.decimalHoursHour(rightAscension); 57 var rightAscensionMinutes = paMacros.decimalHoursMinute(rightAscension); 58 var rightAscensionSeconds = paMacros.decimalHoursSecond(rightAscension); 59 60 return [rightAscensionHours, rightAscensionMinutes, rightAscensionSeconds]; 61 } 62 63 /** 64 * Convert Equatorial Coordinates to Horizon Coordinates 65 */ 66 function equatorialCoordinatesToHorizonCoordinates(hourAngleHours, hourAngleMinutes, hourAngleSeconds, declinationDegrees, declinationMinutes, declinationSeconds, geographicalLatitude) { 67 var azimuthInDecimalDegrees = paMacros.equatorialCoordinatesToAzimuth(hourAngleHours, hourAngleMinutes, hourAngleSeconds, declinationDegrees, declinationMinutes, declinationSeconds, geographicalLatitude); 68 69 var altitudeInDecimalDegrees = paMacros.equatorialCoordinatesToAltitude(hourAngleHours, hourAngleMinutes, hourAngleSeconds, declinationDegrees, declinationMinutes, declinationSeconds, geographicalLatitude); 70 71 var azimuthDegrees = paMacros.decimalDegreesDegrees(azimuthInDecimalDegrees); 72 var azimuthMinutes = paMacros.decimalDegreesMinutes(azimuthInDecimalDegrees); 73 var azimuthSeconds = paMacros.decimalDegreesSeconds(azimuthInDecimalDegrees); 74 75 var altitudeDegrees = paMacros.decimalDegreesDegrees(altitudeInDecimalDegrees); 76 var altitudeMinutes = paMacros.decimalDegreesMinutes(altitudeInDecimalDegrees); 77 var altitudeSeconds = paMacros.decimalDegreesSeconds(altitudeInDecimalDegrees); 78 79 return [azimuthDegrees, azimuthMinutes, azimuthSeconds, altitudeDegrees, altitudeMinutes, altitudeSeconds]; 80 } 81 82 /** 83 * Convert Horizon Coordinates to Equatorial Coordinates 84 */ 85 function horizonCoordinatesToEquatorialCoordinates(azimuthDegrees, azimuthMinutes, azimuthSeconds, altitudeDegrees, altitudeMinutes, altitudeSeconds, geographicalLatitude) { 86 var hourAngleInDecimalDegrees = paMacros.horizonCoordinatesToHourAngle(azimuthDegrees, azimuthMinutes, azimuthSeconds, altitudeDegrees, altitudeMinutes, altitudeSeconds, geographicalLatitude); 87 88 var declinationInDecimalDegrees = paMacros.horizonCoordinatesToDeclination(azimuthDegrees, azimuthMinutes, azimuthSeconds, altitudeDegrees, altitudeMinutes, altitudeSeconds, geographicalLatitude); 89 90 var hourAngleHours = paMacros.decimalHoursHour(hourAngleInDecimalDegrees); 91 var hourAngleMinutes = paMacros.decimalHoursMinute(hourAngleInDecimalDegrees); 92 var hourAngleSeconds = paMacros.decimalHoursSecond(hourAngleInDecimalDegrees); 93 94 var declinationDegrees = paMacros.decimalDegreesDegrees(declinationInDecimalDegrees); 95 var declinationMinutes = paMacros.decimalDegreesMinutes(declinationInDecimalDegrees); 96 var declinationSeconds = paMacros.decimalDegreesSeconds(declinationInDecimalDegrees); 97 98 return [hourAngleHours, hourAngleMinutes, hourAngleSeconds, declinationDegrees, declinationMinutes, declinationSeconds]; 99 } 100 101 /** 102 * Calculate Mean Obliquity of the Ecliptic for a Greenwich Date 103 */ 104 function meanObliquityOfTheEcliptic(greenwichDay, greenwichMonth, greenwichYear) { 105 var jd = paMacros.civilDateToJulianDate(greenwichDay, greenwichMonth, greenwichYear); 106 var mjd = jd - 2451545; 107 var t = mjd / 36525; 108 var de1 = t * (46.815 + t * (0.0006 - (t * 0.00181))); 109 var de2 = de1 / 3600; 110 111 return 23.439292 - de2; 112 } 113 114 /** 115 * Convert Ecliptic Coordinates to Equatorial Coordinates 116 */ 117 function eclipticCoordinateToEquatorialCoordinate(eclipticLongitudeDegrees, eclipticLongitudeMinutes, eclipticLongitudeSeconds, eclipticLatitudeDegrees, eclipticLatitudeMinutes, eclipticLatitudeSeconds, greenwichDay, greenwichMonth, greenwichYear) { 118 var eclonDeg = paMacros.degreesMinutesSecondsToDecimalDegrees(eclipticLongitudeDegrees, eclipticLongitudeMinutes, eclipticLongitudeSeconds); 119 var eclatDeg = paMacros.degreesMinutesSecondsToDecimalDegrees(eclipticLatitudeDegrees, eclipticLatitudeMinutes, eclipticLatitudeSeconds); 120 var eclonRad = paUtils.degreesToRadians(eclonDeg); 121 var eclatRad = paUtils.degreesToRadians(eclatDeg); 122 var obliqDeg = paMacros.obliq(greenwichDay, greenwichMonth, greenwichYear); 123 var obliqRad = paUtils.degreesToRadians(obliqDeg); 124 var sinDec = Math.sin(eclatRad) * Math.cos(obliqRad) + Math.cos(eclatRad) * Math.sin(obliqRad) * Math.sin(eclonRad); 125 var decRad = Math.asin(sinDec); 126 var decDeg = paMacros.degrees(decRad); 127 var y = Math.sin(eclonRad) * Math.cos(obliqRad) - Math.tan(eclatRad) * Math.sin(obliqRad); 128 var x = Math.cos(eclonRad); 129 var raRad = Math.atan2(y, x); 130 var raDeg1 = paMacros.degrees(raRad); 131 var raDeg2 = raDeg1 - 360 * Math.floor(raDeg1 / 360); 132 var raHours = paMacros.decimalDegreesToDegreeHours(raDeg2); 133 134 var outRAHours = paMacros.decimalHoursHour(raHours); 135 var outRAMinutes = paMacros.decimalHoursMinute(raHours); 136 var outRASeconds = paMacros.decimalHoursSecond(raHours); 137 var outDecDegrees = paMacros.decimalDegreesDegrees(decDeg); 138 var outDecMinutes = paMacros.decimalDegreesMinutes(decDeg); 139 var outDecSeconds = paMacros.decimalDegreesSeconds(decDeg); 140 141 return [outRAHours, outRAMinutes, outRASeconds, outDecDegrees, outDecMinutes, outDecSeconds]; 142 } 143 144 /** 145 * Convert Equatorial Coordinates to Ecliptic Coordinates 146 */ 147 function equatorialCoordinateToEclipticCoordinate(raHours, raMinutes, raSeconds, decDegrees, decMinutes, decSeconds, gwDay, gwMonth, gwYear) { 148 var raDeg = paMacros.degreeHoursToDecimalDegrees(paMacros.HMStoDH(raHours, raMinutes, raSeconds)); 149 var decDeg = paMacros.degreesMinutesSecondsToDecimalDegrees(decDegrees, decMinutes, decSeconds); 150 var raRad = paUtils.degreesToRadians(raDeg); 151 var decRad = paUtils.degreesToRadians(decDeg); 152 var obliqDeg = paMacros.obliq(gwDay, gwMonth, gwYear); 153 var obliqRad = paUtils.degreesToRadians(obliqDeg); 154 var sinEclLat = Math.sin(decRad) * Math.cos(obliqRad) - Math.cos(decRad) * Math.sin(obliqRad) * Math.sin(raRad); 155 var eclLatRad = Math.asin(sinEclLat); 156 var eclLatDeg = paMacros.degrees(eclLatRad); 157 var y = Math.sin(raRad) * Math.cos(obliqRad) + Math.tan(decRad) * Math.sin(obliqRad); 158 var x = Math.cos(raRad); 159 var eclLongRad = Math.atan2(y, x); 160 var eclLongDeg1 = paMacros.degrees(eclLongRad); 161 var eclLongDeg2 = eclLongDeg1 - 360 * Math.floor(eclLongDeg1 / 360); 162 163 var outEclLongDeg = paMacros.decimalDegreesDegrees(eclLongDeg2); 164 var outEclLongMin = paMacros.decimalDegreesMinutes(eclLongDeg2); 165 var outEclLongSec = paMacros.decimalDegreesSeconds(eclLongDeg2); 166 var outEclLatDeg = paMacros.decimalDegreesDegrees(eclLatDeg); 167 var outEclLatMin = paMacros.decimalDegreesMinutes(eclLatDeg); 168 var outEclLatSec = paMacros.decimalDegreesSeconds(eclLatDeg); 169 170 return [outEclLongDeg, outEclLongMin, outEclLongSec, outEclLatDeg, outEclLatMin, outEclLatSec]; 171 } 172 173 /** 174 * 175 * Convert Equatorial Coordinates to Galactic Coordinates 176 */ 177 function equatorialCoordinateToGalacticCoordinate(raHours, raMinutes, raSeconds, decDegrees, decMinutes, decSeconds) { 178 var raDeg = paMacros.degreeHoursToDecimalDegrees(paMacros.HMStoDH(raHours, raMinutes, raSeconds)); 179 var decDeg = paMacros.degreesMinutesSecondsToDecimalDegrees(decDegrees, decMinutes, decSeconds); 180 var raRad = paUtils.degreesToRadians(raDeg); 181 var decRad = paUtils.degreesToRadians(decDeg); 182 var sinB = Math.cos(decRad) * Math.cos(paUtils.degreesToRadians(27.4)) * Math.cos(raRad - paUtils.degreesToRadians(192.25)) + Math.sin(decRad) * Math.sin(paUtils.degreesToRadians(27.4)); 183 var bRadians = Math.asin(sinB); 184 var bDeg = paMacros.degrees(bRadians); 185 var y = Math.sin(decRad) - sinB * Math.sin(paUtils.degreesToRadians(27.4)); 186 var x = Math.cos(decRad) * Math.sin(raRad - paUtils.degreesToRadians(192.25)) * Math.cos(paUtils.degreesToRadians(27.4)); 187 var longDeg1 = paMacros.degrees(Math.atan2(y, x)) + 33; 188 var longDeg2 = longDeg1 - 360 * Math.floor(longDeg1 / 360); 189 190 var galLongDeg = paMacros.decimalDegreesDegrees(longDeg2); 191 var galLongMin = paMacros.decimalDegreesMinutes(longDeg2); 192 var galLongSec = paMacros.decimalDegreesSeconds(longDeg2); 193 var galLatDeg = paMacros.decimalDegreesDegrees(bDeg); 194 var galLatMin = paMacros.decimalDegreesMinutes(bDeg); 195 var galLatSec = paMacros.decimalDegreesSeconds(bDeg); 196 197 return [galLongDeg, galLongMin, galLongSec, galLatDeg, galLatMin, galLatSec]; 198 } 199 200 /** 201 * Convert Galactic Coordinates to Equatorial Coordinates 202 */ 203 function galacticCoordinateToEquatorialCoordinate(galLongDeg, galLongMin, galLongSec, galLatDeg, galLatMin, galLatSec) { 204 var glongDeg = paMacros.degreesMinutesSecondsToDecimalDegrees(galLongDeg, galLongMin, galLongSec); 205 var glatDeg = paMacros.degreesMinutesSecondsToDecimalDegrees(galLatDeg, galLatMin, galLatSec); 206 var glongRad = paUtils.degreesToRadians(glongDeg); 207 var glatRad = paUtils.degreesToRadians(glatDeg); 208 var sinDec = Math.cos(glatRad) * Math.cos(paUtils.degreesToRadians(27.4)) * Math.sin(glongRad - paUtils.degreesToRadians(33.0)) + Math.sin(glatRad) * Math.sin(paUtils.degreesToRadians(27.4)); 209 var decRadians = Math.asin(sinDec); 210 var decDeg = paMacros.degrees(decRadians); 211 var y = Math.cos(glatRad) * Math.cos(glongRad - paUtils.degreesToRadians(33.0)); 212 var x = Math.sin(glatRad) * Math.cos(paUtils.degreesToRadians(27.4)) - Math.cos(glatRad) * Math.sin(paUtils.degreesToRadians(27.4)) * Math.sin(glongRad - paUtils.degreesToRadians(33.0)); 213 214 var raDeg1 = paMacros.degrees(Math.atan2(y, x)) + 192.25; 215 var raDeg2 = raDeg1 - 360 * Math.floor(raDeg1 / 360); 216 var raHours1 = paMacros.decimalDegreesToDegreeHours(raDeg2); 217 218 var raHours = paMacros.decimalHoursHour(raHours1); 219 var raMinutes = paMacros.decimalHoursMinute(raHours1); 220 var raSeconds = paMacros.decimalHoursSecond(raHours1); 221 var decDegrees = paMacros.decimalDegreesDegrees(decDeg); 222 var decMinutes = paMacros.decimalDegreesMinutes(decDeg); 223 var decSeconds = paMacros.decimalDegreesSeconds(decDeg); 224 225 return [raHours, raMinutes, raSeconds, decDegrees, decMinutes, decSeconds]; 226 } 227 228 /** 229 * Calculate the angle between two celestial objects 230 */ 231 function angleBetweenTwoObjects(raLong1HourDeg, raLong1Min, raLong1Sec, decLat1Deg, decLat1Min, decLat1Sec, raLong2HourDeg, raLong2Min, raLong2Sec, decLat2Deg, decLat2Min, decLat2Sec, hourOrDegree) { 232 var raLong1Decimal = (hourOrDegree == paTypes.AngleMeasure.Hours) ? paMacros.HMStoDH(raLong1HourDeg, raLong1Min, raLong1Sec) : paMacros.degreesMinutesSecondsToDecimalDegrees(raLong1HourDeg, raLong1Min, raLong1Sec); 233 var raLong1Deg = (hourOrDegree == paTypes.AngleMeasure.Hours) ? paMacros.degreeHoursToDecimalDegrees(raLong1Decimal) : raLong1Decimal; 234 235 var raLong1Rad = paUtils.degreesToRadians(raLong1Deg); 236 var decLat1Deg1 = paMacros.degreesMinutesSecondsToDecimalDegrees(decLat1Deg, decLat1Min, decLat1Sec); 237 var decLat1Rad = paUtils.degreesToRadians(decLat1Deg1); 238 239 var raLong2Decimal = (hourOrDegree == paTypes.AngleMeasure.Hours) ? paMacros.HMStoDH(raLong2HourDeg, raLong2Min, raLong2Sec) : paMacros.degreesMinutesSecondsToDecimalDegrees(raLong2HourDeg, raLong2Min, raLong2Sec); 240 var raLong2Deg = (hourOrDegree == paTypes.AngleMeasure.Hours) ? paMacros.degreeHoursToDecimalDegrees(raLong2Decimal) : raLong2Decimal; 241 var raLong2Rad = paUtils.degreesToRadians(raLong2Deg); 242 var decLat2Deg1 = paMacros.degreesMinutesSecondsToDecimalDegrees(decLat2Deg, decLat2Min, decLat2Sec); 243 var decLat2Rad = paUtils.degreesToRadians(decLat2Deg1); 244 245 var cosD = Math.sin(decLat1Rad) * Math.sin(decLat2Rad) + Math.cos(decLat1Rad) * Math.cos(decLat2Rad) * Math.cos(raLong1Rad - raLong2Rad); 246 var dRad = Math.acos(cosD); 247 var dDeg = paMacros.degrees(dRad); 248 249 var angleDeg = paMacros.decimalDegreesDegrees(dDeg); 250 var angleMin = paMacros.decimalDegreesMinutes(dDeg); 251 var angleSec = paMacros.decimalDegreesSeconds(dDeg); 252 253 return [angleDeg, angleMin, angleSec]; 254 } 255 256 /** 257 * Calculate rising and setting times for an object. 258 */ 259 function risingAndSetting(raHours, raMinutes, raSeconds, decDeg, decMin, decSec, gwDateDay, gwDateMonth, gwDateYear, geogLongDeg, geogLatDeg, vertShiftDeg) { 260 var raHours1 = paMacros.HMStoDH(raHours, raMinutes, raSeconds); 261 var decRad = paUtils.degreesToRadians(paMacros.degreesMinutesSecondsToDecimalDegrees(decDeg, decMin, decSec)); 262 var verticalDisplRadians = paUtils.degreesToRadians(vertShiftDeg); 263 var geoLatRadians = paUtils.degreesToRadians(geogLatDeg); 264 var cosH = -(Math.sin(verticalDisplRadians) + Math.sin(geoLatRadians) * Math.sin(decRad)) / (Math.cos(geoLatRadians) * Math.cos(decRad)); 265 var hHours = paMacros.decimalDegreesToDegreeHours(paMacros.degrees(Math.acos(cosH))); 266 var lstRiseHours = (raHours1 - hHours) - 24 * Math.floor((raHours1 - hHours) / 24); 267 var lstSetHours = (raHours1 + hHours) - 24 * Math.floor((raHours1 + hHours) / 24); 268 var aDeg = paMacros.degrees(Math.acos((Math.sin(decRad) + Math.sin(verticalDisplRadians) * Math.sin(geoLatRadians)) / (Math.cos(verticalDisplRadians) * Math.cos(geoLatRadians)))); 269 var azRiseDeg = aDeg - 360 * Math.floor(aDeg / 360); 270 var azSetDeg = (360 - aDeg) - 360 * Math.floor((360 - aDeg) / 360); 271 var utRiseHours1 = paMacros.greenwichSiderealTimeToUniversalTime(paMacros.localSiderealTimeToGreenwichSiderealTime(lstRiseHours, 0, 0, geogLongDeg), 0, 0, gwDateDay, gwDateMonth, gwDateYear); 272 var utSetHours1 = paMacros.greenwichSiderealTimeToUniversalTime(paMacros.localSiderealTimeToGreenwichSiderealTime(lstSetHours, 0, 0, geogLongDeg), 0, 0, gwDateDay, gwDateMonth, gwDateYear); 273 var utRiseAdjustedHours = utRiseHours1 + 0.008333; 274 var utSetAdjustedHours = utSetHours1 + 0.008333; 275 276 var riseSetStatus = paTypes.RiseSetStatus.OK; 277 if (cosH > 1) 278 riseSetStatus = paTypes.RiseSetStatus.NeverRises; 279 if (cosH < -1) 280 riseSetStatus = paTypes.RiseSetStatus.Circumpolar; 281 282 var utRiseHour = (riseSetStatus == paTypes.RiseSetStatus.OK) ? paMacros.decimalHoursHour(utRiseAdjustedHours) : 0; 283 var utRiseMin = (riseSetStatus == paTypes.RiseSetStatus.OK) ? paMacros.decimalHoursMinute(utRiseAdjustedHours) : 0; 284 var utSetHour = (riseSetStatus == paTypes.RiseSetStatus.OK) ? paMacros.decimalHoursHour(utSetAdjustedHours) : 0; 285 var utSetMin = (riseSetStatus == paTypes.RiseSetStatus.OK) ? paMacros.decimalHoursMinute(utSetAdjustedHours) : 0; 286 var azRise = (riseSetStatus == paTypes.RiseSetStatus.OK) ? paUtils.round(azRiseDeg, 2) : 0; 287 var azSet = (riseSetStatus == paTypes.RiseSetStatus.OK) ? paUtils.round(azSetDeg, 2) : 0; 288 289 return [riseSetStatus, utRiseHour, utRiseMin, utSetHour, utSetMin, azRise, azSet]; 290 } 291 292 /** 293 * Calculate precession (corrected coordinates between two epochs) 294 */ 295 function correctForPrecession(raHour, raMinutes, raSeconds, decDeg, decMinutes, decSeconds, epoch1Day, epoch1Month, epoch1Year, epoch2Day, epoch2Month, epoch2Year) { 296 var ra1Rad = paUtils.degreesToRadians(paMacros.degreeHoursToDecimalDegrees(paMacros.HMStoDH(raHour, raMinutes, raSeconds))); 297 var dec1Rad = paUtils.degreesToRadians(paMacros.degreesMinutesSecondsToDecimalDegrees(decDeg, decMinutes, decSeconds)); 298 var tCenturies = (paMacros.civilDateToJulianDate(epoch1Day, epoch1Month, epoch1Year) - 2415020) / 36525; 299 var mSec = 3.07234 + (0.00186 * tCenturies); 300 var nArcsec = 20.0468 - (0.0085 * tCenturies); 301 var nYears = (paMacros.civilDateToJulianDate(epoch2Day, epoch2Month, epoch2Year) - paMacros.civilDateToJulianDate(epoch1Day, epoch1Month, epoch1Year)) / 365.25; 302 var s1Hours = ((mSec + (nArcsec * Math.sin(ra1Rad) * Math.tan(dec1Rad) / 15)) * nYears) / 3600; 303 var ra2Hours = paMacros.HMStoDH(raHour, raMinutes, raSeconds) + s1Hours; 304 var s2Deg = (nArcsec * Math.cos(ra1Rad) * nYears) / 3600; 305 var dec2Deg = paMacros.degreesMinutesSecondsToDecimalDegrees(decDeg, decMinutes, decSeconds) + s2Deg; 306 307 var correctedRAHour = paMacros.decimalHoursHour(ra2Hours); 308 var correctedRAMinutes = paMacros.decimalHoursMinute(ra2Hours); 309 var correctedRASeconds = paMacros.decimalHoursSecond(ra2Hours); 310 var correctedDecDeg = paMacros.decimalDegreesDegrees(dec2Deg); 311 var correctedDecMinutes = paMacros.decimalDegreesMinutes(dec2Deg); 312 var correctedDecSeconds = paMacros.decimalDegreesSeconds(dec2Deg); 313 314 return [correctedRAHour, correctedRAMinutes, correctedRASeconds, correctedDecDeg, correctedDecMinutes, correctedDecSeconds]; 315 } 316 317 /** 318 * Calculate nutation for two values: ecliptic longitude and obliquity, for a Greenwich date. 319 */ 320 function nutationInEclipticLongitudeAndObliquity(greenwichDay, greenwichMonth, greenwichYear) { 321 var jdDays = paMacros.civilDateToJulianDate(greenwichDay, greenwichMonth, greenwichYear); 322 var tCenturies = (jdDays - 2415020) / 36525; 323 var aDeg = 100.0021358 * tCenturies; 324 var l1Deg = 279.6967 + (0.000303 * tCenturies * tCenturies); 325 var lDeg1 = l1Deg + 360 * (aDeg - Math.floor(aDeg)); 326 var lDeg2 = lDeg1 - 360 * Math.floor(lDeg1 / 360); 327 var lRad = paUtils.degreesToRadians(lDeg2); 328 var bDeg = 5.372617 * tCenturies; 329 var nDeg1 = 259.1833 - 360 * (bDeg - Math.floor(bDeg)); 330 var nDeg2 = nDeg1 - 360 * (Math.floor(nDeg1 / 360)); 331 var nRad = paUtils.degreesToRadians(nDeg2); 332 var nutInLongArcsec = -17.2 * Math.sin(nRad) - 1.3 * Math.sin(2 * lRad); 333 var nutInOblArcsec = 9.2 * Math.cos(nRad) + 0.5 * Math.cos(2 * lRad); 334 335 var nutInLongDeg = nutInLongArcsec / 3600; 336 var nutInOblDeg = nutInOblArcsec / 3600; 337 338 return [nutInLongDeg, nutInOblDeg]; 339 } 340 341 /** 342 * Correct ecliptic coordinates for the effects of aberration. 343 */ 344 function correctForAberration(utHour, utMinutes, utSeconds, gwDay, gwMonth, gwYear, trueEclLongDeg, trueEclLongMin, trueEclLongSec, trueEclLatDeg, trueEclLatMin, trueEclLatSec) { 345 var trueLongDeg = paMacros.degreesMinutesSecondsToDecimalDegrees(trueEclLongDeg, trueEclLongMin, trueEclLongSec); 346 var trueLatDeg = paMacros.degreesMinutesSecondsToDecimalDegrees(trueEclLatDeg, trueEclLatMin, trueEclLatSec); 347 var sunTrueLongDeg = paMacros.sunLong(utHour, utMinutes, utSeconds, 0, 0, gwDay, gwMonth, gwYear); 348 var dlongArcsec = -20.5 * Math.cos(paUtils.degreesToRadians(sunTrueLongDeg - trueLongDeg)) / Math.cos(paUtils.degreesToRadians(trueLatDeg)); 349 var dlatArcsec = -20.5 * Math.sin(paUtils.degreesToRadians(sunTrueLongDeg - trueLongDeg)) * Math.sin(paUtils.degreesToRadians(trueLatDeg)); 350 var apparentLongDeg = trueLongDeg + (dlongArcsec / 3600); 351 var apparentLatDeg = trueLatDeg + (dlatArcsec / 3600); 352 353 var apparentEclLongDeg = paMacros.decimalDegreesDegrees(apparentLongDeg); 354 var apparentEclLongMin = paMacros.decimalDegreesMinutes(apparentLongDeg); 355 var apparentEclLongSec = paMacros.decimalDegreesSeconds(apparentLongDeg); 356 var apparentEclLatDeg = paMacros.decimalDegreesDegrees(apparentLatDeg); 357 var apparentEclLatMin = paMacros.decimalDegreesMinutes(apparentLatDeg); 358 var apparentEclLatSec = paMacros.decimalDegreesSeconds(apparentLatDeg); 359 360 return [apparentEclLongDeg, apparentEclLongMin, apparentEclLongSec, apparentEclLatDeg, apparentEclLatMin, apparentEclLatSec]; 361 } 362 363 /** 364 * Calculate corrected RA/Dec, accounting for atmospheric refraction. 365 */ 366 function atmosphericRefraction(trueRAHour, trueRAMin, trueRASec, trueDecDeg, trueDecMin, trueDecSec, coordinateType, geogLongDeg, geogLatDeg, daylightSavingHours, timezoneHours, lcdDay, lcdMonth, lcdYear, lctHour, lctMin, lctSec, atmosphericPressureMbar, atmosphericTemperatureCelsius) { 367 var haHour = paMacros.rightAscensionToHourAngle(trueRAHour, trueRAMin, trueRASec, lctHour, lctMin, lctSec, daylightSavingHours, timezoneHours, lcdDay, lcdMonth, lcdYear, geogLongDeg); 368 var azimuthDeg = paMacros.equatorialCoordinatesToAzimuth(haHour, 0, 0, trueDecDeg, trueDecMin, trueDecSec, geogLatDeg); 369 var altitudeDeg = paMacros.equatorialCoordinatesToAltitude(haHour, 0, 0, trueDecDeg, trueDecMin, trueDecSec, geogLatDeg); 370 var correctedAltitudeDeg = paMacros.refract(altitudeDeg, coordinateType, atmosphericPressureMbar, atmosphericTemperatureCelsius); 371 372 var correctedHAHour = paMacros.horizonCoordinatesToHourAngle(azimuthDeg, 0, 0, correctedAltitudeDeg, 0, 0, geogLatDeg); 373 var correctedRAHour1 = paMacros.hourAngleToRightAscension(correctedHAHour, 0, 0, lctHour, lctMin, lctSec, daylightSavingHours, timezoneHours, lcdDay, lcdMonth, lcdYear, geogLongDeg); 374 var correctedDecDeg1 = paMacros.horizonCoordinatesToDeclination(azimuthDeg, 0, 0, correctedAltitudeDeg, 0, 0, geogLatDeg); 375 376 var correctedRAHour = paMacros.decimalHoursHour(correctedRAHour1); 377 var correctedRAMin = paMacros.decimalHoursMinute(correctedRAHour1); 378 var correctedRASec = paMacros.decimalHoursSecond(correctedRAHour1); 379 var correctedDecDeg = paMacros.decimalDegreesDegrees(correctedDecDeg1); 380 var correctedDecMin = paMacros.decimalDegreesMinutes(correctedDecDeg1); 381 var correctedDecSec = paMacros.decimalDegreesSeconds(correctedDecDeg1); 382 383 return [correctedRAHour, correctedRAMin, correctedRASec, correctedDecDeg, correctedDecMin, correctedDecSec]; 384 } 385 386 /** 387 * Calculate corrected RA/Dec, accounting for geocentric parallax. 388 */ 389 function correctionsForGeocentricParallax(raHour, raMin, raSec, decDeg, decMin, decSec, coordinateType, equatorialHorParallaxDeg, geogLongDeg, geogLatDeg, heightM, daylightSaving, timezoneHours, lcdDay, lcdMonth, lcdYear, lctHour, lctMin, lctSec) { 390 var haHours = paMacros.rightAscensionToHourAngle(raHour, raMin, raSec, lctHour, lctMin, lctSec, daylightSaving, timezoneHours, lcdDay, lcdMonth, lcdYear, geogLongDeg); 391 392 var correctedHAHours = paMacros.parallaxHA(haHours, 0, 0, decDeg, decMin, decSec, coordinateType, geogLatDeg, heightM, equatorialHorParallaxDeg); 393 394 var correctedRAHours = paMacros.hourAngleToRightAscension(correctedHAHours, 0, 0, lctHour, lctMin, lctSec, daylightSaving, timezoneHours, lcdDay, lcdMonth, lcdYear, geogLongDeg); 395 396 var correctedDecDeg1 = paMacros.parallaxDec(haHours, 0, 0, decDeg, decMin, decSec, coordinateType, geogLatDeg, heightM, equatorialHorParallaxDeg); 397 398 var correctedRAHour = paMacros.decimalHoursHour(correctedRAHours); 399 var correctedRAMin = paMacros.decimalHoursMinute(correctedRAHours); 400 var correctedRASec = paMacros.decimalHoursSecond(correctedRAHours); 401 var correctedDecDeg = paMacros.decimalDegreesDegrees(correctedDecDeg1); 402 var correctedDecMin = paMacros.decimalDegreesMinutes(correctedDecDeg1); 403 var correctedDecSec = paMacros.decimalDegreesSeconds(correctedDecDeg1); 404 405 return [correctedRAHour, correctedRAMin, correctedRASec, correctedDecDeg, correctedDecMin, correctedDecSec]; 406 } 407 408 /** 409 * 410 * Calculate heliographic coordinates for a given Greenwich date, with a given heliographic position angle and heliographic displacement in arc minutes. 411 */ 412 function heliographicCoordinates(helioPositionAngleDeg, helioDisplacementArcmin, gwdateDay, gwdateMonth, gwdateYear) { 413 var julianDateDays = paMacros.civilDateToJulianDate(gwdateDay, gwdateMonth, gwdateYear); 414 var tCenturies = (julianDateDays - 2415020) / 36525; 415 var longAscNodeDeg = paMacros.degreesMinutesSecondsToDecimalDegrees(74, 22, 0) + (84 * tCenturies / 60); 416 var sunLongDeg = paMacros.sunLong(0, 0, 0, 0, 0, gwdateDay, gwdateMonth, gwdateYear); 417 var y = Math.sin(paUtils.degreesToRadians(longAscNodeDeg - sunLongDeg)) * Math.cos(paUtils.degreesToRadians(paMacros.degreesMinutesSecondsToDecimalDegrees(7, 15, 0))); 418 var x = -Math.cos(paUtils.degreesToRadians(longAscNodeDeg - sunLongDeg)); 419 var aDeg = paMacros.degrees(Math.atan2(y, x)); 420 var mDeg1 = 360 - (360 * (julianDateDays - 2398220) / 25.38); 421 var mDeg2 = mDeg1 - 360 * Math.floor(mDeg1 / 360); 422 var l0Deg1 = mDeg2 + aDeg; 423 var b0Rad = Math.asin(Math.sin(paUtils.degreesToRadians(sunLongDeg - longAscNodeDeg)) * Math.sin(paUtils.degreesToRadians(paMacros.degreesMinutesSecondsToDecimalDegrees(7, 15, 0)))); 424 var theta1Rad = Math.atan(-Math.cos(paUtils.degreesToRadians(sunLongDeg)) * Math.tan(paUtils.degreesToRadians(paMacros.obliq(gwdateDay, gwdateMonth, gwdateYear)))); 425 var theta2Rad = Math.atan(-Math.cos(paUtils.degreesToRadians(longAscNodeDeg - sunLongDeg)) * Math.tan(paUtils.degreesToRadians(paMacros.degreesMinutesSecondsToDecimalDegrees(7, 15, 0)))); 426 var pDeg = paMacros.degrees(theta1Rad + theta2Rad); 427 var rho1Deg = helioDisplacementArcmin / 60; 428 var rhoRad = Math.asin(2 * rho1Deg / paMacros.sunDia(0, 0, 0, 0, 0, gwdateDay, gwdateMonth, gwdateYear)) - paUtils.degreesToRadians(rho1Deg); 429 var bRad = Math.asin(Math.sin(b0Rad) * Math.cos(rhoRad) + Math.cos(b0Rad) * Math.sin(rhoRad) * Math.cos(paUtils.degreesToRadians(pDeg - helioPositionAngleDeg))); 430 var bDeg = paMacros.degrees(bRad); 431 var lDeg1 = paMacros.degrees(Math.asin(Math.sin(rhoRad) * Math.sin(paUtils.degreesToRadians(pDeg - helioPositionAngleDeg)) / Math.cos(bRad))) + l0Deg1; 432 var lDeg2 = lDeg1 - 360 * Math.floor(lDeg1 / 360); 433 434 var helioLongDeg = paUtils.round(lDeg2, 2); 435 var helioLatDeg = paUtils.round(bDeg, 2); 436 437 return [helioLongDeg, helioLatDeg]; 438 } 439 440 /** 441 * Calculate carrington rotation number for a Greenwich date 442 */ 443 function carringtonRotationNumber(gwdateDay, gwdateMonth, gwdateYear) { 444 var julianDateDays = paMacros.civilDateToJulianDate(gwdateDay, gwdateMonth, gwdateYear); 445 446 var crn = 1690 + paUtils.round((julianDateDays - 2444235.34) / 27.2753, 0); 447 448 return crn; 449 } 450 451 /** 452 * Calculate selenographic (lunar) coordinates (sub-Earth) 453 */ 454 function selenographicCoordinates1(gwdateDay, gwdateMonth, gwdateYear) { 455 var julianDateDays = paMacros.civilDateToJulianDate(gwdateDay, gwdateMonth, gwdateYear); 456 var tCenturies = (julianDateDays - 2451545) / 36525; 457 var longAscNodeDeg = 125.044522 - 1934.136261 * tCenturies; 458 var f1 = 93.27191 + 483202.0175 * tCenturies; 459 var f2 = f1 - 360 * Math.floor(f1 / 360); 460 var geocentricMoonLongDeg = paMacros.moonLong(0, 0, 0, 0, 0, gwdateDay, gwdateMonth, gwdateYear); 461 var geocentricMoonLatRad = paUtils.degreesToRadians(paMacros.moonLat(0, 0, 0, 0, 0, gwdateDay, gwdateMonth, gwdateYear)); 462 var inclinationRad = paUtils.degreesToRadians(paMacros.degreesMinutesSecondsToDecimalDegrees(1, 32, 32.7)); 463 var nodeLongRad = paUtils.degreesToRadians(longAscNodeDeg - geocentricMoonLongDeg); 464 var sinBe = -Math.cos(inclinationRad) * Math.sin(geocentricMoonLatRad) + Math.sin(inclinationRad) * Math.cos(geocentricMoonLatRad) * Math.sin(nodeLongRad); 465 var subEarthLatDeg = paMacros.degrees(Math.asin(sinBe)); 466 var aRad = Math.atan2((-Math.sin(geocentricMoonLatRad) * Math.sin(inclinationRad) - Math.cos(geocentricMoonLatRad) * Math.cos(inclinationRad) * Math.sin(nodeLongRad)), (Math.cos(geocentricMoonLatRad) * Math.cos(nodeLongRad))); 467 var aDeg = paMacros.degrees(aRad); 468 var subEarthLongDeg1 = aDeg - f2; 469 var subEarthLongDeg2 = subEarthLongDeg1 - 360 * Math.floor(subEarthLongDeg1 / 360); 470 var subEarthLongDeg3 = (subEarthLongDeg2 > 180) ? subEarthLongDeg2 - 360 : subEarthLongDeg2; 471 var c1Rad = Math.atan(Math.cos(nodeLongRad) * Math.sin(inclinationRad) / (Math.cos(geocentricMoonLatRad) * Math.cos(inclinationRad) + Math.sin(geocentricMoonLatRad) * Math.sin(inclinationRad) * Math.sin(nodeLongRad))); 472 var obliquityRad = paUtils.degreesToRadians(paMacros.obliq(gwdateDay, gwdateMonth, gwdateYear)); 473 var c2Rad = Math.atan(Math.sin(obliquityRad) * Math.cos(paUtils.degreesToRadians(geocentricMoonLongDeg)) / (Math.sin(obliquityRad) * Math.sin(geocentricMoonLatRad) * Math.sin(paUtils.degreesToRadians(geocentricMoonLongDeg)) - Math.cos(obliquityRad) * Math.cos(geocentricMoonLatRad))); 474 var cDeg = paMacros.degrees(c1Rad + c2Rad); 475 476 var subEarthLongitude = paUtils.round(subEarthLongDeg3, 2); 477 var subEarthLatitude = paUtils.round(subEarthLatDeg, 2); 478 var positionAngleOfPole = paUtils.round(cDeg, 2); 479 480 return [subEarthLongitude, subEarthLatitude, positionAngleOfPole]; 481 } 482 483 /** 484 * Calculate selenographic (lunar) coordinates (sub-Solar) 485 */ 486 function selenographicCoordinates2(gwdateDay, gwdateMonth, gwdateYear) { 487 var julianDateDays = paMacros.civilDateToJulianDate(gwdateDay, gwdateMonth, gwdateYear); 488 var tCenturies = (julianDateDays - 2451545) / 36525; 489 var longAscNodeDeg = 125.044522 - 1934.136261 * tCenturies; 490 var f1 = 93.27191 + 483202.0175 * tCenturies; 491 var f2 = f1 - 360 * Math.floor(f1 / 360); 492 var sunGeocentricLongDeg = paMacros.sunLong(0, 0, 0, 0, 0, gwdateDay, gwdateMonth, gwdateYear); 493 var moonEquHorParallaxArcMin = paMacros.moonHP(0, 0, 0, 0, 0, gwdateDay, gwdateMonth, gwdateYear) * 60; 494 var sunEarthDistAU = paMacros.sunDist(0, 0, 0, 0, 0, gwdateDay, gwdateMonth, gwdateYear); 495 var geocentricMoonLatRad = paUtils.degreesToRadians(paMacros.moonLat(0, 0, 0, 0, 0, gwdateDay, gwdateMonth, gwdateYear)); 496 var geocentricMoonLongDeg = paMacros.moonLong(0, 0, 0, 0, 0, gwdateDay, gwdateMonth, gwdateYear); 497 var adjustedMoonLongDeg = sunGeocentricLongDeg + 180 + (26.4 * Math.cos(geocentricMoonLatRad) * Math.sin(paUtils.degreesToRadians(sunGeocentricLongDeg - geocentricMoonLongDeg)) / (moonEquHorParallaxArcMin * sunEarthDistAU)); 498 var adjustedMoonLatRad = 0.14666 * geocentricMoonLatRad / (moonEquHorParallaxArcMin * sunEarthDistAU); 499 var inclinationRad = paUtils.degreesToRadians(paMacros.degreesMinutesSecondsToDecimalDegrees(1, 32, 32.7)); 500 var nodeLongRad = paUtils.degreesToRadians(longAscNodeDeg - adjustedMoonLongDeg); 501 var sinBs = -Math.cos(inclinationRad) * Math.sin(adjustedMoonLatRad) + Math.sin(inclinationRad) * Math.cos(adjustedMoonLatRad) * Math.sin(nodeLongRad); 502 var subSolarLatDeg = paMacros.degrees(Math.asin(sinBs)); 503 var aRad = Math.atan2((-Math.sin(adjustedMoonLatRad) * Math.sin(inclinationRad) - Math.cos(adjustedMoonLatRad) * Math.cos(inclinationRad) * Math.sin(nodeLongRad)), (Math.cos(adjustedMoonLatRad) * Math.cos(nodeLongRad))); 504 var aDeg = paMacros.degrees(aRad); 505 var subSolarLongDeg1 = aDeg - f2; 506 var subSolarLongDeg2 = subSolarLongDeg1 - 360 * Math.floor(subSolarLongDeg1 / 360); 507 var subSolarLongDeg3 = (subSolarLongDeg2 > 180) ? subSolarLongDeg2 - 360 : subSolarLongDeg2; 508 var subSolarColongDeg = 90 - subSolarLongDeg3; 509 510 var subSolarLongitude = paUtils.round(subSolarLongDeg3, 2); 511 var subSolarColongitude = paUtils.round(subSolarColongDeg, 2); 512 var subSolarLatitude = paUtils.round(subSolarLatDeg, 2); 513 514 return [subSolarLongitude, subSolarColongitude, subSolarLatitude]; 515 } 516 517 518 module.exports = { 519 angleToDecimalDegrees, 520 decimalDegreesToAngle, 521 rightAscensionToHourAngle, 522 hourAngleToRightAscension, 523 equatorialCoordinatesToHorizonCoordinates, 524 horizonCoordinatesToEquatorialCoordinates, 525 meanObliquityOfTheEcliptic, 526 eclipticCoordinateToEquatorialCoordinate, 527 equatorialCoordinateToEclipticCoordinate, 528 equatorialCoordinateToGalacticCoordinate, 529 galacticCoordinateToEquatorialCoordinate, 530 angleBetweenTwoObjects, 531 risingAndSetting, 532 correctForPrecession, 533 nutationInEclipticLongitudeAndObliquity, 534 correctForAberration, 535 atmosphericRefraction, 536 correctionsForGeocentricParallax, 537 heliographicCoordinates, 538 carringtonRotationNumber, 539 selenographicCoordinates1, 540 selenographicCoordinates2 541 };