1 module math.linear.vector;
2 
3 import core.internal.traits : Unconst;
4 ////import std.traits : Unconst;
5 import std.traits;
6 import std.math;
7 import std.range;
8 import std.algorithm;
9 import std.functional;
10 
11 public import math.linear._qv;
12 
13 alias Vec2(T) = Vec!(T, 2);
14 alias Vec3(T) = Vec!(T, 3);
15 alias Vec4(T) = Vec!(T, 4);
16 // TODO: Add tests to ensure T is a compotable type (number, etc...).
17 struct Vec(T, size_t size) {
18 	alias Type = T;
19 	union {
20 		T[size] data;
21 		struct {
22 			static if (size>=1)
23 				T x;
24 			static if (size>=2)
25 				T y;
26 			static if (size>=3)
27 				T z;
28 			static if (size>=4)
29 				T w;
30 		}
31 	}
32 	alias data this;
33 	
34 	this(T[size] data ...) {
35 		this.data = data;
36 	}
37 	this(T x) {
38 		this.data[] = x;
39 	}
40 	this(Ts)(Ts data) if (isInputRange!T) {
41 		this.data = data.staticArray!size;
42 	}
43 	
44 	const
45 	Vec!(NT, size) castType(NT)() {
46 		return Vec!(NT,size)(data.arrayCast!NT);
47 	}
48 	
49 	inout
50 	T opIndex(const size_t i) {
51 		return data[i];
52 	}
53 	void opIndex(const size_t i, T n) {
54 		data[i] = n;
55 	}
56 	
57 	const
58 	auto opBinary(string op, T)(T b) {////if (__traits(compiles, opBinaryImpl!op(this, b))){
59 		static if (__traits(compiles, opBinaryImpl!op(this, b)))
60 			return opBinaryImpl!op(this, b);
61 		else
62 			return opBinaryImpl1!op(this, b);
63 	}
64 	const
65 	auto opBinaryRight(string op, T)(T a) if (__traits(compiles, opBinaryImpl!op(a, this)) || __traits(compiles, opBinaryImpl1!op(a, this))){
66 		static if (__traits(compiles, opBinaryImpl!op(a,this)))
67 			return opBinaryImpl!op(a,this);
68 		else
69 			return opBinaryImpl1!op(a,this);
70 	}
71 	auto opOpAssign(string op, T)(T b) {////if (__traits(compiles, opOpAssignImpl!op(this, b))){
72 		return opOpAssignImpl!op(this, b);
73 	}
74 	
75 	auto map(funs...)() {
76 		return vec(data[].map!funs.array[0..size]);
77 	}
78 	
79 	const nothrow pure @nogc @safe
80 	size_t toHash() {
81 		return data.hashOf;
82 	}
83 }
84 auto vec(T, size_t size)(T[size] data ...) {
85 	return Vec!(T, size)(data);
86 }
87 auto vec(size_t size, T)(T data) {
88 	return Vec!(T, size)(data);
89 }
90 
91 template vecMap(funs...) {
92 	auto vecMap(T, size_t size)(Vec!(T, size) v) {
93 		Vec!(typeof(rvalueOf!T.pipe!funs), size) n;
94 		static foreach(i; 0..size) {
95 			n.data[i] = v[i].pipe!funs;
96 		}
97 		return n;
98 	}
99 }
100 
101 T magnitudeSquared(T, size_t size)(const Vec!(T,size) v) {
102 	return v.data[].map!"a^^2".sum;
103 }
104 T magnitude(T, size_t size)(const Vec!(T,size) v) {
105 	return cast(T) sqrt(cast(real) v.magnitudeSquared);
106 }
107 void normalize(bool zero=true, T, size_t size)(Vec!(T,size) v) {
108 	auto ms = v.magnitudeSquared;
109 	if (zero && ms == 0)
110 		this.data[] = 0;
111 	else
112 		this.data[] /= cast(T) sqrt(cast(real) ms);
113 }
114 Vec!(T,size) normalized(bool zero=true, T, size_t size)(const Vec!(T,size) v) {
115 	Vec!(T,size) n;
116 	auto ms = v.magnitudeSquared;
117 	if (zero && ms == 0)
118 		n.data[] = 0;
119 	else
120 		n.data[] = v.data[] / cast(T) sqrt(cast(real) ms);
121 	return n;
122 }
123 
124 auto rotate(T, U)(Vec!(T,2) v, U a) {
125 	return vec(v.x * a.cos - v.y * a.sin, v.x * a.sin + v.y * a.cos);
126 }
127 
128 
129 void invert(T, size_t size)(Vec!(T,size) v) {
130 	v.data[] = -v.data[];
131 }
132 Vec!(T,size) inverse(T, size_t size)(constVec!(T,size) v) {
133 	Vec!(T,size) n;
134 	n.data[] = -v.data[];
135 	return n;
136 }
137 
138 auto cross(T, U)(const Vec!(T,3) a, const Vec!(U,3) b) {
139 	return Vec!(typeof(a[0]*b[0]),3)	( a.y * b.z - b.y * a.z
140 		, a.z * b.x - b.z * a.x
141 		, a.x * b.y - b.x * a.y
142 		);
143 }
144 auto cross(T, U)(const Vec!(T,2) a, const Vec!(U,2) b) {
145 	return a.x * b.y - b.x * a.y;
146 }
147 auto dot(T, U, size_t size)(const Vec!(T,size) a, const Vec!(U,size) b) if (size==2||size==3) {
148 	return cast(typeof(a[0]*b[0])) zip(a.data[],b.data[]).map!"a[0]*a[1]".sum();// `cast` because sum will increase precision of type.
149 }
150 
151 
152 ////auto cross(T, U)(const Vec!(T,3) a, const U[3] b) {
153 ////	return cross(a, Vec!(U,3)(b));
154 ////}
155 ////auto cross(T, U)(const T[3] a, const Vec!(U,3) b) {
156 ////	return cross(Vec!(T,3)(a), b);
157 ////}
158 ////auto cross(T, U)(const T[3] a, const U[3] b) {
159 ////	return cross(Vec!(T,3)(a), Vec!(U,3)(b));
160 ////}
161 ////auto dot(T, U, size_t size)(const Vec!(T,size) a, const U[size] b) if (size==2||size==3) {
162 ////	return dot(a,Vec!(U,size)(b));
163 ////}
164 ////auto dot(T, U, size_t size)(const T[size] a, const Vec!(U,size) b) if (size==2||size==3) {
165 ////	return dot(Vec!(T,size)(a),b);
166 ////}
167 ////auto dot(T, U, size_t size)(const T[size] a, const U[size] b) if (size==2||size==3) {
168 ////	return dot(Vec!(T,size)(a),Vec!(U,size)(b));
169 ////}
170 
171 auto abs(T, size_t size)(Vec!(T,size) v) {
172 	alias NT = Unconst!(typeof(std.math.abs(rvalueOf!T)));
173 	Vec!(NT, size) n;
174 	n.data[] = v.data[].map!"abs(a)".array[];
175 	return n;
176 }
177 auto distance(T, U, size_t size)(Vec!(T,size) v, Vec!(U,size) w) {
178 	return magnitude(v-w);
179 }
180 
181 auto opBinaryImpl(string op, size_t size,T,U)(const Vec!(T, size) a, const Vec!(U, size) b) 
182 if (__traits(compiles, mixin("rvalueOf!T"~op~"rvalueOf!U")))
183 {
184 	alias NT = Unconst!(typeof(mixin("rvalueOf!T"~op~"rvalueOf!U")));
185 	Vec!(NT, size) n;
186 	static if (__traits(compiles, mixin("a.data[]"~op~"b.data[]")))
187 		n.data[] = mixin("a.data[]"~op~"b.data[]");
188 	else static foreach(i; 0..size)
189 		n.data[i] = mixin("a.data[i]"~op~"b.data[i]");
190 	return n;
191 }
192 auto opBinaryImpl(string op, size_t size,T,U)(const Vec!(T, size) a, const U[size] b) 
193 if (__traits(compiles, mixin("rvalueOf!T"~op~"rvalueOf!U")))
194 {
195 	return mixin("a"~op~"Vec!(U,size)(b)");
196 }
197 auto opBinaryImpl(string op, size_t size,T,U)(const T[size] a, const Vec!(U, size) b) 
198 if (__traits(compiles, mixin("rvalueOf!T"~op~"rvalueOf!U")))
199 {
200 	return mixin("Vec!(T,size)(a)"~op~"b");
201 }
202 
203 auto opBinaryImpl1(string op, size_t size,T,U)(const Vec!(T, size) a, const U b)
204 if (__traits(compiles, mixin("rvalueOf!T"~op~"rvalueOf!U")))
205 {
206 	alias NT = Unconst!(typeof(mixin("rvalueOf!T"~op~"rvalueOf!U")));
207 	Vec!(NT, size) n;
208 	static if (__traits(compiles, mixin("a.data[]"~op~"b")))
209 		n.data[] = mixin("a.data[]"~op~"b");
210 	else static foreach(i; 0..size)
211 		n.data[i] = mixin("a.data[i]"~op~"b");
212 	return n;
213 }
214 
215 auto opBinaryImpl1(string op, size_t size,T,U)(const T a, const Vec!(U, size) b) 
216 if (__traits(compiles, mixin("rvalueOf!T"~op~"rvalueOf!U")) && !__traits(compiles, mixin("opBinaryImpl!\""~op~"\"(rvalueOf!T, rvalueOf!U)")))
217 {
218 	alias NT = Unconst!(typeof(rvalueOf!T*rvalueOf!U));
219 	Vec!(NT, size) n;
220 	n.data[] = mixin("a"~op~"b.data[]");
221 	return n;
222 }
223 
224  
225 
226 
227 
228 
229 auto opOpAssignImpl(string op, size_t size,T,U)(ref Vec!(T, size) a, const Vec!(U, size) b) 
230 if (__traits(compiles, mixin("lvalueOf!T"~op~"=rvalueOf!U")) && !(isIntegral!T && isFloatingPoint!U))
231 {
232 	static if(__traits(compiles,mixin("a.data[]"~op~"=b.data[];")))
233 		mixin("a.data[]"~op~"=b.data[];");
234 	else static foreach(i; 0..size)
235 		mixin("a.data[i]"~op~"=b.data[i];");
236 	return a;
237 }
238 auto opOpAssignImpl(string op, size_t size,T,U)(ref Vec!(T, size) a, const U[size] b) 
239 if (__traits(compiles, mixin("lvalueOf!T"~op~"=rvalueOf!U")) && !(isIntegral!T && isFloatingPoint!U))
240 {
241 	static if(__traits(compiles,mixin("a.data[]"~op~"=b[];")))
242 		mixin("a.data[]"~op~"=b[];");
243 	else static foreach(i; 0..size)
244 		mixin("a.data[i]"~op~"=b[i];");
245 	return a;
246 }
247 auto opOpAssignImpl(string op, size_t size,T,U)(ref Vec!(T, size) a, const U b) 
248 if (__traits(compiles, mixin("lvalueOf!T"~op~"=rvalueOf!U")) && !(isIntegral!T && isFloatingPoint!U))
249 {
250 	static if(__traits(compiles,mixin("a.data[]"~op~"=b;")))
251 		mixin("a.data[]"~op~"=b;");
252 	else static foreach(i; 0..size)
253 		mixin("a.data[i]"~op~"=b;");
254 	return a;
255 }
256 
257 
258 
259 
260 
261 private {
262 	inout (NT[]) arrayCast(NT,OT)(inout OT[] xs) {
263 		NT[] nxs = new NT[xs.length];
264 		foreach (i,e; xs) {
265 			nxs[i] = cast(inout NT) e;
266 		}
267 		return nxs;
268 	}
269 	inout(NT[L]) arrayCast(NT,OT,size_t L)(inout OT[L] xs) {
270 		NT[L] nxs;
271 		foreach (i,e; xs) {
272 			nxs[i] = cast(inout NT) e;
273 		}
274 		return nxs;
275 	}
276 }
277 
278 
279 
280 
281 unittest {
282 	import std.stdio;
283 	void testOp(string op)() {
284 		void testValues(A,B)(A a1, A a2, A a3, B b1, B b2, B b3) {
285 			void testConst(bool aConst, bool bConst)() {
286 				void testTypes(AT, BT)() {
287 					static if (aConst)
288 						const AT a = [a1,a2,a3];
289 					else
290 						AT a = [a1,a2,a3];
291 					static if (bConst)
292 						const BT b = [b1,b2,b3];
293 					else
294 						BT b = [b1,b2,b3];
295 					static assert(is(typeof(mixin("a"~op~"b")) == Vec!(typeof(a1+b1),3)));
296 					assert(mixin("a"~op~"b")== vec([mixin("a1"~op~"b1"),mixin("a2"~op~"b2"),mixin("a3"~op~"b3")]));
297 					static if(op=="*") {
298 						static assert(is(typeof(cross(a,b)) == Vec!(typeof(a1*b1),3)));
299 						static assert(is(typeof(dot(a,b)) == typeof(a1*b1)));
300 					}
301 				}
302 				testTypes!(Vec!(A,3), Vec!(B,3));
303 				testTypes!(Vec!(A,3), B[3]);
304 				testTypes!(A[3], Vec!(B,3));
305 			}
306 			testConst!(false,false);
307 			testConst!(true,true);
308 			testConst!(true,false);
309 			testConst!(false,true);
310 		}
311 		testValues!(int,int)(1,2,3,2,3,4);
312 		testValues!(float,float)(1.5,2.5,3,2.5,3,4.5);
313 		testValues!(int,float)(1,2,3,2.5,3,4.5);
314 		testValues!(float,double)(1.5,2.5,3,2.5,3,4.5);
315 	}
316 	testOp!"+";
317 	testOp!"-";
318 	testOp!"*";
319 	testOp!"/";
320 	testOp!"%";
321 }
322 
323 
324 
325 
326