LCOV - code coverage report
Current view: top level - util - CubitPlane.cpp (source / functions) Hit Total Coverage
Test: coverage_sk.info Lines: 16 179 8.9 %
Date: 2020-06-30 00:58:45 Functions: 3 15 20.0 %
Branches: 0 412 0.0 %

           Branch data     Line data    Source code
       1                 :            : //- Class: CubitPlane
       2                 :            : //- Description: This file defines the CubitPlane class.
       3                 :            : //- Owner: Greg Sjaardema
       4                 :            : //- Checked by:
       5                 :            : 
       6                 :            : 
       7                 :            : #include <cstdio>
       8                 :            : #include <cstdlib>
       9                 :            : #include <math.h>
      10                 :            : #include "CubitPlane.hpp"
      11                 :            : #include "CubitMatrix.hpp"
      12                 :            : #include "CubitVector.hpp"
      13                 :            : #include "DLIList.hpp"
      14                 :            : #include "CubitMessage.hpp"
      15                 :            : #include "CubitDefines.h"
      16                 :            : #include "GeometryDefines.h"
      17                 :            : 
      18                 :          0 : CubitPlane::CubitPlane(const double A, const double B,
      19                 :          0 :                        const double C, const double D) : normal_(A, B, C)
      20                 :            : {
      21                 :          0 :   double length = normal_.length();
      22                 :          0 :   d_ = D / length;
      23                 :          0 :   normal_ /= length;
      24                 :          0 : }
      25                 :            : 
      26                 :          0 : CubitPlane::CubitPlane() : normal_(0.0, 0.0, 0.0)
      27                 :            : {
      28                 :          0 :   d_ = 0.0;
      29                 :          0 : }
      30                 :            : 
      31                 :          0 : CubitPlane::CubitPlane(const CubitVector &Normal, const double D) :
      32                 :          0 :   normal_(Normal)
      33                 :            : {
      34                 :            :   // make sure that Normal is not (0,0,0) causing a division by 0
      35         [ #  # ]:          0 :   if(normal_.length()==0)
      36 [ #  # ][ #  # ]:          0 :     throw std::invalid_argument ("Normal Length must not be 0");
      37                 :            :   //assert(!normal_.length()==0);
      38                 :            : 
      39                 :          0 :   double length = normal_.length();
      40                 :          0 :   d_ = D / length;
      41                 :          0 :   normal_ /= length;
      42                 :          0 : }
      43                 :            :         
      44                 :       1584 : CubitPlane::CubitPlane(const CubitVector &Normal, const CubitVector &point) :
      45                 :       1584 :   normal_(Normal)
      46                 :            : {
      47                 :            : // plane_D = -(plane_normal.x()*X + plane_normal.y()*Y + plane_normal.z()*Z)
      48                 :       1584 :   normal_.normalize();
      49                 :       1584 :   d_ = -1.0 * (normal_.x()*point.x() + normal_.y()*point.y() +
      50                 :       1584 :                normal_.z()*point.z());
      51                 :       1584 : }
      52                 :            : 
      53                 :        264 : void CubitPlane::set(const CubitVector &Normal, const CubitVector &point)
      54                 :            : {
      55                 :        264 :   normal_ = Normal;
      56                 :        264 :   normal_.normalize();
      57                 :        264 :   d_ = -1.0 * (normal_.x()*point.x() + normal_.y()*point.y() +
      58                 :        264 :                normal_.z()*point.z());
      59                 :        264 : }
      60                 :            : 
      61                 :          0 : CubitPlane::CubitPlane(DLIList<CubitVector> &positions)
      62                 :            : {
      63                 :            : // Newells method for determining approximate plane equation.
      64                 :            : // Plane equation is of the form:
      65                 :            : // 0 = plane_D +plane_normal.x()*X + plane_normal.y()*Y + plane_normal.z()*Z
      66 [ #  # ][ #  # ]:          0 :   if(positions.size() < 3)
      67 [ #  # ][ #  # ]:          0 :     throw std::invalid_argument("Must have 3 or more Points");
      68         [ #  # ]:          0 :   CubitVector vector_diff;
      69         [ #  # ]:          0 :   CubitVector vector_sum;
      70         [ #  # ]:          0 :   CubitVector ref_point = CubitVector (0.0, 0.0, 0.0);
      71         [ #  # ]:          0 :   CubitVector tmp_vector;
      72 [ #  # ][ #  # ]:          0 :   normal_ = CubitVector(0.0, 0.0, 0.0);
      73 [ #  # ][ #  # ]:          0 :   CubitVector vector1, vector2;
      74                 :            :   
      75 [ #  # ][ #  # ]:          0 :   for (int i=positions.size(); i > 0; i--)
      76                 :            :   {
      77 [ #  # ][ #  # ]:          0 :     vector1 = positions.get_and_step();
      78 [ #  # ][ #  # ]:          0 :     vector2 = positions.get();
      79 [ #  # ][ #  # ]:          0 :     vector_diff = (vector2) - (vector1);
      80         [ #  # ]:          0 :     ref_point += (vector1);
      81 [ #  # ][ #  # ]:          0 :     vector_sum = (vector1) + (vector2);
      82                 :            :     
      83 [ #  # ][ #  # ]:          0 :     tmp_vector.set(vector_diff.y() * vector_sum.z(),
      84 [ #  # ][ #  # ]:          0 :                    vector_diff.z() * vector_sum.x(),
      85 [ #  # ][ #  # ]:          0 :                    vector_diff.x() * vector_sum.y());
                 [ #  # ]
      86         [ #  # ]:          0 :     normal_ += tmp_vector;
      87                 :            :   }
      88 [ #  # ][ #  # ]:          0 :   double divisor = positions.size() * normal_.length();
      89                 :            : //  if (divisor < .000000001)
      90                 :            : //  {
      91                 :            : //    PRINT_ERROR("Colinear basis vector in CubitPlane constructor");
      92                 :            : //  }
      93         [ #  # ]:          0 :   d_ = (ref_point % normal_) / divisor;
      94         [ #  # ]:          0 :   normal_.normalize();
      95         [ #  # ]:          0 :   normal_ *= -1.0;
      96                 :          0 : }
      97                 :            : 
      98                 :          0 : bool CubitPlane::fit_points(const std::vector<CubitVector> &positions)
      99                 :            : {
     100                 :            :   //- use the method of linear regression
     101                 :            :   //
     102                 :            :   // by creating an Ax=b system where:
     103                 :            :   //
     104                 :            :   //            ___                                 ___
     105                 :            :   //            |   x[i]*x[i],    x[i]*y[i],    x[i]  |
     106                 :            :   //  A = sum_i |   x[i]*y[i],    y[i]*y[i],    y[i]  |
     107                 :            :   //            |   x[i],         y[i],         n     |
     108                 :            :   //            ---                                 ---
     109                 :            :   //            ___         ___
     110                 :            :   //            |  x[i]*z[i]  |
     111                 :            :   //  b = sum_i |  y[i]*z[i]  |
     112                 :            :   //            |  z[i]}      |
     113                 :            :   //            ---         ---
     114                 :            :   // But this assumes that z is a linear function of x and y (i.e. z component
     115                 :            :   // of plane normal != 0.).  We check the rank of A to catch this case.  We
     116                 :            :   // handle this case, by transposing the x or y coordinates for the z,
     117                 :            :   // computing the normal, then transposing back (see itry below).
     118                 :            : 
     119         [ #  # ]:          0 :   for ( int itry=0; itry < 3; itry++ )
     120                 :            :   {
     121         [ #  # ]:          0 :     CubitMatrix A(3,3);
     122 [ #  # ][ #  # ]:          0 :     std::vector<double> b(3);
                 [ #  # ]
     123 [ #  # ][ #  # ]:          0 :     A.set(2,2,positions.size());
     124 [ #  # ][ #  # ]:          0 :     for ( size_t ipt=0; ipt<positions.size(); ipt++ )
     125                 :            :     {
     126                 :          0 :       double x=0., y=0., z=0.;
     127         [ #  # ]:          0 :       if ( itry == 0 )
     128                 :            :       {
     129 [ #  # ][ #  # ]:          0 :         x = positions[ipt].x();
     130 [ #  # ][ #  # ]:          0 :         y = positions[ipt].y();
     131 [ #  # ][ #  # ]:          0 :         z = positions[ipt].z();
     132                 :            :       }
     133         [ #  # ]:          0 :       else if ( itry == 1 )
     134                 :            :       {
     135 [ #  # ][ #  # ]:          0 :         x = positions[ipt].x();
     136 [ #  # ][ #  # ]:          0 :         z = positions[ipt].y();
     137 [ #  # ][ #  # ]:          0 :         y = positions[ipt].z();
     138                 :            :       }
     139         [ #  # ]:          0 :       else if ( itry == 2 )
     140                 :            :       {
     141 [ #  # ][ #  # ]:          0 :         z = positions[ipt].x();
     142 [ #  # ][ #  # ]:          0 :         y = positions[ipt].y();
     143 [ #  # ][ #  # ]:          0 :         x = positions[ipt].z();
     144                 :            :       }
     145         [ #  # ]:          0 :       double sum_xx = x*x + A.get(0,0);
     146         [ #  # ]:          0 :       double sum_yy = y*y + A.get(1,1);
     147         [ #  # ]:          0 :       double sum_xy = x*y + A.get(1,0);
     148         [ #  # ]:          0 :       double sum_x  = x   + A.get(2,0);
     149         [ #  # ]:          0 :       double sum_y  = y   + A.get(2,1);
     150         [ #  # ]:          0 :       A.set(0,0,sum_xx);
     151         [ #  # ]:          0 :       A.set(1,1,sum_yy);
     152 [ #  # ][ #  # ]:          0 :       A.set(1,0,sum_xy); A.set(0,1,sum_xy);
     153 [ #  # ][ #  # ]:          0 :       A.set(2,0,sum_x);  A.set(0,2,sum_x);
     154 [ #  # ][ #  # ]:          0 :       A.set(1,2,sum_y);  A.set(2,1,sum_y);
     155         [ #  # ]:          0 :       b[0] += x*z;
     156         [ #  # ]:          0 :       b[1] += y*z;
     157         [ #  # ]:          0 :       b[2] += z;
     158                 :            :     }
     159                 :            : 
     160                 :            :     // Make sure we have full rank.  If not, it means:
     161                 :            :     // if itry==0, plane is parallel to z-axis.
     162                 :            :     // if itry==1, plane is parallel to z-axis & y-axis
     163                 :            :     // if itry==2, points are colinear
     164         [ #  # ]:          0 :     int rank = A.rank();
     165         [ #  # ]:          0 :     if ( rank == 3 )
     166                 :            :     {
     167         [ #  # ]:          0 :       std::vector<double> coef(3);
     168         [ #  # ]:          0 :       A.solveNxN( b, coef );
     169         [ #  # ]:          0 :       if ( itry == 0 )
     170 [ #  # ][ #  # ]:          0 :         normal_.set(coef[0], coef[1], -1);
                 [ #  # ]
     171         [ #  # ]:          0 :       else if ( itry == 1 )
     172 [ #  # ][ #  # ]:          0 :         normal_.set(coef[0], -1, coef[1]);
                 [ #  # ]
     173         [ #  # ]:          0 :       else if ( itry == 2 )
     174 [ #  # ][ #  # ]:          0 :         normal_.set(-1, coef[1], coef[0]);
                 [ #  # ]
     175         [ #  # ]:          0 :       normal_.normalize();
     176                 :          0 :       d_ = 0;
     177 [ #  # ][ #  # ]:          0 :       for ( size_t ipt=0; ipt<positions.size(); ipt++ )
     178                 :            :       {
     179 [ #  # ][ #  # ]:          0 :         d_ += normal_.x()*positions[ipt].x() +
                 [ #  # ]
     180 [ #  # ][ #  # ]:          0 :               normal_.y()*positions[ipt].y() +
                 [ #  # ]
     181 [ #  # ][ #  # ]:          0 :               normal_.z()*positions[ipt].z();
                 [ #  # ]
     182                 :            :       }
     183         [ #  # ]:          0 :       d_ /= positions.size();
     184 [ #  # ][ #  # ]:          0 :       return true;
                 [ #  # ]
     185                 :            :     }
     186                 :          0 :   }
     187                 :          0 :   d_ = 0.0;
     188                 :          0 :   normal_.set(0.,0.,0.);
     189                 :          0 :   return false;
     190                 :            : }
     191                 :            : 
     192                 :      28204 : CubitPlane::CubitPlane(const CubitPlane& copy_from)
     193                 :            : {
     194                 :      14102 :   normal_ = copy_from.normal_;
     195                 :      14102 :   d_ = copy_from.d_;
     196                 :      14102 : }
     197                 :            : 
     198                 :          0 : int CubitPlane::mk_plane_with_points( const CubitVector& V0, 
     199                 :            :                                       const CubitVector& V1,
     200                 :            :                                       const CubitVector& V2 )
     201                 :            : {
     202                 :            :     // First check to make sure that the points are not collinear
     203                 :            :   
     204                 :            :     // Vector going from Vertex 0 to Vertex 1       
     205         [ #  # ]:          0 :   CubitVector vector01 = V1 - V0;
     206         [ #  # ]:          0 :   vector01.normalize();
     207                 :            :   
     208                 :            :     // Vector going from Vertex 0 to Vertex 2     
     209         [ #  # ]:          0 :   CubitVector vector02 = V2 - V0;
     210         [ #  # ]:          0 :   vector02.normalize();
     211                 :            :   
     212                 :            :     // If the 3 points are collinear, then the cross product of these two
     213                 :            :     // vectors will yield a null vector (one whose length is zero).
     214 [ #  # ][ #  # ]:          0 :   normal_ = vector01 * vector02;
     215                 :            :   
     216 [ #  # ][ #  # ]:          0 :   if(normal_.length() <= CUBIT_RESABS)
     217                 :            :   {
     218 [ #  # ][ #  # ]:          0 :     PRINT_ERROR("Points are collinear.\n"
                 [ #  # ]
     219         [ #  # ]:          0 :                 "       Cannot create a CubitPlane object.\n");
     220                 :          0 :     d_ = 0.0;
     221                 :          0 :     return CUBIT_FAILURE;
     222                 :            :   }
     223                 :            :   
     224         [ #  # ]:          0 :   normal_.normalize();
     225                 :            :   
     226         [ #  # ]:          0 :   double D0 =   -(normal_ % V0);
     227         [ #  # ]:          0 :   double D1 =   -(normal_ % V1);
     228         [ #  # ]:          0 :   double D2 =   -(normal_ % V2);
     229                 :          0 :   d_ = (D0 + D1 + D2) / 3.0;
     230                 :            :   
     231                 :          0 :   return CUBIT_SUCCESS;
     232                 :            : }
     233                 :            : 
     234                 :          0 : CubitVector CubitPlane::point_on_plane() const
     235                 :            : {
     236         [ #  # ]:          0 :   if ( fabs( normal_.x() ) > CUBIT_RESABS )
     237                 :          0 :     return CubitVector(-d_ / normal_.x(), 0, 0);
     238         [ #  # ]:          0 :   else if ( fabs( normal_.y() ) > CUBIT_RESABS )
     239                 :          0 :     return CubitVector(0, -d_ / normal_.y(), 0);
     240         [ #  # ]:          0 :   else if ( fabs( normal_.z() ) > CUBIT_RESABS )
     241                 :          0 :     return CubitVector(0, 0, -d_ / normal_.z());
     242                 :            :     // If A B and C are all zero, the plane is invalid,
     243                 :            :     // Just return <0,0,0>
     244                 :          0 :   return CubitVector(0,0,0);
     245                 :            : }
     246                 :            : 
     247                 :            : //-  Plane assignment operator.
     248                 :          0 : CubitPlane& CubitPlane::operator=(const CubitPlane &plane)
     249                 :            : {
     250         [ #  # ]:          0 :   if (this != &plane)
     251                 :            :   {
     252                 :          0 :     normal_ = plane.normal_;
     253                 :          0 :     d_ = plane.d_;
     254                 :            :   }
     255                 :          0 :   return *this;
     256                 :            : }
     257                 :            : 
     258                 :          0 : double CubitPlane::distance(const CubitVector &vector) const
     259                 :            : {
     260                 :          0 :   return normal_ % vector + d_;
     261                 :            : }
     262                 :            : 
     263                 :          0 : CubitVector CubitPlane::intersect(const CubitVector &base,
     264                 :            :                                   const CubitVector &direction) const
     265                 :            : {
     266                 :          0 :   double t = -(normal_ % base + d_) / (normal_ % direction);
     267         [ #  # ]:          0 :   return (base + direction * t);
     268                 :            : }
     269                 :            : 
     270                 :          0 : int CubitPlane::intersect(const CubitPlane &plane_2,
     271                 :            :                           CubitVector &origin, CubitVector &vector) const
     272                 :            : {
     273                 :            :     // Code from Graphics Gems III, Georgiades
     274                 :            :     // Calculate the line of intersection between two planes. 
     275                 :            :     // Initialize the unit direction vector of the line of intersection in
     276                 :            :     // xdir.
     277                 :            :     // Pick the point on the line of intersection on the coordinate plane most
     278                 :            :     // normal to xdir.
     279                 :            :     // Return TRUE if successful, FALSE otherwise (indicating that the planes
     280                 :            :     // don't intersect). The order in which the planes are given determines the
     281                 :            :     // choice of direction of xdir.
     282                 :            :     //
     283                 :            :     // int GetXLine(vect4 *pl1, vect4 *plane_2, vect3 *vector, vect3 *xpt)
     284                 :            :   double invdet;  // inverse of 2x2 matrix determinant
     285 [ #  # ][ #  # ]:          0 :   vector = normal() * plane_2.normal();
         [ #  # ][ #  # ]
     286 [ #  # ][ #  # ]:          0 :   CubitVector dir2(vector.x()*vector.x(),
     287 [ #  # ][ #  # ]:          0 :                    vector.y()*vector.y(),
     288 [ #  # ][ #  # ]:          0 :                    vector.z()*vector.z());
                 [ #  # ]
     289 [ #  # ][ #  # ]:          0 :   CubitVector plane1n = normal();
     290 [ #  # ][ #  # ]:          0 :   CubitVector plane2n = plane_2.normal();
     291                 :            :   
     292 [ #  # ][ #  # ]:          0 :   if (dir2.z() > dir2.y() && dir2.z() > dir2.x() && dir2.z() > CUBIT_RESABS)
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     293                 :            :   {
     294                 :            :       // then get a point on the XY plane
     295         [ #  # ]:          0 :     invdet = 1.0 / vector.z();
     296                 :            :     
     297                 :            :       //solve < pl1.x * origin.x + pl1.y * origin.y = - pl1.w >
     298                 :            :       //      < plane2n.x * origin.x + plane2n.y * origin.y = - plane2n.w >
     299 [ #  # ][ #  # ]:          0 :     origin.set(plane1n.y() * plane_2.coefficient() -
     300 [ #  # ][ #  # ]:          0 :                plane2n.y() * coefficient(),
     301 [ #  # ][ #  # ]:          0 :                plane2n.x() * coefficient() -
     302 [ #  # ][ #  # ]:          0 :                plane1n.x() * plane_2.coefficient(),
     303         [ #  # ]:          0 :                0.0);
     304                 :            :   }
     305 [ #  # ][ #  # ]:          0 :   else if (dir2.y() > dir2.x() && dir2.y() > CUBIT_RESABS)
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     306                 :            :   {
     307                 :            :       // then get a point on the XZ plane
     308         [ #  # ]:          0 :     invdet = -1.0 / vector.y();
     309                 :            :     
     310                 :            :       // solve < pl1.x * origin.x + pl1.z * origin.z = -pl1.w >
     311                 :            :       //       < plane2n.x * origin.x + plane2n.z * origin.z = -plane2n.w >
     312 [ #  # ][ #  # ]:          0 :     origin.set(plane1n.z() * plane_2.coefficient() -
     313 [ #  # ][ #  # ]:          0 :                plane2n.z() * coefficient(),
     314                 :            :                0.0,
     315 [ #  # ][ #  # ]:          0 :                plane2n.x() * coefficient() -
     316 [ #  # ][ #  # ]:          0 :                plane1n.x() * plane_2.coefficient());
                 [ #  # ]
     317                 :            :   }
     318 [ #  # ][ #  # ]:          0 :   else if (dir2.x() > CUBIT_RESABS)
     319                 :            :   {
     320                 :            :       // then get a point on the YZ plane
     321         [ #  # ]:          0 :     invdet = 1.0 / vector.x();
     322                 :            :     
     323                 :            :       // solve < pl1.y * origin.y + pl1.z * origin.z = - pl1.w >
     324                 :            :       //             < plane2n.y * origin.y + plane2n.z * origin.z = - plane2n.w >
     325                 :            :     origin.set(0.0,
     326 [ #  # ][ #  # ]:          0 :                plane1n.z() * plane_2.coefficient() -
     327 [ #  # ][ #  # ]:          0 :                plane2n.z() * coefficient(),
     328 [ #  # ][ #  # ]:          0 :                plane2n.y() * coefficient() -
     329 [ #  # ][ #  # ]:          0 :                plane1n.y() * plane_2.coefficient());
                 [ #  # ]
     330                 :            :   }
     331                 :            :   else // vector is zero, then no point of intersection exists
     332                 :          0 :     return CUBIT_FALSE;
     333                 :            :   
     334         [ #  # ]:          0 :   origin *= invdet;
     335 [ #  # ][ #  # ]:          0 :   invdet = 1.0 / (float)sqrt(dir2.x() + dir2.y() + dir2.z());
                 [ #  # ]
     336         [ #  # ]:          0 :   vector *= invdet;
     337                 :          0 :   return CUBIT_TRUE;
     338                 :            : }
     339                 :            : 
     340                 :          0 : CubitVector CubitPlane::project( const CubitVector& point ) const
     341                 :            : {
     342         [ #  # ]:          0 :   return point - distance(point) * normal();
     343                 :            : }

Generated by: LCOV version 1.11