1 // -*- Mode: C++; tab-width: 2; -*-
2 // vi: set ts=2:
3 //
4 
5 #ifndef BALL_MATHS_ANALYTICALGEOMETRY_H
6 #define BALL_MATHS_ANALYTICALGEOMETRY_H
7 
8 #ifndef BALL_COMMON_EXCEPTION_H
9 # include <BALL/COMMON/exception.h>
10 #endif
11 
12 #ifndef BALL_MATHS_ANGLE_H
13 #	include <BALL/MATHS/angle.h>
14 #endif
15 
16 #ifndef BALL_MATHS_CIRCLE3_H
17 #	include <BALL/MATHS/circle3.h>
18 #endif
19 
20 #ifndef BALL_MATHS_LINE3_H
21 #	include <BALL/MATHS/line3.h>
22 #endif
23 
24 #ifndef BALL_MATHS_PLANE3_H
25 #	include <BALL/MATHS/plane3.h>
26 #endif
27 
28 #ifndef BALL_MATHS_SPHERE3_H
29 #	include <BALL/MATHS/sphere3.h>
30 #endif
31 
32 #ifndef BALL_MATHS_VECTOR3_H
33 #	include <BALL/MATHS/vector3.h>
34 #endif
35 
36 #define BALL_MATRIX_CELL(m, dim, row, col)   *((m) + (row) * (dim) + (col))
37 #define BALL_CELL(x, y)                      *((m) + (y) * (dim) + (x))
38 
39 namespace BALL
40 {
41 
42 	/**	\defgroup AnalyticalGeometry Analytical Geometry
43 			representation of analytical geometry functions,
44 			using the classes: TAngle, TCircle3, TLine3, TPlane3, TSphere3, TVector3.
45 	  \ingroup Mathematics
46 	*/
47 	//@{
48 
49 	/**	Subroutine to get the determinant of any matrix.
50 			Direct usage of this function should be avoided.
51 			Instead use <tt>T getDeterminant(const T* m, Size dim) </tt>
52 			@param	m pointer to matrix
53 			@param	dim dimension of the matrix
54 	*/
55 	template <typename T>
56 	BALL_INLINE
getDeterminant_(const T * m,Size dim)57 	T getDeterminant_(const T* m, Size dim)
58 	{
59 		T determinant = 0;
60 		Index dim1 = dim - 1;
61 
62 		if (dim > 1)
63 		{
64 			T* submatrix = new T[dim1 * dim1];
65 
66 			for (Index i = 0; i < (Index)dim; ++i)
67 			{
68 				for (Index j = 0; j < dim1; ++j)
69 				{
70 					for (Index k = 0; k < dim1; ++k)
71 					{
72 						*(submatrix + j * dim1 + k) = *(m + (j + 1) * dim + (k < i ? k : k + 1));
73 					}
74 				}
75 				determinant += *(m + i) * (i / 2.0 == i / 2 ? 1 : -1) * getDeterminant_(submatrix, dim1);
76 			}
77 
78 			delete [] submatrix;
79 		}
80 		else
81 		{
82 			determinant = *m;
83 		}
84 
85 		return determinant;
86 	}
87 
88 	/**	Get the determinant of any matrix.
89 			@param	m pointer to matrix
90 			@param	dim dimension of the matrix
91 	*/
92 	template <typename T>
getDeterminant(const T * m,Size dim)93 	T getDeterminant(const T* m, Size dim)
94 	{
95 		if (dim == 2)
96 		{
97 			return (BALL_CELL(0,0) * BALL_CELL(1,1) - BALL_CELL(0,1) * BALL_CELL(1,0));
98 		}
99 		else if (dim == 3)
100 		{
101 			return (  BALL_CELL(0,0) * BALL_CELL(1,1) * BALL_CELL(2,2)
102 							+ BALL_CELL(0,1) * BALL_CELL(1,2) * BALL_CELL(2,0)
103 							+ BALL_CELL(0,2) * BALL_CELL(1,0) * BALL_CELL(2,1)
104 							- BALL_CELL(0,2) * BALL_CELL(1,1) * BALL_CELL(2,0)
105 							- BALL_CELL(0,0) * BALL_CELL(1,2) * BALL_CELL(2,1)
106 							- BALL_CELL(0,1) * BALL_CELL(1,0) * BALL_CELL(2,2));
107 		}
108 		else
109 		{
110 			return getDeterminant_(m, dim);
111 		}
112 	}
113 
114 	/**	Get the determinant of an 2x2 matrix.
115 			@param	m pointer to matrix
116 	*/
117 	template <typename T>
118 	BALL_INLINE
getDeterminant2(const T * m)119 	T getDeterminant2(const T* m)
120 	{
121 		Size dim = 2;
122 		return (BALL_CELL(0,0) * BALL_CELL(1,1) - BALL_CELL(0,1) * BALL_CELL(1,0));
123 	}
124 
125 	/**	Get the determinant of an 2x2 matrix.
126 			@param	m00 first value of the matrix
127 			@param	m01 second value of the matrix
128 			@param	m10 third value of the matrix
129 			@param	m11 fourth value of the matrix
130 	*/
131 	template <typename T>
132 	BALL_INLINE
getDeterminant2(const T & m00,const T & m01,const T & m10,const T & m11)133 	T getDeterminant2(const T& m00, const T& m01, const T& m10, const T& m11)
134 	{
135 		return (m00 * m11 - m01 * m10);
136 	}
137 
138 	/**	Get the determinant of an 3x3 matrix.
139 			@param	m pointer to matrix
140 	*/
141 	template <typename T>
142 	BALL_INLINE
getDeterminant3(const T * m)143 	T getDeterminant3(const T *m)
144 	{
145 		Size dim = 3;
146 		return (  BALL_CELL(0,0) * BALL_CELL(1,1) * BALL_CELL(2,2)
147 						+ BALL_CELL(0,1) * BALL_CELL(1,2) * BALL_CELL(2,0)
148 						+ BALL_CELL(0,2) * BALL_CELL(1,0) * BALL_CELL(2,1)
149 						- BALL_CELL(0,2) * BALL_CELL(1,1) * BALL_CELL(2,0)
150 						- BALL_CELL(0,0) * BALL_CELL(1,2) * BALL_CELL(2,1)
151 						- BALL_CELL(0,1) * BALL_CELL(1,0) * BALL_CELL(2,2));
152 	}
153 
154 	/**	Get the determinant of an 3x3 matrix.
155 			@param	m00, m01, m02, m10, m11, m12, m20, m21, m22 the elements of the matrix
156 	*/
157 	template <typename T>
158 	BALL_INLINE T
getDeterminant3(const T & m00,const T & m01,const T & m02,const T & m10,const T & m11,const T & m12,const T & m20,const T & m21,const T & m22)159 	getDeterminant3(const T& m00, const T& m01, const T& m02, const T& m10, const T& m11, const T& m12, const T& m20, const T& m21, const T& m22)
160 	{
161 		return (  m00 * m11 * m22 + m01 * m12 * m20 + m02 * m10 * m21 - m02 * m11 * m20 - m00 * m12 * m21 - m01 * m10 * m22);
162 	}
163 
164 	/**	Solve a system of linear equations.
165 		  Given a system of linear equations \par
166 			 \par
167 			\f$
168 				\begin{array}{ccccccccc}
169 				 a_{1,1} x_1 & + & a_{1,2} x_2 & + & \ldots & + & a_{1,n} x_n & = & a_{1,(n+1)} \\
170 				 a_{2,1} x_1 & + & a_{2,2} x_2 & + & \ldots & + & a_{2,n} x_n & = & a_{2,(n+1)} \\
171 				   \vdots    &   &   \vdots    &   & \ddots &   &   \vdots    &   &   \vdots \\
172 				 a_{n,1} x_1 & + & a_{n,2} x_2 & + & \ldots & + & a_{n,n} x_n & = & a_{n,(n+1)} \\
173 				\end{array}
174 			\f$
175 			 \par
176 			in matrix form, identify the solution \f$x = (x_1, x_2,\ldots x_N)\f$. \par
177 			<tt>m</tt> should point to a C-style array containing the \f$n\times(n+1)\f$ matrix <b>A</b>. \par
178 			The elements of <b>A</b> are row-ordered, i.e., they are ordered like this: \par
179 			\f$
180 				a_{1,1}, a_{1,2}, \cdot, a_{1,(n+1)}, a_{2,1}, \ldots a_{n,(n+1)}
181 			\f$ \par
182 			<tt>x</tt> points to a C-style array that will contain the solution vector <b>x</b>
183 			upon successful termination of the function. \par
184 			If there is no solution or the system is under-determined, return <b>false</b>.
185 			@param	m pointer to the factors in the equations
186 			@param	x pointer in which the results are stored
187 			@param  dim the dimension of the equation system (number of variables)
188 			@return bool <tt>true</tt> if a solution is found
189 	*/
190 	template <typename T>
SolveSystem(const T * m,T * x,const Size dim)191 	bool SolveSystem(const T* m, T* x, const Size dim)
192 	{
193 		T pivot;
194 		Index i, j, k, p;
195 		// the column dimension of the matrix
196 		const Size col_dim = dim + 1;
197 		T* matrix = new T[dim * (dim + 1)];
198 		const T* source = m;
199 		T* target = (T*)matrix;
200 		T* end = (T*)&BALL_MATRIX_CELL(matrix, col_dim, dim - 1, dim);
201 
202 		while (target <= end)
203 		{
204 			*target++ = *source++;
205 		}
206 
207 		for (i = 0; i < (Index)dim; ++i)
208 		{
209 			pivot = BALL_MATRIX_CELL(matrix, col_dim, i, i);
210 			p = i;
211 			for (j = i + 1; j < (Index)dim; ++j)
212 			{
213 				if (Maths::isLess(pivot, BALL_MATRIX_CELL(matrix, col_dim, j, i)))
214 				{
215 					pivot = BALL_MATRIX_CELL(matrix, col_dim, j, i);
216 					p = j;
217 				}
218 			}
219 
220 			if (p != i)
221 			{
222 				T tmp;
223 
224 				for (k = i; k < (Index)dim + 1; ++k)
225 				{
226 					tmp = BALL_MATRIX_CELL(matrix, dim, i, k);
227 					BALL_MATRIX_CELL(matrix, col_dim, i, k) = BALL_MATRIX_CELL(matrix, col_dim, p, k);
228 					BALL_MATRIX_CELL(matrix, col_dim, p, k) = tmp;
229 				}
230 			}
231 			else if (Maths::isZero(pivot) || Maths::isNan(pivot))
232 			{
233 				// invariant: matrix m is singular
234 				delete [] matrix;
235 
236 				return false;
237 			}
238 
239 			for (j = dim; j >= i; --j)
240 			{
241 				BALL_MATRIX_CELL(matrix, col_dim, i, j) /= pivot;
242 			}
243 
244 			for (j = i + 1; j < (Index)dim; ++j)
245 			{
246 				pivot = BALL_MATRIX_CELL(matrix, col_dim, j, i);
247 
248 				for (k = dim; k>= i; --k)
249 				{
250 					BALL_MATRIX_CELL(matrix, col_dim, j, k) -= pivot * BALL_MATRIX_CELL(matrix, col_dim, i, k);
251 				}
252 			}
253 		}
254 
255 		x[dim - 1] = BALL_MATRIX_CELL(matrix, col_dim, dim - 1, dim);
256 
257 		for (i = dim - 2; i >= 0; --i)
258 		{
259 			x[i] = BALL_MATRIX_CELL(matrix, col_dim, i, dim);
260 
261 			for (j = i + 1; j < (Index)dim; ++j)
262 			{
263 				x[i] -= BALL_MATRIX_CELL(matrix, col_dim, i, j) * x[j];
264 			}
265 		}
266 
267 		delete [] matrix;
268 
269 		return true;
270 	}
271 
272 #undef BALL_CELL
273 #undef BALL_MATRIX_CELL
274 
275 	/**	Solve a system of two equations of the form
276 		  \f$a_1 x_1 + b_1 x_2 = c_1\f$ and
277 		  \f$a_2 x_1 + b_2 x_2 = c_2\f$.
278 			@param	a1, b1, c1, a2, b2, c2 constants of the system
279 			@param x1 the first solution
280 			@param x2 the second solution
281 			@return bool <tt>true</tt> if a solution is found
282 	*/
283 	template <typename T>
284 	BALL_INLINE
SolveSystem2(const T & a1,const T & b1,const T & c1,const T & a2,const T & b2,const T & c2,T & x1,T & x2)285 	bool SolveSystem2(const T& a1, const T& b1, const T& c1, const T& a2, const T& b2, const T& c2, T& x1, T& x2)
286 	{
287 		T quot = (a1 * b2 - a2 * b1);
288 
289 		if (Maths::isZero(quot))
290 		{
291 			return false;
292 		}
293 
294 		x1 = (c1 * b2 - c2 * b1) / quot;
295 		x2 = (a1 * c2 - a2 * c1) / quot;
296 
297 		return true;
298 	}
299 
300 	/**	Solve a quadratic equation of the form
301 			a \f$x^2 + b x + c = 0\f$.
302 			@param	a
303 			@param	b
304 			@param	c
305 			@param x1 the first solution
306 			@param x2 the second solution
307 			@return short the number of solutions (0 - 2)
308 	*/
309 	template <typename T>
SolveQuadraticEquation(const T & a,const T & b,const T & c,T & x1,T & x2)310 	short	SolveQuadraticEquation(const T& a, const T& b, const T &c, T &x1, T &x2)
311 	{
312 		if (a == 0)
313 		{
314 			if (b == 0)
315 			{
316 				return 0;
317 			}
318 			x1 = x2 = c / b;
319 			return 1;
320 		}
321 		T discriminant = b * b - 4 * a * c;
322 
323 		if (Maths::isLess(discriminant, 0))
324 		{
325 			return 0;
326 		}
327 
328 		T sqrt_discriminant = sqrt(discriminant);
329 		if (Maths::isZero(sqrt_discriminant))
330 		{
331 			x1 = x2 = -b / (2 * a);
332 
333 			return 1;
334 		}
335 		else
336 		{
337 			x1 = (-b + sqrt_discriminant) / (2 * a);
338 			x2 = (-b - sqrt_discriminant) / (2 * a);
339 
340 			return 2;
341 		}
342 	}
343 
344 	/**	Get the partition of two vectors.
345 			@param	a the first vector
346 			@param	b the second vector
347 			@return TVector3 the partition
348 	*/
349 	template <typename T>
350 	BALL_INLINE
GetPartition(const TVector3<T> & a,const TVector3<T> & b)351 	TVector3<T> GetPartition(const TVector3<T>& a, const TVector3<T>& b)
352 	{
353 		return TVector3<T>((b.x + a.x) / 2, (b.y + a.y) / 2, (b.z + a.z) / 2);
354 	}
355 
356 	/**	Get the partition of two vectors, calculated
357 			with two ratio factors.
358 			@param	a the first vector
359 			@param	b the second vector
360 			@param  r the ratio factor of the first vector
361 			@param  s the ratio factor of the second vector
362 			@return TVector3 the partition
363 			@throw  Exception::DivisionByZero if r+s == 0
364 	*/
365 	template <typename T>
366 	BALL_INLINE
GetPartition(const TVector3<T> & a,const TVector3<T> & b,const T & r,const T & s)367 	TVector3<T> GetPartition(const TVector3<T>& a, const TVector3<T>& b, const T& r, const T& s)
368 	{
369 		T sum = r + s;
370 		if (sum == (T)0)
371 		{
372 			throw Exception::DivisionByZero(__FILE__, __LINE__);
373 		}
374 		return TVector3<T>
375 			((s * a.x + r * b.x) / sum,
376 			 (s * a.y + r * b.y) / sum,
377 			 (s * a.z + r * b.z) / sum);
378 	}
379 
380 	/**	Get the distance between two points.
381 			@param	a the first point
382 			@param	b the second point
383 			@return T the distance
384 	*/
385 	template <typename T>
386 	BALL_INLINE
GetDistance(const TVector3<T> & a,const TVector3<T> & b)387 	T GetDistance(const TVector3<T>& a, const TVector3<T>& b)
388 	{
389 		T dx = a.x - b.x;
390 		T dy = a.y - b.y;
391 		T dz = a.z - b.z;
392 
393 		return sqrt(dx * dx + dy * dy + dz * dz);
394 	}
395 
396 	/**	Get the distance between a line and a point.
397 			@param	line the line
398 			@param	point the point
399 			@return T the distance
400 			@throw  Exception::DivisionByZero if the line has length 0
401 	*/
402 	template <typename T>
403 	BALL_INLINE
GetDistance(const TLine3<T> & line,const TVector3<T> & point)404 	T GetDistance(const TLine3<T>& line, const TVector3<T>& point)
405 	{
406 		if (line.d.getLength() == (T)0)
407 		{
408 			throw Exception::DivisionByZero(__FILE__, __LINE__);
409 		}
410 		return ((line.d % (point - line.p)).getLength() / line.d.getLength());
411 	}
412 
413 	/**	Get the distance between a point and a line.
414 			@param	point the point
415 			@param	line the line
416 			@return T the distance
417 			@throw  Exception::DivisionByZero if the line has length 0
418 	*/
419 	template <typename T>
420 	BALL_INLINE
GetDistance(const TVector3<T> & point,const TLine3<T> & line)421 	T GetDistance(const TVector3<T>& point, const TLine3<T>& line)
422 	{
423 		return GetDistance(line, point);
424 	}
425 
426 	/**	Get the distance between two lines.
427 			@param	a the first line
428 			@param	b the second line
429 			@return T the distance
430 			@throw  Exception::DivisionByZero if the lines are parallel and a has length 0
431 	*/
432 	template <typename T>
GetDistance(const TLine3<T> & a,const TLine3<T> & b)433 	T GetDistance(const TLine3<T>& a, const TLine3<T>& b)
434 	{
435 		T cross_product_length = (a.d % b.d).getLength();
436 
437 		if (Maths::isZero(cross_product_length))
438 		{ // invariant: parallel lines
439 			if (a.d.getLength() == (T)0)
440 			{
441 				throw Exception::DivisionByZero(__FILE__, __LINE__);
442 			}
443 			return ((a.d % (b.p - a.p)).getLength() / a.d.getLength());
444 		}
445 		else
446 		{
447 			T spat_product = TVector3<T>::getTripleProduct(a.d, b.d, b.p - a.p);
448 
449 			if (Maths::isNotZero(spat_product))
450 			{ // invariant: windschiefe lines
451 
452 				return (Maths::abs(spat_product) / cross_product_length);
453 			}
454 			else
455 			{
456 				// invariant: intersecting lines
457 				return 0;
458 			}
459 		}
460 	}
461 
462 	/**	Get the distance between a point and a plane.
463 			@param	point the point
464 			@param	plane the plane
465 			@return T the distance
466 			@throw  Exception::DivisionByZero if the normal vector of plane has zero length
467 	*/
468 	template <typename T>
469 	BALL_INLINE
GetDistance(const TVector3<T> & point,const TPlane3<T> & plane)470 	T GetDistance(const TVector3<T>& point, const TPlane3<T>& plane)
471 	{
472 		T length = plane.n.getLength();
473 
474 		if (length == (T)0)
475 		{
476 			throw Exception::DivisionByZero(__FILE__, __LINE__);
477 		}
478 		return (Maths::abs(plane.n * (point - plane.p)) / length);
479 	}
480 
481 	/**	Get the distance between a plane and a point.
482 			@param	plane the plane
483 			@param	point the point
484 			@return T the distance
485 			@throw  Exception::DivisionByZero if the normal vector of plane has zero length
486 	*/
487 	template <typename T>
488 	BALL_INLINE
GetDistance(const TPlane3<T> & plane,const TVector3<T> & point)489 	T GetDistance(const TPlane3<T>& plane, const TVector3<T>& point)
490 	{
491 		return GetDistance(point, plane);
492 	}
493 
494 	/**	Get the distance between a line and a plane.
495 			@param	line the line
496 			@param	plane the plane
497 			@return T the distance
498 			@throw  Exception::DivisionByZero if the normal vector of plane has zero length
499 	*/
500 	template <typename T>
501 	BALL_INLINE
GetDistance(const TLine3<T> & line,const TPlane3<T> & plane)502 	T GetDistance(const TLine3<T>& line, const TPlane3<T>& plane)
503 	{
504 		T length = plane.n.getLength();
505 		if (length == (T)0)
506 		{
507 			throw Exception::DivisionByZero(__FILE__, __LINE__);
508 		}
509 		return (Maths::abs(plane.n * (line.p - plane.p)) / length);
510 	}
511 
512 	/**	Get the distance between a plane and a line.
513 			@param	plane the plane
514 			@param	line the line
515 			@return T the distance
516 			@throw  Exception::DivisionByZero if the normal vector of plane has zero length
517 	*/
518 	template <typename T>
519 	BALL_INLINE
GetDistance(const TPlane3<T> & plane,const TLine3<T> & line)520 	T GetDistance(const TPlane3<T>& plane, const TLine3<T>& line)
521 	{
522 		return GetDistance(line, plane);
523 	}
524 
525 	/**	Get the distance between two planes.
526 			@param	a the first plane
527 			@param	b the second plane
528 			@return T the distance
529 			@throw  Exception::DivisionByZero if the normal vector of a has zero length
530 	*/
531 	template <typename T>
532 	BALL_INLINE
GetDistance(const TPlane3<T> & a,const TPlane3<T> & b)533 	T GetDistance(const TPlane3<T>& a, const TPlane3<T>& b)
534 	{
535 		T length = a.n.getLength();
536 		if (length == (T)0)
537 		{
538 			throw Exception::DivisionByZero(__FILE__, __LINE__);
539 		}
540 		return (Maths::abs(a.n * (a.p - b.p)) / length);
541 	}
542 
543 	/**	Get the angle between two Vector3.
544 			@param	a the first vector
545 			@param	b the second vector
546 			@param	intersection_angle the resulting angle
547 			@return bool, always true
548 	*/
549 	template <typename T>
550 	BALL_INLINE
GetAngle(const TVector3<T> & a,const TVector3<T> & b,TAngle<T> & intersection_angle)551 	bool GetAngle(const TVector3<T>& a, const TVector3<T>& b,	TAngle<T> &intersection_angle)
552 	{
553 		T length_product = a.getSquareLength() *  b.getSquareLength();
554 		if(Maths::isZero(length_product))
555 		{
556 			return false;
557 		}
558 		intersection_angle = a.getAngle(b);
559 		return true;
560 	}
561 
562 	/**	Get the angle between two lines.
563 			@param	a the first line
564 			@param	b the second line
565 			@param	intersection_angle the resulting angle
566 			@return bool, true if an angle can be calculated, otherwise false
567 	*/
568 	template <typename T>
569 	BALL_INLINE
GetAngle(const TLine3<T> & a,const TLine3<T> & b,TAngle<T> & intersection_angle)570 	bool GetAngle(const TLine3<T>& a, const TLine3<T>& b, TAngle<T>& intersection_angle)
571 	{
572 		T length_product = a.d.getSquareLength() *  b.d.getSquareLength();
573 
574 		if(Maths::isZero(length_product))
575 		{
576 			return false;
577 		}
578 		intersection_angle = acos(Maths::abs(a.d * b.d) / sqrt(length_product));
579 		return true;
580 	}
581 
582 	/**	Get the angle between a plane and a Vector3.
583 			@param	plane the plane
584 			@param	vector the Vector3
585 			@param	intersection_angle the resulting angle
586 			@return bool, true if an angle can be calculated, otherwise false
587 	*/
588 	template <typename T>
589 	BALL_INLINE
GetAngle(const TPlane3<T> & plane,const TVector3<T> & vector,TAngle<T> & intersection_angle)590 	bool GetAngle(const TPlane3<T>& plane, const TVector3<T>& vector, TAngle<T>& intersection_angle)
591 	{
592 		T length_product = plane.n.getSquareLength() * vector.getSquareLength();
593 
594 		if (Maths::isZero(length_product))
595 		{
596 			return false;
597 		}
598 		else
599 		{
600 			intersection_angle = asin(Maths::abs(plane.n * vector) / sqrt(length_product));
601 			return true;
602 		}
603 	}
604 
605 	/**	Get the angle between a vector3 and a plane.
606 			@param	vector the vector3
607 			@param	plane the plane
608 			@param	intersection_angle the resulting angle
609 			@return bool, true if an angle can be calculated, otherwise false
610 	*/
611 	template <typename T>
612 	BALL_INLINE
GetAngle(const TVector3<T> & vector,const TPlane3<T> & plane,TAngle<T> & intersection_angle)613 	bool GetAngle(const TVector3<T>& vector ,const TPlane3<T>& plane, TAngle<T> &intersection_angle)
614 	{
615 		return GetAngle(plane, vector, intersection_angle);
616 	}
617 
618 	/**	Get the angle between a plane and a line.
619 			@param	plane the plane
620 			@param	line the line
621 			@param	intersection_angle the resulting angle
622 			@return bool, true if an angle can be calculated, otherwise false
623 	*/
624 	template <typename T>
625 	BALL_INLINE
GetAngle(const TPlane3<T> & plane,const TLine3<T> & line,TAngle<T> & intersection_angle)626 	bool GetAngle(const TPlane3<T>& plane,const TLine3<T>& line, TAngle<T>& intersection_angle)
627 	{
628 		T length_product = plane.n.getSquareLength() * line.d.getSquareLength();
629 
630 		if (Maths::isZero(length_product))
631 		{
632 			return false;
633 		}
634 
635 		intersection_angle = asin(Maths::abs(plane.n * line.d) / sqrt(length_product));
636 		return true;
637 	}
638 
639 	/**	Get the angle between a line and a plane.
640 			@param	line the line
641 			@param	plane the plane
642 			@param	intersection_angle the resulting angle
643 			@return bool, true if an angle can be calculated, otherwise false
644 	*/
645 	template <typename T>
646 	BALL_INLINE
GetAngle(const TLine3<T> & line,const TPlane3<T> & plane,TAngle<T> & intersection_angle)647 	bool GetAngle(const TLine3<T>& line, const TPlane3<T>& plane, TAngle<T>& intersection_angle)
648 	{
649 		return GetAngle(plane, line, intersection_angle);
650 	}
651 
652 
653 	/**	Get the angle between two planes.
654 			@param	a the first plane
655 			@param	b the second plane
656 			@param	intersection_angle the resulting angle
657 			@return bool, true if an angle can be calculated, otherwise false
658 	*/
659 	template <typename T>
660 	BALL_INLINE
GetAngle(const TPlane3<T> & a,const TPlane3<T> & b,TAngle<T> & intersection_angle)661 	bool GetAngle(const TPlane3<T>& a, const TPlane3<T>& b, TAngle<T>& intersection_angle)
662 	{
663 		T length_product = a.n.getSquareLength() * b.n.getSquareLength();
664 
665 		if(Maths::isZero(length_product))
666 		{
667 			return false;
668 		}
669 
670 		intersection_angle = acos(Maths::abs(a.n * b.n) / sqrt(length_product));
671 		return true;
672 	}
673 
674 	/**	Get the intersection point between two lines.
675 			@param	a the first line
676 			@param	b the second line
677 			@param	point the resulting intersection
678 			@return bool, true if an intersection can be calculated, otherwise false
679 	*/
680 	template <typename T>
GetIntersection(const TLine3<T> & a,const TLine3<T> & b,TVector3<T> & point)681 	bool GetIntersection(const TLine3<T>& a, const TLine3<T>& b, TVector3<T>& point)
682 	{
683 		T c1, c2;
684 		if ((SolveSystem2(a.d.x, -b.d.x, b.p.x - a.p.x, a.d.y,  -b.d.y, b.p.y - a.p.y, c1, c2) == true && Maths::isEqual(a.p.z + a.d.z * c1, b.p.z + b.d.z * c2)) || (SolveSystem2(a.d.x, -b.d.x, b.p.x - a.p.x, a.d.z, -b.d.z, b.p.z - a.p.z, c1, c2) == true && Maths::isEqual(a.p.y + a.d.y * c1, b.p.y + b.d.y * c2)) || (SolveSystem2(a.d.y, -b.d.y, b.p.y - a.p.y, a.d.z, -b.d.z, b.p.z - a.p.z, c1, c2) == true && Maths::isEqual(a.p.x + a.d.x * c1, b.p.x + b.d.x * c2)))
685 		{
686 			point.set(a.p.x + a.d.x * c1, a.p.y + a.d.y * c1, a.p.z + a.d.z * c1);
687 			return true;
688 		}
689 
690 		return false;
691 	}
692 
693 	/**	Get the intersection point between a plane and a line.
694 			@param	plane the plane
695 			@param	line the line
696 			@param	intersection_point the resulting intersection
697 			@return bool, true if an intersection can be calculated, otherwise false
698 	*/
699 	template <typename T>
700 	BALL_INLINE
GetIntersection(const TPlane3<T> & plane,const TLine3<T> & line,TVector3<T> & intersection_point)701 	bool GetIntersection(const TPlane3<T>& plane, const TLine3<T>& line, TVector3<T>& intersection_point)
702 	{
703 		T dot_product = plane.n * line.d;
704 		if (Maths::isZero(dot_product))
705 		{
706 			return false;
707 		}
708 		intersection_point.set(line.p + (plane.n * (plane.p - line.p)) * line.d / dot_product);
709 		return true;
710 	}
711 
712 	/**	Get the intersection point between a line and a plane.
713 			@param	line the line
714 			@param	plane the plane
715 			@param	intersection_point the resulting intersection
716 			@return bool, true if an intersection can be calculated, otherwise false
717 	*/
718 	template <typename T>
719 	BALL_INLINE
GetIntersection(const TLine3<T> & line,const TPlane3<T> & plane,TVector3<T> & intersection_point)720 	bool GetIntersection(const TLine3<T>& line, const TPlane3<T>& plane, TVector3<T>& intersection_point)
721 	{
722 		return GetIntersection(plane, line, intersection_point);
723 	}
724 
725 	/**	Get the intersection line between two planes.
726 			@param	plane1 the first plane
727 			@param	plane2 the second plane
728 			@param	line the resulting intersection
729 			@return bool, true if an intersection can be calculated, otherwise false
730 	*/
731 	template <typename T>
GetIntersection(const TPlane3<T> & plane1,const TPlane3<T> & plane2,TLine3<T> & line)732 	bool GetIntersection(const TPlane3<T>& plane1, const TPlane3<T>& plane2, TLine3<T>& line)
733 	{
734 		T u = plane1.p*plane1.n;
735 		T v = plane2.p*plane2.n;
736 		T det = plane1.n.x*plane2.n.y-plane1.n.y*plane2.n.x;
737 		if (Maths::isZero(det))
738 		{
739 			det = plane1.n.x*plane2.n.z-plane1.n.z*plane2.n.x;
740 			if (Maths::isZero(det))
741 			{
742 				det = plane1.n.y*plane2.n.z-plane1.n.z*plane2.n.y;
743 				if (Maths::isZero(det))
744 				{
745 					return false;
746 				}
747 				else
748 				{
749 					T a = plane2.n.z/det;
750 					T b = -plane1.n.z/det;
751 					T c = -plane2.n.y/det;
752 					T d = plane1.n.y/det;
753 					line.p.x = 0;
754 					line.p.y = a*u+b*v;
755 					line.p.z = c*u+d*v;
756 					line.d.x = -1;
757 					line.d.y = a*plane1.n.x+b*plane2.n.x;
758 					line.d.z = c*plane1.n.x+d*plane2.n.x;
759 				}
760 			}
761 			else
762 			{
763 				T a = plane2.n.z/det;
764 				T b = -plane1.n.z/det;
765 				T c = -plane2.n.x/det;
766 				T d = plane1.n.x/det;
767 				line.p.x = a*u+b*v;
768 				line.p.y = 0;
769 				line.p.z = c*u+d*v;
770 				line.d.x = a*plane1.n.y+b*plane2.n.y;
771 				line.d.y = -1;
772 				line.d.z = c*plane1.n.y+d*plane2.n.y;
773 			}
774 		}
775 		else
776 		{
777 			T a = plane2.n.y/det;
778 			T b = -plane1.n.y/det;
779 			T c = -plane2.n.x/det;
780 			T d = plane1.n.x/det;
781 			line.p.x = a*u+b*v;
782 			line.p.y = c*u+d*v;
783 			line.p.z = 0;
784 			line.d.x = a*plane1.n.z+b*plane2.n.z;
785 			line.d.y = c*plane1.n.z+d*plane2.n.z;
786 			line.d.z = -1;
787 		}
788 		return true;
789 	}
790 
791 	/**	Get the intersection point between a sphere and a line.
792 			@param	sphere the sphere
793 			@param	line the line
794 			@param	intersection_point1 the first intersection point
795 			@param	intersection_point2 the second intersection point
796 			@return bool, true if an intersection can be calculated, otherwise false
797 	*/
798 	template <typename T>
GetIntersection(const TSphere3<T> & sphere,const TLine3<T> & line,TVector3<T> & intersection_point1,TVector3<T> & intersection_point2)799 	bool GetIntersection(const TSphere3<T>& sphere, const TLine3<T>& line, TVector3<T>& intersection_point1, TVector3<T>& intersection_point2)
800 	{
801 		T x1, x2;
802 		short number_of_solutions = SolveQuadraticEquation (line.d * line.d, (line.p - sphere.p) * line.d * 2, (line.p - sphere.p) * (line.p - sphere.p) - sphere.radius * sphere.radius, x1, x2);
803 
804 		if (number_of_solutions == 0)
805 		{
806 			return false;
807 		}
808 
809 		intersection_point1 = line.p + x1 * line.d;
810 		intersection_point2 = line.p + x2 * line.d;
811 
812 		return true;
813 	}
814 
815 	/**	Get the intersection point between a line and a sphere.
816 			@param	line the line
817 			@param	sphere the sphere
818 			@param	intersection_point1 the first intersection point
819 			@param	intersection_point2 the second intersection point
820 			@return bool, true if an intersection can be calculated, otherwise false
821 	*/
822 	template <typename T>
823 	BALL_INLINE
GetIntersection(const TLine3<T> & line,const TSphere3<T> & sphere,TVector3<T> & intersection_point1,TVector3<T> & intersection_point2)824 	bool GetIntersection(const TLine3<T>& line, const TSphere3<T>& sphere, TVector3<T>& intersection_point1, TVector3<T>& intersection_point2)
825 	{
826 		return GetIntersection(sphere, line, intersection_point1, intersection_point2);
827 	}
828 
829 	/**	Get the intersection circle between a sphere and a plane.
830 			@param	sphere the sphere
831 			@param	plane the plane
832 			@param	intersection_circle the intersection circle
833 			@return bool, true if an intersection can be calculated, otherwise false
834 	*/
835 	template <typename T>
GetIntersection(const TSphere3<T> & sphere,const TPlane3<T> & plane,TCircle3<T> & intersection_circle)836 	bool GetIntersection(const TSphere3<T>& sphere, const TPlane3<T>& plane, TCircle3<T>& intersection_circle)
837 	{
838 		T distance = GetDistance(sphere.p, plane);
839 
840 		if (Maths::isGreater(distance, sphere.radius))
841 		{
842 			return false;
843 		}
844 
845 		TVector3<T> Vector3(plane.n);
846 		Vector3.normalize();
847 
848 		if (Maths::isEqual(distance, sphere.radius))
849 		{
850 			intersection_circle.set(sphere.p + sphere.radius * Vector3, plane.n, 0);
851 		}
852 		else
853 		{
854 			intersection_circle.set
855 				(sphere.p + distance * Vector3, plane.n,
856 				 sqrt(sphere.radius * sphere.radius - distance * distance));
857 		}
858 
859 		return true;
860 	}
861 
862 	/**	Get the intersection circle between a plane and a sphere.
863 			@param	plane the plane
864 			@param	sphere the sphere
865 			@param	intersection_circle the intersection circle
866 			@return bool, true if an intersection can be calculated, otherwise false
867 	*/
868 	template <typename T>
869 	BALL_INLINE bool
GetIntersection(const TPlane3<T> & plane,const TSphere3<T> & sphere,TCircle3<T> & intersection_circle)870 	GetIntersection(const TPlane3<T>& plane, const TSphere3<T>& sphere, TCircle3<T>& intersection_circle)
871 	{
872 		return GetIntersection(sphere, plane, intersection_circle);
873 	}
874 
875 	/**	Get the intersection circle between two spheres.
876 			This methods returns <b>false</b>, if the two spheres
877 			are identical, since then no intersection circle exists.
878 			@param	a the first sphere
879 			@param	b the second sphere
880 			@param	intersection_circle the intersection circle
881 			@return bool, <b>true</b> if an intersection can be calculated, otherwise <b>false</b>
882 	*/
883 	template <typename T>
GetIntersection(const TSphere3<T> & a,const TSphere3<T> & b,TCircle3<T> & intersection_circle)884 	bool GetIntersection(const TSphere3<T>& a, const TSphere3<T>& b, TCircle3<T>& intersection_circle)
885 	{
886 		TVector3<T> norm = b.p - a.p;
887 		T square_dist = norm * norm;
888 		if (Maths::isZero(square_dist))
889 		{
890 			return false;
891 		}
892 		T dist = sqrt(square_dist);
893 		if (Maths::isLess(a.radius + b.radius, dist))
894 		{
895 			return false;
896 		}
897 		if (Maths::isGreaterOrEqual(Maths::abs(a.radius - b.radius), dist))
898 		{
899 			return false;
900 		}
901 
902 		T radius1_square = a.radius * a.radius;
903 		T radius2_square = b.radius * b.radius;
904 		T u = radius1_square - radius2_square + square_dist;
905 		T length = u / (2 * square_dist);
906 		T square_radius = radius1_square - u * length / 2;
907 		if (square_radius < 0)
908 		{
909 			return false;
910 		}
911 
912 		intersection_circle.p = a.p + (norm * length);
913 		intersection_circle.radius = sqrt(square_radius);
914 		intersection_circle.n = norm / dist;
915 
916 		return true;
917 	}
918 
919 	/**	Get the intersection points between three spheres.
920 			@param	s1 the first sphere
921 			@param	s2 the second sphere
922 			@param	s3 the third sphere
923 			@param	p1 the first intersection point
924 			@param	p2 the second intersection point
925 			@param	test
926 			@return bool, <b>true</b> if an intersection can be calculated, otherwise <b>false</b>
927 	*/
928 	template <class T>
929 	bool GetIntersection(const TSphere3<T>& s1, const TSphere3<T>& s2, const TSphere3<T>& s3, TVector3<T>& p1, TVector3<T>& p2, bool test = true)
930 	{
931 		T r1_square = s1.radius*s1.radius;
932 		T r2_square = s2.radius*s2.radius;
933 		T r3_square = s3.radius*s3.radius;
934 		T p1_square_length = s1.p*s1.p;
935 		T p2_square_length = s2.p*s2.p;
936 		T p3_square_length = s3.p*s3.p;
937 		T u = (r2_square-r1_square-p2_square_length+p1_square_length)/2;
938 		T v = (r3_square-r1_square-p3_square_length+p1_square_length)/2;
939 		TPlane3<T> plane1;
940 		TPlane3<T> plane2;
941 		try
942 		{
943 			plane1 = TPlane3<T>(s2.p.x-s1.p.x,s2.p.y-s1.p.y,s2.p.z-s1.p.z,u);
944 			plane2 = TPlane3<T>(s3.p.x-s1.p.x,s3.p.y-s1.p.y,s3.p.z-s1.p.z,v);
945 		}
catch(Exception::DivisionByZero &)946 		catch (Exception::DivisionByZero&)
947 		{
948 			return false;
949 		}
950 		TLine3<T> line;
951 		if (GetIntersection(plane1,plane2,line))
952 		{
953 			TVector3<T> diff(s1.p-line.p);
954 			T x1, x2;
955 			if (SolveQuadraticEquation(line.d*line.d, -diff*line.d*2, diff*diff-r1_square, x1,x2) > 0)
956 			{
957 				p1 = line.p+x1*line.d;
958 				p2 = line.p+x2*line.d;
959 				if (test)
960 				{
961 					TVector3<T> test = s1.p-p1;
962 					if (Maths::isNotEqual(test*test,r1_square))
963 					{
964 						return false;
965 					}
966 					test = s1.p-p2;
967 					if (Maths::isNotEqual(test*test,r1_square))
968 					{
969 						return false;
970 					}
971 					test = s2.p-p1;
972 					if (Maths::isNotEqual(test*test,r2_square))
973 					{
974 						return false;
975 					}
976 					test = s2.p-p2;
977 					if (Maths::isNotEqual(test*test,r2_square))
978 					{
979 						return false;
980 					}
981 					test = s3.p-p1;
982 					if (Maths::isNotEqual(test*test,r3_square))
983 					{
984 						return false;
985 					}
986 					test = s3.p-p2;
987 					if (Maths::isNotEqual(test*test,r3_square))
988 					{
989 						return false;
990 					}
991 				}
992 				return true;
993 			}
994 		}
995 		return false;
996 	}
997 
998 
999 	/**	Test whether two vector3 are collinear
1000 			@param	a the first vector3
1001 			@param	b the second vector3
1002 			@return bool, true or false
1003 	*/
1004 	template <typename T>
1005 	BALL_INLINE
isCollinear(const TVector3<T> & a,const TVector3<T> & b)1006 	bool isCollinear(const TVector3<T>& a, const TVector3<T>& b)
1007 	{
1008 		return (a % b).isZero();
1009 	}
1010 
1011 	/**	Test whether three vector3 are complanar
1012 			@param	a the first vector3
1013 			@param	b the second vector3
1014 			@param	c the third vector3
1015 			@return bool, true or false
1016 	*/
1017 	template <typename T>
1018 	BALL_INLINE
isComplanar(const TVector3<T> & a,const TVector3<T> & b,const TVector3<T> & c)1019 	bool isComplanar(const TVector3<T>& a, const TVector3<T>& b, const TVector3<T>& c)
1020 	{
1021 		return Maths::isZero(TVector3<T>::getTripleProduct(a, b, c));
1022 	}
1023 
1024 	/**	Test whether four vector3 are complanar
1025 			@param	a the first vector3
1026 			@param	b the second vector3
1027 			@param	c the third vector3
1028 			@param	d the fourth vector3
1029 			@return bool, true or false
1030 	*/
1031 	template <typename T>
1032 	BALL_INLINE
isComplanar(const TVector3<T> & a,const TVector3<T> & b,const TVector3<T> & c,const TVector3<T> & d)1033 	bool isComplanar(const TVector3<T>& a, const TVector3<T>& b, const TVector3<T>& c, const TVector3<T>& d)
1034 	{
1035 		return isComplanar(a - b, a - c, a - d);
1036 	}
1037 
1038 	/**	Test whether two vector3 are orthogonal
1039 			@param	a the first vector3
1040 			@param	b the second vector3
1041 			@return bool, true or false
1042 	*/
1043 	template <typename T>
1044 	BALL_INLINE
isOrthogonal(const TVector3<T> & a,const TVector3<T> & b)1045 	bool isOrthogonal(const TVector3<T>& a, const TVector3<T>& b)
1046 	{
1047 		return Maths::isZero(a * b);
1048 	}
1049 
1050 	/**	Test whether a vector3 and a line are orthogonal
1051 			@param	vector the vector
1052 			@param	line the line
1053 			@return bool, true or false
1054 	*/
1055 	template <typename T>
1056 	BALL_INLINE
isOrthogonal(const TVector3<T> & vector,const TLine3<T> & line)1057 	bool isOrthogonal(const TVector3<T>& vector, const TLine3<T>& line)
1058 	{
1059 		return Maths::isZero(vector * line.d);
1060 	}
1061 
1062 	/**	Test whether a line and a vector3 are orthogonal
1063 			@param	line the line
1064 			@param	vector the vector
1065 			@return bool, true or false
1066 	*/
1067 	template <typename T>
1068 	BALL_INLINE
isOrthogonal(const TLine3<T> & line,const TVector3<T> & vector)1069 	bool isOrthogonal(const TLine3<T>& line, const TVector3<T>& vector)
1070 	{
1071 		return isOrthogonal(vector, line);
1072 	}
1073 
1074 	/**	Test whether two lines are orthogonal.
1075 			@param	a the first line
1076 			@param	b the second line
1077 			@return bool, true or false
1078 	*/
1079 	template <typename T>
1080 	BALL_INLINE
isOrthogonal(const TLine3<T> & a,const TLine3<T> & b)1081 	bool isOrthogonal(const TLine3<T>& a, const TLine3<T>& b)
1082 	{
1083 		return Maths::isZero(a.d * b.d);
1084 	}
1085 
1086 	/**	Test whether a vector3 and a plane are orthogonal.
1087 			@param	vector the vector3
1088 			@param	plane the plane
1089 			@return bool, true or false
1090 	*/
1091 	template <typename T>
1092 	BALL_INLINE
isOrthogonal(const TVector3<T> & vector,const TPlane3<T> & plane)1093 	bool isOrthogonal(const TVector3<T>& vector, const TPlane3<T>& plane)
1094 	{
1095 		return isCollinear(vector, plane.n);
1096 	}
1097 
1098 	/**	Test whether a plane and a vector3 are orthogonal.
1099 			@param	plane the plane
1100 			@param	vector the vector3
1101 			@return bool, true or false
1102 	*/
1103 	template <typename T>
1104 	BALL_INLINE
isOrthogonal(const TPlane3<T> & plane,const TVector3<T> & vector)1105 	bool isOrthogonal(const TPlane3<T>& plane, const TVector3<T>& vector)
1106 	{
1107 		return isOrthogonal(vector, plane);
1108 	}
1109 
1110 	/**	Test whether two planes are orthogonal.
1111 			@param	a the first plane
1112 			@param	b the second plane
1113 			@return bool, true or false
1114 	*/
1115 	template <typename T>
1116 	BALL_INLINE
isOrthogonal(const TPlane3<T> & a,const TPlane3<T> & b)1117 	bool isOrthogonal(const TPlane3<T>& a, const TPlane3<T>& b)
1118 	{
1119 		return Maths::isZero(a.n * b.n);
1120 	}
1121 
1122 	/**	Test whether a line is intersecting a point.
1123 			@param	point the point
1124 			@param	line the line
1125 			@return bool, true or false
1126 	*/
1127 	template <typename T>
1128 	BALL_INLINE
isIntersecting(const TVector3<T> & point,const TLine3<T> & line)1129 	bool isIntersecting(const TVector3<T>& point, const TLine3<T>& line)
1130 	{
1131 		return Maths::isZero(GetDistance(point, line));
1132 	}
1133 
1134 	/**	Test whether a line is intersecting a point.
1135 			@param	line the line
1136 			@param	point the point
1137 			@return bool, true or false
1138 	*/
1139 	template <typename T>
1140 	BALL_INLINE
isIntersecting(const TLine3<T> & line,const TVector3<T> & point)1141 	bool isIntersecting(const TLine3<T>& line, const TVector3<T>& point)
1142 	{
1143 		return isIntersecting(point, line);
1144 	}
1145 
1146 	/**	Test whether two lines are intersecting.
1147 			@param	a the first line
1148 			@param	b the second line
1149 			@return bool, true or false
1150 	*/
1151 	template <typename T>
1152 	BALL_INLINE
isIntersecting(const TLine3<T> & a,const TLine3<T> & b)1153 	bool isIntersecting(const TLine3<T>& a, const TLine3<T>& b)
1154 	{
1155 		return Maths::isZero(GetDistance(a, b));
1156 	}
1157 
1158 	/**	Test whether a point lies in a plane.
1159 			@param	point the point
1160 			@param	plane the plane
1161 			@return bool, true or false
1162 	*/
1163 	template <typename T>
1164 	BALL_INLINE
isIntersecting(const TVector3<T> & point,const TPlane3<T> & plane)1165 	bool isIntersecting(const TVector3<T>& point, const TPlane3<T>& plane)
1166 	{
1167 		return Maths::isZero(GetDistance(point, plane));
1168 	}
1169 
1170 	/**	Test whether a point lies in a plane.
1171 			@param	plane the plane
1172 			@param	point the point
1173 			@return bool, true or false
1174 	*/
1175 	template <typename T>
1176 	BALL_INLINE
isIntersecting(const TPlane3<T> & plane,const TVector3<T> & point)1177 	bool isIntersecting(const TPlane3<T>& plane, const TVector3<T>& point)
1178 	{
1179 		return isIntersecting(point, plane);
1180 	}
1181 
1182 	/**	Test whether a line is intersecting a plane.
1183 			@param	line the line
1184 			@param	plane the plane
1185 			@return bool, true or false
1186 	*/
1187 	template <typename T>
1188 	BALL_INLINE
isIntersecting(const TLine3<T> & line,const TPlane3<T> & plane)1189 	bool isIntersecting(const TLine3<T>& line, const TPlane3<T>& plane)
1190 	{
1191 		return Maths::isZero(GetDistance(line, plane));
1192 	}
1193 
1194 	/**	Test whether a plane is intersecting a line.
1195 			@param	plane the plane
1196 			@param	line the line
1197 			@return bool, true or false
1198 	*/
1199 	template <typename T>
1200 	BALL_INLINE
isIntersecting(const TPlane3<T> & plane,const TLine3<T> & line)1201 	bool isIntersecting(const TPlane3<T>& plane, const TLine3<T>& line)
1202 	{
1203 		return isIntersecting(line, plane);
1204 	}
1205 
1206 	/**	Test whether two planes are intersecting.
1207 			@param	a the first plane
1208 			@param	b the second plane
1209 			@return bool, true or false
1210 	*/
1211 	template <typename T>
1212 	BALL_INLINE
isIntersecting(const TPlane3<T> & a,const TPlane3<T> & b)1213 	bool isIntersecting(const TPlane3<T>& a, const TPlane3<T>& b)
1214 	{
1215 		return Maths::isZero(GetDistance(a, b));
1216 	}
1217 
1218 	/**	Test whether a line and a plane are parallel.
1219 			@param	line the line
1220 			@param	plane the plane
1221 			@return bool, true or false
1222 	*/
1223 	template <typename T>
1224 	BALL_INLINE
isParallel(const TLine3<T> & line,const TPlane3<T> & plane)1225 	bool isParallel(const TLine3<T>& line, const TPlane3<T>& plane)
1226 	{
1227 		return isOrthogonal(line.d, plane.n);
1228 	}
1229 
1230 	/**	Test whether a plane and a line are parallel.
1231 			@param	plane the plane
1232 			@param	line the line
1233 			@return bool, true or false
1234 	*/
1235 	template <typename T>
1236 	BALL_INLINE
isParallel(const TPlane3<T> & plane,const TLine3<T> & line)1237 	bool isParallel(const TPlane3<T>& plane, const TLine3<T>& line)
1238 	{
1239 		return isParallel(line, plane);
1240 	}
1241 
1242 	/**	Test whether two planes are parallel.
1243 			@param	a the first plane
1244 			@param	b the second plane
1245 			@return bool, true or false
1246 	*/
1247 	template <typename T>
1248 	BALL_INLINE
isParallel(const TPlane3<T> & a,const TPlane3<T> & b)1249 	bool isParallel(const TPlane3<T>& a, const TPlane3<T>& b)
1250 	{
1251 		return isCollinear(a.n, b.n);
1252 	}
1253 
1254 	/**	Return the oriented angle of two vectors with a normal vector.
1255 	 *  @throw Exception::DivisionByZero if at least one vector is zero
1256 	*/
1257 	template <typename T>
getOrientedAngle(const T & ax,const T & ay,const T & az,const T & bx,const T & by,const T & bz,const T & nx,const T & ny,const T & nz)1258 	TAngle<T> getOrientedAngle
1259 		(const T& ax, const T& ay, const T& az,
1260 		 const T& bx, const T& by, const T& bz,
1261 		 const T& nx, const T& ny, const T& nz)
1262 	{
1263     // Calculate the length of the two normals
1264     T bl = (T) sqrt((double)ax * ax + ay * ay + az * az);
1265     T el = (T) sqrt((double)bx * bx + by * by + bz * bz);
1266     T bel = (T) (ax * bx + ay * by + az * bz);
1267 
1268     // if one or both planes are degenerated
1269     if (bl * el == 0)
1270     {
1271       throw Exception::DivisionByZero(__FILE__, __LINE__);
1272 		}
1273     bel /= (bl * el);
1274     if (bel > 1.0)
1275     {
1276       bel = 1;
1277 		}
1278     else if (bel < -1.0)
1279     {
1280       bel = -1;
1281 		}
1282 
1283     T acosbel = (T) acos(bel);	// >= 0
1284 
1285     if (( nx * (az * by - ay * bz)
1286 				 + ny * (ax * bz - az * bx)
1287 				 + nz * (ay * bx - ax * by)) > 0)
1288     {
1289     	acosbel = Constants::PI+Constants::PI-acosbel;
1290 		}
1291 
1292 		return TAngle<T>(acosbel);
1293 	}
1294 
1295 	/**	Return the oriented angle of two vectors with a normal vector.
1296 	 *  @throw Exception::DivisionByZero if at least one vector is zero
1297 	*/
1298   template <typename T>
1299 	BALL_INLINE
getOrientedAngle(const TVector3<T> & a,const TVector3<T> & b,const TVector3<T> & normal)1300   TAngle<T>getOrientedAngle(const TVector3<T>& a, const TVector3<T>& b, const TVector3<T>& normal)
1301   {
1302     return getOrientedAngle(a.x, a.y, a.z, b.x, b.y, b.z, normal.x, normal.y, normal.z);
1303 	}
1304 
1305 	/**	Return the torsion angle of four points to each other.
1306 			@param  ax 1. vector x component
1307 			@param  ay 1. vector y component
1308 			@param  az 1. vector z component
1309 			@param  bx 2. vector x component
1310 			@param  by 2. vector y component
1311 			@param  bz 2. vector z component
1312 			@param  cx 3. vector x component
1313 			@param  cy 3. vector y component
1314 			@param  cz 3. vector z component
1315 			@param  dx 4. vector x component
1316 			@param  dy 4. vector y component
1317 			@param  dz 4. vector z component
1318 			@return TAngle the torsion angle
1319 			@throw  Exception::DivisionByZero if one of the outer vectors is collinear with the middle one
1320 	*/
1321 	template <typename T>
getTorsionAngle(const T & ax,const T & ay,const T & az,const T & bx,const T & by,const T & bz,const T & cx,const T & cy,const T & cz,const T & dx,const T & dy,const T & dz)1322 	TAngle<T> getTorsionAngle
1323 		(const T& ax, const T& ay, const T& az,
1324 		 const T& bx, const T& by, const T& bz,
1325 		 const T& cx, const T& cy, const T& cz,
1326 		 const T& dx, const T& dy, const T& dz)
1327 	{
1328 		T abx = ax - bx;
1329 		T aby = ay - by;
1330 		T abz = az - bz;
1331 
1332 		T cbx = cx - bx;
1333 		T cby = cy - by;
1334 		T cbz = cz - bz;
1335 
1336 		T cdx = cx - dx;
1337 		T cdy = cy - dy;
1338 		T cdz = cz - dz;
1339 
1340 		// Calculate the normals to the two planes n1 and n2
1341 		// this is given as the cross products:
1342 		//		 AB x BC
1343 		//		--------- = n1
1344 		//		|AB x BC|
1345 		//
1346 		//		 BC x CD
1347 		// 	  --------- = n2
1348 		// 	  |BC x CD|
1349 
1350 		// Normal to plane 1
1351 		T ndax = aby * cbz - abz * cby;
1352 		T nday = abz * cbx - abx * cbz;
1353 		T ndaz = abx * cby - aby * cbx;
1354 
1355 		// Normal to plane 2
1356 		T neax = cbz * cdy - cby * cdz;
1357 		T neay = cbx * cdz - cbz * cdx;
1358 		T neaz = cby * cdx - cbx * cdy;
1359 
1360 		// Calculate the length of the two normals
1361 		T bl = (T) sqrt((double)ndax * ndax + nday * nday + ndaz * ndaz);
1362 		T el = (T) sqrt((double)neax * neax + neay * neay + neaz * neaz);
1363 		T bel = (T) (ndax * neax + nday * neay + ndaz * neaz);
1364 
1365 		// if one or both planes are degenerated
1366 		if (bl * el == 0)
1367 		{
1368 			throw Exception::DivisionByZero(__FILE__, __LINE__);
1369 		}
1370 		bel /= (bl * el);
1371 		if (bel > 1.0)
1372 		{
1373 			bel = 1;
1374 		}
1375 		else if (bel < -1.0)
1376 		{
1377 			bel = -1;
1378 		}
1379 
1380 		T acosbel = (T) acos(bel);
1381 
1382 		if ((cbx * (ndaz * neay - nday * neaz)
1383 				 + cby * (ndax * neaz - ndaz * neax)
1384 				 + cbz * (nday * neax - ndax * neay))
1385 				< 0)
1386 		{
1387 			acosbel = -acosbel;
1388 		}
1389 
1390 		acosbel = (acosbel > 0.0)
1391 			? Constants::PI - acosbel
1392 			: -(Constants::PI + acosbel);
1393 
1394 		return TAngle<T>(acosbel);
1395 	}
1396 	//@}
1397 } // namespace BALL
1398 
1399 
1400 #endif // BALL_MATHS_ANALYTICALGEOMETRY_H
1401