File Coverage

lib/Geo/ShapeFile/Point.pm
Criterion Covered Total %
statement 83 146 56.8
branch 25 52 48.0
condition 14 39 35.9
subroutine 21 47 44.6
pod 19 26 73.0
total 162 310 52.2


line stmt bran cond sub pod time code
1             package Geo::ShapeFile::Point;
2             # TODO - add dimension operators (to specify if 2 or 3 dimensional point)
3 2     2   13 use strict;
  2         4  
  2         57  
4 2     2   10 use warnings;
  2         3  
  2         57  
5 2     2   1143 use Math::Trig 1.04;
  2         29910  
  2         294  
6 2     2   20 use Carp;
  2         3  
  2         231  
7              
8             our $VERSION = '3.03';
9              
10             use overload
11 2         15 '==' => 'eq',
12             'eq' => 'eq',
13             '""' => 'stringify',
14             '+' => \&add,
15             '-' => \&subtract,
16             '*' => \&multiply,
17             '/' => \÷,
18             fallback => 1,
19 2     2   15 ;
  2         4  
20              
21             my %config = (
22             comp_includes_z => 1,
23             comp_includes_m => 1,
24             );
25              
26             sub new {
27 83413     83413 1 155754 my $proto = shift;
28 83413   33     191428 my $class = ref($proto) || $proto;
29              
30 83413         244622 my $self = {@_};
31              
32 83413         115252 bless $self, $class;
33              
34 83413         220598 return $self;
35             }
36              
37             sub _var {
38 107360     107360   139113 my $self = shift;
39 107360         134379 my $var = shift;
40              
41 107360 100       158761 if (@_) {
42 10098         24710 return $self->{$var} = shift;
43             }
44             else {
45 97262         177533 return $self->{$var};
46             }
47             }
48              
49             # these could be factory generated
50 48490     48490 1 2738800 sub X { shift()->_var('X', @_); }
51 48490     48490 1 144930 sub Y { shift()->_var('Y', @_); }
52 7791     7791 1 14699 sub Z { shift()->_var('Z', @_); }
53 2589     2589 1 5602 sub M { shift()->_var('M', @_); }
54              
55 0     0 1 0 sub x_min { $_[0]->_var('X'); }
56 0     0 1 0 sub x_max { $_[0]->_var('X'); }
57 0     0 1 0 sub y_min { $_[0]->_var('Y'); }
58 0     0 1 0 sub y_max { $_[0]->_var('Y'); }
59 0     0 1 0 sub z_min { $_[0]->_var('Z'); }
60 0     0 1 0 sub z_max { $_[0]->_var('Z'); }
61 0     0 1 0 sub m_min { $_[0]->_var('M'); }
62 0     0 1 0 sub m_max { $_[0]->_var('M'); }
63              
64 16984     16984 1 41765 sub get_x { $_[0]->{X} }
65 16984     16984 1 54747 sub get_y { $_[0]->{Y} }
66 0     0 1 0 sub get_z { $_[0]->{Z} }
67 0     0 1 0 sub get_m { $_[0]->{M} }
68              
69              
70             sub import {
71 4     4   145 my $self = shift;
72 4         13 my %args = @_;
73              
74 4         136 foreach(keys %args) { $config{$_} = $args{$_}; }
  0         0  
75             }
76              
77             sub eq {
78 8     8 0 1296 my $left = shift;
79 8         12 my $right = shift;
80              
81 8 100 66     34 if ($config{comp_includes_z} && (defined $left->Z || defined $right->Z)) {
      33        
82 1 50 33     14 return 0 unless defined $left->Z && defined $right->Z;
83 1 50       4 return 0 unless $left->Z == $right->Z;
84             }
85 8 100 66     25 if ($config{comp_includes_m} && (defined $left->M || defined $right->M)) {
      33        
86 3 50 33     23 return 0 unless defined $left->M && defined $right->M;
87 3 50       16 return 0 unless $left->M == $right->M;
88             }
89              
90 8   33     19 return ($left->X == $right->X && $left->Y == $right->Y);
91             }
92              
93             sub stringify {
94 107     107 0 2955 my $self = shift;
95              
96 107         197 my @foo = ();
97 107         223 foreach(qw/X Y Z M/) {
98 428 100       976 if(defined $self->$_()) {
99 230         508 push @foo, "$_=" . $self->$_();
100             }
101             }
102 107         886 my $r = 'Point(' . join(',', @foo) . ')';
103             }
104              
105             sub distance_from {
106 0     0 1 0 my ($p1, $p2) = @_;
107              
108 0         0 my $dp = $p2->subtract($p1);
109 0         0 return sqrt ( ($dp->X ** 2) + ($dp->Y **2) );
110             }
111              
112 0     0 0 0 sub distance_to { distance_from(@_); }
113              
114             sub angle_to {
115 8     8 1 32 my ($p1, $p2) = @_;
116              
117 8         23 my $dp = $p2->subtract ($p1);
118              
119 8         19 my $x_off = $dp->get_x;
120 8         18 my $y_off = $dp->get_y;
121              
122 8 100 100     33 return 0 if !($x_off || $y_off);
123              
124 7         49 my $bearing = 90 - Math::Trig::rad2deg (Math::Trig::atan2 ($y_off, $x_off));
125 7 100       194 if ($bearing < 0) {
126 2         4 $bearing += 360;
127             }
128              
129 7         25 return $bearing;
130             }
131              
132 0     0 0 0 sub add { _mathemagic('add', @_); }
133 8     8 0 21 sub subtract { _mathemagic('subtract', @_); }
134 0     0 0 0 sub multiply { _mathemagic('multiply', @_); }
135 0     0 0 0 sub divide { _mathemagic('divide', @_); }
136              
137             sub _mathemagic {
138 8     8   19 my ($op, $l, $r, $reverse) = @_;
139              
140 8 50       24 if ($reverse) { # put them back in the right order
141 0         0 ($l, $r) = ($r, $l);
142             }
143 8         13 my ($left, $right);
144              
145 8 50       35 if (UNIVERSAL::isa($l, 'Geo::ShapeFile::Point')) { $left = 'point'; }
  8         14  
146 8 50       22 if (UNIVERSAL::isa($r, 'Geo::ShapeFile::Point')) { $right = 'point'; }
  8         14  
147              
148 8 50       27 if ($l =~ /^[\d\.]+$/) { $left = 'number'; }
  0         0  
149 8 50       20 if ($r =~ /^[\d\.]+$/) { $right = 'number'; }
  0         0  
150              
151 8 50       25 unless ($left) { croak "Couldn't identify $l for $op"; }
  0         0  
152 8 50       23 unless ($right) { croak "Couldn't identify $r for $op"; }
  0         0  
153              
154 8         63 my $function = '_' . join '_', $op, $left, $right;
155              
156             croak "Don't know how to $op $left and $right"
157 8 50       13 if !defined &{$function};
  8         40  
158              
159 8         13 do {
160 2     2   2909 no strict 'refs';
  2         5  
  2         1618  
161 8         29 return $function->($l, $r);
162             }
163             }
164              
165             sub _add_point_point {
166 0     0   0 my ($p1, $p2) = @_;
167              
168 0         0 my $z;
169 0 0 0     0 if(defined($p2->Z) && defined($p1->Z)) { $z = ($p2->Z + $p1->Z); }
  0         0  
170              
171             Geo::ShapeFile::Point->new(
172 0         0 X => ($p2->X + $p1->X),
173             Y => ($p2->Y + $p1->Y),
174             Z => $z,
175             );
176             }
177              
178             sub _add_point_number {
179 0     0   0 my ($p1, $n) = @_;
180              
181 0         0 my $z;
182 0 0       0 if (defined($p1->Z)) { $z = ($p1->Z + $n); }
  0         0  
183              
184             Geo::ShapeFile::Point->new(
185 0         0 X => ($p1->X + $n),
186             Y => ($p1->Y + $n),
187             Z => $z,
188             );
189             }
190 0     0   0 sub _add_number_point { add_point_number(@_); }
191              
192             sub _subtract_point_point {
193 8     8   18 my($p1, $p2) = @_;
194              
195 8         11 my $z;
196 8 50 33     18 if(defined($p2->Z) && defined($p1->Z)) { $z = ($p2->Z - $p1->Z); }
  0         0  
197              
198 8         24 my $result = Geo::ShapeFile::Point->new(
199             X => ($p1->X - $p2->X),
200             Y => ($p1->Y - $p2->Y),
201             Z => $z,
202             );
203 8         25 return $result;
204             }
205              
206             sub _subtract_point_number {
207 0     0     my($p1, $n) = @_;
208              
209 0           my $z;
210 0 0         if (defined $p1->Z) {
211 0           $z = ($p1->Z - $n);
212             }
213              
214             Geo::ShapeFile::Point->new(
215 0           X => ($p1->X - $n),
216             Y => ($p1->Y - $n),
217             Z => $z,
218             );
219             }
220 0     0     sub _subtract_number_point { _subtract_point_number(reverse @_); }
221              
222             sub _multiply_point_point {
223 0     0     my ($p1, $p2) = @_;
224              
225 0           my $z;
226 0 0 0       if (defined $p2->Z and defined $p1->Z) {
227 0           $z = $p2->Z * $p1->Z;
228             }
229              
230             Geo::ShapeFile::Point->new(
231 0           X => ($p2->X * $p1->X),
232             Y => ($p2->Y * $p1->Y),
233             Z => $z,
234             );
235             }
236             sub _multiply_point_number {
237 0     0     my($p1, $n) = @_;
238              
239 0           my $z;
240 0 0         if (defined $p1->Z) {
241 0           $z = $p1->Z * $n;
242             }
243              
244             Geo::ShapeFile::Point->new(
245 0           X => ($p1->X * $n),
246             Y => ($p1->Y * $n),
247             Z => $z,
248             );
249             }
250              
251 0     0     sub _multiply_number_point { _multiply_point_number(reverse @_); }
252              
253             sub _divide_point_point {
254 0     0     my($p1, $p2) = @_;
255              
256 0           my $z;
257 0 0 0       if (defined $p2->Z and defined $p1->Z) {
258 0           $z = $p1->Z / $p2->Z;
259             }
260              
261             Geo::ShapeFile::Point->new(
262 0           X => ($p1->X / $p2->X),
263             Y => ($p1->Y / $p2->Y),
264             Z => $z,
265             );
266             }
267              
268             sub _divide_point_number {
269 0     0     my ($p1, $n) = @_;
270              
271 0           my $z;
272 0 0         if (defined $p1->Z) {
273 0           $z = $p1->Z / $n;
274             }
275              
276             Geo::ShapeFile::Point->new(
277 0           X => ($p1->X / $n),
278             Y => ($p1->Y / $n),
279             Z => $z,
280             );
281             }
282              
283 0     0     sub _divide_number_point { divide_point_number(reverse @_); }
284              
285             1;
286             __END__