You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
788 lines
30 KiB
788 lines
30 KiB
/**************************************************************************** |
|
* VCGLib o o * |
|
* Visual and Computer Graphics Library o o * |
|
* _ O _ * |
|
* Copyright(C) 2004-2016 \/)\/ * |
|
* 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. * |
|
* * |
|
****************************************************************************/ |
|
|
|
#ifndef VCG_SPACE_INDEX_OCTREE_H |
|
#define VCG_SPACE_INDEX_OCTREE_H |
|
|
|
#include <stdlib.h> |
|
#include <vector> |
|
|
|
#ifdef __glut_h__ |
|
#include <vcg/space/color4.h> |
|
#include <wrap/gl/space.h> |
|
#endif |
|
|
|
#include <vcg/space/index/base.h> |
|
#include <vcg/space/index/octree_template.h> |
|
#include <vcg/space/box3.h> |
|
|
|
namespace vcg |
|
{ |
|
/*! |
|
* Given an object or an object pointer, return the reference to the object |
|
*/ |
|
template <typename TYPE> |
|
struct Dereferencer |
|
{ |
|
static TYPE& Ref(TYPE &t) { return ( t); } |
|
static TYPE& Ref(TYPE* &t) { return (*t); } |
|
static const TYPE& Ref(const TYPE &t) { return ( t); } |
|
static const TYPE& Ref(const TYPE* &t) { return (*t); } |
|
}; |
|
|
|
|
|
/*! |
|
* Given a type, return the type |
|
*/ |
|
template <typename T> |
|
class ReferenceType |
|
{ |
|
public: |
|
typedef T Type; |
|
}; |
|
|
|
|
|
/*! |
|
* Given as type a pointer to type, return the type |
|
*/ |
|
template <typename T> |
|
class ReferenceType<T *> |
|
{ |
|
public: |
|
typedef typename ReferenceType<T>::Type Type; |
|
}; |
|
|
|
|
|
|
|
/*! |
|
* The type of the octree voxels |
|
*/ |
|
struct Voxel |
|
{ |
|
Voxel() { count = begin = end = -1; } |
|
|
|
void SetRange(const int begin, const int end) |
|
{ |
|
this->begin = begin; |
|
this->end = end; |
|
count = end-begin; |
|
}; |
|
|
|
void AddRange(const Voxel *voxel) |
|
{ |
|
assert(voxel->end>end); |
|
|
|
count += voxel->count; |
|
end = voxel->end; |
|
}; |
|
|
|
int begin; |
|
int end; |
|
int count; |
|
}; |
|
|
|
|
|
template < class OBJECT_TYPE, class SCALAR_TYPE> |
|
class Octree : public vcg::OctreeTemplate< Voxel, SCALAR_TYPE >, public vcg::SpatialIndex< OBJECT_TYPE, SCALAR_TYPE > |
|
{ |
|
protected: |
|
struct Neighbour; |
|
|
|
public: |
|
typedef SCALAR_TYPE ScalarType; |
|
typedef OBJECT_TYPE ObjectType; |
|
typedef typename Octree::Leaf * LeafPointer; |
|
typedef typename Octree::InnerNode * InnerNodePointer; |
|
typedef typename ReferenceType<OBJECT_TYPE>::Type * ObjectPointer; |
|
|
|
typedef vcg::Voxel VoxelType; |
|
typedef VoxelType * VoxelPointer; |
|
|
|
typedef vcg::OctreeTemplate< VoxelType, SCALAR_TYPE > TemplatedOctree; |
|
typedef typename TemplatedOctree::ZOrderType ZOrderType; |
|
|
|
typedef typename TemplatedOctree::BoundingBoxType BoundingBoxType; |
|
typedef typename TemplatedOctree::CenterType CenterType; |
|
typedef typename TemplatedOctree::CoordinateType CoordType; |
|
|
|
typedef typename TemplatedOctree::NodeType NodeType; |
|
typedef typename TemplatedOctree::NodePointer NodePointer; |
|
typedef typename TemplatedOctree::NodeIndex NodeIndex; |
|
|
|
typedef typename std::vector< Neighbour >::iterator NeighbourIterator; |
|
|
|
protected: |
|
/*********************************************** |
|
* INNER DATA STRUCTURES AND PREDICATES * |
|
***********************************************/ |
|
/*! |
|
* Structure used during the sorting of the dataset |
|
*/ |
|
template < typename LEAF_TYPE > |
|
struct ObjectPlaceholder |
|
{ |
|
typedef LEAF_TYPE* LeafPointer; |
|
|
|
ObjectPlaceholder() { z_order = object_index = -1, leaf_pointer = NULL;} |
|
|
|
ObjectPlaceholder(ZOrderType zOrder, void* leafPointer, unsigned int objectIndex) |
|
{ |
|
z_order = zOrder; |
|
leaf_pointer = leafPointer; |
|
object_index = objectIndex; |
|
} |
|
|
|
ZOrderType z_order; |
|
LeafPointer leaf_pointer; |
|
unsigned int object_index; |
|
}; |
|
|
|
|
|
/*! |
|
* Predicate used during the sorting of the dataset |
|
*/ |
|
template <typename LEAF_TYPE > |
|
struct ObjectSorter |
|
{ |
|
inline bool operator()(const ObjectPlaceholder< LEAF_TYPE > &first, const ObjectPlaceholder< LEAF_TYPE > &second) |
|
{ |
|
return (first.z_order<second.z_order); |
|
} |
|
}; |
|
|
|
/*! |
|
* Structure which holds the reference to the object and the position of the mark for that object |
|
*/ |
|
struct ObjectReference |
|
{ |
|
ObjectReference() {pMark=NULL; pObject=NULL;} |
|
|
|
unsigned char *pMark; |
|
ObjectPointer pObject; |
|
}; |
|
|
|
/* |
|
* The generic item in the neighbors vector computed by GetNearestNeighbors; |
|
*/ |
|
struct Neighbour |
|
{ |
|
Neighbour() |
|
{ |
|
this->object = NULL; |
|
this->distance = -1.0f; |
|
}; |
|
|
|
Neighbour(ObjectPointer &object, CoordType &point, ScalarType distance) |
|
{ |
|
this->object = object; |
|
this->point = point; |
|
this->distance = distance; |
|
} |
|
|
|
inline bool operator<(const Neighbour &n) const |
|
{ |
|
return distance<n.distance; |
|
} |
|
|
|
|
|
ObjectPointer object; |
|
CoordType point; |
|
ScalarType distance; |
|
}; |
|
|
|
public: |
|
Octree() |
|
{ |
|
//marks=0; |
|
} |
|
~Octree() |
|
{ |
|
//if(marks) delete []marks; |
|
int node_count = TemplatedOctree::NodeCount(); |
|
for (int i=0; i<node_count; i++) |
|
delete TemplatedOctree::nodes[i]; |
|
TemplatedOctree::nodes.clear(); |
|
} |
|
|
|
|
|
/*! |
|
* Populate the octree |
|
*/ |
|
template < class OBJECT_ITERATOR > |
|
void Set(const OBJECT_ITERATOR & bObj, const OBJECT_ITERATOR & eObj /*, vcg::CallBackPos *callback=NULL*/) |
|
{ |
|
// 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); |
|
CoordType offset = bounding_box.Dim()*Octree::EXPANSION_FACTOR; |
|
CoordType center = bounding_box.Center(); |
|
resulting_bb.Offset(offset); |
|
ScalarType longest_side = vcg::math::Max( resulting_bb.DimX(), resulting_bb.DimY(), resulting_bb.DimZ())/2.0f; |
|
resulting_bb.Set(center); |
|
resulting_bb.Offset(longest_side); |
|
TemplatedOctree::boundingBox = resulting_bb; |
|
|
|
// Try to find a reasonable octree depth |
|
int dataset_dimension = int(std::distance(bObj, eObj)); |
|
|
|
int primitives_per_voxel; |
|
int depth = 4; |
|
do |
|
{ |
|
int number_of_voxel = 1<<(3*depth); // i.e. 8^depth |
|
float density = float(number_of_voxel)/float(depth); |
|
primitives_per_voxel = int(float(dataset_dimension)/density); |
|
depth++; |
|
} |
|
while (primitives_per_voxel>25 && depth<15); |
|
TemplatedOctree::Initialize(++depth); |
|
|
|
// Sort the dataset (using the lebesgue space filling curve...) |
|
std::string message("Indexing dataset..."); |
|
NodePointer *route = new NodePointer[depth+1]; |
|
OBJECT_ITERATOR iObj = bObj; |
|
|
|
//if (callback!=NULL) callback(int((i+1)*100/dataset_dimension), message.c_str()); |
|
|
|
std::vector< ObjectPlaceholder< NodeType > > placeholders/*(dataset_dimension)*/; |
|
vcg::Box3<ScalarType> object_bb; |
|
vcg::Point3<ScalarType> hit_leaf; |
|
for (int i=0; i<dataset_dimension; i++, iObj++) |
|
{ |
|
(*iObj).GetBBox(object_bb); |
|
hit_leaf = object_bb.min; |
|
|
|
while (object_bb.IsIn(hit_leaf)) |
|
{ |
|
int placeholder_index = int(placeholders.size()); |
|
placeholders.push_back( ObjectPlaceholder< NodeType >() ); |
|
placeholders[placeholder_index].z_order = TemplatedOctree::BuildRoute(hit_leaf, route); |
|
placeholders[placeholder_index].leaf_pointer = route[depth]; |
|
placeholders[placeholder_index].object_index = i; |
|
|
|
hit_leaf.X() += TemplatedOctree::leafDimension.X(); |
|
if (hit_leaf.X()>object_bb.max.X()) |
|
{ |
|
hit_leaf.X() = object_bb.min.X(); |
|
hit_leaf.Z()+= TemplatedOctree::leafDimension.Z(); |
|
if (hit_leaf.Z()>object_bb.max.Z()) |
|
{ |
|
hit_leaf.Z() = object_bb.min.Z(); |
|
hit_leaf.Y()+= TemplatedOctree::leafDimension.Y(); |
|
} |
|
} |
|
} |
|
} |
|
delete []route; |
|
|
|
int placeholder_count = int(placeholders.size()); |
|
|
|
// Allocate the mark array |
|
global_mark = 1; |
|
marks.resize(placeholder_count); |
|
std::fill(marks.begin(), marks.end(), 0); |
|
|
|
std::sort(placeholders.begin(), placeholders.end(), ObjectSorter< NodeType >()); |
|
std::vector< NodePointer > filled_leaves(placeholder_count); |
|
sorted_dataset.resize( placeholder_count ); |
|
for (int i=0; i<placeholder_count; i++) |
|
{ |
|
std::advance((iObj=bObj), placeholders[i].object_index); |
|
sorted_dataset[i].pObject = &DereferencerType::Ref(*iObj); |
|
sorted_dataset[i].pMark = &marks[i]; |
|
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: |
|
// we assign to each leaf the range inside the sorted dataset of the primitives contained inside the leaf |
|
int begin = -1; |
|
NodePointer initial_leaf = NULL; |
|
for (int end=0; end<placeholder_count; ) |
|
{ |
|
begin = end; |
|
initial_leaf = filled_leaves[begin]; |
|
do end++; |
|
while (end<placeholder_count && initial_leaf==filled_leaves[end]); |
|
|
|
VoxelType *voxel = TemplatedOctree::Voxel(initial_leaf); |
|
voxel->SetRange(begin, end); |
|
} |
|
|
|
// The octree is built, the dataset is sorted but only the leaves are indexed: |
|
// we propagate the indexing information bottom-up to the root |
|
IndexInnerNodes( TemplatedOctree::Root() ); |
|
} //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 = true |
|
) |
|
{ |
|
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; |
|
|
|
IncrementMark(); |
|
AdjustBoundingBox(query_bb, sphere_radius, max_distance, leaves, 1); |
|
|
|
if (sphere_radius>max_distance) |
|
return NULL; |
|
|
|
std::vector< Neighbour > neighbors; |
|
RetrieveContainedObjects(query_point, distance_functor, max_distance, allow_zero_distance, leaves, neighbors); |
|
|
|
typename std::vector< Neighbour >::iterator first = neighbors.begin(); |
|
typename std::vector< Neighbour >::iterator last = neighbors.end(); |
|
std::partial_sort(first, first+1, last); |
|
|
|
distance = neighbors[0].distance; |
|
point = neighbors[0].point; |
|
return neighbors[0].object; |
|
}; //end of GetClosest |
|
|
|
/*! |
|
* Retrieve 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_CONTAINER> |
|
unsigned int GetKClosest |
|
( |
|
OBJECT_POINT_DISTANCE_FUNCTOR & distance_functor, |
|
OBJECT_MARKER & /*marker*/, |
|
unsigned int k, |
|
const CoordType & query_point, |
|
const ScalarType & max_distance, |
|
OBJECT_POINTER_CONTAINER & objects, |
|
DISTANCE_CONTAINER & distances, |
|
POINT_CONTAINER & points, |
|
bool sort_per_distance = true, |
|
bool allow_zero_distance = true |
|
) |
|
{ |
|
BoundingBoxType query_bb; |
|
ScalarType sphere_radius; |
|
if (!GuessInitialBoundingBox(query_point, max_distance, sphere_radius, query_bb)) |
|
return 0; |
|
|
|
std::vector< NodePointer > leaves; |
|
std::vector< Neighbour > neighbors; |
|
|
|
unsigned int object_count; |
|
float k_distance; |
|
|
|
OBJECT_RETRIEVER: |
|
IncrementMark(); |
|
AdjustBoundingBox(query_bb, sphere_radius, max_distance, leaves, k); |
|
object_count = RetrieveContainedObjects(query_point, distance_functor, max_distance, allow_zero_distance, leaves, neighbors); |
|
|
|
if (sphere_radius<max_distance && object_count<k) |
|
goto OBJECT_RETRIEVER; |
|
|
|
NeighbourIterator first = neighbors.begin(); |
|
NeighbourIterator last = neighbors.end(); |
|
|
|
object_count = std::min(k, object_count); |
|
if (sort_per_distance) std::partial_sort< NeighbourIterator >(first, first+object_count, last ); |
|
else std::nth_element < NeighbourIterator >(first, first+object_count, last ); |
|
|
|
k_distance = neighbors[object_count-1].distance; |
|
if (k_distance>sphere_radius && sphere_radius<max_distance) |
|
goto OBJECT_RETRIEVER; |
|
|
|
return CopyQueryResults<OBJECT_POINTER_CONTAINER, DISTANCE_CONTAINER, POINT_CONTAINER>(neighbors, object_count, objects, distances, points); |
|
}; //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 (!TemplatedOctree::boundingBox.Collide(query_bb)) |
|
return 0; |
|
|
|
std::vector< NodePointer > leaves; |
|
std::vector< Neighbour > neighbors; |
|
|
|
IncrementMark(); |
|
TemplatedOctree::ContainedLeaves(query_bb, leaves, TemplatedOctree::Root(), TemplatedOctree::boundingBox); |
|
|
|
int leaves_count = int(leaves.size()); |
|
if (leaves_count==0) |
|
return 0; |
|
|
|
int object_count = RetrieveContainedObjects(sphere_center, distance_functor, sphere_radius, allow_zero_distance, leaves, neighbors); |
|
|
|
NeighbourIterator first = neighbors.begin(); |
|
NeighbourIterator last = neighbors.end(); |
|
if (sort_per_distance) std::partial_sort< NeighbourIterator >(first, first+object_count, last ); |
|
else std::nth_element < NeighbourIterator >(first, first+object_count, last ); |
|
|
|
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; |
|
int leaves_count; |
|
|
|
TemplatedOctree::ContainedLeaves(query_bounding_box, leaves, TemplatedOctree::Root(), TemplatedOctree::boundingBox); |
|
leaves_count = int(leaves.size()); |
|
if (leaves_count==0) |
|
return 0; |
|
|
|
IncrementMark(); |
|
for (int i=0; i<leaves_count; i++) |
|
{ |
|
VoxelType *voxel = TemplatedOctree::Voxel(leaves[i]); |
|
int begin = voxel->begin; |
|
int end = voxel->end; |
|
for ( ; begin<end; begin++) |
|
{ |
|
ObjectReference *ref = &sorted_dataset[begin]; |
|
if (IsMarked(ref)) |
|
continue; |
|
|
|
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 |
|
|
|
protected: |
|
/*! |
|
* Contains pointer to the objects in the dataset. |
|
* The pointers are sorted so that the object pointed to result ordered in the space |
|
*/ |
|
std::vector< ObjectReference > sorted_dataset; |
|
|
|
/*! |
|
* Markers used to avoid duplication of the same result during a query |
|
*/ |
|
std::vector<unsigned char> marks; |
|
unsigned char global_mark; |
|
|
|
/*! |
|
* The expansion factor used to solve the spatial queries |
|
* The current expansion factor is computed on the basis of the last expansion factor |
|
* and on the history of these values, through the following heuristic: |
|
* current_expansion_factor = alpha*last_expansion_factor + (1.0f-alpha)*mean_expansion_factor |
|
* where alpha = 1.0/3.0; |
|
*/ |
|
//float last_expansion_factor; |
|
//float mean_expansion_factor; |
|
//float ALPHA; |
|
//float ONE_MINUS_ALPHA; |
|
|
|
protected: |
|
/*! |
|
*/ |
|
inline void IncrementMark() |
|
{ |
|
// update the marks |
|
global_mark = (global_mark+1)%255; |
|
if (global_mark == 0) |
|
{ |
|
std::fill(marks.begin(), marks.begin() + sorted_dataset.size(), 0); |
|
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); |
|
|
|
// the radius of the sphere centered in query |
|
sphere_radius = 0.0f; |
|
|
|
// if the bounding-box doesn't intersect the bounding-box of the octree, then it must be immediately expanded |
|
if (!query_bb.IsIn(query_point)) |
|
{ |
|
do |
|
{ |
|
query_bb.Offset(TemplatedOctree::leafDiagonal); |
|
sphere_radius += TemplatedOctree::leafDiagonal; |
|
} |
|
while ( !TemplatedOctree::boundingBox.Collide(query_bb) || sphere_radius>max_distance); |
|
} |
|
return (sphere_radius<=max_distance); |
|
}; |
|
|
|
/*! |
|
* Modify the bounding-box used during the query until either at least k points |
|
* are contained inside the box or the box radius became greater than the threshold distance |
|
* Return the number of leaves contained inside the bounding-box |
|
*/ |
|
inline int AdjustBoundingBox |
|
( |
|
BoundingBoxType & query_bb, |
|
ScalarType & sphere_radius, |
|
const ScalarType max_allowed_distance, |
|
std::vector< NodePointer > & leaves, |
|
const int required_object_count |
|
) |
|
{ |
|
int leaves_count; |
|
int object_count; |
|
do |
|
{ |
|
leaves.clear(); |
|
|
|
query_bb.Offset(TemplatedOctree::leafDiagonal); |
|
sphere_radius+= TemplatedOctree::leafDiagonal; |
|
|
|
TemplatedOctree::ContainedLeaves(query_bb, leaves, TemplatedOctree::Root(), TemplatedOctree::boundingBox); |
|
|
|
leaves_count = int(leaves.size()); |
|
object_count = 0; |
|
for (int i=0; i<leaves_count; i++) |
|
object_count += TemplatedOctree::Voxel( leaves[i] )->count; |
|
} |
|
while (object_count<required_object_count && sphere_radius<max_allowed_distance); |
|
|
|
return leaves_count; |
|
} |
|
|
|
/*! |
|
* Retrieves the objects contained inside the leaves whose distance isn't greater than max_distance. |
|
* Returns the number of valid objects |
|
*/ |
|
template < class OBJECT_POINT_DISTANCE_FUNCTOR > |
|
inline int RetrieveContainedObjects |
|
( |
|
const CoordType query_point, |
|
OBJECT_POINT_DISTANCE_FUNCTOR & distance_functor, |
|
const ScalarType max_allowed_distance, |
|
bool allow_zero_distance, |
|
std::vector< NodePointer > & leaves, |
|
std::vector< Neighbour > & neighbors |
|
) |
|
{ |
|
CoordType closest_point; |
|
neighbors.clear(); |
|
for (int i=0, leaves_count=int(leaves.size()); i<leaves_count; i++) |
|
{ |
|
VoxelType *voxel = TemplatedOctree::Voxel(leaves[i]); |
|
int begin = voxel->begin; |
|
int end = voxel->end; |
|
for ( ; begin<end; begin++) |
|
{ |
|
ObjectReference * ref = &sorted_dataset[begin]; |
|
if (IsMarked(ref)) |
|
continue; |
|
|
|
ScalarType distance = max_allowed_distance; |
|
if (!distance_functor(*ref->pObject, query_point, distance, closest_point)) |
|
continue; |
|
|
|
Mark(ref); |
|
if ((distance!=ScalarType(0.0) || allow_zero_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++) |
|
return int(neighbors.size()); |
|
}; |
|
|
|
/*! |
|
* 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 |
|
points.resize( object_count ); |
|
distances.resize( object_count ); |
|
objects.resize( object_count ); |
|
|
|
typename POINT_CONTAINER::iterator iPoint = points.begin(); |
|
typename DISTANCE_CONTAINER::iterator iDistance = distances.begin(); |
|
typename 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 |
|
*/ |
|
void IndexInnerNodes(NodePointer n) |
|
{ |
|
assert(n!=NULL); |
|
|
|
VoxelPointer current_voxel = TemplatedOctree::Voxel(n); |
|
VoxelPointer son_voxel; |
|
for (int s=0; s<8; s++) |
|
{ |
|
NodePointer son_index = TemplatedOctree::Son(n, s); |
|
if (son_index!=NULL) |
|
{ |
|
if (TemplatedOctree::Level(son_index)!=TemplatedOctree::maximumDepth) |
|
IndexInnerNodes(son_index); |
|
|
|
son_voxel = TemplatedOctree::Voxel(son_index); |
|
current_voxel->AddRange( son_voxel ); |
|
} |
|
} |
|
}; // end of IndexInnerNodes |
|
}; |
|
|
|
#ifdef __glut_h__ |
|
/************************************************************************/ |
|
/* Rendering */ |
|
/************************************************************************/ |
|
protected: |
|
/*! |
|
* Structure which holds the rendering settings |
|
*/ |
|
struct OcreeRenderingSetting |
|
{ |
|
OcreeRenderingSetting() |
|
{ |
|
color = vcg::Color4b(155, 155, 155, 255); |
|
isVisible = false; |
|
minVisibleDepth = 1; |
|
maxVisibleDepth = 4; |
|
}; |
|
|
|
int isVisible; |
|
int minVisibleDepth; |
|
int maxVisibleDepth; |
|
vcg::Color4b color; |
|
}; |
|
|
|
public: |
|
/* |
|
* Draw the octree in a valid OpenGL context according to the rendering settings |
|
*/ |
|
void DrawOctree(vcg::Box3f &boundingBox, NodePointer n) |
|
{ |
|
char level = TemplatedOctree::Level(n); |
|
NodePointer son; |
|
if (rendering_settings.minVisibleDepth>level) |
|
{ |
|
for (int s=0; s<8; s++) |
|
if ((son=Son(n, s))!=0) |
|
DrawOctree(TemplatedOctree::SubBox(boundingBox, s), son); |
|
} |
|
else |
|
{ |
|
vcg::glBoxWire(boundingBox); |
|
if (level<rendering_settings.maxVisibleDepth) |
|
for (int s=0; s<8; s++) |
|
if ((son=Son(n, s))!=0) |
|
DrawOctree(TemplatedOctree::SubBox(boundingBox, s), son); |
|
} |
|
}; |
|
|
|
OcreeRenderingSetting rendering_settings; |
|
#endif |
|
} //end of namespace vcg |
|
|
|
#endif //VCG_SPACE_INDEX_OCTREE_H
|
|
|