File Coverage

blib/lib/Astro/FITS/HdrTrans/Base.pm
Criterion Covered Total %
statement 204 239 85.3
branch 37 54 68.5
condition 14 30 46.6
subroutine 73 79 92.4
pod 36 65 55.3
total 364 467 77.9


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 68     68   1609960 use 5.006;
  62         648  
26 57     62   434 use strict;
  56         183  
  54         1368  
27 60     57   361 use warnings;
  52         121  
  55         1656  
28 52     56   330 use Carp;
  57         141  
  52         3787  
29 52     54   24539 use Math::Trig qw/ deg2rad /;
  52         587591  
  52         5315  
30              
31 52     60   581 use vars qw/ $VERSION /;
  52         348  
  52         7601  
32 52     52   27654 use Astro::FITS::HdrTrans (); # for the generic header list
  52         174  
  52         117107  
33              
34             $VERSION = "1.63";
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     20 1 45 my $class = shift;
72 20         48 my $FITS = shift;
73 20         89 my %opts = @_;
74              
75 20         45 my $prefix = '';
76 20 100 66     130 if ( exists( $opts{prefix} ) &&
77             defined( $opts{prefix} ) ) {
78 1         13 $prefix = $opts{prefix};
79             }
80              
81 20         39 my $frameset;
82 20 50 33     128 if ( exists( $opts{frameset} ) &&
83             defined( $opts{frameset} ) ) {
84 0         0 $frameset = $opts{frameset};
85             }
86              
87 20 50 33     135 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         125 my @GEN = Astro::FITS::HdrTrans->generic_headers;
93              
94 20         82 my %generic;
95             my @failed;
96 20         70 for my $g (@GEN) {
97 2820         4991 my $method = "to_$g";
98 2820 100       15793 if ($class->can( $method )) {
99 1159         23305 my $result = $class->$method( $FITS, $frameset );
100 1159 100       13265 if (defined $result) {
101 898         2845 $generic{"$prefix$g"} = $result;
102             } else {
103 261         686 push(@failed, $g);
104             }
105             }
106             }
107              
108             # store the failed translations (if we had any)
109 20 50       107 $generic{_UNDEFINED_TRANSLATIONS} = \@failed if @failed;
110              
111             # store the translation class
112 20         70 $generic{_TRANSLATION_CLASS} = $class;
113              
114 20         814 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     20 1 39 my $class = shift;
128 15         31 my $generic = shift;
129              
130 15 50 33     96 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         57 my @GEN = Astro::FITS::HdrTrans->generic_headers;
136              
137 15         37 my %FITS;
138 15         32 for my $g (@GEN) {
139 2115         3540 my $method = "from_$g";
140 2115 100       10478 if ($class->can( $method )) {
141 777         15675 %FITS = (%FITS,$class->$method( $generic ));
142             }
143              
144             }
145              
146 15         392 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 900 my $class = shift;
174 527         806 my $headers = shift;
175              
176             # get the reference instrument string
177 527         1988 my $ref = $class->this_instrument();
178 527 50       1417 return 0 unless defined $ref;
179              
180             # For consistency in subsequent algorithm convert
181             # a string to a pattern match object
182 527 100       1106 if (not ref($ref)) {
183 243         479 $ref = quotemeta($ref);
184 243         2837 $ref = qr/^$ref$/i;
185             }
186              
187             # check against the FITS and Generic versions.
188 527         853 my $inst;
189 527         974 for my $k (qw/ INSTRUME INSTRUMENT /) {
190 540 100 66     2226 if (exists $headers->{$k} && defined $headers->{$k}) {
191 527         38886 $inst = $headers->{$k};
192 527         24710 last;
193             }
194             }
195              
196             # no recognizable instrument
197 527 50       1377 return 0 unless defined $inst;
198              
199             # Now do the test
200 527         3917 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   1228 my $class = shift;
279 512         933 my $const = shift;
280 512         795 my $unit = shift;
281 512         809 my $null = shift;
282 512         801 my $endobs = shift;
283              
284             # Have to go into a different package
285 512         8521 my $p = "{\n package $class;\n";
286 512         1009 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         2439 for my $key (keys %$unit) {
291              
292             # Get the original FITS header name
293 4826         11885 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         10186 my $subname = "to_$key";
299 4826         11998 my $sub = qq/ $p sub $subname { scalar \$_[0]->via_subheader_undef_check(\$_[1],\"$fhdr\"); } $ep /;
300 4826     0 0 406184 eval "$sub";
  0     15 0 0  
  15     7 1 132  
  7     3 1 59  
  3     9 1 21  
  9     12 1 53  
  12     7 0 383  
  7     22 0 50  
  22     40 0 131  
  40     52 0 245  
  52     63 0 319  
  63     34 0 347  
  34     70 0 200  
  70     22 0 494  
  22     56 1 146  
  56     75 1 286  
  75     36 1 409  
  36     56 0 203  
  56     37 0 281  
  37     44 0 208  
  44     22 1 245  
  22     19 1 165  
  19     16 1 119  
  16     16 0 128  
  16     13 0 96  
  13     9 0 70  
  9     4 0 47  
  4         28  
301             #print "Sub: $sub\n";
302              
303             # Now the from
304 4826         12022 $subname = "from_$key";
305 4826         13403 $sub = qq/ $p sub $subname { (\"$fhdr\", \$_[1]->{\"$key\"}); } $ep/;
306 4826     14 1 378227 eval "$sub";
  14     27 1 83  
  27     29 1 205  
  29     18 1 189  
  18     21 1 139  
  21     27 0 137  
  27     17 0 219  
  17     26 0 140  
  26     19 0 200  
  19     49 0 188  
  49     61 0 526  
  61     32 1 1469  
  32     49 1 341  
  49     24 1 617  
  24     41 0 264  
  41     36 0 503  
  36     44 1 466  
  44     46 1 679  
  46     30 1 735  
  30     16 1 523  
  16     10 0 257  
  10         56  
307             #print "Sub: $sub\n";
308              
309             }
310              
311             # and the CONSTANT mappings (only to_GENERIC_NAME)
312 512         2270 for my $key (keys %$const) {
313 793         2113 my $subname = "to_$key";
314 793         1634 my $val = $const->{$key};
315             # A method so no gain in using a null prototype
316 793         2499 my $sub = qq/ $p sub $subname { \"$val\" } $ep /;
317 793     16 1 54509 eval "$sub";
  16     16 1 265  
  16     28 1 148  
  28     20 0 403  
  10     12 0 64  
  21     14 0 139  
  17     8 1 100  
  13         68  
318             }
319              
320             # the null mappings
321 512 100       2017 if (defined $null) {
322 272         731 for my $key (@$null) {
323             # to generic
324 62         175 my $subname = "to_$key";
325 62         192 my $sub = qq/ $p sub $subname { } $ep /;
326 62         3911 eval "$sub";
327              
328             # to generic
329 62         171 $subname = "from_$key";
330 62         194 $sub = qq/ $p sub $subname { return (); } $ep /;
331 62         4000 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       2057 if (defined $endobs) {
338 30         115 for my $key (keys %$endobs) {
339              
340             # Get the original FITS header name
341 60         139 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         145 my $subname = "to_$key";
347 60         191 my $sub = qq/ $p sub $subname {
348             my \@allresults = \$_[0]->via_subheader_undef_check(\$_[1],\"$fhdr\");
349             return \$allresults[-1];
350             } $ep /;
351 60         6015 eval "$sub";
352             #print "Sub: $sub\n";
353              
354             # Now the from
355 60         177 $subname = "from_$key";
356 60         206 $sub = qq/ $p sub $subname { (\"$fhdr\", \$_[1]->{\"$key\"}); } $ep/;
357 60         4649 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 28     19 1 168 my $class = shift;
376 13         50 my $value = shift;
377              
378 9 50       31 if ($value >= 0) {
379 8         28 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     75   135 my $self = shift;
396 65         141 my $datestr = shift;
397 65         89 my $return;
398 65 50       197 if (defined $datestr) {
399             # Not part of standard but we can deal with it
400 65         168 $datestr =~ s/Z//g;
401             # Time::Piece can not do fractional seconds. Should switch to DateTime
402 65         206 $datestr =~ s/\.\d+$//;
403             # parse
404 65         307 $return = Time::Piece->strptime( $datestr, "%Y-%m-%dT%T" );
405             }
406 65         4161 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     11   14 my $self = shift;
423 8         12 my $datestr = shift;
424 8         14 my $sep = shift;
425 8 50       17 $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       19 if (!$sep) {
431 1         2 $sep = "-";
432 1         5 $datestr = join($sep, substr($datestr,0,4),
433             substr($datestr,4,2),
434             substr($datestr,6));
435             }
436              
437 8         37 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 1232 my $self = shift;
516 970         1617 my $FITS_headers = shift;
517 970         1301 my $keyword = shift;
518              
519 970         1251 my @values;
520 970 100 100     3217 if (exists $FITS_headers->{$keyword}
    50 66        
    50 33        
521             && defined $FITS_headers->{$keyword}) {
522              
523 713 50       55540 if ( ref( $FITS_headers->{$keyword} ) eq 'ARRAY' ) {
524 0         0 @values = @{$FITS_headers->{$keyword}};
  0         0  
525             } else {
526 713         36327 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       53554 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 1696 my $self = shift;
561 896         1729 my @values = $self->via_subheader( @_ );
562              
563             # completely filter out undefs
564 896         1437 @values = grep { defined $_ } @values;
  661         1459  
565 896 100       2521 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   114 my $class = shift;
587              
588             # this is where we are going to install the methods
589 35         91 my $callpkg = caller();
590              
591             # Prepend the from_ and to_ prefixes
592 35         751 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         65 my @directions = qw/ from_ to_ /;
596 20 50 33     191 if ($key =~ /^from_/ || $key =~ /^to_/) {
597 0         0 @directions = ( '' ); # empty prefix
598             }
599              
600 20         53 for my $dir (@directions) {
601 40         95 my $method = $dir . $key;
602             #print "Importing method $method\n";
603 52     55   895 no strict 'refs';
  52         189  
  52         10003  
604              
605 40 50       66 if (!defined *{"$class\::$method"}) {
  40         189  
606 0         0 croak "Method $method is not available for export from class $class";
607             }
608              
609             # assign it
610 40         64 *{"$callpkg\::$method"} = \&{"$class\::$method"};
  40         518  
  40         117  
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;