1 //Package for test, maybe there will be full implementation
2 module mutils.linalg.vec;
3 
4 import std.format : FormatSpec, formatValue;
5 import std.math : sqrt;
6 import std.traits;
7 
8 import mutils.serializer.common;
9 
10 struct Vec(T, int dim) {
11 	static assert(dim > 0);
12 	enum dimension = dim;
13 
14 	alias vector this;
15 
16 	union {
17 		T[dim] vector;
18 
19 		static if (dim == 2) {
20 			struct {
21 				T x;
22 				T y;
23 			}
24 		}
25 
26 		static if (dim == 3) {
27 			struct {
28 				T x;
29 				T y;
30 				T z;
31 			}
32 		}
33 
34 		static if (dim == 4) {
35 			struct {
36 				T x;
37 				T y;
38 				T z;
39 				T w;
40 			}
41 		}
42 	}
43 
44 	this(T[dim] val) {
45 		vector = val;
46 	}
47 
48 	this(X)(X val) if (!isArray!X && isAssignable!(T, X)) {
49 		vector[] = val;
50 	}
51 
52 	this(X)(X[dim] values) if (!isArray!X && isAssignable!(T, X)) {
53 		foreach (i, val; values) {
54 			vector[i] = values[i];
55 		}
56 	}
57 
58 	this(Args...)(Args values) if (Args.length == dim) {
59 		foreach (i, val; values) {
60 			vector[i] = values[i];
61 		}
62 	}
63 
64 	float length() {
65 		float len = 0;
66 		foreach (el; vector) {
67 			len += el * el;
68 		}
69 		return sqrt(len);
70 	}
71 
72 	float length_squared() {
73 		float len = 0;
74 		foreach (el; vector) {
75 			len += el * el;
76 		}
77 		return len;
78 	}
79 
80 	Vec!(T, dim) normalized() {
81 		return this / length;
82 	}
83 
84 	void normalize()() {
85 		this /= length;
86 	}
87 
88 	Vec!(T, dim) opUnary(string s)() if (s == "-") {
89 		Vec!(T, dim) tmp = this;
90 		tmp *= -1;
91 		return tmp;
92 	}
93 
94 	void opAssign(T[dim] rhs) {
95 		vector = rhs;
96 	}
97 
98 	auto opBinaryRight(string op, X)(X lft) if (isAssignable!(T, X)) {
99 		return this.opBinary!(op)(lft);
100 	}
101 
102 	Vec!(T, dim) opBinary(string op)(T[dim] rhs) {
103 		Vec!(T, dim) ret;
104 		// MonoDevelop lexer does not support static forach
105 		mixin("static foreach(i; 0..dim){  ret.vector[i]=this.vector[i] " ~ op ~ " rhs[i];  }");
106 
107 		return ret;
108 	}
109 
110 	Vec!(T, dim) opBinary(string op)(double rhs) {
111 		Vec!(T, dim) ret = this;
112 		foreach (ref v; ret.vector) {
113 			mixin("v=cast(T)(v " ~ op ~ " rhs);");
114 
115 		}
116 		return ret;
117 	}
118 
119 	void opOpAssign(string op)(T rhs) {
120 		foreach (ref v; vector) {
121 			mixin("v" ~ op ~ "= rhs;");
122 		}
123 	}
124 
125 	void opOpAssign(string op, X)(X[dim] rhs)
126 			if (!isArray!X && isAssignable!(T, X)) {
127 		foreach (i, ref v; vector) {
128 			mixin("v" ~ op ~ "= rhs[i];");
129 		}
130 	}
131 
132 	/**
133 	 * Preety print
134 	 */
135 	void toString(scope void delegate(const(char)[]) sink, FormatSpec!char fmt) {
136 		formatValue(sink, vector, fmt);
137 	}
138 
139 	void customSerialize(Load load, Serializer, COS)(Serializer serializer,
140 			ref COS con) {
141 		serializer.serialize!(load)(vector, con);
142 	}
143 
144 }
145 
146 @nogc nothrow pure unittest {
147 	alias vec2i = Vec!(int, 2);
148 	int[2] arr = [1, 2];
149 	vec2i v1 = vec2i(1, 1);
150 	vec2i v2 = vec2i(3);
151 	vec2i v3 = arr;
152 	assert(v2 == vec2i(3, 3));
153 	v1.opBinary!("+")(v2);
154 	assert((v1 + v2) == vec2i(4, 4));
155 	assert((v1 * v2) == vec2i(3, 3));
156 	assert((v1 / v2) == vec2i(0, 0));
157 	assert((v2 / v1) == vec2i(3, 3));
158 	assert(v1 * 3.0 == vec2i(3, 3));
159 }
160 
161 @nogc nothrow pure unittest {
162 	alias vec2i = Vec!(int, 2);
163 	alias vec2b = Vec!(byte, 2);
164 	byte b1 = 1;
165 	int[2] arr = [1, 2];
166 	vec2i v1 = vec2i(1, 1);
167 	assert(v1 * -1 == vec2i(-1, -1));
168 	assert(-v1 == vec2i(-1, -1));
169 	assert(vec2i(vec2b(b1, b1)) == vec2i(1, 1));
170 }
171 
172 @nogc nothrow pure unittest {
173 	alias vec2 = Vec!(float, 2);
174 	vec2 v1 = vec2(2, 2);
175 	v1 *= 2;
176 	assert(v1 == vec2(4, 4));
177 	v1 /= 2;
178 	assert(v1 == vec2(2, 2));
179 	assert(2 * v1 == vec2(4, 4));
180 	vec2 vN = v1.normalized;
181 	assert(vN[0] > 0.7 && vN[0] < 0.8);
182 	assert(vN[1] > 0.7 && vN[1] < 0.8);
183 	assert(v1 == vec2(2, 2));
184 	v1.normalize();
185 	assert(v1[0] > 0.7 && v1[0] < 0.8);
186 	assert(v1[1] > 0.7 && v1[1] < 0.8);
187 
188 }
189 
190 auto dot(V)(V vA, V vB) if (!isStaticArray!V) {
191 	return dot(vA.vector, vB.vector);
192 }
193 
194 auto dot(T)(T arrA, T arrB) if (isStaticArray!T) {
195 	ForeachType!T val;
196 
197 	foreach (i; 0 .. T.length) {
198 		val += arrA[i] * arrB[i];
199 	}
200 
201 	return val;
202 }
203 
204 @nogc nothrow pure unittest {
205 	alias vec2i = Vec!(int, 2);
206 	int[2] arr = [1, 2];
207 	vec2i vec = vec2i(arr);
208 	assert(dot(arr, arr) == 5);
209 	assert(dot(vec, vec) == 5);
210 }