123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- /*
- -----------------------------------------------------------------------------
- This source file is part of GIMPACT Library.
- For the latest info, see http://gimpact.sourceforge.net/
- Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
- email: projectileman@yahoo.com
- This library is free software; you can redistribute it and/or
- modify it under the terms of EITHER:
- (1) The GNU Lesser General Public License as published by the Free
- Software Foundation; either version 2.1 of the License, or (at
- your option) any later version. The text of the GNU Lesser
- General Public License is included with this library in the
- file GIMPACT-LICENSE-LGPL.TXT.
- (2) The BSD-style license that is included with this library in
- the file GIMPACT-LICENSE-BSD.TXT.
- (3) The zlib/libpng license that is included with this library in
- the file GIMPACT-LICENSE-ZLIB.TXT.
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
- GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
- -----------------------------------------------------------------------------
- */
- #include "gim_box_set.h"
- GUINT GIM_BOX_TREE::_calc_splitting_axis(
- gim_array<GIM_AABB_DATA> & primitive_boxes, GUINT startIndex, GUINT endIndex)
- {
- GUINT i;
- btVector3 means(btScalar(0.),btScalar(0.),btScalar(0.));
- btVector3 variance(btScalar(0.),btScalar(0.),btScalar(0.));
- GUINT numIndices = endIndex-startIndex;
- for (i=startIndex;i<endIndex;i++)
- {
- btVector3 center = btScalar(0.5)*(primitive_boxes[i].m_bound.m_max +
- primitive_boxes[i].m_bound.m_min);
- means+=center;
- }
- means *= (btScalar(1.)/(btScalar)numIndices);
- for (i=startIndex;i<endIndex;i++)
- {
- btVector3 center = btScalar(0.5)*(primitive_boxes[i].m_bound.m_max +
- primitive_boxes[i].m_bound.m_min);
- btVector3 diff2 = center-means;
- diff2 = diff2 * diff2;
- variance += diff2;
- }
- variance *= (btScalar(1.)/ ((btScalar)numIndices-1) );
- return variance.maxAxis();
- }
- GUINT GIM_BOX_TREE::_sort_and_calc_splitting_index(
- gim_array<GIM_AABB_DATA> & primitive_boxes, GUINT startIndex,
- GUINT endIndex, GUINT splitAxis)
- {
- GUINT i;
- GUINT splitIndex =startIndex;
- GUINT numIndices = endIndex - startIndex;
- // average of centers
- btScalar splitValue = 0.0f;
- for (i=startIndex;i<endIndex;i++)
- {
- splitValue+= 0.5f*(primitive_boxes[i].m_bound.m_max[splitAxis] +
- primitive_boxes[i].m_bound.m_min[splitAxis]);
- }
- splitValue /= (btScalar)numIndices;
- //sort leafNodes so all values larger then splitValue comes first, and smaller values start from 'splitIndex'.
- for (i=startIndex;i<endIndex;i++)
- {
- btScalar center = 0.5f*(primitive_boxes[i].m_bound.m_max[splitAxis] +
- primitive_boxes[i].m_bound.m_min[splitAxis]);
- if (center > splitValue)
- {
- //swap
- primitive_boxes.swap(i,splitIndex);
- splitIndex++;
- }
- }
- //if the splitIndex causes unbalanced trees, fix this by using the center in between startIndex and endIndex
- //otherwise the tree-building might fail due to stack-overflows in certain cases.
- //unbalanced1 is unsafe: it can cause stack overflows
- //bool unbalanced1 = ((splitIndex==startIndex) || (splitIndex == (endIndex-1)));
- //unbalanced2 should work too: always use center (perfect balanced trees)
- //bool unbalanced2 = true;
- //this should be safe too:
- GUINT rangeBalancedIndices = numIndices/3;
- bool unbalanced = ((splitIndex<=(startIndex+rangeBalancedIndices)) || (splitIndex >=(endIndex-1-rangeBalancedIndices)));
- if (unbalanced)
- {
- splitIndex = startIndex+ (numIndices>>1);
- }
- btAssert(!((splitIndex==startIndex) || (splitIndex == (endIndex))));
- return splitIndex;
- }
- void GIM_BOX_TREE::_build_sub_tree(gim_array<GIM_AABB_DATA> & primitive_boxes, GUINT startIndex, GUINT endIndex)
- {
- GUINT current_index = m_num_nodes++;
- btAssert((endIndex-startIndex)>0);
- if((endIndex-startIndex) == 1) //we got a leaf
- {
- m_node_array[current_index].m_left = 0;
- m_node_array[current_index].m_right = 0;
- m_node_array[current_index].m_escapeIndex = 0;
- m_node_array[current_index].m_bound = primitive_boxes[startIndex].m_bound;
- m_node_array[current_index].m_data = primitive_boxes[startIndex].m_data;
- return;
- }
- //configure inner node
- GUINT splitIndex;
- //calc this node bounding box
- m_node_array[current_index].m_bound.invalidate();
- for (splitIndex=startIndex;splitIndex<endIndex;splitIndex++)
- {
- m_node_array[current_index].m_bound.merge(primitive_boxes[splitIndex].m_bound);
- }
- //calculate Best Splitting Axis and where to split it. Sort the incoming 'leafNodes' array within range 'startIndex/endIndex'.
- //split axis
- splitIndex = _calc_splitting_axis(primitive_boxes,startIndex,endIndex);
- splitIndex = _sort_and_calc_splitting_index(
- primitive_boxes,startIndex,endIndex,splitIndex);
- //configure this inner node : the left node index
- m_node_array[current_index].m_left = m_num_nodes;
- //build left child tree
- _build_sub_tree(primitive_boxes, startIndex, splitIndex );
- //configure this inner node : the right node index
- m_node_array[current_index].m_right = m_num_nodes;
- //build right child tree
- _build_sub_tree(primitive_boxes, splitIndex ,endIndex);
- //configure this inner node : the escape index
- m_node_array[current_index].m_escapeIndex = m_num_nodes - current_index;
- }
- //! stackless build tree
- void GIM_BOX_TREE::build_tree(
- gim_array<GIM_AABB_DATA> & primitive_boxes)
- {
- // initialize node count to 0
- m_num_nodes = 0;
- // allocate nodes
- m_node_array.resize(primitive_boxes.size()*2);
-
- _build_sub_tree(primitive_boxes, 0, primitive_boxes.size());
- }
|