Vector2

Manipulate 2D vectors

PhilipRBrenan@yahoo.com, 2004, Perl License

Synopsis

Example t/vector2.t

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

use Math::Zap::Vector2 vector2=>v, units=>u;
use Test::Simple tests=>7;

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

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

Description

Manipulate 2D vectors

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

Constructors

new

Create a vector from numbers

sub new($$)
 {return bless {x=>$_[0], y=>$_[1]} unless debug;
  my ($x, $y) = @_; 
  round(bless({x=>$x, y=>$y})); 
 }

vector2

Create a vector from numbers - synonym for "new"

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

units

Unit vectors

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

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

Methods

check

Check its a vector

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

is

Test its a vector

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

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

components

x,y components of vector

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

clone

Create a vector from another vector

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

length

Length of a vector

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

print

Print vector

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

  "vector2($x, $y)";
 } 

normalize

Normalize vector

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

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

  new($v->x / $l, $v->y / $l);
 }

rightAngle

At right angles

sub rightAngle($)
 {my ($v) = check(@_); # Vectors
  new(-$v->y, $v->x);
 } 

dot

Dot product

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

angle

Angle between two vectors

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

add

Add vectors

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

subtract

Subtract vectors

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

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);
 }

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);
 }

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

Operators

# 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
 '<'        => \&angle3,    # Angle in radians between two vectors
 '>'        => \&angle3,    # Angle in radians between two vectors
 '=='       => \&equals3,   # Equals
 '""'       => \&print3,    # Print
 '!'        => \&length,    # Length
 'fallback' => FALSE;

add

Add operator.

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

subtract

Subtract operator.

sub subtract3
 {#my ($a, $b, $c) = @_;
  #return $a->subtract($b) if ref($b);
  return new($_[0]->{x}-$_[1]->{x}, $_[0]->{y}-$_[1]->{y}) if ref($_[1]);
  new(-$_[0]->{x}, -$_[0]->{y});
 }

multiply

Multiply operator.

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

divide

Divide operator.

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

angle

Angle between two vectors.

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

equals

Equals operator.

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

print

Print a vector.

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

Exports

Export "vector2", "units", "check", "is"

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

#_ Vector2 ____________________________________________________________
# Package loaded successfully
#______________________________________________________________________

1;

Credits

Author

philiprbrenan@yahoo.com

philiprbrenan@yahoo.com, 2004

License

Perl License.