| 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 |