- Vector

- Synopsis
- Description

- Constructors

- new
- units

- Methods

- check
- is
- accuracy
- round
- x,y,z
- clone
- length
- print
- norm
- dot
- angle
- cross
- add
- subtract
- multiply
- divide
- equals
- Operator Overloads
- Add operator
- Subtract Operator
- Multiply Operator
- Divide Operator
- Cross Operator
- Angle Operator
- Equals Operator
- Print Operator

- Export Definitions
- Credits

- Author
- Copyright
- License

# Vector

Manipulate 3D vectors

PhilipRBrenan@yahoo.com, 2004, Perl licence

## Synopsis

Example t/vector.t

     #_ Vector _____________________________________________________________
     # Test 3d vectors
     # philiprbrenan@yahoo.com, 2004, Perl License
     #______________________________________________________________________

     use Math::Zap::Vector vector=>'v', units=>'u';
     use Test::Simple tests=>7;

     my ($x, $y, $z) = u();

     ok(!$x                            == 1);
     ok(2*$x+3*$y+4*$z                 == v( 2,  3,   4));
     ok(-$x-$y-$z                      == v(-1, -1,  -1));
     ok((2*$x+3*$y+4*$z) + (-$x-$y-$z) == v( 1,  2,   3));
     ok((2*$x+3*$y+4*$z) * (-$x-$y-$z) == -9);
     ok($x*2                           == v( 2,  0,   0));
     ok($y/2                           == v( 0,  0.5, 0));

## Description

Manipulate 3 dimensional vectors via operators.

     package Math::Zap::Vector;
     $VERSION=1.03;
     use Math::Trig;
     use Carp;
     use constant debug => 0; # Debugging level

### Constructors

#### new

Create a vector from numbers

     sub new($$$)
      {return round(bless({x=>$_[0], y=>$_[1], z=>$_[2]})) if debug;
       bless {x=>$_[0], y=>$_[1], z=>$_[2]};
      }

     sub vector($$$) {new($_[0], $_[1], $_[2])}

#### units

Unit vectors

     sub units() {($x, $y, $z)}

### Methods

#### check

Check its a vector

     sub check(@)
      {if (debug)
        {for my $v(@_)
          {confess "$v is not a vector" unless ref($v) eq __PACKAGE__;
          }
        }
       return (@_)
      }

#### is

Test its a vector

     sub is(@)
      {for my $v(@_)
        {return 0 unless ref($v) eq __PACKAGE__;
        }
       'vector';
      }

#### accuracy

Get/Set accuracy for comparisons

     my $accuracy = 1e-10;

     sub accuracy
      {return $accuracy unless scalar(@_);
       $accuracy = shift();
      }

#### round

Round: round to nearest integer if within accuracy of that integer

     sub round($)
      {unless (debug)
        {return $_[0];
        }
       else
        {my ($a) = @_;
         for my $k(keys(%$a))
          {my $n = $a->{$k};
           my $N = int($n);
           $a->{$k} = $N if abs($n-$N) < $accuracy;
          }
         return $a;
        }
      }

#### x,y,z

x,y,z components of vector

     sub x($) {check(@_) if debug; $_[0]->{x}}
     sub y($) {check(@_) if debug; $_[0]->{y}}
     sub z($) {check(@_) if debug; $_[0]->{z}}

     $x = new(1,0,0);
     $y = new(0,1,0);
     $z = new(0,0,1);

#### clone

Create a vector from another vector

     sub clone($)
      {my ($v) = check(@_); # Vectors
       round bless {x=>$v->x, y=>$v->y, z=>$v->z};
      }

#### length

Length of a vector

     sub length($)
      {my ($v) = check(@_[0..0]); # Vectors
       sqrt($v->x**2+$v->y**2+$v->z**2);
      }

#### print

Print vector

     sub print($)
      {my ($v) = check(@_); # Vectors
       my ($x, $y, $z) = ($v->x, $v->y, $v->z);

       "vector($x, $y, $z)";
      }

#### norm

Normalize vector

     sub norm($)
      {my ($v) = check(@_); # Vectors
          $v = $v->clone;   # Copy vector
       my $l = $v->length;

       $l > 0 or confess "Cannot normalize zero length vector $v";

       $v->{x} /= $l;
       $v->{y} /= $l;
       $v->{z} /= $l;
       $v;
      }

#### dot

Dot product

     sub dot($$)
      {my ($a, $b) = check(@_); # Vectors
       $a->x*$b->x+$a->y*$b->y+$a->z*$b->z;
      }

#### angle

Angle between two vectors

     sub angle($$)
      {my ($a, $b) = check(@_); # Vectors
       acos($a->norm->dot($b->norm));
      }

#### cross

Cross product

     sub cross($$)
      {my ($a, $b) = check(@_); # Vectors

            new
       ((($a->y * $b->z) - ($a->z * $b->y)),
             (($a->z * $b->x) - ($a->x * $b->z)),
             (($a->x * $b->y) - ($a->y * $b->x))
       );
      }

#### add

Add vectors

     sub add($$)
      {my ($a, $b) = check(@_); # Vectors
       new($a->x+$b->x, $a->y+$b->y, $a->z+$b->z);
      }

#### subtract

Subtract vectors

     sub subtract($$)
      {check(@_) if debug; # Vectors
       new($_[0]->{x}-$_[1]->{x}, $_[0]->{y}-$_[1]->{y}, $_[0]->{z}-$_[1]->{z});
      }

#### multiply

Vector times a scalar

     sub multiply($$)
      {my ($a) = check(@_[0..0]); # Vector
       my ($b) =       @_[1..1];  # Scalar

       confess "$b is not a scalar" if ref($b);
       new($a->x*$b, $a->y*$b, $a->z*$b);
      }

#### divide

Vector divided by a non zero scalar

     sub divide($$)
      {my ($a) = check(@_[0..0]); # Vector
       my ($b) =       @_[1..1];  # Scalar

       confess "$b is not a scalar" if ref($b);
       confess "$b is zero"         if $b == 0;
       new($a->x/$b, $a->y/$b, $a->z/$b);
      }

#### equals

Equals to within accuracy

     sub equals($$)
      {my ($a, $b) = check(@_); # Vectors
       abs($a->x-$b->x) < $accuracy and
       abs($a->y-$b->y) < $accuracy and
       abs($a->z-$b->z) < $accuracy;
      }

#### Operator Overloads

Operator overloads

     use overload
      '+'        => \&add3,      # Add two vectors
      '-'        => \&subtract3, # Subtract one vector from another
      '*'        => \&multiply3, # Times by a scalar, or vector dot product
      '/'        => \&divide3,   # Divide by a scalar
      'x'        => \&cross3,    # BEWARE LOW PRIORITY! Cross product
      '<'        => \&angle3,    # Angle in radians between two vectors
      '>'        => \&angle3,    # Angle in radians between two vectors
      '=='       => \&equals3,   # Equals
      '""'       => \&print3,    # Print
      '!'        => \&length,    # Length
      'fallback' => FALSE;

#### Add operator

Add operator, see add

     sub add3
      {my ($a, $b) = @_;
       $a->add($b);
      }

#### Subtract Operator

Subtract operator.

     sub subtract3
      {return new($_[0]->{x}-$_[1]->{x}, $_[0]->{y}-$_[1]->{y}, $_[0]->{z}-$_[1]->{z}) if ref($_[1]);
       new(-$_[0]->{x}, -$_[0]->{y}, -$_[0]->{z});
      }

#### Multiply Operator

Multiply operator, see multiply

     sub multiply3
      {my ($a, $b) = @_;
       return $a->dot     ($b) if ref($b);
       return $a->multiply($b);
      }

#### Divide Operator

Divide operator, see divide

     sub divide3
      {my ($a, $b, $c) = @_;
       return $a->divide($b);
      }

#### Cross Operator

Cross operator, see cross

     sub cross3
      {my ($a, $b, $c) = @_;
       return $a->cross($b);
      }

#### Angle Operator

Angle operator, see angle

     sub angle3
      {my ($a, $b, $c) = @_;
       return $a->angle($b);
      }

#### Equals Operator

Equals operator, see equals

     sub equals3
      {my ($a, $b, $c) = @_;
       return $a->equals($b);
      }

#### Print Operator

Print a vector, see print

     sub print3
      {my ($a) = @_;
       return $a->print;
      }

## Export Definitions

Export vector, units, check, is

     use Math::Zap::Exports qw(
       vector ($$$)
       units  ()
       check  (@)
       is     (@)
      );

     #______________________________________________________________________
     # Package loaded successfully
     #______________________________________________________________________

     1;

## Credits

### Author

philiprbrenan@yahoo.com

### Copyright

philiprbrenan@yahoo.com, 2004

### License

Perl License.