moab
|
00001 00016 #ifdef WIN32 00017 #pragma warning (disable : 4786) 00018 #endif 00019 00020 #include "moab/MeshTopoUtil.hpp" 00021 #include "moab/Range.hpp" 00022 #include "Internals.hpp" 00023 #include "moab/Interface.hpp" 00024 #include "moab/CN.hpp" 00025 00026 #include <assert.h> 00027 00028 #define RR {if (MB_SUCCESS != result) return result;} 00029 00030 namespace moab { 00031 00033 ErrorCode MeshTopoUtil::construct_aentities(const Range &vertices) 00034 { 00035 Range out_range; 00036 ErrorCode result; 00037 result = mbImpl->get_adjacencies(vertices, 1, true, out_range, Interface::UNION); 00038 if (MB_SUCCESS != result) return result; 00039 out_range.clear(); 00040 result = mbImpl->get_adjacencies(vertices, 2, true, out_range, Interface::UNION); 00041 if (MB_SUCCESS != result) return result; 00042 out_range.clear(); 00043 result = mbImpl->get_adjacencies(vertices, 3, true, out_range, Interface::UNION); 00044 00045 return result; 00046 } 00047 00049 ErrorCode MeshTopoUtil::get_average_position(Range &entities, 00050 double *avg_position) 00051 { 00052 std::vector<EntityHandle> ent_vec; 00053 std::copy(entities.begin(), entities.end(), std::back_inserter(ent_vec)); 00054 return get_average_position(&ent_vec[0], ent_vec.size(), avg_position); 00055 } 00056 00058 ErrorCode MeshTopoUtil::get_average_position(const EntityHandle *entities, 00059 const int num_entities, 00060 double *avg_position) 00061 { 00062 double dum_pos[3]; 00063 avg_position[0] = avg_position[1] = avg_position[2] = 0.0; 00064 00065 Range connect; 00066 ErrorCode result = mbImpl->get_adjacencies(entities, num_entities, 0, false, 00067 connect, Interface::UNION); 00068 if (MB_SUCCESS != result) return result; 00069 00070 if (connect.empty()) return MB_FAILURE; 00071 00072 for (Range::iterator rit = connect.begin(); rit != connect.end(); rit++) { 00073 result = mbImpl->get_coords(&(*rit), 1, dum_pos); 00074 if (MB_SUCCESS != result) return result; 00075 avg_position[0] += dum_pos[0]; 00076 avg_position[1] += dum_pos[1]; 00077 avg_position[2] += dum_pos[2]; 00078 } 00079 avg_position[0] /= (double) connect.size(); 00080 avg_position[1] /= (double) connect.size(); 00081 avg_position[2] /= (double) connect.size(); 00082 00083 return MB_SUCCESS; 00084 } 00085 00087 ErrorCode MeshTopoUtil::get_average_position(const EntityHandle entity, 00088 double *avg_position) 00089 { 00090 const EntityHandle *connect; 00091 int num_connect; 00092 if (MBVERTEX == mbImpl->type_from_handle(entity)) 00093 return mbImpl->get_coords(&entity, 1, avg_position); 00094 00095 ErrorCode result = mbImpl->get_connectivity(entity, connect, num_connect); 00096 if (MB_SUCCESS != result) return result; 00097 00098 return get_average_position(connect, num_connect, avg_position); 00099 } 00100 00101 // given an entity, find the entities of next higher dimension around 00102 // that entity, ordered by connection through next higher dimension entities; 00103 // if any of the star entities is in only one entity of next higher dimension, 00104 // on_boundary is returned true 00105 ErrorCode MeshTopoUtil::star_entities(const EntityHandle star_center, 00106 std::vector<EntityHandle> &star_ents, 00107 bool &bdy_entity, 00108 const EntityHandle starting_star_entity, 00109 std::vector<EntityHandle> *star_entities_dp2, 00110 Range *star_candidates_dp2) 00111 { 00112 // now start the traversal 00113 bdy_entity = false; 00114 EntityHandle last_entity = starting_star_entity, last_dp2 = 0, next_entity, next_dp2; 00115 std::vector<EntityHandle> star_dp2; 00116 ErrorCode result; 00117 int center_dim = mbImpl->dimension_from_handle(star_center); 00118 00119 Range tmp_candidates_dp2; 00120 if (NULL != star_candidates_dp2) tmp_candidates_dp2 = *star_candidates_dp2; 00121 else { 00122 result = mbImpl->get_adjacencies(&star_center, 1, 00123 center_dim+2, 00124 false, tmp_candidates_dp2); 00125 if (MB_SUCCESS != result) return result; 00126 } 00127 00128 do { 00129 // get the next star entity 00130 result = star_next_entity(star_center, last_entity, last_dp2, 00131 &tmp_candidates_dp2, 00132 next_entity, next_dp2); 00133 if (MB_SUCCESS != result) return result; 00134 00135 // special case: if starting_star_entity isn't connected to any entities of next 00136 // higher dimension, it's the only entity in the star; put it on the list and return 00137 if (star_ents.empty() && next_entity == 0 && next_dp2 == 0) { 00138 star_ents.push_back(last_entity); 00139 bdy_entity = true; 00140 return MB_SUCCESS; 00141 } 00142 00143 // if we're at a bdy and bdy_entity hasn't been set yet, we're at the 00144 // first bdy; reverse the lists and start traversing in the other direction; but, 00145 // pop the last star entity off the list and find it again, so that we properly 00146 // check for next_dp2 00147 if (0 == next_dp2 && !bdy_entity) { 00148 star_ents.push_back(next_entity); 00149 bdy_entity = true; 00150 std::reverse(star_ents.begin(), star_ents.end()); 00151 star_ents.pop_back(); 00152 last_entity = star_ents.back(); 00153 if (!star_dp2.empty()) { 00154 std::reverse(star_dp2.begin(), star_dp2.end()); 00155 last_dp2 = star_dp2.back(); 00156 } 00157 } 00158 // else if we're not on the bdy and next_entity is already in star, that means 00159 // we've come all the way around; don't put next_entity on list again, and 00160 // zero out last_dp2 to terminate while loop 00161 else if (!bdy_entity && 00162 std::find(star_ents.begin(), star_ents.end(), next_entity) != 00163 star_ents.end() && 00164 (std::find(star_dp2.begin(), star_dp2.end(), next_dp2) != 00165 star_dp2.end() || !next_dp2)) 00166 { 00167 last_dp2 = 0; 00168 } 00169 00170 // else, just assign last entities seen and go on to next iteration 00171 else { 00172 if (std::find(star_ents.begin(), star_ents.end(), next_entity) == 00173 star_ents.end()) 00174 star_ents.push_back(next_entity); 00175 if (0 != next_dp2) { 00176 star_dp2.push_back(next_dp2); 00177 tmp_candidates_dp2.erase(next_dp2); 00178 } 00179 last_entity = next_entity; 00180 last_dp2 = next_dp2; 00181 } 00182 } 00183 while (0 != last_dp2); 00184 00185 // copy over the star_dp2 list, if requested 00186 if (NULL != star_entities_dp2) 00187 (*star_entities_dp2).swap(star_dp2); 00188 00189 return MB_SUCCESS; 00190 } 00191 00192 ErrorCode MeshTopoUtil::star_next_entity(const EntityHandle star_center, 00193 const EntityHandle last_entity, 00194 const EntityHandle last_dp1, 00195 Range *star_candidates_dp1, 00196 EntityHandle &next_entity, 00197 EntityHandle &next_dp1) 00198 { 00199 // given a star_center, a last_entity (whose dimension should be 1 greater than center) 00200 // and last_dp1 (dimension 2 higher than center), returns the next star entity across 00201 // last_dp1, and the next dp1 entity sharing next_entity; if star_candidates is non-empty, 00202 // star must come from those 00203 Range from_ents, to_ents; 00204 from_ents.insert(star_center); 00205 if (0 != last_dp1) from_ents.insert(last_dp1); 00206 00207 int dim = mbImpl->dimension_from_handle(star_center); 00208 00209 ErrorCode result = mbImpl->get_adjacencies(from_ents, dim+1, true, to_ents); 00210 if (MB_SUCCESS != result) return result; 00211 00212 // remove last_entity from result, and should only have 1 left, if any 00213 if (0 != last_entity) to_ents.erase(last_entity); 00214 00215 // if no last_dp1, contents of to_ents should share dp1-dimensional entity with last_entity 00216 if (0 != last_entity && 0 == last_dp1) { 00217 Range tmp_to_ents; 00218 for (Range::iterator rit = to_ents.begin(); rit != to_ents.end(); rit++) { 00219 if (0 != common_entity(last_entity, *rit, dim+2)) 00220 tmp_to_ents.insert(*rit); 00221 } 00222 to_ents = tmp_to_ents; 00223 } 00224 00225 if (0 == last_dp1 && to_ents.size() > 1 && NULL != star_candidates_dp1 && 00226 !star_candidates_dp1->empty()) { 00227 // if we have a choice of to_ents and no previous dp1 and there are dp1 candidates, 00228 // the one we choose needs to be adjacent to one of the candidates 00229 result = mbImpl->get_adjacencies(*star_candidates_dp1, dim+1, true, 00230 from_ents, Interface::UNION); 00231 if (MB_SUCCESS != result) return result; 00232 to_ents = intersect( to_ents, from_ents); 00233 } 00234 00235 if (!to_ents.empty()) next_entity = *to_ents.begin(); 00236 else { 00237 next_entity = 0; 00238 next_dp1 = 0; 00239 return MB_SUCCESS; 00240 } 00241 00242 // get next_dp1 00243 if (0 != star_candidates_dp1) to_ents = *star_candidates_dp1; 00244 else to_ents.clear(); 00245 00246 result = mbImpl->get_adjacencies(&next_entity, 1, dim+2, true, to_ents); 00247 if (MB_SUCCESS != result) return result; 00248 00249 // can't be last one 00250 if (0 != last_dp1) to_ents.erase(last_dp1); 00251 00252 if (!to_ents.empty()) next_dp1 = *to_ents.begin(); 00253 00254 // could be zero, means we're at bdy 00255 else next_dp1 = 0; 00256 00257 return MB_SUCCESS; 00258 } 00259 00260 ErrorCode MeshTopoUtil::star_entities_nonmanifold(const EntityHandle star_entity, 00261 std::vector<std::vector<EntityHandle> > &stars, 00262 std::vector<bool> *bdy_flags, 00263 std::vector<std::vector<EntityHandle> > *dp2_stars) 00264 { 00265 // Get a series of (d+1)-dimensional stars around a d-dimensional entity, such that 00266 // each star is on a (d+2)-manifold containing the d-dimensional entity; each star 00267 // is either open or closed, and also defines a (d+2)-star whose entities are bounded by 00268 // (d+1)-entities on the star and on the (d+2)-manifold 00269 // 00270 // Algorithm: 00271 // get the (d+2)-manifold entities; for d=1 / d+2=3, just assume all connected elements, since 00272 // we don't do 4d yet 00273 // get intersection of (d+1)-entities adjacent to star entity and union of (d+1)-entities 00274 // adjacent to (d+2)-manifold entities; these will be the entities in the star 00275 // while (d+1)-entities 00276 // remove (d+1)-entity from (d+1)-entities 00277 // get the (d+1)-star and (d+2)-star around that (d+1)-entity (using star_entities) 00278 // save that star to the star list, and the bdy flag and (d+2)-star if requested 00279 // remove (d+2)-entities from the (d+2)-manifold entities 00280 // remove (d+1)-entities from the (d+1)-entities 00281 // (end while) 00282 00283 int this_dim = mbImpl->dimension_from_handle(star_entity); 00284 if (3 <= this_dim || 0 > this_dim) return MB_FAILURE; 00285 00286 // get the (d+2)-manifold entities; for d=1 / d+2=3, just assume all connected elements, since 00287 // we don't do 4d yet 00288 Range dp2_manifold; 00289 ErrorCode result = get_manifold(star_entity, this_dim+2, dp2_manifold); 00290 if (MB_SUCCESS != result) return result; 00291 00292 // get intersection of (d+1)-entities adjacent to star and union of (d+1)-entities 00293 // adjacent to (d+2)-manifold entities; also add manifold (d+1)-entities, to catch 00294 // any not connected to (d+2)-entities 00295 Range dp1_manifold; 00296 result = mbImpl->get_adjacencies(dp2_manifold, this_dim+1, false, dp1_manifold, 00297 Interface::UNION); 00298 if (MB_SUCCESS != result) return result; 00299 00300 result = mbImpl->get_adjacencies(&star_entity, 1, this_dim+1, false, dp1_manifold); 00301 if (MB_SUCCESS != result) return result; 00302 00303 result = get_manifold(star_entity, this_dim+1, dp1_manifold); 00304 if (MB_SUCCESS != result) return result; 00305 00306 // while (d+1)-entities 00307 while (!dp1_manifold.empty()) { 00308 00309 // get (d+1)-entity from (d+1)-entities (don't remove it until after star, 00310 // since the star entities must come from dp1_manifold) 00311 EntityHandle this_ent = *dp1_manifold.begin(); 00312 00313 // get the (d+1)-star and (d+2)-star around that (d+1)-entity (using star_entities) 00314 std::vector<EntityHandle> this_star_dp1, this_star_dp2; 00315 bool on_bdy; 00316 result = star_entities(star_entity, this_star_dp1, on_bdy, this_ent, &this_star_dp2, 00317 &dp2_manifold); 00318 if (MB_SUCCESS != result) return result; 00319 00320 // if there's no star entities, it must mean this_ent isn't bounded by any dp2 00321 // entities (wasn't put into star in star_entities 'cuz we're passing in non-null 00322 // dp2_manifold above); put it in 00323 if (this_star_dp1.empty()) { 00324 Range dum_range; 00325 result = mbImpl->get_adjacencies(&this_ent, 1, this_dim+2, false, dum_range); 00326 if (MB_SUCCESS != result) return result; 00327 if (dum_range.empty()) this_star_dp1.push_back(this_ent); 00328 } 00329 00330 // now we can remove it 00331 dp1_manifold.erase(dp1_manifold.begin()); 00332 00333 // save that star to the star list, and the bdy flag and (d+2)-star if requested 00334 if (!this_star_dp1.empty()) { 00335 stars.push_back(this_star_dp1); 00336 if (NULL != bdy_flags) bdy_flags->push_back(on_bdy); 00337 if (NULL != dp2_stars) dp2_stars->push_back(this_star_dp2); 00338 } 00339 00340 // remove (d+2)-entities from the (d+2)-manifold entities 00341 for (std::vector<EntityHandle>::iterator vit = this_star_dp2.begin(); 00342 vit != this_star_dp2.end(); vit++) 00343 dp2_manifold.erase(*vit); 00344 00345 // remove (d+1)-entities from the (d+1)-entities 00346 for (std::vector<EntityHandle>::iterator vit = this_star_dp1.begin(); 00347 vit != this_star_dp1.end(); vit++) 00348 dp1_manifold.erase(*vit); 00349 00350 // (end while) 00351 } 00352 00353 // check for leftover dp2 manifold entities, these should be in one of the 00354 // stars 00355 if (!dp2_manifold.empty()) { 00356 for (Range::iterator rit = dp2_manifold.begin(); rit != dp2_manifold.end(); rit++) { 00357 } 00358 } 00359 00360 return MB_SUCCESS; 00361 } 00362 00367 ErrorCode MeshTopoUtil::get_manifold(const EntityHandle star_entity, 00368 const int target_dim, 00369 Range &manifold) 00370 { 00371 // get all the entities of target dimension connected to star 00372 Range tmp_range; 00373 ErrorCode result = mbImpl->get_adjacencies(&star_entity, 1, target_dim, false, tmp_range); 00374 if (MB_SUCCESS != result) return result; 00375 00376 // now save the ones which are (target_dim+1)-dimensional manifold; 00377 // for target_dim=3, just return whole range, since we don't do 4d 00378 if (target_dim == 3) { 00379 manifold.merge(tmp_range); 00380 return MB_SUCCESS; 00381 } 00382 00383 for (Range::iterator rit = tmp_range.begin(); rit != tmp_range.end(); rit++) { 00384 Range dum_range; 00385 // get (target_dim+1)-dimensional entities 00386 result = mbImpl->get_adjacencies(&(*rit), 1, target_dim+1, false, dum_range); 00387 if (MB_SUCCESS != result) return result; 00388 00389 // if there are only 1 or zero, add to manifold list 00390 if (1 >= dum_range.size()) manifold.insert(*rit); 00391 } 00392 00393 return MB_SUCCESS; 00394 } 00395 00397 ErrorCode MeshTopoUtil::get_bridge_adjacencies(Range &from_entities, 00398 int bridge_dim, 00399 int to_dim, 00400 Range &to_ents, 00401 int num_layers) 00402 { 00403 Range bridge_ents, last_toents, new_toents(from_entities); 00404 ErrorCode result; 00405 if (0 == num_layers || from_entities.empty()) return MB_FAILURE; 00406 00407 // for each layer, get bridge-adj entities and accumulate 00408 for (int nl = 0; nl < num_layers; nl++) { 00409 Range new_bridges; 00410 // get bridge ents 00411 result = mbImpl->get_adjacencies(new_toents, bridge_dim, true, new_bridges, 00412 Interface::UNION); 00413 if (MB_SUCCESS != result) return result; 00414 00415 // get to_dim adjacencies, merge into to_ents 00416 last_toents = to_ents; 00417 if (-1 == to_dim) { 00418 result = mbImpl->get_adjacencies(new_bridges, 3, false, to_ents, 00419 Interface::UNION); 00420 if (MB_SUCCESS != result) return result; 00421 for (int d = 2; d >= 1; d--) { 00422 result = mbImpl->get_adjacencies(to_ents, d, true, to_ents, 00423 Interface::UNION); 00424 if (MB_SUCCESS != result) return result; 00425 } 00426 } 00427 else { 00428 result = mbImpl->get_adjacencies(new_bridges, to_dim, false, to_ents, 00429 Interface::UNION); 00430 if (MB_SUCCESS != result) return result; 00431 } 00432 00433 // subtract last_toents to get new_toents 00434 if (nl < num_layers-1) 00435 new_toents = subtract( to_ents, last_toents); 00436 } 00437 00438 return MB_SUCCESS; 00439 } 00440 00442 ErrorCode MeshTopoUtil::get_bridge_adjacencies(const EntityHandle from_entity, 00443 const int bridge_dim, 00444 const int to_dim, 00445 Range &to_adjs) 00446 { 00447 // get pointer to connectivity for this entity 00448 const EntityHandle *connect; 00449 int num_connect; 00450 ErrorCode result = MB_SUCCESS; 00451 EntityType from_type = TYPE_FROM_HANDLE(from_entity); 00452 if (from_type == MBVERTEX) { 00453 connect = &from_entity; 00454 num_connect = 1; 00455 } 00456 else { 00457 result = mbImpl->get_connectivity(from_entity, connect, num_connect); 00458 if (MB_SUCCESS != result) return result; 00459 } 00460 00461 if (from_type >= MBENTITYSET) return MB_FAILURE; 00462 00463 int from_dim = CN::Dimension(from_type); 00464 00465 Range to_ents; 00466 00467 if (MB_SUCCESS != result) return result; 00468 00469 if (bridge_dim < from_dim) { 00470 // looping over each sub-entity of dimension bridge_dim... 00471 if (MBPOLYGON == from_type) 00472 { 00473 for (int i=0; i<num_connect; i++) 00474 { 00475 // loop over edges, and get the vertices 00476 EntityHandle verts_on_edge[2]={connect[i], connect[(i+1)%num_connect]}; 00477 to_ents.clear(); 00478 ErrorCode tmp_result = mbImpl->get_adjacencies(verts_on_edge, 2, 00479 to_dim, false, to_ents, Interface::INTERSECT); 00480 if (MB_SUCCESS != tmp_result) result = tmp_result; 00481 to_adjs.merge(to_ents); 00482 } 00483 } 00484 else 00485 { 00486 EntityHandle bridge_verts[MAX_SUB_ENTITIES]; 00487 int bridge_indices[MAX_SUB_ENTITIES]; 00488 for (int i = 0; i < CN::NumSubEntities(from_type, bridge_dim); i++) { 00489 00490 // get the vertices making up this sub-entity 00491 int num_bridge_verts = CN::VerticesPerEntity( CN::SubEntityType( from_type, bridge_dim, i ) ); 00492 CN::SubEntityVertexIndices( from_type, bridge_dim, i, bridge_indices ); 00493 for (int j = 0; j < num_bridge_verts; ++j) 00494 bridge_verts[j]= connect[bridge_indices[j]]; 00495 //CN::SubEntityConn(connect, from_type, bridge_dim, i, &bridge_verts[0], num_bridge_verts); 00496 00497 // get the to_dim entities adjacent 00498 to_ents.clear(); 00499 ErrorCode tmp_result = mbImpl->get_adjacencies(bridge_verts, num_bridge_verts, 00500 to_dim, false, to_ents, Interface::INTERSECT); 00501 if (MB_SUCCESS != tmp_result) result = tmp_result; 00502 00503 to_adjs.merge(to_ents); 00504 } 00505 } 00506 00507 } 00508 00509 // now get the direct ones too, or only in the case where we're 00510 // going to higher dimension for bridge 00511 Range bridge_ents, tmp_ents; 00512 tmp_ents.insert(from_entity); 00513 ErrorCode tmp_result = mbImpl->get_adjacencies(tmp_ents, bridge_dim, 00514 false, bridge_ents, 00515 Interface::UNION); 00516 if (MB_SUCCESS != tmp_result) return tmp_result; 00517 00518 tmp_result = mbImpl->get_adjacencies(bridge_ents, to_dim, false, to_adjs, 00519 Interface::UNION); 00520 if (MB_SUCCESS != tmp_result) return tmp_result; 00521 00522 // if to_dimension is same as that of from_entity, make sure from_entity isn't 00523 // in list 00524 if (to_dim == from_dim) to_adjs.erase(from_entity); 00525 00526 return result; 00527 } 00528 00530 EntityHandle MeshTopoUtil::common_entity(const EntityHandle ent1, 00531 const EntityHandle ent2, 00532 const int dim) 00533 { 00534 Range tmp_range, tmp_range2; 00535 tmp_range.insert(ent1); tmp_range.insert(ent2); 00536 ErrorCode result = mbImpl->get_adjacencies(tmp_range, dim, false, tmp_range2); 00537 if (MB_SUCCESS != result || tmp_range2.empty()) return 0; 00538 else return *tmp_range2.begin(); 00539 } 00540 00548 ErrorCode MeshTopoUtil::opposite_entity(const EntityHandle parent, 00549 const EntityHandle child, 00550 EntityHandle &opposite_element) 00551 { 00552 // get the side no. 00553 int side_no, offset, sense; 00554 ErrorCode result = mbImpl->side_number(parent, child, side_no, 00555 offset, sense); 00556 if (MB_SUCCESS != result) return result; 00557 00558 // get the child index from CN 00559 int opposite_index, opposite_dim; 00560 int status = CN::OppositeSide(mbImpl->type_from_handle(parent), 00561 side_no, mbImpl->dimension_from_handle(child), 00562 opposite_index, opposite_dim); 00563 if (0 != status) return MB_FAILURE; 00564 00565 // now get the side element from MOAB 00566 result = mbImpl->side_element(parent, opposite_dim, opposite_index, 00567 opposite_element); 00568 if (MB_SUCCESS != result) return result; 00569 00570 return MB_SUCCESS; 00571 } 00572 00573 ErrorCode MeshTopoUtil::split_entities_manifold(Range &entities, 00574 Range &new_entities, 00575 Range *fill_entities) 00576 { 00577 Range tmp_range, *tmp_ptr_fill_entity; 00578 if (NULL != fill_entities) tmp_ptr_fill_entity = &tmp_range; 00579 else tmp_ptr_fill_entity = NULL; 00580 00581 for (Range::iterator rit = entities.begin(); rit != entities.end(); rit++) { 00582 EntityHandle new_entity; 00583 if (NULL != tmp_ptr_fill_entity) tmp_ptr_fill_entity->clear(); 00584 00585 EntityHandle this_ent = *rit; 00586 ErrorCode result = split_entities_manifold(&this_ent, 1, &new_entity, 00587 tmp_ptr_fill_entity); 00588 if (MB_SUCCESS != result) return result; 00589 00590 new_entities.insert(new_entity); 00591 if (NULL != fill_entities) fill_entities->merge(*tmp_ptr_fill_entity); 00592 } 00593 00594 return MB_SUCCESS; 00595 } 00596 00597 00598 ErrorCode MeshTopoUtil::split_entities_manifold(EntityHandle *entities, 00599 const int num_entities, 00600 EntityHandle *new_entities, 00601 Range *fill_entities, 00602 EntityHandle *gowith_ents) 00603 { 00604 // split entities by duplicating them; splitting manifold means that there is at 00605 // most two higher-dimension entities bounded by a given entity; after split, the 00606 // new entity bounds one and the original entity bounds the other 00607 00608 #define ITERATE_RANGE(range, it) for (Range::iterator it = range.begin(); it != range.end(); it++) 00609 #define GET_CONNECT_DECL(ent, connect, num_connect) \ 00610 const EntityHandle *connect; int num_connect; \ 00611 {ErrorCode connect_result = mbImpl->get_connectivity(ent, connect, num_connect); \ 00612 if (MB_SUCCESS != connect_result) return connect_result;} 00613 #define GET_CONNECT(ent, connect, num_connect) \ 00614 {ErrorCode connect_result = mbImpl->get_connectivity(ent, connect, num_connect);\ 00615 if (MB_SUCCESS != connect_result) return connect_result;} 00616 #define TC if (MB_SUCCESS != tmp_result) {result = tmp_result; continue;} 00617 00618 ErrorCode result = MB_SUCCESS; 00619 for (int i = 0; i < num_entities; i++) { 00620 ErrorCode tmp_result; 00621 00622 // get original higher-dimensional bounding entities 00623 Range up_adjs[4]; 00624 // can only do a split_manifold if there are at most 2 entities of each 00625 // higher dimension; otherwise it's a split non-manifold 00626 bool valid_up_adjs = true; 00627 for (int dim = 1; dim <= 3; dim++) { 00628 tmp_result = mbImpl->get_adjacencies(entities+i, 1, dim, false, up_adjs[dim]); TC; 00629 if (dim > CN::Dimension(TYPE_FROM_HANDLE(entities[i])) && up_adjs[dim].size() > 2) { 00630 valid_up_adjs = false; 00631 break; 00632 } 00633 } 00634 if (!valid_up_adjs) return MB_FAILURE; 00635 00636 // ok to split; create the new entity, with connectivity of the original 00637 GET_CONNECT_DECL(entities[i], connect, num_connect); 00638 EntityHandle new_entity; 00639 result = mbImpl->create_element(mbImpl->type_from_handle(entities[i]), connect, num_connect, 00640 new_entity); TC; 00641 00642 // by definition, new entity and original will be equivalent; need to add explicit 00643 // adjs to distinguish them; don't need to check if there's already one there, 00644 // 'cuz add_adjacency does that for us 00645 for (int dim = 1; dim <= 3; dim++) { 00646 if (up_adjs[dim].empty() || dim == CN::Dimension(TYPE_FROM_HANDLE(entities[i]))) continue; 00647 00648 if (dim < CN::Dimension(TYPE_FROM_HANDLE(entities[i]))) { 00649 // adjacencies from other entities to this one; if any of those are equivalent entities, 00650 // need to make explicit adjacency to new entity too 00651 for (Range::iterator rit = up_adjs[dim].begin(); rit != up_adjs[dim].end(); rit++) { 00652 if (equivalent_entities(*rit)) 00653 result = mbImpl->add_adjacencies(*rit, &new_entity, 1, false); 00654 } 00655 } 00656 else { 00657 00658 // get the two up-elements 00659 EntityHandle up_elem1 = *(up_adjs[dim].begin()), 00660 up_elem2 = (up_adjs[dim].size() > 1 ? *(up_adjs[dim].rbegin()) : 0); 00661 00662 // if two, and a gowith entity was input, make sure the new entity goes with 00663 // that one 00664 if (gowith_ents && up_elem2 && 00665 gowith_ents[i] != up_elem1 && gowith_ents[i] == up_elem2) { 00666 EntityHandle tmp_elem = up_elem1; 00667 up_elem1 = up_elem2; 00668 up_elem2 = tmp_elem; 00669 } 00670 00671 tmp_result = mbImpl->remove_adjacencies(entities[i], &up_elem1, 1); 00672 // (ok if there's an error, that just means there wasn't an explicit adj) 00673 00674 tmp_result = mbImpl->add_adjacencies(new_entity, &up_elem1, 1, false); TC; 00675 if (!up_elem2) continue; 00676 00677 // add adj to other up_adj 00678 tmp_result = mbImpl->add_adjacencies(entities[i], &up_elem2, 1, false); TC; 00679 } 00680 } 00681 00682 // if we're asked to build a next-higher-dimension object, do so 00683 EntityHandle fill_entity = 0; 00684 EntityHandle tmp_ents[2]; 00685 if (NULL != fill_entities) { 00686 // how to do this depends on dimension 00687 switch (CN::Dimension(TYPE_FROM_HANDLE(entities[i]))) { 00688 case 0: 00689 tmp_ents[0] = entities[i]; 00690 tmp_ents[1] = new_entity; 00691 tmp_result = mbImpl->create_element(MBEDGE, tmp_ents, 2, fill_entity); TC; 00692 break; 00693 case 1: 00694 tmp_result = mbImpl->create_element(MBPOLYGON, connect, 2, fill_entity); TC; 00695 // need to create explicit adj in this case 00696 tmp_result = mbImpl->add_adjacencies(entities[i], &fill_entity, 1, false); TC; 00697 tmp_result = mbImpl->add_adjacencies(new_entity, &fill_entity, 1, false); TC; 00698 break; 00699 case 2: 00700 tmp_ents[0] = entities[i]; 00701 tmp_ents[1] = new_entity; 00702 tmp_result = mbImpl->create_element(MBPOLYHEDRON, tmp_ents, 2, fill_entity); TC; 00703 break; 00704 } 00705 if (0 == fill_entity) { 00706 result = MB_FAILURE; 00707 continue; 00708 } 00709 fill_entities->insert(fill_entity); 00710 } 00711 00712 new_entities[i] = new_entity; 00713 00714 } // end for over input entities 00715 00716 return result; 00717 } 00718 00719 ErrorCode MeshTopoUtil::split_entity_nonmanifold(EntityHandle split_ent, 00720 Range &old_adjs, 00721 Range &new_adjs, 00722 EntityHandle &new_entity) 00723 { 00724 // split an entity into two entities; new entity gets explicit adj to new_adjs, 00725 // old to old_adjs 00726 00727 // make new entities and add adjacencies 00728 // create the new entity 00729 EntityType split_type = mbImpl->type_from_handle(split_ent); 00730 00731 ErrorCode result; 00732 if (MBVERTEX == split_type) { 00733 double coords[3]; 00734 result = mbImpl->get_coords(&split_ent, 1, coords); RR; 00735 result = mbImpl->create_vertex(coords, new_entity); RR; 00736 } 00737 else { 00738 const EntityHandle *connect; 00739 int num_connect; 00740 result = mbImpl->get_connectivity(split_ent, connect, num_connect); RR; 00741 result = mbImpl->create_element(split_type, connect, num_connect, new_entity); RR; 00742 00743 // remove any explicit adjacencies between new_adjs and split entity 00744 for (Range::iterator rit = new_adjs.begin(); rit != new_adjs.end(); rit++) 00745 mbImpl->remove_adjacencies(split_ent, &(*rit), 1); 00746 } 00747 00748 if (MBVERTEX != split_type) { 00749 // add adj's between new_adjs & new entity, old_adjs & split_entity 00750 for (Range::iterator rit = new_adjs.begin(); rit != new_adjs.end(); rit++) 00751 mbImpl->add_adjacencies(new_entity, &(*rit), 1, true); 00752 for (Range::iterator rit = old_adjs.begin(); rit != old_adjs.end(); rit++) 00753 mbImpl->add_adjacencies(split_ent, &(*rit), 1, true); 00754 } 00755 else if (split_ent != new_entity) { 00756 // in addition to explicit adjs, need to check if vertex is part of any 00757 // other entities, and check those entities against ents in old and new adjs 00758 Range other_adjs; 00759 for (int i = 1; i < 4; i++) { 00760 result = mbImpl->get_adjacencies(&split_ent, 1, i, false, other_adjs, 00761 Interface::UNION); RR; 00762 } 00763 other_adjs = subtract( other_adjs, old_adjs); 00764 other_adjs = subtract( other_adjs, new_adjs); 00765 for (Range::iterator rit1 = other_adjs.begin(); rit1 != other_adjs.end(); rit1++) { 00766 // find an adjacent lower-dimensional entity in old_ or new_ adjs 00767 bool found = false; 00768 for (Range::iterator rit2 = old_adjs.begin(); rit2 != old_adjs.end(); rit2++) { 00769 if (mbImpl->dimension_from_handle(*rit1) != mbImpl->dimension_from_handle(*rit2) && 00770 common_entity(*rit1, *rit2, mbImpl->dimension_from_handle(*rit1))) { 00771 found = true; old_adjs.insert(*rit1); break; 00772 } 00773 } 00774 if (found) continue; 00775 for (Range::iterator rit2 = new_adjs.begin(); rit2 != new_adjs.end(); rit2++) { 00776 if (mbImpl->dimension_from_handle(*rit1) != mbImpl->dimension_from_handle(*rit2) && 00777 common_entity(*rit1, *rit2, mbImpl->dimension_from_handle(*rit1))) { 00778 found = true; new_adjs.insert(*rit1); break; 00779 } 00780 } 00781 if (!found) return MB_FAILURE; 00782 } 00783 00784 // instead of adjs replace in connectivity 00785 std::vector<EntityHandle> connect; 00786 for (Range::iterator rit = new_adjs.begin(); rit != new_adjs.end(); rit++) { 00787 connect.clear(); 00788 result = mbImpl->get_connectivity(&(*rit), 1, connect); RR; 00789 std::replace(connect.begin(), connect.end(), split_ent, new_entity); 00790 result = mbImpl->set_connectivity(*rit, &connect[0], connect.size()); RR; 00791 } 00792 } 00793 00794 return result; 00795 00796 /* 00797 00798 Commented out for now, because I decided to do a different implementation 00799 for the sake of brevity. However, I still think this function is the right 00800 way to do it, if I ever get the time. Sigh. 00801 00802 // split entity d, producing entity nd; generates various new entities, 00803 // see algorithm description in notes from 2/25/05 00804 const EntityHandle split_types = {MBEDGE, MBPOLYGON, MBPOLYHEDRON}; 00805 ErrorCode result = MB_SUCCESS; 00806 const int dim = CN::Dimension(TYPE_FROM_HANDLE(d)); 00807 MeshTopoUtil mtu(this); 00808 00809 // get all (d+2)-, (d+1)-cells connected to d 00810 Range dp2s, dp1s, dp1s_manif, dp2s_manif; 00811 result = get_adjacencies(&d, 1, dim+2, false, dp2s); RR; 00812 result = get_adjacencies(&d, 1, dim+1, false, dp1s); RR; 00813 00814 // also get (d+1)-cells connected to d which are manifold 00815 get_manifold_dp1s(d, dp1s_manif); 00816 get_manifold_dp2s(d, dp2s_manif); 00817 00818 // make new cell nd, then ndp1 00819 result = copy_entity(d, nd); RR; 00820 EntityHandle tmp_connect[] = {d, nd}; 00821 EntityHandle ndp1; 00822 result = create_element(split_types[dim], 00823 tmp_connect, 2, ndp1); RR; 00824 00825 // modify (d+2)-cells, depending on what type they are 00826 ITERATE_RANGE(dp2s, dp2) { 00827 // first, get number of connected manifold (d+1)-entities 00828 Range tmp_range, tmp_range2(dp1s_manif); 00829 tmp_range.insert(*dp2); 00830 tmp_range.insert(d); 00831 tmp_result = get_adjacencies(tmp_range, 1, false, tmp_range2); TC; 00832 EntityHandle ndp2; 00833 00834 // a. manif (d+1)-cells is zero 00835 if (tmp_range2.empty()) { 00836 // construct new (d+1)-cell 00837 EntityHandle ndp1a; 00838 EntityHandle tmp_result = create_element(split_types[dim], 00839 tmp_connect, 2, ndp1a); TC; 00840 // now make new (d+2)-cell 00841 EntityHandle tmp_connect2[] = {ndp1, ndp1a}; 00842 tmp_result = create_element(split_types[dim+1], 00843 tmp_connect2, 2, ndp2); TC; 00844 // need to add explicit adjacencies, since by definition ndp1, ndp1a will be equivalent 00845 tmp_result = add_adjacencies(ndp1a, &dp2, 1, false); TC; 00846 tmp_result = add_adjacencies(ndp1a, &ndp2, 1, false); TC; 00847 tmp_result = add_adjacencies(ndp1, &ndp2, 1, false); TC; 00848 00849 // now insert nd into connectivity of dp2, right after d if dim < 1 00850 std::vector<EntityHandle> connect; 00851 tmp_result = get_connectivity(&dp2, 1, connect); TC; 00852 if (dim < 1) { 00853 std::vector<EntityHandle>::iterator vit = std::find(connect.begin(), connect.end(), d); 00854 if (vit == connect.end()) { 00855 result = MB_FAILURE; 00856 continue; 00857 } 00858 connect.insert(vit, nd); 00859 } 00860 else 00861 connect.push_back(nd); 00862 tmp_result = set_connectivity(dp2, connect); TC; 00863 00864 // if dim < 1, need to add explicit adj from ndp2 to higher-dim ents, since it'll 00865 // be equiv to other dp2 entities 00866 if (dim < 1) { 00867 Range tmp_dp3s; 00868 tmp_result = get_adjacencies(&dp2, 1, dim+3, false, tmp_dp3s); TC; 00869 tmp_result = add_adjacencies(ndp2, tmp_dp3s, false); TC; 00870 } 00871 } // end if (tmp_range2.empty()) 00872 00873 // b. single manifold (d+1)-cell, which isn't adjacent to manifold (d+2)-cell 00874 else if (tmp_range2.size() == 1) { 00875 // b1. check validity, and skip if not valid 00876 00877 // only change if not dp1-adjacent to manifold dp2cell; check that... 00878 Range tmp_adjs(dp2s_manif); 00879 tmp_result = get_adjacencies(&(*tmp_range2.begin()), 1, dim+2, false, tmp_adjs); TC; 00880 if (!tmp_adjs.empty()) continue; 00881 00882 EntityHandle dp1 = *tmp_range2.begin(); 00883 00884 // b2. make new (d+1)- and (d+2)-cell next to dp2 00885 00886 // get the (d+2)-cell on the other side of dp1 00887 tmp_result = get_adjacencies(&dp1, 1, dim+2, false, tmp_adjs); TC; 00888 EntityHandle odp2 = *tmp_adjs.begin(); 00889 if (odp2 == dp2) odp2 = *tmp_adjs.rbegin(); 00890 00891 // get od, the d-cell on dp1_manif which isn't d 00892 tmp_result = get_adjacencies(&dp1_manif, 1, dim, false, tmp_adjs); TC; 00893 tmp_adjs.erase(d); 00894 if (tmp_adjs.size() != 1) { 00895 result = MB_FAILURE; 00896 continue; 00897 } 00898 EntityHandle od = *tmp_adjs.begin(); 00899 00900 // make a new (d+1)-cell from od and nd 00901 tmp_adjs.insert(nd); 00902 tmp_result = create_element(split_types[1], tmp_adjs, ndp1a); TC; 00903 00904 // construct new (d+2)-cell from dp1, ndp1, ndp1a 00905 tmp_adjs.clear(); 00906 tmp_adjs.insert(dp1); tmp_adjs.insert(ndp1); tmp_adjs.insert(ndp1a); 00907 tmp_result = create_element(split_types[2], tmp_adjs, ndp2); TC; 00908 00909 // b3. replace d, dp1 in connect/adjs of odp2 00910 std::vector<EntityHandle> connect; 00911 tmp_result = get_connectivity(&odp2, 1, connect); TC; 00912 if (dim == 0) { 00913 *(std::find(connect.begin(), connect.end(), d)) = nd; 00914 remove_adjacency(dp1, odp2); 00915 00916 00917 00918 // if dp1 was explicitly adj to odp2, remove it 00919 remove_adjacency 00920 00921 ... 00922 00923 */ 00924 } 00925 00929 bool MeshTopoUtil::equivalent_entities(const EntityHandle entity, 00930 Range *equiv_ents) 00931 { 00932 const EntityHandle *connect; 00933 int num_connect; 00934 ErrorCode result = mbImpl->get_connectivity(entity, connect, num_connect); 00935 if (MB_SUCCESS != result) return false; 00936 00937 Range dum; 00938 result = mbImpl->get_adjacencies(connect, num_connect, 00939 mbImpl->dimension_from_handle(entity), 00940 false, dum); 00941 dum.erase(entity); 00942 00943 if (NULL != equiv_ents) { 00944 equiv_ents->swap(dum); 00945 } 00946 00947 if (!dum.empty()) return true; 00948 else return false; 00949 } 00950 00951 } // namespace moab 00952