1 /** Geometry types and algorithms.
2 
3    Special thanks to:
4    $(UL
5    $(LI Tomasz Stachowiak (h3r3tic): allowed me to use parts of $(LINK2 https://bitbucket.org/h3r3tic/boxen/src/default/src/xf/omg, omg).)
6    $(LI Jakob Øvrum (jA_cOp): improved the code a lot!)
7    $(LI Florian Boesch (___doc__): helps me to understand opengl/complex maths better, see: $(LINK http://codeflow.org/).)
8    $(LI #D on freenode: answered general questions about D.)
9    )
10 
11    Note: All methods marked with pure are weakly pure since, they all access an
12    instance member.  All static methods are strongly pure.
13 
14    TODO: Support radian and degree types (from units-d package)
15 
16    TODO: Use `sink` as param in `toMathML` and `toLaTeX`
17 
18    TODO: Replace toMathML() with fmt argument %M to toString functions
19    TODO: Replace toLaTeX() with fmt argument %L to toString functions
20 
21    TODO: Optimize using core.simd or std.simd
22    TODO: Merge with analyticgeometry
23    TODO: Merge with https://github.com/CyberShadow/ae/blob/master/utils/geometry.d
24    TODO: Integrate with http://code.dlang.org/packages/blazed2
25    TODO: logln, log.warn, log.error, log.info, log.debug
26    TODO: Make use of staticReduce etc when they become available in Phobos.
27    TODO: Go through all usages of real and use CommonType!(real, E) to make it work when E is a bignum.
28    TODO: ead and perhaps make use of http://stackoverflow.com/questions/3098242/fast-vector-struct-that-allows-i-and-xyz-operations-in-d?rq=1
29    TODO: Tag member functions in t_geom.d as pure as is done https://github.com/D-Programming-Language/phobos/blob/master/std/bigint.d
30    TODO: Remove need to use [] in x[] == y[]
31 
32    See: https://www.google.se/search?q=point+plus+vector
33    See: http://mosra.cz/blog/article.php?a=22-introducing-magnum-a-multiplatform-2d-3d-graphics-engine
34 */
35 module old_geometry;
36 
37 /+ TODO: use import core.simd; +/
38 import std.math: sqrt, PI, sin, cos, acos;
39 import std.traits: isFloatingPoint, isNumeric, isSigned, isDynamicArray, isAssignable, isArray, CommonType;
40 import std.string: format, rightJustify;
41 import std.array: join;
42 import std.algorithm.iteration : map, reduce;
43 import std.algorithm.searching : all, any;
44 import std.algorithm.comparison : min, max;
45 import std.random: uniform;
46 
47 import nxt.mathml;
48 
49 enum isVector(E)	 = is(typeof(isVectorImpl(E.init)));
50 enum isPoint(E)	  = is(typeof(isPointImpl(E.init)));
51 enum isMatrix(E)	 = is(typeof(isMatrixImpl(E.init)));
52 enum isQuaternion(E) = is(typeof(isQuaternionImpl(E.init)));
53 enum isPlane(E)	  = is(typeof(isPlaneImpl(E.init)));
54 
55 private void isVectorImpl	(E, uint D)		(Vector	!(E, D)	vec) {}
56 private void isPointImpl	 (E, uint D)		(Point	 !(E, D)	vec) {}
57 private void isMatrixImpl	(E, uint R, uint C)(Matrix	!(E, R, C) mat) {}
58 private void isQuaternionImpl(E)				(Quaternion!(E)		qu) {}
59 private void isPlaneImpl	 (E)				(PlaneT	!(E)		 p) {}
60 
61 enum isFixVector(E) = isFix(typeof(isFixVectorImpl(E.init)));
62 enum isFixPoint(E)  = isFix(typeof(isFixPointImpl (E.init)));
63 enum isFixMatrix(E) = isFix(typeof(isFixMatrixImpl(E.init)));
64 
65 private void isFixVectorImpl (E, uint D)		(Vector!(E, D)	vec) {}
66 private void isFixPointImpl  (E, uint D)		(Point !(E, D)	vec) {}
67 private void isFixMatrixImpl (E, uint R, uint C)(Matrix!(E, R, C) mat) {}
68 
69 // See_Also: http://stackoverflow.com/questions/18552454/using-ctfe-to-generate-set-of-struct-aliases/18553026?noredirect=1#18553026
70 version (none)
71 string makeInstanceAliases(in string templateName,
72 						   string aliasName = "",
73 						   in uint minDimension = 2,
74 						   in uint maxDimension = 4,
75 						   in string[] elementTypes = defaultElementTypes)
76 in
77 {
78 	assert(templateName.length);
79 	assert(minDimension <= maxDimension);
80 }
81 do
82 {
83 	import std.string : toLower;
84 	import std.conv : to;
85 	string code;
86 	if (!aliasName.length)
87 	{
88 		aliasName = templateName.toLower;
89 	}
90 	foreach (immutable n; minDimension .. maxDimension + 1)
91 	{
92 		foreach (const et; elementTypes) // for each elementtype
93 		{
94 			immutable prefix = ("alias " ~ templateName ~ "!("~et~", " ~
95 								to!string(n) ~ ") " ~ aliasName ~ "" ~
96 								to!string(n));
97 			if (et == "float")
98 			{
99 				code ~= (prefix ~ ";\n"); // GLSL-style prefix-less single precision
100 			}
101 			code ~= (prefix ~ et[0] ~ ";\n");
102 		}
103 	}
104 	return code;
105 }
106 
107 version (none)
108 mixin(makeInstanceAliases("Point", "point", 2,3,
109 						   ["int", "float", "double", "real"]));
110 
111 /* Copied from https://github.com/CyberShadow/ae/blob/master/utils/geometry.d */
112 auto sqrtx(T)(T x)
113 {
114 	static if (is(T : int))
115 	{
116 		return std.math.sqrt(cast(float)x);
117 	}
118 	else
119 	{
120 		return std.math.sqrt(x);
121 	}
122 }
123 
124 import std.meta : AliasSeq;
125 
126 version (unittest)
127 {
128 	static foreach (T; AliasSeq!(ubyte, int, float, double, real))
129 	{
130 		static foreach (uint n; 2 .. 4 + 1)
131 		{
132 		}
133 	}
134 
135 	alias vec2b = Vector!(byte, 2, false);
136 
137 	alias vec2f = Vector!(float, 2, true);
138 	alias vec3f = Vector!(float, 3, true);
139 
140 	alias vec2d = Vector!(float, 2, true);
141 
142 	alias nvec2f = Vector!(float, 2, true);
143 }
144 
145 // mixin(makeInstanceAliases("Vector", "vec", 2,4,
146 //						   ["ubyte", "int", "float", "double", "real"]));
147 
148 ///
149 pure nothrow @safe @nogc unittest {
150 	assert(vec2f(2, 3)[] == [2, 3].s);
151 	assert(vec2f(2, 3)[0] == 2);
152 	assert(vec2f(2) == 2);
153 	assert(vec2f(true) == true);
154 	assert(vec2b(true) == true);
155 	assert(all!"a"(vec2b(true)[]));
156 	assert(any!"a"(vec2b(false, true)[]));
157 	assert(any!"a"(vec2b(true, false)[]));
158 	assert(!any!"a"(vec2b(false, false)[]));
159 	assert((vec2f(1, 3)*2.5f)[] == [2.5f, 7.5f].s);
160 	nvec2f v = vec2f(3, 4);
161 	assert(v[] == nvec2f(0.6, 0.8)[]);
162 }
163 
164 ///
165 @safe unittest {
166 	import std.conv : to;
167 	auto x = vec2f(2, 3);
168 	assert(to!string(vec2f(2, 3)) == `ColumnVector(2,3)`);
169 	assert(to!string(transpose(vec2f(11, 22))) == `RowVector(11,22)`);
170 	assert(vec2f(11, 22).toLaTeX == `\begin{pmatrix} 11 \\ 22 \end{pmatrix}`);
171 	assert(vec2f(11, 22).T.toLaTeX == `\begin{pmatrix} 11 & 22 \end{pmatrix}`);
172 }
173 
174 auto transpose(E, uint D,
175 			   bool normalizedFlag,
176 			   Orient orient)(in Vector!(E, D,
177 										 normalizedFlag,
178 										 orient) a)
179 {
180 	static if (orient == Orient.row)
181 	{
182 		return Vector!(E, D, normalizedFlag, Orient.column)(a._vector);
183 	}
184 	else
185 	{
186 		return Vector!(E, D, normalizedFlag, Orient.row)(a._vector);
187 	}
188 }
189 alias T = transpose; // C++ Armadillo naming convention.
190 
191 auto elementwiseLessThanOrEqual(Ta, Tb,
192 								uint D,
193 								bool normalizedFlag,
194 								Orient orient)(in Vector!(Ta, D, normalizedFlag, orient) a,
195 											   in Vector!(Tb, D, normalizedFlag, orient) b)
196 {
197 	Vector!(bool, D) c = void;
198 	static foreach (i; 0 .. D)
199 	{
200 		c[i] = a[i] <= b[i];
201 	}
202 	return c;
203 }
204 
205 pure nothrow @safe @nogc unittest {
206 	assert(elementwiseLessThanOrEqual(vec2f(1, 1),
207 									  vec2f(2, 2)) == vec2b(true, true));
208 }
209 
210 /// Returns: Scalar/Dot-Product of Two Vectors `a` and `b`.
211 T dotProduct(T, U)(in T a, in U b)
212 if (is(T == Vector!(_), _) &&
213 	is(U == Vector!(_), _) &&
214 	(T.dimension ==
215 	 U.dimension))
216 {
217 	T c = void;
218 	static foreach (i; 0 .. T.dimension)
219 	{
220 		c[i] = a[i] * b[i];
221 	}
222 	return c;
223 }
224 alias dot = dotProduct;
225 
226 /// Returns: Outer-Product of Two Vectors `a` and `b`.
227 auto outerProduct(Ta, Tb, uint Da, uint Db)(in Vector!(Ta, Da) a,
228 											in Vector!(Tb, Db) b)
229 if (Da >= 1 &&
230 	Db >= 1)
231 {
232 	Matrix!(CommonType!(Ta, Tb), Da, Db) y = void;
233 	static foreach (r; 0 .. Da)
234 	{
235 		static foreach (c; 0 .. Db)
236 		{
237 			y.at(r,c) = a[r] * b[c];
238 		}
239 	}
240 	return y;
241 }
242 alias outer = outerProduct;
243 
244 /// Returns: Vector/Cross-Product of two 3-Dimensional Vectors.
245 auto crossProduct(T, U)(in T a,
246 						in U b)
247 if (is(T == Vector!(_), _) && T.dimension == 3 &&
248 	is(U == Vector!(_), _) && U.dimension == 3)
249 {
250 	return T(a.y * b.z - b.y * a.z,
251 			 a.z * b.x - b.z * a.x,
252 			 a.x * b.y - b.x * a.y);
253 }
254 
255 /// Returns: (Euclidean) Distance between `a` and `b`.
256 real distance(T, U)(in T a,
257 					in U b)
258 if ((is(T == Vector!(_), _) && // either both vectors
259 	 is(U == Vector!(_), _) &&
260 	 T.dimension == U.dimension) ||
261 	(isPoint!T && // or both points
262 	 isPoint!U))  /+ TODO: support distance between vector and point +/
263 {
264 	return (a - b).magnitude;
265 }
266 
267 pure nothrow @safe @nogc unittest {
268 	auto v1 = vec3f(1, 2, -3);
269 	auto v2 = vec3f(1, 3, 2);
270 	assert(crossProduct(v1, v2)[] == [13, -5, 1].s);
271 	assert(distance(vec2f(0, 0), vec2f(0, 10)) == 10);
272 	assert(distance(vec2f(0, 0), vec2d(0, 10)) == 10);
273 	assert(dot(v1, v2) == dot(v2, v1)); // commutative
274 }
275 
276 enum Layout { columnMajor, rowMajor }; // Matrix Storage Major Dimension.
277 
278 /// Base template for all matrix-types.
279 /// Params:
280 ///  E = all values get stored as this type
281 ///  rows_ = rows of the matrix
282 ///  cols_ = columns of the matrix
283 ///  layout = matrix layout
284 struct Matrix(E, uint rows_, uint cols_,
285 			  Layout layout = Layout.rowMajor)
286 if (rows_ >= 1 &&
287 	cols_ >= 1)
288 {
289 	alias mT = E; /// Internal type of the _matrix
290 	static const uint rows = rows_; /// Number of rows
291 	static const uint cols = cols_; /// Number of columns
292 
293 	/** Matrix $(RED row-major) in memory. */
294 	static if (layout == Layout.rowMajor)
295 	{
296 		E[cols][rows] _matrix; // In C it would be mt[rows][cols], D does it like this: (mt[cols])[rows]
297 
298 		ref inout(E) opCall()(uint row, uint col) inout
299 		{
300 			return _matrix[row][col];
301 		}
302 
303 		ref inout(E) at()(uint row, uint col) inout
304 		{
305 			return _matrix[row][col];
306 		}
307 	}
308 	else
309 	{
310 		E[rows][cols] _matrix; // In C it would be mt[cols][rows], D does it like this: (mt[rows])[cols]
311 		ref inout(E) opCall()(uint row, uint col) inout
312 		{
313 			return _matrix[col][row];
314 		}
315 
316 		ref inout(E) at()(uint row, uint col) inout
317 		{
318 			return _matrix[col][row];
319 		}
320 	}
321 	alias _matrix this;
322 
323 	/// Returns: The pointer to the stored values as OpenGL requires it.
324 	/// Note this will return a pointer to a $(RED row-major) _matrix,
325 	/// $(RED this means you've to set the transpose argument to GL_TRUE when passing it to OpenGL).
326 	/// Examples:
327 	/// ---
328 	/// // 3rd argument = GL_TRUE
329 	/// glUniformMatrix4fv(programs.main.model, 1, GL_TRUE, mat4.translation(-0.5f, -0.5f, 1.0f).value_ptr);
330 	/// ---
331 	// @property auto value_ptr() { return _matrix[0].ptr; }
332 
333 	/// Returns: The current _matrix formatted as flat string.
334 
335 	@property void toString(Sink)(ref scope Sink sink) const
336 	{
337 		import std.conv : to;
338 		sink(`Matrix(`);
339 		sink(to!string(_matrix));
340 		sink(`)`);
341 	}
342 
343 	@property string toLaTeX()() const
344 	{
345 		string s;
346 		static foreach (r; 0 .. rows)
347 		{
348 			static foreach (c; 0 .. cols)
349 			{
350 				s ~= to!string(at(r, c)) ;
351 				if (c != cols - 1) { s ~= ` & `; } // if not last column
352 			}
353 			if (r != rows - 1) { s ~= ` \\ `; } // if not last row
354 		}
355 		return `\begin{pmatrix} ` ~ s ~ ` \end{pmatrix}`;
356 	}
357 
358 	@property string toMathML()() const
359 	{
360 		// opening
361 		string str = `<math><mrow>
362   <mo>❲</mo>
363   <mtable>`;
364 
365 		static foreach (r; 0 .. rows)
366 		{
367 			str ~=  `
368 	<mtr>`;
369 			static foreach (c; 0 .. cols)
370 			{
371 				str ~= `
372 	  <mtd>
373 		<mn>` ~ at(r, c).toMathML ~ `</mn>
374 	  </mtd>`;
375 			}
376 			str ~=  `
377 	</mtr>`;
378 		}
379 
380 		// closing
381 		str ~= `
382   </mtable>
383   <mo>❳</mo>
384 </mrow></math>
385 `;
386 		return str;
387 	}
388 
389 	/// Returns: The current _matrix as pretty formatted string.
390 	@property string toPrettyString()()
391 	{
392 		string fmtr = "%s";
393 
394 		size_t rjust = max(format(fmtr, reduce!(max)(_matrix[])).length,
395 						   format(fmtr, reduce!(min)(_matrix[])).length) - 1;
396 
397 		string[] outer_parts;
398 		foreach (E[] row; _matrix)
399 		{
400 			string[] inner_parts;
401 			foreach (E col; row)
402 			{
403 				inner_parts ~= rightJustify(format(fmtr, col), rjust);
404 			}
405 			outer_parts ~= " [" ~ join(inner_parts, ", ") ~ "]";
406 		}
407 
408 		return "[" ~ join(outer_parts, "\n")[1..$] ~ "]";
409 	}
410 
411 	static void isCompatibleMatrixImpl(uint r, uint c)(Matrix!(E, r, c) m) {}
412 
413 	enum isCompatibleMatrix(T) = is(typeof(isCompatibleMatrixImpl(T.init)));
414 
415 	static void isCompatibleVectorImpl(uint d)(Vector!(E, d) vec) {}
416 
417 	enum isCompatibleVector(T) = is(typeof(isCompatibleVectorImpl(T.init)));
418 
419 	private void construct(uint i, T, Tail...)(T head, Tail tail)
420 	{
421 		static if (i >= rows*cols)
422 		{
423 			static assert(0, "Too many arguments passed to constructor");
424 		}
425 		else static if (is(T : E))
426 		{
427 			_matrix[i / cols][i % cols] = head;
428 			construct!(i + 1)(tail);
429 		}
430 		else static if (is(T == Vector!(E, cols)))
431 		{
432 			static if (i % cols == 0)
433 			{
434 				_matrix[i / cols] = head._vector;
435 				construct!(i + T.dimension)(tail);
436 			}
437 			else
438 			{
439 				static assert(0, "Can't convert Vector into the matrix. Maybe it doesn't align to the columns correctly or dimension doesn't fit");
440 			}
441 		}
442 		else
443 		{
444 			static assert(0, "Matrix constructor argument must be of type " ~ E.stringof ~ " or Vector, not " ~ T.stringof);
445 		}
446 	}
447 
448 	private void construct(uint i)()  // terminate
449 	{
450 		static assert(i == rows*cols, "Not enough arguments passed to constructor");
451 	}
452 
453 	/// Constructs the matrix:
454 	/// If a single value is passed, the matrix will be cleared with this value (each column in each row will contain this value).
455 	/// If a matrix with more rows and columns is passed, the matrix will be the upper left nxm matrix.
456 	/// If a matrix with less rows and columns is passed, the passed matrix will be stored in the upper left of an identity matrix.
457 	/// It's also allowed to pass vectors and scalars at a time, but the vectors dimension must match the number of columns and align correctly.
458 	/// Examples:
459 	/// ---
460 	/// mat2 m2 = mat2(0.0f); // mat2 m2 = mat2(0.0f, 0.0f, 0.0f, 0.0f);
461 	/// mat3 m3 = mat3(m2); // mat3 m3 = mat3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
462 	/// mat3 m3_2 = mat3(vec3(1.0f, 2.0f, 3.0f), 4.0f, 5.0f, 6.0f, vec3(7.0f, 8.0f, 9.0f));
463 	/// mat4 m4 = mat4.identity; // just an identity matrix
464 	/// mat3 m3_3 = mat3(m4); // mat3 m3_3 = mat3.identity
465 	/// ---
466 	this(Args...)(Args args)
467 	{
468 		construct!(0)(args);
469 	}
470 
471 	this(T)(T mat)
472 	if (isMatrix!T &&
473 		(T.cols >= cols) &&
474 		(T.rows >= rows))
475 	{
476 		_matrix[] = mat._matrix[];
477 	}
478 
479 	this(T)(T mat)
480 	if (isMatrix!T &&
481 		(T.cols < cols) &&
482 		(T.rows < rows))
483 	{
484 		makeIdentity();
485 		static foreach (r; 0 .. T.rows)
486 		{
487 			static foreach (c; 0 .. T.cols)
488 			{
489 				at(r, c) = mat.at(r, c);
490 			}
491 		}
492 	}
493 
494 	this()(E value) { clear(value); }
495 
496 	/// Sets all values of the matrix to value (each column in each row will contain this value).
497 	void clear()(E value)
498 	{
499 		static foreach (r; 0 .. rows)
500 		{
501 			static foreach (c; 0 .. cols)
502 			{
503 				at(r,c) = value;
504 			}
505 		}
506 	}
507 
508 	static if (rows == cols)
509 	{
510 		/// Makes the current matrix an identity matrix.
511 		void makeIdentity()()
512 		{
513 			clear(0);
514 			static foreach (r; 0 .. rows)
515 			{
516 				at(r,r) = 1;
517 			}
518 		}
519 
520 		/// Returns: Identity Matrix.
521 		static @property Matrix identity()
522 		{
523 			Matrix ret;
524 			ret.clear(0);
525 			static foreach (r; 0 .. rows)
526 			{
527 				ret.at(r,r) = 1;
528 			}
529 
530 			return ret;
531 		}
532 		alias id = identity;	// shorthand
533 
534 		/// Transpose Current Matrix.
535 		void transpose()()
536 		{
537 			_matrix = transposed()._matrix;
538 		}
539 		alias T = transpose; // C++ Armadillo naming convention.
540 
541 		unittest
542 		{
543 			mat2 m2 = mat2(1.0f);
544 			m2.transpose();
545 			assert(m2._matrix == mat2(1.0f)._matrix);
546 			m2.makeIdentity();
547 			assert(m2._matrix == [[1.0f, 0.0f],
548 								  [0.0f, 1.0f]]);
549 			m2.transpose();
550 			assert(m2._matrix == [[1.0f, 0.0f],
551 								  [0.0f, 1.0f]]);
552 			assert(m2._matrix == m2.identity._matrix);
553 
554 			mat3 m3 = mat3(1.1f, 1.2f, 1.3f,
555 						   2.1f, 2.2f, 2.3f,
556 						   3.1f, 3.2f, 3.3f);
557 			m3.transpose();
558 			assert(m3._matrix == [[1.1f, 2.1f, 3.1f],
559 								  [1.2f, 2.2f, 3.2f],
560 								  [1.3f, 2.3f, 3.3f]]);
561 
562 			mat4 m4 = mat4(2.0f);
563 			m4.transpose();
564 			assert(m4._matrix == mat4(2.0f)._matrix);
565 			m4.makeIdentity();
566 			assert(m4._matrix == [[1.0f, 0.0f, 0.0f, 0.0f],
567 								  [0.0f, 1.0f, 0.0f, 0.0f],
568 								  [0.0f, 0.0f, 1.0f, 0.0f],
569 								  [0.0f, 0.0f, 0.0f, 1.0f]]);
570 			assert(m4._matrix == m4.identity._matrix);
571 		}
572 
573 	}
574 
575 	/// Returns: a transposed copy of the matrix.
576 	@property Matrix!(E, cols, rows) transposed()() const
577 	{
578 		typeof(return) ret;
579 		static foreach (r; 0 .. rows)
580 		{
581 			static foreach (c; 0 .. cols)
582 			{
583 				ret.at(c,r) = at(r,c);
584 			}
585 		}
586 		return ret;
587 	}
588 
589 }
590 alias mat2i = Matrix!(int, 2, 2);
591 alias mat2 = Matrix!(float, 2, 2);
592 alias mat2d = Matrix!(real, 2, 2);
593 alias mat2r = Matrix!(real, 2, 2);
594 alias mat3 = Matrix!(float, 3, 3);
595 alias mat34 = Matrix!(float, 3, 4);
596 alias mat4 = Matrix!(float, 4, 4);
597 alias mat2_cm = Matrix!(float, 2, 2, Layout.columnMajor);
598 
599 pure nothrow @safe @nogc unittest {
600 	auto m = mat2(1, 2,
601 				  3, 4);
602 	assert(m(0, 0) == 1);
603 	assert(m(0, 1) == 2);
604 	assert(m(1, 0) == 3);
605 	assert(m(1, 1) == 4);
606 }
607 
608 pure nothrow @safe @nogc unittest {
609 	auto m = mat2_cm(1, 3,
610 					 2, 4);
611 	assert(m(0, 0) == 1);
612 	assert(m(0, 1) == 2);
613 	assert(m(1, 0) == 3);
614 	assert(m(1, 1) == 4);
615 }
616 
617 pure nothrow @safe @nogc unittest {
618 	alias E = float;
619 	immutable a = Vector!(E, 2, false, Orient.column)(1, 2);
620 	immutable b = Vector!(E, 3, false, Orient.column)(3, 4, 5);
621 	immutable c = outerProduct(a, b);
622 	assert(c[] == [[3, 4, 5].s,
623 				   [6, 8, 10].s].s);
624 }
625 
626 /// 3-Dimensional Spherical Point with Coordinate Type (Precision) `E`.
627 struct SpherePoint3(E)
628 if (isFloatingPoint!E)
629 {
630 	enum D = 3;				 // only in three dimensions
631 	alias ElementType = E;
632 
633 	/** Construct from Components `args`. */
634 	this(T...)(T args)
635 	{
636 		foreach (immutable ix, arg; args)
637 		{
638 			_spherePoint[ix] = arg;
639 		}
640 	}
641 	/** Element data. */
642 	E[D] _spherePoint;
643 	enum dimension = D;
644 
645 	@property void toString(Sink)(ref scope Sink sink) const
646 	{
647 		sink(`SpherePoint3(`);
648 		foreach (const ix, const e ; _spherePoint)
649 		{
650 			if (ix != 0) { sink(","); }
651 			sink(to!string(e));
652 		}
653 		sink(`)`);
654 	}
655 
656 	@property string toMathML()() const
657 	{
658 		// opening
659 		string str = `<math><mrow>
660   <mo>(</mo>
661   <mtable>`;
662 
663 		static foreach (i; 0 .. D)
664 		{
665 			str ~= `
666 	<mtr>
667 	  <mtd>
668 		<mn>` ~ _spherePoint[i].toMathML ~ `</mn>
669 	  </mtd>
670 	</mtr>`;
671 		}
672 
673 		// closing
674 		str ~= `
675   </mtable>
676   <mo>)</mo>
677 </mrow></math>
678 `;
679 		return str;
680 	}
681 
682 	/** Returns: Area 0 */
683 	@property E area() const { return 0; }
684 
685 	auto opSlice() { return _spherePoint[]; }
686 }
687 
688 /** Instantiator for `SpherePoint3`. */
689 auto spherePoint(Ts...)(Ts args)
690 if (!is(CommonType!Ts == void))
691 {
692 	return SpherePoint3!(CommonType!Ts, args.length)(args);
693 }
694 
695 /** `D`-Dimensional Particle with Cartesian Coordinate `position` and
696 	`velocity` of Element (Component) Type `E`.
697 */
698 struct Particle(E, uint D,
699 				bool normalizedVelocityFlag = false)
700 if (D >= 1)
701 {
702 	Point!(E, D) position;
703 	Vector!(E, D, normalizedVelocityFlag) velocity;
704 	E mass;
705 }
706 
707 // mixin(makeInstanceAliases("Particle", "particle", 2,4,
708 //						   ["float", "double", "real"]));
709 
710 /** `D`-Dimensional Particle with Coordinate Position and
711 	Direction/Velocity/Force Type (Precision) `E`.
712 	F = m*a; where F is force, m is mass, a is acceleration.
713 */
714 struct ForcedParticle(E, uint D,
715 					  bool normalizedVelocityFlag = false)
716 if (D >= 1)
717 {
718 	Point!(E, D) position;
719 	Vector!(E, D, normalizedVelocityFlag) velocity;
720 	Vector!(E, D) force;
721 	E mass;
722 
723 	/// Get acceleration.
724 	@property auto acceleration()() const { return force/mass; }
725 }
726 
727 /** `D`-Dimensional Axis-Aligned (Hyper) Cartesian `Box` with Element (Component) Type `E`.
728 
729 	Note: We must use inclusive compares betweeen boxes and points in inclusion
730 	functions such as inside() and includes() in order for the behaviour of
731 	bounding boxes (especially in integer space) to work as desired.
732  */
733 struct Box(E, uint D)
734 if (D >= 1)
735 {
736 	this(Vector!(E,D) lh) { min = lh; max = lh; }
737 	this(Vector!(E,D) l_,
738 		 Vector!(E,D) h_) { min = l_; max = h_; }
739 
740 	@property void toString(Sink)(ref scope Sink sink) const
741 	{
742 		sink(`Box(lower:`);
743 		min.toString(sink);
744 		sink(`, upper:`);
745 		max.toString(sink);
746 		sink(`)`);
747 	}
748 
749 	/// Get Box Center.
750 	/+ TODO: @property Vector!(E,D) center() { return (min + max) / 2;} +/
751 
752 	/// Constructs a Box enclosing `points`.
753 	static Box fromPoints(in Vector!(E,D)[] points)
754 	{
755 		Box y;
756 		foreach (p; points)
757 		{
758 			y.expand(p);
759 		}
760 		return y;
761 	}
762 
763 	/// Expands the Box, so that $(I v) is part of the Box.
764 	ref Box expand(Vector!(E,D) v)
765 	{
766 		static foreach (i; 0 .. D)
767 		{
768 			if (min[i] > v[i]) min[i] = v[i];
769 			if (max[i] < v[i]) max[i] = v[i];
770 		}
771 		return this;
772 	}
773 
774 	/// Expands box by another box `b`.
775 	ref Box expand()(Box b)
776 	{
777 		return this.expand(b.min).expand(b.max);
778 	}
779 
780 	unittest
781 	{
782 		immutable auto b = Box(Vector!(E,D)(1),
783 							   Vector!(E,D)(3));
784 		assert(b.sides == Vector!(E,D)(2));
785 		immutable auto c = Box(Vector!(E,D)(0),
786 							   Vector!(E,D)(4));
787 		assert(c.sides == Vector!(E,D)(4));
788 		assert(c.sidesProduct == 4^^D);
789 		assert(unite(b, c) == c);
790 	}
791 
792 	/** Returns: Length of Sides */
793 	@property auto sides()() const { return max - min; }
794 
795 	/** Returns: Area */
796 	@property real sidesProduct()() const
797 	{
798 		typeof(return) y = 1;
799 		foreach (const ref side; sides)
800 		{
801 			y *= side;
802 		}
803 		return y;
804 	}
805 
806 	static if (D == 2)
807 	{
808 		alias area = sidesProduct;
809 	}
810 	else static if (D == 3)
811 	{
812 		alias volume = sidesProduct;
813 	}
814 	else static if (D >= 4)
815 	{
816 		alias hyperVolume = sidesProduct;
817 	}
818 
819 	alias include = expand;
820 
821 	Vector!(E,D) min;		   /// Low.
822 	Vector!(E,D) max;		   /// High.
823 
824 	/** Either an element in min or max is nan or min <= max. */
825 	invariant()
826 	{
827 		// assert(any!"a==a.nan"(min),
828 		//				  all!"a || a == a.nan"(elementwiseLessThanOrEqual(min, max)[]));
829 	}
830 }
831 
832 // mixin(makeInstanceAliases("Box","box", 2,4,
833 //						   ["int", "float", "double", "real"]));
834 
835 Box!(E,D) unite(E, uint D)(Box!(E,D) a,
836 						   Box!(E,D) b) { return a.expand(b); }
837 Box!(E,D) unite(E, uint D)(Box!(E,D) a,
838 						   Vector!(E,D) b) { return a.expand(b); }
839 
840 /** `D`-Dimensional Infinite Cartesian (Hyper)-Plane with Element (Component) Type `E`.
841 	See_Also: http://stackoverflow.com/questions/18600328/preferred-representation-of-a-3d-plane-in-c-c
842  */
843 struct Plane(E, uint D)
844 if (D >= 2 &&
845 	isFloatingPoint!E)
846 {
847 	enum dimension = D;
848 
849 	alias ElementType = E;
850 
851 	/// Normal type of plane.
852 	alias NormalType = Vector!(E, D, true);
853 
854 	union
855 	{
856 		static if (D == 3)
857 		{
858 			struct
859 			{
860 				E a; /// normal.x
861 				E b; /// normal.y
862 				E c; /// normal.z
863 			}
864 		}
865 		NormalType normal;	  /// Plane Normal.
866 	}
867 	E distance;				  /// Plane Constant (Offset from origo).
868 
869 	@property void toString(Sink)(ref scope Sink sink) const
870 	{
871 		import std.conv : to;
872 		sink(`Plane(normal:`);
873 		sink(to!string(normal));
874 		sink(`, distance:`);
875 		sink(to!string(distance));
876 		sink(`)`);
877 	}
878 
879 	/// Constructs the plane, from either four scalars of type $(I E)
880 	/// or from a 3-dimensional vector (= normal) and a scalar.
881 	static if (D == 2)
882 	{
883 		this()(E a, E b, E distance)
884 		{
885 			this.normal.x = a;
886 			this.normal.y = b;
887 			this.distance = distance;
888 		}
889 	}
890 	else static if (D == 3)
891 	{
892 		this()(E a, E b, E c, E distance)
893 		{
894 			this.normal.x = a;
895 			this.normal.y = b;
896 			this.normal.z = c;
897 			this.distance = distance;
898 		}
899 	}
900 
901 	this()(NormalType normal, E distance)
902 	{
903 		this.normal = normal;
904 		this.distance = distance;
905 	}
906 
907 	/* unittest
908 	   { */
909 	/*	 Plane p = Plane(0.0f, 1.0f, 2.0f, 3.0f); */
910 	/*	 assert(p.normal == N(0.0f, 1.0f, 2.0f)); */
911 	/*	 assert(p.distance == 3.0f); */
912 
913 	/*	 p.normal.x = 4.0f; */
914 	/*	 assert(p.normal == N(4.0f, 1.0f, 2.0f)); */
915 	/*	 assert(p.x == 4.0f); */
916 	/*	 assert(p.y == 1.0f); */
917 	/*	 assert(p.c == 2.0f); */
918 	/*	 assert(p.distance == 3.0f); */
919 	/* } */
920 
921 	/// Normalizes the plane inplace.
922 	void normalize()()
923 	{
924 		immutable E det = cast(E)1 / normal.magnitude;
925 		normal *= det;
926 		distance *= det;
927 	}
928 
929 	/// Returns: a normalized copy of the plane.
930 	/* @property Plane normalized() const { */
931 	/*	 Plane y = Plane(a, b, c, distance); */
932 	/*	 y.normalize(); */
933 	/*	 return y; */
934 	/* } */
935 
936 //	 unittest {
937 //		 Plane p = Plane(0.0f, 1.0f, 2.0f, 3.0f);
938 //		 Plane pn = p.normalized();
939 //		 assert(pn.normal == N(0.0f, 1.0f, 2.0f).normalized);
940 //		 assert(almost_equal(pn.distance, 3.0f / N(0.0f, 1.0f, 2.0f).length));
941 //		 p.normalize();
942 //		 assert(p == pn);
943 //	 }
944 
945 	/// Returns: distance from a point to the plane.
946 	/// Note: the plane $(RED must) be normalized, the result can be negative.
947 	/* E distanceTo(N point) const { */
948 	/*	 return dot(point, normal) + distance; */
949 	/* } */
950 
951 	/// Returns: distanceTo from a point to the plane.
952 	/// Note: the plane does not have to be normalized, the result can be negative.
953 	/* E ndistance(N point) const { */
954 	/*	 return (dot(point, normal) + distance) / normal.magnitude; */
955 	/* } */
956 
957 	/* unittest
958 	   { */
959 	/*	 Plane p = Plane(-1.0f, 4.0f, 19.0f, -10.0f); */
960 	/*	 assert(almost_equal(p.ndistance(N(5.0f, -2.0f, 0.0f)), -1.182992)); */
961 	/*	 assert(almost_equal(p.ndistance(N(5.0f, -2.0f, 0.0f)), */
962 	/*						 p.normalized.distanceTo(N(5.0f, -2.0f, 0.0f)))); */
963 	/* } */
964 
965 	/* bool opEquals(Plane other) const { */
966 	/*	 return other.normal == normal && other.distance == distance; */
967 	/* } */
968 
969 }
970 
971 // mixin(makeInstanceAliases("Plane","plane", 3,4,
972 //						   defaultElementTypes));
973 
974 /** `D`-Dimensional Cartesian (Hyper)-Sphere with Element (Component) Type `E`.
975  */
976 struct Sphere(E, uint D)
977 if (D >= 2 &&
978 	isNumeric!E)
979 {
980 	alias CenterType = Point!(E, D);
981 
982 	CenterType center;
983 	E radius;
984 
985 	void translate(Vector!(E, D) shift)
986 	{
987 		center = center + shift; // point + vector => point
988 	}
989 	alias shift = translate;
990 
991 	@property:
992 
993 	E diameter()() const
994 	{
995 		return 2 * radius;
996 	}
997 	static if (D == 2)
998 	{
999 		auto area()() const
1000 		{
1001 			return PI * radius ^^ 2;
1002 		}
1003 	}
1004 	else static if (D == 3)
1005 	{
1006 		auto area()() const
1007 		{
1008 			return 4 * PI * radius ^^ 2;
1009 		}
1010 		auto volume()() const
1011 		{
1012 			return 4 * PI * radius ^^ 3 / 3;
1013 		}
1014 	}
1015 	else static if (D >= 4)
1016 	{
1017 		// See_Also: https://en.wikipedia.org/wiki/Volume_of_an_n-ball
1018 		real n = D;
1019 		auto volume()() const
1020 		{
1021 			import std.mathspecial: gamma;
1022 			return PI ^^ (n / 2) / gamma(n / 2 + 1) * radius ^^ n;
1023 		}
1024 	}
1025 }
1026 
1027 auto sphere(C, R)(C center, R radius)
1028 {
1029 	return Sphere!(C.ElementType, C.dimension)(center, radius);
1030 }
1031 /+ TODO: Use this instead: +/
1032 // auto sphere(R, C...)(Point!(CommonType!C, C.length) center, R radius) {
1033 // return Sphere!(CommonType!C, C.length)(center, radius);
1034 // }
1035 
1036 /**
1037    See_Also: http://stackoverflow.com/questions/401847/circle-rectangle-collision-detection-intersect
1038  */
1039 bool intersect(T)(Circle!T circle, Rect!T rect)
1040 {
1041 	immutable hw = rect.w/2, hh = rect.h/2;
1042 
1043 	immutable dist = Point!T(abs(circle.x - rect.x0 - hw),
1044 							 abs(circle.y - rect.y0 - hh));
1045 
1046 	if (dist.x > (hw + circle.r)) return false;
1047 	if (dist.y > (hh + circle.r)) return false;
1048 
1049 	if (dist.x <= hw) return true;
1050 	if (dist.y <= hh) return true;
1051 
1052 	immutable cornerDistance_sq = ((dist.x - hw)^^2 +
1053 								   (dist.y - hh)^^2);
1054 
1055 	return (cornerDistance_sq <= circle.r^^2);
1056 }
1057 
1058 @safe unittest {
1059 	assert(box2f(vec2f(1, 2), vec2f(3, 3)).to!string == `Box(lower:ColumnVector(1,2), upper:ColumnVector(3,3))`);
1060 	assert([12, 3, 3].to!string == `[12, 3, 3]`);
1061 
1062 	assert(vec2f(2, 3).to!string == `ColumnVector(2,3)`);
1063 
1064 	assert(vec2f(2, 3).to!string == `ColumnVector(2,3)`);
1065 	assert(vec2f(2, 3).to!string == `ColumnVector(2,3)`);
1066 
1067 	assert(vec3f(2, 3, 4).to!string == `ColumnVector(2,3,4)`);
1068 
1069 	assert(box2f(vec2f(1, 2),
1070 				 vec2f(3, 4)).to!string == `Box(lower:ColumnVector(1,2), upper:ColumnVector(3,4))`);
1071 
1072 	assert(vec2i(2, 3).to!string == `ColumnVector(2,3)`);
1073 	assert(vec3i(2, 3, 4).to!string == `ColumnVector(2,3,4)`);
1074 	assert(vec3i(2, 3, 4).to!string == `ColumnVector(2,3,4)`);
1075 
1076 	assert(vec2i(2, 3).toMathML == `<math><mrow>
1077   <mo>⟨</mo>
1078   <mtable>
1079 	<mtr>
1080 	  <mtd>
1081 		<mn>2</mn>
1082 	  </mtd>
1083 	</mtr>
1084 	<mtr>
1085 	  <mtd>
1086 		<mn>3</mn>
1087 	  </mtd>
1088 	</mtr>
1089   </mtable>
1090   <mo>⟩</mo>
1091 </mrow></math>
1092 `);
1093 
1094 	auto m = mat2(1, 2, 3, 4);
1095 	assert(m.toLaTeX == `\begin{pmatrix} 1 & 2 \\ 3 & 4 \end{pmatrix}`);
1096 	assert(m.toMathML == `<math><mrow>
1097   <mo>❲</mo>
1098   <mtable>
1099 	<mtr>
1100 	  <mtd>
1101 		<mn>1</mn>
1102 	  </mtd>
1103 	  <mtd>
1104 		<mn>2</mn>
1105 	  </mtd>
1106 	</mtr>
1107 	<mtr>
1108 	  <mtd>
1109 		<mn>3</mn>
1110 	  </mtd>
1111 	  <mtd>
1112 		<mn>4</mn>
1113 	  </mtd>
1114 	</mtr>
1115   </mtable>
1116   <mo>❳</mo>
1117 </mrow></math>
1118 `);
1119 }
1120 
1121 version (unittest)
1122 {
1123 	import std.conv : to;
1124 	import nxt.array_help : s;
1125 }