cgma
SplitSurfaceTool.cpp
Go to the documentation of this file.
00001 //-------------------------------------------------------------------------
00002 // Filename      : SplitSurfaceTool.cpp
00003 //
00004 // Purpose       : Split a single or chain of surfaces (e.g., split a fillet 
00005 //                 down the middle so that a mesh sweep can occur, or split
00006 //                 across a surface).  Used by the "split surface" commands.
00007 //
00008 //   Split Surface <id> Across [Pair] Location <options multiple locs>
00009 //       [Preview [Create]]
00010 //   Split Surface <id> Across Location <multiple locs> Onto Curve <id>
00011 //       [Preview [Create]]
00012 //   Split Surface <id_list> Extend [Vertex <id_list> | Auto] [Preview [Create]]
00013 //
00014 //   Split Surface <id_list> [Corner Vertex <id_list>] [Direction Curve <id>]
00015 //       [Segment <val> | Fraction|Distance <val> [From Curve <id>]]
00016 //       [Through Vertex <id_list>] [Parametric <on|OFF>] [Tolerance <value>]
00017 //       [Preview [Create]]
00018 //
00019 // Special Notes : 
00020 //
00021 // Creator       : Steve Storm
00022 //
00023 // Creation Date : 10/06/2002
00024 //-------------------------------------------------------------------------
00025 
00026 #include "SplitSurfaceTool.hpp"
00027 #include "AnalyticGeometryTool.hpp"
00028 #include "Body.hpp"
00029 #include "RefFace.hpp"
00030 #include "Point.hpp"
00031 #include "Curve.hpp"
00032 #include "Surface.hpp"
00033 #include "Loop.hpp"
00034 #include "CubitMessage.hpp"
00035 #include "GeometryModifyTool.hpp"
00036 #include "GeometryModifyEngine.hpp"
00037 #include "GeometryQueryTool.hpp"
00038 #include "CubitUtil.hpp"
00039 #include "DLIList.hpp"
00040 #include "TDSplitSurface.hpp"
00041 #include "GfxDebug.hpp"
00042 #include "GfxPreview.hpp"
00043 #include "Cubit2DPoint.hpp"
00044 #include "GMem.hpp"
00045 #include "SettingHandler.hpp"
00046 
00047 CubitBoolean SplitSurfaceTool::parametricFlg = CUBIT_FALSE;
00048 double SplitSurfaceTool::splitTolerance = 1.0;
00049 CubitBoolean SplitSurfaceTool::autoDetectTriangles = CUBIT_TRUE;
00050 double SplitSurfaceTool::sideAngleThreshold = 27.0; // From 180
00051 double SplitSurfaceTool::pointAngleThreshold = 45.0; // Below is a point
00052 double SplitSurfaceTool::extendGapThreshold = CUBIT_DBL_MAX;
00053 CubitBoolean SplitSurfaceTool::extendNormalFlg = CUBIT_FALSE;
00054 double SplitSurfaceTool::extendTolerance = .1;
00055 
00056 SplitSurfaceTool::SplitSurfaceTool()
00057 {
00058   int i;
00059   for(i=0; i<4; i++)
00060   {
00061     sideInterval[i] = 0;
00062     cornerCoEdge[i] = NULL;
00063   }
00064   isLoop = CUBIT_FALSE;
00065 }
00066 
00067 //Initialize all settings in this class
00068 void
00069 SplitSurfaceTool::initialize_settings()
00070 {
00071   SettingHandler::instance()->add_setting("Split Surface Tolerance", 
00072                                           SplitSurfaceTool::set_tolerance, 
00073                                           SplitSurfaceTool::get_tolerance);
00074 
00075   SettingHandler::instance()->add_setting("Split Surface Parametric", 
00076                                           SplitSurfaceTool::set_parametric_flg, 
00077                                           SplitSurfaceTool::get_parametric_flg);
00078 
00079   SettingHandler::instance()->add_setting("Split Surface Auto Detect Triangles", 
00080                                           SplitSurfaceTool::set_auto_detect_triangles_flg, 
00081                                           SplitSurfaceTool::get_auto_detect_triangles_flg);
00082 
00083   SettingHandler::instance()->add_setting("Split Surface Side Angle Threshold",
00084                                           SplitSurfaceTool::set_side_angle_threshold, 
00085                                           SplitSurfaceTool::get_side_angle_threshold);
00086 
00087   SettingHandler::instance()->add_setting("Split Surface Point Angle Threshold", 
00088                                           SplitSurfaceTool::set_point_angle_threshold, 
00089                                           SplitSurfaceTool::get_point_angle_threshold);
00090 
00091   SettingHandler::instance()->add_setting("Split Surface Extend Gap Threshold", 
00092                                           SplitSurfaceTool::set_extend_gap_threshold, 
00093                                           SplitSurfaceTool::get_extend_gap_threshold);
00094 
00095   SettingHandler::instance()->add_setting("Split Surface Extend Tolerance", 
00096                                           SplitSurfaceTool::set_extend_tolerance, 
00097                                           SplitSurfaceTool::get_extend_tolerance);
00098 
00099   SettingHandler::instance()->add_setting("Split Surface Extend Normal", 
00100                                           SplitSurfaceTool::set_extend_normal_flg, 
00101                                           SplitSurfaceTool::get_extend_normal_flg);
00102 }
00103 
00104 CubitStatus                                
00105 SplitSurfaceTool::preview( RefFace *ref_face_ptr,
00106                            DLIList<CubitVector*> &locations,
00107                            DLIList<DLIList<CubitVector*>*> &vec_lists,
00108                            CubitBoolean create_ref_edges_flg,
00109                            CubitBoolean clear_previous_previews )
00110 {
00111   // Create curves from the input vec_lists (locations are just the original
00112   // locations the user specified - these need to be drawn)
00113   int i, j;
00114   Curve *curve_ptr;
00115   DLIList<CubitVector*> *vec_list_ptr;
00116   vec_lists.reset();
00117   DLIList<Surface*> surfs;
00118 
00119   Surface *surf_ptr = ref_face_ptr->get_surface_ptr();
00120 
00121   // Support composite surfaces by getting the surfaces underlying
00122   // the composite and creating split curves for them individually.
00123   GeometryQueryEngine *gqe = surf_ptr->get_geometry_query_engine();
00124   DLIList<TopologyBridge*> tbs;
00125   gqe->get_underlying_surfaces(surf_ptr, tbs);
00126   if(tbs.size() > 0)
00127   {
00128     for(j=tbs.size(); j>0; j--)
00129       surfs.append(dynamic_cast<Surface*>(tbs.get_and_step()));
00130   }
00131   else
00132     surfs.append(surf_ptr);
00133 
00134   // Clear previous previews if necessary
00135   if( clear_previous_previews == CUBIT_TRUE )
00136     GfxPreview::clear();
00137 
00138   for( i=vec_lists.size(); i--; )
00139   {
00140     vec_list_ptr = vec_lists.get_and_step();
00141 
00142     vec_list_ptr->reset();
00143     if( vec_list_ptr->size() < 2 )
00144     {
00145       PRINT_ERROR( "Unable to create a curve from less than two locations.\n" );
00146       continue;
00147     }
00148 
00149     for(j=surfs.size(); j>0; j--)
00150     {
00151       Surface *cur_surf = surfs.get_and_step();
00152       curve_ptr = create_curve( *vec_list_ptr, cur_surf );
00153 
00154       if( curve_ptr )
00155       {
00156         if( create_ref_edges_flg == CUBIT_TRUE )
00157         {
00158           RefEdge *ref_edge_ptr;
00159           ref_edge_ptr = GeometryQueryTool::instance()->make_free_RefEdge(curve_ptr);
00160           if( ref_edge_ptr )
00161             PRINT_INFO( "Created new curve %d\n", ref_edge_ptr->id() );
00162         }
00163         else
00164         {
00165           draw_preview( curve_ptr, CUBIT_FALSE );
00166           curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
00167         }
00168       }
00169     }
00170   }
00171   
00172   // Draw locations too
00173   draw_points( locations, CUBIT_BLUE_INDEX );
00174   
00175   return CUBIT_SUCCESS;
00176 }
00177 
00178 CubitStatus                                
00179 SplitSurfaceTool::preview( DLIList<RefFace*> &ref_face_list,
00180                            DLIList<CubitVector*> &locations,
00181                            DLIList<DLIList<DLIList<CubitVector*>*>*> &list_of_vec_lists,
00182                            CubitBoolean create_ref_edges_flg,
00183                            CubitBoolean clear_previous_previews )
00184 {
00185    //Reset ref_face_list and list_of_vec_lists (just in case)
00186    ref_face_list.reset();
00187    list_of_vec_lists.reset();
00188 
00189    // Clear previous previews if necessary
00190    if( clear_previous_previews == CUBIT_TRUE )
00191       GfxPreview::clear();  
00192    
00193    int qq;
00194    for( qq = ref_face_list.size(); qq > 0 ; qq--)
00195    {
00196       //Initialize the values to be used upon each iteration
00197       RefFace* ref_face_ptr = ref_face_list.get_and_step();
00198       DLIList<DLIList<CubitVector*>*> vec_lists = *( list_of_vec_lists.get_and_step() );
00199 
00200       int i, j;
00201       Curve *curve_ptr;
00202       DLIList<CubitVector*> *vec_list_ptr;
00203       vec_lists.reset();
00204       DLIList<Surface*> surfs;
00205 
00206       Surface *surf_ptr = ref_face_ptr->get_surface_ptr();
00207 
00208       // Support composite surfaces by getting the surfaces underlying
00209       // the composite and creating split curves for them individually.
00210       GeometryQueryEngine *gqe = surf_ptr->get_geometry_query_engine();
00211       DLIList<TopologyBridge*> tbs;
00212       gqe->get_underlying_surfaces(surf_ptr, tbs);
00213       if(tbs.size() > 0)
00214       {
00215          for(j=tbs.size(); j>0; j--)
00216             surfs.append(dynamic_cast<Surface*>(tbs.get_and_step()));
00217       }
00218       else
00219          surfs.append(surf_ptr);
00220 
00221       for( i=vec_lists.size(); i--; )
00222       {
00223          vec_list_ptr = vec_lists.get_and_step();
00224 
00225          vec_list_ptr->reset();
00226          if( vec_list_ptr->size() < 2 )
00227          {
00228             PRINT_ERROR( "Unable to create a curve from less than two locations.\n" );
00229             continue;
00230          }
00231 
00232          for(j=surfs.size(); j>0; j--)
00233          {
00234             Surface *cur_surf = surfs.get_and_step();
00235             curve_ptr = create_curve( *vec_list_ptr, cur_surf );
00236 
00237             if( curve_ptr )
00238             {
00239                if( create_ref_edges_flg == CUBIT_TRUE )
00240                {
00241                   RefEdge *ref_edge_ptr;
00242                   ref_edge_ptr = GeometryQueryTool::instance()->make_free_RefEdge(curve_ptr);
00243                   if( ref_edge_ptr )
00244                      PRINT_INFO( "Created new curve %d\n", ref_edge_ptr->id() );
00245                }
00246                else
00247                {
00248                   draw_preview( curve_ptr, CUBIT_FALSE );
00249                   curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
00250                }
00251             }
00252          }
00253       }
00254    }
00255   
00256   // Draw locations too
00257   draw_points( locations, CUBIT_BLUE_INDEX );
00258   
00259   return CUBIT_SUCCESS;
00260 }
00261 
00262 // Create the curves used by the splitting algorithm.
00263 // Note: calling code is responsible for cleaning up the
00264 //       created curves when it is done with them.
00265 CubitStatus                                
00266 SplitSurfaceTool::calculate_split_curves( RefFace *ref_face_ptr,
00267                                  DLIList<DLIList<CubitVector*>*> &vec_lists,
00268                                  DLIList<Curve*>& curve_list )
00269 {
00270   Surface *surf_ptr = ref_face_ptr->get_surface_ptr();
00271 
00272   return calculate_split_curves(surf_ptr, vec_lists, curve_list);
00273 }
00274 
00275 CubitStatus                                
00276 SplitSurfaceTool::calculate_split_curves( Surface *surf_ptr,
00277                                  DLIList<DLIList<CubitVector*>*> &vec_lists,
00278                                  DLIList<Curve*>& curve_list )
00279 {
00280   int i;
00281   Curve *curve_ptr;
00282   DLIList<CubitVector*> *vec_list_ptr;
00283   vec_lists.reset();
00284 
00285   for( i=vec_lists.size(); i--; )
00286   {
00287     vec_list_ptr = vec_lists.get_and_step();
00288 
00289     vec_list_ptr->reset();
00290     if( vec_list_ptr->size() < 2 )
00291     {
00292       PRINT_ERROR( "Unable to create a curve from less than two locations.\n" );
00293       continue;
00294     }
00295 
00296     curve_ptr = create_curve( *vec_list_ptr, surf_ptr );
00297 
00298     if( curve_ptr )
00299     {
00300       curve_list.append( curve_ptr );
00301       if( DEBUG_FLAG( 100 ) )
00302         draw_preview( curve_ptr, CUBIT_TRUE, CUBIT_RED_INDEX );
00303     }
00304   }
00305 
00306   if( !curve_list.size() )
00307     return CUBIT_FAILURE;
00308 
00309   return CUBIT_SUCCESS;
00310 }
00311 
00312 CubitStatus                                
00313 SplitSurfaceTool::split_surface( RefFace *ref_face_ptr, DLIList<Curve*> &curve_list)
00314 {
00315   // Count number of surfaces in owning body prior to split - this is used to
00316   // determine if split is actually successful.
00317   Body *body_ptr;
00318   int num_surfaces_prior = count_surfaces_in_owning_body( ref_face_ptr, body_ptr );
00319   int num_curves_prior = count_curves_in_body( body_ptr );
00320 
00321   if( num_surfaces_prior == -1 )
00322   {
00323     PRINT_ERROR( "Cannot split a surface that is not part of a volume\n" );
00324     return CUBIT_FAILURE;
00325   }
00326   else if( num_surfaces_prior == -2 )
00327   {
00328     PRINT_ERROR( "Cannot split a surface that is contained by multiple volumes\n" );
00329     return CUBIT_FAILURE;
00330   }
00331 
00332   // Clear any previews
00333   GfxPreview::clear();
00334 
00335   // Perform the split on the real (e.g. OCC) geometry.
00336   Surface *surf_ptr = ref_face_ptr->get_surface_ptr();
00337 
00338   DLIList<Surface*> surface_list;
00339   surface_list.append( surf_ptr );
00340   DLIList<DLIList<Curve*>*> curve_lists_list;
00341   curve_lists_list.append( &curve_list );
00342 
00343   Body *new_body_ptr;
00344 
00345   if( GeometryModifyTool::instance()->imprint( surface_list,
00346     curve_lists_list, new_body_ptr ) == CUBIT_FAILURE )
00347   {
00348     while( curve_list.size() ) 
00349       delete curve_list.pop();
00350     return CUBIT_FAILURE;
00351   }
00352 
00353   while( curve_list.size() ) 
00354     delete curve_list.pop();
00355 
00356   // Draw locations too
00357   // draw_points( locations, CUBIT_BLUE_INDEX );
00358   
00359   int num_surfaces_after = count_surfaces_in_body( body_ptr );
00360   
00361   if( num_surfaces_after > num_surfaces_prior )
00362     return CUBIT_SUCCESS;
00363   else
00364   {
00365     int num_curves_after = count_curves_in_body( body_ptr );
00366     if( num_curves_after > num_curves_prior )
00367       return CUBIT_SUCCESS;
00368   }
00369   
00370   PRINT_ERROR( "Split failed - surface %d was not split\n", ref_face_ptr->id() );
00371   return CUBIT_FAILURE;
00372 }
00373 
00374 CubitStatus                                
00375 SplitSurfaceTool::split_surface( RefFace *ref_face_ptr,
00376                                  DLIList<DLIList<CubitVector*>*> &vec_lists )
00377 {
00378   // Count number of surfaces in owning body prior to split - this is used to
00379   // determine if split is actually successful.
00380   Body *body_ptr;
00381   int num_surfaces_prior = count_surfaces_in_owning_body( ref_face_ptr, body_ptr );
00382   if( num_surfaces_prior == -1 )
00383   {
00384     PRINT_ERROR( "Cannot split a surface that is not part of a volume\n" );
00385     return CUBIT_FAILURE;
00386   }
00387   else if( num_surfaces_prior == -2 )
00388   {
00389     PRINT_ERROR( "Cannot split a surface that is contained by multiple volumes\n" );
00390     return CUBIT_FAILURE;
00391   }
00392   int num_curves_prior = count_curves_in_body( body_ptr );
00393 
00394   int original_id = ref_face_ptr->id();
00395   Surface *surf_ptr = ref_face_ptr->get_surface_ptr();
00396 
00397   // Clear any previews
00398   GfxPreview::clear();
00399 
00400   // Find the splitting curves
00401   DLIList<DLIList<Curve*>*> curve_lists_list;
00402 
00403   // Support composite surfaces by getting the surfaces underlying
00404   // the composite and creating split curves for them individually.
00405   GeometryQueryEngine *gqe = surf_ptr->get_geometry_query_engine();
00406   DLIList<TopologyBridge*> tbs;
00407   gqe->get_underlying_surfaces(surf_ptr, tbs);
00408   CubitStatus err = CUBIT_SUCCESS;
00409   if(tbs.size() > 0)
00410   {
00411     err = CUBIT_FAILURE;
00412     for(int k=tbs.size(); k>0; k--)
00413     {
00414       Surface *srf = dynamic_cast<Surface*>(tbs.get_and_step());
00415       if(srf)
00416       {
00417         DLIList<Curve*> *curve_list = new DLIList<Curve*>;
00418         CubitStatus tmp_status = calculate_split_curves( srf, vec_lists, *curve_list );
00419         // If at least one split is successful return success.  We anticipate that some curves
00420         // won't imprint on some of the underlying surfaces of the composite surface.  Because
00421         // we are allowing success this way there are sometimes errors that get printed even
00422         // though we are calling it a success.  Need to find a good way to fix this.
00423         if(tmp_status)
00424           err = CUBIT_SUCCESS;
00425         curve_lists_list.append(curve_list);
00426       }
00427     }
00428   }
00429   else
00430   {
00431     DLIList<Curve*> *curve_list = new DLIList<Curve*>;
00432     err = calculate_split_curves( ref_face_ptr, vec_lists, *curve_list );
00433     curve_lists_list.append(curve_list);
00434   }
00435 
00436   if( err == CUBIT_FAILURE )
00437   {
00438     while(curve_lists_list.size())
00439     {
00440       DLIList<Curve*> *cur_list = curve_lists_list.pop();
00441       while(cur_list->size())
00442       {
00443         Curve* curve_ptr = cur_list->pop();
00444         curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
00445       }
00446       delete cur_list;
00447     }
00448     return CUBIT_FAILURE;
00449   }
00450 
00451   // Perform the split on the real (e.g. OCC) geometry.
00452   DLIList<Surface*> surface_list;
00453   surface_list.append( surf_ptr );
00454 
00455   Body *new_body_ptr;
00456 
00457   if( GeometryModifyTool::instance()->imprint( surface_list,
00458     curve_lists_list, new_body_ptr ) == CUBIT_FAILURE )
00459   {
00460     while(curve_lists_list.size())
00461     {
00462       DLIList<Curve*> *cur_list = curve_lists_list.pop();
00463       while(cur_list->size())
00464       {
00465         Curve* curve_ptr = cur_list->pop();
00466         curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
00467       }
00468       delete cur_list;
00469     }
00470     return CUBIT_FAILURE;
00471   }
00472 
00473   while(curve_lists_list.size())
00474   {
00475     DLIList<Curve*> *cur_list = curve_lists_list.pop();
00476     while(cur_list->size())
00477       {
00478         Curve* curve_ptr = cur_list->pop();
00479         curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
00480       }
00481     delete cur_list;
00482   }
00483 
00484   // Draw locations too
00485   //draw_points( locations, CUBIT_BLUE_INDEX );
00486 
00487   int num_surfaces_after = count_surfaces_in_body( body_ptr );
00488   
00489   if( num_surfaces_after > num_surfaces_prior )
00490     return CUBIT_SUCCESS;
00491   else
00492   {
00493     int num_curves_after = count_curves_in_body( body_ptr );
00494     if( num_curves_after > num_curves_prior )
00495       return CUBIT_SUCCESS;
00496   }
00497   
00498   PRINT_ERROR( "Split failed - surface %d was not split\n", original_id );
00499   return CUBIT_FAILURE;
00500 }
00501 //ADDED BY GJS (CAT) 6/26/08 @ 11:00am
00502 CubitStatus                                
00503 SplitSurfaceTool::split_surface( DLIList<RefFace*> &ref_face_list,
00504                                  DLIList<DLIList<DLIList<CubitVector*>*>*> &list_of_vec_lists )
00505 {
00506    //Initialize inputs to imprint function call     
00507    DLIList<Surface*> surface_list;
00508    DLIList<DLIList<Curve*>*> curve_lists_list;
00509 
00510    // Clear any previews
00511    GfxPreview::clear();
00512 
00513    //Reset all lists
00514    ref_face_list.reset();
00515    list_of_vec_lists.reset();
00516 
00517    int hh;
00518    for( hh = ref_face_list.size() ; hh > 0 ; hh--)
00519    {
00520       // Count number of surfaces in owning body prior to split - this is used to
00521       // determine if split is actually successful.   0
00522       RefFace* ref_face_ptr = ref_face_list.get_and_step();
00523       Body* body_ptr;
00524       
00525       int num_surfaces_prior = count_surfaces_in_owning_body( ref_face_ptr, body_ptr );
00526       if( num_surfaces_prior == -1 )
00527       {
00528          PRINT_ERROR( "Cannot split a surface that is not part of a volume\n" );
00529          return CUBIT_FAILURE;
00530       }
00531       else if( num_surfaces_prior == -2 )
00532       {
00533          PRINT_ERROR( "Cannot split a surface that is contained by multiple volumes\n" );
00534          return CUBIT_FAILURE;
00535       }
00536       ref_face_ptr->id();
00537       Surface *surf_ptr = ref_face_ptr->get_surface_ptr();
00538 
00539 
00540 
00541       // Support composite surfaces by getting the surfaces underlying
00542       // the composite and creating split curves for them individually.
00543       GeometryQueryEngine *gqe = surf_ptr->get_geometry_query_engine();
00544       DLIList<TopologyBridge*> tbs;
00545       gqe->get_underlying_surfaces(surf_ptr, tbs);
00546       CubitStatus err = CUBIT_SUCCESS;
00547       if(tbs.size() > 0)
00548       {
00549          err = CUBIT_FAILURE;
00550          for(int k=tbs.size(); k>0; k--)
00551          {
00552             Surface *srf = dynamic_cast<Surface*>(tbs.get_and_step());
00553             if(srf)
00554             {
00555                DLIList<Curve*> *curve_list = new DLIList<Curve*>;
00556                DLIList<DLIList<CubitVector*>*> temp_vec_lists = *( list_of_vec_lists.get_and_step() );
00557                CubitStatus tmp_status = calculate_split_curves( srf, temp_vec_lists, *curve_list );
00558                // If at least one split is successful return success.  We anticipate that some curves
00559                // won't imprint on some of the underlying surfaces of the composite surface.  Because
00560                // we are allowing success this way there are sometimes errors that get printed even
00561                // though we are calling it a success.  Need to find a good way to fix this.
00562                if(tmp_status)
00563                   err = CUBIT_SUCCESS;
00564                curve_lists_list.append(curve_list);
00565             }
00566          }
00567       }
00568       else
00569       {
00570          DLIList<Curve*> *curve_list = new DLIList<Curve*>;
00571          DLIList<DLIList<CubitVector*>*> temp_vec_lists = *( list_of_vec_lists.get_and_step() );
00572          err = calculate_split_curves( ref_face_ptr, temp_vec_lists, *curve_list );
00573          curve_lists_list.append(curve_list);
00574       }
00575 
00576       if( err == CUBIT_FAILURE )
00577       {
00578          while(curve_lists_list.size())
00579          {
00580             DLIList<Curve*> *cur_list = curve_lists_list.pop();
00581             while(cur_list->size())
00582                delete cur_list->pop();
00583             delete cur_list;
00584          }
00585          return CUBIT_FAILURE;
00586       }
00587 
00588       surface_list.append( surf_ptr );
00589    }
00590 
00591    // Perform the split on the real (e.g. OCC) geometry.
00592    Body *new_body_ptr;
00593 
00594    if( GeometryModifyTool::instance()->imprint( surface_list,
00595       curve_lists_list, new_body_ptr ) == CUBIT_FAILURE )
00596    {
00597       while(curve_lists_list.size())
00598       {
00599          DLIList<Curve*> *cur_list = curve_lists_list.pop();
00600          while(cur_list->size())
00601             delete cur_list->pop();
00602          delete cur_list;
00603       }
00604       return CUBIT_FAILURE;
00605    }
00606 
00607    while(curve_lists_list.size())
00608    {
00609       DLIList<Curve*> *cur_list = curve_lists_list.pop();
00610       while(cur_list->size())
00611          delete cur_list->pop();
00612       delete cur_list;
00613    }
00614 
00615    //NOTE: current assumption is failure will not occur since user does not
00616    //      control input parameters to this function (may need to fix).
00617    //int num_surfaces_after = count_surfaces_in_body( body_ptr );
00618 
00619    //if( num_surfaces_after > num_surfaces_prior )
00620    //   return CUBIT_SUCCESS;
00621    //else
00622    //{
00623    //   int num_curves_after = count_curves_in_body( body_ptr );
00624    //   if( num_curves_after > num_curves_prior )
00625    //      return CUBIT_SUCCESS;
00626    //}
00627 
00628    //PRINT_ERROR( "Split failed - surface %d was not split\n", original_id );
00629    //return CUBIT_FAILURE;
00630 
00631    return CUBIT_SUCCESS;
00632 }
00633 
00634 CubitStatus
00635 SplitSurfaceTool::draw_points( DLIList<CubitVector*> &pnt_list, int color, 
00636                                int flush )
00637 {
00638   int i;
00639   for( i=pnt_list.size(); i--; )
00640   {
00641     CubitVector *pnt_ptr = pnt_list.get_and_step();
00642     draw_point( *pnt_ptr, color );
00643   }
00644 
00645   if( flush )
00646   {
00647     GfxPreview::flush();
00648   }
00649 
00650   return CUBIT_SUCCESS;
00651 }
00652 
00653 CubitStatus
00654 SplitSurfaceTool::draw_point( CubitVector &pnt, int color, int flush )
00655 {
00656   GfxPreview::draw_point( pnt, color );
00657   if( flush )
00658   {
00659     GfxPreview::flush();
00660   }
00661   return CUBIT_SUCCESS;
00662 }
00663 
00664 CubitStatus
00665 SplitSurfaceTool::split_surfaces( DLIList<RefFace*> &ref_face_list,
00666                                  int num_segs,
00667                                  double fraction,
00668                                  double distance,
00669                                  RefEdge *from_curve_ptr,
00670                                  DLIList<RefVertex*> &corner_vertex_list,
00671                                  DLIList<RefVertex*> &through_vertex_list,
00672                                  RefEdge *curve_dir_ptr,
00673                                  CubitBoolean preview_flg,
00674                                  CubitBoolean create_ref_edges_flg )
00675 {
00676   CubitStatus status;
00677 
00678   CubitBoolean just_curves_flg = CUBIT_FALSE;
00679   DLIList<DLIList<Curve*>*> curve_lists_list;
00680 
00681   // Clear any previous previews
00682   GfxPreview::clear();
00683 
00684   // Call the primary function
00685   status = split_surfaces( ref_face_list, num_segs, fraction, distance, 
00686                            from_curve_ptr, corner_vertex_list, 
00687                            through_vertex_list, curve_dir_ptr,
00688                            preview_flg, create_ref_edges_flg,
00689                            just_curves_flg, curve_lists_list );
00690 
00691   free_curves_lists( curve_lists_list );
00692 
00693   return status;
00694 }
00695 
00696 CubitStatus
00697 SplitSurfaceTool::split_surfaces( DLIList<RefFace*> &ref_face_list,
00698                                   int num_segs,
00699                                   double fraction,
00700                                   double distance,
00701                                   RefEdge *from_curve_ptr,
00702                                   DLIList<RefVertex*> &corner_vertex_list,
00703                                   DLIList<RefVertex*> &through_vertex_list,
00704                                   RefEdge *curve_dir_ptr,
00705                                   DLIList<DLIList<Curve*>*> &curve_lists_list )
00706 {
00707   CubitStatus status;
00708   CubitBoolean preview_flg = CUBIT_FALSE;
00709   CubitBoolean create_ref_edges_flg = CUBIT_FALSE;
00710   CubitBoolean just_curves_flg = CUBIT_TRUE;
00711 
00712   // Call the primary function
00713   status = split_surfaces( ref_face_list, num_segs, fraction, distance, 
00714                            from_curve_ptr, corner_vertex_list, 
00715                            through_vertex_list, curve_dir_ptr,
00716                            preview_flg, create_ref_edges_flg,
00717                            just_curves_flg, curve_lists_list );
00718 
00719   return status;
00720 }
00721 
00722 CubitStatus
00723 SplitSurfaceTool::split_surfaces( DLIList<RefFace*> &ref_face_list,
00724                                   int num_segs,
00725                                   double fraction,
00726                                   double distance,
00727                                   RefEdge *from_curve_ptr,
00728                                   DLIList<RefVertex*> &corner_vertex_list,
00729                                   DLIList<RefVertex*> &through_vertex_list,
00730                                   RefEdge *curve_dir_ptr,
00731                                   DLIList<Curve*> &curve_list )
00732 {
00733   CubitStatus status;
00734   CubitBoolean preview_flg = CUBIT_FALSE;
00735   CubitBoolean create_ref_edges_flg = CUBIT_FALSE;
00736   CubitBoolean just_curves_flg = CUBIT_TRUE;
00737   DLIList<DLIList<Curve*>*> curve_lists_list;
00738 
00739   // Call the primary function
00740   status = split_surfaces( ref_face_list, num_segs, fraction, distance, 
00741                            from_curve_ptr, corner_vertex_list, 
00742                            through_vertex_list, curve_dir_ptr,
00743                            preview_flg, create_ref_edges_flg,
00744                            just_curves_flg, curve_lists_list );
00745 
00746   // Convert the curves to the simple curve_list
00747   int i, j;
00748   curve_lists_list.reset();
00749   for( i=curve_lists_list.size(); i--; )
00750   {
00751     DLIList<Curve*> *curve_list_ptr = curve_lists_list.get_and_step();
00752 
00753     curve_list_ptr->reset();
00754     for( j=curve_list_ptr->size(); j--; )
00755     {
00756       Curve *curve_ptr = curve_list_ptr->get_and_step();
00757       curve_list.append( curve_ptr );
00758     }
00759   }
00760 
00761   free_curves_lists( curve_lists_list, CUBIT_FALSE );
00762 
00763   return status;
00764 }
00765 
00766 CubitStatus
00767 SplitSurfaceTool::calculate_split_curves( DLIList<RefFace*> &ref_face_list, 
00768                                           int num_segs, 
00769                                           double fraction,
00770                                           double distance,
00771                                           RefEdge *from_curve_ptr,
00772                                           DLIList<RefVertex*> &corner_vertex_list,
00773                                           DLIList<RefVertex*> &through_vertex_list,
00774                                           RefEdge *curve_dir_ptr,
00775                                           CubitBoolean preview_flg,
00776                                           CubitBoolean create_ref_edges_flg,
00777                                           CubitBoolean just_curves_flg,
00778                                           DLIList<DLIList<Curve*>*> &curve_lists_list )
00779 {
00780   int i;
00781   refFaceChain = ref_face_list;
00782   throughVertexList = through_vertex_list;
00783 
00784   // Get tolerance and parametric_flg from member variables
00785   double tolerance = splitTolerance;
00786   CubitBoolean parametric_flg = parametricFlg;
00787 
00788   // Check for valid fraction
00789   if( fraction<0.0 || fraction>1.0 )
00790   {
00791     PRINT_ERROR( "Fraction must be between 0.0 and 1.0 - aborting.\n" );
00792     return CUBIT_FAILURE;
00793   }
00794 
00795   // Check for valid number of segments
00796   if( num_segs < 2 )
00797   {
00798     PRINT_ERROR( "Number of specified segments must be >= 2\n" );
00799     return CUBIT_FAILURE;
00800   }
00801 
00802   // Not valid to specify through vertices with multiple segments
00803   if( num_segs > 2 && throughVertexList.size() )
00804   {
00805     PRINT_ERROR( "Through vertices specified - not valid if number of segments > 2\n" );
00806     return CUBIT_FAILURE;
00807   }
00808 
00809   // Check number of through vertices
00810   if( throughVertexList.size() > refFaceChain.size()+1 )
00811   {
00812     PRINT_ERROR( "Too many 'through' vertices specified.\n"
00813       "       Can only be equal to one more than the number of surfaces to split.\n" );
00814     return CUBIT_FAILURE;
00815   }
00816 
00817   // If a distance was specified, set the parametric flag to FALSE
00818   if( distance != -1.0 )
00819     parametric_flg = CUBIT_FALSE;
00820 
00821   // Check the individual surfaces for errors (multiple loops, hardlines)
00822   if( check_valid_faces() == CUBIT_FAILURE )
00823     return CUBIT_FAILURE;
00824 
00825   // Order the face list from one end of the chain to the other.  This function
00826   // also checks for the isLoop condition.
00827   if( order_face_list() == CUBIT_FAILURE )
00828     return CUBIT_FAILURE;
00829   if( DEBUG_FLAG(154) )
00830   {
00831     DLIList<CubitEntity*> cubit_faces;
00832     CAST_LIST(refFaceChain, cubit_faces, CubitEntity);
00833     CubitUtil::list_entity_ids( "\nOrdered surface list: ", 
00834       cubit_faces, 80, "\n", CUBIT_FALSE );
00835   }
00836 
00837   // Get all the outer loops, in the proper order.  This also makes sure 
00838   // they start at the beginning of the first surface in the chain.
00839   if( get_outer_loops() == CUBIT_FAILURE )
00840     return CUBIT_FAILURE;
00841 
00842   // Make sure direction and from curves are valid, if specified
00843   if( curve_dir_ptr && !is_curve_in_outer_loop( curve_dir_ptr ) )
00844   {
00845     PRINT_ERROR( "Specified direction curve %d not found on side of logical rectangle\n",
00846       curve_dir_ptr->id() );
00847     return CUBIT_FAILURE;
00848   }
00849   if( from_curve_ptr && !is_curve_in_outer_loop( from_curve_ptr ) )
00850   {
00851     PRINT_ERROR( "Specified from curve %d not found on side of logical rectangle\n",
00852       from_curve_ptr->id() );
00853     return CUBIT_FAILURE;
00854   }
00855 
00856   // Find the corners
00857   if( corner_vertex_list.size() )
00858   {
00859     if( corner_vertex_list.size() != 4 )
00860     {
00861       PRINT_ERROR( "You must select exactly 4 corner vertices\n" );
00862       return CUBIT_FAILURE;
00863     }
00864 
00865     if( isLoop )
00866     {
00867       PRINT_WARNING( "Ignoring specified corners since continuous loop situation\n" );
00868     }
00869     else
00870     {
00871       // Now order these vertices properly w/respect to the outerCoEdgeLoop
00872       if( order_selected_corners( corner_vertex_list ) == CUBIT_FAILURE )
00873         return CUBIT_FAILURE;
00874     }
00875   }
00876   else
00877   {
00878     // Pick the corners based on angle criteria
00879     if( refFaceChain.size() > 1 )
00880     {
00881       if( pick_4_corners() == CUBIT_FAILURE )
00882         return CUBIT_FAILURE;
00883     }
00884     else
00885     {
00886       // Single surface case
00887       if( pick_4_corners_simple() == CUBIT_FAILURE )
00888         return CUBIT_FAILURE;
00889     }
00890   }
00891 
00892   // Adjust the surface to the split direction.  This function also adjusts
00893   // and checks for errors if a throughVertexList was specified.
00894   if( adjust_for_split_direction( curve_dir_ptr, from_curve_ptr, corner_vertex_list )
00895     == CUBIT_FAILURE )
00896     return CUBIT_FAILURE;
00897 
00898   // If previewing, draw the corners in RED
00899   if( preview_flg == CUBIT_TRUE )
00900   {
00901     CubitVector temp_vec = start_vertex(cornerCoEdge[0])->coordinates();
00902   
00903     draw_point( temp_vec, CUBIT_RED_INDEX );
00904     temp_vec = start_vertex(cornerCoEdge[1])->coordinates();
00905     draw_point( temp_vec, CUBIT_RED_INDEX );
00906     temp_vec = start_vertex(cornerCoEdge[2])->coordinates();
00907     draw_point( temp_vec, CUBIT_RED_INDEX );
00908     temp_vec = start_vertex(cornerCoEdge[3])->coordinates();
00909     draw_point( temp_vec, CUBIT_RED_INDEX, CUBIT_TRUE );
00910   }
00911 
00912   if( DEBUG_FLAG(154) )
00913   {
00914     DLIList<RefEdge*> curve_list;
00915     get_outer_curves( curve_list );
00916     DLIList<CubitEntity*> cubit_edges;
00917     CAST_LIST(curve_list, cubit_edges, CubitEntity);
00918     CubitUtil::list_entity_ids( "Ordered curves outer loop: ", 
00919       cubit_edges, 80, "\n", CUBIT_FALSE );
00920     
00921     PRINT_INFO( "Best corner 1 = Vertex %d\n", start_vertex(cornerCoEdge[0])->id() );
00922     PRINT_INFO( "Best corner 2 = Vertex %d\n", start_vertex(cornerCoEdge[1])->id() );
00923     PRINT_INFO( "Best corner 3 = Vertex %d\n", start_vertex(cornerCoEdge[2])->id() );
00924     PRINT_INFO( "Best corner 4 = Vertex %d\n", start_vertex(cornerCoEdge[3])->id() );
00925 
00926     PRINT_INFO( "Side interval #1 = %d\n", sideInterval[0] );
00927     PRINT_INFO( "Side interval #2 = %d\n", sideInterval[1] );
00928     PRINT_INFO( "Side interval #3 = %d\n", sideInterval[2] );
00929     PRINT_INFO( "Side interval #4 = %d\n", sideInterval[3] );
00930   }
00931 
00932   // Add a tooldata to each surface for later use
00933   RefFace *ref_face_ptr;
00934   refFaceChain.reset();
00935   for( i=refFaceChain.size(); i--; )
00936   {
00937     ref_face_ptr = refFaceChain.get_and_step();
00938     ref_face_ptr->add_TD( new TDSplitSurface( ref_face_ptr ) );
00939   }
00940 
00941   // Add curve loops to each tooldata.  These curve loops will form the
00942   // boundary of a mapped mesh algorithm that will find the interior
00943   // points for the split locations.
00944   if( populate_curve_loops() == CUBIT_FAILURE )
00945   {
00946     delete_surf_tooldatas( refFaceChain );
00947     return CUBIT_FAILURE;
00948   }
00949 
00950   // Now build up the coordinates and get the curve(s) for each surface
00951   // curve_lists_list will contain a list of curve lists for each surface
00952 
00953   // Keep track of new RefEdges created
00954   DLIList<RefEdge*> new_ref_edge_list;
00955 
00956   TDSplitSurface *tdss;
00957   refFaceChain.reset();
00958   for(i=refFaceChain.size(); i--; )
00959   {
00960     ref_face_ptr = refFaceChain.get_and_step();
00961     tdss = (TDSplitSurface *)ref_face_ptr->
00962       get_TD(&TDSplitSurface::is_split_surface);
00963 
00964     // Setup matched curve tessellations on all curves (the tessellations
00965     // are "matched" from side to side - the points on each side are
00966     // at identical parameter values along the side).  This is not a 
00967     // perfect solution but seems to work okay for the typical geometry
00968     // types this tool is used on.
00969     if( tdss->tessellate_sides( tolerance, fraction, distance, num_segs,
00970         throughVertexList ) == CUBIT_FAILURE )
00971     {
00972       delete_vertex_tooldatas( through_vertex_list );
00973       delete_surf_tooldatas( refFaceChain );
00974       return CUBIT_FAILURE;
00975     }
00976 
00977     // curve_list_ptr will contain a list of curves for the individual surface
00978     DLIList<Curve*> *curve_list_ptr = new DLIList<Curve*>;
00979     curve_lists_list.append( curve_list_ptr );
00980 
00981     // Use a mapping concept to get the spline coordinates of the curve to
00982     // split with.  The function find_spline_curves will populate curve_list_ptr
00983     // with potentially multiple curves (typically there will only be one curve 
00984     // though).
00985     if( find_spline_curves( ref_face_ptr, num_segs, distance, curve_list_ptr,
00986                             tolerance, parametric_flg, preview_flg,
00987                             create_ref_edges_flg ) == CUBIT_FAILURE )
00988     {
00989       delete_vertex_tooldatas( throughVertexList );
00990       delete_surf_tooldatas( refFaceChain );
00991       return CUBIT_FAILURE;
00992     }
00993 
00994     if( just_curves_flg == CUBIT_TRUE )
00995       continue;
00996 
00997     if( preview_flg == CUBIT_TRUE )
00998     {
00999       if( create_ref_edges_flg == CUBIT_FALSE )
01000         draw_preview( *curve_list_ptr );
01001       else
01002       {
01003         create_ref_edges( *curve_list_ptr, new_ref_edge_list );
01004 
01005         // This just draws each curve as we go, same as preview does
01006         GfxPreview::flush();
01007       }
01008     }
01009   }
01010 
01011   // Let the user know if new curves were created
01012   if( preview_flg == CUBIT_TRUE && create_ref_edges_flg == CUBIT_TRUE
01013       && new_ref_edge_list.size() )
01014   {
01015     DLIList<CubitEntity*> cubit_entity_list;
01016     CAST_LIST( new_ref_edge_list, cubit_entity_list, CubitEntity );
01017     CubitUtil::list_entity_ids( "Created new curves: ", cubit_entity_list );
01018   }
01019 
01020   // Determine if all of the 'through' vertices were used - if not give a warning
01021   if( throughVertexList.size() )
01022   {
01023     DLIList<RefVertex*> non_used_through_vertex_list;
01024     RefVertex *ref_vertex_ptr;
01025     throughVertexList.reset();
01026     for( i=throughVertexList.size(); i--; )
01027     {
01028       ref_vertex_ptr = throughVertexList.get_and_step();
01029       tdss = (TDSplitSurface *)ref_vertex_ptr->
01030         get_TD(&TDSplitSurface::is_split_surface);
01031       if( !tdss )
01032         non_used_through_vertex_list.append( ref_vertex_ptr );
01033     }
01034     
01035     if( non_used_through_vertex_list.size() )
01036     {
01037       DLIList<CubitEntity*> cubit_verts;
01038       CAST_LIST(non_used_through_vertex_list, cubit_verts, CubitEntity);
01039       CubitUtil::list_entity_ids( "WARNING - unused 'through' vertices: ", 
01040         cubit_verts, 80, "\n", CUBIT_FALSE );
01041       PRINT_INFO("         They were not found on the split path.\n" );
01042     }
01043   }
01044 
01045   // Remove tooldatas
01046   delete_vertex_tooldatas( throughVertexList );
01047   delete_surf_tooldatas( refFaceChain );
01048 
01049   return CUBIT_SUCCESS;
01050 }
01051 
01052 //- Begin Private Functions
01053 CubitStatus
01054 SplitSurfaceTool::split_surfaces( DLIList<RefFace*> &ref_face_list, 
01055                                   int num_segs, 
01056                                   double fraction,
01057                                   double distance,
01058                                   RefEdge *from_curve_ptr,
01059                                   DLIList<RefVertex*> &corner_vertex_list,
01060                                   DLIList<RefVertex*> &through_vertex_list,
01061                                   RefEdge *curve_dir_ptr,
01062                                   CubitBoolean preview_flg,
01063                                   CubitBoolean create_ref_edges_flg,
01064                                   CubitBoolean just_curves_flg,
01065                                   DLIList<DLIList<Curve*>*> &curve_lists_list )
01066 {
01067 
01068   // Find the splitting curves
01069   if( calculate_split_curves( ref_face_list, num_segs, fraction, distance,
01070                               from_curve_ptr, corner_vertex_list, through_vertex_list,
01071                               curve_dir_ptr, preview_flg, create_ref_edges_flg,
01072                               just_curves_flg, curve_lists_list ) == CUBIT_FAILURE )
01073     return CUBIT_FAILURE;                         
01074   
01075   // Do the splitting
01076   if( preview_flg==CUBIT_FALSE && just_curves_flg==CUBIT_FALSE )
01077   {
01078     int i;
01079     DLIList<Surface*> surface_list;
01080     refFaceChain.reset();
01081     for( i=refFaceChain.size(); i--; )
01082       surface_list.append( refFaceChain.get_and_step()->get_surface_ptr() );
01083 
01084     Body *new_body_ptr;
01085     if( GeometryModifyTool::instance()->imprint( surface_list,
01086       curve_lists_list, new_body_ptr ) == CUBIT_FAILURE )
01087     {
01088       return CUBIT_FAILURE;
01089     }
01090   }
01091 
01092   return CUBIT_SUCCESS;
01093 }
01094 
01095 void
01096 SplitSurfaceTool::free_curves_lists( DLIList<DLIList<Curve*>*> &curve_lists_list,
01097                                      CubitBoolean free_curves_flg)
01098 {
01099   while( curve_lists_list.size() )
01100   {
01101     DLIList<Curve*> *curve_list_ptr = curve_lists_list.pop();
01102     
01103     if( free_curves_flg == CUBIT_TRUE )
01104     {
01105       while( curve_list_ptr->size() )
01106       {
01107         Curve *curve_ptr = curve_list_ptr->pop();
01108         
01109         // If there is no RefEdge attached to this Curve, delete it
01110         RefEdge* ref_edge_ptr = dynamic_cast<RefEdge*>(curve_ptr->topology_entity());
01111         if( !ref_edge_ptr )
01112            curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
01113       }
01114     }
01115 
01116     delete curve_list_ptr;
01117   }
01118 }
01119 
01120 void
01121 SplitSurfaceTool::delete_surf_tooldatas( DLIList<RefFace*> &ref_face_list )
01122 {
01123   int i;
01124   for( i=ref_face_list.size(); i--; )
01125   {
01126     RefFace *ref_face_ptr = ref_face_list.get_and_step();
01127     ref_face_ptr->delete_TD( &TDSplitSurface::is_split_surface );
01128   }
01129 }
01130 
01131 void
01132 SplitSurfaceTool::delete_coedge_tooldatas( DLIList<CoEdge*> &co_edge_list )
01133 {
01134   int i;
01135   for( i=co_edge_list.size(); i--; )
01136   {
01137     CoEdge *co_edge_ptr = co_edge_list.get_and_step();
01138     co_edge_ptr->delete_TD( &TDSplitSurface::is_split_surface );
01139   }
01140 }
01141 
01142 void
01143 SplitSurfaceTool::delete_vertex_tooldatas( DLIList<RefVertex*> &ref_vertex_list )
01144 {
01145   int i;
01146   for( i=ref_vertex_list.size(); i--; )
01147   {
01148     RefVertex *ref_vertex_ptr = ref_vertex_list.get_and_step();
01149     ref_vertex_ptr->delete_TD( &TDSplitSurface::is_split_surface );
01150   }
01151 }
01152 
01153 CubitStatus
01154 SplitSurfaceTool::check_valid_faces()
01155 {
01156   // Make sure each face doesn't have multiple loops or hardlines
01157   int i;
01158   RefFace *ref_face_ptr;
01159   CubitBoolean is_loop;
01160   refFaceChain.reset();
01161   for( i=refFaceChain.size(); i--; )
01162   {
01163     ref_face_ptr = refFaceChain.get_and_step();
01164     if( check_face_loop( ref_face_ptr, is_loop ) == CUBIT_FAILURE )
01165       return CUBIT_FAILURE;
01166 
01167     if( refFaceChain.size()>1 && is_loop==CUBIT_TRUE )
01168     {
01169       PRINT_ERROR( "Surface %d loops back on itself - cannot split chain.\n",
01170         ref_face_ptr->id() );
01171       return CUBIT_FAILURE;
01172     }
01173   }
01174   return CUBIT_SUCCESS;
01175 }
01176 
01177 CubitStatus
01178 SplitSurfaceTool::order_face_list()
01179 {
01180   int i;
01181   RefFace *ref_face_ptr = NULL;
01182 
01183   if( refFaceChain.size() > 1 )
01184   {
01185     // First make sure surfaces are at least connected
01186     refFaceChain.reset();
01187     for( i=refFaceChain.size(); i--; )
01188     {
01189       ref_face_ptr = refFaceChain.get_and_step();
01190 
01191       DLIList<RefFace*> neighbor_ref_faces;
01192       get_neighbors( ref_face_ptr, refFaceChain, neighbor_ref_faces );
01193       if( neighbor_ref_faces.size() == 0 )
01194       {
01195         PRINT_ERROR( "You must select a continuous chain of surfaces.\n"
01196           "       Surface %d is not attached to the other surfaces.\n",
01197           ref_face_ptr->id() );
01198         return CUBIT_FAILURE;
01199       }
01200     } 
01201   }
01202 
01203   if( refFaceChain.size() < 3 )
01204   {
01205     if( refFaceChain.size() == 1 )
01206     {
01207       // Check for isLoop situation.  Assume we have a loop if some of
01208       // the RefEdges have 2 CoEdges that don't immediately loop back
01209       // on themselves (this is a hardline).
01210       ref_face_ptr = refFaceChain.get();
01211       if( check_face_loop( ref_face_ptr, isLoop ) == CUBIT_FAILURE )
01212         return CUBIT_FAILURE;
01213 
01214       return CUBIT_SUCCESS;
01215     }
01216 
01217     if( refFaceChain.size() == 2 )
01218     {
01219       // Check for isLoop situation.  Assume we have a loop if two separate
01220       // chains of curves from the first surface are shared by the second
01221       // surface.
01222       refFaceChain.reset();
01223       RefFace *ref_face_ptr1 = refFaceChain.get_and_step();
01224       RefFace *ref_face_ptr2 = refFaceChain.get();
01225       CoEdge *start_co_edge_ptr = NULL; // Dummy
01226       if( check_for_loop( ref_face_ptr1, ref_face_ptr2, isLoop, start_co_edge_ptr )
01227         == CUBIT_FAILURE )
01228         return CUBIT_FAILURE;
01229     }
01230     return CUBIT_SUCCESS;
01231   }
01232 
01233   // Get the face list going from one end to the other
01234   DLIList<RefFace*> ordered_face_list;
01235 
01236   // Find an end - would have only one attached face
01237   int found = 0;
01238   refFaceChain.reset();
01239   for( i=refFaceChain.size(); i--; )
01240   {
01241     ref_face_ptr = refFaceChain.get_and_step();
01242 
01243     DLIList<RefFace*> neighbor_ref_faces;
01244     get_neighbors( ref_face_ptr, refFaceChain, neighbor_ref_faces );
01245     if( neighbor_ref_faces.size() == 1 )
01246     {
01247       found = 1;
01248       break;
01249     }
01250     else if( neighbor_ref_faces.size() == 0 )
01251     {
01252       PRINT_ERROR( "You must select a continuous chain of surfaces.\n"
01253         "       Surface %d is not attached to the other surfaces.\n",
01254         ref_face_ptr->id() );
01255       return CUBIT_FAILURE;
01256     }
01257   }
01258 
01259   // Check for continuous loop of surfaces
01260   if( !found )
01261   {
01262     // This is a continuous loop of surfaces - just use the first one the 
01263     // user picked as starting surface of the patch.
01264     isLoop = CUBIT_TRUE;
01265     refFaceChain.reset();
01266     ref_face_ptr = refFaceChain.get();
01267   }
01268 
01269   // Walk across the surfaces
01270   ordered_face_list.append( ref_face_ptr );
01271   DLIList<RefFace*> remaining_face_list = refFaceChain;
01272   remaining_face_list.remove( ref_face_ptr );
01273   remaining_face_list.reset();
01274   int num_faces = refFaceChain.size()-1;
01275 
01276   for( i=num_faces; i--; )
01277   {
01278     DLIList<RefFace*> neighbor_ref_faces;
01279     get_neighbors( ref_face_ptr, remaining_face_list, neighbor_ref_faces );
01280     if( (!isLoop && neighbor_ref_faces.size() != 1) ||
01281         (i==num_faces-1 && isLoop && neighbor_ref_faces.size() != 2) ||
01282         (i!=num_faces-1 && isLoop && neighbor_ref_faces.size() != 1) )
01283     {
01284       PRINT_ERROR( "Selected surfaces do not appear to form logical rectangle\n" );
01285       return CUBIT_FAILURE;
01286     }
01287     neighbor_ref_faces.reset();
01288     ref_face_ptr = neighbor_ref_faces.get();
01289     ordered_face_list.append( ref_face_ptr );
01290     remaining_face_list.remove( ref_face_ptr );
01291   }
01292 
01293   refFaceChain.clean_out();
01294   ordered_face_list.reset();
01295   refFaceChain = ordered_face_list;
01296 
01297   return CUBIT_SUCCESS;
01298 }
01299 
01300 CubitStatus
01301 SplitSurfaceTool::check_face_loop( RefFace *ref_face_ptr, CubitBoolean &is_loop )
01302 {
01303   is_loop = CUBIT_FALSE;
01304   
01305   // Get list of coedges for this surface
01306   DLIList<CoEdge*> co_edge_list;
01307   if( ordered_co_edges( ref_face_ptr, co_edge_list ) == CUBIT_FAILURE )
01308     return CUBIT_FAILURE;
01309 
01310   int i;
01311   co_edge_list.reset();
01312   CoEdge *co_edge_ptr;
01313   DLIList<RefEdge*> ref_edge_list;
01314   RefEdge *ref_edge_ptr;
01315   int prev_i = -99;
01316   RefEdge *prev_ref_edge_ptr = NULL;
01317   for( i=co_edge_list.size(); i--; )
01318   {
01319     co_edge_ptr = co_edge_list.get_and_step();
01320     ref_edge_ptr = co_edge_ptr->get_ref_edge_ptr();
01321 
01322     if( ref_edge_list.is_in_list( ref_edge_ptr ) )
01323     {
01324       // This may be a loop.
01325       is_loop = CUBIT_TRUE;
01326 
01327       // Make sure it is not a hardline.  Check for situation where loop
01328       // turns back on itself.
01329 
01330       if( ref_edge_ptr==prev_ref_edge_ptr && prev_i==i+1 )
01331       {
01332         PRINT_ERROR( "Detected hardline in Surface %d - cannot split.\n", 
01333           ref_face_ptr->id() );
01334         return CUBIT_FAILURE;
01335       }
01336     }
01337 
01338     prev_i = i;
01339     prev_ref_edge_ptr = ref_edge_ptr;
01340 
01341     ref_edge_list.append( ref_edge_ptr );
01342   }
01343 
01344   return CUBIT_SUCCESS;
01345 }
01346 
01347 CubitStatus 
01348 SplitSurfaceTool::check_for_loop( RefFace *ref_face_ptr1, RefFace *ref_face_ptr2, 
01349                                   CubitBoolean &is_loop, CoEdge *&start_co_edge_ptr )
01350 {
01351   // This algorithm is not perfect, but should cover most cases.
01352   RefEdge *ref_edge_ptr;
01353 
01354   is_loop = CUBIT_FALSE;
01355   
01356   // Get list of coedges for the first surface
01357   DLIList<CoEdge*> co_edge_list1;
01358   if( ordered_co_edges( ref_face_ptr1, co_edge_list1 ) == CUBIT_FAILURE )
01359     return CUBIT_FAILURE;
01360 
01361   // Get list of refedges for the second surface
01362   DLIList<RefEdge*> ref_edge_list2;
01363   DLIList<Loop*> loop_list;
01364   ref_face_ptr2->ordered_loops( loop_list );
01365   if( loop_list.size() > 1 )
01366   {
01367     PRINT_ERROR( "Only surfaces with a single loop are allowed.\n"
01368       "       Surface %d has %d loops.\n", ref_face_ptr2->id(), 
01369       loop_list.size() );
01370     return CUBIT_FAILURE;
01371   }
01372   loop_list.get()->ordered_ref_edges( ref_edge_list2 );
01373 
01374   // Walk around the first surface
01375 
01376   // First, position the list at a starting coedge - one that is shared with
01377   // the other surface.
01378   int i, j;
01379   co_edge_list1.reset();
01380   for( i=0; i<co_edge_list1.size(); i++ )
01381   {
01382     ref_edge_ptr = co_edge_list1.get()->get_ref_edge_ptr();
01383     
01384     if( ref_edge_list2.is_in_list( ref_edge_ptr ) )
01385     {
01386       if( i==0 ) // Backup until we are at the start
01387       {
01388         for( j=co_edge_list1.size(); j--; )
01389         {
01390           co_edge_list1.back();
01391           ref_edge_ptr = co_edge_list1.get()->get_ref_edge_ptr();
01392           if( ref_edge_list2.is_in_list( ref_edge_ptr ) )
01393             continue;
01394           co_edge_list1.step();
01395         }
01396       }
01397       break;
01398     }
01399     co_edge_list1.step();
01400   }
01401   
01402   // Now the list is positioned at the start of one of the shared chains of 
01403   // curves.
01404   start_co_edge_ptr = co_edge_list1.get();
01405 
01406   // Walk along the first surface
01407   int found_break = 0;
01408   for( i=co_edge_list1.size(); i--; )
01409   {
01410     ref_edge_ptr = co_edge_list1.get_and_step()->get_ref_edge_ptr();
01411 
01412     if( found_break && ref_edge_list2.is_in_list( ref_edge_ptr ) )
01413     {
01414       is_loop = CUBIT_TRUE;
01415       return CUBIT_SUCCESS;
01416     }
01417 
01418     if( !ref_edge_list2.is_in_list( ref_edge_ptr ) )
01419       found_break = 1;
01420   }
01421 
01422   return CUBIT_SUCCESS;
01423 }
01424 
01425 CubitStatus 
01426 SplitSurfaceTool::get_neighbors( RefFace *seed_ref_face,
01427                                  DLIList<RefFace*> &input_ref_faces,
01428                                  DLIList<RefFace*> &neighbor_ref_faces )
01429 {
01430   int i, j;
01431 
01432   // Copy the input_ref_faces_copy list so as to not change it
01433   DLIList<RefFace*> input_ref_faces_copy(input_ref_faces.size());
01434   input_ref_faces_copy = input_ref_faces;
01435 
01436   // Get the edges
01437   DLIList<RefEdge*> ref_edge_list;
01438   seed_ref_face->ref_edges( ref_edge_list );
01439 
01440   // Get all ref_faces attached to these edges
01441   RefEdge *ref_edge_ptr;
01442   RefFace *ref_face_ptr;
01443   for( i=ref_edge_list.size(); i--; )
01444   {
01445     ref_edge_ptr = ref_edge_list.get_and_step();
01446 
01447     DLIList<RefFace*> attached_ref_faces;
01448     ref_edge_ptr->ref_faces( attached_ref_faces );
01449 
01450     for( j=attached_ref_faces.size(); j--; )
01451     {
01452       ref_face_ptr = attached_ref_faces.get_and_step();
01453 
01454       if( ref_face_ptr == seed_ref_face )
01455         continue;
01456 
01457       // Don't consider ref_faces that aren't in the input list
01458       if( input_ref_faces_copy.is_in_list( ref_face_ptr ) )
01459       {
01460         neighbor_ref_faces.append_unique( ref_face_ptr );
01461       }
01462     }
01463   }
01464 
01465   // Respect the incoming order of ref_faces
01466   if( neighbor_ref_faces.size() == 2 )
01467   {
01468     input_ref_faces_copy.reset();
01469     neighbor_ref_faces.reset();
01470     RefFace *first_neighbor = neighbor_ref_faces.get_and_step();
01471     RefFace *second_neighbor = neighbor_ref_faces.get_and_step();
01472     for( i=input_ref_faces_copy.size(); i--; )
01473     {
01474       ref_face_ptr = input_ref_faces_copy.get_and_step();
01475       if( ref_face_ptr == first_neighbor )
01476         break;
01477       else if( ref_face_ptr == second_neighbor )
01478       {
01479         // Reverse the order
01480         neighbor_ref_faces.reverse();
01481         break;
01482       }
01483     }
01484   }
01485 
01486   return CUBIT_SUCCESS;
01487 }
01488 
01489 CubitStatus
01490 SplitSurfaceTool::get_outer_loops()
01491 {
01492   // Get the outer curve loop
01493   if( get_outer_coedge_loop() == CUBIT_FAILURE )
01494     return CUBIT_FAILURE;
01495 
01496   // If we found a loop, we already setup the rest of the datastructures
01497   if( isLoop )
01498     return CUBIT_SUCCESS;
01499 
01500   // Make sure the loop has at least 3 vertices, to form at least a 
01501   // degenerate rectangle
01502   if( outerCoEdgeLoop.size() < 3 )
01503   {
01504     PRINT_ERROR( "Selected surfaces do not appear to form logical rectangle\n" );
01505     return CUBIT_FAILURE;
01506   }
01507 
01508   // Orient the loops so they start at the first CoEdge of the 
01509   // starting RefFace in the chain
01510   if( refFaceChain.size() > 1 )
01511   {
01512     refFaceChain.reset();
01513     RefFace *first_ref_face = refFaceChain.get();
01514 
01515     // Move forward in the vertex list until we are on a surface
01516     // other than the first one
01517     int i;
01518     CoEdge *co_edge_ptr = NULL;
01519     outerCoEdgeLoop.reset();
01520     for( i=outerCoEdgeLoop.size(); i--; )
01521     {
01522       co_edge_ptr = outerCoEdgeLoop.get_and_step();
01523       if( co_edge_ptr->get_ref_face() != first_ref_face )
01524         break;
01525     }
01526 
01527     // Now move forward in the list until we are on the first surface
01528     for( i=outerCoEdgeLoop.size(); i--; )
01529     {
01530       co_edge_ptr = outerCoEdgeLoop.get();
01531       if( co_edge_ptr->get_ref_face() == first_ref_face )
01532         break;
01533       outerCoEdgeLoop.step();
01534     }
01535 
01536     PRINT_DEBUG_154( "First vertex on first surface = %d\n", start_vertex( co_edge_ptr )->id() );
01537     PRINT_DEBUG_154( "Index of vertex list = %d\n", outerCoEdgeLoop.get_index() );
01538 
01539     // Reorient the lists appropriately
01540     reorient_loop( outerCoEdgeLoop.get_index() );
01541 
01542     if( DEBUG_FLAG(154) )
01543     {
01544       DLIList<RefVertex*> ref_vertex_list;
01545       get_outer_vertices( ref_vertex_list );
01546       DLIList<CubitEntity*> cubit_verts;
01547       CAST_LIST(ref_vertex_list, cubit_verts, CubitEntity);
01548       CubitUtil::list_entity_ids( "New vertex list: ", 
01549         cubit_verts, 80, "\n", CUBIT_FALSE );
01550     }
01551   }
01552 
01553   return CUBIT_SUCCESS;
01554 }
01555 
01556 CubitStatus
01557 SplitSurfaceTool::get_outer_coedge_loop()
01558 {
01559 
01560   // Walk around the loop
01561 
01562   // Start by gathering a list of all coedges
01563   int i;
01564   DLIList<CoEdge*> co_edge_list;
01565 
01566   RefFace *ref_face_ptr;
01567   refFaceChain.reset();
01568   for( i=refFaceChain.size(); i--; )
01569   {
01570     ref_face_ptr = refFaceChain.get_and_step();
01571     if( ordered_co_edges( ref_face_ptr, co_edge_list ) == CUBIT_FAILURE )
01572       return CUBIT_FAILURE;
01573   }
01574 
01575 //  PRINT_INFO( "Entire coedge loop, starting at beginning -\n" );
01576 //  PRINT_INFO( "-------------------------------------------\n" );
01577 //  co_edge_list.reset();
01578 //  for( i=co_edge_list.size(); i--; )
01579 //  {
01580 //    CoEdge *co_edge_ptr = co_edge_list.get_and_step();
01581 //    PRINT_INFO( " Curve %d on Surface %d\n",
01582 //      co_edge_ptr->get_ref_edge_ptr()->id(), 
01583 //      co_edge_ptr->get_ref_face()->id() );
01584 //  }
01585 
01586   CoEdge *start_co_edge_ptr;
01587   if( find_loop_start( start_co_edge_ptr ) == CUBIT_FAILURE )
01588   {
01589     PRINT_ERROR( "Unable to find loop start\n" ); // TODO: better message
01590     return CUBIT_FAILURE;
01591   }
01592 
01593 //  PRINT_INFO( "Loop start = Curve %d on Surface %d\n", 
01594 //  start_co_edge_ptr->get_ref_edge_ptr()->id(),
01595 //  start_co_edge_ptr->get_ref_face()->id() );
01596 
01597   // Remove CoEdges on curves shared between surfaces (except for the starting
01598   // chain for isLoop situation).  For isLoop, lets create a list of those to
01599   // be added back in later (keep_co_edge_list).
01600   DLIList<CoEdge*> keep_co_edge_list;
01601   CoEdge *shared_co_edge_ptr;
01602   CoEdge *co_edge_ptr;  
01603   if( isLoop )
01604   {
01605     // Method - traverse co_edge_list, adding coedges to keep_co_edge_list 
01606     // until we don't find a coedge that shares a RefEdge with another coedge.  
01607     // We use the term "complimentary" CoEdge to refer to the other CoEdge that
01608     // shares the common RefEdge.
01609     //    
01610     // To illustrate, in the diagram below, assume S1 is the first surface and
01611     // S2 is the last surface in the surface loop we are splitting (note that
01612     // S1 can equal S2).  C1, C2 and C3 make up the "chain" of curvs, or "seam"
01613     // that is between S1 and S2.  Note that C1 has 2 CoEdges, one owned by S1 
01614     // and one owned by S2.  So, starting at C1 on S1, we step through the list
01615     // until we encounter a CoEdge that does not have a "complimentary" CoEdge.  
01616     // Just keep track of the CoEdges as we go.
01617     //
01618     //     ------------+------------
01619     //    .            |            .
01620     //    .            |C1          .
01621     //    .            |            .
01622     //    .        ^   +   |        .
01623     //    .        |   |   |        .
01624     //    .   S2   |   |C2 |   S1   .
01625     //    .        |   |   v        .
01626     //    .            +            .
01627     //    .            |            .
01628     //    .            |C3          .
01629     //    .            |            .
01630     //     ------------+------------      
01631 
01632     // For this code, it is important that all the ordered coedges from the 
01633     // starting surface are at the beginning of the co_edge_list (otherwise, we 
01634     // will traverse partway up the first chain and then back).  So we rebuild 
01635     // co_edge_list - putting all the ordered coedges from the first surface at
01636     // the beginning of co_edge_list. 
01637     DLIList<CoEdge*> temp_co_edge_list = co_edge_list;
01638     temp_co_edge_list.move_to( start_co_edge_ptr );
01639     co_edge_list.clean_out();
01640 
01641     RefFace *start_ref_face_ptr = start_co_edge_ptr->get_ref_face();
01642 
01643     for( i=temp_co_edge_list.size(); i--; )
01644     {
01645       co_edge_ptr = temp_co_edge_list.get();
01646       if( co_edge_ptr->get_ref_face() == start_ref_face_ptr )
01647       {
01648         co_edge_list.append( co_edge_ptr );
01649         temp_co_edge_list.change_to( NULL );
01650       }
01651       temp_co_edge_list.step();
01652     }
01653     temp_co_edge_list.remove_all_with_value( NULL );
01654 
01655     co_edge_list += temp_co_edge_list;
01656 
01657 //    PRINT_INFO( "Entire coedge loop -\n" );
01658 //    PRINT_INFO( "--------------------\n" );
01659 //    co_edge_list.reset();
01660 //    for( i=co_edge_list.size(); i--; )
01661 //    {
01662 //      CoEdge *co_edge_ptr = co_edge_list.get_and_step();
01663 //      PRINT_INFO( " Curve %d on Surface %d\n",
01664 //        co_edge_ptr->get_ref_edge_ptr()->id(), 
01665 //        co_edge_ptr->get_ref_face()->id() );
01666 //    }
01667 
01668 //    PRINT_INFO( "Coedges to keep - \n" );
01669     co_edge_list.reset();
01670     co_edge_ptr = co_edge_list.get();
01671     RefFace *ref_ref_face_ptr = co_edge_ptr->get_ref_face();
01672     RefFace *shared_ref_face_ptr;
01673     shared_co_edge_ptr = get_complimentary_co_edge( co_edge_ptr, co_edge_list );
01674     RefFace *ref_shared_ref_face_ptr = shared_co_edge_ptr->get_ref_face();
01675     for( i=co_edge_list.size(); i--; )
01676     {
01677       // Keep track of the starting and ending chain which we will lose in the
01678       // code below that removes all coedges that share a refedge. To do this, 
01679       // add coedges until we don't find a shared one, or the reference surfaces
01680       // change (ref_ref_face_ptr || ref_shared_ref_face_ptr).  Why look at
01681       // the reference surfaces?  Because there could be a triangle as in the
01682       // diagram below.
01683       // 
01684       //     ------------+-------------
01685       //    .            |             .
01686       //    .            |C1           .
01687       //    .            |             .
01688       //    .        ^   +   |    S1   .
01689       //    .        |   |   |         .
01690       //    .   S2   |   |C2 |       / .
01691       //    .        |   |   v     /   .
01692       //    .            +       /     .
01693       //    .            |     /       .
01694       //    .            |C3 /     S3  .
01695       //    .            | /           .
01696       //     ------------+-------------      
01697       co_edge_ptr = co_edge_list.get_and_step();
01698       ref_face_ptr = co_edge_ptr->get_ref_face();
01699       shared_co_edge_ptr = get_complimentary_co_edge( co_edge_ptr, co_edge_list );
01700       if( !shared_co_edge_ptr )
01701         break;
01702       shared_ref_face_ptr = shared_co_edge_ptr->get_ref_face();
01703       if( ref_face_ptr==ref_ref_face_ptr && 
01704           shared_ref_face_ptr==ref_shared_ref_face_ptr  )
01705       {
01706         keep_co_edge_list.append( co_edge_ptr );
01707 //        PRINT_INFO( " Keeping Curve %d on Surface %d\n", 
01708 //          co_edge_ptr->get_ref_edge_ptr()->id(), 
01709 //          co_edge_ptr->get_ref_face()->id() );
01710         keep_co_edge_list.append( shared_co_edge_ptr );
01711 //        PRINT_INFO( " Keeping Curve %d on Surface %d\n", 
01712 //          shared_co_edge_ptr->get_ref_edge_ptr()->id(), 
01713 //          shared_co_edge_ptr->get_ref_face()->id() );
01714       }
01715       else
01716         break;
01717     }
01718   }
01719 
01720   // Remove all coedges that share a RefEdge
01721   for( i=co_edge_list.size(); i--; )
01722   {
01723     // Add coedges until we don't find a shared one - this adds just the
01724     // first chain.
01725     co_edge_ptr = co_edge_list.get();
01726     if( co_edge_ptr == NULL )
01727     {
01728       co_edge_list.step();
01729       continue;
01730     }
01731     shared_co_edge_ptr = get_complimentary_co_edge( co_edge_ptr, co_edge_list );
01732     if( shared_co_edge_ptr )
01733     {
01734       // This is not very efficient, but okay since we have relatively short
01735       // lists.
01736       co_edge_list.move_to( shared_co_edge_ptr );
01737 //      PRINT_INFO( " Removing Curve %d on Surface %d\n",
01738 //        shared_co_edge_ptr->get_ref_edge_ptr()->id(), 
01739 //          shared_co_edge_ptr->get_ref_face()->id() );
01740 
01741       co_edge_list.change_to( NULL );
01742       co_edge_list.move_to( co_edge_ptr );
01743 //      PRINT_INFO( " Removing Curve %d on Surface %d\n",
01744 //        co_edge_ptr->get_ref_edge_ptr()->id(), 
01745 //          co_edge_ptr->get_ref_face()->id() );
01746 
01747       co_edge_list.change_to( NULL );
01748     }
01749     co_edge_list.step();
01750   }
01751 
01752   co_edge_list.remove_all_with_value( NULL );
01753 
01754   // Add back in the removed coedges if isLoop
01755   if( isLoop )
01756   {
01757     // Put them at the beginning for a slight efficiency gain
01758     DLIList<CoEdge*> temp_co_edge_list = co_edge_list;
01759     co_edge_list.clean_out();
01760     co_edge_list += keep_co_edge_list;
01761     co_edge_list += temp_co_edge_list;
01762   }
01763 
01764   // Walk around the loop until we encounter the start coedge again.
01765   // Note loop is positioned at starting coedge.
01766   CoEdge *prev_co_edge_ptr = start_co_edge_ptr;
01767   outerCoEdgeLoop.append( start_co_edge_ptr );
01768   for( i=co_edge_list.size(); i--; )
01769   {
01770     co_edge_ptr = get_next_co_edge( prev_co_edge_ptr, co_edge_list );
01771 
01772     if( co_edge_ptr == NULL )
01773     {
01774       PRINT_ERROR( "Selected surfaces do not appear to form logical rectangle\n" );
01775       return CUBIT_FAILURE;
01776     }
01777 
01778     if( co_edge_ptr == start_co_edge_ptr ) // We're done
01779       break;
01780 
01781     outerCoEdgeLoop.append( co_edge_ptr );
01782     prev_co_edge_ptr = co_edge_ptr;
01783     co_edge_list.remove( co_edge_ptr );
01784   }
01785 
01786   // Set the corners and such if isLoop
01787   if( isLoop )
01788   {
01789     // Start of first curve is first corner
01790     int best_corner_1, best_corner_2, best_corner_3=-1, best_corner_4=-1;
01791 
01792     best_corner_1 = 0;
01793     best_corner_2 = keep_co_edge_list.size()/2;
01794     outerCoEdgeLoop.reset();
01795     for( i=0; i<outerCoEdgeLoop.size()+1; i++ )
01796     {
01797       co_edge_ptr = outerCoEdgeLoop.get_and_step();
01798       if( i == best_corner_1 )
01799       {
01800         cornerCoEdge[0] = co_edge_ptr;
01801         continue;
01802       }
01803 
01804       if( i == best_corner_2 )
01805       {
01806         cornerCoEdge[1] = co_edge_ptr;
01807         continue;
01808       }
01809 
01810       if( start_vertex(co_edge_ptr) == start_vertex(cornerCoEdge[1]) )
01811       {
01812         best_corner_3 = i;
01813         cornerCoEdge[2] = co_edge_ptr;
01814         continue;
01815       }
01816 
01817       if( start_vertex(co_edge_ptr) == start_vertex(cornerCoEdge[0]) )
01818       {
01819         if( i==outerCoEdgeLoop.size() )
01820           best_corner_4 = i-1;
01821         else
01822           best_corner_4 = i;
01823         cornerCoEdge[3] = co_edge_ptr;
01824         break;
01825       }
01826     }
01827 
01828     if( best_corner_3==-1 || best_corner_4==-1 )
01829     {
01830       PRINT_ERROR( "unable to find corners\n" );
01831       return CUBIT_FAILURE;
01832     }
01833 
01834     fill_side_intervals( best_corner_1, best_corner_2, best_corner_3, best_corner_4 );
01835   }
01836 
01837   return CUBIT_SUCCESS;
01838 }
01839 
01840 CubitStatus
01841 SplitSurfaceTool::find_loop_start( CoEdge *&start_co_edge_ptr )
01842 {
01843   // For non-isLoop situation, start of loop will be first non-shared curve
01844   // on surface loop
01845   
01846   int i, j;
01847   RefFace *ref_face_ptr;
01848   if( !isLoop )
01849   {
01850     // First, get the outer curve loop of the surfaces
01851     refFaceChain.reset();
01852     ref_face_ptr = refFaceChain.get_and_step();
01853 
01854     DLIList<CoEdge*> co_edge_list;
01855     if( ordered_co_edges( ref_face_ptr, co_edge_list ) == CUBIT_FAILURE )
01856       return CUBIT_FAILURE;
01857 
01858     // If we have one surface just return
01859     co_edge_list.reset();
01860     if( refFaceChain.size() == 1 )
01861     {
01862       start_co_edge_ptr = co_edge_list.get();
01863       return CUBIT_SUCCESS;
01864     }
01865 
01866     // Get the list of coedges in the next surface in the chain
01867     ref_face_ptr = refFaceChain.get();
01868     DLIList<CoEdge*> next_co_edge_list;
01869     if( ordered_co_edges( ref_face_ptr, next_co_edge_list ) == CUBIT_FAILURE )
01870       return CUBIT_FAILURE;
01871 
01872     // Find a coedge on first surface that shares a curve with the next surface
01873     CoEdge *co_edge_ptr;
01874     RefEdge *ref_edge_ptr;
01875     co_edge_list.reset();
01876     int found = 0;
01877     for( i=co_edge_list.size(); i--; )
01878     {
01879       co_edge_ptr = co_edge_list.get_and_step();
01880       ref_edge_ptr = co_edge_ptr->get_ref_edge_ptr();
01881       if( is_edge_in_list( ref_edge_ptr, next_co_edge_list ) )
01882       {
01883         found = 1;
01884         break;
01885       }
01886     }
01887 
01888     // This should never happen
01889     if( !found )
01890     {
01891       PRINT_ERROR( "Unable to find curves shared between surfaces\n" );
01892       return CUBIT_FAILURE;
01893     }
01894 
01895     // Loop until we find a curve not shared with the other surface - this
01896     // is the start
01897     for( i=co_edge_list.size(); i--; )
01898     {
01899       co_edge_ptr = co_edge_list.get_and_step();
01900       ref_edge_ptr = co_edge_ptr->get_ref_edge_ptr();
01901       if( !is_edge_in_list( ref_edge_ptr, next_co_edge_list ) )
01902       {
01903         start_co_edge_ptr = co_edge_ptr;
01904         return CUBIT_SUCCESS;
01905       }
01906     }
01907 
01908     // This should never happen
01909     PRINT_ERROR( "Unable to find start of loop - please report this\n" );
01910     return CUBIT_FAILURE;
01911   }
01912 
01913   // isLoop situation
01914   if( refFaceChain.size() == 1 )
01915   {
01916     // Find first edge that has two coedges on this surface - this is the
01917     // start of the list
01918     refFaceChain.reset();
01919     ref_face_ptr = refFaceChain.get_and_step();
01920 
01921     DLIList<CoEdge*> co_edge_list;
01922     if( ordered_co_edges( ref_face_ptr, co_edge_list ) == CUBIT_FAILURE )
01923       return CUBIT_FAILURE;
01924 
01925     co_edge_list.reset();
01926     for( i=0; i<co_edge_list.size(); i++ )
01927     {
01928       RefEdge *ref_edge_ptr = co_edge_list.get()->get_ref_edge_ptr();
01929       if( number_coedges( ref_edge_ptr, ref_face_ptr ) == 2 )
01930       {
01931         if( i==0 ) // Backup until we are at the start
01932         {
01933           for( j=co_edge_list.size(); j--; )
01934           {
01935             co_edge_list.back();
01936             ref_edge_ptr = co_edge_list.get()->get_ref_edge_ptr();
01937             if( number_coedges( ref_edge_ptr, ref_face_ptr ) == 1 )
01938               break;
01939             co_edge_list.step();
01940           }
01941         }
01942         break;
01943       }
01944       co_edge_list.step();
01945     }
01946 
01947     start_co_edge_ptr = co_edge_list.get();
01948     return CUBIT_SUCCESS;
01949   }
01950 
01951   if( refFaceChain.size() == 2 )
01952   {
01953     refFaceChain.reset();
01954     RefFace *ref_face_ptr1 = refFaceChain.get_and_step();
01955     RefFace *ref_face_ptr2 = refFaceChain.get();
01956     CubitBoolean is_loop; // Dummy
01957     return check_for_loop( ref_face_ptr1, ref_face_ptr2, is_loop, start_co_edge_ptr );
01958   }
01959 
01960   // Case refFaceChain.size() > 2
01961 
01962   // Use first and last surfaces.  Also, adjust order of refFaceChain to
01963   // account for user's selection of start and end vertex, if selected.
01964   refFaceChain.reset();
01965   RefFace *start_surf = refFaceChain.get_and_back();
01966   RefFace *end_surf = refFaceChain.get();
01967   
01968   // Get list of coedges for the first surface
01969   DLIList<CoEdge*> start_co_edge_list;
01970   if( ordered_co_edges( start_surf, start_co_edge_list ) == CUBIT_FAILURE )
01971       return CUBIT_FAILURE;
01972 
01973   // Get list of refedges for the last surface
01974   DLIList<RefEdge*> end_ref_edge_list;
01975   DLIList<Loop*> loop_list;
01976   end_surf->ordered_loops( loop_list );
01977   loop_list.get()->ordered_ref_edges( end_ref_edge_list );
01978 
01979   // Walk around the first surface
01980   RefEdge *ref_edge_ptr;
01981 
01982   // First, position the list at a starting coedge - one that is shared with
01983   // the other surface.
01984   start_co_edge_list.reset();
01985   for( i=0; i<start_co_edge_list.size(); i++ )
01986   {
01987     ref_edge_ptr = start_co_edge_list.get()->get_ref_edge_ptr();
01988     
01989     if( end_ref_edge_list.is_in_list( ref_edge_ptr ) )
01990     {
01991       if( i==0 ) // Backup until we are at the start
01992       {
01993         for( j=start_co_edge_list.size(); j--; )
01994         {
01995           start_co_edge_list.back();
01996           ref_edge_ptr = start_co_edge_list.get()->get_ref_edge_ptr();
01997           if( end_ref_edge_list.is_in_list( ref_edge_ptr ) )
01998             continue;
01999           start_co_edge_list.step();
02000         }
02001       }
02002       break;
02003     }
02004     start_co_edge_list.step();
02005   }
02006   
02007   // Now the list is positioned at the start of one of the shared chains of 
02008   // curves.
02009   start_co_edge_ptr = start_co_edge_list.get();
02010 
02011   return CUBIT_SUCCESS;
02012 }
02013 
02014 CubitStatus
02015 SplitSurfaceTool::get_outer_vertices( DLIList<RefVertex*> &ref_vertex_list )
02016 {
02017   int i;
02018 
02019   outerCoEdgeLoop.reset();
02020   for( i=outerCoEdgeLoop.size(); i--; )
02021     ref_vertex_list.append( start_vertex( outerCoEdgeLoop.get_and_step() ) );
02022 
02023   return CUBIT_SUCCESS;
02024 }
02025 
02026 CubitStatus
02027 SplitSurfaceTool::get_outer_curves( DLIList<RefEdge*> &ref_edge_list )
02028 {
02029   int i;
02030   
02031   outerCoEdgeLoop.reset();
02032   for( i=outerCoEdgeLoop.size(); i--; )
02033     ref_edge_list.append( outerCoEdgeLoop.get_and_step()->get_ref_edge_ptr() );
02034   
02035   return CUBIT_SUCCESS;
02036 }
02037 
02038 CubitStatus
02039 SplitSurfaceTool::populate_curve_loops()
02040 {
02041   int i;
02042   RefFace *ref_face_ptr;
02043   TDSplitSurface *tdss;
02044 
02045   if( refFaceChain.size() == 1 )
02046   {
02047     ref_face_ptr = refFaceChain.get();
02048     tdss = (TDSplitSurface *)ref_face_ptr->get_TD(&TDSplitSurface::is_split_surface);
02049     tdss->add_coedges( outerCoEdgeLoop, sideInterval );
02050     return CUBIT_SUCCESS;
02051   }
02052   
02053   // Steps
02054   // 1. Go through each CoEdge on outside, adding TD to each CoEdge
02055   //    (with data for the start vertex of the CoEdge), marking them
02056   //    per the code in the diagram below. 
02057   //
02058   //    6    5   4
02059   //    +----+---+ 
02060   //    |        | 
02061   //    |        | 
02062   //   7+        +3 
02063   //    |        | 
02064   //   7+----+---+3 
02065   //    |        | 
02066   //    |        | 
02067   //   7+        +3 
02068   //    |        | 
02069   //   7+-+---+--+3 
02070   //    |        | 
02071   //    |        | 
02072   //   7+        +3 
02073   //    |        | 
02074   //    +---+----+ 
02075   //    0   1    2 
02076   //
02077   //    
02078   // 2. Traverse through the curves in each surface, assigning 
02079   //    curves to proper side of surface utilizing vertex classification
02080   //    from above.
02081   
02082   // First gather a list of all coedges
02083   DLIList<CoEdge*> all_co_edge_list;
02084   refFaceChain.reset();
02085   for( i=refFaceChain.size(); i--; )
02086   {
02087     ref_face_ptr = refFaceChain.get_and_step();
02088     ordered_co_edges( ref_face_ptr, all_co_edge_list );
02089   }
02090   
02091   refFaceChain.reset();
02092   RefFace *start_surf = refFaceChain.get();
02093   refFaceChain.last();
02094   RefFace *end_surf = refFaceChain.get();
02095   
02096   // STEP 1
02097   CoEdge *co_edge_ptr;
02098   int type = 0;
02099   outerCoEdgeLoop.reset();
02100   outerCoEdgeLoop.back();
02101   CoEdge *prev_co_edge_ptr = outerCoEdgeLoop.get_and_step();
02102   for( i=0; i<outerCoEdgeLoop.size(); i++ )
02103   {
02104     co_edge_ptr = outerCoEdgeLoop.get_and_step();
02105     
02106     // Get all CoEdges whose start vertices are attached to the start of this
02107     // CoEdge.
02108     DLIList<CoEdge*> att_co_edge_list;
02109     get_attached_coedges_start( co_edge_ptr, all_co_edge_list, att_co_edge_list );
02110     // This should never happen, but check anyway
02111     if( att_co_edge_list.size() == 0 )
02112     {
02113       PRINT_ERROR( "Unable to find any curves attached to the start of Curve %d\n",
02114         co_edge_ptr->get_ref_edge_ptr()->id() );
02115       delete_coedge_tooldatas( all_co_edge_list );
02116       return CUBIT_FAILURE;
02117     }
02118     
02119     // Remove CoEdges from outerCoEdgeLoop
02120     att_co_edge_list -= outerCoEdgeLoop;
02121     
02122     // Add back in the current co_edge_ptr
02123     att_co_edge_list.append( co_edge_ptr );
02124     
02125     // Special case - need to remove possible wrong CoEdges.  If isLoop remove
02126     // all of the other CoEdges that are on the outerCoEdgeLoop (particularly
02127     // necessary as we traverse up and down the "seam", and at the corners).
02128     // If a corner, we need to deal with a possible triangle there by keeping
02129     // the proper CoEdge.
02130     if( isLoop )
02131     {
02132       // Find corner number from i
02133       int corner = -1;
02134       if( i == 0 )
02135         corner = 0;
02136       else if( i == sideInterval[0] )
02137         corner = 1;
02138       else if( i == sideInterval[0] + sideInterval[1] )
02139         corner = 2;
02140       else if( i== sideInterval[0] + sideInterval[1] + sideInterval[2] )
02141         corner = 3;
02142       
02143       if( corner != -1 )
02144       {        
02145         // Remove coedges that belong to the other corner shared by this corner
02146         if( remove_other_corner_coedges( prev_co_edge_ptr, co_edge_ptr,
02147           all_co_edge_list, att_co_edge_list ) == CUBIT_FAILURE )
02148         {
02149           delete_coedge_tooldatas( all_co_edge_list );
02150           return CUBIT_FAILURE;
02151         }
02152       }
02153     }
02154     
02155     // DEBUG
02156     //      if( att_co_edge_list.size() > 1 )
02157     //      {
02158     //        PRINT_INFO( "Att_co_edge_list.size() = %d\n", att_co_edge_list.size() );
02159     //        att_co_edge_list.reset();
02160     //        for( int k=att_co_edge_list.size(); k--; )
02161     //          PRINT_INFO( "  Adding TD to Curve = %d, Surface = %d\n", att_co_edge_list.get()->
02162     //          get_ref_edge_ptr()->id(), att_co_edge_list.get_and_step()->get_ref_face()->id() );
02163     //      }
02164     //      else
02165     //        PRINT_INFO( " Adding TD to Curve %d on Surface %d\n",
02166     //        att_co_edge_list.get()->get_ref_edge_ptr()->id(),
02167     //        att_co_edge_list.get()->get_ref_face()->id() );
02168     
02169     switch (type)
02170     {
02171     case 0:
02172       if( add_tooldata( att_co_edge_list, 0 ) == CUBIT_FAILURE )
02173       {
02174         delete_coedge_tooldatas( all_co_edge_list );
02175         return CUBIT_FAILURE;
02176       }
02177       if( cornerCoEdge[0] != cornerCoEdge[1] )
02178         type = 1;
02179       else
02180         type = 3;
02181       break;
02182     case 1:
02183       if( co_edge_ptr != cornerCoEdge[1] )
02184       {
02185         if( add_tooldata( att_co_edge_list, 1 ) == CUBIT_FAILURE )
02186         {
02187           delete_coedge_tooldatas( all_co_edge_list );
02188           return CUBIT_FAILURE;
02189         }
02190       }
02191       else
02192       {
02193         if( add_tooldata( att_co_edge_list, 2 ) == CUBIT_FAILURE )
02194         {
02195           delete_coedge_tooldatas( all_co_edge_list );
02196           return CUBIT_FAILURE;
02197         }
02198         if( cornerCoEdge[1] != cornerCoEdge[2] )
02199           type = 3;
02200         else
02201           type = 5;
02202       }
02203       break;
02204     case 3:
02205       if( co_edge_ptr != cornerCoEdge[2] )
02206       {
02207         if( add_tooldata( att_co_edge_list, 3 ) == CUBIT_FAILURE )
02208         {
02209           delete_coedge_tooldatas( all_co_edge_list );
02210           return CUBIT_FAILURE;
02211         }
02212       }
02213       else
02214       {
02215         if( add_tooldata( att_co_edge_list, 4 ) == CUBIT_FAILURE )
02216         {
02217           delete_coedge_tooldatas( all_co_edge_list );
02218           return CUBIT_FAILURE;
02219         }
02220         if( cornerCoEdge[2] != cornerCoEdge[3] )
02221           type = 5;
02222         else
02223           type = 7;
02224       }
02225       break;
02226     case 5:
02227       if( co_edge_ptr != cornerCoEdge[3] )
02228       {
02229         if( add_tooldata( att_co_edge_list, 5 ) == CUBIT_FAILURE )
02230         {
02231           delete_coedge_tooldatas( all_co_edge_list );
02232           return CUBIT_FAILURE;
02233         }
02234       }
02235       else
02236       {
02237         if( add_tooldata( att_co_edge_list, 6 ) == CUBIT_FAILURE )
02238         {
02239           delete_coedge_tooldatas( all_co_edge_list );
02240           return CUBIT_FAILURE;
02241         }
02242         type = 7;
02243       }
02244       break;
02245     case 7:
02246       if( add_tooldata( att_co_edge_list, 7 ) == CUBIT_FAILURE )
02247       {
02248         delete_coedge_tooldatas( all_co_edge_list );
02249         return CUBIT_FAILURE;
02250       }
02251       break;
02252     }
02253     
02254     prev_co_edge_ptr = co_edge_ptr;
02255     
02256   }
02257     
02258   // Debug
02259   if( DEBUG_FLAG(154) )
02260   {
02261     outerCoEdgeLoop.reset();
02262     for( i=outerCoEdgeLoop.size(); i--; )
02263     {
02264       co_edge_ptr = outerCoEdgeLoop.get_and_step();
02265       TDSplitSurface *tdssv = (TDSplitSurface *)co_edge_ptr->
02266         get_TD(&TDSplitSurface::is_split_surface);
02267       
02268       PRINT_INFO( "Vertex %d - type %d\n", start_vertex( co_edge_ptr )->id(),
02269         tdssv->get_type() );
02270     }
02271   }
02272   
02273   // STEP 2
02274   refFaceChain.reset();
02275   for( i=0; i<refFaceChain.size(); i++ )
02276   {
02277     ref_face_ptr = refFaceChain.get_and_step();
02278     tdss = (TDSplitSurface *)ref_face_ptr->
02279       get_TD(&TDSplitSurface::is_split_surface);
02280     
02281     // Get loop of coedges on this surface
02282     DLIList<CoEdge*> co_edge_list;
02283     ordered_co_edges( ref_face_ptr, co_edge_list );
02284     
02285     // Now, get to the start of the loop.  This will either be on vertex 0 or
02286     // the last vertex 7 (see diagram above).
02287     position_co_edge_list( i, co_edge_list );
02288     
02289     PRINT_DEBUG_154( "Surface %d: start of loop = curve %d\n", 
02290       ref_face_ptr->id(), co_edge_list.get()->get_ref_edge_ptr()->id() );
02291     
02292     // Now that we have the loop positioned properly, we can add the proper
02293     // curves (classified by side) to the TD on the surface.      
02294     DLIList<CoEdge*> side_coedges;
02295     int num_so_far = 0;
02296     // Check for special case - side A collapsed - triangle tip at start of
02297     // split
02298     if( ref_face_ptr == start_surf && cornerCoEdge[0] == cornerCoEdge[1] )
02299       ;
02300     else
02301       get_a_coedges( co_edge_list, side_coedges );
02302     num_so_far = side_coedges.size();
02303     
02304     // Side A could be collapsed (in case of triangle tip at start of split)
02305     if( side_coedges.size() )
02306       tdss->add_a_coedges( side_coedges );
02307     else
02308       tdss->add_a_coedges( side_coedges, start_vertex( cornerCoEdge[0] ) );
02309     
02310     side_coedges.clean_out();
02311     get_b_coedges( co_edge_list, side_coedges );
02312     num_so_far += side_coedges.size();
02313     // Side B could be collapsed (if we are on a triangle)
02314     if( side_coedges.size() )
02315       tdss->add_b_coedges( side_coedges );
02316     else
02317       tdss->add_b_coedges( side_coedges, start_vertex( co_edge_list.get() ) );
02318     
02319     side_coedges.clean_out();
02320     // Check for special case - side C collapsed - triangle tip at end of
02321     // split
02322     if( ref_face_ptr == end_surf && cornerCoEdge[2] == cornerCoEdge[3] )
02323       ;
02324     else
02325       get_c_coedges( co_edge_list, side_coedges );
02326     num_so_far += side_coedges.size();
02327     
02328     // Side C could be collapsed (in case of triangle tip at end of split)
02329     if( side_coedges.size() )
02330       tdss->add_c_coedges( side_coedges );
02331     else
02332       tdss->add_c_coedges( side_coedges, start_vertex( cornerCoEdge[2] ) );
02333     
02334     side_coedges.clean_out();
02335     if( get_d_coedges( co_edge_list, num_so_far, 
02336       side_coedges ) == CUBIT_FAILURE )
02337     {
02338       // Remove tooldatas from coedges
02339       delete_coedge_tooldatas( all_co_edge_list );
02340       return CUBIT_FAILURE;
02341     }
02342     
02343     // Side D could be collapsed (if we are on a triangle)
02344     if( side_coedges.size() )
02345       tdss->add_d_coedges( side_coedges );
02346     else
02347       tdss->add_d_coedges( side_coedges, start_vertex( co_edge_list.get() ) );
02348   }
02349   
02350   // Remove tooldatas from coedges
02351   delete_coedge_tooldatas( all_co_edge_list );
02352 
02353   return CUBIT_SUCCESS;  
02354 }
02355 
02356 CubitStatus
02357 SplitSurfaceTool::ordered_co_edges( RefFace *ref_face_ptr, 
02358                                     DLIList<CoEdge*> &co_edge_list )
02359 {
02360   DLIList<Loop*> loop_list;
02361   ref_face_ptr->ordered_loops( loop_list );
02362 
02363   if( loop_list.size() > 1 )
02364   {
02365     PRINT_ERROR( "Only surfaces with a single loop are allowed.\n"
02366       "       Surface %d has %d loops.\n", ref_face_ptr->id(), 
02367       loop_list.size() );
02368 
02369     //if you are splitting a single surface across a vertex pair
02370     //recomment the 'split surface <id> across' command
02371     if( 1 == refFaceChain.size() && 2 == throughVertexList.size() )
02372       PRINT_INFO("Perhaps try the 'Split Surface <id> Across ...' command instead.\n");
02373 
02374     return CUBIT_FAILURE;
02375   }
02376 
02377   if( loop_list.size() == 0 )
02378   {
02379     PRINT_ERROR( "Surface %d does not contain any loops - cannot split\n",
02380       ref_face_ptr->id() );
02381     return CUBIT_FAILURE;
02382   }
02383 
02384   loop_list.get()->ordered_co_edges( co_edge_list );
02385 
02386   return CUBIT_SUCCESS;
02387 }
02388 
02389 CoEdge *
02390 SplitSurfaceTool::get_next_co_edge( CoEdge *prev_co_edge_ptr, 
02391                                     DLIList<CoEdge*> &co_edge_list )
02392 {
02393   RefVertex *end_vertex_ptr = end_vertex( prev_co_edge_ptr );
02394 
02395   // Find all potential connected coedges
02396   int i;
02397   CoEdge *co_edge_ptr;
02398   DLIList<CoEdge*> connected_co_edge_list;
02399   co_edge_list.reset();
02400   for( i=co_edge_list.size(); i--; )
02401   {
02402     co_edge_ptr = co_edge_list.get_and_step();
02403     if( end_vertex_ptr == start_vertex( co_edge_ptr ) )
02404       connected_co_edge_list.append( co_edge_ptr );
02405   }
02406 
02407   // We should always have one or two connected coedges - if not error
02408   if( connected_co_edge_list.size() == 0 )
02409   {
02410     PRINT_ERROR( "Didn't find connected coedge after Curve %d on Surface %d\n", 
02411       prev_co_edge_ptr->get_ref_edge_ptr()->id(), 
02412       prev_co_edge_ptr->get_ref_face()->id() );
02413     return NULL;
02414   }
02415   else if( connected_co_edge_list.size() == 1 )
02416   {
02417     return connected_co_edge_list.get();
02418   }
02419   else if( connected_co_edge_list.size() > 2 )
02420   {
02421     PRINT_ERROR( "Found %d coedges after Curve %d on Surface %d\n", 
02422       connected_co_edge_list.size(),
02423       prev_co_edge_ptr->get_ref_edge_ptr()->id(),
02424       prev_co_edge_ptr->get_ref_face()->id() );
02425     return NULL;
02426   }
02427   else if( connected_co_edge_list.size() == 2 )
02428   {
02429     // Avoid looping back on ourselves
02430     connected_co_edge_list.reset();
02431     if( prev_co_edge_ptr->get_ref_edge_ptr() == 
02432       connected_co_edge_list.get()->get_ref_edge_ptr() )
02433       return connected_co_edge_list.step_and_get();
02434     else
02435       return connected_co_edge_list.get();
02436   }
02437 
02438   return NULL;  
02439 }
02440 
02441 CubitBoolean
02442 SplitSurfaceTool::is_edge_in_list( RefEdge *ref_edge_ptr, DLIList<CoEdge*> &co_edge_list )
02443 {
02444   int i;
02445   CoEdge *co_edge_ptr;
02446   for( i=co_edge_list.size(); i--; )
02447   {
02448     co_edge_ptr = co_edge_list.get_and_step();
02449     if( co_edge_ptr->get_ref_edge_ptr() == ref_edge_ptr )
02450       return CUBIT_TRUE;
02451   }
02452   return CUBIT_FALSE;
02453 }
02454 
02455 RefVertex *
02456 SplitSurfaceTool::start_vertex( CoEdge *co_edge_ptr )
02457 {
02458   if( co_edge_ptr == NULL )
02459     return NULL;
02460 
02461   RefEdge *ref_edge_ptr = co_edge_ptr->get_ref_edge_ptr();
02462   
02463   if ( co_edge_ptr->get_sense() == CUBIT_REVERSED )
02464     return ref_edge_ptr->end_vertex();
02465   else
02466     return ref_edge_ptr->start_vertex();
02467 }
02468 
02469 RefVertex *
02470 SplitSurfaceTool::end_vertex( CoEdge *co_edge_ptr )
02471 {
02472   if( co_edge_ptr == NULL )
02473     return NULL;
02474 
02475   RefEdge *ref_edge_ptr = co_edge_ptr->get_ref_edge_ptr();
02476   
02477   if ( co_edge_ptr->get_sense() == CUBIT_REVERSED )
02478     return ref_edge_ptr->start_vertex();
02479   else
02480     return ref_edge_ptr->end_vertex();
02481 }
02482 
02483 CoEdge *
02484 SplitSurfaceTool::get_complimentary_co_edge( CoEdge *co_edge_ptr, 
02485                                              DLIList<CoEdge*> co_edge_list )
02486 {
02487   // Note: co_edge_list must be copied so that the calling code's list
02488   //       position is not changed.
02489   RefEdge *ref_edge_ptr = co_edge_ptr->get_ref_edge_ptr();
02490   CoEdge *shared_co_edge_ptr;
02491   int i;
02492   for( i=co_edge_list.size(); i--; )
02493   {
02494     shared_co_edge_ptr = co_edge_list.get_and_step();
02495     if( shared_co_edge_ptr == NULL )
02496       continue;
02497     if( shared_co_edge_ptr == co_edge_ptr )
02498       continue;
02499     if( shared_co_edge_ptr->get_ref_edge_ptr() == ref_edge_ptr )
02500       return shared_co_edge_ptr;
02501   }
02502   return NULL;
02503 }
02504 
02505 CubitStatus
02506 SplitSurfaceTool::get_attached_coedges_start( CoEdge *co_edge_ptr,
02507                                               DLIList<CoEdge*> &co_edge_list,
02508                                               DLIList<CoEdge*> &attached_co_edge_list )
02509 {
02510   int i;
02511   CoEdge *attached_co_edge_ptr;
02512 
02513   RefVertex *start_vertex_ptr;
02514   start_vertex_ptr = start_vertex( co_edge_ptr );
02515 
02516   RefVertex *attached_start_vertex_ptr;
02517 
02518   co_edge_list.reset();
02519   for( i=co_edge_list.size(); i--; )
02520   {
02521     attached_co_edge_ptr = co_edge_list.get_and_step();
02522 
02523     attached_start_vertex_ptr = start_vertex( attached_co_edge_ptr );
02524 
02525     if( attached_start_vertex_ptr == start_vertex_ptr )
02526       attached_co_edge_list.append( attached_co_edge_ptr );
02527   }
02528   
02529   return CUBIT_SUCCESS;
02530 }
02531 
02532 CubitStatus 
02533 SplitSurfaceTool::remove_other_corner_coedges( CoEdge *co_edge_1,
02534                                                CoEdge *co_edge_2,
02535                                                DLIList<CoEdge*> &all_co_edge_list,
02536                                                DLIList<CoEdge*> &att_co_edge_list )
02537 {
02538   // If only one attached coedge there is nothing to do
02539   if( att_co_edge_list.size() == 1 )
02540   {
02541     // It should be co_edge_2
02542     if( att_co_edge_list.get() != co_edge_2 )
02543     {
02544       PRINT_ERROR( "Internal error in split surface function - please report this.\n" );
02545       PRINT_DEBUG_154( "       Function remove_other_coedges.\n" );
02546       PRINT_DEBUG_154( "       Using curves %d and %d on surface %d, got curve %d\n",
02547         co_edge_1->get_ref_edge_ptr()->id(), co_edge_2->get_ref_edge_ptr()->id(),
02548         co_edge_1->get_ref_face()->id(), att_co_edge_list.get()->get_ref_edge_ptr()->id() );
02549       return CUBIT_FAILURE;
02550     }
02551     return CUBIT_SUCCESS;
02552   }
02553 
02554   // If we got this far, there are CoEdges we must examine to determine if they
02555   // belong with this corner or the other corner that shares this vertex.
02556 
02557   DLIList<CoEdge*> keep_co_edge_list;
02558 
02559   // Always keep co_edge_2 (the tooldata represents the start vertex on this coedge)
02560   keep_co_edge_list.append( co_edge_2 );
02561   att_co_edge_list.remove( co_edge_2 );
02562 
02563   // Traverse from co_edge_2
02564   DLIList<CoEdge*> keep_co_edge_list2;
02565   int done = 0;
02566   CoEdge *comp_co_edge_ptr = co_edge_2;
02567   CoEdge *co_edge_ptr;
02568   while( !done )
02569   {
02570     RefFace *ref_face_ptr = comp_co_edge_ptr->get_ref_face();
02571     DLIList<CoEdge*> co_edge_list;
02572     ordered_co_edges( ref_face_ptr, co_edge_list );
02573     co_edge_list.move_to( comp_co_edge_ptr );
02574     co_edge_list.back();
02575     co_edge_ptr = co_edge_list.get();
02576     if( co_edge_ptr == co_edge_1 )
02577       break;
02578 
02579     comp_co_edge_ptr = get_complimentary_co_edge( co_edge_ptr, all_co_edge_list );
02580 
02581     keep_co_edge_list2.append( comp_co_edge_ptr );
02582 
02583     // Avoid infinite loop, in case of something we didn't anticipate
02584     if( keep_co_edge_list2.size() > att_co_edge_list.size() )
02585     {
02586       PRINT_ERROR( "Internal error in split surface function - please report this.\n" );
02587       PRINT_DEBUG_154( "       Function remove_other_coedges #1.\n" );
02588       return CUBIT_FAILURE;
02589     }
02590   }
02591 
02592   int i;
02593   for( i=keep_co_edge_list2.size(); i--; )
02594   {
02595     co_edge_ptr = keep_co_edge_list2.get_and_step();
02596     if( !att_co_edge_list.is_in_list( co_edge_ptr ) )
02597     {
02598       PRINT_ERROR( "Internal error in split surface function - please report this.\n" );
02599       PRINT_DEBUG_154( "       Function remove_other_coedges #2.\n" );
02600       return CUBIT_FAILURE;
02601     }
02602   }
02603 
02604   keep_co_edge_list += keep_co_edge_list2;
02605 
02606   att_co_edge_list.clean_out();
02607 
02608   att_co_edge_list = keep_co_edge_list;
02609 
02610   return CUBIT_SUCCESS;
02611 }
02612 
02613 CubitStatus
02614 SplitSurfaceTool::add_tooldata( DLIList<CoEdge*> &co_edge_list, int vertex_type )
02615 {
02616   int i;
02617   CoEdge *co_edge_ptr;
02618   for( i=co_edge_list.size(); i--; )
02619   {
02620     co_edge_ptr = co_edge_list.get_and_step();
02621 
02622     // Something's wrong if we have are trying to put a tooldata on a CoEdge that
02623     // already has one.
02624     if( (TDSplitSurface *)co_edge_ptr->get_TD(&TDSplitSurface::is_split_surface) )
02625     {
02626       PRINT_ERROR( "Internal error in split surface function - please report this.\n" );
02627       PRINT_DEBUG_154( "       Function add_tooldata.\n" );
02628       PRINT_DEBUG_154( "       Curve = %d on surface %d\n", co_edge_ptr->get_ref_edge_ptr()->id(),
02629         co_edge_ptr->get_ref_face()->id() );
02630       return CUBIT_FAILURE;
02631     }
02632 
02633     co_edge_ptr->add_TD( new TDSplitSurface( vertex_type ) );
02634   }
02635   return CUBIT_SUCCESS;
02636 }
02637 
02638 CubitStatus 
02639 SplitSurfaceTool::pick_4_corners()
02640 {
02641   // Special case - for the loop situation the corners are already picked
02642   if( isLoop )
02643     return CUBIT_SUCCESS;
02644 
02645   // Find 4 reasonable corners preferably close to PI/2.  We find at least 
02646   // 2 corners from the starting surface and 2 from the ending surface.
02647   
02648   // Note that at this point, the vertex loop starts at the beginning
02649   // of the first surface in the chain.
02650 
02651   // Check for trivial case
02652   if( outerCoEdgeLoop.size() == 4 )
02653   {
02654     outerCoEdgeLoop.reset();
02655     cornerCoEdge[0] = outerCoEdgeLoop.get_and_step();
02656     cornerCoEdge[1] = outerCoEdgeLoop.get_and_step();
02657     cornerCoEdge[2] = outerCoEdgeLoop.get_and_step();
02658     cornerCoEdge[3] = outerCoEdgeLoop.get();
02659     
02660     sideInterval[0] = 1;
02661     sideInterval[1] = 1;
02662     sideInterval[2] = 1;
02663     sideInterval[3] = 1;
02664 
02665     return CUBIT_SUCCESS;
02666   }
02667 
02668   // Initialize variables
02669   refFaceChain.reset();
02670   RefFace *start_surf = refFaceChain.get();
02671   refFaceChain.last();
02672   RefFace *end_surf = refFaceChain.get();
02673   outerCoEdgeLoop.reset();
02674   CoEdge *co_edge_ptr;
02675   int A_i=-1, B_i=-1, D_i=-1, E_i=-1;
02676 
02677   // Walk along the loop, to find the best corners for the first and last
02678   // surfaces.  The leading edge (B) tries to push forward, but the rear (A) 
02679   // tries to hang back.  Move the lead forward, then check to see if the rear
02680   // should move into it's old spot.
02681 
02682   // Note that the outerCoEdgeLoop starts at the first vertex of the starting
02683   // surface (shown after A in this diagram).
02684   // 
02685   // Final result for this patch results in corners where the 0's are shown.
02686 
02687   //
02688   //          E     D
02689   //          0-----+-------+------0 
02690   //          |     |       |      |
02691   //        F |     |       |      | 
02692   //   +------+     |       |      +------+
02693   //   |            |       |             |   ^
02694   //   |    End     |       |    Start    |   | Loop
02695   //   |  Surface   |       |   Surface   |   | Direction
02696   //   |            |       |             |   |
02697   //   +------+     |       |      +------+
02698   //          |     |       |      | C
02699   //          |     |       |      |
02700   //          0-----+-------+------0 B
02701   //                        A
02702   //
02703 
02704   double epsilon = .001745; // Angles considered comparable within about .1 degrees.
02705   int offset = 0;
02706 
02707   pick_expanded_corners( start_surf, outerCoEdgeLoop, offset, epsilon, A_i, B_i );
02708   PRINT_DEBUG_154( "First pass picked %d and %d on surf %d\n",
02709     A_i, B_i, start_surf->id() );
02710 
02711   // Advance the vertex and coedge lists until we are on the end_surf
02712 
02713   // Special case - if vertices are shared between start and end surface, we
02714   // want the opportunity to use the start vertex on the end surface, even
02715   // though we may have already picked it. We want to consider it again so
02716   // that we can find the best corners on the end surface.  Since we will 
02717   // always find at least two corners on a surface, if we did not consider
02718   // all vertices on the end surface, we might find a garbage vertex.  If
02719   // we do pick up a duplicate, we will clean it out and find the next best
02720   // vertex later.  If we did not do this, in the figure below, the first
02721   // pass through pick_expanded corners would find C1 and C2.  The next
02722   // pass would find C3 and C4.  We don't want C4, but we would pick it 
02723   // just because pick_expanded_corners must pick exactly two corners.  
02724   // Instead, lets pick C2 and C3 the next time around and pickup the lower
02725   // left corner as a cleanup step later.
02726   //                
02727   //               C4
02728   //   C1 +--------+--------------------+ C3
02729   //      |         \                   |
02730   //      |           \                 |
02731   //      |             \      end      |
02732   //      |               \             |
02733   //      |                 \           |
02734   //      |    start          \         |
02735   //      |                     \       |
02736   //      |                       \     |
02737   //      |                         \   |
02738   //      |                           \ |
02739   //      +--------+--------------------+ C2
02740   
02741   // Backup (to consider last vertex again, as explained above)
02742   outerCoEdgeLoop.back();
02743   offset--;
02744   
02745   int i;
02746   for( i=0; i<outerCoEdgeLoop.size(); i++ )
02747   {
02748     co_edge_ptr = outerCoEdgeLoop.get();
02749     if( is_vertex_in_surface( start_vertex(co_edge_ptr), end_surf ) )
02750       break;
02751     
02752     offset++;
02753     outerCoEdgeLoop.step();
02754   }
02755 
02756   pick_expanded_corners( end_surf, outerCoEdgeLoop, offset, epsilon, D_i, E_i );
02757 
02758   PRINT_DEBUG_154( "Second pass picked %d and %d on surf %d\n",
02759     D_i, E_i, end_surf->id() );
02760 
02761   if( E_i == outerCoEdgeLoop.size() )
02762     E_i = 0;
02763 
02764   // Error checking
02765   if( A_i==B_i )
02766     B_i = -1;
02767   if( A_i==D_i )
02768     D_i = -1;
02769   if( A_i==E_i )
02770     E_i = -1;
02771   if( B_i==D_i )
02772     D_i = -1;
02773   if( B_i==E_i )
02774     E_i = -1;
02775   if( D_i==E_i )
02776     E_i = -1;
02777   
02778   if( A_i==-1 || B_i==-1 || D_i==-1 || E_i==-1 )
02779   {
02780     // Most likely error case is that we only found three corners.  Here
02781     // is an example where this can happen.  Notice that the upper left
02782     // corner did not get selected.  This is because when processing the
02783     // left surface, the best corners were found that were "expanded out"
02784     // the farthest - thus we missed the "inside" corner.
02785     // 
02786     //    
02787     //    +-----------------------------+ C
02788     //    |                            /|
02789     //    |                          /  |
02790     //    |                        /    |
02791     //    |                      /      |
02792     //    |                    /        |
02793     //    |                  /          |
02794     //    |                /            |
02795     //    |              /              |
02796     //    |            /                |
02797     //    |          /                  |
02798     //  C +--------+--------------------+ C
02799 
02800     //
02801     // In this case, lets just cop out and find the next best corner(s)
02802     int num = 0;
02803     if( A_i==-1 )
02804       num++;
02805     if( B_i==-1 )
02806       num++;
02807     if( D_i==-1 )
02808       num++;
02809     if( E_i==-1 )
02810       num++;
02811 
02812     if( num>2 )
02813     {
02814       PRINT_ERROR( "Unable to pick corners - please specify manually.\n"
02815         "       Type 'help split surface' for proper syntax\n" );
02816       return CUBIT_FAILURE;
02817     }
02818 
02819     int best_corner_1 = -1, best_corner_2 = -1;
02820 
02821     double diff;
02822     double pi2 = CUBIT_PI/2.0;
02823     double min = CUBIT_DBL_MAX;
02824     outerCoEdgeLoop.reset();
02825     for( i=0; i<outerCoEdgeLoop.size(); i++ )
02826     {
02827       co_edge_ptr = outerCoEdgeLoop.get();
02828 
02829       if( i==A_i || i==B_i || i==D_i || i==E_i ||
02830           (!is_vertex_in_surface( start_vertex(co_edge_ptr), start_surf ) &&
02831            !is_vertex_in_surface( start_vertex(co_edge_ptr), end_surf ) ) )
02832       {
02833         outerCoEdgeLoop.step();
02834         continue;
02835       }
02836 
02837       diff = fabs( pi2 - compute_next_angle( outerCoEdgeLoop ) );
02838 
02839       if( diff < min )
02840       {
02841         best_corner_1 = i;
02842         min = diff;
02843       }
02844     }
02845 
02846     if( best_corner_1 == -1 )
02847     {
02848       PRINT_ERROR( "Unable to pick corners - please specify manually.\n"
02849         "       Type 'help split surface' for proper syntax\n" );
02850       return CUBIT_FAILURE;
02851     }
02852 
02853     if( num>1 )
02854     {
02855       min = CUBIT_DBL_MAX;
02856       outerCoEdgeLoop.reset();
02857       for( i=0; i<outerCoEdgeLoop.size(); i++ )
02858       {
02859         co_edge_ptr = outerCoEdgeLoop.get();
02860         
02861         if( i==A_i || i==B_i || i==D_i || i==E_i ||
02862           i==best_corner_1 ||
02863           (!is_vertex_in_surface( start_vertex(co_edge_ptr), start_surf ) &&
02864            !is_vertex_in_surface( start_vertex(co_edge_ptr), end_surf ) ) )
02865         {
02866           outerCoEdgeLoop.step();
02867           continue;
02868         }
02869         
02870         diff = fabs( pi2 - compute_next_angle( outerCoEdgeLoop ) );
02871         
02872         if( diff < min )
02873         {
02874           best_corner_2 = i;
02875           min = diff;
02876         }
02877       }
02878       if( best_corner_2 == -1 )
02879       {
02880         PRINT_ERROR( "Unable to pick corners - please specify manually.\n"
02881           "       Type 'help split surface' for proper syntax\n" );
02882         return CUBIT_FAILURE;
02883       }
02884     }
02885 
02886     int best_corner[6];
02887 
02888     // Find the four corners we have
02889     i = 0;
02890     if( A_i != -1 )
02891       best_corner[i++] = A_i;
02892     if( B_i != -1 )
02893       best_corner[i++] = B_i;
02894     if( D_i != -1 )
02895       best_corner[i++] = D_i;
02896     if( E_i != -1 )
02897       best_corner[i++] = E_i;
02898     if( best_corner_1 != -1 )
02899       best_corner[i++] = best_corner_1;
02900     if( best_corner_2 != -1 )
02901       best_corner[i++] = best_corner_2;
02902 
02903     if( i>4 )
02904     {
02905       PRINT_ERROR( "Internal error in split surface function - please report\n" );
02906       return CUBIT_FAILURE;
02907     }
02908 
02909     order_corners( best_corner[0], best_corner[1], best_corner[2], best_corner[3] );
02910 
02911     A_i = best_corner[0];
02912     B_i = best_corner[1];
02913     D_i = best_corner[2];
02914     E_i = best_corner[3];
02915   }
02916 
02917   // Fill cornerCoEdge array
02918   fill_corners( A_i, B_i, D_i, E_i );
02919 
02920   // Make sure we found at least two vertices on start surf and two vertices
02921   // on end surf
02922   if( !is_vertex_in_surface( start_vertex(cornerCoEdge[0]), start_surf ) ||
02923       !is_vertex_in_surface( start_vertex(cornerCoEdge[1]), start_surf ) ||
02924       !is_vertex_in_surface( start_vertex(cornerCoEdge[2]), end_surf ) ||
02925       !is_vertex_in_surface( start_vertex(cornerCoEdge[3]), end_surf ) )
02926   {
02927     PRINT_ERROR( "Unable to pick corners - please specify manually.\n"
02928       "       Type 'help split surface' for proper syntax\n" );
02929     return CUBIT_FAILURE;
02930   }
02931 
02932   // Fill sideInterval array
02933   fill_side_intervals( A_i, B_i, D_i, E_i );
02934 
02935   // Get loops in proper position (from start)
02936   reorient_loop( A_i );
02937 
02938   if( autoDetectTriangles == CUBIT_TRUE )
02939   {
02940     // Check to see if any corners are close to 180 and should be removed
02941     // to create a triangle or triangles
02942     if( update_corners_for_triangle() == CUBIT_FAILURE )
02943       return CUBIT_FAILURE;
02944   }
02945 
02946   return CUBIT_SUCCESS;
02947 }
02948 
02949 CubitStatus
02950 SplitSurfaceTool::pick_expanded_corners( RefFace *ref_face_ptr,
02951                                          DLIList<CoEdge*> &co_edge_list,
02952                                          int &offset, double epsilon, int &A_i, int &B_i )
02953 {
02954   CoEdge *co_edge_ptr;
02955   double pi2 = CUBIT_PI/2.0; // Target angle (find vertices closest to this)
02956   double A = -1.0, B = -1.0, C;
02957   int old_B_i;
02958   double old_B;
02959 
02960   A_i = -1;
02961   B_i = -1;
02962 
02963   int initial_offset = offset;
02964 
02965   int i;
02966   for( i=0; i<co_edge_list.size(); i++ )
02967   {
02968     co_edge_ptr = co_edge_list.get();
02969 
02970     // If no longer in the surface we are done
02971     if( !is_vertex_in_surface( start_vertex(co_edge_ptr), ref_face_ptr ) )
02972     {
02973       A_i += initial_offset;
02974       B_i += initial_offset;
02975       return CUBIT_SUCCESS;
02976     }
02977     
02978     // Calculate difference of angle from PI/2.  Looking for smaller C as 
02979     // compared to previous A & B.  This also steps the lists.
02980     C = fabs( pi2 - compute_next_angle( co_edge_list ) );
02981     
02982     if( A == -1.0 ) // Initialization of A
02983     {
02984       A_i = i;
02985       A = C;
02986     }
02987     else if( B == -1.0 ) // Initialization of B
02988     {
02989       B_i = i;
02990       B = C;
02991     }
02992     // Check if B should move forward (it wants to!)
02993     else if( fabs(C - B) < epsilon || C < B ) // C == B || C < B
02994     {                                         // C <= B (effectively)
02995       // Push B forward to C's spot.
02996       old_B = B;
02997       old_B_i = B_i;
02998       B = C;
02999       B_i = i;
03000       
03001       // Check if A should move into B's old spot (it doesn't want to!)
03002       if( !(fabs(old_B - A)<epsilon) && old_B < A ) // old_B != A && old_B < A
03003       {                                             // old_B < A (effectively)
03004         // Push A forward to B's old spot
03005         A = old_B;
03006         A_i = old_B_i;
03007       }
03008     }
03009     // Also look for smaller C as compared to A
03010     else if( !(fabs(C - A)<epsilon) && C < A ) // C != A && C < A
03011     {                                          // C < A (effectively)
03012       // Push B forward to C's spot.
03013       old_B = B;
03014       old_B_i = B_i;
03015       B = C;
03016       B_i = i;
03017       
03018       // Push A forward to B's old spot
03019       A = old_B;
03020       A_i = old_B_i;
03021     }
03022     offset++;
03023   }
03024 
03025   A_i += initial_offset;
03026   B_i += initial_offset;
03027   return CUBIT_SUCCESS;
03028 }
03029 
03030 CubitStatus
03031 SplitSurfaceTool::pick_4_corners_simple()
03032 {
03033   // Special case - for the loop situation the corners are already picked
03034   if( isLoop )
03035     return CUBIT_SUCCESS;
03036 
03037   // We simply find the 4 corners closest to PI/2 - used
03038   // when we only have one surface.  Results sometimes 
03039   // aren't ideal....but user can pick corners in these
03040   // situations.
03041 
03042   // Store best quadruple
03043   int best_corner_1, best_corner_2, best_corner_3, best_corner_4;
03044 
03045   const int number_vertices = outerCoEdgeLoop.size();
03046   if( number_vertices == 3 )
03047   {
03048     // Triangle - special case (default to split to first tip of triangle)
03049     best_corner_1 = 0;
03050     best_corner_2 = 0;
03051     best_corner_3 = 1;
03052     best_corner_4 = 2;
03053   }
03054   else
03055   {
03056     const int num_angles = number_vertices;  
03057     
03058     // Compute angles
03059     double *angles;
03060     double turn_angle_sum = 0.;
03061     compute_angles( angles, turn_angle_sum );
03062     
03063     // For now just find the 4 vertices that are closest to PI/2
03064     int i;
03065     double diff;
03066     double pi2 = CUBIT_PI/2.0;
03067     double min = CUBIT_DBL_MAX;
03068     for( i=0; i<num_angles; i++ )
03069     {
03070       diff = fabs( pi2 - angles[i] );
03071       if( diff < min )
03072       {
03073         best_corner_1 = i;
03074         min = diff;
03075       }
03076     }
03077     
03078     min = CUBIT_DBL_MAX;
03079     for( i=0; i<num_angles; i++ )
03080     {
03081       diff = fabs( pi2 - angles[i] );
03082       if( diff < min && i != best_corner_1 )
03083       {
03084         best_corner_2 = i;
03085         min = diff;
03086       }
03087     }
03088     
03089     min = CUBIT_DBL_MAX;
03090     for( i=0; i<num_angles; i++ )
03091     {
03092       diff = fabs( pi2 - angles[i] );
03093       if( diff < min && i != best_corner_1 && i != best_corner_2 )
03094       {
03095         best_corner_3 = i;
03096         min = diff;
03097       }
03098     }
03099     
03100     min = CUBIT_DBL_MAX;
03101     for( i=0; i<num_angles; i++ )
03102     {
03103       diff = fabs( pi2 - angles[i] );
03104       if( diff < min && i != best_corner_1 && i != best_corner_2 && i != best_corner_3 )
03105       {
03106         best_corner_4 = i;
03107         min = diff;
03108       }
03109     }
03110 
03111     delete [] angles;
03112     
03113     order_corners( best_corner_1, best_corner_2, best_corner_3, best_corner_4 );
03114   }
03115 
03116   // Fill cornerCoEdge and sideInterval arrays
03117   fill_corners( best_corner_1, best_corner_2, best_corner_3, best_corner_4 );
03118   fill_side_intervals( best_corner_1, best_corner_2, best_corner_3, best_corner_4 );
03119 
03120   // Get loops in proper position (from start)
03121   reorient_loop( best_corner_1 );
03122 
03123   if( autoDetectTriangles == CUBIT_TRUE )
03124   {
03125     // Check to see if any corners are close to 180 and should be removed
03126     // to create a triangle
03127     if( update_corners_for_triangle() == CUBIT_FAILURE )
03128       return CUBIT_FAILURE;
03129   }
03130 
03131   return CUBIT_SUCCESS;
03132 }
03133 
03134 CubitStatus
03135 SplitSurfaceTool::update_corners_for_triangle()
03136 {
03137   // Get four angles, in degrees
03138   double angle[4];
03139   outerCoEdgeLoop.reset();
03140   angle[0] = 180.0/CUBIT_PI * compute_next_angle( outerCoEdgeLoop );
03141   outerCoEdgeLoop.step( sideInterval[0]-1 );
03142   angle[1] = 180.0/CUBIT_PI * compute_next_angle( outerCoEdgeLoop );
03143   outerCoEdgeLoop.step( sideInterval[1]-1 );
03144   angle[2] = 180.0/CUBIT_PI * compute_next_angle( outerCoEdgeLoop );
03145   outerCoEdgeLoop.step( sideInterval[2]-1 );
03146   angle[3] = 180.0/CUBIT_PI * compute_next_angle( outerCoEdgeLoop );
03147 
03148   if( refFaceChain.size() > 1 )
03149   {
03150     // If a chain, do for both sides.  Check end surface first (otherwise
03151     // arrays could be previously modified when checking the other side)
03152     int corner_to_remove = -1;
03153     int collapsed_corner = -1;
03154 
03155     if( fabs(180.0-angle[2])<=sideAngleThreshold && angle[3] <= pointAngleThreshold )
03156     {
03157       corner_to_remove = 2;
03158       collapsed_corner = 3;
03159     }
03160     else if( fabs(180.0-angle[3])<=sideAngleThreshold && angle[2] <= pointAngleThreshold )
03161     {
03162       corner_to_remove = 3;
03163       collapsed_corner = 2;
03164     }
03165 
03166     if( corner_to_remove != -1 )
03167       remove_corner( corner_to_remove, collapsed_corner, CUBIT_FALSE );
03168 
03169     // Now check start surface
03170     corner_to_remove = -1;
03171     collapsed_corner = -1;
03172 
03173     if( fabs(180.0-angle[0])<=sideAngleThreshold && angle[1] <= pointAngleThreshold )
03174     {
03175       corner_to_remove = 0;
03176       collapsed_corner = 1;
03177     }
03178     else if( fabs(180.0-angle[1])<=sideAngleThreshold && angle[0] <= pointAngleThreshold )
03179     {
03180       corner_to_remove = 1;
03181       collapsed_corner = 0;
03182     }
03183 
03184     if( corner_to_remove != -1 )
03185       remove_corner( corner_to_remove, collapsed_corner, CUBIT_TRUE );
03186   }
03187   else
03188   {
03189     // Determine angle within sideAngleThreshold and closest to 180
03190     double diff = CUBIT_DBL_MAX;
03191     int best_side_corner = -1;
03192     int i;
03193     for( i=0; i<4; i++ )
03194     {
03195       if( fabs(180.0-angle[i])<=sideAngleThreshold && fabs(180.0-angle[i])<diff )
03196       {
03197         best_side_corner = i;
03198         diff = fabs(180.0-angle[i]);
03199       }
03200     }
03201 
03202     if( best_side_corner == -1 )
03203     {
03204       //PRINT_INFO( "No angle within criteria above sideAngleThreshold\n" );
03205       return CUBIT_SUCCESS;
03206     }
03207 
03208     //PRINT_INFO( "Best side corner = %d, angle = %f\n", best_side_corner, 
03209     //  angle[best_side_corner] );
03210 
03211     // Determine angle most below pointAngleThreshold
03212     diff = CUBIT_DBL_MAX;
03213     int best_point_corner = -1;
03214     for( i=0; i<4; i++ )
03215     {
03216       if( angle[i] <= pointAngleThreshold && (pointAngleThreshold-angle[i]) < diff )
03217       {
03218         best_point_corner = i;
03219         diff = pointAngleThreshold - angle[i];
03220       }
03221     }
03222 
03223     if( best_point_corner == -1 )
03224     {
03225       //PRINT_INFO( "No angle within criteria below pointAngleThreshold\n" );
03226       return CUBIT_SUCCESS;
03227     }
03228 
03229     //PRINT_INFO( "Best point corner = %d, angle = %f\n", best_point_corner, 
03230     //  angle[best_point_corner] );
03231 
03232     if( best_side_corner != -1 && best_point_corner != -1 )
03233       remove_corner( best_side_corner, best_point_corner, CUBIT_TRUE );
03234   }
03235 
03236   return CUBIT_SUCCESS;
03237 }
03238 
03239 CubitStatus
03240 SplitSurfaceTool::remove_corner( int corner_to_remove, int collapsed_corner,
03241                                  CubitBoolean set_collapsed_first )
03242 {
03243   // Need to adjust:
03244   //  outerCoEdgeLoop
03245   //  cornerCoEdge
03246   //  sideInterval
03247 
03248   // Shuffle the corners so that corner to remove is 2nd corner
03249   switch( corner_to_remove )
03250   {
03251   case 0:
03252     shuffle_corners_forward();
03253     shuffle_corners_forward();
03254     shuffle_corners_forward();
03255     collapsed_corner += 1;
03256 
03257     // Ensure collapsed_corner does not wrap the array (note we could have used
03258     // the remainder function instead, as follows:
03259     // int remainder = 0;
03260     // collapsed_corner = (remainder=collapsed_corner%4) ? remainder : collapsed_corner;
03261     if( collapsed_corner == 4 )
03262       collapsed_corner = 0;    
03263 
03264     break;
03265   case 1:
03266     break;
03267   case 2:
03268     shuffle_corners_forward();
03269     collapsed_corner -= 1;
03270     break;
03271   case 3:
03272     shuffle_corners_forward();
03273     shuffle_corners_forward();
03274     collapsed_corner -= 2;
03275     break;
03276   }
03277 
03278   if( collapsed_corner < 0 )
03279     collapsed_corner += 4;
03280 
03281   switch( collapsed_corner )
03282   {
03283   case 0:
03284     sideInterval[1] = sideInterval[0] + sideInterval[1];
03285     sideInterval[0] = 0;
03286     break;
03287   case 1:
03288     PRINT_ERROR( "Algorithm error in auto-detecting triangle - please report.\n" );
03289     return CUBIT_FAILURE;
03290   case 2:
03291     sideInterval[0] = sideInterval[0] + sideInterval[1];
03292     sideInterval[1] = 0;
03293     break;
03294   case 3:
03295     sideInterval[0] = sideInterval[0] + sideInterval[1];
03296     sideInterval[1] = sideInterval[2];
03297     sideInterval[2] = 0;
03298   }
03299 
03300   // Now redo cornerCoEdge array
03301   outerCoEdgeLoop.reset();
03302   cornerCoEdge[0] = outerCoEdgeLoop.get();
03303   outerCoEdgeLoop.step( sideInterval[0] );
03304   cornerCoEdge[1] = outerCoEdgeLoop.get();
03305   outerCoEdgeLoop.step( sideInterval[1] );
03306   cornerCoEdge[2] = outerCoEdgeLoop.get();
03307   outerCoEdgeLoop.step( sideInterval[2] );
03308   cornerCoEdge[3] = outerCoEdgeLoop.get();
03309 
03310   if( set_collapsed_first == CUBIT_TRUE )
03311   {
03312     // Adjust the arrays so that collapsed_corner is at the front
03313     switch( collapsed_corner )
03314     {
03315     case 2:
03316       shuffle_corners_forward();
03317       break;
03318     case 3:
03319       shuffle_corners_forward();
03320       shuffle_corners_forward();
03321       shuffle_corners_forward();
03322     }
03323   }
03324   else
03325   {
03326     // Return to original position
03327     switch( corner_to_remove )
03328     {
03329     case 0:
03330       shuffle_corners_forward();
03331       break;
03332     case 1:
03333       break;
03334     case 2:
03335       shuffle_corners_forward();
03336       shuffle_corners_forward();
03337       shuffle_corners_forward();
03338       break;
03339     case 3:
03340       shuffle_corners_forward();
03341       shuffle_corners_forward();
03342       break;
03343     }
03344   }
03345 
03346   return CUBIT_SUCCESS;
03347 }
03348 
03349 CubitStatus
03350 SplitSurfaceTool::fill_corners( int best_corner_1, int best_corner_2,
03351                                 int best_corner_3, int best_corner_4 )
03352 {
03353   outerCoEdgeLoop.reset();
03354   outerCoEdgeLoop.step(best_corner_1);
03355   cornerCoEdge[0] = outerCoEdgeLoop.get();
03356 
03357   outerCoEdgeLoop.reset();
03358   outerCoEdgeLoop.step(best_corner_2);
03359   cornerCoEdge[1] = outerCoEdgeLoop.get();
03360 
03361   outerCoEdgeLoop.reset();
03362   outerCoEdgeLoop.step(best_corner_3);
03363   cornerCoEdge[2] = outerCoEdgeLoop.get();
03364 
03365   outerCoEdgeLoop.reset();
03366   outerCoEdgeLoop.step(best_corner_4);
03367   cornerCoEdge[3] = outerCoEdgeLoop.get();
03368 
03369   return CUBIT_SUCCESS;
03370 }
03371 
03372 CubitStatus
03373 SplitSurfaceTool::fill_side_intervals( int best_corner_1, int best_corner_2,
03374                                        int best_corner_3, int best_corner_4 )
03375 {
03376   sideInterval[0] = best_corner_2 - best_corner_1;
03377   sideInterval[1] = best_corner_3 - best_corner_2;
03378   sideInterval[2] = best_corner_4 - best_corner_3;
03379   sideInterval[3] = best_corner_1 + outerCoEdgeLoop.size() - best_corner_4;
03380 
03381   return CUBIT_SUCCESS;
03382 }
03383 
03384 CubitStatus 
03385 SplitSurfaceTool::compute_angles( double *&angles, double &turn_angle_sum )
03386 {
03387   const int num_angles = outerCoEdgeLoop.size();
03388   angles = new double[ num_angles ];
03389   turn_angle_sum = 0.;
03390   outerCoEdgeLoop.reset();
03391   int i;
03392   for(i=0; i<num_angles; i++) 
03393   {
03394     angles[i] = compute_next_angle( outerCoEdgeLoop );
03395     //turn_angle_sum += CUBIT_PI - angles[i]; // Not currently used
03396   }
03397   return CUBIT_SUCCESS;
03398 }
03399 
03400 double
03401 SplitSurfaceTool::compute_next_angle( DLIList<CoEdge*> &co_edge_list )
03402 {  
03403   CoEdge *co_edge_1 = co_edge_list.prev();
03404   CoEdge *co_edge_2 = co_edge_list.get_and_step();
03405 
03406   // Coordinates of common point
03407   CubitVector vertex_point = start_vertex( co_edge_2 )->coordinates();
03408   
03409   // Find normal to the the face at the common vertex
03410   RefFace *ref_face1 = co_edge_1->get_ref_face();
03411   CubitVector normal1 = ref_face1->normal_at(vertex_point, NULL);
03412 
03413   RefFace *ref_face2 = co_edge_2->get_ref_face();
03414   CubitVector normal2 = ref_face2->normal_at(vertex_point, NULL);
03415 
03416   CubitVector normal = (normal1 + normal2)/2; // Average
03417 
03418   // Find directed tangents to determine interior angle
03419   // Use sense of edge with respect to this face's loop.
03420   CubitVector tangent_1, tangent_2;
03421   co_edge_1->get_ref_edge_ptr()->tangent( vertex_point, tangent_1 );
03422   co_edge_2->get_ref_edge_ptr()->tangent( vertex_point, tangent_2 );
03423   
03424   if ( co_edge_1->get_sense() == CUBIT_REVERSED )
03425     tangent_1 = -tangent_1;
03426   if ( co_edge_2->get_sense() == CUBIT_REVERSED )
03427     tangent_2 = -tangent_2;
03428   
03429   //  At this point we have the tangents going in the correct loop
03430   //  sense.
03431   //  Now get tangent pointing away from the center for the correct
03432   //  angle
03433   tangent_1 = -tangent_1;
03434 
03435   // Return angle from given tangents and normal to face
03436   double angle = normal.vector_angle( tangent_2, tangent_1 );
03437 
03438   PRINT_DEBUG_154( " Angle at vertex %d = %f\n", start_vertex( co_edge_2 )->id(), 
03439                    angle*180.0/CUBIT_PI );
03440   return angle;
03441 }
03442 
03443 void
03444 SplitSurfaceTool::order_corners( int &corner_1, int &corner_2,
03445                                  int &corner_3, int &corner_4 )
03446 {
03447   // sort the corners by indices
03448   int swap_temp;
03449 #define SWAP( a, b ) swap_temp = (a); (a) = (b); (b) = swap_temp
03450   if ( corner_1 > corner_2 ) {
03451     SWAP( corner_1, corner_2 );
03452   }
03453   if ( corner_2 > corner_3 ) {
03454     SWAP( corner_2, corner_3 );
03455   }
03456   if ( corner_3 > corner_4 ) {
03457     SWAP( corner_3, corner_4 );
03458   }
03459   // 4 is now set
03460   order_corners( corner_1, corner_2, corner_3 );
03461 #undef SWAP
03462 }
03463 
03464 void
03465 SplitSurfaceTool::order_corners( int &corner_1, int &corner_2, 
03466                                  int &corner_3 )
03467 {
03468   // sort the corners by indices
03469   int swap_temp;
03470 #define SWAP( a, b ) swap_temp = (a); (a) = (b); (b) = swap_temp
03471   if ( corner_1 > corner_2 ) {
03472     SWAP( corner_1, corner_2 );
03473   }
03474   if ( corner_2 > corner_3 ) {
03475     SWAP( corner_2, corner_3 );
03476   }
03477   // 3 is now set
03478   if ( corner_1 > corner_2 ) {
03479     SWAP( corner_1, corner_2 );
03480   }
03481   // 2 is now set
03482   // 1 is set as its the only one left
03483 #undef SWAP
03484 }
03485 
03486 CubitStatus 
03487 SplitSurfaceTool::order_selected_corners( DLIList<RefVertex*> &corner_vertex_list )
03488 {
03489   int i;
03490 
03491   RefVertex *ref_vertex_ptr;
03492   CoEdge *co_edge_ptr;
03493 
03494   // Verify that these corners exist in the outerCoEdgeLoop
03495   for( i = corner_vertex_list.size(); i--; )
03496   {
03497     ref_vertex_ptr = corner_vertex_list.get_and_step();
03498 
03499     if( is_in_outer_loop( ref_vertex_ptr ) == CUBIT_FALSE )
03500     {
03501       PRINT_ERROR( "Selected corner, Vertex %d, not found in outer loop of patch.\n",
03502         ref_vertex_ptr->id() );
03503       return CUBIT_FAILURE;
03504     }
03505   }
03506 
03507   // We need to start at the first corner the user selected - shuffle the
03508   // lists to do this.
03509   corner_vertex_list.reset();
03510   RefVertex *start_corner = corner_vertex_list.get();
03511 
03512   int offset = 0;
03513   outerCoEdgeLoop.reset();
03514   for( i=outerCoEdgeLoop.size(); i--; )
03515   {
03516     ref_vertex_ptr = start_vertex( outerCoEdgeLoop.get_and_step() );
03517     if( ref_vertex_ptr == start_corner )
03518       break;
03519     offset++;
03520   }
03521 
03522   // Now shuffle the lists to get them into the proper order
03523   if( offset )
03524   {
03525     outerCoEdgeLoop.reset();
03526     DLIList<CoEdge*> outer_co_edge_loop = outerCoEdgeLoop;
03527     
03528     outerCoEdgeLoop.clean_out();
03529 
03530     outer_co_edge_loop.reset();
03531     
03532     // Set the loop at start offset
03533     outer_co_edge_loop.step( offset );
03534     for( i=outer_co_edge_loop.size(); i--; )
03535     {
03536       outerCoEdgeLoop.append( outer_co_edge_loop.get_and_step() );
03537     }
03538   }
03539 
03540   // Cruise through the outer coedge list to get the proper corner order 
03541   int corner = 0;
03542   int num = 0;
03543   int side_interval = 0;
03544   outerCoEdgeLoop.reset();
03545 
03546   co_edge_ptr = outerCoEdgeLoop.get_and_step();
03547 
03548   // Special case for first corner (always at first corner to start)
03549   num = number_in_list( corner_vertex_list, start_vertex(co_edge_ptr) );
03550   if( num > 2 )
03551   {
03552     PRINT_ERROR( "Vertex %d was selected for %d of the corners - max is 2\n",
03553       start_vertex(co_edge_ptr)->id(), num );
03554     return CUBIT_FAILURE;
03555   }
03556 
03557   cornerCoEdge[corner++] = co_edge_ptr;
03558   if( num == 2 )
03559   {
03560     sideInterval[corner-1] = 0;
03561     cornerCoEdge[corner++] = co_edge_ptr;
03562   }
03563 
03564   for( i=1; i<outerCoEdgeLoop.size(); i++ )
03565   {
03566     co_edge_ptr = outerCoEdgeLoop.get_and_step();
03567     side_interval++;
03568 
03569     num = number_in_list( corner_vertex_list, start_vertex(co_edge_ptr) );
03570     if( num > 2 )
03571     {
03572       PRINT_ERROR( "Vertex %d was selected for %d of the corners - max is 2\n",
03573         start_vertex(co_edge_ptr)->id(), num );
03574       return CUBIT_FAILURE;
03575     }
03576 
03577     if( num > 0 )
03578     {
03579       sideInterval[corner-1] = side_interval;
03580       side_interval = 0;
03581       cornerCoEdge[corner++] = co_edge_ptr;
03582 
03583       if( num == 2 )
03584       {
03585         sideInterval[corner-1] = 0;
03586         cornerCoEdge[corner++] = co_edge_ptr;
03587       }
03588     }
03589   }
03590 
03591   sideInterval[3] = outerCoEdgeLoop.size() - sideInterval[0] - sideInterval[1] - sideInterval[2];
03592 
03593   return CUBIT_SUCCESS;
03594 }
03595 
03596 int
03597 SplitSurfaceTool::number_in_list( DLIList<RefVertex*> &corner_vertex_list, 
03598                                   RefVertex *ref_vertex_ptr )
03599 {
03600   int num = 0;
03601   int i;
03602   corner_vertex_list.reset();
03603   RefVertex *check_ptr;
03604   for( i=4; i--; )
03605   {
03606     check_ptr = corner_vertex_list.get_and_step();
03607     if( check_ptr == ref_vertex_ptr )
03608       num++;
03609   }
03610 
03611   return num;
03612 }
03613 
03614 CubitBoolean
03615 SplitSurfaceTool::is_in_outer_loop( RefVertex *ref_vertex_ptr )
03616 {
03617   int i;
03618   outerCoEdgeLoop.reset();
03619 
03620   for( i=outerCoEdgeLoop.size(); i--; )
03621   {
03622     if( ref_vertex_ptr == start_vertex( outerCoEdgeLoop.get_and_step() ) )
03623       return CUBIT_TRUE;
03624   }
03625   return CUBIT_FALSE;
03626 }
03627 
03628 CubitStatus
03629 SplitSurfaceTool::adjust_for_split_direction( RefEdge *curve_dir_ptr,
03630                                               RefEdge *from_curve_ptr,
03631                                               DLIList<RefVertex*> &corner_vertex_list )
03632 {
03633   // Adjust the loops to the split direction. The split direction is
03634   // determined as follows:
03635   // 1) For multiple surfaces - always across the chain.
03636   //
03637   //          split direction
03638   //   c2        <-------->            c1
03639   //   +---------+-----------+-----------+
03640   //   |         |           |           |
03641   //   |_  _  _  |_  _  _  _ | _  _  _  _|
03642   //   |         |  split    |           |side 0
03643   //   |         |           |           |
03644   //   +---------+-----------+-----------+
03645   //   c3            side 3              c0
03646   //
03647   // 2) If a "from" curve is specfied, put the "from" curve on 
03648   //    side 3, so that the fraction and distance goes from the
03649   //    right side.
03650 
03651 
03652   // For single surfaces, the logic is a little more tricky:
03653   // 1) From optional "direction" curve given by user (parallel to split) 
03654   // 2) From optional "from" curve given by user (parallel to split)
03655   // 3) From optional through vertex list given by user.
03656   // 4) From optional corner vertices given by user, if given in a 
03657   //    sensible order (ie., not criss-crossed). Split direction
03658   //    will be perpendicular to the side from first to second
03659   //    selected corner (ie., perpendicular to c0-c1 in the 
03660   //    diagram below).
03661   // 5) From aspect ratio of patch - split along "skinny" direction.
03662  
03663   //          split direction
03664   //   c2        <-------->            c1
03665   //   +-------------------------------+
03666   //   |                               |
03667   //   |_  _  _  _  _  _  _  _  _  _  _|
03668   //   |           split               |
03669   //   |                               |
03670   //   +-------------------------------+
03671   //   c3                              c0
03672   //
03673   //   In all cases check for incompatible inputs (i.e., conflicting 
03674   //   "direction" and "from" curves, conflicting "through" vertices
03675   //   on single surfaces, etc.)
03676 
03677   corner_vertex_list.reset();
03678 
03679   if( refFaceChain.size() > 1 && corner_vertex_list.size() )
03680   {
03681     refFaceChain.reset();
03682     RefFace *start_surf = refFaceChain.get();
03683     refFaceChain.last();
03684     RefFace *end_surf = refFaceChain.get();
03685 
03686     // We might have to shuffle the selected corners to orient them to split 
03687     // across the surfaces.  To be valid, we must have the two starting 
03688     // corners in the start surface and the two ending corners in the end 
03689     // surface.  Shuffle the corners until this condition is met.  If
03690     // we shuffle three times and the condition is still not met, we have
03691     // been given invalid vertices.
03692     //
03693     // Here is a case we must be able to handle, with corners specified
03694     // as shown.  We must shuffle three times.
03695 
03696     //  C3                        C2
03697     //   +-----+------------------+
03698     //   |\     \                 |
03699     //   |  \    \                |
03700     //   |    \    \     end      |
03701     //   |      \   \             |
03702     //   |        \   \           |
03703     //   |          \   \         |
03704     //   |            \   \       |
03705     //   |              \  \      |
03706     //   |                \  \    |
03707     //   |     start        \ \   |
03708     //   |                    \ \ |
03709     //   |                      \\|
03710     //   +------------------------+
03711     //  C0                        C1
03712 
03713     if( !is_vertex_in_surface( start_vertex(cornerCoEdge[0]), start_surf ) ||
03714         !is_vertex_in_surface( start_vertex(cornerCoEdge[1]), start_surf ) ||
03715         !is_vertex_in_surface( start_vertex(cornerCoEdge[2]), end_surf ) ||
03716         !is_vertex_in_surface( start_vertex(cornerCoEdge[3]), end_surf ) )
03717     {
03718       shuffle_corners_forward();
03719       if( !is_vertex_in_surface( start_vertex(cornerCoEdge[0]), start_surf ) ||
03720           !is_vertex_in_surface( start_vertex(cornerCoEdge[1]), start_surf ) ||
03721           !is_vertex_in_surface( start_vertex(cornerCoEdge[2]), end_surf ) ||
03722           !is_vertex_in_surface( start_vertex(cornerCoEdge[3]), end_surf ) )
03723       {
03724         shuffle_corners_forward();
03725         if( !is_vertex_in_surface( start_vertex(cornerCoEdge[0]), start_surf ) ||
03726             !is_vertex_in_surface( start_vertex(cornerCoEdge[1]), start_surf ) ||
03727             !is_vertex_in_surface( start_vertex(cornerCoEdge[2]), end_surf ) ||
03728             !is_vertex_in_surface( start_vertex(cornerCoEdge[3]), end_surf ) )
03729         {
03730           shuffle_corners_forward();
03731           if( !is_vertex_in_surface( start_vertex(cornerCoEdge[0]), start_surf ) ||
03732               !is_vertex_in_surface( start_vertex(cornerCoEdge[1]), start_surf ) ||
03733               !is_vertex_in_surface( start_vertex(cornerCoEdge[2]), end_surf ) ||
03734               !is_vertex_in_surface( start_vertex(cornerCoEdge[3]), end_surf ) )
03735           {
03736             PRINT_ERROR( "Selected vertices are invalid.  Two vertices must be on\n"
03737               "       start surface and two on end surface of chain.\n" );
03738             return CUBIT_FAILURE;
03739           }
03740         }
03741       }
03742     }
03743   }
03744   if( refFaceChain.size() > 1 )
03745   {
03746     if( curve_dir_ptr )
03747     {
03748       // Check for rare case with two triangles - that case allows a switch in
03749       // direction
03750       if( is_chain_two_triangles() )
03751       {
03752         if( is_curve_on_side( curve_dir_ptr, 0 ) ||
03753             is_curve_on_side( curve_dir_ptr, 2 ) )
03754         {
03755           shuffle_corners_forward();
03756         }
03757 
03758         if( throughVertexList.size() > 2 )
03759         {
03760           PRINT_ERROR( "For two triangle case, you can only specify 2 'through' vertices.\n" );
03761           return CUBIT_FAILURE;
03762         }
03763 
03764         // Make sure through vertices (if any) are on side 0 or 2
03765         if( check_through_vertices( "'direction'" ) == CUBIT_FAILURE )
03766           return CUBIT_FAILURE;
03767       }
03768       else
03769         PRINT_WARNING( "Curve direction ignored - not necessary for a chain of surfaces.\n" );
03770     }
03771       
03772     // Flip sides if user selected a from curve
03773     if( from_curve_ptr )
03774     {
03775       // Check for rare case with two triangles - that case allows a switch in
03776       // direction
03777       if( is_chain_two_triangles() )
03778       {
03779         if( is_curve_on_side( from_curve_ptr, 0 ) ||
03780             is_curve_on_side( from_curve_ptr, 2 ) )
03781         {
03782           if( curve_dir_ptr )
03783           {
03784             PRINT_ERROR( "From curve must be parallel to direction of split.\n" );
03785             return CUBIT_FAILURE;
03786           }
03787           else
03788             shuffle_corners_forward();
03789         }
03790 
03791         // Next two checks are redundant if a direction was specified, but that 
03792         // doesn't hurt anything.
03793         if( throughVertexList.size() > 2 )
03794         {
03795           PRINT_ERROR( "For two triangle case, you can only specify 2 'through' vertices.\n" );
03796           return CUBIT_FAILURE;
03797         }
03798 
03799         // Make sure through vertices (if any) are on side 0 or 2
03800         if( check_through_vertices( "'from'" ) == CUBIT_FAILURE )
03801           return CUBIT_FAILURE;
03802       }
03803       else
03804       {
03805         // Make sure this curve is on side 3
03806         if( is_curve_on_side( from_curve_ptr, 0 ) ||
03807             is_curve_on_side( from_curve_ptr, 2 ) )
03808         {
03809           PRINT_ERROR( "From curve must be parallel to direction of split.\n" );
03810           return CUBIT_FAILURE;
03811         }
03812         if( is_curve_on_side( from_curve_ptr, 1 ) )
03813         {
03814           shuffle_corners_forward();
03815           shuffle_corners_forward();
03816         }
03817       }   
03818     }
03819     return CUBIT_SUCCESS;
03820   }
03821   else
03822     // SINGLE surface
03823   {
03824     // Special case for triangle
03825     if( is_triangle() && (curve_dir_ptr || from_curve_ptr ) )
03826     {
03827       // For a triangle, curve_dir_ptr and from_curve_ptr mean the same
03828       // thing.  Do a check.
03829       if( curve_dir_ptr && from_curve_ptr && (from_curve_ptr != curve_dir_ptr) )
03830       {
03831         PRINT_ERROR( "For triangle case, specifying both a 'direction' and 'from'\n"
03832           "       curve is redundant - these have the same meaning.\n" );
03833         return CUBIT_FAILURE;
03834       }
03835 
03836       if( from_curve_ptr && !curve_dir_ptr )
03837         curve_dir_ptr = from_curve_ptr;
03838 
03839       // Desired state: 0 interval side opposite the side that curve_dir_ptr
03840       // is on.  Then ensure that side past selected curve is side 0.  A
03841       // tricky bit of logic!        
03842 
03843       // Start out by setting zero side to side 0
03844       if( sideInterval[1] == 0 )
03845       {
03846         shuffle_corners_forward();          
03847       }
03848       else if (sideInterval[2] == 0 )
03849       {
03850         shuffle_corners_forward();
03851         shuffle_corners_forward();
03852       }
03853       else if( sideInterval[3] == 0 )
03854       {
03855         shuffle_corners_forward();
03856         shuffle_corners_forward();
03857         shuffle_corners_forward();
03858       }
03859 
03860       // Move zero side and ensure that side past selected curve is side 0.
03861       if( is_curve_on_side( curve_dir_ptr, 1 ) )
03862       {
03863         // Zero side should be 3
03864         shuffle_zero_side_forward();
03865         shuffle_zero_side_forward();
03866 
03867         shuffle_corners_forward();
03868       }
03869       else if( is_curve_on_side( curve_dir_ptr, 2 ) )
03870       {
03871         shuffle_corners_forward();
03872         shuffle_corners_forward();
03873         shuffle_corners_forward();
03874       }
03875       else if( is_curve_on_side( curve_dir_ptr, 3 ) )
03876       {
03877         shuffle_zero_side_forward();
03878       }
03879 
03880       // Check through vertices to make sure they are valid
03881       if( check_through_vertices( "'direction'" ) == CUBIT_FAILURE )
03882         return CUBIT_FAILURE;
03883 
03884       return CUBIT_SUCCESS;
03885     }
03886     else if( curve_dir_ptr )
03887     {
03888       // Curve should be on side 1 or 3 - otherwise adjust the loops forward
03889       if( is_curve_on_side( curve_dir_ptr, 0 ) )
03890         shuffle_corners_forward();
03891       else if( is_curve_on_side( curve_dir_ptr, 2 ) )
03892         shuffle_corners_forward();
03893 
03894       // Now check if there is a from curve too, along with curve direction
03895       if( from_curve_ptr )
03896       {
03897         if( is_curve_on_side( from_curve_ptr, 0 ) ||
03898           is_curve_on_side( from_curve_ptr, 2 ) )
03899         {
03900           PRINT_ERROR( "'Direction' and 'From' curves must be on same or opposite\n"
03901             "       sides of logical rectangle\n" );
03902           return CUBIT_FAILURE;
03903         }
03904         // Must be on side 3
03905         if( is_curve_on_side( from_curve_ptr, 1 ) )
03906         {
03907           shuffle_corners_forward();
03908           shuffle_corners_forward();
03909         }
03910       }
03911 
03912       // Check through vertices to make sure they are valid
03913       if( check_through_vertices( "'direction'" ) == CUBIT_FAILURE )
03914         return CUBIT_FAILURE;
03915 
03916       return CUBIT_SUCCESS;
03917     }
03918 
03919     // Single surface WITHOUT a direction given
03920     if( from_curve_ptr )
03921     {
03922       // Curve should be on side 3 - otherwise adjust the loops forward
03923       if( is_curve_on_side( from_curve_ptr, 2 ) )
03924       {
03925         shuffle_corners_forward();
03926         shuffle_corners_forward();
03927         shuffle_corners_forward();
03928       }
03929       else if( is_curve_on_side( from_curve_ptr, 1 ) )
03930       {
03931         shuffle_corners_forward();
03932         shuffle_corners_forward();
03933       }
03934       else if( is_curve_on_side( from_curve_ptr, 0 ) )
03935         shuffle_corners_forward();
03936 
03937       // Check through vertices to make sure they are valid
03938       if( check_through_vertices( "'from'" ) == CUBIT_FAILURE )
03939         return CUBIT_FAILURE;
03940 
03941       return CUBIT_SUCCESS;
03942     }
03943 
03944     // Single surface WITHOUT a 'direction' or 'from' curve given - if through
03945     // vertices let them determine the split direction.
03946     if( throughVertexList.size() > 2 )
03947     {
03948       PRINT_ERROR( "For a single surface, you can only specify 2 'through' vertices.\n" );
03949       return CUBIT_FAILURE;
03950     }
03951 
03952     RefVertex *start_vertex_ptr = NULL;
03953     RefVertex *end_vertex_ptr = NULL;
03954     throughVertexList.reset();
03955     if( throughVertexList.size() > 0 )
03956       start_vertex_ptr = throughVertexList.get_and_step();
03957     if( throughVertexList.size() > 1 )
03958       end_vertex_ptr = throughVertexList.get();
03959 
03960     // First check for start and end vertices
03961     if( start_vertex_ptr || end_vertex_ptr )
03962     {
03963       if( start_vertex_ptr )
03964       {
03965         // Check if on side A
03966         if( !is_vertex_on_side( start_vertex_ptr, 0 ) )
03967         {
03968           // Shuffle forward and check again
03969           shuffle_corners_forward();
03970           if( !is_vertex_on_side( start_vertex_ptr, 0 ) )
03971           {
03972             // Shuffle forward and check again
03973             shuffle_corners_forward();
03974             if( !is_vertex_on_side( start_vertex_ptr, 0 ) )
03975             {
03976               // Shuffle forward and check again
03977               shuffle_corners_forward();
03978               if( !is_vertex_on_side( start_vertex_ptr, 0 ) )
03979               {
03980                 PRINT_ERROR( "Specified 'through' vertex %d is not valid\n",
03981                   start_vertex_ptr->id() );
03982                 return CUBIT_FAILURE;
03983               }
03984             }
03985           }
03986         }
03987       }
03988       if( end_vertex_ptr )
03989       {
03990         // Check if on side C
03991         if( !is_vertex_on_side( end_vertex_ptr, 2 ) )
03992         {
03993           // Shuffle forward and check again
03994           shuffle_corners_forward();
03995           if( !is_vertex_on_side( end_vertex_ptr, 2 ) )
03996           {
03997             // Shuffle forward and check again
03998             shuffle_corners_forward();
03999             if( !is_vertex_on_side( end_vertex_ptr, 2 ) )
04000             {
04001               // Shuffle forward and check again
04002               shuffle_corners_forward();
04003               if( !is_vertex_on_side( end_vertex_ptr, 2 ) )
04004               {
04005                 PRINT_ERROR( "Specified 'through' vertex %d is not valid\n",
04006                   end_vertex_ptr->id() );
04007                 return CUBIT_FAILURE;
04008               }
04009             }
04010           }
04011         }
04012       }
04013       if( start_vertex_ptr && end_vertex_ptr )
04014       {
04015         if( !is_vertex_on_side( start_vertex_ptr, 0 ) ||
04016             !is_vertex_on_side( end_vertex_ptr, 2 ) )
04017         {
04018           PRINT_ERROR( "Specified 'through' vertices invalid - both not on split path.\n" );
04019           return CUBIT_FAILURE;
04020         }
04021       }
04022 
04023       return CUBIT_SUCCESS;
04024 
04025     }
04026     
04027     // If second corner is 1 or 3, use the direction implied.  Otherwise,
04028     // user gave corners in a criss-crossed manner and we can't gain any
04029     // implied direction from them.
04030     else if( corner_vertex_list.size() && 
04031              corner_vertex_list.step_and_get() == start_vertex( cornerCoEdge[1]) )
04032       return CUBIT_SUCCESS;
04033     else if( corner_vertex_list.size() && 
04034              corner_vertex_list.get() == start_vertex( cornerCoEdge[3]) )
04035       ;
04036     else
04037     {
04038       // We use aspect ratio to determine split direction.  Split along
04039       // narrowest direction.
04040 
04041       // Skip if we have a triangle
04042       if( is_triangle() )
04043         return CUBIT_SUCCESS;
04044 
04045       double len0 = get_side_length( 0 );
04046       double len1 = get_side_length( 1 );
04047       double len2 = get_side_length( 2 );
04048       double len3 = get_side_length( 3 );
04049 
04050       double ratio = (len0+len2) / (len1+len3);
04051       PRINT_DEBUG_154( "Ratio = %f\n", ratio );
04052 
04053       if( ratio < 1.0001 )
04054         return CUBIT_SUCCESS;
04055       else
04056         PRINT_DEBUG_154( "Ratio deems we adjust forward\n" );
04057     }
04058     
04059     // If we got this far, we need to adjust the split direction - move
04060     // loops forward by sideInterval[0] (start at corner 1)
04061     shuffle_corners_forward();
04062   }
04063 
04064   return CUBIT_SUCCESS;
04065 }
04066 
04067 CubitBoolean
04068 SplitSurfaceTool::is_chain_two_triangles()
04069 {
04070   if( refFaceChain.size() != 2 )
04071     return CUBIT_FALSE;
04072 
04073   //  C3-0-1-2                 C2-3-0-1
04074   //   +------------------------+
04075   //   |\                       |
04076   //   |  \                     |
04077   //   |    \          end      |
04078   //   |      \                 |
04079   //   |        \               |
04080   //   |          \             |
04081   //   |            \           |
04082   //   |              \         |
04083   //   |                \       |
04084   //   |     start        \     |
04085   //   |                    \   |
04086   //   |                      \ |
04087   //   +------------------------+
04088   //  C0-1-2-3                 C1-2-3-0
04089 
04090   // 4 possibilities (see diagram above - corners 0-1-2-3 or 1-2-3-0 etc
04091   // going ccw from bottom left)
04092 
04093   CoEdge *c0 = cornerCoEdge[0];
04094   CoEdge *c1 = cornerCoEdge[1];
04095   CoEdge *c2 = cornerCoEdge[2];
04096   CoEdge *c3 = cornerCoEdge[3];
04097 
04098   if( (prev_co_edge(c0)->get_ref_face() == c0->get_ref_face() &&
04099       prev_co_edge(c1)->get_ref_face() != c1->get_ref_face() &&
04100       prev_co_edge(c2)->get_ref_face() == c2->get_ref_face() &&
04101       prev_co_edge(c3)->get_ref_face() != c3->get_ref_face() ) ||
04102 
04103       (prev_co_edge(c1)->get_ref_face() == c1->get_ref_face() &&
04104       prev_co_edge(c2)->get_ref_face() != c2->get_ref_face() &&
04105       prev_co_edge(c3)->get_ref_face() == c3->get_ref_face() &&
04106       prev_co_edge(c0)->get_ref_face() != c0->get_ref_face() ) )
04107   {
04108     // 2-triangle case
04109     return CUBIT_TRUE;
04110   }
04111 
04112   return CUBIT_FALSE;
04113 }
04114 
04115 CubitBoolean
04116 SplitSurfaceTool::is_triangle()
04117 {
04118   if( sideInterval[0]==0 || sideInterval[1]==0 ||
04119     sideInterval[2]==0 || sideInterval[3]==0 )
04120     return CUBIT_TRUE;
04121   else
04122     return CUBIT_FALSE;
04123 }
04124 
04125 CubitStatus
04126 SplitSurfaceTool::check_through_vertices( const char *type )
04127 {
04128   if( throughVertexList.size() )
04129   {
04130     RefVertex *start_vertex_ptr = NULL;
04131     RefVertex *end_vertex_ptr = NULL;
04132     throughVertexList.reset();
04133     start_vertex_ptr = throughVertexList.get_and_step();
04134     if( throughVertexList.size() > 1 )
04135       end_vertex_ptr = throughVertexList.get();
04136     
04137     if( start_vertex_ptr )
04138     {
04139       if( is_vertex_on_side( start_vertex_ptr, 0 ) || 
04140           is_vertex_on_side( start_vertex_ptr, 2 ) )
04141         ;
04142       else
04143       {
04144         if( throughVertexList.size() == 1 )
04145           PRINT_ERROR( "Through vertice(s) not compatible with %s curve given\n",
04146           type );
04147         else
04148           PRINT_ERROR( "Through vertices not compatible with %s curve given\n",
04149           type);
04150         return CUBIT_FAILURE;
04151       }
04152     }
04153     if( end_vertex_ptr )
04154     {
04155       if( is_vertex_on_side( end_vertex_ptr, 0 ) || 
04156           is_vertex_on_side( end_vertex_ptr, 2 ) )
04157         ;
04158       else
04159       {
04160         PRINT_ERROR( "%s", "Through vertices not compatible with %s curve given\n" );
04161         return CUBIT_FAILURE;
04162       }
04163     }
04164   }
04165   return CUBIT_SUCCESS;  
04166 }
04167 
04168 CoEdge *
04169 SplitSurfaceTool::prev_co_edge( CoEdge *co_edge_ptr )
04170 {
04171   outerCoEdgeLoop.move_to( co_edge_ptr );
04172   return outerCoEdgeLoop.prev();
04173 }
04174 
04175 double
04176 SplitSurfaceTool::get_side_length( int side )
04177 {
04178   int i;
04179   RefEdge *ref_edge_ptr;
04180   double length = 0.0;
04181   outerCoEdgeLoop.reset();
04182   switch( side )
04183   {
04184   case 0:
04185     for( i=sideInterval[0]; i--; )
04186     {
04187       ref_edge_ptr = outerCoEdgeLoop.get_and_step()->get_ref_edge_ptr();
04188       length += ref_edge_ptr->measure();
04189     }
04190     break;
04191 
04192   case 1:
04193     outerCoEdgeLoop.step( sideInterval[0] );
04194     for( i=sideInterval[1]; i--; )
04195     {
04196       ref_edge_ptr = outerCoEdgeLoop.get_and_step()->get_ref_edge_ptr();
04197       length += ref_edge_ptr->measure();
04198     }
04199     break;
04200 
04201   case 2:
04202 
04203     outerCoEdgeLoop.step( sideInterval[0]+sideInterval[1] );
04204     for( i=sideInterval[2]; i--; )
04205     {
04206       ref_edge_ptr = outerCoEdgeLoop.get_and_step()->get_ref_edge_ptr();
04207       length += ref_edge_ptr->measure();
04208     }
04209     break;
04210 
04211   case 3:
04212 
04213     outerCoEdgeLoop.step( sideInterval[0]+sideInterval[1]+sideInterval[2] );
04214     for( i=sideInterval[3]; i--; )
04215     {
04216       ref_edge_ptr = outerCoEdgeLoop.get_and_step()->get_ref_edge_ptr();
04217       length += ref_edge_ptr->measure();
04218     }
04219     break;
04220   }
04221 
04222   return length;
04223 }
04224 
04225 CubitStatus
04226 SplitSurfaceTool::reorient_loop( int start_offset )
04227 {
04228   if( start_offset == 0 )
04229     return CUBIT_SUCCESS;
04230 
04231   DLIList<CoEdge*> outer_co_edge_loop( outerCoEdgeLoop.size() );
04232 
04233   outerCoEdgeLoop.reset();
04234   outerCoEdgeLoop.step( start_offset );
04235 
04236   int i;
04237   for( i=outerCoEdgeLoop.size(); i--; )
04238     outer_co_edge_loop.append( outerCoEdgeLoop.get_and_step() );
04239 
04240   outerCoEdgeLoop.clean_out();
04241 
04242   outer_co_edge_loop.reset();
04243 
04244   outerCoEdgeLoop = outer_co_edge_loop;
04245 
04246   return CUBIT_SUCCESS;
04247 }
04248 
04249 CubitStatus
04250 SplitSurfaceTool::shuffle_corners_forward()
04251 {
04252   // Simply move loops forward by sideInterval[0] (start at corner 1)
04253   reorient_loop( sideInterval[0] );
04254   
04255   // Shuffle sideInterval and cornerCoEdge too
04256   int side_interval_temp = sideInterval[0];
04257   sideInterval[0] = sideInterval[1];
04258   sideInterval[1] = sideInterval[2];
04259   sideInterval[2] = sideInterval[3];
04260   sideInterval[3] = side_interval_temp;
04261 
04262   CoEdge *corner_coedge_temp = cornerCoEdge[0];
04263   cornerCoEdge[0] = cornerCoEdge[1];
04264   cornerCoEdge[1] = cornerCoEdge[2];
04265   cornerCoEdge[2] = cornerCoEdge[3];
04266   cornerCoEdge[3] = corner_coedge_temp;
04267   
04268   return CUBIT_SUCCESS;
04269 }
04270 
04271 CubitStatus
04272 SplitSurfaceTool::shuffle_zero_side_forward()
04273 {
04274   if( sideInterval[0] == 0 )
04275   {
04276     cornerCoEdge[1] = cornerCoEdge[2];
04277     sideInterval[0] = sideInterval[1];
04278     sideInterval[1] = 0;
04279   }
04280   else if( sideInterval[1] == 0 )
04281   {
04282     cornerCoEdge[2] = cornerCoEdge[3];
04283     sideInterval[1] = sideInterval[2];
04284     sideInterval[2] = 0;
04285   }
04286   else if( sideInterval[2] == 0 )
04287   {
04288     cornerCoEdge[3] = cornerCoEdge[0];
04289     sideInterval[2] = sideInterval[3];
04290     sideInterval[3] = 0;
04291   }
04292   else if( sideInterval[3] == 0 )
04293   {
04294     cornerCoEdge[0] = cornerCoEdge[1];
04295     sideInterval[3] = sideInterval[0];
04296     sideInterval[0] = 0;
04297   }
04298   return CUBIT_SUCCESS;
04299 }
04300 
04301 CubitBoolean
04302 SplitSurfaceTool::is_vertex_on_side( RefVertex *ref_vertex_ptr, int side )
04303 {
04304   // Note this will return CUBIT_TRUE if the input vertex is on one of the
04305   // specified corners.
04306 
04307   // Position outerCoEdge loop to start of corner (note switch statement
04308   // falls through - case 3 will step 3 times).
04309   outerCoEdgeLoop.reset();
04310   switch( side )
04311   {
04312   case 3:
04313     outerCoEdgeLoop.step( sideInterval[2] );
04314   case 2:
04315     outerCoEdgeLoop.step( sideInterval[1] );
04316   case 1:
04317     outerCoEdgeLoop.step( sideInterval[0] );
04318   }
04319 
04320   CoEdge *co_edge_ptr = outerCoEdgeLoop.get();
04321   CubitVector ref_coords = ref_vertex_ptr->coordinates();
04322 
04323   if( sideInterval[side] == 0 )
04324   {
04325     // Compare coordinates
04326     RefVertex *start_vertex_ptr = start_vertex( co_edge_ptr );
04327     if( start_vertex_ptr == ref_vertex_ptr )
04328       return CUBIT_TRUE;
04329     if( ref_coords.about_equal( start_vertex_ptr->coordinates() ) )
04330       return CUBIT_TRUE;
04331     else
04332       return CUBIT_FALSE;
04333   }
04334 
04335   // Check if it is on each coedge
04336   CubitPointContainment pnt_containment;
04337   int i;
04338   for( i=sideInterval[side]; i--; )
04339   {
04340     co_edge_ptr = outerCoEdgeLoop.get_and_step();
04341     pnt_containment = co_edge_ptr->get_ref_edge_ptr()->
04342       point_containment( ref_coords );
04343     if( pnt_containment == CUBIT_PNT_ON )
04344       return CUBIT_TRUE;
04345   }
04346 
04347   return CUBIT_FALSE;
04348 }
04349 
04350 CubitBoolean
04351 SplitSurfaceTool::is_vertex_in_surface( RefVertex *ref_vertex_ptr, 
04352                                         RefFace *ref_face_ptr )
04353 {
04354   // Base on finding RefFaces since there will typically be fewer RefFaces
04355   // to search than RefVertices
04356   DLIList<RefFace*> ref_face_list;
04357   ref_vertex_ptr->ref_faces( ref_face_list );
04358   return ref_face_list.is_in_list( ref_face_ptr );
04359 }
04360 
04361 CubitBoolean
04362 SplitSurfaceTool::is_curve_in_outer_loop( RefEdge *ref_edge_ptr )
04363 {
04364   outerCoEdgeLoop.reset();
04365   int i;
04366   for( i=outerCoEdgeLoop.size(); i--; )
04367   {
04368     if( ref_edge_ptr == outerCoEdgeLoop.get_and_step()->get_ref_edge_ptr() )
04369       return CUBIT_TRUE;
04370   }
04371   return CUBIT_FALSE;
04372 }
04373 
04374 CubitBoolean
04375 SplitSurfaceTool::is_curve_on_side( RefEdge *ref_edge_ptr, int side )
04376 {
04377   if( sideInterval[side] == 0 )
04378     return CUBIT_FALSE;
04379 
04380   // Position outerCoEdge loop to start of corner (note switch statement
04381   // falls through - case 3 will step 3 times).
04382   outerCoEdgeLoop.reset();
04383   switch( side )
04384   {
04385   case 3:
04386     outerCoEdgeLoop.step( sideInterval[2] );
04387   case 2:
04388     outerCoEdgeLoop.step( sideInterval[1] );
04389   case 1:
04390     outerCoEdgeLoop.step( sideInterval[0] );
04391   }
04392 
04393   // Compare against each coedge on the given side
04394   int i;
04395   for( i=sideInterval[side]; i--; )
04396   {
04397     if( ref_edge_ptr == outerCoEdgeLoop.get_and_step()->get_ref_edge_ptr() )
04398       return CUBIT_TRUE;
04399   }
04400 
04401   return CUBIT_FALSE;
04402 }
04403 
04404 CubitStatus
04405 SplitSurfaceTool::position_co_edge_list( int i, DLIList<CoEdge*> &co_edge_list )
04406 {
04407   //    6    5   4
04408   //    +----+---+ 
04409   //    |        | 
04410   //    |        | 
04411   //   7+        +3 
04412   //    |        | 
04413   //   7+----+---+3 
04414   //    |        | 
04415   //    |        | 
04416   //   7+        +3 
04417   //    |        | 
04418   //   7+-+---+--+3 
04419   //    |        | 
04420   //    |        | 
04421   //   7+        +3 
04422   //    |        | 
04423   //    +---+----+ 
04424   //    0   1    2 
04425   // Now, get to the start of the loop.  This will either be on vertex 0 or
04426   // the last vertex 7 (see diagram above).
04427 
04428   CoEdge *co_edge_ptr;
04429   CoEdge *next_co_edge_ptr;
04430   co_edge_list.reset();
04431   for( i=co_edge_list.size(); i--; )
04432   {
04433     co_edge_ptr = co_edge_list.get_and_step();
04434     next_co_edge_ptr = co_edge_list.get_and_back();
04435     
04436     // Get the tooldata from the start vertex
04437     TDSplitSurface *tdssv_start = (TDSplitSurface *)co_edge_ptr->
04438       get_TD(&TDSplitSurface::is_split_surface);
04439     
04440     if( tdssv_start )
04441     {
04442       if( tdssv_start->get_type() == 0 )
04443         break; // This is the start
04444       else if (tdssv_start->get_type() == 7)
04445       {
04446         // Check end of curve - if not a 7 or 0 we are done
04447         TDSplitSurface *tdssv_end = (TDSplitSurface *)next_co_edge_ptr->
04448           get_TD(&TDSplitSurface::is_split_surface);
04449         if( !tdssv_end )
04450           break;
04451         if( tdssv_end->get_type() != 7 && tdssv_end->get_type() != 0 )
04452           break;
04453       }
04454       else if (tdssv_start->get_type() == 6)
04455       {
04456         // Check end of curve - if not a 7 or 0 we are done
04457         //  (it will typically be NULL or type 3 - see top surface
04458         //   in diagram below)
04459         //
04460         //    6   5    4    
04461         //    +---+----+
04462         //    | \      |
04463         //    |   \    |
04464         //    |     +  |
04465         //    |       \|
04466         //   7+-+---+--+3 
04467         //    |        | 
04468         //    |        | 
04469         //   7+        +3 
04470         //    |        | 
04471         //    +---+----+ 
04472         //    0   1    2 
04473         
04474         TDSplitSurface *tdssv_end = (TDSplitSurface *)next_co_edge_ptr->
04475           get_TD(&TDSplitSurface::is_split_surface);
04476         if( !tdssv_end )
04477           break;
04478         if( tdssv_end->get_type() != 7 && tdssv_end->get_type() != 0 )
04479           break;
04480       }
04481     }
04482     co_edge_list.step();
04483   }
04484 
04485   return CUBIT_SUCCESS;
04486 }
04487 
04488 CubitStatus
04489 SplitSurfaceTool::get_a_coedges( DLIList<CoEdge*> &co_edge_list, 
04490                                  DLIList<CoEdge*> &a_coedges )
04491 {
04492   // Get all curves until end vertex type = 2 or 3 or 4 (3 or 4 in case of triangle)
04493   int i;
04494   CoEdge *co_edge_ptr;
04495   CoEdge *next_co_edge_ptr;
04496   for( i=co_edge_list.size(); i--; )
04497   {
04498     co_edge_ptr = co_edge_list.get_and_step();
04499     a_coedges.append( co_edge_ptr );
04500 
04501     next_co_edge_ptr = co_edge_list.get();
04502     
04503     // Get the tooldata from the next coedge (need value on end vertex of 
04504     // first coedge).
04505     TDSplitSurface *tdss = (TDSplitSurface *)next_co_edge_ptr->
04506       get_TD(&TDSplitSurface::is_split_surface);
04507 
04508     if( !tdss )
04509       continue;
04510 
04511     if( tdss->get_type() == 2 || tdss->get_type() == 3 
04512         || tdss->get_type() == 4 )
04513       break;
04514   }
04515   return CUBIT_SUCCESS;
04516 }
04517 
04518 CubitStatus
04519 SplitSurfaceTool::get_b_coedges( DLIList<CoEdge*> &co_edge_list, 
04520                                  DLIList<CoEdge*> &b_coedges )
04521 {
04522   // Keep getting curves as long as end vertex type = 3 or 4 (stop at 4)
04523   int i;
04524   CoEdge *co_edge_ptr;
04525   CoEdge *next_co_edge_ptr;
04526   for( i=co_edge_list.size(); i--; )
04527   {
04528     co_edge_ptr = co_edge_list.get_and_step();
04529     next_co_edge_ptr = co_edge_list.get_and_back();
04530     
04531     // Get the tooldata from the end vertex
04532     TDSplitSurface *tdss = (TDSplitSurface *)next_co_edge_ptr->
04533       get_TD(&TDSplitSurface::is_split_surface);
04534 
04535     if( !tdss )
04536       return CUBIT_SUCCESS;
04537 
04538     if( tdss->get_type() == 4 )
04539     {
04540       b_coedges.append( co_edge_ptr );
04541       co_edge_list.step();
04542       return CUBIT_SUCCESS;
04543     }
04544 
04545     if( tdss->get_type() == 3 )
04546     {
04547       b_coedges.append( co_edge_ptr );
04548       co_edge_list.step();
04549       continue;
04550     }
04551 
04552     return CUBIT_SUCCESS;
04553   }
04554   return CUBIT_SUCCESS;
04555 }
04556 
04557 CubitStatus
04558 SplitSurfaceTool::get_c_coedges( DLIList<CoEdge*> &co_edge_list, 
04559                                  DLIList<CoEdge*> &c_coedges )
04560 {
04561   // Keep getting curves until end vertex type = 6 or 7 or 0 (for triangle)
04562   int i;
04563   CoEdge *co_edge_ptr;
04564   CoEdge *next_co_edge_ptr;
04565   for( i=co_edge_list.size(); i--; )
04566   {
04567     co_edge_ptr = co_edge_list.get_and_step();
04568     next_co_edge_ptr = co_edge_list.get_and_back();
04569     
04570     // Get the tooldata from the end vertex
04571     TDSplitSurface *tdss = (TDSplitSurface *)next_co_edge_ptr->
04572       get_TD(&TDSplitSurface::is_split_surface);
04573 
04574     if( !tdss )
04575     {
04576       c_coedges.append( co_edge_ptr );
04577       co_edge_list.step();
04578       continue;
04579     }
04580 
04581     if( tdss->get_type() == 6 || tdss->get_type() == 7 ||
04582         tdss->get_type() == 0 )
04583     {
04584       c_coedges.append( co_edge_ptr );
04585       co_edge_list.step();
04586       return CUBIT_SUCCESS;
04587     }
04588     
04589     c_coedges.append( co_edge_ptr );
04590     co_edge_list.step();
04591 
04592   }
04593   return CUBIT_SUCCESS;
04594 }
04595 
04596 CubitStatus
04597 SplitSurfaceTool::get_d_coedges( DLIList<CoEdge*> &co_edge_list, 
04598                                 int num_so_far, DLIList<CoEdge*> &d_coedges )
04599 {
04600   // Get remaining curves
04601   if( co_edge_list.size() == num_so_far )
04602     return CUBIT_SUCCESS;
04603 
04604   if( num_so_far > co_edge_list.size() )
04605   {
04606     PRINT_ERROR( "Unexpected error in algorithm; aborting.\n" );
04607     PRINT_DEBUG_154( "       Surface = %d, num_so_far = %d\n", 
04608       co_edge_list.get()->get_ref_face()->id(), num_so_far );
04609     return CUBIT_FAILURE;
04610   }
04611 
04612   int i;
04613   CoEdge *co_edge_ptr;
04614   for( i=co_edge_list.size()-num_so_far; i--; )
04615   {
04616     co_edge_ptr = co_edge_list.get_and_step();
04617     d_coedges.append( co_edge_ptr );
04618   }
04619 
04620   return CUBIT_SUCCESS;
04621 }
04622 
04623 void
04624 SplitSurfaceTool::list_sides_debug()
04625 {
04626   if( !DEBUG_FLAG(154) )
04627     return;
04628 
04629   int i, j;
04630   RefFace *ref_face_ptr;
04631   TDSplitSurface *tdss;
04632 
04633   refFaceChain.reset();
04634   for( i=refFaceChain.size(); i--; )
04635   {
04636     ref_face_ptr = refFaceChain.get_and_step();
04637     tdss = (TDSplitSurface *)ref_face_ptr->
04638       get_TD(&TDSplitSurface::is_split_surface);
04639     
04640     PRINT_INFO( "Surface %d:\n", ref_face_ptr->id() );
04641     
04642     DLIList<CoEdge*> *side_co_edge_list;
04643     side_co_edge_list = tdss->get_a_coedges();
04644     DLIList<RefEdge*> side_ref_edge_list;
04645     side_co_edge_list->reset();
04646     for( j=side_co_edge_list->size(); j--; )
04647       side_ref_edge_list.append( side_co_edge_list->get_and_step()->get_ref_edge_ptr() );
04648     
04649     DLIList<CubitEntity*> cubit_edges;
04650     CAST_LIST(side_ref_edge_list, cubit_edges, CubitEntity);
04651     CubitUtil::list_entity_ids( "Side 0: ", 
04652       cubit_edges, 80, "\n", CUBIT_FALSE );
04653     
04654     side_co_edge_list = tdss->get_b_coedges();
04655     side_ref_edge_list.clean_out();
04656     side_co_edge_list->reset();
04657     for( j=side_co_edge_list->size(); j--; )
04658       side_ref_edge_list.append( side_co_edge_list->get_and_step()->get_ref_edge_ptr() );
04659     
04660     CAST_LIST(side_ref_edge_list, cubit_edges, CubitEntity);
04661     CubitUtil::list_entity_ids( "Side 1: ", 
04662       cubit_edges, 80, "\n", CUBIT_FALSE );
04663     
04664     side_co_edge_list = tdss->get_c_coedges();
04665     side_ref_edge_list.clean_out();
04666     side_co_edge_list->reset();
04667     for( j=side_co_edge_list->size(); j--; )
04668       side_ref_edge_list.append( side_co_edge_list->get_and_step()->get_ref_edge_ptr() );
04669     
04670     CAST_LIST(side_ref_edge_list, cubit_edges, CubitEntity);
04671     CubitUtil::list_entity_ids( "Side 2: ", 
04672       cubit_edges, 80, "\n", CUBIT_FALSE );
04673     
04674     side_co_edge_list = tdss->get_d_coedges();
04675     side_ref_edge_list.clean_out();
04676     side_co_edge_list->reset();
04677     for( j=side_co_edge_list->size(); j--; )
04678       side_ref_edge_list.append( side_co_edge_list->get_and_step()->get_ref_edge_ptr() );
04679     
04680     CAST_LIST(side_ref_edge_list, cubit_edges, CubitEntity);
04681     CubitUtil::list_entity_ids( "Side 3: ", 
04682       cubit_edges, 80, "\n", CUBIT_FALSE );
04683   }
04684 }
04685 
04686 CubitStatus
04687 SplitSurfaceTool::find_spline_curves( RefFace *ref_face_ptr, int num_segs, 
04688                                       double distance, 
04689                                       DLIList<Curve*> *curve_list_ptr,
04690                                       double tolerance,
04691                                       CubitBoolean parametric_flg,
04692                                       CubitBoolean preview_flg,
04693                                       CubitBoolean create_ref_edges_flg )
04694 {
04695   int i, j;
04696 
04697   TDSplitSurface *tdss = (TDSplitSurface *)ref_face_ptr->
04698     get_TD(&TDSplitSurface::is_split_surface);
04699 
04700   TopologyBridge* bridge = 0;
04701 //   GeometryModifyEngine* gme = 
04702   GeometryModifyTool::instance()->get_engine( ref_face_ptr, &bridge );
04703   Surface* surf_ptr = dynamic_cast<Surface*>(bridge);
04704 
04705   // Interpolate to find the spline points
04706   //
04707   //                          sideC
04708   //                        a[nr-1][i]
04709   //          _________________________________________
04710   //    (0,1)|                                         |(1,1)
04711   //         |                                         |
04712   //         |                                         |
04713   //         |                                         |
04714   //         |                                         |
04715   //         |                                         |
04716   // a[j][0] |                                         |
04717   //         |                                         | a[j][nc-1] 
04718   //  sideD  |                                         |
04719   //         | ada (row)                               | sideB
04720   //         | ^                                       |
04721   //         | |                                       |
04722   //         | | (tse,ada)                             |
04723   //         | |                                       |
04724   //         | +----->tse (column)                     |
04725   //    (0,0)|_________________________________________|(1,0)
04726   //                           a[0][i]    
04727   //                            sideA
04728   
04729   // Split direction is vertical in the above diagram.
04730   
04731   if( ref_face_ptr->is_parametric() && parametric_flg==CUBIT_TRUE )
04732   {
04733     PRINT_DEBUG_154( "Using 2D mapping to find interior points\n" );
04734     // Do the mapping in parametric space - we have found this is
04735     // more accurate (especially since we don't have the benefit of
04736     // any elemental smoothing when we are done).  However, we have
04737     // also found that occasionally, especially on conic surfaces,
04738     // the mapping will create points in the wrong space of the 
04739     // surface (i.e., on the "other side".).  For this reason we
04740     // default to 3D mapping.
04741     // Allocate a matrix of CubitVector pointers
04742     int nr = tdss->coord_list_size_b(); // number of rows
04743     int nc = num_segs+1;                // number of columns
04744     Cubit2DPoint ***coords;
04745     coords = new Cubit2DPoint **[nr];
04746     
04747     for( j=0; j<nr; j++ )
04748       coords[j] = new Cubit2DPoint *[nc];
04749     
04750     // Initialize      
04751     for( i=0; i<nr; i++ )
04752     {
04753       for( j=0; j<nc; j++ )
04754         coords[i][j] = NULL;
04755     }
04756     
04757     // Fill the boundary coordinates into coords
04758     fill_boundary_coords( tdss, nr, nc, coords );
04759     
04760     // Fill the interior coords
04761     fill_interior_coords( tdss, nr, nc, coords );
04762     
04763     // Generate the 3D vectors
04764     CubitVector vec;
04765 
04766     for( j=1; j<nc-1; j++ )
04767     {
04768       DLIList<CubitVector*> spline_points;
04769       for( i=0; i<nr; i++ )
04770       {
04771         vec = ref_face_ptr->position_from_u_v( coords[i][j]->x(), coords[i][j]->y() );
04772         spline_points.append( new CubitVector( vec ) );
04773       }
04774 
04775       // Create the curve from the vectors
04776       CubitBoolean project_curve = CUBIT_TRUE;
04777       if( preview_flg == CUBIT_TRUE && create_ref_edges_flg == CUBIT_FALSE )
04778         project_curve = CUBIT_FALSE;
04779       Curve *curve_ptr = create_curve( spline_points, surf_ptr, tolerance, 
04780                                        CUBIT_TRUE, preview_flg, project_curve );      
04781 
04782       // Free spline points
04783       while( spline_points.size() ) delete spline_points.pop();
04784       
04785       if( curve_ptr == NULL )
04786       {
04787         // Just fail if a curve can't be created
04788         PRINT_ERROR( "Unable to create curve on Surface %d\n", ref_face_ptr->id() );
04789         while( curve_list_ptr->size() ) delete curve_list_ptr->pop();
04790         return CUBIT_FAILURE;
04791       }
04792       else
04793       {
04794         curve_list_ptr->append( curve_ptr );
04795       }
04796     }
04797     
04798     // Free memory - all of the Cubit2DPoints were allocated      
04799     for( i=0; i<nr; i++ )
04800     {
04801       for( j=0; j<nc; j++ )
04802         delete coords[i][j];
04803     }
04804     
04805     // Free matrix memory
04806     for( i=0; i<nr; i++ )
04807       delete []coords[i];
04808     delete []coords;
04809     coords = NULL;
04810   }
04811   else
04812   {
04813     // Need to do the mapping in 3D space and project back to surface
04814     PRINT_DEBUG_154( "Using 3D mapping to find interior points\n" );
04815     
04816     // Allocate a matrix of CubitVector pointers
04817     int nr = tdss->coord_list_size_b(); // number of rows
04818     int nc = num_segs+1;                // number of columns
04819     CubitVector ***coords;
04820     coords = new CubitVector **[nr];
04821     
04822     for( i=0; i<nr; i++ )
04823       coords[i] = new CubitVector *[nc];
04824     
04825     // Initialize      
04826     for( i=0; i<nr; i++ )
04827     {
04828       for( j=0; j<nc; j++ )
04829         coords[i][j] = NULL;
04830     }
04831     
04832     // Fill the boundary coordinates into coords
04833     fill_boundary_coords( tdss, nr, nc, coords );
04834     
04835     // Fill the interior coords
04836     fill_interior_coords( tdss, nr, nc, coords );
04837 
04838     // Smooth the 3D points (note - don't check result - the function only gives
04839     // a warning if it fails).
04840     smooth_interior_coords( ref_face_ptr, tdss, tolerance, nr, nc, distance, coords );
04841     
04842     // Create split curves
04843     for( j=1; j<nc-1; j++ )
04844     {
04845       DLIList<CubitVector*> spline_points;
04846       for( i=0; i<nr; i++ )
04847       {
04848         ref_face_ptr->move_to_surface( *(coords[i][j]) );
04849         spline_points.append( new CubitVector( *(coords[i][j]) ) );
04850       }
04851 
04852       // Create the curve from the vectors
04853       CubitBoolean project_curve = CUBIT_TRUE;
04854       if( preview_flg == CUBIT_TRUE && create_ref_edges_flg == CUBIT_FALSE )
04855         project_curve = CUBIT_FALSE;
04856       Curve *curve_ptr = create_curve( spline_points, surf_ptr, tolerance,
04857         CUBIT_TRUE, preview_flg, project_curve ); 
04858 
04859       // Free spline points
04860       while( spline_points.size() ) delete spline_points.pop();
04861       
04862       if( curve_ptr == NULL )
04863       {
04864         // Just fail if a curve can't be created
04865         PRINT_ERROR( "Unable to create curve on Surface %d\n", ref_face_ptr->id() );
04866         while( curve_list_ptr->size() ) delete curve_list_ptr->pop();
04867         return CUBIT_FAILURE;
04868       }
04869       else
04870         curve_list_ptr->append( curve_ptr );
04871     }
04872     
04873     // Free interior points (the boundary locations were not allocated for 
04874     // the matrix)     
04875     for( i=1; i<nr-1; i++ )
04876     {
04877       for( j=1; j<nc-1; j++ )
04878         delete coords[i][j];
04879     }
04880     
04881     // Free matrix memory
04882     for( i=0; i<nr; i++ )
04883       delete []coords[i];
04884     delete []coords;
04885     coords = NULL;
04886   }
04887 
04888   return CUBIT_SUCCESS; 
04889 }
04890 
04891 CubitStatus
04892 SplitSurfaceTool::fill_boundary_coords( TDSplitSurface *tdss, int nr, 
04893                                         int nc, CubitVector ***coords )
04894 {
04895   //                                sideC
04896   //                            coords[nr-1][c]
04897   //               _________________________________________
04898   //         (0,1)|                                         |(1,1)
04899   //              |                                         |
04900   //              |                                         |
04901   //              |                                         |
04902   //              |                                         |
04903   //              |                                         |
04904   // coords[r][0] |                                         |
04905   //              |                                         | coords[r][nc-1] 
04906   //       sideD  |                                         |
04907   //              | ada (row)                               | sideB
04908   //              | ^                                       |
04909   //              | |                                       |
04910   //              | | (tse,ada)                             |
04911   //              | |                                       |
04912   //              | +----->tse (column)                     |
04913   //         (0,0)|_________________________________________|(1,0)
04914   //                            coords[0][c]    
04915   //                               sideA
04916   
04917   // Split direction is vertical in the above diagram.
04918 
04919   // Debug (with DEBUG_FLAG_154)
04920   draw_boundary_coords( tdss );
04921 
04922   int r, c;
04923 
04924   // Note: sideB and sideD contain the corner coords (sideA and sideC just 
04925   //       contain the interior coords)
04926   tdss->coord_list_reset_a();
04927   tdss->coord_list_reset_b();
04928   tdss->coord_list_last_c(); // Will need to be traversed backwards
04929   tdss->coord_list_last_d(); // Will need to be traversed backwards
04930 
04931   for( r=0; r<nr; r++ )
04932   {
04933     // Rows go up B and D (note these contain the corner coords)
04934     coords[r][0] = tdss->coord_list_get_and_back_d();
04935     coords[r][nc-1] = tdss->coord_list_get_and_step_b();
04936   }
04937 
04938   for( c=1; c<nc-1; c++ )
04939   {
04940     // Columns go up A and C (note these DO NOT contain the corner coords)
04941     coords[0][c] = tdss->coord_list_get_and_step_a();
04942     coords[nr-1][c] = tdss->coord_list_get_and_back_c();
04943   }
04944 
04945   return CUBIT_SUCCESS;
04946 }
04947 
04948 // Debug function
04949 CubitStatus
04950 SplitSurfaceTool::draw_boundary_coords( TDSplitSurface *tdss )
04951 {
04952   if( !DEBUG_FLAG(154) )
04953     return CUBIT_SUCCESS;
04954 
04955   int i;
04956   CubitVector *vec_ptr;
04957   CoEdge *co_edge_ptr;
04958   DLIList<CoEdge*> *co_edge_list_ptr;
04959   DLIList<RefEdge*> curve_list;
04960   DLIList<CubitEntity*> cubit_curves;
04961 
04962   // Note: sideB and sideD contain the corner coords (sideA and sideC just 
04963   //       contain the interior coords)
04964 
04965   PRINT_INFO( "Surface %d, Side A, %d coords, YELLOW\n", 
04966     tdss->ref_face_ptr()->id(), tdss->coord_list_size_a() );
04967   
04968   co_edge_list_ptr = tdss->get_a_coedges();
04969   co_edge_list_ptr->reset();
04970   for( i=co_edge_list_ptr->size(); i--; )
04971   {
04972     co_edge_ptr = co_edge_list_ptr->get_and_step();
04973     curve_list.append( co_edge_ptr->get_ref_edge_ptr() );
04974   }
04975   CAST_LIST(curve_list, cubit_curves, CubitEntity);
04976   CubitUtil::list_entity_ids( " Curves: ", 
04977     cubit_curves, 80, "\n", CUBIT_FALSE );
04978 
04979   tdss->coord_list_reset_a();
04980   for( i=tdss->coord_list_size_a(); i--; )
04981   {
04982     vec_ptr = tdss->coord_list_get_and_step_a();
04983     PRINT_DEBUG_100( " create vertex %f %f %f color yellow\n", vec_ptr->x(),
04984       vec_ptr->y(), vec_ptr->z() );
04985     GfxDebug::draw_point( *vec_ptr, CUBIT_YELLOW_INDEX );
04986   }
04987 
04988   PRINT_INFO( "Surface %d, Side B, %d coords, MAGENTA\n", 
04989     tdss->ref_face_ptr()->id(), tdss->coord_list_size_b() );
04990 
04991   co_edge_list_ptr = tdss->get_b_coedges();
04992   co_edge_list_ptr->reset();
04993   curve_list.clean_out();
04994   for( i=co_edge_list_ptr->size(); i--; )
04995   {
04996     co_edge_ptr = co_edge_list_ptr->get_and_step();
04997     curve_list.append( co_edge_ptr->get_ref_edge_ptr() );
04998   }
04999   cubit_curves.clean_out();
05000   CAST_LIST(curve_list, cubit_curves, CubitEntity);
05001   CubitUtil::list_entity_ids( " Curves: ", 
05002     cubit_curves, 80, "\n", CUBIT_FALSE );
05003 
05004   tdss->coord_list_reset_b();
05005   for( i=tdss->coord_list_size_b(); i--; )
05006   {
05007     vec_ptr = tdss->coord_list_get_and_step_b();
05008     PRINT_DEBUG_100( " create vertex %f %f %f color magenta\n", vec_ptr->x(),
05009       vec_ptr->y(), vec_ptr->z() );
05010     GfxDebug::draw_point( *vec_ptr, CUBIT_MAGENTA_INDEX );
05011   }
05012 
05013   PRINT_INFO( "Surface %d, Side C, %d coords, GREEN\n", 
05014     tdss->ref_face_ptr()->id(), tdss->coord_list_size_c() );
05015 
05016   co_edge_list_ptr = tdss->get_c_coedges();
05017   co_edge_list_ptr->reset();
05018   curve_list.clean_out();
05019   for( i=co_edge_list_ptr->size(); i--; )
05020   {
05021     co_edge_ptr = co_edge_list_ptr->get_and_step();
05022     curve_list.append( co_edge_ptr->get_ref_edge_ptr() );
05023   }
05024   cubit_curves.clean_out();
05025   CAST_LIST(curve_list, cubit_curves, CubitEntity);
05026   CubitUtil::list_entity_ids( " Curves: ", 
05027     cubit_curves, 80, "\n", CUBIT_FALSE );
05028 
05029   tdss->coord_list_reset_c();
05030   for( i=tdss->coord_list_size_c(); i--; )
05031   {
05032     vec_ptr = tdss->coord_list_get_and_step_c();
05033     PRINT_DEBUG_100( " create vertex %f %f %f color green\n", vec_ptr->x(),
05034       vec_ptr->y(), vec_ptr->z() );
05035     GfxDebug::draw_point( *vec_ptr, CUBIT_GREEN_INDEX );
05036   }
05037 
05038   PRINT_INFO( "Surface %d, Side D, %d coords, RED\n", 
05039     tdss->ref_face_ptr()->id(), tdss->coord_list_size_d() );
05040 
05041   co_edge_list_ptr = tdss->get_d_coedges();
05042   co_edge_list_ptr->reset();
05043   curve_list.clean_out();
05044   for( i=co_edge_list_ptr->size(); i--; )
05045   {
05046     co_edge_ptr = co_edge_list_ptr->get_and_step();
05047     curve_list.append( co_edge_ptr->get_ref_edge_ptr() );
05048   }
05049   cubit_curves.clean_out();
05050   CAST_LIST(curve_list, cubit_curves, CubitEntity);
05051   CubitUtil::list_entity_ids( " Curves: ", 
05052     cubit_curves, 80, "\n", CUBIT_FALSE );
05053 
05054   tdss->coord_list_reset_d();
05055   for( i=tdss->coord_list_size_d(); i--; )
05056   {
05057     vec_ptr = tdss->coord_list_get_and_step_d();
05058     PRINT_DEBUG_100( " create vertex %f %f %f color red\n", vec_ptr->x(),
05059       vec_ptr->y(), vec_ptr->z() );
05060     GfxDebug::draw_point( *vec_ptr, CUBIT_RED_INDEX );
05061   }
05062   
05063   GfxDebug::flush();
05064 
05065   return CUBIT_SUCCESS;
05066 }
05067 
05068 // Cloned from MapToolSupport, except MapToolSupport does not accurately
05069 // calculate ada and tse
05070 CubitStatus
05071 SplitSurfaceTool::fill_interior_coords( TDSplitSurface *tdss,
05072                                         int nr, int nc, CubitVector ***coords )
05073 {
05074   int r, c;
05075 
05076   int ada_ints = nr-1;
05077   int tse_ints = nc-1;
05078 
05079   double ada, tse;
05080 
05081   DLIList<double> tse_array;
05082   if( get_tse_array( tdss, tse_ints, tse_array ) == CUBIT_FAILURE )
05083     return CUBIT_FAILURE;
05084   
05085   // Create all the new coords in the interior of the array
05086   if( tdss )
05087   {
05088     // Initialize list position
05089 
05090     // Must use side that is not collapsed
05091     if( tdss->is_b_collapsed() && tdss->is_d_collapsed() )
05092       ; // Nothing to do
05093     else if( tdss->is_b_collapsed() == CUBIT_FALSE )
05094     {
05095       tdss->param_list_reset_b();
05096       ada = tdss->param_list_get_and_step_b();
05097     }
05098     else
05099     {
05100       // Must go backwards on this list
05101       tdss->param_list_last_d();
05102       ada = tdss->param_list_get_and_back_d();
05103     }
05104   }
05105   for( r=1; r<ada_ints; r++ )
05106   {
05107     if( tdss )
05108     {
05109       if( tdss->is_b_collapsed() && tdss->is_d_collapsed() )
05110         ada = (double)r/(double)ada_ints;
05111       else if( tdss->is_b_collapsed() )
05112         ada = tdss->param_list_get_and_back_d()/tdss->length_d();
05113       else
05114         ada = tdss->param_list_get_and_step_b()/tdss->length_b();
05115     }
05116     else
05117     {
05118       ada = (double)r/(double)ada_ints;
05119     }
05120 
05121     tse_array.reset();
05122     for( c=1; c<tse_ints; c++ )
05123     {
05124       tse = tse_array.get_and_step();
05125       
05126       // Create a new coord at the mapped location on the face
05127       coords[r][c] = make_interior_coord( coords, nr, nc, ada, tse, r, c );
05128     }  
05129   }   
05130   
05131   return CUBIT_SUCCESS;
05132 }
05133 
05134 CubitStatus
05135 SplitSurfaceTool::smooth_interior_coords( RefFace *ref_face_ptr,
05136                                           TDSplitSurface *tdss,
05137                                           double tolerance,
05138                                           int nr, int nc, double distance,
05139                                           CubitVector ***coords )
05140 {
05141   int r, c; // Row, Column
05142   CubitVector *vec_ptr;
05143 
05144   // Preserve original coordinates and restore to those if there is an error 
05145   // (just give warning).
05146   DLIList<CubitVector*> backup_coords( nr*nc );
05147   for( r=0; r<nr; r++ )
05148   {
05149     for( c=0; c<nc; c++ )
05150       backup_coords.append( new CubitVector( *coords[r][c] ) );
05151   }
05152 
05153   // Problem: after doing a 3D map, when the interior coordinates are projected
05154   // back to the surface they may not lie at the correct percentage across the
05155   // surface (thus a fillet may not be split exactly in the middle).
05156 
05157   // Solution: create spline curves on the surface (perpendicular to the split
05158   // direction) at each coordinate.  Move the coordinate to the proper fraction
05159   // distance along the spline curve.  The trick is to find the proper fraction
05160   // distance - we use a mapping concept to determine the fraction.  The real 
05161   // need for the "fraction map" is that point A and point B in the diagram
05162   // below can be at different percentages along sideA and sideC, so the 
05163   // internal fractions need to be "smoothed out".  An alternative to this
05164   // "spline" technique might be to do something like real Winslow smoothing,
05165   // but that would require a lot more work to implement...
05166 
05167   // Setup fraction "map" (actual surface split is vertical in diagram below) -
05168   // note the splines perpendicular to the split direction).
05169   //
05170   //                           sideC            A
05171   //          _________________________+________+____________
05172   //    (0,1)|                                               |(1,1)
05173   //         |                                               |
05174   //         |                                               |
05175   //         +............spline......+........+.............+ 
05176   //         |                                               |
05177   //         |                                               |
05178   //         |                                               |
05179   //         |                                               | 
05180   //  sideD  +............spline.....+........+..............+ 
05181   //         |                                               |
05182   //         | y (row)                                       | sideB (tessellations)
05183   //         | ^                                             |
05184   //         | |                                             |
05185   //         | | (x,y)                                       |
05186   //         | |                                             |
05187   //         | +----->x (column)              B              |
05188   //    (0,0)|_____________________+________ +______________ |(1,0)
05189   //
05190   //                            sideA (split locations)
05191 
05192   Cubit2DPoint ***frac_coords;
05193   frac_coords = new Cubit2DPoint **[nr];
05194   
05195   for( r=0; r<nr; r++ )
05196     frac_coords[r] = new Cubit2DPoint *[nc];
05197   
05198   // Initialize      
05199   for( r=0; r<nr; r++ )
05200   {
05201     for( c=0; c<nc; c++ )
05202       frac_coords[r][c] = NULL;
05203   }
05204     
05205   // Fill the boundary "fractions" into frac_coords
05206 
05207   frac_coords[0][0] = new Cubit2DPoint( 0.0, 0.0 );
05208   frac_coords[0][nc-1] = new Cubit2DPoint( 1.0, 0.0 );
05209   frac_coords[nr-1][0] = new Cubit2DPoint( 0.0, 1.0 );
05210   frac_coords[nr-1][nc-1] = new Cubit2DPoint( 1.0, 1.0 );
05211 
05212   // Note: sideB and sideD contain the corner coords (sideA and sideC just 
05213   //       contain the interior coord)
05214   tdss->param_list_reset_a();
05215   tdss->param_list_reset_b();
05216   tdss->param_list_get_and_step_b(); // Move off the corner
05217   tdss->param_list_last_c(); // Will need to be traversed backwards
05218   tdss->param_list_last_d(); // Will need to be traversed backwards
05219   tdss->param_list_get_and_back_d(); // Move off the corner
05220 
05221   double frac_a, frac_b, frac_c, frac_d;
05222   
05223   for( r=1; r<nr-1; r++ )
05224   {
05225     // Rows go up B and D (note these contain the corner coords)
05226     if( tdss->is_b_collapsed() && tdss->is_d_collapsed() )
05227     {
05228       frac_b = double(r)/double(nr-1);
05229       frac_d = frac_b;
05230     }
05231     else if( tdss->is_d_collapsed() )
05232     {
05233       // Use B for both sides
05234       frac_b = tdss->param_list_get_and_step_b()/tdss->length_b();
05235       frac_d = frac_b;
05236     }
05237     else if( tdss->is_b_collapsed() )
05238     {
05239       // Use D for both sides
05240       frac_d = (tdss->length_d()-tdss->param_list_get_and_back_d())/tdss->length_d();
05241       frac_b = frac_d;
05242     }
05243     else
05244     {
05245       frac_b = tdss->param_list_get_and_step_b()/tdss->length_b();
05246       frac_d = (tdss->length_d()-tdss->param_list_get_and_back_d())/tdss->length_d();
05247     }
05248 
05249     frac_coords[r][0] = new Cubit2DPoint( 0.0, frac_d );
05250     frac_coords[r][nc-1] = new Cubit2DPoint( 1.0, frac_b );
05251 
05252 //    PRINT_INFO( "frac_coords[%d][0] = %f, %f\n", r, frac_coords[r][0]->x(),
05253 //    frac_coords[r][0]->y() );
05254 //    PRINT_INFO( "frac_coords[%d][%d] = %f, %f\n", r, nc-1, frac_coords[r][nc-1]->x(),
05255 //    frac_coords[r][nc-1]->y() );
05256   }
05257 
05258   for( c=1; c<nc-1; c++ )
05259   {
05260     // Columns go up A and C (note these DO NOT contain the corner coords)
05261     if( tdss->is_a_collapsed() && tdss->is_c_collapsed() )
05262     {
05263       frac_a = double(c)/double(nc-1);
05264       frac_c = frac_a;
05265     }
05266     else if( tdss->is_a_collapsed() )
05267     {
05268       // Use C for both sides
05269       frac_c = (tdss->length_c()-tdss->param_list_get_and_back_c())/tdss->length_c();
05270       frac_a = frac_c;
05271     }
05272     else if( tdss->is_c_collapsed() )
05273     {
05274       // Use A for both sides
05275       frac_a = tdss->param_list_get_and_step_a()/tdss->length_a();
05276       frac_c = frac_a;
05277     }
05278     else
05279     {
05280       frac_a = tdss->param_list_get_and_step_a()/tdss->length_a();
05281       frac_c = (tdss->length_c()-tdss->param_list_get_and_back_c())/tdss->length_c();
05282     }
05283 
05284     frac_coords[0][c] = new Cubit2DPoint( frac_a, 0.0 );
05285     frac_coords[nr-1][c] = new Cubit2DPoint( frac_c, 1.0 );
05286 
05287 //    PRINT_INFO( "frac_coords[0][%d] = %f, %f\n", c, frac_coords[0][c]->x(), 
05288 //    frac_coords[0][c]->y() );
05289 //    PRINT_INFO( "frac_coords[%d][%d] = %f, %f\n", nr-1, c, frac_coords[nr-1][c]->x(),
05290 //    frac_coords[nr-1][c]->y() );
05291   }
05292 
05293   // Fill interior coordinates
05294   fill_interior_coords( tdss, nr, nc, frac_coords );
05295 
05296   // Now create the splines
05297 
05298   TopologyBridge* bridge = 0;
05299   GeometryModifyEngine* gme = 
05300     GeometryModifyTool::instance()->get_engine( ref_face_ptr, &bridge );
05301 //   Surface* surf_ptr = dynamic_cast<Surface*>(bridge);
05302 
05303   for( r=1; r<nr-1; r++ )
05304   {
05305     // Move interior points to surface
05306     for( c=1; c<nc-1; c++ )
05307       ref_face_ptr->move_to_surface( *(coords[r][c]) );
05308 
05309     // Make a spline across the surface
05310     DLIList<CubitVector*> spline_points;
05311     for( c=0; c<nc; c++ )
05312       spline_points.append( coords[r][c] );
05313 
05314     spline_points.reset();
05315     CubitVector *start_pnt = spline_points.get_and_back();
05316     CubitVector *end_pnt = spline_points.get();
05317 
05318     TBPoint *start_Point = gme->make_Point( *start_pnt );
05319     TBPoint *end_Point = gme->make_Point( *end_pnt );
05320     if( start_Point == NULL || end_Point == NULL )
05321     {
05322       PRINT_WARNING( "Unable to adjust split positions - split may be inaccurate\n" );
05323 
05324       // Restore ALL original points & move to surface
05325       backup_coords.reset();
05326       for( r=0; r<nr; r++ )
05327       {
05328         for( c=0; c<nc; c++ )
05329         {
05330           vec_ptr = backup_coords.get_and_step();
05331           ref_face_ptr->move_to_surface( *vec_ptr );
05332           coords[r][c]->set( *vec_ptr );
05333           delete vec_ptr;
05334         }
05335       }
05336 
05337       // Free memory
05338       if( start_Point ) start_Point->get_geometry_query_engine()->delete_solid_model_entities(start_Point);
05339       if( end_Point ) end_Point->get_geometry_query_engine()->delete_solid_model_entities(end_Point);
05340       for( r=0; r<nr; r++ )
05341       {
05342         for( c=0; c<nc; c++ )
05343           delete frac_coords[r][c];
05344       }
05345       for( r=0; r<nr; r++ )
05346         delete []frac_coords[r];
05347       delete []frac_coords;
05348       frac_coords = NULL;
05349       
05350       return CUBIT_FAILURE;
05351     }
05352 
05353     // Here, note it is not necessary to create the curve on the surface
05354     Curve *curve_ptr = gme->make_Curve( SPLINE_CURVE_TYPE, start_Point, end_Point, 
05355                                         spline_points );
05356 
05357     // Debug
05358     if( DEBUG_FLAG( 100 ) )
05359       draw_preview( curve_ptr, CUBIT_TRUE, CUBIT_RED_INDEX );
05360 
05361     if( curve_ptr == NULL )
05362     {
05363       PRINT_WARNING( "Unable to adjust split positions - split may be inaccurate\n" );
05364 
05365       // Restore ALL original points & move to surface
05366       backup_coords.reset();
05367       for( r=0; r<nr; r++ )
05368       {
05369         for( c=0; c<nc; c++ )
05370         {
05371           vec_ptr = backup_coords.get_and_step();
05372           ref_face_ptr->move_to_surface( *vec_ptr );
05373           coords[r][c]->set( *vec_ptr );
05374           delete vec_ptr;
05375         }
05376       }
05377 
05378       // Free memory
05379       for( r=0; r<nr; r++ )
05380       {
05381         for( c=0; c<nc; c++ )
05382           delete frac_coords[r][c];
05383       }
05384       for( r=0; r<nr; r++ )
05385         delete []frac_coords[r];
05386       delete []frac_coords;
05387       frac_coords = NULL;
05388       
05389       return CUBIT_FAILURE;
05390     }
05391 
05392     // Space interior points along the Curve per the original fractions
05393     spline_points.reset();
05394     spline_points.step();
05395     double curve_length = curve_ptr->measure();
05396     for ( c=1; c<nc-1; c++ )
05397     {
05398       vec_ptr = spline_points.get_and_step();
05399       
05400       // Find total length of curve and multiply by the fraction
05401       double mv_distance;
05402       if( distance == -1.0 )
05403         mv_distance = curve_length*(frac_coords[r][c]->x());
05404       else
05405         mv_distance = distance;
05406       
05407       CubitVector curve_position;
05408       if( curve_ptr->point_from_arc_length ( *start_pnt, mv_distance, curve_position )
05409         == CUBIT_FAILURE )
05410       {
05411         PRINT_WARNING( "Unable to adjust split positions - split may be inaccurate\n" );
05412 
05413         // Restore ALL original points & move to surface
05414         backup_coords.reset();
05415         for( r=0; r<nr; r++ )
05416         {
05417           for( c=0; c<nc; c++ )
05418           {
05419             vec_ptr = backup_coords.get_and_step();
05420             ref_face_ptr->move_to_surface( *vec_ptr );
05421             coords[r][c]->set( *vec_ptr );
05422             delete vec_ptr;
05423           }
05424         }
05425 
05426         // Free memory
05427         for( r=0; r<nr; r++ )
05428         {
05429           for( c=0; c<nc; c++ )
05430             delete frac_coords[r][c];
05431         }
05432         
05433         // Free matrix memory
05434         for( r=0; r<nr; r++ )
05435           delete []frac_coords[r];
05436         delete []frac_coords;
05437         frac_coords = NULL;
05438         
05439         // Free spline
05440         curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
05441         return CUBIT_FAILURE;
05442       }
05443 
05444       vec_ptr->set( curve_position );
05445     }
05446 
05447     curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
05448     //GeometryQueryTool::instance()->make_free_RefEdge(curve_ptr);
05449   }
05450 
05451   // Free memory - all of the frac_coords were allocated      
05452   for( r=0; r<nr; r++ )
05453   {
05454     for( c=0; c<nc; c++ )
05455       delete frac_coords[r][c];
05456   }
05457   
05458   // Free matrix memory
05459   for( r=0; r<nr; r++ )
05460     delete []frac_coords[r];
05461   delete []frac_coords;
05462   frac_coords = NULL;
05463   
05464   // Free backup coords
05465   while( backup_coords.size() )
05466     delete backup_coords.pop();
05467 
05468   return CUBIT_SUCCESS;
05469 }
05470 
05471 CubitVector*
05472 SplitSurfaceTool::make_interior_coord( CubitVector ***coords, 
05473                                        int nr, int nc,
05474                                        double ada, double tse,
05475                                        int r, int c )
05476 {
05477   double temp_x, temp_y, temp_z;
05478   CubitVector *vec;
05479   int ada_ints = nr-1;
05480   int tse_ints = nc-1;
05481 
05482   temp_x =   (1.0 - ada)*coords[0][c]->x()
05483           + ada*coords[ada_ints][c]->x()
05484           + (1.0 - tse)*coords[r][0]->x()
05485           + tse*coords[r][tse_ints]->x()
05486           - (1.0 - tse)*(1.0 - ada)*coords[0][0]->x()
05487           - (1.0 - tse)*ada*coords[ada_ints][0]->x()
05488           - tse*(1.0 - ada)*coords[0][tse_ints]->x()
05489           - tse*ada*coords[ada_ints][tse_ints]->x();
05490 
05491   temp_y =   (1.0 - ada)*coords[0][c]->y() 
05492           + ada*coords[ada_ints][c]->y()
05493           + (1.0 - tse)*coords[r][0]->y() 
05494           + tse*coords[r][tse_ints]->y()
05495           - (1.0 - tse)*(1.0 - ada)*coords[0][0]->y()
05496           - (1.0 - tse)*ada*coords[ada_ints][0]->y()
05497           - tse*(1.0 - ada)*coords[0][tse_ints]->y()
05498           - tse*ada*coords[ada_ints][tse_ints]->y();
05499 
05500   temp_z =   (1.0 - ada)*coords[0][c]->z() 
05501           + ada*coords[ada_ints][c]->z()
05502           + (1.0 - tse)*coords[r][0]->z() 
05503           + tse*coords[r][tse_ints]->z()
05504           - (1.0 - tse)*(1.0 - ada)*coords[0][0]->z()
05505           - (1.0 - tse)*ada*coords[ada_ints][0]->z()
05506           - tse*(1.0 - ada)*coords[0][tse_ints]->z()
05507           - tse*ada*coords[ada_ints][tse_ints]->z();
05508 
05509   vec = new CubitVector( temp_x, temp_y, temp_z );
05510 
05511   return vec;
05512 }
05513 
05514 CubitStatus
05515 SplitSurfaceTool::fill_boundary_coords( TDSplitSurface *tdss, int nr, 
05516                                         int nc, Cubit2DPoint ***coords )
05517 {
05518   //                                sideC
05519   //                            coords[nr-1][c]
05520   //               _________________________________________
05521   //         (0,1)|                                         |(1,1)
05522   //              |                                         |
05523   //              |                                         |
05524   //              |                                         |
05525   //              |                                         |
05526   //              |                                         |
05527   // coords[r][0] |                                         |
05528   //              |                                         | coords[r][nc-1] 
05529   //       sideD  |                                         |
05530   //              | ada (row)                               | sideB
05531   //              | ^                                       |
05532   //              | |                                       |
05533   //              | | (tse,ada)                             |
05534   //              | |                                       |
05535   //              | +----->tse (column)                     |
05536   //         (0,0)|_________________________________________|(1,0)
05537   //                            coords[0][c]    
05538   //                               sideA
05539   
05540   // Split direction is vertical in the above diagram.
05541 
05542   // Debug (with DEBUG_FLAG_154)
05543   draw_boundary_coords( tdss );
05544 
05545   int r, c;
05546   RefFace *ref_face_ptr = tdss->ref_face_ptr();
05547 
05548   // Note: sideB and sideD contain the corner coords (sideA and sideC just 
05549   //       contain the interior coords)
05550   tdss->coord_list_reset_a();
05551   tdss->coord_list_reset_b();
05552   tdss->coord_list_last_c(); // Will need to be traversed backwards
05553   tdss->coord_list_last_d(); // Will need to be traversed backwards
05554 
05555   for( r=0; r<nr; r++ )
05556   {
05557     // Rows go up B and D (note these contain the corner coords)
05558     coords[r][0] = get_uv_point( ref_face_ptr, tdss->coord_list_get_and_back_d() );
05559     coords[r][nc-1] = get_uv_point( ref_face_ptr, tdss->coord_list_get_and_step_b() );
05560   }
05561 
05562   for( c=1; c<nc-1; c++ )
05563   {
05564     // Columns go up A and C (note these DO NOT contain the corner coords)
05565     coords[0][c] = get_uv_point( ref_face_ptr, tdss->coord_list_get_and_step_a() );
05566     coords[nr-1][c] = get_uv_point( ref_face_ptr, tdss->coord_list_get_and_back_c() );
05567   }
05568 
05569   return CUBIT_SUCCESS;
05570 }
05571 
05572 Cubit2DPoint *
05573 SplitSurfaceTool::get_uv_point( RefFace *ref_face_ptr, CubitVector *vec_ptr )
05574 {
05575   double u, v;
05576   ref_face_ptr->u_v_from_position( *vec_ptr, u, v );
05577   return( new Cubit2DPoint( u, v ) );
05578 }
05579 
05580 // Cloned from MapToolSupport, except MapToolSupport does not accurately
05581 // calculate ada and tse
05582 CubitStatus
05583 SplitSurfaceTool::fill_interior_coords( TDSplitSurface *tdss,
05584                                         int nr, int nc, Cubit2DPoint ***coords )
05585 {
05586   int r, c;
05587 
05588   int ada_ints = nr-1;
05589   int tse_ints = nc-1;
05590 
05591   double ada, tse;
05592 
05593   DLIList<double> tse_array;
05594   if( get_tse_array( tdss, tse_ints, tse_array ) == CUBIT_FAILURE )
05595     return CUBIT_FAILURE;
05596   
05597   // Create all the new coords in the interior of the array
05598   if( tdss )
05599   {
05600     // Initialize list position
05601 
05602     // Must use side that is not collapsed
05603     if( tdss->is_b_collapsed() && tdss->is_d_collapsed() )
05604       ; // Nothing to do
05605     else if( tdss->is_b_collapsed() == CUBIT_FALSE )
05606     {
05607       tdss->param_list_reset_b();
05608       ada = tdss->param_list_get_and_step_b();
05609     }
05610     else
05611     {
05612       // Must go backwards on this list
05613       tdss->param_list_last_d();
05614       ada = tdss->param_list_get_and_back_d();
05615     }
05616   }
05617   for( r=1; r<ada_ints; r++ )
05618   {
05619     if( tdss )
05620     {
05621       if( tdss->is_b_collapsed() && tdss->is_d_collapsed() )
05622         ada = (double)r/(double)ada_ints;
05623       else if( tdss->is_b_collapsed() )
05624         ada = tdss->param_list_get_and_back_d()/tdss->length_d();
05625       else
05626         ada = tdss->param_list_get_and_step_b()/tdss->length_b();
05627     }
05628     else
05629     {
05630       ada = (double)r/(double)ada_ints;
05631     }
05632 
05633     tse_array.reset();
05634     for( c=1; c<tse_ints; c++ )
05635     {
05636       tse = tse_array.get_and_step();
05637       
05638       // Create a new coord at the mapped location on the face
05639       coords[r][c] = make_interior_coord( coords, nr, nc, ada, tse, r, c );
05640     }  
05641   }   
05642   
05643   return CUBIT_SUCCESS;
05644 }
05645 
05646 CubitStatus
05647 SplitSurfaceTool::get_tse_array( TDSplitSurface *tdss, int tse_ints,
05648                                  DLIList<double> &tse_array )
05649 {
05650   int c;
05651   double tse;
05652 
05653   tdss->param_list_reset_a();
05654   tdss->param_list_last_c();
05655 
05656   for( c = 1; c < tse_ints; c++ )
05657   {
05658     if( tdss )
05659     {
05660       if( tdss->is_a_collapsed() && tdss->is_c_collapsed() )
05661       {
05662         tse = (double)c/(double)tse_ints;
05663       }
05664       else if( tdss->is_a_collapsed() )
05665       {
05666         // Just use C (go backwards on side C)
05667         tse =  tdss->param_list_get_and_back_c()/tdss->length_c();
05668       }
05669       else if( tdss->is_c_collapsed() )
05670       {
05671         // Just use A
05672         tse = tdss->param_list_get_and_step_a()/tdss->length_a();
05673       }
05674       else
05675       {
05676         // Take average fractional location across the surface
05677         tse = (tdss->param_list_get_and_step_a()/tdss->length_a() + 1.0 - 
05678           tdss->param_list_get_and_back_c()/tdss->length_c())/2.0;
05679       }      
05680     }
05681     else
05682     {
05683       tse = (double)c/(double)tse_ints;
05684     }
05685     
05686     tse_array.append( tse );
05687 
05688   }
05689 
05690   return CUBIT_SUCCESS;
05691 }
05692 
05693 Cubit2DPoint*
05694 SplitSurfaceTool::make_interior_coord( Cubit2DPoint ***coords, 
05695                                        int nr, int nc,
05696                                        double ada, double tse,
05697                                        int r, int c )
05698 {
05699   double temp_x, temp_y;
05700   Cubit2DPoint *pnt;
05701   int ada_ints = nr-1;
05702   int tse_ints = nc-1;
05703 
05704   temp_x =   (1.0 - ada)*coords[0][c]->x()
05705           + ada*coords[ada_ints][c]->x()
05706           + (1.0 - tse)*coords[r][0]->x()
05707           + tse*coords[r][tse_ints]->x()
05708           - (1.0 - tse)*(1.0 - ada)*coords[0][0]->x()
05709           - (1.0 - tse)*ada*coords[ada_ints][0]->x()
05710           - tse*(1.0 - ada)*coords[0][tse_ints]->x()
05711           - tse*ada*coords[ada_ints][tse_ints]->x();
05712 
05713   temp_y =   (1.0 - ada)*coords[0][c]->y() 
05714           + ada*coords[ada_ints][c]->y()
05715           + (1.0 - tse)*coords[r][0]->y() 
05716           + tse*coords[r][tse_ints]->y()
05717           - (1.0 - tse)*(1.0 - ada)*coords[0][0]->y()
05718           - (1.0 - tse)*ada*coords[ada_ints][0]->y()
05719           - tse*(1.0 - ada)*coords[0][tse_ints]->y()
05720           - tse*ada*coords[ada_ints][tse_ints]->y();
05721 
05722   pnt = new Cubit2DPoint( temp_x, temp_y );
05723 
05724   return pnt;
05725 }
05726 
05727 CubitStatus
05728 SplitSurfaceTool::draw_preview( DLIList<Curve*> &curve_list, int color )
05729 {
05730   int i;
05731   Curve *curve_ptr;
05732   curve_list.reset();
05733 
05734   for( i=curve_list.size(); i--; )
05735   {
05736     curve_ptr = curve_list.get_and_step();
05737     draw_preview( curve_ptr, CUBIT_FALSE, color );
05738   }
05739 
05740   GfxPreview::flush();
05741 
05742   return CUBIT_SUCCESS;
05743 }
05744 
05745 CubitStatus
05746 SplitSurfaceTool::draw_preview( Curve *curve_ptr, CubitBoolean flush,
05747                                 int color )
05748 {
05749   CubitStatus result;
05750   GMem g_mem;
05751   
05752   // get the graphics 
05753   result = curve_ptr->get_geometry_query_engine()->
05754     get_graphics( curve_ptr, &g_mem );
05755   
05756   if (result==CUBIT_FAILURE || g_mem.pointListCount == 0)
05757   {
05758     PRINT_WARNING("Unable to preview a curve\n" );
05759   }
05760   
05761   // Draw the polyline
05762   GfxPreview::draw_polyline( g_mem.point_list(), g_mem.pointListCount, color );
05763   if( flush )
05764     GfxPreview::flush();
05765 
05766   return CUBIT_SUCCESS;
05767 }
05768 
05769 CubitStatus
05770 SplitSurfaceTool::create_ref_edges( DLIList<Curve*> &curve_list,
05771                                     DLIList<RefEdge*> &ref_edge_list )
05772 {
05773   int i;
05774   Curve *curve_ptr;
05775   RefEdge *ref_edge_ptr;
05776   curve_list.reset();  
05777   for( i=curve_list.size(); i--; )
05778   {
05779     curve_ptr = curve_list.get_and_step();
05780     ref_edge_ptr = GeometryQueryTool::instance()->make_free_RefEdge(curve_ptr);
05781     if( ref_edge_ptr ) ref_edge_list.append( ref_edge_ptr );
05782   }
05783   return CUBIT_SUCCESS;
05784 }
05785 
05786 int
05787 SplitSurfaceTool::number_coedges( RefEdge *ref_edge_ptr, RefFace *ref_face_ptr )
05788 {
05789   DLIList<CoEdge*> co_edge_list;
05790   ref_edge_ptr->get_co_edges( co_edge_list, ref_face_ptr );
05791   return co_edge_list.size();
05792 }
05793 
05794 Curve *
05795 SplitSurfaceTool::create_curve( DLIList<CubitVector*> &vec_list,
05796                                 Surface *surf_ptr,
05797                                 double tolerance,
05798                                 CubitBoolean iterate,
05799                                 CubitBoolean draw_pnts,
05800                                 CubitBoolean project_curve )
05801 {
05802   Curve *curve_ptr = NULL;
05803 
05804   if( vec_list.size() < 2 )
05805   {
05806     PRINT_ERROR( "Unable to create a curve from less than two locations.\n" );
05807     return NULL;
05808   }
05809 
05810   GeometryModifyEngine* gme = 
05811     GeometryModifyTool::instance()->get_engine( surf_ptr );
05812 
05813   if (NULL == gme)
05814   {
05815     PRINT_ERROR("No geometry modify engine available.  Unable to create split curve.\n");
05816     return NULL;
05817   }
05818 
05819   GeometryQueryEngine* gqe = surf_ptr->get_geometry_query_engine();
05820   // Note the user can set the following value through
05821   //  set geometry accuracy <val>
05822   double resabs = gqe->get_sme_resabs_tolerance();
05823 
05824   // Find start and end locations
05825   vec_list.reset();
05826   CubitVector *start_pnt = vec_list.get_and_back();
05827   CubitVector *end_pnt = vec_list.get();
05828   
05829   // Check to see if a simple straight line should be created.  Use 1/2 the
05830   // tolerance because points can deviate on either side of the straight line
05831   // (unless tolerance is resabs - then just use it).
05832   if( check_points_straight( surf_ptr, vec_list, 
05833                              tolerance==resabs ? resabs : 0.5*tolerance  ) )
05834   {
05835     // Create a straight line on the surface
05836     TBPoint *start_Point = gme->make_Point( *start_pnt );
05837     TBPoint *end_Point = gme->make_Point( *end_pnt );
05838     if( start_Point == NULL || end_Point == NULL )
05839     {
05840       if( start_Point ) start_Point->get_geometry_query_engine()->delete_solid_model_entities(start_Point);
05841       if( end_Point ) end_Point->get_geometry_query_engine()->delete_solid_model_entities(end_Point);
05842       return NULL;
05843     }
05844     curve_ptr = gme->make_Curve( start_Point, end_Point, surf_ptr );
05845     if( draw_pnts == CUBIT_TRUE )
05846     {
05847       // Drawing here is a bit of a hack but it saves storing the point
05848       // list
05849       draw_point( *start_pnt, CUBIT_BLUE_INDEX );
05850       draw_point( *end_pnt, CUBIT_BLUE_INDEX );
05851     }
05852 
05853     // Free memory
05854    // start_Point->get_geometry_query_engine()->delete_solid_model_entities(start_Point );
05855   //  end_Point->get_geometry_query_engine()->delete_solid_model_entities(end_Point );
05856 
05857     return curve_ptr;
05858   }
05859 
05860   // Check to see if an arc should be created.  Use 1/2 the tolerance because 
05861   // points can deviate on either side of the arc (unless tolerance is resabs -
05862   // then just use resabs).
05863   if( (curve_ptr = check_points_arc( surf_ptr, gme, vec_list, resabs, 
05864                                     tolerance==resabs ? resabs : 0.5*tolerance ) ) != NULL )
05865   {
05866     if( draw_pnts == CUBIT_TRUE )
05867     {
05868       // Drawing here is a bit of a hack but it saves storing the point
05869       // lists
05870       draw_point( *start_pnt, CUBIT_BLUE_INDEX );
05871       draw_point( *end_pnt, CUBIT_BLUE_INDEX );
05872     }
05873     return curve_ptr;
05874   }
05875 
05876   // Ok - its not a straight line or arc, so create a spline
05877 
05878   // Copy the vectors since we are going to add to the list
05879   DLIList<CubitVector*> spline_points;
05880   int i;
05881   vec_list.reset();
05882   for( i=vec_list.size(); i--; )
05883     spline_points.append( new CubitVector(*vec_list.get_and_step()) );
05884 
05885   int times_through_loop = 0;
05886   int done = 0;
05887   while( !done )
05888   {
05889     times_through_loop++;
05890 
05891     // Create a spline.  Do not create on the surface since that can be
05892     // computationally expensive and we are going to iterate.  Later we
05893     // will project the final result to the surface.  Note: the preceeding
05894     // statement is not true - the gme->make_Curve function would not 
05895     // actually create the curve on the surface - it only projects the 
05896     // points to the surface then makes a free spline - this is puzzling.
05897     TBPoint *start_Point = gme->make_Point( *start_pnt );
05898     TBPoint *end_Point = gme->make_Point( *end_pnt );
05899     if( start_Point == NULL || end_Point == NULL )
05900     {
05901       while( spline_points.size() ) delete spline_points.pop();
05902       if( start_Point ) start_Point->get_geometry_query_engine()->delete_solid_model_entities(start_Point);
05903       if( end_Point ) end_Point->get_geometry_query_engine()->delete_solid_model_entities(end_Point);
05904       return NULL;
05905     }
05906 
05907     if( spline_points.size() == 2 )
05908       curve_ptr = gme->make_Curve( STRAIGHT_CURVE_TYPE, start_Point, end_Point, NULL );
05909     else
05910       curve_ptr = gme->make_Curve( SPLINE_CURVE_TYPE, start_Point, end_Point, 
05911                                  spline_points );
05912 
05913     if( curve_ptr == NULL )
05914     {
05915       while( spline_points.size() ) delete spline_points.pop();
05916       start_Point->get_geometry_query_engine()->delete_solid_model_entities(start_Point);
05917       end_Point->get_geometry_query_engine()->delete_solid_model_entities(end_Point);
05918       return NULL;
05919     }
05920 
05921     if( iterate == CUBIT_FALSE )
05922       break;
05923     
05924     // Check to see if spline is close enough
05925     CubitVector *start_vec_ptr, *end_vec_ptr;
05926     spline_points.reset();
05927     CubitVector mid_vec;
05928     double dist;
05929     int insert_num = 0;
05930     for( i=spline_points.size()-1; i--; )
05931     {
05932       start_vec_ptr = spline_points.get_and_step();
05933       end_vec_ptr = spline_points.get();
05934       mid_vec = (*start_vec_ptr + *end_vec_ptr)/2.0;
05935       
05936       // Check distance from mid_vec to Curve
05937       CubitVector mid_vec_crv;
05938       curve_ptr->closest_point( mid_vec, mid_vec_crv );
05939       
05940       double x2 = mid_vec.x()-mid_vec_crv.x();
05941       x2 = x2*x2;
05942       double y2 = mid_vec.y()-mid_vec_crv.y();
05943       y2 = y2*y2;
05944       double z2 = mid_vec.z()-mid_vec_crv.z();
05945       z2 = z2*z2;
05946       
05947       dist = sqrt( x2+y2+z2 );
05948       
05949       if( dist > tolerance )
05950       {
05951         // Insert the midpoint location into the list
05952         spline_points.back();
05953         spline_points.insert( new CubitVector( mid_vec ) );
05954         insert_num++;
05955       }
05956       
05957     }
05958 
05959     if( insert_num == 0 )
05960       done++;
05961 
05962     if( times_through_loop > 100 )
05963     {
05964       PRINT_WARNING( "Unable to closely approximate spline\n" );
05965       done++;
05966     }
05967 
05968     if( !done )
05969     {
05970        curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
05971     }
05972     
05973     if( insert_num > 0 ) {
05974       PRINT_DEBUG_154( "Inserted %d points when creating spline\n", insert_num );
05975     }
05976   }
05977 
05978   // Project the spline to the surface (if the surface is not planar)
05979   DLIList<Surface*> surf_list;
05980   surf_list.append( surf_ptr );
05981   DLIList<Curve*> curve_list;
05982   curve_list.append( curve_ptr );
05983   DLIList<Curve*> curve_list_new;
05984 
05985   if( gme->project_edges( surf_list, curve_list, curve_list_new ) == CUBIT_FAILURE )
05986   {
05987     PRINT_WARNING( "Unable to project curve to surface - split may fail\n" );
05988   }
05989   else
05990   {
05991       curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
05992       curve_ptr = curve_list_new.get();
05993   }
05994 
05995   if( curve_ptr && draw_pnts == CUBIT_TRUE )
05996   {
05997     // Drawing here is a bit of a hack but it saves storing the point
05998     // lists
05999     draw_points( spline_points, CUBIT_BLUE_INDEX, CUBIT_FALSE );
06000   }
06001 
06002   // Free memory
06003   while( spline_points.size() ) delete spline_points.pop();
06004 
06005   return curve_ptr;
06006 }
06007 
06008 CubitBoolean
06009 SplitSurfaceTool::check_points_straight( Surface *surf_ptr,
06010                                          DLIList<CubitVector*> &point_list,
06011                                          double tolerance )
06012 {
06013   GeometryType geom_type = surf_ptr->geometry_type();
06014 
06015   // Get start and end point
06016   point_list.reset();
06017   CubitVector start_pnt( *point_list.get_and_back() );
06018   CubitVector end_pnt( *point_list.get() );
06019 
06020   // If 2 or 3 points, check points along a straight line to make sure they
06021   // lie on the surface.  If we only have 2 points and we meet this criteria
06022   // we are done.
06023   if( point_list.size() < 4 )
06024   {
06025     if( point_list.size()==2 && geom_type == PLANE_SURFACE_TYPE )
06026       return CUBIT_TRUE;
06027 
06028     // Check several points on the straight line - see if on surface
06029 
06030     CubitVector check_pnt;
06031     check_pnt.set( start_pnt.x() + .25 * (end_pnt.x() - start_pnt.x()),
06032                    start_pnt.y() + .25 * (end_pnt.y() - start_pnt.y()),
06033                    start_pnt.z() + .25 * (end_pnt.z() - start_pnt.z()) );
06034     if( is_point_on_surface( surf_ptr, check_pnt, GEOMETRY_RESABS ) == CUBIT_FALSE ) 
06035       return CUBIT_FALSE;
06036 
06037     check_pnt.set( start_pnt.x() + .5 * (end_pnt.x() - start_pnt.x()),
06038                    start_pnt.y() + .5 * (end_pnt.y() - start_pnt.y()),
06039                    start_pnt.z() + .5 * (end_pnt.z() - start_pnt.z()) );
06040     if( is_point_on_surface( surf_ptr, check_pnt, GEOMETRY_RESABS ) == CUBIT_FALSE )
06041       return CUBIT_FALSE;
06042 
06043     check_pnt.set( start_pnt.x() + .75 * (end_pnt.x() - start_pnt.x()),
06044                    start_pnt.y() + .75 * (end_pnt.y() - start_pnt.y()),
06045                    start_pnt.z() + .75 * (end_pnt.z() - start_pnt.z()) );
06046     if( is_point_on_surface( surf_ptr, check_pnt, GEOMETRY_RESABS ) == CUBIT_FALSE )
06047       return CUBIT_FALSE;
06048 
06049     if( point_list.size() == 2 )
06050       return CUBIT_TRUE;
06051   }
06052 
06053   // Get vector along the line
06054   CubitVector ln_vec = end_pnt - start_pnt;
06055   ln_vec.normalize();
06056   
06057   int i;
06058   point_list.reset();
06059   point_list.step();
06060   for( i=point_list.size()-2; i--; )
06061   {
06062     CubitVector *pnt = point_list.get_and_step();
06063     
06064     // Get vector from point to line origin
06065     CubitVector vec = *pnt - start_pnt;
06066     
06067     // Calculate distance from point to origin
06068     double distpnt_orig = vec.length();
06069     
06070     // Take dot product of vec & unit vector to get distance to intersection 
06071     // along the line
06072     double dot = fabs( vec % ln_vec );
06073     
06074     // Calculate distance from point to line w/sqrt (use fabs to account for
06075     // tiny roundoff error that could result in a negative number)
06076     double distance = sqrt(fabs(distpnt_orig*distpnt_orig - dot*dot));
06077     
06078     if( distance > tolerance )
06079       return CUBIT_FALSE;
06080     
06081     if( geom_type != PLANE_SURFACE_TYPE )
06082     {      
06083       // Find the actual intersection point and determine if it is within
06084       // GEOMETRY_RESABS of the surface
06085       
06086       // Travel along the line to get the intersection point
06087       CubitVector int_pnt;
06088       start_pnt.next_point( ln_vec, dot, int_pnt );
06089       
06090       // Find the closest point on the surface
06091       CubitVector closest_loc_on_surf;
06092       if( surf_ptr->closest_point( int_pnt, &closest_loc_on_surf ) == CUBIT_FAILURE )
06093       {
06094         return CUBIT_FALSE;
06095       }
06096       
06097       // Find the distance between these two points
06098       double dist = int_pnt.distance_between( closest_loc_on_surf );
06099       if( dist > GEOMETRY_RESABS )
06100           return CUBIT_FALSE;
06101       }
06102     }
06103 
06104   return CUBIT_TRUE;
06105 }
06106 
06107 Curve *
06108 SplitSurfaceTool:: check_points_arc( Surface *surf_ptr,
06109                                      GeometryModifyEngine *gme,
06110                                      DLIList<CubitVector*> &point_list,
06111                                      double resabs,
06112                                      double tolerance )
06113 {
06114   if( point_list.size() < 2 )
06115     return 0;
06116 
06117   point_list.reset();
06118   CubitVector start_pnt( *point_list.get_and_back() );
06119   CubitVector end_pnt( *point_list.get() );
06120 
06121   if( point_list.size() == 2 )
06122     return create_arc_two( gme, surf_ptr, start_pnt, end_pnt, resabs,
06123                            tolerance );
06124 
06125   // Get a mid point location
06126   CubitVector mid_pnt;
06127   int mid = point_list.size()/2;
06128   point_list.reset();
06129   point_list.step( mid );
06130   mid_pnt = *point_list.get();
06131 
06132   // Check if 3 points are colinear
06133   double a = (start_pnt-mid_pnt).length();
06134   double b = (mid_pnt-end_pnt).length();
06135   double c = (end_pnt-start_pnt).length();
06136   
06137   double denom = sqrt((a+b+c)*(b+c-a)*(c+a-b)*(a+b-c));
06138   if( denom < GEOMETRY_RESABS )
06139     return 0;
06140 
06141   // Special case if 3 points
06142   if( point_list.size() == 3 )
06143     return create_arc_three( gme, surf_ptr, start_pnt, mid_pnt, end_pnt, resabs );
06144 
06145   // Get a potentially more accurate arc mid_pnt
06146   get_arc_mid_pnt( surf_ptr, start_pnt, end_pnt, mid_pnt, tolerance );
06147 
06148   // Create an actual arc and do some comparisons
06149   double deviation;
06150   Curve *curve_ptr = check_if_arc( gme, surf_ptr, point_list, start_pnt,
06151                                    mid_pnt, end_pnt, resabs, tolerance, deviation );
06152 
06153   if( curve_ptr )
06154     return curve_ptr;
06155 
06156   // Try harder to find an arc - use each point as the center point
06157   int i;
06158   point_list.reset();
06159   point_list.step();
06160   CubitVector *mid_pnt_ptr;
06161   for( i=point_list.size()-2; i--; )
06162   {
06163     mid_pnt_ptr = point_list.get_and_step();
06164 
06165     curve_ptr = check_if_arc( gme, surf_ptr, point_list, start_pnt,
06166                               *mid_pnt_ptr, end_pnt, resabs, tolerance,
06167                               deviation );
06168 
06169     if( curve_ptr )
06170       return curve_ptr;
06171 
06172     if( deviation > tolerance )
06173     {
06174       return 0;
06175     }
06176   }
06177 
06178   return 0;
06179 }
06180 
06181 CubitStatus
06182 SplitSurfaceTool::get_arc_mid_pnt( Surface *surf_ptr,
06183                                    CubitVector &start_pnt,
06184                                    CubitVector &end_pnt,
06185                                    CubitVector &mid_pnt,
06186                                    double tolerance )
06187 {
06188   // Possible Surface types.
06189   //  CONE_SURFACE_TYPE
06190   //  PLANE_SURFACE_TYPE
06191   //  SPHERE_SURFACE_TYPE
06192   //  SPLINE_SURFACE_TYPE
06193   //  TORUS_SURFACE_TYPE
06194   //  BEST_FIT_SURFACE_TYPE
06195   //  FACET_SURFACE_TYPE
06196   //  UNDEFINED_SURFACE_TYPE
06197   GeometryType geom_type = surf_ptr->geometry_type();
06198 
06199   // If surface is a cone, sphere or torus, we will *try* to get a more accurate
06200   // mid point location.  This can often result in a better arc.
06201   if( (geom_type == CONE_SURFACE_TYPE || 
06202       geom_type == SPHERE_SURFACE_TYPE ||
06203       geom_type == TORUS_SURFACE_TYPE) &&
06204       surf_ptr->is_parametric() )
06205   {
06206     // Determine if arc traverses approximately along the uv space of the surface
06207     // Using the surface uv space to create the arc should be the most accurate
06208     // method of creating the arc.
06209 
06210     double start_u, start_v;
06211     if( surf_ptr->u_v_from_position ( start_pnt, start_u, start_v )
06212       == CUBIT_FAILURE )
06213       return CUBIT_FAILURE;
06214     
06215     double end_u, end_v;
06216     if( surf_ptr->u_v_from_position ( end_pnt, end_u, end_v )
06217       == CUBIT_FAILURE )
06218       return CUBIT_FAILURE;
06219     
06220     // Use average.  Note this could go to the opposite side of the surface
06221     // - I'm not sure how to handle this other than checking the resultant 
06222     // point and flipping to the other side if it is off.
06223     double mid_u, mid_v;
06224     mid_u = (start_u+end_u)/2.0;
06225     mid_v = (start_v+end_v)/2.0;
06226 
06227     CubitVector new_mid_pnt = surf_ptr->position_from_u_v( mid_u, mid_v );
06228 
06229     CubitPointContainment pnt_on_flg;
06230     pnt_on_flg = surf_ptr->point_containment( mid_u, mid_v );
06231     if( pnt_on_flg == CUBIT_PNT_OUTSIDE ||
06232         pnt_on_flg == CUBIT_PNT_UNKNOWN )
06233     {
06234       CubitVector mid_pnt_ref;
06235 
06236       if( reflect_arc_pnt( start_pnt, new_mid_pnt, end_pnt, new_mid_pnt, mid_pnt_ref ) ==
06237         CUBIT_SUCCESS )
06238       {
06239         // Make sure the point is on the surface
06240         CubitVector mid_pnt_ref_on;
06241         surf_ptr->closest_point( mid_pnt_ref, &mid_pnt_ref_on );
06242         if( mid_pnt_ref.distance_between( mid_pnt_ref_on ) < tolerance )
06243         {
06244           pnt_on_flg = surf_ptr->point_containment( mid_pnt_ref );
06245           if( pnt_on_flg == CUBIT_PNT_INSIDE ||
06246               pnt_on_flg == CUBIT_PNT_BOUNDARY )
06247           {
06248             mid_pnt = mid_pnt_ref_on;
06249             return CUBIT_SUCCESS;
06250           }
06251         }
06252       }
06253     }
06254     else
06255     {
06256       mid_pnt = new_mid_pnt;
06257       return CUBIT_SUCCESS;
06258     }
06259   }
06260 
06261   return CUBIT_FAILURE;
06262 }
06263 
06264 Curve*
06265 SplitSurfaceTool::create_arc_two( GeometryModifyEngine *gme,
06266                                   Surface *surf_ptr,
06267                                   CubitVector &start_pnt,
06268                                   CubitVector &end_pnt,
06269                                   double resabs,
06270                                   double tolerance )
06271 {
06272   CubitVector mid_pnt;
06273   if( get_arc_mid_pnt( surf_ptr, start_pnt, end_pnt, mid_pnt, tolerance )
06274     == CUBIT_FAILURE )
06275     return 0;
06276 
06277   // Check if 3 points are colinear
06278   double a = (start_pnt-mid_pnt).length();
06279   double b = (mid_pnt-end_pnt).length();
06280   double c = (end_pnt-start_pnt).length();
06281   
06282   double denom = sqrt((a+b+c)*(b+c-a)*(c+a-b)*(a+b-c));
06283   if( denom < GEOMETRY_RESABS )
06284     return 0;
06285 
06286   TBPoint *start_Point = gme->make_Point( start_pnt );
06287   TBPoint *end_Point = gme->make_Point( end_pnt );
06288   TBPoint *mid_Point = gme->make_Point( mid_pnt );
06289   if( start_Point == NULL || mid_Point == NULL || end_Point == NULL )
06290   {
06291     if( start_Point ) start_Point->get_geometry_query_engine()->delete_solid_model_entities(start_Point);
06292     if( mid_Point ) mid_Point->get_geometry_query_engine()->delete_solid_model_entities(mid_Point);
06293     if( end_Point ) end_Point->get_geometry_query_engine()->delete_solid_model_entities(end_Point);
06294     return 0;
06295   }
06296 
06297   // Create a 3-pt arc with the GeometryModifyEngine
06298   Curve *curve_ptr = gme->create_arc_three( start_Point, 
06299                                             mid_Point,
06300                                             end_Point );
06301 
06302   if( mid_Point ) mid_Point->get_geometry_query_engine()->delete_solid_model_entities(mid_Point);
06303 
06304   if( !curve_ptr )
06305   {
06306     if( start_Point ) start_Point->get_geometry_query_engine()->delete_solid_model_entities(start_Point);
06307     if( end_Point ) end_Point->get_geometry_query_engine()->delete_solid_model_entities(end_Point);
06308     return 0;
06309   }
06310 
06311   // Check 1/4 and 3/4 location - make sure on surface
06312   CubitVector check_loc;
06313   if( curve_ptr->position_from_fraction( .25, check_loc ) == CUBIT_FAILURE )
06314   {
06315     curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
06316     return 0;
06317   }
06318 
06319   // Now make sure within GEOMETRY_RESABS to the surface
06320   if( is_point_on_surface( surf_ptr, check_loc, resabs ) == CUBIT_FALSE )
06321   {
06322     curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
06323     return 0;
06324   }
06325 
06326   if( curve_ptr->position_from_fraction( .75, check_loc ) == CUBIT_FAILURE )
06327   {
06328     curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
06329     return 0;
06330   }
06331 
06332   // Now make sure within GEOMETRY_RESABS to the surface
06333   if( is_point_on_surface( surf_ptr, check_loc, resabs ) == CUBIT_FALSE )
06334   {
06335     curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
06336     return 0;
06337   }
06338 
06339   return curve_ptr;
06340 }
06341 
06342 Curve*
06343 SplitSurfaceTool::create_arc_three( GeometryModifyEngine *gme,
06344                                     Surface *surf_ptr,
06345                                     CubitVector &start_pnt,
06346                                     CubitVector &mid_pnt,
06347                                     CubitVector &end_pnt,
06348                                     double resabs )
06349 {
06350   TBPoint *start_Point = gme->make_Point( start_pnt );
06351   TBPoint *end_Point = gme->make_Point( end_pnt );
06352   TBPoint *mid_Point = gme->make_Point( mid_pnt );
06353   if( start_Point == NULL || mid_Point == NULL || end_Point == NULL )
06354   {
06355     if( start_Point ) start_Point->get_geometry_query_engine()->delete_solid_model_entities(start_Point);
06356     if( mid_Point ) mid_Point->get_geometry_query_engine()->delete_solid_model_entities(mid_Point);
06357     if( end_Point ) end_Point->get_geometry_query_engine()->delete_solid_model_entities(end_Point);
06358     return 0;
06359   }
06360 
06361   // Create a 3-pt arc with the GeometryModifyEngine
06362   Curve *curve_ptr = gme->create_arc_three( start_Point, 
06363                                             mid_Point,
06364                                             end_Point );
06365 
06366   if( mid_Point ) mid_Point->get_geometry_query_engine()->delete_solid_model_entities(mid_Point);
06367 
06368   if( !curve_ptr )
06369   {
06370     if( start_Point ) start_Point->get_geometry_query_engine()->delete_solid_model_entities(start_Point);
06371     if( end_Point ) end_Point->get_geometry_query_engine()->delete_solid_model_entities(end_Point);
06372     return 0;
06373   }
06374 
06375   // Check 1/4 and 3/4 location - make sure on surface
06376   CubitVector check_loc;
06377   if( curve_ptr->position_from_fraction( .25, check_loc ) == CUBIT_FAILURE )
06378   {
06379      curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
06380     return 0;
06381   }
06382 
06383   // Now make sure within GEOMETRY_RESABS to the surface
06384   if( is_point_on_surface( surf_ptr, check_loc, resabs ) == CUBIT_FALSE )
06385   {
06386      curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
06387     return 0;
06388   }
06389 
06390   if( curve_ptr->position_from_fraction( .75, check_loc ) == CUBIT_FAILURE )
06391   {
06392      curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
06393     return 0;
06394   }
06395 
06396   // Now make sure within GEOMETRY_RESABS to the surface
06397   if( is_point_on_surface( surf_ptr, check_loc, resabs ) == CUBIT_FALSE )
06398   {
06399      curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
06400     return 0;
06401   }
06402 
06403   return curve_ptr;
06404 }
06405 
06406 Curve *
06407 SplitSurfaceTool::check_if_arc( GeometryModifyEngine *gme,
06408                                 Surface *surf_ptr,
06409                                 DLIList<CubitVector*> &point_list,
06410                                 CubitVector &start_pnt,
06411                                 CubitVector &mid_pnt,
06412                                 CubitVector &end_pnt,
06413                                 double resabs,
06414                                 double tolerance,
06415                                 double &deviation )
06416 {
06417   // Check if 3 points are colinear
06418   double a = (start_pnt-mid_pnt).length();
06419   double b = (mid_pnt-end_pnt).length();
06420   double c = (end_pnt-start_pnt).length();
06421   
06422   double denom = sqrt((a+b+c)*(b+c-a)*(c+a-b)*(a+b-c));
06423   if( denom < GEOMETRY_RESABS )
06424   {
06425     deviation = 99999.0;
06426     return 0;
06427   }
06428   
06429   // Create an actual arc and do some comparisons
06430 
06431   TBPoint *start_Point = gme->make_Point( start_pnt );
06432   TBPoint *end_Point = gme->make_Point( end_pnt );
06433   TBPoint *mid_Point = gme->make_Point( mid_pnt );
06434   if( start_Point == NULL || mid_Point == NULL || end_Point == NULL )
06435   {
06436     if( start_Point ) start_Point->get_geometry_query_engine()->delete_solid_model_entities(start_Point);
06437     if( mid_Point ) mid_Point->get_geometry_query_engine()->delete_solid_model_entities(mid_Point);
06438     if( end_Point ) end_Point->get_geometry_query_engine()->delete_solid_model_entities(end_Point);
06439     return 0;
06440   }
06441 
06442   // Create a 3-pt arc with the GeometryModifyEngine
06443   Curve *curve_ptr = gme->create_arc_three( start_Point, 
06444                                             mid_Point,
06445                                             end_Point );
06446 
06447   if( mid_Point ) mid_Point->get_geometry_query_engine()->delete_solid_model_entities(mid_Point);
06448 
06449   if( curve_ptr == NULL )
06450   {
06451     if( start_Point ) start_Point->get_geometry_query_engine()->delete_solid_model_entities(start_Point);
06452     if( end_Point ) end_Point->get_geometry_query_engine()->delete_solid_model_entities(end_Point);
06453     return 0;
06454   }
06455 
06456   // Now check all points to see if they are within tolerance to the arc
06457   // At the same time, check to make sure that each point on the arc is
06458   // within GEOMETRY_RESABS of the surface (otherwise an imprint will likely
06459   // not occur).
06460   int i;
06461   CubitVector closest_loc;
06462   point_list.reset();
06463   double max_deviation = -1.0;
06464   for( i=point_list.size(); i--; )
06465   {
06466     CubitVector *vec_ptr = point_list.get_and_step();
06467     if( curve_ptr->closest_point( *vec_ptr, closest_loc ) == CUBIT_FAILURE )
06468     {
06469        curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
06470       return 0;
06471     }
06472 
06473     deviation = vec_ptr->distance_between( closest_loc );
06474     if( deviation > max_deviation )
06475       max_deviation = deviation;
06476 
06477     if( deviation > tolerance )
06478     {
06479        curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
06480       return 0;
06481     }
06482 
06483     // Now make sure within GEOMETRY_RESABS (actually resbas) to the surface
06484     if( is_point_on_surface( surf_ptr, closest_loc, resabs ) == CUBIT_FALSE )
06485     {
06486        curve_ptr->get_geometry_query_engine()->delete_solid_model_entities(curve_ptr );
06487       return 0;
06488     }
06489   }
06490 
06491   deviation = max_deviation;
06492   return curve_ptr;
06493 }
06494 
06495 CubitStatus
06496 SplitSurfaceTool::reflect_arc_pnt( CubitVector &vec1,
06497                                    CubitVector &vec2,
06498                                    CubitVector &vec3,
06499                                    CubitVector &pnt_to_reflect,
06500                                    CubitVector &out_pnt )
06501 
06502 {
06503   double a = (vec1-vec2).length();
06504   double b = (vec2-vec3).length();
06505   double c = (vec3-vec1).length();
06506   
06507   double denom = sqrt((a+b+c)*(b+c-a)*(c+a-b)*(a+b-c));
06508   if(denom < GEOMETRY_RESABS )
06509     return CUBIT_FAILURE;
06510 
06511   AnalyticGeometryTool *agt = AnalyticGeometryTool::instance();
06512   
06513   // Find the circle radius
06514   double rad = (a*b*c)/denom;
06515   
06516   // Find a coordinate system in the plane of the arc
06517   // Start by getting normal to arc
06518   CubitVector z = (vec1-vec2)*(vec2-vec3);
06519   z.normalize();
06520   CubitVector x;
06521   CubitVector y;
06522   z.orthogonal_vectors( x,y );
06523 
06524   // Now we are going to transform the points to a local coordinate
06525   // system in the plane of the arc - thats where we can work to
06526   // determine the equation of the circle (in 2D).
06527   double mtx_global_to_local[4][4];
06528   double mtx_local_to_global[4][4];
06529 
06530   double xt[3], yt[3], zt[3], origint[3];
06531   agt->copy_pnt( x, xt );
06532   agt->copy_pnt( y, yt );
06533   agt->copy_pnt( z, zt );
06534   agt->copy_pnt( vec1, origint );
06535 
06536   agt->vecs_to_mtx( xt, yt, zt, origint, mtx_local_to_global );
06537   agt->inv_trans_mtx( mtx_local_to_global, mtx_global_to_local );
06538 
06539   double vec1_loc[3], vec2_loc[3], vec3_loc[3];
06540   agt->copy_pnt( vec1, vec1_loc );
06541   agt->copy_pnt( vec2, vec2_loc );
06542   agt->copy_pnt( vec3, vec3_loc );
06543 
06544   agt->transform_pnt( mtx_global_to_local, vec1_loc, vec1_loc );
06545   agt->transform_pnt( mtx_global_to_local, vec2_loc, vec2_loc );
06546   agt->transform_pnt( mtx_global_to_local, vec3_loc, vec3_loc );
06547 
06548 //  PRINT_INFO( "vec1_loc = %f, %f, %f\n", vec1_loc[0], vec1_loc[1], vec1_loc[2] );
06549 //  PRINT_INFO( "vec2_loc = %f, %f, %f\n", vec2_loc[0], vec2_loc[1], vec2_loc[2] );
06550 //  PRINT_INFO( "vec3_loc = %f, %f, %f\n", vec3_loc[0], vec3_loc[1], vec3_loc[2] );
06551 
06552   double x_1 = vec1_loc[0];
06553   double y_1 = vec1_loc[1];
06554   double x_2 = vec2_loc[0];
06555   double y_2 = vec2_loc[1];
06556   double x_3 = vec3_loc[0];
06557   double y_3 = vec3_loc[1];
06558   
06559   double N_1_mat[2][2];
06560   N_1_mat[0][0] = (x_2*x_2 + y_2*y_2-(x_1*x_1 + y_1*y_1));
06561   N_1_mat[0][1] = y_2-y_1;
06562   N_1_mat[1][0] = (x_3*x_3 + y_3*y_3-(x_1*x_1 + y_1*y_1));
06563   N_1_mat[1][1] = y_3-y_1;
06564   double N_2_mat[2][2];
06565   N_2_mat[0][0] = x_2-x_1;
06566   N_2_mat[0][1] = (x_2*x_2 + y_2*y_2-(x_1*x_1 + y_1*y_1));
06567   N_2_mat[1][0] = x_3-x_1;
06568   N_2_mat[1][1] = (x_3*x_3 + y_3*y_3-(x_1*x_1 + y_1*y_1));
06569   double D_mat[2][2];
06570   D_mat[0][0] = x_2-x_1;
06571   D_mat[0][1] = y_2-y_1;
06572   D_mat[1][0] = x_3-x_1;
06573   D_mat[1][1] = y_3-y_1;
06574   
06575   double N_1 = N_1_mat[0][0]*N_1_mat[1][1] - N_1_mat[0][1]*N_1_mat[1][0];
06576   double N_2 = N_2_mat[0][0]*N_2_mat[1][1] - N_2_mat[0][1]*N_2_mat[1][0];
06577   double D = D_mat[0][0]*D_mat[1][1] - D_mat[0][1]*D_mat[1][0];
06578 
06579   double center_loc[3];
06580   center_loc[0] = N_1/(2.0*D);
06581   center_loc[1] = N_2/(2.0*D);
06582   center_loc[2] = 0.0;
06583 
06584 //  double centert[3];
06585 //  agt->transform_pnt( mtx_local_to_global, center_loc, centert );
06586 //  
06587 //  CubitVector center( centert );
06588 //  PRINT_INFO( "Arc Center = %f, %f, %f\n", center.x(), center.y(), center.z() );
06589 //
06590 //  GfxDebug::draw_point( center, CUBIT_BLUE_INDEX );
06591 
06592   // Now that we have the center, it is simple matter to find the reflected
06593   // point from pnt_to_reflect by traversing 2*rad along a vector from
06594   // pnt_to_reflect to center.
06595   double pnt_to_reflectt[3];
06596   agt->copy_pnt( pnt_to_reflect, pnt_to_reflectt );
06597   double pnt_to_reflect_loc[3];
06598   agt->transform_pnt( mtx_global_to_local, pnt_to_reflectt, pnt_to_reflect_loc );
06599   double trav_vec[3];
06600   if( agt->get_vec( pnt_to_reflect_loc, center_loc, trav_vec ) == CUBIT_FAILURE )
06601     return CUBIT_FAILURE;
06602 
06603   agt->unit_vec( trav_vec, trav_vec );
06604 
06605   double ref_pnt_loc[3];
06606   agt->next_pnt( pnt_to_reflect_loc, trav_vec, 2.0*rad, ref_pnt_loc );
06607 
06608   // Now transform this point to the global csys
06609   double ref_pntt[3];
06610   agt->transform_pnt( mtx_local_to_global, ref_pnt_loc, ref_pntt );
06611 
06612   out_pnt.set( ref_pntt[0], ref_pntt[1], ref_pntt[2] );
06613 
06614   return CUBIT_SUCCESS;
06615 }
06616 
06617 CubitBoolean
06618 SplitSurfaceTool::is_point_on_surface( Surface *surf_ptr, CubitVector &pnt, 
06619                                        double resabs )
06620 {
06621   // Make sure within GEOMETRY_RESABS to the surface
06622   CubitVector closest_loc_on_surf;
06623   if( surf_ptr->closest_point( pnt, &closest_loc_on_surf ) == CUBIT_FAILURE )
06624     return CUBIT_FALSE;
06625 
06626   double dist = pnt.distance_between( closest_loc_on_surf );
06627   if( dist > resabs ) // Was GEOMETRY_RESABS
06628     return CUBIT_FALSE;
06629   
06630   return CUBIT_TRUE;
06631 }
06632 
06633 int
06634 SplitSurfaceTool::count_surfaces_in_owning_body( RefFace *ref_face_ptr, 
06635                                                  Body *&body_ptr )
06636 {
06637   // Returns: Number of surfaces in the owning body of the RefFace
06638   //          -1 - RefFace is free (no owning body)
06639   //          -2 - RefFace is owned by more than one body
06640   body_ptr = 0;
06641   DLIList<Body*> body_list;
06642 
06643   ref_face_ptr->bodies( body_list );
06644   if( body_list.size() == 0 )
06645     return -1;
06646   else if( body_list.size() > 1 )
06647     return -2;
06648   
06649   body_ptr = body_list.get();
06650   DLIList<RefFace*> ref_face_list;
06651   body_ptr->ref_faces( ref_face_list );
06652   return ref_face_list.size();
06653 }
06654 
06655 int
06656 SplitSurfaceTool::count_surfaces_in_body( Body *body_ptr )
06657 {
06658   // Return number of surfaces in the body
06659   DLIList<RefFace*> ref_face_list;
06660   body_ptr->ref_faces( ref_face_list );
06661   return ref_face_list.size();
06662 }
06663 
06664 int
06665 SplitSurfaceTool::count_curves_in_body( Body *body_ptr )
06666 {
06667   // Return number of edges in the body
06668   DLIList<RefEdge*> ref_edge_list;
06669   body_ptr->ref_edges( ref_edge_list );
06670   return ref_edge_list.size();
06671 }
06672 
06673 CubitStatus
06674 SplitSurfaceTool::split_surfaces_extend( DLIList<RefFace*> &ref_face_list,
06675                                          DLIList<RefVertex*> &ref_vertex_list,
06676                                          CubitBoolean preview_flg,
06677                                          CubitBoolean create_ref_edges_flg )
06678 {
06679   // In the below code, "manual" mode refers to when vertices are passed in. In
06680   // this mode, an extension must occur from each given vertex for success.
06681   // "Auto" mode refers to when no vertices are passed in.  In this mode the 
06682   // vertices (curves to extend) are found automatically - the ends of 
06683   // hardlines.  Only in auto mode are the gap threshold and normal settings
06684   // valid.
06685   int i, j;
06686   RefFace *ref_face_ptr = NULL;
06687   RefVertex *ref_vertex_ptr = NULL;
06688   GeometryModifyEngine *gme = NULL;
06689   TDSplitSurfaceExtend *tdsse = NULL;
06690 
06691   // Clear previous graphics previews
06692   GfxPreview::clear();
06693   
06694   CubitBoolean auto_flg = CUBIT_TRUE;
06695   if( ref_vertex_list.size() )
06696     auto_flg = CUBIT_FALSE;
06697 
06698   // Copy input face list since we don't want to modify it
06699   DLIList<RefFace*> copied_ref_face_list = ref_face_list;
06700   
06701   // Check for errors
06702   copied_ref_face_list.reset();
06703   for( i=copied_ref_face_list.size(); i--; )
06704   {
06705     ref_face_ptr = copied_ref_face_list.get();
06706 
06707     // Check for free and merged surfaces... for both manual and auto cases.
06708     //  (we make this fatal for the auto case too since the user can correct
06709     //   these and may not even know about them)
06710     DLIList<Body*> body_list;
06711     ref_face_ptr->bodies( body_list );
06712     if( body_list.size()==0 )
06713     {
06714       PRINT_ERROR( "Surface %d is not contained within a parent body.\n"
06715         "       It cannot be split.\n", ref_face_ptr->id() );
06716       return CUBIT_FAILURE;
06717     }
06718     else if( body_list.size() > 1 )
06719     {
06720       PRINT_ERROR( "Surface %d is merged and cannot be split.\n",
06721         ref_face_ptr->id() );
06722       return CUBIT_FAILURE;
06723     }
06724 
06725     // Check for nonplanar surface.  For auto case, just remove these, but
06726     // for manual case, give a fatal error.
06727     if( ref_face_ptr->is_planar() == CUBIT_FALSE )
06728     {
06729       if( auto_flg == CUBIT_TRUE )
06730       {
06731         copied_ref_face_list.change_to( NULL );
06732         copied_ref_face_list.step();
06733         continue;
06734       }
06735       else
06736       {
06737         // Error out
06738         PRINT_ERROR( "The 'split across extend' command only works on planar surfaces.\n"
06739           "       Surface %d is nonplanar\n", ref_face_ptr->id() );
06740         return CUBIT_FAILURE;
06741       }
06742     }
06743     copied_ref_face_list.step();
06744   }
06745 
06746   copied_ref_face_list.remove_all_with_value( NULL );
06747 
06748   // If we don't have any faces left, we exit (could only occur for auto case...
06749   // make this a warning instead of an error).
06750   if( !copied_ref_face_list.size() )
06751   {
06752     PRINT_WARNING( "No valid surfaces found to be split. Note to be split, they\n"
06753       "         must be nonplanar, contained in a body, and not merged.\n" );
06754     return CUBIT_SUCCESS;
06755   }
06756 
06757   // Mark each of the input vertices with a tooldata
06758   ref_vertex_list.reset();
06759   for( i=ref_vertex_list.size(); i--; )
06760   {
06761     ref_vertex_ptr = ref_vertex_list.get_and_step();
06762     ref_vertex_ptr->add_TD( new TDSplitSurfaceExtend() );
06763   }
06764 
06765   // Store list of faces and new curves sorted by body and face
06766   DLIList<DLIList<Surface*>*> body_surf_list_list;
06767   DLIList<DLIList<DLIList<Curve*>*>*> curve_lists_lists_list;
06768 
06769   // Store ids of Curves that are extended
06770   DLIList<int> ext_curve_ids;
06771 
06772   // Operate by common body - pull faces out of the input face list that are
06773   // from a common Body and place them in a separate list (split_face_list).  
06774   Body *curr_Body_ptr;
06775   while( copied_ref_face_list.size() )
06776   {
06777     DLIList<RefFace*> split_face_list; // Holds faces from common body
06778 
06779     // Store new curves for this body, sorted by face
06780     DLIList<DLIList<Curve*>*> *curve_lists_list_ptr;
06781     curve_lists_list_ptr = new DLIList<DLIList<Curve*>*>;
06782     curve_lists_lists_list.append( curve_lists_list_ptr );
06783 
06784     curr_Body_ptr = NULL;
06785 
06786     copied_ref_face_list.reset();
06787     for( i=copied_ref_face_list.size(); i--; )
06788     {
06789       ref_face_ptr = copied_ref_face_list.get();
06790 
06791       DLIList<Body*> body_list;
06792       ref_face_ptr->bodies( body_list );
06793 
06794       if( curr_Body_ptr == NULL )
06795         curr_Body_ptr = body_list.get();
06796 
06797       if( curr_Body_ptr == body_list.get() )
06798       {
06799         split_face_list.append( ref_face_ptr );
06800         copied_ref_face_list.change_to( NULL );
06801       }
06802 
06803       copied_ref_face_list.step();
06804     }
06805 
06806     copied_ref_face_list.remove_all_with_value( NULL );
06807 
06808     DLIList<Surface*> *body_surf_list_ptr;
06809     body_surf_list_ptr = new DLIList<Surface*>;
06810     body_surf_list_list.append( body_surf_list_ptr );
06811 
06812     // Loop through each face on the common body
06813     RefFace *split_face_ptr;
06814     DLIList<Curve*> *curve_list_ptr;
06815     split_face_list.reset();
06816     for( i=split_face_list.size(); i--; )
06817     {
06818       split_face_ptr = split_face_list.get_and_step();
06819       body_surf_list_ptr->append( split_face_ptr->get_surface_ptr() );
06820 
06821       curve_list_ptr = new DLIList<Curve*>;
06822       curve_lists_list_ptr->append( curve_list_ptr );
06823 
06824       // Get the RefEdges to fire a ray at (from surface)
06825       DLIList<RefEdge*> ref_edge_list;
06826       split_face_ptr->ref_edges( ref_edge_list );
06827       DLIList<RefEntity*> at_entity_list;
06828       CAST_LIST( ref_edge_list, at_entity_list, RefEntity );
06829 
06830       // Fire a ray from each vertex in an outward direction from the tangent
06831       // of the owning curve at the at_entity_list
06832       DLIList<RefVertex*> tmp_vertex_list;
06833       split_face_ptr->ref_vertices( tmp_vertex_list );
06834 
06835       tmp_vertex_list.reset();
06836       for( j=tmp_vertex_list.size(); j--; )
06837       {
06838         ref_vertex_ptr = tmp_vertex_list.get_and_step();
06839 
06840         // The vertex must be part of the surface being considered, plus
06841         // the attached curve must be on the surface.  We must have one and
06842         // only one attached curve.  This curve must be linear.
06843 
06844         // For manual case, only consider vertices that are in the input list
06845         if( auto_flg == CUBIT_FALSE )
06846         {
06847           tdsse = (TDSplitSurfaceExtend *)ref_vertex_ptr->
06848             get_TD(&TDSplitSurfaceExtend::is_split_surface_extend);
06849           if( !tdsse ) continue;
06850         }
06851 
06852         // Get attached RefEdges to this vertex
06853         DLIList<RefEdge*> att_ref_edge_list;
06854         ref_vertex_ptr->ref_edges( att_ref_edge_list );
06855 
06856         RefEdge *extend_edge_ptr = 0;
06857         RefEdge *ref_edge_ptr;
06858         int k;
06859         for( k=att_ref_edge_list.size(); k--; )
06860         {
06861           ref_edge_ptr = att_ref_edge_list.get_and_step();
06862           if( ref_edge_ptr->is_directly_related( split_face_ptr ) )
06863           {
06864             if( !extend_edge_ptr ) 
06865               extend_edge_ptr = ref_edge_ptr;
06866             else
06867             {
06868               extend_edge_ptr = 0;
06869               break;
06870             }
06871           }
06872         }
06873 
06874         if( !extend_edge_ptr )
06875           continue;
06876 
06877         // For now, limit this to linear curves.  Technically, we should be able
06878         // to extend non-linear curves though.
06879         Curve *curve_ptr = extend_edge_ptr->get_curve_ptr();
06880         if( curve_ptr->geometry_type() != STRAIGHT_CURVE_TYPE )
06881           continue;
06882 
06883         RefVertex *start_vertex_ptr, *end_vertex_ptr;
06884 
06885         start_vertex_ptr = extend_edge_ptr->start_vertex();
06886         end_vertex_ptr = extend_edge_ptr->end_vertex();
06887 
06888         DLIList<double> ray_params;
06889         CubitVector start_loc = ref_vertex_ptr->coordinates();
06890 
06891         // Find direction to fire ray
06892         CubitVector ray_dir;
06893 
06894         if( ref_vertex_ptr == start_vertex_ptr )
06895           ray_dir = start_vertex_ptr->coordinates() - 
06896           end_vertex_ptr->coordinates();
06897         else
06898           ray_dir = end_vertex_ptr->coordinates() - 
06899           start_vertex_ptr->coordinates();
06900 
06901         ray_dir.normalize();
06902 
06903         // Remove the curve being extended from the at_entity_list
06904         DLIList<RefEntity*> tmp_at_entity_list = at_entity_list;
06905         tmp_at_entity_list.remove_all_with_value( extend_edge_ptr );
06906 
06907         // Fire the ray, asking for only one hit
06908         DLIList<RefEntity*> hit_entity_list;
06909         if( GeometryQueryTool::instance()->fire_ray( start_loc, ray_dir,
06910           tmp_at_entity_list, ray_params, 1, 0.0, &hit_entity_list  ) 
06911           == CUBIT_FAILURE  ||
06912           ray_params.size() == 0 || ray_params.get() == 0.0 )
06913           continue;
06914 
06915         //PRINT_INFO( "Got hit from vertex %d on surface %d at distance %lf\n", 
06916         //  ref_vertex_ptr->id(), split_face_ptr->id(), ray_params.get() )
06917 
06918         CubitVector end_loc;
06919         double ray_param = ray_params.get();
06920 
06921         // Note the hit entity could be a curve or a vertex
06922         RefEntity *hit_entity_ptr = 0;
06923         RefEdge *hit_edge_ptr = 0;
06924         if( hit_entity_list.size() ) // In case fire_ray didn't return hit ents
06925         {
06926           hit_entity_ptr = hit_entity_list.get();
06927           hit_edge_ptr = CAST_TO( hit_entity_ptr, RefEdge );
06928         }
06929 
06930         if( extendNormalFlg == CUBIT_TRUE )
06931         {
06932           // Try going normal to the curve hit.
06933           double norm_dist = CUBIT_DBL_MAX;
06934 
06935           if( hit_edge_ptr )
06936           {
06937             hit_edge_ptr->closest_point( start_loc, end_loc );
06938 
06939             // Only valid if end_loc is ON the curve
06940             CubitPointContainment contain = hit_edge_ptr->
06941                 point_containment( end_loc );
06942 
06943             if( contain != CUBIT_PNT_ON )
06944             {
06945                 // find the nearest curve which the vertex can be extended to and normal
06946                 RefEdge* new_edge_ptr = NULL;
06947                 CubitVector new_end_loc;
06948                 find_nearest_curve_for_normal_projection(
06949                     hit_edge_ptr, start_loc, split_face_ptr, ray_dir, new_edge_ptr, new_end_loc);
06950 
06951                 if (new_edge_ptr)
06952                 {
06953                     hit_edge_ptr = new_edge_ptr;
06954                     end_loc = new_end_loc;
06955                 }
06956             }
06957 
06958             norm_dist = start_loc.distance_between( end_loc );
06959           }
06960 
06961           // Use shortest distance between closest normal and ray_param
06962           if( ray_param < norm_dist )
06963             start_loc.next_point( ray_dir, ray_param, end_loc );
06964         }
06965         else
06966           // Use ray_dir along ray
06967           start_loc.next_point( ray_dir, ray_param, end_loc );
06968 
06969         // For auto mode, check to see if we are out of the extendGapThreshold
06970         if( auto_flg && 
06971            ( start_loc.distance_between( end_loc ) > extendGapThreshold ) )
06972           continue;
06973 
06974         // Check for close vertex
06975         if( hit_edge_ptr )
06976         {
06977           double arc_length;
06978           
06979           // Check distance to start of curve
06980           arc_length = hit_edge_ptr->get_arc_length( end_loc, 0 );
06981 
06982           if( arc_length <= extendTolerance )
06983           {
06984             end_loc = hit_edge_ptr->start_coordinates();
06985             PRINT_INFO( "Snapping to close vertex for curve %d extended from vertex %d\n",
06986               extend_edge_ptr->id(), ref_vertex_ptr->id() );
06987           }
06988           else
06989           {
06990             // Check distance to end of curve
06991             arc_length = hit_edge_ptr->get_arc_length( end_loc, 1 );
06992 
06993             if( arc_length <= extendTolerance )
06994             {
06995               end_loc = hit_edge_ptr->end_coordinates();
06996               PRINT_INFO( "Snapping to close vertex for curve %d extended from vertex %d\n",
06997                 extend_edge_ptr->id(), ref_vertex_ptr->id() );
06998             }
06999           }
07000         }
07001 
07002         curve_ptr = NULL;
07003 
07004         // Create curve (from start_vec to end_vec)
07005         Surface *surf_ptr = split_face_ptr->get_surface_ptr();
07006 
07007         gme = GeometryModifyTool::instance()->get_engine( surf_ptr );
07008         if( gme == NULL )
07009         {
07010           PRINT_ERROR("No geometry modify engine available for surface %d\n"
07011             "       Unable to create split curve.\n", split_face_ptr->id());
07012           // Remove tooldatas and free memory
07013           cleanup_for_extend_op( ref_vertex_list, body_surf_list_list,
07014             curve_lists_lists_list );
07015           return CUBIT_FAILURE;
07016         }
07017 
07018         // Create a straight line on the surface
07019         TBPoint *start_Point = gme->make_Point( start_loc );
07020         TBPoint *end_Point = gme->make_Point( end_loc );
07021         if( start_Point == NULL || end_Point == NULL )
07022         {
07023           PRINT_ERROR("Unable to create points for curve on surface %d\n",
07024             split_face_ptr->id() );
07025           // Remove tooldatas and free memory
07026           cleanup_for_extend_op( ref_vertex_list, body_surf_list_list,
07027             curve_lists_lists_list );
07028           return CUBIT_FAILURE;
07029         }
07030         curve_ptr = gme->make_Curve( start_Point, end_Point, surf_ptr );
07031         if( !curve_ptr )
07032         {
07033           PRINT_ERROR( "Unable to create split curve from vertex %d on surface %d\n",
07034             ref_vertex_ptr->id(), split_face_ptr->id() );
07035           // Remove tooldatas and free memory
07036           cleanup_for_extend_op( ref_vertex_list, body_surf_list_list,
07037             curve_lists_lists_list );
07038           return CUBIT_FAILURE;
07039         }
07040 
07041         curve_list_ptr->append( curve_ptr );
07042 
07043         // Keep track of which curves are extended
07044         ext_curve_ids.append( extend_edge_ptr->id() );
07045 
07046         if( tdsse )
07047           tdsse->set_success();
07048       }
07049 
07050     }
07051 
07052     curr_Body_ptr = 0;
07053   }
07054 
07055   // For manual mode, check to make sure that all vertices had success,
07056   // otherwise, this is an error.  Note... vertices seem to live through
07057   // these operations.
07058   DLIList<int> vertex_id_list;
07059   for( i=ref_vertex_list.size(); i--; )
07060   {
07061     ref_vertex_ptr = ref_vertex_list.get_and_step();
07062 
07063     tdsse = (TDSplitSurfaceExtend *)ref_vertex_ptr->
07064       get_TD(&TDSplitSurfaceExtend::is_split_surface_extend);
07065 
07066     if( !tdsse ) continue;
07067 
07068     if( !tdsse->is_success() )
07069       vertex_id_list.append( ref_vertex_ptr->id() );
07070   }
07071   if( vertex_id_list.size() )
07072   {
07073     if( vertex_id_list.size() == 1 )
07074       PRINT_ERROR( "Unable to extend from vertex %d\n", ref_vertex_ptr->id() );
07075     else
07076     {
07077       PRINT_ERROR( "Unable to extend from vertices\n" );
07078       CubitUtil::list_entity_ids( "       Problem vertices: ", vertex_id_list );
07079     }
07080     PRINT_INFO( "       Vertices must be at the end of only one curve on the surface to split,\n"
07081                 "       extended curves must be linear, and surfaces to split must be planar.\n" );
07082 
07083     // Remove tooldatas and free memory
07084     cleanup_for_extend_op( ref_vertex_list, body_surf_list_list,
07085       curve_lists_lists_list );
07086     return CUBIT_FAILURE;
07087   }
07088 
07089   // Give message as to which curves were extended
07090   char msg[50];
07091   if( ext_curve_ids.size() )
07092   {
07093     // Remove duplicates (curves extended from both ends)
07094     ext_curve_ids.uniquify_ordered();
07095 
07096     // Give a nice message
07097     if( ext_curve_ids.size() == 1 )
07098       CubitUtil::list_entity_ids( "1 curve extended: ", ext_curve_ids );
07099     else
07100     {
07101       sprintf( msg, "%d curves extended: ", ext_curve_ids.size() );
07102       CubitUtil::list_entity_ids( msg, ext_curve_ids );
07103     }
07104   }
07105   else
07106   {
07107     // Might as well exit
07108     PRINT_INFO( "No curves found to extend\n" );
07109     // Remove tooldatas and free memory
07110     cleanup_for_extend_op( ref_vertex_list, body_surf_list_list, 
07111       curve_lists_lists_list );
07112     return CUBIT_SUCCESS;
07113   }
07114 
07115   // Do the splitting
07116   DLIList<Surface*> *surf_list_ptr;
07117   DLIList<DLIList<Curve*>*> *curve_lists_list_ptr;
07118   body_surf_list_list.reset();
07119   curve_lists_lists_list.reset();
07120   if( preview_flg==CUBIT_FALSE && create_ref_edges_flg==CUBIT_FALSE )
07121   {
07122     for( i=body_surf_list_list.size(); i--; )
07123     {
07124       surf_list_ptr = body_surf_list_list.get_and_step();
07125       curve_lists_list_ptr = curve_lists_lists_list.get_and_step();
07126 
07127       Body *new_body_ptr;
07128       if( GeometryModifyTool::instance()->imprint( *surf_list_ptr,
07129         *curve_lists_list_ptr, new_body_ptr ) == CUBIT_FAILURE )
07130       {
07131         // Remove tooldatas and free memory
07132         cleanup_for_extend_op( ref_vertex_list, body_surf_list_list, 
07133           curve_lists_lists_list );
07134         return CUBIT_FAILURE;
07135       }
07136     }
07137   }
07138   else if( preview_flg==CUBIT_TRUE && create_ref_edges_flg==CUBIT_TRUE )
07139   {
07140     // Just create the RefEdges
07141     DLIList<RefEdge*> new_ref_edge_list;
07142     curve_lists_lists_list.reset();
07143 
07144     for( i=curve_lists_lists_list.size(); i--; )
07145     {
07146       curve_lists_list_ptr = curve_lists_lists_list.get_and_step();
07147 
07148       curve_lists_list_ptr->reset();
07149       for( j=curve_lists_list_ptr->size(); j--; )
07150       {
07151         DLIList<Curve*> *curve_list_ptr = curve_lists_list_ptr->get_and_step();
07152         curve_list_ptr->reset();
07153 
07154         create_ref_edges( *curve_list_ptr, new_ref_edge_list );
07155       }
07156     }
07157     // Let the user know about the new curves created
07158     if( new_ref_edge_list.size() )
07159     {
07160       DLIList<CubitEntity*> cubit_entity_list;
07161       CAST_LIST( new_ref_edge_list, cubit_entity_list, CubitEntity );
07162       CubitUtil::list_entity_ids( "Created new curves: ", cubit_entity_list );
07163     }
07164   }
07165   else
07166   {
07167     // Just preview
07168     for( i=body_surf_list_list.size(); i--; )
07169     {
07170       curve_lists_list_ptr = curve_lists_lists_list.get_and_step();
07171 
07172       curve_lists_list_ptr->reset();
07173       for( j=curve_lists_list_ptr->size(); j--; )
07174       {
07175         DLIList<Curve*> *curve_list_ptr = curve_lists_list_ptr->get_and_step();
07176 
07177         // Draw the curves
07178         draw_preview( *curve_list_ptr );
07179       }
07180     }
07181   }
07182 
07183   // Flush the graphics
07184   GfxPreview::flush();
07185 
07186   // Remove tooldatas and free memory
07187   cleanup_for_extend_op( ref_vertex_list, body_surf_list_list, 
07188     curve_lists_lists_list );
07189 
07190   return CUBIT_SUCCESS;
07191 }
07192 
07193 void
07194 SplitSurfaceTool::cleanup_for_extend_op( DLIList<RefVertex*> &ref_vertex_list,
07195                    DLIList<DLIList<Surface*>*> &body_surf_list_list,
07196                    DLIList<DLIList<DLIList<Curve*>*>*> &curve_lists_lists_list,
07197                    CubitBoolean free_curves_flg )
07198 {
07199   int i;
07200   RefVertex *ref_vertex_ptr;
07201 
07202   // Remove tooldatas from vertices
07203   ref_vertex_list.reset();
07204   for( i=ref_vertex_list.size(); i--; )
07205   {
07206     ref_vertex_ptr = ref_vertex_list.get_and_step();
07207     ref_vertex_ptr->delete_TD( &TDSplitSurfaceExtend::is_split_surface_extend );
07208   }
07209 
07210   // Free allocated lists in body_surf_list_list
07211   while( body_surf_list_list.size() ) delete body_surf_list_list.pop();
07212 
07213   // Free allocated lists in curve_list_lists_list, as well as Curves (if not
07214   // attached to RefEdges).
07215   DLIList<DLIList<Curve*>*> *curve_list_lists_ptr;
07216   for( i=curve_lists_lists_list.size(); i--; )
07217   {
07218     curve_list_lists_ptr = curve_lists_lists_list.get();
07219 
07220     free_curves_lists( *curve_list_lists_ptr );
07221     delete curve_list_lists_ptr;
07222 
07223     curve_lists_lists_list.step();
07224   }
07225 
07226   return;
07227 }
07228 
07229 void SplitSurfaceTool::find_nearest_curve_for_normal_projection(
07230   RefEdge* hit_edge_ptr, CubitVector& start_loc, 
07231   RefFace* face, CubitVector& ray_dir, RefEdge*& new_edge_ptr,
07232   CubitVector& new_end_loc)
07233 {
07234   // traverse the curves in the surface and find the closest curve to the hardline
07235   // which the hardline can extend normal to
07236 
07237   DLIList<RefEdge*> edge_list;
07238   face->ref_edges(edge_list);
07239 
07240   std::map<double, std::pair<RefEdge*, CubitVector> > potential_curves_map;
07241 
07242   // maybe traverse all curves all of the time, and use the one closest to the point
07243   int i;
07244   for (i=edge_list.size(); i--;)
07245   {
07246     RefEdge* edge = edge_list.get_and_step();
07247 
07248     if (edge == hit_edge_ptr)
07249       continue;
07250 
07251     CubitVector closest_point;
07252     edge->closest_point(start_loc, closest_point);
07253 
07254     // Only valid if location is ON the curve
07255     CubitPointContainment contain = edge->point_containment( closest_point );
07256     if( contain == CUBIT_PNT_ON )
07257     {
07258       // check to make sure angle isn't too bad
07259       // have a user setting for this in the future
07260       // but for now, use 90 degrees
07261       CubitVector split_direction = closest_point - start_loc;
07262       if (split_direction.length_squared() <= GEOMETRY_RESABS) //ignore self
07263         continue;
07264 
07265       double angle = ray_dir.interior_angle(split_direction);
07266       if (fabs(angle) <= 90.0)
07267       {
07268         double dist = start_loc.distance_between(closest_point);
07269         potential_curves_map.insert(std::map<double, std::pair<RefEdge*, CubitVector> >::value_type(
07270           dist, std::make_pair(edge, closest_point)));
07271       }
07272     }
07273   }
07274 
07275   if (potential_curves_map.size())
07276   {
07277     std::map<double, std::pair<RefEdge*, CubitVector> >::iterator iter = potential_curves_map.begin();
07278     new_edge_ptr = (iter->second).first;
07279     new_end_loc = (iter->second).second;
07280   }
07281 
07282   return;
07283 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines