Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
GeomTopoTool.cpp
Go to the documentation of this file.
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  */
15 
16 #include "moab/GeomTopoTool.hpp"
17 #include "moab/GeomQueryTool.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>
26 
27 namespace moab
28 {
29 
30 // 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 the
34 // forward and reverse volumes, respectively. If a surface
35 // is non-manifold in a single volume, the same volume will
36 // be listed for both the forward and reverse slots.
37 const char GEOM_SENSE_2_TAG_NAME[] = "GEOM_SENSE_2";
38 
39 const char GEOM_SENSE_N_ENTS_TAG_NAME[] = "GEOM_SENSE_N_ENTS";
40 const char GEOM_SENSE_N_SENSES_TAG_NAME[] = "GEOM_SENSE_N_SENSES";
41 const char OBB_ROOT_TAG_NAME[] = "OBB_ROOT";
42 const char OBB_GSET_TAG_NAME[] = "OBB_GSET";
43 
44 const char IMPLICIT_COMPLEMENT_NAME[] = "impl_complement";
45 
47  bool find_geoments,
48  EntityHandle modelRootSet,
49  bool p_rootSets_vector,
50  bool restore_rootSets )
51  : mdbImpl( impl ), sense2Tag( 0 ), senseNEntsTag( 0 ), senseNSensesTag( 0 ), geomTag( 0 ), gidTag( 0 ),
52  obbRootTag( 0 ), obbGsetTag( 0 ), modelSet( modelRootSet ), updated( false ), setOffset( 0 ),
53  m_rootSets_vector( p_rootSets_vector ), oneVolRootSet( 0 )
54 {
55 
56  obbTree = new OrientedBoxTreeTool( impl, NULL, true );
57 
58  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" );
60 
61  // global id tag is not really needed, but mbsize complains if we do not set it for
62  // geometry entities
64 
65  rval =
67 
68  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" );
69 
70  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" );
71 
72  // set this value to zero for comparisons
74 
75  maxGlobalId[0] = maxGlobalId[1] = maxGlobalId[2] = maxGlobalId[3] = maxGlobalId[4] = 0;
76  if( find_geoments )
77  {
78  find_geomsets();
79  if( restore_rootSets )
80  {
81  rval = restore_obb_index();
82  if( 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 }
90 
92 {
93  delete obbTree;
94 }
95 
97 {
98  ErrorCode result;
99  if( 0 == geomTag )
100  {
102  MB_CHK_SET_ERR( result, "Failed to get the geometry dimension tag" );
103  }
104 
105  // check if the geo set belongs to this model
106  if( modelSet )
107  {
108  if( !mdbImpl->contains_entities( modelSet, &this_set, 1 ) )
109  {
110  // this g set does not belong to the current model
111  return -1;
112  }
113  }
114  // get the data for those tags
115  int dim;
116  result = mdbImpl->tag_get_data( geomTag, &this_set, 1, &dim );
117  if( MB_SUCCESS != result )
118  return -1;
119  else
120  return dim;
121 }
122 
124 {
125  ErrorCode result;
126  if( 0 == gidTag )
127  {
129  }
130 
131  // check if the geo set belongs to this model
132  if( modelSet )
133  {
134  if( !mdbImpl->contains_entities( modelSet, &this_set, 1 ) )
135  {
136  // this g set does not belong to the current model
137  return -1;
138  }
139  }
140 
141  // get the data for those tags
142  int id;
143  result = mdbImpl->tag_get_data( gidTag, &this_set, 1, &id );
144  if( MB_SUCCESS != result )
145  return -1;
146  else
147  return id;
148 }
149 
150 EntityHandle GeomTopoTool::entity_by_id( int dimension1, int id )
151 {
152  if( 0 > dimension1 || 3 < dimension1 )
153  {
154  MB_CHK_SET_ERR_CONT( MB_FAILURE, "Incorrect dimension provided" );
155  }
156  const Tag tags[] = { gidTag, geomTag };
157  const void* const vals[] = { &id, &dimension1 };
158  ErrorCode rval;
159 
160  Range results;
161  rval = mdbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET, tags, vals, 2, results );
162 
163  if( MB_SUCCESS != rval )
164  return 0;
165  else
166  return results.front();
167 }
168 
170  EntityHandle not_this,
171  EntityHandle across,
172  EntityHandle& other )
173 {
174  other = 0;
175 
176  // get all children of bounded
177  Range bdy, tmpr;
178  MB_CHK_SET_ERR( mdbImpl->get_child_meshsets( bounded, bdy ), "Failed to get the bounded entity's child meshsets" );
179 
180  // get all the parents of across
181  MB_CHK_SET_ERR( mdbImpl->get_parent_meshsets( across, tmpr ), "failed to get parent meshsets" );
182 
183  // possible candidates is the intersection
184  bdy = intersect( bdy, tmpr );
185 
186  // if only two, choose the other
187  if( 1 == bdy.size() && *bdy.begin() == not_this )
188  {
189  return MB_SUCCESS;
190  }
191  else if( 2 == bdy.size() )
192  {
193  if( *bdy.begin() == not_this ) other = *bdy.rbegin();
194  if( *bdy.rbegin() == not_this )
195  other = *bdy.begin();
196  else
197  return MB_FAILURE;
198  }
199  else
200  {
201  return MB_FAILURE;
202  }
203 
204  return MB_SUCCESS;
205 }
206 
208 {
210 
211  ErrorCode rval;
212  EntityHandle root;
213 
214  for( int dim = 2; dim <= 3; dim++ )
215  for( Range::iterator rit = geomRanges[dim].begin(); rit != geomRanges[dim].end(); ++rit )
216  {
217  rval = mdbImpl->tag_get_data( obbRootTag, &( *rit ), 1, &root );
218 
219  if( MB_SUCCESS == rval )
220  set_root_set( *rit, root );
221  else
222  {
223  return MB_TAG_NOT_FOUND;
224  }
225  }
226 
227  return MB_SUCCESS;
228 }
229 
231 {
232  // get all sets with this tag
233  Range geom_sets;
234 
235  if( 0 == geomTag )
236  {
238  "Failed to get geom dimension tag handle" );
239  }
240 
242  "Failed to get the geometry entities" );
243 
244  MB_CHK_SET_ERR( separate_by_dimension( geom_sets ), "Failed to separate geometry sets by dimension" );
245 
246  if( ranges )
247  {
248  for( int i = 0; i < 5; i++ )
249  {
250  ranges[i] = geomRanges[i];
251  }
252  }
253 
254  return MB_SUCCESS;
255 }
256 
258 {
259  const int val = dim;
260  const void* const dim_val[] = { &val };
262  "Failed to get entity set by type and tag" );
263 
264  return MB_SUCCESS;
265 }
266 
268 {
269  // store original offset for later
270  EntityHandle orig_offset = setOffset;
271 
272  // get all surfaces and volumes
273  Range surfs, vols;
274  MB_CHK_SET_ERR( get_gsets_by_dimension( 2, surfs ), "Could not get surface sets" );
275  MB_CHK_SET_ERR( get_gsets_by_dimension( 3, vols ), "Could not get volume sets" );
276 
277  // check the vector size
278  Range surfs_and_vols;
279  surfs_and_vols = vols;
280  surfs_and_vols.merge( surfs );
281 
282  // update the setOffset
283  setOffset = surfs_and_vols.front();
284 
285  EntityHandle exp_size = surfs_and_vols.back() - setOffset + 1;
286 
287  // if new EnitytHandle(s) are lower than the original offset
288  if( setOffset < orig_offset )
289  {
290  // insert empty values at the beginning of the vector
291  rootSets.insert( rootSets.begin(), orig_offset - setOffset, 0 );
292  }
293 
294  if( exp_size != rootSets.size() )
295  {
296  // resize rootSets vector if necessary (new space will be added at the back)
297  rootSets.resize( exp_size );
298  }
299 
300  return MB_SUCCESS;
301 }
302 
304 {
305  // make sure entity set is part of the model
306  Range model_ents;
307  MB_CHK_SET_ERR( mdbImpl->get_entities_by_handle( modelSet, model_ents ), "Failed to get entities" );
308  if( model_ents.find( eh ) == model_ents.end() )
309  {
310  MB_SET_ERR( MB_FAILURE, "Entity handle not in model set" );
311  }
312  return MB_SUCCESS;
313 }
314 
316 {
317  // Make sure this set is part of the model
318  MB_CHK_SET_ERR( is_owned_set( gset ), "Entity set is not part of this model" );
319 
320  // Find the dimension of the entity
321  int dim;
322  MB_CHK_SET_ERR( mdbImpl->tag_get_data( geomTag, &gset, 1, &dim ), "Failed to get dimension" );
323 
324  // Attempt to find a root for this set
325  EntityHandle root;
326  MB_CHK_SET_ERR( get_root( gset, root ), "Failed to find an obb tree root for the entity set" );
327 
328  // Create range of tree nodes to delete
329  Range nodes_to_delete;
330  nodes_to_delete.insert( root );
331 
332  // If passed ent is a vol and 'vol_only' is true, delete vol root and all nodes between vol and
333  // surf root
334  if( dim == 3 && vol_only )
335  {
336  // Range of child nodes to check before adding to delete list
337  Range child_tree_nodes;
338  MB_CHK_SET_ERR( mdbImpl->get_child_meshsets( root, child_tree_nodes ), "Problem getting child tree nodes" );
339 
340  // Traverse the tree, checking each child node until
341  // a surface root node is reached
342  while( child_tree_nodes.size() != 0 )
343  {
344  EntityHandle child = *child_tree_nodes.begin();
345  EntityHandle surf;
346  ErrorCode rval = mdbImpl->tag_get_data( obbGsetTag, &child, 1, &surf );
347  // If the node has a gset tag, it is a surf root. Stop here.
348  // If not, it is a tree node that needs to 1) have its children checked and
349  // 2) be added to delete range
350  if( MB_TAG_NOT_FOUND == rval )
351  {
352  Range new_child_tree_nodes;
353  MB_CHK_SET_ERR( mdbImpl->get_child_meshsets( child, new_child_tree_nodes ),
354  "Problem getting child nodes" );
355  child_tree_nodes.insert_list( new_child_tree_nodes.begin(), new_child_tree_nodes.end() );
356  nodes_to_delete.insert( child );
357  }
358  // We're done checking this node, so can erase from child list
359  child_tree_nodes.erase( child );
360  }
361  }
362  // If passed ent is a surf or a vol and 'vol_only' is false, recursively gather all child nodes
363  // and add them to delete list
364  else
365  {
366  Range all_tree_nodes;
367  MB_CHK_SET_ERR( mdbImpl->get_child_meshsets( root, all_tree_nodes, 0 ), "Failed to get child tree node sets" );
368  nodes_to_delete.insert_list( all_tree_nodes.begin(), all_tree_nodes.end() );
369  }
370 
371  // Remove the root nodes from the GTT data structures
372  for( Range::iterator it = nodes_to_delete.begin(); it != nodes_to_delete.end(); ++it )
373  {
374  // Check to see if node is a root
375  EntityHandle vol_or_surf;
376  ErrorCode rval = mdbImpl->tag_get_data( obbGsetTag, &( *it ), 1, &vol_or_surf );
377  if( MB_SUCCESS == rval )
378  {
379  // Remove from set of all roots
380  MB_CHK_SET_ERR( remove_root( vol_or_surf ), "Failed to remove node from GTT data structure" );
381  }
382  }
383 
384  // Delete the tree nodes from the database
385  MB_CHK_SET_ERR( mdbImpl->delete_entities( nodes_to_delete ), "Failed to delete node set" );
386 
387  return MB_SUCCESS;
388 }
389 
391 {
392  for( Range::iterator rit = geomRanges[3].begin(); rit != geomRanges[3].end(); ++rit )
393  {
394  EntityHandle root;
395  MB_CHK_ERR( mdbImpl->tag_get_data( obbRootTag, &( *rit ), 1, &root ) );
396 
397  MB_CHK_SET_ERR( delete_obb_tree( *rit, false ), "Failed to delete obb tree" );
398  }
399 
400  return MB_SUCCESS;
401 }
402 
404 {
405  MB_CHK_SET_ERR( is_owned_set( eh ), "Entity set is not part of this model" );
406 
407  // get the type
408  EntityType type = mdbImpl->type_from_handle( eh );
409 
410  // find the dimension of the entity
411  int dim;
412  MB_CHK_SET_ERR( mdbImpl->tag_get_data( geomTag, &eh, 1, &dim ), "Failed to get dimension" );
413 
414  // ensure that the rootSets vector is of the correct size
415  if( m_rootSets_vector && ( eh < setOffset || eh >= setOffset + rootSets.size() ) )
416  {
417  MB_CHK_SET_ERR( resize_rootSets(), "Error setting offset and sizing rootSets vector." );
418  }
419 
420  EntityHandle root;
421  // if it's a surface
422  if( dim == 2 && type == MBENTITYSET )
423  {
424  ErrorCode rval = get_root( eh, root );
425  if( MB_SUCCESS == rval )
426  {
427  std::cerr << "Surface obb tree already exists" << std::endl;
428  return MB_SUCCESS;
429  }
430  else if( MB_INDEX_OUT_OF_RANGE != rval )
431  {
432  MB_CHK_SET_ERR( rval, "Failed to get surface obb tree root" );
433  }
434 
435  Range tris;
436  MB_CHK_SET_ERR( mdbImpl->get_entities_by_dimension( eh, 2, tris ), "Failed to get entities by dimension" );
437 
438  if( tris.empty() )
439  {
440  std::cerr << "WARNING: Surface id " << global_id( eh ) << " (handle: " << eh << ")" << "has no facets"
441  << std::endl;
442  }
443 
444  MB_CHK_SET_ERR( obbTree->build( tris, root ), "Failed to build obb Tree for surface" );
445 
446  MB_CHK_SET_ERR( mdbImpl->add_entities( root, &eh, 1 ), "Failed to add entities to root set" );
447 
448  // add this root to the GeomTopoTool tree root indexing
449  set_root_set( eh, root );
450 
451  // if just building tree for surface, return here
452  return MB_SUCCESS;
453  }
454  // if it's a volume
455  else if( dim == 3 && type == MBENTITYSET )
456  {
457  // get its surfaces
458  Range tmp_surfs, surf_trees;
459  MB_CHK_SET_ERR( mdbImpl->get_child_meshsets( eh, tmp_surfs ), "Failed to get surface meshsets" );
460 
461  // get OBB trees or create for each surface
462  for( Range::iterator j = tmp_surfs.begin(); j != tmp_surfs.end(); ++j )
463  {
464  ErrorCode rval = get_root( *j, root );
465  // if root doesn't exist, create obb tree
466  if( MB_INDEX_OUT_OF_RANGE == rval )
467  {
468  MB_CHK_SET_ERR( construct_obb_tree( *j ), "Failed to get create surface obb tree" );
469  MB_CHK_SET_ERR( get_root( *j, root ), "Failed to get surface obb tree root" );
470  }
471  else
472  {
473  MB_CHK_SET_ERR( rval, "Failed to get surface obb tree root" );
474  }
475 
476  surf_trees.insert( root );
477  }
478 
479  // build OBB tree for volume
480  MB_CHK_SET_ERR( obbTree->join_trees( surf_trees, root ), "Failed to join the obb trees" );
481 
482  // add this root to the GeomTopoTool tree root indexing
483  set_root_set( eh, root );
484 
485  return MB_SUCCESS;
486  }
487  else
488  {
489  MB_SET_ERR( MB_FAILURE, "Improper dimension or type for constructing obb tree" );
490  }
491 }
492 
494 {
495 
496  // Tag the vol or surf with its obb root (obbRootTag)
497  MB_CHK_SET_ERR( mdbImpl->tag_set_data( obbRootTag, &vol_or_surf, 1, &root ), "Failed to set the obb root tag" );
498 
499  // Tag obb root with corresponding gset (obbGsetTag)
500  MB_CHK_SET_ERR( mdbImpl->tag_set_data( obbGsetTag, &root, 1, &vol_or_surf ), "Failed to set the obb gset tag" );
501 
502  // Add to the set of all roots
503  if( m_rootSets_vector )
504  rootSets[vol_or_surf - setOffset] = root;
505  else
506  mapRootSets[vol_or_surf] = root;
507 
508  return MB_SUCCESS;
509 }
510 
512 {
513  // Find the root of the vol or surf
514  EntityHandle root;
515  MB_CHK_SET_ERR( mdbImpl->tag_get_data( obbRootTag, &( vol_or_surf ), 1, &root ), "Failed to get obb root tag" );
516 
517  // If the ent is a vol, remove its root from obbtreetool
518  int dim;
519  MB_CHK_SET_ERR( mdbImpl->tag_get_data( geomTag, &vol_or_surf, 1, &dim ), "Failed to get dimension" );
520  if( dim == 3 )
521  {
522  MB_CHK_SET_ERR( obbTree->remove_root( root ), "Failed to remove root from obbTreeTool" );
523  }
524 
525  // Delete the obbGsetTag data from the root
526  MB_CHK_SET_ERR( mdbImpl->tag_delete_data( obbGsetTag, &root, 1 ), "Failed to delete obb root tag" );
527 
528  // Delete the obbRootTag data from the vol or surf
529  MB_CHK_SET_ERR( mdbImpl->tag_delete_data( obbRootTag, &vol_or_surf, 1 ), "Failed to delete obb root tag" );
530 
531  // Remove the root from set of all roots
532  if( m_rootSets_vector )
533  {
534  unsigned int index = vol_or_surf - setOffset;
535  if( index < rootSets.size() )
536  {
537  rootSets[index] = 0;
538  }
539  else
540  {
541  return MB_INDEX_OUT_OF_RANGE;
542  }
543  }
544  else
545  {
546  mapRootSets[vol_or_surf] = 0;
547  }
548 
549  return MB_SUCCESS;
550 }
551 
553 {
554  EntityHandle root;
555 
556  // get all surfaces and volumes
557  Range surfs, vols, vol_trees;
558  MB_CHK_SET_ERR( get_gsets_by_dimension( 2, surfs ), "Could not get surface sets" );
559  MB_CHK_SET_ERR( get_gsets_by_dimension( 3, vols ), "Could not get volume sets" );
560 
561  // for surface
562  Range one_vol_trees;
563  for( Range::iterator i = surfs.begin(); i != surfs.end(); ++i )
564  {
565  MB_CHK_SET_ERR( construct_obb_tree( *i ), "Failed to construct obb tree for surface" );
566  // get the root set of this volume
567  MB_CHK_SET_ERR( get_root( *i, root ), "Failed to get obb tree root for surface" );
568  // add to the Range of volume root sets
569  one_vol_trees.insert( root );
570  }
571 
572  // for volumes
573  for( Range::iterator i = vols.begin(); i != vols.end(); ++i )
574  {
575  // create tree for this volume
576  MB_CHK_SET_ERR( construct_obb_tree( *i ), "Failed to construct obb tree for volume" );
577  }
578 
579  // build OBB tree for volume
580  if( make_one_vol )
581  {
582  MB_CHK_SET_ERR( obbTree->join_trees( one_vol_trees, root ), "Failed to join surface trees into one volume" );
583  oneVolRootSet = root;
584  }
585 
586  return moab::MB_SUCCESS;
587 }
588 
589 //! Restore parent/child links between GEOM_TOPO mesh sets
591 {
592 
593  // look for geometric topology sets and restore parent/child links between them
594  // algorithm:
595  // - for each entity of dimension d=D-1..0:
596  // . get d-dimensional entity in entity
597  // . get all (d+1)-dim adjs to that entity
598  // . for each geom entity if dim d+1, if it contains any of the ents,
599  // add it to list of parents
600  // . make parent/child links with parents
601 
602  // the geomRanges are already known, separated by dimension
603 
604  std::vector< EntityHandle > parents;
605  Range tmp_parents;
606  ErrorCode result;
607 
608  // loop over dimensions
609  for( int dim = 2; dim >= 0; dim-- )
610  {
611  // mark entities of next higher dimension with their owners; regenerate tag
612  // each dimension so prev dim's tag data goes away
613  Tag owner_tag;
614  EntityHandle dum_val = 0;
615  result = mdbImpl->tag_get_handle( "__owner_tag", 1, MB_TYPE_HANDLE, owner_tag, MB_TAG_DENSE | MB_TAG_CREAT,
616  &dum_val );
617  if( MB_SUCCESS != result ) continue;
618  Range dp1ents;
619  std::vector< EntityHandle > owners;
620  for( Range::iterator rit = geomRanges[dim + 1].begin(); rit != geomRanges[dim + 1].end(); ++rit )
621  {
622  dp1ents.clear();
623  result = mdbImpl->get_entities_by_dimension( *rit, dim + 1, dp1ents );
624  if( MB_SUCCESS != result ) continue;
625  owners.resize( dp1ents.size() );
626  std::fill( owners.begin(), owners.end(), *rit );
627  result = mdbImpl->tag_set_data( owner_tag, dp1ents, &owners[0] );
628  if( MB_SUCCESS != result ) continue;
629  }
630 
631  for( Range::iterator d_it = geomRanges[dim].begin(); d_it != geomRanges[dim].end(); ++d_it )
632  {
633  Range dents;
634  result = mdbImpl->get_entities_by_dimension( *d_it, dim, dents );
635  if( MB_SUCCESS != result ) continue;
636  if( dents.empty() ) continue;
637 
638  // get (d+1)-dimensional adjs
639  dp1ents.clear();
640  result = mdbImpl->get_adjacencies( &( *dents.begin() ), 1, dim + 1, false, dp1ents );
641  if( MB_SUCCESS != result || dp1ents.empty() ) continue;
642 
643  // get owner tags
644  parents.resize( dp1ents.size() );
645  result = mdbImpl->tag_get_data( owner_tag, dp1ents, &parents[0] );
646  if( MB_TAG_NOT_FOUND == result )
647  {
648  MB_CHK_SET_ERR( result, "Could not find owner tag" );
649  }
650  if( MB_SUCCESS != result ) continue;
651 
652  // compress to a range to remove duplicates
653  tmp_parents.clear();
654  std::copy( parents.begin(), parents.end(), range_inserter( tmp_parents ) );
655  for( Range::iterator pit = tmp_parents.begin(); pit != tmp_parents.end(); ++pit )
656  {
657  result = mdbImpl->add_parent_child( *pit, *d_it );
658  MB_CHK_SET_ERR( result, "Failed to create parent child relationship" );
659  }
660 
661  // store surface senses within regions, and edge senses within surfaces
662  if( dim == 0 ) continue;
663  const EntityHandle *conn3 = NULL, *conn2 = NULL;
664  int len3 = 0, len2 = 0, err = 0, num = 0, sense = 0, offset = 0;
665  for( size_t i = 0; i < parents.size(); ++i )
666  {
667  result = mdbImpl->get_connectivity( dp1ents[i], conn3, len3, true );
668  MB_CHK_SET_ERR( result, "Failed to get the connectivity of the element" );
669  result = mdbImpl->get_connectivity( dents.front(), conn2, len2, true );
670  MB_CHK_SET_ERR( result, "Failed to get the connectivity of the first element" );
671  if( len2 > 4 )
672  {
673  MB_SET_ERR( MB_FAILURE, "Connectivity of incorrect length" );
674  }
675  err = CN::SideNumber( TYPE_FROM_HANDLE( dp1ents[i] ), conn3, conn2, len2, dim, num, sense, offset );
676  if( err ) return MB_FAILURE;
677 
678  result = set_sense( *d_it, parents[i], sense );
679  if( MB_MULTIPLE_ENTITIES_FOUND == result )
680  {
681  if( 2 == dim )
682  std::cerr << "Warning: Multiple volumes use surface with same sense." << std::endl
683  << " Some geometric sense data lost." << std::endl;
684  }
685  else if( MB_SUCCESS != result )
686  {
687  return result;
688  }
689  }
690  }
691 
692  // now delete owner tag on this dimension, automatically removes tag data
693  result = mdbImpl->tag_delete( owner_tag );
694  MB_CHK_SET_ERR( result, "Failed to delete the owner tag" );
695 
696  } // dim
697 
698  return result;
699 }
700 
702 {
703  ErrorCode result;
704 
705  result = check_geom_tag();
706  MB_CHK_SET_ERR( result, "Could not verify geometry dimension tag" );
707 
708  // get the data for those tags
709  std::vector< int > tag_vals( geom_sets.size() );
710  result = mdbImpl->tag_get_data( geomTag, geom_sets, &tag_vals[0] );
711  MB_CHK_SET_ERR( result, "Failed to get the geometry dimension tag" );
712 
714  std::vector< int >::iterator iit;
715 
716  for( int i = 0; i < 5; i++ )
717  this->geomRanges[i].clear();
718 
719  for( git = geom_sets.begin(), iit = tag_vals.begin(); git != geom_sets.end(); ++git, ++iit )
720  {
721  if( 0 <= *iit && 4 >= *iit )
722  geomRanges[*iit].insert( *git );
723  else
724  {
725  // assert(false);
726  // do nothing for now
727  }
728  }
729 
730  // establish the max global ids so far, per dimension
731  if( 0 == gidTag )
732  {
734  }
735 
736  for( int i = 0; i <= 4; i++ )
737  {
738  maxGlobalId[i] = 0;
739  for( Range::iterator it = geomRanges[i].begin(); it != geomRanges[i].end(); ++it )
740  {
741  EntityHandle set = *it;
742  int gid;
743 
744  result = mdbImpl->tag_get_data( gidTag, &set, 1, &gid );
745  if( MB_SUCCESS == result )
746  {
747  if( gid > maxGlobalId[i] ) maxGlobalId[i] = gid;
748  }
749  }
750  }
751 
752  return MB_SUCCESS;
753 }
754 
755 ErrorCode GeomTopoTool::construct_vertex_ranges( const Range& geom_sets, const Tag verts_tag )
756 {
757  // construct the vertex range for each entity and put on that tag
758  Range *temp_verts, temp_elems;
759  ErrorCode result = MB_SUCCESS;
760  for( Range::const_iterator it = geom_sets.begin(); it != geom_sets.end(); ++it )
761  {
762  temp_elems.clear();
763 
764  // get all the elements in the set, recursively
765  result = mdbImpl->get_entities_by_handle( *it, temp_elems, true );
766  MB_CHK_SET_ERR( result, "Failed to get the geometry set entities" );
767 
768  // make the new range
769  temp_verts = new( std::nothrow ) Range();
770  if( NULL == temp_verts )
771  {
772  MB_SET_ERR( MB_FAILURE, "Could not construct Range object" );
773  }
774 
775  // get all the verts of those elements; use get_adjacencies 'cuz it handles ranges better
776  result = mdbImpl->get_adjacencies( temp_elems, 0, false, *temp_verts, Interface::UNION );
777  if( MB_SUCCESS != result )
778  {
779  delete temp_verts;
780  }
781  MB_CHK_SET_ERR( result, "Failed to get the element's adjacent vertices" );
782 
783  // store this range as a tag on the entity
784  result = mdbImpl->tag_set_data( verts_tag, &( *it ), 1, &temp_verts );
785  if( MB_SUCCESS != result )
786  {
787  delete temp_verts;
788  }
789  MB_CHK_SET_ERR( result, "Failed to get the adjacent vertex data" );
790 
791  delete temp_verts;
792  temp_verts = NULL;
793  }
794 
795  return result;
796 }
797 
798 //! Store sense of entity relative to wrt_entity.
799 //!\return MB_MULTIPLE_ENTITIES_FOUND if surface already has a forward volume.
800 //! MB_SUCCESS if successful
801 //! otherwise whatever internal error code occurred.
803 {
804  // entity is lower dim (edge or face), wrt_entity is face or volume
805  int edim = dimension( entity );
806  int wrtdim = dimension( wrt_entity );
807  if( -1 == edim || -1 == wrtdim ) MB_SET_ERR( MB_FAILURE, "Non-geometric entity provided" );
808  if( wrtdim - edim != 1 ) MB_SET_ERR( MB_FAILURE, "Entity dimension mismatch" );
809  if( sense < -1 || sense > 1 ) MB_SET_ERR( MB_FAILURE, "Invalid sense data provided" );
810 
811  ErrorCode rval;
812 
813  if( 1 == edim )
814  {
815  // this case is about setting the sense of an edge in a face
816  // it could be -1, 0 (rare, non manifold), or 1
817  MB_CHK_SET_ERR( check_edge_sense_tags( true ), "Failed to check the curve to surface sense tag handles" );
818  std::vector< EntityHandle > higher_ents;
819  std::vector< int > senses;
820  rval = get_senses( entity, higher_ents, senses ); // the tags should be defined here
821  // if there are no higher_ents, we are fine, we will just set them
822  // if wrt_entity is not among higher_ents, we will add it to the list
823  // it is possible the entity (edge set) has no prior faces adjancent; in that case, the
824  // tag would not be set, and rval could be MB_TAG_NOT_FOUND; it is not a fatal error
825  if( MB_SUCCESS != rval && MB_TAG_NOT_FOUND != rval )
826  MB_CHK_SET_ERR( rval, "cannot determine sense tags for edge" );
827  bool append = true;
828  if( !higher_ents.empty() )
829  {
830  std::vector< EntityHandle >::iterator it = std::find( higher_ents.begin(), higher_ents.end(), wrt_entity );
831  if( it != higher_ents.end() )
832  {
833  // we should not reset the sense, if the sense is the same
834  // if the sense is different, put BOTH
835  unsigned int idx = it - higher_ents.begin();
836  int oldSense = senses[idx];
837  if( oldSense == sense ) return MB_SUCCESS; // sense already set fine, do not reset
838  if( 0 != oldSense && oldSense + sense != 0 ) return MB_MULTIPLE_ENTITIES_FOUND;
839  senses[idx] = SENSE_BOTH; // allow double senses
840  // do not need to add a new sense, but still need to reset the tag
841  // because of a new value
842  append = false;
843  }
844  }
845  if( append )
846  {
847  // what happens if a var tag data was already set before, and now it is
848  // reset with a different size??
849  higher_ents.push_back( wrt_entity );
850  senses.push_back( sense );
851  }
852  // finally, set the senses :
853  int dum_size = higher_ents.size();
854  void* dum_ptr = &higher_ents[0];
855  MB_CHK_SET_ERR( mdbImpl->tag_set_by_ptr( senseNEntsTag, &entity, 1, &dum_ptr, &dum_size ),
856  "Failed to set the sense data" );
857 
858  dum_ptr = &senses[0];
859  dum_size = higher_ents.size();
860  MB_CHK_SET_ERR( mdbImpl->tag_set_by_ptr( senseNSensesTag, &entity, 1, &dum_ptr, &dum_size ),
861  "Failed to set the sense data by pointer" );
862  }
863  else
864  {
865  // this case is about a face in the volume
866  // there could be only 2 volumes
867 
868  MB_CHK_SET_ERR( check_face_sense_tag( true ), "Failed to verify the face sense tag" );
869 
870  EntityHandle sense_data[2] = { 0, 0 };
871  rval = mdbImpl->tag_get_data( sense2Tag, &entity, 1, sense_data );
872  if( MB_TAG_NOT_FOUND != rval && MB_SUCCESS != rval ) MB_CHK_SET_ERR( rval, "Failed to get the sense2Tag data" );
873 
874  if( 0 == sense )
875  {
876  if( 0 != sense_data[0] && wrt_entity != sense_data[0] ) return MB_MULTIPLE_ENTITIES_FOUND;
877  if( 0 != sense_data[1] && wrt_entity != sense_data[1] ) return MB_MULTIPLE_ENTITIES_FOUND;
878  sense_data[0] = sense_data[1] = wrt_entity;
879  }
880  else if( -1 == sense )
881  {
882  if( 0 != sense_data[1] && wrt_entity != sense_data[1] ) return MB_MULTIPLE_ENTITIES_FOUND;
883  if( sense_data[1] == wrt_entity ) return MB_SUCCESS; // already set as we want
884  sense_data[1] = wrt_entity;
885  }
886  else if( 1 == sense )
887  {
888  if( 0 != sense_data[0] && wrt_entity != sense_data[0] ) return MB_MULTIPLE_ENTITIES_FOUND;
889  if( sense_data[0] == wrt_entity ) return MB_SUCCESS; // already set as we want
890  sense_data[0] = wrt_entity;
891  }
892  return mdbImpl->tag_set_data( sense2Tag, &entity, 1, sense_data );
893  }
894  return MB_SUCCESS;
895 }
896 
897 //! Get the sense of entity with respect to wrt_entity
898 //! Returns MB_ENTITY_NOT_FOUND if no relationship found
900 {
901  // entity is lower dim (edge or face), wrt_entity is face or volume
902  int edim = dimension( entity );
903  int wrtdim = dimension( wrt_entity );
904  if( -1 == edim || -1 == wrtdim ) MB_SET_ERR( MB_FAILURE, "Non-geometric entity provided" );
905  if( wrtdim - edim != 1 ) MB_SET_ERR( MB_FAILURE, "Entity dimension mismatch" );
906 
907  ErrorCode rval;
908 
909  if( 1 == edim )
910  {
911  // edge in face
912  MB_CHK_SET_ERR( check_edge_sense_tags( false ), "Failed to check the curve to surface sense tag handles" );
913 
914  std::vector< EntityHandle > faces;
915  std::vector< int > senses;
916  rval = get_senses( entity, faces, senses ); // the tags should be defined here
917  MB_CHK_SET_ERR( rval, "Failed to get the curve to surface sense data" );
918 
919  std::vector< EntityHandle >::iterator it = std::find( faces.begin(), faces.end(), wrt_entity );
920  if( it == faces.end() ) return MB_ENTITY_NOT_FOUND;
921  unsigned int index = it - faces.begin();
922  sense = senses[index];
923  }
924  else
925  {
926  // face in volume
927  MB_CHK_SET_ERR( check_face_sense_tag( false ), "Failed to check the surface to volume sense tag handle" );
928  EntityHandle sense_data[2] = { 0, 0 };
929  rval = mdbImpl->tag_get_data( sense2Tag, &entity, 1, sense_data );
930  if( MB_TAG_NOT_FOUND != rval && MB_SUCCESS != rval )
931  MB_CHK_SET_ERR( rval, "Failed to get the surface to volume sense data" );
932  if( ( wrt_entity == sense_data[0] ) && ( wrt_entity == sense_data[1] ) )
933  sense = 0;
934  else if( wrt_entity == sense_data[0] )
935  sense = 1;
936  else if( wrt_entity == sense_data[1] )
937  sense = -1;
938  else
939  return MB_ENTITY_NOT_FOUND;
940  }
941  return MB_SUCCESS;
942 }
943 
945  EntityHandle& forward_vol,
946  EntityHandle& reverse_vol )
947 {
948  // this method should only be called to retrieve surface to volume
949  // sense relationships
950  int ent_dim = dimension( surface_ent );
951  // verify the incoming entity dimensions for this call
952  if( ent_dim != 2 )
953  {
954  MB_SET_ERR( MB_FAILURE, "Entity dimension is incorrect for surface meshset" );
955  }
956 
957  // get the sense information for this surface
958  EntityHandle parent_vols[2] = { 0, 0 };
959  MB_CHK_SET_ERR( mdbImpl->tag_get_data( sense2Tag, &surface_ent, 1, parent_vols ),
960  "Failed to get surface sense data" );
961 
962  // set the outgoing values
963  forward_vol = parent_vols[0];
964  reverse_vol = parent_vols[1];
965 
966  return MB_SUCCESS;
967 }
968 
970  EntityHandle forward_vol,
971  EntityHandle reverse_vol )
972 {
973  // this mthod should only be called to retrieve surface to volume
974  // sense relationships
975  int ent_dim = dimension( surface_ent );
976  // verify the incoming entity dimensions for this call
977  if( ent_dim != 2 )
978  {
979  MB_SET_ERR( MB_FAILURE, "Entity dimension is incorrect for surface meshset" );
980  }
981 
982  // set the sense information for this surface
983  EntityHandle parent_vols[2] = { forward_vol, reverse_vol };
984  MB_CHK_SET_ERR( mdbImpl->tag_set_data( sense2Tag, &surface_ent, 1, parent_vols ),
985  "Failed to set surface sense data" );
986 
987  return MB_SUCCESS;
988 }
989 
990 // get sense of surface(s) wrt volume
992  int num_surfaces,
993  const EntityHandle* surfaces,
994  int* senses_out )
995 {
996 
997  /* The sense tags do not reference the implicit complement handle.
998  All surfaces that interact with the implicit complement should have
999  a null handle in the direction of the implicit complement. */
1000  // if (volume == impl_compl_handle)
1001  // volume = (EntityHandle) 0;
1002 
1003  for( int surf_num = 0; surf_num < num_surfaces; surf_num++ )
1004  {
1005  get_sense( surfaces[surf_num], volume, senses_out[surf_num] );
1006  }
1007 
1008  return MB_SUCCESS;
1009 }
1010 
1012  std::vector< EntityHandle >& wrt_entities,
1013  std::vector< int >& senses )
1014 {
1015  // the question here is: the wrt_entities is supplied or not?
1016  // I assume not, we will obtain it !!
1017  int edim = dimension( entity );
1018 
1019  if( -1 == edim ) MB_SET_ERR( MB_FAILURE, "Non-geometric entity provided" );
1020 
1021  wrt_entities.clear();
1022  senses.clear();
1023 
1024  if( 1 == edim ) // edge
1025  {
1026  MB_CHK_SET_ERR( check_edge_sense_tags( false ), "Failed to check the curve to surface sense tag handles" );
1027  const void* dum_ptr;
1028  int num_ents;
1029  MB_CHK_ERR( mdbImpl->tag_get_by_ptr( senseNEntsTag, &entity, 1, &dum_ptr, &num_ents ) );
1030 
1031  const EntityHandle* ents_data = static_cast< const EntityHandle* >( dum_ptr );
1032  std::copy( ents_data, ents_data + num_ents, std::back_inserter( wrt_entities ) );
1033 
1034  MB_CHK_ERR( mdbImpl->tag_get_by_ptr( senseNSensesTag, &entity, 1, &dum_ptr, &num_ents ) );
1035 
1036  const int* senses_data = static_cast< const int* >( dum_ptr );
1037  std::copy( senses_data, senses_data + num_ents, std::back_inserter( senses ) );
1038  }
1039  else // face in volume, edim == 2
1040  {
1041  MB_CHK_SET_ERR( check_face_sense_tag( false ), "Failed to check the surface to volume sense tag handle" );
1042  EntityHandle sense_data[2] = { 0, 0 };
1043  MB_CHK_SET_ERR( mdbImpl->tag_get_data( sense2Tag, &entity, 1, sense_data ),
1044  "Failed to get the surface to volume sense data" );
1045  if( sense_data[0] != 0 && sense_data[1] == sense_data[0] )
1046  {
1047  wrt_entities.push_back( sense_data[0] );
1048  senses.push_back( 0 ); // both
1049  }
1050  else
1051  {
1052  if( sense_data[0] != 0 )
1053  {
1054  wrt_entities.push_back( sense_data[0] );
1055  senses.push_back( 1 );
1056  }
1057  if( sense_data[1] != 0 )
1058  {
1059  wrt_entities.push_back( sense_data[1] );
1060  senses.push_back( -1 );
1061  }
1062  }
1063  }
1064  // filter the results with the sets that are in the model at this time
1065  // this was introduced because extracting some sets (e.g. neumann set, with mbconvert)
1066  // from a model would leave some sense tags not defined correctly
1067  // also, the geom ent set really needs to be part of the current model set
1068  unsigned int currentSize = 0;
1069 
1070  for( unsigned int index = 0; index < wrt_entities.size(); index++ )
1071  {
1072  EntityHandle wrt_ent = wrt_entities[index];
1073  if( wrt_ent )
1074  {
1075  if( mdbImpl->contains_entities( modelSet, &wrt_ent, 1 ) )
1076  {
1077  wrt_entities[currentSize] = wrt_entities[index];
1078  senses[currentSize] = senses[index];
1079  currentSize++;
1080  }
1081  }
1082  }
1083  wrt_entities.resize( currentSize );
1084  senses.resize( currentSize );
1085  //
1086  return MB_SUCCESS;
1087 }
1088 
1090  std::vector< EntityHandle >& wrt_entities,
1091  std::vector< int >& senses )
1092 {
1093  // not efficient, and maybe wrong
1094  for( unsigned int i = 0; i < wrt_entities.size(); i++ )
1095  {
1096  MB_CHK_SET_ERR( set_sense( entity, wrt_entities[i], senses[i] ), "Failed to set the sense" );
1097  }
1098 
1099  return MB_SUCCESS;
1100 }
1101 
1103 {
1104  std::vector< EntityHandle > parents;
1105  ErrorCode rval = mdbImpl->get_parent_meshsets( surface, parents );
1106 
1107  if( MB_SUCCESS == rval )
1108  {
1109  if( parents.size() != 2 )
1110  rval = MB_FAILURE;
1111  else if( parents.front() == old_volume )
1112  new_volume = parents.back();
1113  else if( parents.back() == old_volume )
1114  new_volume = parents.front();
1115  else
1116  rval = MB_FAILURE;
1117  }
1118 
1119  return rval;
1120 }
1121 
1123 {
1124  unsigned flags = create ? MB_TAG_DENSE | MB_TAG_CREAT : MB_TAG_DENSE;
1125  if( !geomTag )
1126  {
1127  // get any kind of tag that already exists
1129  "Could not get/create the geometry dimension tag" );
1130  }
1131  return MB_SUCCESS;
1132 }
1133 
1135 {
1136  unsigned flags = create ? MB_TAG_DENSE | MB_TAG_CREAT : MB_TAG_DENSE;
1137  if( !gidTag )
1138  {
1139  // get any kind of tag that already exists
1141  "Could not get/create the global id tag" );
1142  }
1143  return MB_SUCCESS;
1144 }
1145 
1146 // move the sense tag existence creation in private methods
1147 // verify sense face tag
1149 {
1150  unsigned flags = create ? MB_TAG_SPARSE | MB_TAG_CREAT | MB_TAG_ANY : MB_TAG_SPARSE | MB_TAG_ANY;
1151  if( !sense2Tag )
1152  {
1153  EntityHandle def_val[2] = { 0, 0 };
1155  "Could not get/create the sense2Tag" );
1156  }
1157  return MB_SUCCESS;
1158 }
1159 
1160 // verify sense edge tags
1162 {
1163  unsigned flags = MB_TAG_VARLEN | MB_TAG_SPARSE;
1164  if( create ) flags |= MB_TAG_CREAT;
1165  if( !senseNEntsTag )
1166  {
1168  "Failed to get the curve to surface entity tag handle" );
1170  flags ),
1171  "Failed to get the curve to surface sense tag handle" );
1172  }
1173  return MB_SUCCESS;
1174 }
1175 
1177 {
1178  if( dim < 0 || dim > 4 ) MB_SET_ERR( MB_FAILURE, "Invalid geometric dimension provided" );
1179 
1180  // see if it is not already set
1181  if( geomRanges[dim].find( set ) != geomRanges[dim].end() )
1182  {
1183  return MB_SUCCESS; // nothing to do, we already have it as a geo set of proper dimension
1184  }
1185  updated = false; // this should trigger at least an obb recomputation
1186  // get the geom topology tag
1187  ErrorCode result;
1188  if( 0 == geomTag )
1189  {
1191  MB_CHK_SET_ERR( result, "Failed to get the geometry dimension tag handle" );
1192  }
1193 
1194  if( 0 == gidTag )
1195  {
1197  }
1198 
1199  // make sure the added set has the geom tag properly set
1200  result = mdbImpl->tag_set_data( geomTag, &set, 1, &dim );
1201  MB_CHK_SET_ERR( result, "Failed set the geometry dimension tag value" );
1202 
1203  geomRanges[dim].insert( set );
1204  // not only that, but also add it to the root model set
1205  if( modelSet )
1206  {
1207  result = mdbImpl->add_entities( modelSet, &set, 1 );
1208  MB_CHK_SET_ERR( result, "Failed to add new geometry set to the tool's modelSet" );
1209  }
1210 
1211  // set the global ID value
1212  // if passed 0, just increase the max id for the dimension
1213  if( 0 == gid )
1214  {
1215  gid = ++maxGlobalId[dim];
1216  }
1217 
1218  result = mdbImpl->tag_set_data( gidTag, &set, 1, &gid );
1219  MB_CHK_SET_ERR( result, "Failed to get the global id tag value for the geom entity" );
1220 
1221  return MB_SUCCESS;
1222 }
1223 
1224 // will assume no geo sets are defined for this surface
1225 // will output a mesh_set that contains everything (all sets of interest), for proper output
1227 {
1228  // usual scenario is to read a surface smf file, and "geometrize" it, and output it as a
1229  // h5m file with proper sets, tags defined for mesh-based geometry
1230 
1231  // get all triangles/quads from the surface, then build loops
1232  // we may even have to
1233  // 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 definition
1235  bool debugFlag = false;
1236 
1237  Range surface_ents, edge_ents, loop_range;
1238 
1239  // most of these should be triangles and quads
1240  MB_CHK_SET_ERR( mdbImpl->get_entities_by_dimension( surface, 2, surface_ents ),
1241  "Failed to get the surface entities" );
1242 
1243  EntityHandle face = surface;
1244  if( !surface ) // in the case it is root set, create another set
1245  {
1246  MB_CHK_SET_ERR( mdbImpl->create_meshset( MESHSET_SET, face ), "Failed to create a the new surface meshset" );
1247  }
1248  // set the geo tag
1249  MB_CHK_SET_ERR( add_geo_set( face, 2 ), "Failed to add the geometry set to the tool" );
1250 
1251  // this will be our output set, will contain all our new geo sets
1252  MB_CHK_SET_ERR( mdbImpl->create_meshset( MESHSET_SET, output ), "Failed to create the output meshset" );
1253 
1254  // add first geo set (face) to the output set
1255  MB_CHK_SET_ERR( mdbImpl->add_entities( output, &face, 1 ), "Failed to add the new meshset to the output meshset" );
1256 
1257  // how many edges do we need to create?
1258  // depends on how many loops we have
1259  // also, we should avoid non-manifold topology
1260  if( !surface )
1261  { // in this case, surface is root, so we have to add entities
1262  MB_CHK_SET_ERR( mdbImpl->add_entities( face, surface_ents ),
1263  "Failed to add surface entities to the surface meshset" );
1264  }
1265 
1266  Skinner tool( mdbImpl );
1267  MB_CHK_SET_ERR( tool.find_skin( 0, surface_ents, 1, edge_ents ), "Failed to skin the surface entities" );
1268  if( debugFlag )
1269  {
1270  std::cout << "skinning edges: " << edge_ents.size() << "\n";
1271  for( Range::iterator it = edge_ents.begin(); it != edge_ents.end(); ++it )
1272  {
1273  EntityHandle ed = *it;
1274  std::cout << "edge: " << mdbImpl->id_from_handle( ed ) << " type:" << mdbImpl->type_from_handle( ed )
1275  << "\n";
1276  std::cout << mdbImpl->list_entity( ed );
1277  }
1278  }
1279 
1280  std::vector< EntityHandle > edges_loop;
1281 
1282  Range pool_of_edges = edge_ents;
1283  Range used_edges; // these edges are already used for some loops
1284  // get a new one
1285 
1286  while( !pool_of_edges.empty() )
1287  {
1288  // get the first edge, and start a loop with it
1289  EntityHandle current_edge = pool_of_edges[0];
1290  if( debugFlag )
1291  {
1292  std::cout << "Start current edge: " << mdbImpl->id_from_handle( current_edge ) << "\n ";
1293  std::cout << mdbImpl->list_entity( current_edge );
1294  }
1295  // get its triangle / quad and see its orientation
1296  std::vector< EntityHandle > tris;
1297  MB_CHK_SET_ERR( mdbImpl->get_adjacencies( &current_edge, 1, 2, false, tris ),
1298  "Failed to get the adjacent triangles to the current edge" );
1299  if( tris.size() != 1 ) MB_SET_ERR( MB_FAILURE, "Edge not on boundary" );
1300 
1301  int side_n, sense, offset;
1302  MB_CHK_SET_ERR( mdbImpl->side_number( tris[0], current_edge, side_n, sense, offset ),
1303  "Failed to get the current edge's side number" );
1304 
1305  const EntityHandle* conn2;
1306  int nnodes2;
1307  MB_CHK_SET_ERR( mdbImpl->get_connectivity( current_edge, conn2, nnodes2 ),
1308  "Failed to get the current edge's connectivity" );
1309 
1310  if( nnodes2 != 2 ) MB_SET_ERR( MB_FAILURE, "Incorrect number of nodes found." );
1311 
1312  EntityHandle start_node = conn2[0];
1313  EntityHandle next_node = conn2[1];
1314 
1315  if( sense == -1 )
1316  {
1317  // revert the edge, and start well
1318  EntityHandle nn2[2] = { conn2[1], conn2[0] };
1319  MB_CHK_SET_ERR( mdbImpl->set_connectivity( current_edge, nn2, 2 ),
1320  "Failed to set the connectivity of the current edge" );
1321 
1322  start_node = nn2[0]; // or conn2[0] !!! beware: conn2 is modified
1323  next_node = nn2[1]; // or conn2[1] !!!
1324  // reset connectivity of edge
1325  if( debugFlag ) std::cout << " current edge needs reversed\n";
1326  }
1327  // start a new loop of edges
1328  edges_loop.clear(); // every edge loop starts fresh
1329  edges_loop.push_back( current_edge );
1330  used_edges.insert( current_edge );
1331  pool_of_edges.erase( current_edge );
1332 
1333  if( debugFlag )
1334  {
1335  std::cout << " start node: " << start_node << "\n";
1336  std::cout << mdbImpl->list_entity( start_node );
1337  std::cout << " next node: " << next_node << "\n";
1338  std::cout << mdbImpl->list_entity( next_node );
1339  }
1340  while( next_node != start_node )
1341  {
1342  // find the next edge in the skin
1343  std::vector< EntityHandle > candidate_edges;
1344  MB_CHK_SET_ERR( mdbImpl->get_adjacencies( &next_node, 1, 1, false, candidate_edges ),
1345  "Failed to get the adjacent edges to the next node" );
1346  // filter the edges that are used, or the edges not in the skin
1347  std::vector< EntityHandle > good_edges;
1348  for( int k = 0; k < (int)candidate_edges.size(); k++ )
1349  {
1350  EntityHandle edg = candidate_edges[k];
1351  if( used_edges.find( edg ) != used_edges.end() ) continue;
1352  if( pool_of_edges.find( edg ) != pool_of_edges.end() ) good_edges.push_back( edg );
1353  }
1354  if( good_edges.size() != 1 )
1355  {
1356  std::cout << " good_edges.size()=" << good_edges.size() << " STOP\n";
1357  MB_SET_ERR( MB_FAILURE, "Number of good edges is not one. Could not complete the loop" );
1358  }
1359  // see if the orientation is good; if not, revert it
1360 
1361  current_edge = good_edges[0];
1362  MB_CHK_SET_ERR( mdbImpl->get_connectivity( current_edge, conn2, nnodes2 ),
1363  "Failed to get the connectivity of the current edge" );
1364  if( nnodes2 != 2 ) MB_SET_ERR( MB_FAILURE, "Incorrect number of nodes found" );
1365 
1366  if( conn2[0] != next_node )
1367  {
1368  if( conn2[1] != next_node )
1369  {
1370  // the edge is not connected then to current edge
1371  // bail out
1372  std::cout << "edge " << mdbImpl->id_from_handle( current_edge ) << " not connected to node "
1373  << next_node << "\n";
1374  MB_SET_ERR( MB_FAILURE, "Current edge is not connected to node" );
1375  ;
1376  }
1377  if( debugFlag )
1378  {
1379  std::cout << " revert edge " << mdbImpl->id_from_handle( current_edge ) << "\n";
1380  std::cout << mdbImpl->list_entity( current_edge );
1381  }
1382  // orientation should be reversed
1383  EntityHandle nn2[2] = { conn2[1], conn2[0] };
1384  MB_CHK_SET_ERR( mdbImpl->set_connectivity( current_edge, nn2, 2 ),
1385  "Failed to set the connectivity of the current edge" );
1386 
1387  {
1388  std::cout << "after revert edge " << mdbImpl->id_from_handle( current_edge ) << "\n";
1389  std::cout << mdbImpl->list_entity( current_edge );
1390  std::cout << " conn2: " << conn2[0] << " " << conn2[1] << "\n";
1391  }
1392  }
1393  // before reversion, conn2 was something { n1, next_node}
1394  // after reversion, conn2 became {next_node, n1}, so the
1395  // new next node will be still conn2[1]; big surprise, as
1396  // I didn't expect the conn2 to change.
1397  // it seems that const EntityHandle * conn2 means conn2 cannot be
1398  // changed, but what is pointed to by it will change when we reset connectivity for edge
1399  next_node = conn2[1];
1400 
1401  if( debugFlag )
1402  {
1403  std::cout << " current edge: " << mdbImpl->id_from_handle( current_edge ) << "\n ";
1404  std::cout << mdbImpl->list_entity( current_edge );
1405  std::cout << "next node: " << next_node << "\n ";
1406  std::cout << mdbImpl->list_entity( next_node );
1407  }
1408  edges_loop.push_back( current_edge );
1409  used_edges.insert( current_edge );
1410  pool_of_edges.erase( current_edge );
1411  }
1412  // at this point, we have a loop formed;
1413  // create a geo edge, a vertex set, and add it to our sets
1414 
1416  MB_CHK_SET_ERR( mdbImpl->create_meshset( MESHSET_ORDERED, edge ), "Failed to create the edge meshset" );
1417 
1418  MB_CHK_SET_ERR( add_geo_set( edge, 1 ), "Failed to add the edge meshset to the tool's model set" );
1419  // add the mesh edges:
1420  // add loops edges to the edge set
1421  MB_CHK_SET_ERR( mdbImpl->add_entities( edge, &edges_loop[0], edges_loop.size() ),
1422  "Failed to add entities to the edge meshset" );
1423  // create a vertex set
1425  MB_CHK_SET_ERR( mdbImpl->create_meshset( MESHSET_SET, vertex ), "Failed to create the vertex meshset" );
1426  MB_CHK_SET_ERR( add_geo_set( vertex, 0 ), "Failed to add the vertex meshset to the tool's model set" );
1427  // add one node to the vertex set
1428 
1429  MB_CHK_SET_ERR( mdbImpl->add_entities( vertex, &start_node, 1 ),
1430  "Failed to add entities to the vertex meshset" );
1431 
1433  "Failed to create the edge to face parent child relationship" );
1434 
1436  "Failed to create the vertex to edge parent child relationship" );
1437 
1438  // the sense of the edge in face is for sure positive (forward)
1439  MB_CHK_SET_ERR( set_sense( edge, face, 1 ), "Failed to set the edge to face sense" );
1440  // also add our sets to the output set, to be sure to be exported
1441 
1442  MB_CHK_SET_ERR( mdbImpl->add_entities( output, &edge, 1 ), "Failed to add the edge meshset to the output set" );
1444  "Failed to add the vertex meshset to the output set" );
1445 
1446  if( debugFlag )
1447  {
1448  std::cout << "add edge with start node " << start_node << " with " << edges_loop.size() << " edges\n";
1449  }
1450  }
1451 
1452  return MB_SUCCESS;
1453 }
1454 
1455 /*
1456  * This would create a deep copy of the geom topo model, into a new geom topo tool
1457  * sets will be duplicated, but entities not
1458  * modelSet will be a new one
1459  * if the original set was null (root), a new model set will be created for
1460  * original model, and its entities will be the original g sets
1461  * Scenario: split a face along a ground line, then write only one surface
1462  * the common line has 2 faces in var len tag for sense edge; if we write only one
1463  * surface to a new database, the var len tag of the edge will be extracted with 2 values, but
1464  * only one value will make sense, the other will be zero.
1465  *
1466  * There is no workaround; we need to create a duplicate model that has only that surface
1467  * and its children (and grand-children). Then the var len sense edge-face tags will have
1468  * the right size.
1469  *
1470  */
1471 ErrorCode GeomTopoTool::duplicate_model( GeomTopoTool*& duplicate, std::vector< EntityHandle >* pvGEnts )
1472 {
1473  // will
1474  EntityHandle rootModelSet;
1475  MB_CHK_SET_ERR( mdbImpl->create_meshset( MESHSET_SET, rootModelSet ), "Failed to create the rootModelSet" );
1476 
1477  if( 0 == geomTag )
1478  {
1480  "Failed to get the geometry dimension tag handle" );
1481  }
1482  if( 0 == gidTag )
1483  {
1485  }
1486  // extract from the geomSet the dimension, children, and grand-children
1487  Range depSets; // dependents of the geomSet, including the geomSet
1488  // add in this range all the dependents of this, to filter the ones that need to be deep copied
1489 
1490  if( pvGEnts != NULL )
1491  {
1492  unsigned int numGents = pvGEnts->size();
1493  for( unsigned int k = 0; k < numGents; k++ )
1494  {
1495  EntityHandle geomSet = ( *pvGEnts )[k];
1496  // will keep accumulating to the depSets range
1497  // dependents are returned, not only the direct children.
1498  // 0 for numHops means that all
1499  MB_CHK_SET_ERR( mdbImpl->get_child_meshsets( geomSet, depSets, 0 ),
1500  "Failed to get the geometry set's child meshsets" );
1501 
1502  depSets.insert( geomSet );
1503  }
1504  }
1505 
1506  // add to the root model set copies of the gsets, with correct sets
1507  // keep a map between sets to help in copying parent/child relations
1508  std::map< EntityHandle, EntityHandle > relate;
1509  // each set will get the same entities as the original
1510  for( int dim = 0; dim < 5; dim++ )
1511  {
1512  int gid = 0;
1513  unsigned int set_options = ( ( 1 != dim ) ? MESHSET_SET : MESHSET_ORDERED );
1514  for( Range::iterator it = geomRanges[dim].begin(); it != geomRanges[dim].end(); ++it )
1515  {
1516  EntityHandle set = *it;
1517  if( pvGEnts != NULL && depSets.find( set ) == depSets.end() )
1518  continue; // this means that this set is not of interest, skip it
1519  EntityHandle newSet;
1520  MB_CHK_SET_ERR( mdbImpl->create_meshset( set_options, newSet ), "Failed to create new meshset" );
1521 
1522  relate[set] = newSet;
1523  MB_CHK_SET_ERR( mdbImpl->add_entities( rootModelSet, &newSet, 1 ),
1524  "Failed to add the new meshset to the tool's modelSet" );
1525 
1526  // make it a geo set, and give also global id in order
1527  MB_CHK_SET_ERR( mdbImpl->tag_set_data( geomTag, &newSet, 1, &dim ),
1528  "Failed to set the new meshset's geometry dimension data" );
1529 
1530  gid++; // increment global id, everything starts with 1 in the new model!
1531  MB_CHK_SET_ERR( mdbImpl->tag_set_data( gidTag, &newSet, 1, &gid ),
1532  "Failed to get the new meshset's global id data" );
1533 
1534  if( dim == 1 )
1535  {
1536  // the entities are ordered, we need to retrieve them ordered, and set them ordered
1537  std::vector< EntityHandle > mesh_edges;
1538  MB_CHK_SET_ERR( mdbImpl->get_entities_by_handle( set, mesh_edges ),
1539  "Failed to get the meshset entities by handle" );
1540 
1541  MB_CHK_SET_ERR( mdbImpl->add_entities( newSet, &( mesh_edges[0] ), (int)mesh_edges.size() ),
1542  "Failed to add the new entities to the new meshset" );
1543  }
1544  else
1545  {
1546  Range ents;
1548  "Failed to add the entities to the existing meshset" );
1549 
1550  MB_CHK_SET_ERR( mdbImpl->add_entities( newSet, ents ),
1551  "Failed to add the entities to the new meshset" );
1552  }
1553  // set parent/child relations if dim>=1
1554  if( dim >= 1 )
1555  {
1556  Range children;
1557  // the children of geo sets are only g sets
1558  // num_hops = 1 by default
1559  MB_CHK_SET_ERR( mdbImpl->get_child_meshsets( set, children ),
1560  "Failed to get the child meshsets of the existing set" );
1561 
1562  for( Range::iterator it2 = children.begin(); it2 != children.end(); ++it2 )
1563  {
1564  EntityHandle newChildSet = relate[*it2];
1565  MB_CHK_SET_ERR( mdbImpl->add_parent_child( newSet, newChildSet ),
1566  "Failed to create parent child relationship to the new meshset" );
1567  }
1568  }
1569  }
1570  }
1571 
1572  duplicate = new GeomTopoTool( mdbImpl, true, rootModelSet ); // will retrieve the
1573  // sets and put them in ranges
1574 
1575  // this is the lazy way to it:
1576  // newgtt->restore_topology_from_adjacency(); // will reset the sense entities, and with this,
1577  // the model represented by this new gtt will be complete set senses by peeking at the old model
1578  // make sure we have the sense tags defined
1579  MB_CHK_SET_ERR( check_face_sense_tag( true ), "Failed to check the face to volume sense tag handle" );
1580 
1581  MB_CHK_SET_ERR( check_edge_sense_tags( true ), "Failed to check the curve to surface sense tag handles" );
1582 
1583  for( int dd = 1; dd <= 2; dd++ ) // do it for surfaces and edges
1584  {
1585  for( Range::iterator it = geomRanges[dd].begin(); it != geomRanges[dd].end(); ++it )
1586  {
1587  EntityHandle surf = *it;
1588  if( pvGEnts != NULL && depSets.find( surf ) == depSets.end() )
1589  continue; // this means that this set is not of interest, skip it
1590  EntityHandle newSurf = relate[surf];
1591  // we can actually look at the tag data, to be more efficient
1592  // or use the
1593  std::vector< EntityHandle > solids;
1594  std::vector< int > senses;
1595  MB_CHK_SET_ERR( this->get_senses( surf, solids, senses ),
1596  "Failed to get the sense data for the surface with respect to its volumes" );
1597 
1598  std::vector< EntityHandle > newSolids;
1599  std::vector< int > newSenses;
1600  for( unsigned int i = 0; i < solids.size(); i++ )
1601  {
1602  if( pvGEnts != NULL && depSets.find( solids[i] ) == depSets.end() )
1603  continue; // this means that this set is not of interest, skip it
1604  EntityHandle newSolid = relate[solids[i]];
1605  // see which "solids" are in the new model
1606  newSolids.push_back( newSolid );
1607  newSenses.push_back( senses[i] );
1608  }
1609  MB_CHK_SET_ERR( duplicate->set_senses( newSurf, newSolids, newSenses ),
1610  "Failed to set the sense data for the surface with respect to the new volumes" );
1611  }
1612  }
1613  // if the original root model set for this model is 0 (root set), then create
1614  // a new set and put all the old sets in the new model set
1615  // in this way, the existing gtt remains valid (otherwise, the modelSet would contain all the
1616  // gsets, the old ones and the new ones; the root set contains everything)
1617  if( modelSet == 0 )
1618  {
1619  MB_CHK_SET_ERR( mdbImpl->create_meshset( MESHSET_SET, modelSet ), "Failed to create the modelSet meshset" );
1620 
1621  // add to this new set all previous sets (which are still in ranges)
1622  for( int dim = 0; dim < 5; dim++ )
1623  {
1625  "Failed to add the geometric meshsets to the tool's modelSet" );
1626  }
1627  }
1628  return MB_SUCCESS;
1629 }
1630 
1632 {
1633  if( impl_compl_handle )
1634  {
1635  implicit_complement = impl_compl_handle;
1636  return MB_SUCCESS;
1637  }
1638  else
1639  {
1640  return MB_ENTITY_NOT_FOUND;
1641  }
1642 }
1643 
1645 {
1646 
1647  // if the implicit complement is already setup,
1648  // we're done
1649  if( impl_compl_handle != 0 )
1650  {
1651  std::cout << "IPC already exists!" << std::endl;
1652  return MB_SUCCESS;
1653  }
1654 
1655  // if not, then query for a set with it's name
1656  Range entities;
1657  const void* const tagdata[] = { IMPLICIT_COMPLEMENT_NAME };
1658  ErrorCode rval = mdbImpl->get_entities_by_type_and_tag( modelSet, MBENTITYSET, &nameTag, tagdata, 1, entities );
1659  // query error
1660  MB_CHK_SET_ERR( rval, "Unable to query for implicit complement" );
1661 
1662  // if we found exactly one, set it as the implicit complement
1663  if( entities.size() == 1 )
1664  {
1665  impl_compl_handle = entities.front();
1666  return MB_SUCCESS;
1667  }
1668 
1669  // found too many
1670  if( entities.size() > 1 ) MB_CHK_SET_ERR( MB_MULTIPLE_ENTITIES_FOUND, "Too many implicit complement sets" );
1671 
1672  // found none
1673  if( entities.empty() )
1674  {
1675  // create implicit complement if requested
1676  MB_CHK_SET_ERR( generate_implicit_complement( impl_compl_handle ), "Could not create implicit complement" );
1677 
1679  "Could not set the name tag for the implicit complement" );
1680 
1681  MB_CHK_SET_ERR( add_geo_set( impl_compl_handle, 3 ), "Failed to add implicit complement to model" );
1682 
1683  // assign category tag - this is presumably for consistency so that the
1684  // implicit complement has all the appearance of being the same as any
1685  // other volume
1686  Tag category_tag;
1689  "Could not get the category tag" );
1690 
1691  static const char volume_category[CATEGORY_TAG_SIZE] = "Volume\0";
1692  MB_CHK_SET_ERR( mdbImpl->tag_set_data( category_tag, &impl_compl_handle, 1, volume_category ),
1693  "Could not set the category tag for the implicit complement" );
1694 
1695  return MB_SUCCESS;
1696  }
1697 
1698  return MB_FAILURE;
1699 }
1700 
1702 {
1703  MB_CHK_SET_ERR( mdbImpl->create_meshset( MESHSET_SET, implicit_complement_set ),
1704  "Failed to create mesh set for implicit complement" );
1705 
1706  // make sure the sense2Tag is set
1707  if( !sense2Tag )
1708  {
1709  check_face_sense_tag( true );
1710  }
1711 
1712  // get all geometric surface sets
1713  Range surfs;
1714  MB_CHK_SET_ERR( get_gsets_by_dimension( 2, surfs ), "Could not get surface sets" );
1715 
1716  // search through all surfaces
1717  std::vector< EntityHandle > parent_vols;
1718  for( Range::iterator surf_i = surfs.begin(); surf_i != surfs.end(); ++surf_i )
1719  {
1720 
1721  parent_vols.clear();
1722  // get parents of each surface
1723  MB_CHK_SET_ERR( mdbImpl->get_parent_meshsets( *surf_i, parent_vols ), "Failed to get volume meshsets" );
1724 
1725  // if only one parent, get the OBB root for this surface
1726  if( parent_vols.size() == 1 )
1727  {
1728 
1729  // add this surf to the topology of the implicit complement volume
1730  MB_CHK_SET_ERR( mdbImpl->add_parent_child( implicit_complement_set, *surf_i ),
1731  "Could not add surface to implicit complement set" );
1732 
1733  // get the surface sense wrt original volume
1734  EntityHandle sense_data[2] = { 0, 0 };
1735  MB_CHK_SET_ERR( get_surface_senses( *surf_i, sense_data[0], sense_data[1] ),
1736  "Could not get surface sense data" );
1737 
1738  // set the surface sense wrt implicit complement volume
1739  if( 0 == sense_data[0] && 0 == sense_data[1] )
1740  MB_SET_ERR( MB_FAILURE, "No sense data for current surface" );
1741  if( 0 == sense_data[0] )
1742  sense_data[0] = implicit_complement_set;
1743  else if( 0 == sense_data[1] )
1744  sense_data[1] = implicit_complement_set;
1745  else
1746  MB_SET_ERR( MB_FAILURE, "Could not insert implicit complement into surface sense data" );
1747 
1748  // set the new sense data for this surface
1749  MB_CHK_SET_ERR( set_surface_senses( *surf_i, sense_data[0], sense_data[1] ),
1750  "Failed to set sense tag data" );
1751  }
1752  } // end surface loop
1753 
1754  return MB_SUCCESS;
1755 }
1756 
1757 #define RETFALSE( a, b ) \
1758  { \
1759  std::cout << ( a ) << "\n"; \
1760  mdbImpl->list_entity( b ); \
1761  return false; \
1762  }
1764 {
1765  // vertex sets should have one node
1766  Range::iterator rit;
1767  ErrorCode rval;
1768  for( rit = geomRanges[0].begin(); rit != geomRanges[0].end(); ++rit )
1769  {
1770  EntityHandle vSet = *rit;
1771  Range nodes;
1772  rval = mdbImpl->get_entities_by_handle( vSet, nodes );
1773  if( MB_SUCCESS != rval ) RETFALSE( " failed to get nodes from vertex set ", vSet );
1774  if( nodes.size() != 1 ) RETFALSE( " number of nodes is different from 1 ", vSet )
1775  EntityType type = mdbImpl->type_from_handle( nodes[0] );
1776  if( type != MBVERTEX ) RETFALSE( " entity in vertex set is not a node ", nodes[0] )
1777  // get all parents, and see if they belong to geomRanges[1]
1778  Range edges;
1779  rval = mdbImpl->get_parent_meshsets( vSet, edges );
1780  if( MB_SUCCESS != rval ) RETFALSE( " can't get parent edges for a node set ", vSet )
1781  Range notEdges = subtract( edges, geomRanges[1] );
1782  if( !notEdges.empty() ) RETFALSE( " some parents of a node set are not geo edges ", notEdges[0] )
1783  }
1784 
1785  // edges to be formed by continuous chain of mesh edges, oriented correctly
1786  for( rit = geomRanges[1].begin(); rit != geomRanges[1].end(); ++rit )
1787  {
1788  EntityHandle edge = *rit;
1789  std::vector< EntityHandle > mesh_edges;
1790  rval = mdbImpl->get_entities_by_type( edge, MBEDGE, mesh_edges );
1791  if( MB_SUCCESS != rval ) RETFALSE( " can't get mesh edges from edge set", edge )
1792  int num_edges = (int)mesh_edges.size();
1793  if( num_edges == 0 ) RETFALSE( " no mesh edges in edge set ", edge )
1794  EntityHandle firstNode;
1795  EntityHandle currentNode; // will also hold the last node in chain of edges
1796  const EntityHandle* conn2;
1797  int nnodes2;
1798  // get all parents, and see if they belong to geomRanges[1]
1799  for( int i = 0; i < num_edges; i++ )
1800  {
1801  rval = mdbImpl->get_connectivity( mesh_edges[i], conn2, nnodes2 );
1802  if( MB_SUCCESS != rval || nnodes2 != 2 ) RETFALSE( " mesh edge connectivity is wrong ", mesh_edges[i] )
1803  if( i == 0 )
1804  {
1805  firstNode = conn2[0];
1806  currentNode = conn2[1];
1807  }
1808 
1809  else // if ( (i>0) )
1810  {
1811  // check the current node is conn[0]
1812  if( conn2[0] != currentNode )
1813  {
1814  std::cout << "i=" << i << " conn2:" << conn2[0] << " " << conn2[1] << " currentNode:" << currentNode
1815  << "\n";
1816  mdbImpl->list_entity( mesh_edges[i] );
1817  RETFALSE( " edges are not contiguous in edge set ", edge )
1818  }
1819  currentNode = conn2[1];
1820  }
1821  }
1822  // check the children of the edge set; do they have the first and last node?
1823  Range vertSets;
1824  rval = mdbImpl->get_child_meshsets( edge, vertSets );
1825  if( MB_SUCCESS != rval ) RETFALSE( " can't get vertex children ", edge )
1826  Range notVertices = subtract( vertSets, geomRanges[0] );
1827  if( !notVertices.empty() ) RETFALSE( " children sets that are not vertices ", notVertices[0] )
1828  for( Range::iterator it = vertSets.begin(); it != vertSets.end(); ++it )
1829  {
1830  if( !mdbImpl->contains_entities( *it, &firstNode, 1 ) &&
1831  !mdbImpl->contains_entities( *it, &currentNode, 1 ) )
1832  RETFALSE( " a vertex set is not containing the first and last nodes ", *it )
1833  }
1834  // check now the faces / parents
1835  Range faceSets;
1836  rval = mdbImpl->get_parent_meshsets( edge, faceSets );
1837  if( MB_SUCCESS != rval ) RETFALSE( " can't get edge parents ", edge )
1838  Range notFaces = subtract( faceSets, geomRanges[2] );
1839  if( !notFaces.empty() ) RETFALSE( " parent sets that are not faces ", notFaces[0] )
1840 
1841  // for a geo edge, check the sense tags with respect to the adjacent faces
1842  // in general, it is sufficient to check one mesh edge (the first one)
1843  // edge/face senses
1844  EntityHandle firstMeshEdge = mesh_edges[0];
1845  // get all entities/elements adjacent to it
1846  Range adjElem;
1847  rval = mdbImpl->get_adjacencies( &firstMeshEdge, 1, 2, false, adjElem );
1848  if( MB_SUCCESS != rval ) RETFALSE( " can't get adjacent elements to the edge ", firstMeshEdge )
1849  for( Range::iterator it2 = adjElem.begin(); it2 != adjElem.end(); ++it2 )
1850  {
1851  EntityHandle elem = *it2;
1852  // find the geo face it belongs to
1853  EntityHandle gFace = 0;
1854  for( Range::iterator fit = faceSets.begin(); fit != faceSets.end(); ++fit )
1855  {
1856  EntityHandle possibleFace = *fit;
1857  if( mdbImpl->contains_entities( possibleFace, &elem, 1 ) )
1858  {
1859  gFace = possibleFace;
1860  break;
1861  }
1862  }
1863  if( 0 == gFace )
1864  RETFALSE( " can't find adjacent surface that contains the adjacent element to the edge ",
1865  firstMeshEdge )
1866 
1867  // now, check the sense of mesh_edge in element, and the sense of gedge in gface
1868  // side_number
1869  int side_n, sense, offset;
1870  rval = mdbImpl->side_number( elem, firstMeshEdge, side_n, sense, offset );
1871  if( MB_SUCCESS != rval ) RETFALSE( " can't get sense and side number of an element ", elem )
1872  // now get the sense
1873  int topoSense;
1874  rval = this->get_sense( edge, gFace, topoSense );
1875  if( topoSense != sense ) RETFALSE( " geometric topo sense and element sense do not agree ", edge )
1876  }
1877  }
1878  // surfaces to be true meshes
1879  // for surfaces, check that the skinner will find the correct boundary
1880 
1881  // use the skinner for boundary check
1882  Skinner tool( mdbImpl );
1883 
1884  for( rit = geomRanges[2].begin(); rit != geomRanges[2].end(); ++rit )
1885  {
1886  EntityHandle faceSet = *rit;
1887  // get all boundary edges (adjacent edges)
1888 
1889  Range edges;
1890  rval = mdbImpl->get_child_meshsets( faceSet, edges );
1891  if( MB_SUCCESS != rval ) RETFALSE( " can't get children edges for a face set ", faceSet )
1892  Range notEdges = subtract( edges, geomRanges[1] );
1893  if( !notEdges.empty() ) RETFALSE( " some children of a face set are not geo edges ", notEdges[0] )
1894 
1895  Range boundary_mesh_edges;
1896  for( Range::iterator it = edges.begin(); it != edges.end(); ++it )
1897  {
1898  rval = mdbImpl->get_entities_by_type( *it, MBEDGE, boundary_mesh_edges );
1899  if( MB_SUCCESS != rval ) RETFALSE( " can't get edge elements from the edge set ", *it )
1900  }
1901  // skin the elements of the surface
1902  // most of these should be triangles and quads
1903  Range surface_ents, edge_ents;
1904  rval = mdbImpl->get_entities_by_dimension( faceSet, 2, surface_ents );
1905  if( MB_SUCCESS != rval ) RETFALSE( " can't get surface elements from the face set ", faceSet )
1906 
1907  rval = tool.find_skin( 0, surface_ents, 1, edge_ents );
1908  if( MB_SUCCESS != rval ) RETFALSE( "can't skin a surface ", surface_ents[0] )
1909 
1910  // those 2 ranges for boundary edges now must be equal
1911  if( boundary_mesh_edges != edge_ents ) RETFALSE( "boundary ranges are different", boundary_mesh_edges[0] )
1912  }
1913 
1914  // solids to be filled correctly, maybe a skin procedure too.
1915  // (maybe the solids are empty)
1916 
1917  return true;
1918 }
1919 
1921 {
1922  return rootSets.size() != 0 || mapRootSets.size() != 0;
1923 }
1924 
1925 // This function gets coordinates of the minimum and maxmiumum points
1926 // from an OBB/AABB, ie. such that these points represent
1927 // the maximum and minium extents of an AABB
1928 ErrorCode GeomTopoTool::get_bounding_coords( EntityHandle volume, double minPt[3], double maxPt[3] )
1929 {
1930  double center[3], axis1[3], axis2[3], axis3[3];
1931 
1932  // get center point and vectors to OBB faces
1933  MB_CHK_SET_ERR( get_obb( volume, center, axis1, axis2, axis3 ),
1934  "Failed to get the oriented bounding box of the volume" );
1935 
1936  // compute min and max vertices
1937  for( int i = 0; i < 3; i++ )
1938  {
1939  double sum = fabs( axis1[i] ) + fabs( axis2[i] ) + fabs( axis3[i] );
1940  minPt[i] = center[i] - sum;
1941  maxPt[i] = center[i] + sum;
1942  }
1943  return MB_SUCCESS;
1944 }
1945 
1947  double center[3],
1948  double axis1[3],
1949  double axis2[3],
1950  double axis3[3] )
1951 {
1952  // find EntityHandle node_set for use in box
1953  EntityHandle root;
1954  MB_CHK_SET_ERR( get_root( volume, root ), "Failed to get volume's obb tree root" );
1955 
1956  // call box to get center and vectors to faces
1957  return obbTree->box( root, center, axis1, axis2, axis3 );
1958 }
1959 
1961 {
1962  Range all_children, desired_children;
1963  Range::iterator it;
1964  int actual_dimension;
1965 
1966  desired_children.clear();
1967  all_children.clear();
1968  mdbImpl->get_child_meshsets( parent, all_children );
1969 
1970  for( it = all_children.begin(); it != all_children.end(); ++it )
1971  {
1972  mdbImpl->tag_get_data( geomTag, &( *it ), 1, &actual_dimension );
1973  if( actual_dimension == desired_dimension ) desired_children.insert( *it );
1974  }
1975 
1976  return desired_children;
1977 }
1978 
1979 // runs GeomQueryTool point_in_vol and to test if vol A is inside vol B
1980 // returns true or false
1982 {
1983  Range child_surfaces, triangles, vertices;
1984  double coord[3]; // coord[0] = x, etc.
1985  int result; // point in vol result; 0=F, 1=T
1986 
1987  // find coordinates of any point on surface of A
1988  // get surface corresponding to volume, then get the triangles
1989  child_surfaces = get_ct_children_by_dimension( volume_A, 2 );
1990  MB_CHK_ERR( mdbImpl->get_entities_by_type( *child_surfaces.begin(), MBTRI, triangles ) );
1991 
1992  // now get 1st triangle vertices
1993  MB_CHK_ERR( mdbImpl->get_connectivity( &( *triangles.begin() ), 1, vertices ) );
1994 
1995  // now get coordinates of first vertex
1996  MB_CHK_ERR( mdbImpl->get_coords( &( *vertices.begin() ), 1, &( coord[0] ) ) );
1997 
1998  // if point on A is inside vol B, return T; o.w. return F
1999  MB_CHK_SET_ERR( GQT->point_in_volume( volume_B, coord, result ), "Failed to complete point in volume query." );
2000 
2001  return ( result != 0 );
2002 }
2003 
2005 {
2006  bool inserted = false;
2007  EntityHandle current_volume = volume; // volume to be inserted
2008  EntityHandle tree_volume = ct_root; // volume already existing in the tree
2009  EntityHandle parent = ct_root;
2010  Range child_volumes;
2011 
2012  // while not inserted in tree
2013  while( !inserted )
2014  {
2015  // if current volume is insde of tree volume-- always true if tree volume
2016  // is the root of the tree
2017  if( tree_volume == ct_root || ( tree_volume != ct_root && A_is_in_B( current_volume, tree_volume, GQT ) ) )
2018  {
2019 
2020  parent = tree_volume;
2021 
2022  // if tree_volume has children then we must test them,
2023  // (tree_volume will change)
2024  child_volumes = get_ct_children_by_dimension( tree_volume, 3 );
2025  if( child_volumes.size() > 0 ) tree_volume = child_volumes.pop_front();
2026  // otherwise current_volume is the only child of the tree volume
2027  else
2028  {
2029  MB_CHK_SET_ERR( mdbImpl->add_parent_child( parent, current_volume ),
2030  "Failed to add parent-child relationship." );
2031 
2032  inserted = true;
2033  }
2034  // if current volume is not in the tree volume, the converse may be true
2035  }
2036  else
2037  {
2038  // if the tree volume is inside the current volume
2039  if( A_is_in_B( tree_volume, current_volume, GQT ) )
2040  {
2041  // reverse their parentage
2042  MB_CHK_SET_ERR( mdbImpl->remove_parent_child( parent, tree_volume ),
2043  "Failed to remove parent-child relationship." );
2044  MB_CHK_SET_ERR( mdbImpl->add_parent_child( current_volume, tree_volume ),
2045  "Failed to add parent-child relationship." );
2046  }
2047 
2048  if( child_volumes.size() == 0 )
2049  {
2050  MB_CHK_SET_ERR( mdbImpl->add_parent_child( parent, current_volume ),
2051  "Failed to add parent-child relationship." );
2052  inserted = true;
2053  }
2054  else
2055  tree_volume = child_volumes.pop_front();
2056  }
2057  }
2058  return MB_SUCCESS;
2059 }
2060 
2062 {
2063  // local var will go out of scope if errors appear, no need to free it also
2064  GeomQueryTool GQT( this );
2065  std::map< EntityHandle, EntityHandle > volume_surface; // map of volume
2066  // to its surface
2067 
2068  EntityHandle ct_root;
2069  // create root meshset-- this will be top of tree
2070  std::string meshset_name = "build_hierarchy_root";
2071  MB_CHK_ERR( mdbImpl->create_meshset( MESHSET_SET, ct_root ) );
2072  MB_CHK_ERR( mdbImpl->tag_set_data( nameTag, &ct_root, 1, meshset_name.c_str() ) );
2073 
2074  for( Range::iterator vol = flat_volumes.begin(); vol != flat_volumes.end(); vol++ )
2075  {
2076  // get the surface corresponding to each volume
2077  // at this point, each volume meshset only has one 'child' surface
2078  // which exactly corresponds to that volume
2079  Range child_surfaces = get_ct_children_by_dimension( *vol, 2 );
2080  volume_surface[*vol] = *child_surfaces.begin();
2081 
2082  MB_CHK_SET_ERR( insert_in_tree( ct_root, *vol, &GQT ), "Failed to insert volume into tree." );
2083  }
2084 
2085  // for each original volume, get its child volumes
2086  for( Range::iterator parent_it = flat_volumes.begin(); parent_it != flat_volumes.end(); parent_it++ )
2087  {
2088  Range volume_children = get_ct_children_by_dimension( *parent_it, 3 );
2089 
2090  if( volume_children.size() != 0 )
2091  {
2092  // loop over all of original volume's child volumes
2093  for( Range::iterator child_it = volume_children.begin(); child_it != volume_children.end(); ++child_it )
2094  {
2095  // set the sense of the surface mapped to the child volume to REVERSE
2096  // wrt the parent volume
2097  MB_CHK_SET_ERR( set_sense( volume_surface[*child_it], *parent_it, SENSE_REVERSE ),
2098  "Failed to set sense." );
2099 
2100  // add the child volume's surface as a child of the original volume
2101  // and delete the child volume as a child of original volume
2102  MB_CHK_SET_ERR( mdbImpl->add_parent_child( *parent_it, volume_surface[*child_it] ),
2103  "Failed to add parent-child relationship." );
2104  MB_CHK_SET_ERR( mdbImpl->remove_parent_child( *parent_it, *child_it ),
2105  "Failed to remove parent-child relationship." );
2106  }
2107  }
2108  }
2109 
2110  return MB_SUCCESS;
2111 }
2112 
2113 } // namespace moab