blueyonder.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. // Utility functions for astronomical programming.
  6. // JavaScript by Peter Hayes http://www.peter-hayes.freeserve.co.uk/
  7. // Copyright 2001-2002
  8. // This code is made freely available but please keep this notice.
  9. // I accept no liability for any errors in my coding but please
  10. // let me know of any errors you find. My address is on my home page.
  11. // Modifed (placed in namespace) by Berkeley Churchill March 2015
  12. var BlueYonder = {};
  13. function dayno(year, month, day, hours) {
  14. // Day number is a modified Julian date, day 0 is 2000 January 0.0
  15. // which corresponds to a Julian date of 2451543.5
  16. var d = 367 * year - Math.floor(7 * (year + Math.floor((month + 9) / 12)) / 4) + Math.floor(275 * month / 9) + day - 730530 + hours / 24;
  17. return d;
  18. }
  19. function julian(year, month, day, hours) {
  20. return dayno(year, month, day, hours) + 2451543.5;
  21. }
  22. BlueYonder.jdtocd = function (jd) {
  23. // The calendar date from julian date
  24. // Returns year, month, day, day of week, hours, minutes, seconds
  25. var Z = Math.floor(jd + 0.5);
  26. var F = jd + 0.5 - Z;
  27. if (Z < 2299161) {
  28. var A = Z;
  29. } else {
  30. var alpha = Math.floor((Z - 1867216.25) / 36524.25);
  31. var A = Z + 1 + alpha - Math.floor(alpha / 4);
  32. }
  33. var B = A + 1524;
  34. var C = Math.floor((B - 122.1) / 365.25);
  35. var D = Math.floor(365.25 * C);
  36. var E = Math.floor((B - D) / 30.6001);
  37. var d = B - D - Math.floor(30.6001 * E) + F;
  38. if (E < 14) {
  39. var month = E - 1;
  40. } else {
  41. var month = E - 13;
  42. }
  43. if (month > 2) {
  44. var year = C - 4716;
  45. } else {
  46. var year = C - 4715;
  47. }
  48. var day = Math.floor(d);
  49. var h = (d - day) * 24;
  50. var hours = Math.floor(h);
  51. var m = (h - hours) * 60;
  52. var minutes = Math.floor(m);
  53. var seconds = Math.round((m - minutes) * 60);
  54. if (seconds >= 60) {
  55. minutes = minutes + 1;seconds = seconds - 60;
  56. }
  57. if (minutes >= 60) {
  58. hours = hours + 1;minutes = 0;
  59. }
  60. var dw = Math.floor(jd + 1.5) - 7 * Math.floor((jd + 1.5) / 7);
  61. return new Array(year, month, day, dw, hours, minutes, seconds);
  62. };
  63. function local_sidereal(year, month, day, hours, lon) {
  64. // Compute local siderial time in degrees
  65. // year, month, day and hours are the Greenwich date and time
  66. // lon is the observers longitude
  67. var d = dayno(year, month, day, hours);
  68. var lst = 98.9818 + 0.985647352 * d + hours * 15 + lon;
  69. return rev(lst) / 15;
  70. }
  71. function radtoaa(ra, dec, year, month, day, hours, lat, lon) {
  72. // convert ra and dec to altitude and azimuth
  73. // year, month, day and hours are the Greenwich date and time
  74. // lat and lon are the observers latitude and longitude
  75. var lst = local_sidereal(year, month, day, hours, lon);
  76. var x = cosd(15.0 * (lst - ra)) * cosd(dec);
  77. var y = sind(15.0 * (lst - ra)) * cosd(dec);
  78. var z = sind(dec);
  79. // rotate so z is the local zenith
  80. var xhor = x * sind(lat) - z * cosd(lat);
  81. var yhor = y;
  82. var zhor = x * cosd(lat) + z * sind(lat);
  83. var azimuth = rev(atan2d(yhor, xhor) + 180.0); // so 0 degrees is north
  84. var altitude = atan2d(zhor, Math.sqrt(xhor * xhor + yhor * yhor));
  85. return new Array(altitude, azimuth);
  86. }
  87. // Utility functions for date and time programming.
  88. // JavaScript by Peter Hayes
  89. // http://www.aphayes.pwp.blueyonder.co.uk/
  90. // Copyright 2001-2010
  91. // This code is made freely available but please keep this notice.
  92. // I accept no liability for any errors in my coding but please
  93. // let me know of any errors you find. My address is on my home page.
  94. // Javascript 1.2 includes getFullYear but Netscape 4.6 does not supply it.
  95. function getFullYear(now) {
  96. var year = now.getYear();
  97. if (year == 0) {
  98. year = 2000;
  99. };
  100. if (year < 1900) {
  101. year = year + 1900;
  102. };
  103. return year;
  104. }
  105. function datestring(year, month, day) {
  106. // provides a locale independent format - year:month:day
  107. var datestr = "";datestr += year;
  108. datestr += (month < 10 ? ":0" : ":") + month;
  109. datestr += (day < 10 ? ":0" : ":") + day;
  110. return datestr;
  111. }
  112. function hmstring(t) {
  113. // takes hours and returns hh:mm
  114. var hours = t;
  115. while (hours >= 24) {
  116. hours -= 24;
  117. }
  118. while (hours < 0) {
  119. hours += 24;
  120. }
  121. var minutes = Math.round(60.0 * (hours - Math.floor(hours)));
  122. hours = Math.floor(hours);
  123. if (minutes >= 60) {
  124. hours += 1;minutes -= 60;
  125. }
  126. if (hours >= 24) {
  127. hours -= 24;
  128. }
  129. var hmstr = t < 0 ? "-" : "";
  130. hmstr += (hours < 10 ? "0" : "") + hours;
  131. hmstr += (minutes < 10 ? ":0" : ":") + minutes;
  132. return hmstr;
  133. }
  134. function hmsstring(t) {
  135. // takes hours and returns hh:mm:ss
  136. var hours = Math.abs(t);
  137. var minutes = 60.0 * (hours - Math.floor(hours));
  138. hours = Math.floor(hours);
  139. var seconds = Math.round(60.0 * (minutes - Math.floor(minutes)));
  140. minutes = Math.floor(minutes);
  141. if (seconds >= 60) {
  142. minutes += 1;seconds -= 60;
  143. }
  144. if (minutes >= 60) {
  145. hours += 1;minutes -= 60;
  146. }
  147. if (hours >= 24) {
  148. hours -= 24;
  149. }
  150. var hmsstr = t < 0 ? "-" : "";
  151. hmsstr += (hours < 10 ? "0" : "") + hours;
  152. hmsstr += (minutes < 10 ? ":0" : ":") + minutes;
  153. hmsstr += (seconds < 10 ? ":0" : ":") + seconds;
  154. return hmsstr;
  155. }
  156. // Extensions to the Math routines - Trig routines in degrees
  157. // JavaScript by Peter Hayes http://www.peter-hayes.freeserve.co.uk/
  158. // Copyright 2001-2002
  159. function rev(angle) {
  160. return angle - Math.floor(angle / 360.0) * 360.0;
  161. }
  162. function sind(angle) {
  163. return Math.sin(angle * Math.PI / 180.0);
  164. }
  165. function cosd(angle) {
  166. return Math.cos(angle * Math.PI / 180.0);
  167. }
  168. function tand(angle) {
  169. return Math.tan(angle * Math.PI / 180.0);
  170. }
  171. function asind(c) {
  172. return 180.0 / Math.PI * Math.asin(c);
  173. }
  174. function acosd(c) {
  175. return 180.0 / Math.PI * Math.acos(c);
  176. }
  177. function atan2d(y, x) {
  178. return 180.0 / Math.PI * Math.atan(y / x) - 180.0 * (x < 0);
  179. }
  180. function anglestring(a, circle) {
  181. // returns a in degrees as a string degrees:minutes
  182. // circle is true for range between 0 and 360 and false for -90 to +90
  183. var ar = Math.round(a * 60) / 60;
  184. var deg = Math.abs(ar);
  185. var min = Math.round(60.0 * (deg - Math.floor(deg)));
  186. if (min >= 60) {
  187. deg += 1;min = 0;
  188. }
  189. var anglestr = "";
  190. if (!circle) anglestr += ar < 0 ? "-" : "+";
  191. if (circle) anglestr += Math.floor(deg) < 100 ? "0" : "";
  192. anglestr += (Math.floor(deg) < 10 ? "0" : "") + Math.floor(deg);
  193. anglestr += (min < 10 ? ":0" : ":") + min;
  194. return anglestr;
  195. }
  196. // JavaScript by Peter Hayes http://www.aphayes.pwp.blueyonder.co.uk/
  197. // Copyright 2001-2010
  198. // Unless otherwise stated this code is based on the methods in
  199. // Astronomical Algorithms, first edition, by Jean Meeus
  200. // Published by Willmann-Bell, Inc.
  201. // This code is made freely available but please keep this notice.
  202. // The calculations are approximate but should be good enough for general use,
  203. // I accept no responsibility for errors in astronomy or coding.
  204. // WARNING moonrise code changed on 6 May 2003 to correct a systematic error
  205. // these are now local times NOT UTC as the original code did.
  206. // Meeus first edition table 45.A Longitude and distance of the moon
  207. var T45AD = new Array(0, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 1, 0, 2, 0, 0, 4, 0, 4, 2, 2, 1, 1, 2, 2, 4, 2, 0, 2, 2, 1, 2, 0, 0, 2, 2, 2, 4, 0, 3, 2, 4, 0, 2, 2, 2, 4, 0, 4, 1, 2, 0, 1, 3, 4, 2, 0, 1, 2, 2);
  208. var T45AM = new Array(0, 0, 0, 0, 1, 0, 0, -1, 0, -1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, -1, 0, 0, 0, 1, 0, -1, 0, -2, 1, 2, -2, 0, 0, -1, 0, 0, 1, -1, 2, 2, 1, -1, 0, 0, -1, 0, 1, 0, 1, 0, 0, -1, 2, 1, 0, 0);
  209. var T45AMP = new Array(1, -1, 0, 2, 0, 0, -2, -1, 1, 0, -1, 0, 1, 0, 1, 1, -1, 3, -2, -1, 0, -1, 0, 1, 2, 0, -3, -2, -1, -2, 1, 0, 2, 0, -1, 1, 0, -1, 2, -1, 1, -2, -1, -1, -2, 0, 1, 4, 0, -2, 0, 2, 1, -2, -3, 2, 1, -1, 3, -1);
  210. var T45AF = new Array(0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, -2, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, -2, 2, 0, 2, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, -2, -2, 0, 0, 0, 0, 0, 0, 0, -2);
  211. var T45AL = new Array(6288774, 1274027, 658314, 213618, -185116, -114332, 58793, 57066, 53322, 45758, -40923, -34720, -30383, 15327, -12528, 10980, 10675, 10034, 8548, -7888, -6766, -5163, 4987, 4036, 3994, 3861, 3665, -2689, -2602, 2390, -2348, 2236, -2120, -2069, 2048, -1773, -1595, 1215, -1110, -892, -810, 759, -713, -700, 691, 596, 549, 537, 520, -487, -399, -381, 351, -340, 330, 327, -323, 299, 294, 0);
  212. var T45AR = new Array(-20905355, -3699111, -2955968, -569925, 48888, -3149, 246158, -152138, -170733, -204586, -129620, 108743, 104755, 10321, 0, 79661, -34782, -23210, -21636, 24208, 30824, -8379, -16675, -12831, -10445, -11650, 14403, -7003, 0, 10056, 6322, -9884, 5751, 0, -4950, 4130, 0, -3958, 0, 3258, 2616, -1897, -2117, 2354, 0, 0, -1423, -1117, -1571, -1739, 0, -4421, 0, 0, 0, 0, 1165, 0, 0, 8752);
  213. // Meeus table 45B latitude of the moon
  214. var T45BD = new Array(0, 0, 0, 2, 2, 2, 2, 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 4, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4, 4, 0, 4, 2, 2, 2, 2, 0, 2, 2, 2, 2, 4, 2, 2, 0, 2, 1, 1, 0, 2, 1, 2, 0, 4, 4, 1, 4, 1, 4, 2);
  215. var T45BM = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 1, -1, -1, -1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 1, 0, -1, -2, 0, 1, 1, 1, 1, 1, 0, -1, 1, 0, -1, 0, 0, 0, -1, -2);
  216. var T45BMP = new Array(0, 1, 1, 0, -1, -1, 0, 2, 1, 2, 0, -2, 1, 0, -1, 0, -1, -1, -1, 0, 0, -1, 0, 1, 1, 0, 0, 3, 0, -1, 1, -2, 0, 2, 1, -2, 3, 2, -3, -1, 0, 0, 1, 0, 1, 1, 0, 0, -2, -1, 1, -2, 2, -2, -1, 1, 1, -1, 0, 0);
  217. var T45BF = new Array(1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 3, 1, 1, 1, -1, -1, -1, 1, -1, 1, -3, 1, -3, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 3, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1);
  218. var T45BL = new Array(5128122, 280602, 277693, 173237, 55413, 46271, 32573, 17198, 9266, 8822, 8216, 4324, 4200, -3359, 2463, 2211, 2065, -1870, 1828, -1794, -1749, -1565, -1491, -1475, -1410, -1344, -1335, 1107, 1021, 833, 777, 671, 607, 596, 491, -451, 439, 422, 421, -366, -351, 331, 315, 302, -283, -229, 223, 223, -220, -220, -185, 181, -177, 176, 166, -164, 132, -119, 115, 107);
  219. // MoonPos calculates the Moon position, based on Meeus chapter 45
  220. function MoonPos(year, month, day, hours) {
  221. // julian date
  222. var jd = julian(year, month, day, hours);
  223. var T = (jd - 2451545.0) / 36525;
  224. var T2 = T * T;
  225. var T3 = T2 * T;
  226. var T4 = T3 * T;
  227. // Moons mean longitude L'
  228. var LP = 218.3164477 + 481267.88123421 * T - 0.0015786 * T2 + T3 / 538841.0 - T4 / 65194000.0;
  229. // Moons mean elongation
  230. var D = 297.8501921 + 445267.1114034 * T - 0.0018819 * T2 + T3 / 545868.0 - T4 / 113065000.0;
  231. // Suns mean anomaly
  232. var M = 357.5291092 + 35999.0502909 * T - 0.0001536 * T2 + T3 / 24490000.0;
  233. // Moons mean anomaly M'
  234. var MP = 134.9633964 + 477198.8675055 * T + 0.0087414 * T2 + T3 / 69699.0 - T4 / 14712000.0;
  235. // Moons argument of latitude
  236. var F = 93.2720950 + 483202.0175233 * T - 0.0036539 * T2 - T3 / 3526000.0 + T4 / 863310000.0;
  237. // Additional arguments
  238. var A1 = 119.75 + 131.849 * T;
  239. var A2 = 53.09 + 479264.290 * T;
  240. var A3 = 313.45 + 481266.484 * T;
  241. var E = 1 - 0.002516 * T - 0.0000074 * T2;
  242. var E2 = E * E;
  243. // Sums of periodic terms from table 45.A and 45.B
  244. var Sl = 0.0;
  245. var Sr = 0.0;
  246. for (var i = 0; i < 60; i++) {
  247. var Eterm = 1;
  248. if (Math.abs(T45AM[i]) == 1) Eterm = E;
  249. if (Math.abs(T45AM[i]) == 2) Eterm = E2;
  250. Sl += T45AL[i] * Eterm * sind(rev(T45AD[i] * D + T45AM[i] * M + T45AMP[i] * MP + T45AF[i] * F));
  251. Sr += T45AR[i] * Eterm * cosd(rev(T45AD[i] * D + T45AM[i] * M + T45AMP[i] * MP + T45AF[i] * F));
  252. }
  253. var Sb = 0.0;
  254. for (var i = 0; i < 60; i++) {
  255. var Eterm = 1;
  256. if (Math.abs(T45BM[i]) == 1) Eterm = E;
  257. if (Math.abs(T45BM[i]) == 2) Eterm = E2;
  258. Sb += T45BL[i] * Eterm * sind(rev(T45BD[i] * D + T45BM[i] * M + T45BMP[i] * MP + T45BF[i] * F));
  259. }
  260. // Additional additive terms
  261. Sl = Sl + 3958 * sind(rev(A1)) + 1962 * sind(rev(LP - F)) + 318 * sind(rev(A2));
  262. Sb = Sb - 2235 * sind(rev(LP)) + 382 * sind(rev(A3)) + 175 * sind(rev(A1 - F)) + 175 * sind(rev(A1 + F)) + 127 * sind(rev(LP - MP)) - 115 * sind(rev(LP + MP));
  263. // geocentric longitude, latitude and distance
  264. var mglong = rev(LP + Sl / 1000000.0);
  265. var mglat = rev(Sb / 1000000.0);
  266. if (mglat > 180.0) mglat = mglat - 360;
  267. var mr = Math.round(385000.56 + Sr / 1000.0);
  268. // Obliquity of Ecliptic
  269. var obl = 23.4393 - 3.563E-9 * (jd - 2451543.5);
  270. // RA and dec
  271. var ra = rev(atan2d(sind(mglong) * cosd(obl) - tand(mglat) * sind(obl), cosd(mglong))) / 15.0;
  272. var dec = rev(asind(sind(mglat) * cosd(obl) + cosd(mglat) * sind(obl) * sind(mglong)));
  273. if (dec > 180.0) dec = dec - 360;
  274. return new Array(ra, dec, mr);
  275. }
  276. function MoonRise(year, month, day, TZ, latitude, longitude) {
  277. // returns an array containing rise and set times or one of the
  278. // following codes.
  279. // -1 rise or set event not found and moon was down at 00:00
  280. // -2 rise or set event not found and moon was up at 00:00
  281. // WARNING code changes on 6/7 May 2003 these are now local times
  282. // NOT UTC and rise/set not found codes changed.
  283. var hours = 0;
  284. var riseset = new Array();
  285. // elh is the elevation at the hour elhdone is true if elh calculated
  286. var elh = new Array();
  287. var elhdone = new Array();
  288. for (var i = 0; i <= 24; i++) {
  289. elhdone[i] = false;
  290. }
  291. // Compute the moon elevation at start and end of day
  292. // store elevation at the hours in an array elh to save search time
  293. var rad = MoonPos(year, month, day, hours - TZ);
  294. var altaz = radtoaa(rad[0], rad[1], year, month, day, hours - TZ, latitude, longitude);
  295. elh[0] = altaz[0];elhdone[0] = true;
  296. // set the return code to allow for always up or never rises
  297. if (elh[0] > 0.0) {
  298. riseset = new Array(-2, -2);
  299. } else {
  300. riseset = new Array(-1, -1);
  301. }
  302. hours = 24;
  303. rad = MoonPos(year, month, day, hours - TZ);
  304. altaz = radtoaa(rad[0], rad[1], year, month, day, hours - TZ, latitude, longitude);
  305. elh[24] = altaz[0];elhdone[24] = true;
  306. // search for moonrise and set
  307. for (var rise = 0; rise < 2; rise++) {
  308. var found = false;
  309. var hfirst = 0;
  310. var hlast = 24;
  311. // Try a binary chop on the hours to speed the search
  312. while (Math.ceil((hlast - hfirst) / 2) > 1) {
  313. hmid = hfirst + Math.round((hlast - hfirst) / 2);
  314. if (!elhdone[hmid]) {
  315. hours = hmid;
  316. rad = MoonPos(year, month, day, hours - TZ);
  317. altaz = radtoaa(rad[0], rad[1], year, month, day, hours - TZ, latitude, longitude);
  318. elh[hmid] = altaz[0];elhdone[hmid] = true;
  319. }
  320. if (rise == 0 && elh[hfirst] <= 0.0 && elh[hmid] >= 0.0 || rise == 1 && elh[hfirst] >= 0.0 && elh[hmid] <= 0.0) {
  321. hlast = hmid;found = true;continue;
  322. }
  323. if (rise == 0 && elh[hmid] <= 0.0 && elh[hlast] >= 0.0 || rise == 1 && elh[hmid] >= 0.0 && elh[hlast] <= 0.0) {
  324. hfirst = hmid;found = true;continue;
  325. }
  326. break;
  327. }
  328. // If the binary chop did not find a 1 hour interval
  329. if (hlast - hfirst > 1) {
  330. for (var i = hfirst; i < hlast; i++) {
  331. found = false;
  332. if (!elhdone[i + 1]) {
  333. hours = i + 1;
  334. rad = MoonPos(year, month, day, hours - TZ);
  335. altaz = radtoaa(rad[0], rad[1], year, month, day, hours - TZ, latitude, longitude);
  336. elh[hours] = altaz[0];elhdone[hours] = true;
  337. }
  338. if (rise == 0 && elh[i] <= 0.0 && elh[i + 1] >= 0.0 || rise == 1 && elh[i] >= 0.0 && elh[i + 1] <= 0.0) {
  339. hfirst = i;hlast = i + 1;found = true;break;
  340. }
  341. }
  342. }
  343. // simple linear interpolation for the minutes
  344. if (found) {
  345. var elfirst = elh[hfirst];var ellast = elh[hlast];
  346. hours = hfirst + 0.5;
  347. rad = MoonPos(year, month, day, hours - TZ);
  348. altaz = radtoaa(rad[0], rad[1], year, month, day, hours - TZ, latitude, longitude);
  349. // alert("day ="+day+" hour ="+hours+" altaz="+altaz[0]+" "+altaz[1]);
  350. if (rise == 0 && altaz[0] <= 0.0) {
  351. hfirst = hours;elfirst = altaz[0];
  352. }
  353. if (rise == 0 && altaz[0] > 0.0) {
  354. hlast = hours;ellast = altaz[0];
  355. }
  356. if (rise == 1 && altaz[0] <= 0.0) {
  357. hlast = hours;ellast = altaz[0];
  358. }
  359. if (rise == 1 && altaz[0] > 0.0) {
  360. hfirst = hours;elfirst = altaz[0];
  361. }
  362. var eld = Math.abs(elfirst) + Math.abs(ellast);
  363. riseset[rise] = hfirst + (hlast - hfirst) * Math.abs(elfirst) / eld;
  364. }
  365. } // End of rise/set loop
  366. return riseset;
  367. }
  368. function MoonPhase(year, month, day, hours) {
  369. // the illuminated percentage from Meeus chapter 46
  370. var j = dayno(year, month, day, hours) + 2451543.5;
  371. var T = (j - 2451545.0) / 36525;
  372. var T2 = T * T;
  373. var T3 = T2 * T;
  374. var T4 = T3 * T;
  375. // Moons mean elongation Meeus first edition
  376. // var D=297.8502042+445267.1115168*T-0.0016300*T2+T3/545868.0-T4/113065000.0;
  377. // Moons mean elongation Meeus second edition
  378. var D = 297.8501921 + 445267.1114034 * T - 0.0018819 * T2 + T3 / 545868.0 - T4 / 113065000.0;
  379. // Moons mean anomaly M' Meeus first edition
  380. // var MP=134.9634114+477198.8676313*T+0.0089970*T2+T3/69699.0-T4/14712000.0;
  381. // Moons mean anomaly M' Meeus second edition
  382. var MP = 134.9633964 + 477198.8675055 * T + 0.0087414 * T2 + T3 / 69699.0 - T4 / 14712000.0;
  383. // Suns mean anomaly
  384. var M = 357.5291092 + 35999.0502909 * T - 0.0001536 * T2 + T3 / 24490000.0;
  385. // phase angle
  386. var pa = 180.0 - D - 6.289 * sind(MP) + 2.1 * sind(M) - 1.274 * sind(2 * D - MP) - 0.658 * sind(2 * D) - 0.214 * sind(2 * MP) - 0.11 * sind(D);
  387. return rev(pa);
  388. }
  389. BlueYonder.MoonQuarters = function (year, month, day) {
  390. // returns an array of Julian Ephemeris Days (JDE) for
  391. // new moon, first quarter, full moon and last quarter
  392. // Meeus first edition chapter 47 with only the most larger additional corrections
  393. // Meeus code calculate Terrestrial Dynamic Time
  394. // TDT = UTC + (number of leap seconds) + 32.184
  395. // At the end of June 2012 the 25th leap second was added
  396. //
  397. var quarters = new Array();
  398. // k is an integer for new moon incremented by 0.25 for first quarter 0.5 for new etc.
  399. var k = Math.floor((year + (month - 1 + day / 30) / 12 - 2000) * 12.3685);
  400. // Time in Julian centuries since 2000.0
  401. var T = k / 1236.85;
  402. // Sun's mean anomaly
  403. var M = rev(2.5534 + 29.10535669 * k - 0.0000218 * T * T);
  404. // Moon's mean anomaly (M' in Meeus)
  405. var MP = rev(201.5643 + 385.81693528 * k + 0.0107438 * T * T + 0.00001239 * T * T * T - 0.00000011 * T * T * T);
  406. var E = 1 - 0.002516 * T - 0.0000074 * T * T;
  407. // Moons argument of latitude
  408. var F = rev(160.7108 + 390.67050274 * k - 0.0016341 * T * T - 0.00000227 * T * T * T + 0.000000011 * T * T * T * T);
  409. // Longitude of ascending node of lunar orbit
  410. var Omega = rev(124.7746 - 1.56375580 * k + 0.0020691 * T * T + 0.00000215 * T * T * T);
  411. // The full planetary arguments include 14 terms, only used the 7 most significant
  412. var A = new Array();
  413. A[1] = rev(299.77 + 0.107408 * k - 0.009173 * T * T);
  414. A[2] = rev(251.88 + 0.016321 * k);
  415. A[3] = rev(251.83 + 26.651886 * k);
  416. A[4] = rev(349.42 + 36.412478 * k);
  417. A[5] = rev(84.88 + 18.206239 * k);
  418. A[6] = rev(141.74 + 53.303771 * k);
  419. A[7] = rev(207.14 + 2.453732 * k);
  420. // New moon
  421. var JDE0 = 2451550.09765 + 29.530588853 * k + 0.0001337 * T * T - 0.000000150 * T * T * T + 0.00000000073 * T * T * T * T;
  422. // Correct for TDT since 1 July 2012
  423. JDE0 = JDE0 - 57.184 / (24 * 60 * 60);
  424. var JDE = JDE0 - 0.40720 * sind(MP) + 0.17241 * E * sind(M) + 0.01608 * sind(2 * MP) + 0.01039 * sind(2 * F) + 0.00739 * E * sind(MP - M) - 0.00514 * E * sind(MP + M) + 0.00208 * E * E * sind(2 * M) - 0.00111 * sind(MP - 2 * F) - 0.00057 * sind(MP + 2 * F) + 0.00056 * E * sind(2 * MP + M) - 0.00042 * sind(3 * MP) + 0.00042 * E * sind(M + 2 * F) + 0.00038 * E * sind(M - 2 * F) - 0.00024 * E * sind(2 * MP - M) - 0.00017 * sind(Omega) - 0.00007 * sind(MP + 2 * M);
  425. quarters[0] = JDE + 0.000325 * sind(A[1]) + 0.000165 * sind(A[2]) + 0.000164 * sind(A[3]) + 0.000126 * sind(A[4]) + 0.000110 * sind(A[5]) + 0.000062 * sind(A[6]) + 0.000060 * sind(A[7]);
  426. // The following code needs tidying up with a loop and conditionals for each quarter
  427. // First Quarter k=k+0.25
  428. JDE = JDE0 + 29.530588853 * 0.25;
  429. M = rev(M + 29.10535669 * 0.25);
  430. MP = rev(MP + 385.81693528 * 0.25);
  431. F = rev(F + 390.67050274 * 0.25);
  432. Omega = rev(Omega - 1.56375580 * 0.25);
  433. A[1] = rev(A[1] + 0.107408 * 0.25);A[2] = rev(A[2] + 0.016321 * 0.25);A[3] = rev(A[3] + 26.651886 * 0.25);
  434. A[4] = rev(A[4] + 36.412478 * 0.25);A[5] = rev(A[5] + 18.206239 * 0.25);A[6] = rev(A[6] + 53.303771 * 0.25);
  435. A[7] = rev(A[7] + 2.453732 * 0.25);
  436. JDE = JDE - 0.62801 * sind(MP) + 0.17172 * E * sind(M) - 0.01183 * E * sind(MP + M) + 0.00862 * sind(2 * MP) + 0.00804 * sind(2 * F) + 0.00454 * E * sind(MP - M) + 0.00204 * E * E * sind(2 * M) - 0.00180 * sind(MP - 2 * F) - 0.00070 * sind(MP + 2 * F) - 0.00040 * sind(3 * MP) - 0.00034 * E * sind(2 * MP - M) + 0.00032 * E * sind(M + 2 * F) + 0.00032 * E * sind(M - 2 * F) - 0.00028 * E * E * sind(MP + 2 * M) + 0.00027 * E * sind(2 * MP + M) - 0.00017 * sind(Omega);
  437. // Next term is w add for first quarter & subtract for second
  438. JDE = JDE + (0.00306 - 0.00038 * E * cosd(M) + 0.00026 * cosd(MP) - 0.00002 * cosd(MP - M) + 0.00002 * cosd(MP + M) + 0.00002 * cosd(2 * F));
  439. quarters[1] = JDE + 0.000325 * sind(A[1]) + 0.000165 * sind(A[2]) + 0.000164 * sind(A[3]) + 0.000126 * sind(A[4]) + 0.000110 * sind(A[5]) + 0.000062 * sind(A[6]) + 0.000060 * sind(A[7]);
  440. // Full moon k=k+0.5
  441. JDE = JDE0 + 29.530588853 * 0.5;
  442. // Already added 0.25 for first quarter
  443. M = rev(M + 29.10535669 * 0.25);
  444. MP = rev(MP + 385.81693528 * 0.25);
  445. F = rev(F + 390.67050274 * 0.25);
  446. Omega = rev(Omega - 1.56375580 * 0.25);
  447. A[1] = rev(A[1] + 0.107408 * 0.25);A[2] = rev(A[2] + 0.016321 * 0.25);A[3] = rev(A[3] + 26.651886 * 0.25);
  448. A[4] = rev(A[4] + 36.412478 * 0.25);A[5] = rev(A[5] + 18.206239 * 0.25);A[6] = rev(A[6] + 53.303771 * 0.25);
  449. A[7] = rev(A[7] + 2.453732 * 0.25);
  450. JDE = JDE - 0.40614 * sind(MP) + 0.17302 * E * sind(M) + 0.01614 * sind(2 * MP) + 0.01043 * sind(2 * F) + 0.00734 * E * sind(MP - M) - 0.00515 * E * sind(MP + M) + 0.00209 * E * E * sind(2 * M) - 0.00111 * sind(MP - 2 * F) - 0.00057 * sind(MP + 2 * F) + 0.00056 * E * sind(2 * MP + M) - 0.00042 * sind(3 * MP) + 0.00042 * E * sind(M + 2 * F) + 0.00038 * E * sind(M - 2 * F) - 0.00024 * E * sind(2 * MP - M) - 0.00017 * sind(Omega) - 0.00007 * sind(MP + 2 * M);
  451. quarters[2] = JDE + 0.000325 * sind(A[1]) + 0.000165 * sind(A[2]) + 0.000164 * sind(A[3]) + 0.000126 * sind(A[4]) + 0.000110 * sind(A[5]) + 0.000062 * sind(A[6]) + 0.000060 * sind(A[7]);
  452. // Last Quarter k=k+0.75
  453. JDE = JDE0 + 29.530588853 * 0.75;
  454. // Already added 0.5 for full moon
  455. M = rev(M + 29.10535669 * 0.25);
  456. MP = rev(MP + 385.81693528 * 0.25);
  457. F = rev(F + 390.67050274 * 0.25);
  458. Omega = rev(Omega - 1.56375580 * 0.25);
  459. A[1] = rev(A[1] + 0.107408 * 0.25);A[2] = rev(A[2] + 0.016321 * 0.25);A[3] = rev(A[3] + 26.651886 * 0.25);
  460. A[4] = rev(A[4] + 36.412478 * 0.25);A[5] = rev(A[5] + 18.206239 * 0.25);A[6] = rev(A[6] + 53.303771 * 0.25);
  461. A[7] = rev(A[7] + 2.453732 * 0.25);
  462. JDE = JDE - 0.62801 * sind(MP) + 0.17172 * E * sind(M) - 0.01183 * E * sind(MP + M) + 0.00862 * sind(2 * MP) + 0.00804 * sind(2 * F) + 0.00454 * E * sind(MP - M) + 0.00204 * E * E * sind(2 * M) - 0.00180 * sind(MP - 2 * F) - 0.00070 * sind(MP + 2 * F) - 0.00040 * sind(3 * MP) - 0.00034 * E * sind(2 * MP - M) + 0.00032 * E * sind(M + 2 * F) + 0.00032 * E * sind(M - 2 * F) - 0.00028 * E * E * sind(MP + 2 * M) + 0.00027 * E * sind(2 * MP + M) - 0.00017 * sind(Omega);
  463. // Next term is w add for first quarter & subtract for second
  464. JDE = JDE - (0.00306 - 0.00038 * E * cosd(M) + 0.00026 * cosd(MP) - 0.00002 * cosd(MP - M) + 0.00002 * cosd(MP + M) + 0.00002 * cosd(2 * F));
  465. quarters[3] = JDE + 0.000325 * sind(A[1]) + 0.000165 * sind(A[2]) + 0.000164 * sind(A[3]) + 0.000126 * sind(A[4]) + 0.000110 * sind(A[5]) + 0.000062 * sind(A[6]) + 0.000060 * sind(A[7]);
  466. return quarters;
  467. };
  468. // JavaScript by Peter Hayes
  469. // http://www.aphayes.pwp.blueyonder.co.uk/
  470. // Copyright 2001-2012
  471. // This code is made freely available but please keep this notice.
  472. // The calculations are approximate but should be good enough for general use,
  473. // I accept no responsibility for errors in astronomy or coding.
  474. BlueYonder.SunRiseSet = function (year, month, day, latitude, longitude) {
  475. // Based on method in sci.astro FAQ by Paul Schlyter
  476. // returns an array holding rise and set times in UTC hours
  477. // NOT accurate at high latitudes
  478. // latitude = your local latitude: north positive, south negative
  479. // longitude = your local longitude: east positive, west negative
  480. // Calculate the Suns position at noon local zone time
  481. var d = dayno(year, month, day, 12.0 - longitude / 15);
  482. var oblecl = 23.4393 - 3.563E-7 * d;
  483. var w = 282.9404 + 4.70935E-5 * d;
  484. var M = 356.0470 + 0.9856002585 * d;
  485. var e = 0.016709 - 1.151E-9 * d;
  486. var E = M + e * (180 / Math.PI) * sind(M) * (1.0 + e * cosd(M));
  487. var A = cosd(E) - e;
  488. var B = Math.sqrt(1 - e * e) * sind(E);
  489. var slon = w + atan2d(B, A);
  490. var sRA = atan2d(sind(slon) * cosd(oblecl), cosd(slon));
  491. while (sRA < 0) {
  492. sRA += 360;
  493. }while (sRA > 360) {
  494. sRA -= 360;
  495. }sRA = sRA / 15;
  496. var sDec = asind(sind(oblecl) * sind(slon));
  497. // Time sun is on the meridian
  498. var lst = local_sidereal(year, month, day, 12 - longitude / 15, longitude);
  499. var MT = 12.0 - longitude / 15 + sRA - lst;
  500. while (MT < 0) {
  501. MT += 24;
  502. }while (MT > 24) {
  503. MT -= 24;
  504. } // hour angle
  505. var cHA0 = (sind(-0.833) - sind(latitude) * sind(sDec)) / (cosd(latitude) * cosd(sDec));
  506. var HA0 = acosd(cHA0);
  507. HA0 = rev(HA0) / 15;
  508. // return rise and set times
  509. return new Array(MT - HA0, MT + HA0);
  510. };
  511. exports.default = BlueYonder;