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