1 module polyplex.math.simplemath.vectors;
2 import polyplex.utils.strutils;
3 import std.math, std.traits, std.string;
4 import polyplex.math.simplemath;
5 static import Mathf = polyplex.math.mathf;
6 
7 /**
8 	A 2 dimensional vector.
9 */
10 public struct Vector2T(T) if (isNumeric!(T)) {
11 	private alias GVector = typeof(this);
12 	public alias Type = T;
13 	enum Dimensions = 2;
14 
15 	/**
16 		Due to https://issues.dlang.org/show_bug.cgi?id=8006 this has to be flipped like this
17 
18 		TOOD: Replace with getter/setter structure once https://github.com/dlang/dmd/pull/7079 is merged.
19 	**/
20 	private @safe nothrow @property T* data() {
21 		return this.ptr;
22 	}
23 	
24 	private @property void data(T[Dimensions] data) {
25 		X = data[0];
26 		Y = data[1];
27 	}
28 
29 	/// The X component
30 	public T X = 0;
31 
32 	/// The Y component
33 	public T Y = 0;
34 
35 	/// Constructor
36 	this(T x) {
37 		this.X = x;
38 		this.Y = x;
39 	}
40 
41 	/// Constructor
42 	this(T x, T y) {
43 		this.X = x;
44 		this.Y = y;
45 	}
46 
47 	this(Vector3T!T vec) {
48 		this.X = vec.X;
49 		this.Y = vec.Y;
50 	}
51 
52 	this(Vector4T!T vec) {
53 		this.X = vec.X;
54 		this.Y = vec.Y;
55 	}
56 
57 	/**
58 		Pointer to the underlying array data.
59 	*/
60 	public T* ptr() { return &X; }
61 
62 	// Binary actions.
63 	public @trusted nothrow GVector opBinary(string op, T2)(T2 other) if (IsVector!T2) { 
64 		// Operation on these, (due to being smallest size) can be done faster this way.
65 		mixin(q{
66 			return GVector(
67 				this.X {0} other.X, 
68 				this.Y {0} other.Y);
69 			}.Format(op)
70 		); 
71 	}
72 
73 	// Binary actions numeric.
74 	public @trusted nothrow GVector opBinary(string op, T2)(T2 other) if (isNumeric!(T2)) {
75 		mixin(q{
76 			return GVector(
77 				this.X {0} other, 
78 				this.Y {0} other);
79 			}.Format(op)
80 		); 
81 	}
82 
83 	// Binary Action w/ assignment
84 	public @trusted nothrow void opOpAssign(string op, T2)(T2 other) if (isNumeric!(T2) || IsVector!(T2)) { 
85 		mixin(q{this = this {0} other;}.Format(op));
86 	}
87 
88 	/**
89 		Returns:
90 			The difference between the 2 vectors.
91 	**/
92 	public @trusted nothrow GVector Difference(T2)(T2 other) if (IsVector!T2) {
93 		return other-this;
94 	}
95 
96 	/**
97 		Returns:
98 			The distance between this and another vector.
99 	**/
100 	public @trusted nothrow T Distance(T2)(T2 other) if (IsVector!T2) {
101 		return (other-this).Length;
102 	}
103 
104 	/**
105 		Returns:
106 			The length/magnitude of this vector.
107 	**/
108 	public @trusted nothrow T Length() {
109 		T len = (X*X)+(Y*Y);
110 		return cast(T)Mathf.Sqrt(cast(float)len);
111 	}
112 
113 	/**
114 		Returns:
115 			A normalized version of this vector.
116 	**/
117 	public @trusted nothrow GVector Normalize() {
118 		GVector o;
119 		T len = Length();
120 		o.X = this.X/len;
121 		o.Y = this.Y/len;
122 		return o;
123 	}
124 
125 	/// Dot product of a vector.
126 	public @trusted nothrow T Dot(GVector other) {
127 		return (this.X*other.X)+(this.Y*other.Y);
128 	}
129 
130 	/**
131 		Returns:
132 			Initial (zero) state of this vector.
133 	**/
134 	public static GVector Zero() {
135 		return GVector(0, 0);
136 	}
137 
138 	/**
139 		Returns:
140 			Initial (one) state of this vector.
141 	**/
142 	public static GVector One() {
143 		return GVector(1, 1);
144 	}
145 	
146 	/**
147 		Returns:
148 			Up unit vector
149 	**/
150 	public static GVector Up() {
151 		return GVector(0, 1);
152 	}
153 
154 	/**
155 		Returns:
156 			Down unit vector
157 	**/
158 	public static GVector Down() {
159 		return GVector(0, -1);
160 	}
161 
162 	/**
163 		Returns:
164 			Left unit vector
165 	**/
166 	public static GVector Left() {
167 		return GVector(0, -1);
168 	}
169 
170 	/**
171 		Returns:
172 			Right unit vector
173 	**/
174 	public static GVector Right() {
175 		return GVector(0, 1);
176 	}
177 
178 	/**
179 		Returns:
180 			String representation of the array.
181 	**/
182 	public string ToString() {
183 		string o = "<";
184 		static foreach(i; 0 .. Dimensions) {
185 			switch(i) {
186 				case (Dimensions-1):
187 					o~= "{0}".Format(this.data[i]);
188 					break;
189 				default:
190 					o ~= "{0}, ".Format(this.data[i]);
191 					break;
192 			}
193 		}
194 		return o~">";
195 	}
196 
197 	/// Backwards compatiblity with glmath.
198 	alias toString = ToString;
199 }
200 
201 public struct Vector3T(T) if (isNumeric!T) {
202 	private alias GVector = typeof(this);
203 	public alias Type = T;
204 	enum Dimensions = 3;
205 
206 	/**
207 		Due to https://issues.dlang.org/show_bug.cgi?id=8006 this has to be flipped like this
208 
209 		TOOD: Replace with getter/setter structure once https://github.com/dlang/dmd/pull/7079 is merged.
210 	**/
211 	private @safe nothrow @property T* data() {
212 		return this.ptr;
213 	}
214 	
215 	private @property void data(T[Dimensions] data) {
216 		X = data[0];
217 		Y = data[1];
218 		Z = data[2];
219 	}
220 
221 	/// The X component
222 	public T X = 0;
223 
224 	/// The Y component
225 	public T Y = 0;
226 
227 	// The Z component
228 	public T Z = 0;
229 
230 	/// Constructor
231 	this(T x) {
232 		this.X = x;
233 		this.Y = x;
234 		this.Z = 0;
235 	}
236 
237 	/// Constructor
238 	this(T x, T y) {
239 		this.X = x;
240 		this.Y = y;
241 		this.Z = 0;
242 	}
243 
244 	/// Constructor
245 	this(T x, T y, T z) {
246 		this.X = x;
247 		this.Y = y;
248 		this.Z = z;
249 	}
250 
251 
252 	this(Vector2T!T vec) {
253 		this.X = vec.X;
254 		this.Y = vec.Y;
255 		this.Z = 0;
256 	}
257 
258 	this(Vector4T!T vec) {
259 		this.X = vec.X;
260 		this.Y = vec.Y;
261 		this.Z = vec.Z;
262 	}
263 
264 	/**
265 		Pointer to the underlying array data.
266 	*/
267 	public T* ptr() { return &X; }
268 
269 	/**
270 		Generic opBinary operation for Vectors.
271 	*/
272 	public @trusted nothrow GVector opBinary(string op, T2)(T2 other) if (IsVector!T2) {
273 		GVector o;
274 		// Get the length of the smallest vector
275 		
276 		static if (other.Dimensions < this.Dimensions) enum len = other.Dimensions;
277 		else enum len = this.Dimensions;
278 
279 		// Do the operations.
280 		static foreach(i; 0 .. len) {
281 			mixin(q{o.data[i] = this.data[i] {0} other.data[i];}.Format(op));
282 		}
283 		return o;
284 	}
285 
286 	// Binary actions numeric.
287 	public @trusted nothrow GVector opBinary(string op)(T other) if (isNumeric!(T)) {
288 		mixin(q{
289 			return GVector(
290 				this.X {0} other, 
291 				this.Y {0} other, 
292 				this.Z {0} other);
293 			}.Format(op)
294 		); 
295 	}
296 
297 	// Binary Action w/ assignment
298 	public @trusted nothrow void opOpAssign(string op)(T other) if (isNumeric!(T) || IsVector!(T)) { 
299 		mixin(q{this = this {0} other;}.Format(op));
300 	}
301 
302 	/**
303 		Returns:
304 			The difference between the 2 vectors.
305 	**/
306 	public @trusted nothrow GVector Difference(T2)(T2 other) if (IsVector!T2) {
307 		return other-this;
308 	}
309 
310 	/**
311 		Returns:
312 			The distance between this and another vector.
313 	**/
314 	public @trusted nothrow T Distance(T2)(T2 other) if (IsVector!T2) {
315 		return (other-this).Length;
316 	}
317 
318 	/**
319 		Returns:
320 			The length/magnitude of this vector.
321 	**/
322 	public @trusted nothrow T Length() {
323 		T len = (X*X)+(Y*Y)+(Z*Z);
324 		return cast(T)Mathf.Sqrt(cast(float)len);
325 	}
326 
327 	/**
328 		Returns:
329 			A normalized version of this vector.
330 	**/
331 	public @trusted nothrow GVector Normalize() {
332 		GVector o;
333 		T len = Length();
334 		static foreach(i; 0 .. Dimensions) {
335 			o.data[i] = this.data[i]/len;
336 		}
337 		return o;
338 	}
339 
340 	/// Dot product of a vector.
341 	public @trusted nothrow T Dot(GVector other) {
342 		return (this.X*other.X)+(this.Y*other.Y)+(this.Z*other.Z);
343 	}
344 
345 	/// Cross product of a vector.
346 	public @trusted nothrow GVector Cross(GVector other) {
347 		return GVector(
348 			(this.Y*other.Z)-(this.Z*other.Y),
349 			(this.Z*other.X)-(this.X*other.Z),
350 			(this.X*other.Y)-(this.Y*other.X));
351 	}
352 
353 	/**
354 		Returns:
355 			Initial (zero) state of this vector.
356 	**/
357 	public static Vector3T!(T) Zero() {
358 		return Vector3T!(T)(0, 0, 0);
359 	}
360 
361 	/**
362 		Returns:
363 			Initial (one) state of this vector.
364 	**/
365 	public static GVector One() {
366 		return GVector(1, 1, 1);
367 	}
368 
369 	/**
370 		Returns:
371 			Up unit vector
372 	**/
373 	public static GVector Up() {
374 		return GVector(0, -1, 0);
375 	}
376 
377 	/**
378 		Returns:
379 			Down unit vector
380 	**/
381 	public static GVector Down() {
382 		return GVector(0, 1, 0);
383 	}
384 
385 	/**
386 		Returns:
387 			Left unit vector
388 	**/
389 	public static GVector Left() {
390 		return GVector(0, -1, 0);
391 	}
392 
393 	/**
394 		Returns:
395 			Right unit vector
396 	**/
397 	public static GVector Right() {
398 		return GVector(0, 1, 0);
399 	}
400 
401 	/**
402 		Returns:
403 			Left unit vector
404 	**/
405 	public static GVector Forward() {
406 		return GVector(0, 0, -1);
407 	}
408 
409 	/**
410 		Returns:
411 			Right unit vector
412 	**/
413 	public static GVector Back() {
414 		return GVector(0, 0, 1);
415 	}
416 
417 	/**
418 		Returns:
419 			String representation of the array.
420 	**/
421 	public string ToString() {
422 		string o = "<";
423 		static foreach(i; 0 .. Dimensions) {
424 			switch(i) {
425 				case (Dimensions-1):
426 					o~= "{0}".Format(this.data[i]);
427 					break;
428 				default:
429 					o ~= "{0}, ".Format(this.data[i]);
430 					break;
431 			}
432 		}
433 		return o~">";
434 	}
435 	
436 	/// Backwards compatiblity with glmath.
437 	alias toString = ToString;
438 }
439 
440 public struct Vector4T(T) if (isNumeric!(T)) {
441 	private alias GVector = typeof(this);
442 	public alias Type = T;
443 	enum Dimensions = 4;
444 
445 	/**
446 		Due to https://issues.dlang.org/show_bug.cgi?id=8006 this has to be flipped like this
447 
448 		TOOD: Replace with getter/setter structure once https://github.com/dlang/dmd/pull/7079 is merged.
449 	**/
450 	private @safe nothrow @property T* data() {
451 		return this.ptr;
452 	}
453 
454 	private @property void data(T[Dimensions] data) {
455 		X = data[0];
456 		Y = data[1];
457 		Z = data[2];
458 		W = data[3];
459 	}
460 
461 	/// The X component
462 	public T X = 0;
463 
464 	/// The Y component
465 	public T Y = 0;
466 
467 	// The Z component
468 	public T Z = 0;
469 
470 	// The W component
471 	public T W = 0;
472 
473 	/// Constructor
474 	this(T x) {
475 		this.X = x;
476 		this.Y = x;
477 		this.Z = 0;
478 		this.W = 0;
479 	}
480 
481 	/// Constructor
482 	this(T x, T y) {
483 		this.X = x;
484 		this.Y = y;
485 		this.Z = 0;
486 		this.W = 0;
487 	}
488 
489 	/// Constructor
490 	this(T x, T y, T z) {
491 		this.X = x;
492 		this.Y = y;
493 		this.Z = z;
494 		this.W = 0;
495 	}
496 
497 	/// Constructor
498 	this(T x, T y, T z, T w) {
499 		this.X = x;
500 		this.Y = y;
501 		this.Z = z;
502 		this.W = w;
503 	}
504 
505 	this(Vector2T!T vec) {
506 		this.X = vec.X;
507 		this.Y = vec.Y;
508 		this.Z = 0;
509 		this.W = 0;
510 	}
511 
512 	this(Vector3T!T vec) {
513 		this.X = vec.X;
514 		this.Y = vec.Y;
515 		this.Z = vec.Z;
516 		this.W = 0;
517 	}
518 
519 	/**
520 		Pointer to the underlying array data.
521 	*/
522 	public T* ptr() { return &X; }
523 	
524 	/**
525 		Generic opBinary operation for Vectors.
526 	*/
527 	public @trusted nothrow GVector opBinary(string op, T2)(T2 other) if (IsVector!(T2)) {
528 		GVector o;
529 		// Get the length of the smallest vector
530 		
531 		static if (other.Dimensions < this.Dimensions) enum len = other.Dimensions;
532 		else enum len = this.Dimensions;
533 
534 		// Do the operations.
535 		static foreach(i; 0 .. len) {
536 			mixin(q{o.data[i] = this.data[i] {0} other.data[i];}.Format(op));
537 		}
538 		return o;
539 	}
540 	
541 	// Binary actions numeric.
542 	public @trusted nothrow GVector opBinary(string op)(T other) if (isNumeric!(T)) {
543 		mixin(q{
544 			return GVector(
545 				this.X {1} other, 
546 				this.Y {1} other, 
547 				this.Z {1} other, 
548 				this.W {1} other);
549 			}.Format(T.stringof, op)
550 		); 
551 	}
552 
553 	// Binary Action w/ assignment
554 	public @trusted nothrow void opOpAssign(string op, T2)(T2 other) if (isNumeric!(T2) || IsVector!(T2)) { 
555 		mixin(q{this = this {0} other;}.Format(op));
556 	}
557 
558 	/**
559 		Returns:
560 			The difference between the 2 vectors.
561 	**/
562 	public @trusted nothrow GVector Difference(T2)(T2 other) if (IsVector!T2){
563 		return other-this;
564 	}
565 
566 	/**
567 		Returns:
568 			The distance between this and another vector.
569 	**/
570 	public @trusted nothrow T Distance(T2)(T2 other) if (IsVector!T2) {
571 		return (other-this).Length;
572 	}
573 
574 	/**
575 		Returns:
576 			The length/magnitude of this vector.
577 	**/
578 	public @trusted nothrow T Length() {
579 		T len = (X*X)+(Y*Y)+(Z*Z)+(W*W);
580 		return cast(T)Mathf.Sqrt(cast(float)len);
581 	}
582 
583 	/**
584 		Returns:
585 			A normalized version of this vector.
586 	**/
587 	public @trusted nothrow GVector Normalize() {
588 		GVector o;
589 		T len = Length();
590 		static foreach(i; 0 .. Dimensions) {
591 			o.data[i] = this.data[i]/len;
592 		}
593 		return o;
594 	}
595 
596 	/// Dot product of a vector.
597 	public @trusted nothrow T Dot(GVector other) {
598 		return (this.X*other.X)+(this.Y*other.Y)+(this.Z*other.Z)+(this.W*other.W);
599 	}
600 
601 	/**
602 		Returns:
603 			Initial (zero) state of this vector.
604 	**/
605 	public static GVector Zero() {
606 		return GVector(0, 0, 0, 0);
607 	}
608 
609 	/**
610 		Returns:
611 			Initial (one) state of this vector.
612 	**/
613 	public static GVector One() {
614 		return GVector(1, 1, 1, 1);
615 	}
616 
617 	/**
618 		Returns:
619 			String representation of the array.
620 	**/
621 	public string ToString() {
622 		string o = "<";
623 		static foreach(i; 0 .. Dimensions) {
624 			switch(i) {
625 				case (Dimensions-1):
626 					o~= "{0}".Format(this.data[i]);
627 					break;
628 				default:
629 					o ~= "{0}, ".Format(this.data[i]);
630 					break;
631 			}
632 		}
633 		return o~">";
634 	}
635 	
636 	/// Backwards compatiblity with glmath.
637 	alias toString = ToString;
638 }
639 
640 // Copied from the GLMath implementation, checks if T is a Vector2T
641 enum IsVector2T(T) = is(T : Vector2T!U, U...);
642 
643 // Copied from the GLMath implementation, checks if T is a Vector3T
644 enum IsVector3T(T) = is(T : Vector3T!U, U...);
645 
646 // Copied from the GLMath implementation, checks if T is a Vector4T
647 enum IsVector4T(T) = is(T : Vector4T!U, U...);
648 
649 //Combination of all IsVector
650 enum IsVector(T) = (IsVector2T!T || IsVector3T!T || IsVector4T!T);
651 
652 alias Vector2 = Vector2T!float;
653 alias Vector2i = Vector2T!int;
654 alias Vector3 = Vector3T!float;
655 alias Vector3i = Vector3T!int;
656 alias Vector4 = Vector4T!float;
657 alias Vector4i = Vector4T!int;