// This source code is property of the Computer Graphics and Visualization // chair of the TU Dresden. Do not distribute! // Copyright (C) CGV TU Dresden - All Rights Reserved #pragma once #include #include #include #include "Box.h" #include "Triangle.h" #include "LineSegment.h" #include "Point.h" /** * Axis aligned bounding volume hierachy data structure. */ template class AABBTree { public: typedef std::vector primitive_list; //iterator type pointing inside the primitive list typedef typename primitive_list::iterator PrimitiveIterator; //const iterator type pointing inside the primitive list typedef typename primitive_list::const_iterator const_primitive_iterator; //abstract base class defining the common interface of all aabb tree node class AABBNode { protected: //storage of bounding box assosiated with aabb_node Box bounds; public: AABBNode() { } AABBNode(const Box& b): bounds(b) { } //returns the bounding box of the node Box GetBounds() const { return bounds; } virtual int NumPrimitives() const = 0; //this method must be implemented to return true for a leaf node and false for a non_lef node virtual bool IsLeaf() const = 0; //virtual destructor virtual ~AABBNode() {} }; ///a class representing a leaf node of an aabb tree (non split node) class AABBLeafNode: public AABBNode { //internal storage to the range (begin and end pointer) of the primitives associated with the current leaf node PrimitiveIterator primitivesBegin, primitivesEnd; public: //construct a leaf node from AABBLeafNode(const PrimitiveIterator& primitivesBegin, const PrimitiveIterator& primitivesEnd, const Box& b): primitivesBegin(primitivesBegin),primitivesEnd(primitivesEnd), AABBNode(b) { } //return always true because its a leaf node bool IsLeaf() const { return true; } //returns the number primitives assosiated with the current leaf int NumPrimitives() const { return (int)(primitivesEnd-primitivesBegin); } const_primitive_iterator begin() const { return primitivesBegin; } const_primitive_iterator end() const { return primitivesEnd; } }; ///a class representing a split node of an aabb tree (non leaf node) class AABBSplitNode: public AABBNode { //child pointers AABBNode* children[2]; public: //default constructor AABBSplitNode() { children[0] = children[1] = nullptr; } //construct a split node from given Left and right child pointers and given bounding box b of the node AABBSplitNode(AABBNode* left_child, AABBNode* right_child,const Box& b): AABBNode(b) { children[0] = left_child; children[1] = right_child; } //destructor of node, recursively deleted whole subtree ~AABBSplitNode() { if(Left() != nullptr) delete Left(); if(Right() != nullptr) delete Right(); } //returns always false because its a split node bool IsLeaf() const { return false; } //returns a pointer to the left child node AABBNode* Left() { return children[0]; } //returns a pointer to the right child node AABBNode* Right() { return children[1]; } //returns a const pointer to the left child node const AABBNode* Left() const { return children[0]; } //returns a const pointer to the right child node const AABBNode* Right() const { return children[1]; } //counts the number of primitives of the subtree int NumPrimitives() const { return Left()->NumPrimitives() + Right()->NumPrimitives(); } }; private: //search entry used internally for nearest and k nearest primitive queries struct SearchEntry { //squared distance to node from query point float sqrDistance; //node const AABBNode* node; //constructor SearchEntry(float sqrDistance, const AABBNode* node) : sqrDistance(sqrDistance), node(node) { } //search entry a < b means a.sqr_distance > b. sqr_distance bool operator<(const SearchEntry& e) const { return sqrDistance > e.sqrDistance; } }; //result entry for nearest and k nearest primitive queries struct ResultEntry { //squared distance from query point to primitive float sqrDistance; //pointer to primitive const Primitive* prim; //default constructor ResultEntry() : sqrDistance(std::numeric_limits::infinity()), prim(nullptr) { } //constructor ResultEntry(float sqrDistance, const Primitive* p) : sqrDistance(sqrDistance), prim(p) { } //result_entry are sorted by their sqr_distance using this less than operator bool operator<(const ResultEntry& e) const { return sqrDistance < e.sqrDistance; } }; //list of all primitives in the tree primitive_list primitives; //maximum allowed tree depth to stop tree construction int maxDepth; //minimal number of primitives to stop tree construction int minSize; //pointer to the root node of the tree AABBNode *root; //a flag indicating if the tree is constructed bool completed; public: //returns a pointer to the root node of the tree AABBNode* Root() { assert(IsCompleted()); return root; } //returns a const pointer to the root node of the tree const AABBNode* Root() const { assert(IsCompleted()); return root; } //constructor of aabb tree //default maximal tree depth is 20 //default minimal size of a node not to be further subdivided in the cnstruction process is two AABBTree(int maxDepth=20, int minSize=2): maxDepth(maxDepth),minSize(minSize),root(nullptr),completed(false) { } //copy constructor AABBTree(const AABBTree& other) { primitives = other.primitives; maxDepth = other.maxDepth; minSize = other.minSize; root = CopyTree(other.primitives,other.root); completed = other.completed; } //move constructor AABBTree(AABBTree&& other):root(nullptr),completed(false) { *this = std::move(other); } //copy assignment operator AABBTree& operator=(const AABBTree& other) { if(this != &other) { if(root != nullptr) delete root; primitives = other.primitives; maxDepth = other.maxDepth; minSize = other.minSize; root = CopyTree(other.primitives,other.root); completed = other.completed; } return *this; } //move assign operator AABBTree& operator=(AABBTree&& other) { if(this != &other) { std::swap(primitives,other.primitives); std::swap(maxDepth, other.maxDepth); std::swap(minSize, other.minSize); std::swap(root,other.root) ; std::swap(completed, other.completed); } return *this; } //remove all primitives from tree void Clear() { primitives.clear(); if(root != nullptr) { delete root; root = nullptr; } completed = false; } //returns true if tree is empty bool Empty() const { return primitives.Empty(); } //insert a primitive into internal primitive list //this method do not construct the tree! //call the method Complete, after insertion of all primitives void Insert(const Primitive& p) { primitives.push_back(p); completed=false; } //construct the tree from all prior inserted primitives void Complete() { //if tree already constructed -> delete tree if(root != nullptr) delete root; //compute bounding box over all primitives using helper function Box bounds = ComputeBounds(primitives.begin(),primitives.end()); //initial call to the recursive tree construction method over the whole range of primitives root = Build(primitives.begin(),primitives.end(),bounds,0); //set completed flag to true completed=true; } //returns true if the tree can be used for queries //if the tree is not completed call the method complete() bool IsCompleted() const { return completed; } //closest primitive computation via linear search ResultEntry ClosestPrimitiveLinearSearch(const Eigen::Vector3f& q) const { ResultEntry best; auto pend = primitives.end(); for(auto pit = primitives.begin(); pit != pend; ++pit) { float dist = pit->SqrDistance(q); if(dist < best.sqrDistance) { best.sqrDistance = dist; best.prim = &(*pit); } } return best; } //computes the k nearest neighbor primitives via linear search std::vector ClosestKPrimitivesLinearSearch(size_t k, const Eigen::Vector3f& q) const { std::priority_queue k_best; Primitive best_p; auto pend = primitives.end(); for(auto pit = primitives.begin(); pit != pend; ++pit) { float dist = pit->SqrDistance(q); if(k_best.size() < k ) { k_best.push(ResultEntry(dist,*pit)); return; } if(k_best.top().SqrDistance > dist) { k_best.pop(); k_best.push(ResultEntry(dist,*pit)); } } std::vector result(k_best.size()); auto rend = result.end(); for(auto rit = result.begin(); rit != rend; ++rit) { *rit = k_best.top(); k_best.pop(); } return result; } //closest k primitive computation std::vector ClosestKPrimitives(size_t k,const Eigen::Vector3f& q) const { //student begin return ClosestKPrimitivesLinearSearch(k,q); //student end } //returns the closest primitive and its squared distance to the point q ResultEntry ClosestPrimitive(const Eigen::Vector3f& q) const { assert(IsCompleted()); if(root == nullptr) return ResultEntry(); /* Task 3.2.1 */ return ClosestPrimitiveLinearSearch(q); } //return the closest point position on the closest primitive in the tree with respect to the query point q Eigen::Vector3f ClosestPoint(const Eigen::Vector3f& p) const { ResultEntry r = ClosestPrimitive(p); return r.prim->ClosestPoint(p); } //return the squared distance between point p and the nearest primitive in the tree float SqrDistance(const Eigen::Vector3f& p) const { ResultEntry r = ClosestPrimitive(p); return r.SqrDistance; } //return the euclidean distance between point p and the nearest primitive in the tree float Distance(const Eigen::Vector3f& p) const { return sqrt(SqrDistance(p)); } protected: //helper function to copy a subtree AABBNode* CopyTree(const primitive_list& other_primitives,AABBNode* node) { if(node == nullptr) return nullptr; if(node->IsLeaf()) { AABBLeafNode* leaf = (AABBLeafNode*)node; return new AABBLeafNode(primitives.begin()+(leaf->primitives.begin()-other_primitives.begin()), primitives.begin()+(leaf->primitives.end()-other_primitives.begin())); } else { AABBSplitNode* split = (AABBSplitNode*)node; return new AABBSplitNode(CopyTree(other_primitives,split->Left()), CopyTree(other_primitives,split->Right())); } } //helper function to compute an axis aligned bounding box over the range of primitives [begin,end) Box ComputeBounds(const_primitive_iterator begin, const_primitive_iterator end) { Box bounds; for(auto pit = begin; pit != end; ++pit) bounds.Insert(pit->ComputeBounds()); return bounds; } //recursive tree construction initially called from method complete() //build an aabb (sub)-tree over the range of primitives [begin,end), //the current bounding box is given by bounds and the current tree depth is given by the parameter depth //if depth >= max_depth or the number of primitives (end-begin) <= min_size a leaf node is constructed //otherwise split node is created // to create a split node the range of primitives [begin,end) must be splitted and reordered into two //sub ranges [begin,mid) and [mid,end), //therefore sort the range of primitives [begin,end) along the largest bounding box extent by its reference //point returned by the method ReferencePoint() //then choose the median element as mid // the STL routine std::nth_element would be very useful here , you only have to provide a ordering predicate //compute the boundg boxed of the two resulting sub ranges and recursivly call build on the two subranges //the resulting subtree are used as children of the resulting split node. AABBNode* Build(PrimitiveIterator begin, PrimitiveIterator end, Box& bounds, int depth) { if(depth >= maxDepth || end-begin <= minSize) { return new AABBLeafNode(begin,end,bounds); } Eigen::Vector3f e = bounds.Extents(); int axis = 0; float max_extent = e[0]; if(max_extent < e[1]) { axis = 1; max_extent = e[1]; } if(max_extent < e[2]) { axis = 2; max_extent = e[2]; } PrimitiveIterator mid= begin + (end-begin)/2; std::nth_element(begin,mid,end,[&axis](const Primitive& a, const Primitive& b) { return a.ReferencePoint()[axis] < b.ReferencePoint()[axis];}); Box lbounds = ComputeBounds(begin,mid); Box rbounds = ComputeBounds(mid,end); return new AABBSplitNode(Build(begin,mid,lbounds,depth+1),Build(mid,end,rbounds,depth+1),bounds); } }; //helper function to construct an aabb tree data structure from the triangle faces of the halfedge mesh m void BuildAABBTreeFromTriangles(const HEMesh& m, AABBTree& tree); //helper function to construct an aabb tree data structure from the vertices of the halfedge mesh m void BuildAABBTreeFromVertices(const HEMesh& m, AABBTree& tree); //helper function to construct an aabb tree data structure from the edges of the halfedge mesh m void BuildAABBTreeFromEdges(const HEMesh& m, AABBTree& tree);