Blender V2.61 - r43446

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