File: README

package info (click to toggle)
libmath-quaternion-perl 0.07-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, sid, stretch
  • size: 208 kB
  • ctags: 54
  • sloc: perl: 420; makefile: 2
file content (374 lines) | stat: -rw-r--r-- 14,135 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
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({ axis => 0.1, angle => [ 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; # 1;
      print $q2->isreal; # 0;

    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 for useful suggestions.

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.