diff --git a/vcg/space/index/octree.h b/vcg/space/index/octree.h new file mode 100644 index 00000000..9f944bfd --- /dev/null +++ b/vcg/space/index/octree.h @@ -0,0 +1,552 @@ +/**************************************************************************** +* 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. * +* * +****************************************************************************/ + +#ifndef OCTREE_H +#define OCTREE_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace vcg +{ + /*! + * Given an object or an object pointer, return the reference to the object + */ + template + 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 + class ReferenceType + { + public: + typedef T Type; + }; + + + /*! + * Given as type a pointer to type, return the type + */ + template + class ReferenceType + { + public: + typedef typename ReferenceType::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 OctreeTemplate< Voxel >, public vcg::SpatialIndex< OBJECT_TYPE, SCALAR_TYPE > + { + public: + typedef OBJECT_TYPE ObjectType; + typedef vcg::Box3 BoundingBoxType; + typedef typename Octree::Leaf * LeafPointer; + typedef typename Octree::InnerNode * InnerNodePointer; + typedef typename ReferenceType::Type * ObjectPointer; + + /*! + * 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; + }; + + + + + + 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(unsigned long long z_order, void* leaf_pointer, unsigned int object_index) + { + this->z_order = z_order; + this->leaf_pointer = leaf_pointer; + this->object_index = object_index; + } + + unsigned long long z_order; + LeafPointer leaf_pointer; + unsigned int object_index; + }; + + + /*! + * Predicate used during the sorting of the dataset + */ + template + struct ObjectSorter + { + inline bool operator()(const ObjectPlaceholder< LEAF_TYPE > &first, const ObjectPlaceholder< LEAF_TYPE > &second) + { + return (first.z_orderobject = NULL; + this->distance = -1.0f; + }; + + Neighbour(ObjectPointer &object, CoordType &point, float distance) + { + this->object = object; + this->point = point; + this->distance = distance; + } + + + ObjectPointer object; + CoordType point; + float distance; + }; + + /* + * The operator used for sorting the items in neighbors based on the distances + */ + struct DistanceCompare + { + inline bool operator()( const Neighbour &p1, const Neighbour &p2) const { return p1.distance + 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::Type > DereferencerType; + + // Compute the bounding-box enclosing the whole dataset + BoundingBoxType resulting_bb(bounding_box); + CoordType offset = bounding_box.Dim()*Octree::EXPANSION_FACTOR; + CoordType center = bounding_box.Center(); + resulting_bb.Offset(offset); + float 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.Offset(longest_side); + boundingBox = resulting_bb; + + // Try to find a reasonable octree depth + 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 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); + Initialize(depth); + + // Sort the dataset (using the lebesgue space filling curve...) + std::string message("Indexing dataset..."); + Octree::NodePointer *route = new Octree::NodePointer[depth+1]; + OBJECT_ITERATOR iObj = bObj; + + //if (callback!=NULL) callback(int((i+1)*100/dataset_dimension), message.c_str()); + + std::vector< ObjectPlaceholder< Octree::Node > > placeholders/*(dataset_dimension)*/; + vcg::Box3 object_bb; + vcg::Point3 hit_leaf; + for (int i=0; i() ); + placeholders[placeholder_index].z_order = BuildRoute(hit_leaf, route); + placeholders[placeholder_index].leaf_pointer = route[depth]; + placeholders[placeholder_index].object_index = i; + + hit_leaf.X() += leafDimension.X(); + if (hit_leaf.X()>object_bb.max.X()) + { + hit_leaf.X() = object_bb.min.X(); + hit_leaf.Z()+= leafDimension.Z(); + if (hit_leaf.Z()>object_bb.max.Z()) + { + hit_leaf.Z() = object_bb.min.Z(); + hit_leaf.Y()+= leafDimension.Y(); + } + } + } + } + delete []route; + + int placeholder_count = int(placeholders.size()); + std::sort(placeholders.begin(), placeholders.end(), ObjectSorter< Octree::Node >()); + std::vector< Octree::Node* > filled_leaves(placeholder_count); + sorted_dataset.resize( dataset_dimension ); + for (int i=0; iSetRange(begin, end); + } + + // The octree is built, the dataset is sorted but only the leaves are indexed: + // we propaget the indexing information bottom-up to the root + IndexInnerNodes( Root() ); + } //end of Set + + /*! + * Retrive the k closest element to the query point + */ + template + unsigned int GetKClosest + ( + OBJECT_POINT_DISTANCE_FUNCTOR &distance_functor, + OBJECT_MARKER &/*marker*/, + const unsigned int k, + const CoordType &query_point, + const ScalarType &max_distance, + OBJECT_POINTER_CONTAINER &objects, + DISTANCE_CONTAINER &distances, + POINT_POINTER_CONTAINER &points, + bool sort_per_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; + query_bb.Set(query_point); + + // Il raggio della sfera centrata nel punto query + 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< Neighbour > neighbors; + + unsigned int object_count; + int leaves_count; + float k_distance = leafDiagonal; + do + { + // 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++; + } + + do + { + leaves.clear(); + object_count = 0; + query_bb.Offset(k_distance); + sphere_radius += vcg::math::Max(leafDiagonal, k_distance); + + ContainedLeaves(query_bb, leaves, Root(), boundingBox); + + leaves_count = int(leaves.size()); + object_count = 0; + for (int i=0; icount; + } + while (object_countmax_distance); // TODO check the termination condintion + + // i punti contenuti nelle foglie sono sufficienti. + // seleziono solamente i k punti più vicini. + CoordType closest_point; + VoxelType *voxel; + ObjectReference *ref; + int begin; + int end; + float distance; + + neighbors.clear(); + for (int i=0; ibegin; + end = voxel->end; + for ( ; beginmark_position]==global_mark) + continue; + + distance = max_distance; + if (!distance_functor(*ref->pObject, query_point, distance, closest_point)) + continue; + + marks[ref->mark_position]=global_mark; + if ((distance!=0.0f || allow_zero_distance)/* && distancepObject, closest_point, distance) ); + } //end of for ( ; begin::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()); + k_distance = neighbors[object_count-1].distance; + } + while (k_distance>sphere_radius && sphere_radiuslevel) + { + for (int s=0; s<8; s++) + if ((son=Son(n, s))!=0) + DrawOctree(SubBox(boundingBox, s), son); + } + else + { + vcg::glBoxWire(boundingBox); + if (level sorted_dataset; + + /*! + * Markers used to avoid duplication of the same result during a query + */ + unsigned char *marks; + unsigned char global_mark; + + public: + OcreeRenderingSetting rendering_settings; + + protected: + /*! + * 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 = Voxel(n); + VoxelPointer son_voxel; + for (int s=0; s<8; s++) + { + NodePointer son_index = Son(n, s); + if (son_index!=NULL) + { + if (Level(son_index)!=maximumDepth) + IndexInnerNodes(son_index); + + son_voxel = Voxel(son_index); + current_voxel->AddRange( son_voxel ); + } + } + }; // end of IndexInnerNodes + }; + + +} //end of namespace vcg + +#endif //OCTREE_H diff --git a/vcg/space/index/octree_template.h b/vcg/space/index/octree_template.h new file mode 100644 index 00000000..8bc97a93 --- /dev/null +++ b/vcg/space/index/octree_template.h @@ -0,0 +1,701 @@ +/**************************************************************************** +* 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. * +* * +****************************************************************************/ + + +#ifndef OCTREETEMPLATE_H +#define OCTREETEMPLATE_H + +#include +#include +#include + + +namespace vcg +{ + +/* Octree Template + +Tiene un dataset volumetrico come un octree +Assunzione che la grandezza sia una potenza di due +La prof max e' fissa. +E' un octree in cui il dato e' nella cella dell'octree. +Anche i nodi non foglia hanno il dato Voxel + +Assunzioni sul tipo voxel: +che abbia definiti gli operatori per poterci fare sopra pushpull. + +Si tiene int invece di puntatori per garantirsi reallocazione dinamica. +I dati veri e propri stanno in un vettore di nodi +*/ + +template +class OctreeTemplate +{ +protected: + struct Node; + +public: + // Octree Type Definitions + typedef typename VOXEL_TYPE VoxelType; + typedef typename VOXEL_TYPE *VoxelPointer; + typedef vcg::Point3i CenterType; + static const float EXPANSION_FACTOR; + typedef int NodeIndex; + typedef Node *NodePointer; + +protected: + /* + * Inner structures: + * Contains the information related to the octree node + */ + struct Node + { + // Default constructor: fill the data members with non-meaningful values + Node() + { + parent = NULL; + level = -1; + } + + // Constructor: create a new Node + Node(NodePointer parent, int level) + { + this->parent = parent; + this->level = (char) level; + } + + inline virtual NodePointer &Son(int sonIndex) = 0; + + inline virtual bool IsLeaf() = 0; + + // The position of the center of the node in integer coords in the 0..2^(2*sz) -1 range + // The root has position (lsz/2,lsz/2,lsz/2) + CenterType center; + char level; + NodePointer parent; + VoxelType voxel; + }; + + /* + * Inner struct: Node + */ + struct InnerNode : public Node + { + InnerNode() : Node() {}; + InnerNode(NodePointer parent, int level) : Node(parent, level) + { + memset(&sons[0], NULL, 8*sizeof(Node*)); + } + + inline NodePointer &Son(int sonIndex) + { + assert(0<=sonIndex && sonIndex<=8); + return sons[sonIndex]; + } + + inline bool IsLeaf() + { + return false; + } + + NodePointer sons[8]; + }; + + /* + * Inner struct: Leaf + */ + struct Leaf : public Node + { + Leaf() : Node() {}; + Leaf(NodePointer parent, int level) : Node(parent, level) {} + + inline NodePointer &Son(int /*sonIndex*/) + { + assert(false); + return parent; + } + + inline bool IsLeaf() + { + return true; + } + }; + +public: + // Inizializza l'octree + void Initialize(int maximumDepth) + { + this->maximumDepth = maximumDepth; + size = 1<< maximumDepth; // e.g. 1*2^maxDepth + lSize = 1<<(maximumDepth+1); // e.g. 1*2^(maxDepth+1) + + InnerNode *root = new InnerNode(NULL,0); + nodes.clear(); + nodes.push_back( root ); + root->center = CenterType(size, size, size); + + float szf = (float) size; + leafDimension = boundingBox.Dim(); + leafDimension /= szf; + leafDiagonal = leafDimension.Norm(); + }; + + // Return the octree bounding-box + inline vcg::Box3f BoundingBox() { return boundingBox; } + + // Return the Voxel of the n-th node + inline VoxelPointer Voxel(const NodePointer n) { return &(n->voxel); } + + // Return the octree node count + inline int NodeCount() const { return int(nodes.size()); } + + // Return the root index + inline const NodePointer Root() const { return nodes[0]; } + + // Return the level of the n-th node + inline char Level(const NodePointer n) const { return n->level; } + + // Return the referente to the i-th son of the n-th node + inline NodePointer& Son(NodePointer n, int i) const { return n->Son(i); } + + // Return the parent index of the n-th node + inline NodePointer Parent(const NodePointer n) const { return n->parent; } + + // Return the index of the current node in its father + int WhatSon(NodePointer n) const + { + if(n==Root()) + assert(false); + + NodePointer parent = Parent(n); + for(int i=0;i<8;++i) + if(parent->Son(i)==n) + return i; + + return -1; + } + + // Return the center of the n-th node + inline CenterType CenterInOctreeCoordinates(const NodePointer n) const { return n->center;} + + // Return the center of the n-th node expressed in world-coordinate + inline vcg::Point3f CenterInWorldCoordinates(const NodePointer n) const + { + assert(0<=n && nlevel; + int shift = maxDepth-level+1; + vcg::Point3f wcCenter; + vcg::Point3f ocCenter = CenterInOctreeCoordinates(n); + vcg::Point3f nodeSize = boundingBox.Dim()/float(1<>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))); + return wcCenter + } + + // Given a node (even not leaf) it returns the center of the box it represent. + // the center is expressed not in world-coordinates. + // e.g. the root is (sz/2,sz/2,sz/2); + // and the finest element in the grid in lower left corner has center (.5, .5, .5) + /* + + 4---------------- 4---------------- 4---------------- + | | | | | | | | | | + 3---+---+---+---| 3 | | 3 | + | | | | | | | | | | + 2---+---+---+---| 2---+---+---+---| 2 c | + | | | | | | | | | | + 1---+---+---+---| 1 b + | 1 | + | a | | | | | | | | | + 0---1---2---3---4 0---1---2---3---4 0---1---2---3---4 + + This is a tree with maxdepth==2, so sz is 2^2=4 + + a) a leaf at the deepest level 2 has position (.5,.5) + b) a mid node (lev 1) has position (1,1) + c) root has level 0 and position (sz/2,sz/2) = (2,2) + + The center of a node has integer coords in the 2^(MaxDepth+1) range. + + The other approach is to use position as a bit string + codifying the tree path, but in this case you have to + supply also the level (e.g. the string lenght) + you desire. The lower left corner node is always 0 ( (,) for the root (0,0) level 1, and (00,00) for level 2) + + | ~~~ | + | 0~~ | 1~~ | + | 00~ | 01~ | 10~ | 11~ | + |000|001|010|011|100|101|110|111| + + The interesting properties is that + if your octree represent a space [minv,maxv] and you want + to find the octree cell containing a point p in [minv,maxv] + you just have to convert p in the range [0,sz) truncate it to an integer and use it as a path. + For example, consider an octree of depth 3, representing a range [0..100) + sz=8 (each cell contains form 0 to 12.5 + the point + 5 -> 0.4 -> path is 000 + 45 -> 3.6 -> path is 011 + 50 -> 4.0 -> path is 100 + 100 -> 8 -> ERROR the interval is right open!!! + + Note how each cell is meant to contains a right open interval (e.g. the first cell contains [0,12.5) and the second [12.5,25) and so on) + + The center of each cell can simply be obtained by adding .5 to the path of the leaves. + */ + vcg::Point3f Center(NodePointer n) const + { + vcg::Point3f center; + center.Import(GetPath(n)); + center+=Point3f(.5f,.5f,.5f); + + //TODO verify the assert + assert(center==nodes[n]->center); + + return center; + } + + // Return the bounding-box of the n-th node expressed in world-coordinate + vcg::Box3f BoundingBoxInWorldCoordinates(const NodePointer n) + { + assert(0<=n && n>shift)); + nodeBB.min.Y() = boundingBox.min.Y() + (nodeDim.Y()*(center.Y()>>shift)); + nodeBB.min.Z() = boundingBox.min.Z() + (nodeDim.Z()*(center.Z()>>shift)); + nodeBB.max = nodeBB.min+nodeDim; + return nodeBB; + }; + + // Return one of the 8 subb box of a given box. + vcg::Box3f SubBox(vcg::Box3f &lbb, int i) + { + vcg::Box3f bs; + 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; + if (i&2) bs.min.Y()=(lbb.min.Y()+(bs.max.Y()=lbb.max.Y()))/2.0f; + else bs.max.Y()=((bs.min.Y()=lbb.min.Y())+lbb.max.Y())/2.0f; + if (i&4) bs.min.Z()=(lbb.min.Z()+(bs.max.Z()=lbb.max.Z()))/2.0f; + else bs.max.Z()=((bs.min.Z()=lbb.min.Z())+lbb.max.Z())/2.0f; + + return bs; + } + + // 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 + vcg::Box3f SubBoxAndCenterInWorldCoordinates(vcg::Box3f &lbb, vcg::Point3f ¢er, int i) + { + vcg::Box3f bs; + if (i&1) + { + bs.min[0]=center[0]; + bs.max[0]=lbb.max[0]; + } + else + { + bs.min[0]=lbb.min[0]; + bs.max[0]=center[0]; + } + if (i&2) + { + bs.min[1]=center[1]; + bs.max[1]=lbb.max[1]; + } + else + { + bs.max[1]=center[1]; + bs.min[1]=lbb.min[1]; + } + if (i&4) + { + bs.min[2]=center[2]; + bs.max[2]=lbb.max[2]; + } + else + { + bs.max[2]=center[2]; + bs.min[2]=lbb.min[2]; + } + return bs; + }; + + /* + * Add a new Node to the octree. + * The created node is the i-th son of the node pointed to by parent. + * Return the pointer to the new node + */ + NodePointer NewNode(NodePointer parent, int i) + { + assert(0<=i && i<8); + assert(Son(parent, i)==NULL); + + //int index = NodeCount(); + char level = Level(parent)+1; + + Node *node = (levelcenter); + int displacement = 1<<(maximumDepth-level); + node->center.X() = parentCenter->X() + ((i&1)? displacement : -displacement); + node->center.Y() = parentCenter->Y() + ((i&2)? displacement : -displacement); + node->center.Z() = parentCenter->Z() + ((i&4)? displacement : -displacement); + + return node; + } + + // Aggiunge un nodo all'octree nella posizione specificata e al livello specificato. + // Vengono inoltre inseriti tutti gli antenati mancanti per andare dalla radice + // al nodo ed al livello specificato seguendo path. + NodePointer AddNode(CenterType path) + { + //the input coordinates must be in the range 0..2^maxdepth + assert(path[0]>=0 && path[0]=0 && path[1]=0 && path[2]= rootLevel) + { + int nextSon=0; + if((path[0]>>shiftLevel)%2) nextSon +=1; + if((path[1]>>shiftLevel)%2) nextSon +=2; + if((path[2]>>shiftLevel)%2) nextSon +=4; + NodePointer nextNode = Son(curNode, nextSon); + if(nextNode!=NULL) // nessun nodo può aver Root() per figlio + curNode = nextNode; + else + { + NodePointer newNode = NewNode(curNode, nextSon); + assert(Son(curNode, nextSon)==newNode); // TODO delete an assignment + curNode=newNode; + } + --shiftLevel; + } + return curNode; + } + + // Convert the point p coordinates to the integer based representation + // in the range 0..size, where size is 2^maxdepth + vcg::Point3i Interize(const vcg::Point3f &pf) const + { + vcg::Point3i pi; + + assert(pf.X()>=boundingBox.min.X() && pf.X()<=boundingBox.max.X()); + assert(pf.Y()>=boundingBox.min.Y() && pf.Y()<=boundingBox.max.Y()); + assert(pf.Z()>=boundingBox.min.Z() && pf.Z()<=boundingBox.max.Z()); + + pi.X() = int((pf.X() - boundingBox.min.X()) * size / (boundingBox.max.X() - boundingBox.min.X())); + pi.Y() = int((pf.Y() - boundingBox.min.Y()) * size / (boundingBox.max.Y() - boundingBox.min.Y())); + pi.Z() = int((pf.Z() - boundingBox.min.Z()) * size / (boundingBox.max.Z() - boundingBox.min.Z())); + + return pi; + } + + // Inverse function of Interize; + // Return to the original coords space (not to the original values!!) + vcg::Point3f DeInterize(const vcg::Point3i &pi ) const + { + vcg::Point3f pf; + + assert(pi.X()>=0 && pi.X()=0 && pi.Y()=0 && pi.Z()=0 && path[0]=0 && path[1]=0 && path[2]>shift)%2) son +=1; + if((path[1]>>shift)%2) son +=2; + if((path[2]>>shift)%2) son +=4; + NodePointer nextNode = Son(curNode, son); + if(nextNode!=NULL) + CurNode=nextNode; + else + break; + + --shift; + } + return CurNode; + } + + + // Return the 'path' from root to the specified node; + // the path is coded as a point3s; each bit of each component code the direction in one level + // only the last 'level' bits of the returned value are meaningful + // for example for the root no bit are meaningfull (path is 0) + // for the first level only one bit of each one of the three components are maninguful; + CenterType GetPath(NodePointer n) const + { + if(n==Root()) + return CenterType(0,0,0); + + CenterType path(0,0,0); + + int shift, mask, son; + int startingLevel = int(Level(n)); + while (n!=Root()) + { + shift = startingLevel-Level(n); //nodes[n].level + mask = 1 << shift; // e.g. 1*2^shift + son = WhatSon(n); + if(son&1) path[0] |= mask; + if(son&2) path[1] |= mask; + if(son&4) path[2] |= mask; + n = Parent(n); // nodes[n].parent + } + return path; + } + + // Dato un punto 3D nello spazio restituisce un array contenente + // i puntatori ai nodi che lo contengono, dalla radice fino alle foglie. + // I nodi mancanti dalla radice fino a profondità maxDepth vengono aggiunti. + // In posizione i ci sarà il nodo di livello i. + // Restituisce lo z-order del punto p + unsigned long long BuildRoute(const vcg::Point3f &p, NodePointer *&route) + { + 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.Z()<=p.Z() && p.Z()<=boundingBox.max.Z() ); + + route[0] = Root(); + NodePointer curNode = Root(); + int finalLevel = 0; + int shift = maximumDepth-1; + + CenterType path = CenterType::Construct(Interize(p)); + while(shift >= finalLevel) + { + int son = 0; + if((path[0]>>shift)%2) son +=1; + if((path[1]>>shift)%2) son +=2; + if((path[2]>>shift)%2) son +=4; + NodePointer nextNode = Son(curNode, son); + + if(nextNode!=NULL) + { + route[maximumDepth-shift] = nextNode; + curNode = nextNode; + } + else + { + NodePointer newNode = NewNode(curNode, son); + route[maximumDepth-shift] = newNode; + curNode = newNode; + } + --shift; + } + return ZOrder(route[maximumDepth]); + }; //end of BuildRoute + + + // Restituisce il percorso dalla radice fino al nodo di profondità + // massima presente nell'octree contenente il nodo p. Nessun nuovo nodo è aggiunto + // all'octree. In route sono inseriti gli indici dei nodi contenti p, dalla radice + // 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 + // dell'otree, false altrimenti + bool GetRoute(const vcg::Point3f &p, NodePointer *&route) + { + 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.Z()<=p.Z() && p.Z()<=boundingBox.max.Z() ); + + memset(route, NULL, maxDepth*sizeof(NodePointer)); + + CenterType path = CenterType::Construct(Interize(p)); + int shift = maxDepth-1; + NodePointer finalLevel = Root(); + NodePointer curNode = Root(); + + while(shift >= finalLevel) + { + int son=0; + if((path[0]>>shift)%2) son +=1; + if((path[1]>>shift)%2) son +=2; + if((path[2]>>shift)%2) son +=4; + NodePointer nextNode = Son(curNode, son); + if(nextNode!=NULL) + { + route[maxDepth-shift] = nextNode; + curNode = nextNode; + } + else + return false; + + --shift; + } + return true; + }; //end of GetReoute + + // Data una bounding-box bb_query, calcola l'insieme dei nodi di + // profondità depth il cui bounding-box ha intersezione non nulla con + // bb (la bounding-box dell'octree); i puntatori a tali nodi sono + // inseriti progressivamente in contained_nodes. + // The vector nodes must be cleared before calling this method. + void ContainedNodes( + vcg::Box3f &query, + std::vector< NodePointer > &nodes, + int depth, + NodePointer n, + vcg::Box3f &nodeBB) + { + if (!query.Collide(nodeBB)) + return; + + if (Level(n)==depth) + nodes.push_back(n); + else + { + NodePointer son; + vcg::Box3f sonBB; + vcg::Point3f nodeCenter = nodeBB.Center(); + for (int s=0; s<8; s++) + { + son = Son(n, s); + if (son!=NULL) + { + sonBB = SubBoxAndCenterInWorldCoordinates(nodeBB, nodeCenter, s); + ContainedNodes(query, nodes, depth, son, sonBB); + } + } + } + }; //end of ContainedNodes + + + // Data una bounding-box bb, calcola l'insieme delle foglie il cui + // bounding-box ha intersezione non nulla con bb; i loro indici + // sono inseriti all'interno di leaves. + void ContainedLeaves( + vcg::Box3f &query, + std::vector< NodePointer > &leaves, + NodePointer node, + vcg::Box3f &nodeBB + ) + { + NodePointer son; + vcg::Box3f sonBB; + vcg::Point3f nodeCenter = nodeBB.Center(); + for (int s=0; s<8; s++) + { + son = Son(node, s); //nodes[nodeIndex].sonIndex[s] + if (son!=NULL) + { + sonBB = SubBoxAndCenterInWorldCoordinates(nodeBB, nodeCenter, s); + if ( query.Collide(sonBB) ) + { + if ( son->IsLeaf() ) + leaves.push_back(son); + else + ContainedLeaves(query, leaves, son, sonBB); + } + } + } + }; //end of ContainedLeaves + + + /* + * Octree Data Members + */ +public: + // the size of the finest grid available (2^maxDepth) + int size; + + // double the size(2^maxDepth) + int lSize; + + // The allowed maximum depth + int maximumDepth; + + // The dimension of a leaf + vcg::Point3f leafDimension; + + // The diagonal of a leaf + float leafDiagonal; + + // The Octree nodes + std::vector< Node* > nodes; + + // The bounding box containing the octree (in world coordinate) + vcg::Box3f boundingBox; +}; //end of class OctreeTemplate + +template +const float OctreeTemplate::EXPANSION_FACTOR = 0.035f; + +} + +#endif //OCTREETEMPLATE_H