Added methods GetClosest, GetInSphere and GetInBox.

Changed signature of Set method to comply with the SpatialIndex interface
This commit is contained in:
Paolo Cignoni 2006-09-28 22:49:15 +00:00
parent 739e46587e
commit 9cf176a0ff
2 changed files with 404 additions and 127 deletions

View File

@ -102,11 +102,11 @@ namespace vcg
template < class OBJECT_TYPE, class SCALAR_TYPE> template < class OBJECT_TYPE, class SCALAR_TYPE>
class Octree : public OctreeTemplate< Voxel >, public vcg::SpatialIndex< OBJECT_TYPE, SCALAR_TYPE > class Octree : public OctreeTemplate< Voxel, SCALAR_TYPE >, public vcg::SpatialIndex< OBJECT_TYPE, SCALAR_TYPE >
{ {
public: public:
typedef SCALAR_TYPE ScalarType;
typedef OBJECT_TYPE ObjectType; typedef OBJECT_TYPE ObjectType;
typedef vcg::Box3<ScalarType> BoundingBoxType;
typedef typename Octree::Leaf * LeafPointer; typedef typename Octree::Leaf * LeafPointer;
typedef typename Octree::InnerNode * InnerNodePointer; typedef typename Octree::InnerNode * InnerNodePointer;
typedef typename ReferenceType<OBJECT_TYPE>::Type * ObjectPointer; typedef typename ReferenceType<OBJECT_TYPE>::Type * ObjectPointer;
@ -178,10 +178,10 @@ namespace vcg
*/ */
struct ObjectReference struct ObjectReference
{ {
ObjectReference() {mark_position=-1; pObject=NULL;} ObjectReference() {pMark=NULL; pObject=NULL;}
int mark_position; unsigned char *pMark;
ObjectPointer pObject; ObjectPointer pObject;
}; };
/* /*
@ -195,7 +195,7 @@ namespace vcg
this->distance = -1.0f; this->distance = -1.0f;
}; };
Neighbour(ObjectPointer &object, CoordType &point, float distance) Neighbour(ObjectPointer &object, CoordType &point, ScalarType distance)
{ {
this->object = object; this->object = object;
this->point = point; this->point = point;
@ -205,7 +205,7 @@ namespace vcg
ObjectPointer object; ObjectPointer object;
CoordType point; CoordType point;
float distance; ScalarType distance;
}; };
/* /*
@ -232,17 +232,25 @@ public:
/*! /*!
* Populate the octree * Populate the octree
*/ */
template <class OBJECT_ITERATOR, class BOUNDING_BOX_FUNCTOR> template <class OBJECT_ITERATOR/*, class BOUNDING_BOX_FUNCTOR*/>
void Set(const OBJECT_ITERATOR & bObj, const OBJECT_ITERATOR & eObj, const BoundingBoxType &bounding_box, const BOUNDING_BOX_FUNCTOR &bb_functor/*, vcg::CallBackPos *callback=NULL*/) void Set(const OBJECT_ITERATOR & bObj, const OBJECT_ITERATOR & eObj /*, const BoundingBoxType &bounding_box*/ /*, const BOUNDING_BOX_FUNCTOR &bb_functor*/ /*, vcg::CallBackPos *callback=NULL*/)
{ {
typedef Dereferencer<typename ReferenceType<typename OBJECT_ITERATOR::value_type>::Type > DereferencerType;
// Compute the bounding-box enclosing the whole dataset // Compute the bounding-box enclosing the whole dataset
typedef Dereferencer<typename ReferenceType<typename OBJECT_ITERATOR::value_type>::Type > DereferencerType;
BoundingBoxType bounding_box, obj_bb;
bounding_box.SetNull();
for (OBJECT_ITERATOR iObj=bObj; iObj!=eObj; iObj++)
{
(*iObj).GetBBox(obj_bb);
bounding_box.Add(obj_bb);
}
//...and expand it a bit more
BoundingBoxType resulting_bb(bounding_box); BoundingBoxType resulting_bb(bounding_box);
CoordType offset = bounding_box.Dim()*Octree::EXPANSION_FACTOR; CoordType offset = bounding_box.Dim()*Octree::EXPANSION_FACTOR;
CoordType center = bounding_box.Center(); CoordType center = bounding_box.Center();
resulting_bb.Offset(offset); resulting_bb.Offset(offset);
float longest_side = vcg::math::Max( resulting_bb.DimX(), vcg::math::Max(resulting_bb.DimY(), resulting_bb.DimZ()) )/2.0f; ScalarType longest_side = vcg::math::Max( resulting_bb.DimX(), vcg::math::Max(resulting_bb.DimY(), resulting_bb.DimZ()) )/2.0f;
resulting_bb.Set(center); resulting_bb.Set(center);
resulting_bb.Offset(longest_side); resulting_bb.Offset(longest_side);
boundingBox = resulting_bb; boundingBox = resulting_bb;
@ -250,11 +258,6 @@ public:
// Try to find a reasonable octree depth // Try to find a reasonable octree depth
int dataset_dimension = std::distance(bObj, eObj); int dataset_dimension = std::distance(bObj, eObj);
// Allocate the mark array
global_mark = 1;
marks = new unsigned char[dataset_dimension];
memset(&marks[0], 0, sizeof(unsigned char)*dataset_dimension);
int primitives_per_voxel; int primitives_per_voxel;
int depth = 4; int depth = 4;
do do
@ -265,7 +268,7 @@ public:
depth++; depth++;
} }
while (primitives_per_voxel>25 && depth<15); while (primitives_per_voxel>25 && depth<15);
Initialize(depth); Initialize(++depth);
// Sort the dataset (using the lebesgue space filling curve...) // Sort the dataset (using the lebesgue space filling curve...)
std::string message("Indexing dataset..."); std::string message("Indexing dataset...");
@ -279,7 +282,7 @@ public:
vcg::Point3<ScalarType> hit_leaf; vcg::Point3<ScalarType> hit_leaf;
for (int i=0; i<dataset_dimension; i++, iObj++) for (int i=0; i<dataset_dimension; i++, iObj++)
{ {
object_bb = bb_functor(*iObj); (*iObj).GetBBox(object_bb);
hit_leaf = object_bb.min; hit_leaf = object_bb.min;
while (object_bb.IsIn(hit_leaf)) while (object_bb.IsIn(hit_leaf))
@ -306,15 +309,21 @@ public:
delete []route; delete []route;
int placeholder_count = int(placeholders.size()); int placeholder_count = int(placeholders.size());
// Allocate the mark array
global_mark = 1;
marks = new unsigned char[placeholder_count];
memset(&marks[0], 0, sizeof(unsigned char)*placeholder_count);
std::sort(placeholders.begin(), placeholders.end(), ObjectSorter< Octree::Node >()); std::sort(placeholders.begin(), placeholders.end(), ObjectSorter< Octree::Node >());
std::vector< Octree::Node* > filled_leaves(placeholder_count); std::vector< Octree::Node* > filled_leaves(placeholder_count);
sorted_dataset.resize( dataset_dimension ); sorted_dataset.resize( placeholder_count );
for (int i=0; i<placeholder_count; i++) for (int i=0; i<placeholder_count; i++)
{ {
std::advance((iObj=bObj), placeholders[i].object_index); std::advance((iObj=bObj), placeholders[i].object_index);
sorted_dataset[i].pObject = &DereferencerType::Ref(*iObj); sorted_dataset[i].pObject = &DereferencerType::Ref(*iObj);
sorted_dataset[i].mark_position = i; sorted_dataset[i].pMark = &marks[i];
filled_leaves[i] = placeholders[i].leaf_pointer; filled_leaves[i] = placeholders[i].leaf_pointer;
} }
// The dataset is sorted and the octree is built, but the indexing information aren't stored yet in the octree: // The dataset is sorted and the octree is built, but the indexing information aren't stored yet in the octree:
@ -337,43 +346,116 @@ public:
IndexInnerNodes( Root() ); IndexInnerNodes( Root() );
} //end of Set } //end of Set
/*!
* Finds the closest object to a given point.
*/
template <class OBJECT_POINT_DISTANCE_FUNCTOR, class OBJECT_MARKER>
ObjectPointer GetClosest
(
OBJECT_POINT_DISTANCE_FUNCTOR & distance_functor,
OBJECT_MARKER & /*marker*/,
const CoordType & query_point,
const ScalarType & max_distance,
ScalarType & distance,
CoordType & point,
bool allow_zero_distance = false
)
{
BoundingBoxType query_bb;
ScalarType sphere_radius;
if (!GuessInitialBoundingBox(query_point, max_distance, sphere_radius, query_bb))
return NULL;
std::vector< NodePointer > leaves;
unsigned int object_count;
int leaves_count;
ScalarType k_distance = leafDiagonal;
IncrementMark();
do
{
leaves.clear();
object_count = 0;
query_bb.Offset(k_distance);
sphere_radius += vcg::math::Max<ScalarType>(leafDiagonal, k_distance);
ContainedLeaves(query_bb, leaves, Root(), boundingBox);
leaves_count = int(leaves.size());
object_count = 0;
for (int i=0; i<leaves_count; i++)
object_count += Voxel( leaves[i] )->count;
}
while (object_count==0 && sphere_radius<max_distance);
if (sphere_radius>max_distance)
return NULL;
CoordType closest_point;
VoxelType *voxel;
ObjectReference *ref;
int begin;
int end;
ScalarType dist;
std::vector< Neighbour > neighbors;
object_count = 0;
for (int i=0; i<leaves_count; i++)
{
voxel = Voxel(leaves[i]);
begin = voxel->begin;
end = voxel->end;
for ( ; begin<end; begin++)
{
ref = &sorted_dataset[begin];
if (IsMarked(ref))
continue;
dist = max_distance;
if (!distance_functor(*ref->pObject, query_point, dist, closest_point))
continue;
Mark(ref);
if (dist!=ScalarType(0.0) || allow_zero_distance)
neighbors.push_back( Neighbour(ref->pObject, closest_point, dist) );
} //end of for ( ; begin<end; begin++)
} // end of for (int i=0; i<leavesCount; i++)
object_count = int(neighbors.size());
std::vector< Neighbour >::iterator first = neighbors.begin();
std::vector< Neighbour >::iterator last = neighbors.end();
std::partial_sort(first, first+object_count, last, DistanceCompare());
distance = neighbors[0].distance;
point = neighbors[0].point;
return neighbors[0].object;
}; //end of GetClosest
/*! /*!
* Retrive the k closest element to the query point * Retrive the k closest element to the query point
*/ */
template <class OBJECT_POINT_DISTANCE_FUNCTOR, class OBJECT_MARKER, class OBJECT_POINTER_CONTAINER, class DISTANCE_CONTAINER, class POINT_POINTER_CONTAINER> template <class OBJECT_POINT_DISTANCE_FUNCTOR, class OBJECT_MARKER, class OBJECT_POINTER_CONTAINER, class DISTANCE_CONTAINER, class POINT_CONTAINER>
unsigned int GetKClosest unsigned int GetKClosest
( (
OBJECT_POINT_DISTANCE_FUNCTOR &distance_functor, OBJECT_POINT_DISTANCE_FUNCTOR & distance_functor,
OBJECT_MARKER &/*marker*/, OBJECT_MARKER & /*marker*/,
const unsigned int k, const unsigned int k,
const CoordType &query_point, const CoordType & query_point,
const ScalarType &max_distance, const ScalarType & max_distance,
OBJECT_POINTER_CONTAINER &objects, OBJECT_POINTER_CONTAINER & objects,
DISTANCE_CONTAINER &distances, DISTANCE_CONTAINER & distances,
POINT_POINTER_CONTAINER &points, POINT_CONTAINER & points,
bool sort_per_distance = false, bool sort_per_distance = false,
bool allow_zero_distance = false bool allow_zero_distance = false
) )
{ {
// costruisco una bounging box centrata in query di dimensione pari a quella di una foglia.
// e controllo se in tale bounging box sono contenute un numero di elementi >= a k.
// Altrimenti espando il bounding box.
BoundingBoxType query_bb; BoundingBoxType query_bb;
query_bb.Set(query_point); ScalarType sphere_radius;
if (!GuessInitialBoundingBox(query_point, max_distance, sphere_radius, query_bb))
// Il raggio della sfera centrata nel punto query return 0;
float sphere_radius = 0.0f;
// se il bounding-box non interseca il bounding-box dell'octree, lo espando subito
if (!query_bb.IsIn(query_point))
{
do
{
query_bb.Offset(leafDiagonal);
sphere_radius += leafDiagonal;
}
while ( !boundingBox.Collide(query_bb) || sphere_radius>max_distance); // TODO check the termination condintion
}
std::vector< NodePointer > leaves; std::vector< NodePointer > leaves;
std::vector< Neighbour > neighbors; std::vector< Neighbour > neighbors;
@ -383,13 +465,7 @@ public:
float k_distance = leafDiagonal; float k_distance = leafDiagonal;
do do
{ {
// update the marks IncrementMark();
global_mark = (global_mark+1)%255;
if (global_mark == 0)
{
memset(&marks[0], 0, sizeof(unsigned char)*int(sorted_dataset.size()));
global_mark++;
}
do do
{ {
@ -405,7 +481,7 @@ public:
for (int i=0; i<leaves_count; i++) for (int i=0; i<leaves_count; i++)
object_count += Voxel( leaves[i] )->count; object_count += Voxel( leaves[i] )->count;
} }
while (object_count<k && sphere_radius>max_distance); // TODO check the termination condintion while (object_count<k && sphere_radius<max_distance); // TODO check the termination condintion
// i punti contenuti nelle foglie sono sufficienti. // i punti contenuti nelle foglie sono sufficienti.
// seleziono solamente i k punti più vicini. // seleziono solamente i k punti più vicini.
@ -417,6 +493,7 @@ public:
float distance; float distance;
neighbors.clear(); neighbors.clear();
object_count = 0;
for (int i=0; i<leaves_count; i++) for (int i=0; i<leaves_count; i++)
{ {
voxel = Voxel(leaves[i]); voxel = Voxel(leaves[i]);
@ -425,23 +502,23 @@ public:
for ( ; begin<end; begin++) for ( ; begin<end; begin++)
{ {
ref = &sorted_dataset[begin]; ref = &sorted_dataset[begin];
if (marks[ref->mark_position]==global_mark) if (IsMarked(ref))
continue; continue;
distance = max_distance; distance = max_distance;
if (!distance_functor(*ref->pObject, query_point, distance, closest_point)) if (!distance_functor(*ref->pObject, query_point, distance, closest_point))
continue; continue;
marks[ref->mark_position]=global_mark; Mark(ref);
if ((distance!=0.0f || allow_zero_distance)/* && distance<max_distance*/) if ((distance!=0.0f || allow_zero_distance))
neighbors.push_back( Neighbour(ref->pObject, closest_point, distance) ); neighbors.push_back( Neighbour(ref->pObject, closest_point, distance) );
} //end of for ( ; begin<end; begin++) } //end of for ( ; begin<end; begin++)
} // end of for (int i=0; i<leavesCount; i++) } // end of for (int i=0; i<leavesCount; i++)
object_count = int(neighbors.size());
if (sphere_radius<max_distance) if (sphere_radius<max_distance)
{ {
if (int(neighbors.size())<k) if (object_count<k)
{ {
k_distance = 2.0f*sphere_radius; k_distance = 2.0f*sphere_radius;
continue; continue;
@ -461,28 +538,142 @@ public:
} }
while (k_distance>sphere_radius && sphere_radius<max_distance); while (k_distance>sphere_radius && sphere_radius<max_distance);
// copy the nearest object into return CopyQueryResults<OBJECT_POINTER_CONTAINER, DISTANCE_CONTAINER, POINT_CONTAINER>(neighbors, object_count, objects, distances, points);
if (points.size()!=object_count)
{
points.resize(object_count);
distances.resize(object_count);
objects.resize(object_count);
}
POINT_POINTER_CONTAINER::iterator iPoint = points.begin();
DISTANCE_CONTAINER::iterator iDistance = distances.begin();
OBJECT_POINTER_CONTAINER::iterator iObject = objects.begin();
for (unsigned int n=0; n<object_count; n++, iPoint++, iDistance++, iObject++)
{
(*iPoint) = neighbors[n].point;
(*iDistance) = neighbors[n].distance;
(*iObject) = neighbors[n].object;
}
return object_count;
}; //end of GetKClosest }; //end of GetKClosest
/*! /*!
* Returns all the objects contained inside a specified sphere
*/
template <class OBJECT_POINT_DISTANCE_FUNCTOR, class OBJECT_MARKER, class OBJECT_POINTER_CONTAINER, class DISTANCE_CONTAINER, class POINT_CONTAINER>
unsigned int GetInSphere
(
OBJECT_POINT_DISTANCE_FUNCTOR &distance_functor,
OBJECT_MARKER &/*marker*/,
const CoordType &sphere_center,
const ScalarType &sphere_radius,
OBJECT_POINTER_CONTAINER &objects,
DISTANCE_CONTAINER &distances,
POINT_CONTAINER &points,
bool sort_per_distance = false,
bool allow_zero_distance = false
)
{
// Define the minimum bounding-box containing the sphere
BoundingBoxType query_bb(sphere_center, sphere_radius);
// If that bounding-box don't collide with the octree bounding-box, simply return 0
if (!boundingBox.Collide(query_bb))
return 0;
std::vector< NodePointer > leaves;
std::vector< Neighbour > neighbors;
unsigned int object_count = 0;
float k_distance = leafDiagonal;
IncrementMark();
ContainedLeaves(query_bb, leaves, Root(), boundingBox);
int leaves_countleaves_count = int(leaves.size());
if (leaves_count==0)
return 0;
CoordType closest_point;
VoxelType *voxel;
ObjectReference *ref;
int begin;
int end;
float distance;
for (int i=0; i<leaves_count; i++)
{
voxel = Voxel(leaves[i]);
begin = voxel->begin;
end = voxel->end;
for ( ; begin<end; begin++)
{
ref = &sorted_dataset[begin];
if (IsMarked(ref))
continue;
distance = sphere_radius;
if (!distance_functor(*ref->pObject, query_point, distance, closest_point))
continue;
object_count++;
Mark(ref);
if ((distance!=0.0f || allow_zero_distance) && distance<max_distance)
neighbors.push_back( Neighbour(ref->pObject, closest_point, distance) );
} //end of for ( ; begin<end; begin++)
} // end of for (int i=0; i<leavesCount; i++)
std::vector< Neighbour >::iterator first = neighbors.begin();
std::vector< Neighbour >::iterator last = neighbors.end();
if (sort_per_distance) std::partial_sort(first, first+object_count, last, DistanceCompare());
else std::nth_element (first, first+object_count, last, DistanceCompare());
return CopyQueryResults<OBJECT_POINTER_CONTAINER, DISTANCE_CONTAINER, POINT_CONTAINER>(neighbors, object_count, objects, distances, points);
};//end of GetInSphere
/*!
* Returns all the objects lying inside the specified bbox
*/
template <class OBJECT_MARKER, class OBJECT_POINTER_CONTAINER>
unsigned int GetInBox
(
OBJECT_MARKER &/*marker*/,
const BoundingBoxType &query_bounding_box,
OBJECT_POINTER_CONTAINER &objects
)
{
//if the query bounding-box don't collide with the octree bounding-box, simply return 0
if (!query_bounding_box.Collide())
{
objects.clear();
return 0;
}
//otherwise, retrieve the leaves and fill the container with the objects contained
std::vector< NodePointer > leaves;
unsigned int object_count;
int leaves_count;
ContainedLeaves(query_bounding_box, leaves, Root(), boundingBox);
leaves_count = int(leaves.size());
if (leaves_count==0)
{
objects.clear();
return 0;
}
IncrementMark();
VoxelType *voxel;
ObjectReference *ref;
int begin;
int end;
object_count = 0;
for (int i=0; i<leaves_count; i++)
{
voxel = Voxel(leaves[i]);
begin = voxel->begin;
end = voxel->end;
for ( ; begin<end; begin++)
{
ref = &sorted_dataset[begin];
if (IsMarked(ref))
continue;
object_count++;
Mark(ref);
objects.push_back(ref->pObject);
} //end of for ( ; begin<end; begin++)
} // end of for (int i=0; i<leavesCount; i++)
return int(objects.size());
}; //end of GetInBox
/*
* Draw the octree in a valid OpenGL context according to the rendering settings * Draw the octree in a valid OpenGL context according to the rendering settings
*/ */
void Octree::DrawOctree(vcg::Box3f &boundingBox, NodePointer n) void Octree::DrawOctree(vcg::Box3f &boundingBox, NodePointer n)
@ -522,6 +713,89 @@ public:
OcreeRenderingSetting rendering_settings; OcreeRenderingSetting rendering_settings;
protected: protected:
/*!
*/
inline void IncrementMark()
{
// update the marks
global_mark = (global_mark+1)%255;
if (global_mark == 0)
{
memset(&marks[0], 0, sizeof(unsigned char)*int(sorted_dataset.size()));
global_mark++;
}
};//end of IncrementMark
/*
*/
inline bool IsMarked(const ObjectReference *ref) const
{ return *ref->pMark == global_mark; };
/*
*/
inline void Mark(const ObjectReference *ref)
{ *ref->pMark = global_mark;};
/*!
* Guess an initial bounding-box from which starting the research of the closest point(s).
* \return true iff it's possibile to find a sphere, centered in query_point and having radius max_distance at most, which collide the octree bounding-box.
*/
inline bool GuessInitialBoundingBox(const CoordType &query_point, const ScalarType max_distance, ScalarType &sphere_radius, BoundingBoxType &query_bb)
{
// costruisco una bounging box centrata in query di dimensione pari a quella di una foglia.
// e controllo se in tale bounging box sono contenute un numero di elementi >= a k.
// Altrimenti espando il bounding box.
query_bb.Set(query_point);
// Il raggio della sfera centrata nel punto query
sphere_radius = 0.0f;
// se il bounding-box non interseca il bounding-box dell'octree, lo espando subito
if (!query_bb.IsIn(query_point))
{
do
{
query_bb.Offset(leafDiagonal);
sphere_radius += leafDiagonal;
}
while ( !boundingBox.Collide(query_bb) || sphere_radius>max_distance); // TODO check the termination condintion
}
return (sphere_radius<=max_distance);
};
/*!
* Copy the results of a query
*/
template <class OBJECT_POINTER_CONTAINER, class DISTANCE_CONTAINER, class POINT_CONTAINER>
inline int CopyQueryResults
(
std::vector< Neighbour > &neighbors,
const unsigned int object_count,
OBJECT_POINTER_CONTAINER &objects,
DISTANCE_CONTAINER &distances,
POINT_CONTAINER &points
)
{
// copy the nearest object into
if (int(points.size())!=object_count)
{
points.resize(object_count);
distances.resize(object_count);
objects.resize(object_count);
}
POINT_CONTAINER::iterator iPoint = points.begin();
DISTANCE_CONTAINER::iterator iDistance = distances.begin();
OBJECT_POINTER_CONTAINER::iterator iObject = objects.begin();
for (unsigned int n=0; n<object_count; n++, iPoint++, iDistance++, iObject++)
{
(*iPoint) = neighbors[n].point;
(*iDistance) = neighbors[n].distance;
(*iObject) = neighbors[n].object;
}
return object_count;
}
/*! /*!
* When all the leaves are indexed, this procedure is called in order to propagate the indexing information to the inner nodes * When all the leaves are indexed, this procedure is called in order to propagate the indexing information to the inner nodes
*/ */

View File

@ -48,7 +48,7 @@ Si tiene int invece di puntatori per garantirsi reallocazione dinamica.
I dati veri e propri stanno in un vettore di nodi I dati veri e propri stanno in un vettore di nodi
*/ */
template <typename VOXEL_TYPE> template <typename VOXEL_TYPE, class SCALAR_TYPE>
class OctreeTemplate class OctreeTemplate
{ {
protected: protected:
@ -56,12 +56,15 @@ protected:
public: public:
// Octree Type Definitions // Octree Type Definitions
typedef typename VOXEL_TYPE VoxelType; typedef SCALAR_TYPE ScalarType;
typedef typename VOXEL_TYPE *VoxelPointer; typedef typename VOXEL_TYPE VoxelType;
typedef vcg::Point3i CenterType; typedef typename VOXEL_TYPE *VoxelPointer;
static const float EXPANSION_FACTOR; typedef vcg::Point3i CenterType;
typedef int NodeIndex; static const ScalarType EXPANSION_FACTOR;
typedef Node *NodePointer; typedef int NodeIndex;
typedef Node *NodePointer;
typedef vcg::Box3<ScalarType> BoundingBoxType;
typedef vcg::Point3<ScalarType> CoordinateType;
protected: protected:
/* /*
@ -154,14 +157,14 @@ public:
nodes.push_back( root ); nodes.push_back( root );
root->center = CenterType(size, size, size); root->center = CenterType(size, size, size);
float szf = (float) size; ScalarType szf = (ScalarType) size;
leafDimension = boundingBox.Dim(); leafDimension = boundingBox.Dim();
leafDimension /= szf; leafDimension /= szf;
leafDiagonal = leafDimension.Norm(); leafDiagonal = leafDimension.Norm();
}; };
// Return the octree bounding-box // Return the octree bounding-box
inline vcg::Box3f BoundingBox() { return boundingBox; } inline BoundingBoxType BoundingBox() { return boundingBox; }
// Return the Voxel of the n-th node // Return the Voxel of the n-th node
inline VoxelPointer Voxel(const NodePointer n) { return &(n->voxel); } inline VoxelPointer Voxel(const NodePointer n) { return &(n->voxel); }
@ -199,15 +202,15 @@ public:
inline CenterType CenterInOctreeCoordinates(const NodePointer n) const { return n->center;} inline CenterType CenterInOctreeCoordinates(const NodePointer n) const { return n->center;}
// Return the center of the n-th node expressed in world-coordinate // Return the center of the n-th node expressed in world-coordinate
inline vcg::Point3f CenterInWorldCoordinates(const NodePointer n) const inline CoordinateType CenterInWorldCoordinates(const NodePointer n) const
{ {
assert(0<=n && n<NodeCount()); assert(0<=n && n<NodeCount());
int level = n->level; int level = n->level;
int shift = maxDepth-level+1; int shift = maxDepth-level+1;
vcg::Point3f wcCenter; CoordinateType wcCenter;
vcg::Point3f ocCenter = CenterInOctreeCoordinates(n); CoordinateType ocCenter = CenterInOctreeCoordinates(n);
vcg::Point3f nodeSize = boundingBox.Dim()/float(1<<level); CoordinateType nodeSize = boundingBox.Dim()/float(1<<level);
wcCenter.X() = boundingBox.min.X() + (nodeSize.X()*(0.5f+(ocCenter.X()>>shift))); wcCenter.X() = boundingBox.min.X() + (nodeSize.X()*(0.5f+(ocCenter.X()>>shift)));
wcCenter.Y() = boundingBox.min.Y() + (nodeSize.Y()*(0.5f+(ocCenter.Y()>>shift))); wcCenter.Y() = boundingBox.min.Y() + (nodeSize.Y()*(0.5f+(ocCenter.Y()>>shift)));
wcCenter.Z() = boundingBox.min.Z() + (nodeSize.Z()*(0.5f+(ocCenter.Z()>>shift))); wcCenter.Z() = boundingBox.min.Z() + (nodeSize.Z()*(0.5f+(ocCenter.Z()>>shift)));
@ -264,9 +267,9 @@ public:
The center of each cell can simply be obtained by adding .5 to the path of the leaves. The center of each cell can simply be obtained by adding .5 to the path of the leaves.
*/ */
vcg::Point3f Center(NodePointer n) const CoordinateType Center(NodePointer n) const
{ {
vcg::Point3f center; CoordinateType center;
center.Import(GetPath(n)); center.Import(GetPath(n));
center+=Point3f(.5f,.5f,.5f); center+=Point3f(.5f,.5f,.5f);
@ -277,15 +280,15 @@ public:
} }
// Return the bounding-box of the n-th node expressed in world-coordinate // Return the bounding-box of the n-th node expressed in world-coordinate
vcg::Box3f BoundingBoxInWorldCoordinates(const NodePointer n) BoundingBoxType BoundingBoxInWorldCoordinates(const NodePointer n)
{ {
assert(0<=n && n<Size()); assert(0<=n && n<Size());
char level = Level(n); char level = Level(n);
int shift = maximumDepth-level+1; int shift = maximumDepth-level+1;
vcg::Point3f nodeDim = boundingBox.Dim()/float(1<<level); CoordinateType nodeDim = boundingBox.Dim()/float(1<<level);
CenterType center = CenterInOctreeCoordinates(n); CenterType center = CenterInOctreeCoordinates(n);
vcg::Box3f nodeBB; BoundingBoxType nodeBB;
nodeBB.min.X() = boundingBox.min.X() + (nodeDim.X()*(center.X()>>shift)); nodeBB.min.X() = boundingBox.min.X() + (nodeDim.X()*(center.X()>>shift));
nodeBB.min.Y() = boundingBox.min.Y() + (nodeDim.Y()*(center.Y()>>shift)); nodeBB.min.Y() = boundingBox.min.Y() + (nodeDim.Y()*(center.Y()>>shift));
nodeBB.min.Z() = boundingBox.min.Z() + (nodeDim.Z()*(center.Z()>>shift)); nodeBB.min.Z() = boundingBox.min.Z() + (nodeDim.Z()*(center.Z()>>shift));
@ -294,9 +297,9 @@ public:
}; };
// Return one of the 8 subb box of a given box. // Return one of the 8 subb box of a given box.
vcg::Box3f SubBox(vcg::Box3f &lbb, int i) BoundingBoxType SubBox(BoundingBoxType &lbb, int i)
{ {
vcg::Box3f bs; BoundingBoxType bs;
if (i&1) bs.min.X()=(lbb.min.X()+(bs.max.X()=lbb.max.X()))/2.0f; if (i&1) bs.min.X()=(lbb.min.X()+(bs.max.X()=lbb.max.X()))/2.0f;
else bs.max.X()=((bs.min.X()=lbb.min.X())+lbb.max.X())/2.0f; else bs.max.X()=((bs.min.X()=lbb.min.X())+lbb.max.X())/2.0f;
if (i&2) bs.min.Y()=(lbb.min.Y()+(bs.max.Y()=lbb.max.Y()))/2.0f; if (i&2) bs.min.Y()=(lbb.min.Y()+(bs.max.Y()=lbb.max.Y()))/2.0f;
@ -309,9 +312,9 @@ public:
// Given the bounding-box and the center (both in world-coordinates) // Given the bounding-box and the center (both in world-coordinates)
// of a node, return the bounding-box (in world-coordinats) of the i-th son // of a node, return the bounding-box (in world-coordinats) of the i-th son
vcg::Box3f SubBoxAndCenterInWorldCoordinates(vcg::Box3f &lbb, vcg::Point3f &center, int i) BoundingBoxType SubBoxAndCenterInWorldCoordinates(BoundingBoxType &lbb, CoordinateType &center, int i)
{ {
vcg::Box3f bs; BoundingBoxType bs;
if (i&1) if (i&1)
{ {
bs.min[0]=center[0]; bs.min[0]=center[0];
@ -407,9 +410,9 @@ public:
// Convert the point p coordinates to the integer based representation // Convert the point p coordinates to the integer based representation
// in the range 0..size, where size is 2^maxdepth // in the range 0..size, where size is 2^maxdepth
vcg::Point3i Interize(const vcg::Point3f &pf) const CenterType Interize(const CoordinateType &pf) const
{ {
vcg::Point3i pi; CenterType pi;
assert(pf.X()>=boundingBox.min.X() && pf.X()<=boundingBox.max.X()); assert(pf.X()>=boundingBox.min.X() && pf.X()<=boundingBox.max.X());
assert(pf.Y()>=boundingBox.min.Y() && pf.Y()<=boundingBox.max.Y()); assert(pf.Y()>=boundingBox.min.Y() && pf.Y()<=boundingBox.max.Y());
@ -424,9 +427,9 @@ public:
// Inverse function of Interize; // Inverse function of Interize;
// Return to the original coords space (not to the original values!!) // Return to the original coords space (not to the original values!!)
vcg::Point3f DeInterize(const vcg::Point3i &pi ) const CoordinateType DeInterize(const CenterType &pi ) const
{ {
vcg::Point3f pf; CoordinateType pf;
assert(pi.X()>=0 && pi.X()<size); assert(pi.X()>=0 && pi.X()<size);
assert(pi.Y()>=0 && pi.Y()<size); assert(pi.Y()>=0 && pi.Y()<size);
@ -525,7 +528,7 @@ public:
// I nodi mancanti dalla radice fino a profondità maxDepth vengono aggiunti. // I nodi mancanti dalla radice fino a profondità maxDepth vengono aggiunti.
// In posizione i ci sarà il nodo di livello i. // In posizione i ci sarà il nodo di livello i.
// Restituisce lo z-order del punto p // Restituisce lo z-order del punto p
unsigned long long BuildRoute(const vcg::Point3f &p, NodePointer *&route) unsigned long long BuildRoute(const CoordinateType &p, NodePointer *&route)
{ {
assert( boundingBox.min.X()<=p.X() && p.X()<=boundingBox.max.X() ); assert( boundingBox.min.X()<=p.X() && p.X()<=boundingBox.max.X() );
assert( boundingBox.min.Y()<=p.Y() && p.Y()<=boundingBox.max.Y() ); assert( boundingBox.min.Y()<=p.Y() && p.Y()<=boundingBox.max.Y() );
@ -568,7 +571,7 @@ public:
// fino al nodo di profontidà massima presente; nelle eventuali posizioni rimaste // fino al nodo di profontidà massima presente; nelle eventuali posizioni rimaste
// libere è inserito il valore -1. Restituisce true se il punto p cade in una foglia // libere è inserito il valore -1. Restituisce true se il punto p cade in una foglia
// dell'otree, false altrimenti // dell'otree, false altrimenti
bool GetRoute(const vcg::Point3f &p, NodePointer *&route) bool GetRoute(const CoordinateType &p, NodePointer *&route)
{ {
assert( boundingBox.min.X()<=p.X() && p.X()<=boundingBox.max.X() ); assert( boundingBox.min.X()<=p.X() && p.X()<=boundingBox.max.X() );
assert( boundingBox.min.Y()<=p.Y() && p.Y()<=boundingBox.max.Y() ); assert( boundingBox.min.Y()<=p.Y() && p.Y()<=boundingBox.max.Y() );
@ -606,12 +609,13 @@ public:
// bb (la bounding-box dell'octree); i puntatori a tali nodi sono // bb (la bounding-box dell'octree); i puntatori a tali nodi sono
// inseriti progressivamente in contained_nodes. // inseriti progressivamente in contained_nodes.
// The vector nodes must be cleared before calling this method. // The vector nodes must be cleared before calling this method.
void ContainedNodes( void ContainedNodes
vcg::Box3f &query, (
BoundingBoxType &query,
std::vector< NodePointer > &nodes, std::vector< NodePointer > &nodes,
int depth, int depth,
NodePointer n, NodePointer n,
vcg::Box3f &nodeBB) BoundingBoxType &nodeBB)
{ {
if (!query.Collide(nodeBB)) if (!query.Collide(nodeBB))
return; return;
@ -621,8 +625,8 @@ public:
else else
{ {
NodePointer son; NodePointer son;
vcg::Box3f sonBB; BoundingBoxType sonBB;
vcg::Point3f nodeCenter = nodeBB.Center(); CoordinateType nodeCenter = nodeBB.Center();
for (int s=0; s<8; s++) for (int s=0; s<8; s++)
{ {
son = Son(n, s); son = Son(n, s);
@ -640,15 +644,15 @@ public:
// bounding-box ha intersezione non nulla con bb; i loro indici // bounding-box ha intersezione non nulla con bb; i loro indici
// sono inseriti all'interno di leaves. // sono inseriti all'interno di leaves.
void ContainedLeaves( void ContainedLeaves(
vcg::Box3f &query, BoundingBoxType &query,
std::vector< NodePointer > &leaves, std::vector< NodePointer > &leaves,
NodePointer node, NodePointer node,
vcg::Box3f &nodeBB BoundingBoxType &nodeBB
) )
{ {
NodePointer son; NodePointer son;
vcg::Box3f sonBB; BoundingBoxType sonBB;
vcg::Point3f nodeCenter = nodeBB.Center(); CoordinateType nodeCenter = nodeBB.Center();
for (int s=0; s<8; s++) for (int s=0; s<8; s++)
{ {
son = Son(node, s); //nodes[nodeIndex].sonIndex[s] son = Son(node, s); //nodes[nodeIndex].sonIndex[s]
@ -681,21 +685,20 @@ public:
int maximumDepth; int maximumDepth;
// The dimension of a leaf // The dimension of a leaf
vcg::Point3f leafDimension; CoordinateType leafDimension;
// The diagonal of a leaf // The diagonal of a leaf
float leafDiagonal; ScalarType leafDiagonal;
// The Octree nodes // The Octree nodes
std::vector< Node* > nodes; std::vector< Node* > nodes;
// The bounding box containing the octree (in world coordinate) // The bounding box containing the octree (in world coordinate)
vcg::Box3f boundingBox; BoundingBoxType boundingBox;
}; //end of class OctreeTemplate }; //end of class OctreeTemplate
template <typename VOXEL_TYPE> template <typename VOXEL_TYPE, class SCALAR_TYPE>
const float OctreeTemplate<VOXEL_TYPE>::EXPANSION_FACTOR = 0.035f; const SCALAR_TYPE OctreeTemplate<VOXEL_TYPE, SCALAR_TYPE>::EXPANSION_FACTOR = SCALAR_TYPE(0.035);
} }
#endif //OCTREETEMPLATE_H #endif //OCTREETEMPLATE_H