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