File Coverage

blib/lib/Astro/FITS/HdrTrans/Base.pm
Criterion Covered Total %
statement 205 239 85.7
branch 37 54 68.5
condition 14 30 46.6
subroutine 74 79 93.6
pod 38 65 58.4
total 368 467 78.8


line stmt bran cond sub pod time code
1             package Astro::FITS::HdrTrans::Base;
2              
3             =head1 NAME
4              
5             Astro::FITS::HdrTrans::Base - Base class for header translation
6              
7             =head1 SYNOPSIS
8              
9             use base qw/ Astro::FITS::HdrTrans::Base /;
10              
11             %generic = Astro::FITS::HdrTrans::Base->translate_from_FITS( \%fits );
12             %fits = Astro::FITS::HdrTrans::Base->translate_to_FITS( \%gen );
13              
14             =head1 DESCRIPTION
15              
16             This is the header translation base class. Not to be confused with
17             C<Astro::FITS::HdrTrans> itself, which is a high level abstraction
18             class. In general users should use C<Astro::FITS::HdrTrans>
19             for initiating header translations unless they know what they are
20             doing. Also C<Astro::FITS::HdrTrans> is the only public interface
21             to the header translation.
22              
23             =cut
24              
25 59     59   1483369 use 5.006;
  66         851  
26 62     66   374 use strict;
  57         166  
  58         1397  
27 54     62   327 use warnings;
  52         169  
  52         1628  
28 53     57   304 use Carp;
  54         169  
  52         3773  
29 52     58   24617 use Math::Trig qw/ deg2rad /;
  52         590393  
  52         4815  
30              
31 52     54   543 use vars qw/ $VERSION /;
  52         342  
  52         4275  
32 52     52   28558 use Astro::FITS::HdrTrans (); # for the generic header list
  52         148  
  52         114872  
33              
34             $VERSION = "1.64";
35              
36             =head1 PUBLIC METHODS
37              
38             All methods in this class are CLASS METHODS. No state is retained
39             outside of the hash argument.
40              
41             =over 4
42              
43             =item B<translate_from_FITS>
44              
45             Do the header translation from FITS for the specified class.
46              
47             %generic = $class->translate_to_FITS( \%fitshdr,
48             prefix => $prefix,
49             frameset => $wcs,
50             );
51              
52             Prefix is attached to the keys in the returned hash if it
53             is defined. The frameset is an optional Starlink::AST object.
54              
55             If a translation results in an undefined value (for example, if the
56             headers can represent both imaging and spectroscopy there may be no
57             requirement for a DISPERSION header), the result is not stored in the
58             translated hash.
59              
60             A list of failed translations is available in the _UNDEFINED_TRANSLATIONS
61             key in the generic hash. This points to a reference to an array of all
62             the failed generic translations.
63              
64             The class used for the translation is stored in the key _TRANSLATION_CLASS.
65             This can then be used to reverse the translation without having to
66             re-scan the headers.
67              
68             =cut
69              
70             sub translate_from_FITS {
71 20     21 1 67 my $class = shift;
72 20         48 my $FITS = shift;
73 20         105 my %opts = @_;
74              
75 20         54 my $prefix = '';
76 20 100 66     148 if ( exists( $opts{prefix} ) &&
77             defined( $opts{prefix} ) ) {
78 1         3 $prefix = $opts{prefix};
79             }
80              
81 20         46 my $frameset;
82 20 50 33     122 if ( exists( $opts{frameset} ) &&
83             defined( $opts{frameset} ) ) {
84 0         0 $frameset = $opts{frameset};
85             }
86              
87 20 50 33     143 croak "translate_from_FITS: Not a hash reference!"
88             unless (ref($FITS) && ref($FITS) eq 'HASH');
89              
90             # Now we need to loop over the known generic headers
91             # which we obtain from Astro::FITS::HdrTrans
92 20         107 my @GEN = Astro::FITS::HdrTrans->generic_headers;
93              
94 20         70 my %generic;
95             my @failed;
96 20         54 for my $g (@GEN) {
97 2820         5238 my $method = "to_$g";
98 2820 100       18114 if ($class->can( $method )) {
99 1159         24445 my $result = $class->$method( $FITS, $frameset );
100 1159 100       13939 if (defined $result) {
101 898         3066 $generic{"$prefix$g"} = $result;
102             } else {
103 261         685 push(@failed, $g);
104             }
105             }
106             }
107              
108             # store the failed translations (if we had any)
109 20 50       112 $generic{_UNDEFINED_TRANSLATIONS} = \@failed if @failed;
110              
111             # store the translation class
112 20         97 $generic{_TRANSLATION_CLASS} = $class;
113              
114 20         1072 return %generic;
115             }
116              
117             =item B<translate_to_FITS>
118              
119             Do the header translation from generic headers to FITS
120             for the specified class.
121              
122             %fits = $class->translate_to_FITS( \%generic );
123              
124             =cut
125              
126             sub translate_to_FITS {
127 15     17 1 39 my $class = shift;
128 15         31 my $generic = shift;
129              
130 15 50 33     97 croak "translate_to_FITS: Not a hash reference!"
131             unless (ref($generic) && ref($generic) eq 'HASH');
132              
133             # Now we need to loop over the known generic headers
134             # which we obtain from Astro::FITS::HdrTrans
135 15         60 my @GEN = Astro::FITS::HdrTrans->generic_headers;
136              
137 15         36 my %FITS;
138 15         44 for my $g (@GEN) {
139 2115         4120 my $method = "from_$g";
140 2115 100       11921 if ($class->can( $method )) {
141 777         18346 %FITS = (%FITS,$class->$method( $generic ));
142             }
143              
144             }
145              
146 15         461 return %FITS;
147             }
148              
149             =back
150              
151             =head1 PROTECTED METHODS
152              
153             These methods are available to translation subclasses and should
154             not be used by external classes.
155              
156             =over 4
157              
158             =item B<can_translate>
159              
160             Returns true if the supplied headers can be handled by this class.
161              
162             $cando = $class->can_translate( \%hdrs );
163              
164             The base class version of this method returns true if either the C<INSTRUME>
165             or C<INSTRUMENT> key exist and match the value returned by the
166             C<this_instrument> method. Comparisons are case-insensitive and can use
167             regular expressions on instrument name if provided by the base class.
168              
169              
170             =cut
171              
172             sub can_translate {
173 527     527 1 1062 my $class = shift;
174 527         883 my $headers = shift;
175              
176             # get the reference instrument string
177 527         2195 my $ref = $class->this_instrument();
178 527 50       1508 return 0 unless defined $ref;
179              
180             # For consistency in subsequent algorithm convert
181             # a string to a pattern match object
182 527 100       1257 if (not ref($ref)) {
183 243         625 $ref = quotemeta($ref);
184 243         3262 $ref = qr/^$ref$/i;
185             }
186              
187             # check against the FITS and Generic versions.
188 527         866 my $inst;
189 527         1226 for my $k (qw/ INSTRUME INSTRUMENT /) {
190 540 100 66     2492 if (exists $headers->{$k} && defined $headers->{$k}) {
191 527         44867 $inst = $headers->{$k};
192 527         27486 last;
193             }
194             }
195              
196             # no recognizable instrument
197 527 50       1451 return 0 unless defined $inst;
198              
199             # Now do the test
200 527         4239 return ( $inst =~ $ref );
201             }
202              
203             =item B<this_instrument>
204              
205             Name of the instrument that can be translated by this class.
206             Defaults to an empty string. The method must be subclassed.
207              
208             $inst = $class->this_instrument();
209              
210             Can return a regular expresion object (C<qr>).
211              
212             =cut
213              
214             sub this_instrument {
215 0     0 1 0 return "";
216             }
217              
218             =item B<valid_class>
219              
220             Historically this method was used to determine whether this class can
221             handle the supplied FITS headers. The headers can be either in
222             generic form or in FITS form.
223              
224             $isvalid = $class->valid_class( \%fits );
225              
226             The base class always returns false. This is a backwards compatibility
227             method to prevent mixing of translation modules from earlier release
228             of C<Astro::FITS::HdrTrans> with the current object-oriented version.
229             See the C<can_translate> method for the new interface.
230              
231             =cut
232              
233             sub valid_class {
234 0     0 1 0 return 0;
235             }
236              
237             =item B<_generate_lookup_methods>
238              
239             We generate the unit and constant mapping methods automatically from a
240             lookup table.
241              
242             Astro::FITS::HdrTrans::UKIRT->_generate_lookup_methods( \%const, \%unit);
243              
244             This method generates all the simple internal methods. Expects two arguments,
245             both references to hashes. The first is a reference to a hash with
246             constant mapping from FITS to generic (and no reverse mapping), the
247             second is a reference to a hash with unit mappings (both from and to
248             methods are created). The methods are placed into the package given
249             by the class supplied to the method.
250              
251             Astro::FITS::HdrTrans::UKIRT->_generate_lookup_methods( \%const, \%unit, \%null);
252              
253             Additionally, an optional third argument can be used to indicate
254             methods that should be null translations. This is a reference to an array
255             of generic keywords and should be used in the rare cases when a base
256             class implementation should be nullified. This will result in undefined
257             values in the generic hash but no value in the generic to FITS mapping.
258              
259             A fourth optional argument can specify those unit mappings that should
260             use the final entry in a subheader (if a subheader is present). Mainly
261             associated with END events such as AIRMASS_END or ELEVATION_END.
262              
263             Astro::FITS::HdrTrans::UKIRT->_generate_lookup_methods( \%const, \%unit,
264             \%null, \%endobs);
265              
266             These methods will have the standard interface of
267              
268             $generic = $class->_to_GENERIC_NAME( \%fits );
269             %fits = $class->_from_GENERIC_NAME( \%generic );
270              
271             Generic unit map translations use the via_subheader() method in scalar
272             context and so will retrieve the first sub header value if the keyword
273             is not present in the primary header.
274              
275             =cut
276              
277             sub _generate_lookup_methods {
278 512     512   1291 my $class = shift;
279 512         885 my $const = shift;
280 512         801 my $unit = shift;
281 512         836 my $null = shift;
282 512         811 my $endobs = shift;
283              
284             # Have to go into a different package
285 512         1344 my $p = "{\n package $class;\n";
286 512         841 my $ep = "\n}"; # close the scope
287              
288             # Loop over the keys to the unit mapping hash
289             # The keys are the GENERIC name
290 512         2441 for my $key (keys %$unit) {
291              
292             # Get the original FITS header name
293 4826         11273 my $fhdr = $unit->{$key};
294              
295             # print "Processing $key and $ohdr and $fhdr\n";
296              
297             # First generate the code to generate Generic headers
298 4826         9786 my $subname = "to_$key";
299 4826         12002 my $sub = qq/ $p sub $subname { scalar \$_[0]->via_subheader_undef_check(\$_[1],\"$fhdr\"); } $ep /;
300 4826     1 0 390850 eval "$sub";
  1     15 0 5  
  15     10 1 82  
  10     5 1 56  
  5     8 1 30  
  8     16 1 51  
  16     23 0 92  
  23     22 0 117  
  22     32 0 156  
  32     39 0 187  
  39     59 0 224  
  59     52 0 360  
  52     77 0 261  
  77     35 0 405  
  35     32 1 195  
  32     61 1 201  
  61     45 1 430  
  45     38 0 226  
  38     40 0 225  
  40     33 1 217  
  33     22 1 166  
  22     18 1 126  
  18     14 1 104  
  14     14 0 74  
  14     8 0 75  
  8     11 0 47  
  11     6 0 65  
  6         34  
301             #print "Sub: $sub\n";
302              
303             # Now the from
304 4826         11936 $subname = "from_$key";
305 4826         13053 $sub = qq/ $p sub $subname { (\"$fhdr\", \$_[1]->{\"$key\"}); } $ep/;
306 4826     38 1 370567 eval "$sub";
  38     35 1 235  
  35     38 1 253  
  38     9 1 216  
  9     23 1 67  
  23     24 1 208  
  24     50 0 179  
  50     16 0 528  
  16     28 0 150  
  28     48 0 330  
  48     52 0 576  
  52     24 1 647  
  24     43 1 288  
  43     35 1 624  
  35     40 0 1127  
  40     19 0 547  
  19     30 1 327  
  30     53 1 524  
  53     22 1 904  
  22     29 1 427  
  29     7 0 443  
  7         36  
307             #print "Sub: $sub\n";
308              
309             }
310              
311             # and the CONSTANT mappings (only to_GENERIC_NAME)
312 512         2313 for my $key (keys %$const) {
313 793         1960 my $subname = "to_$key";
314 793         1575 my $val = $const->{$key};
315             # A method so no gain in using a null prototype
316 793         2656 my $sub = qq/ $p sub $subname { \"$val\" } $ep /;
317 793     13 1 49530 eval "$sub";
  13     30 1 231  
  30     16 1 536  
  16     17 0 213  
  11     11 0 45  
  15     22 0 86  
  26     5 1 110  
  9         54  
318             }
319              
320             # the null mappings
321 512 100       2322 if (defined $null) {
322 272         667 for my $key (@$null) {
323             # to generic
324 62         186 my $subname = "to_$key";
325 62         193 my $sub = qq/ $p sub $subname { } $ep /;
326 62         3717 eval "$sub";
327              
328             # to generic
329 62         258 $subname = "from_$key";
330 62         208 $sub = qq/ $p sub $subname { return (); } $ep /;
331 62         3926 eval "$sub";
332             }
333             }
334              
335             # the mappings that are unit mappings but from the end of a subheader
336             # group (eg ELEVATION_END)
337 512 100       2196 if (defined $endobs) {
338 30         116 for my $key (keys %$endobs) {
339              
340             # Get the original FITS header name
341 60         143 my $fhdr = $endobs->{$key};
342              
343             # print "Processing $key and $ohdr and $fhdr\n";
344              
345             # First generate the code to generate Generic headers
346 60         144 my $subname = "to_$key";
347 60         195 my $sub = qq/ $p sub $subname {
348             my \@allresults = \$_[0]->via_subheader_undef_check(\$_[1],\"$fhdr\");
349             return \$allresults[-1];
350             } $ep /;
351 60         6087 eval "$sub";
352             #print "Sub: $sub\n";
353              
354             # Now the from
355 60         176 $subname = "from_$key";
356 60         209 $sub = qq/ $p sub $subname { (\"$fhdr\", \$_[1]->{\"$key\"}); } $ep/;
357 60         4879 eval "$sub";
358             #print "Sub: $sub\n";
359              
360             }
361             }
362              
363             }
364              
365             =item B<nint>
366              
367             Return the nearest integer to a supplied floating point
368             value. 0.5 is rounded up.
369              
370             $int = Astro::FITS::HdrTrans->nint( $value );
371              
372             =cut
373              
374             sub nint {
375 26     16 1 146 my $class = shift;
376 18         77 my $value = shift;
377              
378 9 50       32 if ($value >= 0) {
379 8         33 return (int($value + 0.5));
380             } else {
381 0         0 return (int($value - 0.5));
382             }
383             }
384              
385             =item B<_parse_iso_date>
386              
387             Converts a UT date in form YYYY-MM-DDTHH:MM:SS.sss into a date
388             object (Time::Piece).
389              
390             $object = $trans->_parse_iso_date( $date );
391              
392             =cut
393              
394             sub _parse_iso_date {
395 65     79   155 my $self = shift;
396 65         148 my $datestr = shift;
397 65         105 my $return;
398 65 50       157 if (defined $datestr) {
399             # Not part of standard but we can deal with it
400 65         261 $datestr =~ s/Z//g;
401             # Time::Piece can not do fractional seconds. Should switch to DateTime
402 65         207 $datestr =~ s/\.\d+$//;
403             # parse
404 65         356 $return = Time::Piece->strptime( $datestr, "%Y-%m-%dT%T" );
405             }
406 65         4832 return $return;
407             }
408              
409             =item B<_parse_yyyymmdd_date>
410              
411             Converts a UT date in format YYYYMMDD into a date object.
412              
413             $ojbect = $trans->_parse_yyyymmdd_date( $date, $sep );
414              
415             Where $sep is the separator string and can be an empty string.
416             This allows 20090215, 2009-02-15 and 2009:02:15 to be parsed
417             by the same routine by using '', '-' and ':' respectively.
418              
419             =cut
420              
421             sub _parse_yyyymmdd_date {
422 8     12   17 my $self = shift;
423 8         17 my $datestr = shift;
424 8         14 my $sep = shift;
425 8 50       21 $sep = '' unless defined $sep;
426              
427             # OSX Leopard has a completely broken strptime that can not
428             # handle %Y%m%d. We need to change the string to make it
429             # into a parseable form (or switch to DateTime).
430 8 100       23 if (!$sep) {
431 1         2 $sep = "-";
432 1         7 $datestr = join($sep, substr($datestr,0,4),
433             substr($datestr,4,2),
434             substr($datestr,6));
435             }
436              
437 8         52 return Time::Piece->strptime( $datestr,join($sep,'%Y','%m','%d') );
438             }
439              
440             =item B<_add_seconds>
441              
442             Add the supplied number of seconds to the supplied time object
443             and return a new object.
444              
445             $new = $trans->_add_seconds( $base, $delta );
446              
447             =cut
448              
449             sub _add_seconds {
450 0     1   0 my $self = shift;
451 0         0 my $base = shift;
452 0         0 my $delta = shift;
453 0         0 return ($base + Time::Seconds->new( $delta ) );
454             }
455              
456             =item B<_utdate_to_object>
457              
458             Converts a UT date in YYYYMMDD format to a date object at midnight.
459              
460             $obj = $trans->_utdate_to_object( $YYYYMMDD );
461              
462             =cut
463              
464             sub _utdate_to_object {
465 0     0   0 my $self = shift;
466 0         0 my $utdate = shift;
467 0         0 my $year = substr($utdate, 0, 4);
468 0         0 my $month= substr($utdate, 4, 2);
469 0         0 my $day = substr($utdate, 6, 2);
470 0         0 my $basedate = $self->_parse_iso_date( $year."-".$month ."-".$day.
471             "T00:00:00");
472 0         0 return $basedate;
473             }
474              
475             =item B<cosdeg>
476              
477             Return the cosine of the angle. The angle must be in degrees.
478              
479             =cut
480              
481             sub cosdeg {
482 0     0 1 0 my $self = shift;
483 0         0 my $deg = shift;
484 0         0 cos( deg2rad($deg) );
485             }
486              
487             =item B<sindeg>
488              
489             Return the sine of the angle. The angle must be in degrees.
490              
491             =cut
492              
493             sub sindeg {
494 0     0 1 0 my $self = shift;
495 0         0 my $deg = shift;
496 0         0 sin( deg2rad($deg) );
497             }
498              
499             =item B<via_subheader>
500              
501             For the supplied FITS header item, first check the primary header
502             for existence, then check SUBHEADERS, then check "In" named subheaders.
503              
504             In scalar context returns the first value that matches.
505              
506             $value = $trans->via_subheader( $FITS_headers, $keyword );
507              
508             In list context returns all the available values in order.
509              
510             @values = $trans->via_subheader( $FITS_headers, $keyword );
511              
512             =cut
513              
514             sub via_subheader {
515 970     970 1 1468 my $self = shift;
516 970         1325 my $FITS_headers = shift;
517 970         1463 my $keyword = shift;
518              
519 970         1414 my @values;
520 970 100 100     3462 if (exists $FITS_headers->{$keyword}
    50 66        
    50 33        
521             && defined $FITS_headers->{$keyword}) {
522              
523 713 50       62723 if ( ref( $FITS_headers->{$keyword} ) eq 'ARRAY' ) {
524 0         0 @values = @{$FITS_headers->{$keyword}};
  0         0  
525             } else {
526 713         41265 push (@values,$FITS_headers->{$keyword});
527             }
528             } elsif ( $FITS_headers->{SUBHEADERS}
529             && exists $FITS_headers->{SUBHEADERS}->[0]->{$keyword}) {
530 0         0 my @subs = @{$FITS_headers->{SUBHEADERS}};
  0         0  
531 0         0 for my $s (@subs) {
532 0 0 0     0 if (exists $s->{$keyword} && defined $s->{$keyword}) {
533 0         0 push(@values, $s->{$keyword});
534             }
535             }
536             } elsif (exists $FITS_headers->{I1}
537             && exists $FITS_headers->{I1}->{$keyword}) {
538             # need to find out how many In we have
539 0         0 my $i = 1;
540 0         0 while (exists $FITS_headers->{"I$i"}) {
541 0         0 push(@values, $FITS_headers->{"I$i"}->{$keyword});
542 0         0 $i++;
543             }
544             }
545              
546 970 50       60985 return (wantarray ? @values : $values[0] );
547             }
548              
549             =item B<via_subheader_undef_check>
550              
551             Version of via_subheader that removes undefined values from the list before
552             returning the answer. Useful for SCUBA-2 where the first dark may not include
553             the TCS information.
554              
555             Same interface as via_subheader.
556              
557             =cut
558              
559             sub via_subheader_undef_check {
560 896     896 1 1635 my $self = shift;
561 896         2126 my @values = $self->via_subheader( @_ );
562              
563             # completely filter out undefs
564 896         1661 @values = grep { defined $_ } @values;
  661         1700  
565 896 100       2734 return (wantarray ? @values : $values[0] );
566             }
567              
568             =back
569              
570             =head1 PROTECTED IMPORTS
571              
572             Not all translation methods warrant a full blown inheritance. For
573             cases where one or two translation routines should be imported
574             (e.g. reading DATE-OBS FITS standard headers without importing the
575             additional FITS methods) a special import routine can be used when
576             using the class.
577              
578             use Astro::FITS::HdrTrans::FITS qw/ ROTATION /;
579              
580             This will load the from_ROTATION and to_ROTATION methods into
581             the namespace.
582              
583             =cut
584              
585             sub import {
586 35     35   101 my $class = shift;
587              
588             # this is where we are going to install the methods
589 35         101 my $callpkg = caller();
590              
591             # Prepend the from_ and to_ prefixes
592 35         759 for my $key (@_) {
593             # The key can be fully specified with from_ and to_ already
594             # In that case we do not want to loop over from_ and to_
595 20         61 my @directions = qw/ from_ to_ /;
596 20 50 33     163 if ($key =~ /^from_/ || $key =~ /^to_/) {
597 0         0 @directions = ( '' ); # empty prefix
598             }
599              
600 20         63 for my $dir (@directions) {
601 40         95 my $method = $dir . $key;
602             #print "Importing method $method\n";
603 52     52   860 no strict 'refs';
  52         183  
  52         9704  
604              
605 40 50       58 if (!defined *{"$class\::$method"}) {
  40         167  
606 0         0 croak "Method $method is not available for export from class $class";
607             }
608              
609             # assign it
610 40         65 *{"$callpkg\::$method"} = \&{"$class\::$method"};
  40         515  
  40         127  
611             }
612             }
613              
614             }
615              
616             =head1 WRITING A TRANSLATION CLASS
617              
618             In order to create a translation class for a new instrument it is
619             first necessary to work out the different types of translations that
620             are required; whether they are unit mappings (a simple change of
621             keyword but no change in value), constant mappings (a constant is
622             returned independently of the FITS header), mappings that already
623             exist in another class or complex mappings that have to be explicitly
624             coded.
625              
626             All translation classes must ultimately inherit from
627             C<Astro::FITS::HdrTrans::Base>.
628              
629             The first step in creation of a class is to handle the "can this class
630             translate the supplied headers" query that will be requested from
631             the C<Astro::FITS::HdrTrans> package. If the instrument name is present
632             in the standard "INSTRUME" FITS header then this can be achieved simply
633             by writing a C<this_instrument> method in the subclass that will return
634             the name of the instrument that can be translated. If a more complex
635             decision is required it will be necessary to subclass the C<can_translate>
636             method. This takes the headers that are to be translated (either in FITS
637             or generic form since the method is queried for either direction) and
638             returns a boolean indicating whether the class can be used.
639              
640             Once the class can declare it's translation instrument the next
641             step is to write the actual translation methods themselves. If any
642             unit- or constant-mappings are required they can be setup by defining
643             the %UNIT_MAP and %CONST_MAP (the names are unimportant) hashes
644             and calling the base class automated method constructor:
645              
646             __PACKAGE__->_generate_lookup_methods( \%CONST_MAP, \%UNIT_MAP );
647              
648             If your translations are very similar to an existing set of translations
649             you can inherit from that class instead of C<Astro::FITS::HdrTrans::Base>.
650             Multiple inheritance is supported if, for example, you need to
651             inherit from both the standard FITS translations (eg for DATE-OBS
652             processing) and from a more telescope-specific set of translations.
653              
654             If inheritance causes some erroneous mappings to leak through it is
655             possible to disable a specific mapping by specifying a @NULL_MAP
656             array to the method generation. This is an array of generic keywords.
657              
658             __PACKAGE__->_generate_lookup_methods( \%CONST_MAP, \%UNIT_MAP,
659             \@NULL_MAP );
660              
661             If a subset of translation methods are required from another class
662             but there is no desire to inherit the full set of methods then it
663             is possible to import specific translation methods from other classes.
664              
665             use Astro::FITS::HdrTrans::FITS qw/ UTSTART UTEND /;
666              
667             would import just the DATE-OBS and DATE-END handling functions from
668             the FITS class. Note that both the from- and to- translations will
669             be imported.
670              
671             At some point you may want to write your own more complex translations.
672             To do this you must write to- and from- methods. The API for all
673             the from_FITS translations is identical:
674              
675             $translation = $class->to_GENERIC_KEYWORD( \%fits_headers );
676              
677             ie given a reference to a hash of FITS headers (which can be
678             a tied C<Astro::FITS::Header> object), return a scalar value which
679             is the translated value.
680              
681             To convert from generic to FITS the interface is:
682              
683             %fits_subset = $class->from_GENERIC_KEYWORD( \%generic_header );
684              
685             ie multiple FITS keywords and values can be returned since in some
686             cases a single generic keyword is obtained by combining information
687             from multiple FITS headers.
688              
689             Finally, if this translation module is to be part of the
690             C<Astro::FITS::HdrTrans> distribution the default list of translation
691             classes must be updated in C<Astro::FITS::HdrTrans>. If this is to be
692             a runtime plugin, then the list of classes can be expanded at
693             runtime. For example, it should be possible for
694             C<Astro::FITS::HdrTrans::MyNewInst> to automatically append itself to
695             the list of known classes if the module is explicitly loaded by the
696             user (rather than dynamically loaded to test the headers).
697              
698             Some generic keywords actually return scalar objects. Any new instruments
699             must consistently return compatible objects. For example, UTDATE,
700             UTSTART and UTEND return (currently) Time::Piece objects.
701              
702             =head1 SEE ALSO
703              
704             C<Astro::FITS::HdrTrans>
705              
706             =head1 AUTHOR
707              
708             Tim Jenness E<lt>t.jenness@jach.hawaii.eduE<gt>
709              
710             =head1 COPYRIGHT
711              
712             Copyright (C) 2003-2005 Particle Physics and Astronomy Research Council.
713             All Rights Reserved.
714              
715             This program is free software; you can redistribute it and/or modify it under
716             the terms of the GNU General Public License as published by the Free Software
717             Foundation; either version 2 of the License, or (at your option) any later
718             version.
719              
720             This program is distributed in the hope that it will be useful,but WITHOUT ANY
721             WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
722             PARTICULAR PURPOSE. See the GNU General Public License for more details.
723              
724             You should have received a copy of the GNU General Public License along with
725             this program; if not, write to the Free Software Foundation, Inc., 59 Temple
726             Place,Suite 330, Boston, MA 02111-1307, USA
727              
728             =cut
729              
730             1;