MeshKit
1.0
|
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