/**************************************************************************** * 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