Astro-Coord-ECI-VSOP87D
view release on metacpan or search on metacpan
lib/Astro/Coord/ECI/VSOP87D/_Inferior.pm view on Meta::CPAN
package Astro::Coord::ECI::VSOP87D::_Inferior;
use 5.008;
use strict;
use warnings;
use base qw{ Astro::Coord::ECI };
use Astro::Coord::ECI::Mixin qw{
almanac almanac_hash
next_quarter_hash
};
use Astro::Coord::ECI::Utils qw{ PI find_first_true mod2pi };
use Astro::Coord::ECI::VSOP87D qw{ :mixin };
use Carp;
our $VERSION = '0.008';
sub new {
my ( $class, %arg ) = @_;
$class->__default( \%arg );
return $class->SUPER::new( %arg );
}
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;
};
}
{
my $get = sub {
my ( $self, $name ) = @_;
return $self->__get_attr()->{$name};
};
my %accessor = (
elongation_in_longitude => $get,
model_cutoff => $get,
nutation_cutoff => $get,
);
sub attribute {
my ( $self, $name ) = @_;
exists $accessor{$name}
and return __PACKAGE__;
return $self->SUPER::attribute( $name );
}
sub get {
my ( $self, @arg ) = @_;
my @rslt;
foreach my $name ( @arg ) {
if ( my $code = $accessor{$name} ) {
push @rslt, $code->( $self, $name );
} else {
push @rslt, $self->SUPER::get( $name );
}
wantarray
or return $rslt[0];
}
return @rslt;
}
}
# NOTE that the %opt arguments are UNSUPPORTED and can be changed or
# removed without notice. Caveat codor.
sub next_quarter {
my ( $self, $quarter, %opt ) = @_;
my $time = $self->universal();
my $elong_method = $self->get( 'elongation_in_longitude' ) ?
'__longitude_from_sun' :
'__angle_subtended_from_earth';
my $increment = $self->synodic_period() / 16;
my @checker = (
sub { # 0 = superior conjunction
my ( $time ) = @_;
$self->__longitude_from_sun( $time ) > 0 ? 4 : 0;
},
sub { # 1 = elongaton east
my ( $time ) = @_;
return $self->$elong_method( $time ) <
$self->$elong_method( $time - 1 ) ? 1 : 0;
},
sub { # 2 = inferior conjunction
my ( $time ) = @_;
$self->__longitude_from_sun( $time ) < 0 ? 2 : 0;
},
sub { # 3 = elongaton west
my ( $time ) = @_;
return $self->$elong_method( $time ) >
$self->$elong_method( $time - 1 ) ? 3 : 0;
},
);
if ( defined $opt{checker_result} ) {
return $checker[$opt{checker_result}]->( $time );
}
my $test;
if ( defined $quarter ) {
$test = $checker[$quarter];
while ( $test->( $time ) ) {
$time += $increment;
}
while ( ! $test->( $time ) ) {
$time += $increment;
}
} else {
my @chk = grep { ! $_->( $time ) } @checker
or confess 'Programming error - no false checks';
my $rslt;
while ( ! $rslt ) {
$time += $increment;
foreach my $c ( @chk ) {
$rslt = $c->( $time )
and last;
}
}
$quarter = $rslt % 4;
$test = $checker[$quarter];
}
my $rslt = find_first_true( $time - $increment, $time, $test );
$self->universal( $rslt );
wantarray
or return $rslt;
return( $rslt, $quarter, $self->__quarter_name( $quarter ) );
}
sub __quarter_name {
my ( $self, $event, $name ) = @_;
$name ||= [
'%s superior conjunction',
'%s elongation east',
'%s inferior conjunction',
'%s elongation west',
];
return sprintf $name->[$event], $self->get( 'name' );
}
{
my $set = sub {
my ( $self, $name, $value ) = @_;
$self->__get_attr()->{$name} = $value;
return $self;
};
my %mutator = (
elongation_in_longitude => $set,
model_cutoff => \&__mutate_model_cutoff,
nutation_cutoff => \&__mutate_nutation_cutoff,
);
sub set {
my ( $self, @arg ) = @_;
while ( @arg ) {
my ( $name, $value ) = splice @arg, 0, 2;
if ( my $code = $mutator{$name} ) {
$code->( $self, $name, $value );
} else {
$self->SUPER::set( $name, $value );
}
}
return $self;
}
}
1;
__END__
=head1 NAME
Astro::Coord::ECI::VSOP87D::_Inferior - VSOP87D inferior planets
=head1 SYNOPSIS
This abstract Perl class is not intended to be invoked directly by the
user.
=head1 DESCRIPTION
This abstract Perl class represents the VSOP87D model of an inferior
planet. It is a subclass of L<Astro::Coord::ECI|Astro::Coord::ECI>.
=head1 METHODS
This class supports the following public methods in addition to those
inherited from the superclass.
=head2 model_cutoff_definition
This method reports, creates, and deletes model cutoff definitions.
The first argument is the name of the model cutoff. If this is the only
argument, a reference to a hash defining the named model cutoff is
returned. This return is a deep clone of the actual definition.
If the second argument is C<undef>, the named model cutoff is deleted.
If the model cutoff does not exist, the call does nothing. It is an
error to try to delete built-in cutoffs C<'none'> and C<'Meeus'>.
If the second argument is a reference to a hash, this defines or
redefines a model cutoff. The keys to the hash are the names of VSOP87D
series (C<'L0'> through C<'L5'>, C<'B0'> through C<'B5'>, and C<'R0'>
through C<'R5'>), and the value of each key is the number of terms of
that series to use. If one of the keys is omitted or has a false value,
that series is not used.
If the second argument is a scalar, it is expected to be a number, and a
model cutoff is generated consisting of all terms whose coefficient
(C<'A'> in Meeus' terminology) is equal to or greater than the number.
If the second argument is a code reference, this code is expected to
return a reference to a valid model cutoff hash as described two
paragraphs previously. Its arguments are the individual series hashes,
extracted from the model. Each hash will have the following keys:
=over
=item series
( run in 1.052 second using v1.01-cache-2.11-cpan-d80b1682f3f )