gim_box_set.cpp

Go to the documentation of this file.
00001 
00002 /*
00003 -----------------------------------------------------------------------------
00004 This source file is part of GIMPACT Library.
00005 
00006 For the latest info, see http://gimpact.sourceforge.net/
00007 
00008 Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
00009 email: projectileman@yahoo.com
00010 
00011  This library is free software; you can redistribute it and/or
00012  modify it under the terms of EITHER:
00013    (1) The GNU Lesser General Public License as published by the Free
00014        Software Foundation; either version 2.1 of the License, or (at
00015        your option) any later version. The text of the GNU Lesser
00016        General Public License is included with this library in the
00017        file GIMPACT-LICENSE-LGPL.TXT.
00018    (2) The BSD-style license that is included with this library in
00019        the file GIMPACT-LICENSE-BSD.TXT.
00020    (3) The zlib/libpng license that is included with this library in
00021        the file GIMPACT-LICENSE-ZLIB.TXT.
00022 
00023  This library is distributed in the hope that it will be useful,
00024  but WITHOUT ANY WARRANTY; without even the implied warranty of
00025  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
00026  GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
00027 
00028 -----------------------------------------------------------------------------
00029 */
00030 
00031 
00032 #include "gim_box_set.h"
00033 
00034 
00035 GUINT GIM_BOX_TREE::_calc_splitting_axis(
00036         gim_array<GIM_AABB_DATA> & primitive_boxes, GUINT startIndex,  GUINT endIndex)
00037 {
00038         GUINT i;
00039 
00040         btVector3 means(btScalar(0.),btScalar(0.),btScalar(0.));
00041         btVector3 variance(btScalar(0.),btScalar(0.),btScalar(0.));
00042         GUINT numIndices = endIndex-startIndex;
00043 
00044         for (i=startIndex;i<endIndex;i++)
00045         {
00046                 btVector3 center = btScalar(0.5)*(primitive_boxes[i].m_bound.m_max +
00047                                          primitive_boxes[i].m_bound.m_min);
00048                 means+=center;
00049         }
00050         means *= (btScalar(1.)/(btScalar)numIndices);
00051 
00052         for (i=startIndex;i<endIndex;i++)
00053         {
00054                 btVector3 center = btScalar(0.5)*(primitive_boxes[i].m_bound.m_max +
00055                                          primitive_boxes[i].m_bound.m_min);
00056                 btVector3 diff2 = center-means;
00057                 diff2 = diff2 * diff2;
00058                 variance += diff2;
00059         }
00060         variance *= (btScalar(1.)/      ((btScalar)numIndices-1)        );
00061 
00062         return variance.maxAxis();
00063 }
00064 
00065 
00066 GUINT GIM_BOX_TREE::_sort_and_calc_splitting_index(
00067         gim_array<GIM_AABB_DATA> & primitive_boxes, GUINT startIndex,
00068         GUINT endIndex, GUINT splitAxis)
00069 {
00070         GUINT i;
00071         GUINT splitIndex =startIndex;
00072         GUINT numIndices = endIndex - startIndex;
00073 
00074         // average of centers
00075         btScalar splitValue = 0.0f;
00076         for (i=startIndex;i<endIndex;i++)
00077         {
00078                 splitValue+= 0.5f*(primitive_boxes[i].m_bound.m_max[splitAxis] +
00079                                          primitive_boxes[i].m_bound.m_min[splitAxis]);
00080         }
00081         splitValue /= (btScalar)numIndices;
00082 
00083         //sort leafNodes so all values larger then splitValue comes first, and smaller values start from 'splitIndex'.
00084         for (i=startIndex;i<endIndex;i++)
00085         {
00086                 btScalar center = 0.5f*(primitive_boxes[i].m_bound.m_max[splitAxis] +
00087                                          primitive_boxes[i].m_bound.m_min[splitAxis]);
00088                 if (center > splitValue)
00089                 {
00090                         //swap
00091                         primitive_boxes.swap(i,splitIndex);
00092                         splitIndex++;
00093                 }
00094         }
00095 
00096         //if the splitIndex causes unbalanced trees, fix this by using the center in between startIndex and endIndex
00097         //otherwise the tree-building might fail due to stack-overflows in certain cases.
00098         //unbalanced1 is unsafe: it can cause stack overflows
00099         //bool unbalanced1 = ((splitIndex==startIndex) || (splitIndex == (endIndex-1)));
00100 
00101         //unbalanced2 should work too: always use center (perfect balanced trees)
00102         //bool unbalanced2 = true;
00103 
00104         //this should be safe too:
00105         GUINT rangeBalancedIndices = numIndices/3;
00106         bool unbalanced = ((splitIndex<=(startIndex+rangeBalancedIndices)) || (splitIndex >=(endIndex-1-rangeBalancedIndices)));
00107 
00108         if (unbalanced)
00109         {
00110                 splitIndex = startIndex+ (numIndices>>1);
00111         }
00112 
00113         btAssert(!((splitIndex==startIndex) || (splitIndex == (endIndex))));
00114 
00115         return splitIndex;
00116 }
00117 
00118 
00119 void GIM_BOX_TREE::_build_sub_tree(gim_array<GIM_AABB_DATA> & primitive_boxes, GUINT startIndex,  GUINT endIndex)
00120 {
00121         GUINT current_index = m_num_nodes++;
00122 
00123         btAssert((endIndex-startIndex)>0);
00124 
00125         if((endIndex-startIndex) == 1) //we got a leaf
00126         {               
00127                 m_node_array[current_index].m_left = 0;
00128                 m_node_array[current_index].m_right = 0;
00129                 m_node_array[current_index].m_escapeIndex = 0;
00130 
00131                 m_node_array[current_index].m_bound = primitive_boxes[startIndex].m_bound;
00132                 m_node_array[current_index].m_data = primitive_boxes[startIndex].m_data;
00133                 return;
00134         }
00135 
00136         //configure inner node
00137 
00138         GUINT splitIndex;
00139 
00140         //calc this node bounding box
00141         m_node_array[current_index].m_bound.invalidate();       
00142         for (splitIndex=startIndex;splitIndex<endIndex;splitIndex++)
00143         {
00144                 m_node_array[current_index].m_bound.merge(primitive_boxes[splitIndex].m_bound);
00145         }
00146 
00147         //calculate Best Splitting Axis and where to split it. Sort the incoming 'leafNodes' array within range 'startIndex/endIndex'.
00148 
00149         //split axis
00150         splitIndex = _calc_splitting_axis(primitive_boxes,startIndex,endIndex);
00151 
00152         splitIndex = _sort_and_calc_splitting_index(
00153                         primitive_boxes,startIndex,endIndex,splitIndex);
00154 
00155         //configure this inner node : the left node index
00156         m_node_array[current_index].m_left = m_num_nodes;
00157         //build left child tree
00158         _build_sub_tree(primitive_boxes, startIndex, splitIndex );
00159 
00160         //configure this inner node : the right node index
00161         m_node_array[current_index].m_right = m_num_nodes;
00162 
00163         //build right child tree
00164         _build_sub_tree(primitive_boxes, splitIndex ,endIndex);
00165 
00166         //configure this inner node : the escape index
00167         m_node_array[current_index].m_escapeIndex  = m_num_nodes - current_index;
00168 }
00169 
00171 void GIM_BOX_TREE::build_tree(
00172         gim_array<GIM_AABB_DATA> & primitive_boxes)
00173 {
00174         // initialize node count to 0
00175         m_num_nodes = 0;
00176         // allocate nodes
00177         m_node_array.resize(primitive_boxes.size()*2);
00178         
00179         _build_sub_tree(primitive_boxes, 0, primitive_boxes.size());
00180 }
00181 
00182