LCOV - code coverage report
Current view: top level - src - AdaptiveKDTree.cpp (source / functions) Hit Total Coverage
Test: coverage_sk.info Lines: 708 1053 67.2 %
Date: 2020-12-16 07:07:30 Functions: 39 59 66.1 %
Branches: 973 2588 37.6 %

           Branch data     Line data    Source code
       1                 :            : /**\file AdaptiveKDTree.cpp
       2                 :            :  */
       3                 :            : 
       4                 :            : #include "moab/AdaptiveKDTree.hpp"
       5                 :            : #include "moab/Interface.hpp"
       6                 :            : #include "moab/GeomUtil.hpp"
       7                 :            : #include "moab/Range.hpp"
       8                 :            : #include "moab/ElemEvaluator.hpp"
       9                 :            : #include "moab/CpuTimer.hpp"
      10                 :            : #include "Internals.hpp"
      11                 :            : #include "moab/Util.hpp"
      12                 :            : #include <math.h>
      13                 :            : 
      14                 :            : #include <assert.h>
      15                 :            : #include <algorithm>
      16                 :            : #include <limits>
      17                 :            : #include <iostream>
      18                 :            : #include <cstdio>
      19                 :            : 
      20                 :            : namespace moab
      21                 :            : {
      22                 :            : 
      23                 :            : const char* AdaptiveKDTree::treeName = "AKDTree";
      24                 :            : 
      25                 :            : #define MB_AD_KD_TREE_DEFAULT_TAG_NAME
      26                 :            : 
      27                 :            : // If defined, use single tag for both axis and location of split plane
      28                 :            : #define MB_AD_KD_TREE_USE_SINGLE_TAG
      29                 :            : 
      30                 :            : // No effect if MB_AD_KD_TREE_USE_SINGLE_TAG is not defined.
      31                 :            : // If defined, store plane axis as double so tag has consistent
      32                 :            : // type (doubles for both location and axis).  If not defined,
      33                 :            : // store struct Plane as opaque.
      34                 :            : #define MB_AD_KD_TREE_USE_TWO_DOUBLE_TAG
      35                 :            : 
      36                 :         23 : AdaptiveKDTree::AdaptiveKDTree( Interface* iface )
      37                 :            :     : Tree( iface ), planeTag( 0 ), axisTag( 0 ), splitsPerDir( 3 ), planeSet( SUBDIVISION_SNAP ), spherical( false ),
      38                 :         23 :       radius( 1.0 )
      39                 :            : {
      40         [ +  - ]:         23 :     boxTagName = treeName;
      41                 :            : 
      42         [ +  - ]:         23 :     ErrorCode rval = init();
      43         [ -  + ]:         23 :     if( MB_SUCCESS != rval ) throw rval;
      44                 :         23 : }
      45                 :            : 
      46                 :          0 : AdaptiveKDTree::AdaptiveKDTree( Interface* iface, const Range& entities, EntityHandle* tree_root_set,
      47                 :            :                                 FileOptions* opts )
      48                 :            :     : Tree( iface ), planeTag( 0 ), axisTag( 0 ), splitsPerDir( 3 ), planeSet( SUBDIVISION_SNAP ), spherical( false ),
      49                 :          0 :       radius( 1.0 )
      50                 :            : {
      51         [ #  # ]:          0 :     boxTagName = treeName;
      52                 :            : 
      53                 :            :     ErrorCode rval;
      54         [ #  # ]:          0 :     if( opts )
      55                 :            :     {
      56         [ #  # ]:          0 :         rval = parse_options( *opts );
      57         [ #  # ]:          0 :         if( MB_SUCCESS != rval ) throw rval;
      58                 :            :     }
      59                 :            : 
      60         [ #  # ]:          0 :     rval = init();
      61         [ #  # ]:          0 :     if( MB_SUCCESS != rval ) throw rval;
      62                 :            : 
      63         [ #  # ]:          0 :     rval = build_tree( entities, tree_root_set, opts );
      64         [ #  # ]:          0 :     if( MB_SUCCESS != rval ) throw rval;
      65                 :          0 : }
      66                 :            : 
      67         [ +  - ]:         46 : AdaptiveKDTree::~AdaptiveKDTree()
      68                 :            : {
      69         [ -  + ]:         23 :     if( !cleanUp ) return;
      70                 :            : 
      71         [ +  + ]:         23 :     if( myRoot )
      72                 :            :     {
      73                 :         21 :         reset_tree();
      74                 :         23 :         myRoot = 0;
      75                 :            :     }
      76         [ -  + ]:         23 : }
      77                 :            : 
      78                 :         16 : ErrorCode AdaptiveKDTree::build_tree( const Range& entities, EntityHandle* tree_root_set, FileOptions* options )
      79                 :            : {
      80                 :            :     ErrorCode rval;
      81         [ +  - ]:         16 :     CpuTimer cp;
      82                 :            : 
      83         [ +  + ]:         16 :     if( options )
      84                 :            :     {
      85         [ +  - ]:          9 :         rval = parse_options( *options );
      86         [ -  + ]:          9 :         if( MB_SUCCESS != rval ) return rval;
      87                 :            : 
      88 [ +  - ][ -  + ]:          9 :         if( !options->all_seen() ) return MB_FAILURE;
      89                 :            :     }
      90                 :            : 
      91                 :            :     // calculate bounding box of elements
      92         [ +  - ]:         16 :     BoundBox box;
      93 [ +  - ][ +  - ]:         16 :     rval = box.update( *moab(), entities, spherical, radius );
      94         [ -  + ]:         16 :     if( MB_SUCCESS != rval ) return rval;
      95                 :            : 
      96                 :            :     // create tree root
      97                 :            :     EntityHandle tmp_root;
      98         [ +  + ]:         16 :     if( !tree_root_set ) tree_root_set = &tmp_root;
      99 [ +  - ][ +  - ]:         16 :     rval = create_root( box.bMin.array(), box.bMax.array(), *tree_root_set );
                 [ +  - ]
     100         [ -  + ]:         16 :     if( MB_SUCCESS != rval ) return rval;
     101 [ +  - ][ +  - ]:         16 :     rval = moab()->add_entities( *tree_root_set, entities );
     102         [ -  + ]:         16 :     if( MB_SUCCESS != rval ) return rval;
     103                 :            : 
     104         [ +  - ]:         32 :     AdaptiveKDTreeIter iter;
     105 [ +  - ][ +  - ]:         16 :     iter.initialize( this, *tree_root_set, box.bMin.array(), box.bMax.array(), AdaptiveKDTreeIter::LEFT );
                 [ +  - ]
     106                 :            : 
     107         [ +  - ]:         32 :     std::vector< double > tmp_data;
     108         [ +  - ]:         32 :     std::vector< EntityHandle > tmp_data2;
     109                 :            :     for( ;; )
     110                 :            :     {
     111                 :            : 
     112                 :            :         int pcount;
     113 [ +  - ][ +  - ]:       6674 :         rval = moab()->get_number_entities_by_handle( iter.handle(), pcount );
                 [ +  - ]
     114         [ -  + ]:       6674 :         if( MB_SUCCESS != rval ) break;
     115                 :            : 
     116                 :       6674 :         const size_t p_count = pcount;
     117 [ +  - ][ +  - ]:      13348 :         Range best_left, best_right, best_both;
                 [ +  - ]
              [ +  +  - ]
              [ +  -  + ]
     118                 :       6674 :         Plane best_plane = { HUGE_VAL, -1 };
     119 [ +  + ][ +  - ]:       6674 :         if( (int)p_count > maxPerLeaf && (int)iter.depth() < maxDepth )
         [ +  + ][ +  + ]
     120                 :            :         {
     121   [ +  +  -  -  :       4872 :             switch( planeSet )
                      - ]
     122                 :            :             {
     123                 :            :                 case AdaptiveKDTree::SUBDIVISION:
     124                 :            :                     rval = best_subdivision_plane( splitsPerDir, iter, best_left, best_right, best_both, best_plane,
     125         [ +  - ]:       2202 :                                                    minWidth );
     126                 :       2202 :                     break;
     127                 :            :                 case AdaptiveKDTree::SUBDIVISION_SNAP:
     128                 :            :                     rval = best_subdivision_snap_plane( splitsPerDir, iter, best_left, best_right, best_both,
     129         [ +  - ]:       2670 :                                                         best_plane, tmp_data, minWidth );
     130                 :       2670 :                     break;
     131                 :            :                 case AdaptiveKDTree::VERTEX_MEDIAN:
     132                 :            :                     rval = best_vertex_median_plane( splitsPerDir, iter, best_left, best_right, best_both, best_plane,
     133         [ #  # ]:          0 :                                                      tmp_data, minWidth );
     134                 :          0 :                     break;
     135                 :            :                 case AdaptiveKDTree::VERTEX_SAMPLE:
     136                 :            :                     rval = best_vertex_sample_plane( splitsPerDir, iter, best_left, best_right, best_both, best_plane,
     137         [ #  # ]:          0 :                                                      tmp_data, tmp_data2, minWidth );
     138                 :          0 :                     break;
     139                 :            :                 default:
     140                 :          0 :                     rval = MB_FAILURE;
     141                 :            :             }
     142                 :            : 
     143         [ -  + ]:       4872 :             if( MB_SUCCESS != rval ) return rval;
     144                 :            :         }
     145                 :            : 
     146         [ +  + ]:       6674 :         if( best_plane.norm >= 0 )
     147                 :            :         {
     148         [ +  - ]:       3329 :             best_left.merge( best_both );
     149         [ +  - ]:       3329 :             best_right.merge( best_both );
     150         [ +  - ]:       3329 :             rval = split_leaf( iter, best_plane, best_left, best_right );
     151         [ -  + ]:       3329 :             if( MB_SUCCESS != rval ) return rval;
     152                 :            :         }
     153                 :            :         else
     154                 :            :         {
     155         [ +  - ]:       3345 :             rval = iter.step();
     156         [ +  + ]:       3345 :             if( MB_ENTITY_NOT_FOUND == rval )
     157                 :            :             {
     158         [ +  - ]:         16 :                 rval               = treeStats.compute_stats( mbImpl, myRoot );
     159         [ +  - ]:         16 :                 treeStats.initTime = cp.time_elapsed();
     160                 :         16 :                 return rval;  // at end
     161                 :            :             }
     162         [ -  + ]:       3329 :             else if( MB_SUCCESS != rval )
     163      [ +  +  - ]:       6674 :                 break;
     164                 :            :         }
     165                 :       6658 :     }
     166                 :            : 
     167         [ #  # ]:         16 :     reset_tree();
     168                 :            : 
     169         [ #  # ]:          0 :     treeStats.reset();
     170                 :            : 
     171                 :         16 :     return rval;
     172                 :            : }
     173                 :            : 
     174                 :         10 : ErrorCode AdaptiveKDTree::parse_options( FileOptions& opts )
     175                 :            : {
     176         [ +  - ]:         10 :     ErrorCode rval = parse_common_options( opts );
     177         [ -  + ]:         10 :     if( MB_SUCCESS != rval ) return rval;
     178                 :            : 
     179                 :            :     //  SPLITS_PER_DIR: number of candidate splits considered per direction; default = 3
     180                 :            :     int tmp_int;
     181         [ +  - ]:         10 :     rval = opts.get_int_option( "SPLITS_PER_DIR", tmp_int );
     182         [ +  + ]:         10 :     if( MB_SUCCESS == rval ) splitsPerDir = tmp_int;
     183                 :            : 
     184                 :            :     //  PLANE_SET: method used to decide split planes; see CandidatePlaneSet enum (below)
     185                 :            :     //           for possible values; default = 1 (SUBDIVISION_SNAP)
     186         [ +  - ]:         10 :     rval = opts.get_int_option( "PLANE_SET", tmp_int );
     187 [ +  + ][ +  - ]:         10 :     if( MB_SUCCESS == rval && ( tmp_int < SUBDIVISION || tmp_int > VERTEX_SAMPLE ) )
                 [ -  + ]
     188                 :          0 :         return MB_FAILURE;
     189         [ +  + ]:         10 :     else if( MB_ENTITY_NOT_FOUND == rval )
     190                 :          1 :         planeSet = SUBDIVISION;
     191                 :            :     else
     192                 :          9 :         planeSet = ( CandidatePlaneSet )( tmp_int );
     193                 :            : 
     194         [ +  - ]:         10 :     rval = opts.get_toggle_option( "SPHERICAL", false, spherical );
     195         [ -  + ]:         10 :     if( MB_SUCCESS != rval ) spherical = false;
     196                 :            : 
     197                 :         10 :     double tmp = 1.0;
     198         [ +  - ]:         10 :     rval       = opts.get_real_option( "RADIUS", tmp );
     199         [ +  - ]:         10 :     if( MB_SUCCESS != rval )
     200                 :         10 :         radius = 1.0;
     201                 :            :     else
     202                 :          0 :         radius = tmp;
     203                 :            : 
     204                 :         10 :     return MB_SUCCESS;
     205                 :            : }
     206                 :            : 
     207                 :         23 : ErrorCode AdaptiveKDTree::make_tag( Interface* iface, std::string name, TagType storage, DataType type, int count,
     208                 :            :                                     void* default_val, Tag& tag_handle, std::vector< Tag >& created_tags )
     209                 :            : {
     210                 :            :     ErrorCode rval =
     211                 :         23 :         iface->tag_get_handle( name.c_str(), count, type, tag_handle, MB_TAG_CREAT | storage, default_val );
     212                 :            : 
     213         [ +  - ]:         23 :     if( MB_SUCCESS == rval )
     214                 :            :     {
     215 [ +  - ][ +  - ]:         23 :         if( std::find( created_tags.begin(), created_tags.end(), tag_handle ) == created_tags.end() )
                 [ +  - ]
     216                 :         23 :             created_tags.push_back( tag_handle );
     217                 :            :     }
     218                 :            :     else
     219                 :            :     {
     220         [ #  # ]:          0 :         while( !created_tags.empty() )
     221                 :            :         {
     222                 :          0 :             iface->tag_delete( created_tags.back() );
     223                 :          0 :             created_tags.pop_back();
     224                 :            :         }
     225                 :            : 
     226                 :          0 :         planeTag = axisTag = (Tag)-1;
     227                 :            :     }
     228                 :            : 
     229                 :         23 :     return rval;
     230                 :            : }
     231                 :            : 
     232                 :         23 : ErrorCode AdaptiveKDTree::init()
     233                 :            : {
     234         [ +  - ]:         23 :     std::vector< Tag > ctl;
     235                 :            : 
     236                 :            : #ifndef MB_AD_KD_TREE_USE_SINGLE_TAG
     237                 :            :     // create two tags, one for axis direction and one for axis coordinate
     238                 :            :     std::string n1( treeName ), n2( treeName );
     239                 :            :     n1 += "_coord";
     240                 :            :     n2 += "_norm";
     241                 :            :     ErrorCode rval = make_tag( moab(), n1, MB_TAG_DENSE, MB_TYPE_DOUBLE, 1, 0, planeTag, ctl );
     242                 :            :     if( MB_SUCCESS != rval ) return rval;
     243                 :            :     rval = make_tag( moab(), n2, MB_TAG_DENSE, MB_TYPE_INT, 1, 0, axisTag, ctl );
     244                 :            :     if( MB_SUCCESS != rval ) return rval;
     245                 :            : 
     246                 :            : #elif defined( MB_AD_KD_TREE_USE_TWO_DOUBLE_TAG )
     247                 :            :     // create tag to hold two doubles, one for location and one for axis
     248 [ +  - ][ +  - ]:         46 :     std::string double_tag_name = std::string( treeName ) + std::string( "_coord_norm" );
                 [ +  - ]
     249 [ +  - ][ +  - ]:         23 :     ErrorCode rval = make_tag( moab(), double_tag_name, MB_TAG_DENSE, MB_TYPE_DOUBLE, 2, 0, planeTag, ctl );
                 [ +  - ]
     250         [ -  + ]:         23 :     if( MB_SUCCESS != rval ) return rval;
     251                 :            : #else
     252                 :            :     // create opaque tag to hold struct Plane
     253                 :            :     ErrorCode rval = make_tag( moab(), tagname, MB_TAG_DENSE, MB_TYPE_OPAQUE, sizeof( Plane ), 0, planeTag, ctl );
     254                 :            :     if( MB_SUCCESS != rval ) return rval;
     255                 :            : 
     256                 :            : #ifdef MOAB_HAVE_HDF5
     257                 :            :     // create a mesh tag holding the HDF5 type for a struct Plane
     258                 :            :     Tag type_tag;
     259                 :            :     std::string type_tag_name = "__hdf5_tag_type_";
     260                 :            :     type_tag_name += boxTagName;
     261                 :            :     rval = make_tag( moab(), type_tag_name, MB_TAG_MESH, MB_TYPE_OPAQUE, sizeof( hid_t ), 0, type_tag, ctl );
     262                 :            :     if( MB_SUCCESS != rval ) return rval;
     263                 :            :     // create HDF5 type object describing struct Plane
     264                 :            :     Plane p;
     265                 :            :     hid_t handle = H5Tcreate( H5T_COMPOUND, sizeof( Plane ) );
     266                 :            :     H5Tinsert( handle, "coord", &( p.coord ) - &p, H5T_NATIVE_DOUBLE );
     267                 :            :     H5Tinsert( handle, "norm", &( p.axis ) - &p, H5T_NATIVE_INT );
     268                 :            :     EntityHandle root = 0;
     269                 :            :     rval              = mbImpl->tag_set_data( type_tag, &root, 1, &handle );
     270                 :            :     if( MB_SUCCESS != rval ) return rval;
     271                 :            : #endif
     272                 :            : #endif
     273                 :            : 
     274                 :         46 :     return rval;
     275                 :            : }
     276                 :            : 
     277                 :      69823 : ErrorCode AdaptiveKDTree::get_split_plane( EntityHandle entity, Plane& plane )
     278                 :            : {
     279                 :            : #ifndef MB_AD_KD_TREE_USE_SINGLE_TAG
     280                 :            :     ErrorCode r1, r2;
     281                 :            :     r1 = moab()->tag_get_data( planeTag, &entity, 1, &plane.coord );
     282                 :            :     r2 = moab()->tag_get_data( axisTag, &entity, 1, &plane.norm );
     283                 :            :     return MB_SUCCESS == r1 ? r2 : r1;
     284                 :            : #elif defined( MB_AD_KD_TREE_USE_TWO_DOUBLE_TAG )
     285                 :            :     double values[2];
     286 [ +  - ][ +  - ]:      69823 :     ErrorCode rval = moab()->tag_get_data( planeTag, &entity, 1, values );
     287                 :      69823 :     plane.coord    = values[0];
     288                 :      69823 :     plane.norm     = (int)values[1];
     289                 :      69823 :     return rval;
     290                 :            : #else
     291                 :            :     return moab()->tag_get_data( planeTag, &entity, 1, &plane );
     292                 :            : #endif
     293                 :            : }
     294                 :            : 
     295                 :       3735 : ErrorCode AdaptiveKDTree::set_split_plane( EntityHandle entity, const Plane& plane )
     296                 :            : {
     297                 :            : #ifndef MB_AD_KD_TREE_USE_SINGLE_TAG
     298                 :            :     ErrorCode r1, r2;
     299                 :            :     r1 = moab()->tag_set_data( planeTag, &entity, 1, &plane.coord );
     300                 :            :     r2 = moab()->tag_set_data( axisTag, &entity, 1, &plane.norm );
     301                 :            :     return MB_SUCCESS == r1 ? r2 : r1;
     302                 :            : #elif defined( MB_AD_KD_TREE_USE_TWO_DOUBLE_TAG )
     303                 :       3735 :     double values[2] = { plane.coord, static_cast< double >( plane.norm ) };
     304 [ +  - ][ +  - ]:       3735 :     return moab()->tag_set_data( planeTag, &entity, 1, values );
     305                 :            : #else
     306                 :            :     return moab()->tag_set_data( planeTag, &entity, 1, &plane );
     307                 :            : #endif
     308                 :            : }
     309                 :            : 
     310                 :         41 : ErrorCode AdaptiveKDTree::get_tree_iterator( EntityHandle root, AdaptiveKDTreeIter& iter )
     311                 :            : {
     312                 :            :     double box[6];
     313 [ +  - ][ +  - ]:         41 :     ErrorCode rval = moab()->tag_get_data( boxTag, &root, 1, box );
     314         [ -  + ]:         41 :     if( MB_SUCCESS != rval ) return rval;
     315                 :            : 
     316         [ +  - ]:         41 :     return get_sub_tree_iterator( root, box, box + 3, iter );
     317                 :            : }
     318                 :            : 
     319                 :          1 : ErrorCode AdaptiveKDTree::get_last_iterator( EntityHandle root, AdaptiveKDTreeIter& iter )
     320                 :            : {
     321                 :            :     double box[6];
     322 [ +  - ][ +  - ]:          1 :     ErrorCode rval = moab()->tag_get_data( boxTag, &root, 1, box );
     323         [ -  + ]:          1 :     if( MB_SUCCESS != rval ) return rval;
     324                 :            : 
     325         [ +  - ]:          1 :     return iter.initialize( this, root, box, box + 3, AdaptiveKDTreeIter::RIGHT );
     326                 :            : }
     327                 :            : 
     328                 :         41 : ErrorCode AdaptiveKDTree::get_sub_tree_iterator( EntityHandle root, const double min[3], const double max[3],
     329                 :            :                                                  AdaptiveKDTreeIter& result )
     330                 :            : {
     331                 :         41 :     return result.initialize( this, root, min, max, AdaptiveKDTreeIter::LEFT );
     332                 :            : }
     333                 :            : 
     334                 :       3735 : ErrorCode AdaptiveKDTree::split_leaf( AdaptiveKDTreeIter& leaf, Plane plane, EntityHandle& left, EntityHandle& right )
     335                 :            : {
     336                 :            :     ErrorCode rval;
     337                 :            : 
     338                 :       3735 :     rval = moab()->create_meshset( meshsetFlags, left );
     339         [ -  + ]:       3735 :     if( MB_SUCCESS != rval ) return rval;
     340                 :            : 
     341                 :       3735 :     rval = moab()->create_meshset( meshsetFlags, right );
     342         [ -  + ]:       3735 :     if( MB_SUCCESS != rval )
     343                 :            :     {
     344                 :          0 :         moab()->delete_entities( &left, 1 );
     345                 :          0 :         return rval;
     346                 :            :     }
     347                 :            : 
     348 [ +  - ][ -  + ]:      11205 :     if( MB_SUCCESS != set_split_plane( leaf.handle(), plane ) ||
     349         [ +  - ]:       7470 :         MB_SUCCESS != moab()->add_child_meshset( leaf.handle(), left ) ||
     350 [ +  - ][ -  + ]:      11205 :         MB_SUCCESS != moab()->add_child_meshset( leaf.handle(), right ) ||
     351                 :       3735 :         MB_SUCCESS != leaf.step_to_first_leaf( AdaptiveKDTreeIter::LEFT ) )
     352                 :            :     {
     353                 :          0 :         EntityHandle children[] = { left, right };
     354 [ #  # ][ #  # ]:          0 :         moab()->delete_entities( children, 2 );
     355                 :          0 :         return MB_FAILURE;
     356                 :            :     }
     357                 :            : 
     358                 :       3735 :     return MB_SUCCESS;
     359                 :            : }
     360                 :            : 
     361                 :        406 : ErrorCode AdaptiveKDTree::split_leaf( AdaptiveKDTreeIter& leaf, Plane plane )
     362                 :            : {
     363                 :            :     EntityHandle left, right;
     364         [ +  - ]:        406 :     return split_leaf( leaf, plane, left, right );
     365                 :            : }
     366                 :            : 
     367                 :       3329 : ErrorCode AdaptiveKDTree::split_leaf( AdaptiveKDTreeIter& leaf, Plane plane, const Range& left_entities,
     368                 :            :                                       const Range& right_entities )
     369                 :            : {
     370         [ +  - ]:       3329 :     EntityHandle left, right, parent = leaf.handle();
     371         [ +  - ]:       3329 :     ErrorCode rval = split_leaf( leaf, plane, left, right );
     372         [ -  + ]:       3329 :     if( MB_SUCCESS != rval ) return rval;
     373                 :            : 
     374 [ +  - ][ +  - ]:       9987 :     if( MB_SUCCESS == moab()->add_entities( left, left_entities ) &&
         [ +  - ][ +  - ]
     375 [ +  - ][ +  - ]:       6658 :         MB_SUCCESS == moab()->add_entities( right, right_entities ) &&
         [ +  - ][ +  - ]
     376 [ +  - ][ +  - ]:       3329 :         MB_SUCCESS == moab()->clear_meshset( &parent, 1 ) )
     377                 :       3329 :         return MB_SUCCESS;
     378                 :            : 
     379 [ #  # ][ #  # ]:          0 :     moab()->remove_child_meshset( parent, left );
     380 [ #  # ][ #  # ]:          0 :     moab()->remove_child_meshset( parent, right );
     381                 :          0 :     EntityHandle children[] = { left, right };
     382 [ #  # ][ #  # ]:          0 :     moab()->delete_entities( children, 2 );
     383                 :       3329 :     return MB_FAILURE;
     384                 :            : }
     385                 :            : 
     386                 :          0 : ErrorCode AdaptiveKDTree::split_leaf( AdaptiveKDTreeIter& leaf, Plane plane,
     387                 :            :                                       const std::vector< EntityHandle >& left_entities,
     388                 :            :                                       const std::vector< EntityHandle >& right_entities )
     389                 :            : {
     390         [ #  # ]:          0 :     EntityHandle left, right, parent = leaf.handle();
     391         [ #  # ]:          0 :     ErrorCode rval = split_leaf( leaf, plane, left, right );
     392         [ #  # ]:          0 :     if( MB_SUCCESS != rval ) return rval;
     393                 :            : 
     394 [ #  # ][ #  # ]:          0 :     if( MB_SUCCESS == moab()->add_entities( left, &left_entities[0], left_entities.size() ) &&
         [ #  # ][ #  # ]
                 [ #  # ]
     395 [ #  # ][ #  # ]:          0 :         MB_SUCCESS == moab()->add_entities( right, &right_entities[0], right_entities.size() ) &&
         [ #  # ][ #  # ]
                 [ #  # ]
     396 [ #  # ][ #  # ]:          0 :         MB_SUCCESS == moab()->clear_meshset( &parent, 1 ) )
     397                 :          0 :         return MB_SUCCESS;
     398                 :            : 
     399 [ #  # ][ #  # ]:          0 :     moab()->remove_child_meshset( parent, left );
     400 [ #  # ][ #  # ]:          0 :     moab()->remove_child_meshset( parent, right );
     401                 :          0 :     EntityHandle children[] = { left, right };
     402 [ #  # ][ #  # ]:          0 :     moab()->delete_entities( children, 2 );
     403                 :          0 :     return MB_FAILURE;
     404                 :            : }
     405                 :            : 
     406                 :         34 : ErrorCode AdaptiveKDTree::merge_leaf( AdaptiveKDTreeIter& iter )
     407                 :            : {
     408                 :            :     ErrorCode rval;
     409 [ +  - ][ -  + ]:         34 :     if( iter.depth() == 1 )  // at root
     410                 :          0 :         return MB_FAILURE;
     411                 :            : 
     412                 :            :     // Move iter to parent
     413                 :            : 
     414         [ +  - ]:         34 :     AdaptiveKDTreeIter::StackObj node = iter.mStack.back();
     415         [ +  - ]:         34 :     iter.mStack.pop_back();
     416                 :            : 
     417                 :         34 :     iter.childVect.clear();
     418 [ +  - ][ +  - ]:         34 :     rval = moab()->get_child_meshsets( iter.mStack.back().entity, iter.childVect );
                 [ +  - ]
     419         [ -  + ]:         34 :     if( MB_SUCCESS != rval ) return rval;
     420                 :            :     Plane plane;
     421 [ +  - ][ +  - ]:         34 :     rval = get_split_plane( iter.mStack.back().entity, plane );
     422         [ -  + ]:         34 :     if( MB_SUCCESS != rval ) return rval;
     423                 :            : 
     424         [ +  - ]:         34 :     int child_idx = iter.childVect[0] == node.entity ? 0 : 1;
     425 [ +  - ][ -  + ]:         34 :     assert( iter.childVect[child_idx] == node.entity );
     426         [ +  - ]:         34 :     iter.mBox[1 - child_idx][plane.norm] = node.coord;
     427                 :            : 
     428                 :            :     // Get all entities from children and put them in parent
     429         [ +  - ]:         34 :     EntityHandle parent = iter.handle();
     430 [ +  - ][ +  - ]:         34 :     moab()->remove_child_meshset( parent, iter.childVect[0] );
                 [ +  - ]
     431 [ +  - ][ +  - ]:         34 :     moab()->remove_child_meshset( parent, iter.childVect[1] );
                 [ +  - ]
     432         [ +  - ]:         34 :     std::vector< EntityHandle > stack( iter.childVect );
     433                 :            : 
     434         [ +  - ]:         68 :     Range range;
     435         [ +  + ]:        104 :     while( !stack.empty() )
     436                 :            :     {
     437         [ +  - ]:         70 :         EntityHandle h = stack.back();
     438         [ +  - ]:         70 :         stack.pop_back();
     439         [ +  - ]:         70 :         range.clear();
     440 [ +  - ][ +  - ]:         70 :         rval = moab()->get_entities_by_handle( h, range );
     441         [ -  + ]:         70 :         if( MB_SUCCESS != rval ) return rval;
     442 [ +  - ][ +  - ]:         70 :         rval = moab()->add_entities( parent, range );
     443         [ -  + ]:         70 :         if( MB_SUCCESS != rval ) return rval;
     444                 :            : 
     445                 :         70 :         iter.childVect.clear();
     446 [ +  - ][ +  - ]:         70 :         rval = moab()->get_child_meshsets( h, iter.childVect );MB_CHK_ERR( rval );
         [ -  + ][ #  # ]
                 [ #  # ]
     447         [ +  + ]:         70 :         if( !iter.childVect.empty() )
     448                 :            :         {
     449 [ +  - ][ +  - ]:          1 :             moab()->remove_child_meshset( h, iter.childVect[0] );
                 [ +  - ]
     450 [ +  - ][ +  - ]:          1 :             moab()->remove_child_meshset( h, iter.childVect[1] );
                 [ +  - ]
     451 [ +  - ][ +  - ]:          1 :             stack.push_back( iter.childVect[0] );
     452 [ +  - ][ +  - ]:          1 :             stack.push_back( iter.childVect[1] );
     453                 :            :         }
     454                 :            : 
     455 [ +  - ][ +  - ]:         70 :         rval = moab()->delete_entities( &h, 1 );
     456         [ -  + ]:         70 :         if( MB_SUCCESS != rval ) return rval;
     457                 :            :     }
     458                 :            : 
     459                 :         68 :     return MB_SUCCESS;
     460                 :            : }
     461                 :            : 
     462                 :         58 : ErrorCode AdaptiveKDTreeIter::initialize( AdaptiveKDTree* ttool, EntityHandle root, const double bmin[3],
     463                 :            :                                           const double bmax[3], Direction direction )
     464                 :            : {
     465                 :         58 :     mStack.clear();
     466                 :         58 :     treeTool      = ttool;
     467                 :         58 :     mBox[BMIN][0] = bmin[0];
     468                 :         58 :     mBox[BMIN][1] = bmin[1];
     469                 :         58 :     mBox[BMIN][2] = bmin[2];
     470                 :         58 :     mBox[BMAX][0] = bmax[0];
     471                 :         58 :     mBox[BMAX][1] = bmax[1];
     472                 :         58 :     mBox[BMAX][2] = bmax[2];
     473         [ +  - ]:         58 :     mStack.push_back( StackObj( root, 0 ) );
     474                 :         58 :     return step_to_first_leaf( direction );
     475                 :            : }
     476                 :            : 
     477                 :       9431 : ErrorCode AdaptiveKDTreeIter::step_to_first_leaf( Direction direction )
     478                 :            : {
     479                 :            :     ErrorCode rval;
     480                 :            :     AdaptiveKDTree::Plane plane;
     481                 :       9431 :     const Direction opposite = static_cast< Direction >( 1 - direction );
     482                 :            : 
     483                 :            :     for( ;; )
     484                 :            :     {
     485                 :      15058 :         childVect.clear();
     486                 :      15058 :         treeTool->treeStats.nodesVisited++;  // not sure whether this is the visit or the push_back below
     487 [ +  - ][ +  - ]:      15058 :         rval = treeTool->moab()->get_child_meshsets( mStack.back().entity, childVect );
                 [ +  - ]
     488         [ -  + ]:      15058 :         if( MB_SUCCESS != rval ) return rval;
     489         [ +  + ]:      15058 :         if( childVect.empty() )
     490                 :            :         {  // leaf
     491                 :       9431 :             treeTool->treeStats.leavesVisited++;
     492                 :       9431 :             break;
     493                 :            :         }
     494                 :            : 
     495 [ +  - ][ +  - ]:       5627 :         rval = treeTool->get_split_plane( mStack.back().entity, plane );
     496         [ -  + ]:       5627 :         if( MB_SUCCESS != rval ) return rval;
     497                 :            : 
     498 [ +  - ][ +  - ]:       5627 :         mStack.push_back( StackObj( childVect[direction], mBox[opposite][plane.norm] ) );
         [ +  - ][ +  - ]
     499         [ +  - ]:       5627 :         mBox[opposite][plane.norm] = plane.coord;
     500                 :            :     }
     501                 :      15058 :     return MB_SUCCESS;
     502                 :            : }
     503                 :            : 
     504                 :       5690 : ErrorCode AdaptiveKDTreeIter::step( Direction direction )
     505                 :            : {
     506 [ +  - ][ +  - ]:       5690 :     StackObj node, parent;
     507                 :            :     ErrorCode rval;
     508                 :            :     AdaptiveKDTree::Plane plane;
     509                 :       5690 :     const Direction opposite = static_cast< Direction >( 1 - direction );
     510                 :            : 
     511                 :            :     // If stack is empty, then either this iterator is uninitialized
     512                 :            :     // or we reached the end of the iteration (and return
     513                 :            :     // MB_ENTITY_NOT_FOUND) already.
     514         [ +  + ]:       5690 :     if( mStack.empty() ) return MB_FAILURE;
     515                 :            : 
     516                 :            :     // Pop the current node from the stack.
     517                 :            :     // The stack should then contain the parent of the current node.
     518                 :            :     // If the stack is empty after this pop, then we've reached the end.
     519         [ +  - ]:       5689 :     node = mStack.back();
     520         [ +  - ]:       5689 :     mStack.pop_back();
     521                 :       5689 :     treeTool->treeStats.nodesVisited++;
     522         [ +  + ]:       5689 :     if( mStack.empty() ) treeTool->treeStats.leavesVisited++;
     523                 :            : 
     524         [ +  + ]:      11267 :     while( !mStack.empty() )
     525                 :            :     {
     526                 :            :         // Get data for parent entity
     527         [ +  - ]:      11216 :         parent = mStack.back();
     528                 :      11216 :         childVect.clear();
     529 [ +  - ][ +  - ]:      11216 :         rval = treeTool->moab()->get_child_meshsets( parent.entity, childVect );
     530         [ -  + ]:      11216 :         if( MB_SUCCESS != rval ) return rval;
     531         [ +  - ]:      11216 :         rval = treeTool->get_split_plane( parent.entity, plane );
     532         [ -  + ]:      11216 :         if( MB_SUCCESS != rval ) return rval;
     533                 :            : 
     534                 :            :         // If we're at the left child
     535 [ +  - ][ +  + ]:      11216 :         if( childVect[opposite] == node.entity )
     536                 :            :         {
     537                 :            :             // change from box of left child to box of parent
     538         [ +  - ]:       5638 :             mBox[direction][plane.norm] = node.coord;
     539                 :            :             // push right child on stack
     540         [ +  - ]:       5638 :             node.entity = childVect[direction];
     541                 :       5638 :             treeTool->treeStats.nodesVisited++;  // changed node
     542         [ +  - ]:       5638 :             node.coord = mBox[opposite][plane.norm];
     543         [ +  - ]:       5638 :             mStack.push_back( node );
     544                 :            :             // change from box of parent to box of right child
     545         [ +  - ]:       5638 :             mBox[opposite][plane.norm] = plane.coord;
     546                 :            :             // descend to left-most leaf of the right child
     547         [ +  - ]:       5638 :             return step_to_first_leaf( opposite );
     548                 :            :         }
     549                 :            : 
     550                 :            :         // The current node is the right child of the parent,
     551                 :            :         // continue up the tree.
     552 [ +  - ][ -  + ]:       5578 :         assert( childVect[direction] == node.entity );
     553         [ +  - ]:       5578 :         mBox[opposite][plane.norm] = node.coord;
     554                 :       5578 :         node                       = parent;
     555                 :       5578 :         treeTool->treeStats.nodesVisited++;
     556         [ +  - ]:       5578 :         mStack.pop_back();
     557                 :            :     }
     558                 :            : 
     559                 :       5690 :     return MB_ENTITY_NOT_FOUND;
     560                 :            : }
     561                 :            : 
     562                 :         12 : ErrorCode AdaptiveKDTreeIter::get_neighbors( AdaptiveKDTree::Axis norm, bool neg,
     563                 :            :                                              std::vector< AdaptiveKDTreeIter >& results, double epsilon ) const
     564                 :            : {
     565 [ +  - ][ +  - ]:         12 :     StackObj node, parent;
     566                 :            :     ErrorCode rval;
     567                 :            :     AdaptiveKDTree::Plane plane;
     568                 :            :     int child_idx;
     569                 :            : 
     570                 :            :     // Find tree node at which the specified side of the box
     571                 :            :     // for this node was created.
     572         [ +  - ]:         12 :     AdaptiveKDTreeIter iter( *this );  // temporary iterator (don't modify *this)
     573         [ +  - ]:         12 :     node = iter.mStack.back();
     574         [ +  - ]:         12 :     iter.mStack.pop_back();
     575                 :            :     for( ;; )
     576                 :            :     {
     577                 :            :         // reached the root - original node was on boundary (no neighbors)
     578         [ +  + ]:         37 :         if( iter.mStack.empty() ) return MB_SUCCESS;
     579                 :            : 
     580                 :            :         // get parent node data
     581         [ +  - ]:         30 :         parent = iter.mStack.back();
     582                 :         30 :         iter.childVect.clear();
     583 [ +  - ][ +  - ]:         30 :         rval = treeTool->moab()->get_child_meshsets( parent.entity, iter.childVect );
     584         [ -  + ]:         30 :         if( MB_SUCCESS != rval ) return rval;
     585         [ +  - ]:         30 :         rval = treeTool->get_split_plane( parent.entity, plane );
     586         [ -  + ]:         30 :         if( MB_SUCCESS != rval ) return rval;
     587                 :            : 
     588         [ +  - ]:         30 :         child_idx = iter.childVect[0] == node.entity ? 0 : 1;
     589 [ +  - ][ -  + ]:         30 :         assert( iter.childVect[child_idx] == node.entity );
     590                 :            : 
     591                 :            :         // if we found the split plane for the desired side
     592                 :            :         // push neighbor on stack and stop
     593 [ +  + ][ +  + ]:         30 :         if( plane.norm == norm && (int)neg == child_idx )
     594                 :            :         {
     595                 :            :             // change from box of previous child to box of parent
     596         [ +  - ]:          5 :             iter.mBox[1 - child_idx][plane.norm] = node.coord;
     597                 :            :             // push other child of parent onto stack
     598         [ +  - ]:          5 :             node.entity = iter.childVect[1 - child_idx];
     599         [ +  - ]:          5 :             node.coord  = iter.mBox[child_idx][plane.norm];
     600         [ +  - ]:          5 :             iter.mStack.push_back( node );
     601                 :            :             // change from parent box to box of new child
     602         [ +  - ]:          5 :             iter.mBox[child_idx][plane.norm] = plane.coord;
     603                 :          5 :             break;
     604                 :            :         }
     605                 :            : 
     606                 :            :         // continue up the tree
     607         [ +  - ]:         25 :         iter.mBox[1 - child_idx][plane.norm] = node.coord;
     608                 :         25 :         node                                 = parent;
     609         [ +  - ]:         25 :         iter.mStack.pop_back();
     610                 :            :     }
     611                 :            : 
     612                 :            :     // now move down tree, searching for adjacent boxes
     613         [ +  - ]:         10 :     std::vector< AdaptiveKDTreeIter > list;
     614                 :            :     // loop over all potential paths to neighbors (until list is empty)
     615                 :            :     for( ;; )
     616                 :            :     {
     617                 :            :         // follow a single path to a leaf, append any other potential
     618                 :            :         // paths to neighbors to 'list'
     619         [ +  - ]:          6 :         node = iter.mStack.back();
     620                 :            :         for( ;; )
     621                 :            :         {
     622                 :         10 :             iter.childVect.clear();
     623 [ +  - ][ +  - ]:         10 :             rval = treeTool->moab()->get_child_meshsets( node.entity, iter.childVect );
     624         [ -  + ]:         10 :             if( MB_SUCCESS != rval ) return rval;
     625                 :            : 
     626                 :            :             // if leaf
     627         [ +  + ]:         10 :             if( iter.childVect.empty() )
     628                 :            :             {
     629         [ +  - ]:          6 :                 results.push_back( iter );
     630                 :          6 :                 break;
     631                 :            :             }
     632                 :            : 
     633         [ +  - ]:          4 :             rval = treeTool->get_split_plane( node.entity, plane );
     634         [ -  + ]:          4 :             if( MB_SUCCESS != rval ) return rval;
     635                 :            : 
     636                 :            :             // if split parallel to side
     637         [ +  + ]:          4 :             if( plane.norm == norm )
     638                 :            :             {
     639                 :            :                 // continue with whichever child is on the correct side of the split
     640         [ +  - ]:          2 :                 node.entity = iter.childVect[neg];
     641         [ +  - ]:          2 :                 node.coord  = iter.mBox[1 - neg][plane.norm];
     642         [ +  - ]:          2 :                 iter.mStack.push_back( node );
     643         [ +  - ]:          2 :                 iter.mBox[1 - neg][plane.norm] = plane.coord;
     644                 :            :             }
     645                 :            :             // if left child is adjacent
     646 [ +  - ][ +  - ]:          2 :             else if( this->mBox[BMIN][plane.norm] - plane.coord <= epsilon )
     647                 :            :             {
     648                 :            :                 // if right child is also adjacent, add to list
     649 [ +  - ][ +  + ]:          2 :                 if( plane.coord - this->mBox[BMAX][plane.norm] <= epsilon )
     650                 :            :                 {
     651         [ +  - ]:          1 :                     list.push_back( iter );
     652 [ +  - ][ +  - ]:          1 :                     list.back().mStack.push_back( StackObj( iter.childVect[1], iter.mBox[BMIN][plane.norm] ) );
         [ +  - ][ +  - ]
                 [ +  - ]
     653 [ +  - ][ +  - ]:          1 :                     list.back().mBox[BMIN][plane.norm] = plane.coord;
     654                 :            :                 }
     655                 :            :                 // continue with left child
     656         [ +  - ]:          2 :                 node.entity = iter.childVect[0];
     657         [ +  - ]:          2 :                 node.coord  = iter.mBox[BMAX][plane.norm];
     658         [ +  - ]:          2 :                 iter.mStack.push_back( node );
     659         [ +  - ]:          2 :                 iter.mBox[BMAX][plane.norm] = plane.coord;
     660                 :            :             }
     661                 :            :             // right child is adjacent
     662                 :            :             else
     663                 :            :             {
     664                 :            :                 // if left child is not adjacent, right must be or something
     665                 :            :                 // is really messed up.
     666 [ #  # ][ #  # ]:          0 :                 assert( plane.coord - this->mBox[BMAX][plane.norm] <= epsilon );
     667                 :            :                 // continue with left child
     668         [ #  # ]:          0 :                 node.entity = iter.childVect[1];
     669         [ #  # ]:          0 :                 node.coord  = iter.mBox[BMIN][plane.norm];
     670         [ #  # ]:          0 :                 iter.mStack.push_back( node );
     671         [ #  # ]:          4 :                 iter.mBox[BMIN][plane.norm] = plane.coord;
     672                 :            :             }
     673                 :            :         }
     674                 :            : 
     675         [ +  + ]:          6 :         if( list.empty() ) break;
     676                 :            : 
     677 [ +  - ][ +  - ]:          1 :         iter = list.back();
     678         [ +  - ]:          1 :         list.pop_back();
     679                 :            :     }
     680                 :            : 
     681                 :         17 :     return MB_SUCCESS;
     682                 :            : }
     683                 :            : 
     684                 :          0 : ErrorCode AdaptiveKDTreeIter::sibling_side( AdaptiveKDTree::Axis& axis_out, bool& neg_out ) const
     685                 :            : {
     686         [ #  # ]:          0 :     if( mStack.size() < 2 )  // at tree root
     687                 :          0 :         return MB_ENTITY_NOT_FOUND;
     688                 :            : 
     689         [ #  # ]:          0 :     EntityHandle parent = mStack[mStack.size() - 2].entity;
     690                 :            :     AdaptiveKDTree::Plane plane;
     691 [ #  # ][ #  # ]:          0 :     ErrorCode rval = tool()->get_split_plane( parent, plane );
     692         [ #  # ]:          0 :     if( MB_SUCCESS != rval ) return MB_FAILURE;
     693                 :            : 
     694                 :          0 :     childVect.clear();
     695 [ #  # ][ #  # ]:          0 :     rval = tool()->moab()->get_child_meshsets( parent, childVect );
                 [ #  # ]
     696 [ #  # ][ #  # ]:          0 :     if( MB_SUCCESS != rval || childVect.size() != 2 ) return MB_FAILURE;
                 [ #  # ]
     697                 :            : 
     698                 :          0 :     axis_out = static_cast< AdaptiveKDTree::Axis >( plane.norm );
     699 [ #  # ][ #  # ]:          0 :     neg_out  = ( childVect[1] == handle() );
     700 [ #  # ][ #  # ]:          0 :     assert( childVect[neg_out] == handle() );
                 [ #  # ]
     701                 :          0 :     return MB_SUCCESS;
     702                 :            : }
     703                 :            : 
     704                 :          0 : ErrorCode AdaptiveKDTreeIter::get_parent_split_plane( AdaptiveKDTree::Plane& plane ) const
     705                 :            : {
     706         [ #  # ]:          0 :     if( mStack.size() < 2 )  // at tree root
     707                 :          0 :         return MB_ENTITY_NOT_FOUND;
     708                 :            : 
     709                 :          0 :     EntityHandle parent = mStack[mStack.size() - 2].entity;
     710                 :          0 :     return tool()->get_split_plane( parent, plane );
     711                 :            : }
     712                 :            : 
     713                 :         10 : bool AdaptiveKDTreeIter::is_sibling( const AdaptiveKDTreeIter& other_leaf ) const
     714                 :            : {
     715                 :         10 :     const size_t s = mStack.size();
     716   [ +  -  +  + ]:         20 :     return ( s > 1 ) && ( s == other_leaf.mStack.size() ) &&
     717 [ +  - ][ +  + ]:         30 :            ( other_leaf.mStack[s - 2].entity == mStack[s - 2].entity ) && other_leaf.handle() != handle();
     718                 :            : }
     719                 :            : 
     720                 :          9 : bool AdaptiveKDTreeIter::is_sibling( EntityHandle other_leaf ) const
     721                 :            : {
     722 [ +  - ][ +  + ]:          9 :     if( mStack.size() < 2 || other_leaf == handle() ) return false;
                 [ +  + ]
     723                 :          8 :     EntityHandle parent = mStack[mStack.size() - 2].entity;
     724                 :          8 :     childVect.clear();
     725                 :          8 :     ErrorCode rval = tool()->moab()->get_child_meshsets( parent, childVect );
     726 [ +  - ][ -  + ]:          8 :     if( MB_SUCCESS != rval || childVect.size() != 2 )
                 [ -  + ]
     727                 :            :     {
     728                 :          0 :         assert( false );
     729                 :            :         return false;
     730                 :            :     }
     731 [ +  + ][ +  + ]:          8 :     return childVect[0] == other_leaf || childVect[1] == other_leaf;
     732                 :            : }
     733                 :            : 
     734                 :          5 : bool AdaptiveKDTreeIter::sibling_is_forward() const
     735                 :            : {
     736         [ -  + ]:          5 :     if( mStack.size() < 2 )  // if root
     737                 :          0 :         return false;
     738                 :          5 :     EntityHandle parent = mStack[mStack.size() - 2].entity;
     739                 :          5 :     childVect.clear();
     740                 :          5 :     ErrorCode rval = tool()->moab()->get_child_meshsets( parent, childVect );
     741 [ +  - ][ -  + ]:          5 :     if( MB_SUCCESS != rval || childVect.size() != 2 )
                 [ -  + ]
     742                 :            :     {
     743                 :          0 :         assert( false );
     744                 :            :         return false;
     745                 :            :     }
     746                 :          5 :     return childVect[0] == handle();
     747                 :            : }
     748                 :            : 
     749                 :         26 : bool AdaptiveKDTreeIter::intersect_ray( const double ray_point[3], const double ray_vect[3], double& t_enter,
     750                 :            :                                         double& t_exit ) const
     751                 :            : {
     752                 :         26 :     treeTool->treeStats.traversalLeafObjectTests++;
     753                 :            :     return GeomUtil::ray_box_intersect( CartVect( box_min() ), CartVect( box_max() ), CartVect( ray_point ),
     754 [ +  - ][ +  - ]:         26 :                                         CartVect( ray_vect ), t_enter, t_exit );
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     755                 :            : }
     756                 :            : 
     757                 :      31879 : ErrorCode AdaptiveKDTree::intersect_children_with_elems( const Range& elems, AdaptiveKDTree::Plane plane, double eps,
     758                 :            :                                                          CartVect box_min, CartVect box_max, Range& left_tris,
     759                 :            :                                                          Range& right_tris, Range& both_tris, double& metric_value )
     760                 :            : {
     761         [ +  - ]:      31879 :     left_tris.clear();
     762         [ +  - ]:      31879 :     right_tris.clear();
     763         [ +  - ]:      31879 :     both_tris.clear();
     764 [ +  - ][ +  + ]:     541943 :     CartVect coords[16];
     765                 :            : 
     766                 :            :     // get extents of boxes for left and right sides
     767 [ +  - ][ +  - ]:      63758 :     BoundBox left_box( box_min, box_max ), right_box( box_min, box_max );
     768                 :      31879 :     right_box.bMin             = box_min;
     769                 :      31879 :     left_box.bMax              = box_max;
     770 [ +  - ][ +  - ]:      31879 :     right_box.bMin[plane.norm] = left_box.bMax[plane.norm] = plane.coord;
     771 [ +  - ][ +  - ]:      31879 :     const CartVect left_cen                                = 0.5 * ( left_box.bMax + box_min );
     772 [ +  - ][ +  - ]:      31879 :     const CartVect left_dim                                = 0.5 * ( left_box.bMax - box_min );
     773 [ +  - ][ +  - ]:      31879 :     const CartVect right_cen                               = 0.5 * ( box_max + right_box.bMin );
     774 [ +  - ][ +  - ]:      31879 :     const CartVect right_dim                               = 0.5 * ( box_max - right_box.bMin );
     775         [ +  - ]:      31879 :     const CartVect dim                                     = box_max - box_min;
     776 [ +  - ][ +  - ]:      31879 :     const double max_tol                                   = std::max( dim[0], std::max( dim[1], dim[2] ) ) / 10;
         [ +  - ][ +  - ]
                 [ +  - ]
     777                 :            : 
     778                 :            :     // test each entity
     779                 :            :     ErrorCode rval;
     780                 :            :     int count, count2;
     781                 :            :     const EntityHandle *conn, *conn2;
     782                 :            : 
     783         [ +  - ]:      31879 :     const Range::const_iterator elem_begin = elems.lower_bound( MBEDGE );
     784         [ +  - ]:      31879 :     const Range::const_iterator poly_begin = elems.lower_bound( MBPOLYHEDRON, elem_begin );
     785         [ +  - ]:      31879 :     const Range::const_iterator set_begin  = elems.lower_bound( MBENTITYSET, poly_begin );
     786         [ +  - ]:      31879 :     Range::iterator left_ins               = left_tris.begin();
     787         [ +  - ]:      31879 :     Range::iterator right_ins              = right_tris.begin();
     788         [ +  - ]:      31879 :     Range::iterator both_ins               = both_tris.begin();
     789         [ +  - ]:      31879 :     Range::const_iterator i;
     790                 :            : 
     791                 :            :     // vertices
     792 [ +  - ][ +  - ]:     112579 :     for( i = elems.begin(); i != elem_begin; ++i )
         [ +  - ][ +  + ]
     793                 :            :     {
     794         [ +  - ]:      80700 :         tree_stats().constructLeafObjectTests++;
     795 [ +  - ][ +  - ]:      80700 :         rval = moab()->get_coords( &*i, 1, coords[0].array() );
         [ +  - ][ +  - ]
     796         [ -  + ]:      80700 :         if( MB_SUCCESS != rval ) return rval;
     797                 :            : 
     798                 :      80700 :         bool lo = false, ro = false;
     799 [ +  - ][ +  + ]:      80700 :         if( coords[0][plane.norm] <= plane.coord ) lo = true;
     800 [ +  - ][ +  + ]:      80700 :         if( coords[0][plane.norm] >= plane.coord ) ro = true;
     801                 :            : 
     802 [ +  + ][ +  + ]:      80700 :         if( lo && ro )
     803 [ +  - ][ +  - ]:      21853 :             both_ins = both_tris.insert( both_ins, *i, *i );
                 [ +  - ]
     804         [ +  + ]:      58847 :         else if( lo )
     805 [ +  - ][ +  - ]:      27331 :             left_ins = left_tris.insert( left_ins, *i, *i );
                 [ +  - ]
     806                 :            :         else  // if (ro)
     807 [ +  - ][ +  - ]:      31516 :             right_ins = right_tris.insert( right_ins, *i, *i );
                 [ +  - ]
     808                 :            :     }
     809                 :            : 
     810                 :            :     // non-polyhedron elements
     811         [ +  - ]:      63758 :     std::vector< EntityHandle > dum_vector;
     812 [ +  - ][ +  - ]:     519774 :     for( i = elem_begin; i != poly_begin; ++i )
                 [ +  + ]
     813                 :            :     {
     814         [ +  - ]:     487895 :         tree_stats().constructLeafObjectTests++;
     815 [ +  - ][ +  - ]:     487895 :         rval = moab()->get_connectivity( *i, conn, count, true, &dum_vector );
                 [ +  - ]
     816         [ -  + ]:     487895 :         if( MB_SUCCESS != rval ) return rval;
     817         [ -  + ]:     487895 :         if( count > (int)( sizeof( coords ) / sizeof( coords[0] ) ) ) return MB_FAILURE;
     818 [ +  - ][ +  - ]:     487895 :         rval = moab()->get_coords( &conn[0], count, coords[0].array() );
                 [ +  - ]
     819         [ -  + ]:     487895 :         if( MB_SUCCESS != rval ) return rval;
     820                 :            : 
     821                 :     487895 :         bool lo = false, ro = false;
     822         [ +  + ]:    3004403 :         for( int j = 0; j < count; ++j )
     823                 :            :         {
     824 [ +  - ][ +  + ]:    2516508 :             if( coords[j][plane.norm] <= plane.coord ) lo = true;
     825 [ +  - ][ +  + ]:    2516508 :             if( coords[j][plane.norm] >= plane.coord ) ro = true;
     826                 :            :         }
     827                 :            : 
     828                 :            :         // Triangle must be in at least one leaf.  If test against plane
     829                 :            :         // identified that leaf, then we're done.  If triangle is on both
     830                 :            :         // sides of plane, do more precise test to ensure that it is really
     831                 :            :         // in both.
     832                 :            :         //        BoundBox box;
     833                 :            :         //        box.update(*moab(), *i);
     834 [ +  + ][ +  + ]:     487895 :         if( lo && ro )
     835                 :            :         {
     836                 :     178119 :             double tol = eps;
     837                 :     178119 :             lo = ro = false;
     838 [ +  + ][ +  + ]:     356238 :             while( !lo && !ro && tol <= max_tol )
                 [ +  - ]
     839                 :            :             {
     840         [ +  - ]:     178119 :                 tree_stats().boxElemTests += 2;
     841 [ +  - ][ +  - ]:     178119 :                 lo = GeomUtil::box_elem_overlap( coords, TYPE_FROM_HANDLE( *i ), left_cen, left_dim + CartVect( tol ),
                 [ +  - ]
     842 [ +  - ][ +  - ]:     178119 :                                                  count );
     843 [ +  - ][ +  - ]:     178119 :                 ro = GeomUtil::box_elem_overlap( coords, TYPE_FROM_HANDLE( *i ), right_cen, right_dim + CartVect( tol ),
                 [ +  - ]
     844 [ +  - ][ +  - ]:     178119 :                                                  count );
     845                 :            : 
     846                 :     178119 :                 tol *= 10.0;
     847                 :            :             }
     848                 :            :         }
     849 [ +  + ][ +  + ]:     487895 :         if( lo && ro )
     850 [ +  - ][ +  - ]:     176435 :             both_ins = both_tris.insert( both_ins, *i, *i );
                 [ +  - ]
     851         [ +  + ]:     311460 :         else if( lo )
     852 [ +  - ][ +  - ]:     150133 :             left_ins = left_tris.insert( left_ins, *i, *i );
                 [ +  - ]
     853         [ +  - ]:     161327 :         else if( ro )
     854 [ +  - ][ +  - ]:     161327 :             right_ins = right_tris.insert( right_ins, *i, *i );
                 [ +  - ]
     855                 :            :     }
     856                 :            : 
     857                 :            :     // polyhedra
     858 [ #  # ][ +  - ]:      31879 :     for( i = poly_begin; i != set_begin; ++i )
                 [ -  + ]
     859                 :            :     {
     860         [ #  # ]:          0 :         tree_stats().constructLeafObjectTests++;
     861 [ #  # ][ #  # ]:          0 :         rval = moab()->get_connectivity( *i, conn, count, true );
                 [ #  # ]
     862         [ #  # ]:          0 :         if( MB_SUCCESS != rval ) return rval;
     863                 :            : 
     864                 :            :         // just check the bounding box of the polyhedron
     865                 :          0 :         bool lo = false, ro = false;
     866         [ #  # ]:          0 :         for( int j = 0; j < count; ++j )
     867                 :            :         {
     868 [ #  # ][ #  # ]:          0 :             rval = moab()->get_connectivity( conn[j], conn2, count2, true );
     869         [ #  # ]:          0 :             if( MB_SUCCESS != rval ) return rval;
     870                 :            : 
     871         [ #  # ]:          0 :             for( int k = 0; k < count2; ++k )
     872                 :            :             {
     873 [ #  # ][ #  # ]:          0 :                 rval = moab()->get_coords( conn2 + k, 1, coords[0].array() );
                 [ #  # ]
     874         [ #  # ]:          0 :                 if( MB_SUCCESS != rval ) return rval;
     875 [ #  # ][ #  # ]:          0 :                 if( coords[0][plane.norm] <= plane.coord ) lo = true;
     876 [ #  # ][ #  # ]:          0 :                 if( coords[0][plane.norm] >= plane.coord ) ro = true;
     877                 :            :             }
     878                 :            :         }
     879                 :            : 
     880 [ #  # ][ #  # ]:          0 :         if( lo && ro )
     881 [ #  # ][ #  # ]:          0 :             both_ins = both_tris.insert( both_ins, *i, *i );
                 [ #  # ]
     882         [ #  # ]:          0 :         else if( lo )
     883 [ #  # ][ #  # ]:          0 :             left_ins = left_tris.insert( left_ins, *i, *i );
                 [ #  # ]
     884         [ #  # ]:          0 :         else if( ro )
     885 [ #  # ][ #  # ]:          0 :             right_ins = right_tris.insert( right_ins, *i, *i );
                 [ #  # ]
     886                 :            :     }
     887                 :            : 
     888                 :            :     // sets
     889         [ +  - ]:      63758 :     BoundBox tbox;
     890 [ #  # ][ +  - ]:      31879 :     for( i = set_begin; i != elems.end(); ++i )
         [ +  - ][ -  + ]
     891                 :            :     {
     892         [ #  # ]:          0 :         tree_stats().constructLeafObjectTests++;
     893 [ #  # ][ #  # ]:          0 :         rval = tbox.update( *moab(), *i, spherical, radius );
                 [ #  # ]
     894         [ #  # ]:          0 :         if( MB_SUCCESS != rval ) return rval;
     895                 :            : 
     896                 :          0 :         bool lo = false, ro = false;
     897 [ #  # ][ #  # ]:          0 :         if( tbox.bMin[plane.norm] <= plane.coord ) lo = true;
     898 [ #  # ][ #  # ]:          0 :         if( tbox.bMax[plane.norm] >= plane.coord ) ro = true;
     899                 :            : 
     900 [ #  # ][ #  # ]:          0 :         if( lo && ro )
     901 [ #  # ][ #  # ]:          0 :             both_ins = both_tris.insert( both_ins, *i, *i );
                 [ #  # ]
     902         [ #  # ]:          0 :         else if( lo )
     903 [ #  # ][ #  # ]:          0 :             left_ins = left_tris.insert( left_ins, *i, *i );
                 [ #  # ]
     904                 :            :         else  // if (ro)
     905 [ #  # ][ #  # ]:          0 :             right_ins = right_tris.insert( right_ins, *i, *i );
                 [ #  # ]
     906                 :            :     }
     907                 :            : 
     908         [ +  - ]:      31879 :     CartVect box_dim  = box_max - box_min;
     909 [ +  - ][ +  - ]:      31879 :     double area_left  = left_dim[0] * left_dim[1] + left_dim[1] * left_dim[2] + left_dim[2] * left_dim[0];
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     910 [ +  - ][ +  - ]:      31879 :     double area_right = right_dim[0] * right_dim[1] + right_dim[1] * right_dim[2] + right_dim[2] * right_dim[0];
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     911 [ +  - ][ +  - ]:      31879 :     double area_both  = box_dim[0] * box_dim[1] + box_dim[1] * box_dim[2] + box_dim[2] * box_dim[0];
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     912 [ +  - ][ +  - ]:      31879 :     metric_value = ( area_left * left_tris.size() + area_right * right_tris.size() ) / area_both + both_tris.size();
                 [ +  - ]
     913                 :      63758 :     return MB_SUCCESS;
     914                 :            : }
     915                 :            : 
     916                 :       2202 : ErrorCode AdaptiveKDTree::best_subdivision_plane( int num_planes, const AdaptiveKDTreeIter& iter, Range& best_left,
     917                 :            :                                                   Range& best_right, Range& best_both,
     918                 :            :                                                   AdaptiveKDTree::Plane& best_plane, double eps )
     919                 :            : {
     920                 :       2202 :     double metric_val = std::numeric_limits< unsigned >::max();
     921                 :            : 
     922                 :            :     ErrorCode r;
     923 [ +  - ][ +  - ]:       2202 :     const CartVect box_min( iter.box_min() );
     924 [ +  - ][ +  - ]:       2202 :     const CartVect box_max( iter.box_max() );
     925         [ +  - ]:       2202 :     const CartVect diff( box_max - box_min );
     926                 :            : 
     927         [ +  - ]:       2202 :     Range entities;
     928 [ +  - ][ +  - ]:       2202 :     r = iter.tool()->moab()->get_entities_by_handle( iter.handle(), entities );
         [ +  - ][ +  - ]
     929         [ -  + ]:       2202 :     if( MB_SUCCESS != r ) return r;
     930         [ +  - ]:       2202 :     const size_t p_count = entities.size();
     931                 :            : 
     932         [ +  + ]:       8808 :     for( int axis = 0; axis < 3; ++axis )
     933                 :            :     {
     934                 :       6606 :         int plane_count = num_planes;
     935 [ +  - ][ -  + ]:       6606 :         if( ( num_planes + 1 ) * eps >= diff[axis] ) plane_count = (int)( diff[axis] / eps ) - 1;
                 [ #  # ]
     936                 :            : 
     937         [ +  + ]:      19350 :         for( int p = 1; p <= plane_count; ++p )
     938                 :            :         {
     939 [ +  - ][ +  - ]:      12744 :             AdaptiveKDTree::Plane plane = { box_min[axis] + ( p / ( 1.0 + plane_count ) ) * diff[axis], axis };
     940 [ +  - ][ +  - ]:      25488 :             Range left, right, both;
                 [ +  - ]
              [ +  -  + ]
              [ +  -  + ]
     941                 :            :             double val;
     942         [ +  - ]:      12744 :             r = intersect_children_with_elems( entities, plane, eps, box_min, box_max, left, right, both, val );
     943         [ -  + ]:      12744 :             if( MB_SUCCESS != r ) return r;
     944         [ +  - ]:      12744 :             const size_t sdiff = p_count - both.size();
     945 [ +  - ][ +  + ]:      12744 :             if( left.size() == sdiff || right.size() == sdiff ) continue;
         [ +  - ][ +  + ]
                 [ +  + ]
     946                 :            : 
     947         [ +  + ]:       2973 :             if( val >= metric_val ) continue;
     948                 :            : 
     949                 :       1366 :             metric_val = val;
     950                 :       1366 :             best_plane = plane;
     951         [ +  - ]:       1366 :             best_left.swap( left );
     952         [ +  - ]:       1366 :             best_right.swap( right );
     953         [ +  - ]:      12744 :             best_both.swap( both );
              [ +  -  + ]
     954                 :      12744 :         }
     955                 :            :     }
     956                 :            : 
     957                 :       2202 :     return MB_SUCCESS;
     958                 :            : }
     959                 :            : 
     960                 :       2670 : ErrorCode AdaptiveKDTree::best_subdivision_snap_plane( int num_planes, const AdaptiveKDTreeIter& iter, Range& best_left,
     961                 :            :                                                        Range& best_right, Range& best_both,
     962                 :            :                                                        AdaptiveKDTree::Plane& best_plane,
     963                 :            :                                                        std::vector< double >& tmp_data, double eps )
     964                 :            : {
     965                 :       2670 :     double metric_val = std::numeric_limits< unsigned >::max();
     966                 :            : 
     967                 :            :     ErrorCode r;
     968                 :            :     // const CartVect tol(eps*diff);
     969                 :            : 
     970 [ +  - ][ +  - ]:       5340 :     Range entities, vertices;
     971 [ +  - ][ +  - ]:       2670 :     r = iter.tool()->moab()->get_entities_by_handle( iter.handle(), entities );
         [ +  - ][ +  - ]
     972         [ -  + ]:       2670 :     if( MB_SUCCESS != r ) return r;
     973         [ +  - ]:       2670 :     const size_t p_count = entities.size();
     974 [ +  - ][ +  - ]:       2670 :     r                    = iter.tool()->moab()->get_adjacencies( entities, 0, false, vertices, Interface::UNION );
                 [ +  - ]
     975         [ -  + ]:       2670 :     if( MB_SUCCESS != r ) return r;
     976                 :            : 
     977         [ +  - ]:       2670 :     unsigned int nverts = vertices.size();
     978         [ +  - ]:       2670 :     tmp_data.resize( 3 * nverts );
     979 [ +  - ][ +  - ]:       2670 :     r = iter.tool()->moab()->get_coords( vertices, &tmp_data[0], &tmp_data[nverts], &tmp_data[2 * nverts] );
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     980         [ -  + ]:       2670 :     if( MB_SUCCESS != r ) return r;
     981                 :            : 
     982                 :            :     // calculate bounding box of vertices
     983                 :            :     // decide based on the actual box the splitting plane
     984                 :            :     // do not decide based on iterator box.
     985                 :            :     // it could be too big
     986                 :            :     // BoundBox box;
     987                 :            :     // r = box.update(*moab(), vertices);
     988         [ +  - ]:       2670 :     CartVect box_min;
     989         [ +  - ]:       2670 :     CartVect box_max;
     990         [ +  + ]:      10680 :     for( int dir = 0; dir < 3; dir++ )
     991                 :            :     {
     992         [ +  - ]:       8010 :         double amin = tmp_data[dir * nverts];
     993                 :       8010 :         double amax = amin;
     994         [ +  - ]:       8010 :         double* p   = &tmp_data[dir * nverts + 1];
     995         [ +  + ]:     204741 :         for( unsigned int i = 1; i < nverts; i++ )
     996                 :            :         {
     997         [ +  + ]:     196731 :             if( *p < amin ) amin = *p;
     998         [ +  + ]:     196731 :             if( *p > amax ) amax = *p;
     999                 :     196731 :             p++;
    1000                 :            :         }
    1001         [ +  - ]:       8010 :         box_min[dir] = amin;
    1002         [ +  - ]:       8010 :         box_max[dir] = amax;
    1003                 :            :     }
    1004         [ +  - ]:       2670 :     CartVect diff( box_max - box_min );
    1005                 :            : 
    1006         [ +  + ]:      10680 :     for( int axis = 0; axis < 3; ++axis )
    1007                 :            :     {
    1008                 :       8010 :         int plane_count = num_planes;
    1009                 :            : 
    1010                 :            :         // if num_planes results in width < eps, reset the plane count
    1011 [ +  - ][ +  + ]:       8010 :         if( ( num_planes + 1 ) * eps >= diff[axis] ) plane_count = (int)( diff[axis] / eps ) - 1;
                 [ +  - ]
    1012                 :            : 
    1013         [ +  + ]:      31671 :         for( int p = 1; p <= plane_count; ++p )
    1014                 :            :         {
    1015                 :            : 
    1016                 :            :             // coord of this plane on axis
    1017 [ +  - ][ +  - ]:      23661 :             double coord = box_min[axis] + ( p / ( 1.0 + plane_count ) ) * diff[axis];
    1018                 :            : 
    1019                 :            :             // find closest vertex coordinate to this plane position
    1020                 :      23661 :             unsigned int istrt   = axis * nverts;
    1021         [ +  - ]:      23661 :             double closest_coord = tmp_data[istrt];
    1022         [ +  + ]:     610497 :             for( unsigned i = 1; i < nverts; ++i )
    1023 [ +  - ][ +  + ]:     586836 :                 if( fabs( coord - tmp_data[istrt + i] ) < fabs( coord - closest_coord ) )
    1024         [ +  - ]:      58616 :                     closest_coord = tmp_data[istrt + i];
    1025 [ +  - ][ +  + ]:      38778 :             if( closest_coord - box_min[axis] <= eps || box_max[axis] - closest_coord <= eps ) continue;
         [ +  - ][ +  + ]
                 [ +  + ]
    1026                 :            : 
    1027                 :            :             // seprate elems into left/right/both, and compute separating metric
    1028                 :      19135 :             AdaptiveKDTree::Plane plane = { closest_coord, axis };
    1029 [ +  - ][ +  - ]:      38270 :             Range left, right, both;
                 [ +  - ]
              [ +  -  + ]
              [ +  +  - ]
    1030                 :            :             double val;
    1031         [ +  - ]:      19135 :             r = intersect_children_with_elems( entities, plane, eps, box_min, box_max, left, right, both, val );
    1032         [ -  + ]:      19135 :             if( MB_SUCCESS != r ) return r;
    1033         [ +  - ]:      19135 :             const size_t d = p_count - both.size();
    1034 [ +  - ][ +  + ]:      19135 :             if( left.size() == d || right.size() == d ) continue;
         [ +  - ][ +  + ]
                 [ +  + ]
    1035                 :            : 
    1036         [ +  + ]:       7634 :             if( val >= metric_val ) continue;
    1037                 :            : 
    1038                 :       4018 :             metric_val = val;
    1039                 :       4018 :             best_plane = plane;
    1040         [ +  - ]:       4018 :             best_left.swap( left );
    1041         [ +  - ]:       4018 :             best_right.swap( right );
    1042         [ +  - ]:      19135 :             best_both.swap( both );
              [ +  -  + ]
    1043                 :       4018 :         }
    1044                 :            :     }
    1045                 :            : 
    1046                 :       5340 :     return MB_SUCCESS;
    1047                 :            : }
    1048                 :            : 
    1049                 :          0 : ErrorCode AdaptiveKDTree::best_vertex_median_plane( int num_planes, const AdaptiveKDTreeIter& iter, Range& best_left,
    1050                 :            :                                                     Range& best_right, Range& best_both,
    1051                 :            :                                                     AdaptiveKDTree::Plane& best_plane, std::vector< double >& coords,
    1052                 :            :                                                     double eps )
    1053                 :            : {
    1054                 :          0 :     double metric_val = std::numeric_limits< unsigned >::max();
    1055                 :            : 
    1056                 :            :     ErrorCode r;
    1057 [ #  # ][ #  # ]:          0 :     const CartVect box_min( iter.box_min() );
    1058 [ #  # ][ #  # ]:          0 :     const CartVect box_max( iter.box_max() );
    1059                 :            : 
    1060 [ #  # ][ #  # ]:          0 :     Range entities, vertices;
    1061 [ #  # ][ #  # ]:          0 :     r = iter.tool()->moab()->get_entities_by_handle( iter.handle(), entities );
         [ #  # ][ #  # ]
    1062         [ #  # ]:          0 :     if( MB_SUCCESS != r ) return r;
    1063         [ #  # ]:          0 :     const size_t p_count = entities.size();
    1064 [ #  # ][ #  # ]:          0 :     r                    = iter.tool()->moab()->get_adjacencies( entities, 0, false, vertices, Interface::UNION );
                 [ #  # ]
    1065         [ #  # ]:          0 :     if( MB_SUCCESS != r ) return r;
    1066                 :            : 
    1067 [ #  # ][ #  # ]:          0 :     coords.resize( vertices.size() );
    1068         [ #  # ]:          0 :     for( int axis = 0; axis < 3; ++axis )
    1069                 :            :     {
    1070 [ #  # ][ #  # ]:          0 :         if( box_max[axis] - box_min[axis] <= 2 * eps ) continue;
                 [ #  # ]
    1071                 :            : 
    1072                 :          0 :         double* ptrs[] = { 0, 0, 0 };
    1073         [ #  # ]:          0 :         ptrs[axis]     = &coords[0];
    1074 [ #  # ][ #  # ]:          0 :         r              = iter.tool()->moab()->get_coords( vertices, ptrs[0], ptrs[1], ptrs[2] );
                 [ #  # ]
    1075         [ #  # ]:          0 :         if( MB_SUCCESS != r ) return r;
    1076                 :            : 
    1077         [ #  # ]:          0 :         std::sort( coords.begin(), coords.end() );
    1078                 :          0 :         std::vector< double >::iterator citer;
    1079 [ #  # ][ #  # ]:          0 :         citer              = std::upper_bound( coords.begin(), coords.end(), box_min[axis] + eps );
    1080 [ #  # ][ #  # ]:          0 :         const size_t count = std::upper_bound( citer, coords.end(), box_max[axis] - eps ) - citer;
                 [ #  # ]
    1081                 :            :         size_t step;
    1082                 :          0 :         int np = num_planes;
    1083         [ #  # ]:          0 :         if( count < 2 * (size_t)num_planes )
    1084                 :            :         {
    1085                 :          0 :             step = 1;
    1086                 :          0 :             np   = count - 1;
    1087                 :            :         }
    1088                 :            :         else
    1089                 :            :         {
    1090                 :          0 :             step = count / ( num_planes + 1 );
    1091                 :            :         }
    1092                 :            : 
    1093         [ #  # ]:          0 :         for( int p = 1; p <= np; ++p )
    1094                 :            :         {
    1095                 :            : 
    1096         [ #  # ]:          0 :             citer += step;
    1097         [ #  # ]:          0 :             AdaptiveKDTree::Plane plane = { *citer, axis };
    1098 [ #  # ][ #  # ]:          0 :             Range left, right, both;
                 [ #  # ]
              [ #  #  # ]
              [ #  #  # ]
    1099                 :            :             double val;
    1100         [ #  # ]:          0 :             r = intersect_children_with_elems( entities, plane, eps, box_min, box_max, left, right, both, val );
    1101         [ #  # ]:          0 :             if( MB_SUCCESS != r ) return r;
    1102         [ #  # ]:          0 :             const size_t diff = p_count - both.size();
    1103 [ #  # ][ #  # ]:          0 :             if( left.size() == diff || right.size() == diff ) continue;
         [ #  # ][ #  # ]
                 [ #  # ]
    1104                 :            : 
    1105         [ #  # ]:          0 :             if( val >= metric_val ) continue;
    1106                 :            : 
    1107                 :          0 :             metric_val = val;
    1108                 :          0 :             best_plane = plane;
    1109         [ #  # ]:          0 :             best_left.swap( left );
    1110         [ #  # ]:          0 :             best_right.swap( right );
    1111         [ #  # ]:          0 :             best_both.swap( both );
              [ #  #  # ]
    1112                 :          0 :         }
    1113                 :            :     }
    1114                 :            : 
    1115                 :          0 :     return MB_SUCCESS;
    1116                 :            : }
    1117                 :            : 
    1118                 :          0 : ErrorCode AdaptiveKDTree::best_vertex_sample_plane( int num_planes, const AdaptiveKDTreeIter& iter, Range& best_left,
    1119                 :            :                                                     Range& best_right, Range& best_both,
    1120                 :            :                                                     AdaptiveKDTree::Plane& best_plane, std::vector< double >& coords,
    1121                 :            :                                                     std::vector< EntityHandle >& indices, double eps )
    1122                 :            : {
    1123                 :          0 :     const size_t random_elem_threshold = 20 * num_planes;
    1124                 :          0 :     double metric_val                  = std::numeric_limits< unsigned >::max();
    1125                 :            : 
    1126                 :            :     ErrorCode r;
    1127 [ #  # ][ #  # ]:          0 :     const CartVect box_min( iter.box_min() );
    1128 [ #  # ][ #  # ]:          0 :     const CartVect box_max( iter.box_max() );
    1129                 :            : 
    1130 [ #  # ][ #  # ]:          0 :     Range entities, vertices;
    1131 [ #  # ][ #  # ]:          0 :     r = iter.tool()->moab()->get_entities_by_handle( iter.handle(), entities );
         [ #  # ][ #  # ]
    1132         [ #  # ]:          0 :     if( MB_SUCCESS != r ) return r;
    1133                 :            : 
    1134                 :            :     // We are selecting random vertex coordinates to use for candidate split
    1135                 :            :     // planes.  So if element list is large, begin by selecting random elements.
    1136         [ #  # ]:          0 :     const size_t p_count = entities.size();
    1137         [ #  # ]:          0 :     coords.resize( 3 * num_planes );
    1138         [ #  # ]:          0 :     if( p_count < random_elem_threshold )
    1139                 :            :     {
    1140 [ #  # ][ #  # ]:          0 :         r = iter.tool()->moab()->get_adjacencies( entities, 0, false, vertices, Interface::UNION );
                 [ #  # ]
    1141         [ #  # ]:          0 :         if( MB_SUCCESS != r ) return r;
    1142                 :            :     }
    1143                 :            :     else
    1144                 :            :     {
    1145         [ #  # ]:          0 :         indices.resize( random_elem_threshold );
    1146                 :          0 :         const int num_rand = p_count / RAND_MAX + 1;
    1147         [ #  # ]:          0 :         for( size_t j = 0; j < random_elem_threshold; ++j )
    1148                 :            :         {
    1149                 :          0 :             size_t rnd = rand();
    1150         [ #  # ]:          0 :             for( int i = num_rand; i > 1; --i )
    1151                 :          0 :                 rnd *= rand();
    1152                 :          0 :             rnd %= p_count;
    1153 [ #  # ][ #  # ]:          0 :             indices[j] = entities[rnd];
    1154                 :            :         }
    1155 [ #  # ][ #  # ]:          0 :         r = iter.tool()->moab()->get_adjacencies( &indices[0], random_elem_threshold, 0, false, vertices,
                 [ #  # ]
    1156         [ #  # ]:          0 :                                                   Interface::UNION );
    1157         [ #  # ]:          0 :         if( MB_SUCCESS != r ) return r;
    1158                 :            :     }
    1159                 :            : 
    1160 [ #  # ][ #  # ]:          0 :     coords.resize( vertices.size() );
    1161         [ #  # ]:          0 :     for( int axis = 0; axis < 3; ++axis )
    1162                 :            :     {
    1163 [ #  # ][ #  # ]:          0 :         if( box_max[axis] - box_min[axis] <= 2 * eps ) continue;
                 [ #  # ]
    1164                 :            : 
    1165                 :          0 :         double* ptrs[] = { 0, 0, 0 };
    1166         [ #  # ]:          0 :         ptrs[axis]     = &coords[0];
    1167 [ #  # ][ #  # ]:          0 :         r              = iter.tool()->moab()->get_coords( vertices, ptrs[0], ptrs[1], ptrs[2] );
                 [ #  # ]
    1168         [ #  # ]:          0 :         if( MB_SUCCESS != r ) return r;
    1169                 :            : 
    1170                 :          0 :         size_t num_valid_coords = 0;
    1171         [ #  # ]:          0 :         for( size_t i = 0; i < coords.size(); ++i )
    1172 [ #  # ][ #  # ]:          0 :             if( coords[i] > box_min[axis] + eps && coords[i] < box_max[axis] - eps ) ++num_valid_coords;
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    1173                 :            : 
    1174         [ #  # ]:          0 :         if( 2 * (size_t)num_planes > num_valid_coords )
    1175                 :            :         {
    1176                 :          0 :             indices.clear();
    1177         [ #  # ]:          0 :             for( size_t i = 0; i < coords.size(); ++i )
    1178 [ #  # ][ #  # ]:          0 :                 if( coords[i] > box_min[axis] + eps && coords[i] < box_max[axis] - eps ) indices.push_back( i );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1179                 :            :         }
    1180                 :            :         else
    1181                 :            :         {
    1182         [ #  # ]:          0 :             indices.resize( num_planes );
    1183                 :            :             // make sure random indices are sufficient to cover entire range
    1184                 :          0 :             const int num_rand = coords.size() / RAND_MAX + 1;
    1185         [ #  # ]:          0 :             for( int j = 0; j < num_planes; ++j )
    1186                 :            :             {
    1187                 :            :                 size_t rnd;
    1188         [ #  # ]:          0 :                 do
    1189                 :            :                 {
    1190                 :          0 :                     rnd = rand();
    1191         [ #  # ]:          0 :                     for( int i = num_rand; i > 1; --i )
    1192                 :          0 :                         rnd *= rand();
    1193                 :          0 :                     rnd %= coords.size();
    1194 [ #  # ][ #  # ]:          0 :                 } while( coords[rnd] <= box_min[axis] + eps || coords[rnd] >= box_max[axis] - eps );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    1195         [ #  # ]:          0 :                 indices[j] = rnd;
    1196                 :            :             }
    1197                 :            :         }
    1198                 :            : 
    1199         [ #  # ]:          0 :         for( unsigned p = 0; p < indices.size(); ++p )
    1200                 :            :         {
    1201                 :            : 
    1202 [ #  # ][ #  # ]:          0 :             AdaptiveKDTree::Plane plane = { coords[indices[p]], axis };
    1203 [ #  # ][ #  # ]:          0 :             Range left, right, both;
                 [ #  # ]
              [ #  #  # ]
              [ #  #  # ]
    1204                 :            :             double val;
    1205         [ #  # ]:          0 :             r = intersect_children_with_elems( entities, plane, eps, box_min, box_max, left, right, both, val );
    1206         [ #  # ]:          0 :             if( MB_SUCCESS != r ) return r;
    1207         [ #  # ]:          0 :             const size_t diff = p_count - both.size();
    1208 [ #  # ][ #  # ]:          0 :             if( left.size() == diff || right.size() == diff ) continue;
         [ #  # ][ #  # ]
                 [ #  # ]
    1209                 :            : 
    1210         [ #  # ]:          0 :             if( val >= metric_val ) continue;
    1211                 :            : 
    1212                 :          0 :             metric_val = val;
    1213                 :          0 :             best_plane = plane;
    1214         [ #  # ]:          0 :             best_left.swap( left );
    1215         [ #  # ]:          0 :             best_right.swap( right );
    1216         [ #  # ]:          0 :             best_both.swap( both );
              [ #  #  # ]
    1217                 :          0 :         }
    1218                 :            :     }
    1219                 :            : 
    1220                 :          0 :     return MB_SUCCESS;
    1221                 :            : }
    1222                 :            : 
    1223                 :       2002 : ErrorCode AdaptiveKDTree::point_search( const double* point, EntityHandle& leaf_out, const double iter_tol,
    1224                 :            :                                         const double inside_tol, bool* multiple_leaves, EntityHandle* start_node,
    1225                 :            :                                         CartVect* params )
    1226                 :            : {
    1227         [ +  - ]:       2002 :     std::vector< EntityHandle > children;
    1228                 :            :     Plane plane;
    1229                 :            : 
    1230                 :       2002 :     treeStats.numTraversals++;
    1231                 :       2002 :     leaf_out = 0;
    1232         [ +  - ]:       4004 :     BoundBox box;
    1233                 :            :     // kdtrees never have multiple leaves containing a pt
    1234         [ -  + ]:       2002 :     if( multiple_leaves ) *multiple_leaves = false;
    1235                 :            : 
    1236         [ +  + ]:       2002 :     EntityHandle node = ( start_node ? *start_node : myRoot );
    1237                 :            : 
    1238                 :       2002 :     treeStats.nodesVisited++;
    1239         [ +  - ]:       2002 :     ErrorCode rval = get_bounding_box( box, &node );
    1240         [ -  + ]:       2002 :     if( MB_SUCCESS != rval ) return rval;
    1241 [ +  - ][ -  + ]:       2002 :     if( !box.contains_point( point, iter_tol ) ) return MB_SUCCESS;
    1242                 :            : 
    1243 [ +  - ][ +  - ]:       2002 :     rval = moab()->get_child_meshsets( node, children );
    1244         [ -  + ]:       2002 :     if( MB_SUCCESS != rval ) return rval;
    1245                 :            : 
    1246         [ +  + ]:      20014 :     while( !children.empty() )
    1247                 :            :     {
    1248                 :      18012 :         treeStats.nodesVisited++;
    1249                 :            : 
    1250         [ +  - ]:      18012 :         rval = get_split_plane( node, plane );
    1251         [ -  + ]:      18012 :         if( MB_SUCCESS != rval ) return rval;
    1252                 :            : 
    1253                 :      18012 :         const double d = point[plane.norm] - plane.coord;
    1254         [ +  - ]:      18012 :         node           = children[( d > 0.0 )];
    1255                 :            : 
    1256                 :      18012 :         children.clear();
    1257 [ +  - ][ +  - ]:      18012 :         rval = moab()->get_child_meshsets( node, children );
    1258         [ -  + ]:      18012 :         if( MB_SUCCESS != rval ) return rval;
    1259                 :            :     }
    1260                 :            : 
    1261                 :       2002 :     treeStats.leavesVisited++;
    1262 [ +  + ][ +  - ]:       2002 :     if( myEval && params )
    1263                 :            :     {
    1264                 :            :         rval = myEval->find_containing_entity( node, point, iter_tol, inside_tol, leaf_out, params->array(),
    1265 [ +  - ][ +  - ]:       1000 :                                                &treeStats.traversalLeafObjectTests );
    1266         [ -  + ]:       1000 :         if( MB_SUCCESS != rval ) return rval;
    1267                 :            :     }
    1268                 :            :     else
    1269                 :       1002 :         leaf_out = node;
    1270                 :            : 
    1271                 :       4004 :     return MB_SUCCESS;
    1272                 :            : }
    1273                 :            : 
    1274                 :          2 : ErrorCode AdaptiveKDTree::point_search( const double* point, AdaptiveKDTreeIter& leaf_it, const double iter_tol,
    1275                 :            :                                         const double /*inside_tol*/, bool* multiple_leaves, EntityHandle* start_node )
    1276                 :            : {
    1277                 :            :     ErrorCode rval;
    1278                 :          2 :     treeStats.numTraversals++;
    1279                 :            : 
    1280                 :            :     // kdtrees never have multiple leaves containing a pt
    1281         [ -  + ]:          2 :     if( multiple_leaves ) *multiple_leaves = false;
    1282                 :            : 
    1283                 :          2 :     leaf_it.mBox[0] = boundBox.bMin;
    1284                 :          2 :     leaf_it.mBox[1] = boundBox.bMax;
    1285                 :            : 
    1286                 :            :     // test that point is inside tree
    1287 [ +  - ][ -  + ]:          2 :     if( !boundBox.contains_point( point, iter_tol ) )
    1288                 :            :     {
    1289                 :          0 :         treeStats.nodesVisited++;
    1290                 :          0 :         return MB_ENTITY_NOT_FOUND;
    1291                 :            :     }
    1292                 :            : 
    1293                 :            :     // initialize iterator at tree root
    1294                 :          2 :     leaf_it.treeTool = this;
    1295                 :          2 :     leaf_it.mStack.clear();
    1296 [ +  + ][ +  - ]:          2 :     leaf_it.mStack.push_back( AdaptiveKDTreeIter::StackObj( ( start_node ? *start_node : myRoot ), 0 ) );
                 [ +  - ]
    1297                 :            : 
    1298                 :            :     // loop until we reach a leaf
    1299                 :            :     AdaptiveKDTree::Plane plane;
    1300                 :            :     for( ;; )
    1301                 :            :     {
    1302                 :         14 :         treeStats.nodesVisited++;
    1303                 :            : 
    1304                 :            :         // get children
    1305                 :         14 :         leaf_it.childVect.clear();
    1306 [ +  - ][ +  - ]:         14 :         rval = moab()->get_child_meshsets( leaf_it.handle(), leaf_it.childVect );
                 [ +  - ]
    1307         [ -  + ]:         14 :         if( MB_SUCCESS != rval ) return rval;
    1308                 :            : 
    1309                 :            :         // if no children, then at leaf (done)
    1310         [ +  + ]:         14 :         if( leaf_it.childVect.empty() )
    1311                 :            :         {
    1312                 :          2 :             treeStats.leavesVisited++;
    1313                 :          2 :             break;
    1314                 :            :         }
    1315                 :            : 
    1316                 :            :         // get split plane
    1317 [ +  - ][ +  - ]:         12 :         rval = get_split_plane( leaf_it.handle(), plane );
    1318         [ -  + ]:         12 :         if( MB_SUCCESS != rval ) return rval;
    1319                 :            : 
    1320                 :            :         // step iterator to appropriate child
    1321                 :            :         // idx: 0->left, 1->right
    1322                 :         12 :         const int idx = ( point[plane.norm] > plane.coord );
    1323                 :            :         leaf_it.mStack.push_back(
    1324 [ +  - ][ +  - ]:         12 :             AdaptiveKDTreeIter::StackObj( leaf_it.childVect[idx], leaf_it.mBox[1 - idx][plane.norm] ) );
         [ +  - ][ +  - ]
    1325         [ +  - ]:         12 :         leaf_it.mBox[1 - idx][plane.norm] = plane.coord;
    1326                 :         12 :     }
    1327                 :            : 
    1328                 :          2 :     return MB_SUCCESS;
    1329                 :            : }
    1330                 :            : 
    1331                 :       4574 : struct NodeDistance
    1332                 :            : {
    1333                 :            :     EntityHandle handle;
    1334                 :            :     CartVect dist;  // from_point - closest_point_on_box
    1335                 :            : };
    1336                 :            : 
    1337                 :       2287 : ErrorCode AdaptiveKDTree::distance_search( const double from_point[3], const double distance,
    1338                 :            :                                            std::vector< EntityHandle >& result_list, const double iter_tol,
    1339                 :            :                                            const double inside_tol, std::vector< double >* result_dists,
    1340                 :            :                                            std::vector< CartVect >* result_params, EntityHandle* tree_root )
    1341                 :            : {
    1342                 :       2287 :     treeStats.numTraversals++;
    1343                 :       2287 :     const double dist_sqr = distance * distance;
    1344         [ +  - ]:       2287 :     const CartVect from( from_point );
    1345         [ +  - ]:       2287 :     std::vector< NodeDistance > list,
    1346         [ +  - ]:       4574 :         result_list_nodes;  // list of subtrees to traverse, and results
    1347                 :            :                             // pre-allocate space for default max tree depth
    1348         [ +  - ]:       2287 :     list.reserve( maxDepth );
    1349                 :            : 
    1350                 :            :     // misc temporary values
    1351                 :            :     Plane plane;
    1352         [ +  - ]:       2287 :     NodeDistance node;
    1353                 :            :     ErrorCode rval;
    1354         [ +  - ]:       4574 :     std::vector< EntityHandle > children;
    1355                 :            : 
    1356                 :            :     // Get distance from input position to bounding box of tree
    1357                 :            :     // (zero if inside box)
    1358         [ +  - ]:       4574 :     BoundBox box;
    1359         [ +  - ]:       2287 :     rval = get_bounding_box( box );
    1360 [ +  - ][ +  - ]:       2287 :     if( MB_SUCCESS == rval && !box.contains_point( from_point, iter_tol ) )
         [ +  + ][ +  + ]
    1361                 :            :     {
    1362                 :         18 :         treeStats.nodesVisited++;
    1363                 :         18 :         return MB_SUCCESS;
    1364                 :            :     }
    1365                 :            : 
    1366                 :            :     // if bounding box is not available (e.g. not starting from true root)
    1367                 :            :     // just start with zero.  Less efficient, but will work.
    1368         [ +  - ]:       2269 :     node.dist = CartVect( 0.0 );
    1369         [ +  - ]:       2269 :     if( MB_SUCCESS == rval )
    1370                 :            :     {
    1371         [ +  + ]:       9076 :         for( int i = 0; i < 3; ++i )
    1372                 :            :         {
    1373 [ +  - ][ -  + ]:       6807 :             if( from_point[i] < box.bMin[i] )
    1374 [ #  # ][ #  # ]:          0 :                 node.dist[i] = box.bMin[i] - from_point[i];
    1375 [ +  - ][ -  + ]:       6807 :             else if( from_point[i] > box.bMax[i] )
    1376 [ #  # ][ #  # ]:          0 :                 node.dist[i] = from_point[i] - box.bMax[i];
    1377                 :            :         }
    1378 [ +  - ][ -  + ]:       2269 :         if( node.dist % node.dist > dist_sqr )
    1379                 :            :         {
    1380                 :          0 :             treeStats.nodesVisited++;
    1381                 :       2269 :             return MB_SUCCESS;
    1382                 :            :         }
    1383                 :            :     }
    1384                 :            : 
    1385                 :            :     // begin with root in list
    1386         [ +  + ]:       2269 :     node.handle = ( tree_root ? *tree_root : myRoot );
    1387         [ +  - ]:       2269 :     list.push_back( node );
    1388                 :            : 
    1389         [ +  + ]:      47417 :     while( !list.empty() )
    1390                 :            :     {
    1391                 :            : 
    1392         [ +  - ]:      45148 :         node = list.back();
    1393         [ +  - ]:      45148 :         list.pop_back();
    1394                 :      45148 :         treeStats.nodesVisited++;
    1395                 :            : 
    1396                 :            :         // If leaf node, test contained triangles
    1397                 :      45148 :         children.clear();
    1398 [ +  - ][ +  - ]:      45148 :         rval = moab()->get_child_meshsets( node.handle, children );
    1399         [ +  + ]:      45148 :         if( children.empty() )
    1400                 :            :         {
    1401                 :      10524 :             treeStats.leavesVisited++;
    1402 [ -  + ][ #  # ]:      10524 :             if( myEval && result_params )
    1403                 :            :             {
    1404                 :            :                 EntityHandle ent;
    1405         [ #  # ]:          0 :                 CartVect params;
    1406                 :            :                 rval = myEval->find_containing_entity( node.handle, from_point, iter_tol, inside_tol, ent,
    1407 [ #  # ][ #  # ]:          0 :                                                        params.array(), &treeStats.traversalLeafObjectTests );
    1408         [ #  # ]:          0 :                 if( MB_SUCCESS != rval )
    1409                 :          0 :                     return rval;
    1410         [ #  # ]:          0 :                 else if( ent )
    1411                 :            :                 {
    1412         [ #  # ]:          0 :                     result_list.push_back( ent );
    1413         [ #  # ]:          0 :                     result_params->push_back( params );
    1414 [ #  # ][ #  # ]:          0 :                     if( result_dists ) result_dists->push_back( 0.0 );
    1415                 :          0 :                 }
    1416                 :            :             }
    1417                 :            :             else
    1418                 :            :             {
    1419         [ +  - ]:      10524 :                 result_list_nodes.push_back( node );
    1420                 :      10524 :                 continue;
    1421                 :            :             }
    1422                 :            :         }
    1423                 :            : 
    1424                 :            :         // If not leaf node, add children to working list
    1425         [ +  - ]:      34624 :         rval = get_split_plane( node.handle, plane );
    1426         [ -  + ]:      34624 :         if( MB_SUCCESS != rval ) return rval;
    1427                 :            : 
    1428         [ +  - ]:      34624 :         const double d = from[plane.norm] - plane.coord;
    1429                 :            : 
    1430                 :            :         // right of plane?
    1431         [ +  + ]:      34624 :         if( d > 0 )
    1432                 :            :         {
    1433         [ +  - ]:      15208 :             node.handle = children[1];
    1434         [ +  - ]:      15208 :             list.push_back( node );
    1435                 :            :             // if the split plane is close to the input point, add
    1436                 :            :             // the left child also (we'll check the exact distance
    1437                 :            :             /// when we pop it from the list.)
    1438         [ -  + ]:      15208 :             if( d <= distance )
    1439                 :            :             {
    1440         [ #  # ]:          0 :                 node.dist[plane.norm] = d;
    1441 [ #  # ][ #  # ]:          0 :                 if( node.dist % node.dist <= dist_sqr )
    1442                 :            :                 {
    1443         [ #  # ]:          0 :                     node.handle = children[0];
    1444         [ #  # ]:          0 :                     list.push_back( node );
    1445                 :            :                 }
    1446                 :            :             }
    1447                 :            :         }
    1448                 :            :         // left of plane
    1449                 :            :         else
    1450                 :            :         {
    1451         [ +  - ]:      19416 :             node.handle = children[0];
    1452         [ +  - ]:      19416 :             list.push_back( node );
    1453                 :            :             // if the split plane is close to the input point, add
    1454                 :            :             // the right child also (we'll check the exact distance
    1455                 :            :             /// when we pop it from the list.)
    1456         [ +  + ]:      19416 :             if( -d <= distance )
    1457                 :            :             {
    1458         [ +  - ]:       8255 :                 node.dist[plane.norm] = -d;
    1459 [ +  - ][ +  - ]:       8255 :                 if( node.dist % node.dist <= dist_sqr )
    1460                 :            :                 {
    1461         [ +  - ]:       8255 :                     node.handle = children[1];
    1462         [ +  - ]:       8255 :                     list.push_back( node );
    1463                 :            :                 }
    1464                 :            :             }
    1465                 :            :         }
    1466                 :            :     }
    1467                 :            : 
    1468 [ -  + ][ #  # ]:       2269 :     if( myEval && result_params ) return MB_SUCCESS;
    1469                 :            : 
    1470                 :            :     // separate loops to avoid if test inside loop
    1471                 :            : 
    1472         [ +  - ]:       2269 :     result_list.reserve( result_list_nodes.size() );
    1473 [ +  - ][ +  - ]:      12793 :     for( std::vector< NodeDistance >::iterator vit = result_list_nodes.begin(); vit != result_list_nodes.end(); ++vit )
                 [ +  + ]
    1474 [ +  - ][ +  - ]:      10524 :         result_list.push_back( ( *vit ).handle );
    1475                 :            : 
    1476 [ -  + ][ #  # ]:       2269 :     if( result_dists && distance > 0.0 )
    1477                 :            :     {
    1478         [ #  # ]:          0 :         result_dists->reserve( result_list_nodes.size() );
    1479 [ #  # ][ #  # ]:          0 :         for( std::vector< NodeDistance >::iterator vit = result_list_nodes.begin(); vit != result_list_nodes.end();
                 [ #  # ]
    1480                 :            :              ++vit )
    1481 [ #  # ][ #  # ]:          0 :             result_dists->push_back( ( *vit ).dist.length() );
                 [ #  # ]
    1482                 :            :     }
    1483                 :            : 
    1484                 :       4556 :     return MB_SUCCESS;
    1485                 :            : }
    1486                 :            : 
    1487                 :         49 : static ErrorCode closest_to_triangles( Interface* moab, const Range& tris, const CartVect& from,
    1488                 :            :                                        double& shortest_dist_sqr, CartVect& closest_pt, EntityHandle& closest_tri )
    1489                 :            : {
    1490                 :            :     ErrorCode rval;
    1491 [ +  - ][ +  - ]:        196 :     CartVect pos, diff, verts[3];
         [ +  - ][ +  + ]
    1492                 :         49 :     const EntityHandle* conn = NULL;
    1493                 :         49 :     int len                  = 0;
    1494                 :            : 
    1495 [ +  - ][ +  - ]:        265 :     for( Range::iterator i = tris.begin(); i != tris.end(); ++i )
         [ +  - ][ +  - ]
                 [ +  + ]
    1496                 :            :     {
    1497 [ +  - ][ +  - ]:        216 :         rval = moab->get_connectivity( *i, conn, len );
    1498         [ -  + ]:        265 :         if( MB_SUCCESS != rval ) return rval;
    1499                 :            : 
    1500 [ +  - ][ +  - ]:        216 :         rval = moab->get_coords( conn, 3, verts[0].array() );
    1501         [ -  + ]:        216 :         if( MB_SUCCESS != rval ) return rval;
    1502                 :            : 
    1503         [ +  - ]:        216 :         GeomUtil::closest_location_on_tri( from, verts, pos );
    1504         [ +  - ]:        216 :         diff            = pos - from;
    1505         [ +  - ]:        216 :         double dist_sqr = diff % diff;
    1506         [ +  + ]:        216 :         if( dist_sqr < shortest_dist_sqr )
    1507                 :            :         {
    1508                 :            :             // new closest location
    1509                 :         65 :             shortest_dist_sqr = dist_sqr;
    1510                 :         65 :             closest_pt        = pos;
    1511         [ +  - ]:         65 :             closest_tri       = *i;
    1512                 :            :         }
    1513                 :            :     }
    1514                 :            : 
    1515                 :         49 :     return MB_SUCCESS;
    1516                 :            : }
    1517                 :            : 
    1518                 :         19 : static ErrorCode closest_to_triangles( Interface* moab, EntityHandle set_handle, const CartVect& from,
    1519                 :            :                                        double& shortest_dist_sqr, CartVect& closest_pt, EntityHandle& closest_tri )
    1520                 :            : {
    1521                 :            :     ErrorCode rval;
    1522         [ +  - ]:         19 :     Range tris;
    1523                 :            : 
    1524         [ +  - ]:         19 :     rval = moab->get_entities_by_type( set_handle, MBTRI, tris );
    1525         [ -  + ]:         19 :     if( MB_SUCCESS != rval ) return rval;
    1526                 :            : 
    1527         [ +  - ]:         19 :     return closest_to_triangles( moab, tris, from, shortest_dist_sqr, closest_pt, closest_tri );
    1528                 :            : }
    1529                 :            : 
    1530                 :         30 : ErrorCode AdaptiveKDTree::find_close_triangle( EntityHandle root, const double from[3], double pt[3],
    1531                 :            :                                                EntityHandle& triangle )
    1532                 :            : {
    1533                 :            :     ErrorCode rval;
    1534         [ +  - ]:         30 :     Range tris;
    1535                 :            :     Plane split;
    1536         [ +  - ]:         60 :     std::vector< EntityHandle > stack;
    1537         [ +  - ]:         60 :     std::vector< EntityHandle > children( 2 );
    1538         [ +  - ]:         30 :     stack.reserve( 30 );
    1539         [ -  + ]:         30 :     assert( root );
    1540         [ +  - ]:         30 :     stack.push_back( root );
    1541                 :            : 
    1542         [ +  - ]:         30 :     while( !stack.empty() )
    1543                 :            :     {
    1544         [ +  - ]:         30 :         EntityHandle node = stack.back();
    1545         [ +  - ]:         30 :         stack.pop_back();
    1546                 :            : 
    1547                 :            :         for( ;; )
    1548                 :            :         {  // loop until we find a leaf
    1549                 :            : 
    1550                 :        191 :             children.clear();
    1551 [ +  - ][ +  - ]:        191 :             rval = moab()->get_child_meshsets( node, children );
    1552         [ -  + ]:        191 :             if( MB_SUCCESS != rval ) return rval;
    1553                 :            : 
    1554                 :            :             // loop termination criterion
    1555         [ +  + ]:        191 :             if( children.empty() ) break;
    1556                 :            : 
    1557                 :            :             // if not a leaf, get split plane
    1558         [ +  - ]:        161 :             rval = get_split_plane( node, split );
    1559         [ -  + ]:        161 :             if( MB_SUCCESS != rval ) return rval;
    1560                 :            : 
    1561                 :            :             // continue down the side that contains the point,
    1562                 :            :             // and push the other side onto the stack in case
    1563                 :            :             // we need to check it later.
    1564         [ +  - ]:        161 :             int rs = split.right_side( from );
    1565         [ +  - ]:        161 :             node   = children[rs];
    1566 [ +  - ][ +  - ]:        161 :             stack.push_back( children[1 - rs] );
    1567                 :        161 :         }
    1568                 :            : 
    1569                 :            :         // We should now be at a leaf.
    1570                 :            :         // If it has some triangles, we're done.
    1571                 :            :         // If not, continue searching for another leaf.
    1572         [ +  - ]:         30 :         tris.clear();
    1573 [ +  - ][ +  - ]:         30 :         rval = moab()->get_entities_by_type( node, MBTRI, tris );
    1574 [ +  - ][ +  - ]:         30 :         if( !tris.empty() )
    1575                 :            :         {
    1576                 :         30 :             double dist_sqr = HUGE_VAL;
    1577         [ +  - ]:         30 :             CartVect point( pt );
    1578 [ +  - ][ +  - ]:         30 :             rval = closest_to_triangles( moab(), tris, CartVect( from ), dist_sqr, point, triangle );
                 [ +  - ]
    1579         [ +  - ]:         30 :             point.get( pt );
    1580                 :         30 :             return rval;
    1581                 :            :         }
    1582                 :            :     }
    1583                 :            : 
    1584                 :            :     // If we got here, then we traversed the entire tree
    1585                 :            :     // and all the leaves were empty.
    1586                 :         30 :     return MB_ENTITY_NOT_FOUND;
    1587                 :            : }
    1588                 :            : 
    1589                 :            : /** Find the triangles in a set that are closer to the input
    1590                 :            :  *  position than any triangles in the 'closest_tris' list.
    1591                 :            :  *
    1592                 :            :  *  closest_tris is assumed to contain a list of triangles for
    1593                 :            :  *  which the first is the closest known triangle to the input
    1594                 :            :  *  position and the first entry in 'closest_pts' is the closest
    1595                 :            :  *  location on that triangle.  Any other values in the lists must
    1596                 :            :  *  be other triangles for which the closest point is within the
    1597                 :            :  *  input tolerance of the closest closest point.  This function
    1598                 :            :  *  will update the lists as appropriate if any closer triangles
    1599                 :            :  *  or triangles within the tolerance of the current closest location
    1600                 :            :  *  are found.  The first entry is maintained as the closest of the
    1601                 :            :  *  list of triangles.
    1602                 :            :  */
    1603                 :            : /*
    1604                 :            :   static ErrorCode closest_to_triangles( Interface* moab,
    1605                 :            :   EntityHandle set_handle,
    1606                 :            :   double tolerance,
    1607                 :            :   const CartVect& from,
    1608                 :            :   std::vector<EntityHandle>& closest_tris,
    1609                 :            :   std::vector<CartVect>& closest_pts )
    1610                 :            :   {
    1611                 :            :   ErrorCode rval;
    1612                 :            :   Range tris;
    1613                 :            :   CartVect pos, diff, verts[3];
    1614                 :            :   const EntityHandle* conn;
    1615                 :            :   int len;
    1616                 :            :   double shortest_dist_sqr = HUGE_VAL;
    1617                 :            :   if (!closest_pts.empty()) {
    1618                 :            :   diff = from - closest_pts.front();
    1619                 :            :   shortest_dist_sqr = diff % diff;
    1620                 :            :   }
    1621                 :            : 
    1622                 :            :   rval = moab->get_entities_by_type( set_handle, MBTRI, tris );
    1623                 :            :   if (MB_SUCCESS != rval)
    1624                 :            :   return rval;
    1625                 :            : 
    1626                 :            :   for (Range::iterator i = tris.begin(); i != tris.end(); ++i) {
    1627                 :            :   rval = moab->get_connectivity( *i, conn, len );
    1628                 :            :   if (MB_SUCCESS != rval)
    1629                 :            :   return rval;
    1630                 :            : 
    1631                 :            :   rval = moab->get_coords( conn, 3, verts[0].array() );
    1632                 :            :   if (MB_SUCCESS != rval)
    1633                 :            :   return rval;
    1634                 :            : 
    1635                 :            :   GeomUtil::closest_location_on_tri( from, verts, pos );
    1636                 :            :   diff = pos - from;
    1637                 :            :   double dist_sqr = diff % diff;
    1638                 :            :   if (dist_sqr < shortest_dist_sqr) {
    1639                 :            :     // new closest location
    1640                 :            :     shortest_dist_sqr = dist_sqr;
    1641                 :            : 
    1642                 :            :     if (closest_pts.empty()) {
    1643                 :            :     closest_tris.push_back( *i );
    1644                 :            :     closest_pts.push_back( pos );
    1645                 :            :     }
    1646                 :            :       // if have a previous closest location
    1647                 :            :       else {
    1648                 :            :         // if previous closest is more than 2*tolerance away
    1649                 :            :           // from new closest, then nothing in the list can
    1650                 :            :           // be within tolerance of new closest point.
    1651                 :            :           diff = pos - closest_pts.front();
    1652                 :            :           dist_sqr = diff % diff;
    1653                 :            :           if (dist_sqr > 4.0 * tolerance * tolerance) {
    1654                 :            :           closest_tris.clear();
    1655                 :            :           closest_pts.clear();
    1656                 :            :           closest_tris.push_back( *i );
    1657                 :            :           closest_pts.push_back( pos );
    1658                 :            :           }
    1659                 :            :             // otherwise need to remove any triangles that are
    1660                 :            :               // not within tolerance of the new closest point.
    1661                 :            :               else {
    1662                 :            :               unsigned r = 0, w = 0;
    1663                 :            :               for (r = 0; r < closest_pts.size(); ++r) {
    1664                 :            :               diff = pos - closest_pts[r];
    1665                 :            :               if (diff % diff <= tolerance*tolerance) {
    1666                 :            :               closest_pts[w] = closest_pts[r];
    1667                 :            :               closest_tris[w] = closest_tris[r];
    1668                 :            :               ++w;
    1669                 :            :               }
    1670                 :            :               }
    1671                 :            :               closest_pts.resize( w + 1 );
    1672                 :            :               closest_tris.resize( w + 1 );
    1673                 :            :                 // always put the closest one in the front
    1674                 :            :                 if (w > 0) {
    1675                 :            :                 closest_pts.back() = closest_pts.front();
    1676                 :            :                 closest_tris.back() = closest_tris.front();
    1677                 :            :                 }
    1678                 :            :                 closest_pts.front() = pos;
    1679                 :            :                 closest_tris.front() = *i;
    1680                 :            :                 }
    1681                 :            :                 }
    1682                 :            :                 }
    1683                 :            :                 else {
    1684                 :            :                   // If within tolerance of old closest triangle,
    1685                 :            :                     // add this one to the list.
    1686                 :            :                     diff = closest_pts.front() - pos;
    1687                 :            :                     if (diff % diff <= tolerance*tolerance) {
    1688                 :            :                     closest_pts.push_back( pos );
    1689                 :            :                     closest_tris.push_back( *i );
    1690                 :            :                     }
    1691                 :            :                     }
    1692                 :            :                     }
    1693                 :            : 
    1694                 :            :                     return MB_SUCCESS;
    1695                 :            :                     }
    1696                 :            : */
    1697                 :            : 
    1698                 :         30 : ErrorCode AdaptiveKDTree::closest_triangle( EntityHandle tree_root, const double from_coords[3],
    1699                 :            :                                             double closest_point_out[3], EntityHandle& triangle_out )
    1700                 :            : {
    1701                 :            :     ErrorCode rval;
    1702                 :         30 :     double shortest_dist_sqr = HUGE_VAL;
    1703         [ +  - ]:         30 :     std::vector< EntityHandle > leaves;
    1704         [ +  - ]:         30 :     const CartVect from( from_coords );
    1705         [ +  - ]:         30 :     CartVect closest_pt;
    1706                 :            : 
    1707                 :            :     // Find the leaf containing the input point
    1708                 :            :     // This search does not take into account any bounding box for the
    1709                 :            :     // tree, so it always returns one leaf.
    1710         [ -  + ]:         30 :     assert( tree_root );
    1711 [ +  - ][ +  - ]:         30 :     rval = find_close_triangle( tree_root, from_coords, closest_pt.array(), triangle_out );
    1712         [ -  + ]:         30 :     if( MB_SUCCESS != rval ) return rval;
    1713                 :            : 
    1714                 :            :     // Find any other leaves for which the bounding box is within
    1715                 :            :     // the same distance from the input point as the current closest
    1716                 :            :     // point is.
    1717         [ +  - ]:         30 :     CartVect diff = closest_pt - from;
    1718 [ +  - ][ +  - ]:         30 :     rval = distance_search( from_coords, sqrt( diff % diff ), leaves, 1.0e-10, 1.0e-6, NULL, NULL, &tree_root );
    1719         [ -  + ]:         30 :     if( MB_SUCCESS != rval ) return rval;
    1720                 :            : 
    1721                 :            :     // Check any close leaves to see if they contain triangles that
    1722                 :            :     // are as close to or closer than the current closest triangle(s).
    1723         [ +  + ]:         49 :     for( unsigned i = 0; i < leaves.size(); ++i )
    1724                 :            :     {
    1725 [ +  - ][ +  - ]:         19 :         rval = closest_to_triangles( moab(), leaves[i], from, shortest_dist_sqr, closest_pt, triangle_out );
                 [ +  - ]
    1726         [ -  + ]:         19 :         if( MB_SUCCESS != rval ) return rval;
    1727                 :            :     }
    1728                 :            : 
    1729                 :            :     // pass back resulting position
    1730         [ +  - ]:         30 :     closest_pt.get( closest_point_out );
    1731                 :         30 :     return MB_SUCCESS;
    1732                 :            : }
    1733                 :            : 
    1734                 :         16 : ErrorCode AdaptiveKDTree::sphere_intersect_triangles( EntityHandle tree_root, const double center[3], double radius,
    1735                 :            :                                                       std::vector< EntityHandle >& triangles )
    1736                 :            : {
    1737                 :            :     ErrorCode rval;
    1738         [ +  - ]:         16 :     std::vector< EntityHandle > leaves;
    1739         [ +  - ]:         16 :     const CartVect from( center );
    1740         [ +  - ]:         16 :     CartVect closest_pt;
    1741                 :            :     const EntityHandle* conn;
    1742 [ +  - ][ +  + ]:         64 :     CartVect coords[3];
    1743                 :            :     int conn_len;
    1744                 :            : 
    1745                 :            :     // get leaves of tree that intersect sphere
    1746         [ -  + ]:         16 :     assert( tree_root );
    1747         [ +  - ]:         16 :     rval = distance_search( center, radius, leaves, 1.0e-10, 1.0e-6, NULL, NULL, &tree_root );
    1748         [ -  + ]:         16 :     if( MB_SUCCESS != rval ) return rval;
    1749                 :            : 
    1750                 :            :     // search each leaf for triangles intersecting sphere
    1751         [ +  + ]:         32 :     for( unsigned i = 0; i < leaves.size(); ++i )
    1752                 :            :     {
    1753         [ +  - ]:         16 :         Range tris;
    1754 [ +  - ][ +  - ]:         16 :         rval = moab()->get_entities_by_type( leaves[i], MBTRI, tris );
                 [ +  - ]
    1755         [ -  + ]:         16 :         if( MB_SUCCESS != rval ) return rval;
    1756                 :            : 
    1757 [ +  - ][ +  - ]:        100 :         for( Range::iterator j = tris.begin(); j != tris.end(); ++j )
         [ +  - ][ +  - ]
                 [ +  + ]
    1758                 :            :         {
    1759 [ +  - ][ +  - ]:         84 :             rval = moab()->get_connectivity( *j, conn, conn_len );
                 [ +  - ]
    1760 [ -  + ][ +  - ]:        100 :             if( MB_SUCCESS != rval ) return rval;
    1761 [ +  - ][ +  - ]:         84 :             rval = moab()->get_coords( conn, 3, coords[0].array() );
                 [ +  - ]
    1762         [ -  + ]:         84 :             if( MB_SUCCESS != rval ) return rval;
    1763         [ +  - ]:         84 :             GeomUtil::closest_location_on_tri( from, coords, closest_pt );
    1764         [ +  - ]:         84 :             closest_pt -= from;
    1765 [ +  - ][ +  + ]:         84 :             if( ( closest_pt % closest_pt ) <= ( radius * radius ) ) triangles.push_back( *j );
         [ +  - ][ +  - ]
    1766                 :            :         }
    1767                 :         16 :     }
    1768                 :            : 
    1769                 :            :     // remove duplicates from triangle list
    1770         [ +  - ]:         16 :     std::sort( triangles.begin(), triangles.end() );
    1771 [ +  - ][ +  - ]:         16 :     triangles.erase( std::unique( triangles.begin(), triangles.end() ), triangles.end() );
    1772                 :         16 :     return MB_SUCCESS;
    1773                 :            : }
    1774                 :            : 
    1775                 :            : struct NodeSeg
    1776                 :            : {
    1777                 :        153 :     NodeSeg( EntityHandle h, double b, double e ) : handle( h ), beg( b ), end( e ) {}
    1778                 :            :     EntityHandle handle;
    1779                 :            :     double beg, end;
    1780                 :            : };
    1781                 :            : 
    1782                 :          8 : ErrorCode AdaptiveKDTree::ray_intersect_triangles( EntityHandle root, const double tol, const double ray_dir_in[3],
    1783                 :            :                                                    const double ray_pt_in[3], std::vector< EntityHandle >& tris_out,
    1784                 :            :                                                    std::vector< double >& dists_out, int max_ints, double ray_end )
    1785                 :            : {
    1786                 :            :     ErrorCode rval;
    1787                 :          8 :     double ray_beg = 0.0;
    1788         [ +  + ]:          8 :     if( ray_end < 0.0 ) ray_end = HUGE_VAL;
    1789                 :            : 
    1790                 :            :     // if root has bounding box, trim ray to that box
    1791         [ +  - ]:          8 :     CartVect tvec( tol );
    1792         [ +  - ]:          8 :     BoundBox box;
    1793 [ +  - ][ +  - ]:          8 :     const CartVect ray_pt( ray_pt_in ), ray_dir( ray_dir_in );
    1794         [ +  - ]:          8 :     rval = get_bounding_box( box );
    1795         [ +  - ]:          8 :     if( MB_SUCCESS == rval )
    1796                 :            :     {
    1797 [ +  - ][ +  - ]:          8 :         if( !GeomUtil::segment_box_intersect( box.bMin - tvec, box.bMax + tvec, ray_pt, ray_dir, ray_beg, ray_end ) )
         [ +  - ][ -  + ]
    1798                 :          0 :             return MB_SUCCESS;  // ray misses entire tree.
    1799                 :            :     }
    1800                 :            : 
    1801         [ +  - ]:         16 :     Range tris;
    1802         [ +  - ]:          8 :     Range::iterator iter;
    1803 [ +  - ][ +  + ]:         32 :     CartVect tri_coords[3];
    1804                 :            :     const EntityHandle* tri_conn;
    1805                 :            :     int conn_len;
    1806                 :            :     double tri_t;
    1807                 :            : 
    1808                 :            :     Plane plane;
    1809         [ +  - ]:         16 :     std::vector< EntityHandle > children;
    1810         [ +  - ]:         16 :     std::vector< NodeSeg > list;
    1811         [ +  - ]:          8 :     NodeSeg seg( root, ray_beg, ray_end );
    1812         [ +  - ]:          8 :     list.push_back( seg );
    1813                 :            : 
    1814         [ +  + ]:        161 :     while( !list.empty() )
    1815                 :            :     {
    1816         [ +  - ]:        153 :         seg = list.back();
    1817         [ +  - ]:        153 :         list.pop_back();
    1818                 :            : 
    1819                 :            :         // If we are limited to a certain number of intersections
    1820                 :            :         // (max_ints != 0), then ray_end will contain the distance
    1821                 :            :         // to the furthest intersection we have so far.  If the
    1822                 :            :         // tree node is further than that, skip it.
    1823         [ +  + ]:        153 :         if( seg.beg > ray_end ) continue;
    1824                 :            : 
    1825                 :            :         // Check if at a leaf
    1826                 :        148 :         children.clear();
    1827 [ +  - ][ +  - ]:        148 :         rval = moab()->get_child_meshsets( seg.handle, children );
    1828         [ -  + ]:        148 :         if( MB_SUCCESS != rval ) return rval;
    1829         [ +  + ]:        148 :         if( children.empty() )
    1830                 :            :         {  // leaf
    1831                 :            : 
    1832         [ +  - ]:         45 :             tris.clear();
    1833 [ +  - ][ +  - ]:         45 :             rval = moab()->get_entities_by_type( seg.handle, MBTRI, tris );
    1834         [ -  + ]:         45 :             if( MB_SUCCESS != rval ) return rval;
    1835                 :            : 
    1836 [ +  - ][ +  - ]:        176 :             for( iter = tris.begin(); iter != tris.end(); ++iter )
         [ +  - ][ +  - ]
                 [ +  + ]
    1837                 :            :             {
    1838 [ +  - ][ +  - ]:        131 :                 rval = moab()->get_connectivity( *iter, tri_conn, conn_len );
                 [ +  - ]
    1839         [ -  + ]:        131 :                 if( MB_SUCCESS != rval ) return rval;
    1840 [ +  - ][ +  - ]:        131 :                 rval = moab()->get_coords( tri_conn, 3, tri_coords[0].array() );
                 [ +  - ]
    1841         [ -  + ]:        131 :                 if( MB_SUCCESS != rval ) return rval;
    1842                 :            : 
    1843 [ +  - ][ +  + ]:        131 :                 if( GeomUtil::ray_tri_intersect( tri_coords, ray_pt, ray_dir, tri_t, &ray_end ) )
    1844                 :            :                 {
    1845         [ +  + ]:         57 :                     if( !max_ints )
    1846                 :            :                     {
    1847 [ +  - ][ +  - ]:         44 :                         if( std::find( tris_out.begin(), tris_out.end(), *iter ) == tris_out.end() )
         [ +  - ][ +  + ]
    1848                 :            :                         {
    1849 [ +  - ][ +  - ]:         16 :                             tris_out.push_back( *iter );
    1850         [ +  - ]:         16 :                             dists_out.push_back( tri_t );
    1851                 :            :                         }
    1852                 :            :                     }
    1853         [ +  + ]:         13 :                     else if( tri_t < ray_end )
    1854                 :            :                     {
    1855 [ +  - ][ +  - ]:          6 :                         if( std::find( tris_out.begin(), tris_out.end(), *iter ) == tris_out.end() )
         [ +  - ][ +  - ]
    1856                 :            :                         {
    1857         [ +  + ]:          6 :                             if( tris_out.size() < (unsigned)max_ints )
    1858                 :            :                             {
    1859         [ +  - ]:          3 :                                 tris_out.resize( tris_out.size() + 1 );
    1860         [ +  - ]:          3 :                                 dists_out.resize( dists_out.size() + 1 );
    1861                 :            :                             }
    1862                 :          6 :                             int w = tris_out.size() - 1;
    1863 [ +  + ][ +  - ]:          7 :                             for( ; w > 0 && tri_t < dists_out[w - 1]; --w )
         [ +  + ][ +  + ]
    1864                 :            :                             {
    1865 [ +  - ][ +  - ]:          1 :                                 tris_out[w]  = tris_out[w - 1];
    1866 [ +  - ][ +  - ]:          1 :                                 dists_out[w] = dists_out[w - 1];
    1867                 :            :                             }
    1868 [ +  - ][ +  - ]:          6 :                             tris_out[w]  = *iter;
    1869         [ +  - ]:          6 :                             dists_out[w] = tri_t;
    1870         [ +  + ]:          6 :                             if( tris_out.size() >= (unsigned)max_ints )
    1871                 :            :                                 // when we have already reached the max intx points, we cans safely
    1872                 :            :                                 // reset ray_end, because we will accept new points only "closer"
    1873                 :            :                                 // than the last one
    1874         [ +  - ]:         57 :                                 ray_end = dists_out.back();
    1875                 :            :                         }
    1876                 :            :                     }
    1877                 :            :                 }
    1878                 :            :             }
    1879                 :            : 
    1880                 :         45 :             continue;
    1881                 :            :         }
    1882                 :            : 
    1883         [ +  - ]:        103 :         rval = get_split_plane( seg.handle, plane );
    1884         [ -  + ]:        103 :         if( MB_SUCCESS != rval ) return rval;
    1885                 :            : 
    1886                 :            :         // Consider two planes that are the split plane +/- the tolerance.
    1887                 :            :         // Calculate the segment parameter at which the line segment intersects
    1888                 :            :         // the true plane, and also the difference between that value and the
    1889                 :            :         // intersection with either of the +/- tol planes.
    1890         [ +  - ]:        103 :         const double inv_dir = 1.0 / ray_dir[plane.norm];                       // only do division once
    1891         [ +  - ]:        103 :         const double t       = ( plane.coord - ray_pt[plane.norm] ) * inv_dir;  // intersection with plane
    1892                 :        103 :         const double diff    = tol * inv_dir;                                   // t adjustment for +tol plane
    1893                 :            :                                             // const double t0 = t - diff; // intersection with -tol plane
    1894                 :            :                                             // const double t1 = t + diff; // intersection with +tol plane
    1895                 :            : 
    1896                 :            :         // The index of the child tree node (0 or 1) that is on the
    1897                 :            :         // side of the plane to which the ray direction points.  That is,
    1898                 :            :         // if the ray direction is opposite the plane normal, the index
    1899                 :            :         // of the child corresponding to the side beneath the plane.  If
    1900                 :            :         // the ray direction is the same as the plane normal, the index
    1901                 :            :         // of the child corresponding to the side above the plane.
    1902         [ +  - ]:        103 :         const int fwd_child = ( ray_dir[plane.norm] > 0.0 );
    1903                 :            : 
    1904                 :            :         // Note: we maintain seg.beg <= seg.end at all times, so assume that here.
    1905                 :            : 
    1906                 :            :         // If segment is parallel to plane
    1907 [ +  - ][ +  + ]:        103 :         if( !Util::is_finite( t ) )
    1908                 :            :         {
    1909 [ +  - ][ +  + ]:         69 :             if( ray_pt[plane.norm] - tol <= plane.coord ) list.push_back( NodeSeg( children[0], seg.beg, seg.end ) );
         [ +  - ][ +  - ]
                 [ +  - ]
    1910 [ +  - ][ +  + ]:         69 :             if( ray_pt[plane.norm] + tol >= plane.coord ) list.push_back( NodeSeg( children[1], seg.beg, seg.end ) );
         [ +  - ][ +  - ]
                 [ +  - ]
    1911                 :            :         }
    1912                 :            :         // If segment is entirely to one side of plane such that the
    1913                 :            :         // intersection with the split plane is past the end of the segment
    1914         [ +  + ]:         34 :         else if( seg.end + diff < t )
    1915                 :            :         {
    1916                 :            :             // If segment direction is opposite that of plane normal, then
    1917                 :            :             // being past the end of the segment means that we are to the
    1918                 :            :             // right (or above) the plane and what the right child (index == 1).
    1919                 :            :             // Otherwise we want the left child (index == 0);
    1920 [ +  - ][ +  - ]:          2 :             list.push_back( NodeSeg( children[1 - fwd_child], seg.beg, seg.end ) );
                 [ +  - ]
    1921                 :            :         }
    1922                 :            :         // If the segment is entirely to one side of the plane such that
    1923                 :            :         // the intersection with the split plane is before the start of the
    1924                 :            :         // segment
    1925         [ +  + ]:         32 :         else if( seg.beg - diff > t )
    1926                 :            :         {
    1927                 :            :             // If segment direction is opposite that of plane normal, then
    1928                 :            :             // being before the start of the segment means that we are to the
    1929                 :            :             // left (or below) the plane and what the left child (index == 0).
    1930                 :            :             // Otherwise we want the right child (index == 1);
    1931 [ +  - ][ +  - ]:          2 :             list.push_back( NodeSeg( children[fwd_child], seg.beg, seg.end ) );
                 [ +  - ]
    1932                 :            :         }
    1933                 :            :         // Otherwise we must intersect the plane.
    1934                 :            :         // Note: be careful not to grow the segment if t is slightly
    1935                 :            :         // outside the current segment, as doing so would effectively
    1936                 :            :         // increase the tolerance as we descend the tree.
    1937         [ +  + ]:         30 :         else if( t <= seg.beg )
    1938                 :            :         {
    1939 [ +  - ][ +  - ]:          1 :             list.push_back( NodeSeg( children[1 - fwd_child], seg.beg, seg.beg ) );
                 [ +  - ]
    1940 [ +  - ][ +  - ]:          1 :             list.push_back( NodeSeg( children[fwd_child], seg.beg, seg.end ) );
                 [ +  - ]
    1941                 :            :         }
    1942         [ +  + ]:         29 :         else if( t >= seg.end )
    1943                 :            :         {
    1944 [ +  - ][ +  - ]:          1 :             list.push_back( NodeSeg( children[1 - fwd_child], seg.beg, seg.end ) );
                 [ +  - ]
    1945 [ +  - ][ +  - ]:          1 :             list.push_back( NodeSeg( children[fwd_child], seg.end, seg.end ) );
                 [ +  - ]
    1946                 :            :         }
    1947                 :            :         else
    1948                 :            :         {
    1949 [ +  - ][ +  - ]:         28 :             list.push_back( NodeSeg( children[1 - fwd_child], seg.beg, t ) );
                 [ +  - ]
    1950 [ +  - ][ +  - ]:         28 :             list.push_back( NodeSeg( children[fwd_child], t, seg.end ) );
                 [ +  - ]
    1951                 :            :         }
    1952                 :            :     }
    1953                 :            : 
    1954                 :         16 :     return MB_SUCCESS;
    1955                 :            : }
    1956                 :            : 
    1957                 :          0 : ErrorCode AdaptiveKDTree::compute_depth( EntityHandle root, unsigned int& min_depth, unsigned int& max_depth )
    1958                 :            : {
    1959         [ #  # ]:          0 :     AdaptiveKDTreeIter iter;
    1960         [ #  # ]:          0 :     get_tree_iterator( root, iter );
    1961         [ #  # ]:          0 :     iter.step_to_first_leaf( AdaptiveKDTreeIter::LEFT );
    1962         [ #  # ]:          0 :     min_depth = max_depth = iter.depth();
    1963                 :            : 
    1964                 :          0 :     int num_of_elements = 0, max, min;
    1965 [ #  # ][ #  # ]:          0 :     moab()->get_number_entities_by_handle( iter.handle(), num_of_elements );
                 [ #  # ]
    1966                 :          0 :     max = min = num_of_elements;
    1967                 :          0 :     int k     = 0;
    1968 [ #  # ][ #  # ]:          0 :     while( MB_SUCCESS == iter.step() )
    1969                 :            :     {
    1970                 :          0 :         int temp = 0;
    1971 [ #  # ][ #  # ]:          0 :         moab()->get_number_entities_by_handle( iter.handle(), temp );
                 [ #  # ]
    1972         [ #  # ]:          0 :         max = std::max( max, temp );
    1973         [ #  # ]:          0 :         min = std::min( min, temp );
    1974 [ #  # ][ #  # ]:          0 :         if( iter.depth() > max_depth )
    1975         [ #  # ]:          0 :             max_depth = iter.depth();
    1976 [ #  # ][ #  # ]:          0 :         else if( iter.depth() < min_depth )
    1977         [ #  # ]:          0 :             min_depth = iter.depth();
    1978                 :          0 :         ++k;
    1979                 :            :     }
    1980                 :          0 :     return MB_SUCCESS;
    1981                 :            : }
    1982                 :            : 
    1983                 :          0 : ErrorCode AdaptiveKDTree::get_info( EntityHandle root, double bmin[3], double bmax[3], unsigned int& dep )
    1984                 :            : {
    1985         [ #  # ]:          0 :     BoundBox box;
    1986         [ #  # ]:          0 :     ErrorCode result = get_bounding_box( box, &root );
    1987         [ #  # ]:          0 :     if( MB_SUCCESS != result ) return result;
    1988         [ #  # ]:          0 :     box.bMin.get( bmin );
    1989         [ #  # ]:          0 :     box.bMax.get( bmax );
    1990                 :            : 
    1991                 :            :     unsigned min_depth;
    1992         [ #  # ]:          0 :     return compute_depth( root, min_depth, dep );
    1993                 :            : }
    1994                 :            : 
    1995                 :          0 : static std::string mem_to_string( unsigned long mem )
    1996                 :            : {
    1997                 :          0 :     char unit[3] = "B";
    1998         [ #  # ]:          0 :     if( mem > 9 * 1024 )
    1999                 :            :     {
    2000                 :          0 :         mem = ( mem + 512 ) / 1024;
    2001                 :          0 :         strcpy( unit, "kB" );
    2002                 :            :     }
    2003         [ #  # ]:          0 :     if( mem > 9 * 1024 )
    2004                 :            :     {
    2005                 :          0 :         mem = ( mem + 512 ) / 1024;
    2006                 :          0 :         strcpy( unit, "MB" );
    2007                 :            :     }
    2008         [ #  # ]:          0 :     if( mem > 9 * 1024 )
    2009                 :            :     {
    2010                 :          0 :         mem = ( mem + 512 ) / 1024;
    2011                 :          0 :         strcpy( unit, "GB" );
    2012                 :            :     }
    2013                 :            :     char buffer[256];
    2014                 :          0 :     sprintf( buffer, "%lu %s", mem, unit );
    2015         [ #  # ]:          0 :     return buffer;
    2016                 :            : }
    2017                 :            : 
    2018                 :            : template < typename T >
    2019                 :            : struct SimpleStat
    2020                 :            : {
    2021                 :            :     T min, max, sum, sqr;
    2022                 :            :     size_t count;
    2023                 :            :     SimpleStat();
    2024                 :            :     void add( T value );
    2025                 :          0 :     double avg() const
    2026                 :            :     {
    2027                 :          0 :         return (double)sum / count;
    2028                 :            :     }
    2029                 :          0 :     double rms() const
    2030                 :            :     {
    2031                 :          0 :         return sqrt( (double)sqr / count );
    2032                 :            :     }
    2033                 :          0 :     double dev() const
    2034                 :            :     {
    2035                 :            :         return ( count > 1
    2036                 :          0 :                      ? sqrt( ( count * (double)sqr - (double)sum * (double)sum ) / ( (double)count * ( count - 1 ) ) )
    2037 [ #  # ][ #  # ]:          0 :                      : 0.0 );
    2038                 :            :     }
    2039                 :            : };
    2040                 :            : 
    2041                 :            : template < typename T >
    2042                 :          0 : SimpleStat< T >::SimpleStat()
    2043                 :          0 :     : min( std::numeric_limits< T >::max() ), max( std::numeric_limits< T >::min() ), sum( 0 ), sqr( 0 ), count( 0 )
    2044                 :            : {
    2045                 :          0 : }
    2046                 :            : 
    2047                 :            : template < typename T >
    2048                 :          0 : void SimpleStat< T >::add( T value )
    2049                 :            : {
    2050 [ #  # ][ #  # ]:          0 :     if( value < min ) min = value;
    2051 [ #  # ][ #  # ]:          0 :     if( value > max ) max = value;
    2052                 :          0 :     sum += value;
    2053                 :          0 :     sqr += value * value;
    2054                 :          0 :     ++count;
    2055                 :          0 : }
    2056                 :            : 
    2057                 :          0 : ErrorCode AdaptiveKDTree::print()
    2058                 :            : {
    2059         [ #  # ]:          0 :     Range range;
    2060                 :            : 
    2061 [ #  # ][ #  # ]:          0 :     Range tree_sets, elem2d, elem3d, verts, all;
         [ #  # ][ #  # ]
                 [ #  # ]
    2062 [ #  # ][ #  # ]:          0 :     moab()->get_child_meshsets( myRoot, tree_sets, 0 );
    2063 [ #  # ][ #  # ]:          0 :     for( Range::iterator rit = tree_sets.begin(); rit != tree_sets.end(); ++rit )
         [ #  # ][ #  # ]
                 [ #  # ]
    2064                 :            :     {
    2065 [ #  # ][ #  # ]:          0 :         moab()->get_entities_by_dimension( *rit, 2, elem2d );
                 [ #  # ]
    2066 [ #  # ][ #  # ]:          0 :         moab()->get_entities_by_dimension( *rit, 3, elem3d );
                 [ #  # ]
    2067 [ #  # ][ #  # ]:          0 :         moab()->get_entities_by_type( *rit, MBVERTEX, verts );
                 [ #  # ]
    2068                 :            :     }
    2069         [ #  # ]:          0 :     all.merge( verts );
    2070         [ #  # ]:          0 :     all.merge( elem2d );
    2071         [ #  # ]:          0 :     all.merge( elem3d );
    2072         [ #  # ]:          0 :     tree_sets.insert( myRoot );
    2073                 :            :     unsigned long long set_used, set_amortized, set_store_used, set_store_amortized, set_tag_used, set_tag_amortized,
    2074                 :            :         elem_used, elem_amortized;
    2075         [ #  # ]:          0 :     moab()->estimated_memory_use( tree_sets, &set_used, &set_amortized, &set_store_used, &set_store_amortized, 0, 0, 0,
    2076         [ #  # ]:          0 :                                   0, &set_tag_used, &set_tag_amortized );
    2077 [ #  # ][ #  # ]:          0 :     moab()->estimated_memory_use( all, &elem_used, &elem_amortized );
    2078                 :            : 
    2079                 :          0 :     int num_2d = 0, num_3d = 0;
    2080                 :            :     ;
    2081 [ #  # ][ #  # ]:          0 :     moab()->get_number_entities_by_dimension( 0, 2, num_2d );
    2082 [ #  # ][ #  # ]:          0 :     moab()->get_number_entities_by_dimension( 0, 3, num_3d );
    2083                 :            : 
    2084         [ #  # ]:          0 :     BoundBox box;
    2085         [ #  # ]:          0 :     ErrorCode rval = get_bounding_box( box, &myRoot );
    2086 [ #  # ][ #  # ]:          0 :     if( MB_SUCCESS != rval || box == BoundBox() ) throw rval;
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
    2087 [ #  # ][ #  # ]:          0 :     double diff[3]        = { box.bMax[0] - box.bMin[0], box.bMax[1] - box.bMin[1], box.bMax[2] - box.bMin[2] };
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
    2088                 :          0 :     double tree_vol       = diff[0] * diff[1] * diff[2];
    2089                 :          0 :     double tree_surf_area = 2 * ( diff[0] * diff[1] + diff[1] * diff[2] + diff[2] * diff[0] );
    2090                 :            : 
    2091 [ #  # ][ #  # ]:          0 :     SimpleStat< unsigned > depth, size;
    2092 [ #  # ][ #  # ]:          0 :     SimpleStat< double > vol, surf;
    2093                 :            : 
    2094         [ #  # ]:          0 :     AdaptiveKDTreeIter iter;
    2095         [ #  # ]:          0 :     get_tree_iterator( myRoot, iter );
    2096         [ #  # ]:          0 :     do
    2097                 :            :     {
    2098 [ #  # ][ #  # ]:          0 :         depth.add( iter.depth() );
    2099                 :            : 
    2100                 :            :         int num_leaf_elem;
    2101 [ #  # ][ #  # ]:          0 :         moab()->get_number_entities_by_handle( iter.handle(), num_leaf_elem );
                 [ #  # ]
    2102         [ #  # ]:          0 :         size.add( num_leaf_elem );
    2103                 :            : 
    2104         [ #  # ]:          0 :         const double* n = iter.box_min();
    2105         [ #  # ]:          0 :         const double* x = iter.box_max();
    2106                 :          0 :         double dims[3]  = { x[0] - n[0], x[1] - n[1], x[2] - n[2] };
    2107                 :            : 
    2108                 :          0 :         double leaf_vol = dims[0] * dims[1] * dims[2];
    2109         [ #  # ]:          0 :         vol.add( leaf_vol );
    2110                 :            : 
    2111                 :          0 :         double area = 2.0 * ( dims[0] * dims[1] + dims[1] * dims[2] + dims[2] * dims[0] );
    2112         [ #  # ]:          0 :         surf.add( area );
    2113                 :            : 
    2114         [ #  # ]:          0 :     } while( MB_SUCCESS == iter.step() );
    2115                 :            : 
    2116         [ #  # ]:          0 :     printf( "------------------------------------------------------------------\n" );
    2117         [ #  # ]:          0 :     printf( "tree volume:      %f\n", tree_vol );
    2118         [ #  # ]:          0 :     printf( "total elements:   %d\n", num_2d + num_3d );
    2119         [ #  # ]:          0 :     printf( "number of leaves: %lu\n", (unsigned long)depth.count );
    2120 [ #  # ][ #  # ]:          0 :     printf( "number of nodes:  %lu\n", (unsigned long)tree_sets.size() );
    2121         [ #  # ]:          0 :     printf( "volume ratio:     %0.2f%%\n", 100 * ( vol.sum / tree_vol ) );
    2122         [ #  # ]:          0 :     printf( "surface ratio:    %0.2f%%\n", 100 * ( surf.sum / tree_surf_area ) );
    2123         [ #  # ]:          0 :     printf( "\nmemory:           used  amortized\n" );
    2124         [ #  # ]:          0 :     printf( "            ---------- ----------\n" );
    2125 [ #  # ][ #  # ]:          0 :     printf( "elements    %10s %10s\n", mem_to_string( elem_used ).c_str(), mem_to_string( elem_amortized ).c_str() );
                 [ #  # ]
    2126 [ #  # ][ #  # ]:          0 :     printf( "sets (total)%10s %10s\n", mem_to_string( set_used ).c_str(), mem_to_string( set_amortized ).c_str() );
                 [ #  # ]
    2127                 :            :     printf( "sets        %10s %10s\n", mem_to_string( set_store_used ).c_str(),
    2128 [ #  # ][ #  # ]:          0 :             mem_to_string( set_store_amortized ).c_str() );
                 [ #  # ]
    2129                 :            :     printf( "set tags    %10s %10s\n", mem_to_string( set_tag_used ).c_str(),
    2130 [ #  # ][ #  # ]:          0 :             mem_to_string( set_tag_amortized ).c_str() );
                 [ #  # ]
    2131         [ #  # ]:          0 :     printf( "\nleaf stats:        min        avg        rms        max    std.dev\n" );
    2132         [ #  # ]:          0 :     printf( "            ---------- ---------- ---------- ---------- ----------\n" );
    2133                 :            :     printf( "depth       %10u %10.1f %10.1f %10u %10.2f\n", depth.min, depth.avg(), depth.rms(), depth.max,
    2134 [ #  # ][ #  # ]:          0 :             depth.dev() );
         [ #  # ][ #  # ]
    2135 [ #  # ][ #  # ]:          0 :     printf( "triangles   %10u %10.1f %10.1f %10u %10.2f\n", size.min, size.avg(), size.rms(), size.max, size.dev() );
         [ #  # ][ #  # ]
    2136 [ #  # ][ #  # ]:          0 :     printf( "volume      %10.2g %10.2g %10.2g %10.2g %10.2g\n", vol.min, vol.avg(), vol.rms(), vol.max, vol.dev() );
         [ #  # ][ #  # ]
    2137                 :            :     printf( "surf. area  %10.2g %10.2g %10.2g %10.2g %10.2g\n", surf.min, surf.avg(), surf.rms(), surf.max,
    2138 [ #  # ][ #  # ]:          0 :             surf.dev() );
         [ #  # ][ #  # ]
    2139         [ #  # ]:          0 :     printf( "------------------------------------------------------------------\n" );
    2140                 :            : 
    2141                 :          0 :     return MB_SUCCESS;
    2142                 :            : }
    2143                 :            : 
    2144 [ +  - ][ +  - ]:        228 : }  // namespace moab

Generated by: LCOV version 1.11