1/**
2 * MOAB, a Mesh-Oriented datABase, is a software component for creating,
3 * storing and accessing finite element mesh data.
4 *
5 * Copyright 2004 Sandia Corporation. Under the terms of Contract
6 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
7 * retains certain rights in this software.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 */1516#include"moab/GeomTopoTool.hpp"17#include"moab/GeomQueryTool.hpp"18#include"moab/OrientedBoxTreeTool.hpp"19#include"moab/Range.hpp"20#include"MBTagConventions.hpp"21#include"moab/Interface.hpp"22#include"moab/CN.hpp"23#include"moab/Skinner.hpp"24#include"Internals.hpp"25#include<iostream>2627namespace moab
28 {
2930// Tag name used for saving sense of faces in volumes.31// We assume that the surface occurs in at most two volumes.32// Code will error out if more than two volumes per surface.33// The tag data is a pair of tag handles, representing the34// forward and reverse volumes, respectively. If a surface35// is non-manifold in a single volume, the same volume will36// be listed for both the forward and reverse slots.37constchar GEOM_SENSE_2_TAG_NAME[] = "GEOM_SENSE_2";
3839constchar GEOM_SENSE_N_ENTS_TAG_NAME[] = "GEOM_SENSE_N_ENTS";
40constchar GEOM_SENSE_N_SENSES_TAG_NAME[] = "GEOM_SENSE_N_SENSES";
41constchar OBB_ROOT_TAG_NAME[] = "OBB_ROOT";
42constchar OBB_GSET_TAG_NAME[] = "OBB_GSET";
4344constchar IMPLICIT_COMPLEMENT_NAME[] = "impl_complement";
4546 GeomTopoTool::GeomTopoTool( Interface* impl,
47bool find_geoments,
48 EntityHandle modelRootSet,
49bool p_rootSets_vector,
50bool restore_rootSets )
51 : mdbImpl( impl ), sense2Tag( 0 ), senseNEntsTag( 0 ), senseNSensesTag( 0 ), geomTag( 0 ), gidTag( 0 ),
52obbRootTag( 0 ), obbGsetTag( 0 ), modelSet( modelRootSet ), updated( false ), setOffset( 0 ),
53m_rootSets_vector( p_rootSets_vector ), oneVolRootSet( 0 )
54 {
5556 obbTree = newOrientedBoxTreeTool( impl, NULL, true );
5758 ErrorCode rval =
59 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" );
6061// global id tag is not really needed, but mbsize complains if we do not set it for62// geometry entities63 gidTag = mdbImpl->globalId_tag();
6465 rval =
66 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" );
6768 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" );
6970 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" );
7172// set this value to zero for comparisons73 impl_compl_handle = 0;
7475 maxGlobalId[0] = maxGlobalId[1] = maxGlobalId[2] = maxGlobalId[3] = maxGlobalId[4] = 0;
76if( find_geoments )
77 {
78find_geomsets();
79if( restore_rootSets )
80 {
81 rval = restore_obb_index();
82if( MB_SUCCESS != rval )
83 {
84 rval = delete_all_obb_trees();MB_CHK_SET_ERR_CONT( rval, "Error: Failed to delete existing obb trees" );
85 rval = construct_obb_trees();MB_CHK_SET_ERR_CONT( rval, "Error: Failed to rebuild obb trees" );
86 }
87 }
88 }
89 }
9091 GeomTopoTool::~GeomTopoTool()
92 {
93delete obbTree;
94 }
9596intGeomTopoTool::dimension( EntityHandle this_set )
97 {
98 ErrorCode result;
99if( 0 == geomTag )
100 {
101 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" );
102 }
103104// check if the geo set belongs to this model105if( modelSet )
106 {
107if( !mdbImpl->contains_entities( modelSet, &this_set, 1 ) )
108 {
109// this g set does not belong to the current model110return-1;
111 }
112 }
113// get the data for those tags114int dim;
115 result = mdbImpl->tag_get_data( geomTag, &this_set, 1, &dim );
116if( MB_SUCCESS != result )
117return-1;
118else119return dim;
120 }
121122intGeomTopoTool::global_id( EntityHandle this_set )
123 {
124 ErrorCode result;
125if( 0 == gidTag )
126 {
127 gidTag = mdbImpl->globalId_tag();
128 }
129130// check if the geo set belongs to this model131if( modelSet )
132 {
133if( !mdbImpl->contains_entities( modelSet, &this_set, 1 ) )
134 {
135// this g set does not belong to the current model136return-1;
137 }
138 }
139140// get the data for those tags141int id;
142 result = mdbImpl->tag_get_data( gidTag, &this_set, 1, &id );
143if( MB_SUCCESS != result )
144return-1;
145else146return id;
147 }
148149EntityHandle GeomTopoTool::entity_by_id( int dimension1, int id )
150 {
151if( 0 > dimension1 || 3 < dimension1 )
152 {
153MB_CHK_SET_ERR_CONT( MB_FAILURE, "Incorrect dimension provided" );
154 }
155const Tag tags[] = { gidTag, geomTag };
156constvoid* const vals[] = { &id, &dimension1 };
157 ErrorCode rval;
158159 Range results;
160 rval = mdbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET, tags, vals, 2, results );
161162if( MB_SUCCESS != rval )
163return0;
164else165return results.front();
166 }
167168ErrorCode GeomTopoTool::other_entity( EntityHandle bounded,
169 EntityHandle not_this,
170 EntityHandle across,
171 EntityHandle& other )
172 {
173 other = 0;
174175// get all children of bounded176 Range bdy, tmpr;
177 ErrorCode rval = mdbImpl->get_child_meshsets( bounded, bdy );MB_CHK_SET_ERR( rval, "Failed to get the bounded entity's child meshsets" );
178179// get all the parents of across180 rval = mdbImpl->get_parent_meshsets( across, tmpr );
181182// possible candidates is the intersection183 bdy = intersect( bdy, tmpr );
184185// if only two, choose the other186if( 1 == bdy.size() && *bdy.begin() == not_this )
187 {
188return MB_SUCCESS;
189 }
190elseif( 2 == bdy.size() )
191 {
192if( *bdy.begin() == not_this ) other = *bdy.rbegin();
193if( *bdy.rbegin() == not_this )
194 other = *bdy.begin();
195else196return MB_FAILURE;
197 }
198else199 {
200return MB_FAILURE;
201 }
202203return MB_SUCCESS;
204 }
205206ErrorCode GeomTopoTool::restore_obb_index()
207 {
208209if( m_rootSets_vector ) resize_rootSets();
210211 ErrorCode rval;
212 EntityHandle root;
213214for( int dim = 2; dim <= 3; dim++ )
215for( Range::iterator rit = geomRanges[dim].begin(); rit != geomRanges[dim].end(); ++rit )
216 {
217 rval = mdbImpl->tag_get_data( obbRootTag, &( *rit ), 1, &root );
218219if( MB_SUCCESS == rval )
220set_root_set( *rit, root );
221else222 {
223return MB_TAG_NOT_FOUND;
224 }
225 }
226227return MB_SUCCESS;
228 }
229230ErrorCode GeomTopoTool::find_geomsets( Range* ranges )
231 {
232 ErrorCode rval;
233// get all sets with this tag234 Range geom_sets;
235236if( 0 == geomTag )
237 {
238 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" );
239 }
240241 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" );
242243 rval = separate_by_dimension( geom_sets );MB_CHK_SET_ERR( rval, "Failed to separate geometry sets by dimension" );
244245if( ranges )
246 {
247for( int i = 0; i < 5; i++ )
248 {
249 ranges[i] = geomRanges[i];
250 }
251 }
252253return MB_SUCCESS;
254 }
255256ErrorCode GeomTopoTool::get_gsets_by_dimension( int dim, Range& gset )
257 {
258 ErrorCode rval;
259260constint val = dim;
261constvoid* const dim_val[] = { &val };
262 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" );
263264return MB_SUCCESS;
265 }
266267ErrorCode GeomTopoTool::resize_rootSets()
268 {
269270 ErrorCode rval;
271272// store original offset for later273 EntityHandle orig_offset = setOffset;
274275// get all surfaces and volumes276 Range surfs, vols;
277 rval = get_gsets_by_dimension( 2, surfs );MB_CHK_SET_ERR( rval, "Could not get surface sets" );
278 rval = get_gsets_by_dimension( 3, vols );MB_CHK_SET_ERR( rval, "Could not get volume sets" );
279280// check the vector size281 Range surfs_and_vols;
282 surfs_and_vols = vols;
283 surfs_and_vols.merge( surfs );
284285// update the setOffset286 setOffset = surfs_and_vols.front();
287288 EntityHandle exp_size = surfs_and_vols.back() - setOffset + 1;
289290// if new EnitytHandle(s) are lower than the original offset291if( setOffset < orig_offset )
292 {
293// insert empty values at the beginning of the vector294 rootSets.insert( rootSets.begin(), orig_offset - setOffset, 0 );
295 }
296297if( exp_size != rootSets.size() )
298 {
299// resize rootSets vector if necessary (new space will be added at the back)300 rootSets.resize( exp_size );
301 }
302303return MB_SUCCESS;
304 }
305306ErrorCode GeomTopoTool::is_owned_set( EntityHandle eh )
307 {
308// make sure entity set is part of the model309 Range model_ents;
310 ErrorCode rval = mdbImpl->get_entities_by_handle( modelSet, model_ents );MB_CHK_SET_ERR( rval, "Failed to get entities" );
311if( model_ents.find( eh ) == model_ents.end() )
312 {
313MB_SET_ERR( MB_FAILURE, "Entity handle not in model set" );
314 }
315return MB_SUCCESS;
316 }
317318ErrorCode GeomTopoTool::delete_obb_tree( EntityHandle gset, bool vol_only )
319 {
320321 ErrorCode rval;
322323// Make sure this set is part of the model324 rval = is_owned_set( gset );MB_CHK_SET_ERR( rval, "Entity set is not part of this model" );
325326// Find the dimension of the entity327int dim;
328 rval = mdbImpl->tag_get_data( geomTag, &gset, 1, &dim );MB_CHK_SET_ERR( rval, "Failed to get dimension" );
329330// Attempt to find a root for this set331 EntityHandle root;
332 rval = get_root( gset, root );MB_CHK_SET_ERR( rval, "Failed to find an obb tree root for the entity set" );
333334// Create range of tree nodes to delete335 Range nodes_to_delete;
336 nodes_to_delete.insert( root );
337338// If passed ent is a vol and 'vol_only' is true, delete vol root and all nodes between vol and339// surf root340if( dim == 3 && vol_only )
341 {
342// Range of child nodes to check before adding to delete list343 Range child_tree_nodes;
344 rval = mdbImpl->get_child_meshsets( root, child_tree_nodes );MB_CHK_SET_ERR( rval, "Problem getting child tree nodes" );
345346// Traverse the tree, checking each child node until347// a surface root node is reached348while( child_tree_nodes.size() != 0 )
349 {
350 EntityHandle child = *child_tree_nodes.begin();
351 EntityHandle surf;
352 rval = mdbImpl->tag_get_data( obbGsetTag, &child, 1, &surf );
353// If the node has a gset tag, it is a surf root. Stop here.354// If not, it is a tree node that needs to 1) have its children checked and355// 2) be added to delete range356if( MB_TAG_NOT_FOUND == rval )
357 {
358 Range new_child_tree_nodes;
359 rval = mdbImpl->get_child_meshsets( child, new_child_tree_nodes );MB_CHK_SET_ERR( rval, "Problem getting child nodes" );
360 child_tree_nodes.insert_list( new_child_tree_nodes.begin(), new_child_tree_nodes.end() );
361 nodes_to_delete.insert( child );
362 }
363// We're done checking this node, so can erase from child list364 child_tree_nodes.erase( child );
365 }
366 }
367// If passed ent is a surf or a vol and 'vol_only' is false, recursively gather all child nodes368// and add them to delete list369else370 {
371 Range all_tree_nodes;
372 rval = mdbImpl->get_child_meshsets( root, all_tree_nodes, 0 );MB_CHK_SET_ERR( rval, "Failed to get child tree node sets" );
373 nodes_to_delete.insert_list( all_tree_nodes.begin(), all_tree_nodes.end() );
374 }
375376// Remove the root nodes from the GTT data structures377for( Range::iterator it = nodes_to_delete.begin(); it != nodes_to_delete.end(); ++it )
378 {
379// Check to see if node is a root380 EntityHandle vol_or_surf;
381 rval = mdbImpl->tag_get_data( obbGsetTag, &( *it ), 1, &vol_or_surf );
382if( MB_SUCCESS == rval )
383 {
384// Remove from set of all roots385 rval = remove_root( vol_or_surf );MB_CHK_SET_ERR( rval, "Failed to remove node from GTT data structure" );
386 }
387 }
388389// Delete the tree nodes from the database390 rval = mdbImpl->delete_entities( nodes_to_delete );MB_CHK_SET_ERR( rval, "Failed to delete node set" );
391392return MB_SUCCESS;
393 }
394395ErrorCode GeomTopoTool::delete_all_obb_trees()
396 {
397398 ErrorCode rval;
399400for( Range::iterator rit = geomRanges[3].begin(); rit != geomRanges[3].end(); ++rit )
401 {
402 EntityHandle root;
403 rval = mdbImpl->tag_get_data( obbRootTag, &( *rit ), 1, &root );
404if( MB_SUCCESS == rval )
405 {
406 rval = delete_obb_tree( *rit, false );MB_CHK_SET_ERR( rval, "Failed to delete obb tree" );
407 }
408 }
409410return MB_SUCCESS;
411 }
412413ErrorCode GeomTopoTool::construct_obb_tree( EntityHandle eh )
414 {
415 ErrorCode rval;
416int dim;
417418 rval = is_owned_set( eh );MB_CHK_SET_ERR( rval, "Entity set is not part of this model" );
419420// get the type421 EntityType type = mdbImpl->type_from_handle( eh );
422423// find the dimension of the entity424 rval = mdbImpl->tag_get_data( geomTag, &eh, 1, &dim );MB_CHK_SET_ERR( rval, "Failed to get dimension" );
425426// ensure that the rootSets vector is of the correct size427if( m_rootSets_vector && ( eh < setOffset || eh >= setOffset + rootSets.size() ) )
428 {
429 rval = resize_rootSets();MB_CHK_SET_ERR( rval, "Error setting offset and sizing rootSets vector." );
430 }
431432 EntityHandle root;
433// if it's a surface434if( dim == 2 && type == MBENTITYSET )
435 {
436 rval = get_root( eh, root );
437if( MB_SUCCESS == rval )
438 {
439 std::cerr << "Surface obb tree already exists" << std::endl;
440return MB_SUCCESS;
441 }
442elseif( MB_INDEX_OUT_OF_RANGE != rval )
443 {
444MB_CHK_SET_ERR( rval, "Failed to get surface obb tree root" );
445 }
446447 Range tris;
448 rval = mdbImpl->get_entities_by_dimension( eh, 2, tris );MB_CHK_SET_ERR( rval, "Failed to get entities by dimension" );
449450if( tris.empty() )
451 {
452 std::cerr << "WARNING: Surface id " << global_id(eh) << " (handle: " << eh << ")" << "has no facets" << std::endl;
453 }
454455 rval = obbTree->build( tris, root );MB_CHK_SET_ERR( rval, "Failed to build obb Tree for surface" );
456457 rval = mdbImpl->add_entities( root, &eh, 1 );MB_CHK_SET_ERR( rval, "Failed to add entities to root set" );
458459// add this root to the GeomTopoTool tree root indexing460set_root_set( eh, root );
461462// if just building tree for surface, return here463return MB_SUCCESS;
464 }
465// if it's a volume466elseif( dim == 3 && type == MBENTITYSET )
467 {
468// get its surfaces469 Range tmp_surfs, surf_trees;
470 rval = mdbImpl->get_child_meshsets( eh, tmp_surfs );MB_CHK_SET_ERR( rval, "Failed to get surface meshsets" );
471472// get OBB trees or create for each surface473for( Range::iterator j = tmp_surfs.begin(); j != tmp_surfs.end(); ++j )
474 {
475 rval = get_root( *j, root );
476// if root doesn't exist, create obb tree477if( MB_INDEX_OUT_OF_RANGE == rval )
478 {
479 rval = construct_obb_tree( *j );MB_CHK_SET_ERR( rval, "Failed to get create surface obb tree" );
480 rval = get_root( *j, root );MB_CHK_SET_ERR( rval, "Failed to get surface obb tree root" );
481 }
482else483 {
484MB_CHK_SET_ERR( rval, "Failed to get surface obb tree root" );
485 }
486487 surf_trees.insert( root );
488 }
489490// build OBB tree for volume491 rval = obbTree->join_trees( surf_trees, root );MB_CHK_SET_ERR( rval, "Failed to join the obb trees" );
492493// add this root to the GeomTopoTool tree root indexing494set_root_set( eh, root );
495496return MB_SUCCESS;
497 }
498else499 {
500MB_SET_ERR( MB_FAILURE, "Improper dimension or type for constructing obb tree" );
501 }
502 }
503504ErrorCode GeomTopoTool::set_root_set( EntityHandle vol_or_surf, EntityHandle root )
505 {
506507// Tag the vol or surf with its obb root (obbRootTag)508 ErrorCode rval;
509 rval = mdbImpl->tag_set_data( obbRootTag, &vol_or_surf, 1, &root );MB_CHK_SET_ERR( rval, "Failed to set the obb root tag" );
510511// Tag obb root with corresponding gset (obbGsetTag)512 rval = mdbImpl->tag_set_data( obbGsetTag, &root, 1, &vol_or_surf );MB_CHK_SET_ERR( rval, "Failed to set the obb gset tag" );
513514// Add to the set of all roots515if( m_rootSets_vector )
516 rootSets[vol_or_surf - setOffset] = root;
517else518 mapRootSets[vol_or_surf] = root;
519520return MB_SUCCESS;
521 }
522523ErrorCode GeomTopoTool::remove_root( EntityHandle vol_or_surf )
524 {
525526// Find the root of the vol or surf527 ErrorCode rval;
528 EntityHandle root;
529 rval = mdbImpl->tag_get_data( obbRootTag, &( vol_or_surf ), 1, &root );MB_CHK_SET_ERR( rval, "Failed to get obb root tag" );
530531// If the ent is a vol, remove its root from obbtreetool532int dim;
533 rval = mdbImpl->tag_get_data( geomTag, &vol_or_surf, 1, &dim );MB_CHK_SET_ERR( rval, "Failed to get dimension" );
534if( dim == 3 )
535 {
536 rval = obbTree->remove_root( root );MB_CHK_SET_ERR( rval, "Failed to remove root from obbTreeTool" );
537 }
538539// Delete the obbGsetTag data from the root540 rval = mdbImpl->tag_delete_data( obbGsetTag, &root, 1 );MB_CHK_SET_ERR( rval, "Failed to delete obb root tag" );
541542// Delete the obbRootTag data from the vol or surf543 rval = mdbImpl->tag_delete_data( obbRootTag, &vol_or_surf, 1 );MB_CHK_SET_ERR( rval, "Failed to delete obb root tag" );
544545// Remove the root from set of all roots546if( m_rootSets_vector )
547 {
548unsignedint index = vol_or_surf - setOffset;
549if( index < rootSets.size() )
550 {
551 rootSets[index] = 0;
552 }
553else554 {
555return MB_INDEX_OUT_OF_RANGE;
556 }
557 }
558else559 {
560 mapRootSets[vol_or_surf] = 0;
561 }
562563return MB_SUCCESS;
564 }
565566ErrorCode GeomTopoTool::construct_obb_trees( bool make_one_vol )
567 {
568 ErrorCode rval;
569 EntityHandle root;
570571// get all surfaces and volumes572 Range surfs, vols, vol_trees;
573 rval = get_gsets_by_dimension( 2, surfs );MB_CHK_SET_ERR( rval, "Could not get surface sets" );
574 rval = get_gsets_by_dimension( 3, vols );MB_CHK_SET_ERR( rval, "Could not get volume sets" );
575576// for surface577 Range one_vol_trees;
578for( Range::iterator i = surfs.begin(); i != surfs.end(); ++i )
579 {
580 rval = construct_obb_tree( *i );MB_CHK_SET_ERR( rval, "Failed to construct obb tree for surface" );
581// get the root set of this volume582 rval = get_root( *i, root );MB_CHK_SET_ERR( rval, "Failed to get obb tree root for surface" );
583// add to the Range of volume root sets584 one_vol_trees.insert( root );
585 }
586587// for volumes588for( Range::iterator i = vols.begin(); i != vols.end(); ++i )
589 {
590// create tree for this volume591 rval = construct_obb_tree( *i );MB_CHK_SET_ERR( rval, "Failed to construct obb tree for volume" );
592 }
593594// build OBB tree for volume595if( make_one_vol )
596 {
597 rval = obbTree->join_trees( one_vol_trees, root );MB_CHK_SET_ERR( rval, "Failed to join surface trees into one volume" );
598 oneVolRootSet = root;
599 }
600601return rval;
602 }
603604//! Restore parent/child links between GEOM_TOPO mesh sets605ErrorCode GeomTopoTool::restore_topology_from_adjacency()
606 {
607608// look for geometric topology sets and restore parent/child links between them609// algorithm:610// - for each entity of dimension d=D-1..0:611// . get d-dimensional entity in entity612// . get all (d+1)-dim adjs to that entity613// . for each geom entity if dim d+1, if it contains any of the ents,614// add it to list of parents615// . make parent/child links with parents616617// the geomRanges are already known, separated by dimension618619 std::vector< EntityHandle > parents;
620 Range tmp_parents;
621 ErrorCode result;
622623// loop over dimensions624for( int dim = 2; dim >= 0; dim-- )
625 {
626// mark entities of next higher dimension with their owners; regenerate tag627// each dimension so prev dim's tag data goes away628 Tag owner_tag;
629 EntityHandle dum_val = 0;
630 result = mdbImpl->tag_get_handle( "__owner_tag", 1, MB_TYPE_HANDLE, owner_tag, MB_TAG_DENSE | MB_TAG_CREAT,
631 &dum_val );
632if( MB_SUCCESS != result ) continue;
633 Range dp1ents;
634 std::vector< EntityHandle > owners;
635for( Range::iterator rit = geomRanges[dim + 1].begin(); rit != geomRanges[dim + 1].end(); ++rit )
636 {
637 dp1ents.clear();
638 result = mdbImpl->get_entities_by_dimension( *rit, dim + 1, dp1ents );
639if( MB_SUCCESS != result ) continue;
640 owners.resize( dp1ents.size() );
641 std::fill( owners.begin(), owners.end(), *rit );
642 result = mdbImpl->tag_set_data( owner_tag, dp1ents, &owners[0] );
643if( MB_SUCCESS != result ) continue;
644 }
645646for( Range::iterator d_it = geomRanges[dim].begin(); d_it != geomRanges[dim].end(); ++d_it )
647 {
648 Range dents;
649 result = mdbImpl->get_entities_by_dimension( *d_it, dim, dents );
650if( MB_SUCCESS != result ) continue;
651if( dents.empty() ) continue;
652653// get (d+1)-dimensional adjs654 dp1ents.clear();
655 result = mdbImpl->get_adjacencies( &( *dents.begin() ), 1, dim + 1, false, dp1ents );
656if( MB_SUCCESS != result || dp1ents.empty() ) continue;
657658// get owner tags659 parents.resize( dp1ents.size() );
660 result = mdbImpl->tag_get_data( owner_tag, dp1ents, &parents[0] );
661if( MB_TAG_NOT_FOUND == result )
662 {
663MB_CHK_SET_ERR( result, "Could not find owner tag" );
664 }
665if( MB_SUCCESS != result ) continue;
666667// compress to a range to remove duplicates668 tmp_parents.clear();
669 std::copy( parents.begin(), parents.end(), range_inserter( tmp_parents ) );
670for( Range::iterator pit = tmp_parents.begin(); pit != tmp_parents.end(); ++pit )
671 {
672 result = mdbImpl->add_parent_child( *pit, *d_it );MB_CHK_SET_ERR( result, "Failed to create parent child relationship" );
673 }
674675// store surface senses within regions, and edge senses within surfaces676if( dim == 0 ) continue;
677const EntityHandle *conn3 = NULL, *conn2 = NULL;
678int len3 = 0, len2 = 0, err = 0, num = 0, sense = 0, offset = 0;
679for( size_t i = 0; i < parents.size(); ++i )
680 {
681 result = mdbImpl->get_connectivity( dp1ents[i], conn3, len3, true );MB_CHK_SET_ERR( result, "Failed to get the connectivity of the element" );
682 result = mdbImpl->get_connectivity( dents.front(), conn2, len2, true );MB_CHK_SET_ERR( result, "Failed to get the connectivity of the first element" );
683if( len2 > 4 )
684 {
685MB_SET_ERR( MB_FAILURE, "Connectivity of incorrect length" );
686 }
687 err = CN::SideNumber( TYPE_FROM_HANDLE( dp1ents[i] ), conn3, conn2, len2, dim, num, sense, offset );
688if( err ) return MB_FAILURE;
689690 result = set_sense( *d_it, parents[i], sense );
691if( MB_MULTIPLE_ENTITIES_FOUND == result )
692 {
693if( 2 == dim )
694 std::cerr << "Warning: Multiple volumes use surface with same sense." << std::endl
695 << " Some geometric sense data lost." << std::endl;
696 }
697elseif( MB_SUCCESS != result )
698 {
699return result;
700 }
701 }
702 }
703704// now delete owner tag on this dimension, automatically removes tag data705 result = mdbImpl->tag_delete( owner_tag );MB_CHK_SET_ERR( result, "Failed to delete the owner tag" );
706707 } // dim708709return result;
710 }
711712ErrorCode GeomTopoTool::separate_by_dimension( const Range& geom_sets )
713 {
714 ErrorCode result;
715716 result = check_geom_tag();MB_CHK_SET_ERR( result, "Could not verify geometry dimension tag" );
717718// get the data for those tags719std::vector< int > tag_vals( geom_sets.size() );
720 result = mdbImpl->tag_get_data( geomTag, geom_sets, &tag_vals[0] );MB_CHK_SET_ERR( result, "Failed to get the geometry dimension tag" );
721722 Range::const_iterator git;
723 std::vector< int >::iterator iit;
724725for( int i = 0; i < 5; i++ )
726this->geomRanges[i].clear();
727728for( git = geom_sets.begin(), iit = tag_vals.begin(); git != geom_sets.end(); ++git, ++iit )
729 {
730if( 0 <= *iit && 4 >= *iit )
731 geomRanges[*iit].insert( *git );
732else733 {
734// assert(false);735// do nothing for now736 }
737 }
738739// establish the max global ids so far, per dimension740if( 0 == gidTag )
741 {
742 gidTag = mdbImpl->globalId_tag();
743 }
744745for( int i = 0; i <= 4; i++ )
746 {
747 maxGlobalId[i] = 0;
748for( Range::iterator it = geomRanges[i].begin(); it != geomRanges[i].end(); ++it )
749 {
750 EntityHandle set = *it;
751int gid;
752753 result = mdbImpl->tag_get_data( gidTag, &set, 1, &gid );
754if( MB_SUCCESS == result )
755 {
756if( gid > maxGlobalId[i] ) maxGlobalId[i] = gid;
757 }
758 }
759 }
760761return MB_SUCCESS;
762 }
763764ErrorCode GeomTopoTool::construct_vertex_ranges( const Range& geom_sets, const Tag verts_tag )
765 {
766// construct the vertex range for each entity and put on that tag767 Range *temp_verts, temp_elems;
768 ErrorCode result = MB_SUCCESS;
769for( Range::const_iterator it = geom_sets.begin(); it != geom_sets.end(); ++it )
770 {
771 temp_elems.clear();
772773// get all the elements in the set, recursively774 result = mdbImpl->get_entities_by_handle( *it, temp_elems, true );MB_CHK_SET_ERR( result, "Failed to get the geometry set entities" );
775776// make the new range777 temp_verts = new( std::nothrow ) Range();
778if( NULL == temp_verts )
779 {
780MB_SET_ERR( MB_FAILURE, "Could not construct Range object" );
781 }
782783// get all the verts of those elements; use get_adjacencies 'cuz it handles ranges better784 result = mdbImpl->get_adjacencies( temp_elems, 0, false, *temp_verts, Interface::UNION );
785if( MB_SUCCESS != result )
786 {
787delete temp_verts;
788 }
789MB_CHK_SET_ERR( result, "Failed to get the element's adjacent vertices" );
790791// store this range as a tag on the entity792 result = mdbImpl->tag_set_data( verts_tag, &( *it ), 1, &temp_verts );
793if( MB_SUCCESS != result )
794 {
795delete temp_verts;
796 }
797MB_CHK_SET_ERR( result, "Failed to get the adjacent vertex data" );
798799delete temp_verts;
800 temp_verts = NULL;
801 }
802803return result;
804 }
805806//! Store sense of entity relative to wrt_entity.807//!\return MB_MULTIPLE_ENTITIES_FOUND if surface already has a forward volume.808//! MB_SUCCESS if successful809//! otherwise whatever internal error code occurred.810ErrorCode GeomTopoTool::set_sense( EntityHandle entity, EntityHandle wrt_entity, int sense )
811 {
812// entity is lower dim (edge or face), wrt_entity is face or volume813int edim = dimension( entity );
814int wrtdim = dimension( wrt_entity );
815if( -1 == edim || -1 == wrtdim ) MB_SET_ERR( MB_FAILURE, "Non-geometric entity provided" );
816if( wrtdim - edim != 1 ) MB_SET_ERR( MB_FAILURE, "Entity dimension mismatch" );
817if( sense < -1 || sense > 1 ) MB_SET_ERR( MB_FAILURE, "Invalid sense data provided" );
818819 ErrorCode rval;
820821if( 1 == edim )
822 {
823// this case is about setting the sense of an edge in a face824// it could be -1, 0 (rare, non manifold), or 1825 rval = check_edge_sense_tags( true );MB_CHK_SET_ERR( rval, "Failed to check the curve to surface sense tag handles" );
826 std::vector< EntityHandle > higher_ents;
827 std::vector< int > senses;
828 rval = get_senses( entity, higher_ents, senses ); // the tags should be defined here829// if there are no higher_ents, we are fine, we will just set them830// if wrt_entity is not among higher_ents, we will add it to the list831// it is possible the entity (edge set) has no prior faces adjancent; in that case, the832// tag would not be set, and rval could be MB_TAG_NOT_FOUND; it is not a fatal error833if( MB_SUCCESS != rval && MB_TAG_NOT_FOUND != rval )
834MB_CHK_SET_ERR( rval, "cannot determine sense tags for edge" );
835bool append = true;
836if( !higher_ents.empty() )
837 {
838 std::vector< EntityHandle >::iterator it = std::find( higher_ents.begin(), higher_ents.end(), wrt_entity );
839if( it != higher_ents.end() )
840 {
841// we should not reset the sense, if the sense is the same842// if the sense is different, put BOTH843unsignedint idx = it - higher_ents.begin();
844int oldSense = senses[idx];
845if( oldSense == sense ) return MB_SUCCESS; // sense already set fine, do not reset846if( 0 != oldSense && oldSense + sense != 0 ) return MB_MULTIPLE_ENTITIES_FOUND;
847 senses[idx] = SENSE_BOTH; // allow double senses848// do not need to add a new sense, but still need to reset the tag849// because of a new value850 append = false;
851 }
852 }
853if( append )
854 {
855// what happens if a var tag data was already set before, and now it is856// reset with a different size??857 higher_ents.push_back( wrt_entity );
858 senses.push_back( sense );
859 }
860// finally, set the senses :861int dum_size = higher_ents.size();
862void* dum_ptr = &higher_ents[0];
863 rval = mdbImpl->tag_set_by_ptr( senseNEntsTag, &entity, 1, &dum_ptr, &dum_size );MB_CHK_SET_ERR( rval, "Failed to set the sense data" );
864865 dum_ptr = &senses[0];
866 dum_size = higher_ents.size();
867 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" );
868 }
869else870 {
871// this case is about a face in the volume872// there could be only 2 volumes873874 rval = check_face_sense_tag( true );MB_CHK_SET_ERR( rval, "Failed to verify the face sense tag" );
875876 EntityHandle sense_data[2] = { 0, 0 };
877 rval = mdbImpl->tag_get_data( sense2Tag, &entity, 1, sense_data );
878if( MB_TAG_NOT_FOUND != rval && MB_SUCCESS != rval ) MB_CHK_SET_ERR( rval, "Failed to get the sense2Tag data" );
879880if( 0 == sense )
881 {
882if( 0 != sense_data[0] && wrt_entity != sense_data[0] ) return MB_MULTIPLE_ENTITIES_FOUND;
883if( 0 != sense_data[1] && wrt_entity != sense_data[1] ) return MB_MULTIPLE_ENTITIES_FOUND;
884 sense_data[0] = sense_data[1] = wrt_entity;
885 }
886elseif( -1 == sense )
887 {
888if( 0 != sense_data[1] && wrt_entity != sense_data[1] ) return MB_MULTIPLE_ENTITIES_FOUND;
889if( sense_data[1] == wrt_entity ) return MB_SUCCESS; // already set as we want890 sense_data[1] = wrt_entity;
891 }
892elseif( 1 == sense )
893 {
894if( 0 != sense_data[0] && wrt_entity != sense_data[0] ) return MB_MULTIPLE_ENTITIES_FOUND;
895if( sense_data[0] == wrt_entity ) return MB_SUCCESS; // already set as we want896 sense_data[0] = wrt_entity;
897 }
898return mdbImpl->tag_set_data( sense2Tag, &entity, 1, sense_data );
899 }
900return MB_SUCCESS;
901 }
902903//! Get the sense of entity with respect to wrt_entity904//! Returns MB_ENTITY_NOT_FOUND if no relationship found905ErrorCode GeomTopoTool::get_sense( EntityHandle entity, EntityHandle wrt_entity, int& sense )
906 {
907// entity is lower dim (edge or face), wrt_entity is face or volume908int edim = dimension( entity );
909int wrtdim = dimension( wrt_entity );
910if( -1 == edim || -1 == wrtdim ) MB_SET_ERR( MB_FAILURE, "Non-geometric entity provided" );
911if( wrtdim - edim != 1 ) MB_SET_ERR( MB_FAILURE, "Entity dimension mismatch" );
912913 ErrorCode rval;
914915if( 1 == edim )
916 {
917// edge in face918 rval = check_edge_sense_tags( false );MB_CHK_SET_ERR( rval, "Failed to check the curve to surface sense tag handles" );
919920 std::vector< EntityHandle > faces;
921 std::vector< int > senses;
922 rval = get_senses( entity, faces, senses ); // the tags should be defined here923MB_CHK_SET_ERR( rval, "Failed to get the curve to surface sense data" );
924925 std::vector< EntityHandle >::iterator it = std::find( faces.begin(), faces.end(), wrt_entity );
926if( it == faces.end() ) return MB_ENTITY_NOT_FOUND;
927unsignedint index = it - faces.begin();
928 sense = senses[index];
929 }
930else931 {
932// face in volume933 rval = check_face_sense_tag( false );MB_CHK_SET_ERR( rval, "Failed to check the surface to volume sense tag handle" );
934 EntityHandle sense_data[2] = { 0, 0 };
935 rval = mdbImpl->tag_get_data( sense2Tag, &entity, 1, sense_data );
936if( MB_TAG_NOT_FOUND != rval && MB_SUCCESS != rval )
937MB_CHK_SET_ERR( rval, "Failed to get the surface to volume sense data" );
938if( ( wrt_entity == sense_data[0] ) && ( wrt_entity == sense_data[1] ) )
939 sense = 0;
940elseif( wrt_entity == sense_data[0] )
941 sense = 1;
942elseif( wrt_entity == sense_data[1] )
943 sense = -1;
944else945return MB_ENTITY_NOT_FOUND;
946 }
947return MB_SUCCESS;
948 }
949950ErrorCode GeomTopoTool::get_surface_senses( EntityHandle surface_ent,
951 EntityHandle& forward_vol,
952 EntityHandle& reverse_vol )
953 {
954 ErrorCode rval;
955// this method should only be called to retrieve surface to volume956// sense relationships957int ent_dim = dimension( surface_ent );
958// verify the incoming entity dimensions for this call959if( ent_dim != 2 )
960 {
961MB_SET_ERR( MB_FAILURE, "Entity dimension is incorrect for surface meshset" );
962 }
963964// get the sense information for this surface965 EntityHandle parent_vols[2] = { 0, 0 };
966 rval = mdbImpl->tag_get_data( sense2Tag, &surface_ent, 1, parent_vols );MB_CHK_SET_ERR( rval, "Failed to get surface sense data" );
967968// set the outgoing values969 forward_vol = parent_vols[0];
970 reverse_vol = parent_vols[1];
971972return MB_SUCCESS;
973 }
974975ErrorCode GeomTopoTool::set_surface_senses( EntityHandle surface_ent,
976 EntityHandle forward_vol,
977 EntityHandle reverse_vol )
978 {
979 ErrorCode rval;
980// this mthod should only be called to retrieve surface to volume981// sense relationships982int ent_dim = dimension( surface_ent );
983// verify the incoming entity dimensions for this call984if( ent_dim != 2 )
985 {
986MB_SET_ERR( MB_FAILURE, "Entity dimension is incorrect for surface meshset" );
987 }
988989// set the sense information for this surface990 EntityHandle parent_vols[2] = { forward_vol, reverse_vol };
991 rval = mdbImpl->tag_set_data( sense2Tag, &surface_ent, 1, parent_vols );MB_CHK_SET_ERR( rval, "Failed to set surface sense data" );
992993return MB_SUCCESS;
994 }
995996// get sense of surface(s) wrt volume997ErrorCode GeomTopoTool::get_surface_senses( EntityHandle volume,
998int num_surfaces,
999const EntityHandle* surfaces,
1000int* senses_out )
1001 {
10021003/* The sense tags do not reference the implicit complement handle.
1004 All surfaces that interact with the implicit complement should have
1005 a null handle in the direction of the implicit complement. */1006// if (volume == impl_compl_handle)1007// volume = (EntityHandle) 0;10081009for( int surf_num = 0; surf_num < num_surfaces; surf_num++ )
1010 {
1011get_sense( surfaces[surf_num], volume, senses_out[surf_num] );
1012 }
10131014return MB_SUCCESS;
1015 }
10161017ErrorCode GeomTopoTool::get_senses( EntityHandle entity,
1018 std::vector< EntityHandle >& wrt_entities,
1019 std::vector< int >& senses )
1020 {
1021// the question here is: the wrt_entities is supplied or not?1022// I assume not, we will obtain it !!1023int edim = dimension( entity );
10241025if( -1 == edim ) MB_SET_ERR( MB_FAILURE, "Non-geometric entity provided" );
10261027 ErrorCode rval;
1028 wrt_entities.clear();
1029 senses.clear();
10301031if( 1 == edim ) // edge1032 {
1033 rval = check_edge_sense_tags( false );MB_CHK_SET_ERR( rval, "Failed to check the curve to surface sense tag handles" );
1034constvoid* dum_ptr;
1035int num_ents;
1036 rval = mdbImpl->tag_get_by_ptr( senseNEntsTag, &entity, 1, &dum_ptr, &num_ents );MB_CHK_ERR( rval );
10371038const EntityHandle* ents_data = static_cast< const EntityHandle* >( dum_ptr );
1039 std::copy( ents_data, ents_data + num_ents, std::back_inserter( wrt_entities ) );
10401041 rval = mdbImpl->tag_get_by_ptr( senseNSensesTag, &entity, 1, &dum_ptr, &num_ents );MB_CHK_ERR( rval );
10421043constint* senses_data = static_cast< constint* >( dum_ptr );
1044 std::copy( senses_data, senses_data + num_ents, std::back_inserter( senses ) );
1045 }
1046else// face in volume, edim == 21047 {
1048 rval = check_face_sense_tag( false );MB_CHK_SET_ERR( rval, "Failed to check the surface to volume sense tag handle" );
1049 EntityHandle sense_data[2] = { 0, 0 };
1050 rval = mdbImpl->tag_get_data( sense2Tag, &entity, 1, sense_data );MB_CHK_SET_ERR( rval, "Failed to get the surface to volume sense data" );
1051if( sense_data[0] != 0 && sense_data[1] == sense_data[0] )
1052 {
1053 wrt_entities.push_back( sense_data[0] );
1054 senses.push_back( 0 ); // both1055 }
1056else1057 {
1058if( sense_data[0] != 0 )
1059 {
1060 wrt_entities.push_back( sense_data[0] );
1061 senses.push_back( 1 );
1062 }
1063if( sense_data[1] != 0 )
1064 {
1065 wrt_entities.push_back( sense_data[1] );
1066 senses.push_back( -1 );
1067 }
1068 }
1069 }
1070// filter the results with the sets that are in the model at this time1071// this was introduced because extracting some sets (e.g. neumann set, with mbconvert)1072// from a model would leave some sense tags not defined correctly1073// also, the geom ent set really needs to be part of the current model set1074unsignedint currentSize = 0;
10751076for( unsignedint index = 0; index < wrt_entities.size(); index++ )
1077 {
1078 EntityHandle wrt_ent = wrt_entities[index];
1079if( wrt_ent )
1080 {
1081if( mdbImpl->contains_entities( modelSet, &wrt_ent, 1 ) )
1082 {
1083 wrt_entities[currentSize] = wrt_entities[index];
1084 senses[currentSize] = senses[index];
1085 currentSize++;
1086 }
1087 }
1088 }
1089 wrt_entities.resize( currentSize );
1090 senses.resize( currentSize );
1091//1092return MB_SUCCESS;
1093 }
10941095ErrorCode GeomTopoTool::set_senses( EntityHandle entity,
1096 std::vector< EntityHandle >& wrt_entities,
1097 std::vector< int >& senses )
1098 {
1099// not efficient, and maybe wrong1100for( unsignedint i = 0; i < wrt_entities.size(); i++ )
1101 {
1102 ErrorCode rval = set_sense( entity, wrt_entities[i], senses[i] );MB_CHK_SET_ERR( rval, "Failed to set the sense" );
1103 }
11041105return MB_SUCCESS;
1106 }
11071108ErrorCode GeomTopoTool::next_vol( EntityHandle surface, EntityHandle old_volume, EntityHandle& new_volume )
1109 {
1110 std::vector< EntityHandle > parents;
1111 ErrorCode rval = mdbImpl->get_parent_meshsets( surface, parents );
11121113if( MB_SUCCESS == rval )
1114 {
1115if( parents.size() != 2 )
1116 rval = MB_FAILURE;
1117elseif( parents.front() == old_volume )
1118 new_volume = parents.back();
1119elseif( parents.back() == old_volume )
1120 new_volume = parents.front();
1121else1122 rval = MB_FAILURE;
1123 }
11241125return rval;
1126 }
11271128ErrorCode GeomTopoTool::check_geom_tag( bool create )
1129 {
1130 ErrorCode rval;
1131unsigned flags = create ? MB_TAG_DENSE | MB_TAG_CREAT : MB_TAG_DENSE;
1132if( !geomTag )
1133 {
1134// get any kind of tag that already exists1135 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" );
1136 }
1137return MB_SUCCESS;
1138 }
11391140ErrorCode GeomTopoTool::check_gid_tag( bool create )
1141 {
1142 ErrorCode rval;
1143unsigned flags = create ? MB_TAG_DENSE | MB_TAG_CREAT : MB_TAG_DENSE;
1144if( !gidTag )
1145 {
1146// get any kind of tag that already exists1147 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" );
1148 }
1149return MB_SUCCESS;
1150 }
11511152// move the sense tag existence creation in private methods1153// verify sense face tag1154ErrorCode GeomTopoTool::check_face_sense_tag( bool create )
1155 {
1156 ErrorCode rval;
1157unsigned flags = create ? MB_TAG_SPARSE | MB_TAG_CREAT | MB_TAG_ANY : MB_TAG_SPARSE | MB_TAG_ANY;
1158if( !sense2Tag )
1159 {
1160 EntityHandle def_val[2] = { 0, 0 };
1161 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" );
1162 }
1163return MB_SUCCESS;
1164 }
11651166// verify sense edge tags1167ErrorCode GeomTopoTool::check_edge_sense_tags( bool create )
1168 {
1169 ErrorCode rval;
1170unsigned flags = MB_TAG_VARLEN | MB_TAG_SPARSE;
1171if( create ) flags |= MB_TAG_CREAT;
1172if( !senseNEntsTag )
1173 {
1174 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" );
1175 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" );
1176 }
1177return MB_SUCCESS;
1178 }
11791180ErrorCode GeomTopoTool::add_geo_set( EntityHandle set, int dim, int gid )
1181 {
1182if( dim < 0 || dim > 4 ) MB_SET_ERR( MB_FAILURE, "Invalid geometric dimension provided" );
11831184// see if it is not already set1185if( geomRanges[dim].find( set ) != geomRanges[dim].end() )
1186 {
1187return MB_SUCCESS; // nothing to do, we already have it as a geo set of proper dimension1188 }
1189 updated = false; // this should trigger at least an obb recomputation1190// get the geom topology tag1191 ErrorCode result;
1192if( 0 == geomTag )
1193 {
1194 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" );
1195 }
11961197if( 0 == gidTag )
1198 {
1199 gidTag = mdbImpl->globalId_tag();
1200 }
12011202// make sure the added set has the geom tag properly set1203 result = mdbImpl->tag_set_data( geomTag, &set, 1, &dim );MB_CHK_SET_ERR( result, "Failed set the geometry dimension tag value" );
12041205 geomRanges[dim].insert( set );
1206// not only that, but also add it to the root model set1207if( modelSet )
1208 {
1209 result = mdbImpl->add_entities( modelSet, &set, 1 );MB_CHK_SET_ERR( result, "Failed to add new geometry set to the tool's modelSet" );
1210 }
12111212// set the global ID value1213// if passed 0, just increase the max id for the dimension1214if( 0 == gid )
1215 {
1216 gid = ++maxGlobalId[dim];
1217 }
12181219 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" );
12201221return MB_SUCCESS;
1222 }
12231224// will assume no geo sets are defined for this surface1225// will output a mesh_set that contains everything (all sets of interest), for proper output1226ErrorCode GeomTopoTool::geometrize_surface_set( EntityHandle surface, EntityHandle& output )
1227 {
1228// usual scenario is to read a surface smf file, and "geometrize" it, and output it as a1229// h5m file with proper sets, tags defined for mesh-based geometry12301231// get all triangles/quads from the surface, then build loops1232// we may even have to1233// proper care has to be given to the orientation, material to the left!!!1234// at some point we may have to reorient triangles, not only edges, for proper definition1235bool debugFlag = false;
12361237 Range surface_ents, edge_ents, loop_range;
12381239// most of these should be triangles and quads1240 ErrorCode rval = mdbImpl->get_entities_by_dimension( surface, 2, surface_ents );MB_CHK_SET_ERR( rval, "Failed to get the surface entities" );
12411242 EntityHandle face = surface;
1243if( !surface ) // in the case it is root set, create another set1244 {
1245 rval = mdbImpl->create_meshset( MESHSET_SET, face );MB_CHK_SET_ERR( rval, "Failed to create a the new surface meshset" );
1246 }
1247// set the geo tag1248 rval = add_geo_set( face, 2 );MB_CHK_SET_ERR( rval, "Failed to add the geometry set to the tool" );
12491250// this will be our output set, will contain all our new geo sets1251 rval = mdbImpl->create_meshset( MESHSET_SET, output );MB_CHK_SET_ERR( rval, "Failed to create the output meshset" );
12521253// add first geo set (face) to the output set1254 rval = mdbImpl->add_entities( output, &face, 1 );MB_CHK_SET_ERR( rval, "Failed to add the new meshset to the output meshset" );
12551256// how many edges do we need to create?1257// depends on how many loops we have1258// also, we should avoid non-manifold topology1259if( !surface )
1260 { // in this case, surface is root, so we have to add entities1261 rval = mdbImpl->add_entities( face, surface_ents );MB_CHK_SET_ERR( rval, "Failed to add surface entities to the surface meshset" );
1262 }
12631264Skinner tool( mdbImpl );
1265 rval = tool.find_skin( 0, surface_ents, 1, edge_ents );MB_CHK_SET_ERR( rval, "Failed to skin the surface entities" );
1266if( debugFlag )
1267 {
1268 std::cout << "skinning edges: " << edge_ents.size() << "\n";
1269for( Range::iterator it = edge_ents.begin(); it != edge_ents.end(); ++it )
1270 {
1271 EntityHandle ed = *it;
1272 std::cout << "edge: " << mdbImpl->id_from_handle( ed ) << " type:" << mdbImpl->type_from_handle( ed )
1273 << "\n";
1274 std::cout << mdbImpl->list_entity( ed );
1275 }
1276 }
12771278 std::vector< EntityHandle > edges_loop;
12791280 Range pool_of_edges = edge_ents;
1281 Range used_edges; // these edges are already used for some loops1282// get a new one12831284while( !pool_of_edges.empty() )
1285 {
1286// get the first edge, and start a loop with it1287 EntityHandle current_edge = pool_of_edges[0];
1288if( debugFlag )
1289 {
1290 std::cout << "Start current edge: " << mdbImpl->id_from_handle( current_edge ) << "\n ";
1291 std::cout << mdbImpl->list_entity( current_edge );
1292 }
1293// get its triangle / quad and see its orientation1294 std::vector< EntityHandle > tris;
1295 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" );
1296if( tris.size() != 1 ) MB_SET_ERR( MB_FAILURE, "Edge not on boundary" );
12971298int side_n, sense, offset;
1299 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" );
13001301const EntityHandle* conn2;
1302int nnodes2;
1303 rval = mdbImpl->get_connectivity( current_edge, conn2, nnodes2 );MB_CHK_SET_ERR( rval, "Failed to get the current edge's connectivity" );
13041305if( nnodes2 != 2 ) MB_SET_ERR( MB_FAILURE, "Incorrect number of nodes found." );
13061307 EntityHandle start_node = conn2[0];
1308 EntityHandle next_node = conn2[1];
13091310if( sense == -1 )
1311 {
1312// revert the edge, and start well1313 EntityHandle nn2[2] = { conn2[1], conn2[0] };
1314 rval = mdbImpl->set_connectivity( current_edge, nn2, 2 );MB_CHK_SET_ERR( rval, "Failed to set the connectivity of the current edge" );
13151316 start_node = nn2[0]; // or conn2[0] !!! beware: conn2 is modified1317 next_node = nn2[1]; // or conn2[1] !!!1318// reset connectivity of edge1319if( debugFlag ) std::cout << " current edge needs reversed\n";
1320 }
1321// start a new loop of edges1322 edges_loop.clear(); // every edge loop starts fresh1323 edges_loop.push_back( current_edge );
1324 used_edges.insert( current_edge );
1325 pool_of_edges.erase( current_edge );
13261327if( debugFlag )
1328 {
1329 std::cout << " start node: " << start_node << "\n";
1330 std::cout << mdbImpl->list_entity( start_node );
1331 std::cout << " next node: " << next_node << "\n";
1332 std::cout << mdbImpl->list_entity( next_node );
1333 }
1334while( next_node != start_node )
1335 {
1336// find the next edge in the skin1337 std::vector< EntityHandle > candidate_edges;
1338 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" );
1339// filter the edges that are used, or the edges not in the skin1340 std::vector< EntityHandle > good_edges;
1341for( int k = 0; k < (int)candidate_edges.size(); k++ )
1342 {
1343 EntityHandle edg = candidate_edges[k];
1344if( used_edges.find( edg ) != used_edges.end() ) continue;
1345if( pool_of_edges.find( edg ) != pool_of_edges.end() ) good_edges.push_back( edg );
1346 }
1347if( good_edges.size() != 1 )
1348 {
1349 std::cout << " good_edges.size()=" << good_edges.size() << " STOP\n";
1350MB_SET_ERR( MB_FAILURE, "Number of good edges is not one. Could not complete the loop" );
1351 }
1352// see if the orientation is good; if not, revert it13531354 current_edge = good_edges[0];
1355 rval = mdbImpl->get_connectivity( current_edge, conn2, nnodes2 );MB_CHK_SET_ERR( rval, "Failed to get the connectivity of the current edge" );
1356if( nnodes2 != 2 ) MB_SET_ERR( MB_FAILURE, "Incorrect number of nodes found" );
13571358if( conn2[0] != next_node )
1359 {
1360if( conn2[1] != next_node )
1361 {
1362// the edge is not connected then to current edge1363// bail out1364 std::cout << "edge " << mdbImpl->id_from_handle( current_edge ) << " not connected to node "1365 << next_node << "\n";
1366MB_SET_ERR( MB_FAILURE, "Current edge is not connected to node" );
1367 ;
1368 }
1369if( debugFlag )
1370 {
1371 std::cout << " revert edge " << mdbImpl->id_from_handle( current_edge ) << "\n";
1372 std::cout << mdbImpl->list_entity( current_edge );
1373 }
1374// orientation should be reversed1375 EntityHandle nn2[2] = { conn2[1], conn2[0] };
1376 rval = mdbImpl->set_connectivity( current_edge, nn2, 2 );MB_CHK_SET_ERR( rval, "Failed to set the connectivity of the current edge" );
13771378 {
1379 std::cout << "after revert edge " << mdbImpl->id_from_handle( current_edge ) << "\n";
1380 std::cout << mdbImpl->list_entity( current_edge );
1381 std::cout << " conn2: " << conn2[0] << " " << conn2[1] << "\n";
1382 }
1383 }
1384// before reversion, conn2 was something { n1, next_node}1385// after reversion, conn2 became {next_node, n1}, so the1386// new next node will be still conn2[1]; big surprise, as1387// I didn't expect the conn2 to change.1388// it seems that const EntityHandle * conn2 means conn2 cannot be1389// changed, but what is pointed to by it will change when we reset connectivity for edge1390 next_node = conn2[1];
13911392if( debugFlag )
1393 {
1394 std::cout << " current edge: " << mdbImpl->id_from_handle( current_edge ) << "\n ";
1395 std::cout << mdbImpl->list_entity( current_edge );
1396 std::cout << "next node: " << next_node << "\n ";
1397 std::cout << mdbImpl->list_entity( next_node );
1398 }
1399 edges_loop.push_back( current_edge );
1400 used_edges.insert( current_edge );
1401 pool_of_edges.erase( current_edge );
1402 }
1403// at this point, we have a loop formed;1404// create a geo edge, a vertex set, and add it to our sets14051406 EntityHandle edge;
1407 rval = mdbImpl->create_meshset( MESHSET_ORDERED, edge );MB_CHK_SET_ERR( rval, "Failed to create the edge meshset" );
14081409 rval = add_geo_set( edge, 1 );MB_CHK_SET_ERR( rval, "Failed to add the edge meshset to the tool's model set" );
1410// add the mesh edges:1411// add loops edges to the edge set1412 rval = mdbImpl->add_entities( edge, &edges_loop[0], edges_loop.size() ); //1413MB_CHK_SET_ERR( rval, "Failed to add entities to the edge meshset" );
1414// create a vertex set1415 EntityHandle vertex;
1416 rval = mdbImpl->create_meshset( MESHSET_SET, vertex );MB_CHK_SET_ERR( rval, "Failed to create the vertex meshset" );
1417 rval = add_geo_set( vertex, 0 );MB_CHK_SET_ERR( rval, "Failed to add the vertex meshset to the tool's model set" );
1418// add one node to the vertex set14191420 rval = mdbImpl->add_entities( vertex, &start_node, 1 ); //1421MB_CHK_SET_ERR( rval, "Failed to add entities to the vertex meshset" );
14221423 rval = mdbImpl->add_parent_child( face, edge );MB_CHK_SET_ERR( rval, "Failed to create the edge to face parent child relationship" );
14241425 rval = mdbImpl->add_parent_child( edge, vertex );MB_CHK_SET_ERR( rval, "Failed to create the vertex to edge parent child relationship" );
14261427// the sense of the edge in face is for sure positive (forward)1428 rval = set_sense( edge, face, 1 ); //1429MB_CHK_SET_ERR( rval, "Failed to set the edge to face sense" );
1430// also add our sets to the output set, to be sure to be exported14311432 rval = mdbImpl->add_entities( output, &edge, 1 );MB_CHK_SET_ERR( rval, "Failed to add the edge meshset to the output set" );
1433 rval = mdbImpl->add_entities( output, &vertex, 1 );MB_CHK_SET_ERR( rval, "Failed to add the vertex meshset to the output set" );
14341435if( debugFlag )
1436 {
1437 std::cout << "add edge with start node " << start_node << " with " << edges_loop.size() << " edges\n";
1438 }
1439 }
14401441return MB_SUCCESS;
1442 }
14431444/*
1445 * This would create a deep copy of the geom topo model, into a new geom topo tool
1446 * sets will be duplicated, but entities not
1447 * modelSet will be a new one
1448 * if the original set was null (root), a new model set will be created for
1449 * original model, and its entities will be the original g sets
1450 * Scenario: split a face along a ground line, then write only one surface
1451 * the common line has 2 faces in var len tag for sense edge; if we write only one
1452 * surface to a new database, the var len tag of the edge will be extracted with 2 values, but
1453 * only one value will make sense, the other will be zero.
1454 *
1455 * There is no workaround; we need to create a duplicate model that has only that surface
1456 * and its children (and grand-children). Then the var len sense edge-face tags will have
1457 * the right size.
1458 *
1459 */1460ErrorCode GeomTopoTool::duplicate_model( GeomTopoTool*& duplicate, std::vector< EntityHandle >* pvGEnts )
1461 {
1462// will1463 EntityHandle rootModelSet;
1464 ErrorCode rval = mdbImpl->create_meshset( MESHSET_SET, rootModelSet );MB_CHK_SET_ERR( rval, "Failed to create the rootModelSet" );
14651466if( 0 == geomTag )
1467 {
1468 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" );
1469 }
1470if( 0 == gidTag )
1471 {
1472 gidTag = mdbImpl->globalId_tag();
1473 }
1474// extract from the geomSet the dimension, children, and grand-children1475 Range depSets; // dependents of the geomSet, including the geomSet1476// add in this range all the dependents of this, to filter the ones that need to be deep copied14771478if( pvGEnts != NULL )
1479 {
1480unsignedint numGents = pvGEnts->size();
1481for( unsignedint k = 0; k < numGents; k++ )
1482 {
1483 EntityHandle geomSet = ( *pvGEnts )[k];
1484// will keep accumulating to the depSets range1485 rval = mdbImpl->get_child_meshsets( geomSet, depSets, 0 ); // 0 for numHops means that all1486// dependents are returned, not only the direct children.1487MB_CHK_SET_ERR( rval, "Failed to get the geometry set's child meshsets" );
14881489 depSets.insert( geomSet );
1490 }
1491 }
14921493// add to the root model set copies of the gsets, with correct sets1494// keep a map between sets to help in copying parent/child relations1495 std::map< EntityHandle, EntityHandle > relate;
1496// each set will get the same entities as the original1497for( int dim = 0; dim < 5; dim++ )
1498 {
1499int gid = 0;
1500unsignedint set_options = ( ( 1 != dim ) ? MESHSET_SET : MESHSET_ORDERED );
1501for( Range::iterator it = geomRanges[dim].begin(); it != geomRanges[dim].end(); ++it )
1502 {
1503 EntityHandle set = *it;
1504if( pvGEnts != NULL && depSets.find( set ) == depSets.end() )
1505continue; // this means that this set is not of interest, skip it1506 EntityHandle newSet;
1507 rval = mdbImpl->create_meshset( set_options, newSet );MB_CHK_SET_ERR( rval, "Failed to create new meshset" );
15081509 relate[set] = newSet;
1510 rval = mdbImpl->add_entities( rootModelSet, &newSet, 1 );MB_CHK_SET_ERR( rval, "Failed to add the new meshset to the tool's modelSet" );
15111512// make it a geo set, and give also global id in order1513 rval = mdbImpl->tag_set_data( geomTag, &newSet, 1, &dim );MB_CHK_SET_ERR( rval, "Failed to set the new meshset's geometry dimension data" );
15141515 gid++; // increment global id, everything starts with 1 in the new model!1516 rval = mdbImpl->tag_set_data( gidTag, &newSet, 1, &gid );MB_CHK_SET_ERR( rval, "Failed to get the new meshset's global id data" );
15171518if( dim == 1 )
1519 {
1520// the entities are ordered, we need to retrieve them ordered, and set them ordered1521 std::vector< EntityHandle > mesh_edges;
1522 rval = mdbImpl->get_entities_by_handle( set, mesh_edges );MB_CHK_SET_ERR( rval, "Failed to get the meshset entities by handle" );
15231524 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" );
1525 }
1526else1527 {
1528 Range ents;
1529 rval = mdbImpl->get_entities_by_handle( set, ents );MB_CHK_SET_ERR( rval, "Failed to add the entities to the existing meshset" );
15301531 rval = mdbImpl->add_entities( newSet, ents );MB_CHK_SET_ERR( rval, "Failed to add the entities to the new meshset" );
1532 }
1533// set parent/child relations if dim>=11534if( dim >= 1 )
1535 {
1536 Range children;
1537// the children of geo sets are only g sets1538 rval = mdbImpl->get_child_meshsets( set, children ); // num_hops = 1 by default1539MB_CHK_SET_ERR( rval, "Failed to get the child meshsets of the existing set" );
15401541for( Range::iterator it2 = children.begin(); it2 != children.end(); ++it2 )
1542 {
1543 EntityHandle newChildSet = relate[*it2];
1544 rval = mdbImpl->add_parent_child( newSet, newChildSet );MB_CHK_SET_ERR( rval, "Failed to create parent child relationship to the new meshset" );
1545 }
1546 }
1547 }
1548 }
15491550 duplicate = newGeomTopoTool( mdbImpl, true, rootModelSet ); // will retrieve the1551// sets and put them in ranges15521553// this is the lazy way to it:1554// newgtt->restore_topology_from_adjacency(); // will reset the sense entities, and with this,1555// the model represented by this new gtt will be complete set senses by peeking at the old model1556// make sure we have the sense tags defined1557 rval = check_face_sense_tag( true );MB_CHK_SET_ERR( rval, "Failed to check the face to volume sense tag handle" );
15581559 rval = check_edge_sense_tags( true );MB_CHK_SET_ERR( rval, "Failed to check the curve to surface sense tag handles" );
15601561for( int dd = 1; dd <= 2; dd++ ) // do it for surfaces and edges1562 {
1563for( Range::iterator it = geomRanges[dd].begin(); it != geomRanges[dd].end(); ++it )
1564 {
1565 EntityHandle surf = *it;
1566if( pvGEnts != NULL && depSets.find( surf ) == depSets.end() )
1567continue; // this means that this set is not of interest, skip it1568 EntityHandle newSurf = relate[surf];
1569// we can actually look at the tag data, to be more efficient1570// or use the1571 std::vector< EntityHandle > solids;
1572 std::vector< int > senses;
1573 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" );
15741575 std::vector< EntityHandle > newSolids;
1576 std::vector< int > newSenses;
1577for( unsignedint i = 0; i < solids.size(); i++ )
1578 {
1579if( pvGEnts != NULL && depSets.find( solids[i] ) == depSets.end() )
1580continue; // this means that this set is not of interest, skip it1581 EntityHandle newSolid = relate[solids[i]];
1582// see which "solids" are in the new model1583 newSolids.push_back( newSolid );
1584 newSenses.push_back( senses[i] );
1585 }
1586 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" );
1587 }
1588 }
1589// if the original root model set for this model is 0 (root set), then create1590// a new set and put all the old sets in the new model set1591// in this way, the existing gtt remains valid (otherwise, the modelSet would contain all the1592// gsets, the old ones and the new ones; the root set contains everything)1593if( modelSet == 0 )
1594 {
1595 rval = mdbImpl->create_meshset( MESHSET_SET, modelSet );MB_CHK_SET_ERR( rval, "Failed to create the modelSet meshset" );
15961597// add to this new set all previous sets (which are still in ranges)1598for( int dim = 0; dim < 5; dim++ )
1599 {
1600 rval = mdbImpl->add_entities( modelSet, geomRanges[dim] );MB_CHK_SET_ERR( rval, "Failed to add the geometric meshsets to the tool's modelSet" );
1601 }
1602 }
1603return MB_SUCCESS;
1604 }
16051606ErrorCode GeomTopoTool::get_implicit_complement( EntityHandle& implicit_complement )
1607 {
1608if( impl_compl_handle )
1609 {
1610 implicit_complement = impl_compl_handle;
1611return MB_SUCCESS;
1612 }
1613else1614 {
1615return MB_ENTITY_NOT_FOUND;
1616 }
1617 }
16181619ErrorCode GeomTopoTool::setup_implicit_complement()
1620 {
16211622// if the implicit complement is already setup,1623// we're done1624if( impl_compl_handle != 0 )
1625 {
1626 std::cout << "IPC already exists!" << std::endl;
1627return MB_SUCCESS;
1628 }
16291630// if not, then query for a set with it's name1631 Range entities;
1632constvoid* const tagdata[] = { IMPLICIT_COMPLEMENT_NAME };
1633 ErrorCode rval = mdbImpl->get_entities_by_type_and_tag( modelSet, MBENTITYSET, &nameTag, tagdata, 1, entities );
1634// query error1635MB_CHK_SET_ERR( rval, "Unable to query for implicit complement" );
16361637// if we found exactly one, set it as the implicit complement1638if( entities.size() == 1 )
1639 {
1640 impl_compl_handle = entities.front();
1641return MB_SUCCESS;
1642 }
16431644// found too many1645if( entities.size() > 1 ) MB_CHK_SET_ERR( MB_MULTIPLE_ENTITIES_FOUND, "Too many implicit complement sets" );
16461647// found none1648if( entities.empty() )
1649 {
1650// create implicit complement if requested1651 rval = generate_implicit_complement( impl_compl_handle );MB_CHK_SET_ERR( rval, "Could not create implicit complement" );
16521653 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" );
16541655 rval = add_geo_set( impl_compl_handle, 3 );MB_CHK_SET_ERR( rval, "Failed to add implicit complement to model" );
16561657// assign category tag - this is presumably for consistency so that the1658// implicit complement has all the appearance of being the same as any1659// other volume1660 Tag category_tag;
1661 rval = mdbImpl->tag_get_handle( CATEGORY_TAG_NAME, CATEGORY_TAG_SIZE, MB_TYPE_OPAQUE, category_tag,
1662 MB_TAG_SPARSE | MB_TAG_CREAT );MB_CHK_SET_ERR( rval, "Could not get the category tag" );
16631664staticconstchar volume_category[CATEGORY_TAG_SIZE] = "Volume\0";
1665 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" );
16661667return MB_SUCCESS;
1668 }
16691670return MB_FAILURE;
1671 }
16721673ErrorCode GeomTopoTool::generate_implicit_complement( EntityHandle& implicit_complement_set )
1674 {
16751676 ErrorCode rval;
1677 rval = mdbImpl->create_meshset( MESHSET_SET, implicit_complement_set );MB_CHK_SET_ERR( rval, "Failed to create mesh set for implicit complement" );
16781679// make sure the sense2Tag is set1680if( !sense2Tag )
1681 {
1682check_face_sense_tag( true );
1683 }
16841685// get all geometric surface sets1686 Range surfs;
1687 rval = get_gsets_by_dimension( 2, surfs );MB_CHK_SET_ERR( rval, "Could not get surface sets" );
16881689// search through all surfaces1690 std::vector< EntityHandle > parent_vols;
1691for( Range::iterator surf_i = surfs.begin(); surf_i != surfs.end(); ++surf_i )
1692 {
16931694 parent_vols.clear();
1695// get parents of each surface1696 rval = mdbImpl->get_parent_meshsets( *surf_i, parent_vols );MB_CHK_SET_ERR( rval, "Failed to get volume meshsets" );
16971698// if only one parent, get the OBB root for this surface1699if( parent_vols.size() == 1 )
1700 {
17011702// add this surf to the topology of the implicit complement volume1703 rval = mdbImpl->add_parent_child( implicit_complement_set, *surf_i );MB_CHK_SET_ERR( rval, "Could not add surface to implicit complement set" );
17041705// get the surface sense wrt original volume1706 EntityHandle sense_data[2] = { 0, 0 };
1707 rval = get_surface_senses( *surf_i, sense_data[0], sense_data[1] );MB_CHK_SET_ERR( rval, "Could not get surface sense data" );
17081709// set the surface sense wrt implicit complement volume1710if( 0 == sense_data[0] && 0 == sense_data[1] )
1711MB_SET_ERR( MB_FAILURE, "No sense data for current surface" );
1712if( 0 == sense_data[0] )
1713 sense_data[0] = implicit_complement_set;
1714elseif( 0 == sense_data[1] )
1715 sense_data[1] = implicit_complement_set;
1716else1717MB_SET_ERR( MB_FAILURE, "Could not insert implicit complement into surface sense data" );
17181719// set the new sense data for this surface1720 rval = set_surface_senses( *surf_i, sense_data[0], sense_data[1] );MB_CHK_SET_ERR( rval, "Failed to set sense tag data" );
1721 }
1722 } // end surface loop17231724return MB_SUCCESS;
1725 }
17261727#define RETFALSE( a, b ) \
1728 { \
1729 std::cout << ( a ) << "\n"; \
1730 mdbImpl->list_entity( b ); \
1731 return false; \
1732 }1733boolGeomTopoTool::check_model()
1734 {
1735// vertex sets should have one node1736 Range::iterator rit;
1737 ErrorCode rval;
1738for( rit = geomRanges[0].begin(); rit != geomRanges[0].end(); ++rit )
1739 {
1740 EntityHandle vSet = *rit;
1741 Range nodes;
1742 rval = mdbImpl->get_entities_by_handle( vSet, nodes );
1743if( MB_SUCCESS != rval ) RETFALSE( " failed to get nodes from vertex set ", vSet );
1744if( nodes.size() != 1 ) RETFALSE( " number of nodes is different from 1 ", vSet )
1745 EntityType type = mdbImpl->type_from_handle( nodes[0] );
1746if( type != MBVERTEX ) RETFALSE( " entity in vertex set is not a node ", nodes[0] )
1747// get all parents, and see if they belong to geomRanges[1]1748 Range edges;
1749 rval = mdbImpl->get_parent_meshsets( vSet, edges );
1750if( MB_SUCCESS != rval ) RETFALSE( " can't get parent edges for a node set ", vSet )
1751 Range notEdges = subtract( edges, geomRanges[1] );
1752if( !notEdges.empty() ) RETFALSE( " some parents of a node set are not geo edges ", notEdges[0] )
1753 }
17541755// edges to be formed by continuous chain of mesh edges, oriented correctly1756for( rit = geomRanges[1].begin(); rit != geomRanges[1].end(); ++rit )
1757 {
1758 EntityHandle edge = *rit;
1759 std::vector< EntityHandle > mesh_edges;
1760 rval = mdbImpl->get_entities_by_type( edge, MBEDGE, mesh_edges );
1761if( MB_SUCCESS != rval ) RETFALSE( " can't get mesh edges from edge set", edge )
1762int num_edges = (int)mesh_edges.size();
1763if( num_edges == 0 ) RETFALSE( " no mesh edges in edge set ", edge )
1764 EntityHandle firstNode;
1765 EntityHandle currentNode; // will also hold the last node in chain of edges1766const EntityHandle* conn2;
1767int nnodes2;
1768// get all parents, and see if they belong to geomRanges[1]1769for( int i = 0; i < num_edges; i++ )
1770 {
1771 rval = mdbImpl->get_connectivity( mesh_edges[i], conn2, nnodes2 );
1772if( MB_SUCCESS != rval || nnodes2 != 2 ) RETFALSE( " mesh edge connectivity is wrong ", mesh_edges[i] )
1773if( i == 0 )
1774 {
1775 firstNode = conn2[0];
1776 currentNode = conn2[1];
1777 }
17781779else// if ( (i>0) )1780 {
1781// check the current node is conn[0]1782if( conn2[0] != currentNode )
1783 {
1784 std::cout << "i=" << i << " conn2:" << conn2[0] << " " << conn2[1] << " currentNode:" << currentNode
1785 << "\n";
1786 mdbImpl->list_entity( mesh_edges[i] );
1787RETFALSE( " edges are not contiguous in edge set ", edge )
1788 }
1789 currentNode = conn2[1];
1790 }
1791 }
1792// check the children of the edge set; do they have the first and last node?1793 Range vertSets;
1794 rval = mdbImpl->get_child_meshsets( edge, vertSets );
1795if( MB_SUCCESS != rval ) RETFALSE( " can't get vertex children ", edge )
1796 Range notVertices = subtract( vertSets, geomRanges[0] );
1797if( !notVertices.empty() ) RETFALSE( " children sets that are not vertices ", notVertices[0] )
1798for( Range::iterator it = vertSets.begin(); it != vertSets.end(); ++it )
1799 {
1800if( !mdbImpl->contains_entities( *it, &firstNode, 1 ) &&
1801 !mdbImpl->contains_entities( *it, ¤tNode, 1 ) )
1802RETFALSE( " a vertex set is not containing the first and last nodes ", *it )
1803 }
1804// check now the faces / parents1805 Range faceSets;
1806 rval = mdbImpl->get_parent_meshsets( edge, faceSets );
1807if( MB_SUCCESS != rval ) RETFALSE( " can't get edge parents ", edge )
1808 Range notFaces = subtract( faceSets, geomRanges[2] );
1809if( !notFaces.empty() ) RETFALSE( " parent sets that are not faces ", notFaces[0] )
18101811// for a geo edge, check the sense tags with respect to the adjacent faces1812// in general, it is sufficient to check one mesh edge (the first one)1813// edge/face senses1814 EntityHandle firstMeshEdge = mesh_edges[0];
1815// get all entities/elements adjacent to it1816 Range adjElem;
1817 rval = mdbImpl->get_adjacencies( &firstMeshEdge, 1, 2, false, adjElem );
1818if( MB_SUCCESS != rval ) RETFALSE( " can't get adjacent elements to the edge ", firstMeshEdge )
1819for( Range::iterator it2 = adjElem.begin(); it2 != adjElem.end(); ++it2 )
1820 {
1821 EntityHandle elem = *it2;
1822// find the geo face it belongs to1823 EntityHandle gFace = 0;
1824for( Range::iterator fit = faceSets.begin(); fit != faceSets.end(); ++fit )
1825 {
1826 EntityHandle possibleFace = *fit;
1827if( mdbImpl->contains_entities( possibleFace, &elem, 1 ) )
1828 {
1829 gFace = possibleFace;
1830break;
1831 }
1832 }
1833if( 0 == gFace )
1834RETFALSE( " can't find adjacent surface that contains the adjacent element to the edge ",
1835 firstMeshEdge )
18361837// now, check the sense of mesh_edge in element, and the sense of gedge in gface1838// side_number1839int side_n, sense, offset;
1840 rval = mdbImpl->side_number( elem, firstMeshEdge, side_n, sense, offset );
1841if( MB_SUCCESS != rval ) RETFALSE( " can't get sense and side number of an element ", elem )
1842// now get the sense1843int topoSense;
1844 rval = this->get_sense( edge, gFace, topoSense );
1845if( topoSense != sense ) RETFALSE( " geometric topo sense and element sense do not agree ", edge )
1846 }
1847 }
1848// surfaces to be true meshes1849// for surfaces, check that the skinner will find the correct boundary18501851// use the skinner for boundary check1852Skinner tool( mdbImpl );
18531854for( rit = geomRanges[2].begin(); rit != geomRanges[2].end(); ++rit )
1855 {
1856 EntityHandle faceSet = *rit;
1857// get all boundary edges (adjacent edges)18581859 Range edges;
1860 rval = mdbImpl->get_child_meshsets( faceSet, edges );
1861if( MB_SUCCESS != rval ) RETFALSE( " can't get children edges for a face set ", faceSet )
1862 Range notEdges = subtract( edges, geomRanges[1] );
1863if( !notEdges.empty() ) RETFALSE( " some children of a face set are not geo edges ", notEdges[0] )
18641865 Range boundary_mesh_edges;
1866for( Range::iterator it = edges.begin(); it != edges.end(); ++it )
1867 {
1868 rval = mdbImpl->get_entities_by_type( *it, MBEDGE, boundary_mesh_edges );
1869if( MB_SUCCESS != rval ) RETFALSE( " can't get edge elements from the edge set ", *it )
1870 }
1871// skin the elements of the surface1872// most of these should be triangles and quads1873 Range surface_ents, edge_ents;
1874 rval = mdbImpl->get_entities_by_dimension( faceSet, 2, surface_ents );
1875if( MB_SUCCESS != rval ) RETFALSE( " can't get surface elements from the face set ", faceSet )
18761877 rval = tool.find_skin( 0, surface_ents, 1, edge_ents );
1878if( MB_SUCCESS != rval ) RETFALSE( "can't skin a surface ", surface_ents[0] )
18791880// those 2 ranges for boundary edges now must be equal1881if( boundary_mesh_edges != edge_ents ) RETFALSE( "boundary ranges are different", boundary_mesh_edges[0] )
1882 }
18831884// solids to be filled correctly, maybe a skin procedure too.1885// (maybe the solids are empty)18861887returntrue;
1888 }
18891890boolGeomTopoTool::have_obb_tree()
1891 {
1892return rootSets.size() != 0 || mapRootSets.size() != 0;
1893 }
18941895// This function gets coordinates of the minimum and maxmiumum points1896// from an OBB/AABB, ie. such that these points represent1897// the maximum and minium extents of an AABB1898ErrorCode GeomTopoTool::get_bounding_coords( EntityHandle volume, double minPt[3], double maxPt[3] )
1899 {
1900double center[3], axis1[3], axis2[3], axis3[3];
19011902// get center point and vectors to OBB faces1903 ErrorCode rval = get_obb( volume, center, axis1, axis2, axis3 );MB_CHK_SET_ERR( rval, "Failed to get the oriented bounding box of the volume" );
19041905// compute min and max vertices1906for( int i = 0; i < 3; i++ )
1907 {
1908double sum = fabs( axis1[i] ) + fabs( axis2[i] ) + fabs( axis3[i] );
1909 minPt[i] = center[i] - sum;
1910 maxPt[i] = center[i] + sum;
1911 }
1912return MB_SUCCESS;
1913 }
19141915ErrorCode GeomTopoTool::get_obb( EntityHandle volume,
1916double center[3],
1917double axis1[3],
1918double axis2[3],
1919double axis3[3] )
1920 {
1921// find EntityHandle node_set for use in box1922 EntityHandle root;
1923 ErrorCode rval = get_root( volume, root );MB_CHK_SET_ERR( rval, "Failed to get volume's obb tree root" );
19241925// call box to get center and vectors to faces1926return obbTree->box( root, center, axis1, axis2, axis3 );
1927 }
19281929Range GeomTopoTool::get_ct_children_by_dimension( EntityHandle parent, int desired_dimension )
1930 {
1931 Range all_children, desired_children;
1932 Range::iterator it;
1933int actual_dimension;
19341935 desired_children.clear();
1936 all_children.clear();
1937 mdbImpl->get_child_meshsets( parent, all_children );
19381939for( it = all_children.begin(); it != all_children.end(); ++it )
1940 {
1941 mdbImpl->tag_get_data( geomTag, &( *it ), 1, &actual_dimension );
1942if( actual_dimension == desired_dimension ) desired_children.insert( *it );
1943 }
19441945return desired_children;
1946 }
19471948// runs GeomQueryTool point_in_vol and to test if vol A is inside vol B1949// returns true or false1950boolGeomTopoTool::A_is_in_B( EntityHandle volume_A, EntityHandle volume_B, GeomQueryTool* GQT )
1951 {
1952 ErrorCode rval;
19531954 Range child_surfaces, triangles, vertices;
1955double coord[3]; // coord[0] = x, etc.1956int result; // point in vol result; 0=F, 1=T19571958// find coordinates of any point on surface of A1959// get surface corresponding to volume, then get the triangles1960 child_surfaces = get_ct_children_by_dimension( volume_A, 2 );
1961 rval = mdbImpl->get_entities_by_type( *child_surfaces.begin(), MBTRI, triangles );MB_CHK_ERR( rval );
19621963// now get 1st triangle vertices1964 rval = mdbImpl->get_connectivity( &( *triangles.begin() ), 1, vertices );MB_CHK_ERR( rval );
19651966// now get coordinates of first vertex1967 rval = mdbImpl->get_coords( &( *vertices.begin() ), 1, &( coord[0] ) );MB_CHK_ERR( rval );
19681969// if point on A is inside vol B, return T; o.w. return F1970 rval = GQT->point_in_volume( volume_B, coord, result );MB_CHK_SET_ERR( rval, "Failed to complete point in volume query." );
19711972return ( result != 0 );
1973 }
19741975ErrorCode GeomTopoTool::insert_in_tree( EntityHandle ct_root, EntityHandle volume, GeomQueryTool* GQT )
1976 {
1977 ErrorCode rval;
19781979bool inserted = false;
1980 EntityHandle current_volume = volume; // volume to be inserted1981 EntityHandle tree_volume = ct_root; // volume already existing in the tree1982 EntityHandle parent = ct_root;
1983 Range child_volumes;
19841985// while not inserted in tree1986while( !inserted )
1987 {
1988// if current volume is insde of tree volume-- always true if tree volume1989// is the root of the tree1990if( tree_volume == ct_root || ( tree_volume != ct_root && A_is_in_B( current_volume, tree_volume, GQT ) ) )
1991 {
19921993 parent = tree_volume;
19941995// if tree_volume has children then we must test them,1996// (tree_volume will change)1997 child_volumes = get_ct_children_by_dimension( tree_volume, 3 );
1998if( child_volumes.size() > 0 ) tree_volume = child_volumes.pop_front();
1999// otherwise current_volume is the only child of the tree volume2000else2001 {
2002 rval = mdbImpl->add_parent_child( parent, current_volume );MB_CHK_SET_ERR( rval, "Failed to add parent-child relationship." );
20032004 inserted = true;
2005 }
2006// if current volume is not in the tree volume, the converse may be true2007 }
2008else2009 {
2010// if the tree volume is inside the current volume2011if( A_is_in_B( tree_volume, current_volume, GQT ) )
2012 {
2013// reverse their parentage2014 rval = mdbImpl->remove_parent_child( parent, tree_volume );MB_CHK_SET_ERR( rval, "Failed to remove parent-child relationship." );
2015 rval = mdbImpl->add_parent_child( current_volume, tree_volume );MB_CHK_SET_ERR( rval, "Failed to add parent-child relationship." );
2016 }
20172018if( child_volumes.size() == 0 )
2019 {
2020 rval = mdbImpl->add_parent_child( parent, current_volume );MB_CHK_SET_ERR( rval, "Failed to add parent-child relationship." );
2021 inserted = true;
2022 }
2023else2024 tree_volume = child_volumes.pop_front();
2025 }
2026 }
2027return MB_SUCCESS;
2028 }
20292030ErrorCode GeomTopoTool::restore_topology_from_geometric_inclusion( const Range& flat_volumes )
2031 {
20322033 ErrorCode rval;
2034// local var will go out of scope if errors appear, no need to free it also2035GeomQueryTool GQT( this );
2036 std::map< EntityHandle, EntityHandle > volume_surface; // map of volume2037// to its surface20382039 EntityHandle ct_root;
2040// create root meshset-- this will be top of tree2041 std::string meshset_name = "build_hierarchy_root";
2042 rval = mdbImpl->create_meshset( MESHSET_SET, ct_root );MB_CHK_ERR( rval );
2043 rval = mdbImpl->tag_set_data( nameTag, &ct_root, 1, meshset_name.c_str() );MB_CHK_ERR( rval );
20442045for( Range::iterator vol = flat_volumes.begin(); vol != flat_volumes.end(); vol++ )
2046 {
2047// get the surface corresponding to each volume2048// at this point, each volume meshset only has one 'child' surface2049// which exactly corresponds to that volume2050 Range child_surfaces = get_ct_children_by_dimension( *vol, 2 );
2051 volume_surface[*vol] = *child_surfaces.begin();
20522053 rval = insert_in_tree( ct_root, *vol, &GQT );MB_CHK_SET_ERR( rval, "Failed to insert volume into tree." );
2054 }
20552056// for each original volume, get its child volumes2057for( Range::iterator parent_it = flat_volumes.begin(); parent_it != flat_volumes.end(); parent_it++ )
2058 {
2059 Range volume_children = get_ct_children_by_dimension( *parent_it, 3 );
20602061if( volume_children.size() != 0 )
2062 {
2063// loop over all of original volume's child volumes2064for( Range::iterator child_it = volume_children.begin(); child_it != volume_children.end(); ++child_it )
2065 {
2066// set the sense of the surface mapped to the child volume to REVERSE2067// wrt the parent volume2068 rval = set_sense( volume_surface[*child_it], *parent_it, SENSE_REVERSE );MB_CHK_SET_ERR( rval, "Failed to set sense." );
20692070// add the child volume's surface as a child of the original volume2071// and delete the child volume as a child of original volume2072 rval = mdbImpl->add_parent_child( *parent_it, volume_surface[*child_it] );MB_CHK_SET_ERR( rval, "Failed to add parent-child relationship." );
2073 rval = mdbImpl->remove_parent_child( *parent_it, *child_it );MB_CHK_SET_ERR( rval, "Failed to remove parent-child relationship." );
2074 }
2075 }
2076 }
20772078return MB_SUCCESS;
2079 }
20802081 } // namespace moab