LCOV - code coverage report
Current view: top level - src - GeomTopoTool.cpp (source / functions) Hit Total Coverage
Test: coverage_sk.info Lines: 698 869 80.3 %
Date: 2020-12-16 07:07:30 Functions: 43 48 89.6 %
Branches: 1052 4389 24.0 %

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

Generated by: LCOV version 1.11