moon.h 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. #ifndef __MOON_H
  2. #define __MOON_H
  3. #include <math.h>
  4. #include <time.h>
  5. #include <string>
  6. namespace moon_constants {
  7. // JDN stands for Julian Day Number
  8. // Angles here are in degrees
  9. // 1980 January 0.0 in JDN
  10. double epoch = 2444239.0;
  11. // Ecliptic longitude of the Sun at epoch 1980.0
  12. double ecliptic_longitude_epoch = 278.833540;
  13. // Ecliptic longitude of the Sun at perigee
  14. double ecliptic_longitude_perigee = 282.596403;
  15. // Eccentricity of Earth's orbit
  16. double eccentricity = 0.016718;
  17. // Semi-major axis of Earth's orbit, in kilometers
  18. double sun_smaxis = 1.49585e8;
  19. // Sun's angular size, in degrees, at semi-major axis distance
  20. double sun_angular_size_smaxis = 0.533128;
  21. //// Elements of the Moon's orbit, epoch 1980.0
  22. // Moon's mean longitude at the epoch
  23. double moon_mean_longitude_epoch = 64.975464;
  24. // Mean longitude of the perigee at the epoch
  25. double moon_mean_perigee_epoch = 349.383063;
  26. // Mean longitude of the node at the epoch
  27. double node_mean_longitude_epoch = 151.950429;
  28. // Inclination of the Moon's orbit
  29. double moon_inclination = 5.145396;
  30. // Eccentricity of the Moon's orbit
  31. double moon_eccentricity = 0.054900;
  32. // Moon's angular size at distance a from Earth
  33. double moon_angular_size = 0.5181;
  34. // Semi-mojor axis of the Moon's orbit, in kilometers
  35. double moon_smaxis = 384401.0;
  36. // Parallax at a distance a from Earth
  37. double moon_parallax = 0.9507;
  38. // Synodic month (new Moon to new Moon), in days
  39. double synodic_month = 29.53058868;
  40. // Base date for E. W. Brown's numbered series of lunations (1923 January 16)
  41. double lunations_base = 2423436.0;
  42. //// Properties of the Earth
  43. double earth_radius = 6378.16;
  44. }
  45. namespace c = moon_constants;
  46. #define THE_PI 3.14159265358979323846
  47. namespace moon {
  48. inline double fixangle(double a) {
  49. return a - 360.0 * floor(a/360.0);
  50. }
  51. inline double torad(double d) {
  52. return d * THE_PI / 180.0;
  53. }
  54. inline double todeg(double r) {
  55. return r * 180.0 / THE_PI;
  56. }
  57. inline double dsin(double d) {
  58. return sin(torad(d));
  59. }
  60. inline double dcos(double d) {
  61. return cos(torad(d));
  62. }
  63. enum PHASE {
  64. NEW = 1,
  65. WAXING_CRESCENT = 2,
  66. FIRST_QUARTER = 3,
  67. WAXING_GIBBOUS = 4,
  68. FULL = 5,
  69. WANING_GIBBOUS = 6,
  70. LAST_QUARTER = 7,
  71. WANING_CRESCENT = 8
  72. };
  73. inline PHASE phase_n(double p) {
  74. double PRECISION = 0.05;
  75. if (p <= 0 + PRECISION) {
  76. return NEW;
  77. } else if (p <= 0.25 - PRECISION) {
  78. return WAXING_CRESCENT;
  79. } else if (p <= 0.25 + PRECISION) {
  80. return FIRST_QUARTER;
  81. } else if (p <= 0.5 - PRECISION) {
  82. return WAXING_GIBBOUS;
  83. } else if (p <= 0.5 + PRECISION) {
  84. return FULL;
  85. } else if (p <= 0.75 - PRECISION) {
  86. return WANING_GIBBOUS;
  87. } else if (p <= 0.75 + PRECISION) {
  88. return LAST_QUARTER;
  89. } else if (p <= 1.0 - PRECISION) {
  90. return WANING_CRESCENT;
  91. } else if (p <= 1.0 + PRECISION) {
  92. return NEW;
  93. }
  94. return NEW;
  95. }
  96. /*
  97. [0.95, 1.00] NEW
  98. [0, 0.05] NEW
  99. [0.05, 0.20] WAXING_CRESCENT
  100. [0.20, 0.30] FIRST_QUARTER
  101. [0.30, 0.45] WAXING_GIBBOUS
  102. [0.45, 0.55] FULL
  103. [0.55, 0.70] WANING_GIBBOUS
  104. [0.70, 0.80] LAST_QUARTER
  105. [0.80, 0.95] WANING_CRESCENT
  106. [0.95, 1.00] NEW
  107. WANING - 0.3
  108. WAXING - 0.3
  109. QUARTER - 0.2
  110. NEW - 0.1
  111. FULL - 0.1
  112. */
  113. inline std::string phase_string(PHASE p) {
  114. switch (p) {
  115. case NEW: return "new"_m;
  116. case WAXING_CRESCENT: return "waxing crescent"_m;
  117. case FIRST_QUARTER: return "first quarter"_m;
  118. case WAXING_GIBBOUS: return "waxing gibbous"_m;
  119. case FULL: return "full"_m;
  120. case WANING_GIBBOUS: return "waning gibbous"_m;
  121. case LAST_QUARTER: return "last quarter"_m;
  122. case WANING_CRESCENT: return "waning crescent"_m;
  123. }
  124. return "error";
  125. }
  126. inline double kepler(double m, double ecc) {
  127. // Solve the equation of Kepler.
  128. double epsilon = 1e-6;
  129. m = torad(m);
  130. double e = m;
  131. while (1) {
  132. double delta = e - ecc * sin(e) - m;
  133. e = e - delta / (1.0 - ecc * cos(e));
  134. if (fabs(delta) <= epsilon)
  135. break;
  136. }
  137. return e;
  138. }
  139. struct PhaseInfo {
  140. double phase_n;
  141. double illuminated;
  142. double age;
  143. double distance;
  144. double angular_diameter;
  145. double sun_distance;
  146. double sun_angular_diameter;
  147. PHASE phase;
  148. std::string phase_str;
  149. };
  150. inline PhaseInfo phase(time_t _phase_date) {
  151. /** Calculate phase of moon as a fraction:
  152. The argument is the time for which the phase is requested.
  153. Returns a struct containing the terminator phase angle as a
  154. percentage of a full circle (i.e., 0 to 1), the illuminated
  155. fraction of the Moon's disc, the Moon's age in days and fraction,
  156. the distance of the Moon from the centre of the Earth, and the
  157. angular diameter subtended by the Moon as seen by an observer at
  158. the centre of the Earth. **/
  159. // Calculation of the Sun's position
  160. // Convert to JDN
  161. double phase_date = ((_phase_date / 86400) + 1) + 2440587.5;
  162. // date within the epoch
  163. double day = phase_date - c::epoch;
  164. // Mean anomaly of the Sun
  165. double N = fixangle((360/365.2422) * day);
  166. // Convert from perigee coordinates to epoch 1980
  167. double M = fixangle(N + c::ecliptic_longitude_epoch - c::ecliptic_longitude_perigee);
  168. // Solve Kepler's equation
  169. double Ec = kepler(M, c::eccentricity);
  170. Ec = sqrt((1 + c::eccentricity) / (1 - c::eccentricity)) * tan(Ec/2.0);
  171. // True anomaly
  172. Ec = 2 * todeg(atan(Ec));
  173. // Suns's geometric ecliptic longuitude
  174. double lambda_sun = fixangle(Ec + c::ecliptic_longitude_perigee);
  175. // Orbital distance factor
  176. double F = ((1 + c::eccentricity * cos(torad(Ec))) / pow(1 - c::eccentricity,2));;
  177. // Distance to Sun in km
  178. double sun_dist = c::sun_smaxis / F;
  179. double sun_angular_diameter = F * c::sun_angular_size_smaxis;
  180. /*
  181. *
  182. * Calculation of the Moon's position */
  183. // Moon's mean longitude
  184. double moon_longitude = fixangle(13.1763966 * day + c::moon_mean_longitude_epoch);
  185. // Moon's mean anomaly
  186. double MM = fixangle(moon_longitude - 0.1114041 * day - c::moon_mean_perigee_epoch);
  187. // Moon's ascending node mean longitude
  188. // MN = fixangle(c.node_mean_longitude_epoch - 0.0529539 * day)
  189. double evection = 1.2739 * sin(torad(2*(moon_longitude - lambda_sun) - MM));
  190. // Annual equation
  191. double annual_eq = 0.1858 * sin(torad(M));
  192. // Correction term
  193. double A3 = 0.37 * sin(torad(M));
  194. double MmP = MM + evection - annual_eq - A3;
  195. // Correction for the equation of the centre
  196. double mEc = 6.2886 * sin(torad(MmP));
  197. // Another correction term
  198. double A4 = 0.214 * sin(torad(2 * MmP));
  199. // Corrected longitude
  200. double lP = moon_longitude + evection + mEc - annual_eq + A4;
  201. // Variation
  202. double variation = 0.6583 * sin(torad(2*(lP - lambda_sun)));
  203. // True longitude
  204. double lPP = lP + variation;
  205. //
  206. // Calculation of the Moon's inclination
  207. // unused for phase calculation.
  208. // Corrected longitude of the node
  209. // NP = MN - 0.16 * sin(torad(M))
  210. // Y inclination coordinate
  211. // y = sin(torad(lPP - NP)) * cos(torad(c.moon_inclination))
  212. // X inclination coordinate
  213. // x = cos(torad(lPP - NP))
  214. // Ecliptic longitude (unused?)
  215. // lambda_moon = todeg(atan2(y,x)) + NP
  216. // Ecliptic latitude (unused?)
  217. // BetaM = todeg(asin(sin(torad(lPP - NP)) * sin(torad(c.moon_inclination))))
  218. /*
  219. *
  220. * Calculation of the phase of the Moon */
  221. // Age of the Moon, in degrees
  222. double moon_age = lPP - lambda_sun;
  223. // Phase of the Moon
  224. double moon_phase = (1 - cos(torad(moon_age))) / 2.0;
  225. // Calculate distance of Moon from the centre of the Earth
  226. double moon_dist = (c::moon_smaxis * pow(1 - c::moon_eccentricity,2)) /
  227. (1 + c::moon_eccentricity * cos(torad(MmP + mEc)));
  228. // Calculate Moon's angular diameter
  229. double moon_diam_frac = moon_dist / c::moon_smaxis;
  230. double moon_angular_diameter = c::moon_angular_size / moon_diam_frac;
  231. // Calculate Moon's parallax (unused?)
  232. // moon_parallax = c.moon_parallax / moon_diam_frac
  233. double pp = fixangle(moon_age) / 360.0;
  234. PHASE ppn = phase_n(pp);
  235. PhaseInfo res;
  236. res.phase_n = pp;
  237. res.illuminated = moon_phase;
  238. res.age = c::synodic_month * fixangle(moon_age) / 360.0;
  239. res.distance = moon_dist;
  240. res.angular_diameter = moon_angular_diameter;
  241. res.sun_distance = sun_dist;
  242. res.sun_angular_diameter = sun_angular_diameter;
  243. res.phase = ppn;
  244. res.phase_str = phase_string(ppn);
  245. return res;
  246. }
  247. struct Moon {
  248. PhaseInfo pi;
  249. void init(time_t date = ::time(NULL)) {
  250. pi = phase(date);
  251. }
  252. };
  253. }
  254. namespace serialize {
  255. template <>
  256. struct reader<moon::Moon> {
  257. void read(Source& s, moon::Moon& t) {
  258. serialize::read(s, t.pi.phase_n);
  259. serialize::read(s, t.pi.illuminated);
  260. serialize::read(s, t.pi.age);
  261. serialize::read(s, t.pi.distance);
  262. serialize::read(s, t.pi.angular_diameter);
  263. serialize::read(s, t.pi.sun_distance);
  264. serialize::read(s, t.pi.sun_angular_diameter);
  265. unsigned int phase;
  266. serialize::read(s, phase);
  267. t.pi.phase = (moon::PHASE)phase;
  268. serialize::read(s, t.pi.phase_str);
  269. }
  270. };
  271. template <>
  272. struct writer<moon::Moon> {
  273. void write(Sink& s, const moon::Moon& t) {
  274. serialize::write(s, t.pi.phase_n);
  275. serialize::write(s, t.pi.illuminated);
  276. serialize::write(s, t.pi.age);
  277. serialize::write(s, t.pi.distance);
  278. serialize::write(s, t.pi.angular_diameter);
  279. serialize::write(s, t.pi.sun_distance);
  280. serialize::write(s, t.pi.sun_angular_diameter);
  281. serialize::write(s, (unsigned int)t.pi.phase);
  282. serialize::write(s, t.pi.phase_str);
  283. }
  284. };
  285. }
  286. #endif