cgma
TetFacetorTool.cpp
Go to the documentation of this file.
00001 //-------------------------------------------------------------------------
00002 // Filename      : TetFacetorTool.cpp
00003 //
00004 // Purpose       : 3D Delaunay Tesselator.  Given a set of 3D points, will define 
00005 //                 a Delaunay tesselation.  Does not currently support boundary 
00006 //                 constraints.  Result will be the convex hull of the points
00007 //
00008 // Description   : TetFacetorTool is a template class that currently accepts 
00009 //                 MeshEntity classes.  Any other data structure that satisfies
00010 //                 the appropriate member functions should also be handled.
00011 //                 see also FacetorTool  
00012 //
00013 //                 Following is the list of required members of the TET and 
00014 //                 NODE classes to use this template
00015 //                 
00016 //                 TET: add_TD, get_TD, tet_nodes, get_connected_tet, 
00017 //                      new, delete
00018 //                 NODE: number_tets, coordinates, add_tet, remove_tet
00019 //                       new, delete, tet_list
00020 //
00021 // Creator       : Steve Owen
00022 //
00023 // Creation Date : 8/2/2003
00024 //
00025 // Owner         : Steve Owen
00026 //-------------------------------------------------------------------------
00027 
00028 //#define DEBUG_TET_FACETOR
00029 
00030 
00031 #ifdef INLINE_TEMPLATES
00032 #define MY_INLINE inline
00033 #else
00034 #define MY_INLINE
00035 #endif
00036 
00037 // defining DEBUG_TET_FACETOR will allow you to compile and link as a 
00038 // standard C++ class rather than a template.  The definitions used for
00039 // NODE and TET are the Cubit mesh entities.  Since they can't be used
00040 // in the geom directory, DEBUG_TET_FACETOR should not be defined under
00041 // normal circumstances.
00042 #ifdef DEBUG_TET_FACETOR
00043 #include "..\mdb\CubitTet.hpp"
00044 #include "..\mdb\NodeTet.hpp"
00045 #include "..\mdb\CubitNode.hpp" 
00046 #define TET CubitTet
00047 #define SUBTET NodeTet
00048 #define NODE CubitNode
00049 #define TET_FACETOR_TOOL    TetFacetorTool::
00050 #define TET_FACETOR_TOOL__I int TetFacetorTool::
00051 #define TET_FACETOR_TOOL__V void TetFacetorTool::
00052 #define TET_FACETOR_TOOL__D double TetFacetorTool::
00053 #define TET_FACETOR_TOOL__B CubitBoolean TetFacetorTool::
00054 #define TET_FACETOR_TOOL__T TET *TetFacetorTool::
00055 #else
00056 #define TET_FACETOR_TOOL    template<class TET, class SUBTET, class NODE> MY_INLINE TetFacetorTool<TET, SUBTET, NODE>::
00057 #define TET_FACETOR_TOOL__I template<class TET, class SUBTET, class NODE> MY_INLINE int TetFacetorTool<TET, SUBTET, NODE>::
00058 #define TET_FACETOR_TOOL__V template<class TET, class SUBTET, class NODE> MY_INLINE void TetFacetorTool<TET, SUBTET, NODE>::
00059 #define TET_FACETOR_TOOL__D template<class TET, class SUBTET, class NODE> MY_INLINE double TetFacetorTool<TET, SUBTET, NODE>::
00060 #define TET_FACETOR_TOOL__B template<class TET, class SUBTET, class NODE> MY_INLINE CubitBoolean TetFacetorTool<TET, SUBTET, NODE>::
00061 #define TET_FACETOR_TOOL__T template<class TET, class SUBTET, class NODE> MY_INLINE TET *TetFacetorTool<TET, SUBTET, NODE>::
00062 #endif
00063 
00064 #ifndef SQR
00065 #define SQR(x) ((x) * (x))
00066 #endif
00067 #include <math.h>
00068 #include "GeometryDefines.h"
00069 #include "TetFacetorTool.hpp"
00070 #include "TDDelaunay.hpp"
00071 #include "TDInterpNode.hpp"
00072 #include <vector>
00073 #include <algorithm>
00074 
00075 //-------------------------------------------------------------------------
00076 // Function:    TetFacetorTool
00077 // Description: constructor
00078 // Author:      sjowen
00079 // Date:        8/2/2003
00080 //-------------------------------------------------------------------------
00081 TET_FACETOR_TOOL 
00082 TetFacetorTool(  )
00083 {
00084   //update private variables
00085   mDebug = 1;
00086 
00087 }
00088 
00089 
00090 //-------------------------------------------------------------------------
00091 // Function:    ~TetFacetorTool
00092 // Description: destructor
00093 // Author:      sjowen
00094 // Date:        8/2/2003
00095 //-------------------------------------------------------------------------
00096 TET_FACETOR_TOOL
00097 ~TetFacetorTool()
00098 {
00099 }
00100 
00101 //-------------------------------------------------------------------------
00102 // Function:    initialize
00103 // Description: initialize the Delaunay domain based on the bounding box
00104 //              provided.  All nodes to be inserted later are intended to
00105 //              lie within this box.  Note that the bounding box should
00106 //              be larger than bounding box of nodes by at least about 10-20%
00107 // Author:      sjowen
00108 // Date:        1/22/2004
00109 //-------------------------------------------------------------------------
00110 TET_FACETOR_TOOL__I
00111 initialize(CubitBox &bounding_box)
00112 {
00113   bBox = bounding_box;
00114   return create_bbox_tets();
00115 }
00116 
00117 //-------------------------------------------------------------------------
00118 // Function:    finish
00119 // Description: complete the tesselation.  Remove bounding box nodes and
00120 //              their connected tets
00121 // Author:      sjowen
00122 // Date:        1/22/2004
00123 //-------------------------------------------------------------------------
00124 TET_FACETOR_TOOL__I
00125 finish()
00126 {
00127   return remove_bbox_tets();
00128 }
00129 
00130 //-------------------------------------------------------------------------
00131 // Function:    get_tets
00132 // Description: get the current tet list
00133 // Author:      sjowen
00134 // Date:        1/22/2004
00135 //-------------------------------------------------------------------------
00136 TET_FACETOR_TOOL__I
00137 get_tets(std::vector<TET*> &tet_list)
00138 {
00139   tet_list += tetList;
00140   return tet_list.size();
00141 }
00142 
00143 //-------------------------------------------------------------------------
00144 // Function:    get_outside_tet
00145 // Description: get the current tet list
00146 // Author:      sjowen
00147 // Date:        1/22/2004
00148 //-------------------------------------------------------------------------
00149 TET_FACETOR_TOOL__T
00150 get_outside_tet()
00151 {
00152   NODE *node = boxNodes[0];
00153   std::vector<TET *> *tet_list_ptr = node->tet_list();
00154   assert(tet_list_ptr != NULL && tet_list_ptr->size() > 0);
00155   tet_list_ptr->reset();
00156   return tet_list_ptr->get();
00157 }
00158 
00159 //-------------------------------------------------------------------------
00160 // Function:    get_interior_tets
00161 // Description: get tets that are not connected to a bounding box node
00162 // Author:      sjowen
00163 // Date:        1/22/2004
00164 //-------------------------------------------------------------------------
00165 TET_FACETOR_TOOL__I
00166 get_interior_tets(std::vector<TET*> &tet_list)
00167 {
00168   size_t ii, jj;
00169   TET *tet_ptr;
00170   NODE *nodes[4];
00171   int found = 0;
00172   for (ii=0; ii<tetList.size(); ii++)
00173   {
00174     tet_ptr = tetList.get_and_step();  
00175     tet_ptr->tet_nodes(nodes[0], nodes[1], nodes[2], nodes[3]);
00176     found = 0;
00177     for(jj=0; jj<4 && !found; jj++)
00178     {
00179       if (is_bbox(nodes[jj]))
00180       {
00181         found = 1;
00182       }
00183     }
00184     if (!found)
00185       tet_list.push_back(tet_ptr);
00186   }
00187 
00188   return tet_list.size();
00189 }
00190 
00191 //-------------------------------------------------------------------------
00192 // Function:    tesselate
00193 // Description: given a set of points, create delaunay tets from them
00194 //              does all initialization and removal of bounding box tets
00195 // Author:      sjowen
00196 // Date:        8/2/2003
00197 //-------------------------------------------------------------------------
00198 TET_FACETOR_TOOL__I
00199 tesselate(std::vector<NODE *> &node_list, std::vector<TET *> &tet_list)
00200 {
00201   int stat;
00202 
00203   // create a set of tets in a bounding box to start
00204   stat = init_box( node_list );
00205 
00206   // insert all the nodes
00207   if (stat == CUBIT_SUCCESS)
00208   {
00209     int num_failed = insert_nodes( node_list );
00210     stat = (num_failed==0) ? CUBIT_SUCCESS : CUBIT_FAILURE;
00211   }
00212 
00213   // remove the nodes at the bounding box.
00214   // this should give you a convex hull of the points (provided your points
00215   // are dense enough)
00216 
00217   if (stat == CUBIT_SUCCESS)
00218   {
00219     stat = remove_bbox_tets();
00220   }
00221 
00222   // copy the local list to the tet_list argument to pass back
00223   if (stat == CUBIT_SUCCESS)
00224   { 
00225     for (unsigned int ii=0; ii<tetList.size(); ii++)
00226     {
00227       tet_list.push_back(tetList[ii]);
00228     }
00229   }
00230 
00231   return stat;
00232 }
00233 
00234 //-------------------------------------------------------------------------
00235 // Function:    init_box
00236 // Description: create a set of tets in a bounding box to start
00237 // Author:      sjowen
00238 // Date:        8/2/2003
00239 //-------------------------------------------------------------------------
00240 TET_FACETOR_TOOL__I
00241 init_box(std::vector<NODE *> &node_list)
00242 {
00243   CubitVector minbox(CUBIT_DBL_MAX, CUBIT_DBL_MAX, CUBIT_DBL_MAX);
00244   CubitVector maxbox(-CUBIT_DBL_MAX, -CUBIT_DBL_MAX, -CUBIT_DBL_MAX);
00245 
00246   // loop through nodes to set bounding box
00247 
00248   CubitVector coor;
00249   NODE *node_ptr;
00250   unsigned int ii;
00251   for (ii=0; ii<node_list.size(); ii++)
00252   {
00253     node_ptr = node_list[ii];
00254     coor = node_ptr->coordinates();
00255 
00256     if (coor.x() > maxbox.x()) maxbox.x( coor.x() );
00257     if (coor.x() < minbox.x()) minbox.x( coor.x() );
00258     if (coor.y() > maxbox.y()) maxbox.y( coor.y() );
00259     if (coor.y() < minbox.y()) minbox.y( coor.y() );
00260     if (coor.z() > maxbox.z()) maxbox.z( coor.z() );
00261     if (coor.z() < minbox.z()) minbox.z( coor.z() );
00262   }
00263 
00264   // Expand the bounding box by 20% of the size of the diagonal
00265 
00266   double dx = maxbox.x() - minbox.x();
00267   double dy = maxbox.y() - minbox.y();
00268   double dz = maxbox.z() - minbox.z();
00269   double expand = 0.2 * sqrt(SQR(dx) + SQR(dy) + SQR(dz));
00270   minbox.x( minbox.x() - expand );
00271   minbox.y( minbox.y() - expand );
00272   minbox.z( minbox.z() - expand );
00273   maxbox.x( maxbox.x() + expand );
00274   maxbox.y( maxbox.y() + expand );
00275   maxbox.z( maxbox.z() + expand );
00276 
00277   bBox.reset( minbox, maxbox );
00278 
00279   return create_bbox_tets();
00280 }
00281 
00282 //-------------------------------------------------------------------------
00283 // Function:    create_bbox_tets
00284 // Description: create the tets that contain a node on the bounding box
00285 // Author:      sjowen
00286 // Date:        8/2/2003
00287 //-------------------------------------------------------------------------
00288 TET_FACETOR_TOOL__I
00289 create_bbox_tets()
00290 {
00291   // use the class global bBox as the bounds of the initial tets
00292 
00293   CubitVector maxbox, minbox;
00294   maxbox = bBox.maximum();
00295   minbox = bBox.minimum();
00296 
00297   // Initialize the class global vars
00298 
00299   lastTet = NULL;
00300   tetVisited = CUBIT_INT_MIN;
00301 
00302   // For tolerance, find a representative (non-zero) number from
00303   // the nodes to determine relative magnitude of numbers.  Take the
00304   // log of this number, subtract 6 from it, then use this number
00305   // as the exponent (likely a negative number) for the tolerance
00306 
00307   double tol = CUBIT_MAX(fabs(maxbox.x()),fabs(maxbox.y()));
00308   tol = CUBIT_MAX(tol,fabs(maxbox.z()));
00309   double temp = CUBIT_MAX(fabs(minbox.x()),fabs(minbox.y()));
00310   temp = CUBIT_MAX(temp,fabs(minbox.z()));
00311   tol = CUBIT_MAX(tol,temp);
00312   tol = pow(10.0, (double)(log10(tol) - 6.0));
00313   csTol = tol * tol;
00314 
00315   // create the bounding box nodes
00316 
00317   CubitVector coor;
00318   int ii;
00319   for (ii=0; ii<8; ii++) 
00320   {
00321     switch (ii) {
00322       case 0: coor.set(minbox.x(), minbox.y(), minbox.z()); break;
00323       case 1: coor.set(maxbox.x(), minbox.y(), minbox.z()); break;
00324       case 2: coor.set(maxbox.x(), maxbox.y(), minbox.z()); break;
00325       case 3: coor.set(minbox.x(), maxbox.y(), minbox.z()); break;
00326       case 4: coor.set(minbox.x(), minbox.y(), maxbox.z()); break;
00327       case 5: coor.set(maxbox.x(), minbox.y(), maxbox.z()); break;
00328       case 6: coor.set(maxbox.x(), maxbox.y(), maxbox.z()); break;
00329       case 7: coor.set(minbox.x(), maxbox.y(), maxbox.z()); break;
00330     }
00331     boxNodes[ii] = new NODE(coor);
00332   }
00333 
00334   // create 5 tets to fill the box
00335   
00336   const int itet_config[5][4] = {{0,1,3,4},{1,2,3,6},{1,5,6,4},
00337                                  {3,7,4,6},{1,6,3,4}};
00338   NODE *tet_nodes[4];
00339   TET *new_tet;
00340   int jj;
00341   for (ii=0; ii<5; ii++)
00342   {
00343     for (jj=0; jj<4; jj++)
00344     {
00345       tet_nodes[jj] = boxNodes[itet_config[ii][jj]];
00346     }
00347     new_tet = new SUBTET( tet_nodes );
00348     for (jj=0; jj<4; jj++)
00349       tet_nodes[jj]->add_element(new_tet);
00350     tetList.push_back( new_tet );
00351   }
00352 
00353 
00354   return CUBIT_SUCCESS;
00355 }
00356 
00357 //-------------------------------------------------------------------------
00358 // Function:    remove_bbox_tets
00359 // Description: remove the tets that contain a node on the bounding box
00360 // Author:      sjowen
00361 // Date:        8/2/2003
00362 //-------------------------------------------------------------------------
00363 TET_FACETOR_TOOL__I
00364 remove_bbox_tets()
00365 {
00366   int stat = CUBIT_SUCCESS;
00367   int found;
00368   TET *tet_ptr;
00369   unsigned int ii, jj, kk;
00370 
00371   NODE *nodes[4];
00372   for (ii=0; ii<tetList.size(); ii++)
00373   {
00374     found = 0;
00375     tet_ptr = tetList[ii];  
00376     tet_ptr->tet_nodes(nodes[0], nodes[1], nodes[2], nodes[3]);
00377     for(jj=0; jj<4 && !found; jj++)
00378     {
00379       if (is_bbox(nodes[jj]))
00380       {
00381         found = 1;
00382         for(kk=0; kk<4; kk++)
00383           nodes[kk]->remove_element(tet_ptr);
00384         tetList[ii] = NULL;
00385         delete tet_ptr;
00386       }
00387     }
00388   }
00389   tet_ptr = NULL;
00390   tetList.erase(std::remove(tetList.begin(), tetList.end(), tet_ptr), tetList.end());
00391 
00392   for (ii=0; ii<8; ii++)
00393   {
00394     delete boxNodes[ii];
00395   }
00396 
00397   return stat;
00398 }
00399 
00400 //-------------------------------------------------------------------------
00401 // Function:    is_bbox
00402 // Description: determine if this node is one of the bounding box nodes
00403 // Author:      sjowen
00404 // Date:        8/2/2003
00405 //-------------------------------------------------------------------------
00406 TET_FACETOR_TOOL__I
00407 is_bbox(NODE *n)
00408 {
00409   int ii;
00410   for(ii=0; ii<8; ii++)
00411     if(n == boxNodes[ii])
00412       return 1;
00413   return 0;
00414 }
00415 
00416 //-------------------------------------------------------------------------
00417 // Function:    insert_nodes
00418 // Description: insert nodes into existing tesselation (aasumes at least
00419 //              bounding box tets exist)
00420 // Author:      sjowen
00421 // Date:        8/2/2003
00422 //-------------------------------------------------------------------------
00423 TET_FACETOR_TOOL__I
00424 insert_nodes( std::vector<NODE *> &node_list )
00425 {
00426   unsigned int ii;
00427   NODE *node_ptr;
00428   int num_failed = 0;
00429   for (ii=0; ii<node_list.size(); ii++)
00430   {
00431     node_ptr = node_list[ii];
00432     if(insert_one_node( node_ptr ) == CUBIT_FAILURE)
00433     {
00434       num_failed++;
00435     }
00436   }
00437 
00438   // If any failed to insert the first time, then try them again
00439 
00440   if (num_failed > 0) 
00441   {
00442     num_failed = 0;
00443     for (ii=0; ii<node_list.size(); ii++)
00444     {
00445       node_ptr = node_list[ii];
00446       if (node_ptr->number_tets() == 0)
00447       {
00448         if(insert_one_node( node_ptr ) == CUBIT_FAILURE)
00449         {
00450          num_failed++;
00451         }
00452       }
00453     }
00454   }
00455       
00456   return num_failed;
00457 
00458 }
00459 
00460 //-------------------------------------------------------------------------
00461 // Function:    insert_one_node
00462 // Description: insert a single node into the tesselation. (Must be within 
00463 //              existing convex hull)
00464 // Author:      sjowen
00465 // Date:        8/4/2003
00466 //-------------------------------------------------------------------------
00467 TET_FACETOR_TOOL__I
00468 insert_one_node( NODE *node_ptr )
00469 {
00470 
00471   // Get all tets whose circumsphere contain the point
00472 
00473   CubitVector xx = node_ptr->coordinates();
00474   std::vector<TET *> neighbor_tet_list;
00475   NODE *duplicate_node = NULL;
00476   int stat = natural_neighbor_tets( xx, neighbor_tet_list, duplicate_node );
00477   if (stat != CUBIT_SUCCESS)
00478     return stat;
00479 
00480 
00481   // If this new node fell exactly on top of an existing node, then
00482   // ignore it
00483 
00484   if (duplicate_node != NULL)
00485   {
00486     PRINT_WARNING("Duplicate node detected in Delaunay insertion at (%f %f %f).\n"
00487                   "  Ignoring node and continuing.\n", xx.x(), xx.y(), xx.z());
00488     return CUBIT_SUCCESS;
00489   }
00490 
00491   // insert the node using the bowyer-watson algorithm
00492 
00493   stat = watson_insert( node_ptr, neighbor_tet_list );
00494 
00495   return stat;
00496 
00497 }
00498 
00499 //-------------------------------------------------------------------------
00500 // Function:    natural_neighbor_tets
00501 // Description: Get all tets whose circumsphere contain the point
00502 // Author:      sjowen
00503 // Date:        8/4/2003
00504 //-------------------------------------------------------------------------
00505 TET_FACETOR_TOOL__I
00506 natural_neighbor_tets( CubitVector &xx, std::vector<TET *> &neighbor_tet_list, 
00507                        NODE *&exact_node )
00508 {
00509   // Determine the tet where the point is located.  If its at a node
00510   // return now with success (trivial interpolation case)
00511 
00512   TET *containing_tet;
00513   int stat = locate_point( xx, exact_node, containing_tet );
00514   if (stat != CUBIT_SUCCESS)
00515     return stat;
00516   if (exact_node != NULL)
00517     return CUBIT_SUCCESS;
00518 
00519   // Put the tet that contains the point as the first one on the list 
00520   // and mark it as visited
00521 
00522   neighbor_tet_list.push_back( containing_tet );
00523   set_tet_visited( containing_tet, ++tetVisited );
00524 
00525   // Recursively search, (starting with the tet the point is in)
00526   // search for all tets whose circumsphere contain the point and place 
00527   // on the neighbor_tet_list
00528 
00529   int iface;
00530   TET *adj_tet = NULL;
00531   NODE *na, *nb, *nc, *nd;
00532   containing_tet->tet_nodes(na, nb, nc, nd);
00533   for (iface=0; iface<4; iface++) 
00534   {
00535     switch(iface)
00536     {
00537       case 0: adj_tet = (TET *)containing_tet->get_connected_tet( nb, nc, nd ); break;
00538       case 1: adj_tet = (TET *)containing_tet->get_connected_tet( nd, nc, na ); break;
00539       case 2: adj_tet = (TET *)containing_tet->get_connected_tet( nd, na, nb ); break;
00540       case 3: adj_tet = (TET *)containing_tet->get_connected_tet( nc, nb, na ); break;
00541     }
00542     if (adj_tet != NULL)
00543     {
00544       if (tet_visited(adj_tet) != tetVisited)
00545       {
00546         point_in_circumsphere( adj_tet, xx, neighbor_tet_list );
00547       }
00548     }
00549   }
00550 
00551   return CUBIT_SUCCESS;
00552 }
00553 
00554 //-------------------------------------------------------------------------
00555 // Function:    watson_insert
00556 // Description: insert a single node into the tesselation using the 
00557 //              bowyer watson algorithm
00558 // Author:      sjowen
00559 // Date:        8/4/2003
00560 //-------------------------------------------------------------------------
00561 TET_FACETOR_TOOL__I
00562 watson_insert( NODE *node_ptr, std::vector<TET *> &neighbor_tet_list )
00563 {
00564   TET *tet_ptr;
00565   unsigned int ii,jj;
00566 
00567   // mark all the tets in the list
00568 
00569   tetVisited++;
00570   for (ii=0; ii<neighbor_tet_list.size(); ii++)
00571     set_tet_visited(neighbor_tet_list[ii], tetVisited);
00572 
00573   // Go through the neighbor tets and find the faces that are not 
00574   // adjacent to any other tet in the neighbor list.  These faces
00575   // will serve as base facets for new tets
00576 
00577   std::vector<TET *> new_tet_list;
00578   CubitVector cc;
00579   double radsq;
00580   TET *adj_tet = NULL, *new_tet = NULL;
00581   std::vector<NODE *> cavity_nodes;
00582   NODE *nodes[4];
00583   size_t itet, iface;
00584   size_t ntet = 0;
00585   NODE *na, *nb, *nc, *nd;
00586 
00587   // form the list of boundary faces of the cavity
00588   for (itet=0; itet<neighbor_tet_list.size(); itet++) 
00589   {
00590     tet_ptr = neighbor_tet_list[itet];
00591     tet_ptr->tet_nodes(na, nb, nc, nd);
00592     for (iface=0; iface<4; iface++) 
00593     {  
00594       switch(iface)
00595       {
00596         case 0: adj_tet = (TET *)tet_ptr->get_connected_tet( nb, nc, nd ); break;
00597         case 1: adj_tet = (TET *)tet_ptr->get_connected_tet( nd, nc, na ); break;
00598         case 2: adj_tet = (TET *)tet_ptr->get_connected_tet( nd, na, nb ); break;
00599         case 3: adj_tet = (TET *)tet_ptr->get_connected_tet( nc, nb, na ); break;
00600       }
00601       if (adj_tet == NULL || tet_visited(adj_tet) != tetVisited)
00602       {
00603         switch(iface)
00604         {
00605           case 0:
00606             cavity_nodes.push_back(nb);
00607             cavity_nodes.push_back(nd);
00608             cavity_nodes.push_back(nc);
00609             break;
00610           case 1:
00611             cavity_nodes.push_back(na);
00612             cavity_nodes.push_back(nc);
00613             cavity_nodes.push_back(nd);
00614             break;
00615           case 2:
00616             cavity_nodes.push_back(na);
00617             cavity_nodes.push_back(nd);
00618             cavity_nodes.push_back(nb);
00619             break;
00620           case 3:
00621             cavity_nodes.push_back(na);
00622             cavity_nodes.push_back(nb);
00623             cavity_nodes.push_back(nc);
00624             break;
00625         }
00626         ntet++;
00627       }
00628     }
00629   }
00630 
00631   for (itet=0; itet<ntet; itet++)
00632   {
00633 
00634     // form a new tet with this face and the node
00635         
00636     nodes[0] = cavity_nodes[itet*3];
00637     nodes[1] = cavity_nodes[itet*3+1];
00638     nodes[2] = cavity_nodes[itet*3+2];
00639     nodes[3] = node_ptr;
00640 
00641     // check volume of this new tet - if its less than zero then the cavity is 
00642     // not strictly star-shaped.  fail the insertion, delete any new tets already
00643     // created and return now.
00644 
00645     double vol = tet_volume(nodes[0]->coordinates(), 
00646                             nodes[2]->coordinates(), 
00647                             nodes[1]->coordinates(), 
00648                             nodes[3]->coordinates());
00649     if (vol < 0.0)
00650     {
00651       for (ii=0; ii<new_tet_list.size(); ii++)
00652       {
00653         tet_ptr = new_tet_list[ii]; 
00654         tet_ptr->tet_nodes(nodes[0], nodes[1], nodes[2], nodes[3]);
00655         for(jj=0; jj<4; jj++)
00656           nodes[jj]->remove_element(tet_ptr);
00657         delete tet_ptr;        
00658       }
00659       return CUBIT_FAILURE;
00660     }
00661     new_tet = new SUBTET(nodes);
00662     for (ii=0; ii<4; ii++)
00663       nodes[ii]->add_element(new_tet);
00664     new_tet_list.push_back(new_tet);
00665 
00666     // define the circumsphere.  If it fails, then fail this
00667     // insertion, delete any tets already created and return now.
00668 
00669     if (circumsphere(new_tet, cc, radsq) == CUBIT_FAILURE)
00670     {
00671       for (ii=0; ii<new_tet_list.size(); ii++)
00672       {
00673         tet_ptr = new_tet_list[ii]; 
00674         tet_ptr->tet_nodes(nodes[0], nodes[1], nodes[2], nodes[3]);
00675         for(jj=0; jj<4; jj++)
00676           nodes[jj]->remove_element(tet_ptr);
00677         delete tet_ptr;       
00678       }
00679       return CUBIT_FAILURE;
00680     }
00681     set_tet_visited(new_tet, tetVisited);
00682   }
00683 
00684   // Set last face for Locate Point
00685 
00686   if (new_tet != NULL)
00687     lastTet = new_tet;
00688 
00689   // Delete all tets in the neighbor tet list
00690 
00691   for (itet=0; itet<neighbor_tet_list.size(); itet++) 
00692   {
00693     tet_ptr = neighbor_tet_list[itet];
00694     tet_ptr->tet_nodes(nodes[0], nodes[1], nodes[2], nodes[3]);
00695     for(jj=0; jj<4; jj++)
00696       nodes[jj]->remove_element(tet_ptr);
00697     tetList.erase(std::find(tetList.begin(), tetList.end(), tet_ptr));
00698     
00699     delete tet_ptr;
00700   }
00701 
00702   for (ii=0; ii<new_tet_list.size(); ii++)
00703   {
00704     tetList.push_back( new_tet_list[ii] );
00705   }
00706   return CUBIT_SUCCESS;
00707 }
00708 
00709 //-------------------------------------------------------------------------
00710 // Function:    locate_point
00711 // Description: return the tet the point is located in.  Do a walking
00712 //              algorithm starting from the lastTet.
00713 // Author:      sjowen
00714 // Date:        8/4/2003
00715 //-------------------------------------------------------------------------
00716 TET_FACETOR_TOOL__I 
00717 locate_point( CubitVector &xx, 
00718               NODE *&exact_node, 
00719               TET *&containing_tet )
00720 {
00721   // Use the last tet to be located as the first try.  If there is
00722   // no last tet, then use one tet on the global list
00723 
00724   exact_node = NULL;
00725   containing_tet = NULL;
00726   TET *cur_tet = lastTet;
00727   if (cur_tet == NULL)
00728   {
00729     cur_tet = tetList[0];
00730   }
00731 
00732   // keep track of the tets we visit by marking as we go - 
00733   // increment the visit flag for this call
00734   tetVisited++;
00735 
00736   TET *adj_tet = NULL;
00737   double tol = GEOMETRY_RESABS;
00738   NODE *na, *nb, *nc, *nd;
00739   CubitVector A, B, C, D;
00740   double volcoord_A, volcoord_B, volcoord_C, volcoord_D, vol;
00741   CubitBoolean found = CUBIT_FALSE;
00742   while (!found) 
00743   {
00744     set_tet_visited( cur_tet, tetVisited );
00745 
00746     // Get the coords of the nodes on the tet and compute the
00747     // barycentric coords (areacoords) of the point with respect 
00748     // to the tet.  If all area coords are positive, then 
00749     // the point is inside the tet.  If any are negative
00750     // then choose the next try as the adjacent tet to
00751     // the area coord that was the smallest
00752 
00753     cur_tet->tet_nodes( na, nb, nc, nd );
00754     A = na->coordinates();
00755     B = nb->coordinates();
00756     C = nc->coordinates();
00757     D = nd->coordinates();
00758     volcoord_A = tet_volume(B, C, D, xx);
00759     volcoord_B = tet_volume(A, D, C, xx);
00760     volcoord_C = tet_volume(A, B, D, xx);
00761     volcoord_D = tet_volume(A, C, B, xx);
00762     vol = tet_volume(A, C, B, D);
00763 
00764     // check for inverted tet
00765     assert (vol > 0.0);
00766 
00767     // normalize coords
00768 
00769     //vol = volcoord_A + volcoord_B + volcoord_C + volcoord_D;
00770     if (fabs(vol) > CUBIT_RESABS) 
00771     {
00772       volcoord_A /= vol;
00773       volcoord_B /= vol;
00774       volcoord_C /= vol;
00775       volcoord_D /= vol;
00776       tol = GEOMETRY_RESABS;
00777     }
00778     else 
00779     {
00780       tol = csTol;
00781     }
00782 
00783     if (volcoord_A > -tol && 
00784         volcoord_B > -tol && 
00785         volcoord_C > -tol &&
00786         volcoord_D > -tol) 
00787     {
00788       found = TRUE;
00789 
00790       // if three of the areacoords are +-tol then we are at an existing node
00791 
00792       if (volcoord_B < tol && volcoord_C < tol && volcoord_D < tol) 
00793       {
00794         exact_node = na;
00795       }
00796       else if (volcoord_A < tol && volcoord_C < tol && volcoord_D < tol) 
00797       {
00798         exact_node = nb;
00799       }
00800       else if (volcoord_A < tol && volcoord_B < tol && volcoord_D < tol) 
00801       {
00802         exact_node = nc;
00803       }
00804       else if (volcoord_A < tol && volcoord_B < tol && volcoord_C < tol) 
00805       {
00806         exact_node = nd;
00807       }
00808 
00809       // this is the general case where all areacoords are positive.
00810       // we have located the tet xx is contained in
00811 
00812       else
00813       {
00814         containing_tet = cur_tet;
00815       }
00816     }
00817 
00818     // at least one of the areacoords is negative.  Advance to the next adjacent
00819     // tet.  Choose the adjacent tet based on the sign of the areacoords
00820 
00821     else 
00822     {
00823       if (volcoord_A <= volcoord_B && 
00824           volcoord_A <= volcoord_C &&
00825           volcoord_A <= volcoord_D) 
00826       {
00827         adj_tet = (TET *)cur_tet->get_connected_tet( nb, nc, nd );
00828       }
00829       else if (volcoord_B <= volcoord_A && 
00830                volcoord_B <= volcoord_C &&
00831                volcoord_B <= volcoord_D) 
00832       {
00833         adj_tet = (TET *)cur_tet->get_connected_tet( nd, nc, na );
00834       }
00835       else if (volcoord_C <= volcoord_A && 
00836                volcoord_C <= volcoord_B &&
00837                volcoord_C <= volcoord_D) 
00838       {
00839         adj_tet = (TET *)cur_tet->get_connected_tet( nd, na, nb );
00840       }
00841       else 
00842       {
00843         adj_tet = (TET *)cur_tet->get_connected_tet( nc, nb, na );
00844       }
00845       cur_tet = adj_tet;
00846       
00847       // Check if we just left the triangulation or we have already been 
00848       // to this tet.  If so, use the exhaustive search
00849       
00850       if(cur_tet == NULL  || tet_visited( cur_tet ) == tetVisited)
00851       {
00852         return exhaustive_locate_point(xx, exact_node, containing_tet);
00853       }
00854     }
00855   }
00856   lastTet = containing_tet;
00857   return CUBIT_SUCCESS;
00858 }
00859 
00860 //-------------------------------------------------------------------------
00861 // Function:    exhaustive_locate_point
00862 // Description: Try all tets in the list (that haven't already been tried)
00863 //              This is called only when locate_point fails
00864 // Author:      sjowen
00865 // Date:        8/4/2003
00866 //-------------------------------------------------------------------------
00867 TET_FACETOR_TOOL__I 
00868 exhaustive_locate_point( CubitVector &xx, 
00869               NODE *&exact_node, 
00870               TET *&containing_tet )
00871 {
00872   // Use the last tet to be located as the first try.  If there is
00873   // no last tet, then use one tet on the global list
00874 
00875   exact_node = NULL;
00876   containing_tet = NULL;
00877   TET *cur_tet;
00878   double tol = GEOMETRY_RESABS;
00879   NODE *na, *nb, *nc, *nd;
00880   CubitVector A, B, C, D;
00881   double volcoord_A, volcoord_B, volcoord_C, volcoord_D, vol;
00882   CubitBoolean found = CUBIT_FALSE;
00883   for (size_t ii=0; ii<tetList.size() && !found; ii++)
00884   {
00885     cur_tet = tetList[ii];
00886 
00887     // Don't chak tets we have already chaked.  tetVisited should be 
00888     // current (was set in locate_point)
00889 
00890     if (tet_visited(cur_tet) == tetVisited)
00891       continue;
00892     set_tet_visited( cur_tet, tetVisited );
00893 
00894     // Get the coords of the nodes on the tet and compute the
00895     // barycentric coords (areacoords) of the point with respect 
00896     // to the tet.  If all area coords are positive, then 
00897     // the point is inside the tet.  If any are negative
00898     // then choose the next try as the adjacent tet to
00899     // the area coord that was the smallest
00900 
00901     cur_tet->tet_nodes( na, nb, nc, nd );
00902     A = na->coordinates();
00903     B = nb->coordinates();
00904     C = nc->coordinates();
00905     D = nd->coordinates();
00906     volcoord_A = tet_volume(B, C, D, xx);
00907     volcoord_B = tet_volume(A, D, C, xx);
00908     volcoord_C = tet_volume(A, B, D, xx);
00909     volcoord_D = tet_volume(A, C, B, xx);
00910     vol = tet_volume(A, C, B, D);
00911 
00912     // normalize coords
00913 
00914     //vol = volcoord_A + volcoord_B + volcoord_C + volcoord_D;
00915     if (fabs(vol) > CUBIT_RESABS) 
00916     {
00917       volcoord_A /= vol;
00918       volcoord_B /= vol;
00919       volcoord_C /= vol;
00920       volcoord_D /= vol;
00921       tol = GEOMETRY_RESABS;
00922     }
00923     else 
00924     {
00925       tol = csTol;
00926     }
00927 
00928     if (volcoord_A > -tol && 
00929         volcoord_B > -tol && 
00930         volcoord_C > -tol &&
00931         volcoord_D > -tol) 
00932     {
00933       found = TRUE;
00934 
00935       // if three of the areacoords are +-tol then we are at an existing node
00936 
00937       if (volcoord_B < tol && volcoord_C < tol && volcoord_D < tol) 
00938       {
00939         exact_node = na;
00940       }
00941       else if (volcoord_A < tol && volcoord_C < tol && volcoord_D < tol) 
00942       {
00943         exact_node = nb;
00944       }
00945       else if (volcoord_A < tol && volcoord_B < tol && volcoord_D < tol) 
00946       {
00947         exact_node = nc;
00948       }
00949       else if (volcoord_A < tol && volcoord_B < tol && volcoord_C < tol) 
00950       {
00951         exact_node = nd;
00952       }
00953 
00954       // this is the general case where all areacoords are positive.
00955       // we have located the tet xx is contained in
00956 
00957       else
00958       {
00959         containing_tet = cur_tet;
00960       }
00961     }
00962   }
00963   if (!found)
00964   {
00965     lastTet = NULL;
00966     return CUBIT_FALSE;
00967   }
00968   lastTet = containing_tet;
00969   return CUBIT_SUCCESS;
00970 }
00971 
00972 //-------------------------------------------------------------------------
00973 // Function:    point_in_circumsphere
00974 // Description: recursive function, determines if the point is within the
00975 //              circumsphere of the given tet and then recurses to its
00976 //              neighbors if it is.  Add to the neighbor_tet_list as we go.
00977 // Author:      sjowen
00978 // Date:        8/4/2003
00979 //-------------------------------------------------------------------------
00980 TET_FACETOR_TOOL__B 
00981 point_in_circumsphere( TET *tet_ptr, 
00982                        CubitVector &xx, 
00983                       std::vector<TET *> &neighbor_tet_list )
00984 {
00985   // The circumsphere of the face has been previously stored with the
00986   // face.  Determine distance squared from center of circle to point
00987 
00988   set_tet_visited(tet_ptr, tetVisited);
00989   double radsq;
00990   CubitVector cc;
00991   circumsphere(tet_ptr, cc, radsq);
00992 
00993   double dist2 = (SQR(xx.x()-cc.x()) + 
00994                   SQR(xx.y()-cc.y()) + 
00995                   SQR(xx.z()-cc.z())) - radsq;
00996 
00997 
00998   CubitBoolean inside_csph;
00999   if (dist2 > csTol) 
01000   {
01001     inside_csph = CUBIT_FALSE;
01002   }
01003   else if (dist2 < -csTol) 
01004   {
01005     inside_csph = CUBIT_TRUE;
01006   }
01007   else 
01008   {
01009     inside_csph = CUBIT_TRUE; // (numerically on the sphere)
01010   }
01011 
01012   if (inside_csph) 
01013   {
01014     // add it to the list and go check its neighbors
01015 
01016     neighbor_tet_list.push_back(tet_ptr);
01017 
01018     int iface;
01019     TET *adj_tet = NULL;
01020     NODE *na, *nb, *nc, *nd;
01021     tet_ptr->tet_nodes( na, nb, nc, nd );
01022     for (iface=0; iface<4; iface++) 
01023     {
01024       switch(iface)
01025       {
01026         case 0: adj_tet = (TET *)tet_ptr->get_connected_tet( nb, nc, nd ); break;
01027         case 1: adj_tet = (TET *)tet_ptr->get_connected_tet( nd, nc, na ); break;
01028         case 2: adj_tet = (TET *)tet_ptr->get_connected_tet( nd, na, nb ); break;
01029         case 3: adj_tet = (TET *)tet_ptr->get_connected_tet( nc, nb, na ); break;
01030       }
01031       if (adj_tet != NULL)
01032       {
01033         if (tet_visited(adj_tet) != tetVisited)
01034         {
01035           point_in_circumsphere( adj_tet, xx, neighbor_tet_list );
01036         }
01037       }
01038     }
01039   }
01040   return inside_csph;
01041 }
01042 
01043 
01044 //-------------------------------------------------------------------------
01045 // Function:    circumsphere
01046 // Description: get the circumsphere info for the tet
01047 //              define a tooldata to hold the info if needed
01048 // Author:      sjowen
01049 // Date:        8/2/2003
01050 //-------------------------------------------------------------------------
01051 TET_FACETOR_TOOL__I
01052 circumsphere( TET *tet_ptr, CubitVector &center, double &radius_squared )
01053 {
01054   ToolData *td = tet_ptr->get_TD( TDDelaunay< TET, NODE >::is_delaunay );
01055     TDDelaunay< TET, NODE > *td_del = dynamic_cast<TDDelaunay< TET, NODE >*> (td);
01056     if(td_del == NULL) {
01057         td_del = new TDDelaunay<TET, NODE>();
01058         tet_ptr->add_TD( td_del );
01059     }
01060 
01061     return td_del->circumsphere( tet_ptr, center, radius_squared );
01062 }
01063 
01064 //-------------------------------------------------------------------------
01065 // Function:    set_tet_visited
01066 // Description: set the visited flag for the tet
01067 // Author:      sjowen
01068 // Date:        8/2/2003
01069 //-------------------------------------------------------------------------
01070 TET_FACETOR_TOOL__V
01071 set_tet_visited( TET *tet_ptr, int new_visit_flag )
01072 {
01073   ToolData *td = tet_ptr->get_TD( TDDelaunay< TET, NODE >::is_delaunay );
01074     TDDelaunay< TET, NODE > *td_del = dynamic_cast<TDDelaunay< TET, NODE >*> (td);
01075     if(td_del == NULL) {
01076         td_del = new TDDelaunay<TET, NODE>();
01077         tet_ptr->add_TD( td_del );
01078     }
01079 
01080     td_del->visit_flag( new_visit_flag );
01081 }
01082 
01083 //-------------------------------------------------------------------------
01084 // Function:    tet_visited
01085 // Description: return the visited flag for the tet
01086 // Author:      sjowen
01087 // Date:        8/2/2003
01088 //-------------------------------------------------------------------------
01089 TET_FACETOR_TOOL__I
01090 tet_visited( TET *tet_ptr )
01091 {
01092   ToolData *td = tet_ptr->get_TD( TDDelaunay< TET, NODE >::is_delaunay );
01093   if (td == NULL)
01094     return CUBIT_INT_MIN;
01095     TDDelaunay< TET, NODE > *td_del = dynamic_cast<TDDelaunay< TET, NODE >*> (td);
01096     if(td_del == NULL) 
01097     return CUBIT_INT_MIN;
01098   return td_del->visit_flag();
01099 }
01100 
01101 //-------------------------------------------------------------------------
01102 // Function:    tet_volume
01103 // Description: return the signed volume contained by the four coordinates
01104 /*
01105                    top view
01106 
01107                        B
01108                        *
01109                       /|\
01110                      / | \
01111                     /  *D \
01112                    / _/ \_ \
01113                   /_/     \_\
01114                A *-----------* C
01115 */ 
01116 // Author:      sjowen
01117 // Date:        8/4/2003
01118 //-------------------------------------------------------------------------
01119 TET_FACETOR_TOOL__D
01120 tet_volume( const CubitVector &a, const CubitVector &b, 
01121             const CubitVector &c, const CubitVector &d )
01122 {
01123    CubitVector da = a - d;
01124    CubitVector db = b - d;
01125    CubitVector dc = c - d;
01126    double vol = da.x()*(db.y()*dc.z() - dc.y()*db.z()) + 
01127                 da.y()*(db.z()*dc.x() - dc.z()*db.x()) +
01128                 da.z()*(db.x()*dc.y() - dc.x()*db.y());
01129    vol /= 6.0;
01130 
01131    return vol;
01132 }
01133 
01134 //-----------------------------------------------------------------------------
01135 // Function: read_data
01136 // Description: reads a "data" file -- a list of nodes and scalar/vector data
01137 // Author: sjowen
01138 // Date:8/13/2003
01139 //------------------------------------------------------------------------------
01140 TET_FACETOR_TOOL__I
01141 read_data( const char *filename, std::vector<NODE *>&node_list )
01142 {
01143   // open the file
01144 
01145   FILE *fp = fopen(filename, "r");
01146   if (fp == NULL)
01147   {
01148     PRINT_ERROR("Could not open file %s for reading\n", filename);
01149     return CUBIT_FAILURE;
01150   }
01151 
01152   PRINT_INFO("Reading data...\n");
01153 
01154   // read the number of nodes
01155 
01156   int iline = 1;
01157   char line[128];
01158   if (fgets(line, 128, fp) == NULL)
01159   {
01160     PRINT_ERROR("Format error in facet file %s on line %d\n", filename, iline);
01161     fclose(fp);
01162     return CUBIT_FAILURE;
01163   }
01164 
01165   int nnodes = 0;
01166   int n = sscanf(line, "%d", &nnodes);
01167   if (n != 1)
01168   {
01169     PRINT_ERROR("Format error in data file %s on line %d\n", filename, iline);
01170     fclose(fp);
01171     return CUBIT_FAILURE;
01172   }
01173   if (nnodes <= 0)
01174   {
01175     PRINT_ERROR("Expecting number of nodes in data file %s on line %d\n", filename, iline);
01176     fclose(fp);
01177     return CUBIT_FAILURE;
01178   }
01179 
01180   // read the nodes
01181 
01182   int ii;
01183   double xx, yy, zz, data;
01184   NODE *new_node;
01185   for (ii=0; ii<nnodes; ii++)
01186   {
01187     iline++;
01188     if (fgets(line, 128, fp)== NULL)
01189     {
01190       PRINT_ERROR("Format error in data file %s on line %d\n", filename, iline);
01191       fclose(fp);
01192       return CUBIT_FAILURE;
01193     }
01194 
01195     n = sscanf(line, "%lf %lf %lf %lf", &xx, &yy, &zz, &data );
01196     if (n < 3 || n > 4)
01197     {
01198       PRINT_ERROR("Format error in data file %s on line %d\n", filename, iline);
01199       PRINT_INFO("  Expecting 3 doubles and an optional data value, but instead read %d values\n", n);
01200       fclose(fp);
01201       return CUBIT_FAILURE;
01202     }  
01203     CubitVector pt( xx, yy, zz );
01204     new_node = (NODE *) new NODE( pt );
01205     node_list.push_back( new_node );
01206 
01207     if (n==4)
01208     {
01209       TDInterpNode *td_interp = new TDInterpNode(data);
01210           new_node->add_TD( td_interp );
01211     }
01212   }
01213 
01214   fclose(fp); 
01215   return CUBIT_SUCCESS;
01216 
01217 }
01218 
01219 
01220 // EOF
01221 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines