File Coverage

blib/lib/Astro/Coords/Angle.pm
Criterion Covered Total %
statement 174 193 90.1
branch 83 108 76.8
condition 8 15 53.3
subroutine 29 30 96.6
pod 16 18 88.8
total 310 364 85.1


line stmt bran cond sub pod time code
1             package Astro::Coords::Angle;
2              
3             =head1 NAME
4              
5             Astro::Coords::Angle - Representation of an angle
6              
7             =head1 SYNOPSIS
8              
9             use Astro::Coords::Angle;
10              
11             $ang = new Astro::Coords::Angle( 45.5, units => 'deg' );
12             $ang = new Astro::Coords::Angle( "45:30:00", units => 'sexagesimal' );
13              
14             $rad = $ang->radians;
15             $deg = $ang->degrees;
16             $asec = $ang->arcsec;
17             $amin = $ang->arcmin;
18             $string = $ang->string;
19              
20             =head1 DESCRIPTION
21              
22             Helper class for C<Astro::Coords> to represent an angle. Methods are
23             provided for parsing angles in sexagesimal format and for returning
24             angles in any desired format.
25              
26             =cut
27              
28 23     23   3283953 use 5.006;
  23         121  
29 23     23   170 use strict;
  23         44  
  23         12713  
30 23     23   157 use warnings;
  23         54  
  23         2074  
31 23     23   165 use warnings::register;
  23         59  
  23         2879  
32 23     23   178 use Carp;
  23         47  
  23         2832  
33              
34 23     23   203 use Scalar::Util qw/ looks_like_number /;
  23         59  
  23         2012  
35 23     23   1674 use Astro::PAL;
  23         14417  
  23         11492  
36              
37             # Overloading
38             use overload
39 23         413 '""' => "stringify",
40             '0+' => "numify",
41 23     23   186 fallback => 1;
  23         86  
42              
43             # Package Global variables
44             our $VERSION = '0.23';
45              
46             =head1 METHODS
47              
48             =head2 Constructor
49              
50             =over 4
51              
52             =item B<new>
53              
54             Construct a new C<Angle> object. Must be called with an angle as first
55             argument. Optional hash arguments can be supplied to specify, for example,
56             the units of the supplied angle.
57              
58             $ang = new Astro::Coords::Angle( $angle,
59             units => "degrees" );
60              
61             Supported options are:
62              
63             units - units of the supplied string or number
64             range - restricted range of the angle
65              
66             Supported units are:
67              
68             sexagesimal - A string of format either dd:mm:ss or "dd mm ss"
69             "dms" separators are also supported.
70             degrees - decimal degrees
71             radians - radians
72             arcsec - arc seconds (abbreviated form is 'as')
73             arcmin - arc minutes (abbreviated form is 'am')
74              
75             The units can be abbreviated to the first 3 characters.
76              
77             If the units are not supplied the default is to assume "sexagesimal"
78             if the supplied string contains spaces or colons or the characters
79             "d", "m" or "s", "degrees" if the supplied number is greater than 2*PI
80             (6.28), and "radians" for all other values. Negative angles are supported.
81              
82             The options for range are documented in the C<range> method.
83              
84             If the angle can not be decoded (if a string), the constructor will fail.
85              
86             =cut
87              
88             sub new {
89 70347     70347 1 148480 my $proto = shift;
90 70347   66     246245 my $class = ref($proto) || $proto;
91              
92 70347 50       158344 croak "Constructor for object of class $class must be called with an argument" unless @_;
93              
94             # first argument is the angle
95 70347         133868 my $input_ang = shift;
96              
97             # optional hash, only read it if we have an even number of
98             # remaining arguments
99 70347         109379 my %args;
100 70347 100       156804 if (@_) {
101 70340 50       172471 if (scalar(@_) % 2 == 0) {
102 70340         249848 %args = @_;
103             } else {
104 0         0 warnings::warnif("An odd number of Optional arguments were supplied to constructor");
105             }
106             }
107              
108             # Now need to convert this to radians (the internal representation)
109             # Allow for inheritance
110 70347         241706 my $rad = $class->_cvt_torad($input_ang, $args{units});
111              
112 70347 0       158899 croak "Unable to decode supplied angle (".
    50          
113             (defined $input_ang ? "'$input_ang'" : "<undef>").")"
114             unless defined $rad;
115              
116             # Create the object
117 70347         355891 my $ang = bless {
118             ANGLE => $rad,
119             RANGE => 'NONE',
120             NDP => undef, # number of decimal places
121             DELIM => undef, # string delimiter
122             }, $class;
123              
124             # If a range was specified, normalise the angle
125 70347 100       281216 $ang->range( $args{range} ) if exists $args{range};
126              
127             # And return the object
128 70347         278349 return $ang;
129             }
130              
131             =back
132              
133             =head2 Accessor Methods
134              
135             =over 4
136              
137             =item B<radians>
138              
139             Return the angle in radians.
140              
141             $rad = $ang->radians;
142              
143             =cut
144              
145             sub radians {
146 106679     106679 1 171392 my $self = shift;
147 106679         1147695 return $self->{ANGLE};
148             }
149              
150             # undocumented since we do not want a public way of changing the
151             # angle
152             sub _setRadians {
153 38410     38410   60312 my $self = shift;
154 38410         62235 my $rad = shift;
155 38410 50       88805 croak "Angle must be defined" unless defined $rad;
156 38410         89866 $self->{ANGLE} = $rad;
157             }
158              
159             =item B<degrees>
160              
161             Return the angle in decimal degrees.
162              
163             $deg = $ang->degrees;
164              
165             =cut
166              
167             sub degrees {
168 227     227 1 445 my $self = shift;
169 227         584 my $rad = $self->radians;
170 227         2156 return $rad * Astro::PAL::DR2D;
171             }
172              
173             =item B<str_ndp>
174              
175             Number of decimal places to use when stringifying the object.
176             Default is to use the global class value (see the C<NDP> class method).
177             Set to C<undef> to revert to the class setting.
178              
179             $ang->str_ndp( 4 );
180             $ndp = $ang->str_ndp;
181              
182             =cut
183              
184             sub str_ndp {
185 96     96 1 716 my $self = shift;
186 96 100       471 if (@_) {
187 12         32 $self->{NDP} = shift;
188             }
189             # A value has been requested. Do we have a local value
190             # or should we return the default.
191 96 100       222 if (defined $self->{NDP} ) {
192 26         67 return $self->{NDP};
193             } else {
194 70         233 return $self->NDP;
195             }
196             }
197              
198             =item B<str_delim>
199              
200             Delimiter to use between components when stringifying.
201             Default is to use the global class value (see the C<DELIM> class method).
202             Set to C<undef> to revert to the class setting.
203              
204             $ang->str_delim( ":" );
205             $delim = $ang->str_delim;
206              
207             =cut
208              
209             sub str_delim {
210 87     87 1 142 my $self = shift;
211 87 100       189 if (@_) {
212 6         31 $self->{DELIM} = shift;
213             }
214             # A value has been requested. Do we have a local value
215             # or should we return the default.
216 87 100       201 if (defined $self->{DELIM} ) {
217 13         35 return $self->{DELIM};
218             } else {
219 74         196 return $self->DELIM;
220             }
221             }
222              
223             =item B<components>
224              
225             Return an array of components that correspond to the sign, degrees,
226             arcminutes and arcseconds of the angle. The sign will be either a '+'
227             or '-' and is required to distinguish '+0' from '-0'.
228              
229             @comp = $ang->components;
230              
231             The number of decimal places in the seconds will not be constrained by the
232             setting of C<str_ndp>, but is constrained by an optional argument:
233              
234             @comp = $ang->components( $ndp );
235              
236             Default resolution is 5 decimal places. The limit is 9 to avoid
237             overflowing the results from palDr2af or palDr2tf.
238              
239             In scalar context, returns a reference to an array.
240              
241             =cut
242              
243             sub components {
244 84     84 1 163 my $self = shift;
245 84         133 my $res = shift; # internal api
246              
247             # Get the angle in radians
248 84         181 my $rad = $self->radians;
249              
250             # Convert to components using PAL. COCO uses 4 dp for high
251             # resolution.
252 84 50       201 $res = 5 unless defined $res;
253              
254             # Limit $res to avoid overflowing results from palDr2af or palDr2tf.
255 84 50       193 if ($res > 9) {
256 0         0 warnings::warnif("Excess dp ($res) requested, limiting to 9");
257 0         0 $res = 9;
258             }
259              
260 84         295 my @dmsf = $self->_r2f( $res );
261              
262             # Combine the fraction with the seconds unless no decimal places
263 84         145 my $frac = pop(@dmsf);
264 84 100       522 $dmsf[-1] .= sprintf( ".%0$res"."d",$frac) unless $res == 0;
265              
266             #use Data::Dumper;
267             #print Dumper(\@dmsf);
268              
269 84 100       264 if (wantarray) {
270 81         280 return @dmsf;
271             } else {
272 3         17 return \@dmsf;
273             }
274              
275             }
276              
277             =item B<string>
278              
279             Return the angle as a string in sexagesimal format (e.g. 12:30:52.4).
280              
281             $string = $ang->string();
282              
283             The form of this string depends on the C<str_delim> and C<str_ndp>
284             settings and on whether the angular range allows negative values (the
285             sign will be dropped if the range is known to be positive).
286              
287             =cut
288              
289             sub string {
290 81     81 1 185 my $self = shift;
291              
292             # Get the components
293 81         222 my $ndp = $self->str_ndp;
294 81         332 my @dms = $self->components( $ndp );
295              
296             # Play it safe, and split the fractional part into two strings.
297             # if ndp > 0
298 81 100       198 if ( $ndp > 0 ) {
299 80         283 my ($sec, $frac) = split(/\./,$dms[-1]);
300 80         143 $dms[-1] = $sec;
301 80         184 push(@dms, $frac);
302             }
303              
304             # Now build the string.
305              
306             # Clear the + sign, setting it to empty string if the angle can never
307             # go negative.
308 81         184 my $sign = shift(@dms);
309 81 100       208 if ($sign eq '+') {
310 50 100       131 if ($self->range eq '2PI') {
311 41         99 $sign = '';
312             } else {
313 9         21 $sign = ' ';
314             }
315             }
316              
317             # Get the delimiter
318 81         222 my $delim = $self->str_delim;
319              
320             # Build the format
321              
322             # fractional part will not require a decimal place
323             # if ndp is 0. If ndp>0 the fraction is formatted
324 81 100       184 my $fracfmt = ( $ndp == 0 ? '' : '.%s' );
325              
326             # starting with the numeric part. Gal longitude will want %03d and no sign.
327             # RA will want no sign and %02d. Dec wants sign with %02d.
328              
329 81         221 my @fmts = ( '%02d', '%02d', '%02d'.$fracfmt);
330 81         137 my $fmt;
331 81 100       165 if (length($delim) == 1) {
332 78         251 $fmt = join($delim, @fmts );
333             } else {
334 3         11 my @chars = split (//, $delim );
335 3         8 for my $f (@fmts) {
336 9         27 $fmt .= $f . shift(@chars);
337             }
338             }
339              
340 81         896 return $sign . sprintf( $fmt, @dms);
341              
342             }
343              
344             =item B<arcsec>
345              
346             Return the angle in arcseconds.
347              
348             $asec = $ang->arcsec;
349              
350             =cut
351              
352             sub arcsec {
353 14     14 1 38 my $self = shift;
354 14         31 my $rad = $self->radians;
355 14         83 return $rad * Astro::PAL::DR2AS;
356             }
357              
358             =item B<arcmin>
359              
360             Return the angle in arcminutes.
361              
362             $amin = $ang->arcmin;
363              
364             =cut
365              
366             sub arcmin {
367 0     0 1 0 my $self = shift;
368 0         0 my $asec = $self->arcsec;
369 0         0 return $asec / 60.0;
370             }
371              
372             =item B<range>
373              
374             String describing the allowed range of the angle. Allowed values
375             are
376              
377             NONE - no pre-determined range
378             2PI - 0 to 2*PI radians (0 to 360 degrees)
379             PI - -PI to +PI radians (-180 to 180 degrees)
380              
381             Any other strings will be ignored (and a warning issued if appropriate).
382              
383             When a new value is provided, the angle is normalised to this range.
384             Note that this is not always reversible (especially if reverting to
385             "NONE"). The range can also be specified to the constructor.
386              
387             Default is not to normalize the angle.
388              
389             =cut
390              
391             sub range {
392 38469     38469 1 69676 my $self = shift;
393 38469 100       85816 if (@_) {
394 38413         71276 my $rng = shift;
395 38413 50       77376 if (defined $rng) {
396             # upper case
397 38413         75603 $rng = uc($rng);
398              
399             # get the current value for the angle
400 38413         95189 my $rad = $self->radians;
401              
402             # Now check validity of string and normalise
403 38413 100       118914 if ($rng eq 'NONE') {
    100          
    50          
404             # do nothing apart from store it
405             } elsif ($rng eq '2PI') {
406 29694         104826 $self->_setRadians( Astro::PAL::palDranrm( $rad ));
407             } elsif ($rng eq 'PI') {
408 8716         34307 $self->_setRadians( Astro::PAL::palDrange( $rad ));
409             } else {
410 0         0 warnings::warnif("Supplied range '$rng' not recognized");
411 0         0 return;
412             }
413             # store it
414 38413         98401 $self->{RANGE} = $rng;
415             } else {
416 0         0 warnings::warnif("Supplied range was not defined");
417             }
418             }
419 38469         77719 return $self->{RANGE};
420             }
421              
422             =item B<in_format>
423              
424             Simple wrapper method to support the backwards compatibility interface
425             in C<Astro::Coords> when requesting an angle by using a string format rather
426             than an explicit method.
427              
428             $angle = $ang->in_format( 'sexagesimal' );
429              
430             Supported formats are:
431              
432             radians calls 'radians' method
433             degrees calls 'degrees' method
434             sexagesimal calls 'string' method
435             array calls 'components' method (returns 2 dp resolution)
436             arcsec calls 'arcsec' method
437             arcmin calls 'arcmin' method
438              
439             The format can be abbreviated to the first 3 letters, or 'am' or 'as'
440             for arcmin and arcsec respectively. If no format is specified explicitly, the
441             object itself will be returned.
442              
443             =cut
444              
445             sub in_format {
446 41451     41451 1 68521 my $self = shift;
447 41451         74270 my $format = shift;
448              
449             # No format (including empty string), return the object
450 41451 100       170097 return $self unless $format;
451 2749         6133 $format = lc($format);
452              
453 2749 100 33     19731 if ($format =~ /^d/) {
    100 33        
    100          
    50          
    50          
    50          
454 184         478 return $self->degrees;
455             } elsif ($format =~ /^s/) {
456 16         42 return $self->string();
457             } elsif ($format =~ /^r/) {
458 2546         6845 return $self->radians();
459             } elsif ($format =~ /^arcm/ || $format eq 'am') {
460 0         0 return $self->arcmin;
461             } elsif ($format =~ /^arcs/ || $format eq 'as') {
462 0         0 return $self->arcsec;
463             } elsif ($format =~ /^a/) {
464 3         10 return $self->components($self->str_ndp);
465             } else {
466 0         0 warnings::warnif("Unsupported format '$format'. Returning radians.");
467 0         0 return $self->radians;
468             }
469             }
470              
471             =item B<clone>
472              
473             Create new cloned copy of this object.
474              
475             $clone = $ang->clone;
476              
477             =cut
478              
479             sub clone {
480 1     1 1 3 my $self = shift;
481 1         8 return bless { %$self }, ref $self;
482             }
483              
484             =item B<negate>
485              
486             Negate the sense of the angle, returning a new angle object.
487              
488             $neg = $ang->negate;
489              
490             Not allowed if the range is defined as 0 to 2PI.
491              
492             =cut
493              
494             sub negate {
495 3     3 1 10 my $self = shift;
496 3 50       11 croak "Angle can not be negated since its range is 0 to 2PI"
497             if $self->range eq '2PI';
498 3         12 my $rad = $self->radians;
499 3         11 return $self->new( $rad * -1.0, units => 'radians', range => $self->range );
500             }
501              
502             =back
503              
504             =head2 Overloading
505              
506             The object is overloaded such that it stringifies via the C<string>
507             method, and returns the angle in radians in numify context.
508              
509             =cut
510              
511             sub stringify {
512 22     22 0 752 my $self = shift;
513 22         67 return $self->string();
514             }
515              
516             sub numify {
517 64963     64963 0 158099 my $self = shift;
518 64963         141454 return $self->radians();
519             }
520              
521             =head2 Class Methods
522              
523             The following methods control the default behaviour of the class.
524              
525             =over 4
526              
527             =item B<NDP>
528              
529             The number of decimal places to use in the fractional part of
530             the number when stringifying (from either the C<string> method
531             or the C<components> method).
532              
533             Astro::Coords::Angle->NDP( 4 );
534              
535             Default value is 2. If this is changed then
536             all instances will be affected on stringification unless the
537             C<str_ndp> attribute has been set explicitly for an instance.
538              
539             If an undefined argument is supplied, the class will revert to its
540             initial state.
541              
542             Astro::Coords::Angle->NDP( undef );
543              
544             =cut
545              
546             {
547             my $DEFAULT_NDP = 2;
548             my $NDP = $DEFAULT_NDP;
549             sub NDP {
550 41     41 1 71 my $class = shift;
551 41 100       103 if (@_) {
552 1         3 my $arg = shift;
553 1 50       4 if (defined $arg) {
554 1         2 $NDP = $arg;
555             } else {
556 0         0 $NDP = $DEFAULT_NDP;
557             }
558             }
559 41         96 return $NDP;
560             }
561             }
562              
563             =item B<DELIM>
564              
565             Delimiter to use to separate components of a sexagesimal triplet when
566             the object is stringified. If this is changed then all instances will
567             be affected on stringification unless the C<str_delim> attribute has
568             been set explicitly for an instance.
569              
570             Common values are a colon (12:52:45.4) or a space (12 52 45.4). If
571             more than one character is present in the string, each character will
572             be used in turn as a delimiter in the string until either no more gaps
573             are present (or characters have been exhausted. In the former, if
574             there are more characters than gaps, the first character remaining in
575             the string will be appended, in the latter case, no more characters
576             will be printed. For example, "dms" would result in '12d52m45.4s',
577             whereas 'dm' would result in '12d52m45.4'
578              
579             Astro::Coords::Angle->DELIM( ':' );
580              
581             Default is ":". An undefined argument will result in the class reverting
582             to the default state.
583              
584             =cut
585              
586             {
587             my $DEFAULT_DELIM = ":";
588             my $DELIM = $DEFAULT_DELIM;
589             sub DELIM {
590 43     43 1 16198 my $class = shift;
591 43 100       135 if (@_) {
592 2         40 my $arg = shift;
593 2 50       6 if (defined $arg) {
594 2         96 $DELIM = $arg;
595             } else {
596 0         0 $DELIM = $DEFAULT_DELIM;
597             }
598             }
599 43         111 return $DELIM;
600             }
601             }
602              
603             =item B<to_radians>
604              
605             Low level utility routine to convert an input value in specified format
606             to radians. This method uses the same code as the object constructor to parse
607             the supplied input argument but does not require the overhead of object
608             construction if the result is only to be used transiently.
609              
610             $rad = Astro::Coords::Angle->to_radians( $string, $format );
611              
612             See the constructor documentation for the supported format strings.
613              
614             =cut
615              
616             sub to_radians {
617 2064     2064 1 4013 my $class = shift;
618             # simply delegate to the internal routine. Could use it directly but it feels
619             # better to leave options open for the moment
620 2064         7312 $class->_cvt_torad( @_ );
621             }
622              
623             =back
624              
625             =begin __PRIVATE_METHODS__
626              
627             =head2 Private Methods
628              
629             These methods are not part of the API and should not be called directly.
630             They are documented for completeness.
631              
632             =over 4
633              
634             =item B<_cvt_torad>
635              
636             Internal class method to convert an input string to the equivalent value in
637             radians. The following units are supported:
638              
639             sexagesimal - A string of format "dd:mm:ss.ss", "dd mm ss.ss"
640             or even "-ddxmmyss.ss" (ie -5x53y28.5z)
641             degrees - decimal degrees
642             radians - radians
643             arcsec - arc seconds (abbreviated form is 'as')
644             arcmin - arc minutes (abbreviated form is 'am')
645              
646             If units are not supplied, default is to call the C<_guess_units>
647             method.
648              
649             $radians = $angle->_cvt_torad( $angle, $units );
650              
651             Warnings are issued if the string can not be parsed or the values are
652             out of range.
653              
654             If the supplied angle is an Angle object itself, units are ignored and
655             the value is extracted directly from the object.
656              
657             Returns C<undef> on error. Does not modify the internal state of the object.
658              
659             =cut
660              
661             sub _cvt_torad {
662 72411     72411   113904 my $self = shift;
663 72411         116765 my $input = shift;
664 72411         116508 my $units = shift;
665              
666 72411 50       156257 return undef unless defined $input;
667              
668             # do we have an object?
669             # and can it implement the radians() method?
670 72411 100       797726 if (UNIVERSAL::can( $input, 'radians')) {
671 214         471 return $input->radians;
672             }
673              
674             # Clean up the string
675 72197         328714 $input =~ s/^\s+//g;
676 72197         235969 $input =~ s/\s+$//g;
677              
678             # guess the units
679 72197 100       156882 unless (defined $units) {
680 28         108 $units = $self->_guess_units( $input );
681 28 50       88 croak "No units supplied, and unable to guess any units either"
682             unless defined $units;
683             }
684              
685             # Now process the input - starting with strings
686 72197         126661 my $output = 0;
687 72197 100 66     495060 if ($units =~ /^s/) {
    100 66        
    100          
    100          
688              
689             # Since we can support aritrary delimiters on write,
690             # we should be flexible on read. Slalib is very flexible
691             # once the numbers are space separated, so remove all
692             # non-numeric characters except + and - and replace with space
693             # For now, remove all alphabetic characters and colon only
694              
695             # Need to clean up the string for PAL
696 2047         12774 $input =~ s/[:[:alpha:]]/ /g;
697              
698 2047         4744 my $nstrt = 1;
699 2047         14129 ($nstrt, $output, my $j) = Astro::PAL::palDafin( $input, $nstrt );
700 2047 50       7460 $output = undef unless $j == 0;
701              
702 2047 50       10009 if ($j == -1) {
    50          
    50          
    50          
703 0         0 warnings::warnif "In coordinate '$input' the degrees do not look right";
704             } elsif ($j == -2) {
705 0         0 warnings::warnif "In coordinate '$input' the minutes field is out of range";
706             } elsif ($j == -3) {
707 0         0 warnings::warnif "In coordinate '$input' the seconds field is out of range (0-59.9)";
708             } elsif ($j == 1) {
709 0         0 warnings::warnif "Unable to find plausible coordinate in string '$input'";
710             }
711              
712             } elsif ($units =~ /^d/) {
713             # Degrees decimal
714 32         100 $output = $input * Astro::PAL::DD2R;
715              
716             } elsif ($units =~ /^arcs/ || $units eq 'as') {
717             # Arcsec
718 25         63 $output = $input * Astro::PAL::DAS2R;
719              
720             } elsif ($units =~ /^arcm/ || $units eq 'am') {
721             # Arcmin
722 2         6 $output = $input * Astro::PAL::DAS2R * 60 ;
723              
724             } else {
725             # Already in radians
726 70091         116941 $output = $input;
727             }
728              
729 72197         206248 return $output;
730             }
731              
732             =item B<_guess_units>
733              
734             Given a string or number, tries to guess the units. Default is to
735             assume "sexagesimal" if the supplied string does not look like a
736             number to perl, "degrees" if the supplied number is greater than 2*PI
737             (6.28), and "radians" for all other values.
738              
739             $units = $class->_guess_units( $input );
740              
741             Returns undef if the input does not look at all plausible or is undef
742             itself.
743              
744             Arcsec or arcmin can not be determined with this routine.
745              
746             =cut
747              
748             sub _guess_units {
749 47     47   107 my $self = shift;
750 47         86 my $input = shift;
751 47 50       124 return undef if !defined $input;
752              
753             # Now if we have a space, colon or alphabetic character
754             # then we have a real string and assume sexagesimal.
755             # Use pre-defined character classes
756 47         78 my $units;
757             # if it does not look like a number choose sexagesimal
758 47 100       255 if (!looks_like_number($input)) {
    100          
759 34         100 $units = "sexagesimal";
760             } elsif ($input > Astro::PAL::D2PI) {
761 4         9 $units = "degrees";
762             } else {
763 9         162 $units = "radians";
764             }
765              
766 47         174 return $units;
767             }
768              
769             =item B<_r2f>
770              
771             Routine to convert angle in radians to a formatted array
772             of numbers in order of sign, deg, min, sec, frac.
773              
774             @retval = $ang->_r2f( $ndp );
775              
776             Note that the number of decimal places is an argument.
777              
778             =cut
779              
780             sub _r2f {
781 48     48   85 my $self = shift;
782 48         108 my $res = shift;
783              
784 48 50       132 warnings::warnif("More than 9 dp requested ($res), result from palDr2af likely to overflow in fractional part") if $res > 9;
785              
786 48         125 my ($sign, @dmsf) = Astro::PAL::palDr2af($res, $self->radians);
787 48         178 return ($sign, @dmsf);
788             }
789              
790             =back
791              
792             =end __PRIVATE_METHODS__
793              
794             =head1 AUTHOR
795              
796             Tim Jenness E<lt>t.jenness@cpan.orgE<gt>
797              
798             =head1 COPYRIGHT
799              
800             Copyright (C) 2004-2005 Tim Jenness. All Rights Reserved.
801              
802             This program is free software; you can redistribute it and/or modify it under
803             the terms of the GNU General Public License as published by the Free Software
804             Foundation; either version 3 of the License, or (at your option) any later
805             version.
806              
807             This program is distributed in the hope that it will be useful,but WITHOUT ANY
808             WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
809             PARTICULAR PURPOSE. See the GNU General Public License for more details.
810              
811             You should have received a copy of the GNU General Public License along with
812             this program; if not, write to the Free Software Foundation, Inc., 59 Temple
813             Place,Suite 330, Boston, MA 02111-1307, USA
814              
815             =cut
816              
817             1;
818