MeshKit  1.0
mw_func.cpp
Go to the documentation of this file.
00001 // ********************************************************************
00002 // Patrick Shriwise
00003 // October, 2013
00004 
00005 // functions needed to seal unwatertight models in make_watertight
00006 
00007 
00008 // make CXXFLAGS=-g for debug
00009 // make CXXFLAGS=-pg for profiling
00010 
00011 
00012 
00013 
00014 #include <iostream>
00015 #include <sstream>
00016 #include <iomanip> // for setprecision
00017 #include <limits> // for min/max values
00018 #include <assert.h>
00019 #include <math.h>
00020 #include <time.h>
00021 #include <vector>
00022 
00023 #include "moab/Core.hpp"
00024 #include "MBTagConventions.hpp"
00025 #include "moab/Range.hpp"
00026 #include "moab/Skinner.hpp"
00027 #include "moab/GeomTopoTool.hpp"
00028 
00029 #include "meshkit/mw_func.hpp"
00030 #include "meshkit/gen.hpp"
00031 #include "meshkit/arc.hpp"
00032 #include "meshkit/zip.hpp"
00033 #include "meshkit/cleanup.hpp"
00034 
00035 
00036 using namespace moab;
00037 namespace mw_func {
00038 
00039 
00040 
00041 ErrorCode delete_all_edges() {
00042   // delete all of the edges. Never keep edges. They are too hard to track and use
00043   // due to orientation and multiple entities errors when merging.
00044   ErrorCode result;
00045   Range edges;
00046   result = MBI()->get_entities_by_type( 0, MBEDGE, edges );
00047   if(gen::error(MB_SUCCESS!=result,"could not get edges")) return result;
00048   assert(MB_SUCCESS == result);
00049   result = MBI()->delete_entities( edges );
00050   if(gen::error(MB_SUCCESS!=result,"could not delete edges")) return result;
00051   assert(MB_SUCCESS == result);
00052   return MB_SUCCESS;
00053 }
00054 
00055 ErrorCode find_degenerate_tris() {
00056   ErrorCode result;
00057   Range tris;
00058   result = MBI()->get_entities_by_type( 0, MBTRI, tris );
00059   if(gen::error(MB_SUCCESS!=result,"could not get tris")) return result;
00060   assert(MB_SUCCESS == result);
00061   int counter = 0;
00062   for(Range::const_iterator i=tris.begin(); i!=tris.end(); ++i) {
00063     if( gen::triangle_degenerate(*i) ) {
00064       result = MBI()->list_entity(*i);
00065       if(gen::error(MB_SUCCESS!=result,"found degenerate tri")) return result;
00066       assert(MB_SUCCESS == result);
00067       ++counter;
00068     }
00069   }
00070   if(counter != 0)
00071   {
00072   std::cout << "Found " << counter << " degenerate triangles. " << std::endl;
00073   }
00074   return MB_SUCCESS;
00075 }
00076 
00077 // Input: Possibly unordered sets of curves that do track ownership. Curves contain
00078 //        edges and vertices. Parents sets are surfaces. Child sets are endpoint
00079 //        vertices.
00080 // Output: Ordered sets of verts that do track ownership. All edges are deleted.
00081 ErrorCode prepare_curves(Range &curve_sets,
00082                            Tag geom_tag, Tag id_tag, Tag merge_tag,
00083                            const double FACET_TOL, const bool debug, bool verbose ) {
00084   ErrorCode result;
00085   if (verbose) std::cout << "Modifying faceted curve representation and removing small curves..." 
00086             << std::endl;
00087 
00088   // process each curve
00089   for(Range::iterator i=curve_sets.begin(); i!=curve_sets.end(); i++ ) {
00090     // get the curve id of the curve meshset
00091     int id;
00092     result = MBI()->tag_get_data( id_tag, &(*i), 1, &id );
00093     if(gen::error(MB_SUCCESS!=result,"could not get id tag")) return result;
00094     if(debug) std::cout << "curve " << id << std::endl;
00095 
00096     // get the range of edges of the curve meshset
00097     std::vector<EntityHandle> curve_edges;
00098     result = MBI()->get_entities_by_type( *i, MBEDGE, curve_edges );
00099     if(gen::error(MB_SUCCESS!=result,"could not get curve_edges")) return result;
00100 
00101     /* Merge the endpoints of the curve and remove its edges if it is too small.
00102     Use the MERGE_TOL because these edges will be merged with the MERGE_TOL 
00103     during zipping anyhow. Doing this now removes small curves from zipping and
00104     reduces ambiguity. */
00105     if(FACET_TOL > gen::length(curve_edges)) {
00106       if (debug)
00107         {
00108           std::cout << "  deleted curve " << id << ", length=" << gen::length(curve_edges) 
00109           << " cm, n_verts=" << curve_edges.size()+1 << std::endl;
00110         }
00111       // get the endpoints of the curve
00112       Range endpt_sets;
00113       result = MBI()->get_child_meshsets( *i, endpt_sets );
00114       if(gen::error(MB_SUCCESS!=result,"could not get curve child sets")) return result;
00115 
00116       if(endpt_sets.empty()) {
00117         if(gen::error(true,"curve has no child sets")) return result;
00118       } else if(1 == endpt_sets.size()) {
00119         // The edges are no longer needed. Remove them before altering the range
00120         // by deleting degenerate edges below.
00121         result = MBI()->delete_entities( &curve_edges[0], curve_edges.size() );
00122         if(gen::error(MB_SUCCESS!=result,"could not delete edges")) return result;
00123 
00124       } else if(2 == endpt_sets.size()) {
00125         // The edges are no longer needed. Remove them before altering the range
00126         // by deleting degenerate edges below.
00127         result = MBI()->delete_entities( &curve_edges[0], curve_edges.size() );
00128         if(gen::error(MB_SUCCESS!=result,"could not delete edges")) return result;
00129 
00130         Range front_endpt, back_endpt;
00131         result = MBI()->get_entities_by_type( endpt_sets.front(), MBVERTEX, front_endpt);
00132         if(gen::error(MB_SUCCESS!=result,"could not get vert from front endpt set")) return result;
00133         if(gen::error(1!=front_endpt.size(),"front endpt set does not have 1 vert")) return result;
00134 
00135         result = MBI()->get_entities_by_type( endpt_sets.back(), MBVERTEX, back_endpt);
00136         if(gen::error(MB_SUCCESS!=result,"could not get vert from back endpt set")) return result;
00137         if(gen::error(1!=back_endpt.size(),"back endpt set does not have 1 vert")) return result;
00138 
00139         // merge the endpoints-ALWAYS CHECK TO AVOID MERGING THE SAME ENTITY!!!
00140         if(front_endpt[0] != back_endpt[0]) {
00141           std::vector<EntityHandle> temp;
00142           result = zip::merge_verts( front_endpt.front(), back_endpt.front(), temp, temp );
00143           if(gen::error(MB_SUCCESS!=result,"could not merge verts")) return result;
00144 
00145           // check for and remove degenerate edges caused by the merge
00146           Range edges;
00147           EntityHandle temp_pt = front_endpt[0];
00148           result = MBI()->get_adjacencies( &temp_pt, 1, 1, false, edges);
00149           if(gen::error(MB_SUCCESS!=result,"could not get adj edges")) return result;
00150 
00151           for(Range::iterator j=edges.begin(); j!=edges.end(); j++) {
00152             const EntityHandle *conn;
00153             int n_verts;
00154             result = MBI()->get_connectivity( *j, conn, n_verts); 
00155             if(gen::error(MB_SUCCESS!=result,"could not get edge conn")) return result;
00156 
00157             if(conn[0] == conn[1]) {
00158               result = MBI()->delete_entities( &(*j), 1 );
00159               if(gen::error(MB_SUCCESS!=result,"could not delete degenerate edge")) return result;
00160             }
00161           }
00162         }
00163       } else {
00164         assert(false);
00165       }
00166       // It is possible that the endpoints themselves are orphaned. Should these
00167       // be deleted?
00168 
00169       // Remove the curve set. This also removes parent-child relationships.
00170       result = MBI()->delete_entities( &(*i), 1);
00171       if(gen::error(MB_SUCCESS!=result,"could not delete curve set")) return result;
00172       i = curve_sets.erase(i) - 1;
00173     } else {
00174 
00175       // convert the curve of edges into a curve of verts 
00176       std::vector<EntityHandle> ordered_verts;
00177       result = gen::ordered_verts_from_ordered_edges( curve_edges, ordered_verts);
00178       if(gen::error(MB_SUCCESS!=result,"could not order_verts_by_edge")) return result;
00179 
00180       // replace the unordered edges with the ordered verts
00181       result = arc::set_meshset( *i, ordered_verts );
00182       if(gen::error(MB_SUCCESS!=result,"could not set_meshset")) return result;
00183       
00184       // The edges are no longer needed.
00185       result = MBI()->delete_entities( &curve_edges[0], curve_edges.size() );
00186       if(gen::error(MB_SUCCESS!=result,"could not delete edges")) return result;
00187     }
00188   }
00189 
00190   // merge curves that are the same within facet_tol 
00191   if (verbose) std::cout << "Identifying coincident curves to be merged..." << std::endl;
00192   result = arc::merge_curves(curve_sets, FACET_TOL, id_tag, merge_tag, debug );
00193   if(gen::error(MB_SUCCESS!=result,"could not merge_curves")) return result;
00194 
00195   return MB_SUCCESS;
00196 }
00197 
00198 /* The chosen curve may need to be reversed to be in the same direction as the skin.
00199    The skin itself is not changed. */
00200     /* PROBLEM: Some sliver surfaces are smaller in every dimension than the 5x 
00201      facet_tol that the skin was found to vary within.   
00202      This method finds the average distance between a curve and skin arc. The
00203      smallest distance is the next curve. */
00207 ErrorCode create_arc_pair(  const double FACET_TOL,
00208                               const EntityHandle surf_set,
00209                               std::vector<EntityHandle> &skin_loop,
00210                               std::vector<EntityHandle> &curve_sets,
00211                               const EntityHandle front_endpt,
00212                               const bool debug,
00213                               EntityHandle &curve_set,
00214                               bool &curve_is_reversed,
00215                               std::vector<EntityHandle> &curve,
00216                               std::vector<EntityHandle> &skin_arc ) {
00217 
00218   /* Now we have a topological connection between the curve and skin. Find other
00219      curves that share this vert. Be aware if the curve is reversed so the
00220      original direction can be preserved when done zipping. */
00221   ErrorCode rval;
00222   if(debug) {
00223     std::cout << curve_sets.size() << " curves remain to be zipped" 
00224               << " skin_loop.size()=" << skin_loop.size() << " front_endpt="
00225               << front_endpt << " skin:" << std::endl; 
00226   }
00227 
00228   // initialize stuff
00229   double min_dist = std::numeric_limits<double>::max();
00230   curve_set = 0;
00231   double curve_set_idx = 0, skin_pos = 0;
00232   curve.clear();
00233   skin_arc.clear();
00234   skin_arc.reserve( skin_loop.size() );
00235   curve.reserve(    skin_loop.size() );
00236   
00237   // Compare all curves, keeping the best pair
00238   for(unsigned i=0; i<curve_sets.size(); ++i) {
00239     // get geometric vertex sets
00240     Range endpt_sets;
00241     rval = MBI()->get_child_meshsets(curve_sets[i], endpt_sets );
00242     if(gen::error(MB_SUCCESS!=rval,"could not get endpt_sets")) return rval;
00243     if(gen::error(endpt_sets.empty() || 2<endpt_sets.size(),
00244                   "too many endpt_sets")) return MB_FAILURE;
00245     // get the vertex handles
00246     std::vector<EntityHandle> endpts;
00247     for(unsigned j=0; j<endpt_sets.size(); ++j) {
00248       Range endpt;
00249       rval = MBI()->get_entities_by_type( endpt_sets[j], MBVERTEX, endpt );
00250       if(gen::error(MB_SUCCESS!=rval,"could not get endpt")) return rval;
00251       if(gen::error(1!=endpt.size(),"not one endpt")) return MB_FAILURE;
00252       endpts.push_back( endpt.front() );
00253       if(debug) std::cout << "curve " << gen::geom_id_by_handle(curve_sets[i]) 
00254                           << " endpt=" << endpt.front() << std::endl;
00255     }
00256 
00257     // if an endpt is not the front_endpt, then this curve isn't adjacent
00258     if(front_endpt!=endpts.front() && front_endpt!=endpts.back()) continue;
00259 
00260     // get the point representation
00261     std::vector<EntityHandle> temp_curve;
00262     rval = arc::get_meshset( curve_sets[i], temp_curve );
00263     if(gen::error(MB_SUCCESS!=rval,"could not get curve set")) return rval;
00264     //if(gen::error(2>temp_curve.size(),"curve is degenerate")) return MB_FAILURE;
00265     if(2>temp_curve.size()) std::cout << "warning11: curve is degenerate" << std::endl;
00266     if(debug) {
00267       std::cout << "  adj curve " << gen::geom_id_by_handle(curve_sets[i]) << ":" << std::endl; 
00268       //gen::print_loop( temp_curve );
00269     }
00270 
00271     // Get the curve-surface relative sense. From CGMA/builds/dbg/include/CubitDefines,
00272     
00273     int sense;
00274     if(debug)
00275     {
00276     std::cout << "surf_set = " << gen::geom_id_by_handle(surf_set) << std::endl;
00277     std::cout << "curve_set = " << gen::geom_id_by_handle(curve_sets[i]) << std::endl;
00278     }
00279     rval = gen::get_curve_surf_sense( surf_set, curve_sets[i], sense );
00280     if(gen::error(MB_SUCCESS!=rval,"could not get_curve_surf_sense")) return rval;
00281 
00282     // get the curve length, for efficient find_closest_vert, plus a tolerance.
00283     // This also helps to find the correct skin arc in special (~1D surfs) cases
00284     // where the closest skin pt is not the correct skin.
00285     const double temp_curve_len = gen::length(temp_curve);
00286     const double extra = 1.0;
00287 
00288     // is it forward oriented? To allow for ambiguous cases, instead of accepting
00289     // only forward-oriented curves, only reject reverse-oriented curves.
00290     if(front_endpt==temp_curve.front() && SENSE_REVERSE!=sense) {
00291       // find the closest skin pt to the curve endpt
00292       unsigned pos;
00293       // if only one curve is left, take the entire skin. Otherwise, due to 
00294       // coordinate drift via merging the closest skin pt may not be the correct one.
00295       if(1==curve_sets.size()) {
00296         pos = skin_loop.size()-1;
00297       } else {
00298         rval = gen::find_closest_vert( temp_curve.back(), skin_loop, pos, temp_curve_len+extra );
00299         if(gen::error(MB_SUCCESS!=rval,"could not find_closest_vert")) return rval;
00300       }
00301       if(debug) std::cout << "  end of skin arc=" << skin_loop[pos] << std::endl; 
00302       // SPECIAL CASE: If the skin is a circle, create an arc out of the circle
00303       if(skin_loop[pos] == skin_loop.front()) pos = skin_loop.size()-1;
00304 
00305       // create a skin arc to test against the curve
00306       std::vector<EntityHandle> temp_skin(skin_loop.begin(), skin_loop.begin()+pos+1);
00307       double d;
00308       rval = gen::dist_between_arcs( debug, temp_skin, temp_curve, d );
00309       if(gen::error(MB_SUCCESS!=rval,"could not get dist_between_arcs")) return rval;
00310       if(debug) std::cout << " curve-skin dist=" << d << std::endl;
00311  
00312       // if less than the min_dist, this curve is the best (thus far)
00313       if(d < min_dist) {
00314         min_dist          = d;
00315         curve_set         = curve_sets[i];
00316         curve_set_idx     = i;
00317         curve_is_reversed = false;
00318         curve             = temp_curve;
00319         skin_arc          = temp_skin;
00320         skin_pos          = pos;
00321       }
00322     }
00323     // is it reverse oriented?
00324     if(front_endpt==temp_curve.back() && SENSE_FORWARD!=sense) {
00325       reverse( temp_curve.begin(), temp_curve.end() );
00326       // find the closest skin pt to the curve endpt
00327       unsigned pos;
00328       // if only one curve is left, take the entire skin. Otherwise, due to 
00329       // coordinate drift via merging the closest skin pt may not be the correct one.
00330       if(1==curve_sets.size()) {
00331         pos = skin_loop.size()-1;
00332       } else {
00333         rval = gen::find_closest_vert( temp_curve.back(), skin_loop, pos, temp_curve_len+extra );
00334         if(gen::error(MB_SUCCESS!=rval,"could not find_closest_vert")) return rval;
00335       }
00336       if(debug) std::cout << "  end of skin arc=" << skin_loop[pos] << std::endl; 
00337       // SPECIAL CASE: If the skin is a circle, create an arc out of the circle
00338       if(skin_loop[pos] == skin_loop.front()) pos = skin_loop.size()-1;
00339 
00340       // create a skin arc to test against the curve
00341       std::vector<EntityHandle> temp_skin(skin_loop.begin(), skin_loop.begin()+pos+1);
00342       double d;
00343       rval = gen::dist_between_arcs( debug, temp_skin, temp_curve, d );
00344       if(gen::error(MB_SUCCESS!=rval,"could not get dist_between_arcs")) return rval;
00345       if(debug) std::cout << " curve-skin dist=" << d << std::endl;
00346 
00347       // if less than the min_dist, this curve is the best (thus far)
00348       if(d < min_dist) {
00349         min_dist          = d;
00350         curve_set         = curve_sets[i];
00351         curve_set_idx     = i;
00352         curve_is_reversed = true;
00353         curve             = temp_curve;
00354         skin_arc          = temp_skin;
00355         skin_pos          = pos;
00356       }
00357     }
00358   } // loop over all remaining curves of the surface
00359 
00360   // If no adjacent curves were found, something is wrong
00361   if(0==curve_set) {
00362     std::cout << "      no adjacent curve found" << std::endl;
00363     for(unsigned i=0; i<curve_sets.size(); ++i) {
00364       std::cout << "  curve " << gen::geom_id_by_handle(curve_sets[i]) 
00365                 << " is unsealed" << std::endl;
00366     }
00367     return MB_FAILURE;
00368   }
00369 
00370   // If the average distance between the closest skin and curve is too far...
00371   if(100*FACET_TOL<=min_dist) {
00372     std::cout << "  warning8: curve too far from skin, average_dist=" 
00373               << min_dist << std::endl;
00374     if(1.0<=min_dist) return MB_FAILURE;
00375   }
00376      
00377   // remove the chosen curve the set of unsealed curves
00378   curve_sets.erase( curve_sets.begin()+curve_set_idx );
00379 
00380   // remove the chosen skin arc from the rest of the skin
00381   skin_loop.erase( skin_loop.begin(), skin_loop.begin()+skin_pos );  
00382 
00383   // If the entire skin loop has been sectioned into arcs, a single point remains.
00384   // This is because the skin_arc needs to have the same back point as the front
00385   // of the remaining skin_loop. If a single point remains, remove it.
00386   if(1==skin_loop.size()) skin_loop.clear();
00387 
00388   if(debug) std::cout << "  curve " << gen::geom_id_by_handle(curve_set) 
00389                       << " paired with skin, min_dist =" << min_dist << std::endl;
00390   return MB_SUCCESS;
00391 }
00392 
00393 
00397 
00398 
00399 //  -Instead of altering the skin and curve vectors, make them const. Put the
00400 // sealed curve in a new vector, using only push_back. This
00401 // would avoid all of the really slow inserts and erases in the curve and skin vectors.
00402 ErrorCode seal_arc_pair( const bool debug,
00403                            const double FACET_TOL,
00404                            const Tag normal_tag,
00405                            std::vector<EntityHandle> &edge, /* in */
00406                            std::vector<EntityHandle> &skin /* in/out */,
00407                            const int surf_id ) {
00408   if(debug) {
00409     std::cout << "edge before sealing:" << std::endl;
00410     gen::print_loop(edge);
00411     std::cout << "skin before sealing:" << std::endl;
00412     gen::print_loop(skin);
00413    }
00414 
00415   ErrorCode rval;
00416   const double TOL_SQR = FACET_TOL*FACET_TOL;
00417   if(gen::error(edge.empty() || skin.empty(),"edge or skin has no verts")) 
00418     return MB_FAILURE;
00419 
00420 
00421   //**************************************************************************
00422   // Merge the front of the skin to the front of the curve
00423   //**************************************************************************
00424   {
00425     EntityHandle keep_vert   = edge.front();
00426     EntityHandle delete_vert = skin.front();
00427     if(keep_vert != delete_vert) {
00428       double merge_dist;
00429       rval = gen::dist_between_verts( keep_vert, delete_vert, merge_dist );
00430       if(gen::error(MB_SUCCESS!=rval,"could not get merge_dist g")) return rval;
00431       if(debug) {
00432         std::cout << "  merged skin_vert=" << delete_vert << " to edge_vert=" << keep_vert
00433                   << " merge_dist=" << merge_dist << std::endl;
00434       }  
00435       if(FACET_TOL < merge_dist) {
00436         std::cout << "  warning0: front pt merge_dist=" << merge_dist << std::endl;
00437       }  
00438       rval = zip::merge_verts( keep_vert, delete_vert, skin, edge );
00439       if(gen::error(MB_SUCCESS!=rval,"could not merge verts g")) return rval;
00440     }
00441   }
00442 
00443   //**************************************************************************
00444   // Merge the back of the skin to the back of the curve
00445   //**************************************************************************
00446   {
00447     EntityHandle keep_vert   = edge.back();
00448     EntityHandle delete_vert = skin.back();
00449     if(keep_vert != delete_vert) {
00450       double merge_dist;
00451       rval = gen::dist_between_verts( keep_vert, delete_vert, merge_dist );
00452       if(gen::error(MB_SUCCESS!=rval,"could not get merge_dist h")) return rval;
00453       if(debug) {
00454         std::cout << "  merged skin_vert=" << delete_vert << " to edge_vert=" << keep_vert
00455                   << " merge_dist=" << merge_dist << std::endl;
00456       }  
00457       if(FACET_TOL < merge_dist) {
00458         std::cout << "  warning0: surf " << surf_id << " back pt merge_dist=" 
00459                   << merge_dist << std::endl;
00460         if(1000*FACET_TOL < merge_dist) return MB_FAILURE;
00461       }  
00462       rval = zip::merge_verts( keep_vert, delete_vert, skin, edge );
00463       if(gen::error(MB_SUCCESS!=rval,"could not merge verts g")) return rval;
00464     }
00465   }
00466 
00467   // ************************************************************************
00468   // zip the skin to the curve until the end of the curve is reached.
00469   // ************************************************************************
00470   // Zip the edge until we reach the end of the curve.
00471   unsigned int e_pos = 1, s_pos = 1; 
00472   bool edge_is_next;
00473   double dist, e_dist, s_dist, es_dist;
00474   while(true) {
00475  
00476     // Special Case: Through merging, a curve may have only a single vertex
00477     if(e_pos==edge.size() || s_pos==skin.size()) break;
00478 
00479     rval = gen::squared_dist_between_verts( edge[e_pos-1], edge[e_pos], e_dist );
00480     if(gen::error(MB_SUCCESS!=rval,"could not get e_dist")) return rval;
00481     rval = gen::squared_dist_between_verts( edge[e_pos-1], skin[s_pos], s_dist );
00482     if(gen::error(MB_SUCCESS!=rval,"could not get s_dist")) return rval;
00483     if(debug) {
00484       std::cout << " e_pos=" << e_pos << " e_dist=" 
00485                 << e_dist << " vert=" << edge[e_pos] << " size="
00486                 << edge.size() << std::endl;
00487       std::cout << " s_pos=" << s_pos << " s_dist=" 
00488                 << s_dist << " vert=" << skin[s_pos] << " size="
00489                 << skin.size() << std::endl;
00490     }
00491 
00492     // If skin is next, move the skin pt to the line extending from the next 
00493     // curve edge.
00494     if(e_dist > s_dist) {
00495       edge_is_next = false;
00496       double move_dist;
00497       rval = gen::line_point_dist( edge[e_pos-1], edge[e_pos], skin[s_pos], move_dist );
00498       if(gen::error(MB_SUCCESS!=rval,"could not get line_point_dist")) return rval;
00499       if(10*FACET_TOL < move_dist) {
00500         std::cout << "  warning5: surf " << surf_id << " vertex move_dist=" 
00501                   << move_dist << std::endl;
00502       }
00503       rval = gen::point_line_projection( edge[e_pos-1], edge[e_pos], skin[s_pos]);
00504       if(gen::error(MB_SUCCESS!=rval,"could not get point_line_projection")) return rval;
00505       rval = gen::squared_dist_between_verts( edge[e_pos-1], skin[s_pos], s_dist );
00506       if(gen::error(MB_SUCCESS!=rval,"could not get s_dist b")) return rval;
00507       dist = s_dist;
00508       if(debug) std::cout << "skin is next, projected dist=" << dist << std::endl;
00509     } else {
00510       edge_is_next = true;
00511       dist = e_dist;
00512       if(debug) std::cout << "edge is next" << std::endl;
00513     }
00514 
00515     // find the cs_dist after moving the skin to the curve (if skin_is_next)
00516     rval = gen::squared_dist_between_verts( edge[e_pos], skin[s_pos], es_dist );
00517     if(gen::error(MB_SUCCESS!=rval,"could not get es_dist")) return rval;
00518   
00519     // **************************************************************************
00520     // Merge with previous vert if it is too close
00521     // **************************************************************************
00522     if(dist < TOL_SQR) {
00523       EntityHandle keep_vert = edge[e_pos-1];
00524       if(edge_is_next) {
00525         EntityHandle delete_vert = edge[e_pos];
00526         if(keep_vert != delete_vert) { // cannot merge the same vert
00527           if(debug) {
00528             double merge_dist;
00529             rval = gen::dist_between_verts( keep_vert, delete_vert, merge_dist );
00530             if(gen::error(MB_SUCCESS!=rval,"could not get merge_dist")) return rval;
00531             std::cout << "  merged edge_vert=" << delete_vert << " to edge_vert=" 
00532                       << keep_vert << " merge_dist=" << merge_dist <<std::endl;
00533           }  
00534           rval = zip::merge_verts( keep_vert, delete_vert, skin, edge );
00535           if(gen::error(MB_SUCCESS!=rval,"could not merge_verts a")) return rval;
00536         }
00537         if(edge.size() < e_pos+1) {
00538           std::cout << "edge.size()=" << edge.size() << " e_pos=" << e_pos << std::endl;
00539         }
00540         edge.erase( edge.begin() + e_pos );
00541       } else {
00542         EntityHandle delete_vert = skin[s_pos];
00543         if(keep_vert != delete_vert) {
00544           if(debug) {
00545             double merge_dist;
00546             rval  = gen::dist_between_verts( keep_vert, delete_vert, merge_dist );
00547             if(gen::error(MB_SUCCESS!=rval,"could not get merge_dist b")) return rval;
00548             std::cout << "  merged skin_vert=" << delete_vert << " to edge_vert=" 
00549                       << keep_vert << " merge_dist=" << merge_dist << std::endl;  
00550           } 
00551           rval = zip::merge_verts( keep_vert, delete_vert, skin, edge );
00552           if(gen::error(MB_SUCCESS!=rval,"could not merge_verts b")) return rval;
00553         }
00554         if(skin.size() < s_pos+1) {
00555           std::cout << "skin.size()=" << skin.size() << " s_pos=" << s_pos << std::endl;
00556         }
00557         skin.erase( skin.begin() + s_pos );      
00558       }
00559       // **************************************************************************
00560       // merge with next vert if it is too close
00561       // **************************************************************************
00562       // If the next hits are at the same distance or within merge tol, 
00563       //   advance the curve ahead. We need to merge all the verts between the
00564       //   current skin vert and the curve vert that we are merging to. This
00565       //   could be more than one! 
00566       //} else if(FACET_TOL > fabs(c_dist-s_dist)) {
00567     } else if(TOL_SQR > es_dist) {
00568       // merge the verts if they are not the same
00569       EntityHandle keep_vert  = edge[e_pos];
00570       if(skin[s_pos] != keep_vert) {
00571         EntityHandle delete_vert= skin[s_pos];
00572         if(debug) {
00573           double merge_dist;
00574           rval  = gen::dist_between_verts( keep_vert, delete_vert, merge_dist );
00575           if(gen::error(MB_SUCCESS!=rval,"could not get merge_dist c")) return rval;
00576           std::cout << "  merged skin_vert=" << delete_vert << " to edge_vert=" 
00577                     << keep_vert << " merge_dist=" << merge_dist << std::endl;
00578         }
00579         rval = zip::merge_verts( keep_vert, delete_vert, skin, edge );
00580         if(gen::error(MB_SUCCESS!=rval,"could not merge_verts b")) return rval;
00581       }
00582       s_pos++;
00583       e_pos++;
00584       // Are there more skin verts in proximity to the merged pt?
00585       while(true) {
00586         // check to see if skin still exists
00587         if(s_pos == skin.size()) break;
00588         // check if the distance is less than merge tol
00589         EntityHandle delete_vert= skin[s_pos];
00590         double merge_dist;
00591         rval = gen::dist_between_verts( keep_vert, delete_vert, merge_dist); 
00592         if(gen::error(MB_SUCCESS!=rval,"could not get merge_dist d")) return rval;
00593         if(FACET_TOL < merge_dist) break;
00594         // merge the verts if they are not the same
00595         if(keep_vert != delete_vert) {
00596           if(debug) {
00597             std::cout << "  merged skin_vert=" << delete_vert << " to edge_vert=" 
00598                       << keep_vert << " merge_dist=" << merge_dist << std::endl;
00599           }
00600           rval = zip::merge_verts( keep_vert, delete_vert, skin, edge );
00601           if(gen::error(MB_SUCCESS!=rval,"could not merge_verts d")) return rval;
00602         }
00603         skin.erase( skin.begin() + s_pos );      
00604       }
00605       // Are there more curve verst in proximity to the merged pt?
00606       while(true) {
00607         // check to see if curve still exists
00608         if(e_pos == edge.size()) break;
00609         // check if the distance is less than merge tol
00610         EntityHandle delete_vert= edge[e_pos];
00611         double merge_dist;
00612         rval = gen::dist_between_verts( keep_vert, delete_vert, merge_dist ); 
00613         if(gen::error(MB_SUCCESS!=rval,"could not get merge_dist e")) return rval;
00614         if(FACET_TOL < merge_dist) break;
00615         // merge the verts if they are not the same
00616         if(keep_vert != delete_vert) {
00617           if(debug) {
00618             std::cout << "  merged edge_vert=" << delete_vert << " to edge_vert=" 
00619                       << keep_vert << " merge_dist=" << merge_dist << std::endl;
00620           }
00621           rval = zip::merge_verts( keep_vert, delete_vert, skin, edge );
00622           if(gen::error(MB_SUCCESS!=rval,"could not merge_verts e")) return rval;
00623         }
00624         edge.erase( edge.begin() + e_pos );
00625       }
00626           
00627       // **************************************************************************
00628       // Otherwise do a t_joint
00629       // **************************************************************************
00630     } else {
00631       if(edge_is_next) {
00632         if(debug) {
00633           std::cout << "  zip phase: t_joint is inserting edge vert " 
00634                     << edge[e_pos] << " between edge vert " << edge[e_pos-1] 
00635                     << " and skin vert " << skin[s_pos] << std::endl;
00636         }
00637         double move_dist;
00638         rval = gen::line_point_dist( edge[e_pos-1], skin[s_pos], edge[e_pos], move_dist );
00639         if(gen::error(MB_SUCCESS!=rval,"could not get line_point_dist")) return rval;
00640         if(10*FACET_TOL < move_dist) {
00641           std::cout << "  warning6: surf " << surf_id << " vertex move_dist=" 
00642                     << move_dist << std::endl;
00643         }
00644         rval = zip::t_joint( normal_tag, edge[e_pos-1], edge[e_pos], skin[s_pos], debug );
00645         if(gen::error(MB_SUCCESS!=rval,"tjoint failed a")) return rval;
00646         skin.insert( skin.begin()+s_pos, edge[e_pos] );
00647         e_pos++;
00648         s_pos++;
00649       } else { // skin is next: move the t to the curve
00650         if(debug) {
00651           std::cout << "  zip phase: inserting projected skin vert " 
00652                     << skin[s_pos] << " between edge verts " 
00653                     << edge[e_pos-1] << " and " << edge[e_pos] << std::endl;
00654         }
00655         double move_dist;
00656         rval = gen::line_point_dist( edge[e_pos-1], edge[e_pos], skin[s_pos], move_dist );
00657         if(gen::error(MB_SUCCESS!=rval,"could not get line_point_dist")) return rval;
00658         if(10*FACET_TOL < move_dist) {
00659           std::cout << "  warning6: surf " << surf_id << " vertex move_dist=" 
00660                     << move_dist << std::endl;
00661         }
00662         rval = zip::t_joint( normal_tag, edge[e_pos-1], skin[s_pos], edge[e_pos], debug );
00663         if(gen::error(MB_SUCCESS!=rval,"tjoint failed b")) return rval;
00664         edge.insert( edge.begin() + e_pos, skin[s_pos] );
00665         e_pos++;
00666         s_pos++;
00667       }
00668     }
00669 
00670 
00671     // exit if at the end of the curve
00672     if(e_pos==edge.size() || s_pos==skin.size()) break;
00673 
00674     // The smallest edge length should be no less than MERGE_TOL.
00675     if(2 <= e_pos) {
00676       double d;
00677       rval = gen::squared_dist_between_verts( edge[e_pos-1], edge[e_pos-2], d );
00678       if(gen::error(MB_SUCCESS!=rval,"could not get dist")) return rval;
00679       if(TOL_SQR > d) { 
00680         std::cout << "zip_loop: d=" << d << std::endl;
00681         gen::print_vertex_coords(edge[e_pos-1]);
00682         gen::print_vertex_coords(edge[e_pos-2]);
00683         std::cout << "warning7: surf " << surf_id 
00684                   << " adjacent edge points are closer than FACET_TOL" << std::endl;
00685       }
00686     }
00687     // The position should be the same. Do not exceed array bounds when checking.
00688     if(gen::error(e_pos!=s_pos,"skin and edge positions do not match")) return rval;
00689     if(edge[e_pos-1] != skin[s_pos-1]) {
00690       std::cout << "edge[" << e_pos-1 << "]=" << edge[e_pos-1]
00691                 << " skin[" << s_pos-1 << "]=" << skin[s_pos-1] << std::endl;
00692     }
00693     if(gen::error(edge[e_pos-1]!=skin[s_pos-1],"skin and edge vert does not match")) 
00694       return rval;
00695   }
00696 
00697   // The skin and curve should be the same size
00698   if(edge.size()!=skin.size()) {
00699     std::cout << "    surf " << surf_id 
00700               << " sealed skin and curve are not the same size" << std::endl;
00701     if(debug) {
00702       std::cout << "edge:" << std::endl;
00703       gen::print_loop(edge);
00704       std::cout << "skin:" << std::endl;
00705       gen::print_loop(skin);
00706     }
00707     //return MB_FAILURE;
00708   }
00709 
00710   if(debug) {
00711     std::vector< std::vector<EntityHandle> > temp;
00712     temp.push_back(edge);
00713     temp.push_back(skin);
00714     rval = zip::test_zipping(FACET_TOL, temp);
00715     if(gen::error(MB_SUCCESS!=rval,"sealing test failed")) return rval;
00716   }
00717 
00718   return MB_SUCCESS;
00719 
00720 }
00721 
00723 ErrorCode seal_loop( bool debug,
00724                        const double FACET_TOL,
00725                        const Tag normal_tag,
00726                        const Tag orig_curve_tag,
00727                        const EntityHandle surf_set,
00728                        std::vector<EntityHandle> &curve_sets,
00729                        std::vector<EntityHandle> &skin_loop,
00730                        bool verbose) {
00731   ErrorCode rval;
00732   debug = false;
00733   // Find a curve that corresponds to the skin. Note that because there is more
00734   // than one skin loop, not all curves of the surface correspond to each skin
00735   // Loop.
00736 
00737   // To establish an inital connection, find the curve with endpoint closest
00738   // to a skin point.
00739   if(debug) std::cout << "seal_loop: new loop contains " << skin_loop.size() 
00740                       << " skin pts" << std::endl;
00741    
00742   // If skin remains but all the curves are zipped an error has occured.
00743   if( curve_sets.empty() ) {
00744     std::cout << "seal_loop: no curves are left, but skin remains" << std::endl;
00745     gen::print_loop(skin_loop);
00746     skin_loop.clear();
00747     return MB_FAILURE;
00748   }
00749 
00750   //**************************************************************************
00751   // choose the closest curve endpoint and align the loop with it
00752   //**************************************************************************
00753   /* Find the closest skin pt to the first curve's front endpt.
00754      MAJOR DESIGN PUSHER: The curves cannot be assembled into loops without
00755      knowing orientation (which we don't know). Instead this information is
00756      pulled from the skin loops. This is why we do not first create loops from
00757      curves. 
00758 
00759      If zipping fails, the failed loop and curve are deleted from the candidate
00760      set of things to be zipped. It is likely that curves of the failed zip
00761      still exist even though their corresponding loop has been removed. Not all
00762      curves in this list will ever be zipped. Select a curve that can be zipped. */
00763     unsigned pos = 0, curve_idx = 0;
00764     EntityHandle closest_skin_pt = 0, closest_front_curve_endpt = 0;
00765     double min_dist = std::numeric_limits<double>::max();
00766     for(unsigned i=0; i<curve_sets.size(); ++i) {
00767       // get geometric vertices
00768       Range endpt_sets;
00769       rval = MBI()->get_child_meshsets(curve_sets[i], endpt_sets );
00770       if(gen::error(MB_SUCCESS!=rval,"could not get endpt_sets")) return rval;
00771       if(gen::error(endpt_sets.empty() || 2<endpt_sets.size(),
00772                     "too many endpt_sets")) return MB_FAILURE;
00773 
00774       std::vector<EntityHandle> endpts;
00775       for(unsigned j=0; j<endpt_sets.size(); ++j) {
00776         Range endpt;
00777         rval = MBI()->get_entities_by_type( endpt_sets[j], MBVERTEX, endpt );
00778         if(gen::error(MB_SUCCESS!=rval,"could not get endpt")) return rval;
00779         if(gen::error(1!=endpt.size(),"not one endpt")) return MB_FAILURE;
00780         endpts.push_back( endpt.front() );
00781       }
00782 
00783       // check to ensure that the endpt sets aren't degenerate
00784 
00785       if(2==endpt_sets.size() && endpts.front()==endpts.back() && debug ) {
00786 
00787         std::cout << "  warning9: curve " << gen::geom_id_by_handle(curve_sets[i]) 
00788                   << " geometric endpoints degenerate" << std::endl;
00789       }
00790       
00791       // check to ensure that geometric verts are the curve endpts
00792       std::vector<EntityHandle> curve;
00793       rval = arc::get_meshset( curve_sets[i], curve );
00794       if(gen::error(MB_SUCCESS!=rval,"could not get_meshset")) return rval;
00795       if(1==endpt_sets.size()) {
00796         if(gen::error(curve.front()!=curve.back(),"endpt discrepancy")) return MB_FAILURE;
00797         if(gen::error(curve.front()!=endpts.front(),
00798           "geometric verts inconsistent with curve")) return MB_FAILURE;
00799       } else {
00800         if(curve.front()==curve.back()) 
00801           if(debug) std::cout << "  warning10: degenerate curve endpts" << std::endl;
00802         if(gen::error(curve.front()!=endpts.front() && curve.front()!=endpts.back(),
00803                       "endpts not consistent")) return MB_FAILURE;
00804         if(gen::error(curve.back()!=endpts.front() && curve.back()!=endpts.back(),
00805                       "endpts not consistent")) return MB_FAILURE;
00806       }
00807 
00808       // determine the orientation of the curve wrt the surf.
00809       int sense;
00810       if(debug)
00811       {
00812       std::cout << "surf_set = " << gen::geom_id_by_handle(surf_set) << std::endl;
00813       std::cout << "curve_set = " << gen::geom_id_by_handle(curve_sets[i]) << std::endl;
00814       }
00815       rval = gen::get_curve_surf_sense( surf_set, curve_sets[i], sense );  
00816       if(gen::error(MB_SUCCESS!=rval,"could not get_curve_surf_sense")) return rval;
00817       // select the front wrt the skin.
00818       EntityHandle curve_endpt = (SENSE_FORWARD==sense) ? curve.front() : curve.back();
00819 
00820       // find closest skin vert to front of curve
00821       std::vector<double> d;
00822       std::vector<unsigned> p;
00823       rval = gen::find_closest_vert( 0, curve_endpt, skin_loop, p, d);
00824       if(gen::error(MB_SUCCESS!=rval,"could not find_closest_vert")) return rval;
00825       if(debug) std::cout << "zip_loop: loop-curve endpt dist=" << d.front() << " skin_vert="
00826                           << skin_loop[p.front()] << " curve="
00827                           << gen::geom_id_by_handle(curve_sets[i]) << " front_endpt="
00828                           << curve_endpt << std::endl;
00829       if(d.front() < min_dist) {
00830         min_dist = d.front();
00831         curve_idx = i;
00832         pos = p.front();
00833         closest_front_curve_endpt = curve_endpt;
00834         closest_skin_pt = skin_loop[p.front()];
00835       }
00836     }
00837 
00838     EntityHandle front_endpt = closest_front_curve_endpt;
00839 
00840     // The closest points should be within facet tolerance
00841     if(100*FACET_TOL<min_dist && verbose) {
00842       std::cout << "closest skin pt farther than 100*FACET_TOL from curve vert (" 
00843                 << min_dist << ")" << std::endl; 
00844       if(true) {
00845         std::cout << "  skin pt:" << std::endl;
00846         rval = MBI()->list_entity(closest_skin_pt);
00847         if(gen::error(MB_SUCCESS!=rval,"error listing skin pt")) return rval;
00848         std::cout << "  curve vert:" << std::endl;
00849         rval = MBI()->list_entity(front_endpt);
00850         if(gen::error(MB_SUCCESS!=rval,"error listing curve_vert")) return rval;
00851       }
00852       return rval;
00853     }
00854 
00855     if(debug) {
00856       std::cout << "closest skin vert=" << skin_loop[pos] << " pos=" << pos 
00857                 << " min_dist=" << min_dist << " curve=" 
00858                 << gen::geom_id_by_handle(curve_sets[curve_idx]) 
00859                 << " front_endpt=" << closest_front_curve_endpt << std::endl;
00860     }
00861 
00862     /* Take the skin loops and advance it such that our common point is at 
00863        location 0. Ensure that that both endpoints are the same. */
00864     std::vector<EntityHandle> temp_loop;
00865     temp_loop.reserve(skin_loop.size());
00866     std::vector<EntityHandle>::iterator j = temp_loop.begin();
00867     std::vector<EntityHandle>::iterator k = skin_loop.begin();
00868     // Do not insert the back endpoint (avoid duplicate).   
00869     temp_loop.insert( j, k+pos, k+skin_loop.size()-1 );
00870     j = temp_loop.begin(); // j became invalid because temp_loop resized
00871     j += skin_loop.size() - pos - 1;
00872     temp_loop.insert( j, k, k+pos+1 );
00873     if(gen::error(temp_loop.size()!=skin_loop.size(),"loop size not conserved")) return MB_FAILURE;
00874     assert(temp_loop.size() == skin_loop.size()); // same size
00875     if(gen::error(temp_loop[0]!=temp_loop[temp_loop.size()-1],
00876       "loop endpts not continuous")) return MB_FAILURE;
00877     assert(temp_loop[0] == temp_loop[temp_loop.size()-1]); // same endpoint
00878     skin_loop = temp_loop;
00879     if(debug) {
00880       std::cout << "  skin:" << std::endl;
00881     }
00882 
00883     // Create a set to store skin_loop so that handles are updated during merging.
00884     // This prevents stale handles, and avoids O(n) search through every handle in
00885     // the skin loop if manually updating the skin_loop vector.
00886     EntityHandle skin_loop_set;
00887     rval = MBI()->create_meshset( MESHSET_TRACK_OWNER|MESHSET_ORDERED, skin_loop_set );
00888     if(gen::error(MB_SUCCESS!=rval,"creating skin_loop_set failed")) return rval;
00889 
00890     while(!skin_loop.empty()) {
00891       //**************************************************************************
00892       // Select the curve adjacent to the common point that best matches the skin 
00893       // using average distance. Chop the corresponding arc of skin, to form a
00894       // curve-skin_arc pair.
00895       //**************************************************************************
00896 
00897       bool curve_is_reversed;
00898       EntityHandle curve_set;
00899       std::vector<EntityHandle> curve, skin_arc;
00900       rval = create_arc_pair( FACET_TOL, surf_set, skin_loop, curve_sets, front_endpt,
00901                               debug, curve_set, curve_is_reversed, curve, skin_arc );
00902       if(gen::error(MB_SUCCESS!=rval,"  pair creation failed")) return rval;
00903 
00904       // Let moab store skin loop to avoid stale vert handles from merging.
00905       rval = arc::set_meshset( skin_loop_set, skin_loop );    
00906       if(gen::error(MB_SUCCESS!=rval,"setting skin_loop_set failed")) return rval;
00907 
00908       // The original faceted curves are never used. Instead they are replaced by
00909       // skin. This reduces the number of new triangles created.
00910       int orig_curve;
00911       rval = MBI()->tag_get_data( orig_curve_tag, &curve_set, 1, &orig_curve );
00912       if(gen::error(MB_SUCCESS!=rval,"can't get tag")) return rval;
00913 
00914       // If the tag is non-zero, the facet edge has already been replaced.
00915       if(orig_curve) {
00916         // this tag is used to mark the edge as updated
00917         int false_int = 0;
00918         rval = MBI()->tag_set_data( orig_curve_tag, &curve_set, 1, &false_int );
00919         if(gen::error(MB_SUCCESS!=rval,"can't set tag")) return rval;
00920 
00921         // merge new endpoints to old endpoints  
00922         if(curve.front()!=skin_arc.front()) {
00923           rval = zip::merge_verts( curve.front(), skin_arc.front(), curve, skin_arc );
00924           if(gen::error(MB_SUCCESS!=rval,"merge verts failed")) return rval;
00925         }
00926         if(curve.back()!=skin_arc.back()) {
00927           rval = zip::merge_verts( curve.back(), skin_arc.back(), curve, skin_arc );
00928           if(gen::error(MB_SUCCESS!=rval,"merge verts failed")) return rval;
00929         }
00930 
00931         // replace the faceted edge with a skin arc
00932         curve = skin_arc;
00933         if(debug) std::cout << "  curve " << gen::geom_id_by_handle(curve_set) 
00934                             << " has been replaced by skin:" << std::endl;
00935 
00936       } else {
00937         // seal the pair together
00938         std::vector<EntityHandle> sealed_curve;
00939         rval = seal_arc_pair( debug, FACET_TOL, normal_tag, curve, skin_arc,
00940                               gen::geom_id_by_handle(surf_set) );
00941         if(gen::error(MB_SUCCESS!=rval, "    can't seal pair")) return rval;
00942       }
00943 
00944       // get new front_endpt to guide selection of next curve
00945       front_endpt = curve.back();
00946      
00947       // To preserve the original rotation, reverse the curve if it has been reversed
00948       if(curve_is_reversed) reverse( curve.begin(), curve.end() );        
00949 
00950       // set the sealed edge
00951       rval = arc::set_meshset( curve_set, curve );    
00952       if(gen::error(MB_SUCCESS!=rval,"setting curve set failed")) return rval;
00953 
00954       // Get skin_loop to cut an arc from it
00955       rval = arc::get_meshset( skin_loop_set, skin_loop );    
00956       if(gen::error(MB_SUCCESS!=rval,"getting skin_loop set failed")) return rval;
00957 
00958       
00959     }
00960 
00961     // The skin_loop_set is no longer needed.
00962     rval = MBI()->delete_entities( &skin_loop_set, 1 );
00963     if(gen::error(MB_SUCCESS!=rval,"deleting skin_loop_set failed")) return rval;
00964 
00965     return MB_SUCCESS;
00966   }
00967 
00968   // input: surface sets, ordered curve sets,
00969   // output: skin arcs corresponding to curves are added to parent surface sets
00970 ErrorCode prepare_surfaces(Range &surface_sets,
00971                              Tag geom_tag, Tag id_tag, Tag normal_tag, Tag merge_tag,
00972                              Tag orig_curve_tag,
00973                              const double SME_RESABS_TOL, const double FACET_TOL, 
00974                              const bool debug, bool verbose) 
00975 {
00976    
00977     ErrorCode result;
00978     // loop over each surface meshset
00979     for(Range::iterator i=surface_sets.begin(); i!=surface_sets.end(); i++ )
00980       {
00981 
00982         // get the surf id of the surface meshset
00983         int surf_id;
00984         result = MBI()->tag_get_data( id_tag, &(*i), 1, &surf_id );
00985         if(gen::error(MB_SUCCESS!=result,"could not get id tag")) return result;
00986         assert(MB_SUCCESS == result);
00987         if(debug) std::cout << "  surf id= " << surf_id << std::endl;
00988 
00989         // get the 2D entities in the surface set
00990         Range dim2_ents;
00991         result = MBI()->get_entities_by_dimension( *i, 2, dim2_ents );
00992         if(gen::error(MB_SUCCESS!=result,"could not get 3D entities")) return result;
00993         assert(MB_SUCCESS == result);
00994 
00995         // get facets of the surface meshset
00996         Range tris;
00997         result = MBI()->get_entities_by_type( *i, MBTRI, tris );
00998         if(gen::error(MB_SUCCESS!=result,"could not get tris")) return result;
00999         assert(MB_SUCCESS == result);
01000 
01001         // Remove any 2D entities that are not triangles. This is needed because
01002         // ReadCGM will add quads and polygons to the surface set. This code only
01003         // works with triangles.
01004         Range not_tris = subtract( dim2_ents, tris );
01005         if(!not_tris.empty()) {
01006         result = MBI()->delete_entities( not_tris );
01007         if(gen::error(MB_SUCCESS!=result,"could not delete not_tris")) return result;
01008         assert(MB_SUCCESS == result);
01009         std::cout << "  removed " << not_tris.size() 
01010                   << " 2D elements that were not triangles from surface " 
01011                   << surf_id << std::endl;
01012         }
01013 
01014         // Get the curves and determine the number of unmerged curves
01015         std::vector<EntityHandle> curve_sets, unmerged_curve_sets;
01016         result = get_unmerged_curves( *i , curve_sets, unmerged_curve_sets, merge_tag, verbose, debug);
01017         if(gen::error(MB_SUCCESS!=result, " could not get the curves and unmerged curves" )) return result;
01018       
01019 
01020         // If all of the curves are merged, remove the surfaces facets.
01021         if(unmerged_curve_sets.empty()) {
01022        
01023           result = gen::delete_surface( *i , geom_tag, tris, surf_id, debug, verbose); 
01024           if( gen::error(MB_SUCCESS!=result, "could not delete surface" )) return result;
01025           // adjust iterator so *i is still the same surface
01026           i = surface_sets.erase(i) - 1;
01027           continue;
01028         }
01029 
01030         // combine merged curve's surface senses
01031         result = gen::combine_merged_curve_senses( curve_sets, merge_tag, debug );
01032         if(gen::error(MB_SUCCESS!=result,"could not combine the merged curve sets")) return result;
01033 
01034 
01035         // Save the normals of the facets. These will later be used to determine if 
01036         // the tri became inverted.
01037         result = gen::save_normals( tris, normal_tag );
01038         if(gen::error(MB_SUCCESS!=result,"could not save_normals")) return result;
01039         assert(MB_SUCCESS == result);
01040   
01041         // Check if edges exist
01042         int n_edges;
01043         result = MBI()->get_number_entities_by_type(0, MBEDGE, n_edges );
01044         if(gen::error(MB_SUCCESS!=result,"could not get number of edges")) return result;
01045         assert(MB_SUCCESS == result);
01046         if(gen::error(0!=n_edges,"edges exist")) return result;
01047         assert(0 == n_edges); //*** Why can't we have edges? (Also, this assertion is never used)
01048 
01049         // get the range of skin edges from the range of facets
01050         Skinner tool(MBI());
01051         Range skin_edges, skin_edges2;
01052         if(tris.empty()) continue; // nothing to zip
01053         // The MOAB skinner is not used here currently as it doesn't allow
01054         // make_watertight to close loops. The local version of find_skin is used instead. 
01055         // This should be ok as the local find_skin fundtion should only be avoided when checking meshes for watertightness
01056         // to keep from altering the data set when checking. 
01057         result = tool.find_skin( 0, tris, 1, skin_edges, false);
01058         if(gen::error(MB_SUCCESS!=result,"could not find_skin")) return result;
01059         assert(MB_SUCCESS == result);
01060      
01061 
01062         // merge the vertices of the skin
01063         // BRANDON: For some reason cgm2moab does not do this? This was the 
01064         // problem with mod13 surf 881. Two skin verts were coincident. A tol=1e-10
01065         // found the verts, but tol=0 did not.
01066         Range skin_verts;
01067         bool cont = false;
01068         result = merge_skin_verts( skin_verts, skin_edges, SME_RESABS_TOL, surf_id, cont, debug);
01069         if(gen::error(MB_SUCCESS!=result,"could not merge the skin verts")) return result;
01070         if(cont) continue;
01071 
01072 
01073         // take skin edges and create loops of vertices
01074         std::vector < std::vector <EntityHandle> > skin;
01075         cont = false;
01076         result = create_skin_vert_loops ( skin_edges, tris, skin , surf_id, cont, debug);
01077         if(gen::error(MB_SUCCESS!=result, " could not create skin loops of vertices")) return result;
01078         if(cont) continue;
01079 
01080 
01081 // separate the remainder into a new function seal surface??
01082 
01083 // separate this part from prepare surfaces into make_mesh_watertight??
01084 
01085 
01086         EntityHandle *skin_loop_sets = new EntityHandle[skin.size()];
01087         result = seal_surface_loops ( *i , skin_loop_sets , skin,  curve_sets, normal_tag, orig_curve_tag, FACET_TOL, surf_id, debug);
01088         if(gen::error(MB_SUCCESS!=result,"could not seal the surface loops")) {
01089           delete [] skin_loop_sets;
01090           return result;
01091         }
01092 
01093     
01094         // Remove the sets of skin loops
01095         result = MBI()->delete_entities( &skin_loop_sets[0], skin.size() );
01096         if(gen::error(MB_SUCCESS!=result,"failed to zip: deleting skin_loop_sets failed")){
01097           delete [] skin_loop_sets;
01098           return result;
01099         }
01100 
01101         delete [] skin_loop_sets;
01102 
01103       } // loop over each surface
01104       return MB_SUCCESS;
01105     }
01106 
01107 
01108 ErrorCode fix_normals(Range surface_sets, Tag id_tag, Tag normal_tag, const bool debug, const bool verbose) {
01109     ErrorCode result;
01110     if(debug) std::cout<< "number of surfaces=" << surface_sets.size() << std::endl;
01111     int inverted_tri_counter = 0;
01112 
01113     // loop over each surface meshset
01114     for(Range::iterator i=surface_sets.begin(); i!=surface_sets.end(); i++ ) {
01115 
01116       // get the surf id of the surface meshset
01117       int surf_id;
01118       result = MBI()->tag_get_data( id_tag, &(*i), 1, &surf_id );
01119       assert(MB_SUCCESS == result);
01120       if(debug) std::cout << "fix_normals surf id=" << surf_id << std::endl;
01121 
01122       // get facets from the surface meshset
01123       Range tris;
01124       result = MBI()->get_entities_by_type( *i, MBTRI, tris );
01125       assert(MB_SUCCESS == result);
01126 
01127       // get the normals, pre zipping
01128       std::vector<CartVect> old_normals(tris.size()), new_normals(tris.size());
01129       result = MBI()->tag_get_data( normal_tag, tris, &old_normals[0]);
01130       assert(MB_SUCCESS == result);
01131 
01132       // get the normals, post zipping
01133       result = gen::triangle_normals( tris, new_normals );
01134       assert(MB_SUCCESS == result);
01135 
01136       // test the normals, finding the inverted tris
01137       std::vector<int> inverted_tri_indices;
01138       result = zip::test_normals( old_normals, new_normals, inverted_tri_indices);
01139       assert(MB_SUCCESS == result);
01140 
01141       // insert the inverted tris into a range
01142       Range inverted_tris;
01143       for(unsigned int j=0; j<inverted_tri_indices.size(); j++) {
01144         inverted_tris.insert( tris[inverted_tri_indices[j]] );
01145         if(debug) gen::print_triangle( tris[inverted_tri_indices[j]], false );
01146       }
01147 
01148       // do edges exist?
01149       int n_edges;
01150       result = MBI()->get_number_entities_by_type( 0, MBEDGE, n_edges );
01151       assert(MB_SUCCESS == result);
01152       assert(0 == n_edges); // *** Why can't we have edges?
01153   
01154       // fix the inverted tris
01155       inverted_tri_counter += inverted_tris.size();
01156       result = zip::remove_inverted_tris(normal_tag, inverted_tris, debug );
01157       if(MB_SUCCESS != result)
01158         std::cout << "  failed to fix inverted triangles in surface " << surf_id << std::endl;
01159 
01160       // if fix_normals exits on an error, we still need to remove its edges
01161       result = delete_all_edges();
01162       assert(MB_SUCCESS == result);
01163     }
01164     if(verbose)
01165     {
01166     std::cout << "  Before fixing, " << inverted_tri_counter 
01167               << " inverted triangles were found." << std::endl;
01168     }
01169     return MB_SUCCESS;
01170   }
01171 
01172   ErrorCode restore_moab_curve_representation( const Range curve_sets ) {
01173     ErrorCode result;
01174     for(Range::const_iterator i=curve_sets.begin(); i!=curve_sets.end(); ++i) {
01175       // get the ordered verts
01176       std::vector<EntityHandle> ordered_verts;
01177       result = arc::get_meshset( *i, ordered_verts );
01178       assert(MB_SUCCESS==result);
01179       if(MB_SUCCESS != result) return result;
01180 
01181       // Check for duplicate verts. This should not happen, but could if line
01182       // surfaces exist. This happens when feature size is violated and skin
01183       // from curves on the other side of the 1D line surf gets sealed. 
01184       if( 1<ordered_verts.size() ) {
01185         for(std::vector<EntityHandle>::iterator j=ordered_verts.begin()+1;
01186             j!=ordered_verts.end(); ++j) {
01187           if( *j == *(j-1) ) {
01188             std::cout << "duplicate vertex found in curve " 
01189                       << gen::geom_id_by_handle(*i) << std::endl;
01190             j = ordered_verts.erase(j) - 1;
01191           }
01192         }
01193       }
01194 
01195       // Check for a point curve (should never happen),
01196       // a single degenerate edge (should never happen), or
01197       // a degenerate loop of two edges (should never happen)
01198       if( 4>ordered_verts.size() && 
01199           ordered_verts.front()==ordered_verts.back() ) {
01200         std::cout << "warning: curve " << gen::geom_id_by_handle(*i) 
01201                   << " is one degenerate edge" << std::endl;
01202         //return MB_FAILURE; **** when this is uncommented, problems occur
01203       }
01204 
01205       // Determine if the curve is a loop or point curve. At least 4 verts are
01206       // needed to form a loop.
01207       bool is_loop = ( ordered_verts.front()==ordered_verts.back() &&
01208                        3<ordered_verts.size() );
01209 
01210       // get geometric endpoint sets of the curve (may be stale)
01211       Range endpt_sets;
01212       result = MBI()->get_child_meshsets( *i, endpt_sets );
01213       assert(MB_SUCCESS==result);
01214       if(MB_SUCCESS != result) return result;
01215 
01216       // do the correct number of endpt sets exist?
01217       const unsigned int n_endpts = (is_loop) ? 1 : 2;
01218       if(n_endpts != endpt_sets.size()) {
01219         std::cout << "curve " << gen::geom_id_by_handle(*i) << " has " << n_endpts 
01220                   << " endpoints, but " << endpt_sets.size()
01221                   << " endpoint sets exist" << std::endl;
01222       }
01223 
01224       // do they match the current endpoints?
01225       for(Range::iterator j=endpt_sets.begin(); j!=endpt_sets.end(); ++j) {
01226         Range endpt_vert;
01227         result = MBI()->get_entities_by_handle( *j, endpt_vert );
01228         if(MB_SUCCESS != result) return result;
01229         assert(MB_SUCCESS==result);
01230         if(1 != endpt_vert.size()) {
01231           std::cout << "curve " << gen::geom_id_by_handle(*i) 
01232                     << " has" << endpt_vert.size() 
01233                     << " endpoint vertices in the geometric vertex set" << std::endl;     
01234           return MB_INVALID_SIZE;
01235         }
01236         if(endpt_vert.front()!=ordered_verts.front() &&
01237           endpt_vert.front()!=ordered_verts.back() ) {
01238           std::cout << "curve " << gen::geom_id_by_handle(*i) 
01239                     << " endpt sets do not match" << std::endl;
01240         }
01241       }
01242 
01243       // create the edges of the curve
01244       std::vector<EntityHandle> ordered_edges(ordered_verts.size()-1);
01245       for(unsigned int j=0; j<ordered_verts.size()-1; ++j) {
01246         EntityHandle edge;
01247         result = MBI()->create_element( MBEDGE, &ordered_verts[j], 2, edge );
01248         assert(MB_SUCCESS==result);
01249         if(MB_SUCCESS != result) return result;
01250         ordered_edges[j] = edge;
01251       }
01252 
01253       // If the curve is a loop, remove the duplicate endpoint.
01254       if(is_loop) ordered_verts.pop_back();
01255 
01256       // clear the set
01257       result = MBI()->clear_meshset( &(*i), 1 );
01258       assert(MB_SUCCESS==result);
01259       if(MB_SUCCESS != result) return result;
01260 
01261       // add the verts then edges to the curve set
01262       result = MBI()->add_entities( *i, &ordered_verts[0], ordered_verts.size() );
01263       assert(MB_SUCCESS==result);
01264       if(MB_SUCCESS != result) return result;
01265       result = MBI()->add_entities( *i, &ordered_edges[0], ordered_edges.size() );
01266       assert(MB_SUCCESS==result);
01267       if(MB_SUCCESS != result) return result;
01268     }
01269     return MB_SUCCESS;
01270   }
01271 
01272 ErrorCode get_geom_size_before_sealing( const Range geom_sets[],
01273                                           const Tag geom_tag,
01274                                           const Tag size_tag,
01275                                           bool debug,
01276                                           bool verbose ) 
01277 {
01278   ErrorCode rval;
01279   for( int dim = 1 ; dim < 4 ; ++dim ) 
01280     {
01281     for(Range::iterator i=geom_sets[dim].begin() ; i != geom_sets[dim].end() ; i++)
01282       {
01283         double size;
01284         //std::cout << "dim = " << dim << " *i =" << *i << std::endl;
01285         rval = gen::measure( *i, geom_tag, size, debug, verbose );
01286         //std::cout << " here in gen mesaure" << std::endl;
01287         if(gen::error(MB_SUCCESS!=rval,"could not measure"))
01288           {
01289             return rval;
01290           }
01291 
01292         
01293         rval = MBI()->tag_set_data( size_tag, &(*i), 1, &size );
01294         //std::cout << " here in set tag data" << std::endl;
01295         if(gen::error(MB_SUCCESS!=rval,"could not set size tag"))
01296           {
01297             return rval;
01298           }
01299       }
01300     }
01301   if (verbose)
01302   { 
01303   std::cout << "finished in get_geom_size_before_sealing" << std::endl;
01304   }
01305   return MB_SUCCESS;
01306 }
01307 
01308 ErrorCode get_geom_size_after_sealing( const Range geom_sets[],
01309                                          const Tag geom_tag,
01310                                          const Tag size_tag,
01311                                          const double FACET_TOL,
01312                                          bool debug,
01313                                          bool verbose ) {
01314   
01315       // save the largest difference for each dimension
01316       struct size_data {
01317         double orig_size, new_size, diff, percent;
01318         int id;
01319       };
01320       size_data largest_diff[3];
01321       size_data largest_percent[3];
01322       size_data smallest_size[3];
01323 
01324       ErrorCode rval;
01325       for(unsigned dim=1; dim<4; dim++) {
01326         largest_diff[dim-1].diff       = 0; 
01327         largest_percent[dim-1].percent = 0; 
01328         smallest_size[dim-1].orig_size = std::numeric_limits<int>::max(); 
01329         for(Range::iterator i=geom_sets[dim].begin(); i!=geom_sets[dim].end(); i++) {
01330           double orig_size = 0, new_size = 0;
01331           rval = MBI()->tag_get_data( size_tag, &(*i), 1, &orig_size );
01332           if(MB_SUCCESS != rval) {
01333             std::cout << "rval=" << rval << " id=" << gen::geom_id_by_handle(*i) << std::endl;
01334           }
01335           assert(MB_SUCCESS == rval);
01336           rval = gen::measure( *i, geom_tag, new_size, debug, verbose );
01337           assert(MB_SUCCESS == rval);
01338 
01339           // Remember the largest difference and associated percent difference
01340           double diff = fabs(new_size - orig_size);
01341           double percent_diff = 100.0*diff/orig_size;
01342           if(diff > largest_diff[dim-1].diff) {
01343             largest_diff[dim-1].orig_size = orig_size;
01344             largest_diff[dim-1].new_size  = new_size;
01345             largest_diff[dim-1].diff    = diff;
01346             largest_diff[dim-1].percent = percent_diff;
01347             largest_diff[dim-1].id      = gen::geom_id_by_handle(*i);
01348           }
01349           if(orig_size < smallest_size[dim-1].orig_size) {
01350             smallest_size[dim-1].orig_size = orig_size;
01351             smallest_size[dim-1].new_size  = new_size;
01352             smallest_size[dim-1].diff      = diff;
01353             smallest_size[dim-1].percent   = percent_diff;
01354             smallest_size[dim-1].id        = gen::geom_id_by_handle(*i);
01355           }
01356           if(percent_diff > largest_percent[dim-1].percent) {
01357             largest_percent[dim-1].orig_size = orig_size;
01358             largest_percent[dim-1].new_size  = new_size;
01359             largest_percent[dim-1].diff      = diff;
01360             largest_percent[dim-1].percent   = percent_diff;
01361             largest_percent[dim-1].id        = gen::geom_id_by_handle(*i);
01362           }
01363 
01364           bool print_warning = false;
01365           // PROBLEM: There is no analytical "maximum" change for this. There are special
01366           // cases in each that could be infinitely large. For example, a curve can oscillate
01367           // up and down infinitely and still be within FACET_TOL of the geometric curve.
01368           // The curve is changed only by merging vertices within FACET_TOL.
01369           if(1 == dim) {
01370             if(FACET_TOL < diff) print_warning = true;
01371 
01372           // The surface cannot change more than its zipped curves.
01373           } else if(2 == dim) {
01374             Range curve_sets;
01375             rval = MBI()->get_child_meshsets( *i, curve_sets );
01376             double total_length = 0;
01377             for(Range::iterator j=curve_sets.begin(); j!=curve_sets.end(); ++j) {
01378               double length;
01379               rval = MBI()->tag_get_data( size_tag, &(*j), 1, &length );
01380               total_length += length;
01381             }
01382             if(total_length*FACET_TOL < fabs(new_size - orig_size)) print_warning = true;
01383             // The volume cannot change more than the "cylinder" of error around each curve.
01384           } else if(3 == dim) {
01385             Range surf_sets;
01386             rval = MBI()->get_child_meshsets( *i, surf_sets );
01387             double total_length = 0;
01388             for(Range::iterator j=surf_sets.begin(); j!=surf_sets.end(); ++j) {
01389               Range curve_sets;
01390               rval = MBI()->get_child_meshsets( *j, curve_sets );
01391               for(Range::iterator k=curve_sets.begin(); k!=curve_sets.end(); ++k) {
01392                 double length;
01393                 rval = MBI()->tag_get_data( size_tag, &(*j), 1, &length );
01394                 total_length += length;
01395               }
01396             }
01397             if(total_length*FACET_TOL*FACET_TOL*3.14 < fabs(new_size - orig_size)) {
01398               print_warning = true;
01399             }
01400           } else {
01401             return MB_FAILURE;
01402           }
01403           if(print_warning && debug) {
01404             std::cout << "  dim=" << dim << " id=" << gen::geom_id_by_handle(*i)
01405                       << " orig_size=" << orig_size << " new_size=" << new_size << std::endl;
01406           }
01407         }
01408       }
01409       // print largest size change among each dimension
01410       std::cout << "Summary of deformation due to sealing: largest absolute change" << std::endl;
01411       std::cout.width(6);
01412       for(unsigned dim=1; dim<4; dim++) {
01413         std::cout << "  dim="            << dim
01414                   << ", id="             << largest_diff[dim-1].id
01415                   << ", orig_size="      << largest_diff[dim-1].orig_size
01416                   << ", new_size="       << largest_diff[dim-1].new_size
01417                   << ", abs_change="     << largest_diff[dim-1].diff 
01418                   << ", percent_change=" << largest_diff[dim-1].percent << std::endl;
01419       }
01420       std::cout << "Summary of deformation due to sealing: largest percent change" << std::endl;
01421       for(unsigned dim=1; dim<4; dim++) {
01422         std::cout << "  dim="            << dim
01423                   << ", id="             << largest_percent[dim-1].id
01424                   << ", orig_size="      << largest_percent[dim-1].orig_size
01425                   << ", new_size="       << largest_percent[dim-1].new_size
01426                   << ", abs_change="     << largest_percent[dim-1].diff
01427                   << ", percent_change=" << largest_percent[dim-1].percent << std::endl;
01428       }
01429       std::cout << "Summary of deformation due to sealing: smallest size" << std::endl;
01430       for(unsigned dim=1; dim<4; dim++) {
01431         std::cout << "  dim="            << dim 
01432                   << ", id="             << smallest_size[dim-1].id
01433                   << ", orig_size="      << smallest_size[dim-1].orig_size
01434                   << ", new_size="       << smallest_size[dim-1].new_size
01435                   << ", abs_change="     << smallest_size[dim-1].diff
01436                   << ", percent_change=" << smallest_size[dim-1].percent << std::endl;
01437       }
01438       std::cout.unsetf(std::ios::scientific|std::ios::showpos);
01439       return MB_SUCCESS;
01440 }
01441 
01442 ErrorCode delete_merged_curves( Range &existing_curve_sets, Tag merge_tag, bool debug){
01443 
01444   ErrorCode result;
01445 
01446    Range curves_to_delete;
01447     result = MBI()->get_entities_by_type_and_tag(0, MBENTITYSET, &merge_tag, NULL,
01448                                                  1, curves_to_delete);
01449     assert(MB_SUCCESS == result);
01450     // loop over the curves to delete 
01451     for(Range::const_iterator i=curves_to_delete.begin(); i!=curves_to_delete.end(); ++i) {
01452       // get the curve_to_keep
01453       EntityHandle curve_to_keep;
01454       result = MBI()->tag_get_data( merge_tag, &(*i), 1, &curve_to_keep );
01455       if(MB_SUCCESS != result) return result;
01456       // get parent surface of the curve_to_delete
01457       Range parent_surfs;
01458       result = MBI()->get_parent_meshsets( *i, parent_surfs );
01459       if(MB_SUCCESS != result) return result;
01460       // remove the curve_to_delete and replace with curve_to_keep
01461       for(Range::iterator j=parent_surfs.begin(); j!=parent_surfs.end(); ++j) {
01462         result = MBI()->remove_parent_child( *j, *i );
01463         if(MB_SUCCESS != result) return result;
01464         result = MBI()->add_parent_child( *j, curve_to_keep );
01465         if(MB_SUCCESS != result) return result;
01466       }
01467     }
01468     result = MBI()->delete_entities( curves_to_delete );
01469     assert(MB_SUCCESS == result);
01470     if ( result != MB_SUCCESS )
01471       {
01472         std::cout << "Houston, we have a problem" << std::endl;
01473       }
01474     existing_curve_sets = subtract(existing_curve_sets, curves_to_delete );
01475     if(debug) std::cout << "deleted " << curves_to_delete.size() << " curves." << std::endl;
01476 
01477 
01478   return result; 
01479 
01480 }
01481 
01482 ErrorCode delete_sealing_tags( Tag normal_tag, Tag merge_tag, Tag size_tag, Tag orig_curve_tag){
01483 
01484   ErrorCode result;
01485 
01486   result = MBI()->tag_delete( normal_tag );
01487     if(MB_SUCCESS != result) return result;
01488     result = MBI()->tag_delete( merge_tag );
01489     if(MB_SUCCESS != result) return result;
01490     result = MBI()->tag_delete( size_tag );
01491     if(MB_SUCCESS != result) return result;
01492     result = MBI()->tag_delete( orig_curve_tag );
01493     if(MB_SUCCESS != result) return result;
01494 
01495   return result; 
01496 }
01497 
01498 ErrorCode get_unmerged_curves( EntityHandle surface, std::vector<EntityHandle> &curves,
01499                                  std::vector<EntityHandle> &unmerged_curves,
01500                                  Tag merge_tag,
01501                                  bool verbose, 
01502                                  bool debug) {
01503 
01504   ErrorCode result;
01505 
01506    result = MBI()->get_child_meshsets( surface, curves );
01507       if(gen::error(MB_SUCCESS!=result,"could not get child sets")) return result;
01508       assert(MB_SUCCESS==result);
01509 
01510       // Update the curve_sets with that contain entity_to_delete curves with their
01511       // entity_to_keep curves. Unmerged_curve_sets will end up holding the curves
01512       // of this surface that are not merged with another curve in this surface.
01513       for(std::vector<EntityHandle>::iterator j=curves.begin();
01514           j!=curves.end(); j++) {
01515         EntityHandle merged_curve, curve;
01516         result = MBI()->tag_get_data( merge_tag, &(*j), 1, &merged_curve );
01517         assert(MB_TAG_NOT_FOUND==result || MB_SUCCESS==result);
01518         if(MB_TAG_NOT_FOUND == result) {
01519           curve = *j;
01520         } else if(MB_SUCCESS == result) {
01521           if(debug) {
01522             std::cout << "  curve_id=" << gen::geom_id_by_handle(*j) 
01523                       << " is entity_to_delete" << std::endl;
01524           }
01525           curve = merged_curve;
01526           // should parent-childs be updated for the entity_to_keep?
01527         } else {
01528           std::cout << "prepare_surfaces: result=" << result << std::endl;
01529           return result;        
01530         }
01531       
01532         // Add a curve (whether it is merged or not) if it is not in unmerged_merged_curve_sets. 
01533         // If it is merged, then the curve handle will appear later and we will remove it. 
01534         std::vector<EntityHandle>::iterator k=find(unmerged_curves.begin(),
01535           unmerged_curves.end(), curve);
01536         if(unmerged_curves.end() == k) {
01537 
01538           unmerged_curves.push_back(curve);
01539         } else {
01540         
01541           unmerged_curves.erase(k);
01542 
01543         }
01544       // If all curves have a partner to be merged to, then unmerged_curve_sets will be empty.
01545       }
01546 
01547 
01548   return MB_SUCCESS;
01549 
01550 }
01551 
01552 
01553 ErrorCode create_skin_vert_loops( Range &skin_edges, Range tris, std::vector < std::vector <EntityHandle> > &skin , int surf_id, bool &cont, bool debug) {
01554 
01555  ErrorCode result;
01556   
01557      /* Remove pairs of edges that are geometrically the same but in opposite 
01558         order due to a faceting error ACIS. In other words, merge (a,b) and (b,a). 
01559         Examples are mod13surf280 and tbm_surf1605. */
01560       result = arc::remove_opposite_pairs_of_edges_fast( skin_edges, debug );
01561       if (MB_SUCCESS != result) {
01562         std::cout << "  surface " << surf_id << " failed to zip: could not remove opposite edges"   
01563                   << surf_id << std::endl;  
01564         result = MBI()->delete_entities(skin_edges);
01565         if(gen::error(MB_SUCCESS!=result,"could not delete skin edges")) return result;
01566         assert(MB_SUCCESS == result);
01567         cont = true;
01568         return result;
01569       }  
01570 
01571 
01572 
01573 
01574       /* Order the edges so that the triangle is on their left side. Skin
01575          edges are adjacent to only one triangle. */
01576       bool catch_error = false;
01577       for(Range::iterator j=skin_edges.begin(); j!=skin_edges.end(); j++) {
01578         Range adj_tris;
01579         result = MBI()->get_adjacencies( &(*j), 1, 2, false, adj_tris );
01580         if(gen::error(MB_SUCCESS!=result,"could not get adj tris")) return result;
01581         assert(MB_SUCCESS == result);
01582         Range skin_tri = intersect( adj_tris, tris );
01583         if(1 != skin_tri.size()) {
01584           std::cout << "skin_tri.size()=" << skin_tri.size() << std::endl;
01585           catch_error = true;
01586           break;
01587         }
01588         result = arc::orient_edge_with_tri( *j, skin_tri.front() );
01589         if(gen::error(MB_SUCCESS!=result,"could not orient_edge_with_tri")) return result;
01590         assert(MB_SUCCESS == result);
01591       }
01592       // I NEED TO ADD BETTER CLEANUP AFTER THESE FAILURE CONDITIONS
01593       if(catch_error) {
01594         std::cout << "  surface " << surf_id << " failed to zip: could not orient edge"   
01595                   << std::endl;  
01596         result = MBI()->delete_entities(skin_edges);
01597         if(gen::error(MB_SUCCESS!=result,"could not delete skin edges")) return result;
01598         assert(MB_SUCCESS == result);
01599         cont = true;
01600         return result;
01601       }
01602 
01603 
01604                                                       
01605       // Create loops with the skin edges.  
01606       std::vector< std::vector<EntityHandle> > skin_loops_of_edges;
01607       result = arc::create_loops_from_oriented_edges( skin_edges, skin_loops_of_edges, debug );
01608       if(MB_SUCCESS != result) {
01609         std::cout << "  surface " << surf_id << " failed to zip: could not create loops" 
01610                   << std::endl;
01611         result = MBI()->delete_entities(skin_edges);
01612         assert(MB_SUCCESS == result);
01613         cont = true;
01614         return result;
01615       }
01616       if(debug) std::cout << skin_loops_of_edges.size() << " skin loop(s)" << std::endl;
01617 
01618       // Convert the loops of skin edges to loops of skin verts.
01619       std::vector< std::vector<EntityHandle> > skin_temp(skin_loops_of_edges.size());
01620       for(unsigned int j=0; j<skin_loops_of_edges.size(); j++) {
01621         result = gen::ordered_verts_from_ordered_edges( skin_loops_of_edges[j], skin_temp[j] );
01622         assert(MB_SUCCESS == result);
01623         // check to make sure that the loop is closed
01624         assert(skin_temp[j].front() == skin_temp[j].back());
01625       }
01626 
01627       skin=skin_temp;
01628 
01629       // edges are no longer needed       
01630       result = MBI()->delete_entities(skin_edges);
01631       if(gen::error(MB_SUCCESS!=result,"could not delete skin_edges")) return result;
01632       assert(MB_SUCCESS == result);
01633 
01634       
01635 
01636  return MB_SUCCESS;
01637 
01638 }
01639 
01640 ErrorCode merge_skin_verts ( Range &skin_verts, Range &skin_edges, double SME_RESABS_TOL, int surf_id, bool cont, bool debug) {
01641 
01642    ErrorCode result;
01643 
01644     result = MBI()->get_adjacencies( skin_edges, 0, false, skin_verts, 
01645                                        Interface::UNION );
01646         if(gen::error(MB_SUCCESS!=result,"could not get adj verts")) return result;
01647         assert(MB_SUCCESS == result);
01648         result = gen::merge_vertices( skin_verts, SME_RESABS_TOL );         
01649         if (MB_SUCCESS != result) {
01650         if(debug) std::cout << "result= " << result << std::endl;                  
01651         std::cout << "  surface " << surf_id << " failed to zip: could not merge vertices"   
01652                   << surf_id << std::endl;  
01653         result = MBI()->delete_entities(skin_edges);
01654         assert(MB_SUCCESS == result);
01655         cont = true;
01656         return result;
01657         }  
01658 
01659         // Merging vertices create degenerate edges.
01660         result = arc::remove_degenerate_edges( skin_edges, debug );
01661         if(MB_SUCCESS!=result) {
01662         std::cout << "  surface " << surf_id 
01663                   << " failed to zip: could not remove degenerate edges" << std::endl;
01664         result = MBI()->delete_entities(skin_edges);
01665         if(gen::error(MB_SUCCESS!=result,"could not delete skin edges")) return result;
01666         assert(MB_SUCCESS == result);
01667         cont = true;
01668         return result;
01669         }  
01670 
01671 
01672    return MB_SUCCESS;
01673 }
01674 
01675 
01676 ErrorCode seal_surface_loops ( EntityHandle surf, EntityHandle skin_loops[] , std::vector < std::vector<EntityHandle> > skin, std::vector<EntityHandle> curves,  Tag normal_tag, Tag orig_curve_tag, double FACET_TOL, int surf_id, bool debug) {
01677 
01678 
01679       /* Get the curves that are part of the surface. Use vectors to store all curve
01680          stuff so that we can remove curves from the set as they are zipped. */
01681      
01682       // Place skin loops in meshsets to allow moab to update merged entities.
01683       // This prevents stale handles. I suspect moab can use upward adjacencies
01684       // to do this more efficiently than a manual O(n) search through an 
01685       // unsorted vector.
01686 
01687    ErrorCode rval;
01688       for(unsigned j=0; j<skin.size(); ++j) {
01689         rval = MBI()->create_meshset( MESHSET_TRACK_OWNER|MESHSET_ORDERED, skin_loops[j] );
01690         if(gen::error(MB_SUCCESS!=rval,"failed to zip: creating skin_loop_set failed"))
01691           return rval;   
01692 
01693         rval = arc::set_meshset( skin_loops[j], skin[j] );    
01694         if(gen::error(MB_SUCCESS!=rval,"failed ot zip: setting skin_loop_set failed"))
01695           return rval;      
01696       }
01697 
01698       // Keep zipping loops until each is either zipped or failed. This function
01699       // returns only after all loops are zipped or a failure occurs.
01700       for(unsigned j=0; j<skin.size(); ++j) {
01701         std::vector<EntityHandle> skin_loop;
01702         rval = arc::get_meshset( skin_loops[j], skin_loop );    
01703         if(gen::error(MB_SUCCESS!=rval,"failed to zip: setting skin_loop_set failed"))
01704           return rval;      
01705 
01706         rval = seal_loop( debug, FACET_TOL, normal_tag, orig_curve_tag, surf, 
01707                           curves, skin_loop );
01708         if(MB_SUCCESS != rval) {
01709           std::cout << "failed to zip: surface " << surf_id << ": failed to seal a loop" 
01710                     << std::endl;
01711         }
01712       }
01713  
01714   return MB_SUCCESS;
01715 
01716 }
01717 
01718 
01719 
01720 ErrorCode make_mesh_watertight(EntityHandle input_set, double &facet_tol, bool verbose)
01721   {
01722 
01723 
01724 
01725     ErrorCode result;
01726 
01727     //added to this function because they are called in make_watertight but aren't used until here
01728     const bool debug = false;
01729     const bool check_geom_size = true;
01730     // duplicated here from make_watertight, seemed to always be set to false
01731     //bool is_acis=false;
01732 
01733    // initialize mesh tags
01734     Tag geom_tag, id_tag, normal_tag, merge_tag, faceting_tol_tag,
01735       geometry_resabs_tag, size_tag, orig_curve_tag;
01736     double sme_resabs_tol=1e-6;
01737     
01738    // retrieve mesh tags necessary for sealing the mesh
01739     result = gen::get_sealing_mesh_tags( facet_tol, sme_resabs_tol, geom_tag, id_tag, normal_tag, merge_tag, faceting_tol_tag, 
01740       geometry_resabs_tag, size_tag, orig_curve_tag); 
01741     if(gen::error(MB_SUCCESS!=result, "could not get the mesh tags")) return result;
01742 
01743 
01744     // In practice, use 2*facet_tol because we are always comparing 2 faceted
01745     // entities. If instead we were comparing a faceted entity and a geometric
01746     // entitiy, then 1*facet_tol is correct.
01747 
01748     const double SME_RESABS_TOL = sme_resabs_tol; // from ACIS through CGM
01749     const double FACET_TOL = facet_tol; // specified by user when faceting cad
01750 
01751     if(verbose)
01752     {
01753     std::cout << "  faceting tolerance=" << facet_tol << " cm" << std::endl;
01754     std::cout << "  absolute tolerance=" << sme_resabs_tol << " cm" << std::endl;
01755     }
01756 
01757     // get all geometry sets and set tracking ordering options appropriately
01758     Range geom_sets[4];
01759     result=gen::get_geometry_meshsets( geom_sets, geom_tag, verbose);
01760     if(gen::error(MB_SUCCESS!=result, "could not get the geometry meshsets")) return result;
01761     
01762     // If desired, find each entity's size before sealing.
01763     if(check_geom_size) 
01764       {
01765         result = get_geom_size_before_sealing( geom_sets, geom_tag, size_tag, debug, verbose );
01766         if(gen::error(MB_SUCCESS!=result,"measuring geom size failed")) return result;
01767       }
01768     
01769 
01770     
01771     if (verbose) std::cout << "Getting entity count before sealing..." << std::endl;
01772     // Get entity count before sealing.
01773     int orig_n_tris;
01774     result = MBI()->get_number_entities_by_type( 0, MBTRI, orig_n_tris );
01775     assert(MB_SUCCESS == result);
01776 
01777     if(verbose)
01778     {
01779     std::cout << "  input faceted geometry contains " << geom_sets[3].size() << " volumes, " 
01780               << geom_sets[2].size() << " surfaces, " << geom_sets[1].size() 
01781               << " curves, and " << orig_n_tris << " triangles" << std::endl;  
01782     }
01783     
01784     if(verbose) std::cout << "Finding degenerate triangles... " << std::endl;
01785     result = find_degenerate_tris();
01786     if(gen::error(result!=MB_SUCCESS,"could not determine if triangles were degenerate or not")) return result;
01787       
01788 
01789     result = prepare_curves(geom_sets[1], geom_tag, id_tag, merge_tag, FACET_TOL, debug, verbose);
01790     if(gen::error(result!=MB_SUCCESS,"could not prepare the curves")) return(result);
01791       
01792     result = gen::check_for_geometry_sets(geom_tag, verbose);
01793 
01794     if(gen::error(MB_SUCCESS!=result,"no geometry sets exist in the model. Please check curve faceting.")) return result;
01795     
01796     if (verbose) 
01797     {
01798     std::cout << "Zipping loops and removing small surfaces whose curves were all merged as pairs..." << std::endl;
01799     std::cout << "SME_RESABS_TOL = " << SME_RESABS_TOL << " FACET_TOL = " << FACET_TOL << std::endl;
01800     }
01801     result = prepare_surfaces(geom_sets[2], geom_tag, id_tag, normal_tag, merge_tag,
01802                               orig_curve_tag,SME_RESABS_TOL, FACET_TOL, debug);
01803     if ( gen::error(result != MB_SUCCESS, "I have failed to zip")) return result;
01804       
01805 
01806     // After zipping surfaces, merged curve entity_to_deletes are no longer needed.
01807     // Swap surface parent-childs for curves to delete with curve to keep. 
01808     // ARE THEIR ORPHANED CHILD VERTEX SETS STILL AROUND? 
01809     if(verbose) std::cout << "Adjusting parent-child links then removing merged curves..." << std::endl;
01810     result = delete_merged_curves( geom_sets[1], merge_tag, debug);
01811     if(gen::error(MB_SUCCESS!=result, "could not delete the merged curves")) return result;
01812 
01813 
01814     // SHOULD COINCIDENT SURFACES ALSO BE MERGED?
01815     // 20100205 Jason: If child curves are the same, check to make sure each
01816     // facet pt is within 2x tol of the opposing surface.
01817 
01818     // This function is still screwed up, but 99% right.
01819     if (verbose) std::cout << "Fixing inverted triangles..." << std::endl;
01820     result = fix_normals(geom_sets[2], id_tag, normal_tag, debug, verbose);
01821     assert(MB_SUCCESS == result);
01822 
01823    
01824     // As sanity check, did zipping drastically change the entity's size?
01825     if(check_geom_size && verbose) {
01826       std::cout << "Checking size change of zipped entities..." << std::endl;
01827       result = get_geom_size_after_sealing( geom_sets, geom_tag, size_tag, FACET_TOL, debug, verbose );
01828       if(gen::error(MB_SUCCESS!=result,"measuring geom size failed")) return result;
01829     }
01830    
01831 
01832     // This tool stores curves as a set of ordered edges. MOAB stores curves as
01833     // ordered vertices and edges. MOAB represents curve endpoints as geometry
01834     // sets containing a singe vertex. This function restores MOAB's curve
01835     // representation.
01836     if (verbose) std::cout << "Restoring faceted curve representation..." << std::endl;
01837     result = restore_moab_curve_representation( geom_sets[1] );
01838     if(gen::error(MB_SUCCESS!=result,"restore_moab_curve_representation failed")) return result;
01839     // If all of a volume's surfaces have been deleted, delete the volume.
01840     if (verbose) std::cout << "Removing small volumes if all surfaces have been removed..." << std::endl;
01841     for(Range::iterator i=geom_sets[3].begin(); i!=geom_sets[3].end(); ++i) {
01842       int n_surfs;
01843       result = MBI()->num_child_meshsets( *i, &n_surfs );
01844       assert(MB_SUCCESS == result);
01845       if(0 == n_surfs) {
01846         // Remove the volume set. This also removes parent-child relationships.
01847         std::cout << "  deleted volume " << gen::geom_id_by_handle(*i)  << std::endl;
01848         result = MBI()->delete_entities( &(*i), 1);
01849         assert(MB_SUCCESS == result);
01850         i = geom_sets[3].erase(i) - 1;
01851       } 
01852     }
01853 
01854     // The obbtrees are no longer valid because the triangles have been altered.
01855     // Surface and volume sets are tagged with tags holding the obb tree
01856     // root handles. Somehow, delete the old tree without deleting the
01857     // surface and volume sets, then build a new tree.    
01858     
01859     // removing this for now, has something to do with an interaction with DAGMC 
01860     // which doesn't actually occur any more
01861     //if (verbose) std::cout << "Removing stale OBB trees..." << std::endl;
01862     //result = cleanup::remove_obb_tree();
01863     //assert(MB_SUCCESS == result);
01864 
01865     //std::cout << "INSERT FUNCTION HERE TO REMOVE STALE VERTS, EDGES, TRIS, VERT SETS, ETC"
01866     //        << std::endl;
01867 
01868     // Resetting meshsets so that they no longer track.
01869     if (verbose) std::cout << "Restoring original meshset options and tags..." << std::endl;
01870     for(unsigned dim=0; dim<4; dim++) {
01871       for(Range::iterator i=geom_sets[dim].begin(); i!=geom_sets[dim].end(); i++) {
01872         result = MBI()->set_meshset_options(*i, 1==dim ? MESHSET_ORDERED : MESHSET_SET);
01873         if(MB_SUCCESS != result) return result;
01874       }
01875     }    
01876 
01877     // Tags for merging curves and checking the change in geometry size were added.
01878     // Delete these because they are no longer needed.
01879     result = delete_sealing_tags( normal_tag, merge_tag, size_tag, orig_curve_tag); 
01880     if(gen::error(MB_SUCCESS!=result, "could not delete sealing tags")) return result;
01881 
01882     // Print new size of the file to the user
01883     int sealed_n_tris;
01884     result = MBI()->get_number_entities_by_type( 0, MBTRI, sealed_n_tris );
01885     assert(MB_SUCCESS == result);
01886     if (verbose)
01887     {
01888     std::cout << "  output file contains " << geom_sets[3].size() << " volumes, " 
01889               << geom_sets[2].size() << " surfaces, " << geom_sets[1].size() 
01890               << " curves, and " << sealed_n_tris << " triangles" << std::endl;  
01891     std::cout << "  triangle count changed " << (double)sealed_n_tris/orig_n_tris
01892               << "x (sealed/unsealed)" << std::endl;
01893     }
01894     return MB_SUCCESS;
01895   }
01896 
01897 }
01898 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines