1 module armos.math.vector;
2 import armos.math;
3 import core.vararg;
4 import std.math;
5 import std.stdio;
6 
7 version(D_SIMD) {
8     import core.simd;
9     enum SIMD_Enable = true;
10 }
11 else {
12     enum SIMD_Enable = false;
13 }
14 
15 /++
16 ベクトル計算を行うstructです
17 +/
18 struct Vector(T, int Dimention)if(__traits(isArithmetic, T) && Dimention > 0){
19     private alias Vector!(T, Dimention) VectorType;
20 
21     enum XMMRegisterSize = 16;
22     enum PackSize = XMMRegisterSize / T.sizeof;
23     enum XMMsNum = Dimention % PackSize == 1 || Dimention % PackSize == 0 ?
24         Dimention / PackSize :
25         Dimention / PackSize + 1;
26     enum XMMsSize = XMMsNum * PackSize;
27 
28     union PackedElements{
29         T[Dimention] arr;
30         static if (!is(T == real) && Dimention > 1) {
31             static if (XMMsNum == 1){
32                 __vector(T[PackSize]) vec;
33             }
34             else {
35                 __vector(T[PackSize])[XMMsNum] vec;
36             }
37         }
38     }
39 
40 
41     private template Compute (string Base) {
42         import std.format : format;
43         static if (Dimention > 1) {
44             enum XMMComputeBase = format("if(__ctfe){%s}else{%%s}",format(Base,"arr[]"));
45             static if (XMMsNum == 1) {
46                 enum ComputeXMM = format(Base,"vec");
47             }
48             else {
49                 enum ComputeXMM = expandFor!(format(Base,"vec[%1$d]"),XMMsNum);
50             }
51             static if (Dimention <= XMMsSize) {
52                 enum Compute = format(XMMComputeBase,ComputeXMM);
53             }
54             else static if (Dimention == XMMsSize + 1) {
55                 enum Compute = format(XMMComputeBase,ComputeXMM ~ format(Base,"arr[$-1]"));
56             }
57             else {
58                 static assert (false,"illegal PackedElements!");
59             }
60         }
61         else {
62             enum Compute = format(Base,"arr[0]");
63         }
64     }
65     unittest {
66         static assert(Vector!(int,3).Compute!("x.%1$s+y.%1$s;") == "if(__ctfe){x.arr[]+y.arr[];}else{x.vec+y.vec;}");
67         static assert(Vector!(int,4).Compute!("x.%1$s+y.%1$s;") == "if(__ctfe){x.arr[]+y.arr[];}else{x.vec+y.vec;}");
68         static assert(Vector!(int,5).Compute!("x.%1$s+y.%1$s;") == "if(__ctfe){x.arr[]+y.arr[];}else{x.vec+y.vec;x.arr[$-1]+y.arr[$-1];}");
69         static assert(Vector!(int,6).Compute!("x.%1$s+y.%1$s;") == "if(__ctfe){x.arr[]+y.arr[];}else{x.vec[0]+y.vec[0];x.vec[1]+y.vec[1];}");
70         static assert(Vector!(int,9).Compute!("x.%1$s+y.%1$s;") == "if(__ctfe){x.arr[]+y.arr[];}else{x.vec[0]+y.vec[0];x.vec[1]+y.vec[1];x.arr[$-1]+y.arr[$-1];}");
71     }
72     unittest {
73     }
74 
75     PackedElements packedElements;
76         
77     // T[Dimention] elements = packedElements.arr[];
78     ref T[Dimention] elements()const{
79         return packedElements.arr[];
80     }
81 
82     //T[Dimention] packedElements = T.init;
83     ///
84     enum int dimention = Dimention;
85     unittest{
86         static assert(Vector!(float, 3).dimention == 3);
87     }
88 
89     alias elementType = T;
90     unittest{
91         static assert(is(Vector!(float, 3).elementType == float));
92     }
93 
94     enum string coordNames = "xyzw";
95 
96     static if (Dimention <= coordNames.length){
97         enum string coordName = coordNames[0..Dimention];
98     }else{
99         enum string coordName = "";
100     }
101     unittest{
102         static assert(Vector!(float,3).coordName == "xyz");
103     }
104 
105     /++
106         Vectorのinitializerです.引数はDimentionと同じ個数の要素を取ります.
107     +/
108     this(T[] arr ...)in{
109         assert(arr.length == 0 || arr.length == Dimention);
110     }body{
111             if(arr.length != 0){
112                 packedElements.arr = arr;
113             }
114         }
115 
116 
117     /++
118     +/
119     pure T opIndex(in size_t index)const{
120         return packedElements.arr[index];
121     }
122 
123     /++
124     +/
125     ref T opIndex(in size_t index){
126         return packedElements.arr[index];
127     }
128     unittest{
129         auto vec = Vector3d(1, 2, 3);
130         assert(vec[0] == 1.0);
131         assert(vec[1] == 2.0);
132         assert(vec[2] == 3.0);
133     }
134 
135     // pure const bool opEquals(Object vec){
136     //  foreach (int index, T v; (cast(VectorType)vec).packedElements.arr) {
137     //      if(v != this.packedElements.arr[index]){
138     //          return false;
139     //      }
140     //  }
141     //  return true;
142     // }
143     unittest{
144         auto vec1 = Vector3d(1, 2, 3);
145         auto vec2 = Vector3d(1, 2, 3);
146         assert(vec1 == vec2);
147     }
148     unittest{
149         auto vec1 = Vector3d(1, 2, 3);
150         auto vec2 = Vector3d(2, 2, 1);
151         assert(vec1 != vec2);
152     }
153 
154     /++
155     +/
156     enum VectorType zero = (){
157         VectorType v;
158         v.packedElements.arr[] = T(0);
159         return v;
160     }();
161     unittest{
162         auto vec = Vector3d.zero;
163         assert(vec[0] == 0);
164         assert(vec[1] == 0);
165         assert(vec[2] == 0);
166     }
167 
168     /++
169     +/
170     VectorType opNeg()const{
171         auto result = VectorType();
172         static if (SIMD_Enable && !is(T == real))
173             mixin(Compute!("result.packedElements.%1$s = -packedElements.%1$s;"));
174         else
175             result.packedElements.arr[] = -packedElements.arr[];
176         return result;
177     };
178     unittest{
179         auto vec1 = Vector3d();
180         vec1[0] = 1.5;
181         assert(vec1[0] == 1.5);
182         assert((-vec1)[0] == -1.5);
183     }
184 
185     /++
186     +/
187     VectorType opAdd(in VectorType r)const{
188         auto result = VectorType();
189         static if (SIMD_Enable && !is(T == real))
190             mixin(Compute!("result.packedElements.%1$s = packedElements.%1$s + r.packedElements.%1$s;"));
191         else
192             result.packedElements.arr[] = packedElements.arr[] + r.packedElements.arr[];
193         return result;
194     }
195     unittest{
196         auto vec1 = Vector3d();
197         vec1[0] = 1.5;
198 
199         auto vec2 = Vector3d();
200         vec2[1] = 0.2;
201         vec2[0] = 0.2;
202         assert((vec1+vec2)[0] == 1.7);
203     }
204 
205     /++
206     +/
207     VectorType opSub(in VectorType r)const{
208         auto result = VectorType();
209         static if (SIMD_Enable && !is(T == real))
210             mixin(Compute!("result.packedElements.%1$s = packedElements.%1$s - r.packedElements.%1$s;"));
211         else
212             result.packedElements.arr[] = packedElements.arr[] - r.packedElements.arr[];
213         return result;
214     }
215     unittest{
216         auto result = Vector3d(3, 2, 1) - Vector3d(1, 2, 3);
217         assert(result == Vector3d(2, 0, -2));
218     }
219 
220     /++
221     +/
222     VectorType opAdd(in T v)const{
223         auto result = VectorType();
224         static if (SIMD_Enable && !is(T == real)) {
225             PackedElements packedV;
226             packedV.arr[] = v;
227             mixin(Compute!("result.packedElements.%1$s = packedElements.%1$s + packedV.%1$s;"));
228         }
229         else
230             result.packedElements.arr[] = packedElements.arr[] + v;
231         return result;
232     }
233     unittest{
234         auto result = Vector3d(3.0, 2.0, 1.0);
235         assert(result+2.0 == Vector3d(5.0, 4.0, 3.0));
236         assert(2.0+result == Vector3d(5.0, 4.0, 3.0));
237     }
238 
239     /++
240     +/
241     VectorType opSub(in T v)const{
242         auto result = VectorType();
243         static if (SIMD_Enable && !is(T == real)) {
244             PackedElements packedV;
245             packedV.arr[] = v;
246             mixin(Compute!("result.packedElements.%1$s = packedElements.%1$s - packedV.%1$s;"));
247         }
248         else
249             result.packedElements.arr[] = packedElements.arr[] - v;
250         return result;
251     }
252     unittest{
253         auto result = Vector3d(3.0, 2.0, 1.0);
254         assert(result-2.0 == Vector3d(1.0, 0.0, -1.0));
255     }
256 
257     /++
258     +/
259     VectorType opMul(in T v)const{
260         auto result = VectorType();
261         static if (SIMD_Enable && (is(T == float) || is(T == double) || is(T == short) || is(T == ushort))) {
262             PackedElements packedV;
263             packedV.arr[] = v;
264             mixin(Compute!("result.packedElements.%1$s = packedElements.%1$s * cast(const)packedV.%1$s;"));
265         }
266         else
267             result.packedElements.arr[] = packedElements.arr[] * v;
268         return result;
269     }
270     unittest{
271         auto result = Vector3d(3.0, 2.0, 1.0);
272         assert(result*2.0 == Vector3d(6.0, 4.0, 2.0));
273         assert(2.0*result == Vector3d(6.0, 4.0, 2.0));
274     }
275 
276     /++
277     +/
278     VectorType opDiv(in T v)const{
279         auto result = VectorType();
280         static if (SIMD_Enable && (is(T == float) || is(T == double))) {
281             PackedElements packedV;
282             packedV.arr[] = v;
283             mixin(Compute!("result.packedElements.%1$s = packedElements.%1$s / packedV.%1$s;"));
284         }
285         else
286             result.packedElements.arr[] = packedElements.arr[] / v;
287         return result;
288     }
289     unittest{
290         auto result = Vector3d(3.0, 2.0, 1.0);
291         assert(result/2.0 == Vector3d(1.5, 1.0, 0.5));
292     }
293 
294     /++
295     +/
296     VectorType opMod(in T v)const{
297         auto result = VectorType();
298         result.packedElements.arr[] = packedElements.arr[] % v;
299         return result;
300     }
301     unittest{
302         auto result = Vector3d(4.0, 2.0, 1.0);
303         assert(result%2.0 == Vector3d(0.0, 0.0, 1.0));
304     }
305 
306     /++
307     +/
308     VectorType opMul(in VectorType v)const{
309         auto result = VectorType();
310         static if (SIMD_Enable && (is(T == float) || is(T == double) || is(T == short) || is(T == ushort)))
311             mixin(Compute!("result.packedElements.%1$s = packedElements.%1$s * v.packedElements.%1$s;"));
312         else
313             result.packedElements.arr[] = packedElements.arr[] * v.packedElements.arr[];
314         return result;
315     }
316     unittest{
317         auto vec1 = Vector3d(3.0, 2.0, 1.0);
318         auto vec2 = Vector3d(2.0, 1.0, 0.0);
319         assert(vec1*vec2 == Vector3d(6.0, 2.0, 0.0));
320     }
321 
322     /++
323     +/
324     VectorType opDiv(in VectorType v)const{
325         auto result = VectorType();
326         static if (SIMD_Enable && (is(T == float) || is(T == double)))
327             mixin(Compute!("result.packedElements.%1$s = packedElements.%1$s / v.packedElements.%1$s;"));
328         else
329             result.packedElements.arr[] = packedElements.arr[] / v.packedElements.arr[];
330         return result;
331     }
332     unittest{
333         auto vec1 = Vector3d(4.0, 2.0, 1.0);
334         auto vec2 = Vector3d(2.0, 1.0, 1.0);
335         assert(vec1/vec2 == Vector3d(2.0, 2.0, 1.0));
336     }
337 
338     /++
339     +/
340     VectorType opMod(in VectorType v)const{
341         auto result = VectorType();
342         result.packedElements.arr[] = packedElements.arr[] % v.packedElements.arr[];
343         return result;
344     }
345     unittest{
346         auto vec1 = Vector3d(3.0, 2.0, 1.0);
347         auto vec2 = Vector3d(2.0, 1.0, 1.0);
348         assert(vec1%vec2 == Vector3d(1.0, 0.0, 0.0));
349     }
350 
351     /++
352     +/
353     void opAddAssign(in VectorType v){
354         static if (SIMD_Enable && !is(T == real))
355             mixin(Compute!("packedElements.%1$s += v.packedElements.%1$s;"));
356         else
357             packedElements.arr[] += v.packedElements.arr[];
358     }
359     unittest{
360         auto vec1 = Vector3d(1.0,2.0,3.0);
361         auto vec2 = Vector3d(1.0,1.0,2.0);
362         vec1 += vec2;
363         assert(vec1 == Vector3d(2.0,3.0,5.0));
364     }
365 
366     /++
367     +/
368     void opSubAssign(in VectorType v){
369         static if (SIMD_Enable && !is(T == real))
370             mixin(Compute!("packedElements.%1$s -= v.packedElements.%1$s;"));
371         else
372             packedElements.arr[] -= v.packedElements.arr[];
373     }
374     unittest{
375         auto vec1 = Vector3d(5.0,4.0,3.0);
376         auto vec2 = Vector3d(3.0,2.0,1.0);
377         vec1 -= vec2;
378         assert(vec1 == Vector3d(2.0,2.0,2.0));
379     }
380 
381     /++
382     +/
383     void opAddAssign(in T v){
384         static if (SIMD_Enable && !is(T == real)) {
385             PackedElements packedV;
386             packedV.arr[] = v;
387             mixin(Compute!("packedElements.%1$s += packedV.%1$s;"));
388         }
389         else
390             packedElements.arr[] += v;
391     }
392     unittest{
393         auto vec1 = Vector3d(1.0,2.0,3.0);
394         vec1 += 1.0;
395         assert(vec1 == Vector3d(2.0,3.0,4.0));
396     }
397 
398     /++
399     +/
400     void opSubAssign(in T v){
401         static if (SIMD_Enable && !is(T == real)) {
402             PackedElements packedV;
403             packedV.arr[] = v;
404             mixin(Compute!("packedElements.%1$s -= packedV.%1$s;"));
405         }
406         else
407             packedElements.arr[] -= v;
408     }
409     unittest{
410         auto vec1 = Vector3d(2.0,3.0,4.0);
411         vec1 -= 3.0;
412         assert(vec1 == Vector3d(-1.0,0.0,1.0));
413     }
414 
415     /++
416     +/
417     void opModAssign(in T v){
418         packedElements.arr[] %= v;
419     }
420     unittest{
421         auto vec1 = Vector3d(4.0,5.0,6.0);
422         vec1 %= 3.0;
423         assert(vec1 == Vector3d(1.0,2.0,0.0));
424     }
425 
426     /++
427     +/
428     void opDivAssign(in T v){
429         static if (SIMD_Enable && (is(T == float) || is(T == double))) {
430             PackedElements packedV;
431             packedV.arr[] = v;
432             mixin(Compute!("packedElements.%1$s /= packedV.%1$s;"));
433         }
434         else
435             packedElements.arr[] /= v;
436     }
437     unittest{
438         auto vec1 = Vector3d(3.0,4.0,5.0);
439         vec1 /= 2.0;
440         assert(vec1 == Vector3d(1.5,2.0,2.5));
441     }
442 
443     /++
444     +/
445     void opMulAssign(in T v){
446         static if (SIMD_Enable && (is(T == float) && is(T == double) && is(T == short) && is(T == ushort))) {
447             PackedElements packedV;
448             packedV.arr[] = v;
449             mixin(Compute!("packedElements.%1$s *= packedV.%1$s;"));
450         }
451         else 
452             packedElements.arr[] *= v;
453     }
454     unittest{
455         auto vec1 = Vector3d(2.0,-1.0,1.0);
456         vec1 *= 3.0;
457         assert(vec1 == Vector3d(6.0,-3.0,3.0));
458     }
459 
460     /++
461     +/
462     void opModAssign(in VectorType v){
463         packedElements.arr[] %= v.packedElements.arr[];
464     }
465     unittest{
466         auto vec1 = Vector3d(3.0,2.0,1.0);
467         auto vec2 = Vector3d(2.0,1.0,1.0);
468         vec1 %= vec2;
469         assert(vec1 == Vector3d(1.0,0.0,0.0));
470     }
471 
472     /++
473     +/
474     void opDivAssign(in VectorType v){
475         static if (SIMD_Enable && (is(T == double) || is(T == float)))
476             mixin(Compute!("packedElements.%1$s /= v.packedElements.%1$s;"));
477         else
478             packedElements.arr[] /= v.packedElements.arr[];
479     }
480     unittest{
481         auto vec1 = Vector3d(4.0,2.0,1.0);
482         auto vec2 = Vector3d(2.0,1.0,1.0);
483         vec1 /= vec2;
484         assert(vec1 == Vector3d(2.0,2.0,1.0));
485     }
486 
487     /++
488     +/
489     void opMulAssign(in VectorType v){
490         static if (SIMD_Enable && (is(T == float) || is(T == double) || is(T == short) || is(T == ushort)))
491             mixin(Compute!("packedElements.%1$s *= v.packedElements.%1$s;"));
492         else
493             packedElements.arr[] *= v.packedElements.arr[];
494     }
495     unittest{
496         auto vec1 = Vector3d(3.0,2.0,1.0);
497         auto vec2 = Vector3d(2.0,1.0,0.0);
498         vec1 *= vec2;
499         assert(vec1 == Vector3d(6.0,2.0,0.0));
500     }
501 
502     /++
503         Vectorのノルムを返します.
504     +/
505     T norm()const{
506         import std.numeric : dotProduct;
507         immutable T sumsq = dotProduct(packedElements.arr, packedElements.arr);
508 
509         static if(__traits(isFloating, T)){
510             return sqrt(sumsq);
511         }else{
512             return cast(T)sqrt(cast(float)sumsq);
513         }
514     }
515     unittest{
516         auto result = Vector3d(3.0, 2.0, 1.0);
517         assert(result.norm() == ( 3.0^^2.0+2.0^^2.0+1.0^^2.0 )^^0.5);
518     }
519 
520     /++
521         Vectorのドット積を返します.
522     +/
523     T dotProduct(in VectorType v)const{
524         //v1 * v2 = v1.x * v2.x + v1.y * v2.y + v1.z * v2.z ...
525         //product = (v1.x * v2.x, v1.y * v2.y, v1.z * v2.z)
526         import std.algorithm.iteration : map;
527         import std.range : iota,join;
528         import std.format : format;
529         auto product = this * v;
530         //expand to "auto result = product.packedElements.arr[0] + product.packedElements.arr[1] + product.packedElements.arr[2] + ..."
531         mixin("return "~Dimention
532                         .iota
533                         .map!(idx => format("product.packedElements.arr[%d]",idx))
534                         .join('+')
535                         ~ ";");
536     }
537     unittest{
538         auto vec1 = Vector3d(3.0, 2.0, 1.0);
539         auto vec2 = Vector3d(2.0, 1.0, 2.0);
540         assert(vec1.dotProduct(vec2) == 10.0);
541     }
542 
543     unittest{
544         auto vec1 = Vector3d(0.4, 0.1, 0.3);
545         auto vec2 = Vector3d(0.2, 0.5, 2.0);
546         assert(vec1.dotProduct(vec2) == 0.73);
547     }
548 
549     /++
550         Vectorのベクトル積(クロス積,外積)を返します.
551         Dimentionが3以上の場合のみ使用できます.
552     +/
553     static if (Dimention == 3){
554         VectorType vectorProduct(in VectorType v)const{
555             return VectorType(
556                 elements[1]*v[2] - elements[2]*v[1], 
557                 elements[2]*v[0] - elements[0]*v[2], 
558                 elements[0]*v[1] - elements[1]*v[0], 
559             );
560         }
561     }
562 
563     static if (Dimention > 3){
564         VectorType vectorProduct(in VectorType[] arg ...)const in{
565             assert(arg.length == Dimention-2);
566         }body{
567             auto return_vector = VectorType.zero;
568             foreach (int i, ref T v; return_vector.packedElements.arr) {
569                 auto matrix = armos.math.Matrix!(T, Dimention, Dimention)();
570                 auto element_vector = VectorType.zero;
571                 element_vector[i] = T(1);
572                 matrix.setRowVector(0, element_vector);
573                 matrix.setRowVector(1, this);
574                 for (int j = 2; j < Dimention; j++) {
575                     matrix.setRowVector(j, arg[j-2]);
576                 }
577                 // matrix.setColumnVector(i+1, this);
578                 v = matrix.determinant;
579             }
580             return return_vector;
581         }
582     }
583     unittest{
584         auto vector0 = Vector3f(1, 2, 3);
585         auto vector1 = Vector3f(4, 5, 6);
586         auto anser = Vector3f(-3, 6, -3);
587         assert(vector0.vectorProduct(vector1) == anser);
588     }
589 
590     /++
591         VectorとVectorの成す角を求めます
592     +/
593     auto angle(in VectorType v)const{
594         /+
595         v1 * v2 = |v1| * |v2| * cosθ
596         θ = acos((v1 * v2) / (|v1| * |v2|))
597         |v1| = √(v1.x^2 + v1.y^2 + v1.z^2 ...) = √(v1 * v1)
598         norm_product = |v1| * |v2| = √(v1*v1 * v2*v2)
599         dotProduct = v1 * v2
600         +/
601         auto innerProduct = dotProduct(v);
602         auto normProduct = dotProduct(this) * v.dotProduct(v);
603         static if (__traits(isIntegral,T)) {
604             return acos(cast(float)innerProduct / sqrt(cast(float)normProduct));
605         }
606         else {
607             return acos (innerProduct / sqrt(normProduct));
608         }
609     }
610     unittest {
611         auto v1 = Vector2i(3,0);
612         auto v2 = Vector2i(0,5);
613         assert (approxEqual(v1.angle(v2),PI/2));
614 
615         auto v3 = Vector3d(1.0 * cos(PI*1/6), 1.0 * sin(PI*1/6),0.0);
616         auto v4 = Vector3d(2.0 * cos(PI*5/6), 2.0 * sin(PI*5/6),0.0);
617         assert (approxEqual(v3.angle(v4),PI*2/3));
618 
619         auto v5 = Vector2i(3,0);
620         auto v6 = Vector2i(0,-5);
621         assert (approxEqual(v5.angle(v6),PI/2));
622 
623         auto v7 = Vector2i(3,0);
624         auto v8 = Vector2i(-5,-5);
625         assert (approxEqual(v7.angle(v8),PI*3/4));
626     }
627 
628     /++
629         正規化したVectorを返します.
630     +/
631     VectorType normalized()const{
632         return this/this.norm();
633     }
634     unittest{
635         auto vec1 = Vector3d(3.0, 2.0, 1.0);
636         assert(vec1.normalized().norm() == 1.0);
637     }
638 
639     /++
640         Vectorを正規化します.
641     +/
642     void normalize(){
643         static if (SIMD_Enable && (is(T == float) || is(T == double))) {
644             PackedElements packedNorm;
645             packedNorm.arr[] = this.norm();
646             mixin(Compute!("this.packedElements.%1$s /= packedNorm.%1$s;"));
647         }
648         else
649             this.packedElements.arr[] /= this.norm();
650     }
651     unittest{
652         auto vec1 = Vector3d(3.0, 2.0, 1.0);
653         vec1.normalize();
654         assert(vec1.norm() == 1.0);
655     }
656 
657     /++
658         Vectorの要素を一次元配列で返します.
659     +/
660     T[Dimention] array()const{
661         return packedElements.arr;
662     }
663     unittest{
664         auto vector = Vector3f(1, 2, 3);
665         float[3] array = vector.array;
666         assert(array == [1, 2, 3]);
667         array[0] = 4;
668         assert(array == [4, 2, 3]);
669         assert(vector == Vector3f(1, 2, 3));
670     }
671 
672     /++
673     +/
674     string toString()const{
675         import std.conv;
676         return typeid(this).to!string ~ "(" ~ packedElements.arr.to!string ~ ")";
677     }
678 
679     /++
680         自身を別の型のVectorへキャストしたものを返します.キャスト後の型は元のVectorと同じ次元である必要があります.
681     +/
682     CastType opCast(CastType)()const if(CastType.dimention == dimention){
683         auto vec = CastType();
684         foreach (int index, const T var; packedElements.arr) {
685             vec.packedElements.arr[index] = cast( typeof( vec.packedElements.arr[0] ) )packedElements.arr[index];
686         }
687         return vec;
688     }
689 
690     unittest{
691         auto vec_f = Vector3f(2.5, 0, 0);
692         auto vec_i = Vector3i(0, 0, 0);
693 
694         vec_i = cast(Vector3i)vec_f;
695 
696         assert(vec_i[0] == 2);
697 
698         //Invalid cast. Different size.
699         assert(!__traits(compiles, {
700             auto vec_f = Vector2f(2.5, 0);
701             auto vec_i = Vector3i(0, 0, 0);
702             vec_i = cast(Vector3i)vec_f;
703         }));
704     }
705 
706     /++
707         vec.x vec.xyのようにベクトルの一部を切り出すことが出来ます
708     +/
709     @property auto opDispatch(string swizzle)()const if (swizzle.length > 0 && swizzle.length < coordName.length && coordName.length > 0) {
710         import std.string : indexOf,join;
711         import std.array : array;
712         import std.conv : to;
713         import std.algorithm.iteration : map;
714 
715         static if (swizzle.length == 1) {
716             enum index = coordName.indexOf(swizzle[0]);
717             static if (index >= 0){
718                 return packedElements.arr[index];
719             }
720         } else {
721             enum int[] indecies = swizzle.map!(axis => coordName.indexOf(axis)).array;
722             mixin("return Vector!(T,swizzle.length)("~indecies.map!(index => "packedElements.arr["~index.to!string~"]").array.join(',')~");");
723         }
724     }
725     
726     /++
727     +/
728     @property void opDispatch(string swizzle)(in T v) if (swizzle.length == 1 && coordName.length > 0) {
729         import std.string : indexOf;
730         enum index = coordName.indexOf(swizzle[0]);
731         static if (index >= 0) {
732             packedElements.arr[index] = v;
733         }else{
734             static assert (false);
735         }
736     }
737 
738     /++
739     +/
740     @property void opDispatch(string swizzle,V)(in V v) if (swizzle.length > 0 && swizzle.length < coordName.length && coordName.length > 0 && isVector!V) {
741         import std.string : indexOf;
742         import std.array : array;
743         import std.conv : to;
744         import std.range : iota,zip;
745         import std.algorithm.iteration : map,reduce;
746         import std.traits;
747         static if (is(T == Unqual!(typeof(v.packedElements.arr[0])))){
748             enum indecies = swizzle.map!(charcter => coordName.indexOf(charcter)).array;
749             mixin(swizzle.length.iota
750                         .zip(indecies)
751                         .map!(pair => "packedElements.arr["~pair[1].to!string~"] = v.packedElements.arr["~pair[0].to!string~"];")
752                         .reduce!"a~b"
753                         );
754          }
755     }
756 }
757 
758 unittest{
759     auto vec = Vector3f(1.0,2.0,3.0);
760 
761     assert(vec.x == 1.0);
762     assert(vec.z == 3.0);
763 
764     assert(vec.xy == Vector2f(1.0,2.0));
765     assert(vec.zx == Vector2f(3.0,1.0));
766 
767     static assert (!__traits(compiles, vec.xw));
768 }
769 
770 unittest{
771     const vec = Vector3f(1.0,2.0,3.0);
772 
773     assert(vec.x == 1.0);
774     assert(vec.z == 3.0);
775 
776     assert(vec.xy == Vector2f(1.0,2.0));
777     assert(vec.zx == Vector2f(3.0,1.0));
778 }
779 
780 unittest{
781     auto vec = Vector3f(1.0,2.0,3.0);
782     vec.x = 4.0;
783     assert (vec == Vector3f(4.0,2.0,3.0));
784 
785     static assert (!__traits(compiles,vec.w = 1.0));
786 }
787 
788 unittest{
789     auto vec = Vector3f(2.0,4.0,6.0);
790     vec.yx = Vector2f(0.0,1.0);
791     assert (vec == Vector3f(1.0,0.0,6.0));
792 
793     static assert (!__traits(compiles,vec.xw = Vector2f(0.0,0.0)));
794 }
795 
796 /// int型の2次元ベクトルです.
797 alias Vector!(int, 2) Vector2i;
798 /// int型の3次元ベクトルです.
799 alias Vector!(int, 3) Vector3i;
800 /// int型の4次元ベクトルです.
801 alias Vector!(int, 4) Vector4i;
802 /// float型の2次元ベクトルです.
803 alias Vector!(float, 2) Vector2f;
804 /// float型の3次元ベクトルです.
805 alias Vector!(float, 3) Vector3f;
806 /// float型の4次元ベクトルです.
807 alias Vector!(float, 4) Vector4f;
808 /// double型の2次元ベクトルです.
809 alias Vector!(double, 2) Vector2d;
810 /// double型の3次元ベクトルです.
811 alias Vector!(double, 3) Vector3d;
812 /// double型の4次元ベクトルです.
813 alias Vector!(double, 4) Vector4d;
814 
815 /++
816 +/
817 template isVector(V) {
818     public{
819         enum bool isVector = __traits(compiles, (){
820                 static assert(is(V == Vector!(typeof(V()[0]), V.dimention)));
821                 });
822     }//public
823 }//template isVector
824 unittest{
825     static assert(isVector!(Vector!(float, 3)));
826     static assert(!isVector!(float));
827 }
828 
829 
830 private template expandFor(string stmt,size_t Limit) {
831     import std.algorithm.iteration : map;
832     import std.range : iota,repeat,join,zip;
833     import std.format : format;
834     enum expandFor = Limit
835                     .iota
836                     .map!(idx => format(stmt,idx))
837                     .join;
838 }
839 unittest {
840     static assert (expandFor!("xs[%1$d] + ys[%1$d];",3) == "xs[0] + ys[0];xs[1] + ys[1];xs[2] + ys[2];");
841 }