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 }