genesis-3d_engine/Engine/foundation/util/quadtree.h
zhongdaohuan 6e8fbca745 genesis-3d engine version 1.3.
match the genesis editor version 1.3.0.653.
2014-05-05 14:50:33 +08:00

428 lines
12 KiB
C++

#pragma once
/****************************************************************************
Copyright (c) 2007, Radon Labs GmbH
Copyright (c) 2011-2013,WebJet Business Division,CYOU
http://www.genesis-3d.com.cn
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "util/fixedarray.h"
#include "math/bbox.h"
#include "math/float4.h"
namespace Util
{
//------------------------------------------------------------------------------
template<class TYPE> class QuadTree
{
public:
class Node;
/// constructor
QuadTree();
/// destructor
~QuadTree();
/// initialize quad tree
void Setup(const Math::bbox& box, uchar depth);
/// get the top level bounding box
const Math::bbox& GetBoundingBox() const;
/// get the tree depth
uchar GetDepth() const;
/// compute number of nodes in a level, including its children
SizeT GetNumNodes(uchar level) const;
/// compute linear chunk index from level, col and row
IndexT GetNodeIndex(uchar level, ushort col, ushort row) const;
/// get overall number of nodes in the tree
SizeT GetNumNodesInTree() const;
/// get pointer to node by index
const Node& GetNodeByIndex(IndexT i) const;
/// read/write access to node
Node& NodeByIndex(IndexT i);
/// recursively find the smallest child node which contains the bounding box
Node* FindContainmentNode(const Math::bbox& box);
/// node in quad tree
class Node
{
public:
/// constructor
Node();
/// destructor
~Node();
/// recursively initialize the node
void Setup(QuadTree<TYPE>* tree, uchar _level, ushort _col, ushort _row);
/// get the node's level
char Level() const;
/// get the node's column
ushort Column() const;
/// get the node's row
ushort Row() const;
/// compute the node's bounding box
const Math::bbox& GetBoundingBox() const;
/// recursively find the smallest child node which contains the bounding box
Node* FindContainmentNode(const Math::bbox& box);
/// set data element associated with node
void SetElement(const TYPE& elm);
/// get data element
const TYPE& GetElement() const;
/// get child at index
Node* GetChildAt(IndexT i);
private:
friend class QuadTree;
Node* children[4];
char level;
ushort col;
ushort row;
Math::bbox box;
TYPE element;
};
private:
friend class Node;
uchar treeDepth;
Math::bbox boundingBox; // global bounding box
Math::vector baseNodeSize; // base chunk bounding box
Util::FixedArray<Node> nodeArray;
};
//------------------------------------------------------------------------------
/**
QuadTree constructor.
*/
template<class TYPE>
QuadTree<TYPE>::QuadTree() :
treeDepth(0),
baseNodeSize(0.0f, 0.0f, 0.0f)
{
// empty
}
//------------------------------------------------------------------------------
/**
QuadTree destructor.
*/
template<class TYPE>
QuadTree<TYPE>::~QuadTree()
{
// empty
}
//------------------------------------------------------------------------------
/**
Initialize the quad tree.
*/
template<class TYPE> void
QuadTree<TYPE>::Setup(const Math::bbox& box, uchar depth)
{
#if NEBULA3_BOUNDSCHECKS
n_assert(depth > 0);
#endif
this->treeDepth = depth;
this->boundingBox = box;
int baseDimension = 1 << (this->treeDepth - 1);
this->baseNodeSize.set(this->boundingBox.size().x() / baseDimension,
this->boundingBox.size().y(),
this->boundingBox.size().z() / baseDimension);
SizeT numNodes = this->GetNumNodes(this->treeDepth);
this->nodeArray.SetSize(numNodes);
this->nodeArray[0].Setup(this, 0, 0, 0);
// make sure all nodes have been initialized
#if NEBULA3_BOUNDSCHECKS
int i;
int num = this->nodeArray.Size();
for (i = 0; i < num; i++)
{
n_assert(this->nodeArray[i].Level() >= 0);
}
#endif
}
//------------------------------------------------------------------------------
/**
Returns depth of quad tree.
*/
template<class TYPE> uchar
QuadTree<TYPE>::GetDepth() const
{
return this->treeDepth;
}
//------------------------------------------------------------------------------
/**
Returns top level bounding box of quad tree.
*/
template<class TYPE> const Math::bbox&
QuadTree<TYPE>::GetBoundingBox() const
{
return this->boundingBox;
}
//------------------------------------------------------------------------------
/**
Computes number of nodes in a level, including its child nodes.
*/
template<class TYPE> SizeT
QuadTree<TYPE>::GetNumNodes(uchar level) const
{
return 0x55555555 & ((1 << level * 2) - 1);
}
//------------------------------------------------------------------------------
/**
Returns the overall number of nodes in the tree for linear access.
*/
template<class TYPE> SizeT
QuadTree<TYPE>::GetNumNodesInTree() const
{
return this->nodeArray.Size();
}
//------------------------------------------------------------------------------
/**
Computes a linear chunk index for a chunk address consisting of
level, col and row.
*/
template<class TYPE> IndexT
QuadTree<TYPE>::GetNodeIndex(uchar level, ushort col, ushort row) const
{
#if NEBULA3_BOUNDSCHECKS
n_assert((col >= 0) && (col < (1 << level)));
n_assert((row >= 0) && (row < (1 << level)));
#endif
return this->GetNumNodes(level) + (row << level) + col;
}
//------------------------------------------------------------------------------
/**
Find the biggest quad tree which completely contains the provided
bounding box.
*/
template<class TYPE> typename QuadTree<TYPE>::Node*
QuadTree<TYPE>::FindContainmentNode(const Math::bbox& checkBox)
{
return this->nodeArray[0].FindContainmentNode(checkBox);
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
QuadTree<TYPE>::Node::Node() :
level(-1),
col(0),
row(0)
{
int i;
for (i = 0; i < 4; i++)
{
this->children[i] = 0;
}
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE>
QuadTree<TYPE>::Node::~Node()
{
// empty
}
//------------------------------------------------------------------------------
/**
Recursively initialize a quad tree node.
*/
template<class TYPE> void
QuadTree<TYPE>::Node::Setup(QuadTree* tree, uchar _level, ushort _col, ushort _row)
{
#if NEBULA3_BOUNDSCHECKS
n_assert(tree);
n_assert(this->level == (char)-1);
n_assert(_col < (1 << _level));
n_assert(_row < (1 << _level));
#endif
// store address
this->level = _level;
this->col = _col;
this->row = _row;
// update my bounding box
float levelFactor = float(1 << (tree->treeDepth - 1 - this->level));
static Math::vector center;
static Math::vector extent;
const Math::vector& baseSize = tree->baseNodeSize;
const Math::bbox& treeBox = tree->boundingBox;
Math::vector treeSize = treeBox.size();
Math::vector treeCenter = treeBox.center();
center.set(treeCenter.x() + (((this->col + 0.5f) * levelFactor * baseSize.x()) - (treeSize.x() * 0.5f)),
treeCenter.y(),
treeCenter.z() + (((this->row + 0.5f) * levelFactor * baseSize.z()) - (treeSize.z() * 0.5f)));
extent.set(levelFactor * baseSize.x() * 0.5f,
treeBox.extents().y(),
levelFactor * baseSize.z() * 0.5f );
this->box.set(center, extent);
// recurse into children
uchar childLevel = this->level + 1;
if (childLevel < tree->treeDepth)
{
ushort i;
for (i = 0; i < 4; i++)
{
ushort childCol = 2 * this->col + (i & 1);
ushort childRow = 2 * this->row + ((i & 2) >> 1);
IndexT childIndex = tree->GetNodeIndex(childLevel, childCol, childRow);
this->children[i] = &(tree->nodeArray[childIndex]);
this->children[i]->Setup(tree, childLevel, childCol, childRow);
}
}
}
//------------------------------------------------------------------------------
/**
This finds the smallest child node which completely contains the
given bounding box. Calls itself recursively.
*/
template<class TYPE> typename QuadTree<TYPE>::Node*
QuadTree<TYPE>::Node::FindContainmentNode(const Math::bbox& checkBox)
{
if (this->box.contains(checkBox))
{
// recurse into children
if (this->children[0] != 0)
{
int i;
for (i = 0; i < 4; i++)
{
Node* containNode = this->children[i]->FindContainmentNode(checkBox);
if (containNode)
{
return containNode;
}
}
}
// not contained in children, but still contained in this
return this;
}
else
{
// not contained in this, break recursion
return 0;
}
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE> const typename QuadTree<TYPE>::Node&
QuadTree<TYPE>::GetNodeByIndex(IndexT index) const
{
return this->nodeArray[index];
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE> typename QuadTree<TYPE>::Node&
QuadTree<TYPE>::NodeByIndex(IndexT index)
{
return this->nodeArray[index];
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE> const Math::bbox&
QuadTree<TYPE>::Node::GetBoundingBox() const
{
return this->box;
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE> char
QuadTree<TYPE>::Node::Level() const
{
return this->level;
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE> ushort
QuadTree<TYPE>::Node::Column() const
{
return this->col;
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE> ushort
QuadTree<TYPE>::Node::Row() const
{
return this->row;
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE> void
QuadTree<TYPE>::Node::SetElement(const TYPE& elm)
{
this->element = elm;
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE> const TYPE&
QuadTree<TYPE>::Node::GetElement() const
{
return this->element;
}
//------------------------------------------------------------------------------
/**
*/
template<class TYPE> typename QuadTree<TYPE>::Node*
QuadTree<TYPE>::Node::GetChildAt(IndexT i)
{
return this->children[i];
}
} // namespace Util
//------------------------------------------------------------------------------