cgma
|
00001 //------------------------------------------------------------------------- 00002 //- Filename: CollapseCurveTool 00003 //- Purpose: To collapse small curves for preparing for mesh 00004 //- "collapse curve <id> vertex <id>\n", 00005 //- 00006 //- Creator: Brett Clark 00007 //- Creation date: 01/10/2006 00008 //------------------------------------------------------------------------- 00009 00010 // ********** BEGIN STANDARD INCLUDES ********** 00011 // ********** END STANDARD INCLUDES ********** 00012 00013 // ********** BEGIN MOTIF INCLUDES ********** 00014 // ********** END MOTIF INCLUDES ********** 00015 00016 // ********** BEGIN CUBIT INCLUDES ********** 00017 #include "GMem.hpp" 00018 #include "RefVertex.hpp" 00019 #include "RefEdge.hpp" 00020 #include "DLIList.hpp" 00021 #include "CoEdge.hpp" 00022 #include "CoFace.hpp" 00023 #include "Shell.hpp" 00024 #include "Point.hpp" 00025 #include "Loop.hpp" 00026 #include "RefFace.hpp" 00027 #include "Body.hpp" 00028 #include "PartitionTool.hpp" 00029 #include "CompositeTool.hpp" 00030 #include "CollapseCurveTool.hpp" 00031 #include "GeometryModifyTool.hpp" 00032 #include "SplitCompositeSurfaceTool.hpp" 00033 #include "CubitUndo.hpp" 00034 #include "CubitMessage.hpp" 00035 //#include "InteropTool.hpp" 00036 00037 /* 00038 */ 00039 // ********** END CUBIT INCLUDES ********** 00040 00041 CollapseCurveTool *CollapseCurveTool::instance_ = NULL; 00042 00043 // ********** BEGIN PUBLIC FUNCTIONS ********** 00044 CollapseCurveTool *CollapseCurveTool::instance() 00045 { 00046 if (instance_ == NULL) 00047 instance_ = new CollapseCurveTool(); 00048 00049 return instance_; 00050 } 00051 00052 CubitStatus CollapseCurveTool::collapse_curve_only_virtual(DLIList <RefEdge*> ref_edge_list, 00053 DLIList<RefVertex*> ref_vertex_list, 00054 int ignore_surfaces, 00055 double *small_curve_size) 00056 { 00057 CubitStatus result = CUBIT_SUCCESS; 00058 00059 RefEdge *edge_to_collapse = ref_edge_list.get(); 00060 RefVertex *keep_vertex = NULL; 00061 RefVertex *discard_vertex = NULL; 00062 CoEdge *exit_coedge = NULL; 00063 CoEdge *enter_coedge = NULL; 00064 DLIList<RefEdge*> curves_to_partition; 00065 DLIList<RefFace*> surfaces_to_partition; 00066 DLIList<CubitVector> partition_positions; 00067 DLIList<CubitVector> keep_vecs; 00068 DLIList<CubitVector> partition_curve_vecs; 00069 DLIList<RefFace*> adjacent_surfaces; 00070 DLIList<double> angles; 00071 DLIList<double> arc_lengths; 00072 DLIList<RefEdge*> ref_edges_on_discard_vertex; 00073 DLIList<RefEdge*> ref_edges_on_keep_vertex; 00074 DLIList<RefVertex*> new_partition_vertices; 00075 DLIList<RefEdge*> new_partition_edges; 00076 RefEdge *close_edge = NULL; 00077 RefEdge *far_edge = NULL; 00078 DLIList<RefEdge*> edges_to_composite; 00079 int keep_vertex_specified = 0; 00080 int discard_valency = 0; 00081 int keep_valency = 0; 00082 int finished = 0; 00083 double arc_length = 0; 00084 double u = 0, v = 0; 00085 CubitVector left_vec(0,0,0), right_vec(0,0,0); 00086 CubitVector position_on_left_curve(0,0,0), position_on_right_curve(0,0,0); 00087 CubitVector discard_pos(0,0,0), keep_pos(0,0,0); 00088 00089 bool undo_state = CubitUndo::get_undo_enabled(); 00090 if( undo_state ) 00091 CubitUndo::save_state_with_cubit_file( ref_edge_list ); 00092 CubitUndo::set_undo_enabled(false); 00093 00094 if(edge_to_collapse == NULL) 00095 { 00096 PRINT_ERROR("No curve was found to collapse.\n"); 00097 finished = 1; 00098 result = CUBIT_FAILURE; 00099 } 00100 00101 if(!finished) 00102 { 00103 // Make sure we have a vertex to keep. 00104 if(ref_vertex_list.size() > 0) 00105 { 00106 keep_vertex_specified = 1; 00107 keep_vertex = ref_vertex_list.get(); 00108 } 00109 // We need to choose a vertex to keep. 00110 else 00111 { 00112 // Arbitrarily choose start vertex. 00113 keep_vertex = edge_to_collapse->start_vertex(); 00114 } 00115 00116 // Get the vertex that will go away. 00117 if(keep_vertex == edge_to_collapse->start_vertex()) 00118 { 00119 discard_vertex = edge_to_collapse->end_vertex(); 00120 } 00121 else if(keep_vertex == edge_to_collapse->end_vertex()) 00122 { 00123 discard_vertex = edge_to_collapse->start_vertex(); 00124 } 00125 else 00126 { 00127 PRINT_ERROR("Vertex to keep was not found on the curve being collapsed.\n"); 00128 result = CUBIT_FAILURE; 00129 finished = 1; 00130 } 00131 } 00132 00133 if(!finished) 00134 { 00135 // Get the valency of the keep and discard vertices. 00136 discard_vertex->ref_edges(ref_edges_on_discard_vertex); 00137 keep_vertex->ref_edges(ref_edges_on_keep_vertex); 00138 discard_valency = ref_edges_on_discard_vertex.size(); 00139 keep_valency = ref_edges_on_keep_vertex.size(); 00140 00141 // Now do some error checking and also some logic to try to 00142 // pick the best vertex to keep/discard. 00143 00144 // If one of the valencies is 2 just composite the vertex out. 00145 if(discard_valency == 2) 00146 { 00147 CompositeTool::instance()->composite(ref_edges_on_discard_vertex); 00148 finished = 1; 00149 } 00150 else if (keep_valency == 2) 00151 { 00152 CompositeTool::instance()->composite(ref_edges_on_keep_vertex); 00153 finished = 1; 00154 } 00155 else 00156 { 00157 // Make sure that at least one of the vertices is qualified to 00158 // be the discard vertex (valency of 3 or 4). The keep vertex 00159 // really doesn't have any restrictions. 00160 if((discard_valency > 4 || discard_valency < 3) && 00161 (keep_valency > 4 || keep_valency < 3)) 00162 { 00163 PRINT_ERROR("Cannot currently collapse curves where one of the vertices does not have a valency equal to 3 or 4.\n"); 00164 result = CUBIT_FAILURE; 00165 finished = 1; 00166 } 00167 else 00168 { 00169 if(keep_vertex_specified) 00170 { 00171 if(discard_valency < 3 || discard_valency > 4) 00172 { 00173 PRINT_ERROR("Cannot currently collapse curves where the discard vertex valency is not 3 or 4.\n" 00174 "Try specifying the keep vertex so that the discard vertex is 3 or 4.\n"); 00175 result = CUBIT_FAILURE; 00176 finished = 1; 00177 } 00178 } 00179 else 00180 { 00181 // The user didn't specify a keep vertex so we can try to choose the best one. 00182 00183 int swap_vertices = 0; 00184 if(discard_valency < 5 && discard_valency > 2 && 00185 keep_valency < 5 && keep_valency > 2) 00186 { 00187 // Either vertex can be the discard/keep vertex so choose the one with the 00188 // lower valency as the discard vertex because it will require fewer operations. 00189 if(discard_valency > keep_valency) 00190 { 00191 swap_vertices = 1; 00192 } 00193 } 00194 else 00195 { 00196 // Only one of the vertices can be the discard vertex so pick it. 00197 if(discard_valency > 4 || discard_valency < 3) 00198 { 00199 swap_vertices = 1; 00200 } 00201 } 00202 00203 if(swap_vertices) 00204 { 00205 // Swap the vertices. 00206 RefVertex *tmp = discard_vertex; 00207 discard_vertex = keep_vertex; 00208 keep_vertex = tmp; 00209 00210 // Make sure to refresh the discard vertex edge list because 00211 // it is used below. 00212 ref_edges_on_discard_vertex.clean_out(); 00213 discard_vertex->ref_edges(ref_edges_on_discard_vertex); 00214 } 00215 } 00216 } 00217 } 00218 } 00219 00220 if(!finished && small_curve_size) 00221 { 00222 // Check if the edges attached to the discard vertex are longer 00223 // than the small curve size. 00224 DLIList<RefEdge*> tmp_edges; 00225 discard_vertex->ref_edges(tmp_edges); 00226 if(tmp_edges.move_to(edge_to_collapse)) 00227 tmp_edges.extract(); 00228 int y; 00229 bool all_edges_long_enough = true; 00230 for(y=tmp_edges.size(); y && all_edges_long_enough; y--) 00231 { 00232 RefEdge *cur_edge = tmp_edges.get_and_step(); 00233 if(cur_edge->get_arc_length() <= *small_curve_size) 00234 all_edges_long_enough = false; 00235 } 00236 if(!all_edges_long_enough) 00237 { 00238 PRINT_ERROR("Cannot collapse curve %d to vertex %d--not all of the curves attached to\n" 00239 "vertex %d are longer than the small_curve_size. Try collapsing to vertex %d instead.\n", 00240 edge_to_collapse->id(), keep_vertex->id(), discard_vertex->id(), discard_vertex->id()); 00241 result = CUBIT_FAILURE; 00242 finished = 1; 00243 } 00244 } 00245 00246 // Look at all of the coedges on the curve being collapsed and 00247 // throw out any that are on nonmanifold surfaces. The collapse 00248 // curve may be on a boundary of a merged surface. This is ok 00249 // but we want to make sure we don't involve this surface 00250 // in the partitions and composites so we will remove from the 00251 // list any coedges that are hooked to merged surfaces. 00252 if(!finished) 00253 { 00254 DLIList<CoEdge*> collapse_curve_coedges; 00255 edge_to_collapse->get_co_edges(collapse_curve_coedges); 00256 00257 int initial_size = collapse_curve_coedges.size(); 00258 while(collapse_curve_coedges.size() > 2 && initial_size > 0) 00259 { 00260 for(int g=collapse_curve_coedges.size(); g--;) 00261 { 00262 CoEdge *cur_coedge = collapse_curve_coedges.get_and_step(); 00263 Loop *loop_ptr = cur_coedge->get_loop_ptr(); 00264 if(loop_ptr) 00265 { 00266 RefFace *ref_face_ptr = loop_ptr->get_ref_face_ptr(); 00267 if(ref_face_ptr) 00268 { 00269 DLIList<CoFace*> coface_list; 00270 ref_face_ptr->co_faces(coface_list); 00271 if(coface_list.size() > 1) 00272 { 00273 collapse_curve_coedges.remove(cur_coedge); 00274 g = 0; 00275 } 00276 } 00277 } 00278 } 00279 00280 // Keep from looping infinitely. 00281 initial_size--; 00282 } 00283 00284 // If we get to this point and have more than 2 coedges left 00285 // in the list we are not sure what to do. 00286 if(collapse_curve_coedges.size() != 2) 00287 { 00288 PRINT_ERROR("Currently can only collapse curves with manifold topology.\n"); 00289 result = CUBIT_FAILURE; 00290 finished = 1; 00291 } 00292 else 00293 { 00294 // Get the collapse curve coedges entering and leaving the discard vertex. 00295 exit_coedge = collapse_curve_coedges.get_and_step(); 00296 enter_coedge = collapse_curve_coedges.get(); 00297 if(enter_coedge->end_vertex() != discard_vertex) 00298 { 00299 CoEdge *tmp = exit_coedge; 00300 exit_coedge = enter_coedge; 00301 enter_coedge = tmp; 00302 } 00303 } 00304 } 00305 00306 // Next we need to explore the topology around the discard vertex 00307 // so that we can get the edges and surfaces that will be involved 00308 // with the partitioning and compositing. We will identify a "left" 00309 // and "right" edge coming out of the discard vertex and adjacent 00310 // surfacs to these edges. 00311 if(!finished) 00312 { 00313 // Get these values for use later on. 00314 discard_pos = discard_vertex->get_point_ptr()->coordinates(); 00315 keep_pos = keep_vertex->get_point_ptr()->coordinates(); 00316 CubitVector discard_to_keep = keep_pos - discard_pos; 00317 arc_length = edge_to_collapse->get_arc_length(); 00318 00319 // Depending on whether the discard vertex has valency of 3 or 4 we will 00320 // either partition 1 or 2 of the curves coming into the discard vertex 00321 // respectively. Set up lists so that below we can just loop through the 00322 // partitioning and compositing for either the 3 or 4 valency case. 00323 00324 // "Left" and "right" will be defined as if you were standing on the 00325 // keep vertex looking at the discard vertex. 00326 Loop *left_loop = enter_coedge->get_loop_ptr(); 00327 Loop *right_loop = exit_coedge->get_loop_ptr(); 00328 DLIList<SenseEntity*> left_sense_entities, right_sense_entities; 00329 left_loop->get_sense_entity_list(left_sense_entities); 00330 right_loop->get_sense_entity_list(right_sense_entities); 00331 00332 // We need to get these two coedges because the chains defined by the "next" and 00333 // "previous" pointers in the CoEdge objects are not circular (you can have a NULL 00334 // "previous" or "next" pointer). We will manage the circularity manually. 00335 CoEdge *left_start = dynamic_cast<CoEdge*>(left_loop->get_first_sense_entity_ptr()); 00336 CoEdge *right_end = dynamic_cast<CoEdge*>(right_loop->get_last_sense_entity_ptr()); 00337 00338 CoEdge *left_coedge = dynamic_cast<CoEdge*>(enter_coedge->next()); 00339 if(left_coedge == NULL) 00340 { 00341 left_coedge = left_start; 00342 } 00343 CoEdge *right_coedge = dynamic_cast<CoEdge*>(exit_coedge->previous()); 00344 if(right_coedge == NULL) 00345 { 00346 right_coedge = right_end; 00347 } 00348 00349 RefEdge *left_edge = left_coedge->get_ref_edge_ptr(); 00350 RefEdge *right_edge = right_coedge->get_ref_edge_ptr(); 00351 RefFace *left_common_face = left_edge->common_ref_face(edge_to_collapse); 00352 RefFace *right_common_face = right_edge->common_ref_face(edge_to_collapse); 00353 00354 double left_arc_length = left_edge->get_arc_length(); 00355 double right_arc_length = right_edge->get_arc_length(); 00356 int left_ok = 1; 00357 int right_ok = 1; 00358 00359 DLIList<RefEdge*> left_face_edges; 00360 DLIList<RefEdge*> right_face_edges; 00361 left_common_face->ref_edges(left_face_edges); 00362 right_common_face->ref_edges(right_face_edges); 00363 if(left_face_edges.size() < 3 || right_face_edges.size() < 3 || 00364 left_sense_entities.size() < 3 || right_sense_entities.size() < 3) 00365 { 00366 PRINT_ERROR("Cannot collapse a curve that bounds a face or loop with only two edges.\n"); 00367 finished = 1; 00368 } 00369 else 00370 { 00371 // We use the length of the curve being collapsed as the distance 00372 // to partition the adjacent curves connected to it. If the 00373 // adjacent curves are shorter than the curve being collapsed we 00374 // will bail because the user should probably be getting rid 00375 // of the adjacent edges instead or at least first. 00376 00377 // Get the length of the adjacent curves. 00378 00379 // If the adjacent curve is within resabs of the length of 00380 // the curve being collapsed we will just snap to the end 00381 // of the adjacent curve for our partition position. 00382 if(arc_length > left_arc_length + GEOMETRY_RESABS) 00383 { 00384 left_ok = 0; 00385 } 00386 if(arc_length > right_arc_length + GEOMETRY_RESABS) 00387 { 00388 right_ok = 0; 00389 } 00390 00391 // If neither curve is ok we need to bail. 00392 if(!left_ok && !right_ok) 00393 { 00394 PRINT_ERROR("Curve being collapsed is too long compared to adjacent curves.\n"); 00395 finished = 1; 00396 } 00397 } 00398 00399 // If it looks like the lengths of the adjacent curves are 00400 // ok we will go ahead and try to find a partition position 00401 // on them. 00402 if(!finished) 00403 { 00404 if(left_ok) 00405 { 00406 // First see if we can just use the end point of the 00407 // adjacent curve as the partition position. 00408 if(fabs(left_arc_length-arc_length) < GEOMETRY_RESABS) 00409 { 00410 if(left_edge->start_vertex() == discard_vertex) 00411 position_on_left_curve = left_edge->end_vertex()->coordinates(); 00412 else 00413 position_on_left_curve = left_edge->start_vertex()->coordinates(); 00414 } 00415 else 00416 { 00417 result = this->position_from_length(left_edge, discard_vertex, 00418 arc_length, position_on_left_curve); 00419 } 00420 } 00421 if(result == CUBIT_SUCCESS && right_ok) 00422 { 00423 // First see if we can just use the end point of the 00424 // adjacent curve as the partition position. 00425 if(fabs(right_arc_length-arc_length) < GEOMETRY_RESABS) 00426 { 00427 if(right_edge->start_vertex() == discard_vertex) 00428 position_on_right_curve = right_edge->end_vertex()->coordinates(); 00429 else 00430 position_on_right_curve = right_edge->start_vertex()->coordinates(); 00431 } 00432 else 00433 { 00434 result = this->position_from_length(right_edge, discard_vertex, 00435 arc_length, position_on_right_curve); 00436 } 00437 } 00438 if(result == CUBIT_FAILURE) 00439 { 00440 PRINT_ERROR("Was unable to locate appropriate partition points on curves adjacent to curve being collapased.\n"); 00441 finished = 1; 00442 } 00443 } 00444 00445 if(!finished) 00446 { 00447 // Get the vectors from the discard vertex to the potential partition locations. 00448 CubitVector left_vec = position_on_left_curve - discard_pos; 00449 CubitVector right_vec = position_on_right_curve - discard_pos; 00450 00451 // Calculate the angles between the left/right edge and the 00452 // edge being collapsed. I am doing it this way rather than just 00453 // calling RefEdge::angle_between() because I want the angle 00454 // calculation done out at the potential partition location. 00455 // This will step over any small kinks in the curve near the 00456 // discard vertex that might otherwise give misleading angles 00457 // that don't represent what is happening out by the potential 00458 // partition position. 00459 left_common_face->u_v_from_position(discard_pos, u, v); 00460 CubitVector left_normal = left_common_face->normal_at(discard_pos, NULL, &u, &v); 00461 double left_angle = left_normal.vector_angle(left_vec, discard_to_keep); 00462 00463 right_common_face->u_v_from_position(discard_pos, u, v); 00464 CubitVector right_normal = right_common_face->normal_at(discard_pos, NULL, &u, &v); 00465 double right_angle = right_normal.vector_angle(discard_to_keep, right_vec); 00466 00467 // 3 valency case: 00468 // We only need to partition one of the curves (left or right) and 00469 // the corresponding surface. 00470 if(ref_edges_on_discard_vertex.size() == 3) 00471 { 00472 int use_left = 0; 00473 // We can use either adjacent curve. 00474 if(left_ok && right_ok) 00475 { 00476 // Choose the side with the smaller angle as this will in general 00477 // give better angles for doing the partitioning on the surface. 00478 if(left_angle < right_angle) 00479 { 00480 use_left = 1; 00481 } 00482 } 00483 else if(left_ok) 00484 { 00485 use_left = 1; 00486 } 00487 if(use_left) 00488 { 00489 curves_to_partition.append(left_edge); 00490 surfaces_to_partition.append(left_common_face); 00491 angles.append(left_angle); 00492 partition_positions.append(position_on_left_curve); 00493 arc_lengths.append(arc_length); 00494 00495 // These vectors will be used in calculating a bisector direction 00496 // below if necessary. 00497 keep_vecs.append(-discard_to_keep); 00498 partition_curve_vecs.append(left_vec); 00499 } 00500 else 00501 { 00502 curves_to_partition.append(right_edge); 00503 surfaces_to_partition.append(right_common_face); 00504 angles.append(right_angle); 00505 partition_positions.append(position_on_right_curve); 00506 arc_lengths.append(arc_length); 00507 00508 // These vectors will be used in calculating a bisector direction 00509 // below if necessary. 00510 keep_vecs.append(discard_to_keep); 00511 partition_curve_vecs.append(-right_vec); 00512 } 00513 } 00514 else if(ref_edges_on_discard_vertex.size() == 4) 00515 { 00516 // We have to partition both left and right curves so make 00517 // sure we can. 00518 if(!left_ok || !right_ok) 00519 { 00520 PRINT_ERROR("One of the curves adjacent to the collapse curve is not long enough for the collapse operation.\n"); 00521 finished = 1; 00522 } 00523 else 00524 { 00525 // Both curves (and surfaces) adjacent to the collapse curve (left and right) 00526 // will need to be partitioned so add them to the lists. 00527 00528 curves_to_partition.append(left_edge); 00529 curves_to_partition.append(right_edge); 00530 surfaces_to_partition.append(left_common_face); 00531 surfaces_to_partition.append(right_common_face); 00532 angles.append(left_angle); 00533 angles.append(right_angle); 00534 keep_vecs.append(-discard_to_keep); 00535 keep_vecs.append(discard_to_keep); 00536 partition_curve_vecs.append(left_vec); 00537 partition_curve_vecs.append(-right_vec); 00538 partition_positions.append(position_on_left_curve); 00539 partition_positions.append(position_on_right_curve); 00540 arc_lengths.append(arc_length); 00541 arc_lengths.append(arc_length); 00542 } 00543 } 00544 else 00545 { 00546 PRINT_ERROR("Currently can only collapse curves with 3 or 4 valency vertices.\n"); 00547 result = CUBIT_FAILURE; 00548 finished = 1; 00549 } 00550 } 00551 } 00552 00553 if(!finished) 00554 { 00555 int num_reps = curves_to_partition.size(); 00556 curves_to_partition.reset(); 00557 surfaces_to_partition.reset(); 00558 for(int n=0; n<num_reps && !finished; ++n) 00559 { 00560 RefEdge *side_edge = curves_to_partition.get_and_step(); 00561 RefFace *side_face = surfaces_to_partition.get_and_step(); 00562 00563 // Now we need to find the face on the other side of the edge. 00564 // Because there may be edges on the boundaries of merged surfaces 00565 // we want to find the 00566 // face on the left/right edge that isn't the face shared by 00567 // the collapse edge and isn't nonmanifold. 00568 DLIList<CoEdge*> side_edge_coedges; 00569 side_edge->co_edges(side_edge_coedges); 00570 DLIList<RefFace*> possible_adj_faces; 00571 00572 // First loop through and get all of the potential faces. 00573 for(int r=side_edge_coedges.size(); r--;) 00574 { 00575 CoEdge *cur_coedge = side_edge_coedges.get_and_step(); 00576 if(cur_coedge && 00577 cur_coedge->get_loop_ptr() && 00578 cur_coedge->get_loop_ptr()->get_ref_face_ptr()) 00579 { 00580 RefFace *cur_ref_face = cur_coedge->get_loop_ptr()->get_ref_face_ptr(); 00581 if(cur_ref_face != side_face) 00582 { 00583 DLIList<CoFace*> coface_list; 00584 cur_ref_face->co_faces(coface_list); 00585 00586 // Along with checking for whether the face is manifold we need 00587 // to check if it belongs to the same volume as the side face. 00588 // We have to check this because we can't composite faces 00589 // from different volumes and these faces will be involved in 00590 // a composite below. 00591 if(coface_list.size() == 1 && 00592 side_face->ref_volume() == cur_ref_face->ref_volume()) 00593 { 00594 possible_adj_faces.append(cur_ref_face); 00595 } 00596 } 00597 } 00598 } 00599 00600 // If we ended up with more than one face in the list it isn't clear 00601 // what we should do so bail out. 00602 if(possible_adj_faces.size() != 1) 00603 { 00604 PRINT_ERROR("Couldn't figure out how to perform the collapse curve with the current topology.\n"); 00605 result = CUBIT_FAILURE; 00606 finished = 1; 00607 } 00608 else 00609 { 00610 adjacent_surfaces.append(possible_adj_faces.get()); 00611 } 00612 } 00613 } 00614 00615 if(!finished) 00616 { 00617 // At this point we should know which curves and surfaces we need 00618 // to partition. 00619 00620 int num_reps = curves_to_partition.size(); 00621 curves_to_partition.reset(); 00622 surfaces_to_partition.reset(); 00623 adjacent_surfaces.reset(); 00624 angles.reset(); 00625 keep_vecs.reset(); 00626 partition_curve_vecs.reset(); 00627 partition_positions.reset(); 00628 arc_lengths.reset(); 00629 00630 for(int i=0; i<num_reps && !finished; ++i) 00631 { 00632 RefEdge *curve_to_partition = curves_to_partition.get_and_step(); 00633 00634 // As we process each curve remove it from the list so that 00635 // at the end we can take the last one in the list and composite 00636 // it with the curve being collapsed. 00637 ref_edges_on_discard_vertex.remove(curve_to_partition); 00638 00639 CubitVector position_on_curve = partition_positions.get_and_step(); 00640 00641 // Partition the curve adjacent to the collapse curve. 00642 RefEdge *edge1, *edge2; 00643 RefVertex *new_vertex = PartitionTool::instance()-> 00644 partition( curve_to_partition, position_on_curve, edge1, edge2 ); 00645 00646 // Keep track of these in case we need to undo the partitioning. 00647 if(new_vertex) 00648 { 00649 new_partition_vertices.append(new_vertex); 00650 } 00651 00652 // Get the two new curves and classify them as close and far. 00653 if(edge1 && edge2) 00654 { 00655 close_edge = edge1; 00656 far_edge = edge2; 00657 if(close_edge->start_vertex() != discard_vertex && 00658 close_edge->end_vertex() != discard_vertex) 00659 { 00660 RefEdge *tmp = close_edge; 00661 close_edge = far_edge; 00662 far_edge = tmp; 00663 } 00664 } 00665 else 00666 { 00667 // If the partition didn't create a new vertex and two new curves 00668 // (the case when the partition position lands on an existing 00669 // vertex) just classify the curve as "close" and set the 00670 // "far" curve to NULL. 00671 close_edge = curve_to_partition; 00672 far_edge = NULL; 00673 } 00674 00675 RefFace *surface_to_partition = surfaces_to_partition.get_and_step(); 00676 00677 DLIList<CubitVector*> positions; 00678 00679 // Add the point on the curve we just partitioned. The other 00680 // point we normally need to add is the keep_vertex. However, 00681 // if the angle between the collapse curve and the curve we 00682 // just partitioned dictates that we need to introduce more points 00683 // (this would be cases where the angle is large and just partitioning the 00684 // surface with one curve--two points--would result in a very skinny 00685 // surface) we need to add them before adding the keep_vertex. Therefore, check 00686 // that now and add the extra points if needed. 00687 positions.append(new CubitVector(position_on_curve)); 00688 00689 double cur_angle = angles.get_and_step(); 00690 arc_length = arc_lengths.get_and_step(); 00691 00692 // These vectors are only used in the block below if we need to 00693 // add extra points but we need to always retrieve them from the lists 00694 // so that the pointer in the list stays in sync with the "for" loop. 00695 CubitVector keep_vec = keep_vecs.get_and_step(); 00696 CubitVector partition_vec = partition_curve_vecs.get_and_step(); 00697 00698 // Greater than 3*PI/2--add 3 interior points. Two of these 00699 // points will be generated by projecting from the discard vertex 00700 // into the surface normal to the vector from the discard vertex 00701 // to the keep point and new partition point respectively. The third 00702 // point will be obtained by projecting from the discard point in the 00703 // direction of the bisector angle of the two previous projections. 00704 if(cur_angle > 4.71) 00705 { 00706 // Get the u,v position of the discard vertex on this surface. 00707 surface_to_partition->u_v_from_position(discard_pos, u, v); 00708 00709 // Get the normal at the discard vertex. 00710 CubitVector normal = surface_to_partition->normal_at(discard_pos, NULL, &u, &v); 00711 normal.normalize(); 00712 00713 // We need to calculate a bisector direction between the 00714 // collape edge and the edge we just partitioned. We will do 00715 // this using the face normal at the discard vertex and the vectors 00716 // we calculated previously with the partition points. Cross 00717 // the face normal into the the direction vectors at the 00718 // discard and partition points to get two vectors pointing 00719 // into the face and then average those two to get the 00720 // bisector direction. This is all approximate but should 00721 // be sufficient for locating another point for partitioning 00722 // the surface. 00723 00724 // I am not normalizing the result here because they should 00725 // be roughly the same length and it shouldn't affect 00726 // the average too much. 00727 CubitVector vec1 = normal * partition_vec; 00728 CubitVector vec2 = normal * keep_vec; 00729 00730 // Get the bisector direction. 00731 CubitVector bisector_dir = vec1 + vec2; 00732 bisector_dir.normalize(); 00733 00734 // Now normalise these because they will be used to 00735 // project two of the new interior points. 00736 vec1.normalize(); 00737 vec2.normalize(); 00738 00739 CubitVector new_pos1 = discard_pos + (arc_length*vec1); 00740 CubitVector mid_pos = discard_pos + (arc_length * bisector_dir); 00741 CubitVector new_pos2 = discard_pos + (arc_length*vec2); 00742 00743 // Use the u,v from the discard vertex because it is fairly 00744 // close to the new position and will at least provide a 00745 // meaningful starting point. 00746 double save_u = u, save_v = v; 00747 surface_to_partition->move_to_surface(new_pos1, &u, &v); 00748 u = save_u; v = save_v; 00749 surface_to_partition->move_to_surface(mid_pos, &u, &v); 00750 u = save_u; v = save_v; 00751 surface_to_partition->move_to_surface(new_pos2, &u, &v); 00752 00753 // Add the new position to the list of partition points. 00754 positions.append(new CubitVector(new_pos1)); 00755 positions.append(new CubitVector(mid_pos)); 00756 positions.append(new CubitVector(new_pos2)); 00757 } 00758 // Greater than 3*PI/4 and less than 3*PI/2--add one interior point 00759 else if(cur_angle > 2.4) 00760 { 00761 CubitVector third_pt; 00762 00763 // Get the u,v position of the discard vertex on this surface. 00764 surface_to_partition->u_v_from_position(discard_pos, u, v); 00765 00766 // Get the normal at the discard vertex. 00767 CubitVector normal = surface_to_partition->normal_at(discard_pos, NULL, &u, &v); 00768 normal.normalize(); 00769 00770 // We need to calculate a bisector direction between the 00771 // collape edge and the edge we just partitioned. We will do 00772 // this using the face normal at the discard vertex and the vectors 00773 // we calculated previously with the partition points. Cross 00774 // the face normal into the the direction vectors at the 00775 // discard and partition points to get two vectors pointing 00776 // into the face and then average those two to get the 00777 // bisector direction. This is all approximate but should 00778 // be sufficient for locating another point for partitioning 00779 // the surface. 00780 00781 // I am not normalizing the result here because they should 00782 // be roughly the same length and it shouldn't affect 00783 // the average too much. 00784 CubitVector vec1 = normal * keep_vec; 00785 CubitVector vec2 = normal * partition_vec; 00786 00787 // Get the bisector direction. 00788 CubitVector bisector_dir = vec1 + vec2; 00789 bisector_dir.normalize(); 00790 00791 // Project from the discard vertex in the direction of the 00792 // bisector direction to get a new point for partitioning 00793 // the surface. 00794 CubitVector new_pos = discard_pos + (arc_length * bisector_dir); 00795 00796 // Use the u,v from the discard vertex because it is fairly 00797 // close to the new position and will at least provide a 00798 // meaningful starting point. 00799 surface_to_partition->move_to_surface(new_pos, &u, &v); 00800 00801 // Add the new position to the list of partition points. 00802 positions.append(new CubitVector(new_pos)); 00803 } 00804 00805 // Finally, add the keep_vertex to the list. 00806 positions.append(new CubitVector(keep_vertex->get_point_ptr()->coordinates())); 00807 00808 DLIList<RefEdge*> new_edges; 00809 PartitionTool::instance()-> 00810 insert_edge( surface_to_partition, positions, CUBIT_FALSE, new_edges, 00811 0, &arc_length); 00812 00813 // Keep for later in case we need to clean up. 00814 if(new_edges.size() > 0) 00815 { 00816 new_partition_edges += new_edges; 00817 } 00818 00819 delete positions.get_and_step(); 00820 delete positions.get_and_step(); 00821 00822 if(cur_angle > 4.71) 00823 { 00824 delete positions.get_and_step(); 00825 delete positions.get_and_step(); 00826 delete positions.get_and_step(); 00827 } 00828 else if(cur_angle > 2.4) 00829 { 00830 delete positions.get(); 00831 } 00832 00833 RefFace *new_small_face = edge_to_collapse->common_ref_face(close_edge); 00834 00835 if(!new_small_face) 00836 { 00837 PRINT_ERROR("Failed to do the partition surface operation of the collapse curve.\n"); 00838 result = CUBIT_FAILURE; 00839 finished = 1; 00840 } 00841 else 00842 { 00843 DLIList<RefFace*> result_faces; 00844 DLIList<RefFace*> faces_to_composite; 00845 00846 // Used below if "ignore" keyword was specified. 00847 int new_small_face_id = new_small_face->id(); 00848 00849 faces_to_composite.append(new_small_face); 00850 faces_to_composite.append(adjacent_surfaces.get_and_step()); 00851 00852 RefFace *new_comp_face = CompositeTool::instance()->composite(faces_to_composite); 00853 00854 CompositeSurface* csurf = NULL; 00855 00856 if(new_comp_face) 00857 { 00858 csurf = dynamic_cast<CompositeSurface*>(new_comp_face->get_surface_ptr()); 00859 } 00860 00861 if(!new_comp_face || !csurf) 00862 { 00863 PRINT_ERROR("Failed to do the composite surface operation of the collapse curve.\n"); 00864 result = CUBIT_FAILURE; 00865 finished = 1; 00866 } 00867 else 00868 { 00869 if(ignore_surfaces) 00870 { 00871 csurf->ignore_surface(new_small_face_id); 00872 } 00873 00874 if(far_edge) 00875 { 00876 for(int k=new_edges.size(); k--;) 00877 { 00878 edges_to_composite.append(new_edges.get_and_step()); 00879 } 00880 edges_to_composite.append(far_edge); 00881 00882 if(edges_to_composite.size() > 1) 00883 { 00884 CompositeTool::instance()->composite(edges_to_composite); 00885 } 00886 } 00887 00888 edges_to_composite.clean_out(); 00889 } 00890 } 00891 } 00892 00893 if(!finished) 00894 { 00895 ref_edges_on_discard_vertex.remove(edge_to_collapse); 00896 00897 // Now there should only be one edge in the ref_edges_on_discard_vertex 00898 // list. It should be the edge that hasn't had any modifications 00899 // done to it. We finally want to composite it with the edge 00900 // being collapsed. 00901 if(ref_edges_on_discard_vertex.size() != 1) 00902 { 00903 PRINT_ERROR("Wasn't able to complete collapse operation.\n"); 00904 result = CUBIT_FAILURE; 00905 finished = 1; 00906 } 00907 else 00908 { 00909 edges_to_composite.append(ref_edges_on_discard_vertex.get()); 00910 edges_to_composite.append(edge_to_collapse); 00911 CompositeTool::instance()->composite(edges_to_composite); 00912 } 00913 } 00914 } 00915 00916 CubitUndo::set_undo_enabled(undo_state); 00917 00918 return result; 00919 } 00920 00921 CubitStatus CollapseCurveTool::collapse_curve(DLIList <RefEdge*> ref_edge_list, 00922 DLIList<RefVertex*> ref_vertex_list, 00923 int ignore_surfaces, 00924 double *small_curve_size) 00925 { 00926 CubitStatus result = CUBIT_SUCCESS; 00927 00928 RefEdge *edge_to_collapse = ref_edge_list.get(); 00929 RefVertex *keep_vertex = NULL; 00930 RefVertex *discard_vertex = NULL; 00931 CoEdge *exit_coedge = NULL; 00932 CoEdge *enter_coedge = NULL; 00933 DLIList<RefEdge*> curves_to_partition; 00934 DLIList<RefFace*> surfaces_to_partition; 00935 DLIList<CubitVector> partition_positions; 00936 DLIList<CubitVector> keep_vecs; 00937 DLIList<CubitVector> partition_curve_vecs; 00938 DLIList<RefFace*> adjacent_surfaces; 00939 DLIList<double> angles; 00940 DLIList<double> arc_lengths; 00941 DLIList<RefEdge*> ref_edges_on_discard_vertex; 00942 DLIList<RefEdge*> ref_edges_on_keep_vertex; 00943 DLIList<RefVertex*> new_partition_vertices; 00944 DLIList<RefEdge*> new_partition_edges; 00945 RefEdge *close_edge = NULL; 00946 RefEdge *far_edge = NULL; 00947 DLIList<RefEdge*> edges_to_composite; 00948 int keep_vertex_specified = 0; 00949 int discard_valency = 0; 00950 int keep_valency = 0; 00951 int finished = 0; 00952 double arc_length = 0; 00953 double u = 0, v = 0; 00954 CubitVector left_vec(0,0,0), right_vec(0,0,0); 00955 CubitVector position_on_left_curve(0,0,0), position_on_right_curve(0,0,0); 00956 CubitVector discard_pos(0,0,0), keep_pos(0,0,0); 00957 Body *the_body; 00958 00959 bool undo_state = CubitUndo::get_undo_enabled(); 00960 if( undo_state ) 00961 CubitUndo::save_state_with_cubit_file( ref_edge_list ); 00962 CubitUndo::set_undo_enabled(false); 00963 00964 if(edge_to_collapse == NULL) 00965 { 00966 PRINT_ERROR("No curve was found to collapse.\n"); 00967 finished = 1; 00968 result = CUBIT_FAILURE; 00969 } 00970 00971 if(edge_to_collapse->is_merged()) 00972 { 00973 PRINT_ERROR("Cannot collapse a merged curve.\n"); 00974 finished = 1; 00975 result = CUBIT_FAILURE; 00976 } 00977 00978 if(edge_to_collapse->start_vertex()->is_merged() && 00979 edge_to_collapse->end_vertex()->is_merged()) 00980 { 00981 PRINT_ERROR("Cannot collapse a curve where both vertices are merged.\n"); 00982 finished = 1; 00983 result = CUBIT_FAILURE; 00984 } 00985 else if(edge_to_collapse->start_vertex()->is_merged()) 00986 { 00987 if(ref_vertex_list.size() > 0) 00988 { 00989 if(ref_vertex_list.get() == edge_to_collapse->end_vertex()) 00990 { 00991 PRINT_ERROR("Specified vertex to collapse to is merged--try using other vertex.\n"); 00992 finished = 1; 00993 result = CUBIT_FAILURE; 00994 } 00995 } 00996 else 00997 ref_vertex_list.append(edge_to_collapse->start_vertex()); 00998 } 00999 else if(edge_to_collapse->end_vertex()->is_merged()) 01000 { 01001 if(ref_vertex_list.size() > 0) 01002 { 01003 if(ref_vertex_list.get() == edge_to_collapse->start_vertex()) 01004 { 01005 PRINT_ERROR("Specified vertex to collapse to is merged--try using other vertex.\n"); 01006 finished = 1; 01007 result = CUBIT_FAILURE; 01008 } 01009 } 01010 else 01011 ref_vertex_list.append(edge_to_collapse->end_vertex()); 01012 } 01013 01014 if(!finished) 01015 { 01016 the_body = edge_to_collapse->body(); 01017 01018 // Make sure we have a vertex to keep. 01019 if(ref_vertex_list.size() > 0) 01020 { 01021 keep_vertex_specified = 1; 01022 keep_vertex = ref_vertex_list.get(); 01023 } 01024 // We need to choose a vertex to keep. 01025 else 01026 { 01027 // Arbitrarily choose start vertex. 01028 keep_vertex = edge_to_collapse->start_vertex(); 01029 } 01030 01031 // Get the vertex that will go away. 01032 if(keep_vertex == edge_to_collapse->start_vertex()) 01033 { 01034 discard_vertex = edge_to_collapse->end_vertex(); 01035 } 01036 else if(keep_vertex == edge_to_collapse->end_vertex()) 01037 { 01038 discard_vertex = edge_to_collapse->start_vertex(); 01039 } 01040 else 01041 { 01042 PRINT_ERROR("Vertex to keep was not found on the curve being collapsed.\n"); 01043 result = CUBIT_FAILURE; 01044 finished = 1; 01045 } 01046 } 01047 01048 if(!finished) 01049 { 01050 // Get the valency of the keep and discard vertices. 01051 discard_vertex->ref_edges(ref_edges_on_discard_vertex); 01052 keep_vertex->ref_edges(ref_edges_on_keep_vertex); 01053 discard_valency = ref_edges_on_discard_vertex.size(); 01054 keep_valency = ref_edges_on_keep_vertex.size(); 01055 01056 // Now do some error checking and also some logic to try to 01057 // pick the best vertex to keep/discard. 01058 01059 // If one of the valencies is 2 just composite the vertex out. 01060 if(discard_valency == 2) 01061 { 01062 CompositeTool::instance()->composite(ref_edges_on_discard_vertex); 01063 finished = 1; 01064 } 01065 else if (keep_valency == 2) 01066 { 01067 CompositeTool::instance()->composite(ref_edges_on_keep_vertex); 01068 finished = 1; 01069 } 01070 else 01071 { 01072 // Make sure that at least one of the vertices is qualified to 01073 // be the discard vertex (valency of 3 or 4). The keep vertex 01074 // really doesn't have any restrictions. 01075 if((discard_valency > 4 || discard_valency < 3) && 01076 (keep_valency > 4 || keep_valency < 3)) 01077 { 01078 PRINT_ERROR("Cannot currently collapse curves where one of the vertices does not have a valency equal to 3 or 4.\n"); 01079 result = CUBIT_FAILURE; 01080 finished = 1; 01081 } 01082 else 01083 { 01084 if(keep_vertex_specified) 01085 { 01086 if(discard_valency < 3 || discard_valency > 4) 01087 { 01088 PRINT_ERROR("Cannot currently collapse curves where the discard vertex valency is not 3 or 4.\n" 01089 "Try specifying the keep vertex so that the discard vertex is 3 or 4.\n"); 01090 result = CUBIT_FAILURE; 01091 finished = 1; 01092 } 01093 } 01094 else 01095 { 01096 // The user didn't specify a keep vertex so we can try to choose the best one. 01097 01098 int swap_vertices = 0; 01099 if(discard_valency < 5 && discard_valency > 2 && 01100 keep_valency < 5 && keep_valency > 2) 01101 { 01102 // Either vertex can be the discard/keep vertex so choose the one with the 01103 // lower valency as the discard vertex because it will require fewer operations. 01104 if(discard_valency > keep_valency) 01105 { 01106 swap_vertices = 1; 01107 } 01108 } 01109 else 01110 { 01111 // Only one of the vertices can be the discard vertex so pick it. 01112 if(discard_valency > 4 || discard_valency < 3) 01113 { 01114 swap_vertices = 1; 01115 } 01116 } 01117 01118 if(swap_vertices) 01119 { 01120 // Swap the vertices. 01121 RefVertex *tmp = discard_vertex; 01122 discard_vertex = keep_vertex; 01123 keep_vertex = tmp; 01124 01125 // Make sure to refresh the discard vertex edge list because 01126 // it is used below. 01127 ref_edges_on_discard_vertex.clean_out(); 01128 discard_vertex->ref_edges(ref_edges_on_discard_vertex); 01129 } 01130 } 01131 } 01132 } 01133 } 01134 01135 if(!finished && small_curve_size) 01136 { 01137 // Check if the edges attached to the discard vertex are longer 01138 // than the small curve size. 01139 DLIList<RefEdge*> tmp_edges; 01140 discard_vertex->ref_edges(tmp_edges); 01141 if(tmp_edges.move_to(edge_to_collapse)) 01142 tmp_edges.extract(); 01143 int y; 01144 bool all_edges_long_enough = true; 01145 for(y=tmp_edges.size(); y && all_edges_long_enough; y--) 01146 { 01147 RefEdge *cur_edge = tmp_edges.get_and_step(); 01148 if(cur_edge->get_arc_length() <= *small_curve_size) 01149 all_edges_long_enough = false; 01150 } 01151 if(!all_edges_long_enough) 01152 { 01153 PRINT_ERROR("Cannot collapse curve %d to vertex %d--not all of the curves attached to\n" 01154 "vertex %d are longer than the small_curve_size. Try collapsing to vertex %d instead.\n", 01155 edge_to_collapse->id(), keep_vertex->id(), discard_vertex->id(), discard_vertex->id()); 01156 result = CUBIT_FAILURE; 01157 finished = 1; 01158 } 01159 } 01160 01161 // Look at all of the coedges on the curve being collapsed and 01162 // throw out any that are on nonmanifold surfaces. The collapse 01163 // curve may be on a boundary of a merged surface. This is ok 01164 // but we want to make sure we don't involve this surface 01165 // in the partitions and composites so we will remove from the 01166 // list any coedges that are hooked to merged surfaces. 01167 if(!finished) 01168 { 01169 DLIList<CoEdge*> collapse_curve_coedges; 01170 edge_to_collapse->get_co_edges(collapse_curve_coedges); 01171 01172 int initial_size = collapse_curve_coedges.size(); 01173 while(collapse_curve_coedges.size() > 2 && initial_size > 0) 01174 { 01175 for(int g=collapse_curve_coedges.size(); g--;) 01176 { 01177 CoEdge *cur_coedge = collapse_curve_coedges.get_and_step(); 01178 Loop *loop_ptr = cur_coedge->get_loop_ptr(); 01179 if(loop_ptr) 01180 { 01181 RefFace *ref_face_ptr = loop_ptr->get_ref_face_ptr(); 01182 if(ref_face_ptr) 01183 { 01184 DLIList<CoFace*> coface_list; 01185 ref_face_ptr->co_faces(coface_list); 01186 if(coface_list.size() > 1) 01187 { 01188 collapse_curve_coedges.remove(cur_coedge); 01189 g = 0; 01190 } 01191 } 01192 } 01193 } 01194 01195 // Keep from looping infinitely. 01196 initial_size--; 01197 } 01198 01199 // If we get to this point and have more than 2 coedges left 01200 // in the list we are not sure what to do. 01201 if(collapse_curve_coedges.size() != 2) 01202 { 01203 PRINT_ERROR("Currently can only collapse curves with manifold topology.\n"); 01204 result = CUBIT_FAILURE; 01205 finished = 1; 01206 } 01207 else 01208 { 01209 // Get the collapse curve coedges entering and leaving the discard vertex. 01210 exit_coedge = collapse_curve_coedges.get_and_step(); 01211 enter_coedge = collapse_curve_coedges.get(); 01212 if(enter_coedge->end_vertex() != discard_vertex) 01213 { 01214 CoEdge *tmp = exit_coedge; 01215 exit_coedge = enter_coedge; 01216 enter_coedge = tmp; 01217 } 01218 } 01219 } 01220 01221 // Next we need to explore the topology around the discard vertex 01222 // so that we can get the edges and surfaces that will be involved 01223 // with the partitioning and compositing. We will identify a "left" 01224 // and "right" edge coming out of the discard vertex and adjacent 01225 // surfacs to these edges. 01226 if(!finished) 01227 { 01228 // Get these values for use later on. 01229 discard_pos = discard_vertex->get_point_ptr()->coordinates(); 01230 keep_pos = keep_vertex->get_point_ptr()->coordinates(); 01231 CubitVector discard_to_keep = keep_pos - discard_pos; 01232 arc_length = edge_to_collapse->get_arc_length(); 01233 01234 // Depending on whether the discard vertex has valency of 3 or 4 we will 01235 // either partition 1 or 2 of the curves coming into the discard vertex 01236 // respectively. Set up lists so that below we can just loop through the 01237 // partitioning and compositing for either the 3 or 4 valency case. 01238 01239 // "Left" and "right" will be defined as if you were standing on the 01240 // keep vertex looking at the discard vertex. 01241 Loop *left_loop = enter_coedge->get_loop_ptr(); 01242 Loop *right_loop = exit_coedge->get_loop_ptr(); 01243 DLIList<SenseEntity*> left_sense_entities, right_sense_entities; 01244 left_loop->get_sense_entity_list(left_sense_entities); 01245 right_loop->get_sense_entity_list(right_sense_entities); 01246 01247 // We need to get these two coedges because the chains defined by the "next" and 01248 // "previous" pointers in the CoEdge objects are not circular (you can have a NULL 01249 // "previous" or "next" pointer). We will manage the circularity manually. 01250 CoEdge *left_start = dynamic_cast<CoEdge*>(left_loop->get_first_sense_entity_ptr()); 01251 CoEdge *right_end = dynamic_cast<CoEdge*>(right_loop->get_last_sense_entity_ptr()); 01252 01253 CoEdge *left_coedge = dynamic_cast<CoEdge*>(enter_coedge->next()); 01254 if(left_coedge == NULL) 01255 { 01256 left_coedge = left_start; 01257 } 01258 CoEdge *right_coedge = dynamic_cast<CoEdge*>(exit_coedge->previous()); 01259 if(right_coedge == NULL) 01260 { 01261 right_coedge = right_end; 01262 } 01263 01264 RefEdge *left_edge = left_coedge->get_ref_edge_ptr(); 01265 RefEdge *right_edge = right_coedge->get_ref_edge_ptr(); 01266 RefFace *left_common_face = left_edge->common_ref_face(edge_to_collapse); 01267 RefFace *right_common_face = right_edge->common_ref_face(edge_to_collapse); 01268 01269 double left_arc_length = left_edge->get_arc_length(); 01270 double right_arc_length = right_edge->get_arc_length(); 01271 int left_ok = 1; 01272 int right_ok = 1; 01273 01274 DLIList<RefEdge*> left_face_edges; 01275 DLIList<RefEdge*> right_face_edges; 01276 left_common_face->ref_edges(left_face_edges); 01277 right_common_face->ref_edges(right_face_edges); 01278 if(left_face_edges.size() < 3 || right_face_edges.size() < 3 || 01279 left_sense_entities.size() < 3 || right_sense_entities.size() < 3) 01280 { 01281 PRINT_ERROR("Cannot collapse a curve that bounds a face or loop with only two edges.\n"); 01282 result = CUBIT_FAILURE; 01283 finished = 1; 01284 } 01285 else 01286 { 01287 // We use the length of the curve being collapsed as the distance 01288 // to partition the adjacent curves connected to it. If the 01289 // adjacent curves are shorter than the curve being collapsed we 01290 // will bail because the user should probably be getting rid 01291 // of the adjacent edges instead or at least first. 01292 01293 // Get the length of the adjacent curves. 01294 01295 // If the adjacent curve is within resabs of the length of 01296 // the curve being collapsed we will just snap to the end 01297 // of the adjacent curve for our partition position. 01298 if(arc_length > left_arc_length + GEOMETRY_RESABS) 01299 { 01300 left_ok = 0; 01301 } 01302 if(arc_length > right_arc_length + GEOMETRY_RESABS) 01303 { 01304 right_ok = 0; 01305 } 01306 01307 // If neither curve is ok we need to bail. 01308 if(!left_ok && !right_ok) 01309 { 01310 PRINT_ERROR("Curve being collapsed is too long compared to adjacent curves.\n"); 01311 result = CUBIT_FAILURE; 01312 finished = 1; 01313 } 01314 } 01315 01316 // If it looks like the lengths of the adjacent curves are 01317 // ok we will go ahead and try to find a partition position 01318 // on them. 01319 if(!finished) 01320 { 01321 if(left_ok) 01322 { 01323 // First see if we can just use the end point of the 01324 // adjacent curve as the partition position. 01325 if(fabs(left_arc_length-arc_length) < GEOMETRY_RESABS) 01326 { 01327 if(left_edge->start_vertex() == discard_vertex) 01328 position_on_left_curve = left_edge->end_vertex()->coordinates(); 01329 else 01330 position_on_left_curve = left_edge->start_vertex()->coordinates(); 01331 } 01332 else 01333 { 01334 result = this->position_from_length(left_edge, discard_vertex, 01335 arc_length, position_on_left_curve); 01336 } 01337 } 01338 if(result == CUBIT_SUCCESS && right_ok) 01339 { 01340 // First see if we can just use the end point of the 01341 // adjacent curve as the partition position. 01342 if(fabs(right_arc_length-arc_length) < GEOMETRY_RESABS) 01343 { 01344 if(right_edge->start_vertex() == discard_vertex) 01345 position_on_right_curve = right_edge->end_vertex()->coordinates(); 01346 else 01347 position_on_right_curve = right_edge->start_vertex()->coordinates(); 01348 } 01349 else 01350 { 01351 result = this->position_from_length(right_edge, discard_vertex, 01352 arc_length, position_on_right_curve); 01353 } 01354 } 01355 if(result == CUBIT_FAILURE) 01356 { 01357 PRINT_ERROR("Was unable to locate appropriate partition points on curves adjacent to curve being collapased.\n"); 01358 result = CUBIT_FAILURE; 01359 finished = 1; 01360 } 01361 } 01362 01363 if(!finished) 01364 { 01365 // Get the vectors from the discard vertex to the potential partition locations. 01366 CubitVector left_vec = position_on_left_curve - discard_pos; 01367 CubitVector right_vec = position_on_right_curve - discard_pos; 01368 01369 // Calculate the angles between the left/right edge and the 01370 // edge being collapsed. I am doing it this way rather than just 01371 // calling RefEdge::angle_between() because I want the angle 01372 // calculation done out at the potential partition location. 01373 // This will step over any small kinks in the curve near the 01374 // discard vertex that might otherwise give misleading angles 01375 // that don't represent what is happening out by the potential 01376 // partition position. 01377 left_common_face->u_v_from_position(discard_pos, u, v); 01378 CubitVector left_normal = left_common_face->normal_at(discard_pos, NULL, &u, &v); 01379 double left_angle = left_normal.vector_angle(left_vec, discard_to_keep); 01380 01381 right_common_face->u_v_from_position(discard_pos, u, v); 01382 CubitVector right_normal = right_common_face->normal_at(discard_pos, NULL, &u, &v); 01383 double right_angle = right_normal.vector_angle(discard_to_keep, right_vec); 01384 01385 // 3 valency case: 01386 // We only need to partition one of the curves (left or right) and 01387 // the corresponding surface. 01388 if(ref_edges_on_discard_vertex.size() == 3) 01389 { 01390 int use_left = 0; 01391 // We can use either adjacent curve. 01392 if(left_ok && right_ok) 01393 { 01394 // Choose the side with the smaller angle as this will in general 01395 // give better angles for doing the partitioning on the surface. 01396 CompositeSurface *cs_left = dynamic_cast<CompositeSurface*>(left_common_face->get_surface_ptr()); 01397 CompositeSurface *cs_right = dynamic_cast<CompositeSurface*>(right_common_face->get_surface_ptr()); 01398 if(!cs_left && cs_right) 01399 use_left = 1; 01400 else if(cs_left && !cs_right) 01401 use_left = 0; 01402 else 01403 { 01404 if(cs_left && cs_right) 01405 { 01406 int edge_on_ignored_left=0, edge_on_ignored_right=0; 01407 DLIList<Surface*> srfs; 01408 cs_left->get_ignored_surfs(srfs); 01409 int g; 01410 for(g=srfs.size(); g>0 && !edge_on_ignored_left; g--) 01411 { 01412 Surface *srf = srfs.get_and_step(); 01413 DLIList<Curve*> crvs; 01414 srf->curves(crvs); 01415 if(crvs.is_in_list(edge_to_collapse->get_curve_ptr())) 01416 edge_on_ignored_left = 1; 01417 } 01418 srfs.clean_out(); 01419 cs_right->get_ignored_surfs(srfs); 01420 for(g=srfs.size(); g>0 && !edge_on_ignored_right; g--) 01421 { 01422 Surface *srf = srfs.get_and_step(); 01423 DLIList<Curve*> crvs; 01424 srf->curves(crvs); 01425 if(crvs.is_in_list(edge_to_collapse->get_curve_ptr())) 01426 edge_on_ignored_right = 1; 01427 } 01428 if(edge_on_ignored_left && !edge_on_ignored_right) 01429 use_left = 0; 01430 else if(!edge_on_ignored_left && edge_on_ignored_right) 01431 use_left = 1; 01432 else 01433 { 01434 if(left_angle < right_angle) 01435 use_left = 1; 01436 } 01437 } 01438 else 01439 { 01440 if(left_angle < right_angle) 01441 use_left = 1; 01442 } 01443 } 01444 } 01445 else if(left_ok) 01446 use_left = 1; 01447 01448 if(use_left) 01449 { 01450 curves_to_partition.append(left_edge); 01451 surfaces_to_partition.append(left_common_face); 01452 angles.append(left_angle); 01453 partition_positions.append(position_on_left_curve); 01454 arc_lengths.append(arc_length); 01455 01456 // These vectors will be used in calculating a bisector direction 01457 // below if necessary. 01458 keep_vecs.append(-discard_to_keep); 01459 partition_curve_vecs.append(left_vec); 01460 } 01461 else 01462 { 01463 curves_to_partition.append(right_edge); 01464 surfaces_to_partition.append(right_common_face); 01465 angles.append(right_angle); 01466 partition_positions.append(position_on_right_curve); 01467 arc_lengths.append(arc_length); 01468 01469 // These vectors will be used in calculating a bisector direction 01470 // below if necessary. 01471 keep_vecs.append(discard_to_keep); 01472 partition_curve_vecs.append(-right_vec); 01473 } 01474 } 01475 else if(ref_edges_on_discard_vertex.size() == 4) 01476 { 01477 // We have to partition both left and right curves so make 01478 // sure we can. 01479 if(!left_ok || !right_ok) 01480 { 01481 PRINT_ERROR("One of the curves adjacent to the collapse curve is not long enough for the collapse operation.\n"); 01482 result = CUBIT_FAILURE; 01483 finished = 1; 01484 } 01485 else 01486 { 01487 // Both curves (and surfaces) adjacent to the collapse curve (left and right) 01488 // will need to be partitioned so add them to the lists. 01489 01490 curves_to_partition.append(left_edge); 01491 curves_to_partition.append(right_edge); 01492 surfaces_to_partition.append(left_common_face); 01493 surfaces_to_partition.append(right_common_face); 01494 angles.append(left_angle); 01495 angles.append(right_angle); 01496 keep_vecs.append(-discard_to_keep); 01497 keep_vecs.append(discard_to_keep); 01498 partition_curve_vecs.append(left_vec); 01499 partition_curve_vecs.append(-right_vec); 01500 partition_positions.append(position_on_left_curve); 01501 partition_positions.append(position_on_right_curve); 01502 arc_lengths.append(arc_length); 01503 arc_lengths.append(arc_length); 01504 } 01505 } 01506 else 01507 { 01508 PRINT_ERROR("Currently can only collapse curves with 3 or 4 valency vertices.\n"); 01509 result = CUBIT_FAILURE; 01510 finished = 1; 01511 } 01512 } 01513 } 01514 01515 if(!finished) 01516 { 01517 int num_reps = curves_to_partition.size(); 01518 curves_to_partition.reset(); 01519 surfaces_to_partition.reset(); 01520 for(int n=0; n<num_reps && !finished; ++n) 01521 { 01522 RefEdge *side_edge = curves_to_partition.get_and_step(); 01523 RefFace *side_face = surfaces_to_partition.get_and_step(); 01524 01525 // Now we need to find the face on the other side of the edge. 01526 // Because there may be edges on the boundaries of merged surfaces 01527 // we want to find the 01528 // face on the left/right edge that isn't the face shared by 01529 // the collapse edge and isn't nonmanifold. 01530 DLIList<CoEdge*> side_edge_coedges; 01531 side_edge->co_edges(side_edge_coedges); 01532 DLIList<RefFace*> possible_adj_faces; 01533 01534 // First loop through and get all of the potential faces. 01535 for(int r=side_edge_coedges.size(); r--;) 01536 { 01537 CoEdge *cur_coedge = side_edge_coedges.get_and_step(); 01538 if(cur_coedge && 01539 cur_coedge->get_loop_ptr() && 01540 cur_coedge->get_loop_ptr()->get_ref_face_ptr()) 01541 { 01542 RefFace *cur_ref_face = cur_coedge->get_loop_ptr()->get_ref_face_ptr(); 01543 if(cur_ref_face != side_face) 01544 { 01545 DLIList<CoFace*> coface_list; 01546 cur_ref_face->co_faces(coface_list); 01547 01548 // Along with checking for whether the face is manifold we need 01549 // to check if it belongs to the same volume as the side face. 01550 // We have to check this because we can't composite faces 01551 // from different volumes and these faces will be involved in 01552 // a composite below. 01553 if(coface_list.size() == 1 && 01554 side_face->ref_volume() == cur_ref_face->ref_volume()) 01555 { 01556 possible_adj_faces.append(cur_ref_face); 01557 } 01558 } 01559 } 01560 } 01561 01562 // If we ended up with more than one face in the list it isn't clear 01563 // what we should do so bail out. 01564 if(possible_adj_faces.size() != 1) 01565 { 01566 PRINT_ERROR("Couldn't figure out how to perform the collapse curve with the current topology.\n"); 01567 result = CUBIT_FAILURE; 01568 finished = 1; 01569 } 01570 else 01571 { 01572 adjacent_surfaces.append(possible_adj_faces.get()); 01573 } 01574 } 01575 } 01576 01577 if(!finished) 01578 { 01579 // At this point we should know which curves and surfaces we need 01580 // to partition. 01581 01582 int num_reps = curves_to_partition.size(); 01583 curves_to_partition.reset(); 01584 surfaces_to_partition.reset(); 01585 adjacent_surfaces.reset(); 01586 angles.reset(); 01587 keep_vecs.reset(); 01588 partition_curve_vecs.reset(); 01589 partition_positions.reset(); 01590 arc_lengths.reset(); 01591 01592 for(int i=0; i<num_reps && !finished; ++i) 01593 { 01594 RefEdge *curve_to_partition = curves_to_partition.get_and_step(); 01595 RefFace *surface_to_partition = surfaces_to_partition.get_and_step(); 01596 01597 // Sanity check to make sure a previous operation has not 01598 // destroyed the current face. 01599 DLIList<RefFace*> body_faces; 01600 the_body->ref_faces(body_faces); 01601 if(body_faces.is_in_list(surface_to_partition)) 01602 { 01603 // As we process each curve remove it from the list so that 01604 // at the end we can take the last one in the list and composite 01605 // it with the curve being collapsed. 01606 ref_edges_on_discard_vertex.remove(curve_to_partition); 01607 01608 CubitVector position_on_curve = partition_positions.get_and_step(); 01609 DLIList<CubitVector*> positions; 01610 01611 // Add the point on the curve we just partitioned. The other 01612 // point we normally need to add is the keep_vertex. However, 01613 // if the angle between the collapse curve and the curve we 01614 // just partitioned dictates that we need to introduce more points 01615 // (this would be cases where the angle is large and just partitioning the 01616 // surface with one curve--two points--would result in a very skinny 01617 // surface) we need to add them before adding the keep_vertex. Therefore, check 01618 // that now and add the extra points if needed. 01619 positions.append(new CubitVector(position_on_curve)); 01620 01621 double cur_angle = angles.get_and_step(); 01622 arc_length = arc_lengths.get_and_step(); 01623 01624 // These vectors are only used in the block below if we need to 01625 // add extra points but we need to always retrieve them from the lists 01626 // so that the pointer in the list stays in sync with the "for" loop. 01627 CubitVector keep_vec = keep_vecs.get_and_step(); 01628 CubitVector partition_vec = partition_curve_vecs.get_and_step(); 01629 01630 // Greater than 3*PI/2--add 3 interior points. Two of these 01631 // points will be generated by projecting from the discard vertex 01632 // into the surface normal to the vector from the discard vertex 01633 // to the keep point and new partition point respectively. The third 01634 // point will be obtained by projecting from the discard point in the 01635 // direction of the bisector angle of the two previous projections. 01636 if(cur_angle > 4.71) 01637 { 01638 // Get the u,v position of the discard vertex on this surface. 01639 surface_to_partition->u_v_from_position(discard_pos, u, v); 01640 01641 // Get the normal at the discard vertex. 01642 CubitVector normal = surface_to_partition->normal_at(discard_pos, NULL, &u, &v); 01643 normal.normalize(); 01644 01645 // We need to calculate a bisector direction between the 01646 // collape edge and the edge we just partitioned. We will do 01647 // this using the face normal at the discard vertex and the vectors 01648 // we calculated previously with the partition points. Cross 01649 // the face normal into the the direction vectors at the 01650 // discard and partition points to get two vectors pointing 01651 // into the face and then average those two to get the 01652 // bisector direction. This is all approximate but should 01653 // be sufficient for locating another point for partitioning 01654 // the surface. 01655 01656 // I am not normalizing the result here because they should 01657 // be roughly the same length and it shouldn't affect 01658 // the average too much. 01659 CubitVector vec1 = normal * partition_vec; 01660 CubitVector vec2 = normal * keep_vec; 01661 01662 // Get the bisector direction. 01663 CubitVector bisector_dir = vec1 + vec2; 01664 bisector_dir.normalize(); 01665 01666 // Now normalise these because they will be used to 01667 // project two of the new interior points. 01668 vec1.normalize(); 01669 vec2.normalize(); 01670 01671 CubitVector new_pos1 = discard_pos + (arc_length*vec1); 01672 CubitVector mid_pos = discard_pos + (arc_length * bisector_dir); 01673 CubitVector new_pos2 = discard_pos + (arc_length*vec2); 01674 01675 // Use the u,v from the discard vertex because it is fairly 01676 // close to the new position and will at least provide a 01677 // meaningful starting point. 01678 double save_u = u, save_v = v; 01679 surface_to_partition->move_to_surface(new_pos1, &u, &v); 01680 u = save_u; v = save_v; 01681 surface_to_partition->move_to_surface(mid_pos, &u, &v); 01682 u = save_u; v = save_v; 01683 surface_to_partition->move_to_surface(new_pos2, &u, &v); 01684 01685 // Add the new position to the list of partition points. 01686 positions.append(new CubitVector(new_pos1)); 01687 positions.append(new CubitVector(mid_pos)); 01688 positions.append(new CubitVector(new_pos2)); 01689 } 01690 // Greater than 3*PI/4 and less than 3*PI/2--add one interior point 01691 else if(cur_angle > 2.4) 01692 { 01693 CubitVector third_pt; 01694 01695 // Get the u,v position of the discard vertex on this surface. 01696 surface_to_partition->u_v_from_position(discard_pos, u, v); 01697 01698 // Get the normal at the discard vertex. 01699 CubitVector normal = surface_to_partition->normal_at(discard_pos, NULL, &u, &v); 01700 normal.normalize(); 01701 01702 // We need to calculate a bisector direction between the 01703 // collape edge and the edge we just partitioned. We will do 01704 // this using the face normal at the discard vertex and the vectors 01705 // we calculated previously with the partition points. Cross 01706 // the face normal into the the direction vectors at the 01707 // discard and partition points to get two vectors pointing 01708 // into the face and then average those two to get the 01709 // bisector direction. This is all approximate but should 01710 // be sufficient for locating another point for partitioning 01711 // the surface. 01712 01713 // I am not normalizing the result here because they should 01714 // be roughly the same length and it shouldn't affect 01715 // the average too much. 01716 CubitVector vec1 = normal * keep_vec; 01717 CubitVector vec2 = normal * partition_vec; 01718 01719 // Get the bisector direction. 01720 CubitVector bisector_dir = vec1 + vec2; 01721 bisector_dir.normalize(); 01722 01723 // Project from the discard vertex in the direction of the 01724 // bisector direction to get a new point for partitioning 01725 // the surface. 01726 CubitVector new_pos = discard_pos + (arc_length * bisector_dir); 01727 01728 // Use the u,v from the discard vertex because it is fairly 01729 // close to the new position and will at least provide a 01730 // meaningful starting point. 01731 surface_to_partition->move_to_surface(new_pos, &u, &v); 01732 01733 // Add the new position to the list of partition points. 01734 positions.append(new CubitVector(new_pos)); 01735 } 01736 01737 // Finally, add the keep_vertex to the list. 01738 positions.append(new CubitVector(keep_vertex->get_point_ptr()->coordinates())); 01739 01740 DLIList<RefEdge*> new_edges; 01741 DLIList<DLIList<CubitVector*>*> vec_lists; 01742 DLIList<CubitVector*> *vec_list = new DLIList<CubitVector*>; 01743 positions.reset(); 01744 for(int m=positions.size(); m--;) 01745 vec_list->append( new CubitVector( *positions.get_and_step() ) ); 01746 vec_lists.append( vec_list ); 01747 01748 if(!SplitCompositeSurfaceTool::instance()->split_surface(surface_to_partition, 01749 positions, vec_lists )) 01750 { 01751 finished = 1; 01752 result = CUBIT_FAILURE; 01753 } 01754 01755 while( vec_lists.size() ) 01756 { 01757 DLIList<CubitVector*> *vec_list = vec_lists.pop(); 01758 while( vec_list->size() ) delete vec_list->pop(); 01759 delete vec_list; 01760 } 01761 01762 delete positions.get_and_step(); 01763 delete positions.get_and_step(); 01764 01765 if(cur_angle > 4.71) 01766 { 01767 delete positions.get_and_step(); 01768 delete positions.get_and_step(); 01769 delete positions.get_and_step(); 01770 } 01771 else if(cur_angle > 2.4) 01772 { 01773 delete positions.get(); 01774 } 01775 01776 if(!finished) 01777 { 01778 RefFace *new_small_face = NULL; 01779 DLIList<RefEdge*> keep_edges, discard_edges; 01780 DLIList<RefFace*> faces_on_collapse_edge; 01781 keep_vertex->ref_edges(keep_edges); 01782 discard_vertex->ref_edges(discard_edges); 01783 keep_edges.intersect_unordered(discard_edges); 01784 if(keep_edges.size() != 1) 01785 { 01786 finished = 1; 01787 result = CUBIT_FAILURE; 01788 } 01789 else 01790 { 01791 edge_to_collapse = keep_edges.get(); 01792 edge_to_collapse->ref_faces(faces_on_collapse_edge); 01793 for(int y=faces_on_collapse_edge.size(); y && !new_small_face; y--) 01794 { 01795 RefFace *cur_face = faces_on_collapse_edge.get_and_step(); 01796 DLIList<RefVertex*> verts_in_face; 01797 cur_face->ref_vertices(verts_in_face); 01798 for(int p=verts_in_face.size(); p && !new_small_face; p--) 01799 { 01800 RefVertex *cur_vert = verts_in_face.get_and_step(); 01801 if(position_on_curve.about_equal(cur_vert->coordinates())) 01802 new_small_face = cur_face; 01803 } 01804 } 01805 } 01806 01807 if(!new_small_face || new_small_face == surface_to_partition) 01808 { 01809 PRINT_ERROR("Failed to do the split surface operation of the collapse curve.\n"); 01810 result = CUBIT_FAILURE; 01811 finished = 1; 01812 } 01813 else 01814 { 01815 RefVertex *vert_at_split_pos; 01816 DLIList<RefEdge*> new_face_edges; 01817 new_small_face->ref_edges(new_face_edges); 01818 if(new_face_edges.is_in_list(curve_to_partition)) 01819 { 01820 // The split went right through one of the vertices of the 01821 // curve_to_partition so just set the close edge to be 01822 // this edge and the far edge to be NULL. 01823 close_edge = curve_to_partition; 01824 far_edge = NULL; 01825 vert_at_split_pos = close_edge->other_vertex(discard_vertex); 01826 } 01827 else 01828 { 01829 close_edge = edge_to_collapse->get_other_curve(discard_vertex, new_small_face); 01830 RefVertex *tmp_vert = close_edge->other_vertex(discard_vertex); 01831 if(tmp_vert) 01832 { 01833 RefEdge *tmp_edge = close_edge->get_other_curve(tmp_vert, new_small_face); 01834 if(tmp_edge) 01835 { 01836 RefFace *other_face = tmp_edge->other_face(new_small_face); 01837 if(other_face) 01838 { 01839 far_edge = tmp_edge->get_other_curve(tmp_vert, other_face); 01840 vert_at_split_pos = tmp_vert; 01841 // If close_edge and far_edge are the same it may mean 01842 // that the split really didn't do much other than maybe 01843 // imprint one point on an edge so bail out. 01844 if(far_edge == close_edge) 01845 { 01846 PRINT_ERROR("Failed to do the split surface operation of the collapse curve.\n"); 01847 result = CUBIT_FAILURE; 01848 finished = 1; 01849 } 01850 } 01851 else 01852 { 01853 result = CUBIT_FAILURE; 01854 finished = 1; 01855 } 01856 } 01857 else 01858 { 01859 result = CUBIT_FAILURE; 01860 finished = 1; 01861 } 01862 } 01863 else 01864 { 01865 finished = 1; 01866 result = CUBIT_FAILURE; 01867 } 01868 } 01869 01870 if(!finished) 01871 { 01872 RefEdge *cur_edge = close_edge; 01873 RefVertex *cur_vert = vert_at_split_pos; 01874 while(cur_vert != keep_vertex) 01875 { 01876 cur_edge = cur_edge->get_other_curve(cur_vert, new_small_face); 01877 cur_vert = cur_edge->other_vertex(cur_vert); 01878 new_edges.append(cur_edge); 01879 } 01880 01881 DLIList<RefFace*> result_faces; 01882 DLIList<RefFace*> faces_to_composite; 01883 01884 // Used below if "ignore" keyword was specified. 01885 int new_small_face_id = new_small_face->id(); 01886 01887 faces_to_composite.append(new_small_face); 01888 faces_to_composite.append(close_edge->other_face(new_small_face)); 01889 01890 RefFace *new_comp_face = CompositeTool::instance()->composite(faces_to_composite); 01891 01892 CompositeSurface* csurf = NULL; 01893 01894 if(new_comp_face) 01895 { 01896 csurf = dynamic_cast<CompositeSurface*>(new_comp_face->get_surface_ptr()); 01897 } 01898 01899 if(!new_comp_face || !csurf) 01900 { 01901 PRINT_ERROR("Failed to do the composite surface operation of the collapse curve.\n"); 01902 result = CUBIT_FAILURE; 01903 finished = 1; 01904 } 01905 else 01906 { 01907 if(ignore_surfaces) 01908 { 01909 csurf->ignore_surface(new_small_face_id); 01910 } 01911 01912 if(far_edge) 01913 { 01914 for(int k=new_edges.size(); k--;) 01915 { 01916 edges_to_composite.append(new_edges.get_and_step()); 01917 } 01918 edges_to_composite.append(far_edge); 01919 01920 if(edges_to_composite.size() > 1) 01921 { 01922 CompositeTool::instance()->composite(edges_to_composite); 01923 } 01924 } 01925 01926 edges_to_composite.clean_out(); 01927 } 01928 } 01929 } 01930 } 01931 } 01932 } 01933 01934 if(!finished) 01935 { 01936 ref_edges_on_discard_vertex.clean_out(); 01937 discard_vertex->ref_edges(ref_edges_on_discard_vertex); 01938 ref_edges_on_discard_vertex.remove(edge_to_collapse); 01939 01940 // Now there should only be one edge in the ref_edges_on_discard_vertex 01941 // list. It should be the edge that hasn't had any modifications 01942 // done to it. We finally want to composite it with the edge 01943 // being collapsed. 01944 if(ref_edges_on_discard_vertex.size() != 1) 01945 { 01946 PRINT_ERROR("Wasn't able to complete collapse operation.\n"); 01947 result = CUBIT_FAILURE; 01948 finished = 1; 01949 } 01950 else 01951 { 01952 edges_to_composite.append(ref_edges_on_discard_vertex.get()); 01953 edges_to_composite.append(edge_to_collapse); 01954 CompositeTool::instance()->composite(edges_to_composite); 01955 } 01956 } 01957 } 01958 01959 CubitUndo::set_undo_enabled(undo_state); 01960 01961 return result; 01962 } 01963 01964 CubitStatus CollapseCurveTool::position_from_length(RefEdge *edge, 01965 RefVertex *root_vertex, 01966 double arc_length, 01967 CubitVector& v_new) 01968 { 01969 CubitStatus result; 01970 double sense = 1.0; 01971 if (root_vertex != edge->start_vertex()) 01972 sense = -1.0; 01973 CubitVector v_root = root_vertex->get_point_ptr()->coordinates(); 01974 result = edge->point_from_arc_length(v_root, arc_length*sense, v_new); 01975 return result; 01976 } 01977 01978 01979 // ********** END PUBLIC FUNCTIONS ********** 01980 01981 // ********** BEGIN PROTECTED FUNCTIONS ********** 01982 // ********** END PROTECTED FUNCTIONS ********** 01983 01984 // ********** BEGIN PRIVATE FUNCTIONS ********** 01985 CollapseCurveTool::CollapseCurveTool() 01986 { 01987 } 01988 01989 CollapseCurveTool::~CollapseCurveTool() 01990 { 01991 } 01992