1 module grape.math;
2 
3 public import std.math;
4 import std.stdio;
5 import std.algorithm;
6 
7 alias Vector3 Vec3;
8 struct Vector3 {
9   public:
10     this(in float[] coord) {
11       set(coord);
12     }
13     
14     this(in float x, in float y, in float z) {
15       set(x, y, z);
16     }
17 
18     Vec3 opBinary(string op)(Vec3 vec3) if (op == "+") {
19       auto tmp = new float[_coord.length];
20       tmp[] = _coord[] + vec3.coord[];
21       auto result = Vec3(tmp);
22       return result;
23     }
24 
25     Vec3 opBinary(string op)(Vec3 vec3) if (op == "-") {
26       auto tmp = new float[_coord.length];
27       tmp[] = _coord[] - vec3.coord[];
28       auto result = Vec3(tmp);
29       return result;
30     }
31 
32     Vec3 opBinary(string op)(float ratio) if (op == "*") {
33       auto tmp = new float[_coord.length];
34       tmp[] = _coord[] * ratio;
35       auto result = Vec3(tmp);
36       return result;
37     }
38 
39     Vec3 opBinaryRight(string op)(float ratio) if (op == "*") {
40       return opBinary!op(ratio);
41     }
42 
43     Vec3 opOpAssign(string op)(Vec3 vec3) if (op == "+") {
44       auto tmp = new float[_coord.length];
45       tmp[] = _coord[] + vec3.coord[];
46       _coord = tmp;
47       return this;
48     }
49 
50     Vec3 opOpAssign(string op)(Vec3 vec3) if (op == "-") {
51       auto tmp = new float[_coord.length];
52       tmp[] = _coord[] - vec3.coord[];
53       _coord = tmp;
54       return this;
55     }
56 
57     void set(in float[] coord) {
58       _coord = coord.dup;
59     }
60 
61     void set(in float x, in float y, in float z) {
62       _coord = [x, y, z];
63     }
64 
65     void set_x(in float x) {
66       _coord[0] = x;
67     }
68 
69     void set_y(in float y) {
70       _coord[1] = y;
71     }
72 
73     void set_z(in float z) {
74       _coord[2] = z;
75     }
76 
77     float dot(Vec3 vec3) {
78       return ( _coord[0]*vec3.x + _coord[1]*vec3.y + _coord[2]*vec3.z );
79     }
80 
81     Vec3 cross(Vec3 vec3) {
82       return Vec3( _coord[1]*vec3.z - _coord[2]*vec3.y,
83                    _coord[2]*vec3.x - _coord[0]*vec3.z,
84                    _coord[0]*vec3.y - _coord[1]*vec3.x );
85     }
86 
87     @property {
88       float[] coord() {
89         return _coord;
90       }
91 
92       float x() {
93         return _coord[0];
94       }
95 
96       float y() {
97         return _coord[1];
98       }
99 
100       float z() {
101         return _coord[2];
102       }
103 
104       float magnitude() {
105         return sqrt(pow(_coord[0], 2) + pow(_coord[1], 2) + pow(_coord[2], 2));
106       }
107 
108       void normalize() {
109         auto m = magnitude();
110         if (m == 0) return;
111         _coord[0] = _coord[0] / m;
112         _coord[1] = _coord[1] / m;
113         _coord[2] = _coord[2] / m;
114       }
115     }
116 
117   private:
118     float[3] _coord;
119 }
120 
121 alias Matrix4 Mat4;
122 struct Matrix4 {
123   public:
124     this(in float[] coords...) {
125       set(coords);
126     }
127 
128     void set(in float[] coords...) {
129       assert(coords.length == 16);
130       _mat[] = coords[];
131     }
132 
133     Mat4 translate(in float x, in float y, in float z) {
134       Mat4 mat4 = Mat4( 1, 0, 0, 0,
135                         0, 1, 0, 0,
136                         0, 0, 1, 0,
137                         x, y, z, 1 );
138       return multiply(mat4);
139     }
140 
141     Mat4 multiply(Mat4 mat4) {
142       float a = _mat[0],  b = _mat[1],  c = _mat[2],  d = _mat[3],
143             e = _mat[4],  f = _mat[5],  g = _mat[6],  h = _mat[7],
144             i = _mat[8],  j = _mat[9],  k = _mat[10], l = _mat[11],
145             m = _mat[12], n = _mat[13], o = _mat[14], p = _mat[15],
146             A = mat4.mat[0],  B = mat4.mat[1],  C = mat4.mat[2],  D = mat4.mat[3],
147             E = mat4.mat[4],  F = mat4.mat[5],  G = mat4.mat[6],  H = mat4.mat[7],
148             I = mat4.mat[8],  J = mat4.mat[9],  K = mat4.mat[10], L = mat4.mat[11],
149             M = mat4.mat[12], N = mat4.mat[13], O = mat4.mat[14], P = mat4.mat[15];
150       return Mat4( A * a + B * e + C * i + D * m,
151                    A * b + B * f + C * j + D * n,
152                    A * c + B * g + C * k + D * o,
153                    A * d + B * h + C * l + D * p,
154                    E * a + F * e + G * i + H * m,
155                    E * b + F * f + G * j + H * n,
156                    E * c + F * g + G * k + H * o,
157                    E * d + F * h + G * l + H * p,
158                    I * a + J * e + K * i + L * m,
159                    I * b + J * f + K * j + L * n,
160                    I * c + J * g + K * k + L * o,
161                    I * d + J * h + K * l + L * p,
162                    M * a + N * e + O * i + P * m,
163                    M * b + N * f + O * j + P * n,
164                    M * c + N * g + O * k + P * o,
165                    M * d + N * h + O * l + P * p );
166     }
167 
168     Mat4 inverse() {
169       float a = _mat[0],  b = _mat[1],  c = _mat[2],  d = _mat[3],
170             e = _mat[4],  f = _mat[5],  g = _mat[6],  h = _mat[7],
171             i = _mat[8],  j = _mat[9],  k = _mat[10], l = _mat[11],
172             m = _mat[12], n = _mat[13], o = _mat[14], p = _mat[15],
173             q = a * f - b * e, r = a * g - c * e,
174             s = a * h - d * e, t = b * g - c * f,
175             u = b * h - d * f, v = c * h - d * g,
176             w = i * n - j * m, x = i * o - k * m,
177             y = i * p - l * m, z = j * o - k * n,
178             A = j * p - l * n, B = k * p - l * o,
179             ivd = 1 / (q * B - r * A + s * z + t * y - u * x + v * w);
180       return Mat4( ( f * B - g * A + h * z) * ivd,
181                    (-b * B + c * A - d * z) * ivd,
182                    ( n * v - o * u + p * t) * ivd,
183                    (-j * v + k * u - l * t) * ivd,
184                    (-e * B + g * y - h * x) * ivd,
185                    ( a * B - c * y + d * x) * ivd,
186                    (-m * v + o * s - p * r) * ivd,
187                    ( i * v - k * s + l * r) * ivd,
188                    ( e * A - f * y + h * w) * ivd,
189                    (-a * A + b * y - d * w) * ivd,
190                    ( m * u - n * s + p * q) * ivd,
191                    (-i * u + j * s - l * q) * ivd,
192                    (-e * z + f * x - g * w) * ivd,
193                    ( a * z - b * x + c * w) * ivd,
194                    (-m * t + n * r - o * q) * ivd,
195                    ( i * t - j * r + k * q) * ivd );
196     }
197 
198     @property {
199       float[16] mat() {
200         return _mat;
201       }
202 
203       Mat4 identity() {
204         return Mat4( 1, 0, 0, 0,
205                      0, 1, 0, 0,
206                      0, 0, 1, 0,
207                      0, 0, 0, 1 );
208       }
209     }
210 
211   private:
212     float[16] _mat;
213 }
214 
215 alias Quaternion Quat;
216 struct Quaternion {
217   public:
218     this(Vec3 vec3) {
219       set(vec3, 0.0);
220     }
221 
222     this(Vec3 vec3, in float rad) { // 回転行列の生成
223       rotate(vec3, rad);
224     }
225 
226     Quat opBinary(string op)(Quat quat) if (op == "*") {
227       auto rad = _rad*quat.rad - _vec3.dot(quat.vec3);
228       auto vec3 = _rad*quat.vec3 + quat.rad*_vec3 + _vec3.cross(quat.vec3);
229       Quat result;
230       result.set(vec3, rad);
231       return result;
232     }
233 
234     void set(in Vec3 vec3) {
235       _vec3 = vec3;
236     }
237 
238     void set(in float rad) {
239       _rad = rad;
240     }
241 
242     void set(in Vec3 vec3, in float rad) {
243       _rad = rad;
244       _vec3 = vec3;
245     }
246 
247     void rotate(Vec3 vec3, in float rad) {
248       vec3.normalize;
249 
250       _rad = cos(rad / 2);
251       _vec3 = Vec3( vec3.x * sin(rad / 2),
252                     vec3.y * sin(rad / 2),
253                     vec3.z * sin(rad / 2) );
254     }
255 
256     @property {
257       Quat conjugate() {
258         Quat quat;
259         quat.set(Vec3(-_vec3.x, -_vec3.y, -_vec3.z), rad); // TODO
260         return quat;
261       }
262 
263       Mat4 to_mat4() {
264         auto x = _vec3.x;
265         auto y = _vec3.y;
266         auto z = _vec3.z;
267         auto w = _rad;
268         return Mat4( 1-2*y^^2-2*z^^2, 2*x*y-2*w*z, 2*x*z+2*w*y, 0,
269                      2*x*y+2*w*z, 1-2*x^^2-2*z^^2, 2*y*z-2*w*x, 0,
270                      2*x*z-2*w*y, 2*y*z+2*w*x, 1-2*x^^2-2*y^^2, 0,
271                      0, 0, 0, 1 );
272       }
273 
274       float rad() {
275         return _rad;
276       }
277 
278       Vec3 vec3() {
279         return _vec3;
280       }
281     }
282 
283   private:
284     Vec3 _vec3;
285     float _rad;
286 }
287