LCOV - code coverage report
Current view: top level - src - Skinner.cpp (source / functions) Hit Total Coverage
Test: coverage_sk.info Lines: 455 846 53.8 %
Date: 2020-12-16 07:07:30 Functions: 50 65 76.9 %
Branches: 772 2358 32.7 %

           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                 :            : #ifdef __MFC_VER
      17                 :            : #pragma warning( disable : 4786 )
      18                 :            : #endif
      19                 :            : 
      20                 :            : #ifdef WIN32               /* windows */
      21                 :            : #define _USE_MATH_DEFINES  // For M_PI
      22                 :            : #endif
      23                 :            : #include "moab/Skinner.hpp"
      24                 :            : #include "moab/Range.hpp"
      25                 :            : #include "moab/CN.hpp"
      26                 :            : #include <vector>
      27                 :            : #include <set>
      28                 :            : #include <algorithm>
      29                 :            : #include <math.h>
      30                 :            : #include <assert.h>
      31                 :            : #include <iostream>
      32                 :            : #include "moab/Util.hpp"
      33                 :            : #include "Internals.hpp"
      34                 :            : #include "MBTagConventions.hpp"
      35                 :            : #include "moab/Core.hpp"
      36                 :            : #include "AEntityFactory.hpp"
      37                 :            : #include "moab/ScdInterface.hpp"
      38                 :            : 
      39                 :            : #ifdef M_PI
      40                 :            : #define SKINNER_PI M_PI
      41                 :            : #else
      42                 :            : #define SKINNER_PI 3.1415926535897932384626
      43                 :            : #endif
      44                 :            : 
      45                 :            : namespace moab
      46                 :            : {
      47                 :            : 
      48                 :         38 : Skinner::~Skinner()
      49                 :            : {
      50                 :            :     // delete the adjacency tag
      51                 :         38 : }
      52                 :            : 
      53                 :          0 : ErrorCode Skinner::initialize()
      54                 :            : {
      55                 :            :     // go through and mark all the target dimension entities
      56                 :            :     // that already exist as not deleteable
      57                 :            :     // also get the connectivity tags for each type
      58                 :            :     // also populate adjacency information
      59                 :            :     EntityType type;
      60                 :          0 :     DimensionPair target_ent_types = CN::TypeDimensionMap[mTargetDim];
      61                 :            : 
      62                 :          0 :     void* null_ptr = NULL;
      63                 :            : 
      64                 :            :     ErrorCode result = thisMB->tag_get_handle( "skinner adj", sizeof( void* ), MB_TYPE_OPAQUE, mAdjTag,
      65 [ #  # ][ #  # ]:          0 :                                                MB_TAG_DENSE | MB_TAG_CREAT, &null_ptr );MB_CHK_ERR( result );
         [ #  # ][ #  # ]
      66                 :            : 
      67         [ #  # ]:          0 :     if( mDeletableMBTag == 0 )
      68                 :            :     {
      69                 :            :         result =
      70 [ #  # ][ #  # ]:          0 :             thisMB->tag_get_handle( "skinner deletable", 1, MB_TYPE_BIT, mDeletableMBTag, MB_TAG_BIT | MB_TAG_CREAT );MB_CHK_ERR( result );
         [ #  # ][ #  # ]
      71                 :            :     }
      72                 :            : 
      73         [ #  # ]:          0 :     Range entities;
      74                 :            : 
      75                 :            :     // go through each type at this dimension
      76 [ #  # ][ #  # ]:          0 :     for( type = target_ent_types.first; type <= target_ent_types.second; ++type )
      77                 :            :     {
      78                 :            :         // get the entities of this type in the MB
      79         [ #  # ]:          0 :         thisMB->get_entities_by_type( 0, type, entities );
      80                 :            : 
      81                 :            :         // go through each entity of this type in the MB
      82                 :            :         // and set its deletable tag to NO
      83 [ #  # ][ #  # ]:          0 :         Range::iterator iter, end_iter;
      84         [ #  # ]:          0 :         end_iter = entities.end();
      85 [ #  # ][ #  # ]:          0 :         for( iter = entities.begin(); iter != end_iter; ++iter )
         [ #  # ][ #  # ]
      86                 :            :         {
      87                 :          0 :             unsigned char bit = 0x1;
      88 [ #  # ][ #  # ]:          0 :             result            = thisMB->tag_set_data( mDeletableMBTag, &( *iter ), 1, &bit );
      89         [ #  # ]:          0 :             assert( MB_SUCCESS == result );
      90                 :            :             // add adjacency information too
      91 [ #  # ][ #  # ]:          0 :             if( TYPE_FROM_HANDLE( *iter ) != MBVERTEX ) add_adjacency( *iter );
         [ #  # ][ #  # ]
                 [ #  # ]
      92                 :            :         }
      93                 :            :     }
      94                 :            : 
      95                 :          0 :     return MB_SUCCESS;
      96                 :            : }
      97                 :            : 
      98                 :          0 : ErrorCode Skinner::deinitialize()
      99                 :            : {
     100                 :            :     ErrorCode result;
     101         [ #  # ]:          0 :     if( 0 != mDeletableMBTag )
     102                 :            :     {
     103         [ #  # ]:          0 :         result          = thisMB->tag_delete( mDeletableMBTag );
     104 [ #  # ][ #  # ]:          0 :         mDeletableMBTag = 0;MB_CHK_ERR( result );
                 [ #  # ]
     105                 :            :     }
     106                 :            : 
     107                 :            :     // remove the adjacency tag
     108         [ #  # ]:          0 :     std::vector< std::vector< EntityHandle >* > adj_arr;
     109                 :          0 :     std::vector< std::vector< EntityHandle >* >::iterator i;
     110         [ #  # ]:          0 :     if( 0 != mAdjTag )
     111                 :            :     {
     112 [ #  # ][ #  # ]:          0 :         for( EntityType t = MBVERTEX; t != MBMAXTYPE; ++t )
     113                 :            :         {
     114         [ #  # ]:          0 :             Range entities;
     115 [ #  # ][ #  # ]:          0 :             result = thisMB->get_entities_by_type_and_tag( 0, t, &mAdjTag, 0, 1, entities );MB_CHK_ERR( result );
         [ #  # ][ #  # ]
     116 [ #  # ][ #  # ]:          0 :             adj_arr.resize( entities.size() );
     117 [ #  # ][ #  # ]:          0 :             result = thisMB->tag_get_data( mAdjTag, entities, &adj_arr[0] );MB_CHK_ERR( result );
         [ #  # ][ #  # ]
                 [ #  # ]
     118 [ #  # ][ #  # ]:          0 :             for( i = adj_arr.begin(); i != adj_arr.end(); ++i )
         [ #  # ][ #  # ]
     119 [ #  # ][ #  # ]:          0 :                 delete *i;
     120                 :          0 :         }
     121                 :            : 
     122         [ #  # ]:          0 :         result  = thisMB->tag_delete( mAdjTag );
     123 [ #  # ][ #  # ]:          0 :         mAdjTag = 0;MB_CHK_ERR( result );
                 [ #  # ]
     124                 :            :     }
     125                 :            : 
     126                 :          0 :     return MB_SUCCESS;
     127                 :            : }
     128                 :            : 
     129                 :          0 : ErrorCode Skinner::add_adjacency( EntityHandle entity )
     130                 :            : {
     131                 :          0 :     std::vector< EntityHandle >* adj = NULL;
     132                 :            :     const EntityHandle* nodes;
     133                 :            :     int num_nodes;
     134 [ #  # ][ #  # ]:          0 :     ErrorCode result = thisMB->get_connectivity( entity, nodes, num_nodes, true );MB_CHK_ERR( result );
         [ #  # ][ #  # ]
     135         [ #  # ]:          0 :     const EntityHandle* iter = std::min_element( nodes, nodes + num_nodes );
     136                 :            : 
     137         [ #  # ]:          0 :     if( iter == nodes + num_nodes ) return MB_SUCCESS;
     138                 :            : 
     139                 :            :     // add this entity to the node
     140 [ #  # ][ #  # ]:          0 :     if( thisMB->tag_get_data( mAdjTag, iter, 1, &adj ) == MB_SUCCESS && adj != NULL ) { adj->push_back( entity ); }
         [ #  # ][ #  # ]
                 [ #  # ]
     141                 :            :     // create a new vector and add it
     142                 :            :     else
     143                 :            :     {
     144 [ #  # ][ #  # ]:          0 :         adj = new std::vector< EntityHandle >;
     145         [ #  # ]:          0 :         adj->push_back( entity );
     146 [ #  # ][ #  # ]:          0 :         result = thisMB->tag_set_data( mAdjTag, iter, 1, &adj );MB_CHK_ERR( result );
         [ #  # ][ #  # ]
     147                 :            :     }
     148                 :            : 
     149                 :          0 :     return MB_SUCCESS;
     150                 :            : }
     151                 :            : 
     152                 :          0 : void Skinner::add_adjacency( EntityHandle entity, const EntityHandle* nodes, const int num_nodes )
     153                 :            : {
     154                 :          0 :     std::vector< EntityHandle >* adj = NULL;
     155         [ #  # ]:          0 :     const EntityHandle* iter         = std::min_element( nodes, nodes + num_nodes );
     156                 :            : 
     157         [ #  # ]:          0 :     if( iter == nodes + num_nodes ) return;
     158                 :            : 
     159                 :            :     // should not be setting adjacency lists in ho-nodes
     160 [ #  # ][ #  # ]:          0 :     assert( TYPE_FROM_HANDLE( entity ) == MBPOLYGON ||
         [ #  # ][ #  # ]
     161         [ #  # ]:          0 :             num_nodes == CN::VerticesPerEntity( TYPE_FROM_HANDLE( entity ) ) );
     162                 :            : 
     163                 :            :     // add this entity to the node
     164 [ #  # ][ #  # ]:          0 :     if( thisMB->tag_get_data( mAdjTag, iter, 1, &adj ) == MB_SUCCESS && adj != NULL ) { adj->push_back( entity ); }
         [ #  # ][ #  # ]
                 [ #  # ]
     165                 :            :     // create a new vector and add it
     166                 :            :     else
     167                 :            :     {
     168 [ #  # ][ #  # ]:          0 :         adj = new std::vector< EntityHandle >;
     169         [ #  # ]:          0 :         adj->push_back( entity );
     170         [ #  # ]:          0 :         thisMB->tag_set_data( mAdjTag, iter, 1, &adj );
     171                 :            :     }
     172                 :            : }
     173                 :            : 
     174                 :          0 : ErrorCode Skinner::find_geometric_skin( const EntityHandle meshset, Range& forward_target_entities )
     175                 :            : {
     176                 :            :     // attempts to find whole model skin, using geom topo sets first then
     177                 :            :     // normal find_skin function
     178                 :          0 :     bool debug = true;
     179                 :            : 
     180                 :            :     // look for geom topo sets
     181                 :            :     Tag geom_tag;
     182                 :            :     ErrorCode result =
     183         [ #  # ]:          0 :         thisMB->tag_get_handle( GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, geom_tag, MB_TAG_SPARSE | MB_TAG_CREAT );
     184                 :            : 
     185         [ #  # ]:          0 :     if( MB_SUCCESS != result ) return result;
     186                 :            : 
     187                 :            :     // get face sets (dimension = 2)
     188         [ #  # ]:          0 :     Range face_sets;
     189                 :          0 :     int two             = 2;
     190                 :          0 :     const void* two_ptr = &two;
     191         [ #  # ]:          0 :     result = thisMB->get_entities_by_type_and_tag( meshset, MBENTITYSET, &geom_tag, &two_ptr, 1, face_sets );
     192                 :            : 
     193         [ #  # ]:          0 :     Range::iterator it;
     194         [ #  # ]:          0 :     if( MB_SUCCESS != result )
     195                 :          0 :         return result;
     196 [ #  # ][ #  # ]:          0 :     else if( face_sets.empty() )
     197                 :          0 :         return MB_ENTITY_NOT_FOUND;
     198                 :            : 
     199                 :            :     // ok, we have face sets; use those to determine skin
     200         [ #  # ]:          0 :     Range skin_sets;
     201 [ #  # ][ #  # ]:          0 :     if( debug ) std::cout << "Found " << face_sets.size() << " face sets total..." << std::endl;
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     202                 :            : 
     203 [ #  # ][ #  # ]:          0 :     for( it = face_sets.begin(); it != face_sets.end(); ++it )
         [ #  # ][ #  # ]
                 [ #  # ]
     204                 :            :     {
     205                 :            :         int num_parents;
     206 [ #  # ][ #  # ]:          0 :         result = thisMB->num_parent_meshsets( *it, &num_parents );
     207         [ #  # ]:          0 :         if( MB_SUCCESS != result )
     208                 :          0 :             return result;
     209         [ #  # ]:          0 :         else if( num_parents == 1 )
     210 [ #  # ][ #  # ]:          0 :             skin_sets.insert( *it );
     211                 :            :     }
     212                 :            : 
     213 [ #  # ][ #  # ]:          0 :     if( debug ) std::cout << "Found " << skin_sets.size() << " 1-parent face sets..." << std::endl;
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     214                 :            : 
     215 [ #  # ][ #  # ]:          0 :     if( skin_sets.empty() ) return MB_FAILURE;
     216                 :            : 
     217                 :            :     // ok, we have the shell; gather up the elements, putting them all in forward for now
     218 [ #  # ][ #  # ]:          0 :     for( it = skin_sets.begin(); it != skin_sets.end(); ++it )
         [ #  # ][ #  # ]
                 [ #  # ]
     219                 :            :     {
     220 [ #  # ][ #  # ]:          0 :         result = thisMB->get_entities_by_handle( *it, forward_target_entities, true );
     221         [ #  # ]:          0 :         if( MB_SUCCESS != result ) return result;
     222                 :            :     }
     223                 :            : 
     224                 :          0 :     return result;
     225                 :            : }
     226                 :            : 
     227                 :         72 : ErrorCode Skinner::find_skin( const EntityHandle meshset, const Range& source_entities, bool get_vertices,
     228                 :            :                               Range& output_handles, Range* output_reverse_handles, bool create_vert_elem_adjs,
     229                 :            :                               bool create_skin_elements, bool look_for_scd )
     230                 :            : {
     231         [ -  + ]:         72 :     if( source_entities.empty() ) return MB_SUCCESS;
     232                 :            : 
     233         [ +  + ]:         72 :     if( look_for_scd )
     234                 :            :     {
     235                 :          2 :         ErrorCode rval = find_skin_scd( source_entities, get_vertices, output_handles, create_skin_elements );
     236                 :            :         // if it returns success, it's all scd, and we don't need to do anything more
     237         [ +  - ]:          2 :         if( MB_SUCCESS == rval ) return rval;
     238                 :            :     }
     239                 :            : 
     240         [ -  + ]:         70 :     Core* this_core = dynamic_cast< Core* >( thisMB );
     241 [ +  - ][ +  + ]:         70 :     if( this_core && create_vert_elem_adjs && !this_core->a_entity_factory()->vert_elem_adjacencies() )
         [ +  + ][ +  + ]
     242                 :         11 :         this_core->a_entity_factory()->create_vert_elem_adjacencies();
     243                 :            : 
     244                 :            :     return find_skin_vertices( meshset, source_entities, get_vertices ? &output_handles : 0,
     245 [ +  + ][ +  + ]:         70 :                                get_vertices ? 0 : &output_handles, output_reverse_handles, create_skin_elements );
     246                 :            : }
     247                 :            : 
     248                 :          2 : ErrorCode Skinner::find_skin_scd( const Range& source_entities, bool get_vertices, Range& output_handles,
     249                 :            :                                   bool create_skin_elements )
     250                 :            : {
     251                 :            :     // get the scd interface and check if it's been initialized
     252                 :          2 :     ScdInterface* scdi = NULL;
     253         [ +  - ]:          2 :     ErrorCode rval     = thisMB->query_interface( scdi );
     254         [ -  + ]:          2 :     if( !scdi ) return MB_FAILURE;
     255                 :            : 
     256                 :            :     // ok, there's scd mesh; see if the entities passed in are all in a scd box
     257                 :            :     // a box needs to be wholly included in entities for this to work
     258 [ +  - ][ +  - ]:          4 :     std::vector< ScdBox* > boxes, myboxes;
     259         [ +  - ]:          4 :     Range myrange;
     260         [ +  - ]:          2 :     rval = scdi->find_boxes( boxes );
     261         [ -  + ]:          2 :     if( MB_SUCCESS != rval ) return rval;
     262 [ +  - ][ +  - ]:          4 :     for( std::vector< ScdBox* >::iterator bit = boxes.begin(); bit != boxes.end(); ++bit )
                 [ +  + ]
     263                 :            :     {
     264 [ +  - ][ +  - ]:          2 :         Range belems( ( *bit )->start_element(), ( *bit )->start_element() + ( *bit )->num_elements() - 1 );
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     265 [ +  - ][ +  - ]:          2 :         if( source_entities.contains( belems ) )
     266                 :            :         {
     267 [ +  - ][ +  - ]:          2 :             myboxes.push_back( *bit );
     268         [ +  - ]:          2 :             myrange.merge( belems );
     269                 :            :         }
     270                 :          2 :     }
     271 [ +  - ][ +  - ]:          2 :     if( myboxes.empty() || myrange.size() != source_entities.size() ) return MB_FAILURE;
         [ +  - ][ -  + ]
                 [ -  + ]
     272                 :            : 
     273                 :            :     // ok, we're all structured; get the skin for each box
     274 [ +  - ][ +  - ]:          4 :     for( std::vector< ScdBox* >::iterator bit = boxes.begin(); bit != boxes.end(); ++bit )
                 [ +  + ]
     275                 :            :     {
     276 [ +  - ][ +  - ]:          2 :         rval = skin_box( *bit, get_vertices, output_handles, create_skin_elements );
     277         [ -  + ]:          2 :         if( MB_SUCCESS != rval ) return rval;
     278                 :            :     }
     279                 :            : 
     280                 :          4 :     return MB_SUCCESS;
     281                 :            : }
     282                 :            : 
     283                 :          2 : ErrorCode Skinner::skin_box( ScdBox* box, bool get_vertices, Range& output_handles, bool create_skin_elements )
     284                 :            : {
     285 [ +  - ][ +  - ]:          2 :     HomCoord bmin = box->box_min(), bmax = box->box_max();
     286                 :            : 
     287                 :            :     // don't support 1d boxes
     288 [ +  - ][ +  - ]:          2 :     if( bmin.j() == bmax.j() && bmin.k() == bmax.k() ) return MB_FAILURE;
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
                 [ -  + ]
     289                 :            : 
     290 [ +  - ][ +  - ]:          2 :     int dim = ( bmin.k() == bmax.k() ? 1 : 2 );
                 [ -  + ]
     291                 :            : 
     292                 :            :     ErrorCode rval;
     293                 :            :     EntityHandle ent;
     294                 :            : 
     295                 :            :     // i=min
     296 [ +  - ][ +  - ]:         12 :     for( int k = bmin.k(); k < bmax.k(); k++ )
                 [ +  + ]
     297                 :            :     {
     298 [ +  - ][ +  - ]:        110 :         for( int j = bmin.j(); j < bmax.j(); j++ )
                 [ +  + ]
     299                 :            :         {
     300                 :        100 :             ent  = 0;
     301 [ +  - ][ +  - ]:        100 :             rval = box->get_adj_edge_or_face( dim, bmin.i(), j, k, 0, ent, create_skin_elements );
     302         [ -  + ]:        100 :             if( MB_SUCCESS != rval ) return rval;
     303 [ +  - ][ +  - ]:        100 :             if( ent ) output_handles.insert( ent );
     304                 :            :         }
     305                 :            :     }
     306                 :            :     // i=max
     307 [ +  - ][ +  - ]:         12 :     for( int k = bmin.k(); k < bmax.k(); k++ )
                 [ +  + ]
     308                 :            :     {
     309 [ +  - ][ +  - ]:        110 :         for( int j = bmin.j(); j < bmax.j(); j++ )
                 [ +  + ]
     310                 :            :         {
     311                 :        100 :             ent  = 0;
     312 [ +  - ][ +  - ]:        100 :             rval = box->get_adj_edge_or_face( dim, bmax.i(), j, k, 0, ent, create_skin_elements );
     313         [ -  + ]:        100 :             if( MB_SUCCESS != rval ) return rval;
     314 [ +  - ][ +  - ]:        100 :             if( ent ) output_handles.insert( ent );
     315                 :            :         }
     316                 :            :     }
     317                 :            :     // j=min
     318 [ +  - ][ +  - ]:         12 :     for( int k = bmin.k(); k < bmax.k(); k++ )
                 [ +  + ]
     319                 :            :     {
     320 [ +  - ][ +  - ]:        110 :         for( int i = bmin.i(); i < bmax.i(); i++ )
                 [ +  + ]
     321                 :            :         {
     322                 :        100 :             ent  = 0;
     323 [ +  - ][ +  - ]:        100 :             rval = box->get_adj_edge_or_face( dim, i, bmin.j(), k, 1, ent, create_skin_elements );
     324         [ -  + ]:        100 :             if( MB_SUCCESS != rval ) return rval;
     325 [ +  - ][ +  - ]:        100 :             if( ent ) output_handles.insert( ent );
     326                 :            :         }
     327                 :            :     }
     328                 :            :     // j=max
     329 [ +  - ][ +  - ]:         12 :     for( int k = bmin.k(); k < bmax.k(); k++ )
                 [ +  + ]
     330                 :            :     {
     331 [ +  - ][ +  - ]:        110 :         for( int i = bmin.i(); i < bmax.i(); i++ )
                 [ +  + ]
     332                 :            :         {
     333                 :        100 :             ent  = 0;
     334 [ +  - ][ +  - ]:        100 :             rval = box->get_adj_edge_or_face( dim, i, bmax.j(), k, 1, ent, create_skin_elements );
     335         [ -  + ]:        100 :             if( MB_SUCCESS != rval ) return rval;
     336 [ +  - ][ +  - ]:        100 :             if( ent ) output_handles.insert( ent );
     337                 :            :         }
     338                 :            :     }
     339                 :            :     // k=min
     340 [ +  - ][ +  - ]:         22 :     for( int j = bmin.j(); j < bmax.j(); j++ )
                 [ +  + ]
     341                 :            :     {
     342 [ +  - ][ +  - ]:        220 :         for( int i = bmin.i(); i < bmax.i(); i++ )
                 [ +  + ]
     343                 :            :         {
     344                 :        200 :             ent  = 0;
     345 [ +  - ][ +  - ]:        200 :             rval = box->get_adj_edge_or_face( dim, i, j, bmin.k(), 2, ent, create_skin_elements );
     346         [ -  + ]:        200 :             if( MB_SUCCESS != rval ) return rval;
     347 [ +  - ][ +  - ]:        200 :             if( ent ) output_handles.insert( ent );
     348                 :            :         }
     349                 :            :     }
     350                 :            :     // k=max
     351 [ +  - ][ +  - ]:         22 :     for( int j = bmin.j(); j < bmax.j(); j++ )
                 [ +  + ]
     352                 :            :     {
     353 [ +  - ][ +  - ]:        220 :         for( int i = bmin.i(); i < bmax.i(); i++ )
                 [ +  + ]
     354                 :            :         {
     355                 :        200 :             ent  = 0;
     356 [ +  - ][ +  - ]:        200 :             rval = box->get_adj_edge_or_face( dim, i, j, bmax.k(), 2, ent, create_skin_elements );
     357         [ -  + ]:        200 :             if( MB_SUCCESS != rval ) return rval;
     358 [ +  - ][ +  - ]:        200 :             if( ent ) output_handles.insert( ent );
     359                 :            :         }
     360                 :            :     }
     361                 :            : 
     362         [ +  + ]:          2 :     if( get_vertices )
     363                 :            :     {
     364         [ +  - ]:          1 :         Range verts;
     365         [ +  - ]:          1 :         rval = thisMB->get_adjacencies( output_handles, 0, true, verts, Interface::UNION );
     366         [ -  + ]:          1 :         if( MB_SUCCESS != rval ) return rval;
     367 [ +  - ][ +  - ]:          1 :         output_handles.merge( verts );
     368                 :            :     }
     369                 :            : 
     370                 :          2 :     return MB_SUCCESS;
     371                 :            : }
     372                 :            : 
     373                 :          0 : ErrorCode Skinner::find_skin_noadj(const Range &source_entities,
     374                 :            :                                  Range &forward_target_entities,
     375                 :            :                                  Range &reverse_target_entities/*,
     376                 :            :                                  bool create_vert_elem_adjs*/)
     377                 :            : {
     378 [ #  # ][ #  # ]:          0 :     if( source_entities.empty() ) return MB_FAILURE;
     379                 :            : 
     380                 :            :     // get our working dimensions
     381 [ #  # ][ #  # ]:          0 :     EntityType type      = thisMB->type_from_handle( *( source_entities.begin() ) );
                 [ #  # ]
     382         [ #  # ]:          0 :     const int source_dim = CN::Dimension( type );
     383                 :          0 :     mTargetDim           = source_dim - 1;
     384                 :            : 
     385                 :            :     // make sure we can handle the working dimensions
     386 [ #  # ][ #  # ]:          0 :     if( mTargetDim < 0 || source_dim > 3 ) return MB_FAILURE;
     387                 :            : 
     388         [ #  # ]:          0 :     initialize();
     389                 :            : 
     390 [ #  # ][ #  # ]:          0 :     Range::const_iterator iter, end_iter;
     391         [ #  # ]:          0 :     end_iter = source_entities.end();
     392                 :            :     const EntityHandle* conn;
     393                 :            :     EntityHandle match;
     394                 :            : 
     395                 :            :     direction direct;
     396                 :            :     ErrorCode result;
     397                 :            :     // assume we'll never have more than 32 vertices on a facet (checked
     398                 :            :     // with assert later)
     399                 :            :     EntityHandle sub_conn[32];
     400         [ #  # ]:          0 :     std::vector< EntityHandle > tmp_conn_vec;
     401                 :            :     int num_nodes, num_sub_nodes, num_sides;
     402                 :            :     int sub_indices[32];  // Also, assume that no polygon has more than 32 nodes
     403                 :            :     // we could increase that, but we will not display it right in visit moab h5m , anyway
     404                 :            :     EntityType sub_type;
     405                 :            : 
     406                 :            :     // for each source entity
     407 [ #  # ][ #  # ]:          0 :     for( iter = source_entities.begin(); iter != end_iter; ++iter )
         [ #  # ][ #  # ]
     408                 :            :     {
     409                 :            :         // get the connectivity of this entity
     410                 :          0 :         int actual_num_nodes_polygon = 0;
     411 [ #  # ][ #  # ]:          0 :         result                       = thisMB->get_connectivity( *iter, conn, num_nodes, false, &tmp_conn_vec );
     412         [ #  # ]:          0 :         if( MB_SUCCESS != result ) return result;
     413                 :            : 
     414 [ #  # ][ #  # ]:          0 :         type = thisMB->type_from_handle( *iter );
     415         [ #  # ]:          0 :         Range::iterator seek_iter;
     416                 :            : 
     417                 :            :         // treat separately polygons (also, polyhedra will need special handling)
     418         [ #  # ]:          0 :         if( MBPOLYGON == type )
     419                 :            :         {
     420                 :            :             // treat padded polygons, if existing; count backwards, see how many of the last nodes
     421                 :            :             // are repeated assume connectivity is fine, otherwise we could be in trouble
     422                 :          0 :             actual_num_nodes_polygon = num_nodes;
     423 [ #  # ][ #  # ]:          0 :             while( actual_num_nodes_polygon >= 3 &&
     424                 :          0 :                    conn[actual_num_nodes_polygon - 1] == conn[actual_num_nodes_polygon - 2] )
     425                 :          0 :                 actual_num_nodes_polygon--;
     426                 :          0 :             num_sides     = actual_num_nodes_polygon;
     427                 :          0 :             sub_type      = MBEDGE;
     428                 :          0 :             num_sub_nodes = 2;
     429                 :            :         }
     430                 :            :         else  // get connectivity of each n-1 dimension entity
     431         [ #  # ]:          0 :             num_sides = CN::NumSubEntities( type, mTargetDim );
     432         [ #  # ]:          0 :         for( int i = 0; i < num_sides; i++ )
     433                 :            :         {
     434         [ #  # ]:          0 :             if( MBPOLYGON == type )
     435                 :            :             {
     436                 :          0 :                 sub_conn[0] = conn[i];
     437                 :          0 :                 sub_conn[1] = conn[i + 1];
     438         [ #  # ]:          0 :                 if( i + 1 == actual_num_nodes_polygon ) sub_conn[1] = conn[0];
     439                 :            :             }
     440                 :            :             else
     441                 :            :             {
     442         [ #  # ]:          0 :                 CN::SubEntityNodeIndices( type, num_nodes, mTargetDim, i, sub_type, num_sub_nodes, sub_indices );
     443         [ #  # ]:          0 :                 assert( (size_t)num_sub_nodes <= sizeof( sub_indices ) / sizeof( sub_indices[0] ) );
     444         [ #  # ]:          0 :                 for( int j = 0; j < num_sub_nodes; j++ )
     445                 :          0 :                     sub_conn[j] = conn[sub_indices[j]];
     446                 :            :             }
     447                 :            : 
     448                 :            :             // see if we can match this connectivity with
     449                 :            :             // an existing entity
     450         [ #  # ]:          0 :             find_match( sub_type, sub_conn, num_sub_nodes, match, direct );
     451                 :            : 
     452                 :            :             // if there is no match, create a new entity
     453         [ #  # ]:          0 :             if( match == 0 )
     454                 :            :             {
     455                 :          0 :                 EntityHandle tmphndl = 0;
     456                 :            :                 int indices[MAX_SUB_ENTITY_VERTICES];
     457                 :            :                 EntityType new_type;
     458                 :            :                 int num_new_nodes;
     459         [ #  # ]:          0 :                 if( MBPOLYGON == type )
     460                 :            :                 {
     461                 :          0 :                     new_type      = MBEDGE;
     462                 :          0 :                     num_new_nodes = 2;
     463                 :            :                 }
     464                 :            :                 else
     465                 :            :                 {
     466         [ #  # ]:          0 :                     CN::SubEntityNodeIndices( type, num_nodes, mTargetDim, i, new_type, num_new_nodes, indices );
     467         [ #  # ]:          0 :                     for( int j = 0; j < num_new_nodes; j++ )
     468                 :          0 :                         sub_conn[j] = conn[indices[j]];
     469                 :            :                 }
     470         [ #  # ]:          0 :                 result = thisMB->create_element( new_type, sub_conn, num_new_nodes, tmphndl );
     471         [ #  # ]:          0 :                 assert( MB_SUCCESS == result );
     472 [ #  # ][ #  # ]:          0 :                 add_adjacency( tmphndl, sub_conn, CN::VerticesPerEntity( new_type ) );
     473         [ #  # ]:          0 :                 forward_target_entities.insert( tmphndl );
     474                 :            :             }
     475                 :            :             // if there is a match, delete the matching entity
     476                 :            :             // if we can.
     477                 :            :             else
     478                 :            :             {
     479 [ #  # ][ #  # ]:          0 :                 if( ( seek_iter = forward_target_entities.find( match ) ) != forward_target_entities.end() )
         [ #  # ][ #  # ]
     480                 :            :                 {
     481         [ #  # ]:          0 :                     forward_target_entities.erase( seek_iter );
     482         [ #  # ]:          0 :                     remove_adjacency( match );
     483 [ #  # ][ #  # ]:          0 :                     if( /*!use_adjs &&*/ entity_deletable( match ) )
     484                 :            :                     {
     485         [ #  # ]:          0 :                         result = thisMB->delete_entities( &match, 1 );
     486         [ #  # ]:          0 :                         assert( MB_SUCCESS == result );
     487                 :            :                     }
     488                 :            :                 }
     489 [ #  # ][ #  # ]:          0 :                 else if( ( seek_iter = reverse_target_entities.find( match ) ) != reverse_target_entities.end() )
         [ #  # ][ #  # ]
     490                 :            :                 {
     491         [ #  # ]:          0 :                     reverse_target_entities.erase( seek_iter );
     492         [ #  # ]:          0 :                     remove_adjacency( match );
     493 [ #  # ][ #  # ]:          0 :                     if( /*!use_adjs &&*/ entity_deletable( match ) )
     494                 :            :                     {
     495         [ #  # ]:          0 :                         result = thisMB->delete_entities( &match, 1 );
     496         [ #  # ]:          0 :                         assert( MB_SUCCESS == result );
     497                 :            :                     }
     498                 :            :                 }
     499                 :            :                 else
     500                 :            :                 {
     501 [ #  # ][ #  # ]:          0 :                     if( direct == FORWARD ) { forward_target_entities.insert( match ); }
     502                 :            :                     else
     503                 :            :                     {
     504         [ #  # ]:          0 :                         reverse_target_entities.insert( match );
     505                 :            :                     }
     506                 :            :                 }
     507                 :            :             }
     508                 :            :         }
     509                 :            :     }
     510                 :            : 
     511         [ #  # ]:          0 :     deinitialize();
     512                 :            : 
     513                 :          0 :     return MB_SUCCESS;
     514                 :            : }
     515                 :            : 
     516                 :          0 : void Skinner::find_match( EntityType type, const EntityHandle* conn, const int num_nodes, EntityHandle& match,
     517                 :            :                           Skinner::direction& direct )
     518                 :            : {
     519                 :          0 :     match = 0;
     520                 :            : 
     521         [ #  # ]:          0 :     if( type == MBVERTEX )
     522                 :            :     {
     523                 :          0 :         match  = *conn;
     524                 :          0 :         direct = FORWARD;
     525                 :          0 :         return;
     526                 :            :     }
     527                 :            : 
     528         [ #  # ]:          0 :     const EntityHandle* iter = std::min_element( conn, conn + num_nodes );
     529                 :            : 
     530                 :          0 :     std::vector< EntityHandle >* adj = NULL;
     531                 :            : 
     532         [ #  # ]:          0 :     ErrorCode result = thisMB->tag_get_data( mAdjTag, iter, 1, &adj );
     533 [ #  # ][ #  # ]:          0 :     if( result == MB_FAILURE || adj == NULL ) { return; }
     534                 :            : 
     535                 :          0 :     std::vector< EntityHandle >::iterator jter, end_jter;
     536                 :          0 :     end_jter = adj->end();
     537                 :            : 
     538                 :            :     const EntityHandle* tmp;
     539                 :            :     int num_verts;
     540                 :            : 
     541 [ #  # ][ #  # ]:          0 :     for( jter = adj->begin(); jter != end_jter; ++jter )
                 [ #  # ]
     542                 :            :     {
     543                 :            :         EntityType tmp_type;
     544 [ #  # ][ #  # ]:          0 :         tmp_type = thisMB->type_from_handle( *jter );
     545                 :            : 
     546         [ #  # ]:          0 :         if( type != tmp_type ) continue;
     547                 :            : 
     548 [ #  # ][ #  # ]:          0 :         result = thisMB->get_connectivity( *jter, tmp, num_verts, false );
     549 [ #  # ][ #  # ]:          0 :         assert( MB_SUCCESS == result && num_verts >= CN::VerticesPerEntity( type ) );
                 [ #  # ]
     550                 :            :         // FIXME: connectivity_match appears to work only for linear elements,
     551                 :            :         //        so ignore higher-order nodes.
     552 [ #  # ][ #  # ]:          0 :         if( connectivity_match( conn, tmp, CN::VerticesPerEntity( type ), direct ) )
                 [ #  # ]
     553                 :            :         {
     554         [ #  # ]:          0 :             match = *jter;
     555                 :          0 :             break;
     556                 :            :         }
     557                 :            :     }
     558                 :            : }
     559                 :            : 
     560                 :          0 : bool Skinner::connectivity_match( const EntityHandle* conn1, const EntityHandle* conn2, const int num_verts,
     561                 :            :                                   Skinner::direction& direct )
     562                 :            : {
     563                 :          0 :     const EntityHandle* iter = std::find( conn2, conn2 + num_verts, conn1[0] );
     564         [ #  # ]:          0 :     if( iter == conn2 + num_verts ) return false;
     565                 :            : 
     566                 :          0 :     bool they_match = true;
     567                 :            : 
     568                 :            :     int i;
     569                 :          0 :     unsigned int j = iter - conn2;
     570                 :            : 
     571                 :            :     // first compare forward
     572         [ #  # ]:          0 :     for( i = 1; i < num_verts; ++i )
     573                 :            :     {
     574         [ #  # ]:          0 :         if( conn1[i] != conn2[( j + i ) % num_verts] )
     575                 :            :         {
     576                 :          0 :             they_match = false;
     577                 :          0 :             break;
     578                 :            :         }
     579                 :            :     }
     580                 :            : 
     581         [ #  # ]:          0 :     if( they_match == true )
     582                 :            :     {
     583                 :            :         // need to check for reversed edges here
     584 [ #  # ][ #  # ]:          0 :         direct = ( num_verts == 2 && j ) ? REVERSE : FORWARD;
     585                 :          0 :         return true;
     586                 :            :     }
     587                 :            : 
     588                 :          0 :     they_match = true;
     589                 :            : 
     590                 :            :     // then compare reverse
     591                 :          0 :     j += num_verts;
     592         [ #  # ]:          0 :     for( i = 1; i < num_verts; )
     593                 :            :     {
     594         [ #  # ]:          0 :         if( conn1[i] != conn2[( j - i ) % num_verts] )
     595                 :            :         {
     596                 :          0 :             they_match = false;
     597                 :          0 :             break;
     598                 :            :         }
     599                 :          0 :         ++i;
     600                 :            :     }
     601         [ #  # ]:          0 :     if( they_match ) { direct = REVERSE; }
     602                 :          0 :     return they_match;
     603                 :            : }
     604                 :            : 
     605                 :          0 : ErrorCode Skinner::remove_adjacency( EntityHandle entity )
     606                 :            : {
     607         [ #  # ]:          0 :     std::vector< EntityHandle > nodes, *adj = NULL;
     608 [ #  # ][ #  # ]:          0 :     ErrorCode result = thisMB->get_connectivity( &entity, 1, nodes );MB_CHK_ERR( result );
         [ #  # ][ #  # ]
     609         [ #  # ]:          0 :     std::vector< EntityHandle >::iterator iter = std::min_element( nodes.begin(), nodes.end() );
     610                 :            : 
     611 [ #  # ][ #  # ]:          0 :     if( iter == nodes.end() ) return MB_FAILURE;
     612                 :            : 
     613                 :            :     // remove this entity from the node
     614 [ #  # ][ #  # ]:          0 :     if( thisMB->tag_get_data( mAdjTag, &( *iter ), 1, &adj ) == MB_SUCCESS && adj != NULL )
         [ #  # ][ #  # ]
                 [ #  # ]
     615                 :            :     {
     616         [ #  # ]:          0 :         iter = std::find( adj->begin(), adj->end(), entity );
     617 [ #  # ][ #  # ]:          0 :         if( iter != adj->end() ) adj->erase( iter );
                 [ #  # ]
     618                 :            :     }
     619                 :            : 
     620                 :          0 :     return result;
     621                 :            : }
     622                 :            : 
     623                 :          0 : bool Skinner::entity_deletable( EntityHandle entity )
     624                 :            : {
     625                 :          0 :     unsigned char deletable = 0;
     626         [ #  # ]:          0 :     ErrorCode result        = thisMB->tag_get_data( mDeletableMBTag, &entity, 1, &deletable );
     627         [ #  # ]:          0 :     assert( MB_SUCCESS == result );
     628 [ #  # ][ #  # ]:          0 :     if( MB_SUCCESS == result && deletable == 1 ) return false;
     629                 :          0 :     return true;
     630                 :            : }
     631                 :            : 
     632                 :          0 : ErrorCode Skinner::classify_2d_boundary( const Range& boundary, const Range& bar_elements, EntityHandle boundary_edges,
     633                 :            :                                          EntityHandle inferred_edges, EntityHandle non_manifold_edges,
     634                 :            :                                          EntityHandle other_edges, int& number_boundary_nodes )
     635                 :            : {
     636 [ #  # ][ #  # ]:          0 :     Range bedges, iedges, nmedges, oedges;
         [ #  # ][ #  # ]
     637                 :            :     ErrorCode result =
     638 [ #  # ][ #  # ]:          0 :         classify_2d_boundary( boundary, bar_elements, bedges, iedges, nmedges, oedges, number_boundary_nodes );MB_CHK_ERR( result );
         [ #  # ][ #  # ]
     639                 :            : 
     640                 :            :     // now set the input meshsets to the output ranges
     641 [ #  # ][ #  # ]:          0 :     result = thisMB->clear_meshset( &boundary_edges, 1 );MB_CHK_ERR( result );
         [ #  # ][ #  # ]
     642 [ #  # ][ #  # ]:          0 :     result = thisMB->add_entities( boundary_edges, bedges );MB_CHK_ERR( result );
         [ #  # ][ #  # ]
     643                 :            : 
     644 [ #  # ][ #  # ]:          0 :     result = thisMB->clear_meshset( &inferred_edges, 1 );MB_CHK_ERR( result );
         [ #  # ][ #  # ]
     645 [ #  # ][ #  # ]:          0 :     result = thisMB->add_entities( inferred_edges, iedges );MB_CHK_ERR( result );
         [ #  # ][ #  # ]
     646                 :            : 
     647 [ #  # ][ #  # ]:          0 :     result = thisMB->clear_meshset( &non_manifold_edges, 1 );MB_CHK_ERR( result );
         [ #  # ][ #  # ]
     648 [ #  # ][ #  # ]:          0 :     result = thisMB->add_entities( non_manifold_edges, nmedges );MB_CHK_ERR( result );
         [ #  # ][ #  # ]
     649                 :            : 
     650 [ #  # ][ #  # ]:          0 :     result = thisMB->clear_meshset( &other_edges, 1 );MB_CHK_ERR( result );
         [ #  # ][ #  # ]
     651 [ #  # ][ #  # ]:          0 :     result = thisMB->add_entities( other_edges, oedges );MB_CHK_ERR( result );
         [ #  # ][ #  # ]
     652                 :            : 
     653                 :          0 :     return MB_SUCCESS;
     654                 :            : }
     655                 :            : 
     656                 :          0 : ErrorCode Skinner::classify_2d_boundary( const Range& boundary, const Range& bar_elements, Range& boundary_edges,
     657                 :            :                                          Range& inferred_edges, Range& non_manifold_edges, Range& other_edges,
     658                 :            :                                          int& number_boundary_nodes )
     659                 :            : {
     660                 :            : 
     661                 :            :     // clear out the edge lists
     662                 :            : 
     663         [ #  # ]:          0 :     boundary_edges.clear();
     664         [ #  # ]:          0 :     inferred_edges.clear();
     665         [ #  # ]:          0 :     non_manifold_edges.clear();
     666         [ #  # ]:          0 :     other_edges.clear();
     667                 :            : 
     668                 :          0 :     number_boundary_nodes = 0;
     669                 :            : 
     670                 :            :     // make sure we have something to work with
     671 [ #  # ][ #  # ]:          0 :     if( boundary.empty() ) { return MB_FAILURE; }
     672                 :            : 
     673                 :            :     // get our working dimensions
     674 [ #  # ][ #  # ]:          0 :     EntityType type      = thisMB->type_from_handle( *( boundary.begin() ) );
                 [ #  # ]
     675         [ #  # ]:          0 :     const int source_dim = CN::Dimension( type );
     676                 :            : 
     677                 :            :     // make sure we can handle the working dimensions
     678         [ #  # ]:          0 :     if( source_dim != 2 ) { return MB_FAILURE; }
     679                 :          0 :     mTargetDim = source_dim - 1;
     680                 :            : 
     681                 :            :     // initialize
     682         [ #  # ]:          0 :     initialize();
     683                 :            : 
     684                 :            :     // additional initialization for this routine
     685                 :            :     // define a tag for MBEDGE which counts the occurrences of the edge below
     686                 :            :     // default should be 0 for existing edges, if any
     687                 :            : 
     688                 :            :     Tag count_tag;
     689                 :          0 :     int default_count = 0;
     690                 :            :     ErrorCode result =
     691 [ #  # ][ #  # ]:          0 :         thisMB->tag_get_handle( 0, 1, MB_TYPE_INTEGER, count_tag, MB_TAG_DENSE | MB_TAG_CREAT, &default_count );MB_CHK_ERR( result );
         [ #  # ][ #  # ]
     692                 :            : 
     693 [ #  # ][ #  # ]:          0 :     Range::const_iterator iter, end_iter;
     694         [ #  # ]:          0 :     end_iter = boundary.end();
     695                 :            : 
     696         [ #  # ]:          0 :     std::vector< EntityHandle > conn;
     697                 :            :     EntityHandle sub_conn[2];
     698                 :            :     EntityHandle match;
     699                 :            : 
     700         [ #  # ]:          0 :     Range edge_list;
     701         [ #  # ]:          0 :     Range boundary_nodes;
     702                 :            :     Skinner::direction direct;
     703                 :            : 
     704                 :            :     EntityType sub_type;
     705                 :            :     int num_edge, num_sub_ent_vert;
     706                 :            :     const short* edge_verts;
     707                 :            : 
     708                 :            :     // now, process each entity in the boundary
     709                 :            : 
     710 [ #  # ][ #  # ]:          0 :     for( iter = boundary.begin(); iter != end_iter; ++iter )
         [ #  # ][ #  # ]
     711                 :            :     {
     712                 :            :         // get the connectivity of this entity
     713                 :          0 :         conn.clear();
     714 [ #  # ][ #  # ]:          0 :         result = thisMB->get_connectivity( &( *iter ), 1, conn, false );
     715         [ #  # ]:          0 :         assert( MB_SUCCESS == result );
     716                 :            : 
     717                 :            :         // add node handles to boundary_node range
     718 [ #  # ][ #  # ]:          0 :         std::copy( conn.begin(), conn.begin() + CN::VerticesPerEntity( type ), range_inserter( boundary_nodes ) );
         [ #  # ][ #  # ]
     719                 :            : 
     720 [ #  # ][ #  # ]:          0 :         type = thisMB->type_from_handle( *iter );
     721                 :            : 
     722                 :            :         // get connectivity of each n-1 dimension entity (edge in this case)
     723                 :          0 :         const struct CN::ConnMap* conn_map = &( CN::mConnectivityMap[type][0] );
     724         [ #  # ]:          0 :         num_edge                           = CN::NumSubEntities( type, 1 );
     725         [ #  # ]:          0 :         for( int i = 0; i < num_edge; i++ )
     726                 :            :         {
     727         [ #  # ]:          0 :             edge_verts = CN::SubEntityVertexIndices( type, 1, i, sub_type, num_sub_ent_vert );
     728 [ #  # ][ #  # ]:          0 :             assert( sub_type == MBEDGE && num_sub_ent_vert == 2 );
     729         [ #  # ]:          0 :             sub_conn[0]       = conn[edge_verts[0]];
     730         [ #  # ]:          0 :             sub_conn[1]       = conn[edge_verts[1]];
     731                 :          0 :             int num_sub_nodes = conn_map->num_corners_per_sub_element[i];
     732                 :            : 
     733                 :            :             // see if we can match this connectivity with
     734                 :            :             // an existing entity
     735         [ #  # ]:          0 :             find_match( MBEDGE, sub_conn, num_sub_nodes, match, direct );
     736                 :            : 
     737                 :            :             // if there is no match, create a new entity
     738         [ #  # ]:          0 :             if( match == 0 )
     739                 :            :             {
     740                 :          0 :                 EntityHandle tmphndl = 0;
     741                 :            :                 int indices[MAX_SUB_ENTITY_VERTICES];
     742                 :            :                 EntityType new_type;
     743                 :            :                 int num_new_nodes;
     744         [ #  # ]:          0 :                 CN::SubEntityNodeIndices( type, conn.size(), 1, i, new_type, num_new_nodes, indices );
     745         [ #  # ]:          0 :                 for( int j = 0; j < num_new_nodes; j++ )
     746         [ #  # ]:          0 :                     sub_conn[j] = conn[indices[j]];
     747                 :            : 
     748         [ #  # ]:          0 :                 result = thisMB->create_element( new_type, sub_conn, num_new_nodes, tmphndl );
     749         [ #  # ]:          0 :                 assert( MB_SUCCESS == result );
     750         [ #  # ]:          0 :                 add_adjacency( tmphndl, sub_conn, num_sub_nodes );
     751                 :            :                 // target_entities.insert(tmphndl);
     752         [ #  # ]:          0 :                 edge_list.insert( tmphndl );
     753                 :            :                 int count;
     754         [ #  # ]:          0 :                 result = thisMB->tag_get_data( count_tag, &tmphndl, 1, &count );
     755         [ #  # ]:          0 :                 assert( MB_SUCCESS == result );
     756                 :          0 :                 count++;
     757         [ #  # ]:          0 :                 result = thisMB->tag_set_data( count_tag, &tmphndl, 1, &count );
     758         [ #  # ]:          0 :                 assert( MB_SUCCESS == result );
     759                 :            :             }
     760                 :            :             else
     761                 :            :             {
     762                 :            :                 // We found a match, we must increment the count on the match
     763                 :            :                 int count;
     764         [ #  # ]:          0 :                 result = thisMB->tag_get_data( count_tag, &match, 1, &count );
     765         [ #  # ]:          0 :                 assert( MB_SUCCESS == result );
     766                 :          0 :                 count++;
     767         [ #  # ]:          0 :                 result = thisMB->tag_set_data( count_tag, &match, 1, &count );
     768         [ #  # ]:          0 :                 assert( MB_SUCCESS == result );
     769                 :            : 
     770                 :            :                 // if the entity is not deletable, it was pre-existing in
     771                 :            :                 // the database.  We therefore may need to add it to the
     772                 :            :                 // edge_list.  Since it will not hurt the range, we add
     773                 :            :                 // whether it was added before or not
     774 [ #  # ][ #  # ]:          0 :                 if( !entity_deletable( match ) ) { edge_list.insert( match ); }
                 [ #  # ]
     775                 :            :             }
     776                 :            :         }
     777                 :            :     }
     778                 :            : 
     779                 :            :     // Any bar elements in the model should be classified separately
     780                 :            :     // If the element is in the skin edge_list, then it should be put in
     781                 :            :     // the non-manifold edge list.  Edges not in the edge_list are stand-alone
     782                 :            :     // bars, and we make them simply boundary elements
     783                 :            : 
     784 [ #  # ][ #  # ]:          0 :     if( !bar_elements.empty() )
     785                 :            :     {
     786         [ #  # ]:          0 :         Range::iterator bar_iter;
     787 [ #  # ][ #  # ]:          0 :         for( iter = bar_elements.begin(); iter != bar_elements.end(); ++iter )
         [ #  # ][ #  # ]
                 [ #  # ]
     788                 :            :         {
     789         [ #  # ]:          0 :             EntityHandle handle = *iter;
     790         [ #  # ]:          0 :             bar_iter            = edge_list.find( handle );
     791 [ #  # ][ #  # ]:          0 :             if( bar_iter != edge_list.end() )
                 [ #  # ]
     792                 :            :             {
     793                 :            :                 // it is in the list, erase it and put in non-manifold list
     794         [ #  # ]:          0 :                 edge_list.erase( bar_iter );
     795         [ #  # ]:          0 :                 non_manifold_edges.insert( handle );
     796                 :            :             }
     797                 :            :             else
     798                 :            :             {
     799                 :            :                 // not in the edge list, make it a boundary edge
     800         [ #  # ]:          0 :                 boundary_edges.insert( handle );
     801                 :            :             }
     802                 :            :         }
     803                 :            :     }
     804                 :            : 
     805                 :            :     // now all edges should be classified.  Go through the edge_list,
     806                 :            :     // and put all in the appropriate lists
     807                 :            : 
     808 [ #  # ][ #  # ]:          0 :     Range::iterator edge_iter, edge_end_iter;
     809         [ #  # ]:          0 :     edge_end_iter = edge_list.end();
     810                 :            :     int count;
     811 [ #  # ][ #  # ]:          0 :     for( edge_iter = edge_list.begin(); edge_iter != edge_end_iter; ++edge_iter )
         [ #  # ][ #  # ]
     812                 :            :     {
     813                 :            :         // check the count_tag
     814 [ #  # ][ #  # ]:          0 :         result = thisMB->tag_get_data( count_tag, &( *edge_iter ), 1, &count );
     815         [ #  # ]:          0 :         assert( MB_SUCCESS == result );
     816 [ #  # ][ #  # ]:          0 :         if( count == 1 ) { boundary_edges.insert( *edge_iter ); }
                 [ #  # ]
     817         [ #  # ]:          0 :         else if( count == 2 )
     818                 :            :         {
     819 [ #  # ][ #  # ]:          0 :             other_edges.insert( *edge_iter );
     820                 :            :         }
     821                 :            :         else
     822                 :            :         {
     823 [ #  # ][ #  # ]:          0 :             non_manifold_edges.insert( *edge_iter );
     824                 :            :         }
     825                 :            :     }
     826                 :            : 
     827                 :            :     // find the inferred edges from the other_edge_list
     828                 :            : 
     829                 :          0 :     double min_angle_degrees = 20.0;
     830         [ #  # ]:          0 :     find_inferred_edges( const_cast< Range& >( boundary ), other_edges, inferred_edges, min_angle_degrees );
     831                 :            : 
     832                 :            :     // we now want to remove the inferred_edges from the other_edges
     833                 :            : 
     834         [ #  # ]:          0 :     Range temp_range;
     835                 :            : 
     836                 :            :     std::set_difference( other_edges.begin(), other_edges.end(), inferred_edges.begin(), inferred_edges.end(),
     837 [ #  # ][ #  # ]:          0 :                          range_inserter( temp_range ), std::less< EntityHandle >() );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     838                 :            : 
     839         [ #  # ]:          0 :     other_edges = temp_range;
     840                 :            : 
     841                 :            :     // get rid of count tag and deinitialize
     842                 :            : 
     843         [ #  # ]:          0 :     result = thisMB->tag_delete( count_tag );
     844         [ #  # ]:          0 :     assert( MB_SUCCESS == result );
     845         [ #  # ]:          0 :     deinitialize();
     846                 :            : 
     847                 :            :     // set the node count
     848         [ #  # ]:          0 :     number_boundary_nodes = boundary_nodes.size();
     849                 :            : 
     850                 :          0 :     return MB_SUCCESS;
     851                 :            : }
     852                 :            : 
     853                 :          0 : void Skinner::find_inferred_edges( Range& skin_boundary, Range& candidate_edges, Range& inferred_edges,
     854                 :            :                                    double reference_angle_degrees )
     855                 :            : {
     856                 :            : 
     857                 :            :     // mark all the entities in the skin boundary
     858                 :            :     Tag mark_tag;
     859         [ #  # ]:          0 :     ErrorCode result = thisMB->tag_get_handle( 0, 1, MB_TYPE_BIT, mark_tag, MB_TAG_CREAT );
     860         [ #  # ]:          0 :     assert( MB_SUCCESS == result );
     861                 :          0 :     unsigned char bit = true;
     862         [ #  # ]:          0 :     result            = thisMB->tag_clear_data( mark_tag, skin_boundary, &bit );
     863         [ #  # ]:          0 :     assert( MB_SUCCESS == result );
     864                 :            : 
     865                 :            :     // find the cosine of the reference angle
     866                 :            : 
     867                 :          0 :     double reference_cosine = cos( reference_angle_degrees * SKINNER_PI / 180.0 );
     868                 :            : 
     869                 :            :     // check all candidate edges for an angle greater than the minimum
     870                 :            : 
     871 [ #  # ][ #  # ]:          0 :     Range::iterator iter, end_iter = candidate_edges.end();
     872         [ #  # ]:          0 :     std::vector< EntityHandle > adjacencies;
     873                 :          0 :     std::vector< EntityHandle >::iterator adj_iter;
     874                 :            :     EntityHandle face[2];
     875                 :            : 
     876 [ #  # ][ #  # ]:          0 :     for( iter = candidate_edges.begin(); iter != end_iter; ++iter )
         [ #  # ][ #  # ]
     877                 :            :     {
     878                 :            : 
     879                 :            :         // get the 2D elements connected to this edge
     880                 :          0 :         adjacencies.clear();
     881 [ #  # ][ #  # ]:          0 :         result = thisMB->get_adjacencies( &( *iter ), 1, 2, false, adjacencies );
     882         [ #  # ]:          0 :         if( MB_SUCCESS != result ) continue;
     883                 :            : 
     884                 :            :         // there should be exactly two, that is why the edge is classified as nonBoundary
     885                 :            :         // and manifold
     886                 :            : 
     887                 :          0 :         int faces_found = 0;
     888 [ #  # ][ #  # ]:          0 :         for( adj_iter = adjacencies.begin(); adj_iter != adjacencies.end() && faces_found < 2; ++adj_iter )
         [ #  # ][ #  # ]
                 [ #  # ]
           [ #  #  #  # ]
     889                 :            :         {
     890                 :            :             // we need to find two of these which are in the skin
     891                 :          0 :             unsigned char is_marked = 0;
     892 [ #  # ][ #  # ]:          0 :             result                  = thisMB->tag_get_data( mark_tag, &( *adj_iter ), 1, &is_marked );
     893         [ #  # ]:          0 :             assert( MB_SUCCESS == result );
     894         [ #  # ]:          0 :             if( is_marked )
     895                 :            :             {
     896         [ #  # ]:          0 :                 face[faces_found] = *adj_iter;
     897                 :          0 :                 faces_found++;
     898                 :            :             }
     899                 :            :         }
     900                 :            : 
     901                 :            :         //    assert(faces_found == 2 || faces_found == 0);
     902         [ #  # ]:          0 :         if( 2 != faces_found ) continue;
     903                 :            : 
     904                 :            :         // see if the two entities have a sufficient angle
     905                 :            : 
     906 [ #  # ][ #  # ]:          0 :         if( has_larger_angle( face[0], face[1], reference_cosine ) ) { inferred_edges.insert( *iter ); }
         [ #  # ][ #  # ]
     907                 :            :     }
     908                 :            : 
     909         [ #  # ]:          0 :     result = thisMB->tag_delete( mark_tag );
     910         [ #  # ]:          0 :     assert( MB_SUCCESS == result );
     911                 :          0 : }
     912                 :            : 
     913                 :          0 : bool Skinner::has_larger_angle( EntityHandle& entity1, EntityHandle& entity2, double reference_angle_cosine )
     914                 :            : {
     915                 :            :     // compare normals to get angle.  We assume that the surface quads
     916                 :            :     // which we test here will be approximately planar
     917                 :            : 
     918                 :            :     double norm[2][3];
     919         [ #  # ]:          0 :     Util::normal( thisMB, entity1, norm[0][0], norm[0][1], norm[0][2] );
     920         [ #  # ]:          0 :     Util::normal( thisMB, entity2, norm[1][0], norm[1][1], norm[1][2] );
     921                 :            : 
     922                 :          0 :     double cosine = norm[0][0] * norm[1][0] + norm[0][1] * norm[1][1] + norm[0][2] * norm[1][2];
     923                 :            : 
     924         [ #  # ]:          0 :     if( cosine < reference_angle_cosine ) { return true; }
     925                 :            : 
     926                 :          0 :     return false;
     927                 :            : }
     928                 :            : 
     929                 :            : // get skin entities of prescribed dimension
     930                 :         33 : ErrorCode Skinner::find_skin( const EntityHandle this_set, const Range& entities, int dim, Range& skin_entities,
     931                 :            :                               bool create_vert_elem_adjs, bool create_skin_elements )
     932                 :            : {
     933         [ +  - ]:         33 :     Range tmp_skin;
     934                 :            :     ErrorCode result =
     935         [ +  - ]:         33 :         find_skin( this_set, entities, ( dim == 0 ), tmp_skin, 0, create_vert_elem_adjs, create_skin_elements );
     936 [ +  - ][ +  - ]:         33 :     if( MB_SUCCESS != result || tmp_skin.empty() ) return result;
         [ -  + ][ -  + ]
     937                 :            : 
     938 [ +  - ][ +  + ]:         33 :     if( tmp_skin.all_of_dimension( dim ) )
     939                 :            :     {
     940 [ +  - ][ +  - ]:         32 :         if( skin_entities.empty() )
     941         [ +  - ]:         32 :             skin_entities.swap( tmp_skin );
     942                 :            :         else
     943         [ #  # ]:         32 :             skin_entities.merge( tmp_skin );
     944                 :            :     }
     945                 :            :     else
     946                 :            :     {
     947 [ +  - ][ -  + ]:          1 :         result = thisMB->get_adjacencies( tmp_skin, dim, create_skin_elements, skin_entities, Interface::UNION );MB_CHK_ERR( result );
         [ #  # ][ #  # ]
     948 [ +  - ][ +  - ]:          1 :         if( this_set ) result = thisMB->add_entities( this_set, skin_entities );
     949                 :            :     }
     950                 :            : 
     951                 :         33 :     return result;
     952                 :            : }
     953                 :            : 
     954                 :         70 : ErrorCode Skinner::find_skin_vertices( const EntityHandle this_set, const Range& entities, Range* skin_verts,
     955                 :            :                                        Range* skin_elems, Range* skin_rev_elems, bool create_skin_elems,
     956                 :            :                                        bool corners_only )
     957                 :            : {
     958                 :            :     ErrorCode rval;
     959 [ +  - ][ -  + ]:         70 :     if( entities.empty() ) return MB_SUCCESS;
     960                 :            : 
     961 [ +  - ][ +  - ]:         70 :     const int dim = CN::Dimension( TYPE_FROM_HANDLE( entities.front() ) );
                 [ +  - ]
     962 [ +  - ][ +  - ]:         70 :     if( dim < 1 || dim > 3 || !entities.all_of_dimension( dim ) ) return MB_TYPE_OUT_OF_RANGE;
         [ +  - ][ -  + ]
                 [ -  + ]
     963                 :            : 
     964                 :            :     // are we skinning all entities
     965         [ +  - ]:         70 :     size_t count = entities.size();
     966                 :            :     int num_total;
     967         [ +  - ]:         70 :     rval = thisMB->get_number_entities_by_dimension( this_set, dim, num_total );
     968         [ -  + ]:         70 :     if( MB_SUCCESS != rval ) return rval;
     969                 :         70 :     bool all = ( count == (size_t)num_total );
     970                 :            : 
     971                 :            :     // Create a bit tag for fast intersection with input entities range.
     972                 :            :     // If we're skinning all the entities in the mesh, we really don't
     973                 :            :     // need the tag.  To save memory, just create it with a default value
     974                 :            :     // of one and don't set it.  That way MOAB will return 1 for all
     975                 :            :     // entities.
     976                 :            :     Tag tag;
     977         [ +  + ]:         70 :     char bit = all ? 1 : 0;
     978         [ +  - ]:         70 :     rval     = thisMB->tag_get_handle( NULL, 1, MB_TYPE_BIT, tag, MB_TAG_CREAT, &bit );
     979         [ -  + ]:         70 :     if( MB_SUCCESS != rval ) return rval;
     980                 :            : 
     981                 :            :     // tag all entities in input range
     982         [ +  + ]:         70 :     if( !all )
     983                 :            :     {
     984         [ +  - ]:         30 :         std::vector< unsigned char > vect( count, 1 );
     985 [ +  - ][ +  - ]:         30 :         rval = thisMB->tag_set_data( tag, entities, &vect[0] );
     986         [ -  + ]:         30 :         if( MB_SUCCESS != rval )
     987                 :            :         {
     988         [ #  # ]:          0 :             thisMB->tag_delete( tag );
     989         [ +  - ]:         30 :             return rval;
     990                 :         30 :         }
     991                 :            :     }
     992                 :            : 
     993   [ +  +  +  - ]:         70 :     switch( dim )
     994                 :            :     {
     995                 :            :         case 1:
     996         [ +  - ]:          4 :             if( skin_verts )
     997         [ +  - ]:          4 :                 rval = find_skin_vertices_1D( tag, entities, *skin_verts );
     998         [ #  # ]:          0 :             else if( skin_elems )
     999         [ #  # ]:          0 :                 rval = find_skin_vertices_1D( tag, entities, *skin_elems );
    1000                 :            :             else
    1001                 :          0 :                 rval = MB_SUCCESS;
    1002                 :          4 :             break;
    1003                 :            :         case 2:
    1004                 :            :             rval = find_skin_vertices_2D( this_set, tag, entities, skin_verts, skin_elems, skin_rev_elems,
    1005         [ +  - ]:         40 :                                           create_skin_elems, corners_only );
    1006                 :         40 :             break;
    1007                 :            :         case 3:
    1008                 :            :             rval = find_skin_vertices_3D( this_set, tag, entities, skin_verts, skin_elems, skin_rev_elems,
    1009         [ +  - ]:         26 :                                           create_skin_elems, corners_only );
    1010                 :         26 :             break;
    1011                 :            :         default:
    1012                 :          0 :             rval = MB_TYPE_OUT_OF_RANGE;
    1013                 :          0 :             break;
    1014                 :            :     }
    1015                 :            : 
    1016         [ +  - ]:         70 :     thisMB->tag_delete( tag );
    1017                 :         70 :     return rval;
    1018                 :            : }
    1019                 :            : 
    1020                 :          4 : ErrorCode Skinner::find_skin_vertices_1D( Tag tag, const Range& edges, Range& skin_verts )
    1021                 :            : {
    1022                 :            :     // This rather simple algorithm is provided for completeness
    1023                 :            :     // (not sure how often one really wants the 'skin' of a chain
    1024                 :            :     // or tangle of edges.)
    1025                 :            :     //
    1026                 :            :     // A vertex is on the skin of the edges if it is contained in exactly
    1027                 :            :     // one of the edges *in the input range*.
    1028                 :            :     //
    1029                 :            :     // This function expects the caller to have tagged all edges in the
    1030                 :            :     // input range with a value of one for the passed bit tag, and all
    1031                 :            :     // other edges with a value of zero.  This allows us to do a faster
    1032                 :            :     // intersection with the input range and the edges adjacent to a vertex.
    1033                 :            : 
    1034                 :            :     ErrorCode rval;
    1035         [ +  - ]:          4 :     Range::iterator hint = skin_verts.begin();
    1036                 :            : 
    1037                 :            :     // All input entities must be edges.
    1038 [ +  - ][ -  + ]:          4 :     if( !edges.all_of_dimension( 1 ) ) return MB_TYPE_OUT_OF_RANGE;
    1039                 :            : 
    1040                 :            :     // get all the vertices
    1041         [ +  - ]:          4 :     Range verts;
    1042         [ +  - ]:          4 :     rval = thisMB->get_connectivity( edges, verts, true );
    1043         [ -  + ]:          4 :     if( MB_SUCCESS != rval ) return rval;
    1044                 :            : 
    1045                 :            :     // Test how many edges each input vertex is adjacent to.
    1046         [ +  - ]:          8 :     std::vector< char > tag_vals;
    1047         [ +  - ]:          8 :     std::vector< EntityHandle > adj;
    1048                 :            :     int n;
    1049 [ +  - ][ +  - ]:         28 :     for( Range::const_iterator it = verts.begin(); it != verts.end(); ++it )
         [ +  - ][ +  - ]
                 [ +  + ]
    1050                 :            :     {
    1051                 :            :         // get edges adjacent to vertex
    1052                 :         24 :         adj.clear();
    1053 [ +  - ][ +  - ]:         24 :         rval = thisMB->get_adjacencies( &*it, 1, 1, false, adj );
    1054         [ -  + ]:         24 :         if( MB_SUCCESS != rval ) return rval;
    1055         [ -  + ]:         24 :         if( adj.empty() ) continue;
    1056                 :            : 
    1057                 :            :         // Intersect adjacent edges with the input list of edges
    1058         [ +  - ]:         24 :         tag_vals.resize( adj.size() );
    1059 [ +  - ][ +  - ]:         24 :         rval = thisMB->tag_get_data( tag, &adj[0], adj.size(), &tag_vals[0] );
                 [ +  - ]
    1060         [ -  + ]:         24 :         if( MB_SUCCESS != rval ) return rval;
    1061                 :            : #ifdef MOAB_OLD_STD_COUNT
    1062                 :            :         n = 0;
    1063                 :            :         std::count( tag_vals.begin(), tag_vals.end(), '\001', n );
    1064                 :            : #else
    1065         [ +  - ]:         24 :         n = std::count( tag_vals.begin(), tag_vals.end(), '\001' );
    1066                 :            : #endif
    1067                 :            :         // If adjacent to only one input edge, then vertex is on skin
    1068 [ +  + ][ +  - ]:         24 :         if( n == 1 ) { hint = skin_verts.insert( hint, *it ); }
                 [ +  - ]
    1069                 :            :     }
    1070                 :            : 
    1071                 :          8 :     return MB_SUCCESS;
    1072                 :            : }
    1073                 :            : 
    1074                 :            : // A Container for storing a list of element sides adjacent
    1075                 :            : // to a vertex.  The template parameter is the number of
    1076                 :            : // corners for the side.
    1077                 :            : template < unsigned CORNERS >
    1078                 :        236 : class AdjSides
    1079                 :            : {
    1080                 :            :   public:
    1081                 :            :     /**
    1082                 :            :      * This struct is used to for a reduced representation of element
    1083                 :            :      * "sides" adjacent to a give vertex.  As such, it
    1084                 :            :      * a) does not store the initial vertex that all sides are adjacent to
    1085                 :            :      * b) orders the remaining vertices in a specific way for fast comparison.
    1086                 :            :      *
    1087                 :            :      * For edge elements, only the opposite vertex is stored.
    1088                 :            :      * For triangle elements, only the other two vertices are stored,
    1089                 :            :      *   and they are stored with the smaller of those two handles first.
    1090                 :            :      * For quad elements, only the other three vertices are stored.
    1091                 :            :      *  They are stored such that the vertex opposite the implicit (not
    1092                 :            :      *  stored) vertex is always in slot 1.  The other two vertices
    1093                 :            :      *  (in slots 0 and 2) are ordered such that the handle of the one in
    1094                 :            :      *  slot 0 is smaller than the handle in slot 2.
    1095                 :            :      *
    1096                 :            :      * For each side, the adj_elem field is used to store the element that
    1097                 :            :      * it is a side of as long as the element is considered to be on the skin.
    1098                 :            :      * The adj_elem field is cleared (set to zero) to indicate that this
    1099                 :            :      * side is no longer considered to be on the skin (and is the side of
    1100                 :            :      * more than one element.)
    1101                 :            :      */
    1102                 :            :     struct Side
    1103                 :            :     {
    1104                 :            :         EntityHandle handles[CORNERS - 1];  //!< side vertices, except for implicit one
    1105                 :            :         EntityHandle adj_elem;              //!< element that this is a side of, or zero
    1106                 :       8720 :         bool skin() const
    1107                 :            :         {
    1108                 :       8720 :             return 0 != adj_elem;
    1109                 :            :         }
    1110                 :            : 
    1111                 :            :         /** construct from connectivity of side
    1112                 :            :          *\param array The connectivity of the element side.
    1113                 :            :          *\param idx   The index of the implicit vertex (contained
    1114                 :            :          *             in all sides in the list.)
    1115                 :            :          *\param adj   The element that this is a side of.
    1116                 :            :          */
    1117                 :      73922 :         Side( const EntityHandle* array, int idx, EntityHandle adj, unsigned short ) : adj_elem( adj )
    1118                 :            :         {
    1119                 :            :             switch( CORNERS )
    1120                 :            :             {
    1121                 :            :                 case 3:
    1122                 :         50 :                     handles[1] = array[( idx + 2 ) % CORNERS];
    1123                 :            :                 case 2:
    1124                 :      73922 :                     handles[0] = array[( idx + 1 ) % CORNERS];
    1125                 :      73922 :                     break;
    1126                 :            :                 default:
    1127                 :            :                     assert( false );
    1128                 :            :                     break;
    1129                 :            :             }
    1130         [ +  + ]:         50 :             if( CORNERS == 3 && handles[1] > handles[0] ) std::swap( handles[0], handles[1] );
    1131                 :      73922 :         }
    1132                 :            : 
    1133                 :            :         /** construct from connectivity of parent element
    1134                 :            :          *\param array The connectivity of the parent element
    1135                 :            :          *\param idx   The index of the implicit vertex (contained
    1136                 :            :          *             in all sides in the list.)  This is an index
    1137                 :            :          *             into 'indices', not 'array'.
    1138                 :            :          *\param adj   The element that this is a side of.
    1139                 :            :          *\param indices  The indices into 'array' at which the vertices
    1140                 :            :          *             representing the side occur.
    1141                 :            :          */
    1142                 :        120 :         Side( const EntityHandle* array, int idx, EntityHandle adj, unsigned short, const short* indices )
    1143                 :        120 :             : adj_elem( adj )
    1144                 :            :         {
    1145                 :            :             switch( CORNERS )
    1146                 :            :             {
    1147                 :            :                 case 3:
    1148                 :        120 :                     handles[1] = array[indices[( idx + 2 ) % CORNERS]];
    1149                 :            :                 case 2:
    1150                 :        120 :                     handles[0] = array[indices[( idx + 1 ) % CORNERS]];
    1151                 :        120 :                     break;
    1152                 :            :                 default:
    1153                 :            :                     assert( false );
    1154                 :            :                     break;
    1155                 :            :             }
    1156         [ +  + ]:        120 :             if( CORNERS == 3 && handles[1] > handles[0] ) std::swap( handles[0], handles[1] );
    1157                 :        120 :         }
    1158                 :            : 
    1159                 :            :         // Compare two side instances.  Relies in the ordering of
    1160                 :            :         // vertex handles as described above.
    1161                 :     213405 :         bool operator==( const Side& other ) const
    1162                 :            :         {
    1163                 :            :             switch( CORNERS )
    1164                 :            :             {
    1165                 :            :                 case 3:
    1166 [ +  + ][ +  + ]:        232 :                     return handles[0] == other.handles[0] && handles[1] == other.handles[1];
    1167                 :            :                 case 2:
    1168                 :     213173 :                     return handles[0] == other.handles[0];
    1169                 :            :                 default:
    1170                 :            :                     assert( false );
    1171                 :            :                     return false;
    1172                 :            :             }
    1173                 :            :         }
    1174                 :            :     };
    1175                 :            : 
    1176                 :            :   private:
    1177                 :            :     std::vector< Side > data;  //!< List of sides
    1178                 :            :     size_t skin_count;         //!< Cached count of sides that are skin
    1179                 :            : 
    1180                 :            :   public:
    1181                 :            :     typedef typename std::vector< Side >::iterator iterator;
    1182                 :            :     typedef typename std::vector< Side >::const_iterator const_iterator;
    1183                 :       1469 :     const_iterator begin() const
    1184                 :            :     {
    1185                 :       1469 :         return data.begin();
    1186                 :            :     }
    1187                 :      10189 :     const_iterator end() const
    1188                 :            :     {
    1189                 :      10189 :         return data.end();
    1190                 :            :     }
    1191                 :            : 
    1192                 :      21312 :     void clear()
    1193                 :            :     {
    1194                 :      21312 :         data.clear();
    1195                 :      21312 :         skin_count = 0;
    1196                 :      21312 :     }
    1197                 :            :     bool empty() const
    1198                 :            :     {
    1199                 :            :         return data.empty();
    1200                 :            :     }
    1201                 :            : 
    1202                 :        236 :     AdjSides() : skin_count( 0 ) {}
    1203                 :            : 
    1204                 :      28486 :     size_t num_skin() const
    1205                 :            :     {
    1206                 :      28486 :         return skin_count;
    1207                 :            :     }
    1208                 :            : 
    1209                 :            :     /** \brief insert side, specifying side connectivity
    1210                 :            :      *
    1211                 :            :      * Either insert a new side, or if the side is already in the
    1212                 :            :      * list, mark it as not on the skin.
    1213                 :            :      *
    1214                 :            :      *\param handles The connectivity of the element side.
    1215                 :            :      *\param skip_idx The index of the implicit vertex (contained
    1216                 :            :      *             in all sides in the list.)
    1217                 :            :      *\param adj_elem The element that this is a side of.
    1218                 :            :      *\param elem_side Which side of adj_elem are we storing
    1219                 :            :      *             (CN side number.)
    1220                 :            :      */
    1221                 :      71808 :     void insert( const EntityHandle* handles, int skip_idx, EntityHandle adj_elem, unsigned short elem_side )
    1222                 :            :     {
    1223 [ +  - ][ #  # ]:      71808 :         Side side( handles, skip_idx, adj_elem, elem_side );
                 [ +  - ]
    1224 [ +  - ][ #  # ]:      71808 :         iterator p = std::find( data.begin(), data.end(), side );
                 [ +  - ]
    1225 [ +  - ][ +  + ]:      71808 :         if( p == data.end() )
         [ #  # ][ #  # ]
         [ +  - ][ +  + ]
    1226                 :            :         {
    1227 [ +  - ][ #  # ]:      37164 :             data.push_back( side );
                 [ +  - ]
    1228                 :      37164 :             ++skin_count;  // not in list yet, so skin side (so far)
    1229                 :            :         }
    1230 [ +  - ][ +  - ]:      34644 :         else if( p->adj_elem )
         [ #  # ][ #  # ]
         [ +  - ][ +  - ]
    1231                 :            :         {
    1232 [ +  - ][ #  # ]:      34644 :             p->adj_elem = 0;  // mark as not on skin
                 [ +  - ]
    1233                 :      34644 :             --skin_count;     // decrement cached count of skin elements
    1234                 :            :         }
    1235                 :      71808 :     }
    1236                 :            : 
    1237                 :            :     /** \brief insert side, specifying list of indices into parent element
    1238                 :            :      * connectivity.
    1239                 :            :      *
    1240                 :            :      * Either insert a new side, or if the side is already in the
    1241                 :            :      * list, mark it as not on the skin.
    1242                 :            :      *
    1243                 :            :      *\param handles The connectivity of the parent element
    1244                 :            :      *\param skip_idx The index of the implicit vertex (contained
    1245                 :            :      *             in all sides in the list.)  This is an index
    1246                 :            :      *             into 'indices', not 'handles'.
    1247                 :            :      *\param adj_elem The element that this is a side of (parent handle).
    1248                 :            :      *\param indices  The indices into 'handles' at which the vertices
    1249                 :            :      *             representing the side occur.
    1250                 :            :      *\param elem_side Which side of adj_elem are we storing
    1251                 :            :      *             (CN side number.)
    1252                 :            :      */
    1253                 :      73320 :     void insert( const EntityHandle* handles, int skip_idx, EntityHandle adj_elem, unsigned short elem_side,
    1254                 :            :                  const short* indices )
    1255                 :            :     {
    1256 [ +  - ][ +  - ]:      73320 :         Side side( handles, skip_idx, adj_elem, elem_side, indices );
    1257 [ +  - ][ +  - ]:      73320 :         iterator p = std::find( data.begin(), data.end(), side );
    1258 [ +  - ][ +  + ]:      73320 :         if( p == data.end() )
         [ +  - ][ +  + ]
    1259                 :            :         {
    1260 [ +  - ][ +  - ]:      42350 :             data.push_back( side );
    1261                 :      42350 :             ++skin_count;  // not in list yet, so skin side (so far)
    1262                 :            :         }
    1263 [ +  - ][ +  - ]:      30970 :         else if( p->adj_elem )
         [ +  - ][ +  - ]
    1264                 :            :         {
    1265 [ +  - ][ +  - ]:      30970 :             p->adj_elem = 0;  // mark as not on skin
    1266                 :      30970 :             --skin_count;     // decrement cached count of skin elements
    1267                 :            :         }
    1268                 :      73320 :     }
    1269                 :            : 
    1270                 :            :     /**\brief Search list for a given side, and if found, mark as not skin.
    1271                 :            :      *
    1272                 :            :      *\param other   Connectivity of side
    1273                 :            :      *\param skip_index Index in 'other' at which implicit vertex occurs.
    1274                 :            :      *\param elem_out If return value is true, the element that the side is a
    1275                 :            :      *                side of.  If return value is false, not set.
    1276                 :            :      *\return true if found and marked not-skin, false if not found.
    1277                 :            :      *
    1278                 :            :      * Given the connectivity of some existing element, check if it occurs
    1279                 :            :      * in the list.  If it does, clear the "is skin" state of the side so
    1280                 :            :      * that we know that we don't need to later create the side element.
    1281                 :            :      */
    1282                 :       9666 :     bool find_and_unmark( const EntityHandle* other, int skip_index, EntityHandle& elem_out )
    1283                 :            :     {
    1284 [ +  - ][ +  - ]:       9666 :         Side s( other, skip_index, 0, 0 );
                 [ +  - ]
    1285 [ +  - ][ +  - ]:       9666 :         iterator p = std::find( data.begin(), data.end(), s );
                 [ +  - ]
    1286 [ +  - ][ +  - ]:       9666 :         if( p == data.end() || !p->adj_elem )
         [ +  - ][ +  + ]
                 [ +  - ]
           [ +  +  #  # ]
         [ +  - ][ +  - ]
         [ +  - ][ -  + ]
                 [ +  - ]
           [ -  +  #  # ]
         [ +  - ][ +  + ]
         [ +  - ][ +  + ]
                 [ +  - ]
           [ +  +  #  # ]
    1287                 :        938 :             return false;
    1288                 :            :         else
    1289                 :            :         {
    1290 [ +  - ][ +  - ]:       8728 :             elem_out    = p->adj_elem;
                 [ +  - ]
    1291 [ +  - ][ +  - ]:       8728 :             p->adj_elem = 0;  // clear "is skin" state for side
                 [ +  - ]
    1292                 :       8728 :             --skin_count;     // decrement cached count of skin sides
    1293                 :       9666 :             return true;
    1294                 :            :         }
    1295                 :            :     }
    1296                 :            : };
    1297                 :            : 
    1298                 :            : /** construct from connectivity of side
    1299                 :            :  *\param array The connectivity of the element side.
    1300                 :            :  *\param idx   The index of the implicit vertex (contained
    1301                 :            :  *             in all sides in the list.)
    1302                 :            :  *\param adj   The element that this is a side of.
    1303                 :            :  */
    1304                 :            : template <>
    1305                 :       7552 : AdjSides< 4 >::Side::Side( const EntityHandle* array, int idx, EntityHandle adj, unsigned short ) : adj_elem( adj )
    1306                 :            : {
    1307                 :       7552 :     const unsigned int CORNERS = 4;
    1308                 :       7552 :     handles[2]                 = array[( idx + 3 ) % CORNERS];
    1309                 :       7552 :     handles[1]                 = array[( idx + 2 ) % CORNERS];
    1310                 :       7552 :     handles[0]                 = array[( idx + 1 ) % CORNERS];
    1311         [ +  + ]:       7552 :     if( handles[2] > handles[0] ) std::swap( handles[0], handles[2] );
    1312                 :       7552 : }
    1313                 :            : 
    1314                 :            : /** construct from connectivity of parent element
    1315                 :            :  *\param array The connectivity of the parent element
    1316                 :            :  *\param idx   The index of the implicit vertex (contained
    1317                 :            :  *             in all sides in the list.)  This is an index
    1318                 :            :  *             into 'indices', not 'array'.
    1319                 :            :  *\param adj   The element that this is a side of.
    1320                 :            :  *\param indices  The indices into 'array' at which the vertices
    1321                 :            :  *             representing the side occur.
    1322                 :            :  */
    1323                 :            : template <>
    1324                 :      73200 : AdjSides< 4 >::Side::Side( const EntityHandle* array, int idx, EntityHandle adj, unsigned short, const short* indices )
    1325                 :      73200 :     : adj_elem( adj )
    1326                 :            : {
    1327                 :      73200 :     const unsigned int CORNERS = 4;
    1328                 :      73200 :     handles[2]                 = array[indices[( idx + 3 ) % CORNERS]];
    1329                 :      73200 :     handles[1]                 = array[indices[( idx + 2 ) % CORNERS]];
    1330                 :      73200 :     handles[0]                 = array[indices[( idx + 1 ) % CORNERS]];
    1331         [ +  + ]:      73200 :     if( handles[2] > handles[0] ) std::swap( handles[0], handles[2] );
    1332                 :      73200 : }
    1333                 :            : 
    1334                 :            : // Compare two side instances.  Relies in the ordering of
    1335                 :            : // vertex handles as described above.
    1336                 :            : template <>
    1337                 :     393423 : bool AdjSides< 4 >::Side::operator==( const Side& other ) const
    1338                 :            : {
    1339 [ +  + ][ +  + ]:     393423 :     return handles[0] == other.handles[0] && handles[1] == other.handles[1] && handles[2] == other.handles[2];
                 [ +  - ]
    1340                 :            : }
    1341                 :            : 
    1342                 :            : // Utility function used by find_skin_vertices_2D and
    1343                 :            : // find_skin_vertices_3D to create elements representing
    1344                 :            : // the skin side of a higher-dimension element if one
    1345                 :            : // does not already exist.
    1346                 :            : //
    1347                 :            : // Some arguments may seem redundant, but they are used
    1348                 :            : // to create the correct order of element when the input
    1349                 :            : // element contains higher-order nodes.
    1350                 :            : //
    1351                 :            : // This function always creates elements that have a "forward"
    1352                 :            : // orientation with respect to the parent element (have
    1353                 :            : // nodes ordered the same as CN returns for the "side").
    1354                 :            : //
    1355                 :            : // elem - The higher-dimension element for which to create
    1356                 :            : //        a lower-dim element representing the side.
    1357                 :            : // side_type - The EntityType of the desired side.
    1358                 :            : // side_conn - The connectivity of the new side.
    1359                 :       1552 : ErrorCode Skinner::create_side( const EntityHandle this_set, EntityHandle elem, EntityType side_type,
    1360                 :            :                                 const EntityHandle* side_conn, EntityHandle& side_elem )
    1361                 :            : {
    1362                 :       1552 :     const int max_side = 9;
    1363                 :            :     const EntityHandle* conn;
    1364                 :            :     int len, side_len, side, sense, offset, indices[max_side];
    1365                 :            :     ErrorCode rval;
    1366         [ +  - ]:       1552 :     EntityType type   = TYPE_FROM_HANDLE( elem ), tmp_type;
    1367         [ +  - ]:       1552 :     const int ncorner = CN::VerticesPerEntity( side_type );
    1368         [ +  - ]:       1552 :     const int d       = CN::Dimension( side_type );
    1369         [ +  - ]:       1552 :     std::vector< EntityHandle > storage;
    1370                 :            : 
    1371                 :            :     // Get the connectivity of the parent element
    1372         [ +  - ]:       1552 :     rval = thisMB->get_connectivity( elem, conn, len, false, &storage );
    1373         [ -  + ]:       1552 :     if( MB_SUCCESS != rval ) return rval;
    1374                 :            : 
    1375                 :            :     // treat separately MBPOLYGON; we want to create the edge in the
    1376                 :            :     // forward sense always ; so figure out the sense first, then get out
    1377 [ -  + ][ #  # ]:       1552 :     if( MBPOLYGON == type && 1 == d && MBEDGE == side_type )
                 [ #  # ]
    1378                 :            :     {
    1379                 :            :         // first find the first vertex in the conn list
    1380                 :          0 :         int i = 0;
    1381         [ #  # ]:          0 :         for( i = 0; i < len; i++ )
    1382                 :            :         {
    1383         [ #  # ]:          0 :             if( conn[i] == side_conn[0] ) break;
    1384                 :            :         }
    1385         [ #  # ]:          0 :         if( len == i ) return MB_FAILURE;  // not found, big error
    1386                 :            :         // now, what if the polygon is padded?
    1387                 :            :         // the previous index is fine always. but the next one could be trouble :(
    1388                 :          0 :         int prevIndex = ( i + len - 1 ) % len;
    1389                 :          0 :         int nextIndex = ( i + 1 ) % len;
    1390                 :            :         // if the next index actually point to the same node, as current, it means it is padded
    1391         [ #  # ]:          0 :         if( conn[nextIndex] == conn[i] )
    1392                 :            :         {
    1393                 :            :             // it really means we are at the end of proper nodes, the last nodes are repeated, so it
    1394                 :            :             // should be the first node
    1395                 :          0 :             nextIndex = 0;  // this is the first node!
    1396                 :            :         }
    1397                 :          0 :         EntityHandle conn2[2] = { side_conn[0], side_conn[1] };
    1398         [ #  # ]:          0 :         if( conn[prevIndex] == side_conn[1] )
    1399                 :            :         {
    1400                 :            :             // reverse, so the edge will be forward
    1401                 :          0 :             conn2[0] = side_conn[1];
    1402                 :          0 :             conn2[1] = side_conn[0];
    1403                 :            :         }
    1404         [ #  # ]:          0 :         else if( conn[nextIndex] != side_conn[1] )
    1405                 :          0 :             return MB_FAILURE;  // it is not adjacent to the polygon
    1406                 :            : 
    1407 [ #  # ][ #  # ]:          0 :         rval = thisMB->create_element( MBEDGE, conn2, 2, side_elem );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1408         [ #  # ]:          0 :         if( this_set )
    1409                 :            :         {
    1410 [ #  # ][ #  # ]:          0 :             rval = thisMB->add_entities( this_set, &side_elem, 1 );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1411                 :            :         }
    1412                 :          0 :         return MB_SUCCESS;
    1413                 :            :     }
    1414                 :            :     // Find which side we are creating and get indices of all nodes
    1415                 :            :     // (including higher-order, if any.)
    1416         [ +  - ]:       1552 :     CN::SideNumber( type, conn, side_conn, ncorner, d, side, sense, offset );
    1417         [ +  - ]:       1552 :     CN::SubEntityNodeIndices( type, len, d, side, tmp_type, side_len, indices );
    1418         [ -  + ]:       1552 :     assert( side_len <= max_side );
    1419         [ -  + ]:       1552 :     assert( side_type == tmp_type );
    1420                 :            : 
    1421                 :            :     // NOTE: re-create conn array even when no higher-order nodes
    1422                 :            :     //      because we want it to always be forward with respect
    1423                 :            :     //      to the side ordering.
    1424                 :            :     EntityHandle side_conn_full[max_side];
    1425         [ +  + ]:       6964 :     for( int i = 0; i < side_len; ++i )
    1426                 :       5412 :         side_conn_full[i] = conn[indices[i]];
    1427                 :            : 
    1428 [ +  - ][ -  + ]:       1552 :     rval = thisMB->create_element( side_type, side_conn_full, side_len, side_elem );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1429         [ +  + ]:       1552 :     if( this_set )
    1430                 :            :     {
    1431 [ +  - ][ -  + ]:         22 :         rval = thisMB->add_entities( this_set, &side_elem, 1 );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
    1432                 :            :     }
    1433                 :       1552 :     return MB_SUCCESS;
    1434                 :       1552 :     ;
    1435                 :            : }
    1436                 :            : 
    1437                 :            : // Test if an edge is reversed with respect CN's ordering
    1438                 :            : // for the "side" of a face.
    1439                 :         10 : bool Skinner::edge_reversed( EntityHandle face, const EntityHandle* edge_ends )
    1440                 :            : {
    1441                 :            :     const EntityHandle* conn;
    1442                 :            :     int len, idx;
    1443         [ +  - ]:         10 :     ErrorCode rval = thisMB->get_connectivity( face, conn, len, true );
    1444         [ -  + ]:         10 :     if( MB_SUCCESS != rval )
    1445                 :            :     {
    1446                 :          0 :         assert( false );
    1447                 :            :         return false;
    1448                 :            :     }
    1449         [ +  - ]:         10 :     idx = std::find( conn, conn + len, edge_ends[0] ) - conn;
    1450         [ -  + ]:         10 :     if( idx == len )
    1451                 :            :     {
    1452                 :          0 :         assert( false );
    1453                 :            :         return false;
    1454                 :            :     }
    1455                 :         10 :     return ( edge_ends[1] == conn[( idx + len - 1 ) % len] );
    1456                 :            : }
    1457                 :            : 
    1458                 :            : // Test if a 2D element representing the side or face of a
    1459                 :            : // volume element is reversed with respect to the CN node
    1460                 :            : // ordering for the corresponding region element side.
    1461                 :        230 : bool Skinner::face_reversed( EntityHandle region, const EntityHandle* face_corners, EntityType face_type )
    1462                 :            : {
    1463                 :            :     const EntityHandle* conn;
    1464                 :            :     int len, side, sense, offset;
    1465         [ +  - ]:        230 :     ErrorCode rval = thisMB->get_connectivity( region, conn, len, true );
    1466         [ -  + ]:        230 :     if( MB_SUCCESS != rval )
    1467                 :            :     {
    1468                 :          0 :         assert( false );
    1469                 :            :         return false;
    1470                 :            :     }
    1471         [ +  - ]:        230 :     short r = CN::SideNumber( TYPE_FROM_HANDLE( region ), conn, face_corners, CN::VerticesPerEntity( face_type ),
    1472 [ +  - ][ +  - ]:        460 :                               CN::Dimension( face_type ), side, sense, offset );
                 [ +  - ]
    1473         [ -  + ]:        230 :     assert( 0 == r );
    1474 [ +  - ][ +  + ]:        230 :     return ( !r && sense == -1 );
    1475                 :            : }
    1476                 :            : 
    1477                 :         40 : ErrorCode Skinner::find_skin_vertices_2D( const EntityHandle this_set, Tag tag, const Range& faces, Range* skin_verts,
    1478                 :            :                                           Range* skin_edges, Range* reversed_edges, bool create_edges,
    1479                 :            :                                           bool corners_only )
    1480                 :            : {
    1481                 :            :     // This function iterates over all the vertices contained in the
    1482                 :            :     // input face list.  For each such vertex, it then iterates over
    1483                 :            :     // all of the sides of the face elements adjacent to the vertex.
    1484                 :            :     // If an adjacent side is the side of only one of the input
    1485                 :            :     // faces, then that side is on the skin.
    1486                 :            :     //
    1487                 :            :     // This algorithm will visit each skin vertex exactly once.  It
    1488                 :            :     // will visit each skin side once for each vertex in the side.
    1489                 :            :     //
    1490                 :            :     // This function expects the caller to have created the passed bit
    1491                 :            :     // tag and set it to one only for the faces in the passed range.  This
    1492                 :            :     // tag is used to do a fast intersection of the faces adjacent to a
    1493                 :            :     // vertex with the faces in the input range (discard any for which the
    1494                 :            :     // tag is not set to one.)
    1495                 :            : 
    1496                 :            :     ErrorCode rval;
    1497                 :         40 :     std::vector< EntityHandle >::iterator i, j;
    1498         [ +  - ]:         40 :     Range::iterator hint;
    1499 [ +  + ][ +  - ]:         40 :     if( skin_verts ) hint = skin_verts->begin();
    1500         [ +  - ]:         40 :     std::vector< EntityHandle > storage;
    1501                 :            :     const EntityHandle* conn;
    1502                 :            :     int len;
    1503 [ +  + ][ +  + ]:         40 :     bool find_edges                      = skin_edges || create_edges;
    1504                 :         40 :     bool printed_nonconformal_ho_warning = false;
    1505                 :            :     EntityHandle face;
    1506                 :            : 
    1507 [ +  - ][ -  + ]:         40 :     if( !faces.all_of_dimension( 2 ) ) return MB_TYPE_OUT_OF_RANGE;
    1508                 :            : 
    1509                 :            :     // get all the vertices
    1510         [ +  - ]:         80 :     Range verts;
    1511         [ +  - ]:         40 :     rval = thisMB->get_connectivity( faces, verts, true );
    1512         [ -  + ]:         40 :     if( MB_SUCCESS != rval ) return rval;
    1513                 :            : 
    1514         [ +  - ]:         80 :     std::vector< char > tag_vals;
    1515         [ +  - ]:         80 :     std::vector< EntityHandle > adj;
    1516         [ +  - ]:         80 :     AdjSides< 2 > adj_edges;
    1517 [ +  - ][ +  - ]:       6622 :     for( Range::const_iterator it = verts.begin(); it != verts.end(); ++it )
         [ +  - ][ +  - ]
                 [ +  + ]
    1518                 :            :     {
    1519                 :       6582 :         bool higher_order = false;
    1520                 :            : 
    1521                 :            :         // get all adjacent faces
    1522                 :       6582 :         adj.clear();
    1523 [ +  - ][ +  - ]:       6582 :         rval = thisMB->get_adjacencies( &*it, 1, 2, false, adj );
    1524         [ -  + ]:       6582 :         if( MB_SUCCESS != rval ) return rval;
    1525         [ -  + ]:       6582 :         if( adj.empty() ) continue;
    1526                 :            : 
    1527                 :            :         // remove those not in the input list (intersect with input list)
    1528                 :       6582 :         i = j = adj.begin();
    1529         [ +  - ]:       6582 :         tag_vals.resize( adj.size() );
    1530 [ +  - ][ +  - ]:       6582 :         rval = thisMB->tag_get_data( tag, &adj[0], adj.size(), &tag_vals[0] );
                 [ +  - ]
    1531         [ -  + ]:       6582 :         if( MB_SUCCESS != rval ) return rval;
    1532                 :            :         // remove non-tagged entries
    1533                 :       6582 :         i = j = adj.begin();
    1534 [ +  - ][ +  - ]:      42844 :         for( ; i != adj.end(); ++i )
                 [ +  + ]
    1535 [ +  - ][ +  - ]:      36262 :             if( tag_vals[i - adj.begin()] ) *( j++ ) = *i;
         [ +  + ][ +  - ]
         [ +  - ][ +  - ]
    1536         [ +  - ]:       6582 :         adj.erase( j, adj.end() );
    1537                 :            : 
    1538                 :            :         // For each adjacent face, check the edges adjacent to the current vertex
    1539         [ +  - ]:       6582 :         adj_edges.clear();  // other vertex for adjacent edges
    1540 [ +  - ][ +  - ]:      42054 :         for( i = adj.begin(); i != adj.end(); ++i )
                 [ +  + ]
    1541                 :            :         {
    1542 [ +  - ][ +  - ]:      35472 :             rval = thisMB->get_connectivity( *i, conn, len, false, &storage );
    1543         [ -  + ]:      35472 :             if( MB_SUCCESS != rval ) return rval;
    1544                 :            : 
    1545                 :            :             // For a single face element adjacent to this vertex, there
    1546                 :            :             // will be exactly two sides (edges) adjacent to the vertex.
    1547                 :            :             // Find the other vertex for each of the two edges.
    1548                 :            : 
    1549                 :            :             EntityHandle prev, next;  // vertices of two adjacent edge-sides
    1550 [ +  - ][ +  - ]:      35472 :             const int idx = std::find( conn, conn + len, *it ) - conn;
    1551         [ -  + ]:      35472 :             assert( idx != len );
    1552                 :            : 
    1553 [ +  - ][ +  - ]:      35472 :             if( TYPE_FROM_HANDLE( *i ) == MBTRI && len > 3 )
         [ +  + ][ +  + ]
                 [ +  + ]
    1554                 :            :             {
    1555                 :         12 :                 len          = 3;
    1556                 :         12 :                 higher_order = true;
    1557         [ -  + ]:         12 :                 if( idx > 2 )
    1558                 :            :                 {  // skip higher-order nodes for now
    1559         [ #  # ]:          0 :                     if( !printed_nonconformal_ho_warning )
    1560                 :            :                     {
    1561                 :          0 :                         printed_nonconformal_ho_warning = true;
    1562         [ #  # ]:          0 :                         std::cerr << "Non-conformal higher-order mesh detected in skinner: "
    1563 [ #  # ][ #  # ]:          0 :                                   << "vertex " << ID_FROM_HANDLE( *it ) << " is a corner in "
         [ #  # ][ #  # ]
                 [ #  # ]
    1564 [ #  # ][ #  # ]:          0 :                                   << "some elements and a higher-order node in others" << std::endl;
    1565                 :            :                     }
    1566                 :          0 :                     continue;
    1567                 :            :                 }
    1568                 :            :             }
    1569 [ +  - ][ +  - ]:      35460 :             else if( TYPE_FROM_HANDLE( *i ) == MBQUAD && len > 4 )
         [ +  + ][ +  + ]
                 [ +  + ]
    1570                 :            :             {
    1571                 :         16 :                 len          = 4;
    1572                 :         16 :                 higher_order = true;
    1573         [ -  + ]:         16 :                 if( idx > 3 )
    1574                 :            :                 {  // skip higher-order nodes for now
    1575         [ #  # ]:          0 :                     if( !printed_nonconformal_ho_warning )
    1576                 :            :                     {
    1577                 :          0 :                         printed_nonconformal_ho_warning = true;
    1578         [ #  # ]:          0 :                         std::cerr << "Non-conformal higher-order mesh detected in skinner: "
    1579 [ #  # ][ #  # ]:          0 :                                   << "vertex " << ID_FROM_HANDLE( *it ) << " is a corner in "
         [ #  # ][ #  # ]
                 [ #  # ]
    1580 [ #  # ][ #  # ]:          0 :                                   << "some elements and a higher-order node in others" << std::endl;
    1581                 :            :                     }
    1582                 :          0 :                     continue;
    1583                 :            :                 }
    1584                 :            :             }
    1585                 :            : 
    1586                 :            :             // so it must be a MBPOLYGON
    1587                 :      35472 :             const int prev_idx = ( idx + len - 1 ) % len;  // this should be fine, always, even for padded case
    1588                 :      35472 :             prev               = conn[prev_idx];
    1589                 :      35472 :             next               = conn[( idx + 1 ) % len];
    1590         [ -  + ]:      35472 :             if( next == conn[idx] )  // it must be the padded case, so roll to the beginning
    1591                 :          0 :                 next = conn[0];
    1592                 :            : 
    1593                 :            :             // Insert sides (edges) in our list of candidate skin sides
    1594 [ +  - ][ +  - ]:      35472 :             adj_edges.insert( &prev, 1, *i, prev_idx );
    1595 [ +  - ][ +  - ]:      35472 :             adj_edges.insert( &next, 1, *i, idx );
    1596                 :            :         }
    1597                 :            : 
    1598                 :            :         // If vertex is not on skin, advance to next vertex.
    1599                 :            :         // adj_edges handled checking for duplicates on insertion.
    1600                 :            :         // If every candidate skin edge occurred more than once (was
    1601                 :            :         // not in fact on the skin), then we're done with this vertex.
    1602 [ +  - ][ +  + ]:       6582 :         if( 0 == adj_edges.num_skin() ) continue;
    1603                 :            : 
    1604                 :            :         // If user requested Range of *vertices* on the skin...
    1605         [ +  + ]:       1092 :         if( skin_verts )
    1606                 :            :         {
    1607                 :            :             // Put skin vertex in output list
    1608 [ +  - ][ +  - ]:         56 :             hint = skin_verts->insert( hint, *it );
    1609                 :            : 
    1610                 :            :             // Add mid edge nodes to vertex list
    1611 [ +  - ][ +  + ]:         56 :             if( !corners_only && higher_order )
    1612                 :            :             {
    1613 [ +  - ][ +  - ]:         80 :                 for( AdjSides< 2 >::const_iterator p = adj_edges.begin(); p != adj_edges.end(); ++p )
         [ +  - ][ +  - ]
                 [ +  + ]
    1614                 :            :                 {
    1615 [ +  - ][ +  - ]:         24 :                     if( p->skin() )
                 [ +  + ]
    1616                 :            :                     {
    1617         [ +  - ]:         20 :                         face            = p->adj_elem;
    1618         [ +  - ]:         20 :                         EntityType type = TYPE_FROM_HANDLE( face );
    1619                 :            : 
    1620         [ +  - ]:         20 :                         rval = thisMB->get_connectivity( face, conn, len, false );
    1621         [ -  + ]:         20 :                         if( MB_SUCCESS != rval ) return rval;
    1622 [ +  - ][ -  + ]:         20 :                         if( !CN::HasMidEdgeNodes( type, len ) ) continue;
    1623                 :            : 
    1624 [ +  - ][ +  - ]:         20 :                         EntityHandle ec[2] = { *it, p->handles[0] };
    1625                 :            :                         int side, sense, offset;
    1626         [ +  - ]:         20 :                         CN::SideNumber( type, conn, ec, 2, 1, side, sense, offset );
    1627         [ +  - ]:         20 :                         offset = CN::HONodeIndex( type, len, 1, side );
    1628 [ +  - ][ -  + ]:         20 :                         assert( offset >= 0 && offset < len );
    1629         [ +  - ]:         20 :                         skin_verts->insert( conn[offset] );
    1630                 :            :                     }
    1631                 :            :                 }
    1632                 :            :             }
    1633                 :            :         }
    1634                 :            : 
    1635                 :            :         // If user requested Range of *edges* on the skin...
    1636         [ +  + ]:       1092 :         if( find_edges )
    1637                 :            :         {
    1638                 :            :             // Search list of existing adjacent edges for any that are on the skin
    1639                 :       1072 :             adj.clear();
    1640 [ +  - ][ +  - ]:       1072 :             rval = thisMB->get_adjacencies( &*it, 1, 1, false, adj );
    1641         [ -  + ]:       1072 :             if( MB_SUCCESS != rval ) return rval;
    1642 [ +  - ][ +  - ]:       3584 :             for( i = adj.begin(); i != adj.end(); ++i )
                 [ +  + ]
    1643                 :            :             {
    1644 [ +  - ][ +  - ]:       2512 :                 rval = thisMB->get_connectivity( *i, conn, len, true );
    1645         [ -  + ]:       2512 :                 if( MB_SUCCESS != rval ) return rval;
    1646                 :            : 
    1647                 :            :                 // bool equality expression within find_and_unmark call
    1648                 :            :                 // will be evaluate to the index of *it in the conn array.
    1649                 :            :                 //
    1650                 :            :                 // Note that the order of the terms in the if statement is important.
    1651                 :            :                 // We want to unmark any existing skin edges even if we aren't
    1652                 :            :                 // returning them.  Otherwise we'll end up creating duplicates
    1653                 :            :                 // if create_edges is true and skin_edges is not.
    1654 [ +  - ][ +  - ]:       2512 :                 if( adj_edges.find_and_unmark( conn, ( conn[1] == *it ), face ) && skin_edges )
         [ +  + ][ +  + ]
                 [ +  + ]
    1655                 :            :                 {
    1656 [ +  + ][ +  - ]:       1666 :                     if( reversed_edges && edge_reversed( face, conn ) )
         [ +  + ][ +  + ]
    1657 [ +  - ][ +  - ]:          4 :                         reversed_edges->insert( *i );
    1658                 :            :                     else
    1659 [ +  - ][ +  - ]:       1666 :                         skin_edges->insert( *i );
    1660                 :            :                 }
    1661                 :            :             }
    1662                 :            :         }
    1663                 :            : 
    1664                 :            :         // If the user requested that we create new edges for sides
    1665                 :            :         // on the skin for which there is no existing edge, and there
    1666                 :            :         // are still skin sides for which no corresponding edge was found...
    1667 [ +  + ][ +  - ]:       1092 :         if( create_edges && adj_edges.num_skin() )
         [ +  + ][ +  + ]
    1668                 :            :         {
    1669                 :            :             // Create any skin edges that don't exist
    1670 [ +  - ][ +  - ]:       1831 :             for( AdjSides< 2 >::const_iterator p = adj_edges.begin(); p != adj_edges.end(); ++p )
         [ +  - ][ +  - ]
                 [ +  + ]
    1671                 :            :             {
    1672 [ +  - ][ +  - ]:       1422 :                 if( p->skin() )
                 [ +  + ]
    1673                 :            :                 {
    1674 [ +  - ][ +  - ]:        442 :                     EntityHandle edge, ec[] = { *it, p->handles[0] };
    1675 [ +  - ][ +  - ]:        442 :                     rval = create_side( this_set, p->adj_elem, MBEDGE, ec, edge );
    1676         [ -  + ]:        442 :                     if( MB_SUCCESS != rval ) return rval;
    1677 [ +  + ][ +  - ]:        442 :                     if( skin_edges ) skin_edges->insert( edge );
    1678                 :            :                 }
    1679                 :            :             }
    1680                 :            :         }
    1681                 :            : 
    1682                 :            :     }  // end for each vertex
    1683                 :            : 
    1684                 :         80 :     return MB_SUCCESS;
    1685                 :            : }
    1686                 :            : 
    1687                 :         26 : ErrorCode Skinner::find_skin_vertices_3D( const EntityHandle this_set, Tag tag, const Range& entities,
    1688                 :            :                                           Range* skin_verts, Range* skin_faces, Range* reversed_faces,
    1689                 :            :                                           bool create_faces, bool corners_only )
    1690                 :            : {
    1691                 :            :     // This function iterates over all the vertices contained in the
    1692                 :            :     // input vol elem list.  For each such vertex, it then iterates over
    1693                 :            :     // all of the sides of the vol elements adjacent to the vertex.
    1694                 :            :     // If an adjacent side is the side of only one of the input
    1695                 :            :     // elements, then that side is on the skin.
    1696                 :            :     //
    1697                 :            :     // This algorithm will visit each skin vertex exactly once.  It
    1698                 :            :     // will visit each skin side once for each vertex in the side.
    1699                 :            :     //
    1700                 :            :     // This function expects the caller to have created the passed bit
    1701                 :            :     // tag and set it to one only for the elements in the passed range.  This
    1702                 :            :     // tag is used to do a fast intersection of the elements adjacent to a
    1703                 :            :     // vertex with the elements in the input range (discard any for which the
    1704                 :            :     // tag is not set to one.)
    1705                 :            :     //
    1706                 :            :     // For each vertex, iterate over each adjacent element.  Construct
    1707                 :            :     // lists of the sides of each adjacent element that contain the vertex.
    1708                 :            :     //
    1709                 :            :     // A list of three-vertex sides is kept for all triangular faces,
    1710                 :            :     // included three-vertex faces of type MBPOLYGON.  Putting polygons
    1711                 :            :     // in the same list ensures that we find polyhedron and non-polyhedron
    1712                 :            :     // elements that are adjacent.
    1713                 :            :     //
    1714                 :            :     // A list of four-vertex sides is kept for all quadrilateral faces,
    1715                 :            :     // including four-vertex faces of type MBPOLYGON.
    1716                 :            :     //
    1717                 :            :     // Sides with more than four vertices must have an explicit MBPOLYGON
    1718                 :            :     // element representing them because MBPOLYHEDRON connectivity is a
    1719                 :            :     // list of faces rather than vertices.  So the third list (vertices>=5),
    1720                 :            :     // need contain only the handle of the face rather than the vertex handles.
    1721                 :            : 
    1722                 :            :     ErrorCode rval;
    1723                 :         26 :     std::vector< EntityHandle >::iterator i, j;
    1724         [ +  - ]:         26 :     Range::iterator hint;
    1725 [ +  + ][ +  - ]:         26 :     if( skin_verts ) hint = skin_verts->begin();
    1726 [ +  - ][ +  - ]:         52 :     std::vector< EntityHandle > storage, storage2;  // temp storage for conn lists
    1727                 :            :     const EntityHandle *conn, *conn2;
    1728                 :            :     int len, len2;
    1729 [ +  + ][ +  + ]:         26 :     bool find_faces = skin_faces || create_faces;
    1730                 :            :     int clen, side, sense, offset, indices[9];
    1731                 :            :     EntityType face_type;
    1732                 :            :     EntityHandle elem;
    1733                 :         26 :     bool printed_nonconformal_ho_warning = false;
    1734                 :            : 
    1735 [ +  - ][ -  + ]:         26 :     if( !entities.all_of_dimension( 3 ) ) return MB_TYPE_OUT_OF_RANGE;
    1736                 :            : 
    1737                 :            :     // get all the vertices
    1738         [ +  - ]:         52 :     Range verts;
    1739         [ +  - ]:         26 :     rval = thisMB->get_connectivity( entities, verts, true );
    1740         [ -  + ]:         26 :     if( MB_SUCCESS != rval ) return rval;
    1741                 :            :     // if there are polyhedra in the input list, need to make another
    1742                 :            :     // call to get vertices from faces
    1743 [ +  - ][ +  + ]:         26 :     if( !verts.all_of_dimension( 0 ) )
    1744                 :            :     {
    1745         [ +  - ]:          3 :         Range::iterator it = verts.upper_bound( MBVERTEX );
    1746         [ +  - ]:          3 :         Range pfaces;
    1747 [ +  - ][ +  - ]:          3 :         pfaces.merge( it, verts.end() );
    1748 [ +  - ][ +  - ]:          3 :         verts.erase( it, verts.end() );
    1749         [ +  - ]:          3 :         rval = thisMB->get_connectivity( pfaces, verts, true );
    1750         [ -  + ]:          3 :         if( MB_SUCCESS != rval ) return rval;
    1751 [ +  - ][ -  + ]:          3 :         assert( verts.all_of_dimension( 0 ) );
                 [ +  - ]
    1752                 :            :     }
    1753                 :            : 
    1754         [ +  - ]:         52 :     AdjSides< 4 > adj_quads;  // 4-node sides adjacent to a vertex
    1755         [ +  - ]:         52 :     AdjSides< 3 > adj_tris;   // 3-node sides adjacent to a vertex
    1756         [ +  - ]:         52 :     AdjSides< 2 > adj_poly;   // n-node sides (n>5) adjacent to vertex
    1757                 :            :                               // (must have an explicit polygon, so store
    1758                 :            :                               // polygon handle rather than vertices.)
    1759         [ +  - ]:         52 :     std::vector< char > tag_vals;
    1760         [ +  - ]:         52 :     std::vector< EntityHandle > adj;
    1761 [ +  - ][ +  - ]:       4936 :     for( Range::const_iterator it = verts.begin(); it != verts.end(); ++it )
         [ +  - ][ +  - ]
                 [ +  + ]
    1762                 :            :     {
    1763                 :       4910 :         bool higher_order = false;
    1764                 :            : 
    1765                 :            :         // get all adjacent elements
    1766                 :       4910 :         adj.clear();
    1767 [ +  - ][ +  - ]:       4910 :         rval = thisMB->get_adjacencies( &*it, 1, 3, false, adj );
    1768         [ -  + ]:       4910 :         if( MB_SUCCESS != rval ) return rval;
    1769         [ -  + ]:       4910 :         if( adj.empty() ) continue;
    1770                 :            : 
    1771                 :            :         // remove those not tagged (intersect with input range)
    1772                 :       4910 :         i = j = adj.begin();
    1773         [ +  - ]:       4910 :         tag_vals.resize( adj.size() );
    1774 [ +  - ][ +  - ]:       4910 :         rval = thisMB->tag_get_data( tag, &adj[0], adj.size(), &tag_vals[0] );
                 [ +  - ]
    1775         [ -  + ]:       4910 :         if( MB_SUCCESS != rval ) return rval;
    1776 [ +  - ][ +  - ]:      29678 :         for( ; i != adj.end(); ++i )
                 [ +  + ]
    1777 [ +  - ][ +  - ]:      24768 :             if( tag_vals[i - adj.begin()] ) *( j++ ) = *i;
         [ +  + ][ +  - ]
         [ +  - ][ +  - ]
    1778         [ +  - ]:       4910 :         adj.erase( j, adj.end() );
    1779                 :            : 
    1780                 :            :         // Build lists of sides of 3D element adjacent to the current vertex
    1781         [ +  - ]:       4910 :         adj_quads.clear();  // store three other vertices for each adjacent quad face
    1782         [ +  - ]:       4910 :         adj_tris.clear();   // store two other vertices for each adjacent tri face
    1783         [ +  - ]:       4910 :         adj_poly.clear();   // store handle of each adjacent polygonal face
    1784                 :            :         int idx;
    1785 [ +  - ][ +  - ]:      29638 :         for( i = adj.begin(); i != adj.end(); ++i )
                 [ +  + ]
    1786                 :            :         {
    1787 [ +  - ][ +  - ]:      24728 :             const EntityType type = TYPE_FROM_HANDLE( *i );
    1788                 :            : 
    1789                 :            :             // Special case for POLYHEDRA
    1790         [ +  + ]:      24728 :             if( type == MBPOLYHEDRON )
    1791                 :            :             {
    1792 [ +  - ][ +  - ]:        288 :                 rval = thisMB->get_connectivity( *i, conn, len );
    1793         [ -  + ]:        288 :                 if( MB_SUCCESS != rval ) return rval;
    1794         [ +  + ]:       2592 :                 for( int k = 0; k < len; ++k )
    1795                 :            :                 {
    1796         [ +  - ]:       2304 :                     rval = thisMB->get_connectivity( conn[k], conn2, len2, true, &storage2 );
    1797         [ -  + ]:       2304 :                     if( MB_SUCCESS != rval ) return rval;
    1798 [ +  - ][ +  - ]:       2304 :                     idx = std::find( conn2, conn2 + len2, *it ) - conn2;
    1799         [ +  + ]:       2304 :                     if( idx == len2 )  // vertex not in this face
    1800                 :       1440 :                         continue;
    1801                 :            : 
    1802                 :            :                     // Treat 3- and 4-vertex faces specially, so that
    1803                 :            :                     // if the mesh contains both elements and polyhedra,
    1804                 :            :                     // we don't miss one type adjacent to the other.
    1805      [ -  +  + ]:        864 :                     switch( len2 )
    1806                 :            :                     {
    1807                 :            :                         case 3:
    1808 [ #  # ][ #  # ]:          0 :                             adj_tris.insert( conn2, idx, *i, k );
    1809                 :          0 :                             break;
    1810                 :            :                         case 4:
    1811 [ +  - ][ +  - ]:        576 :                             adj_quads.insert( conn2, idx, *i, k );
    1812                 :        576 :                             break;
    1813                 :            :                         default:
    1814 [ +  - ][ +  - ]:        288 :                             adj_poly.insert( conn + k, 1, *i, k );
    1815                 :        288 :                             break;
    1816                 :            :                     }
    1817                 :            :                 }
    1818                 :            :             }
    1819                 :            :             else
    1820                 :            :             {
    1821 [ +  - ][ +  - ]:      24440 :                 rval = thisMB->get_connectivity( *i, conn, len, false, &storage );
    1822         [ -  + ]:      24440 :                 if( MB_SUCCESS != rval ) return rval;
    1823                 :            : 
    1824 [ +  - ][ +  - ]:      24440 :                 idx = std::find( conn, conn + len, *it ) - conn;
    1825         [ -  + ]:      24440 :                 assert( idx != len );
    1826                 :            : 
    1827 [ +  - ][ +  + ]:      24440 :                 if( len > CN::VerticesPerEntity( type ) )
    1828                 :            :                 {
    1829                 :         64 :                     higher_order = true;
    1830                 :            :                     // skip higher-order nodes for now
    1831 [ +  - ][ -  + ]:         64 :                     if( idx >= CN::VerticesPerEntity( type ) )
    1832                 :            :                     {
    1833         [ #  # ]:          0 :                         if( !printed_nonconformal_ho_warning )
    1834                 :            :                         {
    1835                 :          0 :                             printed_nonconformal_ho_warning = true;
    1836         [ #  # ]:          0 :                             std::cerr << "Non-conformal higher-order mesh detected in skinner: "
    1837 [ #  # ][ #  # ]:          0 :                                       << "vertex " << ID_FROM_HANDLE( *it ) << " is a corner in "
         [ #  # ][ #  # ]
                 [ #  # ]
    1838 [ #  # ][ #  # ]:          0 :                                       << "some elements and a higher-order node in others" << std::endl;
    1839                 :            :                         }
    1840                 :          0 :                         continue;
    1841                 :            :                     }
    1842                 :            :                 }
    1843                 :            : 
    1844                 :            :                 // For each side of the element...
    1845         [ +  - ]:      24440 :                 const int num_faces = CN::NumSubEntities( type, 2 );
    1846         [ +  + ]:     170976 :                 for( int f = 0; f < num_faces; ++f )
    1847                 :            :                 {
    1848                 :            :                     int num_vtx;
    1849         [ +  - ]:     146536 :                     const short* face_indices = CN::SubEntityVertexIndices( type, 2, f, face_type, num_vtx );
    1850         [ +  - ]:     146536 :                     const short face_idx = std::find( face_indices, face_indices + num_vtx, (short)idx ) - face_indices;
    1851                 :            :                     // skip sides that do not contain vertex from outer loop
    1852         [ +  + ]:     146536 :                     if( face_idx == num_vtx ) continue;  // current vertex not in this face
    1853                 :            : 
    1854         [ -  + ]:      73320 :                     assert( num_vtx <= 4 );  // polyhedra handled above
    1855      [ +  +  - ]:      73320 :                     switch( face_type )
    1856                 :            :                     {
    1857                 :            :                         case MBTRI:
    1858 [ +  - ][ +  - ]:        120 :                             adj_tris.insert( conn, face_idx, *i, f, face_indices );
    1859                 :        120 :                             break;
    1860                 :            :                         case MBQUAD:
    1861 [ +  - ][ +  - ]:      73200 :                             adj_quads.insert( conn, face_idx, *i, f, face_indices );
    1862                 :      73200 :                             break;
    1863                 :            :                         default:
    1864                 :      73320 :                             return MB_TYPE_OUT_OF_RANGE;
    1865                 :            :                     }
    1866                 :            :                 }
    1867                 :            :             }
    1868                 :            :         }  // end for (adj[3])
    1869                 :            : 
    1870                 :            :         // If vertex is not on skin, advance to next vertex
    1871 [ +  - ][ +  - ]:       4910 :         if( 0 == ( adj_tris.num_skin() + adj_quads.num_skin() + adj_poly.num_skin() ) ) continue;
         [ +  - ][ +  + ]
    1872                 :            : 
    1873                 :            :         // If user requested that skin *vertices* be passed back...
    1874         [ +  + ]:       3002 :         if( skin_verts )
    1875                 :            :         {
    1876                 :            :             // Put skin vertex in output list
    1877 [ +  - ][ +  - ]:       1814 :             hint = skin_verts->insert( hint, *it );
    1878                 :            : 
    1879                 :            :             // Add mid-edge and mid-face nodes to vertex list
    1880 [ +  - ][ +  + ]:       1814 :             if( !corners_only && higher_order )
    1881                 :            :             {
    1882 [ +  - ][ #  # ]:         24 :                 for( AdjSides< 3 >::const_iterator t = adj_tris.begin(); t != adj_tris.end(); ++t )
         [ +  - ][ +  - ]
                 [ -  + ]
    1883                 :            :                 {
    1884 [ #  # ][ #  # ]:          0 :                     if( t->skin() )
                 [ #  # ]
    1885                 :            :                     {
    1886         [ #  # ]:          0 :                         elem            = t->adj_elem;
    1887         [ #  # ]:          0 :                         EntityType type = TYPE_FROM_HANDLE( elem );
    1888                 :            : 
    1889         [ #  # ]:          0 :                         rval = thisMB->get_connectivity( elem, conn, len, false );
    1890         [ #  # ]:          0 :                         if( MB_SUCCESS != rval ) return rval;
    1891 [ #  # ][ #  # ]:          0 :                         if( !CN::HasMidNodes( type, len ) ) continue;
    1892                 :            : 
    1893 [ #  # ][ #  # ]:          0 :                         EntityHandle ec[3] = { *it, t->handles[0], t->handles[1] };
                 [ #  # ]
    1894         [ #  # ]:          0 :                         CN::SideNumber( type, conn, ec, 3, 2, side, sense, offset );
    1895         [ #  # ]:          0 :                         CN::SubEntityNodeIndices( type, len, 2, side, face_type, clen, indices );
    1896         [ #  # ]:          0 :                         assert( MBTRI == face_type );
    1897         [ #  # ]:          0 :                         for( int k = 3; k < clen; ++k )
    1898         [ #  # ]:          0 :                             skin_verts->insert( conn[indices[k]] );
    1899                 :            :                     }
    1900                 :            :                 }
    1901 [ +  - ][ +  - ]:       1902 :                 for( AdjSides< 4 >::const_iterator q = adj_quads.begin(); q != adj_quads.end(); ++q )
         [ +  - ][ +  - ]
                 [ +  + ]
    1902                 :            :                 {
    1903 [ +  - ][ +  - ]:         88 :                     if( q->skin() )
                 [ +  + ]
    1904                 :            :                     {
    1905         [ +  - ]:         80 :                         elem            = q->adj_elem;
    1906         [ +  - ]:         80 :                         EntityType type = TYPE_FROM_HANDLE( elem );
    1907                 :            : 
    1908         [ +  - ]:         80 :                         rval = thisMB->get_connectivity( elem, conn, len, false );
    1909         [ -  + ]:         80 :                         if( MB_SUCCESS != rval ) return rval;
    1910 [ +  - ][ -  + ]:         80 :                         if( !CN::HasMidNodes( type, len ) ) continue;
    1911                 :            : 
    1912 [ +  - ][ +  - ]:         80 :                         EntityHandle ec[4] = { *it, q->handles[0], q->handles[1], q->handles[2] };
         [ +  - ][ +  - ]
    1913         [ +  - ]:         80 :                         CN::SideNumber( type, conn, ec, 4, 2, side, sense, offset );
    1914         [ +  - ]:         80 :                         CN::SubEntityNodeIndices( type, len, 2, side, face_type, clen, indices );
    1915         [ -  + ]:         80 :                         assert( MBQUAD == face_type );
    1916         [ +  + ]:        480 :                         for( int k = 4; k < clen; ++k )
    1917         [ +  - ]:        400 :                             skin_verts->insert( conn[indices[k]] );
    1918                 :            :                     }
    1919                 :            :                 }
    1920                 :            :             }
    1921                 :            :         }
    1922                 :            : 
    1923                 :            :         // If user requested that we pass back the list of 2D elements
    1924                 :            :         // representing the skin of the mesh...
    1925         [ +  + ]:       3002 :         if( find_faces )
    1926                 :            :         {
    1927                 :            :             // Search list of adjacent faces for any that are on the skin
    1928                 :       2078 :             adj.clear();
    1929 [ +  - ][ +  - ]:       2078 :             rval = thisMB->get_adjacencies( &*it, 1, 2, false, adj );
    1930         [ -  + ]:       2078 :             if( MB_SUCCESS != rval ) return rval;
    1931                 :            : 
    1932 [ +  - ][ +  - ]:       9232 :             for( i = adj.begin(); i != adj.end(); ++i )
                 [ +  + ]
    1933                 :            :             {
    1934 [ +  - ][ +  - ]:       7154 :                 rval = thisMB->get_connectivity( *i, conn, len, true );
    1935         [ -  + ]:       7154 :                 if( MB_SUCCESS != rval ) return rval;
    1936 [ +  - ][ +  - ]:       7154 :                 const int idx2 = std::find( conn, conn + len, *it ) - conn;
    1937         [ -  + ]:       7154 :                 if( idx2 >= len )
    1938                 :            :                 {
    1939         [ #  # ]:          0 :                     assert( printed_nonconformal_ho_warning );
    1940                 :          0 :                     continue;
    1941                 :            :                 }
    1942                 :            : 
    1943                 :            :                 // Note that the order of the terms in the if statements below
    1944                 :            :                 // is important.  We want to unmark any existing skin faces even
    1945                 :            :                 // if we aren't returning them.  Otherwise we'll end up creating
    1946                 :            :                 // duplicates if create_faces is true.
    1947         [ +  + ]:       7154 :                 if( 3 == len )
    1948                 :            :                 {
    1949 [ +  - ][ +  - ]:         50 :                     if( adj_tris.find_and_unmark( conn, idx2, elem ) && skin_faces )
         [ +  - ][ +  - ]
    1950                 :            :                     {
    1951 [ +  + ][ +  - ]:         50 :                         if( reversed_faces && face_reversed( elem, conn, MBTRI ) )
         [ +  + ][ +  + ]
    1952 [ +  - ][ +  - ]:          6 :                             reversed_faces->insert( *i );
    1953                 :            :                         else
    1954 [ +  - ][ +  - ]:         50 :                             skin_faces->insert( *i );
    1955                 :            :                     }
    1956                 :            :                 }
    1957         [ +  + ]:       7104 :                 else if( 4 == len )
    1958                 :            :                 {
    1959 [ +  - ][ +  + ]:       6976 :                     if( adj_quads.find_and_unmark( conn, idx2, elem ) && skin_faces )
         [ +  + ][ +  + ]
    1960                 :            :                     {
    1961 [ +  + ][ +  - ]:       3822 :                         if( reversed_faces && face_reversed( elem, conn, MBQUAD ) )
         [ -  + ][ -  + ]
    1962 [ #  # ][ #  # ]:          0 :                             reversed_faces->insert( *i );
    1963                 :            :                         else
    1964 [ +  - ][ +  - ]:       3822 :                             skin_faces->insert( *i );
    1965                 :            :                     }
    1966                 :            :                 }
    1967                 :            :                 else
    1968                 :            :                 {
    1969 [ +  - ][ +  - ]:        128 :                     if( adj_poly.find_and_unmark( &*i, 1, elem ) && skin_faces ) skin_faces->insert( *i );
         [ +  + ][ +  - ]
         [ +  + ][ +  - ]
                 [ +  - ]
    1970                 :            :                 }
    1971                 :            :             }
    1972                 :            :         }
    1973                 :            : 
    1974                 :            :         // If user does not want use to create new faces representing
    1975                 :            :         // sides for which there is currently no explicit element,
    1976                 :            :         // skip the remaining code and advance the outer loop to the
    1977                 :            :         // next vertex.
    1978         [ +  + ]:       3002 :         if( !create_faces ) continue;
    1979                 :            : 
    1980                 :            :         // Polyhedra always have explicitly defined faces, so
    1981                 :            :         // there is no way we could need to create such a face.
    1982 [ +  - ][ -  + ]:       2034 :         assert( 0 == adj_poly.num_skin() );
    1983                 :            : 
    1984                 :            :         // Create any skin tris that don't exist
    1985 [ +  - ][ +  + ]:       2034 :         if( adj_tris.num_skin() )
    1986                 :            :         {
    1987 [ +  - ][ +  - ]:         60 :             for( AdjSides< 3 >::const_iterator t = adj_tris.begin(); t != adj_tris.end(); ++t )
         [ +  - ][ +  - ]
                 [ +  + ]
    1988                 :            :             {
    1989 [ +  - ][ +  - ]:         42 :                 if( t->skin() )
                 [ +  + ]
    1990                 :            :                 {
    1991 [ +  - ][ +  - ]:         22 :                     EntityHandle tri, c[3] = { *it, t->handles[0], t->handles[1] };
                 [ +  - ]
    1992 [ +  - ][ +  - ]:         22 :                     rval = create_side( this_set, t->adj_elem, MBTRI, c, tri );
    1993         [ -  + ]:         22 :                     if( MB_SUCCESS != rval ) return rval;
    1994 [ +  - ][ +  - ]:         22 :                     if( skin_faces ) skin_faces->insert( tri );
    1995                 :            :                 }
    1996                 :            :             }
    1997                 :            :         }
    1998                 :            : 
    1999                 :            :         // Create any skin quads that don't exist
    2000 [ +  - ][ +  + ]:       2034 :         if( adj_quads.num_skin() )
    2001                 :            :         {
    2002 [ +  - ][ +  - ]:       8128 :             for( AdjSides< 4 >::const_iterator q = adj_quads.begin(); q != adj_quads.end(); ++q )
         [ +  - ][ +  - ]
                 [ +  + ]
    2003                 :            :             {
    2004 [ +  - ][ +  - ]:       7144 :                 if( q->skin() )
                 [ +  + ]
    2005                 :            :                 {
    2006 [ +  - ][ +  - ]:       1088 :                     EntityHandle quad, c[4] = { *it, q->handles[0], q->handles[1], q->handles[2] };
         [ +  - ][ +  - ]
    2007 [ +  - ][ +  - ]:       1088 :                     rval = create_side( this_set, q->adj_elem, MBQUAD, c, quad );
    2008         [ -  + ]:       1088 :                     if( MB_SUCCESS != rval ) return rval;
    2009 [ +  + ][ +  - ]:       1088 :                     if( skin_faces ) skin_faces->insert( quad );
    2010                 :            :                 }
    2011                 :            :             }
    2012                 :            :         }
    2013                 :            :     }  // end for each vertex
    2014                 :            : 
    2015                 :         52 :     return MB_SUCCESS;
    2016                 :            : }
    2017                 :            : 
    2018 [ +  - ][ +  - ]:        228 : }  // namespace moab

Generated by: LCOV version 1.11