File Coverage

blib/lib/Math/Zap/Vector.pm
Criterion Covered Total %
statement 79 87 90.8
branch 11 18 61.1
condition 1 3 33.3
subroutine 31 35 88.5
pod 21 30 70.0
total 143 173 82.6


line stmt bran cond sub pod time code
1            
2             =head1 Vector
3            
4             Manipulate 3D vectors
5            
6             PhilipRBrenan@yahoo.com, 2004, Perl licence
7            
8            
9             =head2 Synopsis
10            
11             Example t/vector.t
12            
13             #_ Vector _____________________________________________________________
14             # Test 3d vectors
15             # philiprbrenan@yahoo.com, 2004, Perl License
16             #______________________________________________________________________
17            
18             use Math::Zap::Vector vector=>'v', units=>'u';
19             use Test::Simple tests=>7;
20            
21             my ($x, $y, $z) = u();
22            
23             ok(!$x == 1);
24             ok(2*$x+3*$y+4*$z == v( 2, 3, 4));
25             ok(-$x-$y-$z == v(-1, -1, -1));
26             ok((2*$x+3*$y+4*$z) + (-$x-$y-$z) == v( 1, 2, 3));
27             ok((2*$x+3*$y+4*$z) * (-$x-$y-$z) == -9);
28             ok($x*2 == v( 2, 0, 0));
29             ok($y/2 == v( 0, 0.5, 0));
30            
31            
32            
33             =head2 Description
34            
35             Manipulate 3 dimensional vectors via operators.
36            
37             =cut
38            
39            
40             package Math::Zap::Vector;
41             $VERSION=1.07;
42 7     7   6615 use Math::Trig;
  7         119678  
  7         1392  
43 7     7   75 use Carp;
  7         15  
  7         472  
44 7     7   40 use constant debug => 0; # Debugging level
  7         10  
  7         12209  
45            
46            
47             =head3 Constructors
48            
49            
50             =head4 new
51            
52             Create a vector from numbers
53            
54             =cut
55            
56            
57 716     716 1 723 sub new($$$)
58             {return round(bless({x=>$_[0], y=>$_[1], z=>$_[2]})) if debug;
59 716         6642 bless {x=>$_[0], y=>$_[1], z=>$_[2]};
60             }
61            
62 150     150 0 396 sub vector($$$) {new($_[0], $_[1], $_[2])}
63            
64            
65             =head4 units
66            
67             Unit vectors
68            
69             =cut
70            
71            
72 1     1 1 5 sub units() {($x, $y, $z)}
73            
74            
75             =head3 Methods
76            
77            
78             =head4 check
79            
80             Check its a vector
81            
82             =cut
83            
84            
85             sub check(@)
86 470     470 1 506 {if (debug)
87             {for my $v(@_)
88             {confess "$v is not a vector" unless ref($v) eq __PACKAGE__;
89             }
90             }
91 470         902 return (@_)
92             }
93            
94            
95             =head4 is
96            
97             Test its a vector
98            
99             =cut
100            
101            
102 45 100       215 sub is(@)
103 45     45 1 81 {for my $v(@_)
104             {return 0 unless ref($v) eq __PACKAGE__;
105             }
106 38         202 'vector';
107             }
108            
109            
110             =head4 accuracy
111            
112             Get/Set accuracy for comparisons
113            
114             =cut
115            
116            
117             my $accuracy = 1e-10;
118            
119             sub accuracy
120 0 0   0 1 0 {return $accuracy unless scalar(@_);
121 0         0 $accuracy = shift();
122             }
123            
124            
125             =head4 round
126            
127             Round: round to nearest integer if within accuracy of that integer
128            
129             =cut
130            
131            
132 13         30 sub round($)
133 13     13 1 15 {unless (debug)
134             {return $_[0];
135             }
136             else
137             {my ($a) = @_;
138             for my $k(keys(%$a))
139             {my $n = $a->{$k};
140             my $N = int($n);
141             $a->{$k} = $N if abs($n-$N) < $accuracy;
142             }
143             return $a;
144             }
145             }
146            
147            
148             =head4 x,y,z
149            
150             x,y,z components of vector
151            
152             =cut
153            
154            
155 893     893 1 864 sub x($) {check(@_) if debug; $_[0]->{x}}
  893         2426  
156 892     892 1 840 sub y($) {check(@_) if debug; $_[0]->{y}}
  892         2564  
157 901     901 1 868 sub z($) {check(@_) if debug; $_[0]->{z}}
  901         4234  
158            
159             $x = new(1,0,0);
160             $y = new(0,1,0);
161             $z = new(0,0,1);
162            
163            
164             =head4 clone
165            
166             Create a vector from another vector
167            
168             =cut
169            
170            
171 13     13 1 26 sub clone($)
172             {my ($v) = check(@_); # Vectors
173 13         32 round bless {x=>$v->x, y=>$v->y, z=>$v->z};
174             }
175            
176            
177             =head4 length
178            
179             Length of a vector
180            
181             =cut
182            
183            
184 138     138 1 380 sub length($)
185             {my ($v) = check(@_[0..0]); # Vectors
186 138         273 sqrt($v->x**2+$v->y**2+$v->z**2);
187             }
188            
189            
190             =head4 print
191            
192             Print vector
193            
194             =cut
195            
196            
197 8     8 1 16 sub print($)
198             {my ($v) = check(@_); # Vectors
199 8         19 my ($x, $y, $z) = ($v->x, $v->y, $v->z);
200            
201 8         53 "vector($x, $y, $z)";
202             }
203            
204            
205             =head4 norm
206            
207             Normalize vector
208            
209             =cut
210            
211            
212 13     13 1 30 sub norm($)
213             {my ($v) = check(@_); # Vectors
214 13         32 $v = $v->clone; # Copy vector
215 13         31 my $l = $v->length;
216            
217 13 50       36 $l > 0 or confess "Cannot normalize zero length vector $v";
218            
219 13         24 $v->{x} /= $l;
220 13         18 $v->{y} /= $l;
221 13         18 $v->{z} /= $l;
222 13         31 $v;
223             }
224            
225            
226             =head4 dot
227            
228             Dot product
229            
230             =cut
231            
232            
233 18     18 1 48 sub dot($$)
234             {my ($a, $b) = check(@_); # Vectors
235 18         42 $a->x*$b->x+$a->y*$b->y+$a->z*$b->z;
236             }
237            
238            
239             =head4 angle
240            
241             Angle between two vectors
242            
243             =cut
244            
245            
246 0     0 1 0 sub angle($$)
247             {my ($a, $b) = check(@_); # Vectors
248 0         0 acos($a->norm->dot($b->norm));
249             }
250            
251            
252             =head4 cross
253            
254             Cross product
255            
256             =cut
257            
258            
259 79     79 1 143 sub cross($$)
260             {my ($a, $b) = check(@_); # Vectors
261            
262 79         187 new
263             ((($a->y * $b->z) - ($a->z * $b->y)),
264             (($a->z * $b->x) - ($a->x * $b->z)),
265             (($a->x * $b->y) - ($a->y * $b->x))
266             );
267             }
268            
269            
270             =head4 add
271            
272             Add vectors
273            
274             =cut
275            
276            
277 41     41 1 68 sub add($$)
278             {my ($a, $b) = check(@_); # Vectors
279 41         79 new($a->x+$b->x, $a->y+$b->y, $a->z+$b->z);
280             }
281            
282            
283             =head4 subtract
284            
285             Subtract vectors
286            
287             =cut
288            
289            
290 0     0 1 0 sub subtract($$)
291             {check(@_) if debug; # Vectors
292 0         0 new($_[0]->{x}-$_[1]->{x}, $_[0]->{y}-$_[1]->{y}, $_[0]->{z}-$_[1]->{z});
293             }
294            
295            
296             =head4 multiply
297            
298             Vector times a scalar
299            
300             =cut
301            
302            
303 40     40 1 78 sub multiply($$)
304             {my ($a) = check(@_[0..0]); # Vector
305 40         92 my ($b) = @_[1..1]; # Scalar
306            
307 40 50       87 confess "$b is not a scalar" if ref($b);
308 40         75 new($a->x*$b, $a->y*$b, $a->z*$b);
309             }
310            
311            
312             =head4 divide
313            
314             Vector divided by a non zero scalar
315            
316             =cut
317            
318            
319 6     6 1 15 sub divide($$)
320             {my ($a) = check(@_[0..0]); # Vector
321 6         12 my ($b) = @_[1..1]; # Scalar
322            
323 6 50       18 confess "$b is not a scalar" if ref($b);
324 6 50       17 confess "$b is zero" if $b == 0;
325 6         17 new($a->x/$b, $a->y/$b, $a->z/$b);
326             }
327            
328            
329             =head4 equals
330            
331             Equals to within accuracy
332            
333             =cut
334            
335            
336 8     8 1 15 sub equals($$)
337             {my ($a, $b) = check(@_); # Vectors
338 8 50 33     19 abs($a->x-$b->x) < $accuracy and
339             abs($a->y-$b->y) < $accuracy and
340             abs($a->z-$b->z) < $accuracy;
341             }
342            
343            
344             =head4 Operator Overloads
345            
346             Operator overloads
347            
348             =cut
349            
350            
351             use overload
352 7         145 '+' => \&add3, # Add two vectors
353             '-' => \&subtract3, # Subtract one vector from another
354             '*' => \&multiply3, # Times by a scalar, or vector dot product
355             '/' => \÷3, # Divide by a scalar
356             'x' => \&cross3, # BEWARE LOW PRIORITY! Cross product
357             '<' => \&angle3, # Angle in radians between two vectors
358             '>' => \&angle3, # Angle in radians between two vectors
359             '==' => \&equals3, # Equals
360             '""' => \&print3, # Print
361             '!' => \&length, # Length
362 7     7   62 'fallback' => FALSE;
  7         14  
363            
364            
365             =head4 Add operator
366            
367             Add operator, see L
368            
369             =cut
370            
371            
372             sub add3
373 41     41 0 60 {my ($a, $b) = @_;
374 41         81 $a->add($b);
375             }
376            
377            
378             =head4 Subtract Operator
379            
380             Subtract operator.
381            
382             =cut
383            
384            
385             sub subtract3
386 379 100   379 0 1920 {return new($_[0]->{x}-$_[1]->{x}, $_[0]->{y}-$_[1]->{y}, $_[0]->{z}-$_[1]->{z}) if ref($_[1]);
387 3         11 new(-$_[0]->{x}, -$_[0]->{y}, -$_[0]->{z});
388             }
389            
390            
391             =head4 Multiply Operator
392            
393             Multiply operator, see L
394            
395             =cut
396            
397            
398             sub multiply3
399 57     57 0 91 {my ($a, $b) = @_;
400 57 100       145 return $a->dot ($b) if ref($b);
401 40         81 return $a->multiply($b);
402             }
403            
404            
405             =head4 Divide Operator
406            
407             Divide operator, see L
408            
409             =cut
410            
411            
412             sub divide3
413 6     6 0 15 {my ($a, $b, $c) = @_;
414 6         19 return $a->divide($b);
415             }
416            
417            
418             =head4 Cross Operator
419            
420             Cross operator, see L
421            
422             =cut
423            
424            
425             sub cross3
426 79     79 0 130 {my ($a, $b, $c) = @_;
427 79         169 return $a->cross($b);
428             }
429            
430            
431             =head4 Angle Operator
432            
433             Angle operator, see L
434            
435             =cut
436            
437            
438             sub angle3
439 0     0 0 0 {my ($a, $b, $c) = @_;
440 0         0 return $a->angle($b);
441             }
442            
443            
444             =head4 Equals Operator
445            
446             Equals operator, see L
447            
448             =cut
449            
450            
451             sub equals3
452 8     8 0 17 {my ($a, $b, $c) = @_;
453 8         27 return $a->equals($b);
454             }
455            
456            
457             =head4 Print Operator
458            
459             Print a vector, see L
460            
461             =cut
462            
463            
464             sub print3
465 8     8 0 15 {my ($a) = @_;
466 8         20 return $a->print;
467             }
468            
469            
470             =head2 Export Definitions
471            
472             Export L, L, L, L
473            
474             =cut
475            
476            
477 7         48 use Math::Zap::Exports qw(
478             vector ($$$)
479             units ()
480             check (@)
481             is (@)
482 7     7   8370 );
  7         16  
483            
484             #______________________________________________________________________
485             # Package loaded successfully
486             #______________________________________________________________________
487            
488             1;
489            
490            
491             =head2 Credits
492            
493             =head3 Author
494            
495             philiprbrenan@yahoo.com
496            
497             =head3 Copyright
498            
499             philiprbrenan@yahoo.com, 2004
500            
501             =head3 License
502            
503             Perl License.
504            
505            
506             =cut