moab
MeshTopoUtil.cpp
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines