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