App-SourcePlot
view release on metacpan or search on metacpan
lib/App/SourcePlot.pm view on Meta::CPAN
package App::SourcePlot;
=head1 NAME
App::SourcePlot - Implements Souce Plot application
=head1 SYNOPSIS
use App::SourcePlot;
App::SourcePlot::run_sourceplot_gui();
=head1 DESCRIPTION
This module contains the implementation of the Source Plot application,
which can be launched using the L<sourceplot> command.
Source Plot is a simple astronomical source plotter designed to
display a plot of astronomical sources on adjustable axes.
=cut
use strict;
#use warnings;
our $VERSION = '1.32';
use Config::IniFiles;
use Tk;
use Tk::Balloon;
use Tk::FileSelect;
use App::SourcePlot::Plotter::Tk;
use DateTime;
use DateTime::Format::Strptime;
use App::SourcePlot::Source;
use File::HomeDir;
use File::ShareDir qw/dist_file/;
use File::Spec;
use Tk::AstroCatalog;
use Astro::PAL;
use Astro::Telescope;
use Math::Trig;
use Astro::Coords::Planet 0.05;
#global variables that will be used....
my $locateBug = 0;
my $MW;
my $TIME;
my @SOURCE_LIST = ();
my @planets = map {ucfirst($_)} Astro::Coords::Planet::planets();
my $CATALOG_OPEN;
my $EDIT_OPEN;
my $LAST_COMMAND;
my @UNDO_LIST;
my $undoBut;
my $cBut;
my $TimeLap = 30000; # time between white dot updates
my $dotSizeX = 4;
my $dotSizeY = 4;
my @axes = (
'Time',
'Elevation',
'Air Mass',
'Azimuth',
'Parallactic Angle',
);
my %defaults = (
TEL => 'JCMT',
XAXIS => 'Time',
YAXIS => 'Elevation',
TIME => '1:30:00'
);
my $plotter;
my $TEL;
my $X_AXIS;
my $Y_AXIS;
my $DATE;
my $telObject;
my ($minX, $minY);
my ($maxX, $maxY);
my $TELPOSN = undef;
my $NUM_POINTS = 97;
my $BUSY = 0;
my $TIMER;
my @COLOR_LIST = qw/#ffaaaa #00ff00 #ff55ff #ffff00 #00ffff #ff00ff #ffffff #ff5555 #55ff55 #55ffff #ffff55/;
lib/App/SourcePlot.pm view on Meta::CPAN
my @temp;
my $flag = 0;
for (my $index = 0; $index < $len; $index ++) {
if ($element->coords()->summary() eq $$array[$index]->coords()->summary()) {
$flag = -1;
}
else {
$temp[$index + $flag] = $$array[$index];
}
}
@$array = @temp;
}
=item B<update_status>
Invokes the update method of the main window.
=cut
sub update_status {
$MW->update;
}
=item B<changeDate>
Changes the date to a new date.
=cut
sub changeDate {
$dateBut->configure(-state => 'disabled');
my @months = qw/
January February March April May June July August
September October November December/;
my $name;
my $Top = $MW->Toplevel;
$Top->title('Source Plot UT Date');
$Top->resizable(0, 0);
my $topFrame = $Top->Frame(
-relief => 'groove',
-borderwidth => 2,
)->pack(-padx => 10, -pady => 10);
# create the day entry
$topFrame->Label(-text => "Day:")->grid(-column => 0, -row => 0);
my $dayEnt = $topFrame->Entry(
-relief => 'sunken',
-width => 10,
)->grid(-column => 1, -row => 0, -padx => 10, -pady => 5);
# create the month menu button
$topFrame->Label(
-text => "Month:",
)->grid(-column => 0, -row => 1, -padx => 5, -pady => 5);
my $strp = DateTime::Format::Strptime->new(
pattern => '%Y/%m/%d',
time_zone => 'UTC',
on_error => 'croak');
my $dt = $strp->parse_datetime($DATE);
my $monthEnt = $months[$dt->month() - 1];
my $mb = $topFrame->Menubutton(
-text => $monthEnt,
-relief => 'raised',
-width => 10);
foreach $name (@months) {
$mb->command(
-label => $name,
-command => sub {
$mb->configure(-text => $name);
$monthEnt = $name;
},
);
}
$mb->grid(-column => 1, -row => 1, -padx => 10, -pady => 5, -sticky => 'w');
# create the year entry
$topFrame->Label(
-text => 'Year:',
)->grid(-column => 0, -row => 2, -padx => 5, -pady => 5);
my $yearEnt = $topFrame->Entry(
-relief => 'sunken',
-width => 10,
)->grid(-column => 1, -row => 2, -padx => 10, -pady => 5);
$yearEnt->bind('<KeyPress-Return>' => sub {
my $strp = DateTime::Format::Strptime->new(
pattern => '%Y %B %d',
on_error => 'croak');
my $dt = $strp->parse_datetime(
$monthEnt
. ' ' . $dayEnt->get()
. ' ' . $yearEnt->get());
$DATE = $dt->strftime('%Y/%m/%d');
destroy $Top;
});
# create the update subroutine
my $complete = sub {
my $strp = DateTime::Format::Strptime->new(
pattern => '%B %d %Y',
on_error => 'croak');
my $dt = $strp->parse_datetime(
$monthEnt
. ' ' . $dayEnt->get()
. ' ' . $yearEnt->get());
$DATE = $dt->strftime('%Y/%m/%d');
foreach my $source (@SOURCE_LIST) {
$source->erasePoints();
}
plot();
};
# create the apply button
my $F = $Top->Frame->pack();
my $buttonF = $F->Frame->pack(-side => 'left', -padx => 5, -pady => 10);
my $okBut = $buttonF->Button(
-text => 'Apply',
-command => $complete,
)->pack(-side => 'left');
$okBut->bind('<KeyPress-Return>' => $complete);
# create the accept button
$buttonF = $F->Frame->pack(-side => 'right', -padx => 5, -pady => 10);
my $okBut = $buttonF->Button(
-text => 'Accept',
-command => sub {
&$complete;
destroy $Top;
},
)->pack(-side => 'right');
$okBut->bind('<KeyPress-Return>' => sub {
&$complete;
destroy $Top;
});
# create the cancel button
my $canBut = $buttonF->Button(
-text => 'Cancel',
-command => sub {
destroy $Top;
},
)->pack(-side => 'right');
$canBut->bind('<KeyPress-Return>' => sub {
destroy $Top;
});
# Closing the window should reset $dateBut.
$Top->bind('<Destroy>', sub {
my $widget = shift;
return unless $widget == $Top;
$dateBut->configure(-state => 'normal');
});
$dayEnt->insert(0, $dt->day());
$yearEnt->insert(0, $dt->year());
lib/App/SourcePlot.pm view on Meta::CPAN
}
$T->tag(
'configure',
'd' . $source->index(),
-foreground => 'blue',
);
}
@$selected = ();
if ($EDIT_OPEN) {
fillWithSourceList($EditWin, 'full');
}
plot();
$BUSY = 0;
},
);
}
}
}
$T->mark('set', insert => '1.0');
# Disable access to infobox
$T->configure(-state => 'disabled');
}
=item B<plot>
Plots the graphs, including axis.
=cut
sub plot {
print "Entered plot\n" if $locateBug;
my $xplot = $plotter->width;
my $yplot = $plotter->height;
$plotter->usingWorld(0);
$plotter->worldCenter($xborder, $yplot - $yborder);
$plotter->usingWorld(1);
my ($xworldRatio, $yworldRatio);
my $debug = 0;
$TIME =~ s/^\s+//;
$TIME =~ s/\s+$//;
$TIME =~ s/\s+/:/g;
my ($timeH, $min, $sec) = split /:/, $TIME, 3;
my $XSpaceForTime = 0;
my $YSpaceForTime = 0;
my $special = 0;
my $lstDiffX;
my $lstDiffY;
$XSpaceForTime = $xborder if $Y_AXIS =~ /time/i;
$YSpaceForTime = $yborder if $X_AXIS =~ /time/i;
$timeH += $min / 60 + $sec / 3600;
#clear the plot
$plotter->clean();
# calc the world coords
print " Calculating the world coordinate system\n" if $locateBug;
if ($X_AXIS =~ /time/i) {
my $strp = DateTime::Format::Strptime->new(
pattern => '%Y/%m/%d %H:%M:%S',
on_error => 'croak');
my $dt = $strp->parse_datetime($DATE . ' ' . $TIME);
$dt->subtract(hours => 2);
my ($lst, $mjd) = ut2lst(
$dt->year(), $dt->month(), $dt->day(),
$dt->hour(), $dt->minute(), $dt->second(),
$telObject->long_by_rad());
$dt->add(hours => 1);
my ($lst2, $mjd2) = ut2lst(
$dt->year(), $dt->month(), $dt->day(),
$dt->hour(), $dt->minute(), $dt->second(),
$telObject->long_by_rad());
if ($lst2 < $lst) {
$lst2 += 2 * pi;
}
$lstDiffX = $lst2 - $lst;
$xworldRatio = (24 * $lstDiffX) / ($xplot - $xborder * 2 - $XSpaceForTime);
$minX = $lst;
$maxX = $lst + 24 * $lstDiffX;
print "x-axis is time\n" if $debug;
}
elsif ($X_AXIS =~ /air mass/i) {
$xworldRatio = 90 / ($xplot - $xborder * 2 - $XSpaceForTime);
$minX = 0;
$maxX = 90;
print "x-axis is ele\n" if $debug;
}
elsif ($X_AXIS =~ /elevation/i) {
$xworldRatio = 90 / ($xplot - $xborder * 2 - $XSpaceForTime);
$minX = 0;
$maxX = 90;
print "x-axis is ele\n" if $debug;
}
elsif ($X_AXIS =~ /azimuth/i) {
$xworldRatio = 360 / ($xplot - $xborder * 2 - $XSpaceForTime);
$minX = 0;
$maxX = 360;
print "x-axis is pa\n" if $debug;
}
elsif ($X_AXIS =~ /parallactic angle/i) {
$xworldRatio = 360 / ($xplot - $xborder * 2 - $XSpaceForTime);
$minX = -180;
$maxX = 180;
print "x-axis is az\n" if $debug;
}
else {
print "ERROR: X axis undefined!!\n\n";
$minX = 0;
$maxX = 0;
}
if ($Y_AXIS =~ /time/i) {
my $strp = DateTime::Format::Strptime->new(
pattern => '%Y/%m/%d %H:%M:%S',
on_error => 'croak');
my $dt = $strp->parse_datetime($DATE . ' ' . $TIME);
$dt->subtract(hours => 2);
my ($lst, $mjd) = ut2lst(
$dt->year(), $dt->month(), $dt->day(),
$dt->hour(), $dt->minute(), $dt->second(),
$telObject->long_by_rad());
$dt->add(hours => 1);
my ($lst2, $mjd2) = ut2lst(
$dt->year(), $dt->month(), $dt->day(),
$dt->hour(), $dt->minute(), $dt->second(),
$telObject->long_by_rad());
if ($lst2 < $lst) {
$lst2 += 2 * pi;
}
$lstDiffY = $lst2 - $lst;
$yworldRatio = (-24 * $lstDiffY) / ($yplot - $yborder * 2 - $YSpaceForTime);
$maxY = $lst + 24 * $lstDiffY;
$minY = $lst;
print "y-axis is time\n" if $debug;
}
elsif ($Y_AXIS =~ /air mass/i) {
$yworldRatio = -90 / ($yplot - $yborder * 2 - $YSpaceForTime);
$maxY = 90;
$minY = 0;
print "y-axis is ele\n" if $debug;
}
elsif ($Y_AXIS =~ /elevation/i) {
$yworldRatio = -90 / ($yplot - $yborder * 2 - $YSpaceForTime);
$maxY = 90;
$minY = 0;
print "y-axis is ele\n" if $debug;
}
elsif ($Y_AXIS =~ /azimuth/i) {
$yworldRatio = -360 / ($yplot - $yborder * 2 - $YSpaceForTime);
$minY = 0;
$maxY = 360;
print "y-axis is az\n" if $debug;
}
elsif ($Y_AXIS =~ /parallactic angle/i) {
$yworldRatio = -360 / ($yplot - $yborder * 2 - $YSpaceForTime);
$minY = -180;
$maxY = 180;
print "y-axis is pa\n" if $debug;
}
else {
print "ERROR: Y axis undefined!!\n\n";
$minY = 0;
$maxY = 0;
}
if ((($Y_AXIS =~ /azimuth/i) && ($X_AXIS =~ /elevation/i))
|| (($X_AXIS =~ /azimuth/i) && ($Y_AXIS =~ /elevation/i))
lib/App/SourcePlot.pm view on Meta::CPAN
=cut
sub getColor {
my $color = $COLOR_LIST[$COLOR_INDEX];
my $len = @COLOR_LIST;
$COLOR_INDEX ++;
$COLOR_INDEX = $COLOR_INDEX % $len;
return $color;
}
=item B<calcTime>
Draws a dot at the current time on each source.
=cut
sub calcTime {
$TIMER->cancel if defined $TIMER;
my $so = shift;
my ($sources, $telsource);
if (defined $so) {
if (ref $so) {
$sources = [[$so, 'drawFillOval', 1]];
}
elsif ('TelescopePosition' eq $so) {
$sources = [];
$telsource = $TELPOSN->get_position() if defined $TELPOSN;
}
else {
die 'Unexpected source parameter';
}
}
else {
$sources = [map {[$_, 'drawFillOval', 1]} @SOURCE_LIST];
$telsource = $TELPOSN->get_position() if defined $TELPOSN;
}
if (defined $telsource) {
$telsource->color('#ffffff');
push @$sources, [$telsource, 'drawOval', 3];
}
my $timeBug = 0;
my ($ss, $mm, $hh, $md, $mo, $yr, $wd, $yd, $isdst) = gmtime(time);
$mo ++; # this catches the month up to the current date
$mo = '0' . $mo if length($mo) < 2;
$md = '0' . $md if length($md) < 2;
$mm = '0' . $mm if length($mm) < 2;
$ss = '0' . $ss if length($ss) < 2;
$yr += 1900;
my ($sety, $setm, $setd) = split(/\//, $DATE);
if ((! $yr =~ /$sety/) || $setm != $mo || $setd != $md) {
return;
}
print "The gm time is $hh:$mm:$ss and date is $yr\/$mo\/$md\n" if $timeBug;
#calculate the local time
my $strp = DateTime::Format::Strptime->new(
pattern => '%Y/%m/%d %H:%M:%S',
on_error => 'croak');
my $dt = $strp->parse_datetime("$yr\/$mo\/$md $hh:$mm:$ss");
$dt->subtract(hours => 10);
my $t = $dt->strftime('%H:%M:%S');
my $d = $dt->strftime('%Y/%m/%d');
$plotter->drawColor('white');
foreach my $sourceinfo (@$sources) {
my ($source, $plotstyle, $radiusscale) = @$sourceinfo;
next unless $source->active();
$plotter->delete('timeDot' . $source->name());
print "Real time = $TIME and real date = $DATE\n" if $timeBug;
print "Date = $d and time = $t before calcpoint\n" if $timeBug;
my ($lst, $ele, $az, $pa, $elex, $eley, $azx, $azy) = $source->calcPoint($d, $t, $telObject);
if ($lst < $minX) {
$lst += 2 * pi;
}
elsif ($lst > $maxX) {
$lst -= 2 * pi;
}
my ($x, $y);
if ($X_AXIS =~ /time/i) {
$x = $lst;
}
elsif (($X_AXIS =~ /elevation/i) || ($X_AXIS =~ /air mass/i)) {
$x = $ele;
}
elsif ($X_AXIS =~ /azimuth/i) {
$x = $az;
}
elsif ($X_AXIS =~ /parallactic angle/i) {
$x = $pa;
}
if ($Y_AXIS =~ /time/i) {
$y = $lst;
}
elsif (($Y_AXIS =~ /elevation/i) || ($Y_AXIS =~ /air mass/i)) {
$y = $ele;
}
elsif ($Y_AXIS =~ /azimuth/i) {
$y = $az;
}
elsif ($Y_AXIS =~ /parallactic angle/i) {
$y = $pa;
}
if ((($Y_AXIS =~ /azimuth/i) && ($X_AXIS =~ /elevation/i))
|| (($X_AXIS =~ /azimuth/i) && ($Y_AXIS =~ /elevation/i))
|| (($Y_AXIS =~ /azimuth/i) && ($X_AXIS =~ /air mass/i))
|| (($Y_AXIS =~ /air mass/i) && ($X_AXIS =~ /azimuth/i))) {
( run in 0.307 second using v1.01-cache-2.11-cpan-e93a5daba3e )