Perl-Sensitive Sunglasses PerlMonks

### Comment on

 Need Help??
#
```#
# 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';

"="  => \&assign,
"-=" => \&subtract_assign,
"-"  => \&subtract,
"x"  => \&cross_product,
"."  => \&dot_product,
"*"  => \&multiply_scalar,
"/"  => \&divide_scalar,
"*=" => \&multiply_scalar_assign,
"/=" => \&divide_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;
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;
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;
}

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 non-zero') && 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 non-zero') && 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__

Math::Vector - Object oriented vectors

use Math::Vector;
my \$vector = new Math::Vector (i => \$i, j => \$j, k => \$k);

C<Math::Vector> provides an object oriented approach to working with v
+ectors.

Vectors created with this module are three-dimentional, although
two-dimentional 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

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;

=over 4

=item new Math::Vector (i => \$i, j => \$j, k => \$k)

Creates a new vector object with components (\$i, \$j, \$k).

=back

=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

=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

=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

Math::Trig,
Carp

Please email the author (E<lt>mark@sporkstorms.orgE<gt>) with any.

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.

Mark Stratman, E<lt>mark@sporkstorms.orgE<gt>

This modules is free software. It may be used, redistributed and/or
modified under the same terms as Perl itself.

=cut
#

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

• Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
• Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
• Read Where should I post X? if you're not absolutely sure you're posting in the right place.
• Posts may use any of the Perl Monks Approved HTML tags:
a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
• You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
 For: Use: & & < < > > [ [ ] ]
• Link using PerlMonks shortcuts! What shortcuts can I use for linking?

Create A New User
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (5)
As of 2017-08-19 21:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
Who is your favorite scientist and why?

Results (312 votes). Check out past polls.

Notices?