cgma
CollapseCurveTool.cpp
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines