File Coverage

blib/lib/CXC/Types/Astro/Coords/Util.pm
Criterion Covered Total %
statement 102 105 97.1
branch 19 26 73.0
condition 4 11 36.3
subroutine 11 11 100.0
pod 2 2 100.0
total 138 155 89.0


line stmt bran cond sub pod time code
1             package CXC::Types::Astro::Coords::Util;
2              
3             # ABSTRACT: Coordinate Type utilities
4              
5 4     4   349708 use v5.28;
  4         15  
6 4     4   21 use warnings;
  4         9  
  4         227  
7              
8 4     4   445 use experimental 'signatures', 'postderef', 'declared_refs';
  4         1188  
  4         28  
9              
10             our $VERSION = '0.12';
11              
12 4     4   3159 use POSIX ();
  4         30111  
  4         131  
13 4     4   2259 use Regexp::Common;
  4         13090  
  4         16  
14 4     4   715210 use List::Util 'zip', 'sum0';
  4         9  
  4         543  
15 4     4   2168 use Exporter::Shiny qw( mkSexagesimal from_Degrees);
  4         19925  
  4         40  
16 4         59 use String::Interpolate::RE strinterp =>
17 4     4   2668 { opts => { useENV => !!0, format => !!0, recurse => !!0 } };
  4         6210  
18              
19             my sub croak {
20 1     1   9 require Carp;
21 1         155 goto \&Carp::croak;
22             }
23              
24              
25              
26              
27              
28              
29              
30              
31              
32              
33              
34              
35              
36              
37              
38              
39              
40              
41              
42              
43              
44              
45              
46              
47              
48              
49              
50              
51              
52              
53              
54              
55              
56              
57              
58              
59              
60              
61              
62              
63              
64              
65              
66              
67              
68              
69              
70              
71              
72              
73              
74              
75              
76              
77              
78              
79              
80              
81              
82              
83              
84              
85              
86              
87              
88              
89              
90              
91              
92              
93              
94              
95              
96              
97              
98              
99              
100              
101              
102              
103              
104              
105              
106              
107              
108              
109              
110              
111              
112              
113              
114              
115              
116              
117              
118              
119              
120              
121              
122              
123              
124              
125              
126              
127              
128              
129              
130              
131              
132              
133              
134              
135              
136              
137              
138              
139              
140              
141              
142              
143              
144              
145              
146              
147              
148              
149              
150              
151              
152              
153              
154              
155              
156              
157              
158              
159              
160              
161              
162              
163              
164              
165              
166              
167              
168              
169              
170              
171              
172              
173              
174 16     16 1 344173 sub mkSexagesimal ( @wanted ) {
  16         54  
  16         34  
175              
176 16         35 state %comp = do {
177 3         24 my %base = (
178             -ra => q{(?:[0-2]\d)|\d},
179             -dec => q{[+-]?\d\d?},
180             -deg => q{[+]?[0-3]?\d\d?},
181             -negdeg => q{[+-]?[0-3]?\d\d?},
182             );
183 3         12 $base{-lat} = $base{-dec};
184 3         36 $base{-long} = $base{-deg};
185 3         12 $base{-neglong} = $base{-negdeg};
186 3         9 $base{-any} = $base{-negdeg};
187 3         26 %base;
188             };
189              
190 16         59 state %bounds_check = do {
191 3         13 my %base = (
192             -ra => q{( (0 <= $1 && $1 < 24) && (0 <= $2 && $2 < 60) && (0 <= $3 && $3 < 60) )},
193             -dec =>
194             q{( (-90 <= $1 && $1 <= 90) && (0 <= $2 && $2 < 60) && (0 <= $3 && $3 < 60) && (abs( $1 ) + ( $2 + $3 / 60 ) / 60 <= 90) )},
195             -deg => q{( (0 <= $1 && $1 < 360) && (0 <= $2 && $2 < 60) && (0 <= $3 && $3 < 60) )},
196             );
197 3         9 $base{-lat} = $base{-dec};
198 3         11 $base{-long} = $base{-deg};
199 3         7 $base{-negdeg} = q{1};
200 3         9 $base{-neglong} = $base{-negdeg};
201             $base{-any}
202 3         9 = q{ ( ($2//'d') eq 'h' ? (0 <= $1 && $1 < 24 && 0 <= $3 && $3 < 60 && 0 <= $4 && $4 < 60) : 1) };
203 3         24 %base;
204             };
205              
206 16         31 state %ArrayRef_toDegrees = do {
207 3         21 my %base = (
208             -ra => q{ ( 15 * $_->[0] + $_->[1] / 4 + $_->[2] / 240 ) },
209             -dec => q{ POSIX::copysign( abs($_->[0]) + $_->[1]/60 + $_->[2]/3600, $_->[0] ) },
210             -deg => q{ ( $_->[0] + $_->[1]/60 + $_->[2] / 3600 ) },
211             -negdeg => q{ POSIX::copysign( abs($_->[0]) + $_->[1]/60 + $_->[2] / 3600, $_->[0] ) },
212             );
213 3         6 $base{-lat} = $base{-dec};
214 3         38 $base{-long} = $base{-deg};
215 3         9 $base{-neglong} = $base{-negdeg};
216 3         6 $base{-any} = $base{-negdeg};
217              
218 3         19 %base;
219             };
220              
221 16         31 state %StrMatch_toArrayRef = do {
222 3         8 my %base = (
223             -any => <<~'EOS',
224             ($2//'d') eq 'h'
225             ? do {
226             my @array = ( $1, $3, $4 );
227             my $degrees = ( 15 * $array[0] + $array[1] / 4 + $array[2] / 240 );
228             my @comp = ( int($degrees) );
229             $degrees -= $comp[0];
230             $degrees *= 60;
231             $comp[1] = int($degrees);
232             $comp[2] = 60 * ($degrees - $comp[1]);
233             \@comp;
234             }
235             : [ 0+$1, 0+$3, 0+$4 ]
236             EOS
237             );
238 3         24 $base{$_} = q<[ 0+$1, 0+$2, 0+$3 ]> for qw( -ra -dec -deg -negdeg -lat -long -neglong );
239 3         31 %base;
240             };
241              
242             #<<< no tidy
243             state %unit
244 16 100       73 = ( map { $_ =>
  24 100       81  
245             $_ eq '-ra' ? '[h]'
246             : ($_ eq '-any' ? '([hd])' # capture unit, as need
247             # this info to convert to
248             # degrees
249             : '[d]'
250             ) } keys %comp );
251             #>>> ydit on
252              
253             # flag states. sum them
254 16         61 state %mask = (
255             -units => 0x200,
256             -optunits => 0x100,
257             -sep => 0x020,
258             -optsep => 0x010,
259             -ws => 0x002,
260             -optws => 0x001,
261             );
262              
263             state %between_template = (
264             map { ## no critic (BuiltinFunctions::ProhibitComplexMappings)
265 16         113 my @templates = $_->[1]->@*;
  39         90  
266              
267             # the first element in the input array is for the first &
268             # second components. need to repeat it. if there's only
269             # one element in the array, the element is the same for
270             # all three components.
271             ## no critic (ValuesAndExpressions::ProhibitCommaSeparatedStatements)
272 39         152 unshift( @templates, $templates[0] ) while @templates < 3;
273              
274 39         169 ( sum0 @mask{ $_->[0]->@* } ), \@templates;
275             } (
276             [ [ -units ] => ['${units}'] ],
277             [ [ -units, -ws ] => [ '${units}${ws}', '${units}' ] ],
278             [ [ -units, -optws ] => [ '${units}${ows}', '${units}' ] ],
279             [ [ -sep ] => [ '${sep}', q{} ] ],
280             [ [ -sep, -ws ] => [ '${sep}${ws}', q{} ] ],
281             [ [ -optws, -sep ] => [ '${sep}${ows}', q{} ] ],
282             [ [ -ws, ] => [ '${ws}', q{} ] ],
283             [ [ -optsep, -ws ] => [ '${sep}?${ws}', q{} ] ],
284             [ [ -optsep, -optws ] => [ '(?:${sep}|${ws})${ows}', q{} ] ],
285             [ [ -optunits, -ws ] => [ '${units}?${ws}', q{}, ] ],
286             [ [ -optunits, -optws ] => [ '(?:${units}|${ws})${ows}', q{} ] ],
287             [ [ -optsep, -optunits, -ws ] => [ '(?:${units}|${sep})${ws}', '${units}?' ] ],
288             [ [ -optsep, -optunits, -optws ] => [ '(?:${units}|${sep}|${ws})${ows}', '${units}?' ] ],
289             ),
290             );
291              
292 16         52 state %utils;
293              
294 16   33     136 my $utils = $utils{ join $;, sort @wanted } //= do {
295              
296 16         31 my %wanted;
297 16         76 @wanted{@wanted} = @wanted;
298              
299 16 50       153 ( my @parse_flags = grep defined, delete @wanted{ keys %mask } )
300             or croak( 'no parse flags specified' );
301              
302 16 50       195 defined( my $between_template = $between_template{ sum0 @mask{@parse_flags} } )
303             or croak( 'illegal combination of flags: ', join( ', ', @parse_flags ) );
304              
305 16         46 my $want_trim = !!delete $wanted{-trim};
306              
307 16         104 my ( $coord, @extra ) = grep defined delete $wanted{$_}, keys %comp;
308 16 50       46 croak( 'too many coordinate systems specified: ' . join q{, }, $coord, @extra )
309             if @extra;
310              
311 16 50       48 croak( 'unrecognized options: ', join q{, }, keys %wanted ) if keys %wanted;
312              
313 16   100     52 $coord //= '-any';
314              
315 16         174 my @comp = ( $comp{$coord}, '[0-5]?[0-9]', $RE{num}{decimal} );
316 16         895 my @units = ( $unit{$coord}, '[m]', '[s]' );
317              
318             ## no critic(BuiltinFunctions::ProhibitComplexMappings)
319             my $qr = q{^} . join(
320             q{},
321             ( $want_trim ? '\h*' : () ),
322             (
323             map {
324 16 100       147 my ( $template, $comp, $units ) = $_->@*;
  48 100       3606  
325 48         301 join q{}, q{(}, $comp, q{)},
326             strinterp(
327             $template,
328             {
329             units => $units,
330             sep => q{:},
331             ws => '\h+',
332             ows => '\h*',
333             } );
334             } zip( $between_template, \@comp, \@units ),
335             ),
336             ( $want_trim ? '\h*' : () ),
337             ) . q{$};
338              
339             my %_utils = (
340             qr => $qr,
341             constraint => sprintf( q{ ($_ =~ /%s/) && (%s) }, $qr, $bounds_check{$coord} ),
342             StrMatch_toArrayRef => $StrMatch_toArrayRef{$coord},
343 16         3465 ArrayRef_toDegrees => $ArrayRef_toDegrees{$coord},
344             );
345             $_utils{Str_toArrayRef}
346 16         61 = sprintf( q{ ( (%s) ? (%s) : $_ ) }, $_utils{constraint}, $StrMatch_toArrayRef{$coord} );
347              
348             $_utils{Str_toDegrees} = sprintf(
349             q{ ( (%s) ? do { local $_ = %s; %s; } : $_ ) },
350             $_utils{constraint},
351             $_utils{StrMatch_toArrayRef},
352             $_utils{ArrayRef_toDegrees},
353 16         50 );
354              
355 16         115 \%_utils;
356             };
357 16         111 return $utils;
358             }
359              
360             # convert degrees to components
361              
362              
363              
364              
365              
366              
367              
368              
369              
370              
371 7     7 1 10127 sub from_Degrees ( $angle, $coord ) {
  7         12  
  7         23  
  7         9  
372              
373 7         34 my $degrees = $angle;
374 7         23 my $copysign = !!POSIX::signbit( $degrees );
375              
376 7 100 33     34 if ( $coord eq '-ra' ) {
    50 0        
    0          
377 2         9 $degrees = POSIX::fmod( 360 + POSIX::fmod( abs( $degrees ), 360 ), 360 );
378 2         3 $degrees /= 15;
379 2         3 $copysign = !!0;
380             }
381             elsif ( $coord eq '-lat' or $coord eq '-dec' ) {
382 5 100       17 croak( 'illegal argument: must be between [-90,+90]' )
383             if abs( $degrees ) > 90;
384 4         6 $degrees = abs( $degrees );
385             }
386             elsif ( $coord eq '-neglong' or $coord eq '-negdeg' ) {
387 0         0 $degrees = POSIX::fmod( 360 + POSIX::fmod( abs( $degrees ), 360 ), 360 );
388             }
389             else {
390 0         0 $copysign = !!0;
391 0         0 $degrees = POSIX::fmod( 360 + POSIX::fmod( abs( $degrees ), 360 ), 360 );
392             }
393              
394 6         9 my @comp;
395              
396 6         10 $comp[0] = int( $degrees );
397 6         10 $degrees -= $comp[0];
398 6         9 $degrees *= 60;
399 6         31 $comp[1] = int( $degrees );
400 6         13 $comp[2] = 60 * ( $degrees - $comp[1] );
401              
402 6 100       19 $comp[0] = POSIX::copysign( $comp[0], $angle ) if $copysign;
403              
404 6         55 return \@comp;
405             }
406              
407             1;
408              
409             #
410             # This file is part of CXC-Types-Astro-Coords
411             #
412             # This software is Copyright (c) 2018 by Smithsonian Astrophysical Observatory.
413             #
414             # This is free software, licensed under:
415             #
416             # The GNU General Public License, Version 3, June 2007
417             #
418              
419             __END__