File Coverage

blib/lib/Geo/Location/Point.pm
Criterion Covered Total %
statement 87 94 92.5
branch 38 50 76.0
condition 34 48 70.8
subroutine 16 16 100.0
pod 7 7 100.0
total 182 215 84.6


line stmt bran cond sub pod time code
1             package Geo::Location::Point;
2              
3 4     4   649601 use 5.10.0; # For the //= operator
  4         48  
4 4     4   24 use strict;
  4         9  
  4         79  
5 4     4   19 use warnings;
  4         8  
  4         136  
6              
7 4     4   24 use Carp;
  4         8  
  4         251  
8 4     4   2027 use GIS::Distance;
  4         11145  
  4         277  
9              
10             use overload (
11             '==' => \&equal,
12             '!=' => \¬_equal,
13             '""' => \&as_string,
14 6     6   16 bool => sub { 1 },
15 4         58 fallback => 1 # So that boolean tests don't cause as_string to be called
16 4     4   36 );
  4         9  
17              
18             =head1 NAME
19              
20             Geo::Location::Point - Location information
21              
22             =head1 VERSION
23              
24             Version 0.07
25              
26             =cut
27              
28             our $VERSION = '0.07';
29              
30             =head1 SYNOPSIS
31              
32             Geo::Location::Point stores a place.
33              
34             use Geo::Location::Point;
35              
36             my $location = Geo::Location::Point->new();
37              
38             =head1 SUBROUTINES/METHODS
39              
40             =head2 new
41              
42             $location = Geo::Location::Point->new();
43              
44             =cut
45              
46             sub new {
47 11     11 1 3313 my $proto = shift;
48 11   33     67 my $class = ref($proto) || $proto;
49              
50             # Geo::Location::Point->new not Geo::Location::Point::new
51 11 50       29 return unless($class);
52              
53 11 50       65 my %args = (ref($_[0]) eq 'HASH') ? %{$_[0]} : @_;
  0         0  
54              
55 11   66     66 $args{'lat'} //= $args{'latitude'} // $args{'Latitude'};
      100        
56 11 100       33 if(!defined($args{'lat'})) {
57 1         4 Carp::carp(__PACKAGE__, ': latitude not given');
58 1         654 return;
59             }
60 10   66     67 $args{'long'} //= $args{'longitude'} // $args{'Longitude'};
      100        
61 10 100       37 if(!defined($args{'long'})) {
62 1         5 Carp::carp(__PACKAGE__, ': longitude not given');
63 1         340 return;
64             }
65              
66 9         35 return bless \%args, $class;
67             }
68              
69             =head2 lat
70              
71             print 'Latitude: ', $location->lat(), "\n";
72             print 'Longitude: ', $location->long(), "\n";
73              
74             =cut
75              
76             sub lat {
77 15     15 1 34 my $self = shift;
78              
79 15         73 return $self->{'lat'};
80             }
81              
82             =head2 long
83              
84             print 'Latitude: ', $location->lat(), "\n";
85             print 'Longitude: ', $location->long(), "\n";
86              
87             =cut
88              
89             sub long {
90 9     9 1 16 my $self = shift;
91              
92 9         40 return $self->{'long'};
93             }
94              
95             =head2 distance
96              
97             Determine the distance between two locations,
98             returns a L object.
99              
100             =cut
101              
102             sub distance {
103 3     3 1 1489 my ($self, $location) = @_;
104              
105 3 50       31 die unless $location;
106              
107 3   66     23 $self->{'gis'} //= GIS::Distance->new();
108              
109 3         41846 return $self->{'gis'}->distance($self->{'lat'}, $self->{'long'}, $location->lat(), $location->long());
110             }
111              
112             =head2 equal
113              
114             Are two points the same?
115              
116             my $loc1 = Geo::Location::Point->new(lat => 2, long => 2);
117             my $loc2 = Geo::Location::Point->new(lat => 2, long => 2);
118             print ($loc1 == $loc2), "\n"; # Prints 1
119              
120             =cut
121              
122             sub equal {
123 6     6 1 404 my $self = shift;
124 6         11 my $other = shift;
125              
126             # return ($self->distance($other) <= 1e-9);
127 6   66     14 return((abs($self->lat() - $other->lat()) <= 1e-9) && (abs(($self->long() - $other->long())) <= 1e-9));
128             }
129              
130             =head2 not_equal
131              
132             Are two points different?
133              
134             my $loc1 = Geo::Location::Point->new(lat => 2, long => 2);
135             my $loc2 = Geo::Location::Point->new(lat => 2, long => 2);
136             print ($loc1 != $loc2), "\n"; # Prints 0
137              
138             =cut
139              
140             sub not_equal {
141 3     3 1 7 my $self = shift;
142              
143 3         8 return(!$self->equal(shift));
144             }
145              
146             =head2 as_string
147              
148             Prints the object in human-readable format.
149              
150             =cut
151              
152             sub as_string {
153 5     5 1 1057 my $self = shift;
154              
155 5 100       41 if($self->{'location'}) {
156 1         7 return $self->{'location'};
157             }
158              
159 4         5 my $rc = $self->{'name'};
160 4 50       9 if($rc) {
161 0         0 $rc = ucfirst(lc($rc));
162             }
163              
164             # foreach my $field('house_number', 'number', 'road', 'street', 'AccentCity', 'city', 'county', 'region', 'state_district', 'state', 'country') {
165 4         10 foreach my $field('house_number', 'number', 'road', 'street', 'city', 'county', 'region', 'state_district', 'state', 'country') {
166 40 100 100     136 if(my $value = ($self->{$field} || $self->{ucfirst($field)})) {
167 15 100       33 if($rc) {
    50          
168 11 100 66     30 if(($field eq 'street') || ($field eq 'road')) {
169 2 50 33     22 if($self->{'number'} || $self->{'house_number'}) {
170 2         5 $rc .= ' ';
171             } else {
172 0         0 $rc .= ', '
173             }
174             } else {
175 9         14 $rc .= ', ';
176             }
177             } elsif($rc) {
178 0         0 $rc .= ', ';
179             }
180 15         19 my $leave_case = 0;
181 15 50 66     43 if(my $country = $self->{'country'} // $self->{'Country'}) {
182 15 100 33     42 if(uc($country) eq 'US') {
    50          
    50          
183 12 100 100     48 if(($field eq 'state') || ($field eq 'region') || ($field eq 'country')) {
      100        
184 5         7 $leave_case = 1;
185 5 100       11 if(lc($field) eq 'country') {
186 3         5 $value = 'US';
187             }
188             }
189             } elsif(($country eq 'Canada') || ($country eq 'Australia')) {
190 0 0       0 if($field eq 'state') {
191 0         0 $leave_case = 1;
192             }
193             } elsif(uc($country) eq 'GB') {
194 3 100       9 if($field eq 'country') {
195 1         2 $leave_case = 1;
196 1         2 $value = 'GB';
197             }
198             }
199             }
200 15 100       24 if($leave_case) {
201 6         11 $rc .= $value;
202             } else {
203 9         20 $rc .= $self->_sortoutcase($value);
204 9 50 66     75 if((($field eq 'street') || ($field eq 'road')) &&
      66        
205             ($rc =~ /(.+)\s([NS][ew])$/)) {
206             # e.g South Street NW
207 0         0 $rc = "$1 " . uc($2);
208             }
209             }
210             }
211             }
212              
213 4         32 return $self->{'location'} = $rc;
214             }
215              
216             sub _sortoutcase {
217             # my $self = shift;
218             # my $field = lc(shift);
219 9     9   12 my $field = $_[1];
220 9         12 my $rc;
221              
222 9         25 foreach (split(/ /, $field)) {
223 14 100       27 if($rc) {
224 5         5 $rc .= ' ';
225             }
226 14         36 $rc .= ucfirst($_);
227             }
228              
229 9         22 return $rc;
230             }
231              
232             =head2 attr
233              
234             Get/set location attributes, e.g. city
235              
236             $location->city('London');
237             $location->country('UK');
238             print $location->as_string(), "\n";
239             print "$location\n"; # Calls as_string
240              
241             =cut
242              
243             sub AUTOLOAD {
244 12     12   2447 our $AUTOLOAD;
245 12         25 my $key = $AUTOLOAD;
246              
247 12         66 $key =~ s/.*:://;
248              
249 12 100       628 return if($key eq 'DESTROY');
250              
251 3         7 my $self = shift;
252              
253 3 100       10 if(my $value = shift) {
254 1         8 $self->{$key} = $value;
255 1         2 delete $self->{'location'}; # Invalidate the cache
256             }
257              
258 3         13 return $self->{$key};
259             }
260              
261             =head1 AUTHOR
262              
263             Nigel Horne
264              
265             This library is free software; you can redistribute it and/or modify
266             it under the same terms as Perl itself.
267              
268             =head1 BUGS
269              
270             =head1 SEE ALSO
271              
272             L,
273             L
274              
275             =head1 LICENSE AND COPYRIGHT
276              
277             Copyright 2019-2023 Nigel Horne.
278              
279             The program code is released under the following licence: GPL2 for personal use on a single computer.
280             All other users (including Commercial, Charity, Educational, Government)
281             must apply in writing for a licence for use from Nigel Horne at ``.
282              
283             =cut
284              
285             1;