App-SourcePlot

 view release on metacpan or  search on metacpan

lib/App/SourcePlot/Source.pm  view on Meta::CPAN

package App::SourcePlot::Source;

=head1 NAME

App::SourcePlot::Source - Create a observation source

=head1 SYNOPSIS

    use App::SourcePlot::Source;
    $src = App::SourcePlot::Source->new;

=head1 DESCRIPTION

This class will create Source objects that will hold essential
information for any single source.

It is essentially a wrapper around an Astro::Coords object to add
the additional information used to display a source in this
application.

=cut

use 5.004;
use Carp;
use strict;

use Astro::Coords;
use Math::Trig qw/pi/;
use DateTime;
use DateTime::Format::Strptime;

our $VERSION = '1.32';

my $locateBug = 0;

=head1 METHODS

=head2 Constructor

=over 4

=item new

Create a new Source object.

    $obs = App::SourcePlot::Source->new($planet);
    $obs = App::SourcePlot::Source->new($name, $RA, $DEC, $Epoc);

Or using an Astro::Coords object.

    $coords = Astro::Coords->new(...);
    $obs = App::SourcePlot::Source->new($coords);

=cut

sub new {
    print "Creating a new observation Source object\n" if $locateBug;

    my $proto = shift;
    my $class = ref($proto) || $proto;

    my $self = {};  # Anon hash

    bless($self, $class);
    print "New observation Source object has been blessed: $self\n" if $locateBug;

    $self->configure(@_);

    $self->active(1);

    print "Object created\n" if $locateBug;

    return $self;
}


sub configure {
    my $self = shift;

    # Special case: empty source object.
    unless (@_) {
        $self->coords(Astro::Coords->new());
        return;
    }

    my $name = shift;

    if (UNIVERSAL::isa($name, 'Astro::Coords')) {
        $self->coords($name);
    }

lib/App/SourcePlot/Source.pm  view on Meta::CPAN


    $line = $obs->dispLine();

=cut

sub dispLine {
    my $self = shift;
    my $line;
    unless (UNIVERSAL::isa($self->coords(), 'Astro::Coords::Planet')) {
        $line = sprintf
            ' %-4d  %-16s  %-12s  %-13s  %-4s',
            ($self->index() + 1),
            $self->name(), $self->ra(), $self->dec(), $self->epoc();
    }
    else {
        $line = sprintf
            ' %-4d  %-16s  Planet',
            ($self->index() + 1),
            ucfirst($self->name());
    }
    return $line;
}

=item copy

Returns a copy of this object.

    $cp = $obs->copy();

=cut

sub copy {
    my $self = shift;
    my $source = $self->new($self->coords());
    return $source;
}

=item calcPoints

Calculations the Elevation, Azimeth, etc. points
$MW is the main window widget.  Required for
progress bar

    $obs->calcPoints($date, $time, $num_points, $MW, $tel);

=cut

sub calcPoints {
    my $self = shift;
    my $DATE = shift;
    my $TIME = shift;
    my $numPoints = shift;
    my $MW = shift;
    my $tel = shift;
    my $timeBug = 0;

    my $coords = $self->coords();
    $coords->telescope($tel);
    my $dt_save = $coords->datetime();

    my $strp = DateTime::Format::Strptime->new(
        pattern => '%Y/%m/%d %H:%M:%S',
        time_zone => 'UTC',
        on_error => 'croak');

    my $dt = $strp->parse_datetime($DATE . ' ' . $TIME);

    my $dt_running = $dt->clone();

    my $tlen = @{$self->{TIME_ELE_POINTS}} if defined $self->{TIME_ELE_POINTS};
    if (defined $tlen && $tlen > 0) {
        return;
    }

    $dt_running->subtract(hours => 2);
    my $lst_prev = undef;

    for (my $h = 0; $h < $numPoints; $h ++) {
        $MW->update;
        my ($lst, $ele, $az, $pa, undef) = $self->_calcPoint($dt_running);

        if (defined $lst_prev and $lst < $lst_prev) {
            $lst += 2 * pi;

            # Allow a second wrap around in case LST is just under 2 pi at the
            # start (eg on March 5th at JCMT with (default) 1:30:00 center time.
            # This is necessary because we generate points over a full day,
            # and then convert to LST so there is always one wrap-around, with
            # a potential for a second for certain date / location /center time
            # configurations!
            if ($lst < $lst_prev) {
                $lst += 2 * pi;
            }
        }

        $lst_prev = $lst;

        push @{$self->{TIME_ELE_POINTS}}, $lst;
        push @{$self->{TIME_ELE_POINTS}}, $ele;

        push @{$self->{TIME_AZ_POINTS}}, $lst;
        push @{$self->{TIME_AZ_POINTS}}, $az;

        push @{$self->{TIME_PA_POINTS}}, $lst;
        push @{$self->{TIME_PA_POINTS}}, $pa;

        push @{$self->{ELE_TIME_POINTS}}, $ele;
        push @{$self->{ELE_TIME_POINTS}}, $lst;

        push @{$self->{ELE_AZ_POINTS}}, $ele;
        push @{$self->{ELE_AZ_POINTS}}, $az;

        push @{$self->{ELE_PA_POINTS}}, $ele;
        push @{$self->{ELE_PA_POINTS}}, $pa;

        push @{$self->{AZ_TIME_POINTS}}, $az;
        push @{$self->{AZ_TIME_POINTS}}, $lst;

        push @{$self->{AZ_ELE_POINTS}}, $az;
        push @{$self->{AZ_ELE_POINTS}}, $ele;

        push @{$self->{AZ_PA_POINTS}}, $az;
        push @{$self->{AZ_PA_POINTS}}, $pa;

        push @{$self->{PA_TIME_POINTS}}, $pa;
        push @{$self->{PA_TIME_POINTS}}, $lst;

        push @{$self->{PA_ELE_POINTS}}, $pa;
        push @{$self->{PA_ELE_POINTS}}, $ele;

        push @{$self->{PA_AZ_POINTS}}, $pa;
        push @{$self->{PA_AZ_POINTS}}, $az;

        $dt_running->add(seconds => 24 * 3600 / ($numPoints - 1));
    }

    $coords->datetime($dt_save);
}

=item calcPoint

Returns the time in decimal, elevation, azimuth, and parallactic angle
for a given source at a particular time and date.

    ($lst, $ele, $az, $pa) = $obs->calcPoint($date, $time, $tel);

=cut

sub calcPoint {
    my $self = shift;
    my $DATE = shift;
    my $TIME = shift;
    my $tel = shift;

    my $strp = DateTime::Format::Strptime->new(
        pattern => '%Y/%m/%d %H:%M:%S',
        time_zone => 'UTC',
        on_error => 'croak');

    my $dt = $strp->parse_datetime($DATE . ' ' . $TIME);

    $dt->add(hours => 10);

    return $self->_calcPoint($dt, $tel);
}

sub _calcPoint {
    my $self = shift;
    my $dt = shift;
    my $tel = shift;

    # PAL (and so Astro::Coords) can not handle seconds > 59 (used in the case
    # of leap seconds), so replace with 59 seconds when this happens.
    $dt->set_second(59) if $dt->second() > 59;

    my $coords = $self->coords();
    $coords->datetime($dt) if defined $dt;
    $coords->telescope($tel) if defined $tel;

    my $pa = $coords->pa(format => 'r');
    my ($elex, $eley) = _axis_direction($pa, 0, 30);
    my ($azx, $azy) = _axis_direction($pa, 30, 0);

    return (
        $coords->_lst()->radians(),
        $coords->el(format => 'd'),
        $coords->az(format => 'd'),
        $coords->pa(format => 'd'),
        $elex, $eley, $azx, $azy,
    );
}

# Based on the AzToRa function from the old
# Astro::Instrument::SCUBA::Array module
# by Casey Best (University of Victoria).
sub _axis_direction {
    my $pa = shift;
    my $daz = shift;
    my $del = shift;

    my $x = -$daz * cos($pa) + $del * sin($pa);
    my $y = $daz * sin($pa) + $del * cos($pa);
    return ($x, $y);
}


=item erasePoints

Erases all of the plotting points.  Needed when new coords put in.

    $obs->erasePoints();

=cut

sub erasePoints {



( run in 1.406 second using v1.01-cache-2.11-cpan-5a3173703d6 )