Minor improvements

-Added the possibility to create a balanced tree
-Added methods to get the protected members
-Bug fixed in the size of the stack used in the query methods
This commit is contained in:
Gianpaolo Palma 2016-11-16 11:12:42 +01:00
parent a42c279255
commit 0906212a1f
1 changed files with 461 additions and 444 deletions

View File

@ -61,8 +61,8 @@ namespace vcg {
class VectorConstDataWrapper :public ConstDataWrapper<typename StdVectorType::value_type>
{
public:
inline VectorConstDataWrapper(StdVectorType &vec):
ConstDataWrapper<typename StdVectorType::value_type> ( &(vec[0]), vec.size(), sizeof(typename StdVectorType::value_type))
inline VectorConstDataWrapper(StdVectorType &vec) :
ConstDataWrapper<typename StdVectorType::value_type>(&(vec[0]), vec.size(), sizeof(typename StdVectorType::value_type))
{}
};
@ -70,8 +70,8 @@ namespace vcg {
class VertexConstDataWrapper :public ConstDataWrapper<typename MeshType::CoordType>
{
public:
inline VertexConstDataWrapper(MeshType &m):
ConstDataWrapper<typename MeshType::CoordType> ( &(m.vert[0].P()), m.vert.size(), sizeof(typename MeshType::VertexType))
inline VertexConstDataWrapper(MeshType &m) :
ConstDataWrapper<typename MeshType::CoordType>(&(m.vert[0].P()), m.vert.size(), sizeof(typename MeshType::VertexType))
{}
};
@ -96,9 +96,9 @@ namespace vcg {
//standard node
struct {
Scalar splitValue;
unsigned int firstChildId:24;
unsigned int dim:2;
unsigned int leaf:1;
unsigned int firstChildId : 24;
unsigned int dim : 2;
unsigned int leaf : 1;
};
//leaf
struct {
@ -112,10 +112,12 @@ namespace vcg {
// return the protected members which store the nodes and the points list
inline const NodeList& _getNodes(void) { return mNodes; }
inline const std::vector<VectorType>& _getPoints(void) { return mPoints; }
inline unsigned int _getNumLevel(void) { return numLevel; }
inline const AxisAlignedBoxType& _getAABBox(void) { return mAABB; }
public:
KdTree(const ConstDataWrapper<VectorType>& points, unsigned int nofPointsPerCell = 16, unsigned int maxDepth = 64);
KdTree(const ConstDataWrapper<VectorType>& points, unsigned int nofPointsPerCell = 16, unsigned int maxDepth = 64, bool balanced = false);
~KdTree();
@ -140,7 +142,7 @@ namespace vcg {
// and returns the index of the first element of the second subset
unsigned int split(int start, int end, unsigned int dim, float splitValue);
int createTree(unsigned int nodeId, unsigned int start, unsigned int end, unsigned int level, unsigned int targetCellsize, unsigned int targetMaxDepth);
int createTree(unsigned int nodeId, unsigned int start, unsigned int end, unsigned int level);
protected:
@ -148,28 +150,35 @@ namespace vcg {
NodeList mNodes; //kd-tree nodes
std::vector<VectorType> mPoints; //points read from the input DataWrapper
std::vector<unsigned int> mIndices; //points indices
unsigned int targetCellSize; //min number of point in a leaf
unsigned int targetMaxDepth; //max tree depth
unsigned int numLevel; //actual tree depth
bool isBalanced; //true if the tree is balanced
};
template<typename Scalar>
KdTree<Scalar>::KdTree(const ConstDataWrapper<VectorType>& points, unsigned int nofPointsPerCell, unsigned int maxDepth)
KdTree<Scalar>::KdTree(const ConstDataWrapper<VectorType>& points, unsigned int nofPointsPerCell, unsigned int maxDepth, bool balanced)
: mPoints(points.size()), mIndices(points.size())
{
// compute the AABB of the input
mPoints[0] = points[0];
mAABB.Set(mPoints[0]);
for (unsigned int i=1 ; i<mPoints.size() ; ++i)
for (unsigned int i = 1; i < mPoints.size(); ++i)
{
mPoints[i] = points[i];
mIndices[i] = i;
mAABB.Add(mPoints[i]);
}
mNodes.reserve(4*mPoints.size()/nofPointsPerCell);
targetMaxDepth = maxDepth;
targetCellSize = nofPointsPerCell;
isBalanced = balanced;
//mNodes.reserve(4 * mPoints.size() / nofPointsPerCell);
//first node inserted (no leaf). The others are made by the createTree function (recursively)
mNodes.resize(1);
mNodes.back().leaf = 0;
/*int numLevel = */
createTree(0, 0, mPoints.size(), 1, nofPointsPerCell, maxDepth);
numLevel = createTree(0, 0, mPoints.size(), 1);
}
template<typename Scalar>
@ -200,7 +209,7 @@ namespace vcg {
mNeighborQueue.setMaxSize(k);
mNeighborQueue.init();
QueryNode mNodeStack[64];
std::vector<QueryNode> mNodeStack(numLevel + 1);
mNodeStack[0].nodeId = 0;
mNodeStack[0].sq = 0.f;
unsigned int count = 1;
@ -208,7 +217,7 @@ namespace vcg {
while (count)
{
//we select the last node (AABB) inserted in the stack
QueryNode& qnode = mNodeStack[count-1];
QueryNode& qnode = mNodeStack[count - 1];
//while going down the tree qnode.nodeId is the nearest sub-tree, otherwise,
//in backtracking, qnode.nodeId is the other sub-tree that will be visited iff
@ -224,9 +233,9 @@ namespace vcg {
--count; //pop of the leaf
//end is the index of the last element of the leaf in mPoints
unsigned int end = node.start+node.size;
unsigned int end = node.start + node.size;
//adding the element of the leaf to the heap
for (unsigned int i=node.start ; i<end ; ++i)
for (unsigned int i = node.start; i < end; ++i)
mNeighborQueue.insert(mIndices[i], vcg::SquaredNorm(queryPoint - mPoints[i]));
}
//otherwise, if we're not on a leaf
@ -240,12 +249,12 @@ namespace vcg {
{
mNodeStack[count].nodeId = node.firstChildId;
//in the father's nodeId we save the index of the other sub-tree (for backtracking)
qnode.nodeId = node.firstChildId+1;
qnode.nodeId = node.firstChildId + 1;
}
//right sub-tree (same as above)
else
{
mNodeStack[count].nodeId = node.firstChildId+1;
mNodeStack[count].nodeId = node.firstChildId + 1;
qnode.nodeId = node.firstChildId;
}
//distance is inherited from the father (while descending the tree it's equal to 0)
@ -272,7 +281,7 @@ namespace vcg {
template<typename Scalar>
void KdTree<Scalar>::doQueryDist(const VectorType& queryPoint, float dist, std::vector<unsigned int>& points, std::vector<Scalar>& sqrareDists)
{
QueryNode mNodeStack[64];
std::vector<QueryNode> mNodeStack(numLevel + 1);
mNodeStack[0].nodeId = 0;
mNodeStack[0].sq = 0.f;
unsigned int count = 1;
@ -280,7 +289,7 @@ namespace vcg {
float sqrareDist = dist*dist;
while (count)
{
QueryNode& qnode = mNodeStack[count-1];
QueryNode& qnode = mNodeStack[count - 1];
Node & node = mNodes[qnode.nodeId];
if (qnode.sq < sqrareDist)
@ -288,8 +297,8 @@ namespace vcg {
if (node.leaf)
{
--count; // pop
unsigned int end = node.start+node.size;
for (unsigned int i=node.start ; i<end ; ++i)
unsigned int end = node.start + node.size;
for (unsigned int i = node.start; i < end; ++i)
{
float pointSquareDist = vcg::SquaredNorm(queryPoint - mPoints[i]);
if (pointSquareDist < sqrareDist)
@ -306,11 +315,11 @@ namespace vcg {
if (new_off < 0.)
{
mNodeStack[count].nodeId = node.firstChildId;
qnode.nodeId = node.firstChildId+1;
qnode.nodeId = node.firstChildId + 1;
}
else
{
mNodeStack[count].nodeId = node.firstChildId+1;
mNodeStack[count].nodeId = node.firstChildId + 1;
qnode.nodeId = node.firstChildId;
}
mNodeStack[count].sq = qnode.sq;
@ -335,7 +344,7 @@ namespace vcg {
template<typename Scalar>
void KdTree<Scalar>::doQueryClosest(const VectorType& queryPoint, unsigned int& index, Scalar& dist)
{
QueryNode mNodeStack[64];
std::vector<QueryNode> mNodeStack(numLevel + 1);
mNodeStack[0].nodeId = 0;
mNodeStack[0].sq = 0.f;
unsigned int count = 1;
@ -346,7 +355,7 @@ namespace vcg {
while (count)
{
QueryNode& qnode = mNodeStack[count-1];
QueryNode& qnode = mNodeStack[count - 1];
Node & node = mNodes[qnode.nodeId];
if (qnode.sq < minDist)
@ -354,8 +363,8 @@ namespace vcg {
if (node.leaf)
{
--count; // pop
unsigned int end = node.start+node.size;
for (unsigned int i=node.start ; i<end ; ++i)
unsigned int end = node.start + node.size;
for (unsigned int i = node.start; i < end; ++i)
{
float pointSquareDist = vcg::SquaredNorm(queryPoint - mPoints[i]);
if (pointSquareDist < minDist)
@ -372,11 +381,11 @@ namespace vcg {
if (new_off < 0.)
{
mNodeStack[count].nodeId = node.firstChildId;
qnode.nodeId = node.firstChildId+1;
qnode.nodeId = node.firstChildId + 1;
}
else
{
mNodeStack[count].nodeId = node.firstChildId+1;
mNodeStack[count].nodeId = node.firstChildId + 1;
qnode.nodeId = node.firstChildId;
}
mNodeStack[count].sq = qnode.sq;
@ -404,8 +413,8 @@ namespace vcg {
template<typename Scalar>
unsigned int KdTree<Scalar>::split(int start, int end, unsigned int dim, float splitValue)
{
int l(start), r(end-1);
for ( ; l<r ; ++l, --r)
int l(start), r(end - 1);
for (; l < r; ++l, --r)
{
while (l < end && mPoints[l][dim] < splitValue)
l++;
@ -413,11 +422,11 @@ namespace vcg {
r--;
if (l > r)
break;
std::swap(mPoints[l],mPoints[r]);
std::swap(mIndices[l],mIndices[r]);
std::swap(mPoints[l], mPoints[r]);
std::swap(mIndices[l], mIndices[r]);
}
//returns the index of the first element on the second part
return (mPoints[l][dim] < splitValue ? l+1 : l);
return (mPoints[l][dim] < splitValue ? l + 1 : l);
}
/** recursively builds the kdtree
@ -438,7 +447,7 @@ namespace vcg {
* is more expensive than the gain it provides and the memory consumption is x4 higher !
*/
template<typename Scalar>
int KdTree<Scalar>::createTree(unsigned int nodeId, unsigned int start, unsigned int end, unsigned int level, unsigned int targetCellSize, unsigned int targetMaxDepth)
int KdTree<Scalar>::createTree(unsigned int nodeId, unsigned int start, unsigned int end, unsigned int level)
{
//select the first node
Node& node = mNodes[nodeId];
@ -446,7 +455,7 @@ namespace vcg {
//putting all the points in the bounding box
aabb.Set(mPoints[start]);
for (unsigned int i=start+1 ; i<end ; ++i)
for (unsigned int i = start + 1; i < end; ++i)
aabb.Add(mPoints[i]);
//bounding box diagonal
@ -460,22 +469,29 @@ namespace vcg {
dim = diag.Y() > diag.Z() ? 1 : 2;
node.dim = dim;
//we divide the bounding box in 2 partitions, considering the average of the "dim" dimension
if (isBalanced) //we divide the points using the median value along the "dim" dimension
{
std::vector<Scalar> tempVector;
for (unsigned int i = start + 1; i < end; ++i)
tempVector.push_back(mPoints[i][dim]);
std::sort(tempVector.begin(), tempVector.end());
node.splitValue = (tempVector[tempVector.size() / 2.0] + tempVector[tempVector.size() / 2.0 + 1]) / 2.0;
}
else //we divide the bounding box in 2 partitions, considering the average of the "dim" dimension
node.splitValue = Scalar(0.5*(aabb.max[dim] + aabb.min[dim]));
//midId is the index of the first element in the second partition
unsigned int midId = split(start, end, dim, node.splitValue);
node.firstChildId = mNodes.size();
mNodes.resize(mNodes.size()+2);
mNodes.resize(mNodes.size() + 2);
bool flag = (midId == start) || (midId == end);
int leftLevel, rightLevel;
{
// left child
unsigned int childId = mNodes[nodeId].firstChildId;
Node& child = mNodes[childId];
if (midId - start <= targetCellSize || level>=targetMaxDepth)
if (flag || (midId - start) <= targetCellSize || level >= targetMaxDepth)
{
child.leaf = 1;
child.start = start;
@ -485,15 +501,15 @@ namespace vcg {
else
{
child.leaf = 0;
leftLevel = createTree(childId, start, midId, level+1, targetCellSize, targetMaxDepth);
leftLevel = createTree(childId, start, midId, level + 1);
}
}
{
// right child
unsigned int childId = mNodes[nodeId].firstChildId+1;
unsigned int childId = mNodes[nodeId].firstChildId + 1;
Node& child = mNodes[childId];
if (end - midId <= targetCellSize || level>=targetMaxDepth)
if (flag || (end - midId) <= targetCellSize || level >= targetMaxDepth)
{
child.leaf = 1;
child.start = midId;
@ -503,13 +519,14 @@ namespace vcg {
else
{
child.leaf = 0;
rightLevel = createTree(childId, midId, end, level+1, targetCellSize, targetMaxDepth);
rightLevel = createTree(childId, midId, end, level + 1);
}
}
if (leftLevel > rightLevel)
return leftLevel;
return rightLevel;
}
}
#endif