MOAB: Mesh Oriented datABase
(version 5.4.1)
|
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 __MFC_VER 00017 #pragma warning( disable : 4786 ) 00018 #endif 00019 00020 #ifdef WIN32 /* windows */ 00021 #define _USE_MATH_DEFINES // For M_PI 00022 #endif 00023 #include "moab/Skinner.hpp" 00024 #include "moab/Range.hpp" 00025 #include "moab/CN.hpp" 00026 #include <vector> 00027 #include <set> 00028 #include <algorithm> 00029 #include <cmath> 00030 #include <cassert> 00031 #include <iostream> 00032 #include "moab/Util.hpp" 00033 #include "Internals.hpp" 00034 #include "MBTagConventions.hpp" 00035 #include "moab/Core.hpp" 00036 #include "AEntityFactory.hpp" 00037 #include "moab/ScdInterface.hpp" 00038 00039 #ifdef M_PI 00040 #define SKINNER_PI M_PI 00041 #else 00042 #define SKINNER_PI 3.1415926535897932384626 00043 #endif 00044 00045 namespace moab 00046 { 00047 00048 Skinner::~Skinner() 00049 { 00050 // delete the adjacency tag 00051 } 00052 00053 ErrorCode Skinner::initialize() 00054 { 00055 // go through and mark all the target dimension entities 00056 // that already exist as not deleteable 00057 // also get the connectivity tags for each type 00058 // also populate adjacency information 00059 EntityType type; 00060 DimensionPair target_ent_types = CN::TypeDimensionMap[mTargetDim]; 00061 00062 void* null_ptr = NULL; 00063 00064 ErrorCode result = thisMB->tag_get_handle( "skinner adj", sizeof( void* ), MB_TYPE_OPAQUE, mAdjTag, 00065 MB_TAG_DENSE | MB_TAG_CREAT, &null_ptr );MB_CHK_ERR( result ); 00066 00067 if( mDeletableMBTag == 0 ) 00068 { 00069 result = 00070 thisMB->tag_get_handle( "skinner deletable", 1, MB_TYPE_BIT, mDeletableMBTag, MB_TAG_BIT | MB_TAG_CREAT );MB_CHK_ERR( result ); 00071 } 00072 00073 Range entities; 00074 00075 // go through each type at this dimension 00076 for( type = target_ent_types.first; type <= target_ent_types.second; ++type ) 00077 { 00078 // get the entities of this type in the MB 00079 thisMB->get_entities_by_type( 0, type, entities ); 00080 00081 // go through each entity of this type in the MB 00082 // and set its deletable tag to NO 00083 Range::iterator iter, end_iter; 00084 end_iter = entities.end(); 00085 for( iter = entities.begin(); iter != end_iter; ++iter ) 00086 { 00087 unsigned char bit = 0x1; 00088 result = thisMB->tag_set_data( mDeletableMBTag, &( *iter ), 1, &bit ); 00089 assert( MB_SUCCESS == result ); 00090 // add adjacency information too 00091 if( TYPE_FROM_HANDLE( *iter ) != MBVERTEX ) add_adjacency( *iter ); 00092 } 00093 } 00094 00095 return MB_SUCCESS; 00096 } 00097 00098 ErrorCode Skinner::deinitialize() 00099 { 00100 ErrorCode result; 00101 if( 0 != mDeletableMBTag ) 00102 { 00103 result = thisMB->tag_delete( mDeletableMBTag ); 00104 mDeletableMBTag = 0;MB_CHK_ERR( result ); 00105 } 00106 00107 // remove the adjacency tag 00108 std::vector< std::vector< EntityHandle >* > adj_arr; 00109 std::vector< std::vector< EntityHandle >* >::iterator i; 00110 if( 0 != mAdjTag ) 00111 { 00112 for( EntityType t = MBVERTEX; t != MBMAXTYPE; ++t ) 00113 { 00114 Range entities; 00115 result = thisMB->get_entities_by_type_and_tag( 0, t, &mAdjTag, 0, 1, entities );MB_CHK_ERR( result ); 00116 adj_arr.resize( entities.size() ); 00117 result = thisMB->tag_get_data( mAdjTag, entities, &adj_arr[0] );MB_CHK_ERR( result ); 00118 for( i = adj_arr.begin(); i != adj_arr.end(); ++i ) 00119 delete *i; 00120 } 00121 00122 result = thisMB->tag_delete( mAdjTag ); 00123 mAdjTag = 0;MB_CHK_ERR( result ); 00124 } 00125 00126 return MB_SUCCESS; 00127 } 00128 00129 ErrorCode Skinner::add_adjacency( EntityHandle entity ) 00130 { 00131 std::vector< EntityHandle >* adj = NULL; 00132 const EntityHandle* nodes; 00133 int num_nodes; 00134 ErrorCode result = thisMB->get_connectivity( entity, nodes, num_nodes, true );MB_CHK_ERR( result ); 00135 const EntityHandle* iter = std::min_element( nodes, nodes + num_nodes ); 00136 00137 if( iter == nodes + num_nodes ) return MB_SUCCESS; 00138 00139 // add this entity to the node 00140 if( thisMB->tag_get_data( mAdjTag, iter, 1, &adj ) == MB_SUCCESS && adj != NULL ) 00141 { 00142 adj->push_back( entity ); 00143 } 00144 // create a new vector and add it 00145 else 00146 { 00147 adj = new std::vector< EntityHandle >; 00148 adj->push_back( entity ); 00149 result = thisMB->tag_set_data( mAdjTag, iter, 1, &adj );MB_CHK_ERR( result ); 00150 } 00151 00152 return MB_SUCCESS; 00153 } 00154 00155 void Skinner::add_adjacency( EntityHandle entity, const EntityHandle* nodes, const int num_nodes ) 00156 { 00157 std::vector< EntityHandle >* adj = NULL; 00158 const EntityHandle* iter = std::min_element( nodes, nodes + num_nodes ); 00159 00160 if( iter == nodes + num_nodes ) return; 00161 00162 // should not be setting adjacency lists in ho-nodes 00163 assert( TYPE_FROM_HANDLE( entity ) == MBPOLYGON || 00164 num_nodes == CN::VerticesPerEntity( TYPE_FROM_HANDLE( entity ) ) ); 00165 00166 // add this entity to the node 00167 if( thisMB->tag_get_data( mAdjTag, iter, 1, &adj ) == MB_SUCCESS && adj != NULL ) 00168 { 00169 adj->push_back( entity ); 00170 } 00171 // create a new vector and add it 00172 else 00173 { 00174 adj = new std::vector< EntityHandle >; 00175 adj->push_back( entity ); 00176 thisMB->tag_set_data( mAdjTag, iter, 1, &adj ); 00177 } 00178 } 00179 00180 ErrorCode Skinner::find_geometric_skin( const EntityHandle meshset, Range& forward_target_entities ) 00181 { 00182 // attempts to find whole model skin, using geom topo sets first then 00183 // normal find_skin function 00184 bool debug = true; 00185 00186 // look for geom topo sets 00187 Tag geom_tag; 00188 ErrorCode result = 00189 thisMB->tag_get_handle( GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, geom_tag, MB_TAG_SPARSE | MB_TAG_CREAT ); 00190 00191 if( MB_SUCCESS != result ) return result; 00192 00193 // get face sets (dimension = 2) 00194 Range face_sets; 00195 int two = 2; 00196 const void* two_ptr = &two; 00197 result = thisMB->get_entities_by_type_and_tag( meshset, MBENTITYSET, &geom_tag, &two_ptr, 1, face_sets ); 00198 00199 Range::iterator it; 00200 if( MB_SUCCESS != result ) 00201 return result; 00202 else if( face_sets.empty() ) 00203 return MB_ENTITY_NOT_FOUND; 00204 00205 // ok, we have face sets; use those to determine skin 00206 Range skin_sets; 00207 if( debug ) std::cout << "Found " << face_sets.size() << " face sets total..." << std::endl; 00208 00209 for( it = face_sets.begin(); it != face_sets.end(); ++it ) 00210 { 00211 int num_parents; 00212 result = thisMB->num_parent_meshsets( *it, &num_parents ); 00213 if( MB_SUCCESS != result ) 00214 return result; 00215 else if( num_parents == 1 ) 00216 skin_sets.insert( *it ); 00217 } 00218 00219 if( debug ) std::cout << "Found " << skin_sets.size() << " 1-parent face sets..." << std::endl; 00220 00221 if( skin_sets.empty() ) return MB_FAILURE; 00222 00223 // ok, we have the shell; gather up the elements, putting them all in forward for now 00224 for( it = skin_sets.begin(); it != skin_sets.end(); ++it ) 00225 { 00226 result = thisMB->get_entities_by_handle( *it, forward_target_entities, true ); 00227 if( MB_SUCCESS != result ) return result; 00228 } 00229 00230 return result; 00231 } 00232 00233 ErrorCode Skinner::find_skin( const EntityHandle meshset, 00234 const Range& source_entities, 00235 bool get_vertices, 00236 Range& output_handles, 00237 Range* output_reverse_handles, 00238 bool create_vert_elem_adjs, 00239 bool create_skin_elements, 00240 bool look_for_scd ) 00241 { 00242 if( source_entities.empty() ) return MB_SUCCESS; 00243 00244 if( look_for_scd ) 00245 { 00246 ErrorCode rval = find_skin_scd( source_entities, get_vertices, output_handles, create_skin_elements ); 00247 // if it returns success, it's all scd, and we don't need to do anything more 00248 if( MB_SUCCESS == rval ) return rval; 00249 } 00250 00251 Core* this_core = dynamic_cast< Core* >( thisMB ); 00252 if( this_core && create_vert_elem_adjs && !this_core->a_entity_factory()->vert_elem_adjacencies() ) 00253 this_core->a_entity_factory()->create_vert_elem_adjacencies(); 00254 00255 return find_skin_vertices( meshset, source_entities, get_vertices ? &output_handles : 0, 00256 get_vertices ? 0 : &output_handles, output_reverse_handles, create_skin_elements ); 00257 } 00258 00259 ErrorCode Skinner::find_skin_scd( const Range& source_entities, 00260 bool get_vertices, 00261 Range& output_handles, 00262 bool create_skin_elements ) 00263 { 00264 // get the scd interface and check if it's been initialized 00265 ScdInterface* scdi = NULL; 00266 ErrorCode rval = thisMB->query_interface( scdi ); 00267 if( !scdi ) return MB_FAILURE; 00268 00269 // ok, there's scd mesh; see if the entities passed in are all in a scd box 00270 // a box needs to be wholly included in entities for this to work 00271 std::vector< ScdBox* > boxes, myboxes; 00272 Range myrange; 00273 rval = scdi->find_boxes( boxes ); 00274 if( MB_SUCCESS != rval ) return rval; 00275 for( std::vector< ScdBox* >::iterator bit = boxes.begin(); bit != boxes.end(); ++bit ) 00276 { 00277 Range belems( ( *bit )->start_element(), ( *bit )->start_element() + ( *bit )->num_elements() - 1 ); 00278 if( source_entities.contains( belems ) ) 00279 { 00280 myboxes.push_back( *bit ); 00281 myrange.merge( belems ); 00282 } 00283 } 00284 if( myboxes.empty() || myrange.size() != source_entities.size() ) return MB_FAILURE; 00285 00286 // ok, we're all structured; get the skin for each box 00287 for( std::vector< ScdBox* >::iterator bit = boxes.begin(); bit != boxes.end(); ++bit ) 00288 { 00289 rval = skin_box( *bit, get_vertices, output_handles, create_skin_elements ); 00290 if( MB_SUCCESS != rval ) return rval; 00291 } 00292 00293 return MB_SUCCESS; 00294 } 00295 00296 ErrorCode Skinner::skin_box( ScdBox* box, bool get_vertices, Range& output_handles, bool create_skin_elements ) 00297 { 00298 HomCoord bmin = box->box_min(), bmax = box->box_max(); 00299 00300 // don't support 1d boxes 00301 if( bmin.j() == bmax.j() && bmin.k() == bmax.k() ) return MB_FAILURE; 00302 00303 int dim = ( bmin.k() == bmax.k() ? 1 : 2 ); 00304 00305 ErrorCode rval; 00306 EntityHandle ent; 00307 00308 // i=min 00309 for( int k = bmin.k(); k < bmax.k(); k++ ) 00310 { 00311 for( int j = bmin.j(); j < bmax.j(); j++ ) 00312 { 00313 ent = 0; 00314 rval = box->get_adj_edge_or_face( dim, bmin.i(), j, k, 0, ent, create_skin_elements ); 00315 if( MB_SUCCESS != rval ) return rval; 00316 if( ent ) output_handles.insert( ent ); 00317 } 00318 } 00319 // i=max 00320 for( int k = bmin.k(); k < bmax.k(); k++ ) 00321 { 00322 for( int j = bmin.j(); j < bmax.j(); j++ ) 00323 { 00324 ent = 0; 00325 rval = box->get_adj_edge_or_face( dim, bmax.i(), j, k, 0, ent, create_skin_elements ); 00326 if( MB_SUCCESS != rval ) return rval; 00327 if( ent ) output_handles.insert( ent ); 00328 } 00329 } 00330 // j=min 00331 for( int k = bmin.k(); k < bmax.k(); k++ ) 00332 { 00333 for( int i = bmin.i(); i < bmax.i(); i++ ) 00334 { 00335 ent = 0; 00336 rval = box->get_adj_edge_or_face( dim, i, bmin.j(), k, 1, ent, create_skin_elements ); 00337 if( MB_SUCCESS != rval ) return rval; 00338 if( ent ) output_handles.insert( ent ); 00339 } 00340 } 00341 // j=max 00342 for( int k = bmin.k(); k < bmax.k(); k++ ) 00343 { 00344 for( int i = bmin.i(); i < bmax.i(); i++ ) 00345 { 00346 ent = 0; 00347 rval = box->get_adj_edge_or_face( dim, i, bmax.j(), k, 1, ent, create_skin_elements ); 00348 if( MB_SUCCESS != rval ) return rval; 00349 if( ent ) output_handles.insert( ent ); 00350 } 00351 } 00352 // k=min 00353 for( int j = bmin.j(); j < bmax.j(); j++ ) 00354 { 00355 for( int i = bmin.i(); i < bmax.i(); i++ ) 00356 { 00357 ent = 0; 00358 rval = box->get_adj_edge_or_face( dim, i, j, bmin.k(), 2, ent, create_skin_elements ); 00359 if( MB_SUCCESS != rval ) return rval; 00360 if( ent ) output_handles.insert( ent ); 00361 } 00362 } 00363 // k=max 00364 for( int j = bmin.j(); j < bmax.j(); j++ ) 00365 { 00366 for( int i = bmin.i(); i < bmax.i(); i++ ) 00367 { 00368 ent = 0; 00369 rval = box->get_adj_edge_or_face( dim, i, j, bmax.k(), 2, ent, create_skin_elements ); 00370 if( MB_SUCCESS != rval ) return rval; 00371 if( ent ) output_handles.insert( ent ); 00372 } 00373 } 00374 00375 if( get_vertices ) 00376 { 00377 Range verts; 00378 rval = thisMB->get_adjacencies( output_handles, 0, true, verts, Interface::UNION ); 00379 if( MB_SUCCESS != rval ) return rval; 00380 output_handles.merge( verts ); 00381 } 00382 00383 return MB_SUCCESS; 00384 } 00385 00386 ErrorCode Skinner::find_skin_noadj(const Range &source_entities, 00387 Range &forward_target_entities, 00388 Range &reverse_target_entities/*, 00389 bool create_vert_elem_adjs*/) 00390 { 00391 if( source_entities.empty() ) return MB_FAILURE; 00392 00393 // get our working dimensions 00394 EntityType type = thisMB->type_from_handle( *( source_entities.begin() ) ); 00395 const int source_dim = CN::Dimension( type ); 00396 mTargetDim = source_dim - 1; 00397 00398 // make sure we can handle the working dimensions 00399 if( mTargetDim < 0 || source_dim > 3 ) return MB_FAILURE; 00400 00401 initialize(); 00402 00403 Range::const_iterator iter, end_iter; 00404 end_iter = source_entities.end(); 00405 const EntityHandle* conn; 00406 EntityHandle match; 00407 00408 direction direct; 00409 ErrorCode result; 00410 // assume we'll never have more than 32 vertices on a facet (checked 00411 // with assert later) 00412 EntityHandle sub_conn[32]; 00413 std::vector< EntityHandle > tmp_conn_vec; 00414 int num_nodes, num_sub_nodes, num_sides; 00415 int sub_indices[32]; // Also, assume that no polygon has more than 32 nodes 00416 // we could increase that, but we will not display it right in visit moab h5m , anyway 00417 EntityType sub_type; 00418 00419 // for each source entity 00420 for( iter = source_entities.begin(); iter != end_iter; ++iter ) 00421 { 00422 // get the connectivity of this entity 00423 int actual_num_nodes_polygon = 0; 00424 result = thisMB->get_connectivity( *iter, conn, num_nodes, false, &tmp_conn_vec ); 00425 if( MB_SUCCESS != result ) return result; 00426 00427 type = thisMB->type_from_handle( *iter ); 00428 Range::iterator seek_iter; 00429 00430 // treat separately polygons (also, polyhedra will need special handling) 00431 if( MBPOLYGON == type ) 00432 { 00433 // treat padded polygons, if existing; count backwards, see how many of the last nodes 00434 // are repeated assume connectivity is fine, otherwise we could be in trouble 00435 actual_num_nodes_polygon = num_nodes; 00436 while( actual_num_nodes_polygon >= 3 && 00437 conn[actual_num_nodes_polygon - 1] == conn[actual_num_nodes_polygon - 2] ) 00438 actual_num_nodes_polygon--; 00439 num_sides = actual_num_nodes_polygon; 00440 sub_type = MBEDGE; 00441 num_sub_nodes = 2; 00442 } 00443 else // get connectivity of each n-1 dimension entity 00444 num_sides = CN::NumSubEntities( type, mTargetDim ); 00445 for( int i = 0; i < num_sides; i++ ) 00446 { 00447 if( MBPOLYGON == type ) 00448 { 00449 sub_conn[0] = conn[i]; 00450 sub_conn[1] = conn[i + 1]; 00451 if( i + 1 == actual_num_nodes_polygon ) sub_conn[1] = conn[0]; 00452 } 00453 else 00454 { 00455 CN::SubEntityNodeIndices( type, num_nodes, mTargetDim, i, sub_type, num_sub_nodes, sub_indices ); 00456 assert( (size_t)num_sub_nodes <= sizeof( sub_indices ) / sizeof( sub_indices[0] ) ); 00457 for( int j = 0; j < num_sub_nodes; j++ ) 00458 sub_conn[j] = conn[sub_indices[j]]; 00459 } 00460 00461 // see if we can match this connectivity with 00462 // an existing entity 00463 find_match( sub_type, sub_conn, num_sub_nodes, match, direct ); 00464 00465 // if there is no match, create a new entity 00466 if( match == 0 ) 00467 { 00468 EntityHandle tmphndl = 0; 00469 int indices[MAX_SUB_ENTITY_VERTICES]; 00470 EntityType new_type; 00471 int num_new_nodes; 00472 if( MBPOLYGON == type ) 00473 { 00474 new_type = MBEDGE; 00475 num_new_nodes = 2; 00476 } 00477 else 00478 { 00479 CN::SubEntityNodeIndices( type, num_nodes, mTargetDim, i, new_type, num_new_nodes, indices ); 00480 for( int j = 0; j < num_new_nodes; j++ ) 00481 sub_conn[j] = conn[indices[j]]; 00482 } 00483 result = thisMB->create_element( new_type, sub_conn, num_new_nodes, tmphndl ); 00484 assert( MB_SUCCESS == result ); 00485 add_adjacency( tmphndl, sub_conn, CN::VerticesPerEntity( new_type ) ); 00486 forward_target_entities.insert( tmphndl ); 00487 } 00488 // if there is a match, delete the matching entity 00489 // if we can. 00490 else 00491 { 00492 if( ( seek_iter = forward_target_entities.find( match ) ) != forward_target_entities.end() ) 00493 { 00494 forward_target_entities.erase( seek_iter ); 00495 remove_adjacency( match ); 00496 if( /*!use_adjs &&*/ entity_deletable( match ) ) 00497 { 00498 result = thisMB->delete_entities( &match, 1 ); 00499 assert( MB_SUCCESS == result ); 00500 } 00501 } 00502 else if( ( seek_iter = reverse_target_entities.find( match ) ) != reverse_target_entities.end() ) 00503 { 00504 reverse_target_entities.erase( seek_iter ); 00505 remove_adjacency( match ); 00506 if( /*!use_adjs &&*/ entity_deletable( match ) ) 00507 { 00508 result = thisMB->delete_entities( &match, 1 ); 00509 assert( MB_SUCCESS == result ); 00510 } 00511 } 00512 else 00513 { 00514 if( direct == FORWARD ) 00515 { 00516 forward_target_entities.insert( match ); 00517 } 00518 else 00519 { 00520 reverse_target_entities.insert( match ); 00521 } 00522 } 00523 } 00524 } 00525 } 00526 00527 deinitialize(); 00528 00529 return MB_SUCCESS; 00530 } 00531 00532 void Skinner::find_match( EntityType type, 00533 const EntityHandle* conn, 00534 const int num_nodes, 00535 EntityHandle& match, 00536 Skinner::direction& direct ) 00537 { 00538 match = 0; 00539 00540 if( type == MBVERTEX ) 00541 { 00542 match = *conn; 00543 direct = FORWARD; 00544 return; 00545 } 00546 00547 const EntityHandle* iter = std::min_element( conn, conn + num_nodes ); 00548 00549 std::vector< EntityHandle >* adj = NULL; 00550 00551 ErrorCode result = thisMB->tag_get_data( mAdjTag, iter, 1, &adj ); 00552 if( result == MB_FAILURE || adj == NULL ) 00553 { 00554 return; 00555 } 00556 00557 std::vector< EntityHandle >::iterator jter, end_jter; 00558 end_jter = adj->end(); 00559 00560 const EntityHandle* tmp; 00561 int num_verts; 00562 00563 for( jter = adj->begin(); jter != end_jter; ++jter ) 00564 { 00565 EntityType tmp_type; 00566 tmp_type = thisMB->type_from_handle( *jter ); 00567 00568 if( type != tmp_type ) continue; 00569 00570 result = thisMB->get_connectivity( *jter, tmp, num_verts, false ); 00571 assert( MB_SUCCESS == result && num_verts >= CN::VerticesPerEntity( type ) ); 00572 // FIXME: connectivity_match appears to work only for linear elements, 00573 // so ignore higher-order nodes. 00574 if( connectivity_match( conn, tmp, CN::VerticesPerEntity( type ), direct ) ) 00575 { 00576 match = *jter; 00577 break; 00578 } 00579 } 00580 } 00581 00582 bool Skinner::connectivity_match( const EntityHandle* conn1, 00583 const EntityHandle* conn2, 00584 const int num_verts, 00585 Skinner::direction& direct ) 00586 { 00587 const EntityHandle* iter = std::find( conn2, conn2 + num_verts, conn1[0] ); 00588 if( iter == conn2 + num_verts ) return false; 00589 00590 bool they_match = true; 00591 00592 int i; 00593 unsigned int j = iter - conn2; 00594 00595 // first compare forward 00596 for( i = 1; i < num_verts; ++i ) 00597 { 00598 if( conn1[i] != conn2[( j + i ) % num_verts] ) 00599 { 00600 they_match = false; 00601 break; 00602 } 00603 } 00604 00605 if( they_match == true ) 00606 { 00607 // need to check for reversed edges here 00608 direct = ( num_verts == 2 && j ) ? REVERSE : FORWARD; 00609 return true; 00610 } 00611 00612 they_match = true; 00613 00614 // then compare reverse 00615 j += num_verts; 00616 for( i = 1; i < num_verts; ) 00617 { 00618 if( conn1[i] != conn2[( j - i ) % num_verts] ) 00619 { 00620 they_match = false; 00621 break; 00622 } 00623 ++i; 00624 } 00625 if( they_match ) 00626 { 00627 direct = REVERSE; 00628 } 00629 return they_match; 00630 } 00631 00632 ErrorCode Skinner::remove_adjacency( EntityHandle entity ) 00633 { 00634 std::vector< EntityHandle > nodes, *adj = NULL; 00635 ErrorCode result = thisMB->get_connectivity( &entity, 1, nodes );MB_CHK_ERR( result ); 00636 std::vector< EntityHandle >::iterator iter = std::min_element( nodes.begin(), nodes.end() ); 00637 00638 if( iter == nodes.end() ) return MB_FAILURE; 00639 00640 // remove this entity from the node 00641 if( thisMB->tag_get_data( mAdjTag, &( *iter ), 1, &adj ) == MB_SUCCESS && adj != NULL ) 00642 { 00643 iter = std::find( adj->begin(), adj->end(), entity ); 00644 if( iter != adj->end() ) adj->erase( iter ); 00645 } 00646 00647 return result; 00648 } 00649 00650 bool Skinner::entity_deletable( EntityHandle entity ) 00651 { 00652 unsigned char deletable = 0; 00653 ErrorCode result = thisMB->tag_get_data( mDeletableMBTag, &entity, 1, &deletable ); 00654 assert( MB_SUCCESS == result ); 00655 if( MB_SUCCESS == result && deletable == 1 ) return false; 00656 return true; 00657 } 00658 00659 ErrorCode Skinner::classify_2d_boundary( const Range& boundary, 00660 const Range& bar_elements, 00661 EntityHandle boundary_edges, 00662 EntityHandle inferred_edges, 00663 EntityHandle non_manifold_edges, 00664 EntityHandle other_edges, 00665 int& number_boundary_nodes ) 00666 { 00667 Range bedges, iedges, nmedges, oedges; 00668 ErrorCode result = 00669 classify_2d_boundary( boundary, bar_elements, bedges, iedges, nmedges, oedges, number_boundary_nodes );MB_CHK_ERR( result ); 00670 00671 // now set the input meshsets to the output ranges 00672 result = thisMB->clear_meshset( &boundary_edges, 1 );MB_CHK_ERR( result ); 00673 result = thisMB->add_entities( boundary_edges, bedges );MB_CHK_ERR( result ); 00674 00675 result = thisMB->clear_meshset( &inferred_edges, 1 );MB_CHK_ERR( result ); 00676 result = thisMB->add_entities( inferred_edges, iedges );MB_CHK_ERR( result ); 00677 00678 result = thisMB->clear_meshset( &non_manifold_edges, 1 );MB_CHK_ERR( result ); 00679 result = thisMB->add_entities( non_manifold_edges, nmedges );MB_CHK_ERR( result ); 00680 00681 result = thisMB->clear_meshset( &other_edges, 1 );MB_CHK_ERR( result ); 00682 result = thisMB->add_entities( other_edges, oedges );MB_CHK_ERR( result ); 00683 00684 return MB_SUCCESS; 00685 } 00686 00687 ErrorCode Skinner::classify_2d_boundary( const Range& boundary, 00688 const Range& bar_elements, 00689 Range& boundary_edges, 00690 Range& inferred_edges, 00691 Range& non_manifold_edges, 00692 Range& other_edges, 00693 int& number_boundary_nodes ) 00694 { 00695 00696 // clear out the edge lists 00697 00698 boundary_edges.clear(); 00699 inferred_edges.clear(); 00700 non_manifold_edges.clear(); 00701 other_edges.clear(); 00702 00703 number_boundary_nodes = 0; 00704 00705 // make sure we have something to work with 00706 if( boundary.empty() ) 00707 { 00708 return MB_FAILURE; 00709 } 00710 00711 // get our working dimensions 00712 EntityType type = thisMB->type_from_handle( *( boundary.begin() ) ); 00713 const int source_dim = CN::Dimension( type ); 00714 00715 // make sure we can handle the working dimensions 00716 if( source_dim != 2 ) 00717 { 00718 return MB_FAILURE; 00719 } 00720 mTargetDim = source_dim - 1; 00721 00722 // initialize 00723 initialize(); 00724 00725 // additional initialization for this routine 00726 // define a tag for MBEDGE which counts the occurrences of the edge below 00727 // default should be 0 for existing edges, if any 00728 00729 Tag count_tag; 00730 int default_count = 0; 00731 ErrorCode result = 00732 thisMB->tag_get_handle( 0, 1, MB_TYPE_INTEGER, count_tag, MB_TAG_DENSE | MB_TAG_CREAT, &default_count );MB_CHK_ERR( result ); 00733 00734 Range::const_iterator iter, end_iter; 00735 end_iter = boundary.end(); 00736 00737 std::vector< EntityHandle > conn; 00738 EntityHandle sub_conn[2]; 00739 EntityHandle match; 00740 00741 Range edge_list; 00742 Range boundary_nodes; 00743 Skinner::direction direct; 00744 00745 EntityType sub_type; 00746 int num_edge, num_sub_ent_vert; 00747 const short* edge_verts; 00748 00749 // now, process each entity in the boundary 00750 00751 for( iter = boundary.begin(); iter != end_iter; ++iter ) 00752 { 00753 // get the connectivity of this entity 00754 conn.clear(); 00755 result = thisMB->get_connectivity( &( *iter ), 1, conn, false ); 00756 assert( MB_SUCCESS == result ); 00757 00758 // add node handles to boundary_node range 00759 std::copy( conn.begin(), conn.begin() + CN::VerticesPerEntity( type ), range_inserter( boundary_nodes ) ); 00760 00761 type = thisMB->type_from_handle( *iter ); 00762 00763 // get connectivity of each n-1 dimension entity (edge in this case) 00764 const struct CN::ConnMap* conn_map = &( CN::mConnectivityMap[type][0] ); 00765 num_edge = CN::NumSubEntities( type, 1 ); 00766 for( int i = 0; i < num_edge; i++ ) 00767 { 00768 edge_verts = CN::SubEntityVertexIndices( type, 1, i, sub_type, num_sub_ent_vert ); 00769 assert( sub_type == MBEDGE && num_sub_ent_vert == 2 ); 00770 sub_conn[0] = conn[edge_verts[0]]; 00771 sub_conn[1] = conn[edge_verts[1]]; 00772 int num_sub_nodes = conn_map->num_corners_per_sub_element[i]; 00773 00774 // see if we can match this connectivity with 00775 // an existing entity 00776 find_match( MBEDGE, sub_conn, num_sub_nodes, match, direct ); 00777 00778 // if there is no match, create a new entity 00779 if( match == 0 ) 00780 { 00781 EntityHandle tmphndl = 0; 00782 int indices[MAX_SUB_ENTITY_VERTICES]; 00783 EntityType new_type; 00784 int num_new_nodes; 00785 CN::SubEntityNodeIndices( type, conn.size(), 1, i, new_type, num_new_nodes, indices ); 00786 for( int j = 0; j < num_new_nodes; j++ ) 00787 sub_conn[j] = conn[indices[j]]; 00788 00789 result = thisMB->create_element( new_type, sub_conn, num_new_nodes, tmphndl ); 00790 assert( MB_SUCCESS == result ); 00791 add_adjacency( tmphndl, sub_conn, num_sub_nodes ); 00792 // target_entities.insert(tmphndl); 00793 edge_list.insert( tmphndl ); 00794 int count; 00795 result = thisMB->tag_get_data( count_tag, &tmphndl, 1, &count ); 00796 assert( MB_SUCCESS == result ); 00797 count++; 00798 result = thisMB->tag_set_data( count_tag, &tmphndl, 1, &count ); 00799 assert( MB_SUCCESS == result ); 00800 } 00801 else 00802 { 00803 // We found a match, we must increment the count on the match 00804 int count; 00805 result = thisMB->tag_get_data( count_tag, &match, 1, &count ); 00806 assert( MB_SUCCESS == result ); 00807 count++; 00808 result = thisMB->tag_set_data( count_tag, &match, 1, &count ); 00809 assert( MB_SUCCESS == result ); 00810 00811 // if the entity is not deletable, it was pre-existing in 00812 // the database. We therefore may need to add it to the 00813 // edge_list. Since it will not hurt the range, we add 00814 // whether it was added before or not 00815 if( !entity_deletable( match ) ) 00816 { 00817 edge_list.insert( match ); 00818 } 00819 } 00820 } 00821 } 00822 00823 // Any bar elements in the model should be classified separately 00824 // If the element is in the skin edge_list, then it should be put in 00825 // the non-manifold edge list. Edges not in the edge_list are stand-alone 00826 // bars, and we make them simply boundary elements 00827 00828 if( !bar_elements.empty() ) 00829 { 00830 Range::iterator bar_iter; 00831 for( iter = bar_elements.begin(); iter != bar_elements.end(); ++iter ) 00832 { 00833 EntityHandle handle = *iter; 00834 bar_iter = edge_list.find( handle ); 00835 if( bar_iter != edge_list.end() ) 00836 { 00837 // it is in the list, erase it and put in non-manifold list 00838 edge_list.erase( bar_iter ); 00839 non_manifold_edges.insert( handle ); 00840 } 00841 else 00842 { 00843 // not in the edge list, make it a boundary edge 00844 boundary_edges.insert( handle ); 00845 } 00846 } 00847 } 00848 00849 // now all edges should be classified. Go through the edge_list, 00850 // and put all in the appropriate lists 00851 00852 Range::iterator edge_iter, edge_end_iter; 00853 edge_end_iter = edge_list.end(); 00854 int count; 00855 for( edge_iter = edge_list.begin(); edge_iter != edge_end_iter; ++edge_iter ) 00856 { 00857 // check the count_tag 00858 result = thisMB->tag_get_data( count_tag, &( *edge_iter ), 1, &count ); 00859 assert( MB_SUCCESS == result ); 00860 if( count == 1 ) 00861 { 00862 boundary_edges.insert( *edge_iter ); 00863 } 00864 else if( count == 2 ) 00865 { 00866 other_edges.insert( *edge_iter ); 00867 } 00868 else 00869 { 00870 non_manifold_edges.insert( *edge_iter ); 00871 } 00872 } 00873 00874 // find the inferred edges from the other_edge_list 00875 00876 double min_angle_degrees = 20.0; 00877 find_inferred_edges( const_cast< Range& >( boundary ), other_edges, inferred_edges, min_angle_degrees ); 00878 00879 // we now want to remove the inferred_edges from the other_edges 00880 00881 Range temp_range; 00882 00883 std::set_difference( other_edges.begin(), other_edges.end(), inferred_edges.begin(), inferred_edges.end(), 00884 range_inserter( temp_range ), std::less< EntityHandle >() ); 00885 00886 other_edges = temp_range; 00887 00888 // get rid of count tag and deinitialize 00889 00890 result = thisMB->tag_delete( count_tag ); 00891 assert( MB_SUCCESS == result ); 00892 deinitialize(); 00893 00894 // set the node count 00895 number_boundary_nodes = boundary_nodes.size(); 00896 00897 return MB_SUCCESS; 00898 } 00899 00900 void Skinner::find_inferred_edges( Range& skin_boundary, 00901 Range& candidate_edges, 00902 Range& inferred_edges, 00903 double reference_angle_degrees ) 00904 { 00905 00906 // mark all the entities in the skin boundary 00907 Tag mark_tag; 00908 ErrorCode result = thisMB->tag_get_handle( 0, 1, MB_TYPE_BIT, mark_tag, MB_TAG_CREAT ); 00909 assert( MB_SUCCESS == result ); 00910 unsigned char bit = true; 00911 result = thisMB->tag_clear_data( mark_tag, skin_boundary, &bit ); 00912 assert( MB_SUCCESS == result ); 00913 00914 // find the cosine of the reference angle 00915 00916 double reference_cosine = cos( reference_angle_degrees * SKINNER_PI / 180.0 ); 00917 00918 // check all candidate edges for an angle greater than the minimum 00919 00920 Range::iterator iter, end_iter = candidate_edges.end(); 00921 std::vector< EntityHandle > adjacencies; 00922 std::vector< EntityHandle >::iterator adj_iter; 00923 EntityHandle face[2]; 00924 00925 for( iter = candidate_edges.begin(); iter != end_iter; ++iter ) 00926 { 00927 00928 // get the 2D elements connected to this edge 00929 adjacencies.clear(); 00930 result = thisMB->get_adjacencies( &( *iter ), 1, 2, false, adjacencies ); 00931 if( MB_SUCCESS != result ) continue; 00932 00933 // there should be exactly two, that is why the edge is classified as nonBoundary 00934 // and manifold 00935 00936 int faces_found = 0; 00937 for( adj_iter = adjacencies.begin(); adj_iter != adjacencies.end() && faces_found < 2; ++adj_iter ) 00938 { 00939 // we need to find two of these which are in the skin 00940 unsigned char is_marked = 0; 00941 result = thisMB->tag_get_data( mark_tag, &( *adj_iter ), 1, &is_marked ); 00942 assert( MB_SUCCESS == result ); 00943 if( is_marked ) 00944 { 00945 face[faces_found] = *adj_iter; 00946 faces_found++; 00947 } 00948 } 00949 00950 // assert(faces_found == 2 || faces_found == 0); 00951 if( 2 != faces_found ) continue; 00952 00953 // see if the two entities have a sufficient angle 00954 00955 if( has_larger_angle( face[0], face[1], reference_cosine ) ) 00956 { 00957 inferred_edges.insert( *iter ); 00958 } 00959 } 00960 00961 result = thisMB->tag_delete( mark_tag ); 00962 assert( MB_SUCCESS == result ); 00963 } 00964 00965 bool Skinner::has_larger_angle( EntityHandle& entity1, EntityHandle& entity2, double reference_angle_cosine ) 00966 { 00967 // compare normals to get angle. We assume that the surface quads 00968 // which we test here will be approximately planar 00969 00970 double norm[2][3]; 00971 Util::normal( thisMB, entity1, norm[0][0], norm[0][1], norm[0][2] ); 00972 Util::normal( thisMB, entity2, norm[1][0], norm[1][1], norm[1][2] ); 00973 00974 double cosine = norm[0][0] * norm[1][0] + norm[0][1] * norm[1][1] + norm[0][2] * norm[1][2]; 00975 00976 if( cosine < reference_angle_cosine ) 00977 { 00978 return true; 00979 } 00980 00981 return false; 00982 } 00983 00984 // get skin entities of prescribed dimension 00985 ErrorCode Skinner::find_skin( const EntityHandle this_set, 00986 const Range& entities, 00987 int dim, 00988 Range& skin_entities, 00989 bool create_vert_elem_adjs, 00990 bool create_skin_elements ) 00991 { 00992 Range tmp_skin; 00993 ErrorCode result = 00994 find_skin( this_set, entities, ( dim == 0 ), tmp_skin, 0, create_vert_elem_adjs, create_skin_elements ); 00995 if( MB_SUCCESS != result || tmp_skin.empty() ) return result; 00996 00997 if( tmp_skin.all_of_dimension( dim ) ) 00998 { 00999 if( skin_entities.empty() ) 01000 skin_entities.swap( tmp_skin ); 01001 else 01002 skin_entities.merge( tmp_skin ); 01003 } 01004 else 01005 { 01006 result = thisMB->get_adjacencies( tmp_skin, dim, create_skin_elements, skin_entities, Interface::UNION );MB_CHK_ERR( result ); 01007 if( this_set ) result = thisMB->add_entities( this_set, skin_entities ); 01008 } 01009 01010 return result; 01011 } 01012 01013 ErrorCode Skinner::find_skin_vertices( const EntityHandle this_set, 01014 const Range& entities, 01015 Range* skin_verts, 01016 Range* skin_elems, 01017 Range* skin_rev_elems, 01018 bool create_skin_elems, 01019 bool corners_only ) 01020 { 01021 ErrorCode rval; 01022 if( entities.empty() ) return MB_SUCCESS; 01023 01024 const int dim = CN::Dimension( TYPE_FROM_HANDLE( entities.front() ) ); 01025 if( dim < 1 || dim > 3 || !entities.all_of_dimension( dim ) ) return MB_TYPE_OUT_OF_RANGE; 01026 01027 // are we skinning all entities 01028 size_t count = entities.size(); 01029 int num_total; 01030 rval = thisMB->get_number_entities_by_dimension( this_set, dim, num_total ); 01031 if( MB_SUCCESS != rval ) return rval; 01032 bool all = ( count == (size_t)num_total ); 01033 01034 // Create a bit tag for fast intersection with input entities range. 01035 // If we're skinning all the entities in the mesh, we really don't 01036 // need the tag. To save memory, just create it with a default value 01037 // of one and don't set it. That way MOAB will return 1 for all 01038 // entities. 01039 Tag tag; 01040 char bit = all ? 1 : 0; 01041 rval = thisMB->tag_get_handle( NULL, 1, MB_TYPE_BIT, tag, MB_TAG_CREAT, &bit ); 01042 if( MB_SUCCESS != rval ) return rval; 01043 01044 // tag all entities in input range 01045 if( !all ) 01046 { 01047 std::vector< unsigned char > vect( count, 1 ); 01048 rval = thisMB->tag_set_data( tag, entities, &vect[0] ); 01049 if( MB_SUCCESS != rval ) 01050 { 01051 thisMB->tag_delete( tag ); 01052 return rval; 01053 } 01054 } 01055 01056 switch( dim ) 01057 { 01058 case 1: 01059 if( skin_verts ) 01060 rval = find_skin_vertices_1D( tag, entities, *skin_verts ); 01061 else if( skin_elems ) 01062 rval = find_skin_vertices_1D( tag, entities, *skin_elems ); 01063 else 01064 rval = MB_SUCCESS; 01065 break; 01066 case 2: 01067 rval = find_skin_vertices_2D( this_set, tag, entities, skin_verts, skin_elems, skin_rev_elems, 01068 create_skin_elems, corners_only ); 01069 break; 01070 case 3: 01071 rval = find_skin_vertices_3D( this_set, tag, entities, skin_verts, skin_elems, skin_rev_elems, 01072 create_skin_elems, corners_only ); 01073 break; 01074 default: 01075 rval = MB_TYPE_OUT_OF_RANGE; 01076 break; 01077 } 01078 01079 thisMB->tag_delete( tag ); 01080 return rval; 01081 } 01082 01083 ErrorCode Skinner::find_skin_vertices_1D( Tag tag, const Range& edges, Range& skin_verts ) 01084 { 01085 // This rather simple algorithm is provided for completeness 01086 // (not sure how often one really wants the 'skin' of a chain 01087 // or tangle of edges.) 01088 // 01089 // A vertex is on the skin of the edges if it is contained in exactly 01090 // one of the edges *in the input range*. 01091 // 01092 // This function expects the caller to have tagged all edges in the 01093 // input range with a value of one for the passed bit tag, and all 01094 // other edges with a value of zero. This allows us to do a faster 01095 // intersection with the input range and the edges adjacent to a vertex. 01096 01097 ErrorCode rval; 01098 Range::iterator hint = skin_verts.begin(); 01099 01100 // All input entities must be edges. 01101 if( !edges.all_of_dimension( 1 ) ) return MB_TYPE_OUT_OF_RANGE; 01102 01103 // get all the vertices 01104 Range verts; 01105 rval = thisMB->get_connectivity( edges, verts, true ); 01106 if( MB_SUCCESS != rval ) return rval; 01107 01108 // Test how many edges each input vertex is adjacent to. 01109 std::vector< char > tag_vals; 01110 std::vector< EntityHandle > adj; 01111 int n; 01112 for( Range::const_iterator it = verts.begin(); it != verts.end(); ++it ) 01113 { 01114 // get edges adjacent to vertex 01115 adj.clear(); 01116 rval = thisMB->get_adjacencies( &*it, 1, 1, false, adj ); 01117 if( MB_SUCCESS != rval ) return rval; 01118 if( adj.empty() ) continue; 01119 01120 // Intersect adjacent edges with the input list of edges 01121 tag_vals.resize( adj.size() ); 01122 rval = thisMB->tag_get_data( tag, &adj[0], adj.size(), &tag_vals[0] ); 01123 if( MB_SUCCESS != rval ) return rval; 01124 #ifdef MOAB_OLD_STD_COUNT 01125 n = 0; 01126 std::count( tag_vals.begin(), tag_vals.end(), '\001' ); 01127 #else 01128 n = std::count( tag_vals.begin(), tag_vals.end(), '\001' ); 01129 #endif 01130 // If adjacent to only one input edge, then vertex is on skin 01131 if( n == 1 ) 01132 { 01133 hint = skin_verts.insert( hint, *it ); 01134 } 01135 } 01136 01137 return MB_SUCCESS; 01138 } 01139 01140 // A Container for storing a list of element sides adjacent 01141 // to a vertex. The template parameter is the number of 01142 // corners for the side. 01143 template < unsigned CORNERS > 01144 class AdjSides 01145 { 01146 public: 01147 /** 01148 * This struct is used to for a reduced representation of element 01149 * "sides" adjacent to a give vertex. As such, it 01150 * a) does not store the initial vertex that all sides are adjacent to 01151 * b) orders the remaining vertices in a specific way for fast comparison. 01152 * 01153 * For edge elements, only the opposite vertex is stored. 01154 * For triangle elements, only the other two vertices are stored, 01155 * and they are stored with the smaller of those two handles first. 01156 * For quad elements, only the other three vertices are stored. 01157 * They are stored such that the vertex opposite the implicit (not 01158 * stored) vertex is always in slot 1. The other two vertices 01159 * (in slots 0 and 2) are ordered such that the handle of the one in 01160 * slot 0 is smaller than the handle in slot 2. 01161 * 01162 * For each side, the adj_elem field is used to store the element that 01163 * it is a side of as long as the element is considered to be on the skin. 01164 * The adj_elem field is cleared (set to zero) to indicate that this 01165 * side is no longer considered to be on the skin (and is the side of 01166 * more than one element.) 01167 */ 01168 struct Side 01169 { 01170 EntityHandle handles[CORNERS - 1]; //!< side vertices, except for implicit one 01171 EntityHandle adj_elem; //!< element that this is a side of, or zero 01172 bool skin() const 01173 { 01174 return 0 != adj_elem; 01175 } 01176 01177 /** construct from connectivity of side 01178 *\param array The connectivity of the element side. 01179 *\param idx The index of the implicit vertex (contained 01180 * in all sides in the list.) 01181 *\param adj The element that this is a side of. 01182 */ 01183 Side( const EntityHandle* array, int idx, EntityHandle adj, unsigned short ) : adj_elem( adj ) 01184 { 01185 switch( CORNERS ) 01186 { 01187 case 3: 01188 handles[1] = array[( idx + 2 ) % CORNERS]; 01189 // fall through 01190 case 2: 01191 if( 3 == CORNERS ) handles[1] = array[( idx + 2 ) % CORNERS]; 01192 if( 2 <= CORNERS ) handles[0] = array[( idx + 1 ) % CORNERS]; 01193 break; 01194 default: 01195 assert( false ); 01196 break; 01197 } 01198 if( CORNERS == 3 && handles[1] > handles[0] ) std::swap( handles[0], handles[1] ); 01199 } 01200 01201 /** construct from connectivity of parent element 01202 *\param array The connectivity of the parent element 01203 *\param idx The index of the implicit vertex (contained 01204 * in all sides in the list.) This is an index 01205 * into 'indices', not 'array'. 01206 *\param adj The element that this is a side of. 01207 *\param indices The indices into 'array' at which the vertices 01208 * representing the side occur. 01209 */ 01210 Side( const EntityHandle* array, int idx, EntityHandle adj, unsigned short, const short* indices ) 01211 : adj_elem( adj ) 01212 { 01213 switch( CORNERS ) 01214 { 01215 case 3: 01216 handles[1] = array[indices[( idx + 2 ) % CORNERS]]; 01217 // fall through 01218 case 2: 01219 if( 3 == CORNERS ) handles[1] = array[indices[( idx + 2 ) % CORNERS]]; 01220 if( 2 <= CORNERS ) handles[0] = array[indices[( idx + 1 ) % CORNERS]]; 01221 break; 01222 default: 01223 assert( false ); 01224 break; 01225 } 01226 if( CORNERS == 3 && handles[1] > handles[0] ) std::swap( handles[0], handles[1] ); 01227 } 01228 01229 // Compare two side instances. Relies in the ordering of 01230 // vertex handles as described above. 01231 bool operator==( const Side& other ) const 01232 { 01233 switch( CORNERS ) 01234 { 01235 case 3: 01236 return handles[0] == other.handles[0] && handles[1] == other.handles[1]; 01237 case 2: 01238 return handles[0] == other.handles[0]; 01239 default: 01240 assert( false ); 01241 return false; 01242 } 01243 } 01244 }; 01245 01246 private: 01247 std::vector< Side > data; //!< List of sides 01248 size_t skin_count; //!< Cached count of sides that are skin 01249 01250 public: 01251 typedef typename std::vector< Side >::iterator iterator; 01252 typedef typename std::vector< Side >::const_iterator const_iterator; 01253 const_iterator begin() const 01254 { 01255 return data.begin(); 01256 } 01257 const_iterator end() const 01258 { 01259 return data.end(); 01260 } 01261 01262 void clear() 01263 { 01264 data.clear(); 01265 skin_count = 0; 01266 } 01267 bool empty() const 01268 { 01269 return data.empty(); 01270 } 01271 01272 AdjSides() : skin_count( 0 ) {} 01273 01274 size_t num_skin() const 01275 { 01276 return skin_count; 01277 } 01278 01279 /** \brief insert side, specifying side connectivity 01280 * 01281 * Either insert a new side, or if the side is already in the 01282 * list, mark it as not on the skin. 01283 * 01284 *\param handles The connectivity of the element side. 01285 *\param skip_idx The index of the implicit vertex (contained 01286 * in all sides in the list.) 01287 *\param adj_elem The element that this is a side of. 01288 *\param elem_side Which side of adj_elem are we storing 01289 * (CN side number.) 01290 */ 01291 void insert( const EntityHandle* handles, int skip_idx, EntityHandle adj_elem, unsigned short elem_side ) 01292 { 01293 Side side( handles, skip_idx, adj_elem, elem_side ); 01294 iterator p = std::find( data.begin(), data.end(), side ); 01295 if( p == data.end() ) 01296 { 01297 data.push_back( side ); 01298 ++skin_count; // not in list yet, so skin side (so far) 01299 } 01300 else if( p->adj_elem ) 01301 { 01302 p->adj_elem = 0; // mark as not on skin 01303 --skin_count; // decrement cached count of skin elements 01304 } 01305 } 01306 01307 /** \brief insert side, specifying list of indices into parent element 01308 * connectivity. 01309 * 01310 * Either insert a new side, or if the side is already in the 01311 * list, mark it as not on the skin. 01312 * 01313 *\param handles The connectivity of the parent element 01314 *\param skip_idx The index of the implicit vertex (contained 01315 * in all sides in the list.) This is an index 01316 * into 'indices', not 'handles'. 01317 *\param adj_elem The element that this is a side of (parent handle). 01318 *\param indices The indices into 'handles' at which the vertices 01319 * representing the side occur. 01320 *\param elem_side Which side of adj_elem are we storing 01321 * (CN side number.) 01322 */ 01323 void insert( const EntityHandle* handles, 01324 int skip_idx, 01325 EntityHandle adj_elem, 01326 unsigned short elem_side, 01327 const short* indices ) 01328 { 01329 Side side( handles, skip_idx, adj_elem, elem_side, indices ); 01330 iterator p = std::find( data.begin(), data.end(), side ); 01331 if( p == data.end() ) 01332 { 01333 data.push_back( side ); 01334 ++skin_count; // not in list yet, so skin side (so far) 01335 } 01336 else if( p->adj_elem ) 01337 { 01338 p->adj_elem = 0; // mark as not on skin 01339 --skin_count; // decrement cached count of skin elements 01340 } 01341 } 01342 01343 /**\brief Search list for a given side, and if found, mark as not skin. 01344 * 01345 *\param other Connectivity of side 01346 *\param skip_index Index in 'other' at which implicit vertex occurs. 01347 *\param elem_out If return value is true, the element that the side is a 01348 * side of. If return value is false, not set. 01349 *\return true if found and marked not-skin, false if not found. 01350 * 01351 * Given the connectivity of some existing element, check if it occurs 01352 * in the list. If it does, clear the "is skin" state of the side so 01353 * that we know that we don't need to later create the side element. 01354 */ 01355 bool find_and_unmark( const EntityHandle* other, int skip_index, EntityHandle& elem_out ) 01356 { 01357 Side s( other, skip_index, 0, 0 ); 01358 iterator p = std::find( data.begin(), data.end(), s ); 01359 if( p == data.end() || !p->adj_elem ) 01360 return false; 01361 else 01362 { 01363 elem_out = p->adj_elem; 01364 p->adj_elem = 0; // clear "is skin" state for side 01365 --skin_count; // decrement cached count of skin sides 01366 return true; 01367 } 01368 } 01369 }; 01370 01371 /** construct from connectivity of side 01372 *\param array The connectivity of the element side. 01373 *\param idx The index of the implicit vertex (contained 01374 * in all sides in the list.) 01375 *\param adj The element that this is a side of. 01376 */ 01377 template <> 01378 AdjSides< 4 >::Side::Side( const EntityHandle* array, int idx, EntityHandle adj, unsigned short ) : adj_elem( adj ) 01379 { 01380 const unsigned int CORNERS = 4; 01381 handles[2] = array[( idx + 3 ) % CORNERS]; 01382 handles[1] = array[( idx + 2 ) % CORNERS]; 01383 handles[0] = array[( idx + 1 ) % CORNERS]; 01384 if( handles[2] > handles[0] ) std::swap( handles[0], handles[2] ); 01385 } 01386 01387 /** construct from connectivity of parent element 01388 *\param array The connectivity of the parent element 01389 *\param idx The index of the implicit vertex (contained 01390 * in all sides in the list.) This is an index 01391 * into 'indices', not 'array'. 01392 *\param adj The element that this is a side of. 01393 *\param indices The indices into 'array' at which the vertices 01394 * representing the side occur. 01395 */ 01396 template <> 01397 AdjSides< 4 >::Side::Side( const EntityHandle* array, int idx, EntityHandle adj, unsigned short, const short* indices ) 01398 : adj_elem( adj ) 01399 { 01400 const unsigned int CORNERS = 4; 01401 handles[2] = array[indices[( idx + 3 ) % CORNERS]]; 01402 handles[1] = array[indices[( idx + 2 ) % CORNERS]]; 01403 handles[0] = array[indices[( idx + 1 ) % CORNERS]]; 01404 if( handles[2] > handles[0] ) std::swap( handles[0], handles[2] ); 01405 } 01406 01407 // Compare two side instances. Relies in the ordering of 01408 // vertex handles as described above. 01409 template <> 01410 bool AdjSides< 4 >::Side::operator==( const Side& other ) const 01411 { 01412 return handles[0] == other.handles[0] && handles[1] == other.handles[1] && handles[2] == other.handles[2]; 01413 } 01414 01415 // Utility function used by find_skin_vertices_2D and 01416 // find_skin_vertices_3D to create elements representing 01417 // the skin side of a higher-dimension element if one 01418 // does not already exist. 01419 // 01420 // Some arguments may seem redundant, but they are used 01421 // to create the correct order of element when the input 01422 // element contains higher-order nodes. 01423 // 01424 // This function always creates elements that have a "forward" 01425 // orientation with respect to the parent element (have 01426 // nodes ordered the same as CN returns for the "side"). 01427 // 01428 // elem - The higher-dimension element for which to create 01429 // a lower-dim element representing the side. 01430 // side_type - The EntityType of the desired side. 01431 // side_conn - The connectivity of the new side. 01432 ErrorCode Skinner::create_side( const EntityHandle this_set, 01433 EntityHandle elem, 01434 EntityType side_type, 01435 const EntityHandle* side_conn, 01436 EntityHandle& side_elem ) 01437 { 01438 const int max_side = 9; 01439 const EntityHandle* conn; 01440 int len, side_len, side, sense, offset, indices[max_side]; 01441 ErrorCode rval; 01442 EntityType type = TYPE_FROM_HANDLE( elem ), tmp_type; 01443 const int ncorner = CN::VerticesPerEntity( side_type ); 01444 const int d = CN::Dimension( side_type ); 01445 std::vector< EntityHandle > storage; 01446 01447 // Get the connectivity of the parent element 01448 rval = thisMB->get_connectivity( elem, conn, len, false, &storage ); 01449 if( MB_SUCCESS != rval ) return rval; 01450 01451 // treat separately MBPOLYGON; we want to create the edge in the 01452 // forward sense always ; so figure out the sense first, then get out 01453 if( MBPOLYGON == type && 1 == d && MBEDGE == side_type ) 01454 { 01455 // first find the first vertex in the conn list 01456 int i = 0; 01457 for( i = 0; i < len; i++ ) 01458 { 01459 if( conn[i] == side_conn[0] ) break; 01460 } 01461 if( len == i ) return MB_FAILURE; // not found, big error 01462 // now, what if the polygon is padded? 01463 // the previous index is fine always. but the next one could be trouble :( 01464 int prevIndex = ( i + len - 1 ) % len; 01465 int nextIndex = ( i + 1 ) % len; 01466 // if the next index actually point to the same node, as current, it means it is padded 01467 if( conn[nextIndex] == conn[i] ) 01468 { 01469 // it really means we are at the end of proper nodes, the last nodes are repeated, so it 01470 // should be the first node 01471 nextIndex = 0; // this is the first node! 01472 } 01473 EntityHandle conn2[2] = { side_conn[0], side_conn[1] }; 01474 if( conn[prevIndex] == side_conn[1] ) 01475 { 01476 // reverse, so the edge will be forward 01477 conn2[0] = side_conn[1]; 01478 conn2[1] = side_conn[0]; 01479 } 01480 else if( conn[nextIndex] != side_conn[1] ) 01481 return MB_FAILURE; // it is not adjacent to the polygon 01482 01483 rval = thisMB->create_element( MBEDGE, conn2, 2, side_elem );MB_CHK_ERR( rval ); 01484 if( this_set ) 01485 { 01486 rval = thisMB->add_entities( this_set, &side_elem, 1 );MB_CHK_ERR( rval ); 01487 } 01488 return MB_SUCCESS; 01489 } 01490 // Find which side we are creating and get indices of all nodes 01491 // (including higher-order, if any.) 01492 CN::SideNumber( type, conn, side_conn, ncorner, d, side, sense, offset ); 01493 CN::SubEntityNodeIndices( type, len, d, side, tmp_type, side_len, indices ); 01494 assert( side_len <= max_side ); 01495 assert( side_type == tmp_type ); 01496 01497 // NOTE: re-create conn array even when no higher-order nodes 01498 // because we want it to always be forward with respect 01499 // to the side ordering. 01500 EntityHandle side_conn_full[max_side]; 01501 for( int i = 0; i < side_len; ++i ) 01502 side_conn_full[i] = conn[indices[i]]; 01503 01504 rval = thisMB->create_element( side_type, side_conn_full, side_len, side_elem );MB_CHK_ERR( rval ); 01505 if( this_set ) 01506 { 01507 rval = thisMB->add_entities( this_set, &side_elem, 1 );MB_CHK_ERR( rval ); 01508 } 01509 return MB_SUCCESS; 01510 ; 01511 } 01512 01513 // Test if an edge is reversed with respect CN's ordering 01514 // for the "side" of a face. 01515 bool Skinner::edge_reversed( EntityHandle face, const EntityHandle* edge_ends ) 01516 { 01517 const EntityHandle* conn; 01518 int len, idx; 01519 ErrorCode rval = thisMB->get_connectivity( face, conn, len, true ); 01520 if( MB_SUCCESS != rval ) 01521 { 01522 assert( false ); 01523 return false; 01524 } 01525 idx = std::find( conn, conn + len, edge_ends[0] ) - conn; 01526 if( idx == len ) 01527 { 01528 assert( false ); 01529 return false; 01530 } 01531 return ( edge_ends[1] == conn[( idx + len - 1 ) % len] ); 01532 } 01533 01534 // Test if a 2D element representing the side or face of a 01535 // volume element is reversed with respect to the CN node 01536 // ordering for the corresponding region element side. 01537 bool Skinner::face_reversed( EntityHandle region, const EntityHandle* face_corners, EntityType face_type ) 01538 { 01539 const EntityHandle* conn; 01540 int len, side, sense, offset; 01541 ErrorCode rval = thisMB->get_connectivity( region, conn, len, true ); 01542 if( MB_SUCCESS != rval ) 01543 { 01544 assert( false ); 01545 return false; 01546 } 01547 short r = CN::SideNumber( TYPE_FROM_HANDLE( region ), conn, face_corners, CN::VerticesPerEntity( face_type ), 01548 CN::Dimension( face_type ), side, sense, offset ); 01549 assert( 0 == r ); 01550 return ( !r && sense == -1 ); 01551 } 01552 01553 ErrorCode Skinner::find_skin_vertices_2D( const EntityHandle this_set, 01554 Tag tag, 01555 const Range& faces, 01556 Range* skin_verts, 01557 Range* skin_edges, 01558 Range* reversed_edges, 01559 bool create_edges, 01560 bool corners_only ) 01561 { 01562 // This function iterates over all the vertices contained in the 01563 // input face list. For each such vertex, it then iterates over 01564 // all of the sides of the face elements adjacent to the vertex. 01565 // If an adjacent side is the side of only one of the input 01566 // faces, then that side is on the skin. 01567 // 01568 // This algorithm will visit each skin vertex exactly once. It 01569 // will visit each skin side once for each vertex in the side. 01570 // 01571 // This function expects the caller to have created the passed bit 01572 // tag and set it to one only for the faces in the passed range. This 01573 // tag is used to do a fast intersection of the faces adjacent to a 01574 // vertex with the faces in the input range (discard any for which the 01575 // tag is not set to one.) 01576 01577 ErrorCode rval; 01578 std::vector< EntityHandle >::iterator i, j; 01579 Range::iterator hint; 01580 if( skin_verts ) hint = skin_verts->begin(); 01581 std::vector< EntityHandle > storage; 01582 const EntityHandle* conn; 01583 int len; 01584 bool find_edges = skin_edges || create_edges; 01585 bool printed_nonconformal_ho_warning = false; 01586 EntityHandle face; 01587 01588 if( !faces.all_of_dimension( 2 ) ) return MB_TYPE_OUT_OF_RANGE; 01589 01590 // get all the vertices 01591 Range verts; 01592 rval = thisMB->get_connectivity( faces, verts, true ); 01593 if( MB_SUCCESS != rval ) return rval; 01594 01595 std::vector< char > tag_vals; 01596 std::vector< EntityHandle > adj; 01597 AdjSides< 2 > adj_edges; 01598 for( Range::const_iterator it = verts.begin(); it != verts.end(); ++it ) 01599 { 01600 bool higher_order = false; 01601 01602 // get all adjacent faces 01603 adj.clear(); 01604 rval = thisMB->get_adjacencies( &*it, 1, 2, false, adj ); 01605 if( MB_SUCCESS != rval ) return rval; 01606 if( adj.empty() ) continue; 01607 01608 // remove those not in the input list (intersect with input list) 01609 i = j = adj.begin(); 01610 tag_vals.resize( adj.size() ); 01611 rval = thisMB->tag_get_data( tag, &adj[0], adj.size(), &tag_vals[0] ); 01612 if( MB_SUCCESS != rval ) return rval; 01613 // remove non-tagged entries 01614 i = j = adj.begin(); 01615 for( ; i != adj.end(); ++i ) 01616 if( tag_vals[i - adj.begin()] ) *( j++ ) = *i; 01617 adj.erase( j, adj.end() ); 01618 01619 // For each adjacent face, check the edges adjacent to the current vertex 01620 adj_edges.clear(); // other vertex for adjacent edges 01621 for( i = adj.begin(); i != adj.end(); ++i ) 01622 { 01623 rval = thisMB->get_connectivity( *i, conn, len, false, &storage ); 01624 if( MB_SUCCESS != rval ) return rval; 01625 01626 // For a single face element adjacent to this vertex, there 01627 // will be exactly two sides (edges) adjacent to the vertex. 01628 // Find the other vertex for each of the two edges. 01629 01630 EntityHandle prev, next; // vertices of two adjacent edge-sides 01631 const int idx = std::find( conn, conn + len, *it ) - conn; 01632 assert( idx != len ); 01633 01634 if( TYPE_FROM_HANDLE( *i ) == MBTRI && len > 3 ) 01635 { 01636 len = 3; 01637 higher_order = true; 01638 if( idx > 2 ) 01639 { // skip higher-order nodes for now 01640 if( !printed_nonconformal_ho_warning ) 01641 { 01642 printed_nonconformal_ho_warning = true; 01643 std::cerr << "Non-conformal higher-order mesh detected in skinner: " 01644 << "vertex " << ID_FROM_HANDLE( *it ) << " is a corner in " 01645 << "some elements and a higher-order node in others" << std::endl; 01646 } 01647 continue; 01648 } 01649 } 01650 else if( TYPE_FROM_HANDLE( *i ) == MBQUAD && len > 4 ) 01651 { 01652 len = 4; 01653 higher_order = true; 01654 if( idx > 3 ) 01655 { // skip higher-order nodes for now 01656 if( !printed_nonconformal_ho_warning ) 01657 { 01658 printed_nonconformal_ho_warning = true; 01659 std::cerr << "Non-conformal higher-order mesh detected in skinner: " 01660 << "vertex " << ID_FROM_HANDLE( *it ) << " is a corner in " 01661 << "some elements and a higher-order node in others" << std::endl; 01662 } 01663 continue; 01664 } 01665 } 01666 01667 // so it must be a MBPOLYGON 01668 const int prev_idx = ( idx + len - 1 ) % len; // this should be fine, always, even for padded case 01669 prev = conn[prev_idx]; 01670 next = conn[( idx + 1 ) % len]; 01671 if( next == conn[idx] ) // it must be the padded case, so roll to the beginning 01672 next = conn[0]; 01673 01674 // Insert sides (edges) in our list of candidate skin sides 01675 adj_edges.insert( &prev, 1, *i, prev_idx ); 01676 adj_edges.insert( &next, 1, *i, idx ); 01677 } 01678 01679 // If vertex is not on skin, advance to next vertex. 01680 // adj_edges handled checking for duplicates on insertion. 01681 // If every candidate skin edge occurred more than once (was 01682 // not in fact on the skin), then we're done with this vertex. 01683 if( 0 == adj_edges.num_skin() ) continue; 01684 01685 // If user requested Range of *vertices* on the skin... 01686 if( skin_verts ) 01687 { 01688 // Put skin vertex in output list 01689 hint = skin_verts->insert( hint, *it ); 01690 01691 // Add mid edge nodes to vertex list 01692 if( !corners_only && higher_order ) 01693 { 01694 for( AdjSides< 2 >::const_iterator p = adj_edges.begin(); p != adj_edges.end(); ++p ) 01695 { 01696 if( p->skin() ) 01697 { 01698 face = p->adj_elem; 01699 EntityType type = TYPE_FROM_HANDLE( face ); 01700 01701 rval = thisMB->get_connectivity( face, conn, len, false ); 01702 if( MB_SUCCESS != rval ) return rval; 01703 if( !CN::HasMidEdgeNodes( type, len ) ) continue; 01704 01705 EntityHandle ec[2] = { *it, p->handles[0] }; 01706 int side, sense, offset; 01707 CN::SideNumber( type, conn, ec, 2, 1, side, sense, offset ); 01708 offset = CN::HONodeIndex( type, len, 1, side ); 01709 assert( offset >= 0 && offset < len ); 01710 skin_verts->insert( conn[offset] ); 01711 } 01712 } 01713 } 01714 } 01715 01716 // If user requested Range of *edges* on the skin... 01717 if( find_edges ) 01718 { 01719 // Search list of existing adjacent edges for any that are on the skin 01720 adj.clear(); 01721 rval = thisMB->get_adjacencies( &*it, 1, 1, false, adj ); 01722 if( MB_SUCCESS != rval ) return rval; 01723 for( i = adj.begin(); i != adj.end(); ++i ) 01724 { 01725 rval = thisMB->get_connectivity( *i, conn, len, true ); 01726 if( MB_SUCCESS != rval ) return rval; 01727 01728 // bool equality expression within find_and_unmark call 01729 // will be evaluate to the index of *it in the conn array. 01730 // 01731 // Note that the order of the terms in the if statement is important. 01732 // We want to unmark any existing skin edges even if we aren't 01733 // returning them. Otherwise we'll end up creating duplicates 01734 // if create_edges is true and skin_edges is not. 01735 if( adj_edges.find_and_unmark( conn, ( conn[1] == *it ), face ) && skin_edges ) 01736 { 01737 if( reversed_edges && edge_reversed( face, conn ) ) 01738 reversed_edges->insert( *i ); 01739 else 01740 skin_edges->insert( *i ); 01741 } 01742 } 01743 } 01744 01745 // If the user requested that we create new edges for sides 01746 // on the skin for which there is no existing edge, and there 01747 // are still skin sides for which no corresponding edge was found... 01748 if( create_edges && adj_edges.num_skin() ) 01749 { 01750 // Create any skin edges that don't exist 01751 for( AdjSides< 2 >::const_iterator p = adj_edges.begin(); p != adj_edges.end(); ++p ) 01752 { 01753 if( p->skin() ) 01754 { 01755 EntityHandle edge, ec[] = { *it, p->handles[0] }; 01756 rval = create_side( this_set, p->adj_elem, MBEDGE, ec, edge ); 01757 if( MB_SUCCESS != rval ) return rval; 01758 if( skin_edges ) skin_edges->insert( edge ); 01759 } 01760 } 01761 } 01762 01763 } // end for each vertex 01764 01765 return MB_SUCCESS; 01766 } 01767 01768 ErrorCode Skinner::find_skin_vertices_3D( const EntityHandle this_set, 01769 Tag tag, 01770 const Range& entities, 01771 Range* skin_verts, 01772 Range* skin_faces, 01773 Range* reversed_faces, 01774 bool create_faces, 01775 bool corners_only ) 01776 { 01777 // This function iterates over all the vertices contained in the 01778 // input vol elem list. For each such vertex, it then iterates over 01779 // all of the sides of the vol elements adjacent to the vertex. 01780 // If an adjacent side is the side of only one of the input 01781 // elements, then that side is on the skin. 01782 // 01783 // This algorithm will visit each skin vertex exactly once. It 01784 // will visit each skin side once for each vertex in the side. 01785 // 01786 // This function expects the caller to have created the passed bit 01787 // tag and set it to one only for the elements in the passed range. This 01788 // tag is used to do a fast intersection of the elements adjacent to a 01789 // vertex with the elements in the input range (discard any for which the 01790 // tag is not set to one.) 01791 // 01792 // For each vertex, iterate over each adjacent element. Construct 01793 // lists of the sides of each adjacent element that contain the vertex. 01794 // 01795 // A list of three-vertex sides is kept for all triangular faces, 01796 // included three-vertex faces of type MBPOLYGON. Putting polygons 01797 // in the same list ensures that we find polyhedron and non-polyhedron 01798 // elements that are adjacent. 01799 // 01800 // A list of four-vertex sides is kept for all quadrilateral faces, 01801 // including four-vertex faces of type MBPOLYGON. 01802 // 01803 // Sides with more than four vertices must have an explicit MBPOLYGON 01804 // element representing them because MBPOLYHEDRON connectivity is a 01805 // list of faces rather than vertices. So the third list (vertices>=5), 01806 // need contain only the handle of the face rather than the vertex handles. 01807 01808 ErrorCode rval; 01809 std::vector< EntityHandle >::iterator i, j; 01810 Range::iterator hint; 01811 if( skin_verts ) hint = skin_verts->begin(); 01812 std::vector< EntityHandle > storage, storage2; // temp storage for conn lists 01813 const EntityHandle *conn, *conn2; 01814 int len, len2; 01815 bool find_faces = skin_faces || create_faces; 01816 int clen, side, sense, offset, indices[9]; 01817 EntityType face_type; 01818 EntityHandle elem; 01819 bool printed_nonconformal_ho_warning = false; 01820 01821 if( !entities.all_of_dimension( 3 ) ) return MB_TYPE_OUT_OF_RANGE; 01822 01823 // get all the vertices 01824 Range verts; 01825 rval = thisMB->get_connectivity( entities, verts, true ); 01826 if( MB_SUCCESS != rval ) return rval; 01827 // if there are polyhedra in the input list, need to make another 01828 // call to get vertices from faces 01829 if( !verts.all_of_dimension( 0 ) ) 01830 { 01831 Range::iterator it = verts.upper_bound( MBVERTEX ); 01832 Range pfaces; 01833 pfaces.merge( it, verts.end() ); 01834 verts.erase( it, verts.end() ); 01835 rval = thisMB->get_connectivity( pfaces, verts, true ); 01836 if( MB_SUCCESS != rval ) return rval; 01837 assert( verts.all_of_dimension( 0 ) ); 01838 } 01839 01840 AdjSides< 4 > adj_quads; // 4-node sides adjacent to a vertex 01841 AdjSides< 3 > adj_tris; // 3-node sides adjacent to a vertex 01842 AdjSides< 2 > adj_poly; // n-node sides (n>5) adjacent to vertex 01843 // (must have an explicit polygon, so store 01844 // polygon handle rather than vertices.) 01845 std::vector< char > tag_vals; 01846 std::vector< EntityHandle > adj; 01847 for( Range::const_iterator it = verts.begin(); it != verts.end(); ++it ) 01848 { 01849 bool higher_order = false; 01850 01851 // get all adjacent elements 01852 adj.clear(); 01853 rval = thisMB->get_adjacencies( &*it, 1, 3, false, adj ); 01854 if( MB_SUCCESS != rval ) return rval; 01855 if( adj.empty() ) continue; 01856 01857 // remove those not tagged (intersect with input range) 01858 i = j = adj.begin(); 01859 tag_vals.resize( adj.size() ); 01860 rval = thisMB->tag_get_data( tag, &adj[0], adj.size(), &tag_vals[0] ); 01861 if( MB_SUCCESS != rval ) return rval; 01862 for( ; i != adj.end(); ++i ) 01863 if( tag_vals[i - adj.begin()] ) *( j++ ) = *i; 01864 adj.erase( j, adj.end() ); 01865 01866 // Build lists of sides of 3D element adjacent to the current vertex 01867 adj_quads.clear(); // store three other vertices for each adjacent quad face 01868 adj_tris.clear(); // store two other vertices for each adjacent tri face 01869 adj_poly.clear(); // store handle of each adjacent polygonal face 01870 int idx; 01871 for( i = adj.begin(); i != adj.end(); ++i ) 01872 { 01873 const EntityType type = TYPE_FROM_HANDLE( *i ); 01874 01875 // Special case for POLYHEDRA 01876 if( type == MBPOLYHEDRON ) 01877 { 01878 rval = thisMB->get_connectivity( *i, conn, len ); 01879 if( MB_SUCCESS != rval ) return rval; 01880 for( int k = 0; k < len; ++k ) 01881 { 01882 rval = thisMB->get_connectivity( conn[k], conn2, len2, true, &storage2 ); 01883 if( MB_SUCCESS != rval ) return rval; 01884 idx = std::find( conn2, conn2 + len2, *it ) - conn2; 01885 if( idx == len2 ) // vertex not in this face 01886 continue; 01887 01888 // Treat 3- and 4-vertex faces specially, so that 01889 // if the mesh contains both elements and polyhedra, 01890 // we don't miss one type adjacent to the other. 01891 switch( len2 ) 01892 { 01893 case 3: 01894 adj_tris.insert( conn2, idx, *i, k ); 01895 break; 01896 case 4: 01897 adj_quads.insert( conn2, idx, *i, k ); 01898 break; 01899 default: 01900 adj_poly.insert( conn + k, 1, *i, k ); 01901 break; 01902 } 01903 } 01904 } 01905 else 01906 { 01907 rval = thisMB->get_connectivity( *i, conn, len, false, &storage ); 01908 if( MB_SUCCESS != rval ) return rval; 01909 01910 idx = std::find( conn, conn + len, *it ) - conn; 01911 assert( idx != len ); 01912 01913 if( len > CN::VerticesPerEntity( type ) ) 01914 { 01915 higher_order = true; 01916 // skip higher-order nodes for now 01917 if( idx >= CN::VerticesPerEntity( type ) ) 01918 { 01919 if( !printed_nonconformal_ho_warning ) 01920 { 01921 printed_nonconformal_ho_warning = true; 01922 std::cerr << "Non-conformal higher-order mesh detected in skinner: " 01923 << "vertex " << ID_FROM_HANDLE( *it ) << " is a corner in " 01924 << "some elements and a higher-order node in others" << std::endl; 01925 } 01926 continue; 01927 } 01928 } 01929 01930 // For each side of the element... 01931 const int num_faces = CN::NumSubEntities( type, 2 ); 01932 for( int f = 0; f < num_faces; ++f ) 01933 { 01934 int num_vtx; 01935 const short* face_indices = CN::SubEntityVertexIndices( type, 2, f, face_type, num_vtx ); 01936 const short face_idx = std::find( face_indices, face_indices + num_vtx, (short)idx ) - face_indices; 01937 // skip sides that do not contain vertex from outer loop 01938 if( face_idx == num_vtx ) continue; // current vertex not in this face 01939 01940 assert( num_vtx <= 4 ); // polyhedra handled above 01941 switch( face_type ) 01942 { 01943 case MBTRI: 01944 adj_tris.insert( conn, face_idx, *i, f, face_indices ); 01945 break; 01946 case MBQUAD: 01947 adj_quads.insert( conn, face_idx, *i, f, face_indices ); 01948 break; 01949 default: 01950 return MB_TYPE_OUT_OF_RANGE; 01951 } 01952 } 01953 } 01954 } // end for (adj[3]) 01955 01956 // If vertex is not on skin, advance to next vertex 01957 if( 0 == ( adj_tris.num_skin() + adj_quads.num_skin() + adj_poly.num_skin() ) ) continue; 01958 01959 // If user requested that skin *vertices* be passed back... 01960 if( skin_verts ) 01961 { 01962 // Put skin vertex in output list 01963 hint = skin_verts->insert( hint, *it ); 01964 01965 // Add mid-edge and mid-face nodes to vertex list 01966 if( !corners_only && higher_order ) 01967 { 01968 for( AdjSides< 3 >::const_iterator t = adj_tris.begin(); t != adj_tris.end(); ++t ) 01969 { 01970 if( t->skin() ) 01971 { 01972 elem = t->adj_elem; 01973 EntityType type = TYPE_FROM_HANDLE( elem ); 01974 01975 rval = thisMB->get_connectivity( elem, conn, len, false ); 01976 if( MB_SUCCESS != rval ) return rval; 01977 if( !CN::HasMidNodes( type, len ) ) continue; 01978 01979 EntityHandle ec[3] = { *it, t->handles[0], t->handles[1] }; 01980 CN::SideNumber( type, conn, ec, 3, 2, side, sense, offset ); 01981 CN::SubEntityNodeIndices( type, len, 2, side, face_type, clen, indices ); 01982 assert( MBTRI == face_type ); 01983 for( int k = 3; k < clen; ++k ) 01984 skin_verts->insert( conn[indices[k]] ); 01985 } 01986 } 01987 for( AdjSides< 4 >::const_iterator q = adj_quads.begin(); q != adj_quads.end(); ++q ) 01988 { 01989 if( q->skin() ) 01990 { 01991 elem = q->adj_elem; 01992 EntityType type = TYPE_FROM_HANDLE( elem ); 01993 01994 rval = thisMB->get_connectivity( elem, conn, len, false ); 01995 if( MB_SUCCESS != rval ) return rval; 01996 if( !CN::HasMidNodes( type, len ) ) continue; 01997 01998 EntityHandle ec[4] = { *it, q->handles[0], q->handles[1], q->handles[2] }; 01999 CN::SideNumber( type, conn, ec, 4, 2, side, sense, offset ); 02000 CN::SubEntityNodeIndices( type, len, 2, side, face_type, clen, indices ); 02001 assert( MBQUAD == face_type ); 02002 for( int k = 4; k < clen; ++k ) 02003 skin_verts->insert( conn[indices[k]] ); 02004 } 02005 } 02006 } 02007 } 02008 02009 // If user requested that we pass back the list of 2D elements 02010 // representing the skin of the mesh... 02011 if( find_faces ) 02012 { 02013 // Search list of adjacent faces for any that are on the skin 02014 adj.clear(); 02015 rval = thisMB->get_adjacencies( &*it, 1, 2, false, adj ); 02016 if( MB_SUCCESS != rval ) return rval; 02017 02018 for( i = adj.begin(); i != adj.end(); ++i ) 02019 { 02020 rval = thisMB->get_connectivity( *i, conn, len, true ); 02021 if( MB_SUCCESS != rval ) return rval; 02022 const int idx2 = std::find( conn, conn + len, *it ) - conn; 02023 if( idx2 >= len ) 02024 { 02025 assert( printed_nonconformal_ho_warning ); 02026 continue; 02027 } 02028 02029 // Note that the order of the terms in the if statements below 02030 // is important. We want to unmark any existing skin faces even 02031 // if we aren't returning them. Otherwise we'll end up creating 02032 // duplicates if create_faces is true. 02033 if( 3 == len ) 02034 { 02035 if( adj_tris.find_and_unmark( conn, idx2, elem ) && skin_faces ) 02036 { 02037 if( reversed_faces && face_reversed( elem, conn, MBTRI ) ) 02038 reversed_faces->insert( *i ); 02039 else 02040 skin_faces->insert( *i ); 02041 } 02042 } 02043 else if( 4 == len ) 02044 { 02045 if( adj_quads.find_and_unmark( conn, idx2, elem ) && skin_faces ) 02046 { 02047 if( reversed_faces && face_reversed( elem, conn, MBQUAD ) ) 02048 reversed_faces->insert( *i ); 02049 else 02050 skin_faces->insert( *i ); 02051 } 02052 } 02053 else 02054 { 02055 if( adj_poly.find_and_unmark( &*i, 1, elem ) && skin_faces ) skin_faces->insert( *i ); 02056 } 02057 } 02058 } 02059 02060 // If user does not want use to create new faces representing 02061 // sides for which there is currently no explicit element, 02062 // skip the remaining code and advance the outer loop to the 02063 // next vertex. 02064 if( !create_faces ) continue; 02065 02066 // Polyhedra always have explicitly defined faces, so 02067 // there is no way we could need to create such a face. 02068 assert( 0 == adj_poly.num_skin() ); 02069 02070 // Create any skin tris that don't exist 02071 if( adj_tris.num_skin() ) 02072 { 02073 for( AdjSides< 3 >::const_iterator t = adj_tris.begin(); t != adj_tris.end(); ++t ) 02074 { 02075 if( t->skin() ) 02076 { 02077 EntityHandle tri, c[3] = { *it, t->handles[0], t->handles[1] }; 02078 rval = create_side( this_set, t->adj_elem, MBTRI, c, tri ); 02079 if( MB_SUCCESS != rval ) return rval; 02080 if( skin_faces ) skin_faces->insert( tri ); 02081 } 02082 } 02083 } 02084 02085 // Create any skin quads that don't exist 02086 if( adj_quads.num_skin() ) 02087 { 02088 for( AdjSides< 4 >::const_iterator q = adj_quads.begin(); q != adj_quads.end(); ++q ) 02089 { 02090 if( q->skin() ) 02091 { 02092 EntityHandle quad, c[4] = { *it, q->handles[0], q->handles[1], q->handles[2] }; 02093 rval = create_side( this_set, q->adj_elem, MBQUAD, c, quad ); 02094 if( MB_SUCCESS != rval ) return rval; 02095 if( skin_faces ) skin_faces->insert( quad ); 02096 } 02097 } 02098 } 02099 } // end for each vertex 02100 02101 return MB_SUCCESS; 02102 } 02103 02104 } // namespace moab