1 module des.math.linear.quaterni;
2 
3 import des.math.linear.vector;
4 import des.math.linear.matrix;
5 
6 import std.traits;
7 import std.exception : enforce;
8 import std.math;
9 
10 import des.util.testsuite;
11 
12 import des.math.util;
13 import des.math.basic;
14 
15 ///
16 struct Quaterni(T) if( isFloatingPoint!T )
17 {
18     ///
19     alias vectype = Vector!(4,T);
20     ///
21     vectype data;
22     ///
23     alias data this;
24     ///
25     alias selftype = Quaterni!T;
26 
27 pure:
28     ///
29     this(E...)( in E vals ) if( is( typeof( vectype(vals) ) ) )
30     { data = vectype(vals); }
31 
32     mixin accessByString!(4,T,"data.data","i j k a");
33     mixin( BasicMathOp!"data" );
34 
35     ///
36     static selftype fromAngle(size_t K,E)( T alpha, in Vector!(K,E) axis )
37         if( (K==0||K==3) && isFloatingPoint!E )
38     {
39         static if( K==0 ) enforce( axis.length == 3, "wrong length" );
40         T a = alpha / cast(T)(2.0);
41         auto vv = axis * sin(a);
42         return selftype( vv[0], vv[1], vv[2], cos(a) );
43     }
44 
45     ///
46     auto opMul(E)( in Quaterni!E b ) const
47     {
48         alias this a;
49         auto aijk = a.ijk;
50         auto bijk = b.ijk;
51         auto vv = cross( aijk, bijk ) + aijk * b.a + bijk * a.a;
52         return Quaterni!T( vv[0], vv[1], vv[2], a.a * b.a - dot(aijk, bijk) );
53     }
54 
55     ///
56     auto rot(size_t K,E)( in Vector!(K,E) b ) const
57         if( (K==0||K==3) && is( CommonType!(T,E) : T ) )
58     {
59         static if( K==0 ) enforce( b.length == 3, "wrong length" );
60         auto res = this * selftype(b,0) * inv;
61         return Vector!(K,T)( res.ijk );
62     }
63 
64     const @property
65     {
66         ///
67         T norm() { return dot( this, this ); }
68         ///
69         T mag() { return sqrt( norm ); }
70         ///
71         auto con() { return selftype( -this.ijk, this.a ); }
72         ///
73         auto inv() { return selftype( con / norm ); }
74 
75         auto len2() { return data.len2; }
76     }
77 }
78 
79 ///
80 alias Quaterni!float quat;
81 ///
82 alias Quaterni!double dquat;
83 ///
84 alias Quaterni!real rquat;
85 
86 ///
87 unittest
88 {
89     auto q = quat.fromAngle( PI_2, vec3(0,0,1) );
90     auto v = vec3(1,0,0);
91     auto e = vec3(0,1,0);
92     auto r = q.rot(v);
93     assert( eq( r, e ) );
94 }