File Coverage

blib/lib/Math/Vec.pm
Criterion Covered Total %
statement 131 193 67.8
branch 19 36 52.7
condition 1 3 33.3
subroutine 35 54 64.8
pod 35 35 100.0
total 221 321 68.8


line stmt bran cond sub pod time code
1             package Math::Vec;
2             our $VERSION = '1.01';
3              
4             =pod
5              
6             =head1 NAME
7              
8             Math::Vec - Object-Oriented Vector Math Methods in Perl
9              
10             =head1 SYNOPSIS
11              
12             use Math::Vec;
13             $v = Math::Vec->new(0,1,2);
14              
15             or
16              
17             use Math::Vec qw(NewVec);
18             $v = NewVec(0,1,2);
19             @res = $v->Cross([1,2.5,0]);
20             $p = NewVec(@res);
21             $q = $p->Dot([0,1,0]);
22              
23             or
24              
25             use Math::Vec qw(:terse);
26             $v = V(0,1,2);
27             $q = ($v x [1,2.5,0]) * [0,1,0];
28              
29             =head1 NOTICE
30              
31             This module is still somewhat incomplete. If a function does nothing,
32             there is likely a really good reason. Please have a look at the code
33             if you are trying to use this in a production environment.
34              
35             =head1 AUTHOR
36              
37             Eric L. Wilhelm
38              
39             http://scratchcomputing.com
40              
41             =head1 DESCRIPTION
42              
43             This module was adapted from Math::Vector, written by Wayne M. Syvinski.
44              
45             It uses most of the same algorithms, and currently preserves the same
46             names as the original functions, though some aliases have been added to
47             make the interface more natural (at least to the way I think.)
48              
49             The "object" for the object oriented calling style is a blessed array
50             reference which contains a vector of the form [x,y,z]. Methods will
51             typically return a list.
52              
53             =head1 COPYRIGHT NOTICE
54              
55             Copyright (C) 2003-2006 Eric Wilhelm
56              
57             portions Copyright 2003 Wayne M. Syvinski
58              
59             =head1 NO WARRANTY
60              
61             Absolutely, positively NO WARRANTY, neither express or implied, is
62             offered with this software. You use this software at your own risk.
63             In case of loss, neither Wayne M. Syvinski, Eric Wilhelm, nor anyone
64             else, owes you anything whatseover. You have been warned.
65              
66             Note that this includes NO GUARANTEE of MATHEMATICAL CORRECTNESS. If
67             you are going to use this code in a production environment, it is YOUR
68             RESPONSIBILITY to verify that the methods return the correct values.
69              
70             =head1 LICENSE
71              
72             You may use this software under one of the following licenses:
73              
74             (1) GNU General Public License
75             (found at http://www.gnu.org/copyleft/gpl.html)
76             (2) Artistic License
77             (found at http://www.perl.com/pub/language/misc/Artistic.html)
78              
79             =head1 SEE ALSO
80              
81             Math::Vector
82              
83             =cut
84              
85             ########################################################################
86              
87 3     3   111771 use strict;
  3         8  
  3         113  
88 3     3   17 use warnings;
  3         4  
  3         83  
89 3     3   15 use Carp;
  3         10  
  3         733  
90              
91             {
92             package Math::Vec::Support;
93             # Dropping the usage of Math::Complex acos() because we don't want any
94             # complex numbers to happen due to errors in the whee bits.
95             sub acos {
96 3     3   14 my ($z) = @_;
97              
98 3         6 my $abs = abs($z);
99 3 50       13 if($abs > 1) {
100             # just a little sanity checking
101 3 50       12 (($abs - 1) > 2**-16) and die "bad input to acos($z)";
102             # make it safe
103 3 100       8 $z = ($z > 0) ? 1 : -1;
104             }
105              
106 3         38 return CORE::atan2(CORE::sqrt(1-$z*$z), $z);
107             }
108             }
109              
110             BEGIN {
111 3     3   22 use Exporter;
  3         12  
  3         120  
112 3     3   4287 *{import} = \&Exporter::import;
113             }
114             our @EXPORT = ();
115             our @EXPORT_OK = qw(
116             NewVec
117             );
118             our @terse_exp = qw(
119             V
120             U
121             X
122             Y
123             Z
124             );
125             our %EXPORT_TAGS = (
126             terse => [@terse_exp],
127             );
128             Exporter::export_ok_tags(keys(%EXPORT_TAGS));
129              
130              
131             ########################################################################
132              
133             =head1 Constructor
134              
135             =head2 new
136              
137             Returns a blessed array reference to cartesian point ($x, $y, $z),
138             where $z is optional. Note the feed-me-list, get-back-reference syntax
139             here. This is the opposite of the rest of the methods for a good
140             reason (it allows nesting of function calls.)
141              
142             The z value is optional, (and so are x and y.) Undefined values are
143             silently translated into zeros upon construction.
144              
145             $vec = Math::Vec->new($x, $y, $z);
146              
147             =cut
148             sub new {
149 57     57 1 2987 my $caller = shift;
150 57   33     375 my $class = ref($caller) || $caller;
151 57 100       105 my $self = [map({defined($_) ? $_ : 0} @_[0,1,2])];
  171         402  
152 57         122 bless($self, $class);
153 57         219 return($self);
154             } # end subroutine new definition
155             ########################################################################
156              
157             =head2 NewVec
158              
159             This is simply a shortcut to Math::Vec->new($x, $y, $z) for those of
160             you who don't want to type so much so often. This also makes it easier
161             to nest / chain your function calls. Note that methods will typically
162             output lists (e.g. the answer to your question.) While you can simply
163             [bracket] the answer to make an array reference, you need that to be
164             blessed in order to use the $object->method(@args) syntax. This
165             function does that blessing.
166              
167             This function is exported as an option. To use it, simply use
168             Math::Vec qw(NewVec); at the start of your code.
169              
170             use Math::Vec qw(NewVec);
171             $vec = NewVec($x, $y, $z);
172             $diff = NewVec($vec->Minus([$ovec->ScalarMult(0.5)]));
173              
174             =cut
175             sub NewVec {
176 5     5 1 19 return(Math::Vec->new(@_));
177             } # end subroutine NewVec definition
178             ########################################################################
179              
180             =head1 Terse Functions
181              
182             These are all one-letter shortcuts which are imported to your namespace
183             with the :terse flag.
184              
185             use Math::Vec qw(:terse);
186              
187             =head2 V
188              
189             This is the same as Math::Vec->new($x,$y,$z).
190              
191             $vec = V($x, $y, $z);
192              
193             =cut
194             sub V {
195 49     49 1 1373 return(Math::Vec->new(@_));
196             } # end subroutine V definition
197             ########################################################################
198              
199             =head2 U
200              
201             Shortcut to V($x,$y,$z)->UnitVector()
202              
203             $unit = U($x, $y, $z);
204              
205             This will also work if called with a vector object:
206              
207             $unit = U($vector);
208              
209             =cut
210             sub U {
211 0     0 1 0 my $v;
212 0 0       0 if(ref($_[0])) {
213 0         0 $v = _vec_check($_[0]);
214             }
215             else {
216 0         0 $v = V(@_);
217             }
218 0         0 return(V($v->UnitVector()));
219             } # end subroutine U definition
220             ########################################################################
221              
222             =head2 X
223              
224             Returns an x-axis unit vector.
225              
226             $xvec = X();
227              
228             =cut
229             sub X {
230 1     1 1 4 V(1,0,0);
231             } # end subroutine X definition
232             ########################################################################
233              
234             =head2 Y
235              
236             Returns a y-axis unit vector.
237              
238             $yvec = Y();
239              
240             =cut
241             sub Y {
242 1     1 1 3 V(0,1,0);
243             } # end subroutine Y definition
244             ########################################################################
245              
246             =head2 Z
247              
248             Returns a z-axis unit vector.
249              
250             $zvec = Z();
251              
252             =cut
253             sub Z {
254 2     2 1 6 V(0,0,1);
255             } # end subroutine Z definition
256             ########################################################################
257              
258             =head1 Overloading
259              
260             Best used with the :terse functions, the Overloading scheme introduces
261             an interface which is unique from the Methods interface. Where the
262             methods take references and return lists, the overloaded operators will
263             return references. This allows vector arithmetic to be chained together
264             more easily. Of course, you can easily dereference these with @{$vec}.
265              
266             The following sections contain equivelant expressions from the longhand
267             and terse interfaces, respectively.
268              
269             =head2 Negation:
270              
271             @a = NewVec->(0,1,1)->ScalarMult(-1);
272             @a = @{-V(0,1,1)};
273              
274             =head2 Stringification:
275              
276             This also performs concatenation and other string operations.
277              
278             print join(", ", 0,1,1), "\n";
279              
280             print V(0,1,1), "\n";
281              
282             $v = V(0,1,1);
283             print "$v\n";
284             print "$v" . "\n";
285             print $v, "\n";
286              
287             =head2 Addition:
288              
289             @a = NewVec(0,1,1)->Plus([2,2]);
290              
291             @a = @{V(0,1,1) + V(2,2)};
292              
293             # only one argument needs to be blessed:
294             @a = @{V(0,1,1) + [2,2]};
295              
296             # and which one is blessed doesn't matter:
297             @a = @{[0,1,1] + V(2,2)};
298              
299             =head2 Subtraction:
300              
301             @a = NewVec(0,1,1)->Minus([2,2]);
302              
303             @a = @{[0,1,1] - V(2,2)};
304              
305             =head2 Scalar Multiplication:
306              
307             @a = NewVec(0,1,1)->ScalarMult(2);
308              
309             @a = @{V(0,1,1) * 2};
310              
311             @a = @{2 * V(0,1,1)};
312              
313             =head2 Scalar Division:
314              
315             @a = NewVec(0,1,1)->ScalarMult(1/2);
316              
317             # order matters!
318             @a = @{V(0,1,1) / 2};
319              
320             =head2 Cross Product:
321              
322             @a = NewVec(0,1,1)->Cross([0,1]);
323              
324             @a = @{V(0,1,1) x [0,1]};
325              
326             @a = @{[0,1,1] x V(0,1)};
327              
328             =head2 Dot Product:
329              
330             Also known as the "Scalar Product".
331              
332             $a = NewVec(0,1,1)->Dot([0,1]);
333              
334             $a = V(0,1,1) * [0,1];
335              
336             Note: Not using the '.' operator here makes everything more efficient.
337             I know, the * is not a dot, but at least it's a mathematical operator
338             (perl does some implied string concatenation somewhere which drove me to
339             avoid the dot.)
340              
341             =head2 Comparison:
342              
343             The == and != operators will compare vectors for equal direction and
344             magnitude. No attempt is made to apply tolerance to this equality.
345              
346             =head2 Length:
347              
348             $a = NewVec(0,1,1)->Length();
349              
350             $a = abs(V(0,1,1));
351              
352             =head2 Vector Projection:
353              
354             This one is a little different. Where the method is written
355             $a->Proj($b) to give the projection of $b onto $a, this reads like you
356             would say it (b projected onto a): $b>>$a.
357              
358             @a = NewVec(0,1,1)->Proj([0,0,1]);
359              
360             @a = @{V(0,0,1)>>[0,1,1]};
361              
362             =head1 Chaining Operations
363              
364             The above examples simply show how to go from the method interface to
365             the overloaded interface, but where the overloading really shines is in
366             chaining multiple operations together. Because the return values from
367             the overloaded operators are all references, you dereference them only
368             when you are done.
369              
370             =head2 Unit Vector left of a line
371              
372             This comes from the CAD::Calc::line_to_rectangle() function.
373              
374             use Math::Vec qw(:terse);
375             @line = ([0,1],[1,0]);
376             my ($a, $b) = map({V(@$_)} @line);
377             $unit = U($b - $a);
378             $left = $unit x -Z();
379              
380             =head2 Length of a cross product
381              
382             $length = abs($va x $vb);
383              
384             =head2 Vectors as coordinate axes
385              
386             This is useful in drawing eliptical arcs using dxf data.
387              
388             $val = 3.14159; # the 'start parameter'
389             @c = (14.15973317961194, 6.29684276451746); # codes 10, 20, 30
390             @e = (6.146127847120538, 0); # codes 11, 21, 31
391             @ep = @{V(@c) + \@e}; # that's the axis endpoint
392             $ux = U(@e); # unit on our x' axis
393             $uy = U($ux x -Z()); # y' is left of x'
394             $center = V(@c);
395             # autodesk gives you this:
396             @pt = ($a * cos($val), $b * sin($val));
397             # but they don't tell you about the major/minor axis issue:
398             @pt = @{$center + $ux * $pt[0] + $uy * $pt[1]};;
399              
400             =head1 Precedence
401              
402             The operator precedence is going to be whatever perl wants it to be. I
403             have not yet investigated this to see if it matches standard vector
404             arithmetic notation. If in doubt, use parentheses.
405              
406             One item of note here is that the 'x' and '*' operators have the same
407             precedence, so the leftmost wins. In the following example, you can get
408             away without parentheses if you have the cross-product first.
409              
410             # dot product of a cross product:
411             $v1 x $v2 * $v3
412             ($v1 x $v2) * $v3
413              
414             # scalar crossed with a vector (illegal!)
415             $v3 * $v1 x $v2
416              
417             =cut
418              
419             use overload
420             'neg' => sub {
421 1     1   5 return(V($_[0]->ScalarMult(-1)));
422             },
423             '""' => sub {
424 1     1   104 return(join(",", @{$_[0]}));
  1         8  
425             },
426             '+' => sub {
427 1     1   3 my ($v, $arg) = @_;
428 1         4 $arg = _vec_check($arg);
429 1         4 return(V($v->Plus($arg)));
430             },
431             '-' => sub {
432 1     1   3 my ($v, $arg, $flip) = @_;
433 1         3 $arg = _vec_check($arg);
434 1 50       20 $flip and (($v, $arg) = ($arg, $v));
435 1         4 return(V($v->Minus($arg)));
436             },
437             '*' => sub {
438 1     1   8 my($v, $arg) = @_;
439 1 50       5 ref($arg) and
440             return($v->Dot($arg));
441 0         0 return(V($v->ScalarMult($arg)));
442             },
443             '/' => sub {
444 0     0   0 my($v, $arg, $flip) = @_;
445 0 0       0 $flip and croak("cannot divide by vector");
446 0 0       0 $arg or croak("cannot divide vector by zero");
447 0         0 return(V($v->ScalarMult(1 / $arg)));
448             },
449             'x' => sub {
450 2     2   5 my ($v, $arg, $flip) = @_;
451 2         6 $arg = _vec_check($arg);
452 2 50       6 $flip and (($v, $arg) = ($arg, $v));
453 2         7 return(V($v->Cross($arg)));
454             },
455             '==' => sub {
456 14     14   26 my ($v, $arg) = @_;
457 14         27 $arg = _vec_check($arg);
458 14         40 for(my $i = 0; $i < 3; $i++) {
459 41 100       139 ($v->[$i] == $arg->[$i]) or return(0);
460             }
461 13         101 return(1);
462             },
463             '!=' => sub {
464 1     1   2 my ($v, $arg) = @_;
465 1         4 return(! ($v == $arg));
466             },
467             'abs' => sub {
468 2     2   8 return($_[0]->Length());
469             },
470             '>>' => sub {
471 2     2   6 my ($v, $arg, $flip) = @_;
472 2         20 $arg = _vec_check($arg);
473 2 50       7 $flip and (($v, $arg) = ($arg, $v));
474 2         7 return(V($arg->Proj($v)));
475             },
476 3     3   6571 ;
  3         3400  
  3         92  
477              
478             # Check and return a vector (or array reference turns into a vector.)
479             # also serves to initialize Z-coordinate.
480             sub _vec_check {
481 34     34   43 my $arg = shift;
482 34 50       63 if(ref($arg)) {
483 34 100       69 if(ref($arg) eq "ARRAY") {
484 19         39 $arg = V(@$arg);
485             }
486             else {
487 15         24 eval{$arg->isa('Math::Vec')};
  15         48  
488 15 50       38 $@ and
489             croak("cannot use $arg as a vector");
490             }
491             }
492             else {
493 0         0 croak("cannot use $arg as a vector");
494             }
495 34         65 return($arg);
496             } # end subroutine _vec_check definition
497             ########################################################################
498              
499             =head1 Methods
500              
501             The typical theme is that methods require array references and return
502             lists. This means that you can choose whether to create an anonymous
503             array ref for use in feeding back into another function call, or you
504             can simply use the list as-is. Methods which return a scalar or list
505             of scalars (in the mathematical sense, not the Perl SV sense) are
506             exempt from this theme, but methods which return what could become one
507             vector will return it as a list.
508              
509             If you want to chain calls together, either use the NewVec constructor,
510             or enclose the call in square brackets to make an anonymous array out
511             of the result.
512              
513             my $vec = NewVec(@pt);
514             my $doubled = NewVec($vec->ScalarMult(0.5));
515             my $other = NewVec($vec->Plus([0,2,1], [4,2,3]));
516             my @result = $other->Minus($doubled);
517             $unit = NewVec(NewVec(@result)->UnitVector());
518              
519             The vector objects are simply blessed array references. This makes for
520             a fairly limited amount of manipulation, but vector math is not
521             complicated stuff. Hopefully, you can save at least two lines of code
522             per calculation using this module.
523              
524             =head2 Dot
525              
526             Returns the dot product of $vec 'dot' $othervec.
527              
528             $vec->Dot($othervec);
529              
530             =cut
531             sub Dot {
532 7     7 1 14 my $self = shift;
533 7         10 my ($operand) = @_;
534 7         16 $operand = _vec_check($operand);
535 7         13 my @r = map( {$self->[$_] * $operand->[$_]} 0,1,2);
  21         92  
536 7         34 return( $r[0] + $r[1] + $r[2]);
537             } # end subroutine Dot definition
538             ########################################################################
539              
540             =head2 DotProduct
541              
542             Alias to Dot()
543              
544             $number = $vec->DotProduct($othervec);
545              
546             =cut
547             sub DotProduct {
548 0     0 1 0 my $self = shift;
549 0         0 return($self->Dot(@_));
550             } # end subroutine DotProduct definition
551             ########################################################################
552              
553             =head2 Cross
554              
555             Returns $vec x $other_vec
556              
557             @list = $vec->Cross($other_vec);
558             # or, to use the result as a vec:
559             $cvec = NewVec($vec->Cross($other_vec));
560              
561             =cut
562             sub Cross {
563 3     3 1 9 my $a = shift;
564 3         5 my $b = shift;
565 3         7 $b = _vec_check($b);
566 3         9 my $x = (($a->[1] * $b->[2]) - ($a->[2] * $b->[1]));
567 3         8 my $y = (($a->[2] * $b->[0]) - ($a->[0] * $b->[2]));
568 3         6 my $z = (($a->[0] * $b->[1]) - ($a->[1] * $b->[0]));
569 3         12 return($x, $y, $z);
570             } # end subroutine Cross definition
571             ########################################################################
572              
573             =head2 CrossProduct
574              
575             Alias to Cross() (should really strip out all of this clunkiness and go
576             to operator overloading, but that gets into other hairiness.)
577              
578             $vec->CrossProduct();
579              
580             =cut
581             sub CrossProduct {
582 0     0 1 0 my $self = shift;
583 0         0 return($self->Cross(@_));
584             } # end subroutine CrossProduct definition
585             ########################################################################
586              
587             =head2 Length
588              
589             Returns the length of $vec
590              
591             $length = $vec->Length();
592              
593             =cut
594             sub Length {
595 11     11 1 15 my Math::Vec $self = shift;
596 11         299 my $sum;
597 11         45 map( {$sum+=$_**2} @$self );
  33         102  
598 11         38 return(sqrt($sum));
599             } # end subroutine Length definition
600             ########################################################################
601              
602             =head2 Magnitude
603              
604             $vec->Magnitude();
605              
606             =cut
607             sub Magnitude {
608 0     0 1 0 my Math::Vec $self = shift;
609 0         0 return($self->Length());
610             } # end subroutine Magnitude definition
611             ########################################################################
612              
613             =head2 UnitVector
614              
615             $vec->UnitVector();
616              
617             =cut
618             sub UnitVector {
619 3     3 1 4 my Math::Vec $self = shift;
620 3         7 my $mag = $self->Length();
621 3 50       8 $mag || croak("zero-length vector (@$self) has no unit vector");
622 3         5 return(map({$_ / $mag} @$self) );
  9         22  
623             } # end subroutine UnitVector definition
624             ########################################################################
625              
626             =head2 ScalarMult
627              
628             Factors each element of $vec by $factor.
629              
630             @new = $vec->ScalarMult($factor);
631              
632             =cut
633             sub ScalarMult {
634 5     5 1 9 my Math::Vec $self = shift;
635 5         14 my($factor) = @_;
636 5         7 return(map( {$_ * $factor} @{$self}));
  15         39  
  5         9  
637             } # end subroutine ScalarMult definition
638             ########################################################################
639              
640             =head2 Minus
641              
642             Subtracts an arbitrary number of vectors.
643              
644             @result = $vec->Minus($other_vec, $another_vec?);
645              
646             This would be equivelant to:
647              
648             @result = $vec->Minus([$other_vec->Plus(@list_of_vectors)]);
649              
650             =cut
651             sub Minus {
652 1     1 1 3 my Math::Vec $self = shift;
653 1         2 my @list = @_;
654 1         3 my @result = @$self;
655 1         2 foreach my $vec (@list) {
656 1         4 @result = map( {$result[$_] - $vec->[$_]} 0..$#$vec);
  3         9  
657             }
658 1         5 return(@result);
659             } # end subroutine Minus definition
660             ########################################################################
661              
662             =head2 VecSub
663              
664             Alias to Minus()
665              
666             $vec->VecSub();
667              
668             =cut
669             sub VecSub {
670 0     0 1 0 my Math::Vec $self = shift;
671 0         0 return($self->Minus(@_));
672             } # end subroutine VecSub definition
673             ########################################################################
674              
675             =head2 InnerAngle
676              
677             Returns the acute angle (in radians) in the plane defined by the two
678             vectors.
679              
680             $vec->InnerAngle($other_vec);
681              
682             =cut
683             sub InnerAngle {
684 1     1 1 6 my $A = shift;
685 1         3 my $B = shift;
686 1         4 my $dot_prod = $A->Dot($B);
687 1         5 my $m_A = $A->Length();
688 1         4 my $m_B = $B->Length();
689             # NOTE occasionally returned an answer with a very small imaginary
690             # part (for d/(A*B) values very slightly under -1 or very slightly
691             # over 1.) Large imaginary results are not possible with vector
692             # inputs, so we can just drop the imaginary bit.
693 1         5 return(Math::Vec::Support::acos($dot_prod / ($m_A * $m_B)) );
694             } # end subroutine InnerAngle definition
695             ########################################################################
696              
697             =head2 DirAngles
698              
699             $vec->DirAngles();
700              
701             =cut
702             sub DirAngles {
703 0     0 1 0 my Math::Vec $self = shift;
704 0         0 my @unit = $self->UnitVector();
705 0         0 return( map( {acos($_)} @unit) );
  0         0  
706             } # end subroutine DirAngles definition
707             ########################################################################
708              
709             =head2 Plus
710              
711             Adds an arbitrary number of vectors.
712              
713             @result = $vec->Plus($other_vec, $another_vec);
714              
715             =cut
716             sub Plus {
717 1     1 1 2 my Math::Vec $self = shift;
718 1         3 my @list = @_;
719 1         4 my @result = @$self;
720 1         3 foreach my $vec (@list) {
721 1         3 @result = map( {$result[$_] + $vec->[$_]} 0..$#$vec);
  3         10  
722             }
723 1         5 return(@result);
724             } # end subroutine Plus definition
725             ########################################################################
726              
727             =head2 PlanarAngles
728              
729             If called in list context, returns the angle of the vector in each of
730             the primary planes. If called in scalar context, returns only the
731             angle in the xy plane. Angles are returned in radians
732             counter-clockwise from the primary axis (the one listed first in the
733             pairs below.)
734              
735             ($xy_ang, $xz_ang, $yz_ang) = $vec->PlanarAngles();
736              
737             =cut
738             sub PlanarAngles {
739 1     1 1 3 my $self = shift;
740 1         6 my $xy = atan2($self->[1], $self->[0]);
741 1 50       4 wantarray || return($xy);
742 1         41 my $xz = atan2($self->[2], $self->[0]);
743 1         2 my $yz = atan2($self->[2], $self->[1]);
744 1         4 return($xy, $xz, $yz);
745             } # end subroutine PlanarAngles definition
746             ########################################################################
747              
748             =head2 Ang
749              
750             A simpler alias to PlanarAngles() which eliminates the concerns about
751             context and simply returns the angle in the xy plane.
752              
753             $xy_ang = $vec->Ang();
754              
755             =cut
756             sub Ang {
757 0     0 1 0 my $self = shift;
758 0         0 my ($xy) = $self->PlanarAngles();
759 0         0 return($xy);
760             } # end subroutine Ang definition
761             ########################################################################
762              
763             =head2 VecAdd
764              
765             $vec->VecAdd();
766              
767             =cut
768             sub VecAdd {
769 0     0 1 0 my Math::Vec $self = shift;
770 0         0 return($self->Plus(@_));
771             } # end subroutine VecAdd definition
772             ########################################################################
773              
774             =head2 UnitVectorPoints
775              
776             Returns a unit vector which points from $A to $B.
777              
778             $A->UnitVectorPoints($B);
779              
780             =cut
781             sub UnitVectorPoints {
782 0     0 1 0 my $A = shift;
783 0         0 my $B = shift;
784 0         0 $B = NewVec(@$B); # because we cannot guarantee that it was blessed
785 0         0 return(NewVec($B->Minus($A))->UnitVector());
786             } # end subroutine UnitVectorPoints definition
787             ########################################################################
788              
789             =head2 InnerAnglePoints
790              
791             Returns the InnerAngle() between the three points. $Vert is the vertex
792             of the points.
793              
794             $Vert->InnerAnglePoints($endA, $endB);
795              
796             =cut
797             sub InnerAnglePoints {
798 0     0 1 0 my $v = shift;
799 0         0 my ($A, $B) = @_;
800 0         0 my $lead = NewVec($v->UnitVectorPoints($A));
801 0         0 my $tail = NewVec($v->UnitVectorPoints($B));
802 0         0 return($lead->InnerAngle($tail));
803             } # end subroutine InnerAnglePoints definition
804             ########################################################################
805              
806             =head2 PlaneUnitNormal
807              
808             Returns a unit vector normal to the plane described by the three
809             points. The sense of this vector is according to the right-hand rule
810             and the order of the given points. The $Vert vector is taken as the
811             vertex of the three points. e.g. if $Vert is the origin of a
812             coordinate system where the x-axis is $A and the y-axis is $B, then the
813             return value would be a unit vector along the positive z-axis.
814              
815             $Vert->PlaneUnitNormal($A, $B);
816              
817             =cut
818             sub PlaneUnitNormal {
819 0     0 1 0 my $v = shift;
820 0         0 my ($A, $B) = @_;
821 0         0 $A = NewVec(@$A);
822 0         0 $B = NewVec(@$B);
823 0         0 my $lead = NewVec($A->Minus($v));
824 0         0 my $tail = NewVec($B->Minus($v));
825 0         0 return(NewVec($lead->Cross($tail))->UnitVector);
826             } # end subroutine PlaneUnitNormal definition
827             ########################################################################
828              
829             =head2 TriAreaPoints
830              
831             Returns the angle of the triangle formed by the three points.
832              
833             $A->TriAreaPoints($B, $C);
834              
835             =cut
836             sub TriAreaPoints {
837 0     0 1 0 my $A = shift;
838 0         0 my ($B, $C) = @_;
839 0         0 $B = NewVec(@$B);
840 0         0 $C = NewVec(@$C);
841 0         0 my $lead = NewVec($A->Minus($B));
842 0         0 my $tail = NewVec($A->Minus($C));
843 0         0 return(NewVec($lead->Cross($tail))->Length() / 2);
844             } # end subroutine TriAreaPoints definition
845             ########################################################################
846              
847             =head2 Comp
848              
849             Returns the scalar projection of $B onto $A (also called the component
850             of $B along $A.)
851              
852             $A->Comp($B);
853              
854             =cut
855             sub Comp {
856 4     4 1 6 my $self = shift;
857 4         9 my $B = _vec_check(shift);
858 4         17 my $length = $self->Length();
859 4 50       19 $length || croak("cannot Comp() vector without length");
860 4         10 return($self->Dot($B) / $length);
861             } # end subroutine Comp definition
862             ########################################################################
863              
864             =head2 Proj
865              
866             Returns the vector projection of $B onto $A.
867              
868             $A->Proj($B);
869              
870             =cut
871             sub Proj {
872 3     3 1 4 my $self = shift;
873 3         5 my $B = shift;
874 3         10 return(NewVec($self->UnitVector())->ScalarMult($self->Comp($B)));
875             } # end subroutine Proj definition
876             ########################################################################
877              
878             =head2 PerpFoot
879              
880             Returns a point on line $A,$B which is as close to $pt as possible (and
881             therefore perpendicular to the line.)
882              
883             $pt->PerpFoot($A, $B);
884              
885             =cut
886             sub PerpFoot {
887 0     0 1   my $pt = shift;
888 0           my ($A, $B) = @_;
889 0           $pt = NewVec($pt->Minus($A));
890 0           $B = NewVec(NewVec(@$B)->Minus($A));
891 0           my $proj = NewVec($B->Proj($pt));
892 0           return($proj->Plus($A));
893             } # end subroutine PerpFoot definition
894             ########################################################################
895              
896             =head1 Incomplete Methods
897              
898             The following have yet to be translated into this interface. They are
899             shown here simply because I intended to fully preserve the function
900             names from the original Math::Vector module written by Wayne M.
901             Syvinski.
902              
903             =head2 TripleProduct
904              
905             $vec->TripleProduct();
906              
907             =cut
908             sub TripleProduct {
909 0     0 1   die("not written");
910             } # end subroutine TripleProduct definition
911             ########################################################################
912              
913             =head2 IJK
914              
915             $vec->IJK();
916              
917             =cut
918             sub IJK {
919 0     0 1   die("not written");
920              
921             } # end subroutine IJK definition
922             ########################################################################
923              
924             =head2 OrdTrip
925              
926             $vec->OrdTrip();
927              
928             =cut
929             sub OrdTrip {
930 0     0 1   die("not written");
931              
932             } # end subroutine OrdTrip definition
933             ########################################################################
934              
935             =head2 STV
936              
937             $vec->STV();
938              
939             =cut
940             sub STV {
941 0     0 1   die("not written");
942              
943             } # end subroutine STV definition
944             ########################################################################
945              
946             =head2 Equil
947              
948             $vec->Equil();
949              
950             =cut
951             sub Equil {
952 0     0 1   die("not written");
953              
954             } # end subroutine Equil definition
955             ########################################################################
956              
957             1;
958             # vim:ts=4:sw=4:noet