1 /*
2  * Copyright (c) 2017-2018 sel-project
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  *
22  */
23 /**
24  * Copyright: 2017-2018 sel-project
25  * License: MIT
26  * Authors: Kripth
27  * Source: $(HTTP github.com/sel-project/selery/source/selery/math/vector.d, selery/math/vector.d)
28  */
29 module selery.math.vector;
30 
31 import std.algorithm : reverse, canFind;
32 import std.array : join, split;
33 import std.conv : to, ConvException;
34 static import std.math;
35 import std.meta : staticIndexOf;
36 import std.range.primitives : ElementType;
37 import std.string : replace;
38 import std.traits : IntegralTypeOf, isNumeric, isArray, CommonType, isFloatingPointTrait = isFloatingPoint, isImplicitlyConvertible;
39 import std.typecons : isTuple;
40 import std.typetuple : TypeTuple;
41 
42 static import std.typecons;
43 
44 /**
45  * Vector for coordinates storing and operations.
46  */
47 struct Vector(T, char[] c) if(c.length > 1 && areValidCoordinates(c)) {
48 	
49 	public alias Type = T;
50 	public alias coordinates = c;
51 
52 	mixin("alias Tuple = std.typecons.Tuple!(T, \"" ~ join(coordinates.idup.split(""), "\", T, \"") ~ "\");");
53 	
54 	mixin("public enum coords = TypeTuple!('" ~ join(coordinates.idup.split(""), "','") ~ "');");
55 	
56 	enum bool isFloatingPoint = isFloatingPointTrait!T;
57 
58 	private Tuple value;
59 	
60 	mixin((){
61 		string ret;
62 		foreach(immutable c ; coords) {
63 			ret ~= "public pure nothrow @property @safe @nogc T " ~ c ~ "(){ return this.value." ~ c ~ "; }";
64 		}
65 		return ret;
66 	}());
67 
68 	public pure nothrow @safe @nogc this(Tuple value) {
69 		this.value = value;
70 	}
71 
72 	public pure nothrow @safe @nogc this(T value) {
73 		foreach(immutable c ; coords) {
74 			mixin("this.value." ~ c ~ " = value;");
75 		}
76 	}
77 	
78 	public @safe this(F...)(F args) if(F.length == coordinates.length) {
79 		foreach(i, immutable c; coords) {
80 			mixin("this.value." ~ c ~ " = cast(T)args[" ~ to!string(i) ~ "];");
81 		}
82 	}
83 	
84 	public @safe @nogc this(T[coords.length] variables) {
85 		foreach(i, immutable c; coords) {
86 			mixin("this.value." ~ c ~ " = variables[i];");
87 		}
88 	}
89 	
90 	public @safe @nogc this(T[] variables) {
91 		foreach(i, immutable c; coords) {
92 			mixin("this.value." ~ c ~ " = variables[i];");
93 		}
94 	}
95 
96 	/**
97 	 * Gets the vector as a constant tuple.
98 	 * Example:
99 	 * ---
100 	 * auto v = vector(0, 3, 4);
101 	 * assert(v.tuple == typeof(v).Tuple(0, 3, 4));
102 	 * ---
103 	 */
104 	public pure nothrow @property @safe @nogc const Tuple tuple() {
105 		return this.value;
106 	}
107 	
108 	/**
109 	 * Compares the vector with another vector of the same length or with
110 	 * a single number.
111 	 * Returns: true if all the values are equals, false otherwise
112 	 * Example:
113 	 * ---
114 	 * assert(Vector2!int(0, 10) == Vector2!int(0, 10));
115 	 * assert(Vector3!ubyte(1, 1, 255) == Vector3!real(1, 1, 255));
116 	 * assert(vector(0, 0, 0, 0) == 0);
117 	 * assert(vector(1, 2) == [1, 2]);
118 	 * assert(vector(float.nan, float.nan) != vector(float.nan, float.nan));
119 	 * ---
120 	 */
121 	public bool opEquals(F)(F value) {
122 		static if(isVector!F && coords == F.coords) return this.opEqualsImpl!"this.{c}==value.{c}"(value);
123 		else static if(isArray!F) return value.length == coords.length && this.opEqualsImpl!"this.{c}==value[{i}]"(value);
124 		else static if(__traits(compiles, T.init == F.init)) return this.opEqualsImpl!"this.{c}==value"(value);
125 		else return false;
126 	}
127 	
128 	private bool opEqualsImpl(string op, F)(F value) {
129 		mixin((){
130 				string[] ret;
131 				foreach(i, immutable c; coords) {
132 					ret ~= op.replace("{c}", to!string(c)).replace("{i}", to!string(i));
133 				}
134 				return "return " ~ ret.join("&&") ~ ";";
135 			}());
136 	}
137 	
138 	/**
139 	 * Performs an unary operation on the vector.
140 	 * Returns: the new vector
141 	 * Example:
142 	 * ---
143 	 * auto v = vector(-1, 0, 1);
144 	 * assert(-v == vector(1, 0, -1));
145 	 * assert(++v == vector(0, 1, 2)); // this will change the original vector's values!
146 	 * assert(v-- == vector(0, 1, 2) && v == vector(-1, 0, 1));
147 	 * ---
148 	 */
149 	public typeof(this) opUnary(string op)() if(__traits(compiles, { mixin("T t;t=" ~ op ~ "t;"); })) {
150 		typeof(this) ret;
151 		foreach(immutable c ; coords) {
152 			mixin("ret." ~ c ~ "=" ~ op ~ "this.value." ~ c ~ ";");
153 		}
154 		return ret;
155 	}
156 	
157 	/**
158 	 * Performs a binary operation on the vector.
159 	 * Params:
160 	 * 		value = a number, a vector or an array with the same size
161 	 * Returns: the new vector
162 	 * Example:
163 	 * ---
164 	 * assert(vector(1, 1) - 1 == vector(0, 0));
165 	 * assert(vector(10, 10) * vector(0, 9) == vector(0, 90));
166 	 * assert(vector(16, 15) & [15, 3] == vector(0, 3));
167 	 * assert(1 - vector(100, 0, -100) == vector(-99, 1, 101));
168 	 * ---
169 	 */
170 	public typeof(this) opBinary(string op, F)(F value) if(op != "in") {
171 		return this.dup.opOpAssign!op(value);
172 	}
173 	
174 	public typeof(this) opBinaryRight(string op, F)(F value) if(op != "in" && __traits(compiles, typeof(this)(value))) {
175 		return typeof(this)(value).opBinary!op(this);
176 	}
177 	
178 	/**
179 	 * Performs an assign operation on the vector, modifying it.
180 	 * Params:
181 	 * 		value = a number, a vector or an array with the same size
182 	 * Returns:
183 	 * Example:
184 	 * ---
185 	 * auto v = vector(1, 2);
186 	 * v += 4;
187 	 * v *= [0, 2];
188 	 * assert(v == vector(0, 12));
189 	 * ---
190 	 */
191 	public typeof(this) opOpAssign(string op, F)(F value) if(isVector!F && coordinates == F.coordinates) {
192 		return this.opAssignImpl!("this.value.{c}" ~ op ~ "=value.{c}")(value);
193 	}
194 	
195 	/// ditto
196 	public typeof(this) opOpAssign(string op, F)(F value) if(isArray!F) {
197 		return this.opAssignImpl!("this.value.{c}" ~ op ~ "=value[{i}]")(value);
198 	}
199 	
200 	/// ditto
201 	public typeof(this) opOpAssign(string op, F)(F value) if(isImplicitlyConvertible!(F, T)) {
202 		return this.opAssignImpl!("this.value.{c}" ~ op ~ "=value")(value);
203 	}
204 	
205 	private typeof(this) opAssignImpl(string query, F)(F value) {
206 		foreach(i, immutable c; coords) {
207 			mixin(query.replace("{c}", to!string(c)).replace("{i}", to!string(i)) ~ ";");
208 		}
209 		return this;
210 	}
211 	
212 	/**
213 	 * Converts the vector to the given one, mantaining the variables's
214 	 * value when possible.
215 	 * Example:
216 	 * ---
217 	 * assert(cast(Vector2!int)vector(.1, .1, 14) == vector(0, 14));
218 	 * assert(cast(Vector4!real)vector(.5, 100) == vector(.5, 0, 100, 0));
219 	 * // this will only return the vector
220 	 * assert(cast(Vector2!int
221 	 * ---
222 	 */
223 	public @safe auto opCast(F)() if(isVector!F) {
224 		static if(is(T == F) && coordinates == F.coordinates) {
225 			return this;
226 		} else {
227 			F ret;
228 			foreach(immutable c; F.coords) {
229 				static if(coordinates.canFind(c)) {
230 					mixin("ret.value." ~ c ~ "=to!(F.Type)(this." ~ c ~ ");");
231 				}
232 			}
233 			return ret;
234 		}
235 	}
236 	
237 	/**
238 	 * Converts the vector into an array of the same size.
239 	 * Example:
240 	 * ---
241 	 * assert(cast(int[])vector(1, 2) == [1, 2]);
242 	 * assert(cast(long[])vector(.1, 1.5, -.1) == [0L, 1L, 0L]);
243 	 * ---
244 	 */
245 	public @safe auto opCast(F)() if(isArray!F) {
246 		F array;
247 		foreach(immutable c ; coords) {
248 			mixin("array ~= to!(typeof(T.init[0]))(this." ~ c ~ ");");
249 		}
250 		return array;
251 	}
252 	
253 	/**
254 	 * Changes the vector's type.
255 	 */
256 	public auto type(F)() if(isImplicitlyConvertible!(F, T)) {
257 		Vector!(F, coordinates) ret;
258 		foreach(immutable c ; coords) {
259 			mixin("ret.value." ~ c ~ "=this." ~ c ~ ";");
260 		}
261 		return ret;
262 	}
263 	
264 	/**
265 	 * Duplicates the vector, mantaing the type, variables'
266 	 * names and their value.
267 	 * Example:
268 	 * ---
269 	 * assert(vector(1, 1).dup == vector(1, 1));
270 	 * ---
271 	 */
272 	alias dup = type!T;
273 
274 	/**
275 	 * Gets the vector's length.
276 	 */
277 	public @property double length() {
278 		double length = 0;
279 		foreach(immutable c ; coords) {
280 			mixin("length += this.value." ~ c ~ " * this.value." ~ c ~ ";");
281 		}
282 		return std.math.sqrt(length);
283 	}
284 
285 	/**
286 	 * Sets the vector's length.
287 	 */
288 	public @property double length(double length) {
289 		double mult = length / this.length;
290 		foreach(immutable c ; coords) {
291 			mixin("this.value." ~ c ~ " = cast(T)(this.value." ~ c ~ " * mult);");
292 		}
293 		return length;
294 	}
295 	
296 	/**
297 	 * Converts the vector into a string for logging and debugging purposes.
298 	 */
299 	public string toString() {
300 		string[] cs;
301 		foreach(i, coord; coords) {
302 			mixin("cs ~= to!string(this." ~ coord ~ ");");
303 		}
304 		return "Vector!(" ~ T.stringof ~ ", \"" ~ coordinates.idup ~ "\")(" ~ cs.join(", ") ~ ")";
305 	}
306 	
307 }
308 
309 /// ditto
310 alias Vector(T, string coords) = Vector!(T, coords.dup);
311 
312 /// ditto
313 alias Vector2(T) = Vector!(T, "xz");
314 
315 /// ditto
316 alias Vector3(T) = Vector!(T, "xyz");
317 
318 /// ditto
319 alias Vector4(T) = Vector!(T, "xyzw");
320 
321 private bool areValidCoordinates(char[] coords) {
322 	foreach(i, char c; coords[0..$-1]) {
323 		if(coords[i+1..$].canFind(c)) return false;
324 	}
325 	return true;
326 }
327 
328 /**
329  * Automatically creates a vector if the number of the
330  * given arguments matches one of the default vectors.
331  * Example:
332  * ---
333  * assert(is(typeof(vector(1, 1)) == Vector2!int));
334  * assert(is(typeof(vector(2Lu, 4)) == Vector2!ulong));
335  * assert(is(typeof(vector(5, 5, 19.0)) == Vector3!double));
336  * assert(is(typeof(vector(0, real.nan, double.nan, float.nan)) == Vector4!real));
337  * ---
338  */
339 public auto vector(E...)(E args) if(E.length > 1 && E.length <= 4 && !is(CommonType!E == void)) {
340 	mixin("return Vector" ~ to!string(E.length) ~ "!(CommonType!E)(args);");
341 }
342 
343 /// Checks if the given type is a vector
344 enum bool isVector(T) = __traits(compiles, Vector!(T.Type, T.coordinates)(T.Type.init));
345 
346 public nothrow @safe T mathFunction(alias func, T)(T vector) if(isVector!T) {
347 	T.Type[] values;
348 	foreach(immutable c ; T.coords) {
349 		mixin("values ~= cast(T.Type)func(vector." ~ c ~ ");");
350 	}
351 	return T(values);
352 }
353 
354 /**
355  * Rounds a vector to the nearest integer.
356  * Example:
357  * ---
358  * assert(round(vector(.25, .5, .75)) == vector(0, 1, 1));
359  * ---
360  */
361 public nothrow @safe T round(T)(T vector) if(isVector!T) {
362 	return mathFunction!(std.math.round)(vector);
363 }
364 
365 /**
366  * Floors a vector to the nearest integer.
367  * Example:
368  * ---
369  * assert(floor(vector(.25, .5, .75)) == vector(0, 0, 0));
370  * ---
371  */
372 public nothrow @safe T floor(T)(T vector) if(isVector!T) {
373 	return mathFunction!(std.math.floor)(vector);
374 }
375 
376 /**
377  * Ceils a vector to the nearest integer.
378  * Example:
379  * ---
380  * assert(ceil(vector(.25, .5, .75)) == vector(1, 1, 1));
381  * ---
382  */
383 public nothrow @safe T ceil(T)(T vector) if(isVector!T) {
384 	return mathFunction!(std.math.ceil)(vector);
385 }
386 
387 /**
388  * Calculate the absolute value of the array.
389  * Example:
390  * ---
391  * assert(abs(vector(-1, 0, 90)) == vector(1, 0, 90));
392  * ---
393  */
394 public nothrow @safe T abs(T)(T vector) if(isVector!T) {
395 	return mathFunction!(std.math.abs)(vector);
396 }
397 
398 /**
399  * Checks whether or not every member of the vector is finite
400  * (not infite, -inifite, nan).
401  * Example:
402  * ---
403  * assert(isFinite(vector(1, 2)));
404  * assert(isFinite(vector(float.min, float.max)));
405  * assert(!isFinite(vector(1, float.nan)));
406  * assert(!isFinite(vector(-float.infinity, 1f/0f)));
407  * ---
408  */
409 public pure nothrow @safe @nogc bool isFinite(T)(T vector) if(isVector!T && T.isFloatingPoint) {
410 	foreach(immutable c ; T.coords) {
411 		mixin("if(!std.math.isFinite(vector." ~ c ~ ")) return false;");
412 	}
413 	return true;
414 }
415 
416 /**
417  * Checks whether or not at least one member of the vector
418  * is not a number (nan).
419  * Example:
420  * ---
421  * assert(!isNaN(vector(0, 2.1)));
422  * assert(isNaN(vector(float.init, -double.init)));
423  * assert(isNaN(vector(0, float.nan)));
424  * ---
425  */
426 public pure nothrow @safe @nogc bool isNaN(T)(T vector) if(isVector!T && T.isFloatingPoint) {
427 	foreach(immutable c ; T.coords) {
428 		mixin("if(std.math.isNaN(vector." ~ c ~ ")) return true;");
429 	}
430 	return false;
431 }
432 
433 public @safe double distanceSquared(F, G)(F vector1, G vector2) if(isVector!F && isVector!G && F.coordinates == G.coordinates) {
434 	double sum = 0;
435 	foreach(immutable c ; F.coords) {
436 		mixin("sum += std.math.pow(vector1." ~ c ~ " - vector2." ~ c ~ ", 2);");
437 	}
438 	return sum;
439 }
440 
441 /**
442  * Calculates the distance between to vectors of the
443  * same length.
444  * Params:
445  * 		vector1 = the first vector
446  * 		vector2 = the second vector
447  * Returns: the distance between the two vectors (always higher or equals than  0)
448  * Example:
449  * ---
450  * assert(distance(vector(0, 0), vector(1, 0)) == 1);
451  * assert(distance(vector(0, 0, 0) == vector(1, 1, 1)) == 3 ^^ .5); // 3 ^^ .5 is the squared root of 3
452  * ---
453  */
454 public @safe double distance(T, char[] coords, E)(Vector!(T, coords) vector1, Vector!(E, coords) vector2) {
455 	return std.math.sqrt(distanceSquared(vector1, vector2));
456 }
457 
458 public pure nothrow @safe double dot(T, char[] coords, E)(Vector!(T, coords) vector1, Vector!(E, coords) vector2) {
459 	double dot = 0;
460 	foreach(immutable c ; Vector!(T, coords).coords) {
461 		mixin("dot += vector1." ~ c ~ " * vector2." ~ c ~ ";");
462 	}
463 	return dot;
464 }
465 
466 public pure nothrow @safe Vector!(CommonType!(A, B), coords) cross(A, B, char[] coords)(Vector!(A, coords) a, Vector!(B, coords) b) {
467 	foreach(immutable exc ; Vector!(T, coords).coords) {
468 
469 	}
470 }
471 
472 /**
473  * Example:
474  * ---
475  * alias DoublePosition = Vector3!float;
476  * 
477  * ---
478  */
479 deprecated("Use the vector's constructor instead") public V vector(V, T)(T tuple) if(isVector!V && isTuple!T) {
480 	mixin((){
481 		string[] ret;
482 		foreach(field ; T.fieldNames) {
483 			ret ~= "conv!(V.Type)(tuple." ~ field ~ ")";
484 		}
485 		return "return V(" ~ ret.join(",") ~ ");";
486 	}());
487 }
488 
489 deprecated("Use vector's .tuple property instead") public T tuple(T, V)(V vector) if(isTuple!T && isVector!V) {
490 	T tup;
491 	mixin((){
492 		string ret = "";
493 		foreach(i, immutable c; V.coords) {
494 			ret ~= "tup." ~ c ~ "=conv!(T.Types[" ~ to!string(i) ~ "])(vector." ~ c ~ ");";
495 		}
496 		return ret;
497 	}());
498 	return tup;
499 }
500 
501 To conv(To, From)(From from) {
502 	static if(is(From == To)) return from;
503 	else return cast(To)from;
504 }
505 
506 unittest {
507 	
508 	Vector3!int v3 = Vector3!int(-1, 0, 12);
509 	
510 	// comparing
511 	assert(v3.x == -1);
512 	assert(v3.y == 0);
513 	assert(v3.z == 12);
514 	assert(v3 == Vector3!int(-1, 0, 12));
515 	assert(v3 == Vector3!float(-1, 0, 12));
516 	assert(v3 != Vector3!double(-1, 0, 12.00000001));
517 	
518 	// unary
519 	assert(-v3 == Vector3!int(1, 0, -12));
520 	assert(++v3 == Vector3!int(0, 1, 13) && v3 == Vector3!int(0, 1, 13));
521 	assert(v3-- == Vector3!int(0, 1, 13) && v3 == Vector3!int(-1, 0, 12));
522 	
523 	// binary operator
524 	assert(v3 + 3 == Vector3!int(2, 3, 15));
525 	assert(v3 * 100 == Vector3!int(-100, 0, 1200));
526 	assert(v3 - v3 == Vector3!int(0, 0, 0));
527 	assert(Vector3!double(.5, 0, 0) + v3 == Vector3!double(-.5, 0, 12));
528 	assert(v3 * [1, 2, 3] == Vector3!int(-1, 0, 36));
529 	assert((v3 & 1) == Vector3!int(1, 0, 0));
530 	assert(1 - v3 == Vector3!int(2, 1, -11));
531 	
532 	// assign operator
533 	assert((v3 *= 3) == Vector3!int(-3, 0, 36));
534 	assert(v3 == Vector3!int(-3, 0, 36));
535 	v3 >>= 1;
536 	assert(v3 == Vector3!int(-2, 0, 18));
537 	
538 	// cast
539 	Vector3!float v3f = cast(Vector3!float)v3;
540 	Vector2!int reduced = cast(Vector2!int)v3;
541 	Vector4!long bigger = cast(Vector4!long)v3;
542 	assert(v3f == Vector3!float(-2, 0, 18));
543 	assert(reduced == Vector2!float(-2, 18));
544 	assert(bigger == Vector4!long(-2, 0, 18, 0));
545 	
546 	// vector function
547 	assert(vector(8, 19).Type.stringof == "int");
548 	assert(vector(1.0, 2, 99.9).Type.stringof == "double");
549 	assert(vector(1f, .01, 12L).Type.stringof == "double");
550 	
551 	// math functions
552 	assert(round(vector(.2, .7)) == vector(0, 1));
553 	assert(floor(vector(.2, .7)) == vector(0, 0));
554 	assert(ceil(vector(.2, .7)) == vector(1, 1));
555 	assert(abs(vector(-.2, .7)) == vector(.2, .7));
556 	
557 	// distance
558 	assert(distance(vector(0, 0), vector(0, 1)) == 1);
559 	assert(distance(vector(0, 0, 0), vector(1, 1, 1)) == 3 ^^ .5);
560 	
561 }
562 
563 /// Vectors usually used by Minecraft
564 alias ChunkPosition = Vector2!int;
565 
566 /// ditto
567 alias EntityPosition = Vector3!double;
568 
569 /// ditto
570 alias BlockPosition = Vector3!int;
571 
572 /// Gets a ushort that indicates a position in a chunk.
573 public @property @safe ushort shortBlockPosition(BlockPosition position) {
574 	return (position.y << 8 | position.z << 4 | position.x) & ushort.max;
575 }
576 
577 /// Gets a BlockPosition from an ushort that indicates a position in a chunk.
578 public @property @safe BlockPosition blockPositionShort(ushort position) {
579 	return BlockPosition(cast(int)(position & 255), cast(int)(position >> 8), cast(int)((position >> 4) & 255));
580 }
581 
582 /// Casts a BlockPosition to an EntityPosition using vector's opCast.
583 public @property @safe EntityPosition entityPosition(BlockPosition block) {
584 	return cast(EntityPosition)block;
585 }
586 
587 /// Casts an EntityPosition to a BlockPosition using vector's opCast.
588 public @property @safe BlockPosition blockPosition(EntityPosition entity) {
589 	return cast(BlockPosition)entity;
590 }
591 
592 enum Face : uint {
593 	
594 	DOWN = 0,
595 	UP = 1,
596 	NORTH = 2,
597 	SOUTH = 3,
598 	WEST = 4,
599 	EAST = 5
600 	
601 }
602 
603 // Gets the block position from a tap.
604 public @property @safe BlockPosition face(BlockPosition from, uint face) {
605 	switch(face) {
606 		case Face.DOWN: return from - [0, 1, 0];
607 		case Face.UP: return from + [0, 1, 0];
608 		case Face.NORTH: return from - [0, 0, 1];
609 		case Face.SOUTH: return from + [0, 0, 1];
610 		case Face.WEST: return from - [1, 0, 0];
611 		case Face.EAST: return from + [1, 0, 0];
612 		default: return from;
613 	}
614 }
615 
616 abstract class Box(T) {
617 	
618 	public abstract @safe bool intersects(Box!T box);
619 	public abstract @safe bool intersects(Box!T box, bool deep);
620 	
621 	public abstract @property @safe @nogc Vector3!T minimum();
622 	public abstract @property @safe @nogc Vector3!T maximum();
623 	
624 	public abstract @property @safe Box!T dup();
625 	public abstract override @safe string toString();
626 	
627 }
628 
629 abstract class ClassicBox(T) : Box!T {
630 	
631 	public override @safe bool intersects(Box!T box) {
632 		return this.intersects(box, true);
633 	}
634 	
635 	public override @safe bool intersects(Box!T box, bool deep) {
636 		Vector3!T tmin = this.minimum;
637 		Vector3!T tmax = this.maximum;
638 		Vector3!T bmin = box.minimum;
639 		Vector3!T bmax = box.maximum;
640 		if(tmin.x > bmin.x && tmin.x < bmax.x || tmax.x > bmin.x && tmax.x < bmax.x) {
641 			if(tmin.y >= bmin.y && tmin.y <= bmax.y || tmax.y >= bmin.y && tmax.y <= bmax.y) {
642 				if(tmin.z > bmin.z && tmin.z < bmax.z || tmax.z > bmin.z && tmax.z < bmax.z) {
643 					return true;
644 				}
645 			}
646 		}
647 		return deep && box.intersects(this, false);
648 	}
649 	
650 	public override @safe string toString() {
651 		return "min: " ~ this.minimum.to!string ~ ", max: " ~ this.maximum.to!string;
652 	}
653 	
654 }
655 
656 class ClassicEntityBox(T) : ClassicBox!T {
657 	
658 	private T width, height;
659 	
660 	private Vector3!T position;
661 	private Vector3!T min, max;
662 	
663 	public @safe this(T width, T height, Vector3!T position) {
664 		this.width = width;
665 		this.height = height;
666 		this.position = position;
667 		this.update();
668 	}
669 	
670 	public override @safe @nogc Vector3!T minimum() {
671 		return this.min;
672 	}
673 	
674 	public override @safe @nogc Vector3!T maximum() {
675 		return this.max;
676 	}
677 	
678 	public @safe void update(T width, T height) {
679 		this.width = width;
680 		this.height = height;
681 		this.update();
682 	}
683 	
684 	public @safe void update(Vector3!T position) {
685 		this.position = position;
686 		this.update();
687 	}
688 	
689 	protected @safe void update() {
690 		this.min = this.position - [this.width / 2f, 0, this.width / 2f];
691 		this.max = this.position + [this.width / 2f, this.height, this.width / 2f];
692 	}
693 	
694 	public @safe ClassicEntityBox!T grow(T width, T height) {
695 		return new ClassicEntityBox!T(width * 2, height * 2, this.position- [0, height, 0]);
696 	}
697 	
698 	public override @property @safe Box!T dup() {
699 		return new ClassicEntityBox!T(this.width, this.height, this.position);
700 	}
701 	
702 }
703 
704 class ClassicBlockBox(T) : ClassicBox!T {
705 	
706 	private Vector3!T size_start, size_end;
707 	private Vector3!T start, end;
708 	//private bool updated;
709 	
710 	public @safe this(Vector3!T start, Vector3!T end) /*in { assert(start.x.one && start.y.one &&  start.z.one && end.x.one && end.y.one && end.z.one, "Blocks' sizes must be between 0 and 1"); } body*/ {
711 		this.size_start = start;
712 		this.size_end = end;
713 		//this.updated = false;
714 	}
715 	
716 	public @safe this(T startx, T starty, T startz, T endx, T endy, T endz) {
717 		this(Vector3!T(startx, starty, startz), Vector3!T(endx, endy, endz));
718 	}
719 	
720 	public @safe void update(Vector3!T position)/* in { assert(!this.updated, "ClassicBlockBox can only be updated once"); } body*/ {
721 		this.start = position + this.size_start;
722 		this.end = position + this.size_end;
723 	}
724 	
725 	public override @property @safe @nogc Vector3!T minimum() {
726 		return this.start;
727 	}
728 	
729 	public override @property @safe @nogc Vector3!T maximum() {
730 		return this.end;
731 	}
732 	
733 	public override @property @safe Box!T dup() {
734 		ClassicBlockBox!T ret = new ClassicBlockBox!T(this.start, this.end);
735 		//ret.updated = this.updated;
736 		return ret;
737 	}
738 	
739 }
740 
741 /*class ComplexBox(T, bool block, E...) : Box!(T, block) {
742 
743 	private Box!(T, block)[] boxes;
744 
745 	public this(E args) {
746 		super(0, 0, null, null, null);
747 		foreach(e ; args) {
748 			if(typeid(e) == Box!(T, block)) {
749 				this.boxes ~= cast(Box!(T, block))e;
750 			}
751 		}
752 	}
753 
754 	public override void update(Vector3!T position) {
755 		foreach(Box!(T, block) box ; this.boxes) {
756 			box.update(position);
757 		}
758 	}
759 
760 	public override @property Vector3!T minimum() {
761 		Vector3!T ret;
762 		foreach(Box!(T, block) box ; this.boxes) {
763 			Vector3!T min = box.minimum;
764 			if(ret is null || (min.x < ret.x && min.y < ret.y && min.z < ret.z)) ret = min;
765 		}
766 		return ret;
767 	}
768 
769 	public override @property Vector3!T maximum() {
770 		Vector3!T ret;
771 		foreach(Box!(T, block) box ; this.boxes) {
772 			Vector3!T max = box.maximum;
773 			if(ret is null || (max.x > ret.x && max.y > ret.y && max.z > ret.z)) ret = max;
774 		}
775 		return ret;
776 	}
777 
778 	public override string toString() {
779 		return this.boxes.to!string;
780 	}
781 
782 }*/
783 
784 alias EntityAxis = ClassicEntityBox!(EntityPosition.Type);
785 alias BlockAxis = ClassicBlockBox!(EntityPosition.Type);