Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Opcode::AABBTreeNode Class Reference

#include <Opcode.h>

Inheritance diagram for Opcode::AABBTreeNode:
Opcode::AABBTree

Public Member Functions

inline_ const udwordGetPrimitives () const
 
inline_ udword GetNbPrimitives () const
 

Protected Member Functions

udword Split (udword axis, AABBTreeBuilder *builder)
 
bool Subdivide (AABBTreeBuilder *builder)
 
void _BuildHierarchy (AABBTreeBuilder *builder)
 
void _Refit (AABBTreeBuilder *builder)
 

Protected Attributes

udwordmNodePrimitives
 Node-related primitives (shortcut to a position in mIndices below) More...
 
udword mNbPrimitives
 Number of primitives for this node. More...
 

Detailed Description

Definition at line 79 of file Opcode.h.

Member Function Documentation

void AABBTreeNode::_BuildHierarchy ( AABBTreeBuilder builder)
protected

Recursive hierarchy building in a top-down fashion.

Parameters
builder[in] the tree builder

Definition at line 334 of file OPC_AABBTree.cpp.

335 {
336  // 1) Compute the global box for current node. The box is stored in mBV.
338 
339  // 2) Subdivide current node
340  Subdivide(builder);
341 
342  // 3) Recurse
343  AABBTreeNode* Pos = (AABBTreeNode*)GetPos();
344  AABBTreeNode* Neg = (AABBTreeNode*)GetNeg();
345  if(Pos) Pos->_BuildHierarchy(builder);
346  if(Neg) Neg->_BuildHierarchy(builder);
347 }
void AABBTreeNode::_Refit ( AABBTreeBuilder builder)
protected

Refits the tree (top-down).

Parameters
builder[in] the tree builder

Definition at line 355 of file OPC_AABBTree.cpp.

356 {
357  // 1) Recompute the new global box for current node
359 
360  // 2) Recurse
361  AABBTreeNode* Pos = (AABBTreeNode*)GetPos();
362  AABBTreeNode* Neg = (AABBTreeNode*)GetNeg();
363  if(Pos) Pos->_Refit(builder);
364  if(Neg) Neg->_Refit(builder);
365 }
inline_ udword Opcode::AABBTreeNode::GetNbPrimitives ( ) const
inline

Definition at line 85 of file Opcode.h.

inline_ const udword* Opcode::AABBTreeNode::GetPrimitives ( ) const
inline

Definition at line 84 of file Opcode.h.

udword AABBTreeNode::Split ( udword  axis,
AABBTreeBuilder builder 
)
protected

Splits the node along a given axis. The list of indices is reorganized according to the split values.

Parameters
axis[in] splitting axis index
builder[in] the tree builder
Returns
the number of primitives assigned to the first child
Warning
this method reorganizes the internal list of primitives

Definition at line 99 of file OPC_AABBTree.cpp.

100 {
101  // Get node split value
102  float SplitValue = builder->GetSplittingValue(mNodePrimitives, mNbPrimitives, mBV, axis);
103 
104  udword NbPos = 0;
105  // Loop through all node-related primitives. Their indices range from mNodePrimitives[0] to mNodePrimitives[mNbPrimitives-1].
106  // Those indices map the global list in the tree builder.
107  for(udword i=0;i<mNbPrimitives;i++)
108  {
109  // Get index in global list
110  udword Index = mNodePrimitives[i];
111 
112  // Test against the splitting value. The primitive value is tested against the enclosing-box center.
113  // [We only need an approximate partition of the enclosing box here.]
114  float PrimitiveValue = builder->GetSplittingValue(Index, axis);
115 
116  // Reorganize the list of indices in this order: positive - negative.
117  if(PrimitiveValue > SplitValue)
118  {
119  // Swap entries
120  udword Tmp = mNodePrimitives[i];
122  mNodePrimitives[NbPos] = Tmp;
123  // Count primitives assigned to positive space
124  NbPos++;
125  }
126  }
127  return NbPos;
128 }
bool AABBTreeNode::Subdivide ( AABBTreeBuilder builder)
protected

Subdivides the node.

      N
    /   \
  /       \

N/2 N/2 / \ / \ N/4 N/4 N/4 N/4 (etc)

A well-balanced tree should have a O(log n) depth. A degenerate tree would have a O(n) depth. Note a perfectly-balanced tree is not well-suited to collision detection anyway.

Parameters
builder[in] the tree builder
Returns
true if success

Definition at line 150 of file OPC_AABBTree.cpp.

151 {
152  // Checkings
153  if(!builder) return false;
154 
155  // Stop subdividing if we reach a leaf node. This is always performed here,
156  // else we could end in trouble if user overrides this.
157  if(mNbPrimitives==1) return true;
158 
159  // Let the user validate the subdivision
160  if(!builder->ValidateSubdivision(mNodePrimitives, mNbPrimitives, mBV)) return true;
161 
162  bool ValidSplit = true; // Optimism...
163  udword NbPos;
164  if(builder->mSettings.mRules & SPLIT_LARGEST_AXIS)
165  {
166  // Find the largest axis to split along
167  Point Extents; mBV.GetExtents(Extents); // Box extents
168  udword Axis = Extents.LargestAxis(); // Index of largest axis
169 
170  // Split along the axis
171  NbPos = Split(Axis, builder);
172 
173  // Check split validity
174  if(!NbPos || NbPos==mNbPrimitives) ValidSplit = false;
175  }
176  else if(builder->mSettings.mRules & SPLIT_SPLATTER_POINTS)
177  {
178  udword i;
179  // Compute the means
180  Point Means(0.0f, 0.0f, 0.0f);
181  for(i=0;i<mNbPrimitives;i++)
182  {
183  udword Index = mNodePrimitives[i];
184  Means.x+=builder->GetSplittingValue(Index, 0);
185  Means.y+=builder->GetSplittingValue(Index, 1);
186  Means.z+=builder->GetSplittingValue(Index, 2);
187  }
188  Means/=float(mNbPrimitives);
189 
190  // Compute variances
191  Point Vars(0.0f, 0.0f, 0.0f);
192  for(i=0;i<mNbPrimitives;i++)
193  {
194  udword Index = mNodePrimitives[i];
195  float Cx = builder->GetSplittingValue(Index, 0);
196  float Cy = builder->GetSplittingValue(Index, 1);
197  float Cz = builder->GetSplittingValue(Index, 2);
198  Vars.x += (Cx - Means.x)*(Cx - Means.x);
199  Vars.y += (Cy - Means.y)*(Cy - Means.y);
200  Vars.z += (Cz - Means.z)*(Cz - Means.z);
201  }
202  Vars/=float(mNbPrimitives-1);
203 
204  // Choose axis with greatest variance
205  udword Axis = Vars.LargestAxis();
206 
207  // Split along the axis
208  NbPos = Split(Axis, builder);
209 
210  // Check split validity
211  if(!NbPos || NbPos==mNbPrimitives) ValidSplit = false;
212  }
213  else if(builder->mSettings.mRules & SPLIT_BALANCED)
214  {
215  // Test 3 axis, take the best
216  float Results[3];
217  NbPos = Split(0, builder); Results[0] = float(NbPos)/float(mNbPrimitives);
218  NbPos = Split(1, builder); Results[1] = float(NbPos)/float(mNbPrimitives);
219  NbPos = Split(2, builder); Results[2] = float(NbPos)/float(mNbPrimitives);
220  Results[0]-=0.5f; Results[0]*=Results[0];
221  Results[1]-=0.5f; Results[1]*=Results[1];
222  Results[2]-=0.5f; Results[2]*=Results[2];
223  udword Min=0;
224  if(Results[1]<Results[Min]) Min = 1;
225  if(Results[2]<Results[Min]) Min = 2;
226 
227  // Split along the axis
228  NbPos = Split(Min, builder);
229 
230  // Check split validity
231  if(!NbPos || NbPos==mNbPrimitives) ValidSplit = false;
232  }
233  else if(builder->mSettings.mRules & SPLIT_BEST_AXIS)
234  {
235  // Test largest, then middle, then smallest axis...
236 
237  // Sort axis
238  Point Extents; mBV.GetExtents(Extents); // Box extents
239  udword SortedAxis[] = { 0, 1, 2 };
240  float* Keys = (float*)&Extents.x;
241  for(udword j=0;j<3;j++)
242  {
243  for(udword i=0;i<2;i++)
244  {
245  if(Keys[SortedAxis[i]]<Keys[SortedAxis[i+1]])
246  {
247  udword Tmp = SortedAxis[i];
248  SortedAxis[i] = SortedAxis[i+1];
249  SortedAxis[i+1] = Tmp;
250  }
251  }
252  }
253 
254  // Find the largest axis to split along
255  udword CurAxis = 0;
256  ValidSplit = false;
257  while(!ValidSplit && CurAxis!=3)
258  {
259  NbPos = Split(SortedAxis[CurAxis], builder);
260  // Check the subdivision has been successful
261  if(!NbPos || NbPos==mNbPrimitives) CurAxis++;
262  else ValidSplit = true;
263  }
264  }
265  else if(builder->mSettings.mRules & SPLIT_FIFTY)
266  {
267  // Don't even bother splitting (mainly a performance test)
268  NbPos = mNbPrimitives>>1;
269  }
270  else return false; // Unknown splitting rules
271 
272  // Check the subdivision has been successful
273  if(!ValidSplit)
274  {
275  // Here, all boxes lie in the same sub-space. Two strategies:
276  // - if the tree *must* be complete, make an arbitrary 50-50 split
277  // - else stop subdividing
278 // if(builder->mSettings.mRules&SPLIT_COMPLETE)
279  if(builder->mSettings.mLimit==1)
280  {
281  builder->IncreaseNbInvalidSplits();
282  NbPos = mNbPrimitives>>1;
283  }
284  else return true;
285  }
286 
287  // Now create children and assign their pointers.
288  if(builder->mNodeBase)
289  {
290  // We use a pre-allocated linear pool for complete trees [Opcode 1.3]
291  AABBTreeNode* Pool = (AABBTreeNode*)builder->mNodeBase;
292  udword Count = builder->GetCount() - 1; // Count begins to 1...
293  // Set last bit to tell it shouldn't be freed ### pretty ugly, find a better way. Maybe one bit in mNbPrimitives
294  OPASSERT(!(uintptr_t(&Pool[Count+0])&1));
295  OPASSERT(!(uintptr_t(&Pool[Count+1])&1));
296  mPos = uintptr_t(&Pool[Count+0])|1;
297 #ifndef OPC_NO_NEG_VANILLA_TREE
298  mNeg = uintptr_t(&Pool[Count+1])|1;
299 #endif
300  }
301  else
302  {
303  // Non-complete trees and/or Opcode 1.2 allocate nodes on-the-fly
304 #ifndef OPC_NO_NEG_VANILLA_TREE
305  mPos = (uintptr_t)new AABBTreeNode; CHECKALLOC(mPos);
306  mNeg = (uintptr_t)new AABBTreeNode; CHECKALLOC(mNeg);
307 #else
308  AABBTreeNode* PosNeg = new AABBTreeNode[2];
309  CHECKALLOC(PosNeg);
310  mPos = (uintptr_t)PosNeg;
311 #endif
312  }
313 
314  // Update stats
315  builder->IncreaseCount(2);
316 
317  // Assign children
318  AABBTreeNode* Pos = (AABBTreeNode*)GetPos();
319  AABBTreeNode* Neg = (AABBTreeNode*)GetNeg();
320  Pos->mNodePrimitives = &mNodePrimitives[0];
321  Pos->mNbPrimitives = NbPos;
322  Neg->mNodePrimitives = &mNodePrimitives[NbPos];
323  Neg->mNbPrimitives = mNbPrimitives - NbPos;
324 
325  return true;
326 }

Member Data Documentation

udword Opcode::AABBTreeNode::mNbPrimitives
protected

Number of primitives for this node.

Definition at line 90 of file Opcode.h.

udword* Opcode::AABBTreeNode::mNodePrimitives
protected

Node-related primitives (shortcut to a position in mIndices below)

Definition at line 89 of file Opcode.h.


The documentation for this class was generated from the following files: