![]() |
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 #include "moab/GeomTopoTool.hpp"
00017 #include "moab/GeomQueryTool.hpp"
00018 #include "moab/OrientedBoxTreeTool.hpp"
00019 #include "moab/Range.hpp"
00020 #include "MBTagConventions.hpp"
00021 #include "moab/Interface.hpp"
00022 #include "moab/CN.hpp"
00023 #include "moab/Skinner.hpp"
00024 #include "Internals.hpp"
00025 #include
00026
00027 namespace moab
00028 {
00029
00030 // Tag name used for saving sense of faces in volumes.
00031 // We assume that the surface occurs in at most two volumes.
00032 // Code will error out if more than two volumes per surface.
00033 // The tag data is a pair of tag handles, representing the
00034 // forward and reverse volumes, respectively. If a surface
00035 // is non-manifold in a single volume, the same volume will
00036 // be listed for both the forward and reverse slots.
00037 const char GEOM_SENSE_2_TAG_NAME[] = "GEOM_SENSE_2";
00038
00039 const char GEOM_SENSE_N_ENTS_TAG_NAME[] = "GEOM_SENSE_N_ENTS";
00040 const char GEOM_SENSE_N_SENSES_TAG_NAME[] = "GEOM_SENSE_N_SENSES";
00041 const char OBB_ROOT_TAG_NAME[] = "OBB_ROOT";
00042 const char OBB_GSET_TAG_NAME[] = "OBB_GSET";
00043
00044 const char IMPLICIT_COMPLEMENT_NAME[] = "impl_complement";
00045
00046 GeomTopoTool::GeomTopoTool( Interface* impl,
00047 bool find_geoments,
00048 EntityHandle modelRootSet,
00049 bool p_rootSets_vector,
00050 bool restore_rootSets )
00051 : mdbImpl( impl ), sense2Tag( 0 ), senseNEntsTag( 0 ), senseNSensesTag( 0 ), geomTag( 0 ), gidTag( 0 ),
00052 obbRootTag( 0 ), obbGsetTag( 0 ), modelSet( modelRootSet ), updated( false ), setOffset( 0 ),
00053 m_rootSets_vector( p_rootSets_vector ), oneVolRootSet( 0 )
00054 {
00055
00056 obbTree = new OrientedBoxTreeTool( impl, NULL, true );
00057
00058 ErrorCode rval =
00059 mdbImpl->tag_get_handle( GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, geomTag, MB_TAG_CREAT | MB_TAG_SPARSE );MB_CHK_SET_ERR_CONT( rval, "Error: Failed to create geometry dimension tag" );
00060
00061 // global id tag is not really needed, but mbsize complains if we do not set it for
00062 // geometry entities
00063 gidTag = mdbImpl->globalId_tag();
00064
00065 rval =
00066 mdbImpl->tag_get_handle( NAME_TAG_NAME, NAME_TAG_SIZE, MB_TYPE_OPAQUE, nameTag, MB_TAG_CREAT | MB_TAG_SPARSE );MB_CHK_SET_ERR_CONT( rval, "Error: Failed to create name tag" );
00067
00068 rval = mdbImpl->tag_get_handle( OBB_ROOT_TAG_NAME, 1, MB_TYPE_HANDLE, obbRootTag, MB_TAG_CREAT | MB_TAG_SPARSE );MB_CHK_SET_ERR_CONT( rval, "Error: Failed to create obb root tag" );
00069
00070 rval = mdbImpl->tag_get_handle( OBB_GSET_TAG_NAME, 1, MB_TYPE_HANDLE, obbGsetTag, MB_TAG_CREAT | MB_TAG_SPARSE );MB_CHK_SET_ERR_CONT( rval, "Error: Failed to create obb gset tag" );
00071
00072 // set this value to zero for comparisons
00073 impl_compl_handle = 0;
00074
00075 maxGlobalId[0] = maxGlobalId[1] = maxGlobalId[2] = maxGlobalId[3] = maxGlobalId[4] = 0;
00076 if( find_geoments )
00077 {
00078 find_geomsets();
00079 if( restore_rootSets )
00080 {
00081 rval = restore_obb_index();
00082 if( MB_SUCCESS != rval )
00083 {
00084 rval = delete_all_obb_trees();MB_CHK_SET_ERR_CONT( rval, "Error: Failed to delete existing obb trees" );
00085 rval = construct_obb_trees();MB_CHK_SET_ERR_CONT( rval, "Error: Failed to rebuild obb trees" );
00086 }
00087 }
00088 }
00089 }
00090
00091 GeomTopoTool::~GeomTopoTool()
00092 {
00093 delete obbTree;
00094 }
00095
00096 int GeomTopoTool::dimension( EntityHandle this_set )
00097 {
00098 ErrorCode result;
00099 if( 0 == geomTag )
00100 {
00101 result = mdbImpl->tag_get_handle( GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, geomTag );MB_CHK_SET_ERR( result, "Failed to get the geometry dimension tag" );
00102 }
00103
00104 // check if the geo set belongs to this model
00105 if( modelSet )
00106 {
00107 if( !mdbImpl->contains_entities( modelSet, &this_set, 1 ) )
00108 {
00109 // this g set does not belong to the current model
00110 return -1;
00111 }
00112 }
00113 // get the data for those tags
00114 int dim;
00115 result = mdbImpl->tag_get_data( geomTag, &this_set, 1, &dim );
00116 if( MB_SUCCESS != result ) return -1;
00117 else return dim;
00118 }
00119
00120 int GeomTopoTool::global_id( EntityHandle this_set )
00121 {
00122 ErrorCode result;
00123 if( 0 == gidTag )
00124 {
00125 gidTag = mdbImpl->globalId_tag();
00126 }
00127
00128 // check if the geo set belongs to this model
00129 if( modelSet )
00130 {
00131 if( !mdbImpl->contains_entities( modelSet, &this_set, 1 ) )
00132 {
00133 // this g set does not belong to the current model
00134 return -1;
00135 }
00136 }
00137
00138 // get the data for those tags
00139 int id;
00140 result = mdbImpl->tag_get_data( gidTag, &this_set, 1, &id );
00141 if( MB_SUCCESS != result ) return -1;
00142 else return id;
00143 }
00144
00145 EntityHandle GeomTopoTool::entity_by_id( int dimension1, int id )
00146 {
00147 if( 0 > dimension1 || 3 < dimension1 )
00148 {
00149 MB_CHK_SET_ERR_CONT( MB_FAILURE, "Incorrect dimension provided" );
00150 }
00151 const Tag tags[] = { gidTag, geomTag };
00152 const void* const vals[] = { &id, &dimension1 };
00153 ErrorCode rval;
00154
00155 Range results;
00156 rval = mdbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET, tags, vals, 2, results );
00157
00158 if( MB_SUCCESS != rval ) return 0;
00159 else return results.front();
00160 }
00161
00162 ErrorCode GeomTopoTool::other_entity( EntityHandle bounded,
00163 EntityHandle not_this,
00164 EntityHandle across,
00165 EntityHandle& other )
00166 {
00167 other = 0;
00168
00169 // get all children of bounded
00170 Range bdy, tmpr;
00171 ErrorCode rval = mdbImpl->get_child_meshsets( bounded, bdy );MB_CHK_SET_ERR( rval, "Failed to get the bounded entity's child meshsets" );
00172
00173 // get all the parents of across
00174 rval = mdbImpl->get_parent_meshsets( across, tmpr );
00175
00176 // possible candidates is the intersection
00177 bdy = intersect( bdy, tmpr );
00178
00179 // if only two, choose the other
00180 if( 1 == bdy.size() && *bdy.begin() == not_this )
00181 {
00182 return MB_SUCCESS;
00183 }
00184 else if( 2 == bdy.size() )
00185 {
00186 if( *bdy.begin() == not_this ) other = *bdy.rbegin();
00187 if( *bdy.rbegin() == not_this )
00188 other = *bdy.begin();
00189 else
00190 return MB_FAILURE;
00191 }
00192 else
00193 {
00194 return MB_FAILURE;
00195 }
00196
00197 return MB_SUCCESS;
00198 }
00199
00200 ErrorCode GeomTopoTool::restore_obb_index()
00201 {
00202
00203 if( m_rootSets_vector ) resize_rootSets();
00204
00205 ErrorCode rval;
00206 EntityHandle root;
00207
00208 for( int dim = 2; dim <= 3; dim++ )
00209 for( Range::iterator rit = geomRanges[dim].begin(); rit != geomRanges[dim].end(); ++rit )
00210 {
00211 rval = mdbImpl->tag_get_data( obbRootTag, &( *rit ), 1, &root );
00212
00213 if( MB_SUCCESS == rval )
00214 set_root_set( *rit, root );
00215 else
00216 {
00217 return MB_TAG_NOT_FOUND;
00218 }
00219 }
00220
00221 return MB_SUCCESS;
00222 }
00223
00224 ErrorCode GeomTopoTool::find_geomsets( Range* ranges )
00225 {
00226 ErrorCode rval;
00227 // get all sets with this tag
00228 Range geom_sets;
00229
00230 if( 0 == geomTag )
00231 {
00232 rval = mdbImpl->tag_get_handle( GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, geomTag );MB_CHK_SET_ERR( rval, "Failed to get geom dimension tag handle" );
00233 }
00234
00235 rval = mdbImpl->get_entities_by_type_and_tag( modelSet, MBENTITYSET, &geomTag, NULL, 1, geom_sets );MB_CHK_SET_ERR( rval, "Failed to get the geometry entities" );
00236
00237 rval = separate_by_dimension( geom_sets );MB_CHK_SET_ERR( rval, "Failed to separate geometry sets by dimension" );
00238
00239 if( ranges )
00240 {
00241 for( int i = 0; i < 5; i++ )
00242 {
00243 ranges[i] = geomRanges[i];
00244 }
00245 }
00246
00247 return MB_SUCCESS;
00248 }
00249
00250 ErrorCode GeomTopoTool::get_gsets_by_dimension( int dim, Range& gset )
00251 {
00252 ErrorCode rval;
00253
00254 const int val = dim;
00255 const void* const dim_val[] = { &val };
00256 rval = mdbImpl->get_entities_by_type_and_tag( modelSet, MBENTITYSET, &geomTag, dim_val, 1, gset );MB_CHK_SET_ERR( rval, "Failed to get entity set by type and tag" );
00257
00258 return MB_SUCCESS;
00259 }
00260
00261 ErrorCode GeomTopoTool::resize_rootSets()
00262 {
00263
00264 ErrorCode rval;
00265
00266 // store original offset for later
00267 EntityHandle orig_offset = setOffset;
00268
00269 // get all surfaces and volumes
00270 Range surfs, vols;
00271 rval = get_gsets_by_dimension( 2, surfs );MB_CHK_SET_ERR( rval, "Could not get surface sets" );
00272 rval = get_gsets_by_dimension( 3, vols );MB_CHK_SET_ERR( rval, "Could not get volume sets" );
00273
00274 // check the vector size
00275 Range surfs_and_vols;
00276 surfs_and_vols = vols;
00277 surfs_and_vols.merge( surfs );
00278
00279 // update the setOffset
00280 setOffset = surfs_and_vols.front();
00281
00282 EntityHandle exp_size = surfs_and_vols.back() - setOffset + 1;
00283
00284 // if new EnitytHandle(s) are lower than the original offset
00285 if( setOffset < orig_offset )
00286 {
00287 // insert empty values at the beginning of the vector
00288 rootSets.insert( rootSets.begin(), orig_offset - setOffset, 0 );
00289 }
00290
00291 if( exp_size != rootSets.size() )
00292 {
00293 // resize rootSets vector if necessary (new space will be added at the back)
00294 rootSets.resize( exp_size );
00295 }
00296
00297 return MB_SUCCESS;
00298 }
00299
00300 ErrorCode GeomTopoTool::is_owned_set( EntityHandle eh )
00301 {
00302 // make sure entity set is part of the model
00303 Range model_ents;
00304 ErrorCode rval = mdbImpl->get_entities_by_handle( modelSet, model_ents );MB_CHK_SET_ERR( rval, "Failed to get entities" );
00305 if( model_ents.find( eh ) == model_ents.end() )
00306 {
00307 MB_SET_ERR( MB_FAILURE, "Entity handle not in model set" );
00308 }
00309 return MB_SUCCESS;
00310 }
00311
00312 ErrorCode GeomTopoTool::delete_obb_tree( EntityHandle gset, bool vol_only )
00313 {
00314
00315 ErrorCode rval;
00316
00317 // Make sure this set is part of the model
00318 rval = is_owned_set( gset );MB_CHK_SET_ERR( rval, "Entity set is not part of this model" );
00319
00320 // Find the dimension of the entity
00321 int dim;
00322 rval = mdbImpl->tag_get_data( geomTag, &gset, 1, &dim );MB_CHK_SET_ERR( rval, "Failed to get dimension" );
00323
00324 // Attempt to find a root for this set
00325 EntityHandle root;
00326 rval = get_root( gset, root );MB_CHK_SET_ERR( rval, "Failed to find an obb tree root for the entity set" );
00327
00328 // Create range of tree nodes to delete
00329 Range nodes_to_delete;
00330 nodes_to_delete.insert( root );
00331
00332 // If passed ent is a vol and 'vol_only' is true, delete vol root and all nodes between vol and
00333 // surf root
00334 if( dim == 3 && vol_only )
00335 {
00336 // Range of child nodes to check before adding to delete list
00337 Range child_tree_nodes;
00338 rval = mdbImpl->get_child_meshsets( root, child_tree_nodes );MB_CHK_SET_ERR( rval, "Problem getting child tree nodes" );
00339
00340 // Traverse the tree, checking each child node until
00341 // a surface root node is reached
00342 while( child_tree_nodes.size() != 0 )
00343 {
00344 EntityHandle child = *child_tree_nodes.begin();
00345 EntityHandle surf;
00346 rval = mdbImpl->tag_get_data( obbGsetTag, &child, 1, &surf );
00347 // If the node has a gset tag, it is a surf root. Stop here.
00348 // If not, it is a tree node that needs to 1) have its children checked and
00349 // 2) be added to delete range
00350 if( MB_TAG_NOT_FOUND == rval )
00351 {
00352 Range new_child_tree_nodes;
00353 rval = mdbImpl->get_child_meshsets( child, new_child_tree_nodes );MB_CHK_SET_ERR( rval, "Problem getting child nodes" );
00354 child_tree_nodes.insert_list( new_child_tree_nodes.begin(), new_child_tree_nodes.end() );
00355 nodes_to_delete.insert( child );
00356 }
00357 // We're done checking this node, so can erase from child list
00358 child_tree_nodes.erase( child );
00359 }
00360 }
00361 // If passed ent is a surf or a vol and 'vol_only' is false, recursively gather all child nodes
00362 // and add them to delete list
00363 else
00364 {
00365 Range all_tree_nodes;
00366 rval = mdbImpl->get_child_meshsets( root, all_tree_nodes, 0 );MB_CHK_SET_ERR( rval, "Failed to get child tree node sets" );
00367 nodes_to_delete.insert_list( all_tree_nodes.begin(), all_tree_nodes.end() );
00368 }
00369
00370 // Remove the root nodes from the GTT data structures
00371 for( Range::iterator it = nodes_to_delete.begin(); it != nodes_to_delete.end(); ++it )
00372 {
00373 // Check to see if node is a root
00374 EntityHandle vol_or_surf;
00375 rval = mdbImpl->tag_get_data( obbGsetTag, &( *it ), 1, &vol_or_surf );
00376 if( MB_SUCCESS == rval )
00377 {
00378 // Remove from set of all roots
00379 rval = remove_root( vol_or_surf );MB_CHK_SET_ERR( rval, "Failed to remove node from GTT data structure" );
00380 }
00381 }
00382
00383 // Delete the tree nodes from the database
00384 rval = mdbImpl->delete_entities( nodes_to_delete );MB_CHK_SET_ERR( rval, "Failed to delete node set" );
00385
00386 return MB_SUCCESS;
00387 }
00388
00389 ErrorCode GeomTopoTool::delete_all_obb_trees()
00390 {
00391
00392 ErrorCode rval;
00393
00394 for( Range::iterator rit = geomRanges[3].begin(); rit != geomRanges[3].end(); ++rit )
00395 {
00396 EntityHandle root;
00397 rval = mdbImpl->tag_get_data( obbRootTag, &( *rit ), 1, &root );
00398 if( MB_SUCCESS == rval )
00399 {
00400 rval = delete_obb_tree( *rit, false );MB_CHK_SET_ERR( rval, "Failed to delete obb tree" );
00401 }
00402 }
00403
00404 return MB_SUCCESS;
00405 }
00406
00407 ErrorCode GeomTopoTool::construct_obb_tree( EntityHandle eh )
00408 {
00409 ErrorCode rval;
00410 int dim;
00411
00412 rval = is_owned_set( eh );MB_CHK_SET_ERR( rval, "Entity set is not part of this model" );
00413
00414 // get the type
00415 EntityType type = mdbImpl->type_from_handle( eh );
00416
00417 // find the dimension of the entity
00418 rval = mdbImpl->tag_get_data( geomTag, &eh, 1, &dim );MB_CHK_SET_ERR( rval, "Failed to get dimension" );
00419
00420 // ensure that the rootSets vector is of the correct size
00421 if( m_rootSets_vector && ( eh < setOffset || eh >= setOffset + rootSets.size() ) )
00422 {
00423 rval = resize_rootSets();MB_CHK_SET_ERR( rval, "Error setting offset and sizing rootSets vector." );
00424 }
00425
00426 EntityHandle root;
00427 // if it's a surface
00428 if( dim == 2 && type == MBENTITYSET )
00429 {
00430 rval = get_root( eh, root );
00431 if( MB_SUCCESS == rval )
00432 {
00433 std::cerr << "Surface obb tree already exists" << std::endl;
00434 return MB_SUCCESS;
00435 }
00436 else if( MB_INDEX_OUT_OF_RANGE != rval )
00437 {
00438 MB_CHK_SET_ERR( rval, "Failed to get surface obb tree root" );
00439 }
00440
00441 Range tris;
00442 rval = mdbImpl->get_entities_by_dimension( eh, 2, tris );MB_CHK_SET_ERR( rval, "Failed to get entities by dimension" );
00443
00444 if( tris.empty() )
00445 {
00446 std::cerr << "WARNING: Surface has no facets" << std::endl;
00447 }
00448
00449 rval = obbTree->build( tris, root );MB_CHK_SET_ERR( rval, "Failed to build obb Tree for surface" );
00450
00451 rval = mdbImpl->add_entities( root, &eh, 1 );MB_CHK_SET_ERR( rval, "Failed to add entities to root set" );
00452
00453 // add this root to the GeomTopoTool tree root indexing
00454 set_root_set( eh, root );
00455
00456 // if just building tree for surface, return here
00457 return MB_SUCCESS;
00458 }
00459 // if it's a volume
00460 else if( dim == 3 && type == MBENTITYSET )
00461 {
00462 // get its surfaces
00463 Range tmp_surfs, surf_trees;
00464 rval = mdbImpl->get_child_meshsets( eh, tmp_surfs );MB_CHK_SET_ERR( rval, "Failed to get surface meshsets" );
00465
00466 // get OBB trees or create for each surface
00467 for( Range::iterator j = tmp_surfs.begin(); j != tmp_surfs.end(); ++j )
00468 {
00469 rval = get_root( *j, root );
00470 // if root doesn't exist, create obb tree
00471 if( MB_INDEX_OUT_OF_RANGE == rval )
00472 {
00473 rval = construct_obb_tree( *j );MB_CHK_SET_ERR( rval, "Failed to get create surface obb tree" );
00474 rval = get_root( *j, root );MB_CHK_SET_ERR( rval, "Failed to get surface obb tree root" );
00475 }
00476 else
00477 {
00478 MB_CHK_SET_ERR( rval, "Failed to get surface obb tree root" );
00479 }
00480
00481 surf_trees.insert( root );
00482 }
00483
00484 // build OBB tree for volume
00485 rval = obbTree->join_trees( surf_trees, root );MB_CHK_SET_ERR( rval, "Failed to join the obb trees" );
00486
00487 // add this root to the GeomTopoTool tree root indexing
00488 set_root_set( eh, root );
00489
00490 return MB_SUCCESS;
00491 }
00492 else
00493 {
00494 MB_SET_ERR( MB_FAILURE, "Improper dimension or type for constructing obb tree" );
00495 }
00496 }
00497
00498 ErrorCode GeomTopoTool::set_root_set( EntityHandle vol_or_surf, EntityHandle root )
00499 {
00500
00501 // Tag the vol or surf with its obb root (obbRootTag)
00502 ErrorCode rval;
00503 rval = mdbImpl->tag_set_data( obbRootTag, &vol_or_surf, 1, &root );MB_CHK_SET_ERR( rval, "Failed to set the obb root tag" );
00504
00505 // Tag obb root with corresponding gset (obbGsetTag)
00506 rval = mdbImpl->tag_set_data( obbGsetTag, &root, 1, &vol_or_surf );MB_CHK_SET_ERR( rval, "Failed to set the obb gset tag" );
00507
00508 // Add to the set of all roots
00509 if( m_rootSets_vector )
00510 rootSets[vol_or_surf - setOffset] = root;
00511 else
00512 mapRootSets[vol_or_surf] = root;
00513
00514 return MB_SUCCESS;
00515 }
00516
00517 ErrorCode GeomTopoTool::remove_root( EntityHandle vol_or_surf )
00518 {
00519
00520 // Find the root of the vol or surf
00521 ErrorCode rval;
00522 EntityHandle root;
00523 rval = mdbImpl->tag_get_data( obbRootTag, &( vol_or_surf ), 1, &root );MB_CHK_SET_ERR( rval, "Failed to get obb root tag" );
00524
00525 // If the ent is a vol, remove its root from obbtreetool
00526 int dim;
00527 rval = mdbImpl->tag_get_data( geomTag, &vol_or_surf, 1, &dim );MB_CHK_SET_ERR( rval, "Failed to get dimension" );
00528 if( dim == 3 )
00529 {
00530 rval = obbTree->remove_root( root );MB_CHK_SET_ERR( rval, "Failed to remove root from obbTreeTool" );
00531 }
00532
00533 // Delete the obbGsetTag data from the root
00534 rval = mdbImpl->tag_delete_data( obbGsetTag, &root, 1 );MB_CHK_SET_ERR( rval, "Failed to delete obb root tag" );
00535
00536 // Delete the obbRootTag data from the vol or surf
00537 rval = mdbImpl->tag_delete_data( obbRootTag, &vol_or_surf, 1 );MB_CHK_SET_ERR( rval, "Failed to delete obb root tag" );
00538
00539 // Remove the root from set of all roots
00540 if( m_rootSets_vector )
00541 {
00542 unsigned int index = vol_or_surf - setOffset;
00543 if( index < rootSets.size() )
00544 {
00545 rootSets[index] = 0;
00546 }
00547 else
00548 {
00549 return MB_INDEX_OUT_OF_RANGE;
00550 }
00551 }
00552 else
00553 {
00554 mapRootSets[vol_or_surf] = 0;
00555 }
00556
00557 return MB_SUCCESS;
00558 }
00559
00560 ErrorCode GeomTopoTool::construct_obb_trees( bool make_one_vol )
00561 {
00562 ErrorCode rval;
00563 EntityHandle root;
00564
00565 // get all surfaces and volumes
00566 Range surfs, vols, vol_trees;
00567 rval = get_gsets_by_dimension( 2, surfs );MB_CHK_SET_ERR( rval, "Could not get surface sets" );
00568 rval = get_gsets_by_dimension( 3, vols );MB_CHK_SET_ERR( rval, "Could not get volume sets" );
00569
00570 // for surface
00571 Range one_vol_trees;
00572 for( Range::iterator i = surfs.begin(); i != surfs.end(); ++i )
00573 {
00574 rval = construct_obb_tree( *i );MB_CHK_SET_ERR( rval, "Failed to construct obb tree for surface" );
00575 // get the root set of this volume
00576 rval = get_root( *i, root );MB_CHK_SET_ERR( rval, "Failed to get obb tree root for surface" );
00577 // add to the Range of volume root sets
00578 one_vol_trees.insert( root );
00579 }
00580
00581 // for volumes
00582 for( Range::iterator i = vols.begin(); i != vols.end(); ++i )
00583 {
00584 // create tree for this volume
00585 rval = construct_obb_tree( *i );MB_CHK_SET_ERR( rval, "Failed to construct obb tree for volume" );
00586 }
00587
00588 // build OBB tree for volume
00589 if( make_one_vol )
00590 {
00591 rval = obbTree->join_trees( one_vol_trees, root );MB_CHK_SET_ERR( rval, "Failed to join surface trees into one volume" );
00592 oneVolRootSet = root;
00593 }
00594
00595 return rval;
00596 }
00597
00598 //! Restore parent/child links between GEOM_TOPO mesh sets
00599 ErrorCode GeomTopoTool::restore_topology_from_adjacency()
00600 {
00601
00602 // look for geometric topology sets and restore parent/child links between them
00603 // algorithm:
00604 // - for each entity of dimension d=D-1..0:
00605 // . get d-dimensional entity in entity
00606 // . get all (d+1)-dim adjs to that entity
00607 // . for each geom entity if dim d+1, if it contains any of the ents,
00608 // add it to list of parents
00609 // . make parent/child links with parents
00610
00611 // the geomRanges are already known, separated by dimension
00612
00613 std::vector< EntityHandle > parents;
00614 Range tmp_parents;
00615 ErrorCode result;
00616
00617 // loop over dimensions
00618 for( int dim = 2; dim >= 0; dim-- )
00619 {
00620 // mark entities of next higher dimension with their owners; regenerate tag
00621 // each dimension so prev dim's tag data goes away
00622 Tag owner_tag;
00623 EntityHandle dum_val = 0;
00624 result = mdbImpl->tag_get_handle( "__owner_tag", 1, MB_TYPE_HANDLE, owner_tag, MB_TAG_DENSE | MB_TAG_CREAT,
00625 &dum_val );
00626 if( MB_SUCCESS != result ) continue;
00627 Range dp1ents;
00628 std::vector< EntityHandle > owners;
00629 for( Range::iterator rit = geomRanges[dim + 1].begin(); rit != geomRanges[dim + 1].end(); ++rit )
00630 {
00631 dp1ents.clear();
00632 result = mdbImpl->get_entities_by_dimension( *rit, dim + 1, dp1ents );
00633 if( MB_SUCCESS != result ) continue;
00634 owners.resize( dp1ents.size() );
00635 std::fill( owners.begin(), owners.end(), *rit );
00636 result = mdbImpl->tag_set_data( owner_tag, dp1ents, &owners[0] );
00637 if( MB_SUCCESS != result ) continue;
00638 }
00639
00640 for( Range::iterator d_it = geomRanges[dim].begin(); d_it != geomRanges[dim].end(); ++d_it )
00641 {
00642 Range dents;
00643 result = mdbImpl->get_entities_by_dimension( *d_it, dim, dents );
00644 if( MB_SUCCESS != result ) continue;
00645 if( dents.empty() ) continue;
00646
00647 // get (d+1)-dimensional adjs
00648 dp1ents.clear();
00649 result = mdbImpl->get_adjacencies( &( *dents.begin() ), 1, dim + 1, false, dp1ents );
00650 if( MB_SUCCESS != result || dp1ents.empty() ) continue;
00651
00652 // get owner tags
00653 parents.resize( dp1ents.size() );
00654 result = mdbImpl->tag_get_data( owner_tag, dp1ents, &parents[0] );
00655 if( MB_TAG_NOT_FOUND == result )
00656 {
00657 MB_CHK_SET_ERR( result, "Could not find owner tag" );
00658 }
00659 if( MB_SUCCESS != result ) continue;
00660
00661 // compress to a range to remove duplicates
00662 tmp_parents.clear();
00663 std::copy( parents.begin(), parents.end(), range_inserter( tmp_parents ) );
00664 for( Range::iterator pit = tmp_parents.begin(); pit != tmp_parents.end(); ++pit )
00665 {
00666 result = mdbImpl->add_parent_child( *pit, *d_it );MB_CHK_SET_ERR( result, "Failed to create parent child relationship" );
00667 }
00668
00669 // store surface senses within regions, and edge senses within surfaces
00670 if( dim == 0 ) continue;
00671 const EntityHandle *conn3 = NULL, *conn2 = NULL;
00672 int len3 = 0, len2 = 0, err = 0, num = 0, sense = 0, offset = 0;
00673 for( size_t i = 0; i < parents.size(); ++i )
00674 {
00675 result = mdbImpl->get_connectivity( dp1ents[i], conn3, len3, true );MB_CHK_SET_ERR( result, "Failed to get the connectivity of the element" );
00676 result = mdbImpl->get_connectivity( dents.front(), conn2, len2, true );MB_CHK_SET_ERR( result, "Failed to get the connectivity of the first element" );
00677 if( len2 > 4 )
00678 {
00679 MB_SET_ERR( MB_FAILURE, "Connectivity of incorrect length" );
00680 }
00681 err = CN::SideNumber( TYPE_FROM_HANDLE( dp1ents[i] ), conn3, conn2, len2, dim, num, sense, offset );
00682 if( err ) return MB_FAILURE;
00683
00684 result = set_sense( *d_it, parents[i], sense );
00685 if( MB_MULTIPLE_ENTITIES_FOUND == result )
00686 {
00687 if( 2 == dim )
00688 std::cerr << "Warning: Multiple volumes use surface with same sense." << std::endl
00689 << " Some geometric sense data lost." << std::endl;
00690 }
00691 else if( MB_SUCCESS != result )
00692 {
00693 return result;
00694 }
00695 }
00696 }
00697
00698 // now delete owner tag on this dimension, automatically removes tag data
00699 result = mdbImpl->tag_delete( owner_tag );MB_CHK_SET_ERR( result, "Failed to delete the owner tag" );
00700
00701 } // dim
00702
00703 return result;
00704 }
00705
00706 ErrorCode GeomTopoTool::separate_by_dimension( const Range& geom_sets )
00707 {
00708 ErrorCode result;
00709
00710 result = check_geom_tag();MB_CHK_SET_ERR( result, "Could not verify geometry dimension tag" );
00711
00712 // get the data for those tags
00713 std::vector< int > tag_vals( geom_sets.size() );
00714 result = mdbImpl->tag_get_data( geomTag, geom_sets, &tag_vals[0] );MB_CHK_SET_ERR( result, "Failed to get the geometry dimension tag" );
00715
00716 Range::const_iterator git;
00717 std::vector< int >::iterator iit;
00718
00719 for( int i = 0; i < 5; i++ )
00720 this->geomRanges[i].clear();
00721
00722 for( git = geom_sets.begin(), iit = tag_vals.begin(); git != geom_sets.end(); ++git, ++iit )
00723 {
00724 if( 0 <= *iit && 4 >= *iit )
00725 geomRanges[*iit].insert( *git );
00726 else
00727 {
00728 // assert(false);
00729 // do nothing for now
00730 }
00731 }
00732
00733 // establish the max global ids so far, per dimension
00734 if( 0 == gidTag )
00735 {
00736 gidTag = mdbImpl->globalId_tag();
00737 }
00738
00739 for( int i = 0; i <= 4; i++ )
00740 {
00741 maxGlobalId[i] = 0;
00742 for( Range::iterator it = geomRanges[i].begin(); it != geomRanges[i].end(); ++it )
00743 {
00744 EntityHandle set = *it;
00745 int gid;
00746
00747 result = mdbImpl->tag_get_data( gidTag, &set, 1, &gid );
00748 if( MB_SUCCESS == result )
00749 {
00750 if( gid > maxGlobalId[i] ) maxGlobalId[i] = gid;
00751 }
00752 }
00753 }
00754
00755 return MB_SUCCESS;
00756 }
00757
00758 ErrorCode GeomTopoTool::construct_vertex_ranges( const Range& geom_sets, const Tag verts_tag )
00759 {
00760 // construct the vertex range for each entity and put on that tag
00761 Range *temp_verts, temp_elems;
00762 ErrorCode result = MB_SUCCESS;
00763 for( Range::const_iterator it = geom_sets.begin(); it != geom_sets.end(); ++it )
00764 {
00765 temp_elems.clear();
00766
00767 // get all the elements in the set, recursively
00768 result = mdbImpl->get_entities_by_handle( *it, temp_elems, true );MB_CHK_SET_ERR( result, "Failed to get the geometry set entities" );
00769
00770 // make the new range
00771 temp_verts = new( std::nothrow ) Range();
00772 if( NULL == temp_verts )
00773 {
00774 MB_SET_ERR( MB_FAILURE, "Could not construct Range object" );
00775 }
00776
00777 // get all the verts of those elements; use get_adjacencies 'cuz it handles ranges better
00778 result = mdbImpl->get_adjacencies( temp_elems, 0, false, *temp_verts, Interface::UNION );
00779 if( MB_SUCCESS != result )
00780 {
00781 delete temp_verts;
00782 }
00783 MB_CHK_SET_ERR( result, "Failed to get the element's adjacent vertices" );
00784
00785 // store this range as a tag on the entity
00786 result = mdbImpl->tag_set_data( verts_tag, &( *it ), 1, &temp_verts );
00787 if( MB_SUCCESS != result )
00788 {
00789 delete temp_verts;
00790 }
00791 MB_CHK_SET_ERR( result, "Failed to get the adjacent vertex data" );
00792
00793 delete temp_verts;
00794 temp_verts = NULL;
00795 }
00796
00797 return result;
00798 }
00799
00800 //! Store sense of entity relative to wrt_entity.
00801 //!\return MB_MULTIPLE_ENTITIES_FOUND if surface already has a forward volume.
00802 //! MB_SUCCESS if successful
00803 //! otherwise whatever internal error code occurred.
00804 ErrorCode GeomTopoTool::set_sense( EntityHandle entity, EntityHandle wrt_entity, int sense )
00805 {
00806 // entity is lower dim (edge or face), wrt_entity is face or volume
00807 int edim = dimension( entity );
00808 int wrtdim = dimension( wrt_entity );
00809 if( -1 == edim || -1 == wrtdim ) MB_SET_ERR( MB_FAILURE, "Non-geometric entity provided" );
00810 if( wrtdim - edim != 1 ) MB_SET_ERR( MB_FAILURE, "Entity dimension mismatch" );
00811 if( sense < -1 || sense > 1 ) MB_SET_ERR( MB_FAILURE, "Invalid sense data provided" );
00812
00813 ErrorCode rval;
00814
00815 if( 1 == edim )
00816 {
00817 // this case is about setting the sense of an edge in a face
00818 // it could be -1, 0 (rare, non manifold), or 1
00819 rval = check_edge_sense_tags( true );MB_CHK_SET_ERR( rval, "Failed to check the curve to surface sense tag handles" );
00820 std::vector< EntityHandle > higher_ents;
00821 std::vector< int > senses;
00822 rval = get_senses( entity, higher_ents, senses ); // the tags should be defined here
00823 // if there are no higher_ents, we are fine, we will just set them
00824 // if wrt_entity is not among higher_ents, we will add it to the list
00825 // it is possible the entity (edge set) has no prior faces adjancent; in that case, the
00826 // tag would not be set, and rval could be MB_TAG_NOT_FOUND; it is not a fatal error
00827 if( MB_SUCCESS != rval && MB_TAG_NOT_FOUND != rval )
00828 MB_CHK_SET_ERR( rval, "cannot determine sense tags for edge" );
00829 bool append = true;
00830 if( !higher_ents.empty() )
00831 {
00832 std::vector< EntityHandle >::iterator it = std::find( higher_ents.begin(), higher_ents.end(), wrt_entity );
00833 if( it != higher_ents.end() )
00834 {
00835 // we should not reset the sense, if the sense is the same
00836 // if the sense is different, put BOTH
00837 unsigned int idx = it - higher_ents.begin();
00838 int oldSense = senses[idx];
00839 if( oldSense == sense ) return MB_SUCCESS; // sense already set fine, do not reset
00840 if( 0 != oldSense && oldSense + sense != 0 ) return MB_MULTIPLE_ENTITIES_FOUND;
00841 senses[idx] = SENSE_BOTH; // allow double senses
00842 // do not need to add a new sense, but still need to reset the tag
00843 // because of a new value
00844 append = false;
00845 }
00846 }
00847 if( append )
00848 {
00849 // what happens if a var tag data was already set before, and now it is
00850 // reset with a different size??
00851 higher_ents.push_back( wrt_entity );
00852 senses.push_back( sense );
00853 }
00854 // finally, set the senses :
00855 int dum_size = higher_ents.size();
00856 void* dum_ptr = &higher_ents[0];
00857 rval = mdbImpl->tag_set_by_ptr( senseNEntsTag, &entity, 1, &dum_ptr, &dum_size );MB_CHK_SET_ERR( rval, "Failed to set the sense data" );
00858
00859 dum_ptr = &senses[0];
00860 dum_size = higher_ents.size();
00861 rval = mdbImpl->tag_set_by_ptr( senseNSensesTag, &entity, 1, &dum_ptr, &dum_size );MB_CHK_SET_ERR( rval, "Failed to set the sense data by pointer" );
00862 }
00863 else
00864 {
00865 // this case is about a face in the volume
00866 // there could be only 2 volumes
00867
00868 rval = check_face_sense_tag( true );MB_CHK_SET_ERR( rval, "Failed to verify the face sense tag" );
00869
00870 EntityHandle sense_data[2] = { 0, 0 };
00871 rval = mdbImpl->tag_get_data( sense2Tag, &entity, 1, sense_data );
00872 if( MB_TAG_NOT_FOUND != rval && MB_SUCCESS != rval ) MB_CHK_SET_ERR( rval, "Failed to get the sense2Tag data" );
00873
00874 if( 0 == sense )
00875 {
00876 if( 0 != sense_data[0] && wrt_entity != sense_data[0] ) return MB_MULTIPLE_ENTITIES_FOUND;
00877 if( 0 != sense_data[1] && wrt_entity != sense_data[1] ) return MB_MULTIPLE_ENTITIES_FOUND;
00878 sense_data[0] = sense_data[1] = wrt_entity;
00879 }
00880 else if( -1 == sense )
00881 {
00882 if( 0 != sense_data[1] && wrt_entity != sense_data[1] ) return MB_MULTIPLE_ENTITIES_FOUND;
00883 if( sense_data[1] == wrt_entity ) return MB_SUCCESS; // already set as we want
00884 sense_data[1] = wrt_entity;
00885 }
00886 else if( 1 == sense )
00887 {
00888 if( 0 != sense_data[0] && wrt_entity != sense_data[0] ) return MB_MULTIPLE_ENTITIES_FOUND;
00889 if( sense_data[0] == wrt_entity ) return MB_SUCCESS; // already set as we want
00890 sense_data[0] = wrt_entity;
00891 }
00892 return mdbImpl->tag_set_data( sense2Tag, &entity, 1, sense_data );
00893 }
00894 return MB_SUCCESS;
00895 }
00896
00897 //! Get the sense of entity with respect to wrt_entity
00898 //! Returns MB_ENTITY_NOT_FOUND if no relationship found
00899 ErrorCode GeomTopoTool::get_sense( EntityHandle entity, EntityHandle wrt_entity, int& sense )
00900 {
00901 // entity is lower dim (edge or face), wrt_entity is face or volume
00902 int edim = dimension( entity );
00903 int wrtdim = dimension( wrt_entity );
00904 if( -1 == edim || -1 == wrtdim ) MB_SET_ERR( MB_FAILURE, "Non-geometric entity provided" );
00905 if( wrtdim - edim != 1 ) MB_SET_ERR( MB_FAILURE, "Entity dimension mismatch" );
00906
00907 ErrorCode rval;
00908
00909 if( 1 == edim )
00910 {
00911 // edge in face
00912 rval = check_edge_sense_tags( false );MB_CHK_SET_ERR( rval, "Failed to check the curve to surface sense tag handles" );
00913
00914 std::vector< EntityHandle > faces;
00915 std::vector< int > senses;
00916 rval = get_senses( entity, faces, senses ); // the tags should be defined here
00917 MB_CHK_SET_ERR( rval, "Failed to get the curve to surface sense data" );
00918
00919 std::vector< EntityHandle >::iterator it = std::find( faces.begin(), faces.end(), wrt_entity );
00920 if( it == faces.end() ) return MB_ENTITY_NOT_FOUND;
00921 unsigned int index = it - faces.begin();
00922 sense = senses[index];
00923 }
00924 else
00925 {
00926 // face in volume
00927 rval = check_face_sense_tag( false );MB_CHK_SET_ERR( rval, "Failed to check the surface to volume sense tag handle" );
00928 EntityHandle sense_data[2] = { 0, 0 };
00929 rval = mdbImpl->tag_get_data( sense2Tag, &entity, 1, sense_data );
00930 if( MB_TAG_NOT_FOUND != rval && MB_SUCCESS != rval )
00931 MB_CHK_SET_ERR( rval, "Failed to get the surface to volume sense data" );
00932 if( ( wrt_entity == sense_data[0] ) && ( wrt_entity == sense_data[1] ) )
00933 sense = 0;
00934 else if( wrt_entity == sense_data[0] )
00935 sense = 1;
00936 else if( wrt_entity == sense_data[1] )
00937 sense = -1;
00938 else
00939 return MB_ENTITY_NOT_FOUND;
00940 }
00941 return MB_SUCCESS;
00942 }
00943
00944 ErrorCode GeomTopoTool::get_surface_senses( EntityHandle surface_ent,
00945 EntityHandle& forward_vol,
00946 EntityHandle& reverse_vol )
00947 {
00948 ErrorCode rval;
00949 // this method should only be called to retrieve surface to volume
00950 // sense relationships
00951 int ent_dim = dimension( surface_ent );
00952 // verify the incoming entity dimensions for this call
00953 if( ent_dim != 2 )
00954 {
00955 MB_SET_ERR( MB_FAILURE, "Entity dimension is incorrect for surface meshset" );
00956 }
00957
00958 // get the sense information for this surface
00959 EntityHandle parent_vols[2] = { 0, 0 };
00960 rval = mdbImpl->tag_get_data( sense2Tag, &surface_ent, 1, parent_vols );MB_CHK_SET_ERR( rval, "Failed to get surface sense data" );
00961
00962 // set the outgoing values
00963 forward_vol = parent_vols[0];
00964 reverse_vol = parent_vols[1];
00965
00966 return MB_SUCCESS;
00967 }
00968
00969 ErrorCode GeomTopoTool::set_surface_senses( EntityHandle surface_ent,
00970 EntityHandle forward_vol,
00971 EntityHandle reverse_vol )
00972 {
00973 ErrorCode rval;
00974 // this mthod should only be called to retrieve surface to volume
00975 // sense relationships
00976 int ent_dim = dimension( surface_ent );
00977 // verify the incoming entity dimensions for this call
00978 if( ent_dim != 2 )
00979 {
00980 MB_SET_ERR( MB_FAILURE, "Entity dimension is incorrect for surface meshset" );
00981 }
00982
00983 // set the sense information for this surface
00984 EntityHandle parent_vols[2] = { forward_vol, reverse_vol };
00985 rval = mdbImpl->tag_set_data( sense2Tag, &surface_ent, 1, parent_vols );MB_CHK_SET_ERR( rval, "Failed to set surface sense data" );
00986
00987 return MB_SUCCESS;
00988 }
00989
00990 // get sense of surface(s) wrt volume
00991 ErrorCode GeomTopoTool::get_surface_senses( EntityHandle volume,
00992 int num_surfaces,
00993 const EntityHandle* surfaces,
00994 int* senses_out )
00995 {
00996
00997 /* The sense tags do not reference the implicit complement handle.
00998 All surfaces that interact with the implicit complement should have
00999 a null handle in the direction of the implicit complement. */
01000 // if (volume == impl_compl_handle)
01001 // volume = (EntityHandle) 0;
01002
01003 for( int surf_num = 0; surf_num < num_surfaces; surf_num++ )
01004 {
01005 get_sense( surfaces[surf_num], volume, senses_out[surf_num] );
01006 }
01007
01008 return MB_SUCCESS;
01009 }
01010
01011 ErrorCode GeomTopoTool::get_senses( EntityHandle entity,
01012 std::vector< EntityHandle >& wrt_entities,
01013 std::vector< int >& senses )
01014 {
01015 // the question here is: the wrt_entities is supplied or not?
01016 // I assume not, we will obtain it !!
01017 int edim = dimension( entity );
01018
01019 if( -1 == edim ) MB_SET_ERR( MB_FAILURE, "Non-geometric entity provided" );
01020
01021 ErrorCode rval;
01022 wrt_entities.clear();
01023 senses.clear();
01024
01025 if( 1 == edim ) // edge
01026 {
01027 rval = check_edge_sense_tags( false );MB_CHK_SET_ERR( rval, "Failed to check the curve to surface sense tag handles" );
01028 const void* dum_ptr;
01029 int num_ents;
01030 rval = mdbImpl->tag_get_by_ptr( senseNEntsTag, &entity, 1, &dum_ptr, &num_ents );MB_CHK_ERR( rval );
01031
01032 const EntityHandle* ents_data = static_cast< const EntityHandle* >( dum_ptr );
01033 std::copy( ents_data, ents_data + num_ents, std::back_inserter( wrt_entities ) );
01034
01035 rval = mdbImpl->tag_get_by_ptr( senseNSensesTag, &entity, 1, &dum_ptr, &num_ents );MB_CHK_ERR( rval );
01036
01037 const int* senses_data = static_cast< const int* >( dum_ptr );
01038 std::copy( senses_data, senses_data + num_ents, std::back_inserter( senses ) );
01039 }
01040 else // face in volume, edim == 2
01041 {
01042 rval = check_face_sense_tag( false );MB_CHK_SET_ERR( rval, "Failed to check the surface to volume sense tag handle" );
01043 EntityHandle sense_data[2] = { 0, 0 };
01044 rval = mdbImpl->tag_get_data( sense2Tag, &entity, 1, sense_data );MB_CHK_SET_ERR( rval, "Failed to get the surface to volume sense data" );
01045 if( sense_data[0] != 0 && sense_data[1] == sense_data[0] )
01046 {
01047 wrt_entities.push_back( sense_data[0] );
01048 senses.push_back( 0 ); // both
01049 }
01050 else
01051 {
01052 if( sense_data[0] != 0 )
01053 {
01054 wrt_entities.push_back( sense_data[0] );
01055 senses.push_back( 1 );
01056 }
01057 if( sense_data[1] != 0 )
01058 {
01059 wrt_entities.push_back( sense_data[1] );
01060 senses.push_back( -1 );
01061 }
01062 }
01063 }
01064 // filter the results with the sets that are in the model at this time
01065 // this was introduced because extracting some sets (e.g. neumann set, with mbconvert)
01066 // from a model would leave some sense tags not defined correctly
01067 // also, the geom ent set really needs to be part of the current model set
01068 unsigned int currentSize = 0;
01069
01070 for( unsigned int index = 0; index < wrt_entities.size(); index++ )
01071 {
01072 EntityHandle wrt_ent = wrt_entities[index];
01073 if( wrt_ent )
01074 {
01075 if( mdbImpl->contains_entities( modelSet, &wrt_ent, 1 ) )
01076 {
01077 wrt_entities[currentSize] = wrt_entities[index];
01078 senses[currentSize] = senses[index];
01079 currentSize++;
01080 }
01081 }
01082 }
01083 wrt_entities.resize( currentSize );
01084 senses.resize( currentSize );
01085 //
01086 return MB_SUCCESS;
01087 }
01088
01089 ErrorCode GeomTopoTool::set_senses( EntityHandle entity,
01090 std::vector< EntityHandle >& wrt_entities,
01091 std::vector< int >& senses )
01092 {
01093 // not efficient, and maybe wrong
01094 for( unsigned int i = 0; i < wrt_entities.size(); i++ )
01095 {
01096 ErrorCode rval = set_sense( entity, wrt_entities[i], senses[i] );MB_CHK_SET_ERR( rval, "Failed to set the sense" );
01097 }
01098
01099 return MB_SUCCESS;
01100 }
01101
01102 ErrorCode GeomTopoTool::next_vol( EntityHandle surface, EntityHandle old_volume, EntityHandle& new_volume )
01103 {
01104 std::vector< EntityHandle > parents;
01105 ErrorCode rval = mdbImpl->get_parent_meshsets( surface, parents );
01106
01107 if( MB_SUCCESS == rval )
01108 {
01109 if( parents.size() != 2 )
01110 rval = MB_FAILURE;
01111 else if( parents.front() == old_volume )
01112 new_volume = parents.back();
01113 else if( parents.back() == old_volume )
01114 new_volume = parents.front();
01115 else
01116 rval = MB_FAILURE;
01117 }
01118
01119 return rval;
01120 }
01121
01122 ErrorCode GeomTopoTool::check_geom_tag( bool create )
01123 {
01124 ErrorCode rval;
01125 unsigned flags = create ? MB_TAG_DENSE | MB_TAG_CREAT : MB_TAG_DENSE;
01126 if( !geomTag )
01127 {
01128 // get any kind of tag that already exists
01129 rval = mdbImpl->tag_get_handle( GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, geomTag, flags );MB_CHK_SET_ERR( rval, "Could not get/create the geometry dimension tag" );
01130 }
01131 return MB_SUCCESS;
01132 }
01133
01134 ErrorCode GeomTopoTool::check_gid_tag( bool create )
01135 {
01136 ErrorCode rval;
01137 unsigned flags = create ? MB_TAG_DENSE | MB_TAG_CREAT : MB_TAG_DENSE;
01138 if( !gidTag )
01139 {
01140 // get any kind of tag that already exists
01141 rval = mdbImpl->tag_get_handle( GLOBAL_ID_TAG_NAME, 1, MB_TYPE_INTEGER, gidTag, flags );MB_CHK_SET_ERR( rval, "Could not get/create the global id tag" );
01142 }
01143 return MB_SUCCESS;
01144 }
01145
01146 // move the sense tag existence creation in private methods
01147 // verify sense face tag
01148 ErrorCode GeomTopoTool::check_face_sense_tag( bool create )
01149 {
01150 ErrorCode rval;
01151 unsigned flags = create ? MB_TAG_SPARSE | MB_TAG_CREAT | MB_TAG_ANY : MB_TAG_SPARSE | MB_TAG_ANY;
01152 if( !sense2Tag )
01153 {
01154 EntityHandle def_val[2] = { 0, 0 };
01155 rval = mdbImpl->tag_get_handle( GEOM_SENSE_2_TAG_NAME, 2, MB_TYPE_HANDLE, sense2Tag, flags, def_val );MB_CHK_SET_ERR( rval, "Could not get/create the sense2Tag" );
01156 }
01157 return MB_SUCCESS;
01158 }
01159
01160 // verify sense edge tags
01161 ErrorCode GeomTopoTool::check_edge_sense_tags( bool create )
01162 {
01163 ErrorCode rval;
01164 unsigned flags = MB_TAG_VARLEN | MB_TAG_SPARSE;
01165 if( create ) flags |= MB_TAG_CREAT;
01166 if( !senseNEntsTag )
01167 {
01168 rval = mdbImpl->tag_get_handle( GEOM_SENSE_N_ENTS_TAG_NAME, 0, MB_TYPE_HANDLE, senseNEntsTag, flags );MB_CHK_SET_ERR( rval, "Failed to get the curve to surface entity tag handle" );
01169 rval = mdbImpl->tag_get_handle( GEOM_SENSE_N_SENSES_TAG_NAME, 0, MB_TYPE_INTEGER, senseNSensesTag, flags );MB_CHK_SET_ERR( rval, "Failed to get the curve to surface sense tag handle" );
01170 }
01171 return MB_SUCCESS;
01172 }
01173
01174 ErrorCode GeomTopoTool::add_geo_set( EntityHandle set, int dim, int gid )
01175 {
01176 if( dim < 0 || dim > 4 ) MB_SET_ERR( MB_FAILURE, "Invalid geometric dimension provided" );
01177
01178 // see if it is not already set
01179 if( geomRanges[dim].find( set ) != geomRanges[dim].end() )
01180 {
01181 return MB_SUCCESS; // nothing to do, we already have it as a geo set of proper dimension
01182 }
01183 updated = false; // this should trigger at least an obb recomputation
01184 // get the geom topology tag
01185 ErrorCode result;
01186 if( 0 == geomTag )
01187 {
01188 result = mdbImpl->tag_get_handle( GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, geomTag );MB_CHK_SET_ERR( result, "Failed to get the geometry dimension tag handle" );
01189 }
01190
01191 if( 0 == gidTag )
01192 {
01193 gidTag = mdbImpl->globalId_tag();
01194 }
01195
01196 // make sure the added set has the geom tag properly set
01197 result = mdbImpl->tag_set_data( geomTag, &set, 1, &dim );MB_CHK_SET_ERR( result, "Failed set the geometry dimension tag value" );
01198
01199 geomRanges[dim].insert( set );
01200 // not only that, but also add it to the root model set
01201 if( modelSet )
01202 {
01203 result = mdbImpl->add_entities( modelSet, &set, 1 );MB_CHK_SET_ERR( result, "Failed to add new geometry set to the tool's modelSet" );
01204 }
01205
01206 // set the global ID value
01207 // if passed 0, just increase the max id for the dimension
01208 if( 0 == gid )
01209 {
01210 gid = ++maxGlobalId[dim];
01211 }
01212
01213 result = mdbImpl->tag_set_data( gidTag, &set, 1, &gid );MB_CHK_SET_ERR( result, "Failed to get the global id tag value for the geom entity" );
01214
01215 return MB_SUCCESS;
01216 }
01217
01218 // will assume no geo sets are defined for this surface
01219 // will output a mesh_set that contains everything (all sets of interest), for proper output
01220 ErrorCode GeomTopoTool::geometrize_surface_set( EntityHandle surface, EntityHandle& output )
01221 {
01222 // usual scenario is to read a surface smf file, and "geometrize" it, and output it as a
01223 // h5m file with proper sets, tags defined for mesh-based geometry
01224
01225 // get all triangles/quads from the surface, then build loops
01226 // we may even have to
01227 // proper care has to be given to the orientation, material to the left!!!
01228 // at some point we may have to reorient triangles, not only edges, for proper definition
01229 bool debugFlag = false;
01230
01231 Range surface_ents, edge_ents, loop_range;
01232
01233 // most of these should be triangles and quads
01234 ErrorCode rval = mdbImpl->get_entities_by_dimension( surface, 2, surface_ents );MB_CHK_SET_ERR( rval, "Failed to get the surface entities" );
01235
01236 EntityHandle face = surface;
01237 if( !surface ) // in the case it is root set, create another set
01238 {
01239 rval = mdbImpl->create_meshset( MESHSET_SET, face );MB_CHK_SET_ERR( rval, "Failed to create a the new surface meshset" );
01240 }
01241 // set the geo tag
01242 rval = add_geo_set( face, 2 );MB_CHK_SET_ERR( rval, "Failed to add the geometry set to the tool" );
01243
01244 // this will be our output set, will contain all our new geo sets
01245 rval = mdbImpl->create_meshset( MESHSET_SET, output );MB_CHK_SET_ERR( rval, "Failed to create the output meshset" );
01246
01247 // add first geo set (face) to the output set
01248 rval = mdbImpl->add_entities( output, &face, 1 );MB_CHK_SET_ERR( rval, "Failed to add the new meshset to the output meshset" );
01249
01250 // how many edges do we need to create?
01251 // depends on how many loops we have
01252 // also, we should avoid non-manifold topology
01253 if( !surface )
01254 { // in this case, surface is root, so we have to add entities
01255 rval = mdbImpl->add_entities( face, surface_ents );MB_CHK_SET_ERR( rval, "Failed to add surface entities to the surface meshset" );
01256 }
01257
01258 Skinner tool( mdbImpl );
01259 rval = tool.find_skin( 0, surface_ents, 1, edge_ents );MB_CHK_SET_ERR( rval, "Failed to skin the surface entities" );
01260 if( debugFlag )
01261 {
01262 std::cout << "skinning edges: " << edge_ents.size() << "\n";
01263 for( Range::iterator it = edge_ents.begin(); it != edge_ents.end(); ++it )
01264 {
01265 EntityHandle ed = *it;
01266 std::cout << "edge: " << mdbImpl->id_from_handle( ed ) << " type:" << mdbImpl->type_from_handle( ed )
01267 << "\n";
01268 std::cout << mdbImpl->list_entity( ed );
01269 }
01270 }
01271
01272 std::vector< EntityHandle > edges_loop;
01273
01274 Range pool_of_edges = edge_ents;
01275 Range used_edges; // these edges are already used for some loops
01276 // get a new one
01277
01278 while( !pool_of_edges.empty() )
01279 {
01280 // get the first edge, and start a loop with it
01281 EntityHandle current_edge = pool_of_edges[0];
01282 if( debugFlag )
01283 {
01284 std::cout << "Start current edge: " << mdbImpl->id_from_handle( current_edge ) << "\n ";
01285 std::cout << mdbImpl->list_entity( current_edge );
01286 }
01287 // get its triangle / quad and see its orientation
01288 std::vector< EntityHandle > tris;
01289 rval = mdbImpl->get_adjacencies( ¤t_edge, 1, 2, false, tris );MB_CHK_SET_ERR( rval, "Failed to get the adjacent triangles to the current edge" );
01290 if( tris.size() != 1 ) MB_SET_ERR( MB_FAILURE, "Edge not on boundary" );
01291
01292 int side_n, sense, offset;
01293 rval = mdbImpl->side_number( tris[0], current_edge, side_n, sense, offset );MB_CHK_SET_ERR( rval, "Failed to get the current edge's side number" );
01294
01295 const EntityHandle* conn2;
01296 int nnodes2;
01297 rval = mdbImpl->get_connectivity( current_edge, conn2, nnodes2 );MB_CHK_SET_ERR( rval, "Failed to get the current edge's connectivity" );
01298
01299 if( nnodes2 != 2 ) MB_SET_ERR( MB_FAILURE, "Incorrect number of nodes found." );
01300
01301 EntityHandle start_node = conn2[0];
01302 EntityHandle next_node = conn2[1];
01303
01304 if( sense == -1 )
01305 {
01306 // revert the edge, and start well
01307 EntityHandle nn2[2] = { conn2[1], conn2[0] };
01308 rval = mdbImpl->set_connectivity( current_edge, nn2, 2 );MB_CHK_SET_ERR( rval, "Failed to set the connectivity of the current edge" );
01309
01310 start_node = nn2[0]; // or conn2[0] !!! beware: conn2 is modified
01311 next_node = nn2[1]; // or conn2[1] !!!
01312 // reset connectivity of edge
01313 if( debugFlag ) std::cout << " current edge needs reversed\n";
01314 }
01315 // start a new loop of edges
01316 edges_loop.clear(); // every edge loop starts fresh
01317 edges_loop.push_back( current_edge );
01318 used_edges.insert( current_edge );
01319 pool_of_edges.erase( current_edge );
01320
01321 if( debugFlag )
01322 {
01323 std::cout << " start node: " << start_node << "\n";
01324 std::cout << mdbImpl->list_entity( start_node );
01325 std::cout << " next node: " << next_node << "\n";
01326 std::cout << mdbImpl->list_entity( next_node );
01327 }
01328 while( next_node != start_node )
01329 {
01330 // find the next edge in the skin
01331 std::vector< EntityHandle > candidate_edges;
01332 rval = mdbImpl->get_adjacencies( &next_node, 1, 1, false, candidate_edges );MB_CHK_SET_ERR( rval, "Failed to get the adjacent edges to the next node" );
01333 // filter the edges that are used, or the edges not in the skin
01334 std::vector< EntityHandle > good_edges;
01335 for( int k = 0; k < (int)candidate_edges.size(); k++ )
01336 {
01337 EntityHandle edg = candidate_edges[k];
01338 if( used_edges.find( edg ) != used_edges.end() ) continue;
01339 if( pool_of_edges.find( edg ) != pool_of_edges.end() ) good_edges.push_back( edg );
01340 }
01341 if( good_edges.size() != 1 )
01342 {
01343 std::cout << " good_edges.size()=" << good_edges.size() << " STOP\n";
01344 MB_SET_ERR( MB_FAILURE, "Number of good edges is not one. Could not complete the loop" );
01345 }
01346 // see if the orientation is good; if not, revert it
01347
01348 current_edge = good_edges[0];
01349 rval = mdbImpl->get_connectivity( current_edge, conn2, nnodes2 );MB_CHK_SET_ERR( rval, "Failed to get the connectivity of the current edge" );
01350 if( nnodes2 != 2 ) MB_SET_ERR( MB_FAILURE, "Incorrect number of nodes found" );
01351
01352 if( conn2[0] != next_node )
01353 {
01354 if( conn2[1] != next_node )
01355 {
01356 // the edge is not connected then to current edge
01357 // bail out
01358 std::cout << "edge " << mdbImpl->id_from_handle( current_edge ) << " not connected to node "
01359 << next_node << "\n";
01360 MB_SET_ERR( MB_FAILURE, "Current edge is not connected to node" );
01361 ;
01362 }
01363 if( debugFlag )
01364 {
01365 std::cout << " revert edge " << mdbImpl->id_from_handle( current_edge ) << "\n";
01366 std::cout << mdbImpl->list_entity( current_edge );
01367 }
01368 // orientation should be reversed
01369 EntityHandle nn2[2] = { conn2[1], conn2[0] };
01370 rval = mdbImpl->set_connectivity( current_edge, nn2, 2 );MB_CHK_SET_ERR( rval, "Failed to set the connectivity of the current edge" );
01371
01372 {
01373 std::cout << "after revert edge " << mdbImpl->id_from_handle( current_edge ) << "\n";
01374 std::cout << mdbImpl->list_entity( current_edge );
01375 std::cout << " conn2: " << conn2[0] << " " << conn2[1] << "\n";
01376 }
01377 }
01378 // before reversion, conn2 was something { n1, next_node}
01379 // after reversion, conn2 became {next_node, n1}, so the
01380 // new next node will be still conn2[1]; big surprise, as
01381 // I didn't expect the conn2 to change.
01382 // it seems that const EntityHandle * conn2 means conn2 cannot be
01383 // changed, but what is pointed to by it will change when we reset connectivity for edge
01384 next_node = conn2[1];
01385
01386 if( debugFlag )
01387 {
01388 std::cout << " current edge: " << mdbImpl->id_from_handle( current_edge ) << "\n ";
01389 std::cout << mdbImpl->list_entity( current_edge );
01390 std::cout << "next node: " << next_node << "\n ";
01391 std::cout << mdbImpl->list_entity( next_node );
01392 }
01393 edges_loop.push_back( current_edge );
01394 used_edges.insert( current_edge );
01395 pool_of_edges.erase( current_edge );
01396 }
01397 // at this point, we have a loop formed;
01398 // create a geo edge, a vertex set, and add it to our sets
01399
01400 EntityHandle edge;
01401 rval = mdbImpl->create_meshset( MESHSET_ORDERED, edge );MB_CHK_SET_ERR( rval, "Failed to create the edge meshset" );
01402
01403 rval = add_geo_set( edge, 1 );MB_CHK_SET_ERR( rval, "Failed to add the edge meshset to the tool's model set" );
01404 // add the mesh edges:
01405 // add loops edges to the edge set
01406 rval = mdbImpl->add_entities( edge, &edges_loop[0], edges_loop.size() ); //
01407 MB_CHK_SET_ERR( rval, "Failed to add entities to the edge meshset" );
01408 // create a vertex set
01409 EntityHandle vertex;
01410 rval = mdbImpl->create_meshset( MESHSET_SET, vertex );MB_CHK_SET_ERR( rval, "Failed to create the vertex meshset" );
01411 rval = add_geo_set( vertex, 0 );MB_CHK_SET_ERR( rval, "Failed to add the vertex meshset to the tool's model set" );
01412 // add one node to the vertex set
01413
01414 rval = mdbImpl->add_entities( vertex, &start_node, 1 ); //
01415 MB_CHK_SET_ERR( rval, "Failed to add entities to the vertex meshset" );
01416
01417 rval = mdbImpl->add_parent_child( face, edge );MB_CHK_SET_ERR( rval, "Failed to create the edge to face parent child relationship" );
01418
01419 rval = mdbImpl->add_parent_child( edge, vertex );MB_CHK_SET_ERR( rval, "Failed to create the vertex to edge parent child relationship" );
01420
01421 // the sense of the edge in face is for sure positive (forward)
01422 rval = set_sense( edge, face, 1 ); //
01423 MB_CHK_SET_ERR( rval, "Failed to set the edge to face sense" );
01424 // also add our sets to the output set, to be sure to be exported
01425
01426 rval = mdbImpl->add_entities( output, &edge, 1 );MB_CHK_SET_ERR( rval, "Failed to add the edge meshset to the output set" );
01427 rval = mdbImpl->add_entities( output, &vertex, 1 );MB_CHK_SET_ERR( rval, "Failed to add the vertex meshset to the output set" );
01428
01429 if( debugFlag )
01430 {
01431 std::cout << "add edge with start node " << start_node << " with " << edges_loop.size() << " edges\n";
01432 }
01433 }
01434
01435 return MB_SUCCESS;
01436 }
01437
01438 /*
01439 * This would create a deep copy of the geom topo model, into a new geom topo tool
01440 * sets will be duplicated, but entities not
01441 * modelSet will be a new one
01442 * if the original set was null (root), a new model set will be created for
01443 * original model, and its entities will be the original g sets
01444 * Scenario: split a face along a ground line, then write only one surface
01445 * the common line has 2 faces in var len tag for sense edge; if we write only one
01446 * surface to a new database, the var len tag of the edge will be extracted with 2 values, but
01447 * only one value will make sense, the other will be zero.
01448 *
01449 * There is no workaround; we need to create a duplicate model that has only that surface
01450 * and its children (and grand-children). Then the var len sense edge-face tags will have
01451 * the right size.
01452 *
01453 */
01454 ErrorCode GeomTopoTool::duplicate_model( GeomTopoTool*& duplicate, std::vector< EntityHandle >* pvGEnts )
01455 {
01456 // will
01457 EntityHandle rootModelSet;
01458 ErrorCode rval = mdbImpl->create_meshset( MESHSET_SET, rootModelSet );MB_CHK_SET_ERR( rval, "Failed to create the rootModelSet" );
01459
01460 if( 0 == geomTag )
01461 {
01462 rval = mdbImpl->tag_get_handle( GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, geomTag );MB_CHK_SET_ERR( rval, "Failed to get the geometry dimension tag handle" );
01463 }
01464 if( 0 == gidTag )
01465 {
01466 gidTag = mdbImpl->globalId_tag();
01467 }
01468 // extract from the geomSet the dimension, children, and grand-children
01469 Range depSets; // dependents of the geomSet, including the geomSet
01470 // add in this range all the dependents of this, to filter the ones that need to be deep copied
01471
01472 if( pvGEnts != NULL )
01473 {
01474 unsigned int numGents = pvGEnts->size();
01475 for( unsigned int k = 0; k < numGents; k++ )
01476 {
01477 EntityHandle geomSet = ( *pvGEnts )[k];
01478 // will keep accumulating to the depSets range
01479 rval = mdbImpl->get_child_meshsets( geomSet, depSets, 0 ); // 0 for numHops means that all
01480 // dependents are returned, not only the direct children.
01481 MB_CHK_SET_ERR( rval, "Failed to get the geometry set's child meshsets" );
01482
01483 depSets.insert( geomSet );
01484 }
01485 }
01486
01487 // add to the root model set copies of the gsets, with correct sets
01488 // keep a map between sets to help in copying parent/child relations
01489 std::map< EntityHandle, EntityHandle > relate;
01490 // each set will get the same entities as the original
01491 for( int dim = 0; dim < 5; dim++ )
01492 {
01493 int gid = 0;
01494 unsigned int set_options = ( ( 1 != dim ) ? MESHSET_SET : MESHSET_ORDERED );
01495 for( Range::iterator it = geomRanges[dim].begin(); it != geomRanges[dim].end(); ++it )
01496 {
01497 EntityHandle set = *it;
01498 if( pvGEnts != NULL && depSets.find( set ) == depSets.end() )
01499 continue; // this means that this set is not of interest, skip it
01500 EntityHandle newSet;
01501 rval = mdbImpl->create_meshset( set_options, newSet );MB_CHK_SET_ERR( rval, "Failed to create new meshset" );
01502
01503 relate[set] = newSet;
01504 rval = mdbImpl->add_entities( rootModelSet, &newSet, 1 );MB_CHK_SET_ERR( rval, "Failed to add the new meshset to the tool's modelSet" );
01505
01506 // make it a geo set, and give also global id in order
01507 rval = mdbImpl->tag_set_data( geomTag, &newSet, 1, &dim );MB_CHK_SET_ERR( rval, "Failed to set the new meshset's geometry dimension data" );
01508
01509 gid++; // increment global id, everything starts with 1 in the new model!
01510 rval = mdbImpl->tag_set_data( gidTag, &newSet, 1, &gid );MB_CHK_SET_ERR( rval, "Failed to get the new meshset's global id data" );
01511
01512 if( dim == 1 )
01513 {
01514 // the entities are ordered, we need to retrieve them ordered, and set them ordered
01515 std::vector< EntityHandle > mesh_edges;
01516 rval = mdbImpl->get_entities_by_handle( set, mesh_edges );MB_CHK_SET_ERR( rval, "Failed to get the meshset entities by handle" );
01517
01518 rval = mdbImpl->add_entities( newSet, &( mesh_edges[0] ), (int)mesh_edges.size() );MB_CHK_SET_ERR( rval, "Failed to add the new entities to the new meshset" );
01519 }
01520 else
01521 {
01522 Range ents;
01523 rval = mdbImpl->get_entities_by_handle( set, ents );MB_CHK_SET_ERR( rval, "Failed to add the entities to the existing meshset" );
01524
01525 rval = mdbImpl->add_entities( newSet, ents );MB_CHK_SET_ERR( rval, "Failed to add the entities to the new meshset" );
01526 }
01527 // set parent/child relations if dim>=1
01528 if( dim >= 1 )
01529 {
01530 Range children;
01531 // the children of geo sets are only g sets
01532 rval = mdbImpl->get_child_meshsets( set, children ); // num_hops = 1 by default
01533 MB_CHK_SET_ERR( rval, "Failed to get the child meshsets of the existing set" );
01534
01535 for( Range::iterator it2 = children.begin(); it2 != children.end(); ++it2 )
01536 {
01537 EntityHandle newChildSet = relate[*it2];
01538 rval = mdbImpl->add_parent_child( newSet, newChildSet );MB_CHK_SET_ERR( rval, "Failed to create parent child relationship to the new meshset" );
01539 }
01540 }
01541 }
01542 }
01543
01544 duplicate = new GeomTopoTool( mdbImpl, true, rootModelSet ); // will retrieve the
01545 // sets and put them in ranges
01546
01547 // this is the lazy way to it:
01548 // newgtt->restore_topology_from_adjacency(); // will reset the sense entities, and with this,
01549 // the model represented by this new gtt will be complete set senses by peeking at the old model
01550 // make sure we have the sense tags defined
01551 rval = check_face_sense_tag( true );MB_CHK_SET_ERR( rval, "Failed to check the face to volume sense tag handle" );
01552
01553 rval = check_edge_sense_tags( true );MB_CHK_SET_ERR( rval, "Failed to check the curve to surface sense tag handles" );
01554
01555 for( int dd = 1; dd <= 2; dd++ ) // do it for surfaces and edges
01556 {
01557 for( Range::iterator it = geomRanges[dd].begin(); it != geomRanges[dd].end(); ++it )
01558 {
01559 EntityHandle surf = *it;
01560 if( pvGEnts != NULL && depSets.find( surf ) == depSets.end() )
01561 continue; // this means that this set is not of interest, skip it
01562 EntityHandle newSurf = relate[surf];
01563 // we can actually look at the tag data, to be more efficient
01564 // or use the
01565 std::vector< EntityHandle > solids;
01566 std::vector< int > senses;
01567 rval = this->get_senses( surf, solids, senses );MB_CHK_SET_ERR( rval, "Failed to get the sense data for the surface with respect to its volumes" );
01568
01569 std::vector< EntityHandle > newSolids;
01570 std::vector< int > newSenses;
01571 for( unsigned int i = 0; i < solids.size(); i++ )
01572 {
01573 if( pvGEnts != NULL && depSets.find( solids[i] ) == depSets.end() )
01574 continue; // this means that this set is not of interest, skip it
01575 EntityHandle newSolid = relate[solids[i]];
01576 // see which "solids" are in the new model
01577 newSolids.push_back( newSolid );
01578 newSenses.push_back( senses[i] );
01579 }
01580 rval = duplicate->set_senses( newSurf, newSolids, newSenses );MB_CHK_SET_ERR( rval, "Failed to set the sense data for the surface with respect to the new volumes" );
01581 }
01582 }
01583 // if the original root model set for this model is 0 (root set), then create
01584 // a new set and put all the old sets in the new model set
01585 // in this way, the existing gtt remains valid (otherwise, the modelSet would contain all the
01586 // gsets, the old ones and the new ones; the root set contains everything)
01587 if( modelSet == 0 )
01588 {
01589 rval = mdbImpl->create_meshset( MESHSET_SET, modelSet );MB_CHK_SET_ERR( rval, "Failed to create the modelSet meshset" );
01590
01591 // add to this new set all previous sets (which are still in ranges)
01592 for( int dim = 0; dim < 5; dim++ )
01593 {
01594 rval = mdbImpl->add_entities( modelSet, geomRanges[dim] );MB_CHK_SET_ERR( rval, "Failed to add the geometric meshsets to the tool's modelSet" );
01595 }
01596 }
01597 return MB_SUCCESS;
01598 }
01599
01600 ErrorCode GeomTopoTool::get_implicit_complement( EntityHandle& implicit_complement )
01601 {
01602 if( impl_compl_handle )
01603 {
01604 implicit_complement = impl_compl_handle;
01605 return MB_SUCCESS;
01606 }
01607 else
01608 {
01609 return MB_ENTITY_NOT_FOUND;
01610 }
01611 }
01612
01613 ErrorCode GeomTopoTool::setup_implicit_complement()
01614 {
01615
01616 // if the implicit complement is already setup,
01617 // we're done
01618 if( impl_compl_handle != 0 )
01619 {
01620 std::cout << "IPC already exists!" << std::endl;
01621 return MB_SUCCESS;
01622 }
01623
01624 // if not, then query for a set with it's name
01625 Range entities;
01626 const void* const tagdata[] = { IMPLICIT_COMPLEMENT_NAME };
01627 ErrorCode rval = mdbImpl->get_entities_by_type_and_tag( modelSet, MBENTITYSET, &nameTag, tagdata, 1, entities );
01628 // query error
01629 MB_CHK_SET_ERR( rval, "Unable to query for implicit complement" );
01630
01631 // if we found exactly one, set it as the implicit complement
01632 if( entities.size() == 1 )
01633 {
01634 impl_compl_handle = entities.front();
01635 return MB_SUCCESS;
01636 }
01637
01638 // found too many
01639 if( entities.size() > 1 ) MB_CHK_SET_ERR( MB_MULTIPLE_ENTITIES_FOUND, "Too many implicit complement sets" );
01640
01641 // found none
01642 if( entities.empty() )
01643 {
01644 // create implicit complement if requested
01645 rval = generate_implicit_complement( impl_compl_handle );MB_CHK_SET_ERR( rval, "Could not create implicit complement" );
01646
01647 rval = mdbImpl->tag_set_data( nameTag, &impl_compl_handle, 1, &IMPLICIT_COMPLEMENT_NAME );MB_CHK_SET_ERR( rval, "Could not set the name tag for the implicit complement" );
01648
01649 rval = add_geo_set( impl_compl_handle, 3 );MB_CHK_SET_ERR( rval, "Failed to add implicit complement to model" );
01650
01651 // assign category tag - this is presumably for consistency so that the
01652 // implicit complement has all the appearance of being the same as any
01653 // other volume
01654 Tag category_tag;
01655 rval = mdbImpl->tag_get_handle( CATEGORY_TAG_NAME, CATEGORY_TAG_SIZE, MB_TYPE_OPAQUE, category_tag,
01656 MB_TAG_SPARSE | MB_TAG_CREAT );MB_CHK_SET_ERR( rval, "Could not get the category tag" );
01657
01658 static const char volume_category[CATEGORY_TAG_SIZE] = "Volume\0";
01659 rval = mdbImpl->tag_set_data( category_tag, &impl_compl_handle, 1, volume_category );MB_CHK_SET_ERR( rval, "Could not set the category tag for the implicit complement" );
01660
01661 return MB_SUCCESS;
01662 }
01663
01664 return MB_FAILURE;
01665 }
01666
01667 ErrorCode GeomTopoTool::generate_implicit_complement( EntityHandle& implicit_complement_set )
01668 {
01669
01670 ErrorCode rval;
01671 rval = mdbImpl->create_meshset( MESHSET_SET, implicit_complement_set );MB_CHK_SET_ERR( rval, "Failed to create mesh set for implicit complement" );
01672
01673 // make sure the sense2Tag is set
01674 if( !sense2Tag )
01675 {
01676 check_face_sense_tag( true );
01677 }
01678
01679 // get all geometric surface sets
01680 Range surfs;
01681 rval = get_gsets_by_dimension( 2, surfs );MB_CHK_SET_ERR( rval, "Could not get surface sets" );
01682
01683 // search through all surfaces
01684 std::vector< EntityHandle > parent_vols;
01685 for( Range::iterator surf_i = surfs.begin(); surf_i != surfs.end(); ++surf_i )
01686 {
01687
01688 parent_vols.clear();
01689 // get parents of each surface
01690 rval = mdbImpl->get_parent_meshsets( *surf_i, parent_vols );MB_CHK_SET_ERR( rval, "Failed to get volume meshsets" );
01691
01692 // if only one parent, get the OBB root for this surface
01693 if( parent_vols.size() == 1 )
01694 {
01695
01696 // add this surf to the topology of the implicit complement volume
01697 rval = mdbImpl->add_parent_child( implicit_complement_set, *surf_i );MB_CHK_SET_ERR( rval, "Could not add surface to implicit complement set" );
01698
01699 // get the surface sense wrt original volume
01700 EntityHandle sense_data[2] = { 0, 0 };
01701 rval = get_surface_senses( *surf_i, sense_data[0], sense_data[1] );MB_CHK_SET_ERR( rval, "Could not get surface sense data" );
01702
01703 // set the surface sense wrt implicit complement volume
01704 if( 0 == sense_data[0] && 0 == sense_data[1] )
01705 MB_SET_ERR( MB_FAILURE, "No sense data for current surface" );
01706 if( 0 == sense_data[0] )
01707 sense_data[0] = implicit_complement_set;
01708 else if( 0 == sense_data[1] )
01709 sense_data[1] = implicit_complement_set;
01710 else
01711 MB_SET_ERR( MB_FAILURE, "Could not insert implicit complement into surface sense data" );
01712
01713 // set the new sense data for this surface
01714 rval = set_surface_senses( *surf_i, sense_data[0], sense_data[1] );MB_CHK_SET_ERR( rval, "Failed to set sense tag data" );
01715 }
01716 } // end surface loop
01717
01718 return MB_SUCCESS;
01719 }
01720
01721 #define RETFALSE( a, b ) \
01722 { \
01723 std::cout << ( a ) << "\n"; \
01724 mdbImpl->list_entity( b ); \
01725 return false; \
01726 }
01727 bool GeomTopoTool::check_model()
01728 {
01729 // vertex sets should have one node
01730 Range::iterator rit;
01731 ErrorCode rval;
01732 for( rit = geomRanges[0].begin(); rit != geomRanges[0].end(); ++rit )
01733 {
01734 EntityHandle vSet = *rit;
01735 Range nodes;
01736 rval = mdbImpl->get_entities_by_handle( vSet, nodes );
01737 if( MB_SUCCESS != rval ) RETFALSE( " failed to get nodes from vertex set ", vSet );
01738 if( nodes.size() != 1 ) RETFALSE( " number of nodes is different from 1 ", vSet )
01739 EntityType type = mdbImpl->type_from_handle( nodes[0] );
01740 if( type != MBVERTEX ) RETFALSE( " entity in vertex set is not a node ", nodes[0] )
01741 // get all parents, and see if they belong to geomRanges[1]
01742 Range edges;
01743 rval = mdbImpl->get_parent_meshsets( vSet, edges );
01744 if( MB_SUCCESS != rval ) RETFALSE( " can't get parent edges for a node set ", vSet )
01745 Range notEdges = subtract( edges, geomRanges[1] );
01746 if( !notEdges.empty() ) RETFALSE( " some parents of a node set are not geo edges ", notEdges[0] )
01747 }
01748
01749 // edges to be formed by continuous chain of mesh edges, oriented correctly
01750 for( rit = geomRanges[1].begin(); rit != geomRanges[1].end(); ++rit )
01751 {
01752 EntityHandle edge = *rit;
01753 std::vector< EntityHandle > mesh_edges;
01754 rval = mdbImpl->get_entities_by_type( edge, MBEDGE, mesh_edges );
01755 if( MB_SUCCESS != rval ) RETFALSE( " can't get mesh edges from edge set", edge )
01756 int num_edges = (int)mesh_edges.size();
01757 if( num_edges == 0 ) RETFALSE( " no mesh edges in edge set ", edge )
01758 EntityHandle firstNode;
01759 EntityHandle currentNode; // will also hold the last node in chain of edges
01760 const EntityHandle* conn2;
01761 int nnodes2;
01762 // get all parents, and see if they belong to geomRanges[1]
01763 for( int i = 0; i < num_edges; i++ )
01764 {
01765 rval = mdbImpl->get_connectivity( mesh_edges[i], conn2, nnodes2 );
01766 if( MB_SUCCESS != rval || nnodes2 != 2 ) RETFALSE( " mesh edge connectivity is wrong ", mesh_edges[i] )
01767 if( i == 0 )
01768 {
01769 firstNode = conn2[0];
01770 currentNode = conn2[1];
01771 }
01772
01773 else // if ( (i>0) )
01774 {
01775 // check the current node is conn[0]
01776 if( conn2[0] != currentNode )
01777 {
01778 std::cout << "i=" << i << " conn2:" << conn2[0] << " " << conn2[1] << " currentNode:" << currentNode
01779 << "\n";
01780 mdbImpl->list_entity( mesh_edges[i] );
01781 RETFALSE( " edges are not contiguous in edge set ", edge )
01782 }
01783 currentNode = conn2[1];
01784 }
01785 }
01786 // check the children of the edge set; do they have the first and last node?
01787 Range vertSets;
01788 rval = mdbImpl->get_child_meshsets( edge, vertSets );
01789 if( MB_SUCCESS != rval ) RETFALSE( " can't get vertex children ", edge )
01790 Range notVertices = subtract( vertSets, geomRanges[0] );
01791 if( !notVertices.empty() ) RETFALSE( " children sets that are not vertices ", notVertices[0] )
01792 for( Range::iterator it = vertSets.begin(); it != vertSets.end(); ++it )
01793 {
01794 if( !mdbImpl->contains_entities( *it, &firstNode, 1 ) &&
01795 !mdbImpl->contains_entities( *it, ¤tNode, 1 ) )
01796 RETFALSE( " a vertex set is not containing the first and last nodes ", *it )
01797 }
01798 // check now the faces / parents
01799 Range faceSets;
01800 rval = mdbImpl->get_parent_meshsets( edge, faceSets );
01801 if( MB_SUCCESS != rval ) RETFALSE( " can't get edge parents ", edge )
01802 Range notFaces = subtract( faceSets, geomRanges[2] );
01803 if( !notFaces.empty() ) RETFALSE( " parent sets that are not faces ", notFaces[0] )
01804
01805 // for a geo edge, check the sense tags with respect to the adjacent faces
01806 // in general, it is sufficient to check one mesh edge (the first one)
01807 // edge/face senses
01808 EntityHandle firstMeshEdge = mesh_edges[0];
01809 // get all entities/elements adjacent to it
01810 Range adjElem;
01811 rval = mdbImpl->get_adjacencies( &firstMeshEdge, 1, 2, false, adjElem );
01812 if( MB_SUCCESS != rval ) RETFALSE( " can't get adjacent elements to the edge ", firstMeshEdge )
01813 for( Range::iterator it2 = adjElem.begin(); it2 != adjElem.end(); ++it2 )
01814 {
01815 EntityHandle elem = *it2;
01816 // find the geo face it belongs to
01817 EntityHandle gFace = 0;
01818 for( Range::iterator fit = faceSets.begin(); fit != faceSets.end(); ++fit )
01819 {
01820 EntityHandle possibleFace = *fit;
01821 if( mdbImpl->contains_entities( possibleFace, &elem, 1 ) )
01822 {
01823 gFace = possibleFace;
01824 break;
01825 }
01826 }
01827 if( 0 == gFace )
01828 RETFALSE( " can't find adjacent surface that contains the adjacent element to the edge ",
01829 firstMeshEdge )
01830
01831 // now, check the sense of mesh_edge in element, and the sense of gedge in gface
01832 // side_number
01833 int side_n, sense, offset;
01834 rval = mdbImpl->side_number( elem, firstMeshEdge, side_n, sense, offset );
01835 if( MB_SUCCESS != rval ) RETFALSE( " can't get sense and side number of an element ", elem )
01836 // now get the sense
01837 int topoSense;
01838 rval = this->get_sense( edge, gFace, topoSense );
01839 if( topoSense != sense ) RETFALSE( " geometric topo sense and element sense do not agree ", edge )
01840 }
01841 }
01842 // surfaces to be true meshes
01843 // for surfaces, check that the skinner will find the correct boundary
01844
01845 // use the skinner for boundary check
01846 Skinner tool( mdbImpl );
01847
01848 for( rit = geomRanges[2].begin(); rit != geomRanges[2].end(); ++rit )
01849 {
01850 EntityHandle faceSet = *rit;
01851 // get all boundary edges (adjacent edges)
01852
01853 Range edges;
01854 rval = mdbImpl->get_child_meshsets( faceSet, edges );
01855 if( MB_SUCCESS != rval ) RETFALSE( " can't get children edges for a face set ", faceSet )
01856 Range notEdges = subtract( edges, geomRanges[1] );
01857 if( !notEdges.empty() ) RETFALSE( " some children of a face set are not geo edges ", notEdges[0] )
01858
01859 Range boundary_mesh_edges;
01860 for( Range::iterator it = edges.begin(); it != edges.end(); ++it )
01861 {
01862 rval = mdbImpl->get_entities_by_type( *it, MBEDGE, boundary_mesh_edges );
01863 if( MB_SUCCESS != rval ) RETFALSE( " can't get edge elements from the edge set ", *it )
01864 }
01865 // skin the elements of the surface
01866 // most of these should be triangles and quads
01867 Range surface_ents, edge_ents;
01868 rval = mdbImpl->get_entities_by_dimension( faceSet, 2, surface_ents );
01869 if( MB_SUCCESS != rval ) RETFALSE( " can't get surface elements from the face set ", faceSet )
01870
01871 rval = tool.find_skin( 0, surface_ents, 1, edge_ents );
01872 if( MB_SUCCESS != rval ) RETFALSE( "can't skin a surface ", surface_ents[0] )
01873
01874 // those 2 ranges for boundary edges now must be equal
01875 if( boundary_mesh_edges != edge_ents ) RETFALSE( "boundary ranges are different", boundary_mesh_edges[0] )
01876 }
01877
01878 // solids to be filled correctly, maybe a skin procedure too.
01879 // (maybe the solids are empty)
01880
01881 return true;
01882 }
01883
01884 bool GeomTopoTool::have_obb_tree()
01885 {
01886 return rootSets.size() != 0 || mapRootSets.size() != 0;
01887 }
01888
01889 // This function gets coordinates of the minimum and maxmiumum points
01890 // from an OBB/AABB, ie. such that these points represent
01891 // the maximum and minium extents of an AABB
01892 ErrorCode GeomTopoTool::get_bounding_coords( EntityHandle volume, double minPt[3], double maxPt[3] )
01893 {
01894 double center[3], axis1[3], axis2[3], axis3[3];
01895
01896 // get center point and vectors to OBB faces
01897 ErrorCode rval = get_obb( volume, center, axis1, axis2, axis3 );MB_CHK_SET_ERR( rval, "Failed to get the oriented bounding box of the volume" );
01898
01899 // compute min and max vertices
01900 for( int i = 0; i < 3; i++ )
01901 {
01902 double sum = fabs( axis1[i] ) + fabs( axis2[i] ) + fabs( axis3[i] );
01903 minPt[i] = center[i] - sum;
01904 maxPt[i] = center[i] + sum;
01905 }
01906 return MB_SUCCESS;
01907 }
01908
01909 ErrorCode GeomTopoTool::get_obb( EntityHandle volume,
01910 double center[3],
01911 double axis1[3],
01912 double axis2[3],
01913 double axis3[3] )
01914 {
01915 // find EntityHandle node_set for use in box
01916 EntityHandle root;
01917 ErrorCode rval = get_root( volume, root );MB_CHK_SET_ERR( rval, "Failed to get volume's obb tree root" );
01918
01919 // call box to get center and vectors to faces
01920 return obbTree->box( root, center, axis1, axis2, axis3 );
01921 }
01922
01923 Range GeomTopoTool::get_ct_children_by_dimension( EntityHandle parent, int desired_dimension )
01924 {
01925 Range all_children, desired_children;
01926 Range::iterator it;
01927 int actual_dimension;
01928
01929 desired_children.clear();
01930 all_children.clear();
01931 mdbImpl->get_child_meshsets( parent, all_children );
01932
01933 for( it = all_children.begin(); it != all_children.end(); ++it )
01934 {
01935 mdbImpl->tag_get_data( geomTag, &( *it ), 1, &actual_dimension );
01936 if( actual_dimension == desired_dimension ) desired_children.insert( *it );
01937 }
01938
01939 return desired_children;
01940 }
01941
01942 // runs GeomQueryTool point_in_vol and to test if vol A is inside vol B
01943 // returns true or false
01944 bool GeomTopoTool::A_is_in_B( EntityHandle volume_A, EntityHandle volume_B, GeomQueryTool* GQT )
01945 {
01946 ErrorCode rval;
01947
01948 Range child_surfaces, triangles, vertices;
01949 double coord[3]; // coord[0] = x, etc.
01950 int result; // point in vol result; 0=F, 1=T
01951
01952 // find coordinates of any point on surface of A
01953 // get surface corresponding to volume, then get the triangles
01954 child_surfaces = get_ct_children_by_dimension( volume_A, 2 );
01955 rval = mdbImpl->get_entities_by_type( *child_surfaces.begin(), MBTRI, triangles );MB_CHK_ERR( rval );
01956
01957 // now get 1st triangle vertices
01958 rval = mdbImpl->get_connectivity( &( *triangles.begin() ), 1, vertices );MB_CHK_ERR( rval );
01959
01960 // now get coordinates of first vertex
01961 rval = mdbImpl->get_coords( &( *vertices.begin() ), 1, &( coord[0] ) );MB_CHK_ERR( rval );
01962
01963 // if point on A is inside vol B, return T; o.w. return F
01964 rval = GQT->point_in_volume( volume_B, coord, result );MB_CHK_SET_ERR( rval, "Failed to complete point in volume query." );
01965
01966 return ( result != 0 );
01967 }
01968
01969 ErrorCode GeomTopoTool::insert_in_tree( EntityHandle ct_root, EntityHandle volume, GeomQueryTool* GQT )
01970 {
01971 ErrorCode rval;
01972
01973 bool inserted = false;
01974 EntityHandle current_volume = volume; // volume to be inserted
01975 EntityHandle tree_volume = ct_root; // volume already existing in the tree
01976 EntityHandle parent = ct_root;
01977 Range child_volumes;
01978
01979 // while not inserted in tree
01980 while( !inserted )
01981 {
01982 // if current volume is insde of tree volume-- always true if tree volume
01983 // is the root of the tree
01984 if( tree_volume == ct_root || ( tree_volume != ct_root && A_is_in_B( current_volume, tree_volume, GQT ) ) )
01985 {
01986
01987 parent = tree_volume;
01988
01989 // if tree_volume has children then we must test them,
01990 // (tree_volume will change)
01991 child_volumes = get_ct_children_by_dimension( tree_volume, 3 );
01992 if( child_volumes.size() > 0 ) tree_volume = child_volumes.pop_front();
01993 // otherwise current_volume is the only child of the tree volume
01994 else
01995 {
01996 rval = mdbImpl->add_parent_child( parent, current_volume );MB_CHK_SET_ERR( rval, "Failed to add parent-child relationship." );
01997
01998 inserted = true;
01999 }
02000 // if current volume is not in the tree volume, the converse may be true
02001 }
02002 else
02003 {
02004 // if the tree volume is inside the current volume
02005 if( A_is_in_B( tree_volume, current_volume, GQT ) )
02006 {
02007 // reverse their parentage
02008 rval = mdbImpl->remove_parent_child( parent, tree_volume );MB_CHK_SET_ERR( rval, "Failed to remove parent-child relationship." );
02009 rval = mdbImpl->add_parent_child( current_volume, tree_volume );MB_CHK_SET_ERR( rval, "Failed to add parent-child relationship." );
02010 }
02011
02012 if( child_volumes.size() == 0 )
02013 {
02014 rval = mdbImpl->add_parent_child( parent, current_volume );MB_CHK_SET_ERR( rval, "Failed to add parent-child relationship." );
02015 inserted = true;
02016 }
02017 else
02018 tree_volume = child_volumes.pop_front();
02019 }
02020 }
02021 return MB_SUCCESS;
02022 }
02023
02024 ErrorCode GeomTopoTool::restore_topology_from_geometric_inclusion( const Range& flat_volumes )
02025 {
02026
02027 ErrorCode rval;
02028 // local var will go out of scope if errors appear, no need to free it also
02029 GeomQueryTool GQT( this );
02030 std::map< EntityHandle, EntityHandle > volume_surface; // map of volume
02031 // to its surface
02032
02033 EntityHandle ct_root;
02034 // create root meshset-- this will be top of tree
02035 std::string meshset_name = "build_hierarchy_root";
02036 rval = mdbImpl->create_meshset( MESHSET_SET, ct_root );MB_CHK_ERR( rval );
02037 rval = mdbImpl->tag_set_data( nameTag, &ct_root, 1, meshset_name.c_str() );MB_CHK_ERR( rval );
02038
02039 for( Range::iterator vol = flat_volumes.begin(); vol != flat_volumes.end(); vol++ )
02040 {
02041 // get the surface corresponding to each volume
02042 // at this point, each volume meshset only has one 'child' surface
02043 // which exactly corresponds to that volume
02044 Range child_surfaces = get_ct_children_by_dimension( *vol, 2 );
02045 volume_surface[*vol] = *child_surfaces.begin();
02046
02047 rval = insert_in_tree( ct_root, *vol, &GQT );MB_CHK_SET_ERR( rval, "Failed to insert volume into tree." );
02048 }
02049
02050 // for each original volume, get its child volumes
02051 for( Range::iterator parent_it = flat_volumes.begin(); parent_it != flat_volumes.end(); parent_it++ )
02052 {
02053 Range volume_children = get_ct_children_by_dimension( *parent_it, 3 );
02054
02055 if( volume_children.size() != 0 )
02056 {
02057 // loop over all of original volume's child volumes
02058 for( Range::iterator child_it = volume_children.begin(); child_it != volume_children.end(); ++child_it )
02059 {
02060 // set the sense of the surface mapped to the child volume to REVERSE
02061 // wrt the parent volume
02062 rval = set_sense( volume_surface[*child_it], *parent_it, SENSE_REVERSE );MB_CHK_SET_ERR( rval, "Failed to set sense." );
02063
02064 // add the child volume's surface as a child of the original volume
02065 // and delete the child volume as a child of original volume
02066 rval = mdbImpl->add_parent_child( *parent_it, volume_surface[*child_it] );MB_CHK_SET_ERR( rval, "Failed to add parent-child relationship." );
02067 rval = mdbImpl->remove_parent_child( *parent_it, *child_it );MB_CHK_SET_ERR( rval, "Failed to remove parent-child relationship." );
02068 }
02069 }
02070 }
02071
02072 return MB_SUCCESS;
02073 }
02074
02075 } // namespace moab