MayaChemTools

   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<