MOAB: Mesh Oriented datABase  (version 5.4.1)
SmoothFace.cpp
Go to the documentation of this file.
00001 #include <iostream>
00002 #include <fstream>
00003 #include <algorithm>
00004 #include <iomanip>
00005 #include <cassert>
00006 #include <limits>
00007 #include "moab/OrientedBoxTreeTool.hpp"
00008 #include "SmoothFace.hpp"
00009 
00010 #define GEOMETRY_RESABS 1.e-6
00011 #define mbsqr( a )      ( ( a ) * ( a ) )
00012 #define mbcube( a )     ( mbsqr( a ) * ( a ) )
00013 #define mbquart( a )    ( mbsqr( a ) * mbsqr( a ) )
00014 
00015 namespace moab
00016 {
00017 
00018 bool within_tolerance( CartVect& p1, CartVect& p2, const double& tolerance )
00019 {
00020     if( ( fabs( p1[0] - p2[0] ) < tolerance ) && ( fabs( p1[1] - p2[1] ) < tolerance ) &&
00021         ( fabs( p1[2] - p2[2] ) < tolerance ) )
00022         return true;
00023     return false;
00024 }
00025 int numAdjTriInSet( Interface* mb, EntityHandle startEdge, EntityHandle set )
00026 {
00027     std::vector< EntityHandle > adjTri;
00028     mb->get_adjacencies( &startEdge, 1, 2, false, adjTri, Interface::UNION );
00029     // count how many are in the set
00030     int nbInSet = 0;
00031     for( size_t i = 0; i < adjTri.size(); i++ )
00032     {
00033         EntityHandle tri = adjTri[i];
00034         if( mb->contains_entities( set, &tri, 1 ) ) nbInSet++;
00035     }
00036     return nbInSet;
00037 }
00038 
00039 bool debug_surf_eval1 = false;
00040 
00041 SmoothFace::SmoothFace( Interface* mb, EntityHandle surface_set, GeomTopoTool* gTool )
00042     : _markTag( 0 ), _gradientTag( 0 ), _tangentsTag( 0 ), _edgeCtrlTag( 0 ), _facetCtrlTag( 0 ),
00043       _facetEdgeCtrlTag( 0 ), _planeTag( 0 ), _mb( mb ), _set( surface_set ), _my_geomTopoTool( gTool ), _obb_root( 0 ),
00044       _evaluationsCounter( 0 )
00045 {
00046     //_smooth_face = NULL;
00047     //_mbOut->create_meshset(MESHSET_SET, _oSet); //will contain the
00048     // get also the obb_root
00049     if( _my_geomTopoTool )
00050     {
00051         _my_geomTopoTool->get_root( this->_set, _obb_root );
00052         if( debug_surf_eval1 ) _my_geomTopoTool->obb_tree()->stats( _obb_root, std::cout );
00053     }
00054 }
00055 
00056 SmoothFace::~SmoothFace() {}
00057 
00058 double SmoothFace::area()
00059 {
00060     // find the area of this entity
00061     // assert(_smooth_face);
00062     // double area1 = _smooth_face->area();
00063     double totArea = 0.;
00064     for( Range::iterator it = _triangles.begin(); it != _triangles.end(); ++it )
00065     {
00066         EntityHandle tria = *it;
00067         const EntityHandle* conn3;
00068         int nnodes;
00069         _mb->get_connectivity( tria, conn3, nnodes );
00070         //
00071         // double coords[9]; // store the coordinates for the nodes
00072         //_mb->get_coords(conn3, 3, coords);
00073         CartVect p[3];
00074         _mb->get_coords( conn3, 3, (double*)&p[0] );
00075         // need to compute the angles
00076         // compute angles and the normal
00077         // CartVect p1(&coords[0]), p2(&coords[3]), p3(&coords[6]);
00078 
00079         CartVect AB( p[1] - p[0] );  //(p2 - p1);
00080         CartVect BC( p[2] - p[1] );  //(p3 - p2);
00081         CartVect normal = AB * BC;
00082         totArea += normal.length() / 2;
00083     }
00084     return totArea;
00085 }
00086 // these tags will be collected for deletion
00087 void SmoothFace::append_smooth_tags( std::vector< Tag >& smoothTags )
00088 {
00089     // these are created locally, for each smooth face
00090     smoothTags.push_back( _gradientTag );
00091     smoothTags.push_back( _planeTag );
00092 }
00093 void SmoothFace::bounding_box( double box_min[3], double box_max[3] )
00094 {
00095 
00096     for( int i = 0; i < 3; i++ )
00097     {
00098         box_min[i] = _minim[i];
00099         box_max[i] = _maxim[i];
00100     }
00101     // _minim, _maxim
00102 }
00103 
00104 void SmoothFace::move_to_surface( double& x, double& y, double& z )
00105 {
00106 
00107     CartVect loc2( x, y, z );
00108     bool trim    = false;  // is it needed?
00109     bool outside = true;
00110     CartVect closestPoint;
00111 
00112     ErrorCode rval = project_to_facets_main( loc2, trim, outside, &closestPoint, NULL );
00113     if( MB_SUCCESS != rval ) return;
00114     assert( rval == MB_SUCCESS );
00115     x = closestPoint[0];
00116     y = closestPoint[1];
00117     z = closestPoint[2];
00118 }
00119 /*
00120  void SmoothFace::move_to_surface(double& x, double& y, double& z,
00121  double& u_guess, double& v_guess) {
00122  if (debug_surf_eval1) {
00123  std::cout << "move_to_surface called." << std::endl;
00124  }
00125  }*/
00126 
00127 bool SmoothFace::normal_at( double x, double y, double z, double& nx, double& ny, double& nz )
00128 {
00129 
00130     CartVect loc2( x, y, z );
00131 
00132     bool trim    = false;  // is it needed?
00133     bool outside = true;
00134     // CartVect closestPoint;// not needed
00135     // not interested in normal
00136     CartVect normal;
00137     ErrorCode rval = project_to_facets_main( loc2, trim, outside, NULL, &normal );
00138     if( MB_SUCCESS != rval ) return false;
00139     assert( rval == MB_SUCCESS );
00140     nx = normal[0];
00141     ny = normal[1];
00142     nz = normal[2];
00143 
00144     return true;
00145 }
00146 
00147 ErrorCode SmoothFace::compute_control_points_on_edges( double min_dot, Tag edgeCtrlTag, Tag markTag )
00148 {
00149 
00150     _edgeCtrlTag = edgeCtrlTag;
00151     _markTag     = markTag;
00152 
00153     // now, compute control points for all edges that are not marked already (they are no on the
00154     // boundary!)
00155     for( Range::iterator it = _edges.begin(); it != _edges.end(); ++it )
00156     {
00157         EntityHandle edg = *it;
00158         // is the edge marked? already computed
00159         unsigned char tagVal = 0;
00160         _mb->tag_get_data( _markTag, &edg, 1, &tagVal );
00161         if( tagVal ) continue;
00162         // double min_dot;
00163         init_bezier_edge( edg, min_dot );
00164         tagVal = 1;
00165         _mb->tag_set_data( _markTag, &edg, 1, &tagVal );
00166     }
00167     return MB_SUCCESS;
00168 }
00169 
00170 int SmoothFace::init_gradient()
00171 {
00172     // first, create a Tag for gradient (or normal)
00173     // loop over all triangles in set, and modify the normals according to the angle as weight
00174     // get all the edges from this subset
00175     if( NULL == _mb ) return 1;  // fail
00176     _triangles.clear();
00177     ErrorCode rval = _mb->get_entities_by_type( _set, MBTRI, _triangles );
00178     if( MB_SUCCESS != rval ) return 1;
00179     // get a new range of edges, and decide the loops from here
00180     _edges.clear();
00181     rval = _mb->get_adjacencies( _triangles, 1, true, _edges, Interface::UNION );
00182     assert( rval == MB_SUCCESS );
00183 
00184     rval = _mb->get_adjacencies( _triangles, 0, false, _nodes, Interface::UNION );
00185     assert( rval == MB_SUCCESS );
00186 
00187     // initialize bounding box limits
00188     CartVect vert1;
00189     EntityHandle v1 = _nodes[0];  // first vertex
00190     _mb->get_coords( &v1, 1, (double*)&vert1 );
00191     _minim = vert1;
00192     _maxim = vert1;
00193 
00194     double defNormal[] = { 0., 0., 0. };
00195     // look for a tag name here that is definitely unique. We do not want the tags to interfere with
00196     // each other this normal will be for each node in a face some nodes have multiple normals, if
00197     // they are at the feature edges
00198     unsigned long setId = _mb->id_from_handle( _set );
00199     char name[50]       = { 0 };
00200     sprintf( name, "GRADIENT%lu",
00201              setId );  // name should be something like GRADIENT29, where 29 is the set ID of the face
00202     rval = _mb->tag_get_handle( name, 3, MB_TYPE_DOUBLE, _gradientTag, MB_TAG_DENSE | MB_TAG_CREAT, &defNormal );
00203     assert( rval == MB_SUCCESS );
00204 
00205     double defPlane[4] = { 0., 0., 1., 0. };
00206     // also define a plane tag ; this will be for each triangle
00207     char namePlaneTag[50] = { 0 };
00208     sprintf( namePlaneTag, "PLANE%lu", setId );
00209     rval = _mb->tag_get_handle( "PLANE", 4, MB_TYPE_DOUBLE, _planeTag, MB_TAG_DENSE | MB_TAG_CREAT, &defPlane );
00210     assert( rval == MB_SUCCESS );
00211     // the fourth double is for weight, accumulated at each vertex so far
00212     // maybe not needed in the end
00213     for( Range::iterator it = _triangles.begin(); it != _triangles.end(); ++it )
00214     {
00215         EntityHandle tria = *it;
00216         const EntityHandle* conn3;
00217         int nnodes;
00218         _mb->get_connectivity( tria, conn3, nnodes );
00219         if( nnodes != 3 ) return 1;  // error
00220         // double coords[9]; // store the coordinates for the nodes
00221         //_mb->get_coords(conn3, 3, coords);
00222         CartVect p[3];
00223         _mb->get_coords( conn3, 3, (double*)&p[0] );
00224         // need to compute the angles
00225         // compute angles and the normal
00226         // CartVect p1(&coords[0]), p2(&coords[3]), p3(&coords[6]);
00227 
00228         CartVect AB( p[1] - p[0] );  //(p2 - p1);
00229         CartVect BC( p[2] - p[1] );  //(p3 - p2);
00230         CartVect CA( p[0] - p[2] );  //(p1 - p3);
00231         double a[3];
00232         a[1]            = angle( AB, -BC );  // angle at B (p2), etc.
00233         a[2]            = angle( BC, -CA );
00234         a[0]            = angle( CA, -AB );
00235         CartVect normal = -AB * CA;
00236         normal.normalize();
00237         double plane[4];
00238 
00239         const double* coordNormal = normal.array();
00240 
00241         plane[0] = coordNormal[0];
00242         plane[1] = coordNormal[1];
00243         plane[2] = coordNormal[2];
00244         plane[3] = -normal % p[0];  // dot product
00245         // set the plane
00246         rval = _mb->tag_set_data( _planeTag, &tria, 1, plane );
00247         assert( rval == MB_SUCCESS );
00248 
00249         // add to each vertex the tag value the normal multiplied by the angle
00250         double values[9];
00251 
00252         _mb->tag_get_data( _gradientTag, conn3, 3, values );
00253         for( int i = 0; i < 3; i++ )
00254         {
00255             // values[4*i]+=a[i]; // first is the weight, which we do not really need
00256             values[3 * i + 0] += a[i] * coordNormal[0];
00257             values[3 * i + 1] += a[i] * coordNormal[1];
00258             values[3 * i + 2] += a[i] * coordNormal[2];
00259         }
00260 
00261         // reset those values
00262         _mb->tag_set_data( _gradientTag, conn3, 3, values );
00263     }
00264     // normalize the gradients at each node; maybe not needed here?
00265     // no, we will do it, it is important
00266     int numNodes      = _nodes.size();
00267     double* normalVal = new double[3 * numNodes];
00268     _mb->tag_get_data( _gradientTag, _nodes,
00269                        normalVal );  // get all the normal values at the _nodes
00270     for( int i = 0; i < numNodes; i++ )
00271     {
00272         CartVect p1( &normalVal[3 * i] );
00273         p1.normalize();
00274         p1.get( &normalVal[3 * i] );
00275     }
00276 
00277     // reset the normal values after normalization
00278     _mb->tag_set_data( _gradientTag, _nodes, normalVal );
00279     // print the loops size and some other stuff
00280     if( debug_surf_eval1 )
00281     {
00282         std::cout << " normals at  " << numNodes << " nodes" << std::endl;
00283         int i = 0;
00284         for( Range::iterator it = _nodes.begin(); it != _nodes.end(); ++it, i++ )
00285         {
00286             EntityHandle node = *it;
00287             std::cout << " Node id " << _mb->id_from_handle( node ) << "  " << normalVal[3 * i] << " "
00288                       << normalVal[3 * i + 1] << " " << normalVal[3 * i + 2] << std::endl;
00289         }
00290     }
00291 
00292     delete[] normalVal;
00293 
00294     return 0;
00295 }
00296 
00297 // init bezier edges
00298 // start copy
00299 //===========================================================================
00300 // Function Name: init_bezier_edge
00301 //
00302 // Member Type:  PRIVATE
00303 // Description:  compute the control points for an edge
00304 //===========================================================================
00305 ErrorCode SmoothFace::init_bezier_edge( EntityHandle edge, double )
00306 {
00307     // min dot was used for angle here
00308     // int stat = 0; // CUBIT_SUCCESS;
00309     // all boundaries will be simple, initially
00310     // we may complicate them afterwards
00311 
00312     CartVect ctrl_pts[3];
00313     int nnodes                = 0;
00314     const EntityHandle* conn2 = NULL;
00315     ErrorCode rval            = _mb->get_connectivity( edge, conn2, nnodes );
00316     assert( rval == MB_SUCCESS );
00317     if( MB_SUCCESS != rval ) return rval;
00318 
00319     assert( 2 == nnodes );
00320     // double coords[6]; // store the coordinates for the nodes
00321     CartVect P[2];
00322     // ErrorCode rval = _mb->get_coords(conn2, 2, coords);
00323     rval = _mb->get_coords( conn2, 2, (double*)&P[0] );
00324     assert( rval == MB_SUCCESS );
00325     if( MB_SUCCESS != rval ) return rval;
00326 
00327     // CartVect P0(&coords[0]);
00328     // CartVect P3(&coords[3]);
00329 
00330     // double normalVec[6];
00331     CartVect N[2];
00332     //_mb->tag_get_data(_gradientTag, conn2, 2, normalVec);
00333     rval = _mb->tag_get_data( _gradientTag, conn2, 2, (double*)&N[0] );
00334     assert( rval == MB_SUCCESS );
00335     if( MB_SUCCESS != rval ) return rval;
00336 
00337     CartVect T[2];  // T0, T3
00338 
00339     rval = _mb->tag_get_data( _tangentsTag, &edge, 1, &T[0] );
00340     assert( rval == MB_SUCCESS );
00341     if( MB_SUCCESS != rval ) return rval;
00342 
00343     rval = init_edge_control_points( P[0], P[1], N[0], N[1], T[0], T[1], ctrl_pts );
00344     assert( rval == MB_SUCCESS );
00345     if( MB_SUCCESS != rval ) return rval;
00346 
00347     rval = _mb->tag_set_data( _edgeCtrlTag, &edge, 1, &ctrl_pts[0] );
00348     assert( rval == MB_SUCCESS );
00349     if( MB_SUCCESS != rval ) return rval;
00350 
00351     if( debug_surf_eval1 )
00352     {
00353         std::cout << "edge: " << _mb->id_from_handle( edge ) << " tangents: " << T[0] << T[1] << std::endl;
00354         std::cout << "  points: " << P[0] << " " << P[1] << std::endl;
00355         std::cout << "  normals: " << N[0] << " " << N[1] << std::endl;
00356         std::cout << "  Control points  " << ctrl_pts[0] << " " << ctrl_pts[1] << " " << ctrl_pts[2] << std::endl;
00357     }
00358 
00359     return MB_SUCCESS;
00360 }
00361 
00362 ErrorCode SmoothFace::compute_tangents_for_each_edge()
00363 // they will be used for control points
00364 {
00365     double defTangents[6] = { 0., 0., 0., 0., 0., 0. };
00366     ErrorCode rval =
00367         _mb->tag_get_handle( "TANGENTS", 6, MB_TYPE_DOUBLE, _tangentsTag, MB_TAG_DENSE | MB_TAG_CREAT, &defTangents );
00368     if( MB_SUCCESS != rval ) return MB_FAILURE;
00369 
00370     // now, compute Tangents for all edges that are not on boundary, so they are not marked
00371     for( Range::iterator it = _edges.begin(); it != _edges.end(); ++it )
00372     {
00373         EntityHandle edg = *it;
00374 
00375         int nnodes;
00376         const EntityHandle* conn2;  //
00377         _mb->get_connectivity( edg, conn2, nnodes );
00378         assert( nnodes == 2 );
00379         CartVect P[2];  // store the coordinates for the nodes
00380         rval = _mb->get_coords( conn2, 2, (double*)&P[0] );
00381         if( MB_SUCCESS != rval ) return rval;
00382         assert( rval == MB_SUCCESS );
00383         CartVect T[2];
00384         T[0] = P[1] - P[0];
00385         T[0].normalize();
00386         T[1] = T[0];  //
00387         _mb->tag_set_data( _tangentsTag, &edg, 1,
00388                            (double*)&T[0] );  // set the tangents computed at every edge
00389     }
00390     return MB_SUCCESS;
00391 }
00392 // start copy
00393 //===========================================================================
00394 // Function Name: init_edge_control_points
00395 //
00396 // Member Type:  PRIVATE
00397 // Description:  compute the control points for an edge
00398 //===========================================================================
00399 ErrorCode SmoothFace::init_edge_control_points( CartVect& P0,
00400                                                 CartVect& P3,
00401                                                 CartVect& N0,
00402                                                 CartVect& N3,
00403                                                 CartVect& T0,
00404                                                 CartVect& T3,
00405                                                 CartVect* Pi )
00406 {
00407     CartVect Vi[4];
00408     Vi[0] = P0;
00409     Vi[3] = P3;
00410     CartVect P03( P3 - P0 );
00411     double di    = P03.length();
00412     double ai    = N0 % N3;  // this is the dot operator, the same as in cgm for CubitVector
00413     double ai0   = N0 % T0;
00414     double ai3   = N3 % T3;
00415     double denom = 4 - ai * ai;
00416     if( fabs( denom ) < 1e-20 )
00417     {
00418         return MB_FAILURE;  // CUBIT_FAILURE;
00419     }
00420     double row   = 6.0e0 * ( 2.0e0 * ai0 + ai * ai3 ) / denom;
00421     double omega = 6.0e0 * ( 2.0e0 * ai3 + ai * ai0 ) / denom;
00422     Vi[1]        = Vi[0] + ( di * ( ( ( 6.0e0 * T0 ) - ( ( 2.0e0 * row ) * N0 ) + ( omega * N3 ) ) / 18.0e0 ) );
00423     Vi[2]        = Vi[3] - ( di * ( ( ( 6.0e0 * T3 ) + ( row * N0 ) - ( ( 2.0e0 * omega ) * N3 ) ) / 18.0e0 ) );
00424     // CartVect Wi[3];
00425     // Wi[0] = Vi[1] - Vi[0];
00426     // Wi[1] = Vi[2] - Vi[1];
00427     // Wi[2] = Vi[3] - Vi[2];
00428 
00429     Pi[0] = 0.25 * Vi[0] + 0.75 * Vi[1];
00430     Pi[1] = 0.50 * Vi[1] + 0.50 * Vi[2];
00431     Pi[2] = 0.75 * Vi[2] + 0.25 * Vi[3];
00432 
00433     return MB_SUCCESS;
00434 }
00435 
00436 ErrorCode SmoothFace::find_edges_orientations( EntityHandle edges[3],
00437                                                const EntityHandle* conn3,
00438                                                int orient[3] )  // maybe we will set it?
00439 {
00440     // find the edge that is adjacent to 2 vertices at a time
00441     for( int i = 0; i < 3; i++ )
00442     {
00443         // edge 0 is 1-2, 1 is 3-1, 2 is 0-1
00444         EntityHandle v[2];
00445         v[0] = conn3[( i + 1 ) % 3];
00446         v[1] = conn3[( i + 2 ) % 3];
00447         std::vector< EntityHandle > adjacencies;
00448         // generate all edges for these two hexes
00449         ErrorCode rval = _mb->get_adjacencies( v, 2, 1, false, adjacencies, Interface::INTERSECT );
00450         if( MB_SUCCESS != rval ) return rval;
00451 
00452         // find the edge connected to both vertices, and then see its orientation
00453         assert( adjacencies.size() == 1 );
00454         const EntityHandle* conn2 = NULL;
00455         int nnodes                = 0;
00456         rval                      = _mb->get_connectivity( adjacencies[0], conn2, nnodes );
00457         assert( rval == MB_SUCCESS );
00458         assert( 2 == nnodes );
00459         edges[i] = adjacencies[0];
00460         // what is the story morning glory?
00461         if( conn2[0] == v[0] && conn2[1] == v[1] )
00462             orient[i] = 1;
00463         else if( conn2[0] == v[1] && conn2[1] == v[0] )
00464             orient[i] = -1;
00465         else
00466             return MB_FAILURE;
00467     }
00468     return MB_SUCCESS;
00469 }
00470 ErrorCode SmoothFace::compute_internal_control_points_on_facets( double, Tag facetCtrlTag, Tag facetEdgeCtrlTag )
00471 {
00472     // collect from each triangle the control points in order
00473     //
00474 
00475     _facetCtrlTag     = facetCtrlTag;
00476     _facetEdgeCtrlTag = facetEdgeCtrlTag;
00477 
00478     for( Range::iterator it = _triangles.begin(); it != _triangles.end(); ++it )
00479     {
00480         EntityHandle tri = *it;
00481         // first get connectivity, and the edges
00482         // we need a fast method to retrieve the adjacent edges to each triangle
00483         const EntityHandle* conn3;
00484         int nnodes;
00485         ErrorCode rval = _mb->get_connectivity( tri, conn3, nnodes );
00486         assert( MB_SUCCESS == rval );
00487         if( MB_SUCCESS != rval ) return rval;
00488         assert( 3 == nnodes );
00489 
00490         // would it be easier to do
00491         CartVect vNode[3];  // position at nodes
00492         rval = _mb->get_coords( conn3, 3, (double*)&vNode[0] );
00493         assert( MB_SUCCESS == rval );
00494         if( MB_SUCCESS != rval ) return rval;
00495 
00496         // get gradients (normal) at each node of triangle
00497         CartVect NN[3];
00498         rval = _mb->tag_get_data( _gradientTag, conn3, 3, &NN[0] );
00499         assert( MB_SUCCESS == rval );
00500         if( MB_SUCCESS != rval ) return rval;
00501 
00502         EntityHandle edges[3];
00503         int orient[3];  // + 1 or -1, if the edge is positive or negative within the face
00504         rval = find_edges_orientations( edges, conn3, orient );  // maybe we will set it?
00505         assert( MB_SUCCESS == rval );
00506         if( MB_SUCCESS != rval ) return rval;
00507         // maybe we will store some tags with edges and their orientation with respect to
00508         // a triangle;
00509         CartVect P[3][5];
00510         CartVect N[6], G[6];
00511         // create the linear array for control points on edges, for storage (expensive !!!)
00512         CartVect CP[9];
00513         int index = 0;
00514         // maybe store a tag / entity handle for edges?
00515         for( int i = 0; i < 3; i++ )
00516         {
00517             // populate P and N with the right vectors
00518             int i1       = ( i + 1 ) % 3;  // the first node of the edge
00519             int i2       = ( i + 2 ) % 3;  // the second node of the edge
00520             N[2 * i]     = NN[i1];
00521             N[2 * i + 1] = NN[i2];
00522             P[i][0]      = vNode[i1];
00523             rval         = _mb->tag_get_data( _edgeCtrlTag, &edges[i], 1, &( P[i][1] ) );
00524             // if sense is -1, swap 1 and 3 control points
00525             if( orient[i] == -1 )
00526             {
00527                 CartVect tmp;
00528                 tmp     = P[i][1];
00529                 P[i][1] = P[i][3];
00530                 P[i][3] = tmp;
00531             }
00532             P[i][4] = vNode[i2];
00533             for( int j = 1; j < 4; j++ )
00534                 CP[index++] = P[i][j];
00535 
00536             // the first edge control points
00537         }
00538 
00539         //  stat = facet->get_edge_control_points( P );
00540         init_facet_control_points( N, P, G );
00541         // what do we need to store in the tag control points?
00542         rval = _mb->tag_set_data( _facetCtrlTag, &tri, 1, &G[0] );
00543         assert( MB_SUCCESS == rval );
00544         if( MB_SUCCESS != rval ) return rval;
00545 
00546         // store here again the 9 control points on the edges
00547         rval = _mb->tag_set_data( _facetEdgeCtrlTag, &tri, 1, &CP[0] );
00548         assert( MB_SUCCESS == rval );
00549         if( MB_SUCCESS != rval ) return rval;
00550         // look at what we retrieve later
00551 
00552         // adjust the bounding box
00553         int j = 0;
00554         for( j = 0; j < 3; j++ )
00555             adjust_bounding_box( vNode[j] );
00556         // edge control points
00557         for( j = 0; j < 9; j++ )
00558             adjust_bounding_box( CP[j] );
00559         // internal facet control points
00560         for( j = 0; j < 6; j++ )
00561             adjust_bounding_box( G[j] );
00562     }
00563     return MB_SUCCESS;
00564 }
00565 void SmoothFace::adjust_bounding_box( CartVect& vect )
00566 {
00567     // _minim, _maxim
00568     for( int j = 0; j < 3; j++ )
00569     {
00570         if( _minim[j] > vect[j] ) _minim[j] = vect[j];
00571         if( _maxim[j] < vect[j] ) _maxim[j] = vect[j];
00572     }
00573 }
00574 //===============================================================
00575 ////Function Name: init_facet_control_points
00576 ////
00577 ////Member Type:  PRIVATE
00578 ////Description:  compute the control points for a facet
00579 ////===============================================================
00580 ErrorCode SmoothFace::init_facet_control_points( CartVect N[6],     // vertex normals (per edge)
00581                                                  CartVect P[3][5],  // edge control points
00582                                                  CartVect G[6] )    // return internal control points
00583 {
00584     CartVect Di[4], Ai[3], N0, N3, Vi[4], Wi[3];
00585     double denom;
00586     double lambda[2], mu[2];
00587 
00588     ErrorCode rval = MB_SUCCESS;
00589 
00590     for( int i = 0; i < 3; i++ )
00591     {
00592         N0    = N[i * 2];
00593         N3    = N[i * 2 + 1];
00594         Vi[0] = P[i][0];
00595         Vi[1] = ( P[i][1] - 0.25 * P[i][0] ) / 0.75;
00596         Vi[2] = ( P[i][3] - 0.25 * P[i][4] ) / 0.75;
00597         Vi[3] = P[i][4];
00598         Wi[0] = Vi[1] - Vi[0];
00599         Wi[1] = Vi[2] - Vi[1];
00600         Wi[2] = Vi[3] - Vi[2];
00601         Di[0] = P[( i + 2 ) % 3][3] - 0.5 * ( P[i][1] + P[i][0] );
00602         Di[3] = P[( i + 1 ) % 3][1] - 0.5 * ( P[i][4] + P[i][3] );
00603         Ai[0] = ( N0 * Wi[0] ) / Wi[0].length();
00604         Ai[2] = ( N3 * Wi[2] ) / Wi[2].length();
00605         Ai[1] = Ai[0] + Ai[2];
00606         denom = Ai[1].length();
00607         Ai[1] /= denom;
00608         lambda[0] = ( Di[0] % Wi[0] ) / ( Wi[0] % Wi[0] );
00609         lambda[1] = ( Di[3] % Wi[2] ) / ( Wi[2] % Wi[2] );
00610         mu[0]     = ( Di[0] % Ai[0] );
00611         mu[1]     = ( Di[3] % Ai[2] );
00612         G[i * 2]  = 0.5 * ( P[i][1] + P[i][2] ) + 0.66666666666666 * lambda[0] * Wi[1] +
00613                    0.33333333333333 * lambda[1] * Wi[0] + 0.66666666666666 * mu[0] * Ai[1] +
00614                    0.33333333333333 * mu[1] * Ai[0];
00615         G[i * 2 + 1] = 0.5 * ( P[i][2] + P[i][3] ) + 0.33333333333333 * lambda[0] * Wi[2] +
00616                        0.66666666666666 * lambda[1] * Wi[1] + 0.33333333333333 * mu[0] * Ai[2] +
00617                        0.66666666666666 * mu[1] * Ai[1];
00618     }
00619     return rval;
00620 }
00621 
00622 void SmoothFace::DumpModelControlPoints()
00623 {
00624     // here, we will dump all control points from edges and facets (6 control points for each facet)
00625     // we may also create some edges; maybe later...
00626     // create a point3D file
00627     // output a Point3D file (special visit format)
00628     unsigned long setId = _mb->id_from_handle( _set );
00629     char name[50]       = { 0 };
00630     sprintf( name, "%lucontrol.Point3D", setId );  // name should be something 2control.Point3D
00631     std::ofstream point3DFile;
00632     point3DFile.open( name );  //("control.Point3D");
00633     point3DFile << "# x y z \n";
00634     std::ofstream point3DEdgeFile;
00635     sprintf( name, "%lucontrolEdge.Point3D", setId );  //
00636     point3DEdgeFile.open( name );                      //("controlEdge.Point3D");
00637     point3DEdgeFile << "# x y z \n";
00638     std::ofstream smoothPoints;
00639     sprintf( name, "%lusmooth.Point3D", setId );  //
00640     smoothPoints.open( name );                    //("smooth.Point3D");
00641     smoothPoints << "# x y z \n";
00642     CartVect controlPoints[3];  // edge control points
00643     for( Range::iterator it = _edges.begin(); it != _edges.end(); ++it )
00644     {
00645         EntityHandle edge = *it;
00646 
00647         _mb->tag_get_data( _edgeCtrlTag, &edge, 1, (double*)&controlPoints[0] );
00648         for( int i = 0; i < 3; i++ )
00649         {
00650             CartVect& c = controlPoints[i];
00651             point3DEdgeFile << std::setprecision( 11 ) << c[0] << " " << c[1] << " " << c[2] << " \n";
00652         }
00653     }
00654     CartVect controlTriPoints[6];  // triangle control points
00655     CartVect P_facet[3];           // result in 3 "mid" control points
00656     for( Range::iterator it2 = _triangles.begin(); it2 != _triangles.end(); ++it2 )
00657     {
00658         EntityHandle tri = *it2;
00659 
00660         _mb->tag_get_data( _facetCtrlTag, &tri, 1, (double*)&controlTriPoints[0] );
00661 
00662         // draw a line of points between pairs of control points
00663         int numPoints = 7;
00664         for( int n = 0; n < numPoints; n++ )
00665         {
00666             double a = 1. * n / ( numPoints - 1 );
00667             double b = 1.0 - a;
00668 
00669             P_facet[0] = a * controlTriPoints[3] + b * controlTriPoints[4];
00670             // 1,2,1
00671             P_facet[1] = a * controlTriPoints[0] + b * controlTriPoints[5];
00672             // 1,1,2
00673             P_facet[2] = a * controlTriPoints[1] + b * controlTriPoints[2];
00674             for( int i = 0; i < 3; i++ )
00675             {
00676                 CartVect& c = P_facet[i];
00677                 point3DFile << std::setprecision( 11 ) << c[0] << " " << c[1] << " " << c[2] << " \n";
00678             }
00679         }
00680 
00681         // evaluate for each triangle a lattice of points
00682         int N = 40;
00683         for( int k = 0; k <= N; k++ )
00684         {
00685             for( int m = 0; m <= N - k; m++ )
00686             {
00687                 int n = N - m - k;
00688                 CartVect areacoord( 1. * k / N, 1. * m / N, 1. * n / N );
00689                 CartVect pt;
00690                 eval_bezier_patch( tri, areacoord, pt );
00691                 smoothPoints << std::setprecision( 11 ) << pt[0] << " " << pt[1] << " " << pt[2] << " \n";
00692             }
00693         }
00694     }
00695     point3DFile.close();
00696     smoothPoints.close();
00697     point3DEdgeFile.close();
00698     return;
00699 }
00700 //===========================================================================
00701 // Function Name: evaluate_single
00702 //
00703 // Member Type:  PUBLIC
00704 // Description:  evaluate edge not associated with a facet (this is used
00705 // by camal edge mesher!!!)
00706 // Note:         t is a value from 0 to 1, for us
00707 //===========================================================================
00708 ErrorCode SmoothFace::evaluate_smooth_edge( EntityHandle eh, double& tt, CartVect& outv )
00709 {
00710     CartVect P[2];              // P0 and P1
00711     CartVect controlPoints[3];  // edge control points
00712     double t4, t3, t2, one_minus_t, one_minus_t2, one_minus_t3, one_minus_t4;
00713 
00714     // project the position to the linear edge
00715     // t is from 0 to 1 only!!
00716     // double tt = (t + 1) * 0.5;
00717     if( tt <= 0.0 ) tt = 0.0;
00718     if( tt >= 1.0 ) tt = 1.0;
00719 
00720     int nnodes                = 0;
00721     const EntityHandle* conn2 = NULL;
00722     ErrorCode rval            = _mb->get_connectivity( eh, conn2, nnodes );
00723     assert( rval == MB_SUCCESS );
00724     if( MB_SUCCESS != rval ) return rval;
00725 
00726     rval = _mb->get_coords( conn2, 2, (double*)&P[0] );
00727     assert( rval == MB_SUCCESS );
00728     if( MB_SUCCESS != rval ) return rval;
00729 
00730     rval = _mb->tag_get_data( _edgeCtrlTag, &eh, 1, (double*)&controlPoints[0] );
00731     assert( rval == MB_SUCCESS );
00732     if( MB_SUCCESS != rval ) return rval;
00733 
00734     t2           = tt * tt;
00735     t3           = t2 * tt;
00736     t4           = t3 * tt;
00737     one_minus_t  = 1. - tt;
00738     one_minus_t2 = one_minus_t * one_minus_t;
00739     one_minus_t3 = one_minus_t2 * one_minus_t;
00740     one_minus_t4 = one_minus_t3 * one_minus_t;
00741 
00742     outv = one_minus_t4 * P[0] + 4. * one_minus_t3 * tt * controlPoints[0] + 6. * one_minus_t2 * t2 * controlPoints[1] +
00743            4. * one_minus_t * t3 * controlPoints[2] + t4 * P[1];
00744 
00745     return MB_SUCCESS;
00746 }
00747 
00748 ErrorCode SmoothFace::eval_bezier_patch( EntityHandle tri, CartVect& areacoord, CartVect& pt )
00749 {
00750     //
00751     // interpolate internal control points
00752 
00753     CartVect gctrl_pts[6];
00754     // get the control points  facet->get_control_points( gctrl_pts );
00755     // init_facet_control_points( N, P, G) ;
00756     // what do we need to store in the tag control points?
00757     ErrorCode rval = _mb->tag_get_data( _facetCtrlTag, &tri, 1, &gctrl_pts[0] );  // get all 6 control points
00758     assert( MB_SUCCESS == rval );
00759     if( MB_SUCCESS != rval ) return rval;
00760     const EntityHandle* conn3 = NULL;
00761     int nnodes                = 0;
00762     rval                      = _mb->get_connectivity( tri, conn3, nnodes );
00763     assert( MB_SUCCESS == rval );
00764 
00765     CartVect vN[3];
00766     _mb->get_coords( conn3, 3, (double*)&vN[0] );  // fill the coordinates of the vertices
00767 
00768     if( fabs( areacoord[1] + areacoord[2] ) < 1.0e-6 )
00769     {
00770         pt = vN[0];
00771         return MB_SUCCESS;
00772     }
00773     if( fabs( areacoord[0] + areacoord[2] ) < 1.0e-6 )
00774     {
00775         pt = vN[0];
00776         return MB_SUCCESS;
00777     }
00778     if( fabs( areacoord[0] + areacoord[1] ) < 1.0e-6 )
00779     {
00780         pt = vN[0];
00781         return MB_SUCCESS;
00782     }
00783 
00784     CartVect P_facet[3];
00785     // 2,1,1
00786     P_facet[0] =
00787         ( 1.0e0 / ( areacoord[1] + areacoord[2] ) ) * ( areacoord[1] * gctrl_pts[3] + areacoord[2] * gctrl_pts[4] );
00788     // 1,2,1
00789     P_facet[1] =
00790         ( 1.0e0 / ( areacoord[0] + areacoord[2] ) ) * ( areacoord[0] * gctrl_pts[0] + areacoord[2] * gctrl_pts[5] );
00791     // 1,1,2
00792     P_facet[2] =
00793         ( 1.0e0 / ( areacoord[0] + areacoord[1] ) ) * ( areacoord[0] * gctrl_pts[1] + areacoord[1] * gctrl_pts[2] );
00794 
00795     // sum the contribution from each of the control points
00796 
00797     pt = CartVect( 0. );  // set all to 0, we start adding / accumulating different parts
00798     // first edge is from node 0 to 1, index 2 in
00799 
00800     // retrieve the points, in order, and the control points on edges
00801 
00802     // store here again the 9 control points on the edges
00803     CartVect CP[9];
00804     rval = _mb->tag_get_data( _facetEdgeCtrlTag, &tri, 1, &CP[0] );
00805     assert( MB_SUCCESS == rval );
00806 
00807     // CubitFacetEdge *edge;
00808     // edge = facet->edge(2);! start with edge 2, from 0-1
00809     int k = 0;
00810     CartVect ctrl_pts[5];
00811     // edge->control_points(facet, ctrl_pts);
00812     ctrl_pts[0] = vN[0];  //
00813     for( k = 1; k < 4; k++ )
00814         ctrl_pts[k] = CP[k + 5];  // for edge index 2
00815     ctrl_pts[4] = vN[1];          //
00816 
00817     // i=4; j=0; k=0;
00818     double B = mbquart( areacoord[0] );
00819     pt += B * ctrl_pts[0];
00820 
00821     // i=3; j=1; k=0;
00822     B = 4.0 * mbcube( areacoord[0] ) * areacoord[1];
00823     pt += B * ctrl_pts[1];
00824 
00825     // i=2; j=2; k=0;
00826     B = 6.0 * mbsqr( areacoord[0] ) * mbsqr( areacoord[1] );
00827     pt += B * ctrl_pts[2];
00828 
00829     // i=1; j=3; k=0;
00830     B = 4.0 * areacoord[0] * mbcube( areacoord[1] );
00831     pt += B * ctrl_pts[3];
00832 
00833     // edge = facet->edge(0);
00834     // edge->control_points(facet, ctrl_pts);
00835     // edge index 0, from 1 to 2
00836     ctrl_pts[0] = vN[1];  //
00837     for( k = 1; k < 4; k++ )
00838         ctrl_pts[k] = CP[k - 1];  // for edge index 0
00839     ctrl_pts[4] = vN[2];          //
00840 
00841     // i=0; j=4; k=0;
00842     B = mbquart( areacoord[1] );
00843     pt += B * ctrl_pts[0];
00844 
00845     // i=0; j=3; k=1;
00846     B = 4.0 * mbcube( areacoord[1] ) * areacoord[2];
00847     pt += B * ctrl_pts[1];
00848 
00849     // i=0; j=2; k=2;
00850     B = 6.0 * mbsqr( areacoord[1] ) * mbsqr( areacoord[2] );
00851     pt += B * ctrl_pts[2];
00852 
00853     // i=0; j=1; k=3;
00854     B = 4.0 * areacoord[1] * mbcube( areacoord[2] );
00855     pt += B * ctrl_pts[3];
00856 
00857     // edge = facet->edge(1);
00858     // edge->control_points(facet, ctrl_pts);
00859     // edge index 1, from 2 to 0
00860     ctrl_pts[0] = vN[2];  //
00861     for( k = 1; k < 4; k++ )
00862         ctrl_pts[k] = CP[k + 2];  // for edge index 0
00863     ctrl_pts[4] = vN[0];          //
00864 
00865     // i=0; j=0; k=4;
00866     B = mbquart( areacoord[2] );
00867     pt += B * ctrl_pts[0];
00868 
00869     // i=1; j=0; k=3;
00870     B = 4.0 * areacoord[0] * mbcube( areacoord[2] );
00871     pt += B * ctrl_pts[1];
00872 
00873     // i=2; j=0; k=2;
00874     B = 6.0 * mbsqr( areacoord[0] ) * mbsqr( areacoord[2] );
00875     pt += B * ctrl_pts[2];
00876 
00877     // i=3; j=0; k=1;
00878     B = 4.0 * mbcube( areacoord[0] ) * areacoord[2];
00879     pt += B * ctrl_pts[3];
00880 
00881     // i=2; j=1; k=1;
00882     B = 12.0 * mbsqr( areacoord[0] ) * areacoord[1] * areacoord[2];
00883     pt += B * P_facet[0];
00884 
00885     // i=1; j=2; k=1;
00886     B = 12.0 * areacoord[0] * mbsqr( areacoord[1] ) * areacoord[2];
00887     pt += B * P_facet[1];
00888 
00889     // i=1; j=1; k=2;
00890     B = 12.0 * areacoord[0] * areacoord[1] * mbsqr( areacoord[2] );
00891     pt += B * P_facet[2];
00892 
00893     return MB_SUCCESS;
00894 }
00895 
00896 //===========================================================================
00897 // Function Name: project_to_facet_plane
00898 //
00899 // Member Type:  PUBLIC
00900 // Descriptoin:  Project a point to the plane of a facet
00901 //===========================================================================
00902 void SmoothFace::project_to_facet_plane( EntityHandle tri,
00903                                          CartVect& pt,
00904                                          CartVect& point_on_plane,
00905                                          double& dist_to_plane )
00906 {
00907     double plane[4];
00908 
00909     ErrorCode rval = _mb->tag_get_data( _planeTag, &tri, 1, plane );
00910     if( MB_SUCCESS != rval ) return;
00911     assert( rval == MB_SUCCESS );
00912     // _planeTag
00913     CartVect normal( &plane[0] );  // just first 3 components are used
00914 
00915     double dist    = normal % pt + plane[3];  // coeff d is saved!!!
00916     dist_to_plane  = fabs( dist );
00917     point_on_plane = pt - dist * normal;
00918 
00919     return;
00920 }
00921 
00922 //===========================================================================
00923 // Function Name: facet_area_coordinate
00924 //
00925 // Member Type:  PUBLIC
00926 // Descriptoin:  Determine the area coordinates of a point on the plane
00927 //              of a facet
00928 //===========================================================================
00929 void SmoothFace::facet_area_coordinate( EntityHandle facet, CartVect& pt_on_plane, CartVect& areacoord )
00930 {
00931 
00932     const EntityHandle* conn3 = NULL;
00933     int nnodes                = 0;
00934     ErrorCode rval            = _mb->get_connectivity( facet, conn3, nnodes );
00935     assert( MB_SUCCESS == rval );
00936     if( rval )
00937     {
00938     }  // empty statement to prevent compiler warning
00939 
00940     // double coords[9]; // store the coordinates for the nodes
00941     //_mb->get_coords(conn3, 3, coords);
00942     CartVect p[3];
00943     rval = _mb->get_coords( conn3, 3, (double*)&p[0] );
00944     assert( MB_SUCCESS == rval );
00945     if( rval )
00946     {
00947     }  // empty statement to prevent compiler warning
00948     double plane[4];
00949 
00950     rval = _mb->tag_get_data( _planeTag, &facet, 1, plane );
00951     assert( rval == MB_SUCCESS );
00952     if( rval )
00953     {
00954     }                              // empty statement to prevent compiler warning
00955     CartVect normal( &plane[0] );  // just first 3 components are used
00956 
00957     double area2;
00958 
00959     double tol = GEOMETRY_RESABS * 1.e-5;  // 1.e-11;
00960 
00961     CartVect v1( p[1] - p[0] );
00962     CartVect v2( p[2] - p[0] );
00963 
00964     area2 = ( v1 * v2 ).length_squared();  // the same for CartVect
00965     if( area2 < 100 * tol )
00966     {
00967         tol = .01 * area2;
00968     }
00969     CartVect absnorm( fabs( normal[0] ), fabs( normal[1] ), fabs( normal[2] ) );
00970 
00971     // project to the closest coordinate plane so we only have to do this in 2D
00972 
00973     if( absnorm[0] >= absnorm[1] && absnorm[0] >= absnorm[2] )
00974     {
00975         area2 = determ3( p[0][1], p[0][2], p[1][1], p[1][2], p[2][1], p[2][2] );
00976         if( fabs( area2 ) < tol )
00977         {
00978             areacoord = CartVect( -std::numeric_limits< double >::min() );  // .set(
00979                                                                             // -std::numeric_limits<double>::min(),
00980                                                                             // -std::numeric_limits<double>::min(),
00981                                                                             // -std::numeric_limits<double>::min() );
00982         }
00983         else if( within_tolerance( p[0], pt_on_plane, GEOMETRY_RESABS ) )
00984         {
00985             areacoord = CartVect( 1., 0., 0. );  //.set( 1.0, 0.0, 0.0 );
00986         }
00987         else if( within_tolerance( p[1], pt_on_plane, GEOMETRY_RESABS ) )
00988         {
00989             areacoord = CartVect( 0., 1., 0. );  //.set( 0.0, 1.0, 0.0 );
00990         }
00991         else if( within_tolerance( p[2], pt_on_plane, GEOMETRY_RESABS ) )
00992         {
00993             areacoord = CartVect( 0., 0., 1. );  //.set( 0.0, 0.0, 1.0 );
00994         }
00995         else
00996         {
00997 
00998             areacoord[0] = determ3( pt_on_plane[1], pt_on_plane[2], p[1][1], p[1][2], p[2][1], p[2][2] ) / area2;
00999 
01000             areacoord[1] = determ3( p[0][1], p[0][2], pt_on_plane[1], pt_on_plane[2], p[2][1], p[2][2] ) / area2;
01001 
01002             areacoord[2] = determ3( p[0][1], p[0][2], p[1][1], p[1][2], pt_on_plane[1], pt_on_plane[2] ) / area2;
01003         }
01004     }
01005     else if( absnorm[1] >= absnorm[0] && absnorm[1] >= absnorm[2] )
01006     {
01007 
01008         area2 = determ3( p[0][0], p[0][2], p[1][0], p[1][2], p[2][0], p[2][2] );
01009         if( fabs( area2 ) < tol )
01010         {
01011             areacoord = CartVect( -std::numeric_limits< double >::min() );  //.set(
01012                                                                             //-std::numeric_limits<double>::min(),
01013                                                                             //-std::numeric_limits<double>::min(),
01014                                                                             //-std::numeric_limits<double>::min() );
01015         }
01016         else if( within_tolerance( p[0], pt_on_plane, GEOMETRY_RESABS ) )
01017         {
01018             areacoord = CartVect( 1., 0., 0. );  //.set( 1.0, 0.0, 0.0 );
01019         }
01020         else if( within_tolerance( p[1], pt_on_plane, GEOMETRY_RESABS ) )
01021         {
01022             areacoord = CartVect( 0., 1., 0. );  //.set( 0.0, 1.0, 0.0 );
01023         }
01024         else if( within_tolerance( p[2], pt_on_plane, GEOMETRY_RESABS ) )
01025         {
01026             areacoord = CartVect( 0., 0., 1. );  //.set( 0.0, 0.0, 1.0 );
01027         }
01028         else
01029         {
01030 
01031             areacoord[0] = determ3( pt_on_plane[0], pt_on_plane[2], p[1][0], p[1][2], p[2][0], p[2][2] ) / area2;
01032 
01033             areacoord[1] = determ3( p[0][0], p[0][2], pt_on_plane[0], pt_on_plane[2], p[2][0], p[2][2] ) / area2;
01034 
01035             areacoord[2] = determ3( p[0][0], p[0][2], p[1][0], p[1][2], pt_on_plane[0], pt_on_plane[2] ) / area2;
01036         }
01037     }
01038     else
01039     {
01040         /*area2 = determ3(pt0->x(), pt0->y(),
01041          pt1->x(), pt1->y(),
01042          pt2->x(), pt2->y());*/
01043         area2 = determ3( p[0][0], p[0][1], p[1][0], p[1][1], p[2][0], p[2][1] );
01044         if( fabs( area2 ) < tol )
01045         {
01046             areacoord = CartVect( -std::numeric_limits< double >::min() );  //.set(
01047                                                                             //-std::numeric_limits<double>::min(),
01048                                                                             //-std::numeric_limits<double>::min(),
01049                                                                             //-std::numeric_limits<double>::min() );
01050         }
01051         else if( within_tolerance( p[0], pt_on_plane, GEOMETRY_RESABS ) )
01052         {
01053             areacoord = CartVect( 1., 0., 0. );  //.set( 1.0, 0.0, 0.0 );
01054         }
01055         else if( within_tolerance( p[1], pt_on_plane, GEOMETRY_RESABS ) )
01056         {
01057             areacoord = CartVect( 0., 1., 0. );  //.set( 0.0, 1.0, 0.0 );
01058         }
01059         else if( within_tolerance( p[2], pt_on_plane, GEOMETRY_RESABS ) )
01060         {
01061             areacoord = CartVect( 0., 0., 1. );  //.set( 0.0, 0.0, 1.0 );
01062         }
01063         else
01064         {
01065 
01066             areacoord[0] = determ3( pt_on_plane[0], pt_on_plane[1], p[1][0], p[1][1], p[2][0], p[2][1] ) / area2;
01067 
01068             areacoord[1] = determ3( p[0][0], p[0][1], pt_on_plane[0], pt_on_plane[1], p[2][0], p[2][1] ) / area2;
01069 
01070             areacoord[2] = determ3( p[0][0], p[0][1], p[1][0], p[1][1], pt_on_plane[0], pt_on_plane[1] ) / area2;
01071         }
01072     }
01073 }
01074 
01075 ErrorCode SmoothFace::project_to_facets_main( CartVect& this_point,
01076                                               bool trim,
01077                                               bool& outside,
01078                                               CartVect* closest_point_ptr,
01079                                               CartVect* normal_ptr )
01080 {
01081 
01082     // if there are a lot of facets on this surface - use the OBB search first
01083     // to narrow the selection
01084 
01085     _evaluationsCounter++;
01086     double tolerance = 1.e-5;
01087     std::vector< EntityHandle > facets_out;
01088     // we will start with a list of facets anyway, the best among them wins
01089     ErrorCode rval =
01090         _my_geomTopoTool->obb_tree()->closest_to_location( (double*)&this_point, _obb_root, tolerance, facets_out );
01091     if( MB_SUCCESS != rval ) return rval;
01092 
01093     int interpOrder        = 4;
01094     double compareTol      = 1.e-5;
01095     EntityHandle lastFacet = facets_out.front();
01096     rval = project_to_facets( facets_out, lastFacet, interpOrder, compareTol, this_point, trim, outside,
01097                               closest_point_ptr, normal_ptr );
01098 
01099     return rval;
01100 }
01101 ErrorCode SmoothFace::project_to_facets( std::vector< EntityHandle >& facet_list,
01102                                          EntityHandle& lastFacet,
01103                                          int interpOrder,
01104                                          double compareTol,
01105                                          CartVect& this_point,
01106                                          bool,
01107                                          bool& outside,
01108                                          CartVect* closest_point_ptr,
01109                                          CartVect* normal_ptr )
01110 {
01111 
01112     bool outside_facet      = false;
01113     bool best_outside_facet = true;
01114     double mindist          = 1.e20;
01115     CartVect close_point, best_point( mindist, mindist, mindist ), best_areacoord;
01116     EntityHandle best_facet = 0L;  // no best facet found yet
01117     EntityHandle facet;
01118     assert( facet_list.size() > 0 );
01119 
01120     double big_dist = compareTol * 1.0e3;
01121 
01122     // from the list of close facets, determine the closest point
01123     for( size_t i = 0; i < facet_list.size(); i++ )
01124     {
01125         facet = facet_list[i];
01126         CartVect pt_on_plane;
01127         double dist_to_plane;
01128         project_to_facet_plane( facet, this_point, pt_on_plane, dist_to_plane );
01129 
01130         CartVect areacoord;
01131         // CartVect close_point;
01132         facet_area_coordinate( facet, pt_on_plane, areacoord );
01133         if( interpOrder != 0 )
01134         {
01135 
01136             // modify the areacoord - project to the bezier patch- snaps to the
01137             // edge of the patch if necessary
01138 
01139             if( project_to_facet( facet, this_point, areacoord, close_point, outside_facet, compareTol ) != MB_SUCCESS )
01140             {
01141                 return MB_FAILURE;
01142             }
01143             // if (closest_point_ptr)
01144             //*closest_point_ptr = close_point;
01145         }
01146         // keep track of the minimum distance
01147 
01148         double dist = ( close_point - this_point ).length();  // close_point.distance_between(this_point);
01149         if( ( best_outside_facet == outside_facet && dist < mindist ) ||
01150             ( best_outside_facet && !outside_facet && ( dist < big_dist || best_facet == 0L /*!best_facet*/ ) ) )
01151         {
01152             mindist            = dist;
01153             best_point         = close_point;
01154             best_facet         = facet;
01155             best_areacoord     = areacoord;
01156             best_outside_facet = outside_facet;
01157 
01158             if( dist < compareTol )
01159             {
01160                 break;
01161             }
01162             big_dist = 10.0 * mindist;
01163         }
01164         // facet->marked(1);
01165         // used_facet_list.append(facet);
01166     }
01167 
01168     if( normal_ptr )
01169     {
01170         CartVect normal;
01171         if( eval_bezier_patch_normal( best_facet, best_areacoord, normal ) != MB_SUCCESS )
01172         {
01173             return MB_FAILURE;
01174         }
01175         *normal_ptr = normal;
01176     }
01177 
01178     if( closest_point_ptr )
01179     {
01180         *closest_point_ptr = best_point;
01181     }
01182 
01183     outside   = best_outside_facet;
01184     lastFacet = best_facet;
01185 
01186     return MB_SUCCESS;
01187     // end copy
01188 }
01189 
01190 //===========================================================================
01191 // Function Name: project_to_patch
01192 //
01193 // Member Type:  PUBLIC
01194 // Description:  Project a point to a bezier patch. Pass in the areacoord
01195 //              of the point projected to the linear facet.  Function
01196 //              assumes that the point is contained within the patch -
01197 //              if not, it will project to one of its edges.
01198 //===========================================================================
01199 ErrorCode SmoothFace::project_to_patch( EntityHandle facet,   // (IN) the facet where the patch is defined
01200                                         CartVect& ac,         // (IN) area coordinate initial guess (from linear facet)
01201                                         CartVect& pt,         // (IN) point we are projecting to patch
01202                                         CartVect& eval_pt,    // (OUT) The projected point
01203                                         CartVect* eval_norm,  // (OUT) normal at evaluated point
01204                                         bool& outside,        // (OUT) the closest point on patch to pt is on an edge
01205                                         double compare_tol,   // (IN) comparison tolerance
01206                                         int edge_id )         // (IN) only used if this is to be projected to one
01207 //      of the edges.  Otherwise, should be -1
01208 {
01209     ErrorCode status = MB_SUCCESS;
01210 
01211     // see if we are at a vertex
01212 
01213 #define INCR 0.01
01214     const double tol = compare_tol;
01215 
01216     if( is_at_vertex( facet, pt, ac, compare_tol, eval_pt, eval_norm ) )
01217     {
01218         outside = false;
01219         return MB_SUCCESS;
01220     }
01221 
01222     // check if the start ac is inside the patch -if not, then move it there
01223 
01224     int nout          = 0;
01225     const double atol = 0.001;
01226     if( move_ac_inside( ac, atol ) ) nout++;
01227 
01228     int diverge = 0;
01229     int iter    = 0;
01230     CartVect newpt;
01231     eval_bezier_patch( facet, ac, newpt );
01232     CartVect move   = pt - newpt;
01233     double lastdist = move.length();
01234     double bestdist = lastdist;
01235     CartVect bestac = ac;
01236     CartVect bestpt = newpt;
01237     CartVect bestnorm( 0, 0, 0 );
01238 
01239     // If we are already close enough, then return now
01240 
01241     if( lastdist <= tol && !eval_norm && nout == 0 )
01242     {
01243         eval_pt = pt;
01244         outside = false;
01245         return status;
01246     }
01247 
01248     double ratio, mag, umove, vmove, det, distnew, movedist;
01249     CartVect lastpt = newpt;
01250     CartVect lastac = ac;
01251     CartVect norm;
01252     CartVect xpt, ypt, zpt, xac, yac, zac, xvec, yvec, zvec;
01253     CartVect du, dv, newac;
01254     bool done = false;
01255     while( !done )
01256     {
01257 
01258         // We will be locating the projected point within the u,v,w coordinate
01259         // system of the triangular bezier patch.  Since u+v+w=1, the components
01260         // are not linearly independent.  We will choose only two of the
01261         // coordinates to use and compute the third.
01262 
01263         int system;
01264         if( lastac[0] >= lastac[1] && lastac[0] >= lastac[2] )
01265         {
01266             system = 0;
01267         }
01268         else if( lastac[1] >= lastac[2] )
01269         {
01270             system = 1;
01271         }
01272         else
01273         {
01274             system = 2;
01275         }
01276 
01277         // compute the surface derivatives with respect to each
01278         // of the barycentric coordinates
01279 
01280         if( system == 1 || system == 2 )
01281         {
01282             xac[0] = lastac[0] + INCR;  // xac.x( lastac.x() + INCR );
01283             if( lastac[1] + lastac[2] == 0.0 ) return MB_FAILURE;
01284             ratio  = lastac[2] / ( lastac[1] + lastac[2] );  // ratio = lastac.z() / (lastac.y() + lastac.z());
01285             xac[1] = ( 1.0 - xac[0] ) * ( 1.0 - ratio );     // xac.y( (1.0 - xac.x()) * (1.0 - ratio) );
01286             xac[2] = 1.0 - xac[0] - xac[1];                  // xac.z( 1.0 - xac.x() - xac.y() );
01287             eval_bezier_patch( facet, xac, xpt );
01288             xvec = xpt - lastpt;
01289             xvec /= INCR;
01290         }
01291         if( system == 0 || system == 2 )
01292         {
01293             yac[1] = ( lastac[1] + INCR );      // yac.y( lastac.y() + INCR );
01294             if( lastac[0] + lastac[2] == 0.0 )  // if (lastac.x() + lastac.z() == 0.0)
01295                 return MB_FAILURE;
01296             ratio  = lastac[2] / ( lastac[0] + lastac[2] );   // ratio = lastac.z() / (lastac.x() + lastac.z());
01297             yac[0] = ( ( 1.0 - yac[1] ) * ( 1.0 - ratio ) );  // yac.x( (1.0 - yac.y()) * (1.0 - ratio) );
01298             yac[2] = ( 1.0 - yac[0] - yac[1] );               // yac.z( 1.0 - yac.x() - yac.y() );
01299             eval_bezier_patch( facet, yac, ypt );
01300             yvec = ypt - lastpt;
01301             yvec /= INCR;
01302         }
01303         if( system == 0 || system == 1 )
01304         {
01305             zac[2] = ( lastac[2] + INCR );      // zac.z( lastac.z() + INCR );
01306             if( lastac[0] + lastac[1] == 0.0 )  // if (lastac.x() + lastac.y() == 0.0)
01307                 return MB_FAILURE;
01308             ratio  = lastac[1] / ( lastac[0] + lastac[1] );   // ratio = lastac.y() / (lastac.x() + lastac.y());
01309             zac[0] = ( ( 1.0 - zac[2] ) * ( 1.0 - ratio ) );  // zac.x( (1.0 - zac.z()) * (1.0 - ratio) );
01310             zac[1] = ( 1.0 - zac[0] - zac[2] );               // zac.y( 1.0 - zac.x() - zac.z() );
01311             eval_bezier_patch( facet, zac, zpt );
01312             zvec = zpt - lastpt;
01313             zvec /= INCR;
01314         }
01315 
01316         // compute the surface normal
01317 
01318         switch( system )
01319         {
01320             case 0:
01321                 du = yvec;
01322                 dv = zvec;
01323                 break;
01324             case 1:
01325                 du = zvec;
01326                 dv = xvec;
01327                 break;
01328             case 2:
01329                 du = xvec;
01330                 dv = yvec;
01331                 break;
01332         }
01333         norm = du * dv;
01334         mag  = norm.length();
01335         if( mag < DBL_EPSILON )
01336         {
01337             return MB_FAILURE;
01338             // do something else here (it is likely a flat triangle -
01339             // so try evaluating just an edge of the bezier patch)
01340         }
01341         norm /= mag;
01342         if( iter == 0 ) bestnorm = norm;
01343 
01344         // project the move vector to the tangent plane
01345 
01346         move = ( norm * move ) * norm;
01347 
01348         // compute an equivalent u-v-w vector
01349 
01350         CartVect absnorm( fabs( norm[0] ), fabs( norm[1] ), fabs( norm[2] ) );
01351         if( absnorm[2] >= absnorm[1] && absnorm[2] >= absnorm[0] )
01352         {
01353             det = du[0] * dv[1] - dv[0] * du[1];
01354             if( fabs( det ) <= DBL_EPSILON )
01355             {
01356                 return MB_FAILURE;  // do something else here
01357             }
01358             umove = ( move[0] * dv[1] - dv[0] * move[1] ) / det;
01359             vmove = ( du[0] * move[1] - move[0] * du[1] ) / det;
01360         }
01361         else if( absnorm[1] >= absnorm[2] && absnorm[1] >= absnorm[0] )
01362         {
01363             det = du[0] * dv[2] - dv[0] * du[2];
01364             if( fabs( det ) <= DBL_EPSILON )
01365             {
01366                 return MB_FAILURE;
01367             }
01368             umove = ( move[0] * dv[2] - dv[0] * move[2] ) / det;
01369             vmove = ( du[0] * move[2] - move[0] * du[2] ) / det;
01370         }
01371         else
01372         {
01373             det = du[1] * dv[2] - dv[1] * du[2];
01374             if( fabs( det ) <= DBL_EPSILON )
01375             {
01376                 return MB_FAILURE;
01377             }
01378             umove = ( move[1] * dv[2] - dv[1] * move[2] ) / det;
01379             vmove = ( du[1] * move[2] - move[1] * du[2] ) / det;
01380         }
01381 
01382         /* === compute the new u-v coords and evaluate surface at new location */
01383 
01384         switch( system )
01385         {
01386             case 0:
01387                 newac[1] = ( lastac[1] + umove );          // newac.y( lastac.y() + umove );
01388                 newac[2] = ( lastac[2] + vmove );          // newac.z( lastac.z() + vmove );
01389                 newac[0] = ( 1.0 - newac[1] - newac[2] );  // newac.x( 1.0 - newac.y() - newac.z() );
01390                 break;
01391             case 1:
01392                 newac[2] = ( lastac[2] + umove );          // newac.z( lastac.z() + umove );
01393                 newac[0] = ( lastac[0] + vmove );          // newac.x( lastac.x() + vmove );
01394                 newac[1] = ( 1.0 - newac[2] - newac[0] );  // newac.y( 1.0 - newac.z() - newac.x() );
01395                 break;
01396             case 2:
01397                 newac[0] = ( lastac[0] + umove );          // newac.x( lastac.x() + umove );
01398                 newac[1] = ( lastac[1] + vmove );          // newac.y( lastac.y() + vmove );
01399                 newac[2] = ( 1.0 - newac[0] - newac[1] );  // newac.z( 1.0 - newac.x() - newac.y() );
01400                 break;
01401         }
01402 
01403         // Keep it inside the patch
01404 
01405         if( newac[0] >= -atol && newac[1] >= -atol && newac[2] >= -atol )
01406         {
01407             nout = 0;
01408         }
01409         else
01410         {
01411             if( move_ac_inside( newac, atol ) ) nout++;
01412         }
01413 
01414         // Evaluate at the new location
01415 
01416         if( edge_id != -1 ) ac_at_edge( newac, newac, edge_id );  // move to edge first
01417         eval_bezier_patch( facet, newac, newpt );
01418 
01419         // Check for convergence
01420 
01421         distnew  = ( pt - newpt ).length();  // pt.distance_between(newpt);
01422         move     = newpt - lastpt;
01423         movedist = move.length();
01424         if( movedist < tol || distnew < tol )
01425         {
01426             done = true;
01427             if( distnew < bestdist )
01428             {
01429                 bestdist = distnew;
01430                 bestac   = newac;
01431                 bestpt   = newpt;
01432                 bestnorm = norm;
01433             }
01434         }
01435         else
01436         {
01437 
01438             // don't allow more than 30 iterations
01439 
01440             iter++;
01441             if( iter > 30 )
01442             {
01443                 // if (movedist > tol * 100.0) nout=1;
01444                 done = true;
01445             }
01446 
01447             // Check for divergence - don't allow more than 5 divergent
01448             // iterations
01449 
01450             if( distnew > lastdist )
01451             {
01452                 diverge++;
01453                 if( diverge > 10 )
01454                 {
01455                     done = true;
01456                     // if (movedist > tol * 100.0) nout=1;
01457                 }
01458             }
01459 
01460             // Check if we are continuing to project outside the facet.
01461             // If so, then stop now
01462 
01463             if( nout > 3 )
01464             {
01465                 done = true;
01466             }
01467 
01468             // set up for next iteration
01469 
01470             if( !done )
01471             {
01472                 if( distnew < bestdist )
01473                 {
01474                     bestdist = distnew;
01475                     bestac   = newac;
01476                     bestpt   = newpt;
01477                     bestnorm = norm;
01478                 }
01479                 lastdist = distnew;
01480                 lastpt   = newpt;
01481                 lastac   = newac;
01482                 move     = pt - lastpt;
01483             }
01484         }
01485     }
01486 
01487     eval_pt = bestpt;
01488     if( eval_norm )
01489     {
01490         *eval_norm = bestnorm;
01491     }
01492     outside = ( nout > 0 ) ? true : false;
01493     ac      = bestac;
01494 
01495     return status;
01496 }
01497 
01498 //===========================================================================
01499 // Function Name: ac_at_edge
01500 //
01501 // Member Type:  PRIVATE
01502 // Description:  determine the area coordinate of the facet at the edge
01503 //===========================================================================
01504 void SmoothFace::ac_at_edge( CartVect& fac,  // facet area coordinate
01505                              CartVect& eac,  // edge area coordinate
01506                              int edge_id )   // id of edge
01507 {
01508     double u, v, w;
01509     switch( edge_id )
01510     {
01511         case 0:
01512             u = 0.0;
01513             v = fac[1] / ( fac[1] + fac[2] );  // v = fac.y() / (fac.y() + fac.z());
01514             w = 1.0 - v;
01515             break;
01516         case 1:
01517             u = fac[0] / ( fac[0] + fac[2] );  // u = fac.x() / (fac.x() + fac.z());
01518             v = 0.0;
01519             w = 1.0 - u;
01520             break;
01521         case 2:
01522             u = fac[0] / ( fac[0] + fac[1] );  // u = fac.x() / (fac.x() + fac.y());
01523             v = 1.0 - u;
01524             w = 0.0;
01525             break;
01526         default:
01527             assert( 0 );
01528             u = -1;  // needed to eliminate warnings about used before set
01529             v = -1;  // needed to eliminate warnings about used before set
01530             w = -1;  // needed to eliminate warnings about used before set
01531             break;
01532     }
01533     eac[0] = u;
01534     eac[1] = v;
01535     eac[2] = w;  //= CartVect(u, v, w);
01536 }
01537 
01538 //===========================================================================
01539 // Function Name: project_to_facet
01540 //
01541 // Member Type:  PUBLIC
01542 // Description:  project to a single facet.  Uses the input areacoord as
01543 //              a starting guess.
01544 //===========================================================================
01545 ErrorCode SmoothFace::project_to_facet( EntityHandle facet,
01546                                         CartVect& pt,
01547                                         CartVect& areacoord,
01548                                         CartVect& close_point,
01549                                         bool& outside_facet,
01550                                         double compare_tol )
01551 {
01552     const EntityHandle* conn3 = NULL;
01553     int nnodes                = 0;
01554     _mb->get_connectivity( facet, conn3, nnodes );
01555     //
01556     // double coords[9]; // store the coordinates for the nodes
01557     //_mb->get_coords(conn3, 3, coords);
01558     CartVect p[3];
01559     _mb->get_coords( conn3, 3, (double*)&p[0] );
01560 
01561     int edge_id    = -1;
01562     ErrorCode stat = project_to_patch( facet, areacoord, pt, close_point, NULL, outside_facet, compare_tol, edge_id );
01563     /* }
01564      break;
01565      }*/
01566 
01567     return stat;
01568 }
01569 
01570 //===========================================================================
01571 // Function Name: is_at_vertex
01572 //
01573 // Member Type:  PRIVATE
01574 // Description:  determine if the point is at one of the facet's vertices
01575 //===========================================================================
01576 bool SmoothFace::is_at_vertex( EntityHandle facet,        // (IN) facet we are evaluating
01577                                CartVect& pt,              // (IN) the point
01578                                CartVect& ac,              // (IN) the ac of the point on the facet plane
01579                                double compare_tol,        // (IN) return TRUE of closer than this
01580                                CartVect& eval_pt,         // (OUT) location at vertex if TRUE
01581                                CartVect* eval_norm_ptr )  // (OUT) normal at vertex if TRUE
01582 {
01583     double dist;
01584     CartVect vert_loc;
01585     const double actol = 0.1;
01586     // get coordinates get_coords
01587     const EntityHandle* conn3 = NULL;
01588     int nnodes                = 0;
01589     _mb->get_connectivity( facet, conn3, nnodes );
01590     //
01591     // double coords[9]; // store the coordinates for the nodes
01592     //_mb->get_coords(conn3, 3, coords);
01593     CartVect p[3];
01594     _mb->get_coords( conn3, 3, (double*)&p[0] );
01595     // also get the normals at nodes
01596     CartVect NN[3];
01597     _mb->tag_get_data( _gradientTag, conn3, 3, (double*)&NN[0] );
01598     if( fabs( ac[0] ) < actol && fabs( ac[1] ) < actol )
01599     {
01600         vert_loc = p[2];
01601         dist     = ( pt - vert_loc ).length();  // pt.distance_between( vert_loc );
01602         if( dist <= compare_tol )
01603         {
01604             eval_pt = vert_loc;
01605             if( eval_norm_ptr )
01606             {
01607                 *eval_norm_ptr = NN[2];
01608             }
01609             return true;
01610         }
01611     }
01612 
01613     if( fabs( ac[0] ) < actol && fabs( ac[2] ) < actol )
01614     {
01615         vert_loc = p[1];
01616         dist     = ( pt - vert_loc ).length();  // pt.distance_between( vert_loc );
01617         if( dist <= compare_tol )
01618         {
01619             eval_pt = vert_loc;
01620             if( eval_norm_ptr )
01621             {
01622                 *eval_norm_ptr = NN[1];  // facet->point(1)->normal( facet );
01623             }
01624             return true;
01625         }
01626     }
01627 
01628     if( fabs( ac[1] ) < actol && fabs( ac[2] ) < actol )
01629     {
01630         vert_loc = p[0];
01631         dist     = ( pt - vert_loc ).length();  // pt.distance_between( vert_loc );
01632         if( dist <= compare_tol )
01633         {
01634             eval_pt = vert_loc;
01635             if( eval_norm_ptr )
01636             {
01637                 *eval_norm_ptr = NN[0];
01638             }
01639             return true;
01640         }
01641     }
01642 
01643     return false;
01644 }
01645 
01646 //===========================================================================
01647 // Function Name: move_ac_inside
01648 //
01649 // Member Type:  PRIVATE
01650 // Description:  find the closest area coordinate to the boundary of the
01651 //              patch if any of its components are < 0
01652 //              Return if the ac was modified.
01653 //===========================================================================
01654 bool SmoothFace::move_ac_inside( CartVect& ac, double tol )
01655 {
01656     int nout = 0;
01657     if( ac[0] < -tol )
01658     {
01659         ac[0] = 0.0;
01660         ac[1] = ac[1] / ( ac[1] + ac[2] );  //( ac.y() / (ac.y() + ac.z()) ;
01661         ac[2] = 1. - ac[1];                 // ac.z( 1.0 - ac.y() );
01662         nout++;
01663     }
01664     if( ac[1] < -tol )
01665     {
01666         ac[1] = 0.;                         // ac.y( 0.0 );
01667         ac[0] = ac[0] / ( ac[0] + ac[2] );  // ac.x( ac.x() / (ac.x() + ac.z()) );
01668         ac[2] = 1. - ac[0];                 // ac.z( 1.0 - ac.x() );
01669         nout++;
01670     }
01671     if( ac[2] < -tol )
01672     {
01673         ac[2] = 0.;                         // ac.z( 0.0 );
01674         ac[0] = ac[0] / ( ac[0] + ac[1] );  // ac.x( ac.x() / (ac.x() + ac.y()) );
01675         ac[1] = 1. - ac[0];                 // ac.y( 1.0 - ac.x() );
01676         nout++;
01677     }
01678     return ( nout > 0 ) ? true : false;
01679 }
01680 
01681 //===========================================================================
01682 // Function Name: hodograph
01683 //
01684 // Member Type:  PUBLIC
01685 // Description:  get the hodograph control points for the facet
01686 // Note:  This is a triangle cubic patch that is defined by the
01687 //       normals of quartic facet control point lattice.  Returned coordinates
01688 //       in Nijk are defined by the following diagram
01689 //
01690 //
01691 //                         *9               index  polar
01692 //                        / \                 0     300    point(0)
01693 //                       /   \                1     210
01694 //                     7*-----*8              2     120
01695 //                     / \   / \              3     030    point(1)
01696 //                    /   \ /   \             4     201
01697 //                  4*----5*-----*6           5     111
01698 //                  / \   / \   / \           6     021
01699 //                 /   \ /   \ /   \          7     102
01700 //                *-----*-----*-----*         8     012
01701 //                0     1     2     3         9     003    point(2)
01702 //
01703 
01704 //===========================================================================
01705 // Function Name: eval_bezier_patch_normal
01706 //
01707 // Member Type:  PRIVATE
01708 // Description:  evaluate the Bezier patch defined at a facet
01709 //===========================================================================
01710 ErrorCode SmoothFace::eval_bezier_patch_normal( EntityHandle facet, CartVect& areacoord, CartVect& normal )
01711 {
01712     // interpolate internal control points
01713 
01714     CartVect gctrl_pts[6];
01715     // facet->get_control_points( gctrl_pts );
01716     ErrorCode rval = _mb->tag_get_data( _facetCtrlTag, &facet, 1, &gctrl_pts[0] );
01717     assert( rval == MB_SUCCESS );
01718     if( MB_SUCCESS != rval ) return rval;
01719     // _gradientTag
01720     // get normals at points
01721     const EntityHandle* conn3 = NULL;
01722     int nnodes                = 0;
01723     rval                      = _mb->get_connectivity( facet, conn3, nnodes );
01724     if( MB_SUCCESS != rval ) return rval;
01725 
01726     CartVect NN[3];
01727     rval = _mb->tag_get_data( _gradientTag, conn3, 3, &NN[0] );
01728     assert( rval == MB_SUCCESS );
01729     if( MB_SUCCESS != rval ) return rval;
01730 
01731     if( fabs( areacoord[1] + areacoord[2] ) < 1.0e-6 )
01732     {
01733         normal = NN[0];
01734         return MB_SUCCESS;
01735     }
01736     if( fabs( areacoord[0] + areacoord[2] ) < 1.0e-6 )
01737     {
01738         normal = NN[1];  // facet->point(1)->normal(facet);
01739         return MB_SUCCESS;
01740     }
01741     if( fabs( areacoord[0] + areacoord[1] ) < 1.0e-6 )
01742     {
01743         normal = NN[2];  // facet->point(2)->normal(facet);
01744         return MB_SUCCESS;
01745     }
01746 
01747     // compute the hodograph of the quartic Gregory patch
01748 
01749     CartVect Nijk[10];
01750     // hodograph(facet,areacoord,Nijk);
01751     // start copy from hodograph
01752     // CubitVector gctrl_pts[6];
01753     // facet->get_control_points( gctrl_pts );
01754     CartVect P_facet[3];
01755 
01756     // 2,1,1
01757     /*P_facet[0] = (1.0e0 / (areacoord.y() + areacoord.z())) *
01758      (areacoord.y() * gctrl_pts[3] +
01759      areacoord.z() * gctrl_pts[4]);*/
01760     P_facet[0] =
01761         ( 1.0e0 / ( areacoord[1] + areacoord[2] ) ) * ( areacoord[1] * gctrl_pts[3] + areacoord[2] * gctrl_pts[4] );
01762     // 1,2,1
01763     /*P_facet[1] = (1.0e0 / (areacoord.x() + areacoord.z())) *
01764      (areacoord.x() * gctrl_pts[0] +
01765      areacoord.z() * gctrl_pts[5]);*/
01766     P_facet[1] =
01767         ( 1.0e0 / ( areacoord[0] + areacoord[2] ) ) * ( areacoord[0] * gctrl_pts[0] + areacoord[2] * gctrl_pts[5] );
01768     // 1,1,2
01769     /*P_facet[2] = (1.0e0 / (areacoord.x() + areacoord.y())) *
01770      (areacoord.x() * gctrl_pts[1] +
01771      areacoord.y() * gctrl_pts[2]);*/
01772     P_facet[2] =
01773         ( 1.0e0 / ( areacoord[0] + areacoord[1] ) ) * ( areacoord[0] * gctrl_pts[1] + areacoord[1] * gctrl_pts[2] );
01774 
01775     // corner control points are just the normals at the points
01776 
01777     // 3, 0, 0
01778     Nijk[0] = NN[0];
01779     // 0, 3, 0
01780     Nijk[3] = NN[1];
01781     // 0, 0, 3
01782     Nijk[9] = NN[2];  // facet->point(2)->normal(facet);
01783 
01784     // fill in the boundary control points.  Define as the normal to the local
01785     // triangle formed by the quartic control point lattice
01786 
01787     // store here again the 9 control points on the edges
01788     CartVect CP[9];  // 9 control points on the edges,
01789     rval = _mb->tag_get_data( _facetEdgeCtrlTag, &facet, 1, &CP[0] );
01790     if( MB_SUCCESS != rval ) return rval;
01791     // there are 3 CP for each edge, 0, 1, 2; first edge is 1-2
01792     // CubitFacetEdge *edge;
01793     // edge = facet->edge( 2 );
01794     // CubitVector ctrl_pts[5];
01795     // edge->control_points(facet, ctrl_pts);
01796 
01797     // 2, 1, 0
01798     // Nijk[1] = (ctrl_pts[2] - ctrl_pts[1]) * (P_facet[0] - ctrl_pts[1]);
01799     Nijk[1] = ( CP[7] - CP[6] ) * ( P_facet[0] - CP[6] );
01800     Nijk[1].normalize();
01801 
01802     // 1, 2, 0
01803     // Nijk[2] = (ctrl_pts[3] - ctrl_pts[2]) * (P_facet[1] - ctrl_pts[2]);
01804     Nijk[2] = ( CP[8] - CP[7] ) * ( P_facet[1] - CP[7] );
01805     Nijk[2].normalize();
01806 
01807     // edge = facet->edge( 0 );
01808     // edge->control_points(facet, ctrl_pts);
01809 
01810     // 0, 2, 1
01811     // Nijk[6] = (ctrl_pts[1] - P_facet[1]) * (ctrl_pts[2] - P_facet[1]);
01812     Nijk[6] = ( CP[0] - P_facet[1] ) * ( CP[1] - P_facet[1] );
01813     Nijk[6].normalize();
01814 
01815     // 0, 1, 2
01816     // Nijk[8] = (ctrl_pts[2] - P_facet[2]) * (ctrl_pts[3] - P_facet[2]);
01817     Nijk[8] = ( CP[1] - P_facet[2] ) * ( CP[2] - P_facet[2] );
01818     Nijk[8].normalize();
01819 
01820     // edge = facet->edge( 1 );
01821     // edge->control_points(facet, ctrl_pts);
01822 
01823     // 1, 0, 2
01824     // Nijk[7] = (P_facet[2] - ctrl_pts[2]) * (ctrl_pts[1] - ctrl_pts[2]);
01825     Nijk[7] = ( P_facet[2] - CP[4] ) * ( CP[3] - CP[4] );
01826     Nijk[7].normalize();
01827 
01828     // 2, 0, 1
01829     // Nijk[4] = (P_facet[0] - ctrl_pts[3]) * (ctrl_pts[2] - ctrl_pts[3]);
01830     Nijk[4] = ( P_facet[0] - CP[5] ) * ( CP[4] - CP[5] );
01831     Nijk[4].normalize();
01832 
01833     // 1, 1, 1
01834     Nijk[5] = ( P_facet[1] - P_facet[0] ) * ( P_facet[2] - P_facet[0] );
01835     Nijk[5].normalize();
01836     // end copy from hodograph
01837 
01838     // sum the contribution from each of the control points
01839 
01840     normal = CartVect( 0.0e0, 0.0e0, 0.0e0 );
01841 
01842     // i=3; j=0; k=0;
01843     // double Bsum = 0.0;
01844     double B = mbcube( areacoord[0] );
01845     // Bsum += B;
01846     normal += B * Nijk[0];
01847 
01848     // i=2; j=1; k=0;
01849     B = 3.0 * mbsqr( areacoord[0] ) * areacoord[1];
01850     // Bsum += B;
01851     normal += B * Nijk[1];
01852 
01853     // i=1; j=2; k=0;
01854     B = 3.0 * areacoord[0] * mbsqr( areacoord[1] );
01855     // Bsum += B;
01856     normal += B * Nijk[2];
01857 
01858     // i=0; j=3; k=0;
01859     B = mbcube( areacoord[1] );
01860     // Bsum += B;
01861     normal += B * Nijk[3];
01862 
01863     // i=2; j=0; k=1;
01864     B = 3.0 * mbsqr( areacoord[0] ) * areacoord[2];
01865     // Bsum += B;
01866     normal += B * Nijk[4];
01867 
01868     // i=1; j=1; k=1;
01869     B = 6.0 * areacoord[0] * areacoord[1] * areacoord[2];
01870     // Bsum += B;
01871     normal += B * Nijk[5];
01872 
01873     // i=0; j=2; k=1;
01874     B = 3.0 * mbsqr( areacoord[1] ) * areacoord[2];
01875     // Bsum += B;
01876     normal += B * Nijk[6];
01877 
01878     // i=1; j=0; k=2;
01879     B = 3.0 * areacoord[0] * mbsqr( areacoord[2] );
01880     // Bsum += B;
01881     normal += B * Nijk[7];
01882 
01883     // i=0; j=1; k=2;
01884     B = 3.0 * areacoord[1] * mbsqr( areacoord[2] );
01885     // Bsum += B;
01886     normal += B * Nijk[8];
01887 
01888     // i=0; j=0; k=3;
01889     B = mbcube( areacoord[2] );
01890     // Bsum += B;
01891     normal += B * Nijk[9];
01892 
01893     // assert(fabs(Bsum - 1.0) < 1e-9);
01894 
01895     normal.normalize();
01896 
01897     return MB_SUCCESS;
01898 }
01899 
01900 ErrorCode SmoothFace::get_normals_for_vertices( const EntityHandle* conn2, CartVect N[2] )
01901 // this method will be called to retrieve the normals needed in the calculation of control edge
01902 // points..
01903 {
01904     // CartVect N[2];
01905     //_mb->tag_get_data(_gradientTag, conn2, 2, normalVec);
01906     ErrorCode rval = _mb->tag_get_data( _gradientTag, conn2, 2, (double*)&N[0] );
01907     return rval;
01908 }
01909 
01910 ErrorCode SmoothFace::ray_intersection_correct( EntityHandle,       // (IN) the facet where the patch is defined
01911                                                 CartVect& pt,       // (IN) shoot from
01912                                                 CartVect& ray,      // (IN) ray direction
01913                                                 CartVect& eval_pt,  // (INOUT) The intersection point
01914                                                 double& distance,   // (IN OUT) the new distance
01915                                                 bool& outside )
01916 {
01917     // find a point on the smooth surface
01918     CartVect currentPoint = eval_pt;
01919     int numIter           = 0;
01920     double improvement    = 1.e20;
01921     CartVect diff;
01922     while( numIter++ < 5 && improvement > 0.01 )
01923     {
01924         CartVect newPos;
01925 
01926         bool trim = false;  // is it needed?
01927         outside   = true;
01928         CartVect closestPoint;
01929         CartVect normal;
01930 
01931         ErrorCode rval = project_to_facets_main( currentPoint, trim, outside, &newPos, &normal );
01932         if( MB_SUCCESS != rval ) return rval;
01933         assert( rval == MB_SUCCESS );
01934         diff        = newPos - currentPoint;
01935         improvement = diff.length();
01936         // ( pt + t * ray - closest ) % normal = 0;
01937         // intersect tangent plane that goes through closest point with the direction
01938         // t = normal%(closest-pt) / normal%ray;
01939         double dot = normal % ray;  // if it is 0, get out while we can
01940         if( dot < 0.00001 )
01941         {
01942             // bad convergence, get out, do not modify anything
01943             return MB_SUCCESS;
01944         }
01945         double t     = ( ( newPos - pt ) % normal ) / ( dot );
01946         currentPoint = pt + t * ray;
01947     }
01948     eval_pt  = currentPoint;
01949     diff     = currentPoint - pt;
01950     distance = diff.length();
01951     return MB_SUCCESS;
01952 }
01953 }  // namespace moab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines