1 module math.linear.axis_rot;
2 
3 import std.math;
4 
5 import math.linear.vector;
6 
7 public import math.linear._qa;
8 
9 // TODO: Add tests to ensure T is a compotable type (number, etc...).
10 struct AxisRot(T) {
11 	union {
12 		T[4] data;
13 		struct {
14 			T angle;
15 			Vec3!T axis;
16 		}
17 		struct {
18 			T a;
19 			T x;
20 			T y;
21 			T z;
22 		}
23 	}
24 	
25 	this(T angle, T[3] axis ...) {
26 		this.angle = angle;
27 		this.axis = axis;
28 	}
29 	this(T[4] data) {
30 		this.data = data;
31 	}
32 	this(T[3] axis, T angle) {
33 		this.angle = angle;
34 		this.axis = axis;
35 	}
36 	this(typeof(this) v) {
37 		this.data = v.data;
38 	}
39 	
40 	Quat!T _toQuat() {
41 		return Quat!T(this);
42 	}
43 	alias _toQuat this;
44 	
45 	auto opBinary(string op, T)(T b) if (__traits(compiles, opBinaryImpl!op(this, b))){
46 		return opBinaryImpl!op(this, b);
47 	}
48 	auto opBinaryRight(string op, T)(T a) if (__traits(compiles, opBinaryImpl!op(a, this))){
49 		return opBinaryImpl!op(a,this);
50 	}
51 	auto opOpAssign(string op, T)(T b) if (__traits(compiles, opOpAssignImpl!op(this, b))){
52 		return opOpAssignImpl!op(this, b);
53 	}
54 }
55 auto axisRot(T)(T[4] data) {
56 	return AxisRot!T(data);
57 }
58 auto axisRot(T)(T angle, T[3] axis ...) {
59 	return AxisRot!T(angle, axis);
60 }
61 auto axisRot(T)(T[3] axis, T angle) {
62 	return AxisRot!T(angle, axis);
63 }
64 auto axisRot(T)(axisRot!T data) {
65 	return AxisRot!T(data);
66 }
67 
68 
69 Quat!T toQuat(T)(AxisRot!T a) {
70 	return Quat!T(a);
71 }
72 
73 
74 AxisRot!T identity(T)() {
75 	return AxisRot!T(0,[0,0,0]);
76 }
77 
78 void normalize(T)(AxisRot!T t) {
79 	if (t.angle==0) return;
80 	t.axis.normalize;
81 }
82 AxisRot!T normalized(T)(AxisRot!T t) {
83 	if (t.angle==0) return identity;
84 	return AxisRot!T(t.angle,t.axis.normalized);
85 }
86 
87 
88 void invert(T)(AxisRot!T t) {
89 	t.axis.invert;
90 }
91 AxisRot!T inverse(T)(AxisRot!T t) {
92 	return AxisRot!T(t.a, [-t.x, -t.y, -t.z]);
93 }
94 
95 
96 
97 auto opBinaryImpl(string op:"*", T,U)(AxisRot!T a, AxisRot!U b) 
98 if	(__traits(compiles, typeof(mixin("a.data[0]*b.data[0]")))
99 	&& __traits(compiles, typeof(mixin("a.data[0]+b.data[0]")))
100 	&& __traits(compiles, typeof(mixin("a.data[0]-b.data[0]")))
101 	)
102 {
103 	if (a.angle == 0) return b;
104 	if (b.angle == 0) return a;
105 	return axisRot	(	acos(cos(a.a)*cos(b.a) - dot(a.axis*sin(a.a),(b.axis*sin(b.a))))
106 		,	((cos(a.a))*(b.axis*sin(b.a)) + (cos(b.a))*(a.axis*sin(a.a)) + cross((a.axis*sin(a.a)),(b.axis*sin(b.a)))).normalized
107 		);
108 }
109 
110 auto opBinaryImpl(string op:"*", T,U)(AxisRot!T a, U b) 
111 if	(__traits(compiles, typeof(mixin("a.data[0]*b"))))
112 {
113 	return axisRot(a.angle*b, a.axis);
114 }
115  
116 
117 
118 
119 
120 auto opOpAssignImpl(string op, size_t size,T,U)(ref Vec!(T, size) a, Vec!(U, size) b) 
121 if (__traits(compiles, typeof(mixin("a.data[0]"~op~"=b.data[0]"))))
122 {
123 	mixin("a.data[]"~op~"=b.data[];");
124 	return a;
125 }
126 auto opOpAssignImpl(string op, size_t size,T,U)(ref Vec!(T, size) a, U[size] b) 
127 if (__traits(compiles, typeof(mixin("a.data[0]"~op~"=b[0]"))))
128 {
129 	mixin("a.data[]"~op~"=b[];");
130 	return a;
131 }
132 auto opOpAssignImpl(string op, size_t size,T,U)(ref Vec!(T, size) a, U b) 
133 if (__traits(compiles, typeof(mixin("a[0]"~op~"=b"))))
134 {
135 	mixin("a.data[]"~op~"=b;");
136 	return a;
137 }
138