File Coverage

blib/lib/GPS/Track/Point.pm
Criterion Covered Total %
statement 59 59 100.0
branch 22 22 100.0
condition 11 12 91.6
subroutine 10 10 100.0
pod 4 5 80.0
total 106 108 98.1


line stmt bran cond sub pod time code
1             package GPS::Track::Point;
2              
3 2     2   779261 use Moo;
  2         6952  
  2         9  
4 2     2   1685 use Scalar::Util qw/blessed/;
  2         4  
  2         96  
5 2     2   546 use Geo::Distance;
  2         13790  
  2         149  
6              
7             use overload
8 1     1   6 '!=' => sub { !shift->equals(shift) },
9 2     2   17 '==' => \=
  2         5  
  2         21  
10              
11             has ["lon", "lat", "ele", "spd", "bpm", "cad" ] => (
12             is => "rw",
13             default => undef
14             );
15              
16             has "time" => (
17             is => "rw",
18             default => undef,
19             isa => sub {
20             my $val = shift;
21             die "Not a DateTime object!" if(defined($val) && !$val->isa("DateTime"));
22             }
23             );
24              
25             has "geoDistance" => (
26             is => "ro",
27             default => sub { return Geo::Distance->new(); },
28             );
29              
30             sub distanceTo {
31 10     10 1 6848 my $self = shift;
32 10         24 my $other = shift;
33              
34 10         21 my $otherLon = undef;
35 10         20 my $otherLat = undef;
36              
37 10 100       50 if(blessed($other)) {
38 6 100       39 unless($other->isa("GPS::Track::Point")) {
39 1         14 die "\$other is not a GPS::Track::Point!";
40             }
41              
42 5         19 $otherLon = $other->lon;
43 5         15 $otherLat = $other->lat;
44             }
45             else {
46 4 100       19 unless(ref($other) eq "HASH") {
47 1         25 die "\$other is not a HASH reference!";
48             }
49              
50 3         9 $otherLon = $other->{lon};
51 3         9 $otherLat = $other->{lat};
52             }
53              
54 8 100       45 die "\$other is missing a 'lon' value!" unless(defined $otherLon);
55 6 100       40 die "\$other is missing a 'lat' value!" unless(defined $otherLat);
56              
57 4 100       52 die "\$self is missing a 'lon' value!" unless(defined $self->lon);
58 3 100       22 die "\$self is missing a 'lat' value!" unless(defined $self->lat);
59              
60 2         19 return $self->geoDistance->distance("meter", $self->lon, $self->lat, $otherLon, $otherLat);
61             }
62              
63             sub equals {
64 9     9 1 174 my $self = shift;
65 9         19 my $other = shift;
66              
67 9 100 66     87 unless(blessed($other) && $other->isa("GPS::Track::Point")) {
68 1         14 die "First argument not a GPS::Track::Point!";
69             }
70              
71 8         22 my $equal = 1;
72              
73 8         24 foreach my $attr ($self->attributes) {
74 32         225 my $me = $self->$attr();
75 32         212 my $other = $other->$attr();
76              
77 32   100     139 my $bothDefined = defined($me) && defined($other);
78 32         66 my $onlyOneDefined = defined($me) ^ defined($other);
79              
80 32 100 100     148 if($onlyOneDefined || ($bothDefined && $me != $other)) {
      100        
81 4         9 $equal = 0;
82 4         11 last;
83             }
84             }
85              
86 8         67 return $equal;
87             }
88             sub toString {
89 1     1 1 18 my $self = shift;
90 1         4 my @parts;
91 1         5 foreach my $attr ($self->attributes) {
92 7         50 my $value = $self->$attr();
93 7 100       44 push(@parts, "$attr=" . (defined($value) ? $value : "undef"));
94             }
95              
96 1         12 return join(" ", @parts);
97             }
98             sub toHash {
99 4     4 1 28 my $self = shift;
100 4         8 my $data = {};
101            
102 4         12 foreach my $attr ($self->attributes) {
103 28         156 my $value = $self->$attr();
104 28 100       81 if(defined($value)) {
105 14         20 $data->{$attr} = $value;
106             }
107             }
108              
109 4         24 return $data;
110             }
111              
112             sub attributes {
113 13     13 0 49 return qw/lon lat time ele spd cad bpm/;
114             }
115              
116             1;
117              
118             __END__
119              
120             =head1 NAME
121              
122             GPS::Track::Point - Represent a Point of a GPS::Track
123              
124             =head1 SYNOPSIS
125              
126             # Construct an empty point
127             my $point = GPS::Track::Point->new();
128            
129             # Construct a simple point
130             my $point = GPS::Track::Point->new(lon => 12, lat => 13, ele => 8848);
131             my $point = GPS::Track::Point->new( { lon => 12, lat => 13 } ); # Hashref Construction supported too
132            
133             my $pointsEqual = $pointA == $pointB; # Watch out for floating point troubles!
134             my $distance = $pointA->distanceTo($pointB);
135             my $distance = $pointaA->distanceTo( { lon => 12, lat => 13 } );
136              
137             =head1 DESCRIPTION
138              
139             C<GPS::Track::Point> is a thin module representing a Point as parsed by L<GPS::Track>.
140              
141             =head1 ATTRIBUTES
142              
143             =head2 lon
144              
145             my $lon = $point->lon;
146             $point = $point->lon(48);
147              
148             =head2 lat
149              
150             my $lat = $point->lat;
151             $point = $point->lat(9);
152              
153             =head2 time
154              
155             Accepts/Returns a L<DateTime>-Object or undef (if no time information is present)
156              
157             my $time = $point->time;
158             my $point = $point->time(DateTime->now());
159              
160             =head2 ele
161              
162             my $ele = $point->ele;
163             $point = $point->ele(8848);
164              
165             =head2 spd
166              
167             The speed at this point, measured in meter per second.
168              
169             my $spd = $point->spd;
170             my $point = $point->spd(10);
171              
172             =head2 cad
173              
174             my $cad = $point->cad;
175             $point = $point->cad(75);
176              
177             =head2 bpm
178              
179             my $bpm = $point->bpm;
180             $point = $point->bpm(180);
181              
182             =head1 METHODS
183              
184             =head2 distanceTo($otherPoint)
185              
186             Return the 2D distance to the other point in meters.
187              
188             Dies if one of the points is missing lon/lat.
189              
190             my $distance = $pointA->distanceTo($pointB);
191              
192             =head2 distanceTo( { lon => X, lat => Y } )
193              
194             Shorthand method to get the 2D distance to a known lon-lat-pair.
195              
196             my $distance = $pointA->distanceTo( { lon => 12, lat => 6 } );
197              
198             =head2 equals($otherPoint)
199              
200             Compares to point object attribute by attribute.
201              
202             Equal means, that ALL atributes of both points are equal in the sense of perl. You may experience troubles with floating point precision!
203              
204             Return 1 for equal points, otherwise 0.
205              
206             my $equal = $pointA->equals($pointB);
207              
208             =head2 toHash()
209              
210             Convert the point to a plain hash ref. Only C<defined> attributes are included as keys in the hash.
211              
212             my $point = GPS::Track::Point->new(lon => 1, lat => 2);
213             my $ref = $point->toHash();
214             # { lon => 1, lat => 2 }
215              
216             =head2 toString()
217              
218             Converts the point to a string representation.
219              
220             my $point = GPS::Trakc::Point->new(lon => 1, lat => 2, ele => 8848);
221             say $point->toString();
222             # lon=1 lat=2 ele=8848 time=undef cad=undef bpm=undef spd=undef
223              
224             =head1 OPERATORS
225              
226             =head2 ==
227              
228             Shorthand operator to call L</"equals-otherPoint"> on $pointA with $pointB as argument.
229              
230             my $areEqual = $pointA == $pointB;
231             # Equivalent to $pointA->equals($pointB);
232              
233             =cut