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