/MoonPhase.php

https://github.com/mootinator/PDFCalendarLib · PHP · 183 lines · 152 code · 17 blank · 14 comment · 38 complexity · 4f15d4fbe2a8f8153ba3d3f1bbd6cf64 MD5 · raw file

  1. <?php
  2. /**
  3. * -MoonPhase - Calculte the percent moon phase.
  4. * Calculate the phases commonly found on a monthly calendar.
  5. *
  6. * Reasonably accurate at 1 hour resolution.
  7. *
  8. * @author Kevin Stricker
  9. *
  10. * Ported from http://www.voidware.com/phase.c
  11. *
  12. */
  13. define("PI", 3.1415926535897932384626433832795);
  14. define("RAD", (PI/180.0));
  15. define("SMALL_FLOAT", 1e-12);
  16. define("MINUTE", 0.016666666666667);
  17. function trunc($number)
  18. {
  19. if ($number >= 0)
  20. {
  21. return floor($number);
  22. }
  23. else
  24. {
  25. return ceil($number);
  26. }
  27. }
  28. class MoonPhase {
  29. function julian($year, $month, $day)
  30. {
  31. $a = $b = $c = $e = 0;
  32. if ($month < 3) {
  33. $year--;
  34. $month += 12;
  35. }
  36. if ($year > 1582 || ($year == 1582 && $month > 10) ||
  37. ($year == 1582 && $month == 10 && $day > 15)){
  38. $a = trunc($year / 100);
  39. $b = 2-$a+trunc($a/4);
  40. }
  41. $c = trunc(365.25*$year);
  42. $e = trunc(30.6001*($month+1));
  43. return $b+$c+$e+$day+1720994.5;
  44. }
  45. function sun_position($julian = 11567.666666667)
  46. {
  47. $n = $x = $e = $l = $dl = $v = 0.0;
  48. $m2 = 0.0;
  49. $i = 0;
  50. $n = 360.0/365.2422 * $julian;
  51. $i = trunc($n/360.0);
  52. $n = $n-$i*360.0;
  53. $x=$n-3.762863;
  54. if ($x<0) $x += 360;
  55. $x *= RAD;
  56. $e = $x;
  57. do {
  58. $dl = $e-0.016718*sin($e)-$x;
  59. $e=$e-$dl/(1-.016718*cos($e));
  60. } while (abs($dl)>=SMALL_FLOAT);
  61. $v=360.0/PI*atan(1.01686011182*tan($e/2));
  62. $l=$v+282.596403;
  63. $i=trunc($l/360);
  64. $l=$l-$i*360.0;
  65. return $l;
  66. }
  67. function moon_position($julian = 11567.666666667, $sun=158.8689200455)
  68. {
  69. $ms = $l = $mm = $n = $ev = $sms = $z = $x = $lm = $bm = $ae = $ec = 0.0;
  70. $d = 0.0;
  71. $ds = $as = $dm = 0.0;
  72. $i = 0;
  73. $ms = 0.985647332099*$julian - 3.762863;
  74. if ($ms < 0) $ms += 360.0;
  75. $l = 13.176396*$julian + 64.975464;
  76. $i = trunc($l/360);
  77. $l = $l - $i*360.0;
  78. if ($l < 0) $l += 360.0;
  79. $mm = $l-0.1114041*$julian-349.383063;
  80. $i = trunc($mm/360);
  81. $mm -= $i*360.0;
  82. $n = 151.950429 - 0.0529539*$julian;
  83. $i = trunc($n/360);
  84. $n -= $i*360.0;
  85. $ev = 1.2739*sin((2*($l-$sun)-$mm)*RAD);
  86. $sms = sin($ms*RAD);
  87. $ae = 0.1858*$sms;
  88. $mm += $ev-$ae- 0.37*$sms;
  89. $ec = 6.2886*sin($mm*RAD);
  90. $l += $ev+$ec-$ae+ 0.214*sin(2*$mm*RAD);
  91. $l= 0.6583*sin(2*($l-$sun)*RAD)+$l;
  92. return $l;
  93. }
  94. function moon_phase($year, $month, $day, $hour)
  95. {
  96. $julian = $this->julian($year, $month, $day+$hour/24.0)-2444238.5;
  97. $ls = $this->sun_position($julian);
  98. $lm = $this->moon_position($julian, $ls);
  99. $t = $lm - $ls;
  100. if ($t < 0) $t += 360;
  101. return (1.0 - cos(($lm - $ls)*RAD))/2;
  102. }
  103. function phase_changes($year, $month, $hours_step = 0.25)
  104. {
  105. $ts = mktime(0,0,0,$month,1,$year);
  106. $days_in_month = date('t',$ts);
  107. $phase_max = 0;
  108. $phase_min = 1;
  109. $phase_last = 0;
  110. $day_last = 0;
  111. $hour_last = 0;
  112. $minute_last = 0;
  113. $first = true;
  114. $return = array();
  115. for($day = 0; $day <= $days_in_month + 1; $day++)
  116. {
  117. for($hour = 0; $hour < 24; $hour += $hours_step)
  118. {
  119. $phase = $this->moon_phase($year, $month, $day, $hour);
  120. if (!$first)
  121. {
  122. /* Full */
  123. if ($phase > $phase_last && $phase > $phase_max)
  124. {
  125. $phase_max = $phase;
  126. }
  127. else if ($phase_max > 0)
  128. {
  129. if ($day_last > 0 && $day_last <= $days_in_month)
  130. $return[] = array('day' => $day_last, 'hour' => $hour_last, 'minute' => $minute_last, 'phase' => 'Full Moon');
  131. $phase_max = 0;
  132. }
  133. /* Quarters */
  134. if ($phase >= 0.5 && $phase_last < 0.5)
  135. {
  136. if ($day_last > 0 && $day_last <= $days_in_month)
  137. $return[] = array('day' => $day_last, 'hour' => $hour_last, 'minute' => $minute_last, 'phase' => 'First Quarter');
  138. }
  139. if ($phase <= 0.5 && $phase_last > 0.5)
  140. {
  141. if ($day_last > 0 && $day_last <= $days_in_month)
  142. $return[] = array('day' => $day_last, 'hour' => $hour_last, 'minute' => $minute_last, 'phase' => 'Last Quarter');
  143. }
  144. /* New */
  145. if ($phase < $phase_last && $phase < $phase_min)
  146. {
  147. $phase_min = $phase;
  148. }
  149. else if($phase_min < 1)
  150. {
  151. if ($day_last > 0 && $day_last <= $days_in_month)
  152. $return[] = array('day' => $day_last, 'hour' => $hour_last, 'minute' => $minute_last, 'phase' => 'New Moon');
  153. $phase_min = 1;
  154. }
  155. }
  156. $phase_last = $phase;
  157. $day_last = $day;
  158. $hour_last = trunc($hour);
  159. $minute_last = round(($hour - $hour_last)/MINUTE);
  160. $first = false;
  161. }
  162. }
  163. return $return;
  164. }
  165. }
  166. ?>