cgma
|
00001 //-Class: BoundaryConstrainTool 00002 //-Description: recover edges from a triangle mesh. Currently 2D meshes only 00003 //-Owner: Steve Owen 00004 //-Checked by: 00005 00006 00007 #include "GeometryDefines.h" 00008 #include "CubitVector.hpp" 00009 #include "BoundaryConstrainTool.hpp" 00010 00011 #define ON_LINE_TOL 1.0e-7 00012 #ifndef SQR 00013 #define SQR(x) ((x) * (x)) 00014 #endif 00015 00016 //----------------------------------------------------------------------------- 00017 // Function: BoundaryConstrainTool 00018 // Type: Public 00019 // Description: constructor 00020 // Author: sjowen 00021 // Altered by: jitken(07/08/02) 00022 // Date: 2/17/02 00023 //----------------------------------------------------------------------------- 00024 template <class SURF, class TRI, class EDGE, class NODE, class TRICHILD> 00025 BoundaryConstrainTool<SURF,TRI,EDGE,NODE,TRICHILD>::BoundaryConstrainTool(SURF *ref_face_ptr) 00026 { 00027 refFacePtr = ref_face_ptr; 00028 } 00029 00030 00031 //----------------------------------------------------------------------------- 00032 // Function: BoundaryConstrainTool 00033 // Type: Public 00034 // Description: constructor 00035 // Author: sjowen 00036 // Altered by: jitken(07/08/02) 00037 // Date: 2/17/02 00038 //----------------------------------------------------------------------------- 00039 template <class SURF, class TRI, class EDGE, class NODE, class TRICHILD> 00040 BoundaryConstrainTool<SURF,TRI,EDGE,NODE,TRICHILD>::BoundaryConstrainTool() 00041 { 00042 refFacePtr = NULL; 00043 } 00044 00045 //----------------------------------------------------------------------------- 00046 // Function: ~BoundaryConstrainTool 00047 // Type: Public 00048 // Description: desctructor 00049 // Author: sjowen 00050 // Date: 2/17/02 00051 //----------------------------------------------------------------------------- 00052 template <class SURF, class TRI, class EDGE, class NODE, class TRICHILD> 00053 BoundaryConstrainTool<SURF,TRI,EDGE,NODE,TRICHILD>::~BoundaryConstrainTool() 00054 { 00055 } 00056 00057 //----------------------------------------------------------------------------- 00058 // Function: ~BoundaryConstrainTool 00059 // Type: Public 00060 // Description: desctructor 00061 // Author: sjowen 00062 // Date: 2/17/02 00063 //----------------------------------------------------------------------------- 00064 00065 //----------------------------------------------------------------------------- 00066 // Function: recover_edge 00067 // Type: Public 00068 // Description: flip edges in the triangulation to recover the edge between 00069 // n0_ptr and n1_ptr. Assumes 2D (x-y-0) 00070 // Author: sjowen 00071 // Altered by: jitken(07/08/02) 00072 // Date: 2/17/02 00073 //----------------------------------------------------------------------------- 00074 template <class SURF, class TRI, class EDGE, class NODE, class TRICHILD> 00075 CubitStatus BoundaryConstrainTool<SURF,TRI,EDGE,NODE,TRICHILD>::recover_edge( 00076 NODE *n0_ptr, 00077 NODE *n1_ptr, 00078 EDGE *&recovered_edge_ptr, 00079 DLIList <TRI *> *facet_list) 00080 { 00081 assert(n0_ptr && n1_ptr); 00082 CubitStatus rv = CUBIT_SUCCESS; 00083 00084 //Update the private Variable 00085 facetList = facet_list; 00086 00087 // TRIvial case: edge is already in the triangulation. Return 00088 // now with the edge 00089 00090 recovered_edge_ptr = n0_ptr->shared_edge(n1_ptr); 00091 00092 if ( recovered_edge_ptr != NULL ) 00093 return CUBIT_SUCCESS; 00094 00095 00096 // Define the vector from node0 to node1. This is the direction 00097 // of the edge we want to recover 00098 00099 00100 CubitVector edge_vec = n1_ptr->coordinates() - n0_ptr->coordinates(); 00101 double length = edge_vec.normalize( ); 00102 if (length == 0.0) 00103 return CUBIT_FAILURE; 00104 00105 zeroTol = length * CUBIT_RESABS; 00106 00107 // Initialize the edge cross queue 00108 00109 edgeCrossQueue.clean_out(); 00110 00111 // Fill in the Queue with edges that cross the edge_vec 00112 00113 rv = get_crossing_edges( edge_vec, n0_ptr, n1_ptr ); 00114 if (rv != CUBIT_SUCCESS) 00115 return rv; 00116 00117 // Process each edge in the queue and swap edges on faces 00118 // adjacent to the edges crossing the recover vector 00119 00120 EDGE *edge_ptr; 00121 SwapStatus swap_stat; 00122 while (edgeCrossQueue.size() > 0) 00123 { 00124 edge_ptr = edgeCrossQueue.remove(); 00125 swap_stat = swap_edge( edge_ptr ); 00126 switch (swap_stat) 00127 { 00128 00129 case SWAP_FAILURE: 00130 return CUBIT_FAILURE; 00131 00132 case SWAP_INVALID: 00133 00134 // If flip was not valid, then put it back at the end of 00135 // the queue to be processed later 00136 00137 edgeCrossQueue.append( edge_ptr ); 00138 break; 00139 00140 case SWAP_SUCCESS: 00141 00142 // Check if the edge just created by the flip also 00143 // crosses the recover vector. If it does, then 00144 // add these at the end of the queue to be processed later 00145 00146 if (edgeCrossQueue.size() > 0) 00147 { 00148 rv = edge_intersected( edge_vec, edge_ptr, n0_ptr, n1_ptr ); 00149 if (rv != CUBIT_SUCCESS) 00150 return rv; 00151 } 00152 } 00153 } 00154 00155 // Retrieve the recovered edge to pass back 00156 00157 recovered_edge_ptr = n0_ptr->shared_edge(n1_ptr); 00158 if ( recovered_edge_ptr == NULL ) 00159 rv = CUBIT_FAILURE; 00160 00161 return rv; 00162 } 00163 00164 00165 00166 //----------------------------------------------------------------------------- 00167 // Function: get_crossing_edges 00168 // Type: Private 00169 // Description: generate the initial list of all edges that cross the edge_vec 00170 // between n0 and n1 00171 // Author: sjowen 00172 // Date: 2/17/02 00173 //----------------------------------------------------------------------------- 00174 template <class SURF, class TRI, class EDGE, class NODE, class TRICHILD> 00175 CubitStatus BoundaryConstrainTool<SURF,TRI,EDGE,NODE,TRICHILD>::get_crossing_edges( 00176 CubitVector &edge_vec, 00177 NODE *n0_ptr, 00178 NODE *n1_ptr ) 00179 { 00180 CubitStatus status = CUBIT_FAILURE; 00181 IntersectionType isect_type = AT_BEGIN; 00182 IntersectionType last_isect_type = NO_ISECT; 00183 NODE *node_ptr; 00184 EDGE *edge_ptr; 00185 TRI *tri_ptr; 00186 CubitBoolean done = CUBIT_FALSE; 00187 00188 do 00189 { 00190 switch(isect_type) 00191 { 00192 case AT_BEGIN: 00193 last_isect_type = AT_BEGIN; 00194 isect_type = intersect_from_node( edge_vec, n0_ptr, 00195 tri_ptr, edge_ptr, node_ptr ); 00196 break; 00197 case AT_EDGE: 00198 last_isect_type = AT_EDGE; 00199 edgeCrossQueue.append( edge_ptr ); 00200 isect_type = intersect_from_edge( edge_vec, n0_ptr, n1_ptr, 00201 tri_ptr, edge_ptr, node_ptr ); 00202 break; 00203 case AT_MID: 00204 status = node_at_mid( edge_vec, tri_ptr, node_ptr ); 00205 if (status != CUBIT_SUCCESS) { 00206 return status; 00207 } 00208 isect_type = last_isect_type; 00209 break; 00210 case AT_END: 00211 done = CUBIT_TRUE; 00212 status = CUBIT_SUCCESS; 00213 break; 00214 case NO_ISECT: 00215 done = 1; 00216 return CUBIT_FAILURE; 00217 } 00218 } while (!done); 00219 00220 return status; 00221 } 00222 00223 //----------------------------------------------------------------------------- 00224 // Function: intersect_from_node 00225 // Type: Private 00226 // Description: determine next intersection assuming start from n0 00227 // Author: sjowen 00228 // Date: 2/17/02 00229 //----------------------------------------------------------------------------- 00230 template <class SURF, class TRI, class EDGE, class NODE, class TRICHILD> 00231 IntersectionType BoundaryConstrainTool<SURF,TRI,EDGE,NODE,TRICHILD>::intersect_from_node( 00232 CubitVector &edge_vec, 00233 NODE *n0_ptr, 00234 TRI *&tri_ptr, 00235 EDGE *&edge_ptr, 00236 NODE *&node_ptr ) 00237 { 00238 IntersectionType isect_type = NO_ISECT; 00239 00240 // get all tris adjacent to n0_ptr 00241 00242 DLIList<TRI *> tri_list; 00243 n0_ptr->tris( tri_list ); 00244 CubitBoolean found = CUBIT_FALSE; 00245 00246 int itri; 00247 for (itri=0; itri<tri_list.size() && !found; itri++) 00248 { 00249 tri_ptr = tri_list.get_and_step(); 00250 00251 // If the dot product of edges radiating from the node 00252 // are both greater than zero, then it is a candidate 00253 00254 NODE *n1_ptr = tri_ptr->next_node( n0_ptr ); 00255 assert( n1_ptr != NULL ); 00256 edge_ptr = n0_ptr->shared_edge( n1_ptr ); 00257 assert( edge_ptr != NULL ); 00258 00259 // define the normal vector to the edge 00260 00261 CubitVector vec = n1_ptr->coordinates() - n0_ptr->coordinates(); 00262 vec.z( vec.x() ); 00263 vec.x( -vec.y() ); 00264 vec.y( vec.z() ); 00265 vec.z( 0.0 ); 00266 double length = sqrt(SQR(vec.x()) + SQR(vec.y())); 00267 if (length == 0.0) 00268 { 00269 node_ptr = NULL; 00270 edge_ptr = NULL; 00271 tri_ptr = NULL; 00272 return NO_ISECT; 00273 } 00274 vec.x( vec.x() / length ); 00275 vec.y( vec.y() / length ); 00276 00277 // dot with the recover vector 00278 00279 double dot = edge_vec.x() * vec.x() + edge_vec.y() * vec.y(); 00280 00281 if (dot > -ON_LINE_TOL) { 00282 00283 // Dot product within tolerance of zero means the vector 00284 // follows along edge of face and passes through a node 00285 00286 if (fabs(dot) < ON_LINE_TOL) { 00287 vec = n1_ptr->coordinates() - n0_ptr->coordinates(); 00288 double direction = edge_vec.x() * vec.x() + edge_vec.y() * vec.y(); 00289 //if vector n1-n0 is in the same direction as edge_vec 00290 if(direction > 0){ 00291 vec = n1_ptr->coordinates() - n0_ptr->coordinates(); 00292 node_ptr = n1_ptr; 00293 isect_type = AT_MID; 00294 return isect_type; 00295 } 00296 } 00297 00298 // do the same check on the other edge 00299 00300 NODE *n2_ptr = tri_ptr->next_node( n1_ptr ); 00301 assert( n2_ptr != NULL ); 00302 edge_ptr = n0_ptr->shared_edge( n2_ptr ); 00303 assert( edge_ptr != NULL ); 00304 vec = n0_ptr->coordinates() - n2_ptr->coordinates(); 00305 vec.z( vec.x() ); 00306 vec.x( -vec.y() ); 00307 vec.y( vec.z() ); 00308 vec.z( 0.0 ); 00309 length = sqrt(SQR(vec.x()) + SQR(vec.y())); 00310 if (length == 0.0) 00311 { 00312 node_ptr = NULL; 00313 edge_ptr = NULL; 00314 tri_ptr = NULL; 00315 return NO_ISECT; 00316 } 00317 vec.x( vec.x() / length ); 00318 vec.y( vec.y() / length ); 00319 dot = edge_vec.x() * vec.x() + edge_vec.y() * vec.y(); 00320 if (fabs(dot) < ON_LINE_TOL) { 00321 node_ptr = n2_ptr; 00322 isect_type = AT_MID; 00323 return isect_type; 00324 } 00325 00326 if (dot > -ON_LINE_TOL){ 00327 node_ptr = NULL; 00328 edge_ptr = n1_ptr->shared_edge( n2_ptr ); 00329 isect_type = AT_EDGE; 00330 return isect_type; 00331 } 00332 } 00333 } 00334 00335 if (!found) 00336 { 00337 isect_type = NO_ISECT; 00338 node_ptr = NULL; 00339 edge_ptr = NULL; 00340 tri_ptr = NULL; 00341 } 00342 00343 return isect_type; 00344 } 00345 00346 //----------------------------------------------------------------------------- 00347 // Function: intersect_from_edge 00348 // Type: Private 00349 // Description: determine next intersection assuming start from edge_ptr 00350 // Author: sjowen 00351 // Date: 2/17/02 00352 //----------------------------------------------------------------------------- 00353 template <class SURF, class TRI, class EDGE, class NODE, class TRICHILD> 00354 IntersectionType BoundaryConstrainTool<SURF,TRI,EDGE,NODE,TRICHILD>::intersect_from_edge( 00355 CubitVector &edge_vec, 00356 NODE *n0_ptr, 00357 NODE *n1_ptr, 00358 TRI * &tri_ptr, 00359 EDGE *&edge_ptr, 00360 NODE *&node_ptr ) 00361 { 00362 IntersectionType isect_type = NO_ISECT; 00363 assert( edge_ptr != NULL && tri_ptr != NULL); 00364 00365 // Get the adjacent face to the edge - there must be exactly two faces 00366 // next to this edge otherwise we've left the triangulation 00367 00368 DLIList<TRI *> adjtris; 00369 edge_ptr->tris( adjtris ); 00370 if (adjtris.size() != 2) 00371 return NO_ISECT; 00372 TRI * nexttri_ptr = adjtris.get_and_step(); 00373 if (nexttri_ptr == tri_ptr) 00374 { 00375 nexttri_ptr = adjtris.get(); 00376 assert(nexttri_ptr != NULL && nexttri_ptr != tri_ptr); 00377 } 00378 tri_ptr = nexttri_ptr; 00379 00380 // Check if we've arrived at the end (Does the this triangle contain n1) 00381 00382 int ii; 00383 NODE *n_ptr[3]; 00384 nexttri_ptr->tri_nodes( n_ptr[0], n_ptr[1], n_ptr[2] ); 00385 CubitBoolean found = CUBIT_FALSE; 00386 for (ii=0; ii<3 && !found; ii++) { 00387 if (n_ptr[ii] == n1_ptr) { 00388 found = CUBIT_TRUE; 00389 edge_ptr = NULL; 00390 node_ptr = n1_ptr; 00391 tri_ptr = nexttri_ptr; 00392 isect_type = AT_END; 00393 } 00394 } 00395 00396 // Determine which edge (or node) the vector intersects 00397 00398 if (!found) { 00399 NODE *tn0_ptr, *tn1_ptr, *tn2_ptr; 00400 tn0_ptr = edge_ptr->start_node(); 00401 tn1_ptr = edge_ptr->end_node(); 00402 tn2_ptr = tri_ptr->next_node(tn1_ptr); 00403 //Checking for CCW order. Correct it if it is wrong 00404 if(tn2_ptr == tn0_ptr){ 00405 tn0_ptr = tn1_ptr; 00406 tn1_ptr = tn2_ptr; 00407 tn2_ptr = tri_ptr->next_node(tn1_ptr); 00408 } 00409 00410 // Determine vector from n0 to tn2 00411 00412 CubitVector vec( tn2_ptr->coordinates().x() - n0_ptr->coordinates().x(), 00413 tn2_ptr->coordinates().y() - n0_ptr->coordinates().y(), 00414 0.0 ); 00415 double len = sqrt(SQR(vec.x()) + SQR(vec.y())); 00416 if (len == 0.0) 00417 return NO_ISECT; 00418 vec.x( vec.x()/len ); 00419 vec.y( vec.y()/len ); 00420 00421 // Compute the dot product of the normal to vec (above) 00422 // with the edgevec. 00423 // One of the following will result: 00424 // Dot > 0: edge defined by tn2 - tn0 is intersected 00425 // Dot < 0: edge defined by tn1 - tn2 is intersected 00426 // Dot = 0: node tn2 is intersected */ 00427 00428 vec.z( vec.x() ); 00429 vec.x( -vec.y() ); 00430 vec.y( vec.z() ); 00431 vec.z( 0.0 ); 00432 00433 double dot = vec.x() * edge_vec.x() + vec.y() * edge_vec.y(); 00434 00435 if (fabs(dot) < ON_LINE_TOL) { 00436 isect_type = AT_MID; 00437 edge_ptr = NULL; 00438 node_ptr = tn2_ptr; 00439 } 00440 else if (dot > 0) { 00441 isect_type = AT_EDGE; 00442 edge_ptr = tn0_ptr->shared_edge( tn2_ptr ); 00443 node_ptr = NULL; 00444 } 00445 else { 00446 isect_type = AT_EDGE; 00447 edge_ptr = tn1_ptr->shared_edge( tn2_ptr ); 00448 node_ptr = NULL; 00449 } 00450 } 00451 00452 return isect_type; 00453 } 00454 00455 //----------------------------------------------------------------------------- 00456 // Function: node_at_mid 00457 // Type: Private 00458 // Description: the vector hit a node on its way to the n1 00459 // Author: sjowen 00460 // Date: 2/17/02 00461 //----------------------------------------------------------------------------- 00462 template <class SURF, class TRI, class EDGE, class NODE, class TRICHILD> 00463 CubitStatus BoundaryConstrainTool<SURF,TRI,EDGE,NODE,TRICHILD>::node_at_mid( 00464 CubitVector &edge_vec, 00465 TRI * tri_ptr, 00466 NODE *node_ptr ) 00467 { 00468 // don't know what to do here yet 00469 return CUBIT_FAILURE; 00470 } 00471 00472 //----------------------------------------------------------------------------- 00473 // Function: swap_edge 00474 // Type: Private 00475 // Description: attempt to swap a single edge. Check for valid swap 00476 // before doing so 00477 // Author: sjowen 00478 // Date: 2/17/02 00479 //----------------------------------------------------------------------------- 00480 template <class SURF, class TRI, class EDGE, class NODE, class TRICHILD> 00481 SwapStatus BoundaryConstrainTool<SURF,TRI,EDGE,NODE,TRICHILD>::swap_edge( 00482 EDGE *&edge_ptr ) 00483 { 00484 00485 DLIList<TRI *>adjtris; 00486 edge_ptr->tris(refFacePtr, adjtris); 00487 if(adjtris.size() != 2) 00488 return SWAP_FAILURE; 00489 00490 // check the potential new triangles 00491 00492 TRI * tri0 = adjtris.get_and_step(); 00493 TRI * tri1 = adjtris.get(); 00494 NODE *n0, *n1, *n2, *n3; 00495 n0 = edge_ptr->start_node(); 00496 n1 = edge_ptr->end_node(); 00497 n2 = tri0 ->next_node(n1); 00498 //if direction is not in CCW order, correct it. 00499 if(n2 == n0){ 00500 n0 = n1; 00501 n1 = n2; 00502 n2 = tri0->next_node(n1); 00503 } 00504 n3 = tri1->next_node(n0); 00505 00506 CubitVector e1( n1->coordinates().x() - n3->coordinates().x(), 00507 n1->coordinates().y() - n3->coordinates().y(), 00508 0.0 ); 00509 double len = sqrt(SQR(e1.x()) + SQR(e1.y())); 00510 if (len == 0.0) 00511 return SWAP_FAILURE; 00512 e1.x( e1.x()/len ); e1.y( e1.y()/len ); 00513 CubitVector diag( n2->coordinates().x() - n3->coordinates().x(), 00514 n2->coordinates().y() - n3->coordinates().y(), 00515 0.0 ); 00516 len = sqrt(SQR(diag.x()) + SQR(diag.y())); 00517 if (len == 0.0) 00518 return SWAP_FAILURE; 00519 diag.x( diag.x()/len ); diag.y( diag.y()/len ); 00520 00521 CubitVector e2( n0->coordinates().x() - n3->coordinates().x(), 00522 n0->coordinates().y() - n3->coordinates().y(), 00523 0.0 ); 00524 len = sqrt(SQR(e2.x()) + SQR(e2.y())); 00525 if (len == 0.0) 00526 return SWAP_FAILURE; 00527 e2.x( e2.x()/len ); e2.y( e2.y()/len ); 00528 00529 // return now if we would create invalid triangles 00530 00531 double cross = e1.x() * diag.y() - e1.y() * diag.x(); 00532 if (cross < ON_LINE_TOL) 00533 return SWAP_INVALID; 00534 00535 cross = diag.x() * e2.y() - diag.y() * e2.x(); 00536 if (cross < ON_LINE_TOL) 00537 return SWAP_INVALID; 00538 00539 // Do the swap 00540 // Delete the old triangles 00541 00542 facetList->move_to(tri0); 00543 facetList->extract(); 00544 facetList->move_to(tri1); 00545 facetList->extract(); 00546 delete tri0; 00547 delete tri1; 00548 delete edge_ptr; 00549 00550 // Create the new triangles 00551 00552 tri0 = (TRI *) new TRICHILD( n1, n2, n3, refFacePtr); 00553 tri1 = (TRI *) new TRICHILD( n0, n3, n2, refFacePtr); 00554 facetList->append(tri0); 00555 facetList->append(tri1); 00556 edge_ptr = n2->shared_edge( n3 ); 00557 00558 return SWAP_SUCCESS; 00559 } 00560 00561 //----------------------------------------------------------------------------- 00562 // Function: edge_intersected 00563 // Type: Private 00564 // Description: check to see if the edge we just generated crosses the 00565 // edge_vec. If so, the add it to the queue 00566 // Author: sjowen 00567 // Date: 2/17/02 00568 //----------------------------------------------------------------------------- 00569 template <class SURF, class TRI, class EDGE, class NODE, class TRICHILD> 00570 CubitStatus BoundaryConstrainTool<SURF,TRI,EDGE,NODE,TRICHILD>::edge_intersected( 00571 CubitVector &edge_vec, 00572 EDGE *edge_ptr, 00573 NODE *n0_ptr, 00574 NODE *n1_ptr ) 00575 { 00576 00577 // if the end nodes match the end nodes of the edge we are checking, then 00578 // we are OK - no intersection 00579 00580 NODE *en0_ptr = edge_ptr->start_node(); 00581 NODE *en1_ptr = edge_ptr->end_node(); 00582 if (en0_ptr == n0_ptr || en1_ptr == n0_ptr || 00583 en0_ptr == n1_ptr || en1_ptr == n1_ptr) 00584 return CUBIT_SUCCESS; 00585 00586 CubitVector vec1( en0_ptr->coordinates().x() - n0_ptr->coordinates().x(), 00587 en0_ptr->coordinates().y() - n0_ptr->coordinates().y(), 00588 0.0 ); 00589 double len = sqrt( SQR( vec1.x() ) + SQR( vec1.y() ) ); 00590 if (len == 0.0) 00591 return CUBIT_FAILURE; 00592 vec1.x( vec1.x() / len ); vec1.y( vec1.y() / len ); 00593 00594 CubitVector vec2( en1_ptr->coordinates().x() - n0_ptr->coordinates().x(), 00595 en1_ptr->coordinates().y() - n0_ptr->coordinates().y(), 00596 0.0 ); 00597 len = sqrt( SQR( vec2.x() ) + SQR( vec2.y() ) ); 00598 if (len == 0.0) 00599 return CUBIT_FAILURE; 00600 vec2.x( vec2.x() / len ); vec2.y( vec2.y() / len ); 00601 00602 double cross1 = edge_vec.x() * vec1.y() - edge_vec.y() * vec1.x(); 00603 double cross2 = edge_vec.x() * vec2.y() - edge_vec.y() * vec2.x(); 00604 00605 // if the en0 and en1 are both on opposite sides of edge_vec then 00606 // we know that it intersects somewhere 00607 00608 if (cross1 * cross2 <= 0.0) 00609 { 00610 edgeCrossQueue.append( edge_ptr ); 00611 } 00612 00613 return CUBIT_SUCCESS; 00614 } 00615 // EOF