File Coverage

blib/lib/Ham/Locator.pm
Criterion Covered Total %
statement 71 78 91.0
branch 8 18 44.4
condition n/a
subroutine 10 10 100.0
pod 2 4 50.0
total 91 110 82.7


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             #=======================================================================
4             # Locator.pm / Ham::Locator
5             # $Id: Locator.pm 10 2011-01-16 15:36:53Z andys $
6             # $HeadURL: http://daedalus.dmz.dn7.org.uk/svn/Ham-Locator/lib/Ham/Locator.pm $
7             # (c)2010 Andy Smith
8             #-----------------------------------------------------------------------
9             #:Description
10             # Module to easily convert between Maidenhead locators and coordinates
11             # in latitude and longitude format.
12             #-----------------------------------------------------------------------
13             #:Synopsis
14             #
15             # use Ham::Locator;
16             # my $m = new Ham::Locator;
17             # $m->set_loc('IO93lo');
18             # my ($latitude, $longitude) = $m->loc2latlng;
19             #=======================================================================
20             #
21             # With thanks to:-
22             # * http://home.arcor.de/waldemar.kebsch/The_Makrothen_Contest/fmaidenhead.js
23             # * http://no.nonsense.ee/qthmap/index.js
24              
25             # The pod (Perl documentation) for this module is provided inline. For a
26             # better-formatted version, please run:-
27             # $ perldoc Locator.pm
28              
29             =head1 NAME
30              
31             Ham::Locator - Convert between Maidenhead locators and latitude/longitude.
32              
33             =head1 SYNOPSIS
34              
35             use Ham::Locator;
36             my $m = new Ham::Locator;
37             $m->set_loc('IO93lo');
38             my ($latitude, $longitude) = $m->loc2latlng;
39              
40             =head1 DEPENDENCIES
41              
42             =over4
43              
44             =item * Carp - for error handling
45              
46             =item * Class::Accessor - for accessor method generation
47              
48             =back
49              
50             =cut
51              
52             # Module setup
53             package Ham::Locator;
54              
55 1     1   40201 use strict;
  1         3  
  1         48  
56 1     1   6 use warnings;
  1         2  
  1         54  
57              
58             our $VERSION = '0.1000';
59              
60             # Module inclusion
61 1     1   5 use Carp;
  1         6  
  1         101  
62 1     1   3062 use Data::Dumper;
  1         18398  
  1         95  
63 1     1   2928 use POSIX qw(floor fmod);
  1         13589  
  1         29  
64              
65             # Set up accessor methods with Class::Accessor
66 1     1   1958 use base qw(Class::Accessor);
  1         2  
  1         1808  
67             __PACKAGE__->follow_best_practice;
68             __PACKAGE__->mk_accessors( qw(loc latlng precision) );
69              
70             =head1 CONSTRUCTORS
71              
72             =head2 Locator->new
73              
74             Creates a new C object.
75              
76             =head1 ACCESSORS
77              
78             =head2 $locator->set_loc(I)
79              
80             Sets the locator to use for conversion to latitude and longitude.
81              
82             =head2 $locator->set_latlng((I, I))
83              
84             Sets the longitude and latitude to use for conversion to the locator.
85              
86             =head2 $locator->set_precision(I)
87              
88             Sets the number of characters of the locator reference to return when calling B.
89              
90             =cut
91              
92             sub l2n
93             {
94 6     6 0 10 my ($self, $letter) = @_;
95              
96 6         12 my $lw = lc $letter;
97              
98 6         75 my $index = { 'a' => 0,
99             'b' => 1,
100             'c' => 2,
101             'd' => 3,
102             'e' => 4,
103             'f' => 5,
104             'g' => 6,
105             'h' => 7,
106             'i' => 8,
107             'j' => 9,
108             'k' => 10,
109             'l' => 11,
110             'm' => 12,
111             'n' => 13,
112             'o' => 14,
113             'p' => 15,
114             'q' => 16,
115             'r' => 17,
116             's' => 18,
117             't' => 19,
118             'u' => 20,
119             'v' => 21,
120             'w' => 22,
121             'x' => 23
122             };
123              
124 6         37 return $index->{$lw};
125             };
126              
127             sub n2l
128             {
129 30     30 0 125 my ($self, $number) = @_;
130              
131 30         417 my $index = { 0 => 'a',
132             1 => 'b',
133             2 => 'c',
134             3 => 'd',
135             4 => 'e',
136             5 => 'f',
137             6 => 'g',
138             7 => 'h',
139             8 => 'i',
140             9 => 'j',
141             10 => 'k',
142             11 => 'l',
143             12 => 'm',
144             13 => 'n',
145             14 => 'o',
146             15 => 'p',
147             16 => 'q',
148             17 => 'r',
149             18 => 's',
150             19 => 't',
151             20 => 'u',
152             21 => 'v',
153             22 => 'w',
154             23 => 'x'
155             };
156              
157 30         268 return $index->{$number};
158             };
159              
160             =head1 METHODS
161              
162             =head2 $locator->latlng2loc
163              
164             converts the latitude and longitude set by B to the locator, and returns it as a string.
165              
166             =cut
167              
168             sub latlng2loc
169             {
170 5     5 1 11333 my ($self) = @_;
171              
172 5 50       20 if($self->get_latlng eq "")
173             {
174 0         0 return 0;
175             }
176              
177 5         73 my $latlng = $self->get_latlng;
178              
179 5         41 my $field_lat = @{$latlng}[0];
  5         10  
180 5         7 my $field_lng = @{$latlng}[1];
  5         8  
181              
182 5         9 my $locator;
183              
184 5         11 my $lat = $field_lat + 90;
185 5         8 my $lng = $field_lng + 180;
186              
187             # Field
188 5         13 $lat = ($lat / 10) + 0.0000001;
189 5         9 $lng = ($lng / 20) + 0.0000001;
190 5         41 $locator .= uc($self->n2l(floor($lng))).uc($self->n2l(floor($lat)));
191              
192             # Square
193 5         18 $lat = 10 * ($lat - floor($lat));
194 5         13 $lng = 10 * ($lng - floor($lng));
195 5         26 $locator .= floor($lng).floor($lat);
196            
197             # Subsquare
198 5         12 $lat = 24 * ($lat - floor($lat));
199 5         11 $lng = 24 * ($lng - floor($lng));
200 5         24 $locator .= $self->n2l(floor($lng)).$self->n2l(floor($lat));
201              
202             # Extended square
203 5         16 $lat = 10 * ($lat - floor($lat));
204 5         11 $lng = 10 * ($lng - floor($lng));
205 5         20 $locator .= floor($lng).floor($lat);
206            
207             # Extended Subsquare
208 5         12 $lat = 24 * ($lat - floor($lat));
209 5         35 $lng = 24 * ($lng - floor($lng));
210 5         19 $locator .= $self->n2l(floor($lng)).$self->n2l(floor($lat));
211              
212 5 100       18 if($self->get_precision)
213             {
214 4         43 return substr $locator, 0, $self->get_precision;
215             }
216             else
217             {
218 1         11 return $locator;
219             }
220             }
221            
222              
223             =head2 $locator->loc2latlng
224              
225             Converts the locator set by B to latitude and longitude, and returns them as an array of two values.
226              
227             =cut
228              
229             sub loc2latlng
230             {
231 1     1 1 2650 my ($self) = @_;
232              
233 1 50       7 if($self->get_loc eq "")
234             {
235 0         0 return 0;
236             }
237              
238 1         28 my $loc = $self->get_loc;
239              
240 1 50       16 if(length $loc lt 4)
    0          
    0          
    0          
241             {
242 1         3 $loc .= "55LL55LL";
243             }
244             elsif(length $loc lt 6)
245             {
246 0         0 $loc .= "LL55LL";
247             }
248             elsif(length $loc lt 8)
249             {
250 0         0 $loc .= "55LL";
251             }
252             elsif(length $loc lt 10)
253             {
254 0         0 $loc .= "LL";
255             }
256              
257 1 50       9 if($loc !~ m/[a-rA-R]{2}[0-9]{2}[a-xA-X]{2}[0-9]{2}[a-xA-X]{2}/)
258             {
259 0         0 print "Not a valid locator.\n";
260 0         0 return 0;
261             }
262              
263 1         4 $loc = lc($loc);
264              
265 1         3 my $i = 0;
266 1         3 my @l = ();
267              
268 1         3 while ($i < 10)
269             {
270 10         19 my $a = substr $loc, $i, 1;
271 10 100       35 if($a =~ m/[a-zA-Z]/)
272             {
273 6         17 $l[$i] = $self->l2n($a);
274             }
275             else
276             {
277 4         12 $l[$i] = int(substr $loc, $i, 1);
278             }
279 10         25 $i++;
280             }
281              
282 1         8 my $lng = (($l[0] * 20) + ($l[2] * 2) + ($l[4]/12) + ($l[6]/120) + ($l[8]/2880) - 180);
283 1         6 my $lat = (($l[1] * 10) + $l[3] + ($l[5]/24) + ($l[7]/240) + ($l[9]/5760) - 90);
284              
285 1         7 return ($lat, $lng);
286              
287             };
288              
289             =head1 CAVEATS
290              
291             =head1 BUGS
292              
293             =item1 * None, hopefully!
294              
295             This module was written by B .
296              
297             =head1 COPYRIGHT
298              
299             $Id: Locator.pm 10 2011-01-16 15:36:53Z andys $
300              
301             (c)2009 Andy Smith (L)
302              
303             This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
304              
305             =cut
306              
307             1;