NAME
Astro::App::Satpass2::Format::Template - Format Astro::App::Satpass2 output as text.
SYNOPSIS
use strict;
use warnings;
use Astro::App::Satpass2::Format::Template;
use Astro::Coord::ECI;
use Astro::Coord::ECI::Moon;
use Astro::Coord::ECI::Sun;
use Astro::Coord::ECI::Utils qw{ deg2rad };
my $time = time();
my $moon = Astro::Coord::ECI::Moon->universal($time);
my $sun = Astro::Coord::ECI::Sun->universal($time);
my $station = Astro::Coord::ECI->new(
name => 'White House',
)->geodetic(
deg2rad(38.8987), # latitude
deg2rad(-77.0377), # longitude
17 / 1000); # height above sea level, Km
my $fmt = Astro::App::Satpass2::Format::Template->new();
print $fmt->location( $station );
print $fmt->position( {
bodies => [ $sun, $moon ],
station => $station,
time => $time,
} );
NOTICE
This is alpha code. It has been tested on my box, but has limited exposure to the wild. Also, the public interface may not be completely stable, and may change if needed to support Astro::App::Satpass2. I will try to document any incompatible changes.
DETAILS
This class is intended to perform output formatting for Astro::App::Satpass2, producing output similar to that produced by the satpass script distributed with Astro::Coord::ECI. It is a subclass of Astro::App::Satpass2::Format, and conforms to that interface.
The Astro::App::Satpass2::Format interface specifies a set of methods corresponding (more or less) to the interactive methods of Astro::App::Satpass2. This class implements those methods in terms of a canned set of Template-Toolkit templates, with the data from the Astro::App::Satpass2 methods wrapped in Astro::App::Satpass2::FormatValue objects to provide formatting at the field level.
The names and contents of the templates used by each formatter are described with each formatter. The templates may be retrieved or modified using the template() method, or may be exported to a working Template-Toolkit file using the export() method.
METHODS
This class supports the following public methods. Methods inherited from Astro::App::Satpass2::Format are documented here if this class adds significant functionality.
Instantiator
new
$fmt = Astro::App::Satpass2::Format::Template->new();
This static method instantiates a new formatter.
Accessors and Mutators
local_coord
print 'Local coord: ', $fmt->local_coord(), "\n";
$fmt->local_coord( 'azel_rng' );
This method overrides the Astro::App::Satpass2::Format local_coord() method, and performs the same function.
Out of the box, legal values for this are consistent with the superclass' documentation; that is, 'az_rng'
, 'azel'
, 'azel_rng'
, 'equatorial'
, and 'equatorial_rng'
. These are actually implemented as templates, as follows:
az_rng => <<'EOD',
[% data.azimuth( arg, bearing = 2 ) %]
[%= data.range( arg ) -%]
EOD
azel => <<'EOD',
[% data.elevation( arg ) %]
[%= data.azimuth( arg, bearing = 2 ) -%]
EOD
azel_rng => <<'EOD',
[% data.elevation( arg ) %]
[%= data.azimuth( arg, bearing = 2 ) %]
[%= data.range( arg ) -%]
EOD
equatorial => <<'EOD',
[% data.right_ascension( arg ) %]
[%= data.declination( arg ) -%]
EOD
equatorial_rng => <<'EOD',
[% data.right_ascension( arg ) %]
[%= data.declination( arg ) %]
[%= data.range( arg ) -%]
EOD
These definitions can be changed, or new local coordinates added, using the template() method.
Formatters
As stated in the Astro::App::Satpass2::Format documentation, there is actually only one formatter method:
format
print $fmtr->format( template => 'location', data => $sta );
This formatter implements the format()
method using Template-Toolkit. The template
argument is required, and selects one of the canned templates provided. The data
argument is required unless your templates are capable of calling Astro::App::Satpass2 methods on their own account, and must (if provided) be whatever is expected by the template. See Templates below for the details.
This method can also execute an arbitrary template if you pass an Astro::App::Satpass2 object in the sp
argument. These templates can call methods on the sp
object to generate their data. If a method which calls the format()
method on its own behalf (like almanac()
) is called on the sp
object, the recursive call is detected, and the data are passed back to the calling template. If arguments for Astro::App::Satpass2 methods are passed in, it is strongly recommended that they be passed in the arg
argument.
Except for the template
argument, all named arguments to format()
are provided to the template. In addition, the following arguments will be provided:
- provider
-
This is simply the value returned by provider().
- time
-
This is the current time wrapped in an Astro::App::Satpass2::FormatValue object.
- title
-
This is an Astro::App::Satpass2::FormatValue configured to produce field titles rather than data.
- TITLE_GRAVITY_BOTTOM
-
This manifest constant is defined in Astro::App::Satpass2::FormatValue. See the title_gravity() documentation for the details.
If the
title
object has itstitle_gravity()
set to this value after template processing, and the output of the template has a leading newline, that newline is removed. See the Astro::App::Satpass2::FormatValue title_gravity() documentation for why this hack was imposed on the output. - TITLE_GRAVITY_TOP
-
This manifest constant is defined in Astro::App::Satpass2::FormatValue. See the title_gravity() documentation for the details.
In addition to any variables passed in, the following array methods are defined for Template-Toolkit
before it is invoked:
- events
-
If called on an array of passes, returns all events in all passes, in chronological order.
- fixed_width
-
If called on an array of Astro::App::Satpass2::FormatValue objects, calls fixed_width() on them. You may specify an argument to
fixed_width()
.Nothing is returned.
Templates
The required values of the template
argument are supported by same-named Template-Toolkit templates, as follows. The data
provided should be as described in the documentation for the Astro::App::Satpass2 format() method. if the data
value is not provided, each of the default templates will call an appropriate Astro::App::Satpass2 method on the sp
value, passing it the arg
value as arguments.
almanac
This template defaults to
[% DEFAULT data = sp.almanac( arg ) %]
[%- FOREACH item IN data %]
[%- item.date %] [% item.time %]
[%= item.almanac( units = 'description' ) %]
[% END -%]
flare
This template defaults to
[% DEFAULT data = sp.flare( arg ) %]
[%- CALL title.title_gravity( TITLE_GRAVITY_BOTTOM ) %]
[%- WHILE title.more_title_lines %]
[%- title.time %]
[%= title.name( width = 12 ) %]
[%= title.local_coord %]
[%= title.magnitude %]
[%= title.angle( 'Degrees From Sun' ) %]
[%= title.azimuth( 'Center Azimuth', bearing = 2 ) %]
[%= title.range( 'Center Range', width = 6 ) %]
[%- END %]
[%- prior_date = '' -%]
[% FOR item IN data %]
[%- center = item.center %]
[%- current_date = item.date %]
[%- IF prior_date != current_date %]
[%- prior_date = current_date %]
[%- current_date %]
[%- END %]
[%- item.time %]
[%= item.name( units = 'title_case', width = 12 ) %]
[%= item.local_coord %]
[%= item.magnitude %]
[%= IF 'day' == item.type( width = '' ) %]
[%- item.appulse.angle %]
[%- ELSE %]
[%- item.appulse.angle( literal = 'night' ) %]
[%- END %]
[%= center.azimuth( bearing = 2 ) %]
[%= center.range( width = 6 ) %]
[% END -%]
list
This template defaults to
[% DEFAULT data = sp.list( arg ) %]
[%- CALL title.title_gravity( TITLE_GRAVITY_BOTTOM ) %]
[%- WHILE title.more_title_lines %]
[%- title.oid( align_left = 0 ) %]
[%= title.name %]
[%= title.epoch %]
[%= title.period( align_left = 1 ) %]
[%- END %]
[%- FOR item IN data %]
[%- IF item.inertial %]
[%- item.oid %] [% item.name %] [% item.epoch %]
[%= item.period( align_left = 1 ) %]
[%- ELSE %]
[%- item.oid %] [% item.name %] [% item.latitude %]
[%= item.longitude %] [% item.altitude %]
[%- END %]
[% END -%]
location
This template defaults to
[% DEFAULT data = sp.location( arg ) -%]
Location: [% data.name( width = '' ) %]
Latitude [% data.latitude( places = 4,
width = '' ) %], longitude
[%= data.longitude( places = 4, width = '' )
%], height
[%= data.altitude( units = 'meters', places = 0,
width = '' ) %] m
pass
This template defaults to
[% DEFAULT data = sp.pass( arg ) %]
[%- CALL title.title_gravity( TITLE_GRAVITY_BOTTOM ) %]
[%- WHILE title.more_title_lines %]
[%- title.time( align_left = 0 ) %]
[%= title.local_coord %]
[%= title.latitude %]
[%= title.longitude %]
[%= title.altitude %]
[%= title.illumination %]
[%= title.event( width = '' ) %]
[%- END %]
[%- FOR pass IN data %]
[%- events = pass.events %]
[%- evt = events.first %]
[%- evt.date %] [% evt.oid %] - [% evt.name( width = '' ) %]
[%- FOREACH evt IN events %]
[%- evt.time %]
[%= evt.local_coord %]
[%= evt.latitude %]
[%= evt.longitude %]
[%= evt.altitude %]
[%= evt.illumination %]
[%= evt.event( width = '' ) %]
[%- IF 'apls' == evt.event( units = 'string', width = '' ) %]
[%- apls = evt.appulse %]
[%- title.time( '' ) %]
[%= apls.local_coord %]
[%= apls.angle %] degrees from [% apls.name( width = '' ) %]
[%- END %]
[%- END %]
[%- END -%]
pass_events
This template defaults to
[% DEFAULT data = sp.pass( arg ) %]
[%- CALL title.title_gravity( TITLE_GRAVITY_BOTTOM ) %]
[%- WHILE title.more_title_lines %]
[%- title.date %] [% title.time %]
[%= title.oid %] [% title.event %]
[%= title.illumination %] [% title.local_coord %]
[%- END %]
[%- FOREACH evt IN data.events %]
[%- evt.date %] [% evt.time %]
[%= evt.oid %] [% evt.event %]
[%= evt.illumination %] [% evt.local_coord %]
[% END -%]
The difference between this template and the pass template is that this template orders the events chronologically, without respect to their source, whereas the pass template orders passes chronologically by satellite.
phase
This template defaults to
[% DEFAULT data = sp.phase( arg ) -%]
[%- CALL title.title_gravity( TITLE_GRAVITY_BOTTOM ) %]
[%- WHILE title.more_title_lines %]
[%- title.date( align_left = 0 ) %]
[%= title.time( align_left = 0 ) %]
[%= title.name( width = 8, align_left = 0 ) %]
[%= title.phase( places = 0, width = 4 ) %]
[%= title.phase( width = 16, units = 'phase',
align_left = 1 ) %]
[%= title.fraction_lit( title = 'Lit', places = 0, width = 4,
units = 'percent', align_left = 0 ) %]
[%- END %]
[%- FOR item IN data %]
[%- item.date %] [% item.time %]
[%= item.name( width = 8, align_left = 0 ) %]
[%= item.phase( places = 0, width = 4 ) %]
[%= item.phase( width = 16, units = 'phase',
align_left = 1 ) %]
[%= item.fraction_lit( places = 0, width = 4,
units = 'percent' ) %]%
[% END -%]
position
This template defaults to
[% DEFAULT data = sp.position( arg ) %]
[%- CALL title.title_gravity( TITLE_GRAVITY_BOTTOM ) %]
[%- data.date %] [% data.time %]
[%- WHILE title.more_title_lines %]
[%- title.name( align_left = 0, width = 16 ) %]
[%= title.local_coord %]
[%= title.epoch( align_left = 0 ) %]
[%= title.illumination %]
[%- END %]
[%- FOR item IN data.bodies() %]
[%- item.name( width = 16, missing = 'oid', align_left = 0 ) %]
[%= item.local_coord %]
[%= item.epoch( align_left = 0 ) %]
[%= item.illumination %]
[%- FOR refl IN item.reflections() %]
[%- item.name( literal = '', width = 16 ) %]
[%= item.local_coord( literal = '' ) %] MMA
[%- IF refl.status( width = '' ) %]
[%= refl.mma( width = '' ) %] [% refl.status( width = '' ) %]
[%- ELSE %]
[%= refl.mma( width = '' ) %] mirror angle [%
refl.angle( width = '' ) %] magnitude [%
refl.magnitude( width = '' ) %]
[%- END %]
[%- END -%]
[% END -%]
tle
This template defaults to
[% DEFAULT data = sp.tle( arg ) -%]
[% FOR item IN data %]
[%- item.tle -%]
[% END -%]
Note the absence of the trailing newline, which is assumed to be part of the tle data itself.
tle_verbose
This template defaults to
[% DEFAULT data = sp.tle( arg ) -%]
[% CALL title.fixed_width( 0 ) -%]
[% FOR item IN data -%]
[% CALL item.fixed_width( 0 ) -%]
[% title.oid %]: [% item.oid %]
[% title.name %]: [% item.name %]
[% title.international %]: [% item.international %]
[% title.epoch %]: [% item.epoch( units = 'zulu' ) %] GMT
[% title.effective_date %]: [%
item.effective_date( units = 'zulu',
missing = '<none>' ) %] GMT
[% title.classification %]: [% item.classification %]
[% title.mean_motion %]: [% item.mean_motion( places = 8 )
%] degrees/minute
[% title.first_derivative %]: [%
item.first_derivative( places = 8 ) %] degrees/minute squared
[% title.second_derivative %]: [%
item.second_derivative( places = 5 ) %] degrees/minute cubed
[% title.b_star_drag %]: [% item.b_star_drag( places = 5 ) %]
[% title.ephemeris_type %]: [% item.ephemeris_type %]
[% title.inclination %]: [% item.inclination( places = 4 ) %] degrees
[% title.ascending_node %]: [% item.ascending_node(
places = 0 ) %] in right ascension
[% title.eccentricity %]: [% item.eccentricity( places = 7 ) %]
[% title.argument_of_perigee %]: [%
item.argument_of_perigee( places = 4 )
%] degrees from ascending node
[% title.mean_anomaly %]: [%
item.mean_anomaly( places = 4 ) %] degrees
[% title.element_number %]: [% item.element_number %]
[% title.revolutions_at_epoch %]: [% item.revolutions_at_epoch %]
[% title.period %]: [% item.period %]
[% title.semimajor %]: [% item.semimajor( places = 1 ) %] kilometers
[% title.perigee %]: [% item.perigee( places = 1 ) %] kilometers
[% title.apogee %]: [% item.apogee( places = 1 ) %] kilometers
[% END -%]
Other Methods
The following other methods are provided.
decode
$fmt->decode( format_effector => 'azimuth' );
This method overrides the Astro::App::Satpass2::Format decode() method. In addition to the functionality provided by the parent, the following methods return something different when invoked via this method:
- format_effector
-
If called as an accessor, the name of the formatter accessed is prepended to the returned array. If this leaves the returned array with just one entry, the string
'undef'
is appended. The return is still an array in list context, and an array reference in scalar context.If called as a mutator, you still get back the object reference.
If a subclass overrides this method, the override should either perform the decoding itself, or delegate to SUPER::decode
.
report
$fmt->report( template => $template, ... );
This method represents the interface to Template-Toolkit, and all the "Formatter" methods come through here eventually.
The arguments to this method are name/value pairs. The template
argument is required, and is either the name of a template file, or a reference to a string containing the template. All other arguments are passed to Template-Toolkit
as variables. If argument arg
is specified and its value is an array reference, the value is enclosed in an Astro::App::Satpass2::Wrap::Array object, since by convention this is the argument passed back to Astro::App::Satpass2 methods.
In addition to any variables passed in, the following array methods are defined for Template-Toolkit
before it is invoked:
- events
-
If called on an array of passes, returns all events in all passes, in chronological order.
- fixed_width
-
If called on an array of Astro::App::Satpass2::FormatValue objects, calls fixed_width() on them. You may specify an argument to
fixed_width()
.Nothing is returned.
The canned templates can also be run as reports, and in fact will be taken in preference to files of the same name. If you do this, you will need to pass the relevant Astro::App::Satpass2 object as the sp
argument, since by convention the canned templates all look to that variable to compute their data if they do not already have a data
variable.
template
print "Template 'almanac' is :\n", $fmt->template( 'almanac' );
$fmt->template( almanac => <<'EOD' );
[% DEFAULT data = sp.almanac( arg ) -%]
[% FOREACH item IN data %]
[%- item.date %] [% item.time %]
[%= item.almanac( units = 'description' ) %]
[% END -%]
EOD
This method is not inherited from Astro::App::Satpass2::Format.
If called with a single argument (the name of a template) this method is an accessor that returns the named template. If the named template does not exist, this method croaks.
If called with two arguments (the name of a template and the template itself), this method is a mutator that sets the named template. If the template is undef
, the named template is deleted. The object itself is returned, to allow call chaining.
SUPPORT
Support is by the author. Please file bug reports at http://rt.cpan.org, or in electronic mail to the author.
AUTHOR
Thomas R. Wyant, III wyant at cpan dot org
COPYRIGHT AND LICENSE
Copyright (C) 2010-2011 by Thomas R. Wyant, III
This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES.
This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.