Subversion Repositories AndroidProjects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1452 chris 1
#region --- License ---
2
/*
3
Copyright (c) 2006 - 2008 The Open Toolkit library.
4
 
5
Permission is hereby granted, free of charge, to any person obtaining a copy of
6
this software and associated documentation files (the "Software"), to deal in
7
the Software without restriction, including without limitation the rights to
8
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
of the Software, and to permit persons to whom the Software is furnished to do
10
so, subject to the following conditions:
11
 
12
The above copyright notice and this permission notice shall be included in all
13
copies or substantial portions of the Software.
14
 
15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
SOFTWARE.
22
 */
23
#endregion
24
 
25
using System;
26
using System.Runtime.InteropServices;
27
using System.ComponentModel;
28
using System.Xml.Serialization;
29
 
30
namespace OpenTK
31
{
32
    /// <summary>
33
    /// Represents a Quaternion.
34
    /// </summary>
35
    [Serializable]
36
    [StructLayout(LayoutKind.Sequential)]
37
    public struct Quaternion : IEquatable<Quaternion>
38
    {
39
        #region Fields
40
 
41
        Vector3 xyz;
42
        float w;
43
 
44
        #endregion
45
 
46
        #region Constructors
47
 
48
        /// <summary>
49
        /// Construct a new Quaternion from vector and w components
50
        /// </summary>
51
        /// <param name="v">The vector part</param>
52
        /// <param name="w">The w part</param>
53
        public Quaternion(Vector3 v, float w)
54
        {
55
            this.xyz = v;
56
            this.w = w;
57
        }
58
 
59
        /// <summary>
60
        /// Construct a new Quaternion
61
        /// </summary>
62
        /// <param name="x">The x component</param>
63
        /// <param name="y">The y component</param>
64
        /// <param name="z">The z component</param>
65
        /// <param name="w">The w component</param>
66
        public Quaternion(float x, float y, float z, float w)
67
            : this(new Vector3(x, y, z), w)
68
        { }
69
 
70
        #endregion
71
 
72
        #region Public Members
73
 
74
        #region Properties
75
 
76
        /// <summary>
77
        /// Gets or sets an OpenTK.Vector3 with the X, Y and Z components of this instance.
78
        /// </summary>
79
        [Obsolete("Use Xyz property instead.")]
80
        [CLSCompliant(false)]
81
        [EditorBrowsable(EditorBrowsableState.Never)]
82
        [XmlIgnore]
83
        public Vector3 XYZ { get { return Xyz; } set { Xyz = value; } }
84
 
85
        /// <summary>
86
        /// Gets or sets an OpenTK.Vector3 with the X, Y and Z components of this instance.
87
        /// </summary>
88
        public Vector3 Xyz { get { return xyz; } set { xyz = value; } }
89
 
90
        /// <summary>
91
        /// Gets or sets the X component of this instance.
92
        /// </summary>
93
        [XmlIgnore]
94
        public float X { get { return xyz.X; } set { xyz.X = value; } }
95
 
96
        /// <summary>
97
        /// Gets or sets the Y component of this instance.
98
        /// </summary>
99
        [XmlIgnore]
100
        public float Y { get { return xyz.Y; } set { xyz.Y = value; } }
101
 
102
        /// <summary>
103
        /// Gets or sets the Z component of this instance.
104
        /// </summary>
105
        [XmlIgnore]
106
        public float Z { get { return xyz.Z; } set { xyz.Z = value; } }
107
 
108
        /// <summary>
109
        /// Gets or sets the W component of this instance.
110
        /// </summary>
111
        public float W { get { return w; } set { w = value; } }
112
 
113
        #endregion
114
 
115
        #region Instance
116
 
117
        #region ToAxisAngle
118
 
119
        /// <summary>
120
        /// Convert the current quaternion to axis angle representation
121
        /// </summary>
122
        /// <param name="axis">The resultant axis</param>
123
        /// <param name="angle">The resultant angle</param>
124
        public void ToAxisAngle(out Vector3 axis, out float angle)
125
        {
126
            Vector4 result = ToAxisAngle();
127
            axis = result.Xyz;
128
            angle = result.W;
129
        }
130
 
131
        /// <summary>
132
        /// Convert this instance to an axis-angle representation.
133
        /// </summary>
134
        /// <returns>A Vector4 that is the axis-angle representation of this quaternion.</returns>
135
        public Vector4 ToAxisAngle()
136
        {
137
            Quaternion q = this;
138
            if (q.W > 1.0f)
139
                q.Normalize();
140
 
141
            Vector4 result = new Vector4();
142
 
143
            result.W = 2.0f * (float)System.Math.Acos(q.W); // angle
144
            float den = (float)System.Math.Sqrt(1.0 - q.W * q.W);
145
            if (den > 0.0001f)
146
            {
147
                result.Xyz = q.Xyz / den;
148
            }
149
            else
150
            {
151
                // This occurs when the angle is zero. 
152
                // Not a problem: just set an arbitrary normalized axis.
153
                result.Xyz = Vector3.UnitX;
154
            }
155
 
156
            return result;
157
        }
158
 
159
        #endregion
160
 
161
        #region public float Length
162
 
163
        /// <summary>
164
        /// Gets the length (magnitude) of the quaternion.
165
        /// </summary>
166
        /// <seealso cref="LengthSquared"/>
167
        public float Length
168
        {
169
            get
170
            {
171
                return (float)System.Math.Sqrt(W * W + Xyz.LengthSquared);
172
            }
173
        }
174
 
175
        #endregion
176
 
177
        #region public float LengthSquared
178
 
179
        /// <summary>
180
        /// Gets the square of the quaternion length (magnitude).
181
        /// </summary>
182
        public float LengthSquared
183
        {
184
            get
185
            {
186
                return W * W + Xyz.LengthSquared;
187
            }
188
        }
189
 
190
        #endregion
191
 
192
        #region public void Normalize()
193
 
194
        /// <summary>
195
        /// Scales the Quaternion to unit length.
196
        /// </summary>
197
        public void Normalize()
198
        {
199
            float scale = 1.0f / this.Length;
200
            Xyz *= scale;
201
            W *= scale;
202
        }
203
 
204
        #endregion
205
 
206
        #region public void Conjugate()
207
 
208
        /// <summary>
209
        /// Convert this quaternion to its conjugate
210
        /// </summary>
211
        public void Conjugate()
212
        {
213
            Xyz = -Xyz;
214
        }
215
 
216
        #endregion
217
 
218
        #endregion
219
 
220
        #region Static
221
 
222
        #region Fields
223
 
224
        /// <summary>
225
        /// Defines the identity quaternion.
226
        /// </summary>
227
        public static Quaternion Identity = new Quaternion(0, 0, 0, 1);
228
 
229
        #endregion
230
 
231
        #region Add
232
 
233
        /// <summary>
234
        /// Add two quaternions
235
        /// </summary>
236
        /// <param name="left">The first operand</param>
237
        /// <param name="right">The second operand</param>
238
        /// <returns>The result of the addition</returns>
239
        public static Quaternion Add(Quaternion left, Quaternion right)
240
        {
241
            return new Quaternion(
242
                left.Xyz + right.Xyz,
243
                left.W + right.W);
244
        }
245
 
246
        /// <summary>
247
        /// Add two quaternions
248
        /// </summary>
249
        /// <param name="left">The first operand</param>
250
        /// <param name="right">The second operand</param>
251
        /// <param name="result">The result of the addition</param>
252
        public static void Add(ref Quaternion left, ref Quaternion right, out Quaternion result)
253
        {
254
            result = new Quaternion(
255
                left.Xyz + right.Xyz,
256
                left.W + right.W);
257
        }
258
 
259
        #endregion
260
 
261
        #region Sub
262
 
263
        /// <summary>
264
        /// Subtracts two instances.
265
        /// </summary>
266
        /// <param name="left">The left instance.</param>
267
        /// <param name="right">The right instance.</param>
268
        /// <returns>The result of the operation.</returns>
269
        public static Quaternion Sub(Quaternion left, Quaternion right)
270
        {
271
            return  new Quaternion(
272
                left.Xyz - right.Xyz,
273
                left.W - right.W);
274
        }
275
 
276
        /// <summary>
277
        /// Subtracts two instances.
278
        /// </summary>
279
        /// <param name="left">The left instance.</param>
280
        /// <param name="right">The right instance.</param>
281
        /// <param name="result">The result of the operation.</param>
282
        public static void Sub(ref Quaternion left, ref Quaternion right, out Quaternion result)
283
        {
284
            result = new Quaternion(
285
                left.Xyz - right.Xyz,
286
                left.W - right.W);
287
        }
288
 
289
        #endregion
290
 
291
        #region Mult
292
 
293
        /// <summary>
294
        /// Multiplies two instances.
295
        /// </summary>
296
        /// <param name="left">The first instance.</param>
297
        /// <param name="right">The second instance.</param>
298
        /// <returns>A new instance containing the result of the calculation.</returns>
299
        [Obsolete("Use Multiply instead.")]
300
        public static Quaternion Mult(Quaternion left, Quaternion right)
301
        {
302
            return new Quaternion(
303
                right.W * left.Xyz + left.W * right.Xyz + Vector3.Cross(left.Xyz, right.Xyz),
304
                left.W * right.W - Vector3.Dot(left.Xyz, right.Xyz));
305
        }
306
 
307
        /// <summary>
308
        /// Multiplies two instances.
309
        /// </summary>
310
        /// <param name="left">The first instance.</param>
311
        /// <param name="right">The second instance.</param>
312
        /// <param name="result">A new instance containing the result of the calculation.</param>
313
        [Obsolete("Use Multiply instead.")]
314
        public static void Mult(ref Quaternion left, ref Quaternion right, out Quaternion result)
315
        {
316
            result = new Quaternion(
317
                right.W * left.Xyz + left.W * right.Xyz + Vector3.Cross(left.Xyz, right.Xyz),
318
                left.W * right.W - Vector3.Dot(left.Xyz, right.Xyz));
319
        }
320
 
321
        /// <summary>
322
        /// Multiplies two instances.
323
        /// </summary>
324
        /// <param name="left">The first instance.</param>
325
        /// <param name="right">The second instance.</param>
326
        /// <returns>A new instance containing the result of the calculation.</returns>
327
        public static Quaternion Multiply(Quaternion left, Quaternion right)
328
        {
329
            Quaternion result;
330
            Multiply(ref left, ref right, out result);
331
            return result;
332
        }
333
 
334
        /// <summary>
335
        /// Multiplies two instances.
336
        /// </summary>
337
        /// <param name="left">The first instance.</param>
338
        /// <param name="right">The second instance.</param>
339
        /// <param name="result">A new instance containing the result of the calculation.</param>
340
        public static void Multiply(ref Quaternion left, ref Quaternion right, out Quaternion result)
341
        {
342
            result = new Quaternion(
343
                right.W * left.Xyz + left.W * right.Xyz + Vector3.Cross(left.Xyz, right.Xyz),
344
                left.W * right.W - Vector3.Dot(left.Xyz, right.Xyz));
345
        }
346
 
347
        /// <summary>
348
        /// Multiplies an instance by a scalar.
349
        /// </summary>
350
        /// <param name="quaternion">The instance.</param>
351
        /// <param name="scale">The scalar.</param>
352
        /// <param name="result">A new instance containing the result of the calculation.</param>
353
        public static void Multiply(ref Quaternion quaternion, float scale, out Quaternion result)
354
        {
355
            result = new Quaternion(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale);
356
        }
357
 
358
        /// <summary>
359
        /// Multiplies an instance by a scalar.
360
        /// </summary>
361
        /// <param name="quaternion">The instance.</param>
362
        /// <param name="scale">The scalar.</param>
363
        /// <returns>A new instance containing the result of the calculation.</returns>
364
        public static Quaternion Multiply(Quaternion quaternion, float scale)
365
        {
366
            return new Quaternion(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale);
367
        }
368
 
369
        #endregion
370
 
371
        #region Conjugate
372
 
373
        /// <summary>
374
        /// Get the conjugate of the given quaternion
375
        /// </summary>
376
        /// <param name="q">The quaternion</param>
377
        /// <returns>The conjugate of the given quaternion</returns>
378
        public static Quaternion Conjugate(Quaternion q)
379
        {
380
            return new Quaternion(-q.Xyz, q.W);
381
        }
382
 
383
        /// <summary>
384
        /// Get the conjugate of the given quaternion
385
        /// </summary>
386
        /// <param name="q">The quaternion</param>
387
        /// <param name="result">The conjugate of the given quaternion</param>
388
        public static void Conjugate(ref Quaternion q, out Quaternion result)
389
        {
390
            result = new Quaternion(-q.Xyz, q.W);
391
        }
392
 
393
        #endregion
394
 
395
        #region Invert
396
 
397
        /// <summary>
398
        /// Get the inverse of the given quaternion
399
        /// </summary>
400
        /// <param name="q">The quaternion to invert</param>
401
        /// <returns>The inverse of the given quaternion</returns>
402
        public static Quaternion Invert(Quaternion q)
403
        {
404
            Quaternion result;
405
            Invert(ref q, out result);
406
            return result;
407
        }
408
 
409
        /// <summary>
410
        /// Get the inverse of the given quaternion
411
        /// </summary>
412
        /// <param name="q">The quaternion to invert</param>
413
        /// <param name="result">The inverse of the given quaternion</param>
414
        public static void Invert(ref Quaternion q, out Quaternion result)
415
        {
416
            float lengthSq = q.LengthSquared;
417
            if (lengthSq != 0.0)
418
            {
419
                float i = 1.0f / lengthSq;
420
                result = new Quaternion(q.Xyz * -i, q.W * i);
421
            }
422
            else
423
            {
424
                result = q;
425
            }
426
        }
427
 
428
        #endregion
429
 
430
        #region Normalize
431
 
432
        /// <summary>
433
        /// Scale the given quaternion to unit length
434
        /// </summary>
435
        /// <param name="q">The quaternion to normalize</param>
436
        /// <returns>The normalized quaternion</returns>
437
        public static Quaternion Normalize(Quaternion q)
438
        {
439
            Quaternion result;
440
            Normalize(ref q, out result);
441
            return result;
442
        }
443
 
444
        /// <summary>
445
        /// Scale the given quaternion to unit length
446
        /// </summary>
447
        /// <param name="q">The quaternion to normalize</param>
448
        /// <param name="result">The normalized quaternion</param>
449
        public static void Normalize(ref Quaternion q, out Quaternion result)
450
        {
451
            float scale = 1.0f / q.Length;
452
            result = new Quaternion(q.Xyz * scale, q.W * scale);
453
        }
454
 
455
        #endregion
456
 
457
        #region FromAxisAngle
458
 
459
        /// <summary>
460
        /// Build a quaternion from the given axis and angle
461
        /// </summary>
462
        /// <param name="axis">The axis to rotate about</param>
463
        /// <param name="angle">The rotation angle in radians</param>
464
        /// <returns></returns>
465
        public static Quaternion FromAxisAngle(Vector3 axis, float angle)
466
        {
467
            if (axis.LengthSquared == 0.0f)
468
                return Identity;
469
 
470
            Quaternion result = Identity;
471
 
472
            angle *= 0.5f;
473
            axis.Normalize();
474
            result.Xyz = axis * (float)System.Math.Sin(angle);
475
            result.W = (float)System.Math.Cos(angle);
476
 
477
            return Normalize(result);
478
        }
479
 
480
        #endregion
481
 
482
        #region Slerp
483
 
484
        /// <summary>
485
        /// Do Spherical linear interpolation between two quaternions 
486
        /// </summary>
487
        /// <param name="q1">The first quaternion</param>
488
        /// <param name="q2">The second quaternion</param>
489
        /// <param name="blend">The blend factor</param>
490
        /// <returns>A smooth blend between the given quaternions</returns>
491
        public static Quaternion Slerp(Quaternion q1, Quaternion q2, float blend)
492
        {
493
            // if either input is zero, return the other.
494
            if (q1.LengthSquared == 0.0f)
495
            {
496
                if (q2.LengthSquared == 0.0f)
497
                {
498
                    return Identity;
499
                }
500
                return q2;
501
            }
502
            else if (q2.LengthSquared == 0.0f)
503
            {
504
                return q1;
505
            }
506
 
507
 
508
            float cosHalfAngle = q1.W * q2.W + Vector3.Dot(q1.Xyz, q2.Xyz);
509
 
510
            if (cosHalfAngle >= 1.0f || cosHalfAngle <= -1.0f)
511
            {
512
                // angle = 0.0f, so just return one input.
513
                return q1;
514
            }
515
            else if (cosHalfAngle < 0.0f)
516
            {
517
                q2.Xyz = -q2.Xyz;
518
                q2.W = -q2.W;
519
                cosHalfAngle = -cosHalfAngle;
520
            }
521
 
522
            float blendA;
523
            float blendB;
524
            if (cosHalfAngle < 0.99f)
525
            {
526
                // do proper slerp for big angles
527
                float halfAngle = (float)System.Math.Acos(cosHalfAngle);
528
                float sinHalfAngle = (float)System.Math.Sin(halfAngle);
529
                float oneOverSinHalfAngle = 1.0f / sinHalfAngle;
530
                blendA = (float)System.Math.Sin(halfAngle * (1.0f - blend)) * oneOverSinHalfAngle;
531
                blendB = (float)System.Math.Sin(halfAngle * blend) * oneOverSinHalfAngle;
532
            }
533
            else
534
            {
535
                // do lerp if angle is really small.
536
                blendA = 1.0f - blend;
537
                blendB = blend;
538
            }
539
 
540
            Quaternion result = new Quaternion(blendA * q1.Xyz + blendB * q2.Xyz, blendA * q1.W + blendB * q2.W);
541
            if (result.LengthSquared > 0.0f)
542
                return Normalize(result);
543
            else
544
                return Identity;
545
        }
546
 
547
        #endregion
548
 
549
        #endregion
550
 
551
        #region Operators
552
 
553
        /// <summary>
554
        /// Adds two instances.
555
        /// </summary>
556
        /// <param name="left">The first instance.</param>
557
        /// <param name="right">The second instance.</param>
558
        /// <returns>The result of the calculation.</returns>
559
        public static Quaternion operator +(Quaternion left, Quaternion right)
560
        {
561
            left.Xyz += right.Xyz;
562
            left.W += right.W;
563
            return left;
564
        }
565
 
566
        /// <summary>
567
        /// Subtracts two instances.
568
        /// </summary>
569
        /// <param name="left">The first instance.</param>
570
        /// <param name="right">The second instance.</param>
571
        /// <returns>The result of the calculation.</returns>
572
        public static Quaternion operator -(Quaternion left, Quaternion right)
573
        {
574
            left.Xyz -= right.Xyz;
575
            left.W -= right.W;
576
            return left;
577
        }
578
 
579
        /// <summary>
580
        /// Multiplies two instances.
581
        /// </summary>
582
        /// <param name="left">The first instance.</param>
583
        /// <param name="right">The second instance.</param>
584
        /// <returns>The result of the calculation.</returns>
585
        public static Quaternion operator *(Quaternion left, Quaternion right)
586
        {
587
            Multiply(ref left, ref right, out left);
588
            return left;
589
        }
590
 
591
        /// <summary>
592
        /// Multiplies an instance by a scalar.
593
        /// </summary>
594
        /// <param name="quaternion">The instance.</param>
595
        /// <param name="scale">The scalar.</param>
596
        /// <returns>A new instance containing the result of the calculation.</returns>
597
        public static Quaternion operator *(Quaternion quaternion, float scale)
598
        {
599
            Multiply(ref quaternion, scale, out quaternion);
600
            return quaternion;
601
        }
602
 
603
        /// <summary>
604
        /// Multiplies an instance by a scalar.
605
        /// </summary>
606
        /// <param name="quaternion">The instance.</param>
607
        /// <param name="scale">The scalar.</param>
608
        /// <returns>A new instance containing the result of the calculation.</returns>
609
        public static Quaternion operator *(float scale, Quaternion quaternion)
610
        {
611
            return new Quaternion(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale);
612
        }
613
 
614
        /// <summary>
615
        /// Compares two instances for equality.
616
        /// </summary>
617
        /// <param name="left">The first instance.</param>
618
        /// <param name="right">The second instance.</param>
619
        /// <returns>True, if left equals right; false otherwise.</returns>
620
        public static bool operator ==(Quaternion left, Quaternion right)
621
        {
622
            return left.Equals(right);
623
        }
624
 
625
        /// <summary>
626
        /// Compares two instances for inequality.
627
        /// </summary>
628
        /// <param name="left">The first instance.</param>
629
        /// <param name="right">The second instance.</param>
630
        /// <returns>True, if left does not equal right; false otherwise.</returns>
631
        public static bool operator !=(Quaternion left, Quaternion right)
632
        {
633
            return !left.Equals(right);
634
        }
635
 
636
        #endregion
637
 
638
        #region Overrides
639
 
640
        #region public override string ToString()
641
 
642
        /// <summary>
643
        /// Returns a System.String that represents the current Quaternion.
644
        /// </summary>
645
        /// <returns></returns>
646
        public override string ToString()
647
        {
648
            return String.Format("V: {0}, W: {1}", Xyz, W);
649
        }
650
 
651
        #endregion
652
 
653
        #region public override bool Equals (object o)
654
 
655
        /// <summary>
656
        /// Compares this object instance to another object for equality. 
657
        /// </summary>
658
        /// <param name="other">The other object to be used in the comparison.</param>
659
        /// <returns>True if both objects are Quaternions of equal value. Otherwise it returns false.</returns>
660
        public override bool Equals(object other)
661
        {
662
            if (other is Quaternion == false) return false;
663
               return this == (Quaternion)other;
664
        }
665
 
666
        #endregion
667
 
668
        #region public override int GetHashCode ()
669
 
670
        /// <summary>
671
        /// Provides the hash code for this object. 
672
        /// </summary>
673
        /// <returns>A hash code formed from the bitwise XOR of this objects members.</returns>
674
        public override int GetHashCode()
675
        {
676
            return Xyz.GetHashCode() ^ W.GetHashCode();
677
        }
678
 
679
        #endregion
680
 
681
        #endregion
682
 
683
        #endregion
684
 
685
        #region IEquatable<Quaternion> Members
686
 
687
        /// <summary>
688
        /// Compares this Quaternion instance to another Quaternion for equality. 
689
        /// </summary>
690
        /// <param name="other">The other Quaternion to be used in the comparison.</param>
691
        /// <returns>True if both instances are equal; false otherwise.</returns>
692
        public bool Equals(Quaternion other)
693
        {
694
            return Xyz == other.Xyz && W == other.W;
695
        }
696
 
697
        #endregion
698
    }
699
}