Astro-Montenbruck

 view release on metacpan or  search on metacpan

lib/Astro/Montenbruck/RiseSet.pm  view on Meta::CPAN

                my ( $evt, $jd ) = @_;
                $res{$evt} = $jd;
                $on_event->(@_);
            },
            on_noevent => sub {
                $on_noevent->(@_);
            },
            %arg,
            get_position => sub { _get_equatorial( $SU, $_[0] ) },
            sin_h0       => sin( deg2rad( $H0_TWL{$type} ) ),
        );
        return %res;
    }

    riseset_func(%arg)->(
        %arg,
        get_position => sub { _get_equatorial( $SU, $_[0] ) },
        sin_h0       => sin( deg2rad( $H0_TWL{$type} ) ),
        on_event     => $on_event,
        on_noevent   => $on_noevent
    );
}

sub riseset {
    my %arg = @_;
    my $pla = delete $arg{planet};
    my $h0  = do {
        given ($pla) {
            $H0_SUN when $SU;
            $H0_MOO when $MO;
            default { $H0_PLA }
        }
    };
    my $func = riseset_func(%arg);
    sub {
        my %arg = ( on_event => sub { }, on_noevent => sub { }, @_ );

        if (wantarray) {

            # if caller asks for a result, collect events to %res hash
            my %res;
            $func->(
                get_position => sub { _get_equatorial( $pla, $_[0] ) },
                sin_h0       => sin( deg2rad($h0) ),
                on_event     => sub {
                    my ( $evt, $jd ) = @_;
                    $arg{on_event}->(@_);
                    $res{$evt} = { ok => 1, jd => $jd };
                },
                on_noevent => sub {
                    my ($state) = shift;
                    $arg{on_noevent}->(@_);
                    my $evt =
                      $state eq $STATE_NEVER_RISES ? $EVT_RISE : $EVT_SET;
                    $res{$evt} = { ok => 0, state => $state };
                }
            );
            return %res;
        }

 # if caller doesn't ask for a result, just call the function with the callbacks
        $func->(
            get_position => sub { _get_equatorial( $pla, $_[0] ) },
            sin_h0       => sin( deg2rad($h0) ),
            on_event     => $arg{on_event},
            on_noevent   => $arg{on_noevent},
        );
    }
}

sub rst {

    # build top-level function for any event and any celestial object
    # for given time and place
    my $rst = rst_func(@_);

    sub {
        my $obj = shift;
        my %arg = ( on_event => sub { }, on_noevent => sub { }, @_ );

        my $h0 = do {
            given ($obj) {
                $H0_SUN when $SU;
                $H0_MOO when $MO;
                default { $H0_PLA }
            }
        };

        # build second level functon for calculating any event for given object
        my $evt_func = $rst->(
            get_position => sub { _get_equatorial( $obj, $_[0] ) },
            sin_h0       => sin( deg2rad($h0) )
        );

        if (wantarray) {

            # if caller asks for a result, collect events to %res hash
            my %res;
            for (@RS_EVENTS) {
                my ( $state, $jd ) = $evt_func->($_);
                if ( $state eq $_ ) {
                    $arg{on_event}->( $_, $jd );
                    $res{$_} = { ok => 1, jd => $jd };
                }
                else {
                    $arg{on_noevent}->( $_, $state );
                    $res{$_} = { ok => 0, state => $state };
                }
            }
            return %res;
        }

 # if caller doesn't ask for a result, just call the function with the callbacks
        for (@RS_EVENTS) {
            my ( $state, $jd ) = $evt_func->($_);
            if ( $state eq $_ ) {
                $arg{on_event}->( $_, $jd );
            }
            else {
                $arg{on_noevent}->( $_, $state );
            }
        }
    }
}

1;
__END__

=pod

=encoding UTF-8

=head1 NAME

Astro::Montenbruck::RiseSet - rise, set, transit.

=head1 SYNOPSIS

    use Astro::Montenbruck::Ephemeris::Planet qw/:ids/;
    use Astro::Montenbruck::MathUtils qw/frac/;
    use Astro::Montenbruck::RiseSet::Constants qw/:all/;
    use Astro::Montenbruck::RiseSet qw/:all/;

    # create function for calculating rise/set/transit events for Munich, Germany, on March 23, 1989.
    my $func = rst(
        date   => [1989, 3, 23],
        phi    => 48.1,
        lambda => -11.6
    );

    # calculate Moon rise, set and transit
    $func->(
        $MO,
        on_event   => sub {
            my ($evt, $jd) = @_;
            say "$evt: $jd";
        },
        on_noevent => sub {
            my ($evt, $state) = @_; # $STATE_CIRCUMPOLAR or $STATE_NEVER_RISES
            say "$evt: $state";
        }        
    );

    # alternatively, call the function in list context:
    my %res = $func->($MO); # result structure is described below

    # calculate civil twilight    
    twilight(
        date       => [1989, 3, 23],
        phi        => 48.1,
        lambda     => -11.6,
        on_event   => sub {
            my ($evt, $jd) = @_;

lib/Astro/Montenbruck/RiseSet.pm  view on Meta::CPAN


Sometimes rise and set happen on different calendar dates. For example, here is the output of C<riseset.pl>
script:

  $ perl .\script\riseset.pl --date=1989-03-28 --place=48.1 -11.6 --timezone=UTC

  Date      :  1989-03-28 UTC
  Place     :  48N06, 011E35
  Time Zone :  UTC

          rise       transit    set     
  Moon    23:34:17   03:23:59   07:10:54

This directly depends on time zone. Since event time is always given as Julian date,
it is not hard to determine correct order of events. 

=head1 EXPORT

=head2 FUNCTIONS

=over

=item * L</rst( %args )>

=item * L</riseset( %args )>

=item * L</twilight( %args )>

=back

=head1 FUNCTIONS


=head2 rst( %args )

Returns function for calculating times of rises, sets and transits of celestial bodies. See
L<Astro::Montenbruck::RiseSet::Plarise/rst> .

=head3 Named Arguments

=over

=item * 

B<date> - array of B<year> (astronomical, zero-based), B<month> [1..12] and B<day>, [1..31].

=item * 

B<phi> - geographical latitude, degrees, positive northward

=item * 

B<lambda> - geographical longitude, degrees, positive westward

=back

=head3 Returns

function, which calculates rise, set and transit for a celestial body. 
It accepts celestial body identifier as positional argument (see L<Astro::Montenbruck::Ephemeris::Planet>)
and two optional callbacks as named arguments: 

=over

=item * 

B<on_event($event, $jd> - callback called when the event time is determined. The first argument
is one of: C<$EVT_RISE>, C<$EVT_SET> or C<$EVT_TRANSIT> constants (see L<Astro::Montenbruck::RiseSet::Constants>),
the second - I<Standard Julian Date>.

=item * 

B<on_noevent($event, $state> - callback called when the body is I<circumpolar> or I<never rises>. 
The first argument is then one of: C<$EVT_RISE>, C<$EVT_SET> or C<$EVT_TRANSIT>, the second - either 
C<$STATE_CIRCUMPOLAR> or C<$STATE_NEVER_RISES>.

=back


=head4 List context

When called in list context:
  
  my %res = func();

the function returns a hash:
  
  (
      rise    => $hashref,
      set     => $hashref,
      transit => $hashref  
  )
  
When rise or set takes place, C<$hashref> contains:

  {ok => 1, jd => JD} 

JD is a Standard Julian Date. Otherwise, 
  
  {ok => 0, state => STATE}

STATE is C<$STATE_CIRCUMPOLAR> or C<$STATE_NEVER_RISES>.


=head2 riseset( %args )

Returns function for calculating times of rises and sets of given celestial body. See
L<Astro::Montenbruck::RiseSet::Sunset/riseset_func>.

=head3 Named Arguments

=over

=item * 

B<planet> - celestial body identifier (see L<Astro::Montenbruck::Ephemeris::Planet>)

=item * 

B<date> - array of B<year> (astronomical, zero-based), B<month> [1..12] and B<day>, [1..31].

=item * 

B<phi> - geographical latitude, degrees, positive northward

=item * 

B<lambda> - geographical longitude, degrees, positive westward

=back

=head3 Returns

function, which calculates rise and set times of the planet. It accepts and two callbacks as named arguments: 

=over

=item * 

B<on_event($event, $jd>) 
callback called when the event time is determined. The first argument
is one of: C<$EVT_RISE>, C<$EVT_SET> or C<$EVT_TRANSIT> constants (see L<Astro::Montenbruck::RiseSet::Constants>),
the second - I<Standard Julian Date>.

=item * 

B<on_noevent($state>
callback called when the body is I<circumpolar> or I<never rises>. 
The argument is either C<$STATE_CIRCUMPOLAR> or C<$STATE_NEVER_RISES>.

=back

When called in list context, returns a hash, described in L<rst( %args )/List context>, except
that C<transit> key is missing.

=head2 twilight( %args )

Function for calculating twilight. See L</TWILIGHT EVENT FUNCTION> below.

=head3 Named Arguments

=over

=item * 

B<type> - type of twilight, C<$TWILIGHT_NAUTICAL>, C<$TWILIGHT_ASTRO>
or C<$TWILIGHT_CIVIL>, see L<Astro::Montenbruck::RiseSet::Constants/TYPES OF TWILIGHT>.

=item * 

B<date> - array of B<year> (astronomical, zero-based), B<month> [1..12] and B<day>, [1..31].

=item * 

B<phi> - geographical latitude, degrees, positive northward

=item * 

B<lambda> - geographical longitude, degrees, positive westward

=item * 

B<on_event> - callback called when the event time is determined. The arguments are:

=over

=item * 

Event type, one of C<$EVT_RISE> or C<$EVT_SET>, L<Astro::Montenbruck::RiseSet::Constants/EVENTS>. 
The first indicates I<dawn>, the second - I<dusk>.

=item * 

time of the event, I<Standard Julian date>.



( run in 1.417 second using v1.01-cache-2.11-cpan-b16cb0d3907 )