##
# An object oriented module for working with vectors.
# Note that 'scalar' refers to the mathmatical definition, not Perl's
+;)
#
package Math::Vector;
use strict;
use Carp;
use Math::Trig;
use vars qw($VERSION);
$VERSION = '0.01';
use overload
"=" => \&assign,
"+=" => \&add_assign,
"=" => \&subtract_assign,
"+" => \&add,
"" => \&subtract,
"x" => \&cross_product,
"." => \&dot_product,
"*" => \&multiply_scalar,
"/" => \÷_scalar,
"*=" => \&multiply_scalar_assign,
"/=" => \÷_scalar_assign;
sub new {
my ($package, %args) = @_;
return bless {
_i => $args{i}  0,
_j => $args{j}  0,
_k => $args{k}  0,
}, $package;
}
# $v_1 = $v_2;
sub assign {
my ($self, $other) = @_;
carp ('Operation only permitted on Math::Vector objects') && retur
+n undef
unless (ref $other eq 'Math::Vector');
$self>set_i($other>i);
$self>set_j($other>j);
$self>set_k($other>k);
return $self;
}
# $v_1 += $v_2;
sub add_assign {
my ($self, $other) = @_;
carp ('Operation only permitted on Math::Vector objects') && retur
+n undef
unless (ref $other eq 'Math::Vector');
$self>set_i($other>i + $self>i);
$self>set_j($other>j + $self>j);
$self>set_k($other>k + $self>k);
return $self;
}
# $v_1 = $v_2;
sub subtract_assign {
my ($self, $other) = @_;
carp ('Operation only permitted on Math::Vector objects') && retur
+n undef
unless (ref $other eq 'Math::Vector');
$self>set_i($other>i  $self>i);
$self>set_j($other>j  $self>j);
$self>set_k($other>k  $self>k);
return $self;
}
# $v_new = $v_1 + $v_2;
# $v_new = $v_1>add($v_2);
sub add {
my ($self, $other) = @_;
carp ('Operation only permitted on Math::Vector objects') && retur
+n undef
unless (ref $other eq 'Math::Vector');
return new Math::Vector (
i => $self>i + $other>i,
j => $self>j + $other>j,
k => $self>k + $other>k,
);
}
# $v_new = $v_1  $v_2;
# $v_new = $v_1>subtract($v_2);
sub subtract {
my ($self, $other) = @_;
carp ('Operation only permitted on Math::Vector objects') && retur
+n undef
unless (ref $other eq 'Math::Vector');
return new Math::Vector (
i => $self>i  $other>i,
j => $self>j  $other>j,
k => $self>k  $other>k,
);
}
# $v *= $scalar;
sub multiply_scalar_assign {
my ($self, $scalar) = @_;
$self>set_i($self>i * $scalar);
$self>set_j($self>j * $scalar);
$self>set_k($self>k * $scalar);
return $self;
}
# $v /= $scalar;
sub divide_scalar_assign {
my ($self, $scalar) = @_;
carp ('Cannot divide by zero') && return undef unless ($scalar);
$self>set_i($self>i / $scalar);
$self>set_j($self>j / $scalar);
$self>set_k($self>k / $scalar);
return $self;
}
# $v_new = $v_1 * $scalar;
# $v_new = $v_1>multiply_scalar($scalar);
sub multiply_scalar {
my ($self, $scalar) = @_;
return new Math::Vector (
i => $self>i * $scalar,
j => $self>j * $scalar,
k => $self>k * $scalar,
);
}
# $v_new = $v_1 / $scalar;
# $v_new = $v_1>divide_scalar($scalar);
sub divide_scalar {
my ($self, $scalar) = @_;
carp ('Cannot divide by zero') && return undef unless ($scalar);
return new Math::Vector (
i => $self>i / $scalar,
j => $self>j / $scalar,
k => $self>k / $scalar,
);
}
# $v_new = $v_1 x $v_2;
# $v_new = $v_1>cross_product($v_2);
sub cross_product {
my ($self, $other) = @_;
carp ('Operation only permitted on Math::Vector objects') && retur
+n undef
unless (ref $other eq 'Math::Vector');
return new Math::Vector (
i => $self>j * $other>k  $self>k * $other>j,
j => $self>k * $other>i  $self>i * $other>k,
z => $self>i * $other>j  $self>j * $other>i,
);
}
# $dot_product = $v_1 . $v_2;
# $v_new = $v_1>dot_product($v_2);
sub dot_product {
my ($self, $other) = @_;
carp ('Operation only permitted on Math::Vector objects') && retur
+n undef
unless (ref $other eq 'Math::Vector');
return $self>i * $other>i + $self>j * $other>j + $self>k * $o
+ther>k;
}
# $magnitude = $v>magnitude();
sub magnitude {
my $self = shift;
return sqrt($self>i * $self>i + $self>j * $self>j + $self>k *
+ $self>k);
}
# Converts the vector to its normal
# $v>normalize();
sub normalize {
my $self = shift;
my $m = $self>magnitude;
carp('Cannot normalize a zero vector') && return undef unless ($m)
+;
$self>set_i( $self>i / $m );
$self>set_j( $self>j / $m );
$self>set_k( $self>k / $m );
}
# $v_normalized = $v>normal();
sub normal {
my $self = shift;
my $normal = new Math::Vector (i=>$self>i, j=>$self>j, k=>$self
+>k);
$normal>normalize();
return $normal;
}
# $angle_in_radians = $v_1>angle($v_2);
sub angle {
my ($self, $other) = @_;
carp ('Operation only permitted on Math::Vector objects') && retur
+n undef
unless (ref $other eq 'Math::Vector');
my $self_m = $self>magnitude;
my $other_m = $other>magnitude;
carp('Vectors must be nonzero') && return undef
unless ($self_m && $other_m);
return (acos (
$self>dot_product($other) / ($self_m * $other_m)
));
}
sub orthogonal {
my ($self, $other) = @_;
carp ('Operation only permitted on Math::Vector objects') && retur
+n undef
unless (ref $other eq 'Math::Vector');
carp('Vectors must be nonzero') && return undef
unless ($self>magnitude && $other>magnitude);
# v1 is perpendicular to v2 if (v1 . v2 == 0)
return ($self>dot_product($other) ? 0 : 1);
}
sub i { return $_[0]>{_i}; }
sub j { return $_[0]>{_j}; }
sub k { return $_[0]>{_k}; }
sub set_i {
my $self = shift;
$self>{_i} = shift  0;
}
sub set_j {
my $self = shift;
$self>{_j} = shift  0;
}
sub set_k {
my $self = shift;
$self>{_k} = shift  0;
}
1;
__END__
=head1 NAME
Math::Vector  Object oriented vectors
=head1 SYNOPSIS
use Math::Vector;
my $vector = new Math::Vector (i => $i, j => $j, k => $k);
=head1 DESCRIPTION
C<Math::Vector> provides an object oriented approach to working with v
+ectors.
Vectors created with this module are threedimentional, although
twodimentional vectors are effectively achieved by omitting the 'k' c
+omponent
(which simply sets it to zero).
It is important to note that this module will carp() if operations inv
+olving
division are attempted on zero values. A basic understanding of vecto
+rs is
expected, and the programmer should check the magnitude of a vector be
+fore
performing operations such as normalization or finding the angle.
=head2 Conventions used in this document
=over 10
The term 'scalar' is used in the mathmatical sense, and is a number re
+presenting
the amount by which a vector is scaled.
Vector objects will always begin with a 'v'. (Example: $v, $v_1, $v_ne
+w)
=back
=head1 OPERATORS
C<Math::Vector> objects override many default operators.
=item '='
$v_1 = $v_2;
=item '+'
$v_new = $v_1 + $v_2;
=item '+='
$v_1 += $v_2
=item ''
$v_new = $v_1  $v_2;
=item '='
$v_1 = $v_2;
=item 'x'
$v_cross_product = $v_1 x $v_2;
=item '.'
$dot_product = $v_1 . $v_2;
=item '*'
$v_new = $v_1 * $scalar_multiple
=item '*='
$v_1 *= $scalar_multiple;
=item '/'
$v_new = $v_1 / $scalar_multiple
=item '/='
$v_1 /= $scalar_multiple;
=head1 METHODS
=head2 Creation
=over 4
=item new Math::Vector (i => $i, j => $j, k => $k)
Creates a new vector object with components ($i, $j, $k).
=back
=head2 Access
=over 4
=item i
Returns the value of the 'i' (first) component of the vector.
=item j
Returns the value of the 'j' (second) component of the vector.
=item k
Returns the value of the 'k' (third) component of the vector.
=item ijk
Returns a list of the three component values. This is included for co
+nvenience, and is the same as:
($v>i, $v>j, $v>k);
=back
=head2 Direct Modifications
=over 4
=item set_i (I)
Sets the value for the 'i' component of the vector.
$v>set_i($new_i_value)
=item set_j (J)
Sets the value for the 'j' component of the vector.
$v>set_j($new_j_value)
=item set_k (K)
Sets the value for the 'k' component of the vector.
$v>set_k($new_k_value)
=back
=head2 Calculations
=over 4
=item dot_product (VECTOR)
Returns the dot product of two vectors.
$dot_product = $v_1>dot_product( $v_2 );
# Note this is equivalent:
$dot_product = $v_1 . $v_2;
=item cross_product (VECTOR)
Returns the cross product of two vectors as a vector object. Note: yo
+u cannot
take the cross product of 2d vectors.
$v_cross = $v_1>cross_product( $v_2 );
# Note this is equivalent:
$v_cross = $v_1 x $v_2;
=item magnitude
Returns the magnitude of the vector.
$magnitude = $v>magnitude;
=item normalize
Normalizes the vector.
$v>normalize;
=item normal
Returns the normal of a vector as a new vector object.
$v_normalized = $v>normal;
# Note the following is similar, but does not preserve $v :
$v>normalize; $v_normalized = $v;
=item angle (VECTOR)
Returns the angle in radians between two vectors.
$angle = $v_1>angle( $v_2 );
=item orthogonal (VECTOR)
Returns 1 if vectors are orthogonal (or perpendicular), 0 if they are
not, and undef if either is a zero vector.
$orthogonal = $v_1>orthogonal( $v_2 );
if ($orthogonal) {
# $v_1 and $v_2 are perpendicular
} elsif (defined $orthogonal) {
# they are not
} else {
# you tried to test a zero vector
}
=back
=head1 SEE ALSO
Math::Trig,
Carp
=head1 BUGS
Please email the author (E<lt>mark@sporkstorms.orgE<gt>) with any.
=head1 FEEDBACK
Feel free to email the author with any questions, comments, or request
+s.
This module was initially written for personal use, and may be lacking
some desired features. I (Mark) would be glad to add anything to it
that you might need.
=head1 AUTHOR
Mark Stratman, E<lt>mark@sporkstorms.orgE<gt>
=head1 COPYRIGHT
Copyright (c) 2001, Mark Stratman. All Rights Reserved.
This modules is free software. It may be used, redistributed and/or
modified under the same terms as Perl itself.
=cut
#
