cgma
|
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 ¢er, 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