cgma
CubitPlane.cpp
Go to the documentation of this file.
00001 //- Class: CubitPlane
00002 //- Description: This file defines the CubitPlane class.
00003 //- Owner: Greg Sjaardema
00004 //- Checked by:
00005 
00006 
00007 #include <cstdio>
00008 #include <cstdlib>
00009 #include <math.h>
00010 #include "CubitPlane.hpp"
00011 #include "CubitMatrix.hpp"
00012 #include "CubitVector.hpp"
00013 #include "DLIList.hpp"
00014 #include "CubitMessage.hpp"
00015 #include "CubitDefines.h"
00016 #include "GeometryDefines.h"
00017 
00018 CubitPlane::CubitPlane(const double A, const double B,
00019                        const double C, const double D) : normal_(A, B, C)
00020 {
00021   double length = normal_.length();
00022   d_ = D / length;
00023   normal_ /= length;
00024 }
00025 
00026 CubitPlane::CubitPlane() : normal_(0.0, 0.0, 0.0)
00027 {
00028   d_ = 0.0;
00029 }
00030 
00031 CubitPlane::CubitPlane(const CubitVector &Normal, const double D) :
00032   normal_(Normal)
00033 {
00034   // make sure that Normal is not (0,0,0) causing a division by 0
00035   if(normal_.length()==0)
00036     throw std::invalid_argument ("Normal Length must not be 0");
00037   //assert(!normal_.length()==0);
00038 
00039   double length = normal_.length();
00040   d_ = D / length;
00041   normal_ /= length;
00042 }
00043     
00044 CubitPlane::CubitPlane(const CubitVector &Normal, const CubitVector &point) :
00045   normal_(Normal)
00046 {
00047 // plane_D = -(plane_normal.x()*X + plane_normal.y()*Y + plane_normal.z()*Z)
00048   normal_.normalize();
00049   d_ = -1.0 * (normal_.x()*point.x() + normal_.y()*point.y() +
00050            normal_.z()*point.z());
00051 }
00052 
00053 void CubitPlane::set(const CubitVector &Normal, const CubitVector &point)
00054 {
00055   normal_ = Normal;
00056   normal_.normalize();
00057   d_ = -1.0 * (normal_.x()*point.x() + normal_.y()*point.y() +
00058            normal_.z()*point.z());
00059 }
00060 
00061 CubitPlane::CubitPlane(DLIList<CubitVector> &positions)
00062 {
00063 // Newells method for determining approximate plane equation.
00064 // Plane equation is of the form:
00065 // 0 = plane_D +plane_normal.x()*X + plane_normal.y()*Y + plane_normal.z()*Z
00066   if(positions.size() < 3)
00067     throw std::invalid_argument("Must have 3 or more Points");
00068   CubitVector vector_diff;
00069   CubitVector vector_sum;
00070   CubitVector ref_point = CubitVector (0.0, 0.0, 0.0);
00071   CubitVector tmp_vector;
00072   normal_ = CubitVector(0.0, 0.0, 0.0);
00073   CubitVector vector1, vector2;
00074   
00075   for (int i=positions.size(); i > 0; i--)
00076   {
00077     vector1 = positions.get_and_step();
00078     vector2 = positions.get();
00079     vector_diff = (vector2) - (vector1);
00080     ref_point += (vector1);
00081     vector_sum = (vector1) + (vector2);
00082     
00083     tmp_vector.set(vector_diff.y() * vector_sum.z(),
00084                    vector_diff.z() * vector_sum.x(),
00085                    vector_diff.x() * vector_sum.y());
00086     normal_ += tmp_vector;
00087   }
00088   double divisor = positions.size() * normal_.length();
00089 //  if (divisor < .000000001)
00090 //  {
00091 //    PRINT_ERROR("Colinear basis vector in CubitPlane constructor");
00092 //  }
00093   d_ = (ref_point % normal_) / divisor;
00094   normal_.normalize();
00095   normal_ *= -1.0;
00096 }
00097 
00098 bool CubitPlane::fit_points(const std::vector<CubitVector> &positions)
00099 {
00100   //- use the method of linear regression
00101   //
00102   // by creating an Ax=b system where:
00103   //
00104   //            ___                                 ___
00105   //            |   x[i]*x[i],    x[i]*y[i],    x[i]  |
00106   //  A = sum_i |   x[i]*y[i],    y[i]*y[i],    y[i]  |
00107   //            |   x[i],         y[i],         n     |
00108   //            ---                                 ---
00109   //            ___         ___
00110   //            |  x[i]*z[i]  |
00111   //  b = sum_i |  y[i]*z[i]  |
00112   //            |  z[i]}      |
00113   //            ---         ---
00114   // But this assumes that z is a linear function of x and y (i.e. z component
00115   // of plane normal != 0.).  We check the rank of A to catch this case.  We
00116   // handle this case, by transposing the x or y coordinates for the z,
00117   // computing the normal, then transposing back (see itry below).
00118 
00119   for ( int itry=0; itry < 3; itry++ )
00120   {
00121     CubitMatrix A(3,3);
00122     std::vector<double> b(3);
00123     A.set(2,2,positions.size());
00124     for ( size_t ipt=0; ipt<positions.size(); ipt++ )
00125     {
00126       double x=0., y=0., z=0.;
00127       if ( itry == 0 )
00128       {
00129         x = positions[ipt].x();
00130         y = positions[ipt].y();
00131         z = positions[ipt].z();
00132       }
00133       else if ( itry == 1 )
00134       {
00135         x = positions[ipt].x();
00136         z = positions[ipt].y();
00137         y = positions[ipt].z();
00138       }
00139       else if ( itry == 2 )
00140       {
00141         z = positions[ipt].x();
00142         y = positions[ipt].y();
00143         x = positions[ipt].z();
00144       }
00145       double sum_xx = x*x + A.get(0,0);
00146       double sum_yy = y*y + A.get(1,1);
00147       double sum_xy = x*y + A.get(1,0);
00148       double sum_x  = x   + A.get(2,0);
00149       double sum_y  = y   + A.get(2,1);
00150       A.set(0,0,sum_xx);
00151       A.set(1,1,sum_yy);
00152       A.set(1,0,sum_xy); A.set(0,1,sum_xy);
00153       A.set(2,0,sum_x);  A.set(0,2,sum_x);
00154       A.set(1,2,sum_y);  A.set(2,1,sum_y);
00155       b[0] += x*z;
00156       b[1] += y*z;
00157       b[2] += z;
00158     }
00159 
00160     // Make sure we have full rank.  If not, it means:
00161     // if itry==0, plane is parallel to z-axis.
00162     // if itry==1, plane is parallel to z-axis & y-axis
00163     // if itry==2, points are colinear
00164     int rank = A.rank();
00165     if ( rank == 3 )
00166     {
00167       std::vector<double> coef(3);
00168       A.solveNxN( b, coef );
00169       if ( itry == 0 )
00170         normal_.set(coef[0], coef[1], -1);
00171       else if ( itry == 1 )
00172         normal_.set(coef[0], -1, coef[1]);
00173       else if ( itry == 2 )
00174         normal_.set(-1, coef[1], coef[0]);
00175       normal_.normalize();
00176       d_ = 0;
00177       for ( size_t ipt=0; ipt<positions.size(); ipt++ )
00178       {
00179         d_ += normal_.x()*positions[ipt].x() +
00180               normal_.y()*positions[ipt].y() +
00181               normal_.z()*positions[ipt].z();
00182       }
00183       d_ /= positions.size();
00184       return true;
00185     }
00186   }
00187   d_ = 0.0;
00188   normal_.set(0.,0.,0.);
00189   return false;
00190 }
00191 
00192 CubitPlane::CubitPlane(const CubitPlane& copy_from)
00193 {
00194   normal_ = copy_from.normal_;
00195   d_ = copy_from.d_;
00196 }
00197 
00198 int CubitPlane::mk_plane_with_points( const CubitVector& V0, 
00199                                       const CubitVector& V1,
00200                                       const CubitVector& V2 )
00201 {
00202     // First check to make sure that the points are not collinear
00203   
00204     // Vector going from Vertex 0 to Vertex 1       
00205   CubitVector vector01 = V1 - V0;
00206   vector01.normalize();
00207   
00208     // Vector going from Vertex 0 to Vertex 2     
00209   CubitVector vector02 = V2 - V0;
00210   vector02.normalize();
00211   
00212     // If the 3 points are collinear, then the cross product of these two
00213     // vectors will yield a null vector (one whose length is zero).
00214   normal_ = vector01 * vector02;
00215   
00216   if(normal_.length() <= CUBIT_RESABS)
00217   {
00218     PRINT_ERROR("Points are collinear.\n"
00219                 "       Cannot create a CubitPlane object.\n");
00220     d_ = 0.0;
00221     return CUBIT_FAILURE;
00222   }
00223   
00224   normal_.normalize();
00225   
00226   double D0 =   -(normal_ % V0);
00227   double D1 =   -(normal_ % V1);
00228   double D2 =   -(normal_ % V2);
00229   d_ = (D0 + D1 + D2) / 3.0;
00230   
00231   return CUBIT_SUCCESS;
00232 }
00233 
00234 CubitVector CubitPlane::point_on_plane() const
00235 {
00236   if ( fabs( normal_.x() ) > CUBIT_RESABS )
00237     return CubitVector(-d_ / normal_.x(), 0, 0);
00238   else if ( fabs( normal_.y() ) > CUBIT_RESABS )
00239     return CubitVector(0, -d_ / normal_.y(), 0);
00240   else if ( fabs( normal_.z() ) > CUBIT_RESABS )
00241     return CubitVector(0, 0, -d_ / normal_.z());
00242     // If A B and C are all zero, the plane is invalid,
00243     // Just return <0,0,0>
00244   return CubitVector(0,0,0);
00245 }
00246 
00247 //-  Plane assignment operator.
00248 CubitPlane& CubitPlane::operator=(const CubitPlane &plane)
00249 {
00250   if (this != &plane)
00251   {
00252     normal_ = plane.normal_;
00253     d_ = plane.d_;
00254   }
00255   return *this;
00256 }
00257 
00258 double CubitPlane::distance(const CubitVector &vector) const
00259 {
00260   return normal_ % vector + d_;
00261 }
00262 
00263 CubitVector CubitPlane::intersect(const CubitVector &base,
00264                                   const CubitVector &direction) const
00265 {
00266   double t = -(normal_ % base + d_) / (normal_ % direction);
00267   return (base + direction * t);
00268 }
00269 
00270 int CubitPlane::intersect(const CubitPlane &plane_2,
00271                           CubitVector &origin, CubitVector &vector) const
00272 {
00273     // Code from Graphics Gems III, Georgiades
00274     // Calculate the line of intersection between two planes. 
00275     // Initialize the unit direction vector of the line of intersection in
00276     // xdir.
00277     // Pick the point on the line of intersection on the coordinate plane most
00278     // normal to xdir.
00279     // Return TRUE if successful, FALSE otherwise (indicating that the planes
00280     // don't intersect). The order in which the planes are given determines the
00281     // choice of direction of xdir.
00282     //
00283     // int GetXLine(vect4 *pl1, vect4 *plane_2, vect3 *vector, vect3 *xpt)
00284   double invdet;  // inverse of 2x2 matrix determinant
00285   vector = normal() * plane_2.normal();
00286   CubitVector dir2(vector.x()*vector.x(),
00287                    vector.y()*vector.y(),
00288                    vector.z()*vector.z());
00289   CubitVector plane1n = normal();
00290   CubitVector plane2n = plane_2.normal();
00291   
00292   if (dir2.z() > dir2.y() && dir2.z() > dir2.x() && dir2.z() > CUBIT_RESABS)
00293   {
00294       // then get a point on the XY plane
00295     invdet = 1.0 / vector.z();
00296     
00297       //solve < pl1.x * origin.x + pl1.y * origin.y = - pl1.w >
00298       //      < plane2n.x * origin.x + plane2n.y * origin.y = - plane2n.w >
00299     origin.set(plane1n.y() * plane_2.coefficient() -
00300                plane2n.y() * coefficient(),
00301                plane2n.x() * coefficient() -
00302                plane1n.x() * plane_2.coefficient(),
00303                0.0);
00304   }
00305   else if (dir2.y() > dir2.x() && dir2.y() > CUBIT_RESABS)
00306   {
00307       // then get a point on the XZ plane
00308     invdet = -1.0 / vector.y();
00309     
00310       // solve < pl1.x * origin.x + pl1.z * origin.z = -pl1.w >
00311       //       < plane2n.x * origin.x + plane2n.z * origin.z = -plane2n.w >
00312     origin.set(plane1n.z() * plane_2.coefficient() -
00313                plane2n.z() * coefficient(),
00314                0.0,
00315                plane2n.x() * coefficient() -
00316                plane1n.x() * plane_2.coefficient());
00317   }
00318   else if (dir2.x() > CUBIT_RESABS)
00319   {
00320       // then get a point on the YZ plane
00321     invdet = 1.0 / vector.x();
00322     
00323       // solve < pl1.y * origin.y + pl1.z * origin.z = - pl1.w >
00324       //             < plane2n.y * origin.y + plane2n.z * origin.z = - plane2n.w >
00325     origin.set(0.0,
00326                plane1n.z() * plane_2.coefficient() -
00327                plane2n.z() * coefficient(),
00328                plane2n.y() * coefficient() -
00329                plane1n.y() * plane_2.coefficient());
00330   }
00331   else // vector is zero, then no point of intersection exists
00332     return CUBIT_FALSE;
00333   
00334   origin *= invdet;
00335   invdet = 1.0 / (float)sqrt(dir2.x() + dir2.y() + dir2.z());
00336   vector *= invdet;
00337   return CUBIT_TRUE;
00338 }
00339 
00340 CubitVector CubitPlane::project( const CubitVector& point ) const
00341 {
00342   return point - distance(point) * normal();
00343 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines