Astro-satpass
view release on metacpan or search on metacpan
lib/Astro/Coord/ECI/Moon.pm view on Meta::CPAN
print "Moon @{[$rise ? 'rise' : 'set']} is ",
scalar localtime $time, "\n";
=head1 DESCRIPTION
This module implements the position of the Moon as a function of time,
as described in Jean Meeus' "Astronomical Algorithms," second edition.
It is a subclass of L<Astro::Coord::ECI|Astro::Coord::ECI>, with the id,
name, and diameter attributes initialized appropriately, and the
time_set() method overridden to compute the position of the Moon at the
given time.
=head2 Methods
The following methods should be considered public:
=over
=cut
package Astro::Coord::ECI::Moon;
use strict;
use warnings;
our $VERSION = '0.134';
use base qw{Astro::Coord::ECI};
use Astro::Coord::ECI::Utils qw{ @CARP_NOT :mainstream };
use Carp;
# Load the periodic terms from the table.
my %terms;
{ # Begin local symbol block.
my $where;
local $_ = undef; # while (<>) ... does not localize $_.
while (<DATA>) {
chomp;
s/ \A \s+ //smx;
s/ \s+ \z //smx;
next unless $_;
next if m/ \A \s* [#] /smx;
s/^-// and do {
last if $_ eq 'end';
$where = $terms{$_} ||= [];
next;
};
s/_//g;
push @$where, [split '\s+', $_];
}
} # End local symbol block.
my %static = (
id => 'Moon',
name => 'Moon',
diameter => 3476,
);
my $weaken = eval {
require Scalar::Util;
Scalar::Util->can('weaken');
};
our $Singleton = $weaken;
my %object; # By class
=item $moon = Astro::Coord::ECI::Moon->new ();
This method instantiates an object to represent the coordinates of the
Moon. This is a subclass of Astro::Coord::ECI, with the id and name
attributes set to 'Moon', and the diameter attribute set to 3476 km
per Jean Meeus' "Astronomical Algorithms", 2nd Edition, Appendix I,
page 407.
Any arguments are passed to the set() method once the object has been
instantiated. Yes, you can override the "hard-wired" id and name in
this way.
If C<$Astro::Coord::ECI::Moon::Singleton> is true, you get a singleton
object; that is, only one object is instantiated and subsequent calls to
C<new()> just return that object. If higher-accuracy subclasses are ever
implemented, there will be one singleton for each class.
The singleton logic only works if L<Scalar::Util|Scalar::Util> exports
C<weaken()>. If it does not, the setting of
C<$Astro::Coord::ECI::Moon::Singleton> is silently ignored. The default
is true if L<Scalar::Util|Scalar::Util> can be loaded and exports
C<weaken()>, and false otherwise.
=cut
sub new {
my ($class, @args) = @_;
ref $class and $class = ref $class;
if ( $Singleton && $weaken && __classisa( $class, __PACKAGE__ ) ) {
my $self;
if ( $self = $object{$class} ) {
$self->set( @args ) if @args;
return $self;
} else {
$self = $object{$class} = $class->SUPER::new (%static, @args);
$weaken->( $object{$class} );
return $self;
}
} else {
return $class->SUPER::new (%static, @args);
}
}
=item @almanac = $moon->almanac ($station, $start, $end);
This method produces almanac data for the Moon for the given observing
station, between the given start and end times. The station is assumed
to be Earth-Fixed - that is, you can't do this for something in orbit.
The C<$station> argument may be omitted if the C<station> attribute has
been set. That is, this method can also be called as
@almanac = $moon->almanac( $start, $end )
The start time defaults to the current time setting of the $moon
object, and the end time defaults to a day after the start time.
The almanac data consists of a list of list references. Each list
reference points to a list containing the following elements:
[0] => time
[1] => event (string)
[2] => detail (integer)
[3] => description (string)
The @almanac list is returned sorted by time.
The following events, details, and descriptions are at least
potentially returned:
horizon: 0 = Moon set, 1 = Moon rise;
transit: 1 = Moon transits meridian;
quarter: 0 = new moon, 1 = first quarter,
2 = full moon, 3 = last quarter.
=cut
sub __almanac_event_type_iterator {
my ( $self, $station ) = @_;
my $inx = 0;
my $horizon = $station->__get_almanac_horizon();
my @events = (
[ $station, next_elevation => [ $self, $horizon, 1 ],
horizon => '__horizon_name' ],
[ $station, next_meridian => [ $self ],
transit => '__transit_name' ],
[ $self, next_quarter => [], quarter => '__quarter_name' ],
);
return sub {
$inx < @events
and return @{ $events[$inx++] };
return;
};
}
use Astro::Coord::ECI::Mixin qw{ almanac };
=item @almanac = $moon->almanac_hash($station, $start, $end);
This convenience method wraps $moon->almanac(), but returns a list of
hash references, sort of like Astro::Coord::ECI::TLE->pass()
does. The hashes contain the following keys:
{almanac} => {
{event} => the event type;
{detail} => the event detail (typically 0 or 1);
{description} => the event description;
}
{body} => the original object ($moon);
{station} => the observing station;
{time} => the time the quarter occurred.
The {time}, {event}, {detail}, and {description} keys correspond to
elements 0 through 3 of the list returned by almanac().
=cut
use Astro::Coord::ECI::Mixin qw{ almanac_hash };
=item $coord2 = $coord->clone ();
If singleton objects are enabled, this override of the superclass'
method simply returns the invocant. Otherwise it does a deep clone of an
object, producing a different but identical object.
Prior to version 0.099_01 it always returned a clone. Yes,
this is a change in long-standing functionality, but a long-standing bug
is still a bug.
=cut
sub clone {
my ( $self ) = @_;
$Singleton
and $weaken
and return $self;
return $self->SUPER::clone();
}
=item $elevation = $moon->correct_for_refraction( $elevation )
This override of the superclass' method simply returns the elevation
passed to it. Since the Moon has no atmosphere to speak of, there should
be no diffraction to speak of either.
See the L<Astro::Coord::ECI|Astro::Coord::ECI> C<azel()> and
C<azel_offset()> documentation for whether this class'
C<correct_for_refraction()> method is actually called by those methods.
=cut
sub correct_for_refraction {
my ( undef, $elevation ) = @_; # Invocant unused
return $elevation;
}
=item ($time, $quarter, $desc) = $moon->next_quarter ($want);
This method calculates the time of the next quarter-phase of the Moon
after the current time setting of the $moon object. The returns are the
time, which quarter-phase it is as a number from 0 (new moon) to
3 (last quarter), and a string describing the phase. If called in
scalar context, you just get the time.
The optional $want argument says which phase you want.
As a side effect, the time of the $moon object ends up set to the
returned time.
The method of calculation is successive approximation, and actually
returns the second B<after> the quarter.
=cut
use constant NEXT_QUARTER_INCREMENT => 86400 * 6; # 6 days.
*__next_quarter_coordinate = __PACKAGE__->can(
'phase' );
use Astro::Coord::ECI::Mixin qw{ next_quarter };
=item $hash_reference = $moon->next_quarter_hash($want);
This convenience method wraps $moon->next_quarter(), but returns the
data in a hash reference, sort of like Astro::Coord::ECI::TLE->pass()
does. The hash contains the following keys:
{body} => the original object ($moon);
{almanac} => {
{event} => 'quarter',
{detail} => the quarter number (0 through 3);
{description} => the quarter description;
}
{time} => the time the quarter occurred.
( run in 0.633 second using v1.01-cache-2.11-cpan-ceb78f64989 )