1
15
16
20
21 #include "moab/Interface.hpp"
22 #include "Internals.hpp"
23 #include "moab/OrientedBoxTreeTool.hpp"
24 #include "moab/Range.hpp"
25 #include "moab/CN.hpp"
26 #include "moab/GeomUtil.hpp"
27 #include "MBTagConventions.hpp"
28 #include <iostream>
29 #include <iomanip>
30 #include <algorithm>
31 #include <limits>
32 #include <cassert>
33 #include <cmath>
34
35
36
37
38 namespace moab
39 {
40
41 #if defined( MB_OBB_USE_VECTOR_QUERIES ) && defined( MB_OBB_USE_TYPE_QUERIES )
42 #undef MB_OBB_USE_TYPE_QUERIES
43 #endif
44
45 const char DEFAULT_TAG_NAME[] = "OBB";
46
47 OrientedBoxTreeTool::Op::~Op() {}
48
49 OrientedBoxTreeTool::OrientedBoxTreeTool( Interface* i, const char* tag_name, bool destroy_created_trees )
50 : instance( i ), cleanUpTrees( destroy_created_trees )
51 {
52 if( !tag_name ) tag_name = DEFAULT_TAG_NAME;
53 ErrorCode rval = OrientedBox::tag_handle( tagHandle, instance, tag_name );
54 if( MB_SUCCESS != rval ) tagHandle = 0;
55 }
56
57 OrientedBoxTreeTool::~OrientedBoxTreeTool()
58 {
59 if( !cleanUpTrees ) return;
60
61 while( !createdTrees.empty() )
62 {
63 EntityHandle tree = createdTrees.back();
64
65 const void* data_ptr = 0;
66 ErrorCode rval = instance->tag_get_by_ptr( tagHandle, &tree, 1, &data_ptr );
67 if( MB_SUCCESS == rval ) rval = delete_tree( tree );
68 if( MB_SUCCESS != rval ) createdTrees.pop_back();
69 }
70 }
71
72 OrientedBoxTreeTool::Settings::Settings()
73 : max_leaf_entities( 8 ), max_depth( 0 ), worst_split_ratio( 0.95 ), best_split_ratio( 0.4 ),
74 set_options( MESHSET_SET )
75 {
76 }
77
78 bool OrientedBoxTreeTool::Settings::valid() const
79 {
80 return max_leaf_entities > 0 && max_depth >= 0 && worst_split_ratio <= 1.0 && best_split_ratio >= 0.0 &&
81 worst_split_ratio >= best_split_ratio;
82 }
83
84
85
86 ErrorCode OrientedBoxTreeTool::box( EntityHandle set, OrientedBox& obb )
87 {
88 return instance->tag_get_data( tagHandle, &set, 1, &obb );
89 }
90
91 ErrorCode OrientedBoxTreeTool::box( EntityHandle set,
92 double center[3],
93 double axis1[3],
94 double axis2[3],
95 double axis3[3] )
96 {
97 OrientedBox obb;
98 ErrorCode rval = this->box( set, obb );
99 obb.center.get( center );
100 obb.scaled_axis( 0 ).get( axis1 );
101 obb.scaled_axis( 1 ).get( axis2 );
102 obb.scaled_axis( 2 ).get( axis3 );
103 return rval;
104 }
105
106
107
108 struct OrientedBoxTreeTool::SetData
109 {
110 EntityHandle handle;
111 OrientedBox::CovarienceData box_data;
112
113 };
114
115 ErrorCode OrientedBoxTreeTool::build( const Range& entities, EntityHandle& set_handle_out, const Settings* settings )
116 {
117 if( !entities.all_of_dimension( 2 ) ) return MB_TYPE_OUT_OF_RANGE;
118 if( settings && !settings->valid() ) return MB_FAILURE;
119
120 return build_tree( entities, set_handle_out, 0, settings ? *settings : Settings() );
121 }
122
123 ErrorCode OrientedBoxTreeTool::join_trees( const Range& sets, EntityHandle& set_handle_out, const Settings* settings )
124 {
125 if( !sets.all_of_type( MBENTITYSET ) ) return MB_TYPE_OUT_OF_RANGE;
126 if( settings && !settings->valid() ) return MB_FAILURE;
127
128
129 std::list< SetData > data;
130 for( Range::const_iterator i = sets.begin(); i != sets.end(); ++i )
131 {
132 Range elements;
133 ErrorCode rval = instance->get_entities_by_dimension( *i, 2, elements, true );
134 if( MB_SUCCESS != rval ) return rval;
135 if( elements.empty() ) continue;
136
137 data.push_back( SetData() );
138 SetData& set_data = data.back();
139 set_data.handle = *i;
140 rval = OrientedBox::covariance_data_from_tris( set_data.box_data, instance, elements );
141 if( MB_SUCCESS != rval ) return rval;
142 }
143
144 ErrorCode result = build_sets( data, set_handle_out, 0, settings ? *settings : Settings() );
145 if( MB_SUCCESS != result ) return result;
146
147 for( Range::reverse_iterator i = sets.rbegin(); i != sets.rend(); ++i )
148 {
149 createdTrees.erase( std::remove( createdTrees.begin(), createdTrees.end(), *i ), createdTrees.end() );
150 }
151 createdTrees.push_back( set_handle_out );
152 return MB_SUCCESS;
153 }
154
155
167 static ErrorCode split_box( Interface* instance,
168 const OrientedBox& box,
169 int axis,
170 const Range& entities,
171 Range& left_list,
172 Range& right_list )
173 {
174 ErrorCode rval;
175 left_list.clear();
176 right_list.clear();
177
178 std::vector< CartVect > coords;
179 for( Range::reverse_iterator i = entities.rbegin(); i != entities.rend(); ++i )
180 {
181 const EntityHandle* conn = NULL;
182 int conn_len = 0;
183 rval = instance->get_connectivity( *i, conn, conn_len );
184 if( MB_SUCCESS != rval ) return rval;
185
186 coords.resize( conn_len );
187 rval = instance->get_coords( conn, conn_len, coords[0].array() );
188 if( MB_SUCCESS != rval ) return rval;
189
190 CartVect centroid( 0.0 );
191 for( int j = 0; j < conn_len; ++j )
192 centroid += coords[j];
193 centroid /= conn_len;
194
195 if( ( box.axis( axis ) % ( centroid - box.center ) ) < 0.0 )
196 left_list.insert( *i );
197 else
198 right_list.insert( *i );
199 }
200
201 return MB_SUCCESS;
202 }
203
204 ErrorCode OrientedBoxTreeTool::build_tree( const Range& entities,
205 EntityHandle& set,
206 int depth,
207 const Settings& settings )
208 {
209 OrientedBox tmp_box;
210 ErrorCode rval;
211
212 if( entities.empty() )
213 {
214 Matrix3 axis;
215 tmp_box = OrientedBox( axis, CartVect( 0. ) );
216 }
217 else
218 {
219 rval = OrientedBox::compute_from_2d_cells( tmp_box, instance, entities );
220 if( MB_SUCCESS != rval ) return rval;
221 }
222
223
224 rval = instance->create_meshset( settings.set_options, set );
225 if( MB_SUCCESS != rval ) return rval;
226
227 rval = instance->tag_set_data( tagHandle, &set, 1, &tmp_box );
228 if( MB_SUCCESS != rval )
229 {
230 delete_tree( set );
231 return rval;
232 }
233
234
235 bool leaf = true;
236 ++depth;
237 if( ( !settings.max_depth || depth < settings.max_depth ) &&
238 entities.size() > (unsigned)settings.max_leaf_entities )
239 {
240
241
242 double best_ratio = settings.worst_split_ratio;
243 Range best_left_list, best_right_list;
244
245 for( int axis = 2; best_ratio > settings.best_split_ratio && axis >= 0; --axis )
246 {
247 Range left_list, right_list;
248
249 rval = split_box( instance, tmp_box, axis, entities, left_list, right_list );
250 if( MB_SUCCESS != rval )
251 {
252 delete_tree( set );
253 return rval;
254 }
255
256 double ratio = fabs( (double)right_list.size() - left_list.size() ) / entities.size();
257
258 if( ratio < best_ratio )
259 {
260 best_ratio = ratio;
261 best_left_list.swap( left_list );
262 best_right_list.swap( right_list );
263 }
264 }
265
266
267 if( !best_left_list.empty() )
268 {
269 EntityHandle child = 0;
270
271 rval = build_tree( best_left_list, child, depth, settings );
272 if( MB_SUCCESS != rval )
273 {
274 delete_tree( set );
275 return rval;
276 }
277 rval = instance->add_child_meshset( set, child );
278 if( MB_SUCCESS != rval )
279 {
280 delete_tree( set );
281 delete_tree( child );
282 return rval;
283 }
284
285 rval = build_tree( best_right_list, child, depth, settings );
286 if( MB_SUCCESS != rval )
287 {
288 delete_tree( set );
289 return rval;
290 }
291 rval = instance->add_child_meshset( set, child );
292 if( MB_SUCCESS != rval )
293 {
294 delete_tree( set );
295 delete_tree( child );
296 return rval;
297 }
298
299 leaf = false;
300 }
301 }
302
303 if( leaf )
304 {
305 rval = instance->add_entities( set, entities );
306 if( MB_SUCCESS != rval )
307 {
308 delete_tree( set );
309 return rval;
310 }
311 }
312
313 createdTrees.push_back( set );
314 return MB_SUCCESS;
315 }
316
317 static ErrorCode split_sets( Interface*,
318 const OrientedBox& box,
319 int axis,
320 const std::list< OrientedBoxTreeTool::SetData >& sets,
321 std::list< OrientedBoxTreeTool::SetData >& left,
322 std::list< OrientedBoxTreeTool::SetData >& right )
323 {
324 left.clear();
325 right.clear();
326
327 std::list< OrientedBoxTreeTool::SetData >::const_iterator i;
328 for( i = sets.begin(); i != sets.end(); ++i )
329 {
330 CartVect centroid( i->box_data.center / i->box_data.area );
331 if( ( box.axis( axis ) % ( centroid - box.center ) ) < 0.0 )
332 left.push_back( *i );
333 else
334 right.push_back( *i );
335 }
336
337 return MB_SUCCESS;
338 }
339
340 ErrorCode OrientedBoxTreeTool::build_sets( std::list< SetData >& sets,
341 EntityHandle& node_set,
342 int depth,
343 const Settings& settings )
344 {
345 ErrorCode rval;
346 int count = sets.size();
347 if( 0 == count ) return MB_FAILURE;
348
349
350 OrientedBox obox;
351
352
353 {
354 Range elems;
355 std::vector< OrientedBox::CovarienceData > data( sets.size() );
356 data.clear();
357 for( std::list< SetData >::iterator i = sets.begin(); i != sets.end(); ++i )
358 {
359 data.push_back( i->box_data );
360 rval = instance->get_entities_by_dimension( i->handle, 2, elems, true );
361 if( MB_SUCCESS != rval ) return rval;
362 }
363
364 Range points;
365 rval = instance->get_adjacencies( elems, 0, false, points, Interface::UNION );
366 if( MB_SUCCESS != rval ) return rval;
367
368 rval = OrientedBox::compute_from_covariance_data( obox, instance, &data[0], data.size(), points );
369 if( MB_SUCCESS != rval ) return rval;
370 }
371
372
373 if( count == 1 )
374 {
375 node_set = sets.front().handle;
376 return instance->tag_set_data( tagHandle, &node_set, 1, &obox );
377 }
378
379
380 rval = instance->create_meshset( settings.set_options, node_set );
381 if( MB_SUCCESS != rval ) return rval;
382
383 rval = instance->tag_set_data( tagHandle, &node_set, 1, &obox );
384 if( MB_SUCCESS != rval )
385 {
386 delete_tree( node_set );
387 return rval;
388 }
389
390 double best_ratio = 2.0;
391 std::list< SetData > best_left_list, best_right_list;
392 for( int axis = 0; axis < 2; ++axis )
393 {
394 std::list< SetData > left_list, right_list;
395 rval = split_sets( instance, obox, axis, sets, left_list, right_list );
396 if( MB_SUCCESS != rval )
397 {
398 delete_tree( node_set );
399 return rval;
400 }
401
402 double ratio = fabs( (double)right_list.size() - left_list.size() ) / sets.size();
403
404 if( ratio < best_ratio )
405 {
406 best_ratio = ratio;
407 best_left_list.swap( left_list );
408 best_right_list.swap( right_list );
409 }
410 }
411
412
413
414
415
416 if( best_left_list.empty() || best_right_list.empty() )
417 {
418 best_left_list.clear();
419 best_right_list.clear();
420 std::list< SetData >* lists[2] = { &best_left_list, &best_right_list };
421 int i = 0;
422 while( !sets.empty() )
423 {
424 lists[i]->push_back( sets.front() );
425 sets.pop_front();
426 i = 1 - i;
427 }
428 }
429 else
430 {
431 sets.clear();
432 }
433
434
435
436 EntityHandle child = 0;
437
438 rval = build_sets( best_left_list, child, depth + 1, settings );
439 if( MB_SUCCESS != rval )
440 {
441 delete_tree( node_set );
442 return rval;
443 }
444 rval = instance->add_child_meshset( node_set, child );
445 if( MB_SUCCESS != rval )
446 {
447 delete_tree( node_set );
448 delete_tree( child );
449 return rval;
450 }
451
452 rval = build_sets( best_right_list, child, depth + 1, settings );
453 if( MB_SUCCESS != rval )
454 {
455 delete_tree( node_set );
456 return rval;
457 }
458 rval = instance->add_child_meshset( node_set, child );
459 if( MB_SUCCESS != rval )
460 {
461 delete_tree( node_set );
462 delete_tree( child );
463 return rval;
464 }
465
466 return MB_SUCCESS;
467 }
468
469 ErrorCode OrientedBoxTreeTool::delete_tree( EntityHandle set )
470 {
471 std::vector< EntityHandle > children;
472 ErrorCode rval = instance->get_child_meshsets( set, children, 0 );
473 if( MB_SUCCESS != rval ) return rval;
474
475 createdTrees.erase( std::remove( createdTrees.begin(), createdTrees.end(), set ), createdTrees.end() );
476 children.insert( children.begin(), set );
477 return instance->delete_entities( &children[0], children.size() );
478 }
479
480 ErrorCode OrientedBoxTreeTool::remove_root( EntityHandle root )
481 {
482 std::vector< EntityHandle >::iterator i = find( createdTrees.begin(), createdTrees.end(), root );
483 if( i != createdTrees.end() )
484 {
485 createdTrees.erase( i );
486 return MB_SUCCESS;
487 }
488 else
489 return MB_ENTITY_NOT_FOUND;
490 }
491
492
493 struct Data
494 {
495 EntityHandle set;
496 int depth;
497 };
498 ErrorCode OrientedBoxTreeTool::preorder_traverse( EntityHandle set, Op& operation, TrvStats* accum )
499 {
500 ErrorCode rval;
501 std::vector< EntityHandle > children;
502 std::vector< Data > the_stack;
503 Data data = { set, 0 };
504 the_stack.push_back( data );
505 int max_depth = -1;
506
507 while( !the_stack.empty() )
508 {
509 data = the_stack.back();
510 the_stack.pop_back();
511
512
513 if( accum )
514 {
515 accum->increment( data.depth );
516 max_depth = std::max( max_depth, data.depth );
517 }
518
519 bool descend = true;
520 rval = operation.visit( data.set, data.depth, descend );
521 assert( MB_SUCCESS == rval );
522 if( MB_SUCCESS != rval ) return rval;
523
524 if( !descend ) continue;
525
526 children.clear();
527 rval = instance->get_child_meshsets( data.set, children );
528 assert( MB_SUCCESS == rval );
529 if( MB_SUCCESS != rval ) return rval;
530 if( children.empty() )
531 {
532 if( accum )
533 {
534 accum->increment_leaf( data.depth );
535 }
536 rval = operation.leaf( data.set );
537 assert( MB_SUCCESS == rval );
538 if( MB_SUCCESS != rval ) return rval;
539 }
540 else if( children.size() == 2 )
541 {
542 data.depth++;
543 data.set = children[0];
544 the_stack.push_back( data );
545 data.set = children[1];
546 the_stack.push_back( data );
547 }
548 else
549 return MB_MULTIPLE_ENTITIES_FOUND;
550 }
551
552 if( accum )
553 {
554 accum->end_traversal( max_depth );
555 }
556
557 return MB_SUCCESS;
558 }
559
560
561
562 struct OBBTreeSITFrame
563 {
564 OBBTreeSITFrame( EntityHandle n, EntityHandle s, int dp ) : node( n ), surf( s ), depth( dp ) {}
565 EntityHandle node;
566 EntityHandle surf;
567 int depth;
568 };
569
570 ErrorCode OrientedBoxTreeTool::sphere_intersect_triangles( const double* center_v,
571 double radius,
572 EntityHandle tree_root,
573 std::vector< EntityHandle >& facets_out,
574 std::vector< EntityHandle >* sets_out,
575 TrvStats* accum )
576 {
577 const double radsqr = radius * radius;
578 OrientedBox b;
579 ErrorCode rval;
580 Range sets;
581 const CartVect center( center_v );
582 CartVect closest, coords[3];
583 const EntityHandle* conn;
584 int num_conn;
585 #ifndef MB_OBB_USE_VECTOR_QUERIES
586 Range tris;
587 Range::const_iterator t;
588 #else
589 std::vector< EntityHandle > tris;
590 std::vector< EntityHandle >::const_iterator t;
591 #endif
592
593 std::vector< OBBTreeSITFrame > stack;
594 std::vector< EntityHandle > children;
595 stack.reserve( 30 );
596 stack.push_back( OBBTreeSITFrame( tree_root, 0, 0 ) );
597
598 int max_depth = -1;
599
600 while( !stack.empty() )
601 {
602 EntityHandle surf = stack.back().surf;
603 EntityHandle node = stack.back().node;
604 int current_depth = stack.back().depth;
605 stack.pop_back();
606
607
608 if( accum )
609 {
610 accum->increment( current_depth );
611 max_depth = std::max( max_depth, current_depth );
612 }
613
614 if( !surf && sets_out )
615 {
616 rval = get_moab_instance()->get_entities_by_type( node, MBENTITYSET, sets );
617 if( !sets.empty() ) surf = sets.front();
618 sets.clear();
619 }
620
621
622 rval = box( node, b );
623 if( MB_SUCCESS != rval ) return rval;
624 b.closest_location_in_box( center, closest );
625 closest -= center;
626 if( ( closest % closest ) > radsqr ) continue;
627
628
629 children.clear();
630 rval = instance->get_child_meshsets( node, children );
631 if( MB_SUCCESS != rval ) return rval;
632 if( !children.empty() )
633 {
634 assert( children.size() == 2 );
635 stack.push_back( OBBTreeSITFrame( children[0], surf, current_depth + 1 ) );
636 stack.push_back( OBBTreeSITFrame( children[1], surf, current_depth + 1 ) );
637 continue;
638 }
639
640 if( accum )
641 {
642 accum->increment_leaf( current_depth );
643 }
644
645 #ifndef MB_OBB_USE_VECTOR_QUERIES
646 #ifdef MB_OBB_USE_TYPE_QUERIES
647 rval = get_moab_instance()->get_entities_by_type( node, MBTRI, tris );
648 #else
649 rval = get_moab_instance()->get_entities_by_handle( node, tris );
650 #endif
651 t = tris.begin();
652 #else
653 rval = get_moab_instance()->get_entities_by_handle( node, tris );
654 t = tris.lower_bound( MBTRI );
655 #endif
656 if( MB_SUCCESS != rval ) return rval;
657
658 for( t = tris.begin(); t != tris.end(); ++t )
659 {
660 #ifndef MB_OBB_USE_VECTOR_QUERIES
661 if( TYPE_FROM_HANDLE( *t ) != MBTRI ) break;
662 #elif !defined( MB_OBB_USE_TYPE_QUERIES )
663 if( TYPE_FROM_HANDLE( *t ) != MBTRI ) continue;
664 #endif
665 rval = get_moab_instance()->get_connectivity( *t, conn, num_conn, true );
666 if( MB_SUCCESS != rval ) return rval;
667 if( num_conn != 3 ) continue;
668
669 rval = get_moab_instance()->get_coords( conn, num_conn, coords[0].array() );
670 if( MB_SUCCESS != rval ) return rval;
671
672 GeomUtil::closest_location_on_tri( center, coords, closest );
673 closest -= center;
674 if( ( closest % closest ) <= radsqr &&
675 std::find( facets_out.begin(), facets_out.end(), *t ) == facets_out.end() )
676 {
677 facets_out.push_back( *t );
678 if( sets_out ) sets_out->push_back( surf );
679 }
680 }
681 }
682
683 if( accum )
684 {
685 accum->end_traversal( max_depth );
686 }
687
688 return MB_SUCCESS;
689 }
690
691
692
693 class RayIntersector : public OrientedBoxTreeTool::Op
694 {
695 private:
696 OrientedBoxTreeTool* tool;
697 const CartVect b, m;
698 const double* len;
699 const double tol;
700 Range& boxes;
701
702 public:
703 RayIntersector( OrientedBoxTreeTool* tool_ptr,
704 const double* ray_point,
705 const double* unit_ray_dir,
706 const double* ray_length,
707 double tolerance,
708 Range& leaf_boxes )
709 : tool( tool_ptr ), b( ray_point ), m( unit_ray_dir ), len( ray_length ), tol( tolerance ), boxes( leaf_boxes )
710 {
711 }
712
713 virtual ErrorCode visit( EntityHandle node, int depth, bool& descend );
714 virtual ErrorCode leaf( EntityHandle node );
715 };
716
717
718
719
720
721
722
723
724
725
726
727
728
729 ErrorCode OrientedBoxTreeTool::ray_intersect_triangles( std::vector< double >& intersection_distances_out,
730 std::vector< EntityHandle >& intersection_facets_out,
731 const Range& boxes,
732 double ,
733 const double ray_point[3],
734 const double unit_ray_dir[3],
735 const double* ray_length,
736 unsigned int* raytri_test_count )
737 {
738 ErrorCode rval;
739 intersection_distances_out.clear();
740 #ifdef MB_OBB_USE_VECTOR_QUERIES
741 std::vector< EntityHandle > tris;
742 #endif
743
744 const CartVect point( ray_point );
745 const CartVect dir( unit_ray_dir );
746
747 for( Range::iterator b = boxes.begin(); b != boxes.end(); ++b )
748 {
749 #ifndef MB_OBB_USE_VECTOR_QUERIES
750 Range tris;
751 #ifdef MB_OBB_USE_TYPE_QUERIES
752 rval = instance->get_entities_by_type( *b, MBTRI, tris );
753 #else
754 rval = instance->get_entities_by_handle( *b, tris );
755 #endif
756 #else
757 tris.clear();
758 rval = instance->get_entities_by_handle( *b, tris );
759 #endif
760 if( MB_SUCCESS != rval ) return rval;
761
762
763 #ifndef MB_OBB_USE_VECTOR_QUERIES
764 for( Range::iterator t = tris.begin(); t != tris.end(); ++t )
765 #else
766 for( std::vector< EntityHandle >::iterator t = tris.begin(); t != tris.end(); ++t )
767 #endif
768 {
769 #ifndef MB_OBB_USE_TYPE_QUERIES
770 if( TYPE_FROM_HANDLE( *t ) != MBTRI ) continue;
771 #endif
772
773 const EntityHandle* conn = NULL;
774 int len = 0;
775 rval = instance->get_connectivity( *t, conn, len, true );
776 if( MB_SUCCESS != rval ) return rval;
777
778 CartVect coords[3];
779 rval = instance->get_coords( conn, 3, coords[0].array() );
780 if( MB_SUCCESS != rval ) return rval;
781
782 if( raytri_test_count ) *raytri_test_count += 1;
783
784 double td;
785 if( GeomUtil::plucker_ray_tri_intersect( coords, point, dir, td, ray_length ) )
786 {
787 intersection_distances_out.push_back( td );
788 intersection_facets_out.push_back( *t );
789 }
790 }
791 }
792
793 return MB_SUCCESS;
794 }
795
796 ErrorCode OrientedBoxTreeTool::ray_intersect_triangles( std::vector< double >& intersection_distances_out,
797 std::vector< EntityHandle >& intersection_facets_out,
798 EntityHandle root_set,
799 double tolerance,
800 const double ray_point[3],
801 const double unit_ray_dir[3],
802 const double* ray_length,
803 TrvStats* accum )
804 {
805 Range boxes;
806 ErrorCode rval;
807
808 rval = ray_intersect_boxes( boxes, root_set, tolerance, ray_point, unit_ray_dir, ray_length, accum );
809 if( MB_SUCCESS != rval ) return rval;
810
811 return ray_intersect_triangles( intersection_distances_out, intersection_facets_out, boxes, tolerance, ray_point,
812 unit_ray_dir, ray_length, accum ? &( accum->ray_tri_tests_count ) : NULL );
813 }
814
815 ErrorCode OrientedBoxTreeTool::ray_intersect_boxes( Range& boxes_out,
816 EntityHandle root_set,
817 double tolerance,
818 const double ray_point[3],
819 const double unit_ray_dir[3],
820 const double* ray_length,
821 TrvStats* accum )
822 {
823 RayIntersector op( this, ray_point, unit_ray_dir, ray_length, tolerance, boxes_out );
824 return preorder_traverse( root_set, op, accum );
825 }
826
827 ErrorCode RayIntersector::visit( EntityHandle node, int, bool& descend )
828 {
829 OrientedBox box;
830 ErrorCode rval = tool->box( node, box );
831 if( MB_SUCCESS != rval ) return rval;
832
833 descend = box.intersect_ray( b, m, tol, len );
834 return MB_SUCCESS;
835 }
836
837 ErrorCode RayIntersector::leaf( EntityHandle node )
838 {
839 boxes.insert( node );
840 return MB_SUCCESS;
841 }
842
843
844
845 ErrorCode OrientedBoxTreeTool::get_close_tris( CartVect int_pt,
846 double tol,
847 const EntityHandle* rootSet,
848 const EntityHandle* geomVol,
849 const Tag* senseTag,
850 std::vector< EntityHandle >& close_tris,
851 std::vector< int >& close_senses )
852 {
853 std::vector< EntityHandle > close_surfs;
854 ErrorCode rval = sphere_intersect_triangles( int_pt.array(), tol, *rootSet, close_tris, &close_surfs );
855 assert( MB_SUCCESS == rval );
856 if( MB_SUCCESS != rval ) return rval;
857
858
859 close_senses.resize( close_surfs.size() );
860 for( unsigned i = 0; i < close_surfs.size(); ++i )
861 {
862 EntityHandle vols[2];
863 rval = get_moab_instance()->tag_get_data( *senseTag, &( close_surfs[i] ), 1, vols );
864 assert( MB_SUCCESS == rval );
865 if( MB_SUCCESS != rval ) return rval;
866 if( vols[0] == vols[1] )
867 {
868 std::cerr << "error: surf has positive and negative sense wrt same volume" << std::endl;
869 return MB_FAILURE;
870 }
871 if( *geomVol == vols[0] )
872 {
873 close_senses[i] = 1;
874 }
875 else if( *geomVol == vols[1] )
876 {
877 close_senses[i] = -1;
878 }
879 else
880 {
881 return MB_FAILURE;
882 }
883 }
884
885 return MB_SUCCESS;
886 }
887
888 class RayIntersectSets : public OrientedBoxTreeTool::Op
889 {
890 private:
891
892 OrientedBoxTreeTool* tool;
893 const CartVect ray_origin;
894 const CartVect ray_direction;
895 OrientedBoxTreeTool::IntersectSearchWindow& search_win;
896 const double tol;
899 OrientedBoxTreeTool::IntRegCtxt& int_reg_callback;
900
901
902 int* surfTriOrient;
903 int surfTriOrient_val;
904
905
906 unsigned int* raytri_test_count;
907 EntityHandle lastSet;
908 int lastSetDepth;
909
910 public:
911 RayIntersectSets( OrientedBoxTreeTool* tool_ptr,
912 const double* ray_point,
913 const double* unit_ray_dir,
914 const double tolerance,
915 OrientedBoxTreeTool::IntersectSearchWindow& win,
916 unsigned int* ray_tri_test_count,
917 OrientedBoxTreeTool::IntRegCtxt& intRegCallback )
918 : tool( tool_ptr ), ray_origin( ray_point ), ray_direction( unit_ray_dir ), search_win( win ), tol( tolerance ),
919 int_reg_callback( intRegCallback ), surfTriOrient_val( 0 ), raytri_test_count( ray_tri_test_count ),
920 lastSet( 0 ), lastSetDepth( 0 )
921 {
922
923
924
925 if( int_reg_callback.getDesiredOrient() )
926 {
927 surfTriOrient = &surfTriOrient_val;
928 }
929 else
930 {
931 surfTriOrient = NULL;
932 }
933
934
935 if( search_win.first )
936 {
937 assert( 0 <= *( search_win.first ) );
938 }
939 if( search_win.second )
940 {
941 assert( 0 >= *( search_win.second ) );
942 }
943 };
944
945 virtual ErrorCode visit( EntityHandle node, int depth, bool& descend );
946 virtual ErrorCode leaf( EntityHandle node );
947 };
948
949 ErrorCode RayIntersectSets::visit( EntityHandle node, int depth, bool& descend )
950 {
951 OrientedBox box;
952 ErrorCode rval = tool->box( node, box );
953 assert( MB_SUCCESS == rval );
954 if( MB_SUCCESS != rval ) return rval;
955
956 descend = box.intersect_ray( ray_origin, ray_direction, tol, search_win.first, search_win.second );
957
958 if( lastSet && depth <= lastSetDepth ) lastSet = 0;
959
960 if( descend && !lastSet )
961 {
962 Range tmp_sets;
963 rval = tool->get_moab_instance()->get_entities_by_type( node, MBENTITYSET, tmp_sets );
964 assert( MB_SUCCESS == rval );
965 if( MB_SUCCESS != rval ) return rval;
966
967 if( !tmp_sets.empty() )
968 {
969 if( tmp_sets.size() > 1 ) return MB_FAILURE;
970 lastSet = *tmp_sets.begin();
971 lastSetDepth = depth;
972
973 rval = int_reg_callback.update_orient( lastSet, surfTriOrient );
974 if( MB_SUCCESS != rval ) return rval;
975 }
976 }
977
978 return MB_SUCCESS;
979 }
980
981 ErrorCode RayIntersectSets::leaf( EntityHandle node )
982 {
983 assert( lastSet );
984 if( !lastSet )
985 return MB_FAILURE;
986
987 #ifndef MB_OBB_USE_VECTOR_QUERIES
988 Range tris;
989 #ifdef MB_OBB_USE_TYPE_QUERIES
990 ErrorCode rval = tool->get_moab_instance()->get_entities_by_type( node, MBTRI, tris );
991 #else
992 ErrorCode rval = tool->get_moab_instance()->get_entities_by_handle( node, tris );
993 #endif
994 #else
995 std::vector< EntityHandle > tris;
996 ErrorCode rval = tool->get_moab_instance()->get_entities_by_handle( node, tris );
997 #endif
998 assert( MB_SUCCESS == rval );
999 if( MB_SUCCESS != rval ) return rval;
1000
1001 #ifndef MB_OBB_USE_VECTOR_QUERIES
1002 for( Range::iterator t = tris.begin(); t != tris.end(); ++t )
1003 #else
1004 for( std::vector< EntityHandle >::iterator t = tris.begin(); t != tris.end(); ++t )
1005 #endif
1006 {
1007 #ifndef MB_OBB_USE_TYPE_QUERIES
1008 if( TYPE_FROM_HANDLE( *t ) != MBTRI ) continue;
1009 #endif
1010
1011 const EntityHandle* conn;
1012 int num_conn;
1013 rval = tool->get_moab_instance()->get_connectivity( *t, conn, num_conn, true );
1014 assert( MB_SUCCESS == rval );
1015 if( MB_SUCCESS != rval ) return rval;
1016
1017 CartVect coords[3];
1018 rval = tool->get_moab_instance()->get_coords( conn, 3, coords[0].array() );
1019 assert( MB_SUCCESS == rval );
1020 if( MB_SUCCESS != rval ) return rval;
1021
1022 if( raytri_test_count ) *raytri_test_count += 1;
1023
1024 double int_dist;
1025 GeomUtil::intersection_type int_type = GeomUtil::NONE;
1026
1027 if( GeomUtil::plucker_ray_tri_intersect( coords, ray_origin, ray_direction, int_dist, search_win.first,
1028 search_win.second, surfTriOrient, &int_type ) )
1029 {
1030 int_reg_callback.register_intersection( lastSet, *t, int_dist, search_win, int_type );
1031 }
1032 }
1033 return MB_SUCCESS;
1034 }
1035
1036 ErrorCode OrientedBoxTreeTool::ray_intersect_sets( std::vector< double >& distances_out,
1037 std::vector< EntityHandle >& sets_out,
1038 std::vector< EntityHandle >& facets_out,
1039 EntityHandle root_set,
1040 const double tolerance,
1041 const double ray_point[3],
1042 const double unit_ray_dir[3],
1043 IntersectSearchWindow& search_win,
1044 IntRegCtxt& int_reg_callback,
1045 TrvStats* accum )
1046
1047 {
1048 RayIntersectSets op( this, ray_point, unit_ray_dir, tolerance, search_win,
1049 accum ? &( accum->ray_tri_tests_count ) : NULL, int_reg_callback );
1050 ErrorCode rval = preorder_traverse( root_set, op, accum );
1051
1052 distances_out = int_reg_callback.get_intersections();
1053 sets_out = int_reg_callback.get_sets();
1054 facets_out = int_reg_callback.get_facets();
1055
1056 return rval;
1057 }
1058
1059 ErrorCode OrientedBoxTreeTool::ray_intersect_sets( std::vector< double >& distances_out,
1060 std::vector< EntityHandle >& sets_out,
1061 std::vector< EntityHandle >& facets_out,
1062 EntityHandle root_set,
1063 double tolerance,
1064 const double ray_point[3],
1065 const double unit_ray_dir[3],
1066 const double* ray_length,
1067 TrvStats* accum )
1068 {
1069 IntRegCtxt int_reg_ctxt;
1070
1071 OrientedBoxTreeTool::IntersectSearchWindow search_win( ray_length, (double*)0 );
1072
1073 RayIntersectSets op( this, ray_point, unit_ray_dir, tolerance, search_win,
1074 accum ? &( accum->ray_tri_tests_count ) : NULL, int_reg_ctxt );
1075
1076 ErrorCode rval = preorder_traverse( root_set, op, accum );
1077
1078 if( MB_SUCCESS != rval )
1079 {
1080 return rval;
1081 }
1082
1083 distances_out = int_reg_ctxt.get_intersections();
1084 sets_out = int_reg_ctxt.get_sets();
1085 facets_out = int_reg_ctxt.get_facets();
1086
1087 return MB_SUCCESS;
1088 }
1089
1090 ErrorCode OrientedBoxTreeTool::ray_intersect_sets( EntityHandle root_set,
1091 const double tolerance,
1092 const double ray_point[3],
1093 const double unit_ray_dir[3],
1094 IntersectSearchWindow& search_win,
1095 IntRegCtxt& int_reg_callback,
1096 TrvStats* accum )
1097
1098 {
1099 RayIntersectSets op( this, ray_point, unit_ray_dir, tolerance, search_win,
1100 accum ? &( accum->ray_tri_tests_count ) : NULL, int_reg_callback );
1101 return preorder_traverse( root_set, op, accum );
1102 }
1103
1104
1105
1106 struct OBBTreeCPFrame
1107 {
1108 OBBTreeCPFrame( double d, EntityHandle n, EntityHandle s, int dp )
1109 : dist_sqr( d ), node( n ), mset( s ), depth( dp )
1110 {
1111 }
1112 double dist_sqr;
1113 EntityHandle node;
1114 EntityHandle mset;
1115 int depth;
1116 };
1117
1118 ErrorCode OrientedBoxTreeTool::closest_to_location( const double* point,
1119 EntityHandle root,
1120 double* point_out,
1121 EntityHandle& facet_out,
1122 EntityHandle* set_out,
1123 TrvStats* accum )
1124 {
1125 ErrorCode rval;
1126 const CartVect loc( point );
1127 double smallest_dist_sqr = std::numeric_limits< double >::max();
1128
1129 EntityHandle current_set = 0;
1130 Range sets;
1131 std::vector< EntityHandle > children( 2 );
1132 std::vector< double > coords;
1133 std::vector< OBBTreeCPFrame > stack;
1134 int max_depth = -1;
1135
1136 stack.push_back( OBBTreeCPFrame( 0.0, root, current_set, 0 ) );
1137
1138 while( !stack.empty() )
1139 {
1140
1141
1142 EntityHandle node = stack.back().node;
1143 double dist_sqr = stack.back().dist_sqr;
1144 current_set = stack.back().mset;
1145 int current_depth = stack.back().depth;
1146 stack.pop_back();
1147
1148
1149 if( dist_sqr > smallest_dist_sqr ) continue;
1150
1151
1152 if( accum )
1153 {
1154 accum->increment( current_depth );
1155 max_depth = std::max( max_depth, current_depth );
1156 }
1157
1158
1159 if( set_out && !current_set )
1160 {
1161 sets.clear();
1162 rval = instance->get_entities_by_type( node, MBENTITYSET, sets );
1163 if( MB_SUCCESS != rval ) return rval;
1164 if( !sets.empty() )
1165 {
1166 if( sets.size() != 1 ) return MB_MULTIPLE_ENTITIES_FOUND;
1167 current_set = sets.front();
1168 }
1169 }
1170
1171
1172 children.clear();
1173 rval = instance->get_child_meshsets( node, children );
1174 if( MB_SUCCESS != rval ) return rval;
1175
1176
1177 if( !children.empty() )
1178 {
1179 if( children.size() != 2 ) return MB_MULTIPLE_ENTITIES_FOUND;
1180
1181
1182 OrientedBox box1, box2;
1183 rval = box( children[0], box1 );
1184 if( MB_SUCCESS != rval ) return rval;
1185 rval = box( children[1], box2 );
1186 if( MB_SUCCESS != rval ) return rval;
1187
1188
1189 CartVect pt1, pt2;
1190 box1.closest_location_in_box( loc, pt1 );
1191 box2.closest_location_in_box( loc, pt2 );
1192 pt1 -= loc;
1193 pt2 -= loc;
1194 const double dsqr1 = pt1 % pt1;
1195 const double dsqr2 = pt2 % pt2;
1196
1197
1198 if( dsqr1 < dsqr2 )
1199 {
1200 stack.push_back( OBBTreeCPFrame( dsqr2, children[1], current_set, current_depth + 1 ) );
1201 stack.push_back( OBBTreeCPFrame( dsqr1, children[0], current_set, current_depth + 1 ) );
1202 }
1203 else
1204 {
1205 stack.push_back( OBBTreeCPFrame( dsqr1, children[0], current_set, current_depth + 1 ) );
1206 stack.push_back( OBBTreeCPFrame( dsqr2, children[1], current_set, current_depth + 1 ) );
1207 }
1208 }
1209 else
1210 {
1211 if( accum )
1212 {
1213 accum->increment_leaf( current_depth );
1214 }
1215
1216 Range facets;
1217 rval = instance->get_entities_by_dimension( node, 2, facets );
1218 if( MB_SUCCESS != rval ) return rval;
1219
1220 const EntityHandle* conn = NULL;
1221 int len = 0;
1222 CartVect tmp, diff;
1223 for( Range::iterator i = facets.begin(); i != facets.end(); ++i )
1224 {
1225 rval = instance->get_connectivity( *i, conn, len, true );
1226 if( MB_SUCCESS != rval ) return rval;
1227
1228 coords.resize( 3 * len );
1229 rval = instance->get_coords( conn, len, &coords[0] );
1230 if( MB_SUCCESS != rval ) return rval;
1231
1232 if( len == 3 )
1233 GeomUtil::closest_location_on_tri( loc, (CartVect*)( &coords[0] ), tmp );
1234 else
1235 GeomUtil::closest_location_on_polygon( loc, (CartVect*)( &coords[0] ), len, tmp );
1236
1237 diff = tmp - loc;
1238 dist_sqr = diff % diff;
1239 if( dist_sqr < smallest_dist_sqr )
1240 {
1241 smallest_dist_sqr = dist_sqr;
1242 facet_out = *i;
1243 tmp.get( point_out );
1244 if( set_out ) *set_out = current_set;
1245 }
1246 }
1247 }
1248 }
1249
1250 if( accum )
1251 {
1252 accum->end_traversal( max_depth );
1253 }
1254
1255 return MB_SUCCESS;
1256 }
1257
1258 ErrorCode OrientedBoxTreeTool::closest_to_location( const double* point,
1259 EntityHandle root,
1260 double tolerance,
1261 std::vector< EntityHandle >& facets_out,
1262 std::vector< EntityHandle >* sets_out,
1263 TrvStats* accum )
1264 {
1265 ErrorCode rval;
1266 const CartVect loc( point );
1267 double smallest_dist_sqr = std::numeric_limits< double >::max();
1268 double smallest_dist = smallest_dist_sqr;
1269
1270 EntityHandle current_set = 0;
1271 Range sets;
1272 std::vector< EntityHandle > children( 2 );
1273 std::vector< double > coords;
1274 std::vector< OBBTreeCPFrame > stack;
1275 int max_depth = -1;
1276
1277 stack.push_back( OBBTreeCPFrame( 0.0, root, current_set, 0 ) );
1278
1279 while( !stack.empty() )
1280 {
1281
1282
1283 EntityHandle node = stack.back().node;
1284 double dist_sqr = stack.back().dist_sqr;
1285 current_set = stack.back().mset;
1286 int current_depth = stack.back().depth;
1287 stack.pop_back();
1288
1289
1290 if( dist_sqr > smallest_dist_sqr + tolerance ) continue;
1291
1292
1293 if( accum )
1294 {
1295 accum->increment( current_depth );
1296 max_depth = std::max( max_depth, current_depth );
1297 }
1298
1299
1300 if( sets_out && !current_set )
1301 {
1302 sets.clear();
1303 rval = instance->get_entities_by_type( node, MBENTITYSET, sets );
1304 if( MB_SUCCESS != rval ) return rval;
1305 if( !sets.empty() )
1306 {
1307 if( sets.size() != 1 ) return MB_MULTIPLE_ENTITIES_FOUND;
1308 current_set = *sets.begin();
1309 }
1310 }
1311
1312
1313 children.clear();
1314 rval = instance->get_child_meshsets( node, children );
1315 if( MB_SUCCESS != rval ) return rval;
1316
1317
1318 if( !children.empty() )
1319 {
1320 if( children.size() != 2 ) return MB_MULTIPLE_ENTITIES_FOUND;
1321
1322
1323 OrientedBox box1, box2;
1324 rval = box( children[0], box1 );
1325 if( MB_SUCCESS != rval ) return rval;
1326 rval = box( children[1], box2 );
1327 if( MB_SUCCESS != rval ) return rval;
1328
1329
1330 CartVect pt1, pt2;
1331 box1.closest_location_in_box( loc, pt1 );
1332 box2.closest_location_in_box( loc, pt2 );
1333 pt1 -= loc;
1334 pt2 -= loc;
1335 const double dsqr1 = pt1 % pt1;
1336 const double dsqr2 = pt2 % pt2;
1337
1338
1339 if( dsqr1 < dsqr2 )
1340 {
1341 stack.push_back( OBBTreeCPFrame( dsqr2, children[1], current_set, current_depth + 1 ) );
1342 stack.push_back( OBBTreeCPFrame( dsqr1, children[0], current_set, current_depth + 1 ) );
1343 }
1344 else
1345 {
1346 stack.push_back( OBBTreeCPFrame( dsqr1, children[0], current_set, current_depth + 1 ) );
1347 stack.push_back( OBBTreeCPFrame( dsqr2, children[1], current_set, current_depth + 1 ) );
1348 }
1349 }
1350 else
1351 {
1352 if( accum )
1353 {
1354 accum->increment_leaf( current_depth );
1355 }
1356
1357 Range facets;
1358 rval = instance->get_entities_by_dimension( node, 2, facets );
1359 if( MB_SUCCESS != rval ) return rval;
1360
1361 const EntityHandle* conn = NULL;
1362 int len = 0;
1363 CartVect tmp, diff;
1364 for( Range::iterator i = facets.begin(); i != facets.end(); ++i )
1365 {
1366 rval = instance->get_connectivity( *i, conn, len, true );
1367 if( MB_SUCCESS != rval ) return rval;
1368
1369 coords.resize( 3 * len );
1370 rval = instance->get_coords( conn, len, &coords[0] );
1371 if( MB_SUCCESS != rval ) return rval;
1372
1373 if( len == 3 )
1374 GeomUtil::closest_location_on_tri( loc, (CartVect*)( &coords[0] ), tmp );
1375 else
1376 GeomUtil::closest_location_on_polygon( loc, (CartVect*)( &coords[0] ), len, tmp );
1377
1378 diff = tmp - loc;
1379 dist_sqr = diff % diff;
1380 if( dist_sqr < smallest_dist_sqr )
1381 {
1382 if( 0.5 * dist_sqr < 0.5 * smallest_dist_sqr + tolerance * ( 0.5 * tolerance - smallest_dist ) )
1383 {
1384 facets_out.clear();
1385 if( sets_out ) sets_out->clear();
1386 }
1387 smallest_dist_sqr = dist_sqr;
1388 smallest_dist = sqrt( smallest_dist_sqr );
1389
1390 facets_out.push_back( *i );
1391 std::swap( facets_out.front(), facets_out.back() );
1392 if( sets_out )
1393 {
1394 sets_out->push_back( current_set );
1395 std::swap( sets_out->front(), sets_out->back() );
1396 }
1397 }
1398 else if( dist_sqr <= smallest_dist_sqr + tolerance * ( tolerance + 2 * smallest_dist ) )
1399 {
1400 facets_out.push_back( *i );
1401 if( sets_out ) sets_out->push_back( current_set );
1402 }
1403 }
1404 }
1405 }
1406
1407 if( accum )
1408 {
1409 accum->end_traversal( max_depth );
1410 }
1411
1412 return MB_SUCCESS;
1413 }
1414
1415
1416
1417 class TreeLayoutPrinter : public OrientedBoxTreeTool::Op
1418 {
1419 public:
1420 TreeLayoutPrinter( std::ostream& stream, Interface* instance );
1421
1422 virtual ErrorCode visit( EntityHandle node, int depth, bool& descend );
1423 virtual ErrorCode leaf( EntityHandle node );
1424
1425 private:
1426 Interface* instance;
1427 std::ostream& outputStream;
1428 std::vector< bool > path;
1429 };
1430
1431 TreeLayoutPrinter::TreeLayoutPrinter( std::ostream& stream, Interface* interface )
1432 : instance( interface ), outputStream( stream )
1433 {
1434 }
1435
1436 ErrorCode TreeLayoutPrinter::visit( EntityHandle node, int depth, bool& descend )
1437 {
1438 descend = true;
1439
1440 if( (unsigned)depth > path.size() )
1441 {
1442
1443 path.push_back( true );
1444 }
1445 else
1446 {
1447 path.resize( depth );
1448 if( depth ) path.back() = false;
1449 }
1450
1451 for( unsigned i = 0; i + 1 < path.size(); ++i )
1452 {
1453 if( path[i] )
1454 outputStream << "| ";
1455 else
1456 outputStream << " ";
1457 }
1458 if( depth )
1459 {
1460 if( path.back() )
1461 outputStream << "+---";
1462 else
1463 outputStream << "\\---";
1464 }
1465 outputStream << instance->id_from_handle( node ) << std::endl;
1466 return MB_SUCCESS;
1467 }
1468
1469 ErrorCode TreeLayoutPrinter::leaf( EntityHandle )
1470 {
1471 return MB_SUCCESS;
1472 }
1473
1474 class TreeNodePrinter : public OrientedBoxTreeTool::Op
1475 {
1476 public:
1477 TreeNodePrinter( std::ostream& stream,
1478 bool list_contents,
1479 bool list_box,
1480 const char* id_tag_name,
1481 OrientedBoxTreeTool* tool_ptr );
1482
1483 virtual ErrorCode visit( EntityHandle node, int depth, bool& descend );
1484
1485 virtual ErrorCode leaf( EntityHandle )
1486 {
1487 return MB_SUCCESS;
1488 }
1489
1490 private:
1491 ErrorCode print_geometry( EntityHandle node );
1492 ErrorCode print_contents( EntityHandle node );
1493 ErrorCode print_counts( EntityHandle node );
1494
1495 bool printContents;
1496 bool printGeometry;
1497 bool haveTag;
1498 Tag tag, gidTag, geomTag;
1499 Interface* instance;
1500 OrientedBoxTreeTool* tool;
1501 std::ostream& outputStream;
1502 };
1503
1504 TreeNodePrinter::TreeNodePrinter( std::ostream& stream,
1505 bool list_contents,
1506 bool list_box,
1507 const char* id_tag_name,
1508 OrientedBoxTreeTool* tool_ptr )
1509 : printContents( list_contents ), printGeometry( list_box ), haveTag( false ), tag( 0 ), gidTag( 0 ), geomTag( 0 ),
1510 instance( tool_ptr->get_moab_instance() ), tool( tool_ptr ), outputStream( stream )
1511 {
1512 ErrorCode rval;
1513 if( id_tag_name )
1514 {
1515 rval = instance->tag_get_handle( id_tag_name, 1, MB_TYPE_INTEGER, tag );
1516 if( !rval )
1517 {
1518 std::cerr << "Could not get tag \"" << id_tag_name << "\"\n";
1519 stream << "Could not get tag \"" << id_tag_name << "\"\n";
1520 }
1521 else
1522 {
1523 haveTag = true;
1524 }
1525 }
1526
1527 gidTag = instance->globalId_tag();
1528
1529 rval = instance->tag_get_handle( GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, geomTag );
1530 if( MB_SUCCESS != rval ) geomTag = 0;
1531 }
1532
1533 ErrorCode TreeNodePrinter::visit( EntityHandle node, int, bool& descend )
1534 {
1535 descend = true;
1536 EntityHandle setid = instance->id_from_handle( node );
1537 outputStream << setid << ":" << std::endl;
1538
1539 Range surfs;
1540 ErrorCode r3 = MB_SUCCESS;
1541 if( geomTag )
1542 {
1543 const int two = 2;
1544 const void* tagdata[] = { &two };
1545 r3 = instance->get_entities_by_type_and_tag( node, MBENTITYSET, &geomTag, tagdata, 1, surfs );
1546
1547 if( MB_SUCCESS == r3 && surfs.size() == 1 )
1548 {
1549 EntityHandle surf = *surfs.begin();
1550 int id;
1551 if( gidTag && MB_SUCCESS == instance->tag_get_data( gidTag, &surf, 1, &id ) )
1552 outputStream << " Surface " << id << std::endl;
1553 else
1554 outputStream << " Surface w/ unknown ID (" << surf << ")" << std::endl;
1555 }
1556 }
1557
1558 ErrorCode r1 = printGeometry ? print_geometry( node ) : MB_SUCCESS;
1559 ErrorCode r2 = printContents ? print_contents( node ) : print_counts( node );
1560 outputStream << std::endl;
1561
1562 if( MB_SUCCESS != r1 )
1563 return r1;
1564 else if( MB_SUCCESS != r2 )
1565 return r2;
1566 else
1567 return r3;
1568 }
1569
1570 ErrorCode TreeNodePrinter::print_geometry( EntityHandle node )
1571 {
1572 OrientedBox box;
1573 ErrorCode rval = tool->box( node, box );
1574 if( MB_SUCCESS != rval ) return rval;
1575
1576 CartVect length = box.dimensions();
1577
1578 outputStream << box.center << " Radius: " << box.inner_radius() << " - " << box.outer_radius() << std::endl
1579 << '+' << box.axis( 0 ) << " : " << length[0] << std::endl
1580 << 'x' << box.axis( 1 ) << " : " << length[1] << std::endl
1581 << 'x' << box.axis( 2 ) << " : " << length[2] << std::endl;
1582 return MB_SUCCESS;
1583 }
1584
1585 ErrorCode TreeNodePrinter::print_counts( EntityHandle node )
1586 {
1587 for( EntityType type = MBVERTEX; type != MBMAXTYPE; ++type )
1588 {
1589 int count = 0;
1590 ErrorCode rval = instance->get_number_entities_by_type( node, type, count );
1591 if( MB_SUCCESS != rval ) return rval;
1592 if( count > 0 ) outputStream << " " << count << " " << CN::EntityTypeName( type ) << std::endl;
1593 }
1594 return MB_SUCCESS;
1595 }
1596
1597 ErrorCode TreeNodePrinter::print_contents( EntityHandle node )
1598 {
1599
1600 for( EntityType type = MBVERTEX; type != MBMAXTYPE; ++type )
1601 {
1602 Range range;
1603 ErrorCode rval = instance->get_entities_by_type( node, type, range );
1604 if( MB_SUCCESS != rval ) return rval;
1605 if( range.empty() ) continue;
1606 outputStream << " " << CN::EntityTypeName( type ) << " ";
1607 std::vector< int > ids( range.size() );
1608 if( haveTag )
1609 {
1610 rval = instance->tag_get_data( tag, range, &ids[0] );
1611 std::sort( ids.begin(), ids.end() );
1612 }
1613 else
1614 {
1615 Range::iterator ri = range.begin();
1616 std::vector< int >::iterator vi = ids.begin();
1617 while( ri != range.end() )
1618 {
1619 *vi = instance->id_from_handle( *ri );
1620 ++ri;
1621 ++vi;
1622 }
1623 }
1624
1625 unsigned i = 0;
1626 for( ;; )
1627 {
1628 unsigned beg = i, end;
1629 do
1630 {
1631 end = i++;
1632 } while( i < ids.size() && ids[end] + 1 == ids[i] );
1633 if( end == beg )
1634 outputStream << ids[end];
1635 else if( end == beg + 1 )
1636 outputStream << ids[beg] << ", " << ids[end];
1637 else
1638 outputStream << ids[beg] << "-" << ids[end];
1639
1640 if( i == ids.size() )
1641 {
1642 outputStream << std::endl;
1643 break;
1644 }
1645 else
1646 outputStream << ", ";
1647 }
1648 }
1649
1650 return MB_SUCCESS;
1651 }
1652
1653 void OrientedBoxTreeTool::print( EntityHandle set, std::ostream& str, bool list, const char* tag )
1654 {
1655 TreeLayoutPrinter op1( str, instance );
1656 TreeNodePrinter op2( str, list, true, tag, this );
1657 ErrorCode r1 = preorder_traverse( set, op1 );
1658 str << std::endl;
1659 ErrorCode r2 = preorder_traverse( set, op2 );
1660 if( r1 != MB_SUCCESS || r2 != MB_SUCCESS )
1661 {
1662 std::cerr << "Errors encountered while printing tree\n";
1663 str << "Errors encountered while printing tree\n";
1664 }
1665 }
1666
1667
1668
1669 void OrientedBoxTreeTool::TrvStats::reset()
1670 {
1671 nodes_visited_count.clear();
1672 leaves_visited_count.clear();
1673 traversals_ended_count.clear();
1674 ray_tri_tests_count = 0;
1675 }
1676
1677 void OrientedBoxTreeTool::TrvStats::increment( unsigned depth )
1678 {
1679
1680 while( nodes_visited_count.size() <= depth )
1681 {
1682 nodes_visited_count.push_back( 0 );
1683 leaves_visited_count.push_back( 0 );
1684 traversals_ended_count.push_back( 0 );
1685 }
1686 nodes_visited_count[depth] += 1;
1687 }
1688
1689 void OrientedBoxTreeTool::TrvStats::increment_leaf( unsigned depth )
1690 {
1691
1692 leaves_visited_count[depth] += 1;
1693 }
1694
1695 void OrientedBoxTreeTool::TrvStats::end_traversal( unsigned depth )
1696 {
1697
1698
1699 traversals_ended_count[depth] += 1;
1700 }
1701
1702 void OrientedBoxTreeTool::TrvStats::print( std::ostream& str ) const
1703 {
1704
1705 const std::string h1 = "OBBTree Depth";
1706 const std::string h2 = " - NodesVisited";
1707 const std::string h3 = " - LeavesVisited";
1708 const std::string h4 = " - TraversalsEnded";
1709
1710 str << h1 << h2 << h3 << h4 << std::endl;
1711
1712 unsigned num_visited = 0, num_leaves = 0, num_traversals = 0;
1713 for( unsigned i = 0; i < traversals_ended_count.size(); ++i )
1714 {
1715
1716 num_visited += nodes_visited_count[i];
1717 num_leaves += leaves_visited_count[i];
1718 num_traversals += traversals_ended_count[i];
1719
1720 str << std::setw( h1.length() ) << i << std::setw( h2.length() ) << nodes_visited_count[i]
1721 << std::setw( h3.length() ) << leaves_visited_count[i] << std::setw( h4.length() )
1722 << traversals_ended_count[i] << std::endl;
1723 }
1724
1725 str << std::setw( h1.length() ) << "---- Totals:" << std::setw( h2.length() ) << num_visited
1726 << std::setw( h3.length() ) << num_leaves << std::setw( h4.length() ) << num_traversals << std::endl;
1727
1728 if( ray_tri_tests_count )
1729 {
1730 str << std::setw( h1.length() ) << "---- Total ray-tri tests: " << ray_tri_tests_count << std::endl;
1731 }
1732 }
1733
1734
1735
1736 class StatData
1737 {
1738 public:
1739 struct Ratio
1740 {
1741 double min, max, sum, sqr;
1742 int hist[10];
1743 Ratio()
1744 : min( std::numeric_limits< double >::max() ), max( -std::numeric_limits< double >::max() ), sum( 0.0 ),
1745 sqr( 0.0 )
1746 {
1747 hist[0] = hist[1] = hist[2] = hist[3] = hist[4] = hist[5] = hist[6] = hist[7] = hist[8] = hist[9] = 0;
1748 }
1749 void accum( double v )
1750 {
1751 if( v < min ) min = v;
1752 if( v > max ) max = v;
1753 sum += v;
1754 sqr += v * v;
1755 int i = (int)( 10 * v );
1756 if( i < 0 )
1757 i = 0;
1758 else if( i > 9 )
1759 i = 9;
1760 ++hist[i];
1761 }
1762 };
1763
1764 template < typename T >
1765 struct Stat
1766 {
1767 T min, max;
1768 double sum, sqr;
1769 Stat() : sum( 0.0 ), sqr( 0.0 )
1770 {
1771 std::numeric_limits< T > lim;
1772 min = lim.max();
1773 if( lim.is_integer )
1774 max = lim.min();
1775 else
1776 max = -lim.max();
1777 }
1778 void accum( T v )
1779 {
1780 if( v < min ) min = v;
1781 if( v > max ) max = v;
1782 sum += v;
1783 sqr += (double)v * v;
1784 }
1785 };
1786
1787 StatData() : count( 0 ) {}
1788
1789 Ratio volume;
1790 Ratio entities;
1791 Ratio radius;
1792 Stat< unsigned > leaf_ent;
1793 Stat< double > vol;
1794 Stat< double > area;
1795 std::vector< unsigned > leaf_depth;
1796 unsigned count;
1797 };
1798
1799 static int measure( const CartVect& v, double& result )
1800 {
1801 const double tol = 1e-6;
1802 int dims = 0;
1803 result = 1;
1804 for( int i = 0; i < 3; ++i )
1805 if( v[i] > tol )
1806 {
1807 ++dims;
1808 result *= v[i];
1809 }
1810 return dims;
1811 }
1812
1813 ErrorCode OrientedBoxTreeTool::recursive_stats( OrientedBoxTreeTool* tool,
1814 Interface* inst,
1815 EntityHandle set,
1816 int depth,
1817 StatData& data,
1818 unsigned& count_out,
1819 CartVect& dimensions_out )
1820 {
1821 ErrorCode rval;
1822 OrientedBox tmp_box;
1823 std::vector< EntityHandle > children( 2 );
1824 unsigned counts[2];
1825 bool isleaf;
1826
1827 ++data.count;
1828
1829 rval = tool->box( set, tmp_box );
1830 if( MB_SUCCESS != rval ) return rval;
1831 children.clear();
1832 rval = inst->get_child_meshsets( set, children );
1833 if( MB_SUCCESS != rval ) return rval;
1834 isleaf = children.empty();
1835 if( !isleaf && children.size() != 2 ) return MB_MULTIPLE_ENTITIES_FOUND;
1836
1837 dimensions_out = tmp_box.dimensions();
1838 data.radius.accum( tmp_box.inner_radius() / tmp_box.outer_radius() );
1839 data.vol.accum( tmp_box.volume() );
1840 data.area.accum( tmp_box.area() );
1841
1842 if( isleaf )
1843 {
1844 if( data.leaf_depth.size() <= (unsigned)depth ) data.leaf_depth.resize( depth + 1, 0 );
1845 ++data.leaf_depth[depth];
1846
1847 int count;
1848 rval = inst->get_number_entities_by_handle( set, count );
1849 if( MB_SUCCESS != rval ) return rval;
1850 count_out = count;
1851 data.leaf_ent.accum( count_out );
1852 }
1853 else
1854 {
1855 for( int i = 0; i < 2; ++i )
1856 {
1857 CartVect dims;
1858 rval = recursive_stats( tool, inst, children[i], depth + 1, data, counts[i], dims );
1859 if( MB_SUCCESS != rval ) return rval;
1860 double this_measure, chld_measure;
1861 int this_dim = measure( dimensions_out, this_measure );
1862 int chld_dim = measure( dims, chld_measure );
1863 double ratio;
1864 if( chld_dim < this_dim )
1865 ratio = 0;
1866 else
1867 ratio = chld_measure / this_measure;
1868
1869 data.volume.accum( ratio );
1870 }
1871 count_out = counts[0] + counts[1];
1872 data.entities.accum( (double)counts[0] / count_out );
1873 data.entities.accum( (double)counts[1] / count_out );
1874 }
1875 return MB_SUCCESS;
1876 }
1877
1878 static inline double std_dev( double sqr, double sum, double count )
1879 {
1880 sum /= count;
1881 sqr /= count;
1882 return sqrt( sqr - sum * sum );
1883 }
1884
1885
1886 #define WE << std::setw( 10 ) <<
1887 #define WW WE
1888 ErrorCode OrientedBoxTreeTool::stats( EntityHandle set,
1889 unsigned& total_entities,
1890 double& rv,
1891 double& tot_node_volume,
1892 double& tot_to_root_volume,
1893 unsigned& tree_height,
1894 unsigned& node_count,
1895 unsigned& num_leaves )
1896 {
1897 StatData d;
1898 ErrorCode rval;
1899 unsigned i;
1900 CartVect total_dim;
1901
1902 rval = recursive_stats( this, instance, set, 0, d, total_entities, total_dim );
1903 if( MB_SUCCESS != rval ) return rval;
1904
1905 tree_height = d.leaf_depth.size();
1906 unsigned min_leaf_depth = tree_height;
1907 num_leaves = 0;
1908 unsigned max_leaf_per_depth = 0;
1909
1910 for( i = 0; i < d.leaf_depth.size(); ++i )
1911 {
1912 unsigned val = d.leaf_depth[i];
1913 num_leaves += val;
1914
1915
1916 if( val && i < min_leaf_depth ) min_leaf_depth = i;
1917 if( max_leaf_per_depth < val ) max_leaf_per_depth = val;
1918 }
1919 rv = total_dim[0] * total_dim[1] * total_dim[2];
1920 tot_node_volume = d.vol.sum;
1921 tot_to_root_volume = d.vol.sum / rv;
1922 node_count = d.count;
1923
1924 return MB_SUCCESS;
1925 }
1926
1927 ErrorCode OrientedBoxTreeTool::stats( EntityHandle set, std::ostream& s )
1928 {
1929 StatData d;
1930 ErrorCode rval;
1931 unsigned total_entities, i;
1932 CartVect total_dim;
1933
1934 rval = recursive_stats( this, instance, set, 0, d, total_entities, total_dim );
1935 if( MB_SUCCESS != rval ) return rval;
1936
1937 unsigned tree_height = d.leaf_depth.size();
1938 unsigned min_leaf_depth = tree_height, num_leaves = 0;
1939 unsigned max_leaf_per_depth = 0;
1940 double sum_leaf_depth = 0, sqr_leaf_depth = 0;
1941 for( i = 0; i < d.leaf_depth.size(); ++i )
1942 {
1943 unsigned val = d.leaf_depth[i];
1944 num_leaves += val;
1945 sum_leaf_depth += (double)val * i;
1946 sqr_leaf_depth += (double)val * i * i;
1947 if( val && i < min_leaf_depth ) min_leaf_depth = i;
1948 if( max_leaf_per_depth < val ) max_leaf_per_depth = val;
1949 }
1950 unsigned num_non_leaf = d.count - num_leaves;
1951
1952 double rv = total_dim[0] * total_dim[1] * total_dim[2];
1953 s << "entities in tree: " << total_entities << std::endl
1954 << "root volume: " << rv << std::endl
1955 << "total node volume: " << d.vol.sum << std::endl
1956 << "total/root volume: " << d.vol.sum / rv << std::endl
1957 << "tree height: " << tree_height << std::endl
1958 << "node count: " << d.count << std::endl
1959 << "leaf count: " << num_leaves << std::endl
1960 << std::endl;
1961
1962 double avg_leaf_depth = sum_leaf_depth / num_leaves;
1963 double rms_leaf_depth = sqrt( sqr_leaf_depth / num_leaves );
1964 double std_leaf_depth = std_dev( sqr_leaf_depth, sum_leaf_depth, num_leaves );
1965
1966 double avg_leaf_ent = d.leaf_ent.sum / num_leaves;
1967 double rms_leaf_ent = sqrt( d.leaf_ent.sqr / num_leaves );
1968 double std_leaf_ent = std_dev( d.leaf_ent.sqr, d.leaf_ent.sum, num_leaves );
1969
1970 unsigned num_child = 2 * num_non_leaf;
1971
1972 double avg_vol_ratio = d.volume.sum / num_child;
1973 double rms_vol_ratio = sqrt( d.volume.sqr / num_child );
1974 double std_vol_ratio = std_dev( d.volume.sqr, d.volume.sum, num_child );
1975
1976 double avg_ent_ratio = d.entities.sum / num_child;
1977 double rms_ent_ratio = sqrt( d.entities.sqr / num_child );
1978 double std_ent_ratio = std_dev( d.entities.sqr, d.entities.sum, num_child );
1979
1980 double avg_rad_ratio = d.radius.sum / d.count;
1981 double rms_rad_ratio = sqrt( d.radius.sqr / d.count );
1982 double std_rad_ratio = std_dev( d.radius.sqr, d.radius.sum, d.count );
1983
1984 double avg_vol = d.vol.sum / d.count;
1985 double rms_vol = sqrt( d.vol.sqr / d.count );
1986 double std_vol = std_dev( d.vol.sqr, d.vol.sum, d.count );
1987
1988 double avg_area = d.area.sum / d.count;
1989 double rms_area = sqrt( d.area.sqr / d.count );
1990 double std_area = std_dev( d.area.sqr, d.area.sum, d.count );
1991
1992 int prec = s.precision();
1993 s << " " WW "Minimum" WW "Average" WW "RMS" WW "Maximum" WW "Std.Dev." << std::endl;
1994 s << std::setprecision( 1 )
1995 << "Leaf Depth " WW min_leaf_depth WW avg_leaf_depth WW rms_leaf_depth WW d.leaf_depth.size() -
1996 1 WW std_leaf_depth
1997 << std::endl;
1998 s << std::setprecision( 0 )
1999 << "Entities/Leaf " WW d.leaf_ent.min WW avg_leaf_ent WW rms_leaf_ent WW d.leaf_ent.max WW std_leaf_ent
2000 << std::endl;
2001 s << std::setprecision( 3 )
2002 << "Child Volume Ratio " WW d.volume.min WW avg_vol_ratio WW rms_vol_ratio WW d.volume.max WW std_vol_ratio
2003 << std::endl;
2004 s << std::setprecision( 3 )
2005 << "Child Entity Ratio " WW d.entities.min WW avg_ent_ratio WW rms_ent_ratio WW d.entities.max WW std_ent_ratio
2006 << std::endl;
2007 s << std::setprecision( 3 )
2008 << "Box Radius Ratio " WW d.radius.min WW avg_rad_ratio WW rms_rad_ratio WW d.radius.max WW std_rad_ratio
2009 << std::endl;
2010 s << std::setprecision( 0 ) << "Box volume " WE d.vol.min WE avg_vol WE rms_vol WE d.vol.max WE std_vol
2011 << std::endl;
2012 s << std::setprecision( 0 ) << "Largest side area " WE d.area.min WE avg_area WE rms_area WE d.area.max WE std_area
2013 << std::endl;
2014 s << std::setprecision( prec ) << std::endl;
2015
2016 s << "Leaf Depth Histogram (Root depth is 0)" << std::endl;
2017 double f = 60.0 / max_leaf_per_depth;
2018 for( i = min_leaf_depth; i < d.leaf_depth.size(); ++i )
2019 s << std::setw( 2 ) << i << " " << std::setw( 5 ) << d.leaf_depth[i] << " |" << std::setfill( '*' )
2020 << std::setw( (int)floor( f * d.leaf_depth[i] + 0.5 ) ) << "" << std::setfill( ' ' ) << std::endl;
2021 s << std::endl;
2022
2023 s << "Child/Parent Volume Ratio Histogram" << std::endl;
2024 f = 60.0 / *( std::max_element( d.volume.hist, d.volume.hist + 10 ) );
2025 for( i = 0; i < 10u; ++i )
2026 s << "0." << i << " " << std::setw( 5 ) << d.volume.hist[i] << " |" << std::setfill( '*' )
2027 << std::setw( (int)floor( f * d.volume.hist[i] + 0.5 ) ) << "" << std::setfill( ' ' ) << std::endl;
2028 s << std::endl;
2029
2030 s << "Child/Parent Entity Count Ratio Histogram" << std::endl;
2031 f = 60.0 / *( std::max_element( d.entities.hist, d.entities.hist + 10 ) );
2032 for( i = 0; i < 10u; ++i )
2033 s << "0." << i << " " << std::setw( 5 ) << d.entities.hist[i] << " |" << std::setfill( '*' )
2034 << std::setw( (int)floor( f * d.entities.hist[i] + 0.5 ) ) << "" << std::setfill( ' ' ) << std::endl;
2035 s << std::endl;
2036
2037 s << "Inner/Outer Radius Ratio Histogram (~0.70 for cube)" << std::endl;
2038
2039
2040 d.radius.hist[6] += d.radius.hist[7];
2041 f = 60.0 / *( std::max_element( d.entities.hist, d.entities.hist + 7 ) );
2042 for( i = 0; i < 7u; ++i )
2043 s << "0." << i << " " << std::setw( 5 ) << d.entities.hist[i] << " |" << std::setfill( '*' )
2044 << std::setw( (int)floor( f * d.entities.hist[i] + 0.5 ) ) << "" << std::setfill( ' ' ) << std::endl;
2045 s << std::endl;
2046
2047 return MB_SUCCESS;
2048 }
2049
2050 }