/** * \file * \author Thomas Fischer * \date 2012-02-27 * \brief Implementation of the OctTree class. * * \copyright * Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org) * Distributed under a Modified BSD License. * See accompanying file LICENSE.txt or * http://www.opengeosys.org/project/license * */ #pragma once #include #include #include #include "MathLib/MathTools.h" #include "MathLib/Point3d.h" namespace GeoLib { /// @tparam POINT point data type the OctTree will use /// @tparam MAX_POINTS maximum number of pointers of POINT in a leaf template class OctTree { public: /// Create an OctTree object. The arguments ll and ur are used to compute a /// cube domain the OctTree will living in. /// @attention This cubic domain can not be resized during the life time of /// the OctTree. /// @param ll lower left front point, used for computation of cubic domain /// @param ur upper right back point, used for computation of cubic domain /// @param eps the euclidean distance as a threshold to make objects unique /// [default std::numeric_limits::epsilon()] /// Adding a new item to an already "filled" OctTree node results in a /// split of the OctTree node. The smaller this number is the more leaves /// the OctTree will have, i.e. it needs more memory and more time to walk /// through the OctTree, but the search inside a leaf is fast. In /// contrast a big value results into a smaller number of OctTree leaves, /// the memory requirements for the OctTree may be lower but the search /// inside a OctTree leaf may be more expensive. The value should be /// chosen application dependent. [default 8] template static OctTree* createOctTree( T ll, T ur, double eps = std::numeric_limits::epsilon()); /// Destroys the children of this node. @attention Does not destroy the /// pointers to the managed objects. virtual ~OctTree(); /// This method adds the given point to the OctTree. If necessary, /// new OctTree nodes will be inserted deploying a split of the /// corresponding OctTree node. /// @param pnt the pointer to a point that should be inserted /// @param ret_pnt the pointer to a point in the OctTree. Three cases can /// occur: /// (1) ret_pnt is nullptr: the given point (pnt) is outside of the OctTree /// domain /// (2) ret_pnt is equal to pnt: the point is added to the OctTree /// (3) In case ret_pnt is neither equal to pnt nor equal to nullptr, /// another item within the eps distance is already in the OctTree and the /// pointer to this object is returned. /// @return If the point can be inserted the method returns true, else /// false. bool addPoint(POINT* pnt, POINT*& ret_pnt); /// range query - returns all points inside the range [min[0], max[0]) x /// [min[1], max[1]) x [min[2], max[2]) template void getPointsInRange(T const& min, T const& max, std::vector& pnts) const; #ifndef NDEBUG MathLib::Point3d const& getLowerLeftCornerPoint() const { return _ll; } MathLib::Point3d const& getUpperRightCornerPoint() const { return _ur; } OctTree const* getChild(std::size_t i) const { return _children[i]; } std::vector const& getPointVector() const { return _pnts; } #endif private: /// private constructor /// @param ll lower left point /// @param ur upper right point /// @param eps the euclidean distance as a threshold to make objects unique OctTree(MathLib::Point3d const& ll, MathLib::Point3d const& ur, double eps); enum class Quadrant : std::int8_t { NEL = 0, //!< north east lower NWL, //!< north west lower SWL, //!< south west lower SEL, //!< south east lower NEU, //!< south west upper NWU, //!< south west upper SWU, //!< south west upper SEU //!< south east upper }; /// This method tries to add the given point to the OctTree. If necessary /// for adding the point, new nodes will be inserted into the OctTree. /// @param pnt, ret_pnt see documentation of addPoint() /// @return If the point can be inserted the method returns true, else /// false. bool addPoint_(POINT* pnt, POINT*& ret_pnt); /** * This method adds the given point to the OctTree. If necessary, * the OctTree will be extended. * @param pnt the point * @return If the point can be inserted the method returns true, else false. */ bool addPointToChild(POINT* pnt); /// Creates the child nodes of this leaf and distribute the points stored /// in _pnts to the children. /// @param pnt the pointer to the points that is responsible for the split void splitNode(POINT* pnt); /// checks if the given point pnt is outside of the OctTree node. /// @param pnt the point that check is performed on /// @return true if the point is outside of the OctTree node. bool isOutside(POINT* pnt) const; /// children are sorted: /// _children[0] is north east lower child /// _children[1] is north west lower child /// _children[2] is south west lower child /// _children[3] is south east lower child /// _children[4] is north east upper child /// _children[5] is north west upper child /// _children[6] is south west upper child /// _children[7] is south east upper child std::array*, 8> _children; /// lower left front face point of the cube MathLib::Point3d const _ll; /// upper right back face point of the cube MathLib::Point3d const _ur; /// vector of pointers to POINT objects std::vector _pnts; /// flag if this OctTree is a leaf bool _is_leaf; /// threshold for point uniqueness double const _eps; }; } // end namespace GeoLib #include "OctTree-impl.h"