moab
|
00001 00016 #include "moab/DualTool.hpp" 00017 #include "moab/Range.hpp" 00018 // using Core for call to check_adjacencies 00019 #include "moab/Core.hpp" 00020 #include "Internals.hpp" 00021 #include "MBTagConventions.hpp" 00022 #include "moab/Skinner.hpp" 00023 #include "moab/Core.hpp" 00024 #include "moab/MeshTopoUtil.hpp" 00025 #include "AEntityFactory.hpp" 00026 #include "moab/CN.hpp" 00027 #include <string> 00028 #include <algorithm> 00029 #include <iostream> 00030 #include <sstream> 00031 #include <assert.h> 00032 00033 #define RR if (MB_SUCCESS != result) return result 00034 #define SWAP(a,b) {EntityHandle tmp_ent = a; a = b; b = tmp_ent;} 00035 00036 namespace moab { 00037 00038 bool debug = false; 00039 bool debug_ap = false; 00040 00042 const char *DualTool::DUAL_SURFACE_TAG_NAME = "DUAL_SURFACE"; 00043 00045 const char *DualTool::DUAL_CURVE_TAG_NAME = "DUAL_CURVE"; 00046 00048 const char *DualTool::IS_DUAL_CELL_TAG_NAME = "__IS_DUAL_CELL"; 00049 00051 const char *DualTool::DUAL_ENTITY_TAG_NAME = "__DUAL_ENTITY"; 00052 00054 const char *DualTool::EXTRA_DUAL_ENTITY_TAG_NAME = "__EXTRA_DUAL_ENTITY"; 00055 00057 const char *DualTool::DUAL_GRAPHICS_POINT_TAG_NAME = "__DUAL_GRAPHICS_POINT"; 00058 00059 //const int DualTool::GP_SIZE = 20; 00060 00061 DualTool::DualTool(Interface *impl) 00062 : mbImpl(impl) 00063 { 00064 EntityHandle dum_handle = 0; 00065 ErrorCode result; 00066 00067 result = mbImpl->tag_get_handle( DUAL_SURFACE_TAG_NAME, 00068 1, MB_TYPE_HANDLE, 00069 dualSurfaceTag, 00070 MB_TAG_SPARSE|MB_TAG_CREAT, 00071 &dum_handle ); 00072 assert(MB_SUCCESS == result); 00073 00074 result = mbImpl->tag_get_handle( DUAL_CURVE_TAG_NAME, 00075 1, MB_TYPE_HANDLE, 00076 dualCurveTag, 00077 MB_TAG_SPARSE|MB_TAG_CREAT, 00078 &dum_handle ); 00079 assert(MB_SUCCESS == result); 00080 00081 unsigned int dummy = 0; 00082 result = mbImpl->tag_get_handle( IS_DUAL_CELL_TAG_NAME, 00083 1, MB_TYPE_INTEGER, 00084 isDualCellTag, 00085 MB_TAG_SPARSE|MB_TAG_CREAT, 00086 &dummy); 00087 assert(MB_SUCCESS == result); 00088 00089 result = mbImpl->tag_get_handle( DUAL_ENTITY_TAG_NAME, 00090 1, MB_TYPE_HANDLE, 00091 dualEntityTag, 00092 MB_TAG_DENSE|MB_TAG_CREAT, 00093 &dum_handle ); 00094 assert(MB_SUCCESS == result); 00095 00096 result = mbImpl->tag_get_handle( EXTRA_DUAL_ENTITY_TAG_NAME, 00097 1, MB_TYPE_HANDLE, 00098 extraDualEntityTag, 00099 MB_TAG_SPARSE|MB_TAG_CREAT, 00100 &dum_handle ); 00101 assert(MB_SUCCESS == result); 00102 00103 static const char dum_name[CATEGORY_TAG_SIZE] = {0}; 00104 result = mbImpl->tag_get_handle( CATEGORY_TAG_NAME, 00105 CATEGORY_TAG_SIZE, MB_TYPE_OPAQUE, 00106 categoryTag, 00107 MB_TAG_SPARSE|MB_TAG_CREAT, 00108 dum_name ); 00109 assert(MB_SUCCESS == result); 00110 00111 DualTool::GraphicsPoint dum_pt(0.0, 0.0, 0.0, -1); 00112 result = mbImpl->tag_get_handle(DUAL_GRAPHICS_POINT_TAG_NAME, 00113 sizeof(DualTool::GraphicsPoint), MB_TYPE_DOUBLE, 00114 dualGraphicsPointTag, 00115 MB_TAG_DENSE|MB_TAG_CREAT|MB_TAG_BYTES, 00116 &dum_pt); 00117 assert(MB_SUCCESS == result); 00118 00119 int dum_int = 0; 00120 result = mbImpl->tag_get_handle( GLOBAL_ID_TAG_NAME, 00121 1, MB_TYPE_INTEGER, 00122 globalIdTag, 00123 MB_TAG_SPARSE|MB_TAG_CREAT, 00124 &dum_int); 00125 assert(MB_SUCCESS == result); 00126 if (MB_SUCCESS == result) {} // empty statement to get rid of warning. 00127 00128 maxHexId = -1; 00129 } 00130 00131 DualTool::~DualTool() 00132 {} 00133 00135 ErrorCode DualTool::construct_dual(EntityHandle *entities, 00136 const int num_entities) 00137 { 00138 // allocate a dual entity for each primal entity in the mesh, starting 00139 // with highest dimension and working downward; do each dimension in a separate code 00140 // block, since they're all handled slightly differently 00141 00142 Range regions, faces, edges, vertices; 00143 ErrorCode result; 00144 00145 if (NULL == entities || 0 == num_entities) { 00146 00147 // first, construct all the aentities, since they're currently needed to 00148 // compute the dual 00149 result = mbImpl->get_entities_by_dimension(0, 0, vertices); 00150 if (MB_SUCCESS != result) return result; 00151 00152 result = MeshTopoUtil(mbImpl).construct_aentities(vertices); 00153 if (MB_SUCCESS != result) return result; 00154 00155 // get all edges, faces and regions now, so we don't need to filter out dual 00156 // entities later 00157 00158 result = mbImpl->get_entities_by_dimension(0, 1, edges); 00159 if (MB_SUCCESS != result) return result; 00160 result = mbImpl->get_entities_by_dimension(0, 2, faces); 00161 if (MB_SUCCESS != result) return result; 00162 result = mbImpl->get_entities_by_dimension(0, 3, regions); 00163 if (MB_SUCCESS != result) return result; 00164 00165 // get the max global id for hexes, we'll need for modification ops 00166 std::vector<int> gid_vec(regions.size()); 00167 result = mbImpl->tag_get_data(globalId_tag(), regions, &gid_vec[0]); 00168 if (MB_SUCCESS != result) return result; 00169 maxHexId = -1; 00170 Range::iterator rit; 00171 unsigned int i; 00172 for (rit = regions.begin(), i = 0; rit != regions.end(); rit++, i++) { 00173 if (gid_vec[i] > maxHexId && mbImpl->type_from_handle(*rit) == MBHEX) 00174 maxHexId = gid_vec[i]; 00175 } 00176 } 00177 else { 00178 // get entities of various dimensions adjacent to these 00179 result = mbImpl->get_adjacencies(entities, num_entities, 0, true, vertices, 00180 Interface::UNION); 00181 if (MB_SUCCESS != result) return result; 00182 result = mbImpl->get_adjacencies(entities, num_entities, 1, true, edges, 00183 Interface::UNION); 00184 if (MB_SUCCESS != result) return result; 00185 result = mbImpl->get_adjacencies(entities, num_entities, 2, true, faces, 00186 Interface::UNION); 00187 if (MB_SUCCESS != result) return result; 00188 result = mbImpl->get_adjacencies(entities, num_entities, 3, true, regions, 00189 Interface::UNION); 00190 if (MB_SUCCESS != result) return result; 00191 00192 } 00193 00194 Range dual_verts; 00195 result = construct_dual_vertices(regions, dual_verts); 00196 if (MB_SUCCESS != result || dual_verts.size() != regions.size()) return result; 00197 if (debug) 00198 std::cout << "Constructed " << dual_verts.size() << " dual vertices." << std::endl; 00199 00200 // don't really need dual edges, but construct 'em anyway 00201 Range dual_edges; 00202 result = construct_dual_edges(faces, dual_edges); 00203 if (MB_SUCCESS != result || dual_edges.size() != faces.size()) return result; 00204 if (debug) 00205 std::cout << "Constructed " << dual_edges.size() << " dual edges." << std::endl; 00206 00207 // construct dual faces 00208 Range dual_faces; 00209 result = construct_dual_faces(edges, dual_faces); 00210 if (MB_SUCCESS != result || dual_faces.size() != edges.size()) return result; 00211 if (debug) 00212 std::cout << "Constructed " << dual_faces.size() << " dual faces." << std::endl; 00213 00214 // construct dual cells 00215 Range dual_cells; 00216 result = construct_dual_cells(vertices, dual_cells); 00217 if (MB_SUCCESS != result || dual_cells.size() != vertices.size()) return result; 00218 if (debug) 00219 std::cout << "Constructed " << dual_cells.size() << " dual cells." << std::endl; 00220 00221 return MB_SUCCESS; 00222 } 00223 00224 ErrorCode DualTool::construct_dual_vertices(const Range &all_regions, 00225 Range &dual_ents) 00226 { 00227 if (all_regions.empty()) return MB_SUCCESS; 00228 00229 // make sure they're all regions 00230 assert(3 == CN::Dimension(TYPE_FROM_HANDLE(*all_regions.begin())) && 00231 3 == CN::Dimension(TYPE_FROM_HANDLE(*all_regions.rbegin()))); 00232 00233 Range::const_iterator rit; 00234 EntityHandle dual_ent; 00235 ErrorCode tmp_result = MB_SUCCESS; 00236 ErrorCode result = MB_SUCCESS; 00237 00238 for (rit = all_regions.begin(); rit != all_regions.end(); rit++) { 00239 if (tmp_result != MB_SUCCESS) result = tmp_result; 00240 00241 tmp_result = mbImpl->tag_get_data(dualEntity_tag(), &(*rit), 1, &dual_ent); 00242 if (MB_SUCCESS == tmp_result && 0 != dual_ent) { 00243 dual_ents.insert(dual_ent); 00244 continue; 00245 } 00246 else if (MB_SUCCESS != tmp_result) continue; 00247 00248 tmp_result = construct_dual_vertex(*rit, dual_ent, false, true); 00249 if (MB_SUCCESS != tmp_result) continue; 00250 00251 // save it in the list of new dual ents 00252 dual_ents.insert(dual_ent); 00253 00254 } 00255 00256 return result; 00257 } 00258 00259 ErrorCode DualTool::construct_dual_vertex(EntityHandle entity, 00260 EntityHandle &dual_ent, 00261 const bool extra, 00262 const bool add_graphics_pt) 00263 { 00264 // no dual entity; construct one; first need the avg coordinates 00265 unsigned int is_dual = 0x1; 00266 double avg_pos[3]; 00267 ErrorCode result = MeshTopoUtil(mbImpl).get_average_position(entity, avg_pos); 00268 if (MB_SUCCESS != result) return result; 00269 00270 // now construct the new dual entity 00271 result = mbImpl->create_vertex(avg_pos, dual_ent); 00272 if (MB_SUCCESS != result) return result; 00273 00274 // tag it indicating it's a dual entity 00275 result = mbImpl->tag_set_data(isDualCell_tag(), &dual_ent, 1, &is_dual); 00276 if (MB_SUCCESS != result) return result; 00277 00278 // tag the primal entity with its dual entity and vica versa 00279 if (extra) 00280 result = mbImpl->tag_set_data(extraDualEntity_tag(), &(entity), 1, &dual_ent); 00281 else 00282 result = mbImpl->tag_set_data(dualEntity_tag(), &(entity), 1, &dual_ent); 00283 if (MB_SUCCESS != result) return result; 00284 00285 result = mbImpl->tag_set_data(dualEntity_tag(), &dual_ent, 1, &(entity)); 00286 if (MB_SUCCESS != result) return result; 00287 00288 if (add_graphics_pt) 00289 // put a graphics point on that vertex too 00290 result = add_graphics_point(dual_ent, avg_pos); 00291 00292 return result; 00293 } 00294 00295 ErrorCode DualTool::add_graphics_point(EntityHandle entity, 00296 double *avg_pos) 00297 { 00298 // add a graphics pt, placed at the same position as the vertex 00299 double my_pos[3]; 00300 ErrorCode result; 00301 00302 if (NULL == avg_pos) { 00303 result = MeshTopoUtil(mbImpl).get_average_position(entity, my_pos); 00304 if (MB_SUCCESS != result) return result; 00305 } 00306 else 00307 for (int i = 0; i < 3; i++) my_pos[i] = avg_pos[i]; 00308 00309 DualTool::GraphicsPoint dum_pt(my_pos, -1); 00310 result = mbImpl->tag_set_data(dualGraphicsPoint_tag(), &entity, 1, 00311 &dum_pt); 00312 return result; 00313 } 00314 00315 ErrorCode DualTool::construct_dual_edges(const Range &all_faces, 00316 Range &dual_ents) 00317 { 00318 if (all_faces.empty()) return MB_SUCCESS; 00319 00320 // make sure they're all faces 00321 assert(2 == CN::Dimension(TYPE_FROM_HANDLE(*all_faces.begin())) && 00322 2 == CN::Dimension(TYPE_FROM_HANDLE(*all_faces.rbegin()))); 00323 00324 Range::const_iterator rit; 00325 EntityHandle dual_ent; 00326 unsigned int is_dual = 0x1; 00327 ErrorCode tmp_result = MB_SUCCESS; 00328 ErrorCode result = MB_SUCCESS; 00329 00330 for (rit = all_faces.begin(); rit != all_faces.end(); rit++) { 00331 if (tmp_result != MB_SUCCESS) result = tmp_result; 00332 00333 tmp_result = mbImpl->tag_get_data(dualEntity_tag(), &(*rit), 1, &dual_ent); 00334 if (MB_SUCCESS == tmp_result && 0 != dual_ent) { 00335 dual_ents.insert(dual_ent); 00336 continue; 00337 } 00338 00339 // no dual entity; construct one; get the bounding regions 00340 std::vector<EntityHandle> in_ents, out_ents; 00341 tmp_result = mbImpl->get_adjacencies(&(*rit), 1, 3, false, out_ents); 00342 if (MB_SUCCESS != tmp_result || out_ents.empty()) continue; 00343 00344 // get the dual vertices 00345 std::vector<EntityHandle> dual_verts(out_ents.size()); 00346 tmp_result = mbImpl->tag_get_data(dualEntity_tag(), &out_ents[0], out_ents.size(), 00347 &dual_verts[0]); 00348 if (MB_SUCCESS != tmp_result) continue; 00349 assert(dual_verts.size() <= 2); 00350 00351 double avg_pos[3]; 00352 bool bdy_face = (dual_verts.size() == 1 ? true : false); 00353 if (bdy_face) { 00354 // boundary face - make a dual vertex at the face center and put in list 00355 tmp_result = construct_dual_vertex(*rit, dual_ent, true, true); 00356 00357 // put it on vertex list 00358 dual_verts.push_back(dual_ent); 00359 } 00360 00361 assert(dual_verts.size() == 2); 00362 00363 // now create the dual edge 00364 tmp_result = mbImpl->create_element(MBEDGE, &dual_verts[0], 2, dual_ent); 00365 if (MB_SUCCESS != tmp_result || 0 == dual_ent) continue; 00366 00367 // save it in the list of new dual ents 00368 dual_ents.insert(dual_ent); 00369 00370 // tag the primal entity with its dual entity and vica versa 00371 tmp_result = mbImpl->tag_set_data(dualEntity_tag(), &(*rit), 1, &dual_ent); 00372 if (MB_SUCCESS != tmp_result) continue; 00373 00374 tmp_result = mbImpl->tag_set_data(dualEntity_tag(), &dual_ent, 1, &(*rit)); 00375 if (MB_SUCCESS != tmp_result) continue; 00376 00377 // tag the edge indicating it's a dual entity 00378 tmp_result = mbImpl->tag_set_data(isDualCell_tag(), &dual_ent, 1, &is_dual); 00379 if (MB_SUCCESS != tmp_result) continue; 00380 00381 // add a graphics point to the edge; position depends on whether it's a 00382 // bdy face (mid-pt of dual edge) or not (mid-pt of primal face) 00383 if (bdy_face) 00384 tmp_result = add_graphics_point(dual_ent); 00385 else { 00386 // get the face's position 00387 tmp_result = MeshTopoUtil(mbImpl).get_average_position(*rit, avg_pos); 00388 if (MB_SUCCESS != tmp_result) continue; 00389 tmp_result = add_graphics_point(dual_ent, avg_pos); 00390 } 00391 if (MB_SUCCESS != tmp_result) continue; 00392 } 00393 00394 return result; 00395 } 00396 00397 ErrorCode DualTool::construct_dual_faces(const Range &all_edges, 00398 Range &dual_ents) 00399 { 00400 if (all_edges.empty()) return MB_SUCCESS; 00401 00402 // make sure they're all edges 00403 assert(1 == CN::Dimension(TYPE_FROM_HANDLE(*all_edges.begin())) && 00404 1 == CN::Dimension(TYPE_FROM_HANDLE(*all_edges.rbegin()))); 00405 00406 Range::const_iterator rit; 00407 EntityHandle dual_ent; 00408 unsigned int is_dual = 0x1; 00409 ErrorCode tmp_result = MB_SUCCESS; 00410 ErrorCode result = MB_SUCCESS; 00411 Range equiv_edges; 00412 #define TRC if (MB_SUCCESS != tmp_result) {result = tmp_result; continue;} 00413 for (rit = all_edges.begin(); rit != all_edges.end(); rit++) { 00414 00415 tmp_result = mbImpl->tag_get_data(dualEntity_tag(), &(*rit), 1, &dual_ent); 00416 if (MB_SUCCESS == tmp_result && 0 != dual_ent) { 00417 dual_ents.insert(dual_ent); 00418 continue; 00419 } 00420 00421 // no dual entity; construct one; get the dual vertices bounding the edge in radial order, 00422 // then construct the dual face 00423 std::vector<EntityHandle> rad_dverts; 00424 bool bdy_edge; 00425 tmp_result = get_radial_dverts(*rit, rad_dverts, bdy_edge);TRC 00426 if (rad_dverts.empty()) continue; 00427 00428 tmp_result = mbImpl->create_element(MBPOLYGON, &rad_dverts[0], rad_dverts.size(), dual_ent);TRC 00429 00430 // tag it indicating it's a dual entity, and tag primal/dual with dual/primal 00431 tmp_result = mbImpl->tag_set_data(isDualCell_tag(), &dual_ent, 1, &is_dual);TRC 00432 tmp_result = mbImpl->tag_set_data(dualEntity_tag(), &(*rit), 1, &dual_ent);TRC 00433 tmp_result = mbImpl->tag_set_data(dualEntity_tag(), &dual_ent, 1, &(*rit));TRC 00434 00435 // save it in the list of new dual ents 00436 dual_ents.insert(dual_ent); 00437 00438 // add a graphics point to the cell; position depends on whether it's a 00439 // bdy cell (mid-pt of cell's vertices) or not (mid-pt of primal edge) 00440 double avg_pos[3]; 00441 tmp_result = MeshTopoUtil(mbImpl).get_average_position(*rit, avg_pos);TRC 00442 if (bdy_edge) { 00443 00444 // add a new dual edge betw last 2 verts 00445 EntityHandle new_edge; 00446 tmp_result = mbImpl->create_element(MBEDGE, &rad_dverts[rad_dverts.size()-2], 00447 2, new_edge);TRC 00448 tmp_result = mbImpl->tag_set_data(isDualCell_tag(), &new_edge, 1, &is_dual);TRC 00449 00450 // tag the new dual edge with the primal edge as it's dual entity; primal 00451 // edge IS NOT likewise tagged, since it's already tagged with the 2cell 00452 tmp_result = mbImpl->tag_set_data(dualEntity_tag(), &new_edge, 1, &(*rit)); TRC 00453 00454 // add a graphics pt, position is center of primal edge 00455 tmp_result = add_graphics_point(dual_ent);TRC 00456 tmp_result = add_graphics_point(new_edge, avg_pos);TRC 00457 } 00458 00459 else { 00460 // if inside, point goes on the 2cell, at primal edge mid-pt 00461 tmp_result = add_graphics_point(dual_ent, avg_pos);TRC 00462 } 00463 00464 // check to see whether we have equiv entities; if we find any, save for later fixup 00465 Range dum_edges, dum_poly(dual_ent, dual_ent); 00466 tmp_result = mbImpl->get_adjacencies(dum_poly, 1, false, dum_edges); 00467 if (MB_MULTIPLE_ENTITIES_FOUND == tmp_result) { 00468 // we do - need to add adjacencies to disambiguate; use the primal 00469 equiv_edges.merge(dum_edges); 00470 } 00471 } 00472 00473 if (!equiv_edges.empty()) 00474 result = check_dual_equiv_edges(equiv_edges); 00475 00476 return result; 00477 } 00478 00479 ErrorCode DualTool::check_dual_equiv_edges(Range &dual_edges) 00480 { 00481 // fix equivalent dual edges (i.e. edges whose vertices define multiple edges) 00482 // by explicitly adding adjacencies to containing polygons; adjacent polygons 00483 // found by going through primal 00484 ErrorCode tmp_result, result = MB_SUCCESS; 00485 00486 Range all_dedges(dual_edges); 00487 // first, go through all dual edges and find equivalent edges (by looking for 00488 // up-adjacent edges on the vertices of each edge) 00489 for (Range::iterator rit = dual_edges.begin(); rit != dual_edges.end(); rit++) { 00490 Range connect, dum_range(*rit, *rit); 00491 tmp_result = mbImpl->get_adjacencies(dum_range, 0, false, connect); 00492 if (MB_SUCCESS != tmp_result) continue; 00493 tmp_result = mbImpl->get_adjacencies(connect, 1, false, all_dedges, Interface::UNION); 00494 if (MB_SUCCESS != tmp_result) continue; 00495 } 00496 00497 // save a copy for checking later 00498 Range save_all_2cells; 00499 00500 // go through each edge 00501 while (!all_dedges.empty()) { 00502 EntityHandle this_edge = *all_dedges.begin(); 00503 all_dedges.erase(all_dedges.begin()); 00504 00505 const EntityHandle *connect; 00506 int num_connect; 00507 result = mbImpl->get_connectivity(this_edge, connect, num_connect); 00508 if (MB_SUCCESS != result) continue; 00509 00510 Range dum_edges, verts; 00511 verts.insert(connect[0]); 00512 verts.insert(connect[1]); 00513 tmp_result = mbImpl->get_adjacencies(verts, 1, false, dum_edges); 00514 if (MB_SUCCESS != tmp_result) { 00515 result = tmp_result; 00516 continue; 00517 } 00518 if (dum_edges.size() == 1) { 00519 // not an equiv edge - already removed from list, so just continue 00520 continue; 00521 } 00522 00523 // ok, have an equiv entity - fix by looking through primal 00524 // pre-get the primal of these 00525 EntityHandle dedge_quad; 00526 tmp_result = mbImpl->tag_get_data(dualEntity_tag(), &this_edge, 1, &dedge_quad); 00527 if (MB_SUCCESS != tmp_result) { 00528 result = tmp_result; 00529 continue; 00530 } 00531 00532 if (MBQUAD == mbImpl->type_from_handle(dedge_quad)) { 00533 00534 // get the primal edges adj to quad 00535 Range dum_quad_range(dedge_quad, dedge_quad), adj_pedges; 00536 tmp_result = mbImpl->get_adjacencies(dum_quad_range, 1, false, adj_pedges); 00537 if (MB_SUCCESS != tmp_result) { 00538 result = tmp_result; 00539 continue; 00540 } 00541 // get the dual 2cells corresponding to those pedges 00542 std::vector<EntityHandle> dcells; 00543 dcells.resize(adj_pedges.size()); 00544 tmp_result = mbImpl->tag_get_data(dualEntity_tag(), adj_pedges, &dcells[0]); 00545 if (MB_SUCCESS != tmp_result) { 00546 result = tmp_result; 00547 continue; 00548 } 00549 // now add explicit adjacencies from the dedge to those dcells 00550 std::vector<EntityHandle>::iterator vit; 00551 for (vit = dcells.begin(); vit != dcells.end(); vit++) { 00552 save_all_2cells.insert(*vit); 00553 00554 assert(MBPOLYGON == mbImpl->type_from_handle(*vit)); 00555 tmp_result = mbImpl->add_adjacencies(this_edge, &(*vit), 1, false); 00556 if (MB_SUCCESS != tmp_result) { 00557 result = tmp_result; 00558 continue; 00559 } 00560 // check that there are really adjacencies and *vit is in them 00561 const EntityHandle *adjs; 00562 int num_adjs; 00563 tmp_result = reinterpret_cast<Core*>(mbImpl)->a_entity_factory()-> 00564 get_adjacencies(this_edge, adjs, num_adjs); 00565 if (NULL == adjs || std::find(adjs, adjs+num_adjs, *vit) == adjs+num_adjs) 00566 std::cout << "Add_adjacencies failed in construct_dual_faces." << std::endl; 00567 } 00568 } 00569 else { 00570 // else, have a dual edge representing a bdy edge - tie directly to 00571 // dual entity if its dual entity 00572 EntityHandle bdy_dcell; 00573 tmp_result = mbImpl->tag_get_data(dualEntity_tag(), &dedge_quad, 1, &bdy_dcell); TRC 00574 assert(MBPOLYGON == mbImpl->type_from_handle(bdy_dcell)); 00575 00576 tmp_result = mbImpl->add_adjacencies(this_edge, &bdy_dcell, 1, false); 00577 if (MB_SUCCESS != tmp_result) { 00578 result = tmp_result; 00579 continue; 00580 } 00581 } 00582 } 00583 00584 00585 // sanity check - look for adj edges again, and check for equiv entities 00586 for (Range::iterator vit = save_all_2cells.begin(); 00587 vit != save_all_2cells.end(); vit++) { 00588 Range adj_edges, dum_quad_range; 00589 dum_quad_range.insert(*vit); 00590 assert(MBPOLYGON == mbImpl->type_from_handle(*vit)); 00591 tmp_result = mbImpl->get_adjacencies(dum_quad_range, 1, false, adj_edges); 00592 if (MB_MULTIPLE_ENTITIES_FOUND == tmp_result) { 00593 std::cout << "Multiple entities returned for polygon " << mbImpl->id_from_handle(*vit) 00594 << "." << std::endl; 00595 continue; 00596 } 00597 } 00598 // success! 00599 return result; 00600 } 00601 00602 ErrorCode DualTool::construct_dual_cells(const Range &all_verts, 00603 Range &dual_ents) 00604 { 00605 if (all_verts.empty()) return MB_SUCCESS; 00606 00607 // make sure they're all edges 00608 assert(0 == CN::Dimension(TYPE_FROM_HANDLE(*all_verts.begin())) && 00609 0 == CN::Dimension(TYPE_FROM_HANDLE(*all_verts.rbegin()))); 00610 00611 Range::const_iterator rit; 00612 EntityHandle dual_ent; 00613 unsigned int is_dual = 0x1; 00614 ErrorCode tmp_result = MB_SUCCESS; 00615 ErrorCode result = MB_SUCCESS; 00616 std::vector<EntityHandle> edges, dfaces; 00617 00618 for (rit = all_verts.begin(); rit != all_verts.end(); rit++) { 00619 if (tmp_result != MB_SUCCESS) result = tmp_result; 00620 00621 tmp_result = mbImpl->tag_get_data(dualEntity_tag(), &(*rit), 1, &dual_ent); 00622 if (MB_SUCCESS == tmp_result && 0 != dual_ent) { 00623 dual_ents.insert(dual_ent); 00624 continue; 00625 } 00626 00627 // no dual entity; construct one; get the edges bounding the vertex 00628 edges.clear(); 00629 dfaces.clear(); 00630 tmp_result = mbImpl->get_adjacencies(&(*rit), 1, 1, false, edges); 00631 if (MB_SUCCESS != tmp_result) continue; 00632 00633 // get the dual faces corresponding to the edges 00634 dfaces.resize(edges.size()); 00635 tmp_result = mbImpl->tag_get_data(dualEntity_tag(), &edges[0], edges.size(), &dfaces[0]); 00636 if (MB_SUCCESS != tmp_result) continue; 00637 00638 // create the dual cell from those faces 00639 tmp_result = mbImpl->create_element(MBPOLYHEDRON, &dfaces[0], dfaces.size(), dual_ent); 00640 if (MB_SUCCESS != tmp_result || 0 == dual_ent) continue; 00641 00642 // save it in the list of new dual ents 00643 dual_ents.insert(dual_ent); 00644 00645 // tag it indicating it's a dual entity 00646 tmp_result = mbImpl->tag_set_data(isDualCell_tag(), &dual_ent, 1, &is_dual); 00647 if (MB_SUCCESS != tmp_result) continue; 00648 00649 // tag the primal entity with its dual entity and vica versa 00650 tmp_result = mbImpl->tag_set_data(dualEntity_tag(), &(*rit), 1, &dual_ent); 00651 if (MB_SUCCESS != tmp_result) continue; 00652 tmp_result = mbImpl->tag_set_data(dualEntity_tag(), &dual_ent, 1, &(*rit)); 00653 if (MB_SUCCESS != tmp_result) continue; 00654 } 00655 00656 return result; 00657 } 00658 00661 ErrorCode DualTool::get_radial_dverts(const EntityHandle edge, 00662 std::vector<EntityHandle> &rad_dverts, 00663 bool &bdy_edge) 00664 { 00665 rad_dverts.clear(); 00666 00667 std::vector<EntityHandle> rad_faces, rad_ents; 00668 ErrorCode result = MeshTopoUtil(mbImpl).star_entities(edge, rad_faces, bdy_edge, 0, 00669 &rad_ents); 00670 if (MB_SUCCESS != result) return result; 00671 00672 if (bdy_edge) { 00673 // if we're a bdy edge, change the order back to what DualTool expects 00674 rad_ents.push_back(*rad_faces.rbegin()); 00675 rad_ents.push_back(*rad_faces.begin()); 00676 } 00677 00678 rad_dverts.resize(rad_ents.size()); 00679 for (unsigned int i = 0; i < rad_ents.size(); i++) { 00680 EntityHandle dual_ent; 00681 result = mbImpl->tag_get_data(dualEntity_tag(), &rad_ents[i], 1, 00682 &dual_ent); 00683 if (!bdy_edge || i < rad_ents.size()-2) rad_dverts[i] = dual_ent; 00684 else { 00685 // fix up this entry 00686 assert(mbImpl->type_from_handle(dual_ent) == MBEDGE); 00687 00688 // get connectivity of that edge 00689 const EntityHandle *connect; 00690 int num_connect; 00691 result = mbImpl->get_connectivity(dual_ent, connect, num_connect); 00692 if (MB_SUCCESS != result) return result; 00693 00694 // we want the one that's not already on the list; reuse last_face 00695 int last_hex = (i == rad_ents.size()-1 ? 0 : i-1); 00696 EntityHandle last_face = (connect[0] == rad_dverts[last_hex] ? connect[1] : connect[0]); 00697 rad_dverts[i] = last_face; 00698 } 00699 } 00700 00701 return result; 00702 } 00703 00705 ErrorCode DualTool::construct_hex_dual(Range &entities) 00706 { 00707 std::vector<EntityHandle> evec; 00708 std::copy(entities.begin(), entities.end(), std::back_inserter(evec)); 00709 return construct_hex_dual(&evec[0], evec.size()); 00710 } 00711 00713 ErrorCode DualTool::construct_hex_dual(EntityHandle *entities, 00714 const int num_entities) 00715 { 00716 // really quite simple: 00717 00718 // construct the dual... 00719 ErrorCode result = construct_dual(entities, num_entities); 00720 if (MB_SUCCESS != result) { 00721 std::cerr << "Error constructing dual entities for primal entities." << std::endl; 00722 return result; 00723 } 00724 00725 // now traverse to build 1d and 2d hyperplanes 00726 result = construct_dual_hyperplanes(1, entities, num_entities); 00727 if (MB_SUCCESS != result) { 00728 std::cerr << "Problem traversing 1d hyperplanes." << std::endl; 00729 return result; 00730 } 00731 if (MB_SUCCESS != result) return result; 00732 00733 result = construct_dual_hyperplanes(2, entities, num_entities); 00734 if (MB_SUCCESS != result) { 00735 std::cerr << "Problem traversing 2d hyperplanes." << std::endl; 00736 return result; 00737 } 00738 if (MB_SUCCESS != result) return result; 00739 00740 result = construct_hp_parent_child(); 00741 if (MB_SUCCESS != result) { 00742 std::cerr << "Problem constructing parent/child relations between hyperplanes." 00743 << std::endl; 00744 return result; 00745 } 00746 if (MB_SUCCESS != result) return result; 00747 00748 // see? simple, just like I said 00749 return MB_SUCCESS; 00750 } 00751 00753 ErrorCode DualTool::get_dual_entities(const int dim, 00754 EntityHandle *entities, 00755 const int num_entities, 00756 Range &dual_ents) 00757 { 00758 if (0 == isDualCell_tag()) return MB_SUCCESS; 00759 if (0 > dim || 3 < dim) return MB_INDEX_OUT_OF_RANGE; 00760 00761 unsigned int dum = 0x1; 00762 const void *dum_ptr = &dum; 00763 static EntityType dual_type[] = {MBVERTEX, MBEDGE, MBPOLYGON, MBPOLYHEDRON}; 00764 00765 Range dim_ents; 00766 00767 ErrorCode result; 00768 00769 if (0 == entities || 0 == num_entities) { 00770 // just get all the dual entities of this dimension 00771 result = mbImpl->get_entities_by_type_and_tag(0, dual_type[dim], 00772 &isDualCellTag, &dum_ptr, 1, 00773 dual_ents); 00774 } 00775 else { 00776 // else look for specific dual entities 00777 result = mbImpl->get_adjacencies(entities, num_entities, 3-dim, false, 00778 dim_ents, Interface::UNION); 00779 if (MB_SUCCESS != result) return result; 00780 std::vector<EntityHandle> dual_ents_vec(dim_ents.size()); 00781 result = mbImpl->tag_get_data(dualEntity_tag(), dim_ents, &dual_ents_vec[0]); 00782 if (MB_SUCCESS != result) return result; 00783 std::copy(dual_ents_vec.begin(), dual_ents_vec.end(), 00784 range_inserter(dual_ents)); 00785 } 00786 00787 return result; 00788 } 00789 00791 ErrorCode DualTool::get_dual_entities(const int dim, 00792 EntityHandle *entities, 00793 const int num_entities, 00794 std::vector<EntityHandle> &dual_ents) 00795 { 00796 Range tmp_range; 00797 ErrorCode result = get_dual_entities(dim, entities, num_entities, tmp_range); 00798 if (MB_SUCCESS != result) 00799 return result; 00800 00801 // dual_ents.insert(dual_ents.end(), tmp_range.begin(), tmp_range.end()); 00802 dual_ents.reserve(dual_ents.size() + tmp_range.size()); 00803 for (Range::const_iterator it = tmp_range.begin(); 00804 it != tmp_range.end(); 00805 ++it) 00806 { 00807 dual_ents.push_back(*it); 00808 } 00809 return MB_SUCCESS; 00810 } 00811 00812 ErrorCode DualTool::get_dual_hyperplanes(const Interface *impl, const int dim, 00813 Range &dual_ents) 00814 { 00815 if (dim != 1 && dim != 2) return MB_INDEX_OUT_OF_RANGE; 00816 00817 Tag dual_tag; 00818 ErrorCode result; 00819 00820 if (dim == 1) 00821 result = impl->tag_get_handle(DUAL_CURVE_TAG_NAME, 1, MB_TYPE_HANDLE, dual_tag ); 00822 else 00823 result = impl->tag_get_handle(DUAL_SURFACE_TAG_NAME, 1, MB_TYPE_HANDLE, dual_tag ); 00824 00825 if (MB_SUCCESS == result) 00826 result = impl->get_entities_by_type_and_tag(0, MBENTITYSET, &dual_tag, NULL, 1, dual_ents, 00827 Interface::UNION); 00828 00829 return result; 00830 } 00831 00832 ErrorCode DualTool::construct_dual_hyperplanes(const int dim, 00833 EntityHandle *entities, 00834 const int num_entities) 00835 { 00836 // this function traverses dual faces of input dimension, constructing 00837 // dual hyperplanes of them in sets as it goes 00838 00839 // check various inputs 00840 int num_quads, num_hexes; 00841 if ( 00842 // this function only makes sense for dim == 1 or dim == 2 00843 (dim != 1 && dim != 2) || 00844 // should either be quads or hexes around 00845 mbImpl->get_number_entities_by_type(0, MBQUAD, num_quads) != MB_SUCCESS || 00846 mbImpl->get_number_entities_by_type(0, MBHEX, num_hexes) != MB_SUCCESS || 00847 // if we're asking for 1d dual ents, should be quads around 00848 (num_quads == 0 && dim == 1) || 00849 // if we're asking for 2d dual ents, should be hexes around 00850 (num_hexes == 0 && dim == 2)) 00851 return MB_FAILURE; 00852 00853 // get tag name for this dimension hyperplane 00854 Tag gid_tag; 00855 int dum = 0; 00856 ErrorCode result = mbImpl->tag_get_handle(GLOBAL_ID_TAG_NAME, 00857 1, MB_TYPE_INTEGER, 00858 gid_tag, 00859 MB_TAG_CREAT|MB_TAG_DENSE, 00860 &dum); 00861 if (MB_SUCCESS != result) 00862 return result; 00863 00864 Tag hp_tag = (1 == dim ? dualCurve_tag() : dualSurface_tag()); 00865 00866 // two stacks: one completely untreated entities, and the other untreated 00867 // entities on the current dual hyperplane 00868 std::vector<EntityHandle> tot_untreated; 00869 00870 // put dual entities of this dimension on the untreated list 00871 result = get_dual_entities(dim, entities, num_entities, tot_untreated); 00872 if (MB_SUCCESS != result) 00873 return result; 00874 00875 // main part of traversal loop 00876 EntityHandle this_ent; 00877 EntityHandle this_hp; 00878 std::vector<EntityHandle> parents; 00879 00880 while (!tot_untreated.empty()) { 00881 if (debug && dim == 2 /*(tot_untreated.size()%report == 0)*/) 00882 std::cout << "Untreated list size " << tot_untreated.size() << "." << std::endl; 00883 00884 this_ent = tot_untreated.back(); tot_untreated.pop_back(); 00885 result = mbImpl->tag_get_data(hp_tag, &this_ent, 1, &this_hp); 00886 if (MB_SUCCESS != result && MB_TAG_NOT_FOUND != result) 00887 return result; 00888 00889 // d for this entity having a hyperplane assignment already 00890 else if (this_hp != 0) 00891 continue; 00892 00893 if (1 == dim && check_1d_loop_edge(this_ent)) continue; 00894 00895 // inner loop: traverse the hyperplane 'till we don't have any more 00896 result = traverse_hyperplane(hp_tag, this_hp, this_ent); 00897 if (MB_SUCCESS != result) { 00898 std::cout << "Failed to traverse hyperplane "; 00899 if (this_hp) std::cout << mbImpl->id_from_handle(this_hp) << "." << std::endl; 00900 else std::cout << "0." << std::endl; 00901 return result; 00902 } 00903 00904 // ok, now order the edges if it's a chord 00905 if (1 == dim) order_chord(this_hp); 00906 } 00907 00908 return MB_SUCCESS; 00909 } 00910 00911 ErrorCode DualTool::traverse_hyperplane(const Tag hp_tag, 00912 EntityHandle &this_hp, 00913 EntityHandle this_ent) 00914 { 00915 Range tmp_star, star, tmp_range, new_hyperplane_ents; 00916 std::vector<EntityHandle> hp_untreated; 00917 int dim = mbImpl->dimension_from_handle(this_ent); 00918 MeshTopoUtil mtu(mbImpl); 00919 this_hp = 0; 00920 ErrorCode result; 00921 00922 unsigned short mark_val = 0x0; 00923 Tag mark_tag; 00924 result = mbImpl->tag_get_handle("__hyperplane_mark", 1, MB_TYPE_BIT, mark_tag, 00925 MB_TAG_CREAT|MB_TAG_BIT); 00926 if (MB_SUCCESS != result) 00927 return result; 00928 mark_val = 0x1; 00929 00930 while (0 != this_ent) { 00931 EntityHandle tmp_hp = get_dual_hyperplane(this_ent); 00932 if (0 == this_hp && 0 != tmp_hp) this_hp = tmp_hp; 00933 00934 if (0 == tmp_hp) new_hyperplane_ents.insert(this_ent); 00935 00936 if (debug && hp_untreated.size()%10 == 0) 00937 std::cout << "Dual surface " << this_hp << ", hp_untreated list size = " 00938 << hp_untreated.size() << "." << std::endl; 00939 00940 // get the 2nd order adjacencies through lower dimension 00941 tmp_range.clear(); tmp_star.clear(); star.clear(); 00942 result = mtu.get_bridge_adjacencies(this_ent, dim-1, dim, star); RR; 00943 00944 // get the bridge adjacencies through higher dimension 00945 result = mtu.get_bridge_adjacencies(this_ent, dim+1, dim, tmp_star); RR; 00946 tmp_range = subtract( star, tmp_star); 00947 00948 for (Range::iterator rit = tmp_range.begin(); rit != tmp_range.end(); rit++) { 00949 if (new_hyperplane_ents.find(*rit) != new_hyperplane_ents.end()) continue; 00950 00951 // check for tag first, 'cuz it's probably faster than checking adjacencies 00952 // assign to avoid valgrind warning 00953 unsigned short tmp_mark = 0x0; 00954 result = mbImpl->tag_get_data(mark_tag, &(*rit), 1, &tmp_mark); 00955 if (MB_SUCCESS == result && mark_val == tmp_mark) 00956 continue; 00957 00958 // if it's on the loop, it's not eligible 00959 if (1 == dim && check_1d_loop_edge(*rit)) continue; 00960 00961 // have one on this hp; just put it on the hp_untreated list for now, 00962 // will get tagged and put in the hp set later 00963 hp_untreated.push_back(*rit); 00964 result = mbImpl->tag_set_data(mark_tag, &(*rit), 1, &mark_val); 00965 if (MB_SUCCESS != result) 00966 return result; 00967 } 00968 00969 // end of inner loop; get the next this_ent, or set to zero 00970 if (hp_untreated.empty()) this_ent = 0; 00971 else { 00972 this_ent = hp_untreated.back(); 00973 hp_untreated.pop_back(); 00974 } 00975 } 00976 00977 if (debug_ap) { 00978 std::string hp_name; 00979 if (2 == dim) hp_name = "sheet"; 00980 else hp_name = "chord"; 00981 00982 if (0 == this_hp) std::cout << "Constructed new " << hp_name << " with "; 00983 else { 00984 int this_id; 00985 result = mbImpl->tag_get_data(globalId_tag(), &this_hp, 1, &this_id); RR; 00986 std::cout << "Added to " << hp_name << " " << this_id << " "; 00987 } 00988 if (dim == 2) std::cout << "edges:" << std::endl; 00989 else std::cout << "quads:" << std::endl; 00990 std::vector<EntityHandle> pents(new_hyperplane_ents.size()); 00991 result = mbImpl->tag_get_data(dualEntity_tag(), new_hyperplane_ents, 00992 &pents[0]); RR; 00993 for (std::vector<EntityHandle>::iterator vit = pents.begin(); 00994 vit != pents.end(); vit++) { 00995 if (vit != pents.begin()) std::cout << ", "; 00996 std::cout << mbImpl->id_from_handle(*vit); 00997 } 00998 std::cout << std::endl; 00999 } 01000 01001 if (0 == this_hp) { 01002 // ok, doesn't have one; make a new hyperplane 01003 int new_id = -1; 01004 result = construct_new_hyperplane(dim, this_hp, new_id); 01005 if (MB_SUCCESS != result) return result; 01006 01007 if (debug_ap) { 01008 std::cout << "New "; 01009 if (2 == dim) std::cout << " sheet "; 01010 else std::cout << " chord "; 01011 std::cout << new_id << " constructed." << std::endl; 01012 } 01013 } 01014 01015 // set the hp_val for entities which didn't have one before 01016 std::vector<EntityHandle> hp_tags(new_hyperplane_ents.size()); 01017 std::fill(hp_tags.begin(), hp_tags.end(), this_hp); 01018 result = mbImpl->tag_set_data(hp_tag, new_hyperplane_ents, &hp_tags[0]); 01019 if (MB_SUCCESS != result) 01020 return result; 01021 result = mbImpl->add_entities(this_hp, new_hyperplane_ents); 01022 if (MB_SUCCESS != result) 01023 return result; 01024 01025 // unmark the entities by removing the tag 01026 result = mbImpl->tag_delete(mark_tag); 01027 if (MB_SUCCESS != result) 01028 return result; 01029 01030 return MB_SUCCESS; 01031 } 01032 01033 ErrorCode DualTool::order_chord(EntityHandle chord_set) 01034 { 01035 // re-order the 1cells in the set so they are in order along the chord 01036 // start by finding the vertex dual to a quad 01037 Range verts, one_cells; 01038 ErrorCode result = mbImpl->get_entities_by_dimension(chord_set, 1, one_cells); 01039 if (MB_SUCCESS != result || one_cells.empty()) return MB_FAILURE; 01040 01041 result = mbImpl->get_adjacencies(one_cells, 0, false, verts, Interface::UNION); 01042 if (MB_SUCCESS != result || verts.empty()) return MB_FAILURE; 01043 01044 EntityHandle last_vert = 0; 01045 for (Range::iterator rit = verts.begin(); rit != verts.end(); rit++) { 01046 if (TYPE_FROM_HANDLE(get_dual_entity(*rit)) == MBQUAD) { 01047 last_vert = *rit; 01048 break; 01049 } 01050 } 01051 // if there's no vertex owned by a quad, just start with 1st one 01052 if (0 == last_vert) last_vert = *verts.begin(); 01053 01054 // now, skip from vertex to vertex, building a list of 1cells 01055 std::vector<EntityHandle> ordered_1cells; 01056 EntityHandle last_1cell = 0; 01057 Range dum1, dum2; 01058 const EntityHandle *connect; 01059 int num_connect; 01060 ErrorCode tmp_result = MB_SUCCESS; 01061 while(ordered_1cells.size() != one_cells.size()) { 01062 dum1 = one_cells; 01063 result = mbImpl->get_adjacencies(&last_vert, 1, 1, false, dum1); 01064 if (0 != last_1cell) dum1.erase(last_1cell); 01065 // assert(1 == dum1.size()); 01066 if (0 != last_1cell && 1 != dum1.size()) { 01067 std::cerr << "unexpected size traversing chord." << std::endl; 01068 tmp_result = MB_FAILURE; 01069 } 01070 01071 last_1cell = *dum1.begin(); 01072 ordered_1cells.push_back(last_1cell); 01073 result = mbImpl->get_connectivity(last_1cell, connect, num_connect); RR; 01074 if (last_vert == connect[0]) last_vert = connect[1]; 01075 else last_vert = connect[0]; 01076 } 01077 01078 // now have the 1cells in order, replace them in the set 01079 if (MB_SUCCESS == tmp_result) { 01080 result = mbImpl->remove_entities(chord_set, one_cells); RR; 01081 result = mbImpl->add_entities(chord_set, &ordered_1cells[0], ordered_1cells.size()); RR; 01082 } 01083 01084 return MB_SUCCESS; 01085 } 01086 01087 ErrorCode DualTool::construct_new_hyperplane(const int dim, 01088 EntityHandle &new_hyperplane, 01089 int &id) 01090 { 01091 ErrorCode result; 01092 if (1 == dim) 01093 result = mbImpl->create_meshset((MESHSET_ORDERED | MESHSET_TRACK_OWNER), 01094 new_hyperplane); 01095 else 01096 result = mbImpl->create_meshset((MESHSET_SET | MESHSET_TRACK_OWNER), 01097 new_hyperplane); 01098 if (MB_SUCCESS != result) return result; 01099 01100 if (-1 == id) { 01101 Range all_hyperplanes; 01102 result = get_dual_hyperplanes(mbImpl, dim, all_hyperplanes); RR; 01103 std::vector<int> gids(all_hyperplanes.size()); 01104 result = mbImpl->tag_get_data(globalIdTag, all_hyperplanes, &gids[0]); RR; 01105 for (unsigned int i = 0; i < gids.size(); i++) 01106 if (gids[i] > id) id = gids[i]; 01107 id++; 01108 if (0 == id) id++; 01109 } 01110 01111 result = mbImpl->tag_set_data(globalId_tag(), &new_hyperplane, 1, &id); RR; 01112 Tag hp_tag = (1 == dim ? dualCurve_tag() : dualSurface_tag()); 01113 result = mbImpl->tag_set_data(hp_tag, &new_hyperplane, 1, &new_hyperplane); 01114 01115 // assign a category name to these sets 01116 static const char dual_category_names[2][CATEGORY_TAG_SIZE] = 01117 {"Chord\0", "Sheet\0"}; 01118 01119 result = mbImpl->tag_set_data(categoryTag, &new_hyperplane, 1, dual_category_names[dim-1]); 01120 01121 return result; 01122 } 01123 01124 bool DualTool::check_1d_loop_edge(EntityHandle this_ent) 01125 { 01126 // make sure it's an edge 01127 if (MBEDGE != mbImpl->type_from_handle(this_ent)) return false; 01128 01129 // also has to be a dual entity 01130 unsigned int dum; 01131 ErrorCode result = mbImpl->tag_get_data(isDualCell_tag(), &this_ent, 1, &dum); 01132 if (MB_SUCCESS != result || dum != 0x1) return false; 01133 01134 const EntityHandle *verts; 01135 EntityHandle vert_tags[2]; 01136 int num_verts; 01137 result = mbImpl->get_connectivity(this_ent, verts, num_verts); 01138 if (MB_SUCCESS != result) return false; 01139 01140 result = mbImpl->tag_get_data(dualEntity_tag(), verts, 2, vert_tags); 01141 if (MB_SUCCESS != result || 01142 mbImpl->type_from_handle(vert_tags[0]) != MBQUAD || 01143 mbImpl->type_from_handle(vert_tags[1]) != MBQUAD) return false; 01144 01145 else return true; 01146 } 01147 01148 ErrorCode DualTool::construct_hp_parent_child() 01149 { 01150 Range dual_surfs, dual_cells, dual_edges; 01151 ErrorCode result = this->get_dual_hyperplanes(mbImpl, 2, dual_surfs); 01152 if (MB_SUCCESS != result || dual_surfs.empty()) return result; 01153 std::vector<EntityHandle> dual_curve_sets; 01154 01155 for (Range::iterator surf_it = dual_surfs.begin(); surf_it != dual_surfs.end(); 01156 surf_it++) { 01157 // get all the cells, edges in those cells, and chords for those edges 01158 dual_cells.clear(); 01159 result = mbImpl->get_entities_by_handle(*surf_it, dual_cells); 01160 if (MB_SUCCESS != result) return result; 01161 dual_edges.clear(); 01162 result = mbImpl->get_adjacencies(dual_cells, 1, false, dual_edges, Interface::UNION); 01163 if (MB_SUCCESS != result) return result; 01164 dual_curve_sets.reserve(dual_edges.size()); 01165 result = mbImpl->tag_get_data(dualCurve_tag(), dual_edges, &dual_curve_sets[0]); 01166 if (MB_SUCCESS != result) return result; 01167 01168 // reuse dual_cells to get unique list of chord sets 01169 dual_cells.clear(); 01170 for (unsigned int i = 0; i < dual_edges.size(); i++) 01171 if (dual_curve_sets[i] != 0) dual_cells.insert(dual_curve_sets[i]); 01172 01173 // now connect up this dual surf with all the 1d ones 01174 for (Range::iterator rit = dual_cells.begin(); rit != dual_cells.end(); rit++) { 01175 result = mbImpl->add_parent_child(*surf_it, *rit); 01176 if (MB_SUCCESS != result) return result; 01177 } 01178 } 01179 01180 return MB_SUCCESS; 01181 } 01182 01183 ErrorCode DualTool::get_graphics_points(EntityHandle dual_ent, 01184 std::vector<int> &npts, 01185 std::vector<GraphicsPoint> &points) 01186 { 01187 // shouldn't be a set 01188 assert(MBENTITYSET != mbImpl->type_from_handle(dual_ent)); 01189 01190 // get the graphics points comprising the given entity 01191 GraphicsPoint gp_array[DualTool::GP_SIZE]; 01192 01193 ErrorCode result = MB_SUCCESS; 01194 01195 // switch based on topological dimension 01196 switch (mbImpl->dimension_from_handle(dual_ent)) { 01197 case 0: 01198 // just return the vertex point 01199 result = mbImpl->tag_get_data(dualGraphicsPoint_tag(), &dual_ent, 1, 01200 gp_array); 01201 if (MB_SUCCESS == result) 01202 points.push_back(gp_array[0]); 01203 01204 break; 01205 01206 case 1: 01207 // get my graphics point then those of my vertices 01208 const EntityHandle *connect; 01209 int num_connect; 01210 result = mbImpl->get_connectivity(dual_ent, connect, num_connect); 01211 if (MB_SUCCESS != result) break; 01212 01213 result = mbImpl->tag_get_data(dualGraphicsPoint_tag(), connect, 2, 01214 gp_array); 01215 if (MB_SUCCESS == result) { 01216 points.push_back(gp_array[0]); 01217 points.push_back(gp_array[0]); 01218 points.push_back(gp_array[1]); 01219 result = mbImpl->tag_get_data(dualGraphicsPoint_tag(), &dual_ent, 1, 01220 gp_array); 01221 if (MB_SUCCESS == result) points[1] = gp_array[0]; 01222 } 01223 01224 npts.push_back(3); 01225 01226 break; 01227 01228 case 2: 01229 result = get_cell_points(dual_ent, npts, points); 01230 break; 01231 } 01232 01233 return result; 01234 } 01235 01236 ErrorCode DualTool::get_cell_points(EntityHandle dual_ent, 01237 std::vector<int> &npts, 01238 std::vector<GraphicsPoint> &points) 01239 { 01240 assert(MBPOLYGON == mbImpl->type_from_handle(dual_ent)); 01241 01242 // get the 1cells in this 2cell 01243 Range one_cells; 01244 01245 Range tc_range; tc_range.insert(dual_ent); 01246 ErrorCode result = mbImpl->get_adjacencies(tc_range, 1, false, one_cells, 01247 Interface::UNION); RR; 01248 01249 int num_edges = one_cells.size(); 01250 std::vector<GraphicsPoint> dum_gps(num_edges+1); 01251 01252 // get graphics points for 0cells and for this cell 01253 result = mbImpl->tag_get_data(dualGraphicsPoint_tag(), one_cells, 01254 &dum_gps[0]); RR; 01255 result = mbImpl->tag_get_data(dualGraphicsPoint_tag(), &dual_ent, 1, 01256 &(dum_gps[num_edges])); RR; 01257 01258 Range::iterator eit; 01259 const EntityHandle *connect; 01260 int num_connect; 01261 GraphicsPoint vert_gps[2]; 01262 int i; 01263 for (i = 0, eit = one_cells.begin(); i < num_edges; i++, eit++) { 01264 // get the vertices and the graphics points for them 01265 result = mbImpl->get_connectivity(*eit, connect, num_connect); RR; 01266 result = mbImpl->tag_get_data(dualGraphicsPoint_tag(), connect, 2, 01267 vert_gps); RR; 01268 01269 // make the 2 tris corresponding to this edge; don't worry about order 01270 // for now 01271 npts.push_back(3); 01272 points.push_back(dum_gps[num_edges]); 01273 points.push_back(vert_gps[0]); 01274 points.push_back(dum_gps[i]); 01275 01276 npts.push_back(3); 01277 points.push_back(dum_gps[num_edges]); 01278 points.push_back(dum_gps[i]); 01279 points.push_back(vert_gps[1]); 01280 } 01281 01282 return result; 01283 } 01284 01285 ErrorCode DualTool::get_graphics_points(const Range &in_range, 01286 std::vector<GraphicsPoint> &points, 01287 const bool assign_ids, 01288 const int start_id) 01289 { 01290 // return graphics points on dual entities in in_range or in entities 01291 // in sets in in_range 01292 ErrorCode result; 01293 01294 // for each dual hyperplane set: 01295 Range::const_iterator rit; 01296 01297 Range two_cells, all_cells; 01298 for (rit = in_range.begin(); rit != in_range.end(); rit++) { 01299 // for each entity: 01300 two_cells.clear(); 01301 EntityType this_type = mbImpl->type_from_handle(*rit); 01302 if (MBENTITYSET == this_type) { 01303 result = mbImpl->get_entities_by_handle(*rit, two_cells); RR; 01304 01305 std::copy(two_cells.begin(), two_cells.end(), range_inserter(all_cells)); 01306 } 01307 01308 else { 01309 two_cells.insert(*rit); 01310 assert(this_type == MBVERTEX || this_type == MBEDGE || 01311 this_type == MBPOLYGON || this_type == MBPOLYHEDRON); 01312 } 01313 01314 result = mbImpl->get_adjacencies(two_cells, 0, false, all_cells, 01315 Interface::UNION); RR; 01316 result = mbImpl->get_adjacencies(two_cells, 1, false, all_cells, 01317 Interface::UNION); RR; 01318 } 01319 01320 // get graphics points 01321 points.resize(all_cells.size()); 01322 01323 result = mbImpl->tag_get_data(dualGraphicsPointTag, all_cells, 01324 &points[0]); RR; 01325 01326 if (assign_ids) { 01327 int i = start_id; 01328 01329 for (std::vector<GraphicsPoint>::iterator vit = points.begin(); 01330 vit != points.end(); vit++) 01331 vit->id = i++; 01332 01333 result = mbImpl->tag_set_data(dualGraphicsPoint_tag(), all_cells, 01334 &points[0]); RR; 01335 } 01336 01337 return result; 01338 } 01339 01340 EntityHandle DualTool::next_loop_vertex(const EntityHandle last_v, 01341 const EntityHandle this_v, 01342 const EntityHandle dual_surf) 01343 { 01344 // given two vertices, find the next one on the loop; if one is a dual 01345 // surface, then just choose either one for that surface 01346 assert((0 == last_v || mbImpl->type_from_handle(last_v) == MBVERTEX) && 01347 mbImpl->type_from_handle(this_v) == MBVERTEX && 01348 mbImpl->type_from_handle(dual_surf) == MBENTITYSET); 01349 01350 // get the connected vertices 01351 MeshTopoUtil tpu(mbImpl); 01352 Range other_verts; 01353 ErrorCode result = tpu.get_bridge_adjacencies(this_v, 1, 0, other_verts); 01354 if (MB_SUCCESS != result || other_verts.empty()) return 0; 01355 01356 //if (mbImpl->type_from_handle(last_v) == MBENTITYSET) { 01357 // dual surface, choose either; first get a 2cell on this surface 01358 Range tcells, tcells2, verts; 01359 result = mbImpl->get_entities_by_type(dual_surf, MBPOLYGON, tcells); 01360 if (MB_SUCCESS != result || tcells.empty()) return 0; 01361 01362 // ok, pay attention here: first get 2cells common to dual surface and this_v 01363 verts.insert(this_v); 01364 result = mbImpl->get_adjacencies(verts, 2, false, tcells); 01365 if (MB_SUCCESS != result || tcells.empty()) return 0; 01366 01367 // next get vertices common to both 2cells and subtract from other_verts; also 01368 // remove last_v if it's non-zero 01369 verts.clear(); 01370 result = mbImpl->get_adjacencies(tcells, 0, false, verts); 01371 if (MB_SUCCESS != result || verts.empty()) return 0; 01372 01373 Range tmp_verts = subtract( other_verts, verts); 01374 other_verts.swap(tmp_verts); 01375 if (0 != last_v) other_verts.erase(last_v); 01376 01377 // now get intersection of remaining vertices and 2 2cells vertices 01378 // look at each one successively; should find one, maybe not on both 01379 tmp_verts = other_verts; 01380 Range tmp_faces(*tcells.begin(), *tcells.begin()); 01381 result = mbImpl->get_adjacencies(tmp_faces, 0, false, tmp_verts); 01382 if (MB_SUCCESS == result && !tmp_verts.empty()) return *tmp_verts.begin(); 01383 tmp_faces.clear(); 01384 tmp_faces.insert(*tcells.rbegin()); 01385 result = mbImpl->get_adjacencies(tmp_faces, 0, false, other_verts); 01386 if (MB_SUCCESS == result && !other_verts.empty()) return *other_verts.begin(); 01387 01388 // if we got here, there isn't any 01389 return 0; 01390 } 01391 01392 EntityHandle DualTool::get_dual_hyperplane(const EntityHandle ncell) 01393 { 01394 // get the sheet or chord it's in 01395 std::vector<EntityHandle> adj_sets; 01396 ErrorCode result = mbImpl->get_adjacencies(&ncell, 1, 4, false, adj_sets); 01397 if (MB_SUCCESS != result) return 0; 01398 01399 EntityHandle dum_set; 01400 for (std::vector<EntityHandle>::iterator vit = adj_sets.begin(); 01401 vit != adj_sets.end(); vit++) { 01402 if (mbImpl->tag_get_data(dualCurve_tag(), &(*vit), 1, &dum_set) != MB_TAG_NOT_FOUND || 01403 mbImpl->tag_get_data(dualSurface_tag(), &(*vit), 1, &dum_set) != MB_TAG_NOT_FOUND) 01404 return *vit; 01405 } 01406 01407 return 0; 01408 } 01409 01411 ErrorCode DualTool::set_dual_surface_or_curve(EntityHandle entity, 01412 const EntityHandle dual_hyperplane, 01413 const int dual_entity_dimension) 01414 { 01415 if (1 == dual_entity_dimension) 01416 mbImpl->tag_set_data(dualCurve_tag(), &entity, 1, &dual_hyperplane); 01417 else if (2 == dual_entity_dimension) 01418 mbImpl->tag_set_data(dualSurface_tag(), &entity, 1, &dual_hyperplane); 01419 else 01420 return MB_INDEX_OUT_OF_RANGE; 01421 01422 return MB_SUCCESS; 01423 } 01424 01426 EntityHandle DualTool::get_dual_entity(const EntityHandle this_ent) const 01427 { 01428 EntityHandle dual_ent; 01429 ErrorCode result = mbImpl->tag_get_data(dualEntity_tag(), &this_ent, 1, &dual_ent); 01430 if (MB_SUCCESS != result || MB_TAG_NOT_FOUND == result) return 0; 01431 else return dual_ent; 01432 } 01433 01435 EntityHandle DualTool::get_extra_dual_entity(const EntityHandle this_ent) 01436 { 01437 EntityHandle dual_ent; 01438 ErrorCode result = mbImpl->tag_get_data(extraDualEntity_tag(), &this_ent, 1, &dual_ent); 01439 if (MB_SUCCESS != result || MB_TAG_NOT_FOUND == result) return 0; 01440 else return dual_ent; 01441 } 01442 01443 ErrorCode DualTool::atomic_pillow(EntityHandle odedge, EntityHandle &quad1, 01444 EntityHandle &quad2) 01445 { 01446 if (debug_ap) ((Core*)mbImpl)->check_adjacencies(); 01447 01448 if (debug_ap) { 01449 Range sets; 01450 Tag ms_tag; 01451 01452 ErrorCode result = mbImpl->tag_get_handle("MATERIAL_SET", 1, MB_TYPE_INTEGER, ms_tag); 01453 if (MB_SUCCESS == result) { 01454 result = mbImpl->get_entities_by_type_and_tag(0, MBENTITYSET, &ms_tag, NULL, 01455 1, sets); 01456 if (MB_SUCCESS == result) 01457 result = mbImpl->delete_entities(sets); 01458 } 01459 } 01460 01461 std::cout << "-AP("; print_cell(odedge); std::cout << ")" << std::endl; 01462 01463 // perform an atomic pillow operation around dedge 01464 01465 // grab the quad before deleting the odedge 01466 quad1 = get_dual_entity(odedge); 01467 assert(0 != quad1); 01468 01469 // 0. get star 2cells around odedge (before odedge changes) and 3cells around 01470 // those 2cells (going to delete the 2cells, therefore need to delete the 3cells 01471 // that depend on those too) 01472 MeshTopoUtil mtu(mbImpl); 01473 Range star_cells, tmp_cells; 01474 ErrorCode result = mbImpl->get_adjacencies(&odedge, 1, 2, false, star_cells); RR; 01475 result = mbImpl->get_adjacencies(star_cells, 3, false, tmp_cells, 01476 Interface::UNION); RR; 01477 star_cells.merge(tmp_cells); 01478 star_cells.insert(odedge); 01479 01480 // tear down the dual entities which will be modified by the ap first 01481 result = delete_dual_entities(star_cells); RR; 01482 01483 // now change the quad to an ap 01484 std::vector<EntityHandle> verts; 01485 result = mbImpl->get_connectivity(&quad1, 1, verts); RR; 01486 01487 // get average position of vertices 01488 double coords[12], avg[3] = {0.0, 0.0, 0.0}; 01489 result = mbImpl->get_coords(&verts[0], verts.size(), coords); RR; 01490 for (int i = 0; i < 4; i++) { 01491 avg[0] += coords[3*i]; avg[1] += coords[3*i+1]; avg[2] += coords[3*i+2]; 01492 } 01493 for (int i = 0; i < 3; i++) avg[i] *= 0.25; 01494 01495 // for each position, get a corresponding position 1/2 way to avg 01496 double new_coords[12]; 01497 for (int i = 0; i < 4; i++) { 01498 new_coords[3*i] = avg[0] + .5*(coords[3*i]-avg[0]); 01499 new_coords[3*i+1] = avg[1] + .5*(coords[3*i+1]-avg[1]); 01500 new_coords[3*i+2] = avg[2] + .5*(coords[3*i+2]-avg[2]); 01501 } 01502 01503 // make the 4 new vertices; store in vector long enough for hex connectivity 01504 for (int i = 0; i < 4; i++) { 01505 verts.push_back(0); 01506 result = mbImpl->create_vertex(&new_coords[3*i], verts[4+i]); RR; 01507 } 01508 01509 // get the hexes connected to the quad 01510 Range hexes; 01511 result = mbImpl->get_adjacencies(&quad1, 1, 3, false, hexes); RR; 01512 assert(hexes.size() <= 2); 01513 01514 // remove any explicit adjacency from the first hex, since that'll get connected 01515 // to the new quad; add adjacency between quad and second hex, if there is a 2nd 01516 result = mbImpl->remove_adjacencies(quad1, &(*hexes.begin()), 1); RR; 01517 if (hexes.size() == 2) { 01518 result = mbImpl->add_adjacencies(quad1, &(*hexes.rbegin()), 1, false); RR; 01519 } 01520 01521 // create the new, inner quad, and make it explicitly adjacent to 1st hex; 01522 // make the connectivity of this quad same as the original one 01523 std::vector<EntityHandle> tmp_verts; 01524 std::copy(verts.begin(), verts.end(), std::back_inserter(tmp_verts)); 01525 01526 result = mbImpl->create_element(MBQUAD, &tmp_verts[0], 4, quad2); RR; 01527 result = mbImpl->add_adjacencies(quad2, &(*hexes.begin()), 1, false); RR; 01528 01529 // reverse the connectivity of the 1st hex 01530 std::reverse(verts.begin(), verts.begin()+4); 01531 std::reverse(verts.begin()+4, verts.end()); 01532 01533 // now make two inner hexes; note connectivity array is flipped for the two hexes 01534 EntityHandle new_hexes[2]; 01535 result = mbImpl->create_element(MBHEX, &verts[0], 8, new_hexes[0]); RR; 01536 result = mbImpl->create_element(MBHEX, &tmp_verts[0], 8, new_hexes[1]); RR; 01537 01538 // set the global id tag on the new hexes 01539 int new_hex_ids[2] = {++maxHexId, ++maxHexId}; 01540 result = mbImpl->tag_set_data(globalId_tag(), new_hexes, 2, new_hex_ids); 01541 if (MB_SUCCESS != result) return result; 01542 01543 // by definition, quad1 is adj to new_hexes[0] 01544 result = mbImpl->add_adjacencies(quad1, &new_hexes[0], 1, false); RR; 01545 result = mbImpl->add_adjacencies(quad2, &new_hexes[1], 1, false); RR; 01546 01547 if (debug_ap) ((Core*)mbImpl)->check_adjacencies(); 01548 01549 // now update the dual 01550 result = construct_hex_dual(&new_hexes[0], 2); RR; 01551 01552 // get the new dual surface, by getting one of the edges between the center 01553 // and outer vertex rings 01554 Range new_edge; 01555 verts[1] = verts[4]; 01556 result = mbImpl->get_adjacencies(&verts[0], 2, 1, false, new_edge); 01557 if (MB_SUCCESS != result || new_edge.size() != 1) return result; 01558 01559 return MB_SUCCESS; 01560 } 01561 01563 ErrorCode DualTool::rev_atomic_pillow(EntityHandle pillow, Range &chords) 01564 { 01565 // get the dual entities associated with elements in the pillow; go through 01566 // the elements instead of the pillow sheet so you get all of them, not just 01567 // the ones on the sheet 01568 if (debug_ap) ((Core*)mbImpl)->check_adjacencies(); 01569 01570 std::cout << "-AP("; print_cell(pillow); std::cout << ")" << std::endl; 01571 01572 Range dverts; 01573 ErrorCode result = get_dual_entities(pillow, NULL, NULL, 01574 &dverts, NULL, NULL); 01575 if (MB_SUCCESS != result) return result; 01576 assert(2 == dverts.size()); 01577 01578 EntityHandle hexes[2]; 01579 result = mbImpl->tag_get_data(dualEntity_tag(), dverts, hexes); RR; 01580 assert(hexes[0] != 0 && hexes[1] != 0); 01581 01582 std::vector<EntityHandle> dcells[4]; 01583 Range pcells[4]; 01584 std::copy(hexes, hexes+2, range_inserter(pcells[3])); 01585 std::copy(dverts.begin(), dverts.end(), std::back_inserter(dcells[0])); 01586 for (int dim = 0; dim <= 2; dim++) { 01587 result = mbImpl->get_adjacencies(hexes, 2, dim, false, pcells[dim], 01588 Interface::UNION); RR; 01589 dcells[3-dim].resize(pcells[dim].size()); 01590 result = mbImpl->tag_get_data(dualEntity_tag(), pcells[dim], &dcells[3-dim][0]); RR; 01591 } 01592 01593 // delete the dual entities which are part of the original pillow 01594 result = mbImpl->delete_entities(&pillow, 1); 01595 if (MB_SUCCESS != result) return result; 01596 01597 result = mbImpl->delete_entities(chords); 01598 if (MB_SUCCESS != result) return result; 01599 01600 for (int i = 3; i >= 0; i--) { 01601 result = delete_dual_entities(&dcells[i][0], dcells[i].size()); RR; 01602 } 01603 01604 // delete the primal entities inserted by the ap; be careful to get the right 01605 // faces, edges and vertices 01606 Range del_faces, del_edges, del_verts, tmp_faces, tmp_verts; 01607 // faces are the shared 5 and the 1 other one with greater handle (which 01608 // we know will be later in the range) 01609 result = mbImpl->get_adjacencies(hexes, 2, 2, false, del_faces); RR; 01610 assert(5 == del_faces.size()); 01611 std::copy(pcells[2].begin(), pcells[2].end(), range_inserter(tmp_faces)); 01612 tmp_faces = subtract( tmp_faces, del_faces); 01613 del_faces.insert(*tmp_faces.rbegin()); 01614 result = mbImpl->get_adjacencies(tmp_faces, 0, false, tmp_verts); RR; 01615 std::copy(pcells[0].begin(), pcells[0].end(), range_inserter(del_verts)); 01616 del_verts = subtract( del_verts, tmp_verts); 01617 assert(4 == del_verts.size()); 01618 result = mbImpl->get_adjacencies(del_verts, 1, false, del_edges, Interface::UNION); RR; 01619 assert(8 == del_edges.size()); 01620 01621 result = mbImpl->delete_entities(hexes, 2); RR; 01622 result = mbImpl->delete_entities(del_faces); RR; 01623 result = mbImpl->delete_entities(del_edges); RR; 01624 result = mbImpl->delete_entities(del_verts); RR; 01625 01626 if (debug_ap) ((Core*)mbImpl)->check_adjacencies(); 01627 01628 // recompute the dual for the hexes on either side of the quad affected 01629 // by the ap removal 01630 Range tmp_hexes; 01631 result = mbImpl->get_adjacencies(tmp_verts, 3, false, tmp_hexes, Interface::UNION); RR; 01632 result = construct_hex_dual(tmp_hexes); RR; 01633 01634 return MB_SUCCESS; 01635 } 01636 01637 ErrorCode DualTool::delete_dual_entities(EntityHandle *entities, 01638 int num_entities) 01639 { 01640 Range tmp_ents; 01641 std::copy(entities, entities+num_entities, range_inserter(tmp_ents)); 01642 return delete_dual_entities(tmp_ents); 01643 } 01644 01645 ErrorCode DualTool::delete_dual_entities(Range &entities) 01646 { 01647 if (entities.empty()) return delete_whole_dual(); 01648 01649 EntityHandle null_entity = 0; 01650 ErrorCode result; 01651 Range ents_to_delete; 01652 01653 while (!entities.empty()) { 01654 EntityHandle this_entity = entities.pop_back(); 01655 01656 // reset the primal's dual entity 01657 EntityHandle primal = get_dual_entity(this_entity); 01658 if (get_dual_entity(primal) == this_entity) { 01659 result = mbImpl->tag_set_data(dualEntity_tag(), &primal, 1, &null_entity); RR; 01660 } 01661 EntityHandle extra = get_extra_dual_entity(primal); 01662 if (0 != extra) { 01663 result = mbImpl->tag_set_data(extraDualEntity_tag(), &primal, 1, &null_entity); RR; 01664 } 01665 01666 ents_to_delete.insert(this_entity); 01667 01668 // check for extra dual entities 01669 if (mbImpl->type_from_handle(this_entity) == MBPOLYGON) { 01670 // for 2cell, might be a loop edge 01671 Range loop_edges; 01672 result = mbImpl->get_adjacencies(&this_entity, 1, 1, false, loop_edges); 01673 for (Range::iterator rit = loop_edges.begin(); rit != loop_edges.end(); rit++) 01674 if (check_1d_loop_edge(*rit)) entities.insert(*rit); 01675 } 01676 else if (extra && extra != this_entity) 01677 // just put it on the list; primal for which we're extra has already been 01678 // reset to not point to extra entity 01679 ents_to_delete.insert(extra); 01680 } 01681 01682 // now delete the entities (sheets and chords will be updated automatically) 01683 return mbImpl->delete_entities(ents_to_delete); 01684 } 01685 01686 void DualTool::print_cell(EntityHandle cell) 01687 { 01688 const EntityHandle *connect; 01689 int num_connect; 01690 ErrorCode result = mbImpl->get_connectivity(cell, connect, num_connect); 01691 if (MB_SUCCESS != result) return; 01692 bool first = true; 01693 EntityHandle primals[20]; 01694 std::vector<int> ids; 01695 01696 assert(num_connect < 20); 01697 result = mbImpl->tag_get_data(dualEntityTag, connect, num_connect, primals); 01698 ids.resize(num_connect); 01699 result = mbImpl->tag_get_data(globalIdTag, primals, 01700 num_connect, &ids[0]); 01701 for (int i = 0; i < num_connect; i++) { 01702 if (!first) std::cout << "-"; 01703 EntityType this_type = mbImpl->type_from_handle(primals[i]); 01704 if (this_type == MBHEX) std::cout << "h"; 01705 else if (this_type == MBQUAD) std::cout << "f"; 01706 else std::cout << "u"; 01707 01708 if (ids[i] != 0) std::cout << ids[i]; 01709 else std::cout << mbImpl->id_from_handle(primals[i]); 01710 01711 first = false; 01712 } 01713 } 01714 01715 ErrorCode DualTool::face_open_collapse(EntityHandle ocl, EntityHandle ocr) 01716 { 01717 if (debug_ap) ((Core*)mbImpl)->check_adjacencies(); 01718 01719 MeshTopoUtil mtu(mbImpl); 01720 01721 std::cout << "OC("; print_cell(ocl); std::cout << ")-("; print_cell(ocr); 01722 std::cout << ")" << std::endl; 01723 01724 // get the primal entities we're dealing with 01725 EntityHandle split_quads[2] = {0}, 01726 split_edges[3] = {0}, split_nodes[2] = {0}, other_edges[6] = {0}, other_nodes[6] = {0}; 01727 Range hexes; 01728 ErrorCode result = foc_get_ents(ocl, ocr, split_quads, split_edges, split_nodes, 01729 hexes, other_edges, other_nodes); RR; 01730 01731 // get star entities around edges, separated into halves 01732 std::vector<EntityHandle> star_dp1[2], star_dp2[2]; 01733 result = foc_get_stars(split_quads, split_edges, star_dp1, star_dp2); RR; 01734 01735 if (MBQUAD != mbImpl->type_from_handle(split_quads[0]) || 01736 MBQUAD != mbImpl->type_from_handle(split_quads[1])) 01737 return MB_TYPE_OUT_OF_RANGE; 01738 01739 result = foc_delete_dual(split_quads, split_edges, hexes); 01740 if (MB_SUCCESS != result) return result; 01741 01742 EntityHandle new_quads[2], new_edges[3], new_nodes[2]; 01743 result = split_pair_nonmanifold(split_quads, split_edges, split_nodes, 01744 star_dp1, star_dp2, 01745 other_edges, other_nodes, 01746 new_quads, new_edges, new_nodes); 01747 if (MB_SUCCESS != result) return result; 01748 01749 // now merge entities, the C of foc 01750 EntityHandle keepit, deleteit; 01751 #define MIN(a,b) (a < b ? a : b) 01752 #define MAX(a,b) (a > b ? a : b) 01753 #define KEEP_DELETE(a,b,c,d) {c = MIN(a,b); d = MAX(a,b);} 01754 01755 // find how many shared edges there were 01756 int num_shared_edges = (split_edges[2] ? 3 : 01757 (split_edges[1] ? 2 : 1)); 01758 01759 // first the node(s) 01760 for (int i = 0; i < 3-num_shared_edges; i++) { 01761 KEEP_DELETE(other_nodes[2+2*i], other_nodes[3+2*i], keepit, deleteit); 01762 result = mbImpl->merge_entities(keepit, deleteit, false, true); RR; 01763 } 01764 01765 // now the edges 01766 for (int i = 0; i < 4-num_shared_edges; i++) { 01767 KEEP_DELETE(other_edges[2*i], other_edges[2*i+1], keepit, deleteit); 01768 result = mbImpl->merge_entities(keepit, deleteit, false, true); RR; 01769 } 01770 01771 // now the faces 01772 KEEP_DELETE(split_quads[0], split_quads[1], keepit, deleteit); 01773 result = mbImpl->merge_entities(keepit, deleteit, false, true); RR; 01774 01775 result = mbImpl->merge_entities(new_quads[0], new_quads[1], false, true); RR; 01776 01777 if (debug_ap) ((Core*)mbImpl)->check_adjacencies(); 01778 01779 // reconstruct dual 01780 result = construct_hex_dual(hexes); 01781 if (MB_SUCCESS != result) return result; 01782 01783 return check_dual_adjs(); 01784 01785 } 01786 01787 ErrorCode DualTool::foc_get_ents(EntityHandle ocl, 01788 EntityHandle ocr, 01789 EntityHandle *split_quads, 01790 EntityHandle *split_edges, 01791 EntityHandle *split_nodes, 01792 Range &hexes, 01793 EntityHandle *other_edges, 01794 EntityHandle *other_nodes) 01795 { 01796 // get the entities used for foc; ocl and ocr are dual 1-cells 01797 // representing quads to be split; returned from this function: 01798 // quads[2] - 2 quads to be split 01799 // split_edges[2] - edge(s) to be split (2nd is 0 if only one) 01800 // split_node - node to be split, if any (otherwise 0) 01801 // hexes - connected hexes to split_edges 01802 // other_edges[0], [1] - edges in quads[0] and [1] sharing node with 01803 // one end of split_edges[0] 01804 // other_edges[2], [3] - other end of split_edges[0] (or [1] if 2 01805 // split_edges) 01806 // other_edges[4], [5] - edges in quads[0], [1] opposite to split_edges[0] 01807 // other_nodes[0], [1] - nodes on other_edges[0], [1] not shared with 01808 // split_edges[0] 01809 // other_nodes[2], [3] - nodes on other_edges[2], [3] not shared with 01810 // split_edges[0] (if 2 split_edges, there's only 1 opposite node 01811 // in each split quad) 01812 // (for diagram, see Tim's notes from 11/12/07) 01813 01814 split_quads[0] = get_dual_entity(ocl); 01815 split_quads[1] = get_dual_entity(ocr); 01816 if (MBQUAD != mbImpl->type_from_handle(split_quads[0]) || 01817 MBQUAD != mbImpl->type_from_handle(split_quads[1])) 01818 return MB_TYPE_OUT_OF_RANGE; 01819 01820 Range common_edges; 01821 ErrorCode result = mbImpl->get_adjacencies(split_quads, 2, 1, false, 01822 common_edges); 01823 if (MB_SUCCESS != result) return result; 01824 01825 if (common_edges.empty()) return MB_FAILURE; 01826 for (unsigned int i = 0; i < common_edges.size(); i++) 01827 split_edges[i] = common_edges[i]; 01828 01829 MeshTopoUtil mtu(mbImpl); 01830 01831 if (common_edges.size() == 3) { 01832 // find other (non-shared) edges 01833 for (int i = 0; i < 2; i++) { 01834 Range tmp_edges; 01835 result = mbImpl->get_adjacencies(&split_quads[i], 1, 1, false, 01836 tmp_edges); 01837 if (MB_SUCCESS != result) return result; 01838 tmp_edges = subtract( tmp_edges, common_edges); 01839 assert(tmp_edges.size() == 1); 01840 other_edges[i] = *tmp_edges.begin(); 01841 } 01842 assert(other_edges[0] && other_edges[1] && 01843 other_edges[0] != other_edges[1]); 01844 01845 // arrange common edges so middle is in middle 01846 result = mtu.opposite_entity(split_quads[0], other_edges[0], 01847 split_edges[1]); RR; 01848 common_edges.erase(split_edges[1]); 01849 split_edges[0] = *common_edges.begin(); 01850 split_edges[2] = *common_edges.rbegin(); 01851 common_edges.insert(split_edges[1]); 01852 01853 // get split nodes and other nodes 01854 split_nodes[0] = mtu.common_entity(split_edges[0], split_edges[1], 0); 01855 split_nodes[1] = mtu.common_entity(split_edges[2], split_edges[1], 0); 01856 other_nodes[0] = mtu.common_entity(split_edges[0], other_edges[0], 0); 01857 other_nodes[1] = mtu.common_entity(split_edges[2], other_edges[1], 0); 01858 01859 assert(other_nodes[0] && other_nodes[1] && split_nodes[0] && split_nodes[1]); 01860 assert(split_edges[0] && split_edges[1] && split_edges[2] && 01861 split_edges[0] != split_edges[1] && split_edges[1] != split_edges[2] && 01862 split_edges[0] != split_edges[2]); 01863 } 01864 else if (common_edges.size() == 2) { 01865 // split node is shared by split edges 01866 split_nodes[0] = mtu.common_entity(split_edges[0], split_edges[1], 0); 01867 if (0 == split_nodes[0]) return MB_FAILURE; 01868 // first two other nodes are on split edges opposite split node 01869 result = mtu.opposite_entity(split_edges[0], split_nodes[0], 01870 other_nodes[0]); RR; 01871 result = mtu.opposite_entity(split_edges[1], split_nodes[0], 01872 other_nodes[1]); RR; 01873 // over split quads: 01874 for (int i = 0; i < 2; i++) { 01875 // 1st other edge is opposite second split edge 01876 result = mtu.opposite_entity(split_quads[i], 01877 split_edges[1], other_edges[i]); RR; 01878 // 2nd other edge is opposite first split edge 01879 result = mtu.opposite_entity(split_quads[i], 01880 split_edges[0], other_edges[2+i]); RR; 01881 // last other node is opposite split node on split quad 01882 result = mtu.opposite_entity(split_quads[i], split_nodes[0], 01883 other_nodes[2+i]); RR; 01884 } 01885 } 01886 else { 01887 const EntityHandle *connect; 01888 int num_connect; 01889 result = mbImpl->get_connectivity(split_edges[0], connect, num_connect); 01890 if (MB_SUCCESS != result) return result; 01891 // other_nodes[0], [1] are on split edge 01892 other_nodes[0] = connect[0]; 01893 other_nodes[1] = connect[1]; 01894 01895 // for each of the split quads 01896 for (int i = 0; i < 2; i++) { 01897 // get the other edge on the split quad adj to node 0 on the split edge, by getting 01898 // edges adj to split quad and node and removing split edge; that's other_edge[i] 01899 Range tmp_range1, tmp_range2; 01900 tmp_range1.insert(connect[0]); 01901 tmp_range1.insert(split_quads[i]); 01902 result = mbImpl->get_adjacencies(tmp_range1, 1, false, tmp_range2); 01903 if (MB_SUCCESS != result) return result; 01904 tmp_range2.erase(split_edges[0]); 01905 assert(tmp_range2.size() == 1); 01906 other_edges[i] = *tmp_range2.begin(); 01907 // get edge connected to other node on split edge & split quad; that's 01908 // opposite prev other_edges on the split quad; that's other_edges[4+i] 01909 result = mtu.opposite_entity(split_quads[i], other_edges[i], 01910 other_edges[4+i]); RR; 01911 // get the edge on the split quad opposite the split edge; that's other_edges[2+i] 01912 result = mtu.opposite_entity(split_quads[i], split_edges[0], 01913 other_edges[2+i]); RR; 01914 // get nodes on other side of split quad from split edge, by getting common 01915 // node between top/bottom edge and opposite edge 01916 other_nodes[2+i] = mtu.common_entity(other_edges[i], other_edges[2+i], 0); 01917 other_nodes[4+i] = mtu.common_entity(other_edges[4+i], other_edges[2+i], 0); 01918 if (0 == other_nodes[2+i] || 0 == other_nodes[4+i]) return MB_FAILURE; 01919 } 01920 } 01921 01922 result = mbImpl->get_adjacencies(split_edges, common_edges.size(), 3, false, 01923 hexes, Interface::UNION); 01924 if (MB_SUCCESS != result) return result; 01925 01926 assert("split node not in other_nodes" && 01927 other_nodes[0] != split_nodes[0] && other_nodes[0] != split_nodes[1] && 01928 other_nodes[1] != split_nodes[0] && other_nodes[1] != split_nodes[1]); 01929 assert("each split node on an end of a split edge" && 01930 mtu.common_entity(other_nodes[0], split_edges[0], 0) && 01931 (((split_edges[2] && mtu.common_entity(other_nodes[1], split_edges[2], 0)) || 01932 (split_edges[1] && mtu.common_entity(other_nodes[1], split_edges[1], 0)) || 01933 mtu.common_entity(other_nodes[1], split_edges[0], 0)))); 01934 assert("opposite other edges meet at an other node" && 01935 (mtu.common_entity(other_edges[0], other_edges[1], 0) == other_nodes[0] || 01936 (split_edges[2] && 01937 mtu.common_entity(other_edges[0], other_edges[1], 0) == other_nodes[1])) && 01938 (split_edges[2] || 01939 (split_edges[1] && 01940 mtu.common_entity(other_edges[2], other_edges[3], 0) == other_nodes[1]) || 01941 mtu.common_entity(other_edges[4], other_edges[5], 0) == other_nodes[1])); 01942 01943 return MB_SUCCESS; 01944 } 01945 01946 ErrorCode DualTool::split_pair_nonmanifold(EntityHandle *split_quads, 01947 EntityHandle *split_edges, 01948 EntityHandle *split_nodes, 01949 std::vector<EntityHandle> *star_dp1, 01950 std::vector<EntityHandle> *star_dp2, 01951 EntityHandle * /*other_edges*/, 01952 EntityHandle * /*other_nodes*/, 01953 EntityHandle *new_quads, 01954 EntityHandle *new_edges, 01955 EntityHandle *new_nodes) 01956 { 01957 01958 // if there's a bdy in the star around the shared edge(s), get the quads on that 01959 // bdy so we know which edges to merge after the split-nonmanifold 01960 MeshTopoUtil mtu(mbImpl); 01961 ErrorCode result; 01962 01963 // get which star the split faces are in, and choose the other one 01964 int new_side = -1; 01965 if (std::find(star_dp1[0].begin(), star_dp1[0].end(), split_quads[0]) != 01966 star_dp1[0].end()) 01967 new_side = 1; 01968 else if (std::find(star_dp1[1].begin(), star_dp1[1].end(), split_quads[0]) != 01969 star_dp1[1].end()) 01970 new_side = 0; 01971 assert(-1 != new_side); 01972 if (-1 == new_side) return MB_FAILURE; 01973 01974 //=============== split faces 01975 01976 for (int i = 0; i < 2; i++) { 01977 // get a hex in star_dp2[new_side] that's adj to this split quad, to tell 01978 // mtu which one the new quad should go with; there should be at least one, 01979 // if we have any hexes connected to the split quad 01980 EntityHandle gowith_hex = 0; 01981 for (std::vector<EntityHandle>::iterator vit = star_dp2[new_side].begin(); 01982 vit != star_dp2[new_side].end(); vit++) { 01983 if (mtu.common_entity(*vit, split_quads[i], 2)) { 01984 gowith_hex = *vit; 01985 break; 01986 } 01987 } 01988 assert(0 != gowith_hex); 01989 01990 // split manifold each of the split_quads, and put the results on the merge list 01991 result = mtu.split_entities_manifold(split_quads+i, 1, new_quads+i, NULL, 01992 (gowith_hex ? &gowith_hex : NULL)); RR; 01993 } 01994 01995 // make ranges of faces which need to be explicitly adj to old, new 01996 // edge; faces come from stars and new_quads (which weren't in the stars); 01997 // new_quads go with side j, which does not have split quads 01998 Range tmp_addl_faces[2], addl_faces[2]; 01999 for (int i = 0; i < 2; i++) { 02000 std::copy(star_dp1[i].begin(), star_dp1[i].end(), 02001 range_inserter(tmp_addl_faces[i])); 02002 tmp_addl_faces[new_side].insert(new_quads[i]); 02003 } 02004 #ifndef NDEBUG 02005 bool cond1 = ("split_quads on 1, new_quads on 0" && 02006 tmp_addl_faces[0].find(split_quads[0]) == tmp_addl_faces[0].end() && 02007 tmp_addl_faces[0].find(split_quads[1]) == tmp_addl_faces[0].end() && 02008 tmp_addl_faces[1].find(split_quads[0]) != tmp_addl_faces[1].end() && 02009 tmp_addl_faces[1].find(split_quads[1]) != tmp_addl_faces[1].end() && 02010 tmp_addl_faces[0].find(new_quads[0]) != tmp_addl_faces[0].end() && 02011 tmp_addl_faces[0].find(new_quads[1]) != tmp_addl_faces[0].end() && 02012 tmp_addl_faces[1].find(new_quads[0]) == tmp_addl_faces[1].end() && 02013 tmp_addl_faces[1].find(new_quads[1]) == tmp_addl_faces[1].end()), 02014 cond2 = ("split_quads on 0, new_quads on 1" && 02015 tmp_addl_faces[0].find(split_quads[0]) != tmp_addl_faces[0].end() && 02016 tmp_addl_faces[0].find(split_quads[1]) != tmp_addl_faces[0].end() && 02017 tmp_addl_faces[1].find(split_quads[0]) == tmp_addl_faces[1].end() && 02018 tmp_addl_faces[1].find(split_quads[1]) == tmp_addl_faces[1].end() && 02019 tmp_addl_faces[0].find(new_quads[0]) == tmp_addl_faces[0].end() && 02020 tmp_addl_faces[0].find(new_quads[1]) == tmp_addl_faces[0].end() && 02021 tmp_addl_faces[1].find(new_quads[0]) != tmp_addl_faces[1].end() && 02022 tmp_addl_faces[1].find(new_quads[1]) != tmp_addl_faces[1].end()); 02023 02024 assert(cond1 || cond2); 02025 #endif 02026 02027 //=============== split edge(s) 02028 for (int j = 0; j < 3; j++) { 02029 if (!split_edges[j]) break; 02030 02031 // filter add'l faces to only those adj to split_edges[j] 02032 addl_faces[0] = tmp_addl_faces[0]; addl_faces[1] = tmp_addl_faces[1]; 02033 for (int i = 0; i < 2; i++) { 02034 result = mbImpl->get_adjacencies(&split_edges[j], 1, 2, false, 02035 addl_faces[i]); RR; 02036 } 02037 02038 // split edge 02039 result = mtu.split_entity_nonmanifold(split_edges[j], addl_faces[1-new_side], 02040 addl_faces[new_side], new_edges[j]); RR; 02041 } 02042 02043 //=============== split node(s) 02044 02045 for (int j = 0; j < 2; j++) { 02046 if (!split_nodes[j]) break; 02047 02048 // if we're splitting multiple edges, there might be other edges that have the split 02049 // node; also need to know which side they're on 02050 Range tmp_addl_edges[2]; 02051 result = foc_get_addl_ents(star_dp1, star_dp2, split_edges, 02052 split_nodes[j], tmp_addl_edges); RR; 02053 02054 // also, we need to know which of the split/new edges go 02055 // with the split/new node; new edges go with side 0, split with 1 02056 for (int i = 0; i < 3; i++) { 02057 if (!split_edges[i]) break; 02058 tmp_addl_edges[new_side].insert(new_edges[i]); 02059 tmp_addl_edges[1-new_side].insert(split_edges[i]); 02060 } 02061 02062 // same for star faces and hexes 02063 for (int i = 0; i < 2; i++) { 02064 std::copy(star_dp1[i].begin(), star_dp1[i].end(), range_inserter(tmp_addl_edges[i])); 02065 std::copy(star_dp2[i].begin(), star_dp2[i].end(), range_inserter(tmp_addl_edges[i])); 02066 } 02067 02068 // finally, new quads 02069 for (int i = 0; i < 2; i++) tmp_addl_edges[new_side].insert(new_quads[i]); 02070 02071 // filter the entities, keeping only the ones adjacent to this node 02072 Range addl_edges[2]; 02073 for (int i = 0; i < 2; i++) { 02074 for (Range::reverse_iterator rit = tmp_addl_edges[i].rbegin(); 02075 rit != tmp_addl_edges[i].rend(); rit++) { 02076 if (mtu.common_entity(*rit, split_nodes[j], 0)) addl_edges[i].insert(*rit); 02077 } 02078 } 02079 02080 // now split the node too 02081 result = mtu.split_entity_nonmanifold(split_nodes[j], addl_edges[1-new_side], 02082 addl_edges[new_side], new_nodes[j]); RR; 02083 } 02084 02085 return MB_SUCCESS; 02086 } 02087 02088 ErrorCode DualTool::foc_get_addl_ents(std::vector<EntityHandle> *star_dp1, 02089 std::vector<EntityHandle> * /*star_dp2*/, 02090 EntityHandle *split_edges, 02091 EntityHandle split_node, 02092 Range *addl_ents) 02093 { 02094 // if we're splitting 2 edges, there might be other edges that have the split 02095 // node; also need to know which side they're on 02096 02097 // algorithm: for a given star_dp1 (faces) on a side: 02098 // - get all edges adj to all faces -> R1 02099 // - get all edges adj to split_node -> R2 02100 // - R3 = R1 & R2 (edges connected to split_node & adj to a star face) 02101 // - R3 -= split_edges (take split edges off addl_ents) 02102 02103 Range R2; 02104 MeshTopoUtil mtu(mbImpl); 02105 ErrorCode result = mbImpl->get_adjacencies(&split_node, 1, 1, false, R2); RR; 02106 Range::iterator rit; 02107 02108 for (int i = 0; i < 2; i++) { 02109 Range R1, R3; 02110 result = mbImpl->get_adjacencies(&star_dp1[i][0], star_dp1[i].size(), 1, false, 02111 R1, Interface::UNION); RR; 02112 R3 = intersect( R1, R2); 02113 for (int j = 0; j < 3; j++) 02114 if (split_edges[j]) R3.erase(split_edges[j]); 02115 addl_ents[i].merge(R3); 02116 } 02117 02118 return MB_SUCCESS; 02119 } 02120 02121 ErrorCode DualTool::foc_get_stars(EntityHandle *split_quads, 02122 EntityHandle *split_edges, 02123 std::vector<EntityHandle> *star_dp1, 02124 std::vector<EntityHandle> *star_dp2) 02125 { 02126 bool on_bdy = false, on_bdy_tmp; 02127 ErrorCode result; 02128 MeshTopoUtil mtu(mbImpl); 02129 02130 // get the star around the split_edge 02131 std::vector<EntityHandle> qstar, hstar; 02132 unsigned int qpos = 0; 02133 02134 for (int i = 0; i < 3; i++) { 02135 if (!split_edges[i]) break; 02136 02137 // get the star around this split edge 02138 unsigned int qpos_tmp = 0; 02139 std::vector<EntityHandle> qstar_tmp, hstar_tmp; 02140 result = mtu.star_entities(split_edges[i], qstar_tmp, on_bdy_tmp, 0, 02141 &hstar_tmp); RR; 02142 // if we're on the bdy, add a null to the hex star too 02143 if (on_bdy_tmp) { 02144 assert(hstar_tmp.size() == qstar_tmp.size()-1); 02145 hstar_tmp.push_back(0); 02146 on_bdy = true; 02147 } 02148 02149 // get the position of first split quad in star 02150 while (qpos_tmp < qstar_tmp.size() && qstar_tmp[qpos_tmp] != split_quads[0]) 02151 qpos_tmp++; 02152 if (qpos_tmp == qstar_tmp.size()) return MB_FAILURE; 02153 02154 bool forward; 02155 // 1st iteration is forward by definition 02156 if (0 == i) forward = true; 02157 02158 // need to be careful about direction on later iters 02159 else if (hstar[qpos] == hstar_tmp[qpos_tmp]) forward = true; 02160 else if (hstar[qpos] == hstar_tmp[(qpos_tmp+qstar_tmp.size()-1)%qstar_tmp.size()] && 02161 hstar_tmp[qpos_tmp] == hstar[(qpos+qstar.size()-1)%qstar.size()]) 02162 forward = false; 02163 else return MB_FAILURE; 02164 02165 if (forward) { 02166 // 1st half of star 02167 // save hex right after split_quad[0] first 02168 star_dp2[0].push_back(hstar_tmp[qpos_tmp]); 02169 qpos_tmp = (qpos_tmp+1)%qstar_tmp.size(); 02170 while (qstar_tmp[qpos_tmp] != split_quads[1]) { 02171 star_dp1[0].push_back(qstar_tmp[qpos_tmp]); 02172 star_dp2[0].push_back(hstar_tmp[qpos_tmp]); 02173 qpos_tmp = (qpos_tmp+1)%qstar_tmp.size(); 02174 } 02175 // 2nd half of star 02176 // save hex right after split_quad[1] first 02177 star_dp2[1].push_back(hstar_tmp[qpos_tmp]); 02178 qpos_tmp = (qpos_tmp+1)%qstar_tmp.size(); 02179 while (qstar_tmp[qpos_tmp] != split_quads[0]) { 02180 star_dp1[1].push_back(qstar_tmp[qpos_tmp]); 02181 star_dp2[1].push_back(hstar_tmp[qpos_tmp]); 02182 qpos_tmp = (qpos_tmp+1)%qstar_tmp.size(); 02183 } 02184 } 02185 else { 02186 // go in reverse - take prev hex instead of current 02187 // one, and step in reverse 02188 02189 // save hex right after split_quad[0] first 02190 qpos_tmp = (qpos_tmp+qstar_tmp.size()-1)%qstar_tmp.size(); 02191 star_dp2[0].push_back(hstar_tmp[qpos_tmp]); 02192 while (qstar_tmp[qpos_tmp] != split_quads[1]) { 02193 star_dp1[0].push_back(qstar_tmp[qpos_tmp]); 02194 qpos_tmp = (qpos_tmp+qstar_tmp.size()-1)%qstar_tmp.size(); 02195 star_dp2[0].push_back(hstar_tmp[qpos_tmp]); 02196 } 02197 // 2nd half of star 02198 // save hex right after split_quad[1] first 02199 qpos_tmp = (qpos_tmp+qstar_tmp.size()-1)%qstar_tmp.size(); 02200 star_dp2[1].push_back(hstar_tmp[qpos_tmp]); 02201 while (qstar_tmp[qpos_tmp] != split_quads[0]) { 02202 star_dp1[1].push_back(qstar_tmp[qpos_tmp]); 02203 qpos_tmp = (qpos_tmp+qstar_tmp.size()-1)%qstar_tmp.size(); 02204 star_dp2[1].push_back(hstar_tmp[qpos_tmp]); 02205 } 02206 } 02207 02208 if (0 == i) { 02209 // if we're on the first iteration, save results and continue, other iters 02210 // get compared to this one 02211 qstar.swap(qstar_tmp); 02212 hstar.swap(hstar_tmp); 02213 on_bdy = on_bdy_tmp; 02214 qpos = qpos_tmp; 02215 } 02216 } 02217 02218 // split quads go on list with NULLs, if any, otherwise on 2nd 02219 if (on_bdy) { 02220 if (std::find(star_dp2[0].begin(), star_dp2[0].end(), 0) != 02221 star_dp2[0].end()) { 02222 // remove *all* the zeros 02223 star_dp2[0].erase(std::remove(star_dp2[0].begin(), star_dp2[0].end(), 0), 02224 star_dp2[0].end()); 02225 // put the split quads on this half 02226 star_dp1[0].push_back(split_quads[0]); 02227 star_dp1[0].push_back(split_quads[1]); 02228 } 02229 else { 02230 star_dp2[1].erase(std::remove(star_dp2[1].begin(), star_dp2[1].end(), 0), 02231 star_dp2[1].end()); 02232 // put the split quads on this half 02233 star_dp1[1].push_back(split_quads[0]); 02234 star_dp1[1].push_back(split_quads[1]); 02235 } 02236 } 02237 else { 02238 star_dp1[1].push_back(split_quads[0]); 02239 star_dp1[1].push_back(split_quads[1]); 02240 } 02241 02242 // some error checking 02243 if (!(((std::find(star_dp1[0].begin(), star_dp1[0].end(), split_quads[0]) == star_dp1[0].end() && 02244 std::find(star_dp1[0].begin(), star_dp1[0].end(), split_quads[1]) == star_dp1[0].end() && 02245 std::find(star_dp1[1].begin(), star_dp1[1].end(), split_quads[0]) != star_dp1[1].end() && 02246 std::find(star_dp1[1].begin(), star_dp1[1].end(), split_quads[1]) != star_dp1[1].end()) || 02247 02248 (std::find(star_dp1[1].begin(), star_dp1[1].end(), split_quads[0]) == star_dp1[1].end() && 02249 std::find(star_dp1[1].begin(), star_dp1[1].end(), split_quads[1]) == star_dp1[1].end() && 02250 std::find(star_dp1[0].begin(), star_dp1[0].end(), split_quads[0]) != star_dp1[0].end() && 02251 std::find(star_dp1[0].begin(), star_dp1[0].end(), split_quads[1]) != star_dp1[0].end())) 02252 )) { 02253 std::cerr << "foc_get_stars: both split quads should be on the same star list half and not " 02254 << "on the other, failed" << std::endl; 02255 return MB_FAILURE; 02256 } 02257 02258 if (!(std::find(star_dp2[0].begin(), star_dp2[0].end(), 0) == star_dp2[0].end() && 02259 std::find(star_dp2[1].begin(), star_dp2[1].end(), 0) == star_dp2[1].end())) { 02260 std::cerr << "foc_get_stars: no NULLs on the hstar lists, failed"; 02261 return MB_FAILURE; 02262 } 02263 02264 return MB_SUCCESS; 02265 } 02266 02267 ErrorCode DualTool::foc_delete_dual(EntityHandle *split_quads, 02268 EntityHandle *split_edges, 02269 Range &hexes) 02270 { 02271 // special delete dual procedure, because in some cases we need to delete 02272 // a sheet too since it'll get merged into another 02273 02274 // figure out whether we'll need to delete a sheet 02275 EntityHandle sheet1, sheet2 = 0; 02276 sheet1 = get_dual_hyperplane(get_dual_entity(split_edges[0])); 02277 if (split_edges[1]) sheet1 = get_dual_hyperplane(get_dual_entity(split_edges[1])); 02278 EntityHandle chordl = get_dual_hyperplane(get_dual_entity(split_quads[0])); 02279 EntityHandle chordr = get_dual_hyperplane(get_dual_entity(split_quads[1])); 02280 assert(0 != sheet1 && 0 != chordl && 0 != chordr); 02281 Range parentsl, parentsr; 02282 ErrorCode result = mbImpl->get_parent_meshsets(chordl, parentsl); 02283 if (MB_SUCCESS != result) return result; 02284 result = mbImpl->get_parent_meshsets(chordr, parentsr); 02285 if (MB_SUCCESS != result) return result; 02286 parentsl.erase(sheet1); 02287 parentsr.erase(sheet1); 02288 if (sheet2) parentsl.erase(sheet1), parentsr.erase(sheet1); 02289 02290 // before deciding which one to delete, collect the other cells which must 02291 // be deleted, and all the chords/sheets they're on 02292 Range adj_ents, dual_ents, cells1or2; 02293 for (int i = 0; i < 3; i++) { 02294 result = mbImpl->get_adjacencies(hexes, i, false, adj_ents, Interface::UNION); 02295 if (MB_SUCCESS != result) return result; 02296 } 02297 02298 // cache any adjacent hexes, for rebuilding the dual later 02299 result = mbImpl->get_adjacencies(adj_ents, 3, false, hexes, Interface::UNION); 02300 if (MB_SUCCESS != result) return result; 02301 02302 for (Range::iterator rit = adj_ents.begin(); rit != adj_ents.end(); rit++) { 02303 EntityHandle this_ent = get_dual_entity(*rit); 02304 dual_ents.insert(this_ent); 02305 int dim = mbImpl->dimension_from_handle(this_ent); 02306 if (1 == dim || 2 == dim) cells1or2.insert(this_ent); 02307 } 02308 02309 Range dual_hps; 02310 for (Range::iterator rit = cells1or2.begin(); rit != cells1or2.end(); rit++) 02311 dual_hps.insert(get_dual_hyperplane(*rit)); 02312 02313 result = delete_dual_entities(dual_ents); 02314 if (MB_SUCCESS != result) return result; 02315 02316 // now decide which sheet to delete (to be merged into the other) 02317 EntityHandle sheet_delete = 0; 02318 if (is_blind(*parentsl.begin())) sheet_delete = *parentsl.begin(); 02319 else if (is_blind(*parentsr.begin())) sheet_delete = *parentsr.begin(); 02320 else { 02321 // neither is blind, take the one with fewer cells 02322 Range tmp_ents; 02323 int numl, numr; 02324 result = mbImpl->get_number_entities_by_handle(*parentsl.begin(), numl); 02325 if (MB_SUCCESS != result) return result; 02326 result = mbImpl->get_number_entities_by_handle(*parentsr.begin(), numr); 02327 if (MB_SUCCESS != result) return result; 02328 sheet_delete = (numl > numr ? *parentsr.begin() : *parentsl.begin()); 02329 } 02330 assert(0 != sheet_delete); 02331 02332 // after deleting cells, check for empty chords & sheets, and delete those too 02333 for (Range::iterator rit = dual_hps.begin(); rit != dual_hps.end(); rit++) { 02334 Range tmp_ents; 02335 result = mbImpl->get_entities_by_handle(*rit, tmp_ents); 02336 if (MB_SUCCESS != result) return result; 02337 if (tmp_ents.empty()) { 02338 result = mbImpl->delete_entities(&(*rit), 1); 02339 if (MB_SUCCESS != result) return result; 02340 } 02341 else if (*rit == sheet_delete) { 02342 // delete the sheet 02343 result = mbImpl->delete_entities(&(*rit), 1); 02344 if (MB_SUCCESS != result) return result; 02345 } 02346 } 02347 02348 // now just to be safe, add the hexes bridge-adjacent across vertices 02349 // to the hexes we already have 02350 Range tmp_hexes; 02351 MeshTopoUtil mtu(mbImpl); 02352 for (Range::iterator rit = hexes.begin(); rit != hexes.end(); rit++) { 02353 result = mtu.get_bridge_adjacencies(*rit, 0, 3, tmp_hexes); 02354 if (MB_SUCCESS != result) return result; 02355 } 02356 hexes.merge(tmp_hexes); 02357 02358 return MB_SUCCESS; 02359 } 02360 02362 bool DualTool::is_blind(const EntityHandle chord_or_sheet) 02363 { 02364 // must be an entity set 02365 if (TYPE_FROM_HANDLE(chord_or_sheet) != MBENTITYSET) return false; 02366 02367 // get the vertices 02368 Range verts, ents; 02369 ErrorCode result = mbImpl->get_entities_by_handle(chord_or_sheet, ents); 02370 if (MB_SUCCESS != result || ents.empty()) return false; 02371 02372 result = mbImpl->get_adjacencies(ents, 0, false, verts, Interface::UNION); 02373 if (MB_SUCCESS != result || verts.empty()) return false; 02374 02375 for (Range::iterator rit = verts.begin(); rit != verts.end(); rit++) { 02376 // get dual entity for this vertex 02377 EntityHandle dual_ent = get_dual_entity(*rit); 02378 if (0 == dual_ent) continue; 02379 if (TYPE_FROM_HANDLE(dual_ent) == MBQUAD) return false; 02380 } 02381 02382 // if none of the vertices' duals were quads, chord_or_sheet must be blind 02383 return true; 02384 } 02385 02388 ErrorCode DualTool::get_opposite_verts(const EntityHandle middle_edge, 02389 const EntityHandle chord, 02390 EntityHandle *verts) 02391 { 02392 // get the edges on the chord, in order, and move to middle_edge 02393 std::vector<EntityHandle> chord_edges; 02394 const EntityHandle *connect; 02395 int num_connect; 02396 02397 ErrorCode result = mbImpl->get_entities_by_handle(chord, chord_edges); RR; 02398 std::vector<EntityHandle>::iterator vit = std::find(chord_edges.begin(), chord_edges.end(), 02399 middle_edge); 02400 result = mbImpl->get_connectivity(middle_edge, connect, num_connect); RR; 02401 02402 if ( 02403 // middle_edge isn't on this chord 02404 vit == chord_edges.end() || 02405 // chord only has 1 edge 02406 chord_edges.size() == 1 || 02407 // middle_edge is at beginning or end and chord isn't blind 02408 ((vit == chord_edges.begin() || vit == chord_edges.end()-1) && !is_blind(chord))) 02409 return MB_FAILURE; 02410 02411 else if (chord_edges.size() == 2) { 02412 // easier if it's a 2-edge blind chord, just get vertices in opposite order 02413 verts[0] = connect[1]; 02414 verts[1] = connect[0]; 02415 return MB_SUCCESS; 02416 } 02417 02418 // get vertices with the prev edge & subtract vertices of 1-cell 02419 if (vit == chord_edges.begin()) 02420 vit = chord_edges.end() - 1; 02421 else vit--; 02422 Range dum_connect, middle_connect; 02423 result = mbImpl->get_connectivity(&middle_edge, 1, middle_connect); RR; 02424 result = mbImpl->get_connectivity(&(*vit), 1, dum_connect); RR; 02425 dum_connect = subtract( dum_connect, middle_connect); 02426 if (dum_connect.size() != 1) { 02427 std::cerr << "Trouble traversing chord." << std::endl; 02428 return MB_FAILURE; 02429 } 02430 02431 // put in verts[0] 02432 verts[0] = *dum_connect.begin(); 02433 02434 // same with prev edge 02435 vit++; 02436 if (vit == chord_edges.end()) vit = chord_edges.begin(); 02437 vit++; 02438 dum_connect.clear(); 02439 result = mbImpl->get_connectivity(&(*vit), 1, dum_connect); RR; 02440 dum_connect = subtract( dum_connect, middle_connect); 02441 if (dum_connect.size() != 1) { 02442 std::cerr << "Trouble traversing chord." << std::endl; 02443 return MB_FAILURE; 02444 } 02445 02446 // put in verts[1] 02447 verts[1] = *dum_connect.begin(); 02448 02449 // if verts[0] and 1st vertex of 1cell don't have common edge, switch verts 02450 MeshTopoUtil mtu(mbImpl); 02451 if (0 == mtu.common_entity(verts[0], connect[0], 1)) { 02452 EntityHandle dum_h = verts[0]; 02453 verts[0] = verts[1]; 02454 verts[1] = dum_h; 02455 } 02456 02457 if (0 == mtu.common_entity(verts[0], connect[0], 1)) { 02458 std::cerr << "Trouble traversing chord." << std::endl; 02459 return MB_FAILURE; 02460 } 02461 02462 return MB_SUCCESS; 02463 } 02464 02465 ErrorCode DualTool::get_dual_entities(const EntityHandle dual_ent, 02466 Range *dcells, 02467 Range *dedges, 02468 Range *dverts, 02469 Range *dverts_loop, 02470 Range *dedges_loop) 02471 { 02472 ErrorCode result = MB_SUCCESS; 02473 02474 if (NULL != dcells) { 02475 result = mbImpl->get_entities_by_type(dual_ent, MBPOLYGON, *dcells); 02476 if (MB_SUCCESS != result) return result; 02477 } 02478 02479 if (NULL != dedges) { 02480 if (NULL != dcells) 02481 result = mbImpl->get_adjacencies(*dcells, 1, false, *dedges, Interface::UNION); 02482 else 02483 result = mbImpl->get_entities_by_type(dual_ent, MBEDGE, *dedges); 02484 02485 if (MB_SUCCESS != result) return result; 02486 } 02487 02488 if (NULL != dverts) { 02489 if (NULL != dcells) 02490 result = mbImpl->get_adjacencies(*dcells, 0, false, *dverts, Interface::UNION); 02491 else if (NULL != dedges) 02492 result = mbImpl->get_adjacencies(*dedges, 0, false, *dverts, Interface::UNION); 02493 else { 02494 Range all_ents; 02495 result = mbImpl->get_entities_by_handle(dual_ent, all_ents); RR; 02496 result = mbImpl->get_adjacencies(all_ents, 0, false, *dverts, Interface::UNION); 02497 } 02498 02499 if (MB_SUCCESS != result) return result; 02500 } 02501 02502 if (NULL != dverts_loop && NULL != dverts) { 02503 static std::vector<EntityHandle> dual_ents; 02504 dual_ents.reserve(dverts->size()); 02505 result = mbImpl->tag_get_data(dualEntity_tag(), *dverts, &dual_ents[0]); 02506 if (MB_SUCCESS != result) return result; 02507 Range::iterator rit; 02508 unsigned int i; 02509 for (rit = dverts->begin(), i = 0; rit != dverts->end(); rit++, i++) 02510 if (0 != dual_ents[i] && mbImpl->type_from_handle(dual_ents[i]) == MBQUAD) 02511 dverts_loop->insert(*rit); 02512 } 02513 02514 if (NULL != dedges_loop && NULL != dedges) { 02515 static std::vector<EntityHandle> dual_ents; 02516 dual_ents.reserve(dedges->size()); 02517 result = mbImpl->tag_get_data(dualEntity_tag(), *dedges, &dual_ents[0]); 02518 if (MB_SUCCESS != result) return result; 02519 Range::iterator rit; 02520 unsigned int i; 02521 for (rit = dedges->begin(), i = 0; rit != dedges->end(); rit++, i++) 02522 if (0 != dual_ents[i] && mbImpl->type_from_handle(dual_ents[i]) == MBEDGE) 02523 dedges_loop->insert(*rit); 02524 } 02525 02526 return result; 02527 } 02528 02529 ErrorCode DualTool::list_entities(const EntityHandle *entities, 02530 const int num_entities) const 02531 { 02532 Range temp_range; 02533 ErrorCode result; 02534 if (NULL == entities && 0 == num_entities) 02535 return mbImpl->list_entities(entities, num_entities); 02536 02537 else if (NULL == entities && 0 < num_entities) { 02538 02539 // list all entities of all types 02540 std::cout << std::endl; 02541 for (EntityType this_type = MBVERTEX; this_type < MBMAXTYPE; this_type++) { 02542 result = mbImpl->get_entities_by_type(0, this_type, temp_range); 02543 if (MB_SUCCESS != result) return result; 02544 } 02545 } 02546 02547 else { 02548 std::copy(entities, entities+num_entities, range_inserter(temp_range)); 02549 } 02550 02551 return list_entities(temp_range); 02552 } 02553 02554 ErrorCode DualTool::list_entities(const Range &entities) const 02555 { 02556 // now print each entity, listing the dual information first then calling Interface to do 02557 // the rest 02558 ErrorCode result = MB_SUCCESS, tmp_result; 02559 for (Range::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { 02560 EntityType this_type = TYPE_FROM_HANDLE(*iter); 02561 std::cout << CN::EntityTypeName(this_type) << " " << ID_FROM_HANDLE(*iter) << ":" << std::endl; 02562 02563 EntityHandle dual_ent = get_dual_entity(*iter); 02564 if (0 != dual_ent) { 02565 std::cout << "Dual to " 02566 << CN::EntityTypeName(mbImpl->type_from_handle(dual_ent)) << " " 02567 << mbImpl->id_from_handle(dual_ent) << std::endl; 02568 } 02569 02570 if (TYPE_FROM_HANDLE(*iter) == MBENTITYSET) { 02571 EntityHandle chord = 0, sheet = 0; 02572 int id; 02573 result = mbImpl->tag_get_data(dualCurve_tag(), &(*iter), 1, &chord); 02574 result = mbImpl->tag_get_data(dualSurface_tag(), &(*iter), 1, &sheet); 02575 result = mbImpl->tag_get_data(globalId_tag(), &(*iter), 1, &id); 02576 02577 if (0 != chord) 02578 std::cout << "(Dual chord " << id << ")" << std::endl; 02579 if (0 != sheet) 02580 std::cout << "(Dual sheet " << id << ")" << std::endl; 02581 } 02582 02583 tmp_result = mbImpl->list_entity(*iter); 02584 if (MB_SUCCESS != tmp_result) result = tmp_result; 02585 } 02586 02587 return result; 02588 } 02589 02590 ErrorCode DualTool::face_shrink(EntityHandle odedge) 02591 { 02592 // some preliminary checking 02593 if (mbImpl->type_from_handle(odedge) != MBEDGE) return MB_TYPE_OUT_OF_RANGE; 02594 02595 if (debug_ap) ((Core*)mbImpl)->check_adjacencies(); 02596 02597 std::cout << "FS("; print_cell(odedge); std::cout << ")" << std::endl; 02598 02599 EntityHandle quads[4], hexes[2]; 02600 std::vector<EntityHandle> connects[4], side_quads[2]; 02601 02602 // get the quads along the chord through the 2 hexes, and the vertices 02603 // for those quads 02604 ErrorCode result = fs_get_quads(odedge, quads, hexes, connects); 02605 if (MB_SUCCESS != result) return result; 02606 02607 // flip/rotate connect arrays so they align & are same sense 02608 result = fs_check_quad_sense(hexes[0], quads[0], connects); 02609 if (MB_SUCCESS != result) return result; 02610 02611 // get the quad loops along the "side" surfaces 02612 result = fs_get_quad_loops(hexes, connects, side_quads); 02613 if (MB_SUCCESS != result) return result; 02614 02615 // ok, done with setup; now delete dual entities affected by this operation, 02616 // which is all the entities adjacent to vertices of dual edge 02617 Range adj_verts, adj_edges, dual_ents, cells1or2; 02618 MeshTopoUtil mtu(mbImpl); 02619 result = mtu.get_bridge_adjacencies(odedge, 0, 1, adj_edges); 02620 if (MB_SUCCESS != result) return result; 02621 result = mbImpl->get_adjacencies(adj_edges, 0, false, adj_verts, 02622 Interface::UNION); 02623 if (MB_SUCCESS != result) return result; 02624 for (int i = 1; i <= 3; i++) { 02625 result = mbImpl->get_adjacencies(adj_verts, i, false, dual_ents, 02626 Interface::UNION); 02627 if (MB_SUCCESS != result) return result; 02628 } 02629 02630 // before deleting dual, grab the 1- and 2-cells 02631 for (Range::iterator rit = dual_ents.begin(); rit != dual_ents.end(); rit++) { 02632 int dim = mbImpl->dimension_from_handle(*rit); 02633 if (1 == dim || 2 == dim) cells1or2.insert(*rit); 02634 } 02635 Range dual_hps; 02636 for (Range::iterator rit = cells1or2.begin(); rit != cells1or2.end(); rit++) 02637 dual_hps.insert(get_dual_hyperplane(*rit)); 02638 02639 dual_ents.insert(odedge); 02640 result = delete_dual_entities(dual_ents); 02641 if (MB_SUCCESS != result) return result; 02642 02643 // after deleting cells, check for empty chords & sheets, and delete those too 02644 for (Range::iterator rit = dual_hps.begin(); rit != dual_hps.end(); rit++) { 02645 Range tmp_ents; 02646 result = mbImpl->get_entities_by_handle(*rit, tmp_ents); 02647 if (MB_SUCCESS != result) return result; 02648 if (tmp_ents.empty()) { 02649 result = mbImpl->delete_entities(&(*rit), 1); 02650 if (MB_SUCCESS != result) return result; 02651 } 02652 } 02653 02654 // remove any explicit adjacencies between side quads and hexes; don't check 02655 // for error, since there might not be adjacencies 02656 for (int i = 0; i < 4; i++) { 02657 for (int j = 0; j < 2; j++) { 02658 result = mbImpl->remove_adjacencies(side_quads[j][i], &hexes[j], 1); 02659 } 02660 } 02661 02662 // make inner ring of vertices 02663 // get centroid of quad2 02664 double q2coords[12], avg[3] = {0.0, 0.0, 0.0}; 02665 result = mbImpl->get_coords(&connects[1][0], 4, q2coords); 02666 if (MB_SUCCESS != result) return result; 02667 for (int i = 0; i < 4; i++) { 02668 avg[0] += q2coords[3*i]; 02669 avg[1] += q2coords[3*i+1]; 02670 avg[2] += q2coords[3*i+2]; 02671 } 02672 avg[0] *= .25; avg[1] *= .25; avg[2] *= .25; 02673 // position new vertices 02674 connects[3].resize(4); 02675 for (int i = 0; i < 4; i++) { 02676 q2coords[3*i] = avg[0] + .25*(q2coords[3*i]-avg[0]); 02677 q2coords[3*i+1] = avg[1] + .25*(q2coords[3*i+1]-avg[1]); 02678 q2coords[3*i+2] = avg[2] + .25*(q2coords[3*i+2]-avg[2]); 02679 result = mbImpl->create_vertex(&q2coords[3*i], connects[3][i]); 02680 if (MB_SUCCESS != result) return result; 02681 } 02682 02683 // ok, now have the 4 connectivity arrays for 4 quads; construct hexes 02684 EntityHandle hconnect[8], new_hexes[4]; 02685 int new_hex_ids[4]; 02686 02687 for (int i = 0; i < 4; i++) { 02688 int i1 = i, i2 = (i+1)%4; 02689 hconnect[0] = connects[0][i1]; 02690 hconnect[1] = connects[0][i2]; 02691 hconnect[2] = connects[3][i2]; 02692 hconnect[3] = connects[3][i1]; 02693 02694 hconnect[4] = connects[1][i1]; 02695 hconnect[5] = connects[1][i2]; 02696 hconnect[6] = connects[2][i2]; 02697 hconnect[7] = connects[2][i1]; 02698 02699 result = mbImpl->create_element(MBHEX, hconnect, 8, new_hexes[i]); 02700 if (MB_SUCCESS != result) return result; 02701 02702 // test for equiv entities from the side quads, and make explicit adjacencies 02703 // if there are any 02704 for (int j = 0; j < 2; j++) { 02705 if (mtu.equivalent_entities(side_quads[j][i])) { 02706 result = mbImpl->add_adjacencies(side_quads[j][i], &new_hexes[i], 1, false); 02707 if (MB_SUCCESS != result) return result; 02708 } 02709 } 02710 02711 new_hex_ids[i] = ++maxHexId; 02712 } 02713 02714 // set the global id tag on the new hexes 02715 result = mbImpl->tag_set_data(globalId_tag(), new_hexes, 4, new_hex_ids); 02716 if (MB_SUCCESS != result) return result; 02717 02718 // now fixup other two hexes; start by getting hex through quads 0, 1 02719 // make this first hex switch to the other side, to make the dual look like 02720 // a hex push 02721 int tmp_ids[2]; 02722 result = mbImpl->tag_get_data(globalId_tag(), hexes, 2, tmp_ids); 02723 if (MB_SUCCESS != result) return result; 02724 02725 02726 result = mbImpl->delete_entities(hexes, 2); 02727 if (MB_SUCCESS != result) return result; 02728 result = mbImpl->delete_entities(&quads[1], 1); 02729 if (MB_SUCCESS != result) return result; 02730 for (int i = 0; i < 4; i++) { 02731 hconnect[i] = connects[3][i]; 02732 hconnect[4+i] = connects[2][i]; 02733 } 02734 result = mbImpl->create_element(MBHEX, hconnect, 8, hexes[0]); 02735 if (MB_SUCCESS != result) return result; 02736 02737 for (int i = 0; i < 4; i++) { 02738 hconnect[i] = connects[0][i]; 02739 hconnect[4+i] = connects[3][i]; 02740 } 02741 result = mbImpl->create_element(MBHEX, hconnect, 8, hexes[1]); 02742 if (MB_SUCCESS != result) return result; 02743 02744 // check for and fix any explicit adjacencies on either end quad 02745 if (mtu.equivalent_entities(quads[0])) 02746 mbImpl->add_adjacencies(quads[0], &hexes[1], 1, false); 02747 if (mtu.equivalent_entities(quads[2])) 02748 mbImpl->add_adjacencies(quads[2], &hexes[0], 1, false); 02749 02750 // re-set the global ids for the hexes to what they were 02751 result = mbImpl->tag_set_data(globalId_tag(), hexes, 2, tmp_ids); 02752 if (MB_SUCCESS != result) return result; 02753 02754 if (debug_ap) ((Core*)mbImpl)->check_adjacencies(); 02755 02756 // now update the dual 02757 Range tmph; 02758 result = mtu.get_bridge_adjacencies(hexes[0], 0, 3, tmph); 02759 if (MB_SUCCESS != result) return result; 02760 result = mtu.get_bridge_adjacencies(hexes[1], 0, 3, tmph); 02761 if (MB_SUCCESS != result) return result; 02762 tmph.insert(hexes[1]); 02763 result = construct_hex_dual(tmph); 02764 if (MB_SUCCESS != result) return result; 02765 02766 return result; 02767 } 02768 02769 ErrorCode DualTool:: fs_get_quad_loops(EntityHandle *hexes, 02770 std::vector<EntityHandle> *connects, 02771 std::vector<EntityHandle> *side_quads) 02772 { 02773 for (int i = 0; i < 4; i++) { 02774 for (int j = 0; j < 2; j++) { 02775 Range adj_ents, dum_quads; 02776 adj_ents.insert(hexes[j]); 02777 adj_ents.insert(connects[j][i]); 02778 adj_ents.insert(connects[j][(i+1)%4]); 02779 adj_ents.insert(connects[j+1][i]); 02780 adj_ents.insert(connects[j+1][(i+1)%4]); 02781 02782 ErrorCode result = mbImpl->get_adjacencies(adj_ents, 2, false, dum_quads); 02783 if (MB_SUCCESS != result) return result; 02784 assert(1 == dum_quads.size()); 02785 side_quads[j].push_back(*dum_quads.begin()); 02786 } 02787 } 02788 02789 return MB_SUCCESS; 02790 } 02791 02792 ErrorCode DualTool::fs_check_quad_sense(EntityHandle hex0, 02793 EntityHandle quad0, 02794 std::vector<EntityHandle> *connects) 02795 { 02796 // check sense of 0th quad wrt hex; since sense is out of element, 02797 // switch if quad is NOT reversed wrt hex 02798 int dum1, dum2, sense = 0; 02799 ErrorCode result = mbImpl->side_number(hex0, quad0, dum1, sense, dum2); 02800 if (MB_SUCCESS != result) return result; 02801 assert(0 != sense); 02802 if (1 == sense) { 02803 // just switch sense of this one; others will get switched next 02804 EntityHandle dum = connects[0][0]; 02805 connects[0][0] = connects[0][2]; 02806 connects[0][2] = dum; 02807 } 02808 02809 // check sense of 1st, 2nd quads, rotate if necessary to align connect arrays 02810 int index0 = -1, index2 = -1, sense0 = 0, sense2 = 0; 02811 MeshTopoUtil mtu(mbImpl); 02812 for (int i = 0; i < 4; i++) { 02813 if (0 != mtu.common_entity(connects[0][0], connects[1][i], 1)) { 02814 index0 = i; 02815 if (0 != mtu.common_entity(connects[0][1], connects[1][(i+1)%4], 1)) 02816 sense0 = 1; 02817 else if (0 != mtu.common_entity(connects[0][1], connects[1][(i+4-1)%4], 1)) 02818 sense0 = -1; 02819 break; 02820 } 02821 } 02822 02823 assert(index0 != -1 && sense0 != 0); 02824 02825 if (sense0 == -1) { 02826 EntityHandle dumh = connects[1][0]; 02827 connects[1][0] = connects[1][2]; 02828 connects[1][2] = dumh; 02829 if (index0%2 == 0) 02830 index0 = (index0+2)%4; 02831 } 02832 02833 if (index0 != 0) { 02834 std::vector<EntityHandle> tmpc; 02835 for (int i = 0; i < 4; i++) 02836 tmpc.push_back(connects[1][(index0+i)%4]); 02837 connects[1].swap(tmpc); 02838 } 02839 02840 for (int i = 0; i < 4; i++) { 02841 if (0 != mtu.common_entity(connects[1][0], connects[2][i], 1)) { 02842 index2 = i; 02843 if (0 != mtu.common_entity(connects[1][1], connects[2][(i+1)%4], 1)) 02844 sense2 = 1; 02845 else if (0 != mtu.common_entity(connects[1][1], connects[2][(i+4-1)%4], 1)) 02846 sense2 = -1; 02847 break; 02848 } 02849 } 02850 02851 assert(index2 != -1 && sense2 != 0); 02852 02853 if (sense2 == -1) { 02854 EntityHandle dumh = connects[2][0]; 02855 connects[2][0] = connects[2][2]; 02856 connects[2][2] = dumh; 02857 if (index2%2 == 0) 02858 index2 = (index2+2)%4; 02859 } 02860 02861 if (index2 != 0) { 02862 std::vector<EntityHandle> tmpc; 02863 for (int i = 0; i < 4; i++) 02864 tmpc.push_back(connects[2][(index2+i)%4]); 02865 connects[2].swap(tmpc); 02866 } 02867 02868 return MB_SUCCESS; 02869 } 02870 02872 ErrorCode DualTool::rev_face_shrink(EntityHandle odedge) 02873 { 02874 if (debug_ap) ((Core*)mbImpl)->check_adjacencies(); 02875 02876 // some preliminary checking 02877 if (mbImpl->type_from_handle(odedge) != MBEDGE) return MB_TYPE_OUT_OF_RANGE; 02878 02879 std::cout << "-FS("; print_cell(odedge); std::cout << ")" << std::endl; 02880 02881 EntityHandle quads[4], hexes[2]; 02882 std::vector<EntityHandle> connects[4], side_quads[2]; 02883 02884 // get three quads (shared quad & 2 end quads), hexes, and quad 02885 // connects 02886 ErrorCode result = fs_get_quads(odedge, quads, hexes, connects); 02887 if (MB_SUCCESS != result) return result; 02888 02889 // adjust sense & rotation so they're aligned, together & wrt first 02890 // hex 02891 result = fs_check_quad_sense(hexes[0], quads[0], connects); 02892 if (MB_SUCCESS != result) return result; 02893 02894 result = fsr_get_fourth_quad(connects, side_quads); 02895 if (MB_SUCCESS != result) { 02896 std::cout << "Can't do -FS here, two hexes must be adjacent to ring of 4 hexes." 02897 << std::endl; 02898 return result; 02899 } 02900 02901 Range adj_ents, outer_hexes, all_adjs; 02902 02903 // first get the entities connected to interior 4 verts 02904 for (int i = 1; i <= 3; i++) { 02905 result = mbImpl->get_adjacencies(&connects[1][0], 4, i, false, adj_ents, 02906 Interface::UNION); 02907 if (MB_SUCCESS != result) return result; 02908 } 02909 02910 // next get all entities adjacent to those; these will have their dual 02911 // entities deleted 02912 for (int i = 0; i < 3; i++) { 02913 result = mbImpl->get_adjacencies(adj_ents, i, false, all_adjs, 02914 Interface::UNION); 02915 if (MB_SUCCESS != result) return result; 02916 } 02917 02918 // get the dual entities and delete them 02919 Range dual_ents, dual_hps; 02920 for (Range::iterator rit = all_adjs.begin(); rit != all_adjs.end(); rit++) { 02921 EntityHandle this_ent = get_dual_entity(*rit); 02922 dual_ents.insert(this_ent); 02923 } 02924 02925 // before deleting dual, grab the 1- and 2-cells 02926 for (Range::iterator rit = dual_ents.begin(); rit != dual_ents.end(); rit++) { 02927 int dim = mbImpl->dimension_from_handle(*rit); 02928 if (1 == dim || 2 == dim) dual_hps.insert(get_dual_hyperplane(*rit)); 02929 } 02930 02931 result = delete_dual_entities(dual_ents); 02932 if (MB_SUCCESS != result) return result; 02933 02934 // after deleting cells, check for empty chords & sheets, and delete those too 02935 for (Range::iterator rit = dual_hps.begin(); rit != dual_hps.end(); rit++) { 02936 Range tmp_ents; 02937 result = mbImpl->get_entities_by_handle(*rit, tmp_ents); 02938 if (MB_SUCCESS != result) return result; 02939 if (tmp_ents.empty()) { 02940 result = mbImpl->delete_entities(&(*rit), 1); 02941 if (MB_SUCCESS != result) return result; 02942 } 02943 } 02944 02945 // before re-connecting two hexes, check for existing quad on 4th quad vertices; 02946 // if there is a quad there, need to add explicit adjs to any adj hexes, since 02947 // by definition there'll be another quad on those vertices 02948 bool need_explicit = false; 02949 Range adj_quads; 02950 result = mbImpl->get_adjacencies(&connects[3][0], 4, 2, false, adj_quads); 02951 if (MB_MULTIPLE_ENTITIES_FOUND == result || !adj_quads.empty()) { 02952 // there's already a quad for these 4 vertices; by definition, 02953 // we'll be creating equivalent entities, so that original quad 02954 // needs explicit adj's to its bounding elements 02955 need_explicit = true; 02956 for (Range::iterator rit = adj_quads.begin(); rit != adj_quads.end(); 02957 rit++) { 02958 Range adj_hexes; 02959 result = mbImpl->get_adjacencies(&(*rit), 1, 3, false, adj_hexes); RR; 02960 result = mbImpl->add_adjacencies(*rit, adj_hexes, false); RR; 02961 } 02962 } 02963 02964 // re-connect the two hexes 02965 std::vector<EntityHandle> new_connect; 02966 std::copy(connects[3].begin(), connects[3].end(), std::back_inserter(new_connect)); 02967 std::copy(connects[2].begin(), connects[2].end(), std::back_inserter(new_connect)); 02968 result = mbImpl->set_connectivity(hexes[0], &new_connect[0], 8); 02969 if (MB_SUCCESS != result) return result; 02970 02971 new_connect.clear(); 02972 std::copy(connects[0].begin(), connects[0].end(), std::back_inserter(new_connect)); 02973 std::copy(connects[3].begin(), connects[3].end(), std::back_inserter(new_connect)); 02974 result = mbImpl->set_connectivity(hexes[1], &new_connect[0], 8); 02975 if (MB_SUCCESS != result) return result; 02976 02977 // test for equiv entities from the side quads, and make explicit 02978 // adjacencies if there are any 02979 MeshTopoUtil mtu(mbImpl); 02980 for (int j = 0; j < 2; j++) { 02981 for (int i = 0; i < 4; i++) { 02982 if (mtu.equivalent_entities(side_quads[j][i])) { 02983 result = mbImpl->add_adjacencies(side_quads[j][i], &hexes[j], 1, false); 02984 if (MB_SUCCESS != result) return result; 02985 } 02986 } 02987 } 02988 02989 // remove hexes we want to keep 02990 adj_ents.erase(hexes[0]); 02991 adj_ents.erase(hexes[1]); 02992 02993 // delete the other interior entities 02994 result = mbImpl->delete_entities(adj_ents); 02995 if (MB_SUCCESS != result) return result; 02996 02997 EntityHandle new_quad; 02998 result = mbImpl->create_element(MBQUAD, &connects[3][0], 4, new_quad); RR; 02999 if (need_explicit) { 03000 result = mbImpl->add_adjacencies(new_quad, hexes, 2, false); RR; 03001 } 03002 03003 if (debug_ap) ((Core*)mbImpl)->check_adjacencies(); 03004 03005 // now update the dual 03006 result = construct_hex_dual(hexes, 2); 03007 if (MB_SUCCESS != result) return result; 03008 03009 return MB_SUCCESS; 03010 } 03011 03012 ErrorCode DualTool::fsr_get_fourth_quad(std::vector<EntityHandle> *connects, 03013 std::vector<EntityHandle> *side_quads) 03014 { 03015 // given the first three quad connectivities in ordered vectors, get the fourth, 03016 // where the fourth is really the 4 vertices originally shared by the 2 hexes 03017 // before the face shrink on them 03018 03019 // vertex on 4th quad is in quad adj to other 3 verts 03020 for (int i = 0; i < 4; i++) { 03021 Range start_verts, tmp_verts, quads; 03022 for (int j = 0; j < 3; j++) start_verts.insert(connects[j][i]); 03023 ErrorCode result = mbImpl->get_adjacencies(start_verts, 2, false, quads); 03024 if (MB_SUCCESS != result) return result; 03025 assert(quads.size() == 1); 03026 result = mbImpl->get_adjacencies(&(*quads.begin()), 1, 0, false, tmp_verts); RR; 03027 tmp_verts = subtract( tmp_verts, start_verts); 03028 assert(1 == tmp_verts.size()); 03029 connects[3].push_back(*tmp_verts.begin()); 03030 } 03031 03032 // now get the side quads 03033 for (int i = 0; i < 4; i++) { 03034 Range dum_ents, hexes; 03035 dum_ents.insert(connects[1][i]); 03036 dum_ents.insert(connects[1][(i+1)%4]); 03037 dum_ents.insert(connects[3][i]); 03038 ErrorCode result = mbImpl->get_adjacencies(dum_ents, 3, false, hexes); 03039 if (MB_SUCCESS != result) return result; 03040 assert(1 == hexes.size()); 03041 03042 hexes.insert(connects[0][i]); 03043 hexes.insert(connects[0][(i+1)%4]); 03044 hexes.insert(connects[3][i]); 03045 hexes.insert(connects[3][(i+1)%4]); 03046 dum_ents.clear(); 03047 result = mbImpl->get_adjacencies(hexes, 2, false, dum_ents); 03048 if (MB_SUCCESS != result) return result; 03049 assert(dum_ents.size() == 1); 03050 side_quads[0].push_back(*dum_ents.begin()); 03051 03052 hexes.erase(connects[0][i]); 03053 hexes.erase(connects[0][(i+1)%4]); 03054 hexes.insert(connects[2][i]); 03055 hexes.insert(connects[2][(i+1)%4]); 03056 dum_ents.clear(); 03057 result = mbImpl->get_adjacencies(hexes, 2, false, dum_ents); 03058 if (MB_SUCCESS != result) return result; 03059 side_quads[1].push_back(*dum_ents.begin()); 03060 } 03061 03062 return MB_SUCCESS; 03063 } 03064 03065 ErrorCode DualTool::fs_get_quads(EntityHandle odedge, 03066 EntityHandle *quads, 03067 EntityHandle *hexes, 03068 std::vector<EntityHandle> *connects) 03069 { 03070 // need to get the three quads along the chord 03071 EntityHandle chord = get_dual_hyperplane(odedge); 03072 if (0 == chord) return MB_FAILURE; 03073 03074 std::vector<EntityHandle> edges; 03075 ErrorCode result = mbImpl->get_entities_by_handle(chord, edges); 03076 if (MB_FAILURE == result) return result; 03077 03078 std::vector<EntityHandle>::iterator vit = std::find(edges.begin(), edges.end(), odedge); 03079 // shouldn't be first or last edge on chord 03080 if (vit == edges.end() || *edges.begin() == *vit || *edges.rbegin() == *vit) 03081 return MB_FAILURE; 03082 03083 // get quads/connectivity for first 3 quads 03084 quads[0] = get_dual_entity(*(vit-1)); 03085 quads[1] = get_dual_entity(*vit); 03086 quads[2] = get_dual_entity(*(vit+1)); 03087 for (int i = 0; i < 3; i++) { 03088 result = mbImpl->get_connectivity(&quads[i], 1, connects[i], true); 03089 if (MB_SUCCESS != result) return result; 03090 } 03091 03092 Range tmph; 03093 result = mbImpl->get_adjacencies(quads, 2, 3, false, tmph); 03094 if (MB_SUCCESS != result) return result; 03095 assert(tmph.size() == 1); 03096 hexes[0] = *tmph.begin(); 03097 03098 tmph.clear(); 03099 result = mbImpl->get_adjacencies(&quads[1], 2, 3, false, tmph); 03100 if (MB_SUCCESS != result) return result; 03101 assert(tmph.size() == 1); 03102 hexes[1] = *tmph.begin(); 03103 03104 return MB_SUCCESS; 03105 } 03106 03107 ErrorCode DualTool::delete_whole_dual() 03108 { 03109 // delete dual hyperplanes 03110 Range dual_surfs, dual_curves; 03111 ErrorCode result = this->get_dual_hyperplanes(mbImpl, 2, dual_surfs); RR; 03112 result = mbImpl->delete_entities(dual_surfs); RR; 03113 result = this->get_dual_hyperplanes(mbImpl, 1, dual_curves); RR; 03114 result = mbImpl->delete_entities(dual_curves); RR; 03115 03116 // gather up all dual entities 03117 Range dual_ents; 03118 result = mbImpl->get_entities_by_type_and_tag(0, MBVERTEX, &isDualCellTag, NULL, 1, dual_ents, 03119 Interface::UNION); RR; 03120 result = mbImpl->get_entities_by_type_and_tag(0, MBEDGE, &isDualCellTag, NULL, 1, dual_ents, 03121 Interface::UNION); RR; 03122 result = mbImpl->get_entities_by_type_and_tag(0, MBPOLYGON, &isDualCellTag, NULL, 1, dual_ents, 03123 Interface::UNION); RR; 03124 result = mbImpl->get_entities_by_type_and_tag(0, MBPOLYHEDRON, &isDualCellTag, NULL, 1, dual_ents, 03125 Interface::UNION); RR; 03126 03127 // delete them, in reverse order of dimension 03128 ErrorCode tmp_result; 03129 for (Range::reverse_iterator rit = dual_ents.rbegin(); rit != dual_ents.rend(); rit++) { 03130 tmp_result = mbImpl->delete_entities(&(*rit), 1); 03131 if (MB_SUCCESS != tmp_result) result = tmp_result; 03132 } 03133 RR; 03134 03135 // delete dual-related tags 03136 if (0 != dualSurfaceTag) { 03137 tmp_result = mbImpl->tag_delete(dualSurfaceTag); 03138 if (MB_SUCCESS != tmp_result && MB_TAG_NOT_FOUND != tmp_result) result = tmp_result; 03139 } 03140 if (0 != dualCurveTag) { 03141 tmp_result = mbImpl->tag_delete(dualCurveTag); 03142 if (MB_SUCCESS != tmp_result && MB_TAG_NOT_FOUND != tmp_result) result = tmp_result; 03143 } 03144 if (0 != dualEntityTag) { 03145 tmp_result = mbImpl->tag_delete(dualEntityTag); 03146 if (MB_SUCCESS != tmp_result && MB_TAG_NOT_FOUND != tmp_result) result = tmp_result; 03147 } 03148 if (0 != extraDualEntityTag) { 03149 tmp_result = mbImpl->tag_delete(extraDualEntityTag); 03150 if (MB_SUCCESS != tmp_result && MB_TAG_NOT_FOUND != tmp_result) result = tmp_result; 03151 } 03152 if (0 != dualGraphicsPointTag) { 03153 tmp_result = mbImpl->tag_delete(dualGraphicsPointTag); 03154 if (MB_SUCCESS != tmp_result && MB_TAG_NOT_FOUND != tmp_result) result = tmp_result; 03155 } 03156 03157 return MB_SUCCESS; 03158 } 03159 03160 ErrorCode DualTool::check_dual_adjs() 03161 { 03162 // check primal-dual correspondence 03163 03164 // get the primal entities 03165 Range pents[4]; 03166 ErrorCode result = mbImpl->get_entities_by_type(0, MBHEX, pents[3]); RR; 03167 for (int i = 2; i >= 0; i--) { 03168 result = mbImpl->get_adjacencies(pents[3], 2, false, pents[2], 03169 Interface::UNION); RR; 03170 } 03171 03172 // for each primal entity of dimension pd 03173 #define PRENT(ent) CN::EntityTypeName(TYPE_FROM_HANDLE(ent)) << " " \ 03174 << ID_FROM_HANDLE(ent) 03175 ErrorCode overall_result = MB_SUCCESS; 03176 for (int pd = 1; pd <= 3; pd++) { 03177 for (Range::iterator prit = pents[pd].begin(); prit != pents[pd].end(); prit++) { 03178 // get corresponding dual entity of dimension dd = 3-pd 03179 EntityHandle dual_ent = get_dual_entity(*prit); 03180 if (0 == dual_ent) 03181 std::cerr << "Problem getting dual entity for " << PRENT(*prit) << std::endl; 03182 03183 // for each sub dimension sd = 0..pd-1 03184 for (int sd = 0; sd < pd; sd++) { 03185 Range R1, R2, R3; 03186 // R1 = entities bounding primal entity of dim sd 03187 result = mbImpl->get_adjacencies(&(*prit), 1, sd, false, R1); RR; 03188 03189 // R2 = entities bounded by dual entity, of dim 3-sd 03190 result = mbImpl->get_adjacencies(&dual_ent, 1, 3-sd, false, R2); RR; 03191 03192 03193 if (R1.size() != R2.size()) { 03194 std::cerr << PRENT(*prit) << ": number of adj ents in " 03195 << "primal/dual don't agree for dimension " << sd << "." << std::endl; 03196 overall_result = MB_FAILURE; 03197 } 03198 03199 // for each entity in R1, get its dual and look for it in R2 03200 for (Range::iterator r1it = R1.begin(); r1it != R1.end(); r1it++) { 03201 EntityHandle tmp_dual = get_dual_entity(*r1it); 03202 if (R2.find(tmp_dual) == R2.end()) { 03203 std::cerr << PRENT(*prit) << ": adj entity " << PRENT(*r1it) 03204 << " isn't adjacent in dual." << std::endl; 03205 overall_result = MB_FAILURE; 03206 } 03207 } 03208 // ditto for R2 03209 for (Range::iterator r2it = R2.begin(); r2it != R2.end(); r2it++) { 03210 EntityHandle tmp_prim = get_dual_entity(*r2it); 03211 if (R1.find(tmp_prim) == R1.end()) { 03212 std::cerr << PRENT(*prit) << ": adj entity " << PRENT(*r2it) 03213 << " isn't adjacent in primal." << std::endl; 03214 overall_result = MB_FAILURE; 03215 } 03216 } 03217 } 03218 } 03219 } 03220 03221 return overall_result; 03222 } 03223 03224 } // namespace moab