analyticalGeometry.h

Go to the documentation of this file.
00001 // -*- Mode: C++; tab-width: 2; -*-
00002 // vi: set ts=2:
00003 //
00004 // $Id: analyticalGeometry.h,v 1.63 2004/02/23 17:26:02 anhi Exp $
00005 //
00006 
00007 #ifndef BALL_MATHS_ANALYTICALGEOMETRY_H
00008 #define BALL_MATHS_ANALYTICALGEOMETRY_H
00009 
00010 #ifndef BALL_COMMON_EXCEPTION_H
00011 # include <BALL/COMMON/exception.h>
00012 #endif
00013 
00014 #ifndef BALL_MATHS_ANGLE_H
00015 # include <BALL/MATHS/angle.h>
00016 #endif
00017 
00018 #ifndef BALL_MATHS_CIRCLE3_H
00019 # include <BALL/MATHS/circle3.h>
00020 #endif
00021 
00022 #ifndef BALL_MATHS_LINE3_H
00023 # include <BALL/MATHS/line3.h>
00024 #endif
00025 
00026 #ifndef BALL_MATHS_PLANE3_H
00027 # include <BALL/MATHS/plane3.h>
00028 #endif
00029 
00030 #ifndef BALL_MATHS_SPHERE3_H
00031 # include <BALL/MATHS/sphere3.h>
00032 #endif
00033 
00034 #ifndef BALL_MATHS_VECTOR3_H
00035 # include <BALL/MATHS/vector3.h>
00036 #endif
00037 
00038 #define BALL_MATRIX_CELL(m, dim, row, col)   *((m) + (row) * (dim) + (col))
00039 #define BALL_CELL(x, y)                      *((m) + (y) * (dim) + (x))
00040 
00041 namespace BALL 
00042 {
00043 
00050 
00057   template <typename T>
00058   BALL_INLINE
00059   T getDeterminant_(const T* m, Size dim)
00060   {
00061     T determinant = 0;
00062     Index dim1 = dim - 1;
00063 
00064     if (dim > 1)
00065     {
00066       T* submatrix = new T[dim1 * dim1];
00067 
00068       for (Index i = 0; i < (Index)dim; ++i) 
00069       {
00070         for (Index j = 0; j < dim1; ++j) 
00071         {
00072           for (Index k = 0; k < dim1; ++k) 
00073           {
00074             *(submatrix + j * dim1 + k) = *(m + (j + 1) * dim + (k < i ? k : k + 1));
00075           }
00076         }
00077         determinant += *(m + i) * (i / 2.0 == i / 2 ? 1 : -1) * getDeterminant_(submatrix, dim1);
00078       }
00079 
00080       delete [] submatrix;
00081     } 
00082     else 
00083     {
00084       determinant = *m;
00085     }
00086 
00087     return determinant;
00088   }
00089 
00094   template <typename T>
00095   T getDeterminant(const T* m, Size dim)
00096   {
00097     if (dim == 2)
00098     {
00099       return (BALL_CELL(0,0) * BALL_CELL(1,1) - BALL_CELL(0,1) * BALL_CELL(1,0));
00100     } 
00101     else if (dim == 3)
00102     {
00103       return (  BALL_CELL(0,0) * BALL_CELL(1,1) * BALL_CELL(2,2) 
00104               + BALL_CELL(0,1) * BALL_CELL(1,2) * BALL_CELL(2,0) 
00105               + BALL_CELL(0,2) * BALL_CELL(1,0) * BALL_CELL(2,1) 
00106               - BALL_CELL(0,2) * BALL_CELL(1,1) * BALL_CELL(2,0) 
00107               - BALL_CELL(0,0) * BALL_CELL(1,2) * BALL_CELL(2,1) 
00108               - BALL_CELL(0,1) * BALL_CELL(1,0) * BALL_CELL(2,2)); 
00109     } 
00110     else 
00111     {
00112       return getDeterminant_(m, dim);
00113     }
00114   }
00115 
00119   template <typename T>
00120   BALL_INLINE 
00121   T getDeterminant2(const T* m)
00122   {
00123     Size dim = 2;
00124     return (BALL_CELL(0,0) * BALL_CELL(1,1) - BALL_CELL(0,1) * BALL_CELL(1,0));
00125   }
00126 
00133   template <typename T>
00134   BALL_INLINE 
00135   T getDeterminant2(const T& m00, const T& m01, const T& m10, const T& m11)
00136   {
00137     return (m00 * m11 - m01 * m10);
00138   }
00139 
00143   template <typename T>
00144   BALL_INLINE 
00145   T getDeterminant3(const T *m)
00146   {
00147     Size dim = 3;
00148     return (  BALL_CELL(0,0) * BALL_CELL(1,1) * BALL_CELL(2,2) 
00149             + BALL_CELL(0,1) * BALL_CELL(1,2) * BALL_CELL(2,0) 
00150             + BALL_CELL(0,2) * BALL_CELL(1,0) * BALL_CELL(2,1) 
00151             - BALL_CELL(0,2) * BALL_CELL(1,1) * BALL_CELL(2,0) 
00152             - BALL_CELL(0,0) * BALL_CELL(1,2) * BALL_CELL(2,1) 
00153             - BALL_CELL(0,1) * BALL_CELL(1,0) * BALL_CELL(2,2)); 
00154   }
00155 
00159   template <typename T>
00160   BALL_INLINE T 
00161   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)
00162   {
00163     return (  m00 * m11 * m22 + m01 * m12 * m20 + m02 * m10 * m21 - m02 * m11 * m20 - m00 * m12 * m21 - m01 * m10 * m22); 
00164   }
00165 
00192   template <typename T>
00193   bool SolveSystem(const T* m, T* x, const Size dim)
00194   {
00195     T pivot;
00196     Index i, j, k, p;
00197     // the column dimension of the matrix
00198     const Size col_dim = dim + 1;
00199     T* matrix = new T[dim * (dim + 1)];
00200     const T* source = m;
00201     T* target = (T*)matrix;
00202     T* end = (T*)&BALL_MATRIX_CELL(matrix, col_dim, dim - 1, dim);
00203 
00204     while (target <= end)
00205     {
00206       *target++ = *source++;
00207     }
00208 
00209     for (i = 0; i < (Index)dim; ++i)
00210     {
00211       pivot = BALL_MATRIX_CELL(matrix, col_dim, i, i);
00212       p = i;
00213       for (j = i + 1; j < (Index)dim; ++j)
00214       {
00215         if (Maths::isLess(pivot, BALL_MATRIX_CELL(matrix, col_dim, j, i)))
00216         {
00217           pivot = BALL_MATRIX_CELL(matrix, col_dim, j, i);
00218           p = j;
00219         }
00220       }
00221 
00222       if (p != i)
00223       {
00224         T tmp;
00225 
00226         for (k = i; k < (Index)dim + 1; ++k)
00227         {
00228           tmp = BALL_MATRIX_CELL(matrix, dim, i, k);
00229           BALL_MATRIX_CELL(matrix, col_dim, i, k) = BALL_MATRIX_CELL(matrix, col_dim, p, k);
00230           BALL_MATRIX_CELL(matrix, col_dim, p, k) = tmp;
00231         }
00232       }
00233       else if (Maths::isZero(pivot) || Maths::isNan(pivot))
00234       { 
00235         // invariant: matrix m is singular
00236         delete [] matrix;
00237         
00238         return false;
00239       }
00240 
00241       for (j = dim; j >= i; --j) 
00242       {
00243         BALL_MATRIX_CELL(matrix, col_dim, i, j) /= pivot;
00244       }
00245 
00246       for (j = i + 1; j < (Index)dim; ++j)
00247       {
00248         pivot = BALL_MATRIX_CELL(matrix, col_dim, j, i);
00249 
00250         for (k = dim; k>= i; --k) 
00251         {
00252           BALL_MATRIX_CELL(matrix, col_dim, j, k) -= pivot * BALL_MATRIX_CELL(matrix, col_dim, i, k);
00253         }
00254       }
00255     }
00256 
00257     x[dim - 1] = BALL_MATRIX_CELL(matrix, col_dim, dim - 1, dim);
00258 
00259     for (i = dim - 2; i >= 0; --i)
00260     {
00261       x[i] = BALL_MATRIX_CELL(matrix, col_dim, i, dim);
00262 
00263       for (j = i + 1; j < (Index)dim; ++j) 
00264       {
00265         x[i] -= BALL_MATRIX_CELL(matrix, col_dim, i, j) * x[j]; 
00266       }
00267     }
00268 
00269     delete [] matrix;
00270     
00271     return true;
00272   }
00273 
00274 #undef BALL_CELL
00275 #undef BALL_MATRIX_CELL
00276 
00285   template <typename T>
00286   BALL_INLINE 
00287   bool SolveSystem2(const T& a1, const T& b1, const T& c1, const T& a2, const T& b2, const T& c2, T& x1, T& x2)
00288   {
00289     T quot = (a1 * b2 - a2 * b1);
00290 
00291     if (Maths::isZero(quot))
00292     {
00293       return false;
00294     }
00295 
00296     x1 = (c1 * b2 - c2 * b1) / quot;
00297     x2 = (a1 * c2 - a2 * c1) / quot;
00298 
00299     return true;
00300   }
00301 
00311   template <typename T>
00312   short SolveQuadraticEquation(const T& a, const T& b, const T &c, T &x1, T &x2)
00313   {
00314     if (a == 0)
00315     {
00316       if (b == 0)
00317       {
00318         return 0;
00319       }
00320       x1 = x2 = c / b;
00321       return 1;
00322     }
00323     T discriminant = b * b - 4 * a * c;
00324 
00325     if (Maths::isLess(discriminant, 0))
00326     {
00327       return 0;
00328     }
00329 
00330     T sqrt_discriminant = sqrt(discriminant);
00331     if (Maths::isZero(sqrt_discriminant))
00332     {
00333       x1 = x2 = -b / (2 * a);
00334 
00335       return 1;
00336     } 
00337     else 
00338     {
00339       x1 = (-b + sqrt_discriminant) / (2 * a);
00340       x2 = (-b - sqrt_discriminant) / (2 * a);
00341 
00342       return 2;
00343     }
00344   }
00345 
00351   template <typename T>
00352   BALL_INLINE 
00353   TVector3<T> GetPartition(const TVector3<T>& a, const TVector3<T>& b)
00354   {
00355     return TVector3<T>((b.x + a.x) / 2, (b.y + a.y) / 2, (b.z + a.z) / 2);
00356   }
00357 
00366   template <typename T>
00367   BALL_INLINE 
00368   TVector3<T> GetPartition(const TVector3<T>& a, const TVector3<T>& b, const T& r, const T& s)
00369     throw(Exception::DivisionByZero)
00370   {
00371     T sum = r + s;
00372     if (sum == (T)0)
00373     {
00374       throw Exception::DivisionByZero(__FILE__, __LINE__);
00375     }   
00376     return TVector3<T>
00377       ((s * a.x + r * b.x) / sum,
00378        (s * a.y + r * b.y) / sum,
00379        (s * a.z + r * b.z) / sum);
00380   }
00381 
00387   template <typename T>
00388   BALL_INLINE 
00389   T GetDistance(const TVector3<T>& a, const TVector3<T>& b)
00390   {
00391     T dx = a.x - b.x;
00392     T dy = a.y - b.y;
00393     T dz = a.z - b.z;
00394     
00395     return sqrt(dx * dx + dy * dy + dz * dz); 
00396   }
00397 
00403   template <typename T>
00404   BALL_INLINE 
00405   T GetDistance(const TLine3<T>& line, const TVector3<T>& point)
00406     throw(Exception::DivisionByZero)
00407   {
00408     if (line.d.getLength() == (T)0)
00409     {
00410       throw Exception::DivisionByZero(__FILE__, __LINE__);
00411     }   
00412     return ((line.d % (point - line.p)).getLength() / line.d.getLength());
00413   }
00414 
00420   template <typename T>
00421   BALL_INLINE 
00422   T GetDistance(const TVector3<T>& point, const TLine3<T>& line)
00423     throw(Exception::DivisionByZero)
00424   {
00425     return GetDistance(line, point);
00426   }
00427 
00433   template <typename T>
00434   T GetDistance(const TLine3<T>& a, const TLine3<T>& b)
00435     throw(Exception::DivisionByZero)
00436   {
00437     T cross_product_length = (a.d % b.d).getLength();
00438     
00439     if (Maths::isZero(cross_product_length))
00440     { // invariant: parallel lines
00441       if (a.d.getLength() == (T)0)
00442       {
00443         throw Exception::DivisionByZero(__FILE__, __LINE__);
00444       }         
00445       return ((a.d % (b.p - a.p)).getLength() / a.d.getLength());
00446     } 
00447     else 
00448     {
00449       T spat_product = TVector3<T>::getTripleProduct(a.d, b.d, b.p - a.p);
00450 
00451       if (Maths::isNotZero(spat_product))
00452       { // invariant: windschiefe lines
00453         
00454         return (Maths::abs(spat_product) / cross_product_length);
00455       } 
00456       else 
00457       { 
00458         // invariant: intersecting lines
00459         return 0;
00460       }
00461     }
00462   }
00463 
00469   template <typename T>
00470   BALL_INLINE 
00471   T GetDistance(const TVector3<T>& point, const TPlane3<T>& plane)
00472     throw(Exception::DivisionByZero)
00473   {
00474     T length = plane.n.getLength();
00475 
00476     if (length == (T)0)
00477     {
00478       throw Exception::DivisionByZero(__FILE__, __LINE__);
00479     }
00480     return (Maths::abs(plane.n * (point - plane.p)) / length);
00481   }
00482 
00488   template <typename T>
00489   BALL_INLINE 
00490   T GetDistance(const TPlane3<T>& plane, const TVector3<T>& point)
00491     throw(Exception::DivisionByZero)
00492   {
00493     return GetDistance(point, plane);
00494   }
00495 
00501   template <typename T>
00502   BALL_INLINE 
00503   T GetDistance(const TLine3<T>& line, const TPlane3<T>& plane)
00504     throw(Exception::DivisionByZero)
00505   {
00506     T length = plane.n.getLength();
00507     if (length == (T)0)
00508     {
00509       throw Exception::DivisionByZero(__FILE__, __LINE__);
00510     }
00511     return (Maths::abs(plane.n * (line.p - plane.p)) / length);
00512   }
00513 
00519   template <typename T>
00520   BALL_INLINE 
00521   T GetDistance(const TPlane3<T>& plane, const TLine3<T>& line)
00522     throw(Exception::DivisionByZero)
00523   {
00524     return GetDistance(line, plane);
00525   }
00526 
00532   template <typename T>
00533   BALL_INLINE 
00534   T GetDistance(const TPlane3<T>& a, const TPlane3<T>& b)
00535     throw(Exception::DivisionByZero)
00536   {
00537     T length = a.n.getLength();
00538     if (length == (T)0)
00539     {
00540       throw Exception::DivisionByZero(__FILE__, __LINE__);
00541     }   
00542     return (Maths::abs(a.n * (a.p - b.p)) / length);
00543   }
00544 
00551   template <typename T>
00552   BALL_INLINE 
00553   bool GetAngle(const TVector3<T>& a, const TVector3<T>& b, TAngle<T> &intersection_angle)
00554   {
00555     T length_product = a.getSquareLength() *  b.getSquareLength();
00556     if(Maths::isZero(length_product))
00557     {
00558       return false;
00559     }
00560     intersection_angle = a.getAngle(b);
00561     return true;
00562   }
00563 
00570   template <typename T>
00571   BALL_INLINE 
00572   bool GetAngle(const TLine3<T>& a, const TLine3<T>& b, TAngle<T>& intersection_angle)
00573   {
00574     T length_product = a.d.getSquareLength() *  b.d.getSquareLength();
00575 
00576     if(Maths::isZero(length_product))
00577     {
00578       return false;
00579     }
00580     intersection_angle = acos(Maths::abs(a.d * b.d) / sqrt(length_product));
00581     return true;
00582   }
00583 
00590   template <typename T>
00591   BALL_INLINE 
00592   bool GetAngle(const TPlane3<T>& plane, const TVector3<T>& vector, TAngle<T>& intersection_angle)
00593   {
00594     T length_product = plane.n.getSquareLength() * vector.getSquareLength();
00595     
00596     if (Maths::isZero(length_product))
00597     {
00598       return false;
00599     } 
00600     else 
00601     {
00602       intersection_angle = asin(Maths::abs(plane.n * vector) / sqrt(length_product));
00603       return true;
00604     }
00605   }
00606 
00613   template <typename T>
00614   BALL_INLINE 
00615   bool GetAngle(const TVector3<T>& vector ,const TPlane3<T>& plane, TAngle<T> &intersection_angle)
00616   {
00617     return GetAngle(plane, vector, intersection_angle);
00618   }
00619 
00626   template <typename T>
00627   BALL_INLINE 
00628   bool GetAngle(const TPlane3<T>& plane,const TLine3<T>& line, TAngle<T>& intersection_angle)
00629   {
00630     T length_product = plane.n.getSquareLength() * line.d.getSquareLength();
00631     
00632     if (Maths::isZero(length_product))
00633     {
00634       return false;
00635     } 
00636 
00637     intersection_angle = asin(Maths::abs(plane.n * line.d) / sqrt(length_product));
00638     return true;
00639   }
00640 
00647   template <typename T>
00648   BALL_INLINE 
00649   bool GetAngle(const TLine3<T>& line, const TPlane3<T>& plane, TAngle<T>& intersection_angle)
00650   {
00651     return GetAngle(plane, line, intersection_angle);
00652   }
00653 
00654 
00661   template <typename T>
00662   BALL_INLINE 
00663   bool GetAngle(const TPlane3<T>& a, const TPlane3<T>& b, TAngle<T>& intersection_angle)
00664   {
00665     T length_product = a.n.getSquareLength() * b.n.getSquareLength();
00666 
00667     if(Maths::isZero(length_product))
00668     {
00669       return false;
00670     }
00671 
00672     intersection_angle = acos(Maths::abs(a.n * b.n) / sqrt(length_product));
00673     return true;
00674   }
00675 
00682   template <typename T>
00683   bool GetIntersection(const TLine3<T>& a, const TLine3<T>& b, TVector3<T>& point)
00684   {
00685     T c1, c2;
00686     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)))
00687     {
00688       point.set(a.p.x + a.d.x * c1, a.p.y + a.d.y * c1, a.p.z + a.d.z * c1);
00689       return true;
00690     } 
00691 
00692     return false;
00693   }
00694 
00701   template <typename T>
00702   BALL_INLINE 
00703   bool GetIntersection(const TPlane3<T>& plane, const TLine3<T>& line, TVector3<T>& intersection_point)
00704   {
00705     T dot_product = plane.n * line.d;
00706     if (Maths::isZero(dot_product))
00707     {
00708       return false;
00709     } 
00710     intersection_point.set(line.p + (plane.n * (plane.p - line.p)) * line.d / dot_product);
00711     return true;
00712   }
00713 
00720   template <typename T>
00721   BALL_INLINE 
00722   bool GetIntersection(const TLine3<T>& line, const TPlane3<T>& plane, TVector3<T>& intersection_point)
00723   {
00724     return GetIntersection(plane, line, intersection_point);
00725   }
00726 
00733   template <typename T>
00734   bool GetIntersection(const TPlane3<T>& plane1, const TPlane3<T>& plane2, TLine3<T>& line)
00735   {
00736     T u = plane1.p*plane1.n;
00737     T v = plane2.p*plane2.n;
00738     T det = plane1.n.x*plane2.n.y-plane1.n.y*plane2.n.x;
00739     if (Maths::isZero(det))
00740     {
00741       det = plane1.n.x*plane2.n.z-plane1.n.z*plane2.n.x;
00742       if (Maths::isZero(det))
00743       {
00744         det = plane1.n.y*plane2.n.z-plane1.n.z*plane2.n.y;
00745         if (Maths::isZero(det))
00746         {
00747           return false;
00748         }
00749         else
00750         {
00751           T a = plane2.n.z/det;
00752           T b = -plane1.n.z/det;
00753           T c = -plane2.n.y/det;
00754           T d = plane1.n.y/det;
00755           line.p.x = 0;
00756           line.p.y = a*u+b*v;
00757           line.p.z = c*u+d*v;
00758           line.d.x = -1;
00759           line.d.y = a*plane1.n.x+b*plane2.n.x;
00760           line.d.z = c*plane1.n.x+d*plane2.n.x;
00761         }
00762       }
00763       else
00764       {
00765         T a = plane2.n.z/det;
00766         T b = -plane1.n.z/det;
00767         T c = -plane2.n.x/det;
00768         T d = plane1.n.x/det;
00769         line.p.x = a*u+b*v;
00770         line.p.y = 0;
00771         line.p.z = c*u+d*v;
00772         line.d.x = a*plane1.n.y+b*plane2.n.y;
00773         line.d.y = -1;
00774         line.d.z = c*plane1.n.y+d*plane2.n.y;
00775       }
00776     }
00777     else
00778     {
00779       T a = plane2.n.y/det;
00780       T b = -plane1.n.y/det;
00781       T c = -plane2.n.x/det;
00782       T d = plane1.n.x/det;
00783       line.p.x = a*u+b*v;
00784       line.p.y = c*u+d*v;
00785       line.p.z = 0;
00786       line.d.x = a*plane1.n.z+b*plane2.n.z;
00787       line.d.y = c*plane1.n.z+d*plane2.n.z;
00788       line.d.z = -1;
00789     }
00790     return true;
00791   }
00792 
00800   template <typename T>
00801   bool GetIntersection(const TSphere3<T>& sphere, const TLine3<T>& line, TVector3<T>& intersection_point1, TVector3<T>& intersection_point2)
00802   {
00803     T x1, x2;
00804     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);
00805 
00806     if (number_of_solutions == 0)
00807     {
00808       return false;
00809     }
00810 
00811     intersection_point1 = line.p + x1 * line.d;
00812     intersection_point2 = line.p + x2 * line.d;
00813 
00814     return true;
00815   }
00816 
00824   template <typename T>
00825   BALL_INLINE 
00826   bool GetIntersection(const TLine3<T>& line, const TSphere3<T>& sphere, TVector3<T>& intersection_point1, TVector3<T>& intersection_point2)
00827   {
00828     return GetIntersection(sphere, line, intersection_point1, intersection_point2);
00829   }
00830 
00837   template <typename T>
00838   bool GetIntersection(const TSphere3<T>& sphere, const TPlane3<T>& plane, TCircle3<T>& intersection_circle)
00839   {
00840     T distance = GetDistance(sphere.p, plane);
00841 
00842     if (Maths::isGreater(distance, sphere.radius))
00843     {
00844       return false;
00845     }
00846 
00847     TVector3<T> Vector3(plane.n);
00848     Vector3.normalize();
00849 
00850     if (Maths::isEqual(distance, sphere.radius))
00851     {
00852       intersection_circle.set(sphere.p + sphere.radius * Vector3, plane.n, 0);
00853     } 
00854     else 
00855     {
00856       intersection_circle.set
00857         (sphere.p + distance * Vector3, plane.n,
00858          sqrt(sphere.radius * sphere.radius - distance * distance));
00859     }
00860 
00861     return true;
00862   }
00863 
00870   template <typename T>
00871   BALL_INLINE bool
00872   GetIntersection(const TPlane3<T>& plane, const TSphere3<T>& sphere, TCircle3<T>& intersection_circle)
00873   {
00874     return GetIntersection(sphere, plane, intersection_circle);
00875   }
00876    
00885   template <typename T>
00886   bool GetIntersection(const TSphere3<T>& a, const TSphere3<T>& b, TCircle3<T>& intersection_circle)
00887   {
00888     TVector3<T> norm = b.p - a.p;
00889     T square_dist = norm * norm;
00890     if (Maths::isZero(square_dist))
00891     {
00892       return false;
00893     }
00894     T dist = sqrt(square_dist);
00895     if (Maths::isLess(a.radius + b.radius, dist))
00896     {
00897       return false;
00898     }
00899     if (Maths::isGreaterOrEqual(Maths::abs(a.radius - b.radius), dist))
00900     {
00901       return false;
00902     }
00903 
00904     T radius1_square = a.radius * a.radius;
00905     T radius2_square = b.radius * b.radius;
00906     T u = radius1_square - radius2_square + square_dist;
00907     T length = u / (2 * square_dist);
00908     T square_radius = radius1_square - u * length / 2;
00909     if (square_radius < 0)
00910     {
00911       return false;
00912     }
00913 
00914     intersection_circle.p = a.p + (norm * length);
00915     intersection_circle.radius = sqrt(square_radius);
00916     intersection_circle.n = norm / dist;
00917 
00918     return true;
00919   }
00920 
00930   template <class T>
00931   bool GetIntersection(const TSphere3<T>& s1, const TSphere3<T>& s2, const TSphere3<T>& s3, TVector3<T>& p1, TVector3<T>& p2, bool test = true)
00932   {
00933     T r1_square = s1.radius*s1.radius;
00934     T r2_square = s2.radius*s2.radius;
00935     T r3_square = s3.radius*s3.radius;
00936     T p1_square_length = s1.p*s1.p;
00937     T p2_square_length = s2.p*s2.p;
00938     T p3_square_length = s3.p*s3.p;
00939     T u = (r2_square-r1_square-p2_square_length+p1_square_length)/2;
00940     T v = (r3_square-r1_square-p3_square_length+p1_square_length)/2;
00941     TPlane3<T> plane1;
00942     TPlane3<T> plane2;
00943     try
00944     {
00945       plane1 = TPlane3<T>(s2.p.x-s1.p.x,s2.p.y-s1.p.y,s2.p.z-s1.p.z,u);
00946       plane2 = TPlane3<T>(s3.p.x-s1.p.x,s3.p.y-s1.p.y,s3.p.z-s1.p.z,v);
00947     }
00948     catch (Exception::DivisionByZero&)
00949     {
00950       return false;
00951     }
00952     TLine3<T> line;
00953     if (GetIntersection(plane1,plane2,line))
00954     {
00955       TVector3<T> diff(s1.p-line.p);
00956       T x1, x2;
00957       if (SolveQuadraticEquation(line.d*line.d, -diff*line.d*2, diff*diff-r1_square, x1,x2) > 0)
00958       {
00959         p1 = line.p+x1*line.d;
00960         p2 = line.p+x2*line.d;
00961         if (test)
00962         {
00963           TVector3<T> test = s1.p-p1;
00964           if (Maths::isNotEqual(test*test,r1_square))
00965           {
00966             return false;
00967           }
00968           test = s1.p-p2;
00969           if (Maths::isNotEqual(test*test,r1_square))
00970           {
00971             return false;
00972           }
00973           test = s2.p-p1;
00974           if (Maths::isNotEqual(test*test,r2_square))
00975           {
00976             return false;
00977           }
00978           test = s2.p-p2;
00979           if (Maths::isNotEqual(test*test,r2_square))
00980           {
00981             return false;
00982           }
00983           test = s3.p-p1;
00984           if (Maths::isNotEqual(test*test,r3_square))
00985           {
00986             return false;
00987           }
00988           test = s3.p-p2;
00989           if (Maths::isNotEqual(test*test,r3_square))
00990           {
00991             return false;
00992           }
00993         }
00994         return true;
00995       }
00996     }
00997     return false;
00998   }
00999 
01000 
01006   template <typename T>
01007   BALL_INLINE 
01008   bool isCollinear(const TVector3<T>& a, const TVector3<T>& b)
01009   {
01010     return (a % b).isZero();
01011   }
01012 
01019   template <typename T>
01020   BALL_INLINE 
01021   bool isComplanar(const TVector3<T>& a, const TVector3<T>& b, const TVector3<T>& c)
01022   {
01023     return Maths::isZero(TVector3<T>::getTripleProduct(a, b, c));
01024   }
01025 
01033   template <typename T>
01034   BALL_INLINE 
01035   bool isComplanar(const TVector3<T>& a, const TVector3<T>& b, const TVector3<T>& c, const TVector3<T>& d)
01036   {
01037     return isComplanar(a - b, a - c, a - d);
01038   }
01039 
01045   template <typename T>
01046   BALL_INLINE 
01047   bool isOrthogonal(const TVector3<T>& a, const TVector3<T>& b)
01048   {
01049     return Maths::isZero(a * b);
01050   }
01051 
01057   template <typename T>
01058   BALL_INLINE 
01059   bool isOrthogonal(const TVector3<T>& vector, const TLine3<T>& line)
01060   {
01061     return Maths::isZero(vector * line.d);
01062   }
01063 
01069   template <typename T>
01070   BALL_INLINE 
01071   bool isOrthogonal(const TLine3<T>& line, const TVector3<T>& vector)
01072   {
01073     return isOrthogonal(vector, line);
01074   }
01075 
01081   template <typename T>
01082   BALL_INLINE 
01083   bool isOrthogonal(const TLine3<T>& a, const TLine3<T>& b)
01084   {
01085     return Maths::isZero(a.d * b.d);
01086   }
01087 
01093   template <typename T>
01094   BALL_INLINE 
01095   bool isOrthogonal(const TVector3<T>& vector, const TPlane3<T>& plane)
01096   {
01097     return isCollinear(vector, plane.n);
01098   }
01099 
01105   template <typename T>
01106   BALL_INLINE 
01107   bool isOrthogonal(const TPlane3<T>& plane, const TVector3<T>& vector)
01108   {
01109     return isOrthogonal(vector, plane);
01110   }
01111 
01117   template <typename T>
01118   BALL_INLINE 
01119   bool isOrthogonal(const TPlane3<T>& a, const TPlane3<T>& b)
01120   {
01121     return Maths::isZero(a.n * b.n);
01122   }
01123 
01129   template <typename T>
01130   BALL_INLINE 
01131   bool isIntersecting(const TVector3<T>& point, const TLine3<T>& line)
01132   {
01133     return Maths::isZero(GetDistance(point, line));
01134   }
01135 
01141   template <typename T>
01142   BALL_INLINE 
01143   bool isIntersecting(const TLine3<T>& line, const TVector3<T>& point)
01144   {
01145     return isIntersecting(point, line);
01146   }
01147 
01153   template <typename T>
01154   BALL_INLINE 
01155   bool isIntersecting(const TLine3<T>& a, const TLine3<T>& b)
01156   {
01157     return Maths::isZero(GetDistance(a, b));
01158   }
01159 
01165   template <typename T>
01166   BALL_INLINE 
01167   bool isIntersecting(const TVector3<T>& point, const TPlane3<T>& plane)
01168   {
01169     return Maths::isZero(GetDistance(point, plane));
01170   }
01171 
01177   template <typename T>
01178   BALL_INLINE 
01179   bool isIntersecting(const TPlane3<T>& plane, const TVector3<T>& point)
01180   {
01181     return isIntersecting(point, plane);
01182   }
01183 
01189   template <typename T>
01190   BALL_INLINE 
01191   bool isIntersecting(const TLine3<T>& line, const TPlane3<T>& plane)
01192   {
01193     return Maths::isZero(GetDistance(line, plane));
01194   }
01195 
01201   template <typename T>
01202   BALL_INLINE 
01203   bool isIntersecting(const TPlane3<T>& plane, const TLine3<T>& line)
01204   {
01205     return isIntersecting(line, plane);
01206   }
01207 
01213   template <typename T>
01214   BALL_INLINE 
01215   bool isIntersecting(const TPlane3<T>& a, const TPlane3<T>& b)
01216   {
01217     return Maths::isZero(GetDistance(a, b));
01218   }
01219 
01225   template <typename T>
01226   BALL_INLINE 
01227   bool isParallel(const TLine3<T>& line, const TPlane3<T>& plane)
01228   {
01229     return isOrthogonal(line.d, plane.n);
01230   }
01231 
01237   template <typename T>
01238   BALL_INLINE 
01239   bool isParallel(const TPlane3<T>& plane, const TLine3<T>& line)
01240   {
01241     return isParallel(line, plane);
01242   }
01243 
01249   template <typename T>
01250   BALL_INLINE 
01251   bool isParallel(const TPlane3<T>& a, const TPlane3<T>& b)
01252   {
01253     return isCollinear(a.n, b.n);
01254   }
01255 
01258   template <typename T>
01259   TAngle<T> getOrientedAngle
01260     (const T& ax, const T& ay, const T& az,
01261      const T& bx, const T& by, const T& bz,
01262      const T& nx, const T& ny, const T& nz)
01263     throw(Exception::DivisionByZero)
01264   {
01265     // Calculate the length of the two normals
01266     T bl = (T) sqrt((double)ax * ax + ay * ay + az * az);
01267     T el = (T) sqrt((double)bx * bx + by * by + bz * bz);
01268     T bel = (T) (ax * bx + ay * by + az * bz);
01269 
01270     // if one or both planes are degenerated
01271     if (bl * el == 0)
01272     {
01273       throw Exception::DivisionByZero(__FILE__, __LINE__);
01274     }
01275     bel /= (bl * el);
01276     if (bel > 1.0)
01277     {
01278       bel = 1;
01279     }
01280     else if (bel < -1.0)
01281     {
01282       bel = -1;
01283     }
01284 
01285     T acosbel = (T) acos(bel);  // >= 0
01286 
01287     if (( nx * (az * by - ay * bz)
01288          + ny * (ax * bz - az * bx)
01289          + nz * (ay * bx - ax * by)) > 0)
01290     {
01291       acosbel = Constants::PI+Constants::PI-acosbel;
01292     }
01293 
01294     return TAngle<T>(acosbel);
01295   }
01296 
01299   template <typename T>
01300   BALL_INLINE 
01301   TAngle<T>getOrientedAngle(const TVector3<T>& a, const TVector3<T>& b, const TVector3<T>& normal)
01302     throw(Exception::DivisionByZero)
01303   {
01304     return getOrientedAngle(a.x, a.y, a.z, b.x, b.y, b.z, normal.x, normal.y, normal.z);
01305   }
01306  
01322   template <typename T>
01323   TAngle<T> getTorsionAngle
01324     (const T& ax, const T& ay, const T& az,
01325      const T& bx, const T& by, const T& bz,
01326      const T& cx, const T& cy, const T& cz, 
01327      const T& dx, const T& dy, const T& dz)
01328     throw(Exception::DivisionByZero)
01329   {
01330     T abx = ax - bx;
01331     T aby = ay - by;
01332     T abz = az - bz;
01333 
01334     T cbx = cx - bx;
01335     T cby = cy - by;
01336     T cbz = cz - bz;
01337 
01338     T cdx = cx - dx;
01339     T cdy = cy - dy;
01340     T cdz = cz - dz;
01341 
01342     // Calculate the normals to the two planes n1 and n2
01343     // this is given as the cross products:
01344     //     AB x BC
01345     //    --------- = n1
01346     //    |AB x BC|
01347     //
01348     //     BC x CD
01349     //    --------- = n2
01350     //    |BC x CD|
01351 
01352     // Normal to plane 1 
01353     T ndax = aby * cbz - abz * cby; 
01354     T nday = abz * cbx - abx * cbz;
01355     T ndaz = abx * cby - aby * cbx;
01356 
01357     // Normal to plane 2 
01358     T neax = cbz * cdy - cby * cdz; 
01359     T neay = cbx * cdz - cbz * cdx;
01360     T neaz = cby * cdx - cbx * cdy;
01361 
01362     // Calculate the length of the two normals 
01363     T bl = (T) sqrt((double)ndax * ndax + nday * nday + ndaz * ndaz);
01364     T el = (T) sqrt((double)neax * neax + neay * neay + neaz * neaz);
01365     T bel = (T) (ndax * neax + nday * neay + ndaz * neaz);
01366     
01367     // if one or both planes are degenerated
01368     if (bl * el == 0)
01369     {
01370       throw Exception::DivisionByZero(__FILE__, __LINE__);
01371     }
01372     bel /= (bl * el);
01373     if (bel > 1.0) 
01374     {
01375       bel = 1;
01376     } 
01377     else if (bel < -1.0) 
01378     {
01379       bel = -1;
01380     }
01381 
01382     T acosbel = (T) acos(bel);
01383 
01384     if ((cbx * (ndaz * neay - nday * neaz) 
01385          + cby * (ndax * neaz - ndaz * neax) 
01386          + cbz * (nday * neax - ndax * neay))
01387         < 0)
01388     {
01389       acosbel = -acosbel;
01390     }
01391     
01392     acosbel = (acosbel > 0.0) 
01393       ? Constants::PI - acosbel 
01394       : -(Constants::PI + acosbel);
01395     
01396     return TAngle<T>(acosbel);
01397   }
01399 } // namespace BALL
01400 
01401 
01402 #endif // BALL_MATHS_ANALYTICALGEOMETRY_H