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