Изгрев и залез на луната

dakata__92

Super Moderator
Здравейте колеги. Някой знае ли как мога да изчисля часът на изгрева и залеза на луната според определена дата и координати? Намерих стара тема тук във форума, но класът който се използва е много лошо структуриран, като код.

http://web-tourist.net/forum/viewtopic.php?t=121915&highlight=moon

Някой правил ли е по-актуална и лесно четима версия?
 
PHP:
<?php

$sun_info = date_sun_info(strtotime("2019-03-06"), 42.69751, 23.32415);
foreach ($sun_info as $key => $val) {
    echo "$key: " . date("H:i:s", $val) . "<br />";
}

sunrise: 04:53:37
sunset: 16:22:12
transit: 10:37:54
civil_twilight_begin: 04:25:30
civil_twilight_end: 16:50:18
nautical_twilight_begin: 03:52:50
nautical_twilight_end: 17:22:59
astronomical_twilight_begin: 03:19:57
astronomical_twilight_end: 17:55:51
 
Ticketa каза:
PHP:
<?php

$sun_info = date_sun_info(strtotime("2019-03-06"), 42.69751, 23.32415);
foreach ($sun_info as $key => $val) {
    echo "$key: " . date("H:i:s", $val) . "<br />";
}

sunrise: 04:53:37
sunset: 16:22:12
transit: 10:37:54
civil_twilight_begin: 04:25:30
civil_twilight_end: 16:50:18
nautical_twilight_begin: 03:52:50
nautical_twilight_end: 17:22:59
astronomical_twilight_begin: 03:19:57
astronomical_twilight_end: 17:55:51

Това е повече от ясно, но се отнася за слънцето. Търся си опростен метод за да ми даде тази информация и за луната.
 
PHP:
<?php
 
/******************************************************************************
* The following is a PHP implementation of the JavaScript code found at:      *
* http://bodmas.org/astronomy/riset.html                                      *
*                                                                             *
* Original maths and code written by Keith Burnett <bodmas.org>               *
* PHP port written by Matt "dxprog" Hackmann <dxprog.com>                     *
*                                                                             *
* This program is free software: you can redistribute it and/or modify        *
* it under the terms of the GNU General Public License as published by        *
* the Free Software Foundation, either version 3 of the License, or           *
* (at your option) any later version.                                         *
*                                                                             *
* This program is distributed in the hope that it will be useful,             *
* but WITHOUT ANY WARRANTY; without even the implied warranty of              *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               *
* GNU General Public License for more details.                                *
*                                                                             *
* You should have received a copy of the GNU General Public License           *
* along with this program.  If not, see <http://www.gnu.org/licenses/>.       *
******************************************************************************/
 
class Moon {
       
        /**
         * Calculates the moon rise/set for a given location and day of year
         */
        public static function calculateMoonTimes($month, $day, $year, $lat, $lon) {
       
                $utrise = $utset = 0;
               
                $timezone = (int)($lon / 15);
                $date = self::modifiedJulianDate($month, $day, $year);
                $date -= $timezone / 24;
                $latRad = deg2rad($lat);
                $sinho = 0.0023271056;
                $sglat = sin($latRad);
                $cglat = cos($latRad);
               
                $rise = false;
                $set = false;
                $above = false;
                $hour = 1;
                $ym = self::sinAlt($date, $hour - 1, $lon, $cglat, $sglat) - $sinho;
               
                $above = $ym > 0;
                while ($hour < 25 && (false == $set || false == $rise)) {
               
                        $yz = self::sinAlt($date, $hour, $lon, $cglat, $sglat) - $sinho;
                        $yp = self::sinAlt($date, $hour + 1, $lon, $cglat, $sglat) - $sinho;
                       
                        $quadout = self::quad($ym, $yz, $yp);
                        $nz = $quadout[0];
                        $z1 = $quadout[1];
                        $z2 = $quadout[2];
                        $xe = $quadout[3];
                        $ye = $quadout[4];
                       
                        if ($nz == 1) {
                                if ($ym < 0) {
                                        $utrise = $hour + $z1;
                                        $rise = true;
                                } else {
                                        $utset = $hour + $z1;
                                        $set = true;
                                }
                        }
                       
                        if ($nz == 2) {
                                if ($ye < 0) {
                                        $utrise = $hour + $z2;
                                        $utset = $hour + $z1;
                                } else {
                                        $utrise = $hour + $z1;
                                        $utset = $hour + $z2;
                                }
                        }
                       
                        $ym = $yp;
                        $hour += 2.0;
               
                }
                // Convert to unix timestamps and return as an object
                $retVal = new stdClass();
                $utrise = self::convertTime($utrise);
                $utset = self::convertTime($utset);
                $retVal->moonrise = $rise ? mktime($utrise['hrs'], $utrise['min'], 0, $month, $day, $year) : mktime(0, 0, 0, $month, $day + 1, $year);
                $retVal->moonset = $set ? mktime($utset['hrs'], $utset['min'], 0, $month, $day, $year) : mktime(0, 0, 0, $month, $day + 1, $year);
                return $retVal;
       
        }
       
        /**
         *      finds the parabola throuh the three points (-1,ym), (0,yz), (1, yp)
         *  and returns the coordinates of the max/min (if any) xe, ye
         *  the values of x where the parabola crosses zero (roots of the self::quadratic)
         *  and the number of roots (0, 1 or 2) within the interval [-1, 1]
         *
         *      well, this routine is producing sensible answers
         *
         *  results passed as array [nz, z1, z2, xe, ye]
         */
        private static function quad($ym, $yz, $yp) {
 
                $nz = $z1 = $z2 = 0;
                $a = 0.5 * ($ym + $yp) - $yz;
                $b = 0.5 * ($yp - $ym);
                $c = $yz;
                $xe = -$b / (2 * $a);
                $ye = ($a * $xe + $b) * $xe + $c;
                $dis = $b * $b - 4 * $a * $c;
                if ($dis > 0) {
                        $dx = 0.5 * sqrt($dis) / abs($a);
                        $z1 = $xe - $dx;
                        $z2 = $xe + $dx;
                        $nz = abs($z1) < 1 ? $nz + 1 : $nz;
                        $nz = abs($z2) < 1 ? $nz + 1 : $nz;
                        $z1 = $z1 < -1 ? $z2 : $z1;
                }
 
                return array($nz, $z1, $z2, $xe, $ye);
               
        }
 
        /**
         *      this rather mickey mouse function takes a lot of
         *  arguments and then returns the sine of the altitude of the moon
         */
        private static function sinAlt($mjd, $hour, $glon, $cglat, $sglat) {
               
                $mjd += $hour / 24;
                $t = ($mjd - 51544.5) / 36525;
                $objpos = self::minimoon($t);
 
                $ra = $objpos[1];
                $dec = $objpos[0];
                $decRad = deg2rad($dec);
                $tau = 15 * (self::lmst($mjd, $glon) - $ra);
 
                return $sglat * sin($decRad) + $cglat * cos($decRad) * cos(deg2rad($tau));
 
        }
 
        /**
         *      returns an angle in degrees in the range 0 to 360
         */
        private static function degRange($x) {
                $b = $x / 360;
                $a = 360 * ($b - (int)$b);
                $retVal = $a < 0 ? $a + 360 : $a;
                return $retVal;
        }
 
        private static function lmst($mjd, $glon) {
                $d = $mjd - 51544.5;
                $t = $d / 36525;
                $lst = self::degRange(280.46061839 + 360.98564736629 * $d + 0.000387933 * $t * $t - $t * $t * $t / 38710000);
                return $lst / 15 + $glon / 15;
        }
 
        /**
         * takes t and returns the geocentric ra and dec in an array mooneq
         * claimed good to 5' (angle) in ra and 1' in dec
         * tallies with another approximate method and with ICE for a couple of dates
         */
        private static function minimoon($t) {
                       
                $p2 = 6.283185307;
                $arc = 206264.8062;
                $coseps = 0.91748;
                $sineps = 0.39778;
               
                $lo = self::frac(0.606433 + 1336.855225 * $t);
                $l = $p2 * self::frac(0.374897 + 1325.552410 * $t);
                $l2 = $l * 2;
                $ls = $p2 * self::frac(0.993133 + 99.997361 * $t);
                $d = $p2 * self::frac(0.827361 + 1236.853086 * $t);
                $d2 = $d * 2;
                $f = $p2 * self::frac(0.259086 + 1342.227825 * $t);
                $f2 = $f * 2;
               
                $sinls = sin($ls);
                $sinf2 = sin($f2);
               
                $dl = 22640 * sin($l);
                $dl += -4586 * sin($l - $d2);
                $dl += 2370 * sin($d2);
                $dl += 769 * sin($l2);
                $dl += -668 * $sinls;
                $dl += -412 * $sinf2;
                $dl += -212 * sin($l2 - $d2);
                $dl += -206 * sin ($l + $ls - $d2);
                $dl += 192 * sin($l + $d2);
                $dl += -165 * sin($ls - $d2);
                $dl += -125 * sin($d);
                $dl += -110 * sin($l + $ls);
                $dl += 148 * sin($l - $ls);
                $dl += -55 * sin($f2 - $d2);
               
                $s = $f + ($dl + 412 * $sinf2 + 541 * $sinls) / $arc;
                $h = $f - $d2;
                $n = -526 * sin($h);
                $n += 44 * sin($l + $h);
                $n += -31 * sin(-$l + $h);
                $n += -23 * sin($ls + $h);
                $n += 11 * sin(-$ls + $h);
                $n += -25 * sin(-$l2 + $f);
                $n += 21 * sin(-$l + $f);
               
                $L_moon = $p2 * self::frac($lo + $dl / 1296000);
                $B_moon = (18520.0 * sin($s) + $n) / $arc;
               
                $cb = cos($B_moon);
                $x = $cb * cos($L_moon);
                $v = $cb * sin($L_moon);
                $w = sin($B_moon);
                $y = $coseps * $v - $sineps * $w;
                $z = $sineps * $v + $coseps * $w;
                $rho = sqrt(1 - $z * $z);
                $dec = (360 / $p2) * atan($z / $rho);
                $ra = (48 / $p2) * atan($y / ($x + $rho));
                $ra = $ra < 0 ? $ra + 24 : $ra;
               
                return array($dec, $ra);
               
        }
 
        /**
         *      returns the self::fractional part of x as used in self::minimoon and minisun
         */
        private static function frac($x) {
                $x -= (int)$x;
                return $x < 0 ? $x + 1 : $x;
        }
 
        /**
         * Takes the day, month, year and hours in the day and returns the
         * modified julian day number defined as mjd = jd - 2400000.5
         * checked OK for Greg era dates - 26th Dec 02
         */
        private static function modifiedJulianDate($month, $day, $year) {
               
                if ($month <= 2) {
                        $month += 12;
                        $year--;
                }
               
                $a = 10000 * $year + 100 * $month + $day;
                $b = 0;
                if ($a <= 15821004.1) {
                        $b = -2 * (int)(($year + 4716) / 4) - 1179;
                } else {
                        $b = (int)($year / 400) - (int)($year / 100) + (int)($year / 4);
                }
 
                $a = 365 * $year - 679004;
                return $a + $b + (int)(30.6001 * ($month + 1)) + $day;
               
        }
 
        /**
         * Converts an hours decimal to hours and minutes
         */
        private static function convertTime($hours) {
 
                $hrs = (int)($hours * 60 + 0.5) / 60.0;
                $h = (int)($hrs);
                $m = (int)(60 * ($hrs - $h) + 0.5);
                return array('hrs'=>$h, 'min'=>$m);
               
        }
}
moon.php



PHP:
date_default_timezone_set('Europe/Sofia');
include('moon.php');
print_r(Moon::calculateMoonTimes(6, 28, 2011, 36.754478, -96.110291));
 

Горе