| Astro-SkyPlot documentation | Contained in the Astro-SkyPlot distribution. |
Astro::SkyPlot - Create very basic sky plots
use Astro::SkyPlot qw/:all/; # export the markers
my $plot = Astro::SkyPlot->new(); # use defaults (see below)
# specify options yourself:
$plot = Astro::SkyPlot->new(
xsize => 200, # mm
ysize => 200,
bgcolor => [0, 0, 0], # RGB => black
projection => 'hammer',
axiscolor => [100, 100, 100], # RGB => grey
);
$plot->setcolor(255, 0, 0); # RGB => red
$plot->plot_lat_long(1, 1); # units: radians
$plot->plot_lat_long(1, 1, size => 0.2, marker => MARK_CIRCLE); # units: radians, radians, mm
$plot->write(file => "skyplot.eps");
A module to create very basic sky plots as EPS documents.
There are multiple types of markers that can be plotted into the sky plot. These are defined through constants that can be exported from the module:
MARK_CIRCLE => circular markers MARK_CIRCLE_FILLED => filled circular markers MARK_BOX => square markers MARK_BOX_FILLED => filled square markers MARK_TRIANGLE => triangularmarkers MARK_TRIANGLE_FILLED => filled triangular markers MARK_DTRIANGLE => downward triangular markers MARK_DTRIANGLE_FILLED => filled downward triangular markers MARK_CROSS => cross shaped markers MARK_DIAGCROSS => diagonal cross shaped markers
You can use the Hammer projection ("hammer"), the Sinusoidal projection
("sinusoidal"), and the Miller projection ("miller"). Default is "hammer".
You can use the projection argument to the constructor to change this.
Cf. Astro::MapProjection for details on these projections and have a look at the default axes by running the examples/projections.pl example.
Constructor. Without arguments, uses the default settings (cf. SYNOPSIS). Supports the following options:
xsize => Plot x-size in mm (def: 200mm)
ysize => Plot y-size in mm (def: 200mm)
bgcolor => Background color as array reference
(RGB value 0-255 per component)
(def: black, [0, 0, 0])
projection => Projection type. Default: Hammer projection ('hammer')
axiscolor => Color for the axes. (def: grey, [100, 100, 100])
Set a new drawing color. Takes three numbers corresponding to red, green and blue values between 0 and 255.
Draw a new latitude/longitude point.
These may be followed by key/value pairs of options. Supported options:
size: the size (radius) of the point (default: 0.1mm)
marker: The type of marker to use (see MARKERS).
Write the plot to the specified EPS file.
The following are read only accessors unless otherwise noted.
Get/Set the default marker type. The marker type for a single
plot operation can be specified as an option to plot_lat_long.
Returns the internals PostScript::Simple object.
Returns the image's width (in mm).
Returns the image's height (in mm).
Draws the plot's background.
Restores the previously saved color.
Plot the sky-plot axis.
Projects given lat/long to x/y to plot coordinates.
Draws a marker at the given plot coordinates. Arguments $x, $y, $markerno, $size.
For more general information on map projections: http://en.wikipedia.org/wiki/Map_projection
Map projections are implemented in Astro::MapProjection
Steffen Mueller, <smueller@cpan.org>
Copyright (C) 2009 by Steffen Mueller
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.0 or, at your option, any later version of Perl 5 you may have available.
| Astro-SkyPlot documentation | Contained in the Astro-SkyPlot distribution. |
package Astro::SkyPlot; use 5.006001; use strict; use warnings; our $VERSION = '0.03'; use Carp 'croak'; use Astro::MapProjection; use PostScript::Simple; use Class::XSAccessor { getters => [qw/xsize ysize ps/], accessors => [qw/marker/] }; use constant { HAMMER_PROJ => 0, SINUSOIDAL_PROJ => 1, MILLER_PROJ => 2, }; use constant PROJ_COORD_TRAFO => [ \&Astro::MapProjection::hammer_projection, \&Astro::MapProjection::sinusoidal_projection, \&Astro::MapProjection::miller_projection, ]; use constant PROJ_CANVAS_TRAFO => [ sub {return( $_[0]*$_[2]/6 + $_[2]/2, $_[1]*$_[3]/6 + $_[3]/2 )}, sub {return( $_[0]*$_[2]/6.5 + $_[2]/2, $_[1]*$_[3]/6.5 + $_[3]/2 )}, sub {return( $_[0]*$_[2]/6.5 + $_[2]/2, $_[1]*$_[3]/6.5 + $_[3]/2 )}, ]; use constant PROJ_NAMES => { 'hammer' => HAMMER_PROJ, 'sinusoidal' => SINUSOIDAL_PROJ, 'miller' => MILLER_PROJ, }; use constant PI => atan2(1,0)*2; use constant DEG2RAD => PI/180; use constant RAD2DEG => 180/PI; use constant { MARK_CIRCLE => 0, MARK_CIRCLE_FILLED => 1, MARK_BOX => 2, MARK_BOX_FILLED => 3, MARK_TRIANGLE => 4, MARK_TRIANGLE_FILLED => 5, MARK_DTRIANGLE => 6, MARK_DTRIANGLE_FILLED => 7, MARK_CROSS => 8, MARK_DIAG_CROSS => 9, }; require Exporter; our @ISA = qw(Exporter); our @EXPORT; our %EXPORT_TAGS = ( 'all' => [ qw( MARK_CIRCLE MARK_CIRCLE_FILLED MARK_BOX MARK_BOX_FILLED MARK_TRIANGLE MARK_TRIANGLE_FILLED MARK_DTRIANGLE MARK_DTRIANGLE_FILLED MARK_CROSS MARK_DIAG_CROSS ) ] ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
sub new { my $class = shift; # todo: arg checking my $self = bless { xsize => 200, # mm ysize => 200, bgcolor => [0, 0, 0], # RGB => black projection => 'hammer', axiscolor => [100, 100, 100], # RGB => grey marker => MARK_CIRCLE_FILLED, @_, } => $class; my $ps = PostScript::Simple->new( eps => 1, units => "mm", xsize => $self->xsize, ysize => $self->ysize, colour => 1, ); $self->{ps} = $ps; $self->setcolor(255, 255, 255); my $proj_name = $self->{projection}; $self->{projection} = PROJ_NAMES->{$proj_name}; croak("Unknown projection '$proj_name'") if not defined $self->{projection}; $self->_draw_bg(); $self->_plot_axis(); return $self; }
sub setcolor { my $self = shift; croak("Need three numbers (RGB) for the drawing color") if @_ != 3; $self->{color} = [@_]; $self->{ps}->setcolour(@_); return $self; }
sub plot_lat_long { my $self = shift; croak("Need latitude/longitude") if @_ < 2; my $lat = shift; my $long = shift; my %opt = @_; my $size = $opt{size}||0.1; my $ps = $self->{ps}; my ($x, $y) = $self->_project($lat, $long); my $marker = exists($opt{marker}) ? $opt{marker} : $self->{marker}; $self->_draw_marker($x, $y, $marker, $size); }
sub write { my $self = shift; my $file = shift; croak("Need file name as argument") if not defined $_[0]; my $ps = $self->{ps}; $ps->output($_[0]); return $self; }
sub _draw_bg { my $self = shift; my $ps = $self->{ps}; $ps->setcolour(0, 0, 0); $ps->box({filled=>1}, 0, 0, $self->xsize, $self->ysize); $ps->setcolour(255, 255, 255); return $self->_restore_color(); }
sub _restore_color { my $self = shift; my $ps = $self->{ps}; $ps->setcolour(@{$self->{color}}); return $self; }
sub _plot_axis { my $self = shift; my $ps = $self->{ps}; my $projection = $self->{projection}; my $old_color = $self->{color}; $self->setcolor(@{$self->{axiscolor}}); my $xsize = $self->{xsize}; my $ysize = $self->{ysize}; my $ps_trafo = PROJ_CANVAS_TRAFO->[$projection]; my $projector = PROJ_COORD_TRAFO->[$projection]; $ps->setlinewidth(0.05); if ($projection == HAMMER_PROJ || $projection == SINUSOIDAL_PROJ) { # plot longitude axes for (my $long = -180*DEG2RAD; $long <= 180.001*DEG2RAD; $long += 45*DEG2RAD) { my $first = 1; for (my $lat = -90*DEG2RAD; $lat <= 90.001*DEG2RAD; $lat += 3.0*DEG2RAD) { my ($x, $y) = $ps_trafo->( $projector->($lat, $long), $xsize, $ysize ); if ($first) { $ps->line($x, $y, $x, $y); $first = 0; } else { $ps->linextend($x, $y); } } } # plot lat axes for (my $lat = -90*DEG2RAD; $lat <= 90.001*DEG2RAD; $lat += 10*DEG2RAD) { my $first = 1; for (my $long = -180*DEG2RAD; $long <= 180.001*DEG2RAD; $long += 5.0*DEG2RAD) { my ($x, $y) = $ps_trafo->( $projector->($lat, $long), $xsize, $ysize ); if ($first) { $ps->line($x, $y, $x, $y); $first = 0; } else { $ps->linextend($x, $y); } } } } elsif ($projection == MILLER_PROJ) { # much, much less steps required ==> special case # plot longitude axes for (my $long = -180*DEG2RAD; $long <= 180.001*DEG2RAD; $long += 45*DEG2RAD) { my ($xs, $ys) = $ps_trafo->( $projector->(-90*DEG2RAD, $long), $xsize, $ysize ); my ($xe, $ye) = $ps_trafo->( $projector->(90*DEG2RAD, $long), $xsize, $ysize ); $ps->line($xs, $ys, $xe, $ye); } # plot lat axes for (my $lat = -90*DEG2RAD; $lat <= 90.001*DEG2RAD; $lat += 10*DEG2RAD) { my ($xs, $ys) = $ps_trafo->( $projector->($lat, -180*DEG2RAD), $xsize, $ysize ); my ($xe, $ye) = $ps_trafo->( $projector->($lat, 180*DEG2RAD), $xsize, $ysize ); $ps->line($xs, $ys, $xe, $ye); } } else { die "Invalid projection type $projection"; } $self->{color} = $old_color; return $self->_restore_color(); }
sub _project { my $self = shift; my $projection = $self->{projection}; my $ps_trafo = PROJ_CANVAS_TRAFO->[$projection]; my $projector = PROJ_COORD_TRAFO->[$projection]; return $ps_trafo->( $projector->(@_), $self->{xsize}, $self->{ysize} ); }
sub _draw_marker { my $self = shift; die('Need $x, $y, $marker, $size') if not @_ == 4; my ($x, $y, $marker, $size) = @_; my $ps = $self->{ps}; if ($marker <= MARK_CIRCLE_FILLED) { $ps->circle( {filled => ($marker == MARK_CIRCLE_FILLED)}, $x, $y, $size ); } elsif ($marker <= MARK_BOX_FILLED) { $ps->box( {filled => ($marker == MARK_BOX_FILLED)}, $x-$size, $y-$size, $x+$size, $y+$size ); } elsif ($marker <= MARK_TRIANGLE_FILLED) { my $lowy = $y-$size; $ps->polygon( {filled => ($marker == MARK_TRIANGLE_FILLED)}, $x-$size, $lowy, $x+$size, $lowy, $x, $y+$size, $x-$size, $lowy, ); } elsif ($marker <= MARK_DTRIANGLE_FILLED) { my $highy = $y+$size; $ps->polygon( {filled => ($marker == MARK_DTRIANGLE_FILLED)}, $x-$size, $highy, $x+$size, $highy, $x, $y-$size, $x-$size, $highy, ); } elsif ($marker == MARK_CROSS) { $ps->line( $x-$size, $y, $x+$size, $y ); $ps->line( $x, $y-$size, $x, $y+$size ); } elsif ($marker == MARK_DIAG_CROSS) { $ps->line( $x-$size, $y-$size, $x+$size, $y+$size ); $ps->line( $x-$size, $y+$size, $x+$size, $y-$size ); } else { die('Invalid marker no. ' . $marker); } } 1; __END__