diff --git a/vcg/space/index/aabb_binary_tree/base.h b/vcg/space/index/aabb_binary_tree/base.h new file mode 100644 index 00000000..88d55da9 --- /dev/null +++ b/vcg/space/index/aabb_binary_tree/base.h @@ -0,0 +1,408 @@ +/**************************************************************************** +* VCGLib o o * +* Visual and Computer Graphics Library o o * +* _ O _ * +* Copyright(C) 2004 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program 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 * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +/**************************************************************************** +History + +$Log: not supported by cvs2svn $ + +****************************************************************************/ + +#ifndef __VCGLIB_AABBBINARYTREEBASE_H +#define __VCGLIB_AABBBINARYTREEBASE_H + +// standard headers +#include + +// stl headers +#include + +// vcg headers +#include +#include + +/***************************************************************************/ + +namespace vcg { + +template +class AABBBinaryTree { + public: + typedef AABBBinaryTree ClassType; + typedef OBJTYPE ObjType; + typedef ObjType * ObjPtr; + typedef SCALARTYPE ScalarType; + typedef NODEAUXDATATYPE NodeAuxDataType; + typedef Point3 CoordType; + + typedef std::vector ObjPtrVector; + typedef typename ObjPtrVector::iterator ObjPtrVectorIterator; + typedef typename ObjPtrVector::const_iterator ObjPtrVectorConstIterator; + + public: + class AABBBinaryTreeNode { + public: + AABBBinaryTreeNode * parent; + AABBBinaryTreeNode * children[2]; + CoordType boxCenter; + CoordType boxHalfDims; + ObjPtrVectorIterator oBegin; + ObjPtrVectorIterator oEnd; + unsigned char splitAxis; + NodeAuxDataType auxData; + + inline AABBBinaryTreeNode(AABBBinaryTreeNode * pParent = 0); + inline ~AABBBinaryTreeNode(void); + + inline void Clear(void); + inline bool IsLeaf(void) const; + inline unsigned int ObjectsCount(void) const; + + inline unsigned int & Flags(void); + inline const unsigned int & Flags(void) const; + + inline ScalarType & ScalarValue(void); + inline const ScalarType & ScalarValue(void) const; + + inline int & IntValue(void); + inline const int & IntValue(void) const; + + inline unsigned int & UIntValue(void); + inline const unsigned int & UIntValue(void) const; + + inline void * & PtrValue(void); + inline const void * & PtrValue(void) const; + + protected: + union SharedDataUnion { + unsigned int flags; + int intValue; + unsigned int uintValue; + ScalarType scalarValue; + void * ptrValue; + }; + + SharedDataUnion sharedData; + }; + + typedef AABBBinaryTreeNode NodeType; + + ObjPtrVector pObjects; + NodeType * pRoot; + + inline AABBBinaryTree(void); + inline ~AABBBinaryTree(void); + + inline void Clear(void); + + template + inline bool Set(const OBJITERATOR & oBegin, const OBJITERATOR & oEnd, OBJITERATORPTRFUNCT & objPtr, OBJBOXFUNCT & objBox, OBJBARYCENTERFUNCT & objBarycenter, const unsigned int maxElemsPerLeaf = 1, const ScalarType & leafBoxMaxVolume = ((ScalarType)0), const bool useVariance = true); + + protected: + template + inline static NodeType * BoundObjects(NodeType * parent, const ObjPtrVectorIterator & oBegin, const ObjPtrVectorIterator & oEnd, const unsigned int size, const unsigned int maxElemsPerLeaf, const ScalarType & leafBoxMaxVolume, const bool useVariance, OBJBOXFUNCT & getBox, OBJBARYCENTERFUNCT & getBarycenter); + + template + inline static int BalanceMedian(const ObjPtrVectorIterator & oBegin, const ObjPtrVectorIterator & oEnd, const int size, const int splitAxis, OBJBARYCENTERFUNCT & getBarycenter, ObjPtrVectorIterator & medianIter); +}; + + + +template +AABBBinaryTree::AABBBinaryTree(void) { + this->pObjects.clear(); + this->pRoot = 0; +} + +template +AABBBinaryTree::~AABBBinaryTree(void) { + this->pObjects.clear(); + delete this->pRoot; +} + +template +void AABBBinaryTree::Clear(void) { + this->pObjects.clear(); + delete this->pRoot; + this->pRoot = 0; +} + +template +template +bool AABBBinaryTree::Set(const OBJITERATOR & oBegin, const OBJITERATOR & oEnd, OBJITERATORPTRFUNCT & objPtr, OBJBOXFUNCT & objBox, OBJBARYCENTERFUNCT & objBarycenter, const unsigned int maxElemsPerLeaf, const ScalarType & leafBoxMaxVolume, const bool useVariance) { + this->Clear(); + + if ((maxElemsPerLeaf == 0) && (leafBoxMaxVolume <= ((ScalarType)0))) { + return (false); + } + + const unsigned int size = (unsigned int)std::distance(oBegin, oEnd); + + this->pObjects.reserve(size); + for (OBJITERATOR oi=oBegin; oi!=oEnd; ++oi) { + this->pObjects.push_back(objPtr(*oi)); + } + + this->pRoot = ClassType::BoundObjects(0, this->pObjects.begin(), this->pObjects.end(), size, maxElemsPerLeaf, leafBoxMaxVolume, useVariance, objBox, objBarycenter); + + return (this->pRoot != 0); +} + +template +template +typename AABBBinaryTree::NodeType * AABBBinaryTree::BoundObjects(NodeType * parent, const ObjPtrVectorIterator & oBegin, const ObjPtrVectorIterator & oEnd, const unsigned int size, const unsigned int maxElemsPerLeaf, const ScalarType & leafBoxMaxVolume, const bool useVariance, OBJBOXFUNCT & getBox, OBJBARYCENTERFUNCT & getBarycenter) { + if (size <= 0) { + return (0); + } + + NodeType * pNode = new NodeType(parent); + if (pNode == 0) { + return (0); + } + + pNode->children[0] = 0; + pNode->children[1] = 0; + + pNode->oBegin = oBegin; + pNode->oEnd = oEnd; + + Box3 bbox; + bbox.SetNull(); + for (ObjPtrVectorConstIterator oi=pNode->oBegin; oi!=pNode->oEnd; ++oi) { + Box3 tbox; + getBox(*(*oi), tbox); + bbox.Add(tbox); + } + + pNode->boxCenter = bbox.Center(); + pNode->boxHalfDims = bbox.Dim() / ((ScalarType)2); + + const bool bMaxObjectsReached = (((maxElemsPerLeaf > 0) && (size <= maxElemsPerLeaf)) || (size == 1)); + const bool bMaxVolumeReached = ((leafBoxMaxVolume > ((ScalarType)0)) && (bbox.Volume() <= leafBoxMaxVolume)); + const bool isLeaf = bMaxObjectsReached || bMaxVolumeReached; + + if (isLeaf) { + pNode->splitAxis = 0; + return (pNode); + } + + CoordType pSplit; + + if (useVariance) { + CoordType mean((ScalarType)0, (ScalarType)0, (ScalarType)0); + CoordType variance((ScalarType)0, (ScalarType)0, (ScalarType)0); + for (ObjPtrVectorIterator oi=oBegin; oi!=oEnd; ++oi) { + CoordType bc; + getBarycenter(*(*oi), bc); + mean += bc; + variance[0] += bc[0] * bc[0]; + variance[1] += bc[1] * bc[1]; + variance[2] += bc[2] * bc[2]; + } + variance[0] -= (mean[0] * mean[0]) / ((ScalarType)size); + variance[1] -= (mean[1] * mean[1]) / ((ScalarType)size); + variance[2] -= (mean[2] * mean[2]) / ((ScalarType)size); + pSplit = variance; + } + else { + pSplit = pNode->boxHalfDims; + } + + ScalarType maxDim = pSplit[0]; + unsigned char splitAxis = 0; + if (maxDim < pSplit[1]) { + maxDim = pSplit[1]; + splitAxis = 1; + } + if (maxDim < pSplit[2]) { + maxDim = pSplit[2]; + splitAxis = 2; + } + + pNode->splitAxis = splitAxis; + + ObjPtrVectorIterator median; + const int lSize = ClassType::BalanceMedian(pNode->oBegin, pNode->oEnd, size, splitAxis, getBarycenter, median); + const int rSize = size - lSize; + + if (lSize > 0) { + pNode->children[0] = ClassType::BoundObjects(pNode, pNode->oBegin, median, lSize, maxElemsPerLeaf, leafBoxMaxVolume, useVariance, getBox, getBarycenter); + if (pNode->children[0] == 0) { + delete pNode; + return (0); + } + } + + if (rSize > 0) { + pNode->children[1] = ClassType::BoundObjects(pNode, median, pNode->oEnd, rSize, maxElemsPerLeaf, leafBoxMaxVolume, useVariance, getBox, getBarycenter); + if (pNode->children[1] == 0) { + delete pNode; + return (0); + } + } + + return (pNode); +} + +template +template +int AABBBinaryTree::BalanceMedian(const ObjPtrVectorIterator & oBegin, const ObjPtrVectorIterator & oEnd, const int size, const int splitAxis, OBJBARYCENTERFUNCT & getBarycenter, ObjPtrVectorIterator & medianIter) { + const int iMedian = (size + 1) / 2; + + ObjPtrVectorIterator l, r, i, j; + ObjPtr iTmp; + ScalarType pos; + ObjPtrVectorIterator median = oBegin + iMedian; + CoordType bc; + + l = oBegin; + r = oEnd - 1; + + while (l < r) { + getBarycenter(*(*r), bc); + pos = bc[splitAxis]; + + i = l; + j = r - 1; + + while (true) { + getBarycenter(*(*i), bc); + while ((bc[splitAxis] <= pos) && (i < r)) { + i++; + getBarycenter(*(*i), bc); + } + getBarycenter(*(*j), bc); + while ((bc[splitAxis] > pos) && (j > l)) { + j--; + getBarycenter(*(*j), bc); + } + if (i >= j) { + break; + } + iTmp = (*i); + (*i) = (*j); + (*j) = iTmp; + } + + iTmp = (*i); + (*i) = (*r); + (*r) = iTmp; + + if (i >= (median)) { + r = i - 1; + } + if (i <= (median)) { + l = i + 1; + } + } + + medianIter = median; + + return (iMedian); +} + +template +AABBBinaryTree::AABBBinaryTreeNode::AABBBinaryTreeNode(NodeType * pParent) { + this->parent = pParent; + this->children[0] = 0; + this->children[1] = 0; +} + +template +AABBBinaryTree::AABBBinaryTreeNode::~AABBBinaryTreeNode(void) { + delete this->children[0]; + delete this->children[1]; +} + +template +void AABBBinaryTree::AABBBinaryTreeNode::Clear(void) { + delete this->children[0]; + this->children[0] = 0; + + delete this->children[1]; + this->children[1] = 0; +} + +template +bool AABBBinaryTree::AABBBinaryTreeNode::IsLeaf(void) const { + return ((this->children[0] == 0) && (this->children[1] == 0)); +} + +template +unsigned int AABBBinaryTree::AABBBinaryTreeNode::ObjectsCount(void) const { + return ((unsigned int)(std::distance(this->oBegin, this->oEnd))); +} + +template +unsigned int & AABBBinaryTree::AABBBinaryTreeNode::Flags(void) { + return (this->sharedData.flags); +} + +template +const unsigned int & AABBBinaryTree::AABBBinaryTreeNode::Flags(void) const { + return (this->sharedData.flags); +} + +template +int & AABBBinaryTree::AABBBinaryTreeNode::IntValue(void) { + return (this->sharedData.intValue); +} + +template +const int & AABBBinaryTree::AABBBinaryTreeNode::IntValue(void) const { + return (this->sharedData.intValue); +} + +template +unsigned int & AABBBinaryTree::AABBBinaryTreeNode::UIntValue(void) { + return (this->sharedData.uintValue); +} + +template +const unsigned int & AABBBinaryTree::AABBBinaryTreeNode::UIntValue(void) const { + return (this->sharedData.uintValue); +} + +template +typename AABBBinaryTree::ScalarType & AABBBinaryTree::AABBBinaryTreeNode::ScalarValue(void) { + return (this->sharedData.scalarValue); +} + +template +const typename AABBBinaryTree::ScalarType & AABBBinaryTree::AABBBinaryTreeNode::ScalarValue(void) const { + return (this->sharedData.scalarValue); +} + +template +void * & AABBBinaryTree::AABBBinaryTreeNode::PtrValue(void) { + return (this->sharedData.ptrValue); +} + +template +const void * & AABBBinaryTree::AABBBinaryTreeNode::PtrValue(void) const { + return (this->sharedData.ptrValue); +} + +} // end namespace vcg + +#endif // #ifndef __VCGLIB_AABBBINARYTREEBASE_H