Mesh Oriented datABase  (version 5.4.1)
Array-based unstructured mesh datastructure
OrientedBoxTreeTool.cpp
Go to the documentation of this file.
00001 /*
00002  * MOAB, a Mesh-Oriented datABase, is a software component for creating,
00003  * storing and accessing finite element mesh data.
00004  *
00005  * Copyright 2004 Sandia Corporation.  Under the terms of Contract
00006  * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
00007  * retains certain rights in this software.
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2.1 of the License, or (at your option) any later version.
00013  *
00014  */
00015 
00016 /**\file OrientedBox.hpp
00017  *\author Jason Kraftcheck ([email protected])
00018  *\date 2006-07-18
00019  */
00020 
00021 #include "moab/Interface.hpp"
00022 #include "Internals.hpp"
00023 #include "moab/OrientedBoxTreeTool.hpp"
00024 #include "moab/Range.hpp"
00025 #include "moab/CN.hpp"
00026 #include "moab/GeomUtil.hpp"
00027 #include "MBTagConventions.hpp"
00028 #include <iostream>
00029 #include <iomanip>
00030 #include <algorithm>
00031 #include <limits>
00032 #include <cassert>
00033 #include <cmath>
00034 
00035 //#define MB_OBB_USE_VECTOR_QUERIES
00036 //#define MB_OBB_USE_TYPE_QUERIES
00037 
00038 namespace moab
00039 {
00040 
00041 #if defined( MB_OBB_USE_VECTOR_QUERIES ) && defined( MB_OBB_USE_TYPE_QUERIES )
00042 #undef MB_OBB_USE_TYPE_QUERIES
00043 #endif
00044 
00045 const char DEFAULT_TAG_NAME[] = "OBB";
00046 
00047 OrientedBoxTreeTool::Op::~Op() {}
00048 
00049 OrientedBoxTreeTool::OrientedBoxTreeTool( Interface* i, const char* tag_name, bool destroy_created_trees )
00050     : instance( i ), cleanUpTrees( destroy_created_trees )
00051 {
00052     if( !tag_name ) tag_name = DEFAULT_TAG_NAME;
00053     ErrorCode rval = OrientedBox::tag_handle( tagHandle, instance, tag_name );
00054     if( MB_SUCCESS != rval ) tagHandle = 0;
00055 }
00056 
00057 OrientedBoxTreeTool::~OrientedBoxTreeTool()
00058 {
00059     if( !cleanUpTrees ) return;
00060 
00061     while( !createdTrees.empty() )
00062     {
00063         EntityHandle tree = createdTrees.back();
00064         // make sure this is a tree (rather than some other, stale handle)
00065         const void* data_ptr = 0;
00066         ErrorCode rval       = instance->tag_get_by_ptr( tagHandle, &tree, 1, &data_ptr );
00067         if( MB_SUCCESS == rval ) rval = delete_tree( tree );
00068         if( MB_SUCCESS != rval ) createdTrees.pop_back();
00069     }
00070 }
00071 
00072 OrientedBoxTreeTool::Settings::Settings()
00073     : max_leaf_entities( 8 ), max_depth( 0 ), worst_split_ratio( 0.95 ), best_split_ratio( 0.4 ),
00074       set_options( MESHSET_SET )
00075 {
00076 }
00077 
00078 bool OrientedBoxTreeTool::Settings::valid() const
00079 {
00080     return max_leaf_entities > 0 && max_depth >= 0 && worst_split_ratio <= 1.0 && best_split_ratio >= 0.0 &&
00081            worst_split_ratio >= best_split_ratio;
00082 }
00083 
00084 /********************** Simple Tree Access Methods ****************************/
00085 
00086 ErrorCode OrientedBoxTreeTool::box( EntityHandle set, OrientedBox& obb )
00087 {
00088     return instance->tag_get_data( tagHandle, &set, 1, &obb );
00089 }
00090 
00091 ErrorCode OrientedBoxTreeTool::box( EntityHandle set,
00092                                     double center[3],
00093                                     double axis1[3],
00094                                     double axis2[3],
00095                                     double axis3[3] )
00096 {
00097     OrientedBox obb;
00098     ErrorCode rval = this->box( set, obb );
00099     obb.center.get( center );
00100     obb.scaled_axis( 0 ).get( axis1 );
00101     obb.scaled_axis( 1 ).get( axis2 );
00102     obb.scaled_axis( 2 ).get( axis3 );
00103     return rval;
00104 }
00105 
00106 /********************** Tree Construction Code ****************************/
00107 
00108 struct OrientedBoxTreeTool::SetData
00109 {
00110     EntityHandle handle;
00111     OrientedBox::CovarienceData box_data;
00112     // Range vertices;
00113 };
00114 
00115 ErrorCode OrientedBoxTreeTool::build( const Range& entities, EntityHandle& set_handle_out, const Settings* settings )
00116 {
00117     if( !entities.all_of_dimension( 2 ) ) return MB_TYPE_OUT_OF_RANGE;
00118     if( settings && !settings->valid() ) return MB_FAILURE;
00119 
00120     return build_tree( entities, set_handle_out, 0, settings ? *settings : Settings() );
00121 }
00122 
00123 ErrorCode OrientedBoxTreeTool::join_trees( const Range& sets, EntityHandle& set_handle_out, const Settings* settings )
00124 {
00125     if( !sets.all_of_type( MBENTITYSET ) ) return MB_TYPE_OUT_OF_RANGE;
00126     if( settings && !settings->valid() ) return MB_FAILURE;
00127 
00128     // Build initial set data list.
00129     std::list< SetData > data;
00130     for( Range::const_iterator i = sets.begin(); i != sets.end(); ++i )
00131     {
00132         Range elements;
00133         ErrorCode rval = instance->get_entities_by_dimension( *i, 2, elements, true );
00134         if( MB_SUCCESS != rval ) return rval;
00135         if( elements.empty() ) continue;
00136 
00137         data.push_back( SetData() );
00138         SetData& set_data = data.back();
00139         set_data.handle   = *i;
00140         rval              = OrientedBox::covariance_data_from_tris( set_data.box_data, instance, elements );
00141         if( MB_SUCCESS != rval ) return rval;
00142     }
00143 
00144     ErrorCode result = build_sets( data, set_handle_out, 0, settings ? *settings : Settings() );
00145     if( MB_SUCCESS != result ) return result;
00146 
00147     for( Range::reverse_iterator i = sets.rbegin(); i != sets.rend(); ++i )
00148     {
00149         createdTrees.erase( std::remove( createdTrees.begin(), createdTrees.end(), *i ), createdTrees.end() );
00150     }
00151     createdTrees.push_back( set_handle_out );
00152     return MB_SUCCESS;
00153 }
00154 
00155 /**\brief Split triangles by which side of a plane they are on
00156  *
00157  * Given a plane specified as a bisecting plane normal to one
00158  * of the axes of a box, split triangles based on which side
00159  * of the plane they are on.
00160  *\param instance   MOAB instance
00161  *\param box        The oriented box containing all the entities
00162  *\param axis       The axis for which the split plane is orthogonal
00163  *\param entities   The entities intersecting plane
00164  *\param left_list  Output, entities to the left of the plane
00165  *\param right_list Output, entities to the right of the plane
00166  */
00167 static ErrorCode split_box( Interface* instance,
00168                             const OrientedBox& box,
00169                             int axis,
00170                             const Range& entities,
00171                             Range& left_list,
00172                             Range& right_list )
00173 {
00174     ErrorCode rval;
00175     left_list.clear();
00176     right_list.clear();
00177 
00178     std::vector< CartVect > coords;
00179     for( Range::reverse_iterator i = entities.rbegin(); i != entities.rend(); ++i )
00180     {
00181         const EntityHandle* conn = NULL;
00182         int conn_len             = 0;
00183         rval                     = instance->get_connectivity( *i, conn, conn_len );
00184         if( MB_SUCCESS != rval ) return rval;
00185 
00186         coords.resize( conn_len );
00187         rval = instance->get_coords( conn, conn_len, coords[0].array() );
00188         if( MB_SUCCESS != rval ) return rval;
00189 
00190         CartVect centroid( 0.0 );
00191         for( int j = 0; j < conn_len; ++j )
00192             centroid += coords[j];
00193         centroid /= conn_len;
00194 
00195         if( ( box.axis( axis ) % ( centroid - box.center ) ) < 0.0 )
00196             left_list.insert( *i );
00197         else
00198             right_list.insert( *i );
00199     }
00200 
00201     return MB_SUCCESS;
00202 }
00203 
00204 ErrorCode OrientedBoxTreeTool::build_tree( const Range& entities,
00205                                            EntityHandle& set,
00206                                            int depth,
00207                                            const Settings& settings )
00208 {
00209     OrientedBox tmp_box;
00210     ErrorCode rval;
00211 
00212     if( entities.empty() )
00213     {
00214         Matrix3 axis;
00215         tmp_box = OrientedBox( axis, CartVect( 0. ) );
00216     }
00217     else
00218     {
00219         rval = OrientedBox::compute_from_2d_cells( tmp_box, instance, entities );
00220         if( MB_SUCCESS != rval ) return rval;
00221     }
00222 
00223     // create an entity set for the tree node
00224     rval = instance->create_meshset( settings.set_options, set );
00225     if( MB_SUCCESS != rval ) return rval;
00226 
00227     rval = instance->tag_set_data( tagHandle, &set, 1, &tmp_box );
00228     if( MB_SUCCESS != rval )
00229     {
00230         delete_tree( set );
00231         return rval;
00232     }
00233 
00234     // check if should create children
00235     bool leaf = true;
00236     ++depth;
00237     if( ( !settings.max_depth || depth < settings.max_depth ) &&
00238         entities.size() > (unsigned)settings.max_leaf_entities )
00239     {
00240         // try splitting with planes normal to each axis of the box
00241         // until we find an acceptable split
00242         double best_ratio = settings.worst_split_ratio;  // worst case ratio
00243         Range best_left_list, best_right_list;
00244         // Axes are sorted from shortest to longest, so search backwards
00245         for( int axis = 2; best_ratio > settings.best_split_ratio && axis >= 0; --axis )
00246         {
00247             Range left_list, right_list;
00248 
00249             rval = split_box( instance, tmp_box, axis, entities, left_list, right_list );
00250             if( MB_SUCCESS != rval )
00251             {
00252                 delete_tree( set );
00253                 return rval;
00254             }
00255 
00256             double ratio = fabs( (double)right_list.size() - left_list.size() ) / entities.size();
00257 
00258             if( ratio < best_ratio )
00259             {
00260                 best_ratio = ratio;
00261                 best_left_list.swap( left_list );
00262                 best_right_list.swap( right_list );
00263             }
00264         }
00265 
00266         // create children
00267         if( !best_left_list.empty() )
00268         {
00269             EntityHandle child = 0;
00270 
00271             rval = build_tree( best_left_list, child, depth, settings );
00272             if( MB_SUCCESS != rval )
00273             {
00274                 delete_tree( set );
00275                 return rval;
00276             }
00277             rval = instance->add_child_meshset( set, child );
00278             if( MB_SUCCESS != rval )
00279             {
00280                 delete_tree( set );
00281                 delete_tree( child );
00282                 return rval;
00283             }
00284 
00285             rval = build_tree( best_right_list, child, depth, settings );
00286             if( MB_SUCCESS != rval )
00287             {
00288                 delete_tree( set );
00289                 return rval;
00290             }
00291             rval = instance->add_child_meshset( set, child );
00292             if( MB_SUCCESS != rval )
00293             {
00294                 delete_tree( set );
00295                 delete_tree( child );
00296                 return rval;
00297             }
00298 
00299             leaf = false;
00300         }
00301     }
00302 
00303     if( leaf )
00304     {
00305         rval = instance->add_entities( set, entities );
00306         if( MB_SUCCESS != rval )
00307         {
00308             delete_tree( set );
00309             return rval;
00310         }
00311     }
00312 
00313     createdTrees.push_back( set );
00314     return MB_SUCCESS;
00315 }
00316 
00317 static ErrorCode split_sets( Interface*,
00318                              const OrientedBox& box,
00319                              int axis,
00320                              const std::list< OrientedBoxTreeTool::SetData >& sets,
00321                              std::list< OrientedBoxTreeTool::SetData >& left,
00322                              std::list< OrientedBoxTreeTool::SetData >& right )
00323 {
00324     left.clear();
00325     right.clear();
00326 
00327     std::list< OrientedBoxTreeTool::SetData >::const_iterator i;
00328     for( i = sets.begin(); i != sets.end(); ++i )
00329     {
00330         CartVect centroid( i->box_data.center / i->box_data.area );
00331         if( ( box.axis( axis ) % ( centroid - box.center ) ) < 0.0 )
00332             left.push_back( *i );
00333         else
00334             right.push_back( *i );
00335     }
00336 
00337     return MB_SUCCESS;
00338 }
00339 
00340 ErrorCode OrientedBoxTreeTool::build_sets( std::list< SetData >& sets,
00341                                            EntityHandle& node_set,
00342                                            int depth,
00343                                            const Settings& settings )
00344 {
00345     ErrorCode rval;
00346     int count = sets.size();
00347     if( 0 == count ) return MB_FAILURE;
00348 
00349     // calculate box
00350     OrientedBox obox;
00351 
00352     // make vector go out of scope when done, so memory is released
00353     {
00354         Range elems;
00355         std::vector< OrientedBox::CovarienceData > data( sets.size() );
00356         data.clear();
00357         for( std::list< SetData >::iterator i = sets.begin(); i != sets.end(); ++i )
00358         {
00359             data.push_back( i->box_data );
00360             rval = instance->get_entities_by_dimension( i->handle, 2, elems, true );
00361             if( MB_SUCCESS != rval ) return rval;
00362         }
00363 
00364         Range points;
00365         rval = instance->get_adjacencies( elems, 0, false, points, Interface::UNION );
00366         if( MB_SUCCESS != rval ) return rval;
00367 
00368         rval = OrientedBox::compute_from_covariance_data( obox, instance, &data[0], data.size(), points );
00369         if( MB_SUCCESS != rval ) return rval;
00370     }
00371 
00372     // If only one set in list...
00373     if( count == 1 )
00374     {
00375         node_set = sets.front().handle;
00376         return instance->tag_set_data( tagHandle, &node_set, 1, &obox );
00377     }
00378 
00379     // create an entity set for the tree node
00380     rval = instance->create_meshset( settings.set_options, node_set );
00381     if( MB_SUCCESS != rval ) return rval;
00382 
00383     rval = instance->tag_set_data( tagHandle, &node_set, 1, &obox );
00384     if( MB_SUCCESS != rval )
00385     {
00386         delete_tree( node_set );
00387         return rval;
00388     }
00389 
00390     double best_ratio = 2.0;
00391     std::list< SetData > best_left_list, best_right_list;
00392     for( int axis = 0; axis < 2; ++axis )
00393     {
00394         std::list< SetData > left_list, right_list;
00395         rval = split_sets( instance, obox, axis, sets, left_list, right_list );
00396         if( MB_SUCCESS != rval )
00397         {
00398             delete_tree( node_set );
00399             return rval;
00400         }
00401 
00402         double ratio = fabs( (double)right_list.size() - left_list.size() ) / sets.size();
00403 
00404         if( ratio < best_ratio )
00405         {
00406             best_ratio = ratio;
00407             best_left_list.swap( left_list );
00408             best_right_list.swap( right_list );
00409         }
00410     }
00411 
00412     // We must subdivide the list of sets, because we want to guarantee that
00413     // there is a node in the tree corresponding to each of the sets.  So if
00414     // we couldn't find a usable split plane, just split them in an arbitrary
00415     // manner.
00416     if( best_left_list.empty() || best_right_list.empty() )
00417     {
00418         best_left_list.clear();
00419         best_right_list.clear();
00420         std::list< SetData >* lists[2] = { &best_left_list, &best_right_list };
00421         int i                          = 0;
00422         while( !sets.empty() )
00423         {
00424             lists[i]->push_back( sets.front() );
00425             sets.pop_front();
00426             i = 1 - i;
00427         }
00428     }
00429     else
00430     {
00431         sets.clear();  // release memory before recursion
00432     }
00433 
00434     // Create child sets
00435 
00436     EntityHandle child = 0;
00437 
00438     rval = build_sets( best_left_list, child, depth + 1, settings );
00439     if( MB_SUCCESS != rval )
00440     {
00441         delete_tree( node_set );
00442         return rval;
00443     }
00444     rval = instance->add_child_meshset( node_set, child );
00445     if( MB_SUCCESS != rval )
00446     {
00447         delete_tree( node_set );
00448         delete_tree( child );
00449         return rval;
00450     }
00451 
00452     rval = build_sets( best_right_list, child, depth + 1, settings );
00453     if( MB_SUCCESS != rval )
00454     {
00455         delete_tree( node_set );
00456         return rval;
00457     }
00458     rval = instance->add_child_meshset( node_set, child );
00459     if( MB_SUCCESS != rval )
00460     {
00461         delete_tree( node_set );
00462         delete_tree( child );
00463         return rval;
00464     }
00465 
00466     return MB_SUCCESS;
00467 }
00468 
00469 ErrorCode OrientedBoxTreeTool::delete_tree( EntityHandle set )
00470 {
00471     std::vector< EntityHandle > children;
00472     ErrorCode rval = instance->get_child_meshsets( set, children, 0 );
00473     if( MB_SUCCESS != rval ) return rval;
00474 
00475     createdTrees.erase( std::remove( createdTrees.begin(), createdTrees.end(), set ), createdTrees.end() );
00476     children.insert( children.begin(), set );
00477     return instance->delete_entities( &children[0], children.size() );
00478 }
00479 
00480 ErrorCode OrientedBoxTreeTool::remove_root( EntityHandle root )
00481 {
00482     std::vector< EntityHandle >::iterator i = find( createdTrees.begin(), createdTrees.end(), root );
00483     if( i != createdTrees.end() )
00484     {
00485         createdTrees.erase( i );
00486         return MB_SUCCESS;
00487     }
00488     else
00489         return MB_ENTITY_NOT_FOUND;
00490 }
00491 
00492 /********************** Generic Tree Traversal ****************************/
00493 struct Data
00494 {
00495     EntityHandle set;
00496     int depth;
00497 };
00498 ErrorCode OrientedBoxTreeTool::preorder_traverse( EntityHandle set, Op& operation, TrvStats* accum )
00499 {
00500     ErrorCode rval;
00501     std::vector< EntityHandle > children;
00502     std::vector< Data > the_stack;
00503     Data data = { set, 0 };
00504     the_stack.push_back( data );
00505     int max_depth = -1;
00506 
00507     while( !the_stack.empty() )
00508     {
00509         data = the_stack.back();
00510         the_stack.pop_back();
00511 
00512         // increment traversal statistics
00513         if( accum )
00514         {
00515             accum->increment( data.depth );
00516             max_depth = std::max( max_depth, data.depth );
00517         }
00518 
00519         bool descend = true;
00520         rval         = operation.visit( data.set, data.depth, descend );
00521         assert( MB_SUCCESS == rval );
00522         if( MB_SUCCESS != rval ) return rval;
00523 
00524         if( !descend ) continue;
00525 
00526         children.clear();
00527         rval = instance->get_child_meshsets( data.set, children );
00528         assert( MB_SUCCESS == rval );
00529         if( MB_SUCCESS != rval ) return rval;
00530         if( children.empty() )
00531         {
00532             if( accum )
00533             {
00534                 accum->increment_leaf( data.depth );
00535             }
00536             rval = operation.leaf( data.set );
00537             assert( MB_SUCCESS == rval );
00538             if( MB_SUCCESS != rval ) return rval;
00539         }
00540         else if( children.size() == 2 )
00541         {
00542             data.depth++;
00543             data.set = children[0];
00544             the_stack.push_back( data );
00545             data.set = children[1];
00546             the_stack.push_back( data );
00547         }
00548         else
00549             return MB_MULTIPLE_ENTITIES_FOUND;
00550     }
00551 
00552     if( accum )
00553     {
00554         accum->end_traversal( max_depth );
00555     }
00556 
00557     return MB_SUCCESS;
00558 }
00559 
00560 /********************** General Sphere/Triangle Intersection ***************/
00561 
00562 struct OBBTreeSITFrame
00563 {
00564     OBBTreeSITFrame( EntityHandle n, EntityHandle s, int dp ) : node( n ), surf( s ), depth( dp ) {}
00565     EntityHandle node;
00566     EntityHandle surf;
00567     int depth;
00568 };
00569 
00570 ErrorCode OrientedBoxTreeTool::sphere_intersect_triangles( const double* center_v,
00571                                                            double radius,
00572                                                            EntityHandle tree_root,
00573                                                            std::vector< EntityHandle >& facets_out,
00574                                                            std::vector< EntityHandle >* sets_out,
00575                                                            TrvStats* accum )
00576 {
00577     const double radsqr = radius * radius;
00578     OrientedBox b;
00579     ErrorCode rval;
00580     Range sets;
00581     const CartVect center( center_v );
00582     CartVect closest, coords[3];
00583     const EntityHandle* conn;
00584     int num_conn;
00585 #ifndef MB_OBB_USE_VECTOR_QUERIES
00586     Range tris;
00587     Range::const_iterator t;
00588 #else
00589     std::vector< EntityHandle > tris;
00590     std::vector< EntityHandle >::const_iterator t;
00591 #endif
00592 
00593     std::vector< OBBTreeSITFrame > stack;
00594     std::vector< EntityHandle > children;
00595     stack.reserve( 30 );
00596     stack.push_back( OBBTreeSITFrame( tree_root, 0, 0 ) );
00597 
00598     int max_depth = -1;
00599 
00600     while( !stack.empty() )
00601     {
00602         EntityHandle surf = stack.back().surf;
00603         EntityHandle node = stack.back().node;
00604         int current_depth = stack.back().depth;
00605         stack.pop_back();
00606 
00607         // increment traversal statistics.
00608         if( accum )
00609         {
00610             accum->increment( current_depth );
00611             max_depth = std::max( max_depth, current_depth );
00612         }
00613 
00614         if( !surf && sets_out )
00615         {
00616             rval = get_moab_instance()->get_entities_by_type( node, MBENTITYSET, sets );
00617             if( !sets.empty() ) surf = sets.front();
00618             sets.clear();
00619         }
00620 
00621         // check if sphere intersects box
00622         rval = box( node, b );
00623         if( MB_SUCCESS != rval ) return rval;
00624         b.closest_location_in_box( center, closest );
00625         closest -= center;
00626         if( ( closest % closest ) > radsqr ) continue;
00627 
00628         // push child boxes on stack
00629         children.clear();
00630         rval = instance->get_child_meshsets( node, children );
00631         if( MB_SUCCESS != rval ) return rval;
00632         if( !children.empty() )
00633         {
00634             assert( children.size() == 2 );
00635             stack.push_back( OBBTreeSITFrame( children[0], surf, current_depth + 1 ) );
00636             stack.push_back( OBBTreeSITFrame( children[1], surf, current_depth + 1 ) );
00637             continue;
00638         }
00639 
00640         if( accum )
00641         {
00642             accum->increment_leaf( current_depth );
00643         }
00644         // if leaf, intersect sphere with triangles
00645 #ifndef MB_OBB_USE_VECTOR_QUERIES
00646 #ifdef MB_OBB_USE_TYPE_QUERIES
00647         rval = get_moab_instance()->get_entities_by_type( node, MBTRI, tris );
00648 #else
00649         rval = get_moab_instance()->get_entities_by_handle( node, tris );
00650 #endif
00651         t = tris.begin();
00652 #else
00653         rval = get_moab_instance()->get_entities_by_handle( node, tris );
00654         t    = tris.lower_bound( MBTRI );
00655 #endif
00656         if( MB_SUCCESS != rval ) return rval;
00657 
00658         for( t = tris.begin(); t != tris.end(); ++t )
00659         {
00660 #ifndef MB_OBB_USE_VECTOR_QUERIES
00661             if( TYPE_FROM_HANDLE( *t ) != MBTRI ) break;
00662 #elif !defined( MB_OBB_USE_TYPE_QUERIES )
00663             if( TYPE_FROM_HANDLE( *t ) != MBTRI ) continue;
00664 #endif
00665             rval = get_moab_instance()->get_connectivity( *t, conn, num_conn, true );
00666             if( MB_SUCCESS != rval ) return rval;
00667             if( num_conn != 3 ) continue;
00668 
00669             rval = get_moab_instance()->get_coords( conn, num_conn, coords[0].array() );
00670             if( MB_SUCCESS != rval ) return rval;
00671 
00672             GeomUtil::closest_location_on_tri( center, coords, closest );
00673             closest -= center;
00674             if( ( closest % closest ) <= radsqr &&
00675                 std::find( facets_out.begin(), facets_out.end(), *t ) == facets_out.end() )
00676             {
00677                 facets_out.push_back( *t );
00678                 if( sets_out ) sets_out->push_back( surf );
00679             }
00680         }
00681     }
00682 
00683     if( accum )
00684     {
00685         accum->end_traversal( max_depth );
00686     }
00687 
00688     return MB_SUCCESS;
00689 }
00690 
00691 /********************** General Ray/Tree and Ray/Triangle Intersection ***************/
00692 
00693 class RayIntersector : public OrientedBoxTreeTool::Op
00694 {
00695   private:
00696     OrientedBoxTreeTool* tool;
00697     const CartVect b, m;
00698     const double* len;
00699     const double tol;
00700     Range& boxes;
00701 
00702   public:
00703     RayIntersector( OrientedBoxTreeTool* tool_ptr,
00704                     const double* ray_point,
00705                     const double* unit_ray_dir,
00706                     const double* ray_length,
00707                     double tolerance,
00708                     Range& leaf_boxes )
00709         : tool( tool_ptr ), b( ray_point ), m( unit_ray_dir ), len( ray_length ), tol( tolerance ), boxes( leaf_boxes )
00710     {
00711     }
00712 
00713     virtual ErrorCode visit( EntityHandle node, int depth, bool& descend );
00714     virtual ErrorCode leaf( EntityHandle node );
00715 };
00716 
00717 //#include <stdio.h>
00718 // inline void dump_fragmentation( const Range& range ) {
00719 //  static FILE* file = fopen( "fragmentation", "w" );
00720 //  unsigned ranges = 0, entities = 0;
00721 //  for (Range::const_pair_iterator i = range.const_pair_begin(); i != range.const_pair_end(); ++i)
00722 //  {
00723 //    ++ranges;
00724 //    entities += i->second - i->first + 1;
00725 //  }
00726 //  fprintf( file, "%u %u\n", ranges, entities );
00727 //}
00728 
00729 ErrorCode OrientedBoxTreeTool::ray_intersect_triangles( std::vector< double >& intersection_distances_out,
00730                                                         std::vector< EntityHandle >& intersection_facets_out,
00731                                                         const Range& boxes,
00732                                                         double /*tolerance*/,
00733                                                         const double ray_point[3],
00734                                                         const double unit_ray_dir[3],
00735                                                         const double* ray_length,
00736                                                         unsigned int* raytri_test_count )
00737 {
00738     ErrorCode rval;
00739     intersection_distances_out.clear();
00740 #ifdef MB_OBB_USE_VECTOR_QUERIES
00741     std::vector< EntityHandle > tris;
00742 #endif
00743 
00744     const CartVect point( ray_point );
00745     const CartVect dir( unit_ray_dir );
00746 
00747     for( Range::iterator b = boxes.begin(); b != boxes.end(); ++b )
00748     {
00749 #ifndef MB_OBB_USE_VECTOR_QUERIES
00750         Range tris;
00751 #ifdef MB_OBB_USE_TYPE_QUERIES
00752         rval = instance->get_entities_by_type( *b, MBTRI, tris );
00753 #else
00754         rval = instance->get_entities_by_handle( *b, tris );
00755 #endif
00756 #else
00757         tris.clear();
00758         rval = instance->get_entities_by_handle( *b, tris );
00759 #endif
00760         if( MB_SUCCESS != rval ) return rval;
00761             // dump_fragmentation( tris );
00762 
00763 #ifndef MB_OBB_USE_VECTOR_QUERIES
00764         for( Range::iterator t = tris.begin(); t != tris.end(); ++t )
00765 #else
00766         for( std::vector< EntityHandle >::iterator t = tris.begin(); t != tris.end(); ++t )
00767 #endif
00768         {
00769 #ifndef MB_OBB_USE_TYPE_QUERIES
00770             if( TYPE_FROM_HANDLE( *t ) != MBTRI ) continue;
00771 #endif
00772 
00773             const EntityHandle* conn = NULL;
00774             int len                  = 0;
00775             rval                     = instance->get_connectivity( *t, conn, len, true );
00776             if( MB_SUCCESS != rval ) return rval;
00777 
00778             CartVect coords[3];
00779             rval = instance->get_coords( conn, 3, coords[0].array() );
00780             if( MB_SUCCESS != rval ) return rval;
00781 
00782             if( raytri_test_count ) *raytri_test_count += 1;
00783 
00784             double td;
00785             if( GeomUtil::plucker_ray_tri_intersect( coords, point, dir, td, ray_length ) )
00786             {
00787                 intersection_distances_out.push_back( td );
00788                 intersection_facets_out.push_back( *t );
00789             }
00790         }
00791     }
00792 
00793     return MB_SUCCESS;
00794 }
00795 
00796 ErrorCode OrientedBoxTreeTool::ray_intersect_triangles( std::vector< double >& intersection_distances_out,
00797                                                         std::vector< EntityHandle >& intersection_facets_out,
00798                                                         EntityHandle root_set,
00799                                                         double tolerance,
00800                                                         const double ray_point[3],
00801                                                         const double unit_ray_dir[3],
00802                                                         const double* ray_length,
00803                                                         TrvStats* accum )
00804 {
00805     Range boxes;
00806     ErrorCode rval;
00807 
00808     rval = ray_intersect_boxes( boxes, root_set, tolerance, ray_point, unit_ray_dir, ray_length, accum );
00809     if( MB_SUCCESS != rval ) return rval;
00810 
00811     return ray_intersect_triangles( intersection_distances_out, intersection_facets_out, boxes, tolerance, ray_point,
00812                                     unit_ray_dir, ray_length, accum ? &( accum->ray_tri_tests_count ) : NULL );
00813 }
00814 
00815 ErrorCode OrientedBoxTreeTool::ray_intersect_boxes( Range& boxes_out,
00816                                                     EntityHandle root_set,
00817                                                     double tolerance,
00818                                                     const double ray_point[3],
00819                                                     const double unit_ray_dir[3],
00820                                                     const double* ray_length,
00821                                                     TrvStats* accum )
00822 {
00823     RayIntersector op( this, ray_point, unit_ray_dir, ray_length, tolerance, boxes_out );
00824     return preorder_traverse( root_set, op, accum );
00825 }
00826 
00827 ErrorCode RayIntersector::visit( EntityHandle node, int, bool& descend )
00828 {
00829     OrientedBox box;
00830     ErrorCode rval = tool->box( node, box );
00831     if( MB_SUCCESS != rval ) return rval;
00832 
00833     descend = box.intersect_ray( b, m, tol, len );
00834     return MB_SUCCESS;
00835 }
00836 
00837 ErrorCode RayIntersector::leaf( EntityHandle node )
00838 {
00839     boxes.insert( node );
00840     return MB_SUCCESS;
00841 }
00842 
00843 /********************** Ray/Set Intersection ****************************/
00844 
00845 ErrorCode OrientedBoxTreeTool::get_close_tris( CartVect int_pt,
00846                                                double tol,
00847                                                const EntityHandle* rootSet,
00848                                                const EntityHandle* geomVol,
00849                                                const Tag* senseTag,
00850                                                std::vector< EntityHandle >& close_tris,
00851                                                std::vector< int >& close_senses )
00852 {
00853     std::vector< EntityHandle > close_surfs;
00854     ErrorCode rval = sphere_intersect_triangles( int_pt.array(), tol, *rootSet, close_tris, &close_surfs );
00855     assert( MB_SUCCESS == rval );
00856     if( MB_SUCCESS != rval ) return rval;
00857 
00858     // for each surface, get the surf sense wrt parent volume
00859     close_senses.resize( close_surfs.size() );
00860     for( unsigned i = 0; i < close_surfs.size(); ++i )
00861     {
00862         EntityHandle vols[2];
00863         rval = get_moab_instance()->tag_get_data( *senseTag, &( close_surfs[i] ), 1, vols );
00864         assert( MB_SUCCESS == rval );
00865         if( MB_SUCCESS != rval ) return rval;
00866         if( vols[0] == vols[1] )
00867         {
00868             std::cerr << "error: surf has positive and negative sense wrt same volume" << std::endl;
00869             return MB_FAILURE;
00870         }
00871         if( *geomVol == vols[0] )
00872         {
00873             close_senses[i] = 1;
00874         }
00875         else if( *geomVol == vols[1] )
00876         {
00877             close_senses[i] = -1;
00878         }
00879         else
00880         {
00881             return MB_FAILURE;
00882         }
00883     }
00884 
00885     return MB_SUCCESS;
00886 }
00887 
00888 class RayIntersectSets : public OrientedBoxTreeTool::Op
00889 {
00890   private:
00891     // Input
00892     OrientedBoxTreeTool* tool;
00893     const CartVect ray_origin;
00894     const CartVect ray_direction;
00895     OrientedBoxTreeTool::IntersectSearchWindow& search_win; /* length to search ahead/behind of ray origin */
00896     const double tol;                                       /* used for box.intersect_ray, radius of
00897                                                                neighborhood for adjacent triangles,
00898                                                                and old mode of add_intersection */
00899     OrientedBoxTreeTool::IntRegCtxt& int_reg_callback;
00900 
00901     // Optional Input - to screen RTIs by orientation and edge/node intersection
00902     int* surfTriOrient; /* holds desired orientation of tri wrt surface */
00903     int surfTriOrient_val;
00904 
00905     // Other Variables
00906     unsigned int* raytri_test_count;
00907     EntityHandle lastSet;
00908     int lastSetDepth;
00909 
00910   public:
00911     RayIntersectSets( OrientedBoxTreeTool* tool_ptr,
00912                       const double* ray_point,
00913                       const double* unit_ray_dir,
00914                       const double tolerance,
00915                       OrientedBoxTreeTool::IntersectSearchWindow& win,
00916                       unsigned int* ray_tri_test_count,
00917                       OrientedBoxTreeTool::IntRegCtxt& intRegCallback )
00918         : tool( tool_ptr ), ray_origin( ray_point ), ray_direction( unit_ray_dir ), search_win( win ), tol( tolerance ),
00919           int_reg_callback( intRegCallback ), surfTriOrient_val( 0 ), raytri_test_count( ray_tri_test_count ),
00920           lastSet( 0 ), lastSetDepth( 0 )
00921     {
00922 
00923         // specified orientation should be 1 or -1, indicating ray and surface
00924         // normal in the same or opposite directions, respectively.
00925         if( int_reg_callback.getDesiredOrient() )
00926         {
00927             surfTriOrient = &surfTriOrient_val;
00928         }
00929         else
00930         {
00931             surfTriOrient = NULL;
00932         }
00933 
00934         // check the limits
00935         if( search_win.first )
00936         {
00937             assert( 0 <= *( search_win.first ) );
00938         }
00939         if( search_win.second )
00940         {
00941             assert( 0 >= *( search_win.second ) );
00942         }
00943     };
00944 
00945     virtual ErrorCode visit( EntityHandle node, int depth, bool& descend );
00946     virtual ErrorCode leaf( EntityHandle node );
00947 };
00948 
00949 ErrorCode RayIntersectSets::visit( EntityHandle node, int depth, bool& descend )
00950 {
00951     OrientedBox box;
00952     ErrorCode rval = tool->box( node, box );
00953     assert( MB_SUCCESS == rval );
00954     if( MB_SUCCESS != rval ) return rval;
00955 
00956     descend = box.intersect_ray( ray_origin, ray_direction, tol, search_win.first, search_win.second );
00957 
00958     if( lastSet && depth <= lastSetDepth ) lastSet = 0;
00959 
00960     if( descend && !lastSet )
00961     {
00962         Range tmp_sets;
00963         rval = tool->get_moab_instance()->get_entities_by_type( node, MBENTITYSET, tmp_sets );
00964         assert( MB_SUCCESS == rval );
00965         if( MB_SUCCESS != rval ) return rval;
00966 
00967         if( !tmp_sets.empty() )
00968         {
00969             if( tmp_sets.size() > 1 ) return MB_FAILURE;
00970             lastSet      = *tmp_sets.begin();
00971             lastSetDepth = depth;
00972 
00973             rval = int_reg_callback.update_orient( lastSet, surfTriOrient );
00974             if( MB_SUCCESS != rval ) return rval;
00975         }
00976     }
00977 
00978     return MB_SUCCESS;
00979 }
00980 
00981 ErrorCode RayIntersectSets::leaf( EntityHandle node )
00982 {
00983     assert( lastSet );
00984     if( !lastSet )  // if no surface has been visited yet, something's messed up.
00985         return MB_FAILURE;
00986 
00987 #ifndef MB_OBB_USE_VECTOR_QUERIES
00988     Range tris;
00989 #ifdef MB_OBB_USE_TYPE_QUERIES
00990     ErrorCode rval = tool->get_moab_instance()->get_entities_by_type( node, MBTRI, tris );
00991 #else
00992     ErrorCode rval = tool->get_moab_instance()->get_entities_by_handle( node, tris );
00993 #endif
00994 #else
00995     std::vector< EntityHandle > tris;
00996     ErrorCode rval = tool->get_moab_instance()->get_entities_by_handle( node, tris );
00997 #endif
00998     assert( MB_SUCCESS == rval );
00999     if( MB_SUCCESS != rval ) return rval;
01000 
01001 #ifndef MB_OBB_USE_VECTOR_QUERIES
01002     for( Range::iterator t = tris.begin(); t != tris.end(); ++t )
01003 #else
01004     for( std::vector< EntityHandle >::iterator t = tris.begin(); t != tris.end(); ++t )
01005 #endif
01006     {
01007 #ifndef MB_OBB_USE_TYPE_QUERIES
01008         if( TYPE_FROM_HANDLE( *t ) != MBTRI ) continue;
01009 #endif
01010 
01011         const EntityHandle* conn;
01012         int num_conn;
01013         rval = tool->get_moab_instance()->get_connectivity( *t, conn, num_conn, true );
01014         assert( MB_SUCCESS == rval );
01015         if( MB_SUCCESS != rval ) return rval;
01016 
01017         CartVect coords[3];
01018         rval = tool->get_moab_instance()->get_coords( conn, 3, coords[0].array() );
01019         assert( MB_SUCCESS == rval );
01020         if( MB_SUCCESS != rval ) return rval;
01021 
01022         if( raytri_test_count ) *raytri_test_count += 1;
01023 
01024         double int_dist;
01025         GeomUtil::intersection_type int_type = GeomUtil::NONE;
01026 
01027         if( GeomUtil::plucker_ray_tri_intersect( coords, ray_origin, ray_direction, int_dist, search_win.first,
01028                                                  search_win.second, surfTriOrient, &int_type ) )
01029         {
01030             int_reg_callback.register_intersection( lastSet, *t, int_dist, search_win, int_type );
01031         }
01032     }
01033     return MB_SUCCESS;
01034 }
01035 
01036 ErrorCode OrientedBoxTreeTool::ray_intersect_sets( std::vector< double >& distances_out,
01037                                                    std::vector< EntityHandle >& sets_out,
01038                                                    std::vector< EntityHandle >& facets_out,
01039                                                    EntityHandle root_set,
01040                                                    const double tolerance,
01041                                                    const double ray_point[3],
01042                                                    const double unit_ray_dir[3],
01043                                                    IntersectSearchWindow& search_win,
01044                                                    IntRegCtxt& int_reg_callback,
01045                                                    TrvStats* accum )
01046 
01047 {
01048     RayIntersectSets op( this, ray_point, unit_ray_dir, tolerance, search_win,
01049                          accum ? &( accum->ray_tri_tests_count ) : NULL, int_reg_callback );
01050     ErrorCode rval = preorder_traverse( root_set, op, accum );
01051 
01052     distances_out = int_reg_callback.get_intersections();
01053     sets_out      = int_reg_callback.get_sets();
01054     facets_out    = int_reg_callback.get_facets();
01055 
01056     return rval;
01057 }
01058 
01059 ErrorCode OrientedBoxTreeTool::ray_intersect_sets( std::vector< double >& distances_out,
01060                                                    std::vector< EntityHandle >& sets_out,
01061                                                    std::vector< EntityHandle >& facets_out,
01062                                                    EntityHandle root_set,
01063                                                    double tolerance,
01064                                                    const double ray_point[3],
01065                                                    const double unit_ray_dir[3],
01066                                                    const double* ray_length,
01067                                                    TrvStats* accum )
01068 {
01069     IntRegCtxt int_reg_ctxt;
01070 
01071     OrientedBoxTreeTool::IntersectSearchWindow search_win( ray_length, (double*)0 );
01072 
01073     RayIntersectSets op( this, ray_point, unit_ray_dir, tolerance, search_win,
01074                          accum ? &( accum->ray_tri_tests_count ) : NULL, int_reg_ctxt );
01075 
01076     ErrorCode rval = preorder_traverse( root_set, op, accum );
01077 
01078     if( MB_SUCCESS != rval )
01079     {
01080         return rval;
01081     }
01082 
01083     distances_out = int_reg_ctxt.get_intersections();
01084     sets_out      = int_reg_ctxt.get_sets();
01085     facets_out    = int_reg_ctxt.get_facets();
01086 
01087     return MB_SUCCESS;
01088 }
01089 
01090 ErrorCode OrientedBoxTreeTool::ray_intersect_sets( EntityHandle root_set,
01091                                                    const double tolerance,
01092                                                    const double ray_point[3],
01093                                                    const double unit_ray_dir[3],
01094                                                    IntersectSearchWindow& search_win,
01095                                                    IntRegCtxt& int_reg_callback,
01096                                                    TrvStats* accum )
01097 
01098 {
01099     RayIntersectSets op( this, ray_point, unit_ray_dir, tolerance, search_win,
01100                          accum ? &( accum->ray_tri_tests_count ) : NULL, int_reg_callback );
01101     return preorder_traverse( root_set, op, accum );
01102 }
01103 
01104 /********************** Closest Point code ***************/
01105 
01106 struct OBBTreeCPFrame
01107 {
01108     OBBTreeCPFrame( double d, EntityHandle n, EntityHandle s, int dp )
01109         : dist_sqr( d ), node( n ), mset( s ), depth( dp )
01110     {
01111     }
01112     double dist_sqr;
01113     EntityHandle node;
01114     EntityHandle mset;
01115     int depth;
01116 };
01117 
01118 ErrorCode OrientedBoxTreeTool::closest_to_location( const double* point,
01119                                                     EntityHandle root,
01120                                                     double* point_out,
01121                                                     EntityHandle& facet_out,
01122                                                     EntityHandle* set_out,
01123                                                     TrvStats* accum )
01124 {
01125     ErrorCode rval;
01126     const CartVect loc( point );
01127     double smallest_dist_sqr = std::numeric_limits< double >::max();
01128 
01129     EntityHandle current_set = 0;
01130     Range sets;
01131     std::vector< EntityHandle > children( 2 );
01132     std::vector< double > coords;
01133     std::vector< OBBTreeCPFrame > stack;
01134     int max_depth = -1;
01135 
01136     stack.push_back( OBBTreeCPFrame( 0.0, root, current_set, 0 ) );
01137 
01138     while( !stack.empty() )
01139     {
01140 
01141         // pop from top of stack
01142         EntityHandle node = stack.back().node;
01143         double dist_sqr   = stack.back().dist_sqr;
01144         current_set       = stack.back().mset;
01145         int current_depth = stack.back().depth;
01146         stack.pop_back();
01147 
01148         // If current best result is closer than the box, skip this tree node.
01149         if( dist_sqr > smallest_dist_sqr ) continue;
01150 
01151         // increment traversal statistics.
01152         if( accum )
01153         {
01154             accum->increment( current_depth );
01155             max_depth = std::max( max_depth, current_depth );
01156         }
01157 
01158         // Check if this node has a set associated with it
01159         if( set_out && !current_set )
01160         {
01161             sets.clear();
01162             rval = instance->get_entities_by_type( node, MBENTITYSET, sets );
01163             if( MB_SUCCESS != rval ) return rval;
01164             if( !sets.empty() )
01165             {
01166                 if( sets.size() != 1 ) return MB_MULTIPLE_ENTITIES_FOUND;
01167                 current_set = sets.front();
01168             }
01169         }
01170 
01171         // Get child boxes
01172         children.clear();
01173         rval = instance->get_child_meshsets( node, children );
01174         if( MB_SUCCESS != rval ) return rval;
01175 
01176         // if not a leaf node
01177         if( !children.empty() )
01178         {
01179             if( children.size() != 2 ) return MB_MULTIPLE_ENTITIES_FOUND;
01180 
01181             // get boxes
01182             OrientedBox box1, box2;
01183             rval = box( children[0], box1 );
01184             if( MB_SUCCESS != rval ) return rval;
01185             rval = box( children[1], box2 );
01186             if( MB_SUCCESS != rval ) return rval;
01187 
01188             // get distance from each box
01189             CartVect pt1, pt2;
01190             box1.closest_location_in_box( loc, pt1 );
01191             box2.closest_location_in_box( loc, pt2 );
01192             pt1 -= loc;
01193             pt2 -= loc;
01194             const double dsqr1 = pt1 % pt1;
01195             const double dsqr2 = pt2 % pt2;
01196 
01197             // push children on tree such that closer one is on top
01198             if( dsqr1 < dsqr2 )
01199             {
01200                 stack.push_back( OBBTreeCPFrame( dsqr2, children[1], current_set, current_depth + 1 ) );
01201                 stack.push_back( OBBTreeCPFrame( dsqr1, children[0], current_set, current_depth + 1 ) );
01202             }
01203             else
01204             {
01205                 stack.push_back( OBBTreeCPFrame( dsqr1, children[0], current_set, current_depth + 1 ) );
01206                 stack.push_back( OBBTreeCPFrame( dsqr2, children[1], current_set, current_depth + 1 ) );
01207             }
01208         }
01209         else
01210         {  // LEAF NODE
01211             if( accum )
01212             {
01213                 accum->increment_leaf( current_depth );
01214             }
01215 
01216             Range facets;
01217             rval = instance->get_entities_by_dimension( node, 2, facets );
01218             if( MB_SUCCESS != rval ) return rval;
01219 
01220             const EntityHandle* conn = NULL;
01221             int len                  = 0;
01222             CartVect tmp, diff;
01223             for( Range::iterator i = facets.begin(); i != facets.end(); ++i )
01224             {
01225                 rval = instance->get_connectivity( *i, conn, len, true );
01226                 if( MB_SUCCESS != rval ) return rval;
01227 
01228                 coords.resize( 3 * len );
01229                 rval = instance->get_coords( conn, len, &coords[0] );
01230                 if( MB_SUCCESS != rval ) return rval;
01231 
01232                 if( len == 3 )
01233                     GeomUtil::closest_location_on_tri( loc, (CartVect*)( &coords[0] ), tmp );
01234                 else
01235                     GeomUtil::closest_location_on_polygon( loc, (CartVect*)( &coords[0] ), len, tmp );
01236 
01237                 diff     = tmp - loc;
01238                 dist_sqr = diff % diff;
01239                 if( dist_sqr < smallest_dist_sqr )
01240                 {
01241                     smallest_dist_sqr = dist_sqr;
01242                     facet_out         = *i;
01243                     tmp.get( point_out );
01244                     if( set_out ) *set_out = current_set;
01245                 }
01246             }
01247         }  // LEAF NODE
01248     }
01249 
01250     if( accum )
01251     {
01252         accum->end_traversal( max_depth );
01253     }
01254 
01255     return MB_SUCCESS;
01256 }
01257 
01258 ErrorCode OrientedBoxTreeTool::closest_to_location( const double* point,
01259                                                     EntityHandle root,
01260                                                     double tolerance,
01261                                                     std::vector< EntityHandle >& facets_out,
01262                                                     std::vector< EntityHandle >* sets_out,
01263                                                     TrvStats* accum )
01264 {
01265     ErrorCode rval;
01266     const CartVect loc( point );
01267     double smallest_dist_sqr = std::numeric_limits< double >::max();
01268     double smallest_dist     = smallest_dist_sqr;
01269 
01270     EntityHandle current_set = 0;
01271     Range sets;
01272     std::vector< EntityHandle > children( 2 );
01273     std::vector< double > coords;
01274     std::vector< OBBTreeCPFrame > stack;
01275     int max_depth = -1;
01276 
01277     stack.push_back( OBBTreeCPFrame( 0.0, root, current_set, 0 ) );
01278 
01279     while( !stack.empty() )
01280     {
01281 
01282         // pop from top of stack
01283         EntityHandle node = stack.back().node;
01284         double dist_sqr   = stack.back().dist_sqr;
01285         current_set       = stack.back().mset;
01286         int current_depth = stack.back().depth;
01287         stack.pop_back();
01288 
01289         // If current best result is closer than the box, skip this tree node.
01290         if( dist_sqr > smallest_dist_sqr + tolerance ) continue;
01291 
01292         // increment traversal statistics.
01293         if( accum )
01294         {
01295             accum->increment( current_depth );
01296             max_depth = std::max( max_depth, current_depth );
01297         }
01298 
01299         // Check if this node has a set associated with it
01300         if( sets_out && !current_set )
01301         {
01302             sets.clear();
01303             rval = instance->get_entities_by_type( node, MBENTITYSET, sets );
01304             if( MB_SUCCESS != rval ) return rval;
01305             if( !sets.empty() )
01306             {
01307                 if( sets.size() != 1 ) return MB_MULTIPLE_ENTITIES_FOUND;
01308                 current_set = *sets.begin();
01309             }
01310         }
01311 
01312         // Get child boxes
01313         children.clear();
01314         rval = instance->get_child_meshsets( node, children );
01315         if( MB_SUCCESS != rval ) return rval;
01316 
01317         // if not a leaf node
01318         if( !children.empty() )
01319         {
01320             if( children.size() != 2 ) return MB_MULTIPLE_ENTITIES_FOUND;
01321 
01322             // get boxes
01323             OrientedBox box1, box2;
01324             rval = box( children[0], box1 );
01325             if( MB_SUCCESS != rval ) return rval;
01326             rval = box( children[1], box2 );
01327             if( MB_SUCCESS != rval ) return rval;
01328 
01329             // get distance from each box
01330             CartVect pt1, pt2;
01331             box1.closest_location_in_box( loc, pt1 );
01332             box2.closest_location_in_box( loc, pt2 );
01333             pt1 -= loc;
01334             pt2 -= loc;
01335             const double dsqr1 = pt1 % pt1;
01336             const double dsqr2 = pt2 % pt2;
01337 
01338             // push children on tree such that closer one is on top
01339             if( dsqr1 < dsqr2 )
01340             {
01341                 stack.push_back( OBBTreeCPFrame( dsqr2, children[1], current_set, current_depth + 1 ) );
01342                 stack.push_back( OBBTreeCPFrame( dsqr1, children[0], current_set, current_depth + 1 ) );
01343             }
01344             else
01345             {
01346                 stack.push_back( OBBTreeCPFrame( dsqr1, children[0], current_set, current_depth + 1 ) );
01347                 stack.push_back( OBBTreeCPFrame( dsqr2, children[1], current_set, current_depth + 1 ) );
01348             }
01349         }
01350         else
01351         {  // LEAF NODE
01352             if( accum )
01353             {
01354                 accum->increment_leaf( current_depth );
01355             }
01356 
01357             Range facets;
01358             rval = instance->get_entities_by_dimension( node, 2, facets );
01359             if( MB_SUCCESS != rval ) return rval;
01360 
01361             const EntityHandle* conn = NULL;
01362             int len                  = 0;
01363             CartVect tmp, diff;
01364             for( Range::iterator i = facets.begin(); i != facets.end(); ++i )
01365             {
01366                 rval = instance->get_connectivity( *i, conn, len, true );
01367                 if( MB_SUCCESS != rval ) return rval;
01368 
01369                 coords.resize( 3 * len );
01370                 rval = instance->get_coords( conn, len, &coords[0] );
01371                 if( MB_SUCCESS != rval ) return rval;
01372 
01373                 if( len == 3 )
01374                     GeomUtil::closest_location_on_tri( loc, (CartVect*)( &coords[0] ), tmp );
01375                 else
01376                     GeomUtil::closest_location_on_polygon( loc, (CartVect*)( &coords[0] ), len, tmp );
01377 
01378                 diff     = tmp - loc;
01379                 dist_sqr = diff % diff;
01380                 if( dist_sqr < smallest_dist_sqr )
01381                 {
01382                     if( 0.5 * dist_sqr < 0.5 * smallest_dist_sqr + tolerance * ( 0.5 * tolerance - smallest_dist ) )
01383                     {
01384                         facets_out.clear();
01385                         if( sets_out ) sets_out->clear();
01386                     }
01387                     smallest_dist_sqr = dist_sqr;
01388                     smallest_dist     = sqrt( smallest_dist_sqr );
01389                     // put closest result at start of lists
01390                     facets_out.push_back( *i );
01391                     std::swap( facets_out.front(), facets_out.back() );
01392                     if( sets_out )
01393                     {
01394                         sets_out->push_back( current_set );
01395                         std::swap( sets_out->front(), sets_out->back() );
01396                     }
01397                 }
01398                 else if( dist_sqr <= smallest_dist_sqr + tolerance * ( tolerance + 2 * smallest_dist ) )
01399                 {
01400                     facets_out.push_back( *i );
01401                     if( sets_out ) sets_out->push_back( current_set );
01402                 }
01403             }
01404         }  // LEAF NODE
01405     }
01406 
01407     if( accum )
01408     {
01409         accum->end_traversal( max_depth );
01410     }
01411 
01412     return MB_SUCCESS;
01413 }
01414 
01415 /********************** Tree Printing Code ****************************/
01416 
01417 class TreeLayoutPrinter : public OrientedBoxTreeTool::Op
01418 {
01419   public:
01420     TreeLayoutPrinter( std::ostream& stream, Interface* instance );
01421 
01422     virtual ErrorCode visit( EntityHandle node, int depth, bool& descend );
01423     virtual ErrorCode leaf( EntityHandle node );
01424 
01425   private:
01426     Interface* instance;
01427     std::ostream& outputStream;
01428     std::vector< bool > path;
01429 };
01430 
01431 TreeLayoutPrinter::TreeLayoutPrinter( std::ostream& stream, Interface* interface )
01432     : instance( interface ), outputStream( stream )
01433 {
01434 }
01435 
01436 ErrorCode TreeLayoutPrinter::visit( EntityHandle node, int depth, bool& descend )
01437 {
01438     descend = true;
01439 
01440     if( (unsigned)depth > path.size() )
01441     {
01442         // assert(depth+1 == path.size); // preorder traversal
01443         path.push_back( true );
01444     }
01445     else
01446     {
01447         path.resize( depth );
01448         if( depth ) path.back() = false;
01449     }
01450 
01451     for( unsigned i = 0; i + 1 < path.size(); ++i )
01452     {
01453         if( path[i] )
01454             outputStream << "|   ";
01455         else
01456             outputStream << "    ";
01457     }
01458     if( depth )
01459     {
01460         if( path.back() )
01461             outputStream << "+---";
01462         else
01463             outputStream << "\\---";
01464     }
01465     outputStream << instance->id_from_handle( node ) << std::endl;
01466     return MB_SUCCESS;
01467 }
01468 
01469 ErrorCode TreeLayoutPrinter::leaf( EntityHandle )
01470 {
01471     return MB_SUCCESS;
01472 }
01473 
01474 class TreeNodePrinter : public OrientedBoxTreeTool::Op
01475 {
01476   public:
01477     TreeNodePrinter( std::ostream& stream,
01478                      bool list_contents,
01479                      bool list_box,
01480                      const char* id_tag_name,
01481                      OrientedBoxTreeTool* tool_ptr );
01482 
01483     virtual ErrorCode visit( EntityHandle node, int depth, bool& descend );
01484 
01485     virtual ErrorCode leaf( EntityHandle )
01486     {
01487         return MB_SUCCESS;
01488     }
01489 
01490   private:
01491     ErrorCode print_geometry( EntityHandle node );
01492     ErrorCode print_contents( EntityHandle node );
01493     ErrorCode print_counts( EntityHandle node );
01494 
01495     bool printContents;
01496     bool printGeometry;
01497     bool haveTag;
01498     Tag tag, gidTag, geomTag;
01499     Interface* instance;
01500     OrientedBoxTreeTool* tool;
01501     std::ostream& outputStream;
01502 };
01503 
01504 TreeNodePrinter::TreeNodePrinter( std::ostream& stream,
01505                                   bool list_contents,
01506                                   bool list_box,
01507                                   const char* id_tag_name,
01508                                   OrientedBoxTreeTool* tool_ptr )
01509     : printContents( list_contents ), printGeometry( list_box ), haveTag( false ), tag( 0 ), gidTag( 0 ), geomTag( 0 ),
01510       instance( tool_ptr->get_moab_instance() ), tool( tool_ptr ), outputStream( stream )
01511 {
01512     ErrorCode rval;
01513     if( id_tag_name )
01514     {
01515         rval = instance->tag_get_handle( id_tag_name, 1, MB_TYPE_INTEGER, tag );
01516         if( !rval )
01517         {
01518             std::cerr << "Could not get tag \"" << id_tag_name << "\"\n";
01519             stream << "Could not get tag \"" << id_tag_name << "\"\n";
01520         }
01521         else
01522         {
01523             haveTag = true;
01524         }
01525     }
01526 
01527     gidTag = instance->globalId_tag();
01528 
01529     rval = instance->tag_get_handle( GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, geomTag );
01530     if( MB_SUCCESS != rval ) geomTag = 0;
01531 }
01532 
01533 ErrorCode TreeNodePrinter::visit( EntityHandle node, int, bool& descend )
01534 {
01535     descend            = true;
01536     EntityHandle setid = instance->id_from_handle( node );
01537     outputStream << setid << ":" << std::endl;
01538 
01539     Range surfs;
01540     ErrorCode r3 = MB_SUCCESS;
01541     if( geomTag )
01542     {
01543         const int two         = 2;
01544         const void* tagdata[] = { &two };
01545         r3 = instance->get_entities_by_type_and_tag( node, MBENTITYSET, &geomTag, tagdata, 1, surfs );
01546 
01547         if( MB_SUCCESS == r3 && surfs.size() == 1 )
01548         {
01549             EntityHandle surf = *surfs.begin();
01550             int id;
01551             if( gidTag && MB_SUCCESS == instance->tag_get_data( gidTag, &surf, 1, &id ) )
01552                 outputStream << "  Surface " << id << std::endl;
01553             else
01554                 outputStream << "  Surface w/ unknown ID (" << surf << ")" << std::endl;
01555         }
01556     }
01557 
01558     ErrorCode r1 = printGeometry ? print_geometry( node ) : MB_SUCCESS;
01559     ErrorCode r2 = printContents ? print_contents( node ) : print_counts( node );
01560     outputStream << std::endl;
01561 
01562     if( MB_SUCCESS != r1 )
01563         return r1;
01564     else if( MB_SUCCESS != r2 )
01565         return r2;
01566     else
01567         return r3;
01568 }
01569 
01570 ErrorCode TreeNodePrinter::print_geometry( EntityHandle node )
01571 {
01572     OrientedBox box;
01573     ErrorCode rval = tool->box( node, box );
01574     if( MB_SUCCESS != rval ) return rval;
01575 
01576     CartVect length = box.dimensions();
01577 
01578     outputStream << box.center << "  Radius: " << box.inner_radius() << " - " << box.outer_radius() << std::endl
01579                  << '+' << box.axis( 0 ) << " : " << length[0] << std::endl
01580                  << 'x' << box.axis( 1 ) << " : " << length[1] << std::endl
01581                  << 'x' << box.axis( 2 ) << " : " << length[2] << std::endl;
01582     return MB_SUCCESS;
01583 }
01584 
01585 ErrorCode TreeNodePrinter::print_counts( EntityHandle node )
01586 {
01587     for( EntityType type = MBVERTEX; type != MBMAXTYPE; ++type )
01588     {
01589         int count      = 0;
01590         ErrorCode rval = instance->get_number_entities_by_type( node, type, count );
01591         if( MB_SUCCESS != rval ) return rval;
01592         if( count > 0 ) outputStream << " " << count << " " << CN::EntityTypeName( type ) << std::endl;
01593     }
01594     return MB_SUCCESS;
01595 }
01596 
01597 ErrorCode TreeNodePrinter::print_contents( EntityHandle node )
01598 {
01599     // list contents
01600     for( EntityType type = MBVERTEX; type != MBMAXTYPE; ++type )
01601     {
01602         Range range;
01603         ErrorCode rval = instance->get_entities_by_type( node, type, range );
01604         if( MB_SUCCESS != rval ) return rval;
01605         if( range.empty() ) continue;
01606         outputStream << " " << CN::EntityTypeName( type ) << " ";
01607         std::vector< int > ids( range.size() );
01608         if( haveTag )
01609         {
01610             rval = instance->tag_get_data( tag, range, &ids[0] );
01611             std::sort( ids.begin(), ids.end() );
01612         }
01613         else
01614         {
01615             Range::iterator ri              = range.begin();
01616             std::vector< int >::iterator vi = ids.begin();
01617             while( ri != range.end() )
01618             {
01619                 *vi = instance->id_from_handle( *ri );
01620                 ++ri;
01621                 ++vi;
01622             }
01623         }
01624 
01625         unsigned i = 0;
01626         for( ;; )
01627         {
01628             unsigned beg = i, end;
01629             do
01630             {
01631                 end = i++;
01632             } while( i < ids.size() && ids[end] + 1 == ids[i] );
01633             if( end == beg )
01634                 outputStream << ids[end];
01635             else if( end == beg + 1 )
01636                 outputStream << ids[beg] << ", " << ids[end];
01637             else
01638                 outputStream << ids[beg] << "-" << ids[end];
01639 
01640             if( i == ids.size() )
01641             {
01642                 outputStream << std::endl;
01643                 break;
01644             }
01645             else
01646                 outputStream << ", ";
01647         }
01648     }
01649 
01650     return MB_SUCCESS;
01651 }
01652 
01653 void OrientedBoxTreeTool::print( EntityHandle set, std::ostream& str, bool list, const char* tag )
01654 {
01655     TreeLayoutPrinter op1( str, instance );
01656     TreeNodePrinter op2( str, list, true, tag, this );
01657     ErrorCode r1 = preorder_traverse( set, op1 );
01658     str << std::endl;
01659     ErrorCode r2 = preorder_traverse( set, op2 );
01660     if( r1 != MB_SUCCESS || r2 != MB_SUCCESS )
01661     {
01662         std::cerr << "Errors encountered while printing tree\n";
01663         str << "Errors encountered while printing tree\n";
01664     }
01665 }
01666 
01667 /********************* Traversal Metrics Code  **************************/
01668 
01669 void OrientedBoxTreeTool::TrvStats::reset()
01670 {
01671     nodes_visited_count.clear();
01672     leaves_visited_count.clear();
01673     traversals_ended_count.clear();
01674     ray_tri_tests_count = 0;
01675 }
01676 
01677 void OrientedBoxTreeTool::TrvStats::increment( unsigned depth )
01678 {
01679 
01680     while( nodes_visited_count.size() <= depth )
01681     {
01682         nodes_visited_count.push_back( 0 );
01683         leaves_visited_count.push_back( 0 );
01684         traversals_ended_count.push_back( 0 );
01685     }
01686     nodes_visited_count[depth] += 1;
01687 }
01688 
01689 void OrientedBoxTreeTool::TrvStats::increment_leaf( unsigned depth )
01690 {
01691     // assume safe depth, because increment is called first
01692     leaves_visited_count[depth] += 1;
01693 }
01694 
01695 void OrientedBoxTreeTool::TrvStats::end_traversal( unsigned depth )
01696 {
01697     // assume safe depth, because increment is always called on a given
01698     // tree level first
01699     traversals_ended_count[depth] += 1;
01700 }
01701 
01702 void OrientedBoxTreeTool::TrvStats::print( std::ostream& str ) const
01703 {
01704 
01705     const std::string h1 = "OBBTree Depth";
01706     const std::string h2 = " - NodesVisited";
01707     const std::string h3 = " - LeavesVisited";
01708     const std::string h4 = " - TraversalsEnded";
01709 
01710     str << h1 << h2 << h3 << h4 << std::endl;
01711 
01712     unsigned num_visited = 0, num_leaves = 0, num_traversals = 0;
01713     for( unsigned i = 0; i < traversals_ended_count.size(); ++i )
01714     {
01715 
01716         num_visited += nodes_visited_count[i];
01717         num_leaves += leaves_visited_count[i];
01718         num_traversals += traversals_ended_count[i];
01719 
01720         str << std::setw( h1.length() ) << i << std::setw( h2.length() ) << nodes_visited_count[i]
01721             << std::setw( h3.length() ) << leaves_visited_count[i] << std::setw( h4.length() )
01722             << traversals_ended_count[i] << std::endl;
01723     }
01724 
01725     str << std::setw( h1.length() ) << "---- Totals:" << std::setw( h2.length() ) << num_visited
01726         << std::setw( h3.length() ) << num_leaves << std::setw( h4.length() ) << num_traversals << std::endl;
01727 
01728     if( ray_tri_tests_count )
01729     {
01730         str << std::setw( h1.length() ) << "---- Total ray-tri tests: " << ray_tri_tests_count << std::endl;
01731     }
01732 }
01733 
01734 /********************** Tree Statistics Code ****************************/
01735 
01736 class StatData
01737 {
01738   public:
01739     struct Ratio
01740     {
01741         double min, max, sum, sqr;
01742         int hist[10];
01743         Ratio()
01744             : min( std::numeric_limits< double >::max() ), max( -std::numeric_limits< double >::max() ), sum( 0.0 ),
01745               sqr( 0.0 )
01746         {
01747             hist[0] = hist[1] = hist[2] = hist[3] = hist[4] = hist[5] = hist[6] = hist[7] = hist[8] = hist[9] = 0;
01748         }
01749         void accum( double v )
01750         {
01751             if( v < min ) min = v;
01752             if( v > max ) max = v;
01753             sum += v;
01754             sqr += v * v;
01755             int i = (int)( 10 * v );
01756             if( i < 0 )
01757                 i = 0;
01758             else if( i > 9 )
01759                 i = 9;
01760             ++hist[i];
01761         }
01762     };
01763 
01764     template < typename T >
01765     struct Stat
01766     {
01767         T min, max;
01768         double sum, sqr;
01769         Stat() : sum( 0.0 ), sqr( 0.0 )
01770         {
01771             std::numeric_limits< T > lim;
01772             min = lim.max();
01773             if( lim.is_integer )
01774                 max = lim.min();
01775             else
01776                 max = -lim.max();
01777         }
01778         void accum( T v )
01779         {
01780             if( v < min ) min = v;
01781             if( v > max ) max = v;
01782             sum += v;
01783             sqr += (double)v * v;
01784         }
01785     };
01786 
01787     StatData() : count( 0 ) {}
01788 
01789     Ratio volume;
01790     Ratio entities;
01791     Ratio radius;
01792     Stat< unsigned > leaf_ent;
01793     Stat< double > vol;
01794     Stat< double > area;
01795     std::vector< unsigned > leaf_depth;
01796     unsigned count;
01797 };
01798 
01799 static int measure( const CartVect& v, double& result )
01800 {
01801     const double tol = 1e-6;
01802     int dims         = 0;
01803     result           = 1;
01804     for( int i = 0; i < 3; ++i )
01805         if( v[i] > tol )
01806         {
01807             ++dims;
01808             result *= v[i];
01809         }
01810     return dims;
01811 }
01812 
01813 ErrorCode OrientedBoxTreeTool::recursive_stats( OrientedBoxTreeTool* tool,
01814                                                 Interface* inst,
01815                                                 EntityHandle set,
01816                                                 int depth,
01817                                                 StatData& data,
01818                                                 unsigned& count_out,
01819                                                 CartVect& dimensions_out )
01820 {
01821     ErrorCode rval;
01822     OrientedBox tmp_box;
01823     std::vector< EntityHandle > children( 2 );
01824     unsigned counts[2];
01825     bool isleaf;
01826 
01827     ++data.count;
01828 
01829     rval = tool->box( set, tmp_box );
01830     if( MB_SUCCESS != rval ) return rval;
01831     children.clear();
01832     rval = inst->get_child_meshsets( set, children );
01833     if( MB_SUCCESS != rval ) return rval;
01834     isleaf = children.empty();
01835     if( !isleaf && children.size() != 2 ) return MB_MULTIPLE_ENTITIES_FOUND;
01836 
01837     dimensions_out = tmp_box.dimensions();
01838     data.radius.accum( tmp_box.inner_radius() / tmp_box.outer_radius() );
01839     data.vol.accum( tmp_box.volume() );
01840     data.area.accum( tmp_box.area() );
01841 
01842     if( isleaf )
01843     {
01844         if( data.leaf_depth.size() <= (unsigned)depth ) data.leaf_depth.resize( depth + 1, 0 );
01845         ++data.leaf_depth[depth];
01846 
01847         int count;
01848         rval = inst->get_number_entities_by_handle( set, count );
01849         if( MB_SUCCESS != rval ) return rval;
01850         count_out = count;
01851         data.leaf_ent.accum( count_out );
01852     }
01853     else
01854     {
01855         for( int i = 0; i < 2; ++i )
01856         {
01857             CartVect dims;
01858             rval = recursive_stats( tool, inst, children[i], depth + 1, data, counts[i], dims );
01859             if( MB_SUCCESS != rval ) return rval;
01860             double this_measure, chld_measure;
01861             int this_dim = measure( dimensions_out, this_measure );
01862             int chld_dim = measure( dims, chld_measure );
01863             double ratio;
01864             if( chld_dim < this_dim )
01865                 ratio = 0;
01866             else
01867                 ratio = chld_measure / this_measure;
01868 
01869             data.volume.accum( ratio );
01870         }
01871         count_out = counts[0] + counts[1];
01872         data.entities.accum( (double)counts[0] / count_out );
01873         data.entities.accum( (double)counts[1] / count_out );
01874     }
01875     return MB_SUCCESS;
01876 }
01877 
01878 static inline double std_dev( double sqr, double sum, double count )
01879 {
01880     sum /= count;
01881     sqr /= count;
01882     return sqrt( sqr - sum * sum );
01883 }
01884 
01885 //#define WW <<std::setw(10)<<std::fixed<<
01886 #define WE << std::setw( 10 ) <<
01887 #define WW WE
01888 ErrorCode OrientedBoxTreeTool::stats( EntityHandle set,
01889                                       unsigned& total_entities,
01890                                       double& rv,
01891                                       double& tot_node_volume,
01892                                       double& tot_to_root_volume,
01893                                       unsigned& tree_height,
01894                                       unsigned& node_count,
01895                                       unsigned& num_leaves )
01896 {
01897     StatData d;
01898     ErrorCode rval;
01899     unsigned i;
01900     CartVect total_dim;
01901 
01902     rval = recursive_stats( this, instance, set, 0, d, total_entities, total_dim );
01903     if( MB_SUCCESS != rval ) return rval;
01904 
01905     tree_height                 = d.leaf_depth.size();
01906     unsigned min_leaf_depth     = tree_height;
01907     num_leaves                  = 0;
01908     unsigned max_leaf_per_depth = 0;
01909     // double sum_leaf_depth = 0, sqr_leaf_depth = 0;
01910     for( i = 0; i < d.leaf_depth.size(); ++i )
01911     {
01912         unsigned val = d.leaf_depth[i];
01913         num_leaves += val;
01914         // sum_leaf_depth += (double)val*i;
01915         // sqr_leaf_depth += (double)val*i*i;
01916         if( val && i < min_leaf_depth ) min_leaf_depth = i;
01917         if( max_leaf_per_depth < val ) max_leaf_per_depth = val;
01918     }
01919     rv                 = total_dim[0] * total_dim[1] * total_dim[2];
01920     tot_node_volume    = d.vol.sum;
01921     tot_to_root_volume = d.vol.sum / rv;
01922     node_count         = d.count;
01923 
01924     return MB_SUCCESS;
01925 }
01926 
01927 ErrorCode OrientedBoxTreeTool::stats( EntityHandle set, std::ostream& s )
01928 {
01929     StatData d;
01930     ErrorCode rval;
01931     unsigned total_entities, i;
01932     CartVect total_dim;
01933 
01934     rval = recursive_stats( this, instance, set, 0, d, total_entities, total_dim );
01935     if( MB_SUCCESS != rval ) return rval;
01936 
01937     unsigned tree_height    = d.leaf_depth.size();
01938     unsigned min_leaf_depth = tree_height, num_leaves = 0;
01939     unsigned max_leaf_per_depth = 0;
01940     double sum_leaf_depth = 0, sqr_leaf_depth = 0;
01941     for( i = 0; i < d.leaf_depth.size(); ++i )
01942     {
01943         unsigned val = d.leaf_depth[i];
01944         num_leaves += val;
01945         sum_leaf_depth += (double)val * i;
01946         sqr_leaf_depth += (double)val * i * i;
01947         if( val && i < min_leaf_depth ) min_leaf_depth = i;
01948         if( max_leaf_per_depth < val ) max_leaf_per_depth = val;
01949     }
01950     unsigned num_non_leaf = d.count - num_leaves;
01951 
01952     double rv = total_dim[0] * total_dim[1] * total_dim[2];
01953     s << "entities in tree:  " << total_entities << std::endl
01954       << "root volume:       " << rv << std::endl
01955       << "total node volume: " << d.vol.sum << std::endl
01956       << "total/root volume: " << d.vol.sum / rv << std::endl
01957       << "tree height:       " << tree_height << std::endl
01958       << "node count:        " << d.count << std::endl
01959       << "leaf count:        " << num_leaves << std::endl
01960       << std::endl;
01961 
01962     double avg_leaf_depth = sum_leaf_depth / num_leaves;
01963     double rms_leaf_depth = sqrt( sqr_leaf_depth / num_leaves );
01964     double std_leaf_depth = std_dev( sqr_leaf_depth, sum_leaf_depth, num_leaves );
01965 
01966     double avg_leaf_ent = d.leaf_ent.sum / num_leaves;
01967     double rms_leaf_ent = sqrt( d.leaf_ent.sqr / num_leaves );
01968     double std_leaf_ent = std_dev( d.leaf_ent.sqr, d.leaf_ent.sum, num_leaves );
01969 
01970     unsigned num_child = 2 * num_non_leaf;
01971 
01972     double avg_vol_ratio = d.volume.sum / num_child;
01973     double rms_vol_ratio = sqrt( d.volume.sqr / num_child );
01974     double std_vol_ratio = std_dev( d.volume.sqr, d.volume.sum, num_child );
01975 
01976     double avg_ent_ratio = d.entities.sum / num_child;
01977     double rms_ent_ratio = sqrt( d.entities.sqr / num_child );
01978     double std_ent_ratio = std_dev( d.entities.sqr, d.entities.sum, num_child );
01979 
01980     double avg_rad_ratio = d.radius.sum / d.count;
01981     double rms_rad_ratio = sqrt( d.radius.sqr / d.count );
01982     double std_rad_ratio = std_dev( d.radius.sqr, d.radius.sum, d.count );
01983 
01984     double avg_vol = d.vol.sum / d.count;
01985     double rms_vol = sqrt( d.vol.sqr / d.count );
01986     double std_vol = std_dev( d.vol.sqr, d.vol.sum, d.count );
01987 
01988     double avg_area = d.area.sum / d.count;
01989     double rms_area = sqrt( d.area.sqr / d.count );
01990     double std_area = std_dev( d.area.sqr, d.area.sum, d.count );
01991 
01992     int prec = s.precision();
01993     s << "                   " WW "Minimum" WW "Average" WW "RMS" WW "Maximum" WW "Std.Dev." << std::endl;
01994     s << std::setprecision( 1 )
01995       << "Leaf Depth         " WW min_leaf_depth WW avg_leaf_depth WW rms_leaf_depth WW d.leaf_depth.size() -
01996              1 WW std_leaf_depth
01997       << std::endl;
01998     s << std::setprecision( 0 )
01999       << "Entities/Leaf      " WW d.leaf_ent.min WW avg_leaf_ent WW rms_leaf_ent WW d.leaf_ent.max WW std_leaf_ent
02000       << std::endl;
02001     s << std::setprecision( 3 )
02002       << "Child Volume Ratio " WW d.volume.min WW avg_vol_ratio WW rms_vol_ratio WW d.volume.max WW std_vol_ratio
02003       << std::endl;
02004     s << std::setprecision( 3 )
02005       << "Child Entity Ratio " WW d.entities.min WW avg_ent_ratio WW rms_ent_ratio WW d.entities.max WW std_ent_ratio
02006       << std::endl;
02007     s << std::setprecision( 3 )
02008       << "Box Radius Ratio   " WW d.radius.min WW avg_rad_ratio WW rms_rad_ratio WW d.radius.max WW std_rad_ratio
02009       << std::endl;
02010     s << std::setprecision( 0 ) << "Box volume         " WE d.vol.min WE avg_vol WE rms_vol WE d.vol.max WE std_vol
02011       << std::endl;
02012     s << std::setprecision( 0 ) << "Largest side area  " WE d.area.min WE avg_area WE rms_area WE d.area.max WE std_area
02013       << std::endl;
02014     s << std::setprecision( prec ) << std::endl;
02015 
02016     s << "Leaf Depth Histogram (Root depth is 0)" << std::endl;
02017     double f = 60.0 / max_leaf_per_depth;
02018     for( i = min_leaf_depth; i < d.leaf_depth.size(); ++i )
02019         s << std::setw( 2 ) << i << " " << std::setw( 5 ) << d.leaf_depth[i] << " |" << std::setfill( '*' )
02020           << std::setw( (int)floor( f * d.leaf_depth[i] + 0.5 ) ) << "" << std::setfill( ' ' ) << std::endl;
02021     s << std::endl;
02022 
02023     s << "Child/Parent Volume Ratio Histogram" << std::endl;
02024     f = 60.0 / *( std::max_element( d.volume.hist, d.volume.hist + 10 ) );
02025     for( i = 0; i < 10u; ++i )
02026         s << "0." << i << " " << std::setw( 5 ) << d.volume.hist[i] << " |" << std::setfill( '*' )
02027           << std::setw( (int)floor( f * d.volume.hist[i] + 0.5 ) ) << "" << std::setfill( ' ' ) << std::endl;
02028     s << std::endl;
02029 
02030     s << "Child/Parent Entity Count Ratio Histogram" << std::endl;
02031     f = 60.0 / *( std::max_element( d.entities.hist, d.entities.hist + 10 ) );
02032     for( i = 0; i < 10u; ++i )
02033         s << "0." << i << " " << std::setw( 5 ) << d.entities.hist[i] << " |" << std::setfill( '*' )
02034           << std::setw( (int)floor( f * d.entities.hist[i] + 0.5 ) ) << "" << std::setfill( ' ' ) << std::endl;
02035     s << std::endl;
02036 
02037     s << "Inner/Outer Radius Ratio Histogram (~0.70 for cube)" << std::endl;
02038     // max radius ratio for a box is about 0.7071.  Move any boxes
02039     // in the .7 bucket into .6 and print .0 to .6.
02040     d.radius.hist[6] += d.radius.hist[7];
02041     f = 60.0 / *( std::max_element( d.entities.hist, d.entities.hist + 7 ) );
02042     for( i = 0; i < 7u; ++i )
02043         s << "0." << i << " " << std::setw( 5 ) << d.entities.hist[i] << " |" << std::setfill( '*' )
02044           << std::setw( (int)floor( f * d.entities.hist[i] + 0.5 ) ) << "" << std::setfill( ' ' ) << std::endl;
02045     s << std::endl;
02046 
02047     return MB_SUCCESS;
02048 }
02049 
02050 }  // namespace moab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines