1 package Vector; 2 # 3 # $RCSfile: Vector.pm,v $ 4 # $Date: 2008/04/19 16:11:03 $ 5 # $Revision: 1.16 $ 6 # 7 # Author: Manish Sud <msud@san.rr.com> 8 # 9 # Copyright (C) 2004-2008 Manish Sud. All rights reserved. 10 # 11 # This file is part of MayaChemTools. 12 # 13 # MayaChemTools is free software; you can redistribute it and/or modify it under 14 # the terms of the GNU Lesser General Public License as published by the Free 15 # Software Foundation; either version 3 of the License, or (at your option) any 16 # later version. 17 # 18 # MayaChemTools is distributed in the hope that it will be useful, but without 19 # any warranty; without even the implied warranty of merchantability of fitness 20 # for a particular purpose. See the GNU Lesser General Public License for more 21 # details. 22 # 23 # You should have received a copy of the GNU Lesser General Public License 24 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or 25 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330, 26 # Boston, MA, 02111-1307, USA. 27 # 28 use 5.006; 29 use strict; 30 use Carp; 31 use Exporter; 32 use Scalar::Util (); 33 34 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); 35 36 $VERSION = '1.00'; 37 @ISA = qw(Exporter); 38 @EXPORT = qw(IsVector UnitXVector UnitYVector UnitZVector UnitVector ZeroVector); 39 @EXPORT_OK = qw(SetValuePrintFormat); 40 41 %EXPORT_TAGS = ( 42 all => [@EXPORT, @EXPORT_OK] 43 ); 44 45 # Setup class variables... 46 my($ClassName, $ValueFormat); 47 _InitializeClass(); 48 49 # 50 # Using the following explicity overloaded operators, Perl automatically generates methods 51 # for operations with no explicitly defined methods. Autogenerated methods are possible for 52 # these operators: 53 # 54 # o Arithmetic operators: += -= *= /= **= %= ++ -- x= .= 55 # o Increment and decrement: ++ -- 56 # 57 # 'fallback' is set to 'false' to raise exception for all other operators. 58 # 59 use overload '""' => 'StringifyVector', 60 61 '0+' => '_NumifyVector', 62 'bool' => '_BoolifyVector', 63 64 '@{}' => '_VectorToArrayOperator', 65 66 '+' => '_VectorAdditionOperator', 67 '-' => '_VectorSubtractionOperator', 68 '*' => '_VectorMultiplicationOperator', 69 '/' => '_VectorDivisionOperator', 70 '**' => '_VectorExponentiationOperator', 71 '%' => '_VectorModulusOperator', 72 73 'x' => '_VectorCrossProductOperator', 74 '.' => '_VectorDotProductOperator', 75 76 '==' => '_VectorEqualOperator', 77 '!=' => '_VectorNotEqualOperator', 78 '<' => '_VectorLessThanOperator', 79 '<=' => '_VectorLessThanEqualOperator', 80 '>' => '_VectorGreatarThanOperator', 81 '>=' => '_VectorGreatarThanEqualOperator', 82 83 'neg' => '_VectorNegativeValueOperator', 84 85 'abs' => '_VectorAbsoluteValueOperator', 86 'exp' => '_VectorExpNaturalBaseOperator', 87 'log' => '_VectorLogNaturalBaseOperator', 88 'sqrt' => '_VectorSquareRootOperator', 89 'cos' => '_VectorCosineOperator', 90 'sin' => '_VectorSineOperator', 91 92 'fallback' => undef; 93 94 # Class constructor... 95 sub new { 96 my($Class, @Values) = @_; 97 98 # Initialize object... 99 my $This = {}; 100 bless $This, ref($Class) || $Class; 101 $This->_InitializeVector(); 102 103 $This->_AddValues(@Values); 104 105 return $This; 106 } 107 108 # Initialize object data... 109 # 110 sub _InitializeVector { 111 my($This) = @_; 112 113 @{$This->{Values}} = (); 114 } 115 116 # Initialize class ... 117 sub _InitializeClass { 118 #Class name... 119 $ClassName = __PACKAGE__; 120 121 # Print format for vectore values... 122 $ValueFormat = "%g"; 123 } 124 125 # Initialize vector values using: 126 # o List of values 127 # o Reference to an list of values 128 # o Another vector object 129 # 130 sub _AddValues { 131 my($This, @Values) = @_; 132 133 if (!@Values) { 134 return; 135 } 136 137 # Set vector values... 138 my($FirstValue, $TypeOfFirstValue); 139 $FirstValue = $Values[0]; 140 $TypeOfFirstValue = ref $FirstValue; 141 if ($TypeOfFirstValue =~ /^(SCALAR|HASH|CODE|REF|GLOB)/) { 142 croak "Error: ${ClassName}->_AddValues: Trying to add values to vector object with a reference to unsupported value format..."; 143 } 144 145 if (_IsVector($FirstValue)) { 146 # Initialize using Vector... 147 push @{$This->{Values}}, @{$FirstValue->{Values}}; 148 } 149 elsif ($TypeOfFirstValue =~ /^ARRAY/) { 150 # Initialize using array refernce... 151 push @{$This->{Values}}, @{$FirstValue}; 152 } 153 else { 154 # It's a list of values... 155 push @{$This->{Values}}, @Values; 156 } 157 } 158 159 # Add values to a vector using a vector, reference to an array or an array... 160 sub AddValues { 161 my($This, @Values) = @_; 162 163 $This->_AddValues(@Values); 164 165 return $This; 166 } 167 168 # Copy vector... 169 sub Copy { 170 my($This) = @_; 171 my($Vector); 172 173 # Copy vector values... 174 $Vector = (ref $This)->new(\@{$This->{Values}}); 175 176 # Copy value format for stringification... 177 if (exists $This->{ValueFormat}) { 178 $Vector->{ValueFormat} = $This->{ValueFormat}; 179 } 180 return $Vector; 181 } 182 183 # Get 3D vector length... 184 sub GetLength { 185 my($This) = @_; 186 187 if ($This->GetSize() != 3) { 188 croak "Error: ${ClassName}->GetGetLength: Object must be a 3D vector..."; 189 } 190 my($Length, $DotProduct); 191 $DotProduct = $This . $This; 192 $Length = sqrt $DotProduct; 193 194 return $Length; 195 } 196 197 # Length of a 3D vector by another name... 198 sub GetMagnitude { 199 my($This) = @_; 200 return $This->GetLength(); 201 } 202 203 # Normalize 3D vector... 204 sub Normalize { 205 my($This) = @_; 206 207 if ($This->GetSize() != 3) { 208 croak "Error: ${ClassName}->GetGetLength: Object must be a 3D vector..."; 209 } 210 my($Vector, $Length); 211 $Length = $This->GetLength(); 212 $Vector = $This / $Length; 213 214 return $Vector; 215 } 216 217 # Is it a vector object? 218 sub IsVector ($) { 219 my($Object) = @_; 220 221 return _IsVector($Object); 222 } 223 224 # Get size... 225 sub GetSize { 226 my($This) = @_; 227 228 return scalar @{$This->{Values}}; 229 } 230 231 # Get X value of a 3D vector... 232 sub GetX { 233 my($This) = @_; 234 235 if ($This->GetSize() != 3) { 236 croak "Error: ${ClassName}->GetX: Object must be a 3D vector..."; 237 } 238 return $This->_GetValue(0); 239 } 240 241 # Set X value of a 3D vector... 242 sub SetX { 243 my($This, $Value) = @_; 244 245 if ($This->GetSize() != 3) { 246 croak "Error: ${ClassName}->SetX: Object must be a 3D vector..."; 247 } 248 return $This->_SetValue(0, $Value); 249 } 250 251 # Get Y value of a 3D vector... 252 sub GetY { 253 my($This) = @_; 254 255 if ($This->GetSize() != 3) { 256 croak "Error: ${ClassName}->GetY: Object must be a 3D vector..."; 257 } 258 return $This->_GetValue(1); 259 } 260 261 # Set Y value of a 3D vector... 262 sub SetY { 263 my($This, $Value) = @_; 264 265 if ($This->GetSize() != 3) { 266 croak "Error: ${ClassName}->SetY: Object must be a 3D vector..."; 267 } 268 return $This->_SetValue(1, $Value); 269 } 270 271 # Get Z value of a 3D vector... 272 sub GetZ { 273 my($This) = @_; 274 275 if ($This->GetSize() != 3) { 276 croak "Error: ${ClassName}->GetZ: Object must be a 3D vector..."; 277 } 278 return $This->_GetValue(2); 279 } 280 281 # Set Z value of a 3D vector... 282 sub SetZ { 283 my($This, $Value) = @_; 284 285 if ($This->GetSize() != 3) { 286 croak "Error: ${ClassName}->SetZ: Object must be a 3D vector..."; 287 } 288 return $This->_SetValue(2, $Value); 289 } 290 291 # Set XYZ value of a 3D vector using: 292 # o List of values 293 # o Reference to an list of values 294 # o Another vector object 295 # 296 sub SetXYZ { 297 my($This, @Values) = @_; 298 299 if (!@Values) { 300 croak "Error: ${ClassName}->SetXYZ: No values specified..."; 301 } 302 303 if ($This->GetSize() != 3) { 304 croak "Error: ${ClassName}->SetXYZ: Object must be a 3D vector..."; 305 } 306 307 # Set vector values... 308 my($FirstValue, $TypeOfFirstValue); 309 $FirstValue = $Values[0]; 310 $TypeOfFirstValue = ref $FirstValue; 311 if ($TypeOfFirstValue =~ /^(SCALAR|HASH|CODE|REF|GLOB)/) { 312 croak "Error: ${ClassName}->SetXYZ: A reference to unsupported value format specified..."; 313 } 314 315 my($X, $Y, $Z); 316 if (_IsVector($FirstValue)) { 317 # SetXYZ using vector... 318 if ($FirstValue->GetSize() != 3) { 319 croak "Error: ${ClassName}->SetXYZ: Input object must be a 3D vector..."; 320 } 321 ($X, $Y, $Z) = @{$FirstValue->{Values}}; 322 } 323 elsif ($TypeOfFirstValue =~ /^ARRAY/) { 324 # SetXYZ using array reference... 325 if (@{$FirstValue} != 3) { 326 croak "Error: ${ClassName}->SetXYZ: Input array reference must correspond to an array with three values..."; 327 } 328 ($X, $Y, $Z) = @{$FirstValue}; 329 } 330 else { 331 # It's a list of values... 332 if (@Values != 3) { 333 croak "Error: ${ClassName}->SetXYZ: Input array must contain three values..."; 334 } 335 ($X, $Y, $Z) = @Values; 336 } 337 $This->{Values}[0] = $X; 338 $This->{Values}[1] = $Y; 339 $This->{Values}[2] = $Z; 340 341 return $This; 342 } 343 344 # Get XYZ as an array or a reference to an array... 345 # 346 sub GetXYZ { 347 my($This) = @_; 348 349 if ($This->GetSize() != 3) { 350 croak "Error: ${ClassName}->GetXYZ: Object must be a 3D vector..."; 351 } 352 return wantarray ? @{$This->{Values}} : \@{$This->{Values}}; 353 } 354 355 # Get a specific value from vector with indicies starting from 0.. 356 sub GetValue { 357 my($This, $Index) = @_; 358 359 if ($Index < 0) { 360 croak "Error: ${ClassName}->GetValue: Index value must be a positive number..."; 361 } 362 if ($Index >= $This->GetSize()) { 363 croak "Error: ${ClassName}->GetValue: Index vaue must be less than size of vector..."; 364 } 365 return $This->_GetValue($Index); 366 } 367 368 # Get a vector value... 369 sub _GetValue { 370 my($This, $Index) = @_; 371 372 return $This->{Values}[$Index]; 373 } 374 375 # Set a specific value in vector with indicies starting from 0.. 376 sub SetValue { 377 my($This, $Index, $Value) = @_; 378 379 if ($Index < 0) { 380 croak "Error: ${ClassName}->SetValue: Index value must be a positive number..."; 381 } 382 if ($Index >= $This->GetSize()) { 383 croak "Error: ${ClassName}->SetValue: Index vaue must be less than size of vector..."; 384 } 385 return $This->_SetValue($Index, $Value); 386 } 387 388 # Set a vector value... 389 sub _SetValue { 390 my($This, $Index, $Value) = @_; 391 392 $This->{Values}[$Index] = $Value; 393 394 return $This; 395 } 396 397 # Return vector values as an array or reference to an array... 398 sub GetValues { 399 my($This) = @_; 400 401 return wantarray ? @{$This->{Values}} : \@{$This->{Values}}; 402 } 403 404 # Set value print format for an individual object or the whole class... 405 sub SetValuePrintFormat ($;$) { 406 my($FirstParameter, $SecondParameter) = @_; 407 408 if ((@_ == 2) && (_IsVector($FirstParameter))) { 409 # Set value print format for the specific object... 410 my($This, $ValuePrintFormat) = ($FirstParameter, $SecondParameter); 411 412 $This->{ValueFormat} = $ValuePrintFormat; 413 } 414 else { 415 # Set value print format for the class... 416 my($ValuePrintFormat) = ($FirstParameter); 417 418 $ValueFormat = $ValuePrintFormat; 419 } 420 } 421 422 # Zero vector of specified size or size 3... 423 sub ZeroVector (;$) { 424 my($Size) = @_; 425 my($Vector, @Values); 426 427 $Size = (defined $Size) ? $Size : 3; 428 @Values = ('0') x $Size; 429 430 $Vector = new Vector(\@Values); 431 return $Vector; 432 } 433 434 # Unit vector of specified size or size 3... 435 sub UnitVector (;$) { 436 my($Size) = @_; 437 my($Vector, @Values); 438 439 $Size = (defined $Size) ? $Size : 3; 440 @Values = ('1') x $Size; 441 442 $Vector = new Vector(\@Values); 443 return $Vector; 444 } 445 446 # Unit X vector of size 3... 447 sub UnitXVector () { 448 my($Vector); 449 450 $Vector = new Vector(1, 0, 0); 451 return $Vector; 452 } 453 454 # Unit Y vector of size 3... 455 sub UnitYVector () { 456 my($Vector); 457 458 $Vector = new Vector(0, 1, 0); 459 return $Vector; 460 } 461 462 # Unit Z vector of size 3... 463 sub UnitZVector () { 464 my($Vector); 465 466 $Vector = new Vector(0, 0, 1); 467 return $Vector; 468 } 469 470 # 471 # Vector addition operator supports two addition modes: 472 # . Addition of two vectors by adding corresponding vector values 473 # . Addition of a scalar value to vector values ($Vector + 1) 474 # 475 # Caveats: 476 # . Addition of a vector to scalar is not allowed (1 + $Vector) 477 # 478 sub _VectorAdditionOperator { 479 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg); 480 481 $ErrorMsg = "_VectorAdditionOperator: Vector addition failed"; 482 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_); 483 484 # Do the addition. Order can be ignored: It's a commumative operation. 485 my($Vector, $ThisSize, $Index); 486 $Vector = $This->Copy(); 487 $ThisSize = $This->GetSize(); 488 489 if ($OtherIsVector) { 490 # $OrderFlipped is set to false for two vectors... 491 for $Index (0 .. ($ThisSize -1)) { 492 $Vector->{Values}[$Index] += $Other->{Values}[$Index]; 493 } 494 } 495 else { 496 if ($OrderFlipped) { 497 croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector..."; 498 } 499 # Scalar addition... 500 for $Index (0 .. ($ThisSize -1)) { 501 $Vector->{Values}[$Index] += $Other; 502 } 503 } 504 return $Vector; 505 } 506 507 # 508 # Vector subtraction operator supports two subtraction modes: 509 # . Subtraction of two vectors by subtracting corresponding vector values 510 # . Subtraction of a scalar value from vector values ($Vector - 1) 511 # 512 # Caveats: 513 # . Subtraction of a vector from scalar is not allowed (1 - $Vector) 514 # 515 sub _VectorSubtractionOperator { 516 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg); 517 518 $ErrorMsg = "_VectorSubtractionOperator: Vector subtracttion failed"; 519 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_); 520 521 # Do the subtraction... 522 my($Vector, $ThisSize, $Index); 523 $Vector = $This->Copy(); 524 $ThisSize = $This->GetSize(); 525 526 if ($OtherIsVector) { 527 # $OrderFlipped is set to false for two vectors... 528 for $Index (0 .. ($ThisSize -1)) { 529 $Vector->{Values}[$Index] -= $Other->{Values}[$Index]; 530 } 531 } 532 else { 533 # Scalar subtraction... 534 if ($OrderFlipped) { 535 croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector..."; 536 } 537 for $Index (0 .. ($ThisSize -1)) { 538 $Vector->{Values}[$Index] -= $Other; 539 } 540 } 541 return $Vector; 542 } 543 544 # 545 # Vector multiplication operator supports two multiplication modes: 546 # . Multiplication of two vectors by multiplying corresponding vector values 547 # . Multiplying vector values by a scalar ($Vector * 1) 548 # 549 # Caveats: 550 # . Multiplication of a scalar by a vector is not allowed (1 * $Vector) 551 # 552 sub _VectorMultiplicationOperator { 553 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg); 554 555 $ErrorMsg = "_VectorMultiplicationOperator: Vector addition failed"; 556 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_); 557 558 # Do the multiplication... 559 my($Vector, $ThisSize, $Index); 560 $Vector = $This->Copy(); 561 $ThisSize = $This->GetSize(); 562 563 if ($OtherIsVector) { 564 # $OrderFlipped is set to false for two vectors... 565 for $Index (0 .. ($ThisSize -1)) { 566 $Vector->{Values}[$Index] *= $Other->{Values}[$Index]; 567 } 568 } 569 else { 570 if ($OrderFlipped) { 571 croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector..."; 572 } 573 # Scalar multiplication... 574 for $Index (0 .. ($ThisSize -1)) { 575 $Vector->{Values}[$Index] *= $Other; 576 } 577 } 578 return $Vector; 579 } 580 581 # 582 # Vector division operator supports two division modes: 583 # . Division of two vectors by dividing corresponding vector values 584 # . Dividing vector values by a scalar ($Vector / 2) 585 # 586 # Caveats: 587 # . Division of a scalar by a vector is not allowed (1 / $Vector) 588 # 589 sub _VectorDivisionOperator { 590 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg); 591 592 $ErrorMsg = "_VectorDivisionOperator: Vector division failed"; 593 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_); 594 595 # Do the division... 596 my($Vector, $ThisSize, $Index); 597 $Vector = $This->Copy(); 598 $ThisSize = $This->GetSize(); 599 600 if ($OtherIsVector) { 601 # $OrderFlipped is set to false for two vectors... 602 for $Index (0 .. ($ThisSize -1)) { 603 $Vector->{Values}[$Index] /= $Other->{Values}[$Index]; 604 } 605 } 606 else { 607 if ($OrderFlipped) { 608 croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector..."; 609 } 610 # Scalar divison... 611 for $Index (0 .. ($ThisSize -1)) { 612 $Vector->{Values}[$Index] /= $Other; 613 } 614 } 615 return $Vector; 616 } 617 618 # 619 # Vector exponentiation operator supports two exponentiation modes: 620 # . Exponent of two vectors by exponentiation of corresponding vector values 621 # . Exponentiation of vector values by a scalar ($Vector ** 2) 622 # 623 # Caveats: 624 # . Exponent of scalar by a vector is not allowed (2 ** $Vector) 625 # 626 sub _VectorExponentiationOperator { 627 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg); 628 629 $ErrorMsg = "_VectorExponentiationOperator: Vector exponentiation failed"; 630 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_); 631 632 # Do the exponentiation... 633 my($Vector, $ThisSize, $Index); 634 $Vector = $This->Copy(); 635 $ThisSize = $This->GetSize(); 636 637 if ($OtherIsVector) { 638 # $OrderFlipped is set to false for two vectors... 639 for $Index (0 .. ($ThisSize -1)) { 640 $Vector->{Values}[$Index] **= $Other->{Values}[$Index]; 641 } 642 } 643 else { 644 if ($OrderFlipped) { 645 croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector..."; 646 } 647 # Scalar exponentiation... 648 for $Index (0 .. ($ThisSize -1)) { 649 $Vector->{Values}[$Index] **= $Other; 650 } 651 } 652 return $Vector; 653 } 654 655 # 656 # Vector modulus operator supports two modulus modes: 657 # . Modulus of two vectors by taking modulus between corresponding vector values 658 # . Modulus of vector values by a scalar ($Vector % 2) 659 # 660 # Caveats: 661 # . Modulus of scalar by a vector is not allowed (2 % $Vector) 662 # 663 sub _VectorModulusOperator { 664 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg); 665 666 $ErrorMsg = "_VectorModulusOperator: Vector exponentiation failed"; 667 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_); 668 669 # Take the modulus... 670 my($Vector, $ThisSize, $Index); 671 $Vector = $This->Copy(); 672 $ThisSize = $This->GetSize(); 673 674 if ($OtherIsVector) { 675 # $OrderFlipped is set to false for two vectors... 676 for $Index (0 .. ($ThisSize -1)) { 677 $Vector->{Values}[$Index] %= $Other->{Values}[$Index]; 678 } 679 } 680 else { 681 if ($OrderFlipped) { 682 croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector..."; 683 } 684 # Scalar modulus... 685 for $Index (0 .. ($ThisSize -1)) { 686 $Vector->{Values}[$Index] %= $Other; 687 } 688 } 689 return $Vector; 690 } 691 692 # 693 # Vector dot product operator supports two modes: 694 # . Dot product of two 3D vectors 695 # . Concatenation of a vector and a scalar 696 # 697 sub _VectorDotProductOperator { 698 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg); 699 700 $ErrorMsg = "_VectorDotProductOperator: Vector dot product failed"; 701 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_); 702 703 if ($OtherIsVector) { 704 # Calculate dot product of two 3D vectors... 705 my($DotProduct); 706 if ($This->GetSize() != 3) { 707 croak "Error: ${ClassName}->${ErrorMsg}: Both vectors must be 3D vectors..."; 708 } 709 $DotProduct = $This->GetX() * $Other->GetX + $This->GetY() * $Other->GetY() + $This->GetZ * $Other->GetZ(); 710 return $DotProduct; 711 } 712 else { 713 # Do a string concatenation and return the string... 714 if ($OrderFlipped) { 715 return $Other . $This->StringifyVector(); 716 } 717 else { 718 return $This->StringifyVector() . $Other; 719 } 720 } 721 } 722 723 # 724 # Vector cross product operator genrates a new vector which is the cross 725 # product of two 3D vectors. 726 # 727 # For two vectors, V1 (X1, Y1, Z1) and V2 (X2, Y2, Z2), cross product 728 # V1 x V2 corresponds: (Y1.Z2 - Z1.Y2), (Z1.X2 - X1.Z2), (X1.Y2 - Y1.X2) 729 # 730 sub _VectorCrossProductOperator { 731 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg); 732 733 $ErrorMsg = "_VectorCrossProductOperator: Vector cross product failed"; 734 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_); 735 736 if (!$OtherIsVector) { 737 croak "Error: ${ClassName}->${ErrorMsg}: Both object must be vectors..."; 738 } 739 740 # Calculate cross product of two 3D vectors... 741 if ($This->GetSize() != 3) { 742 croak "Error: ${ClassName}->${ErrorMsg}: Both vectors must be 3D vectors..."; 743 } 744 my($Vector, $X, $Y, $Z); 745 $X = $This->GetY() * $Other->GetZ() - $This->GetZ() * $Other->GetY(); 746 $Y = $This->GetZ() * $Other->GetX() - $This->GetX() * $Other->GetZ(); 747 $Z = $This->GetX() * $Other->GetY() - $This->GetY() * $Other->GetX(); 748 749 $Vector = (ref $This)->new($X, $Y, $Z); 750 751 return $Vector; 752 } 753 754 # 755 # Vector equal operator supports two modes: 756 # . Comparion of corresponding values in two vectors 757 # . Comparing vectors values to a scalar ($Vector == 2) 758 # 759 # Caveats: 760 # . Comparison of a scalar to vector values is not allowed (2 == $Vector2) 761 # 762 sub _VectorEqualOperator { 763 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg, $CheckVectorSizes); 764 765 $ErrorMsg = "_VectorEqualOperator: Vector equal comparison failed"; 766 $CheckVectorSizes = 0; 767 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_, $CheckVectorSizes); 768 769 # Do the comparison... 770 my($ThisSize, $Index); 771 $ThisSize = $This->GetSize(); 772 773 if ($OtherIsVector) { 774 # $OrderFlipped is set to false for two vectors... 775 my($OtherSize) = $Other->GetSize(); 776 if ($ThisSize != $OtherSize) { 777 return 0; 778 } 779 for $Index (0 .. ($ThisSize -1)) { 780 if ($This->{Values}[$Index] != $Other->{Values}[$Index]) { 781 return 0; 782 } 783 } 784 } 785 else { 786 if ($OrderFlipped) { 787 croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector..."; 788 } 789 # Scalar comparison... 790 for $Index (0 .. ($ThisSize -1)) { 791 if ($This->{Values}[$Index] != $Other) { 792 return 0; 793 } 794 } 795 } 796 return 1; 797 } 798 799 # 800 # Vector not equal operator supports two modes: 801 # . Comparion of corresponding values in two vectors 802 # . Comparing vectors values to a scalar ($Vector != 2) 803 # 804 # Caveats: 805 # . Comparison of a scalar to vector values is not allowed (2 != $Vector2) 806 # 807 sub _VectorNotEqualOperator { 808 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg, $CheckVectorSizes); 809 810 $ErrorMsg = "_VectorNotEqualOperator: Vector not equal comparison failed"; 811 $CheckVectorSizes = 0; 812 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_, $CheckVectorSizes); 813 814 # Do the comparison... 815 my($ThisSize, $Index); 816 $ThisSize = $This->GetSize(); 817 818 if ($OtherIsVector) { 819 # $OrderFlipped is set to false for two vectors... 820 my($OtherSize) = $Other->GetSize(); 821 if ($ThisSize != $OtherSize) { 822 return 1; 823 } 824 for $Index (0 .. ($ThisSize -1)) { 825 if ($This->{Values}[$Index] == $Other->{Values}[$Index]) { 826 return 0; 827 } 828 } 829 } 830 else { 831 if ($OrderFlipped) { 832 croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector..."; 833 } 834 # Scalar comparison... 835 for $Index (0 .. ($ThisSize -1)) { 836 if ($This->{Values}[$Index] == $Other) { 837 return 0; 838 } 839 } 840 } 841 return 1; 842 } 843 844 # 845 # Vector less than operator supports two modes: 846 # . Comparion of corresponding values in two vectors 847 # . Comparing vectors values to a scalar ($Vector < 2) 848 # 849 # Caveats: 850 # . Comparison of a scalar to vector values is not allowed (2 < $Vector2) 851 # 852 sub _VectorLessThanOperator { 853 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg); 854 855 $ErrorMsg = "_VectorLessThanOperator: Vector less than comparison failed"; 856 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_); 857 858 # Do the comparison... 859 my($ThisSize, $Index); 860 $ThisSize = $This->GetSize(); 861 862 if ($OtherIsVector) { 863 # $OrderFlipped is set to false for two vectors... 864 for $Index (0 .. ($ThisSize -1)) { 865 if ($This->{Values}[$Index] >= $Other->{Values}[$Index]) { 866 return 0; 867 } 868 } 869 } 870 else { 871 if ($OrderFlipped) { 872 croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector..."; 873 } 874 # Scalar comparison... 875 for $Index (0 .. ($ThisSize -1)) { 876 if ($This->{Values}[$Index] >= $Other) { 877 return 0; 878 } 879 } 880 } 881 return 1; 882 } 883 884 # 885 # Vector less than equla operator supports two modes: 886 # . Comparion of corresponding values in two vectors 887 # . Comparing vectors values to a scalar ($Vector <= 2) 888 # 889 # Caveats: 890 # . Comparison of a scalar to vector values is not allowed (2 <= $Vector2) 891 # 892 sub _VectorLessThanEqualOperator { 893 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg); 894 895 $ErrorMsg = "_VectorLessThanEqualOperator: Vector less than equal comparison failed"; 896 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_); 897 898 # Do the comparison... 899 my($ThisSize, $Index); 900 $ThisSize = $This->GetSize(); 901 902 if ($OtherIsVector) { 903 # $OrderFlipped is set to false for two vectors... 904 for $Index (0 .. ($ThisSize -1)) { 905 if ($This->{Values}[$Index] > $Other->{Values}[$Index]) { 906 return 0; 907 } 908 } 909 } 910 else { 911 if ($OrderFlipped) { 912 croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector..."; 913 } 914 # Scalar comparison... 915 for $Index (0 .. ($ThisSize -1)) { 916 if ($This->{Values}[$Index] > $Other) { 917 return 0; 918 } 919 } 920 } 921 return 1; 922 } 923 924 # 925 # Vector greatar than operator supports two modes: 926 # . Comparion of corresponding values in two vectors 927 # . Comparing vectors values to a scalar ($Vector > 2) 928 # 929 # Caveats: 930 # . Comparison of a scalar to vector values is not allowed (2 > $Vector2) 931 # 932 sub _VectorGreatarThanOperator { 933 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg); 934 935 $ErrorMsg = "_VectorGreatarThanOperator: Vector greatar than comparison failed"; 936 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_); 937 938 # Do the comparison... 939 my($ThisSize, $Index); 940 $ThisSize = $This->GetSize(); 941 942 if ($OtherIsVector) { 943 # $OrderFlipped is set to false for two vectors... 944 for $Index (0 .. ($ThisSize -1)) { 945 if ($This->{Values}[$Index] <= $Other->{Values}[$Index]) { 946 return 0; 947 } 948 } 949 } 950 else { 951 if ($OrderFlipped) { 952 croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector..."; 953 } 954 # Scalar comparison... 955 for $Index (0 .. ($ThisSize -1)) { 956 if ($This->{Values}[$Index] <= $Other) { 957 return 0; 958 } 959 } 960 } 961 return 1; 962 } 963 964 # 965 # Vector greatar than equal operator supports two modes: 966 # . Comparion of corresponding values in two vectors 967 # . Comparing vectors values to a scalar ($Vector >= 2) 968 # 969 # Caveats: 970 # . Comparison of a scalar to vector values is not allowed (2 <= $Vector2) 971 # 972 sub _VectorGreatarThanEqualOperator { 973 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg); 974 975 $ErrorMsg = "_VectorGreatarThanEqualOperator: Vector greatar than equal comparison failed"; 976 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_); 977 978 # Do the comparison... 979 my($ThisSize, $Index); 980 $ThisSize = $This->GetSize(); 981 982 if ($OtherIsVector) { 983 # $OrderFlipped is set to false for two vectors... 984 for $Index (0 .. ($ThisSize -1)) { 985 if ($This->{Values}[$Index] < $Other->{Values}[$Index]) { 986 return 0; 987 } 988 } 989 } 990 else { 991 if ($OrderFlipped) { 992 croak "Error: ${ClassName}->${ErrorMsg}: First object must be a vector..."; 993 } 994 # Scalar comparison... 995 for $Index (0 .. ($ThisSize -1)) { 996 if ($This->{Values}[$Index] < $Other) { 997 return 0; 998 } 999 } 1000 } 1001 return 1; 1002 } 1003 1004 # 1005 # Vector negative value operator returns a vector with values corresponding to 1006 # negative values of a vector 1007 # 1008 sub _VectorNegativeValueOperator { 1009 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg); 1010 1011 $ErrorMsg = "_VectorNegativeValueOperator: Vector negative value operation failed"; 1012 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_); 1013 1014 # Take the negative value... 1015 my($Vector, $ThisSize, $Index); 1016 $Vector = $This->Copy(); 1017 $ThisSize = $This->GetSize(); 1018 1019 for $Index (0 .. ($ThisSize -1)) { 1020 $Vector->{Values}[$Index] = - $This->{Values}[$Index]; 1021 } 1022 return $Vector; 1023 } 1024 # 1025 # Vector absolute value operator returns a vector with values corresponding to 1026 # absolute values of a vector 1027 # 1028 sub _VectorAbsoluteValueOperator { 1029 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg); 1030 1031 $ErrorMsg = "_VectorAbsoluteValueOperator: Vector absolute value operation failed"; 1032 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_); 1033 1034 # Take the absolute value... 1035 my($Vector, $ThisSize, $Index); 1036 $Vector = $This->Copy(); 1037 $ThisSize = $This->GetSize(); 1038 1039 for $Index (0 .. ($ThisSize -1)) { 1040 $Vector->{Values}[$Index] = abs $This->{Values}[$Index]; 1041 } 1042 return $Vector; 1043 } 1044 1045 # 1046 # Vector exp natural base operator returns a vector with values corresponding to 1047 # e raised to the power of values in a vector 1048 # 1049 sub _VectorExpNaturalBaseOperator { 1050 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg); 1051 1052 $ErrorMsg = "_VectorExpNaturalBaseOperator: Vector exp operation failed"; 1053 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_); 1054 1055 # Take the absolute value... 1056 my($Vector, $ThisSize, $Index); 1057 $Vector = $This->Copy(); 1058 $ThisSize = $This->GetSize(); 1059 1060 for $Index (0 .. ($ThisSize -1)) { 1061 $Vector->{Values}[$Index] = exp $This->{Values}[$Index]; 1062 } 1063 return $Vector; 1064 } 1065 1066 # 1067 # Vector log natural base operator returns a vector with values corresponding to 1068 # log of values in a vector 1069 # 1070 sub _VectorLogNaturalBaseOperator { 1071 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg); 1072 1073 $ErrorMsg = "_VectorLogNaturalBaseOperator: Vector log operation failed"; 1074 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_); 1075 1076 # Take the absolute value... 1077 my($Vector, $ThisSize, $Index); 1078 $Vector = $This->Copy(); 1079 $ThisSize = $This->GetSize(); 1080 1081 for $Index (0 .. ($ThisSize -1)) { 1082 $Vector->{Values}[$Index] = log $This->{Values}[$Index]; 1083 } 1084 return $Vector; 1085 } 1086 1087 # 1088 # Vector cosine operator returns a vector with values corresponding to cosine of values 1089 # in a vector. Input vector values are assumed to be in radians. 1090 # 1091 sub _VectorCosineOperator { 1092 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg); 1093 1094 $ErrorMsg = "_VectorCosineOperator: Vector cos operation failed"; 1095 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_); 1096 1097 # Take the absolute value... 1098 my($Vector, $ThisSize, $Index); 1099 $Vector = $This->Copy(); 1100 $ThisSize = $This->GetSize(); 1101 1102 for $Index (0 .. ($ThisSize -1)) { 1103 $Vector->{Values}[$Index] = cos $This->{Values}[$Index]; 1104 } 1105 return $Vector; 1106 } 1107 1108 # 1109 # Vector sine operator returns a vector with values corresponding to sine of values 1110 # in a vector. Input vector values are assumed to be in radians. 1111 # 1112 sub _VectorSineOperator { 1113 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg); 1114 1115 $ErrorMsg = "_VectorSineOperator: Vector sin operation failed"; 1116 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_); 1117 1118 # Take the absolute value... 1119 my($Vector, $ThisSize, $Index); 1120 $Vector = $This->Copy(); 1121 $ThisSize = $This->GetSize(); 1122 1123 for $Index (0 .. ($ThisSize -1)) { 1124 $Vector->{Values}[$Index] = sin $This->{Values}[$Index]; 1125 } 1126 return $Vector; 1127 } 1128 1129 # 1130 # Vector square root returns a vector with values corresponding to sqrt of values 1131 # in a vector. 1132 # 1133 sub _VectorSquareRootOperator { 1134 my($This, $Other, $OrderFlipped, $OtherIsVector, $ErrorMsg); 1135 1136 $ErrorMsg = "_VectorSquareRootOperator: Vector sqrt operation failed"; 1137 ($This, $Other, $OrderFlipped, $OtherIsVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_); 1138 1139 # Take the absolute value... 1140 my($Vector, $ThisSize, $Index); 1141 $Vector = $This->Copy(); 1142 $ThisSize = $This->GetSize(); 1143 1144 for $Index (0 .. ($ThisSize -1)) { 1145 $Vector->{Values}[$Index] = sqrt $This->{Values}[$Index]; 1146 } 1147 return $Vector; 1148 } 1149 1150 # Turn vector into array for @{$Vector} operation... 1151 sub _VectorToArrayOperator { 1152 my($This) = @_; 1153 1154 return \@{$This->{Values}}; 1155 } 1156 1157 # Turn vector into number for $#Vector operation: It's the size of vector... 1158 sub _NumifyVector { 1159 my($This) = @_; 1160 1161 return $This->GetSize(); 1162 } 1163 1164 # Always return true in boolean context... 1165 sub _BoolifyVector { 1166 my($This) = @_; 1167 1168 return 1; 1169 } 1170 1171 # Process parameters passed to overloaded operators... 1172 # 1173 # For uninary operators, $SecondParameter is not defined. 1174 sub _ProcessOverloadedOperatorParameters { 1175 my($ErrorMsg, $FirstParameter, $SecondParameter, $ParametersOrderStatus, $CheckVectorSizesStatus) = @_; 1176 my($This, $Other, $OrderFlipped<