Provided by: libmath-quaternion-perl_0.07-1_all bug

NAME

       Math::Quaternion - Perl class to represent quaternions

SYNOPSIS

        use Math::Quaternion qw(slerp);
        my $q = Math::Quaternion->new;  # Make a new unit quaternion

        # Make a rotation about the axis (0,1,0)
        my $q2 = Math::Quaternion->new({axis=>[0,1,0],angle=>0.1});
        my @v = (1,2,3); # A vector.
        my @vrotated = $q2->rotate_vector(@v); # Rotate @v about (0,1,0).

        my $q3 = Math::Quaternion::rotation(0.7,2,1,4); # A different rotation.
        my $q4 = slerp($q2,$q3,0.5);                   # Interpolated rotation.
        my @vinterp = $q4->rotate_vector(@v);

DESCRIPTION

       This package lets you create and manipulate quaternions. A quaternion is a mathematical
       object developed as a kind of generalization of complex numbers, usually represented by an
       array of four real numbers, and is often used to represent rotations in three-dimensional
       space.

       See, for example, <http://mathworld.wolfram.com/Quaternion.html> for more details on the
       mathematics of quaternions.

       Quaternions can be added, subtracted, and scaled just like complex numbers or vectors --
       they can also be multiplied, but quaternion multiplication DOES NOT COMMUTE. That is to
       say, if you have quaternions $q1 and $q2, then in general $q1*$q2 != $q2*$q1. This is
       related to their use in representing rotations, which also do not commute.

       If you just want to represent rotations and don't care about the internal mathematical
       details, this should be all you need to know:

       All quaternions have a quantity called the "norm",  similar to the length of a vector. A
       quaternion with norm equal to 1 is called a "unit quaternion". All quaternions which
       represent rotations are unit quaternions.

       If you call new() without any arguments, it will give you a unit quaternion which
       represents no rotation:

          $q = Math::Quaternion->new;

       You can make a quaternion which represents a rotation of a given angle (in radians) about
       a given axis:

          $qrot = Math::Quaternion->new({ angle => 0.1, axis => [ 2,3,4]});

       Say you have two rotations, $q1 and $q2, and you want to make a quaternion representing a
       rotation of $q1 followed by $q2. Then, you do:

         $q3 = $q2 * $q1;   # Rotate by $q1, followed by $q2.

       Remember that this is NOT the same as $q1 * $q2, which will reverse the order of the
       rotations.

       If you perform many iterated quaternion operations, the result may not quite be a unit
       quaternion due to numerical inaccuracies. You can make sure any quaternion has unit
       length, by doing:

         $unitquat = $anyquat->normalize;

       If you have a rotation quaternion, and you want to find the 3x3 matrix which represents
       the corresponding rotation, then:

         @matrix = $q->matrix3x3;

       Similarly, you can generate a 4x4 matrix of the sort you'd pass to OpenGL:

         @glmatrix = $q->matrix4x4;

       If you have a vector representing a direction, and you want to rotate the vector by a
       quaternion $q:

         my @vector = (0,0,1);  # Vector pointing in the Z direction.

         my @newvec = $q->rotate_vector(@vector); # New direction.

       Say you're using quaternions to represent the orientation of a camera, and you have two
       quaternions: one to represent a starting orientation, and another to represent a finishing
       position. If you want to find all the quaternions representing the orientations in
       between, allowing your camera to move smoothly from start to finish, use the slerp()
       routine:

         use Math::Quaternion qw(slerp);

         my ($qstart, $qend) = ... ;

         # Set $tween to 9 points between start and end, exclusive.

         for my $t (1..9) {
           my $tween = slerp($qstart,$qend,0.1*$t);
           ...
         }

METHODS

       new
         my $q = Math::Quaternion->new;          # Make a new unit quaternion.
         my $q2 = Math::Quaternion->new(1,2,3,4);# Make a specific quaternion.
         my $q3 = Math::Quaternion->new($q2);    # Copy an existing quaternion.
         my $q4 = Math::Quaternion->new(5.6);    # Make the quaternion (5.6,0,0,0)
         my $q5 = Math::Quaternion->new(7,8,9);  # Make the quaternion (0,7,8,9)

         my $q6 = Math::Quaternion->new({ # Make a quaternion corresponding
               axis => [ 1,2,3],          # to a rotation of 0.2 radians
               angle => 0.2,              # about the vector (1,2,3).
         });

         my $q7 = Math::Quaternion->new({ # Make a quaternion which would
               'v1' => [ 0,1,2],            # rotate the vector (0,1,2) onto
               'v2' => [ -1,2,0],           # the vector (-1,2,0).
         });

        If no parameters are given, a unit quaternion is returned.  If one non-reference
        parameter is given, a "scalar" quaternion is returned.  If one parameter is given and it
        is a reference to a quaternion or an array of four numbers, the corresponding quaternion
        object is returned.  If three parameters are given, a "vector" quaternion is returned.
        If four parameters are given, the corresponding quaternion is returned.

        Rotation quaternions may also be created by passing a hashref with the axis and angle of
        rotation, or by specifying two vectors specifying start and finish directions. Bear in
        mind that the latter method will take the shortest path between the two vectors, ignoring
        the "roll" angle.

       unit
        Returns a unit quaternion.

         my $u = Math::Quaternion->unit; # Returns the quaternion (1,0,0,0).

       conjugate
        Returns the conjugate of its argument.

         my $q = Math::Quaternion->new(1,2,3,4);
         my $p = $q->conjugate;              # (1,-2,-3,-4)

       inverse
        Returns the inverse of its argument.

         my $q = Math::Quaternion->new(1,2,3,4);
         my $qi = $q->inverse;

       normalize
        Returns its argument, normalized to unit norm.

          my $q = Math::Quaternion->new(1,2,3,4);
          my $qn = $q->normalize;

       modulus
        Returns the modulus of its argument, defined as the square root of the scalar obtained by
        multiplying the quaternion by its conjugate.

         my $q = Math::Quaternion->new(1,2,3,4);
         print $q->modulus;

       isreal
        Returns 1 if the given quaternion is real ,ie has no quaternion part, or else 0.

         my $q1 = Math::Quaternion->new(1,2,3,4);
         my $q2 = Math::Quaternion->new(5,0,0,0);
         print $q1->isreal; # 0;
         print $q2->isreal; # 1;

       multiply
        Performs a quaternion multiplication of its two arguments.  If one of the arguments is a
        scalar, then performs a scalar multiplication instead.

         my $q1 = Math::Quaternion->new(1,2,3,4);
         my $q2 = Math::Quaternion->new(5,6,7,8);
         my $q3 = Math::Quaternion::multiply($q1,$q2);         # (-60 12 30 24)
         my $q4 = Math::Quaternion::multiply($q1,$q1->inverse); # (1 0 0 0)

       dot
        Returns the dot product of two quaternions.

         my $q1=Math::Quaternion->new(1,2,3,4);
         my $q2=Math::Quaternion->new(2,4,5,6);
         my $q3 = Math::Quaternion::dot($q1,$q2);

       plus
        Performs a quaternion addition of its two arguments.

         my $q1 = Math::Quaternion->new(1,2,3,4);
         my $q2 = Math::Quaternion->new(5,6,7,8);
         my $q3 = Math::Quaternion::plus($q1,$q2);         # (6 8 10 12)

       minus
        Performs a quaternion subtraction of its two arguments.

         my $q1 = Math::Quaternion->new(1,2,3,4);
         my $q2 = Math::Quaternion->new(5,6,7,8);
         my $q3 = Math::Quaternion::minus($q1,$q2);         # (-4 -4 -4 -4)

       power
        Raise a quaternion to a scalar or quaternion power.

         my $q1 = Math::Quaternion->new(1,2,3,4);
         my $q2 = Math::Quaternion::power($q1,4);     # ( 668 -224 -336 -448 )
         my $q3 = $q1->power(4);                # ( 668 -224 -336 -448 )
         my $q4 = $q1**(-1);                     # Same as $q1->inverse

         use Math::Trig;
         my $q5 = exp(1)**( Math::Quaternion->new(pi,0,0) ); # approx (-1 0 0 0)

       negate
        Negates the given quaternion.

         my $q = Math::Quaternion->new(1,2,3,4);
         my $q1 = $q->negate;             # (-1,-2,-3,-4)

       squarednorm
        Returns the squared norm of its argument.

         my $q1 = Math::Quaternion->new(1,2,3,4);
         my $sn = $q1->squarednorm;             # 30

       scale
        Performs a scalar multiplication of its two arguments.

         my $q = Math::Quaternion->new(1,2,3,4);
         my $qq = Math::Quaternion::scale($q,2);   # ( 2 4 6 8)
         my $qqq= $q->scale(3);                    # ( 3 6 9 12 )

       rotation
        Generates a quaternion corresponding to a rotation.

        If given three arguments, interprets them as an angle and the three components of an axis
        vector.

         use Math::Trig;            # Define pi.  my $theta = pi/2;
         # Angle of rotation my $rotquat =
         Math::Quaternion::rotation($theta,0,0,1);

         # $rotquat now represents a rotation of 90 degrees about Z axis.

         my ($x,$y,$z) = (1,0,0);       # Unit vector in the X direction.
         my ($xx,$yy,$zz) = $rotquat->rotate_vector($x,$y,$z);

         # ($xx,$yy,$zz) is now ( 0, 1, 0), to within floating-point error.

        rotation() can also be passed a scalar angle and a reference to a vector (in either
        order), and will generate the corresponding rotation quaternion.

         my @axis = (0,0,1);    # Rotate about Z axis
         $theta = pi/2;
         $rotquat = Math::Quaternion::rotation($theta,\@axis);

        If the arguments to rotation() are both references, they are interpreted as two vectors,
        and a quaternion is returned which rotates the first vector onto the second.

         my @startvec = (0,1,0);  # Vector pointing north
         my @endvec   = (-1,0,0); # Vector pointing west
         $rotquat = Math::Quaternion::rotation(\@startvec,\@endvec);

         my @newvec = $rotquat->rotate_vector(@startvec); # Same as @endvec

       rotation_angle
        Returns the angle of rotation represented by the quaternion argument.

         my $q = Math::Quaternion::rotation(0.1,2,3,4);
         my $theta = $q->rotation_angle; # Returns 0.1 .

       rotation_axis
        Returns the unit vector representing the axis about which rotations will be performed,
        for the rotation represented by the quaternion argument.

         my $q = Math::Quaternion::rotation(0.1,1,1,0);
         my @v = $q->rotation_axis; # Returns (0.5*sqrt(2),0.5*sqrt(2),0)

       rotate_vector
        When called as a method on a rotation quaternion, uses this quaternion to perform the
        corresponding rotation on the vector argument.

         use Math::Trig;                     # Define pi.

         my $theta = pi/2;                   # Rotate 90 degrees

         my $rotquat = Math::Quaternion::rotation($theta,0,0,1); # about Z axis

         my ($x,$y,$z) = (1,0,0);       # Unit vector in the X direction.
         my ($xx,$yy,$zz) = $rotquat->rotate_vector($x,$y,$z)

         # ($xx,$yy,$zz) is now ( 0, 1, 0), to within floating-point error.

       matrix4x4
        Takes one argument: a rotation quaternion.  Returns a 16-element array, equal to the
        OpenGL matrix which represents the corresponding rotation.

         my $rotquat = Math::Quaternion::rotation($theta,@axis); # My rotation.
         my @m = $rotquat->matrix4x4;

       matrix3x3
        Takes one argument: a rotation quaternion.  Returns a 9-element array, equal to the 3x3
        matrix which represents the corresponding rotation.

         my $rotquat = Math::Quaternion::rotation($theta,@axis); # My rotation.
         my @m = $rotquat->matrix3x3;

       matrix4x4andinverse
        Similar to matrix4x4, but returnes a list of two array references.  The first is a
        reference to the rotation matrix; the second is a reference to its inverse.  This may be
        useful when rendering sprites, since you can multiply by the rotation matrix for the
        viewer position, perform some translations, and then multiply by the inverse: any
        resulting rectangles drawn will always face the viewer.

         my $rotquat = Math::Quaternion::rotation($theta,@axis); # My rotation.
         my ($matref,$invref) = $rotquat->matrix4x4andinverse;

       stringify
        Returns a string representation of the quaternion. This is used to overload the '""'
        operator, so that quaternions may be freely interpolated in strings.

         my $q = Math::Quaternion->new(1,2,3,4);
         print $q->stringify;                # "( 1 2 3 4 )"
         print "$q";                         # "( 1 2 3 4 )"

       slerp
        Takes two quaternion arguments and one scalar; performs spherical linear interpolation
        between the two quaternions. The quaternion arguments are assumed to be unit quaternions,
        and the scalar is assumed to lie between 0 and 1: a scalar argument of zero will return
        the first quaternion argument, and a scalar argument of one will return the second.

         use Math::Trig;
         my @axis = (0,0,1);
         my $rq1 = Math::Quaternion::rotation(pi/2,\@axis);   # 90  degs about Z
         my $rq2 = Math::Quaternion::rotation(pi,\@axis);     # 180 degs about Z

         my $interp = Math::Quaternion::slerp($rq1,$rq2,0.5); # 135 degs about Z

       exp
        Exponential operator e^q. Any quaternion q can be written as x+uy, where x is a real
        number, and u is a unit pure quaternion.  Then, exp(q) == exp(x) * ( cos(y) + u sin(y) ).

         my $q = Math::Quaternion->new(1,2,3,4);
         print Math::Quaternion::exp($q);

       log
        Returns the logarithm of its argument. The logarithm of a negative real quaternion can
        take any value of them form (log(-q0),u*pi) for any unit vector u. In these cases, u is
        chosen to be (1,0,0).

         my $q = Math::Quaternion->new(1,2,3,4);
         print Math::Quaternion::log($q);

AUTHOR

       Jonathan Chin, <jon-quaternion.pm@earth.li>

ACKNOWLEDGEMENTS

       Thanks to Rene Uittenbogaard and Daniel Connelly for useful suggestions, and Luc Vereecken
       and Bruce Gray for patches.

SEE ALSO

       <http://mathworld.wolfram.com/Quaternion.html>
       <http://sjbaker.org/steve/omniv/eulers_are_evil.html>
       Acts 12:4

COPYRIGHT AND LICENSE

       Copyright 2003 by Jonathan Chin

       This library is free software; you can redistribute it and/or modify it under the same
       terms as Perl itself.