/* * OctoMap - An Efficient Probabilistic 3D Mapping Framework Based on Octrees * https://octomap.github.io/ * * Copyright (c) 2009-2013, K.M. Wurm and A. Hornung, University of Freiburg * All rights reserved. * License: New BSD * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the University of Freiburg nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef OCTOMAP_OCTREE_BASE_IMPL_H #define OCTOMAP_OCTREE_BASE_IMPL_H #include #include #include #include #include #include "octomap_types.h" #include "OcTreeKey.h" #include "ScanGraph.h" namespace octomap { // forward declaration for NODE children array class AbstractOcTreeNode; /** * OcTree base class, to be used with with any kind of OcTreeDataNode. * * This tree implementation currently has a maximum depth of 16 * nodes. For this reason, coordinates values have to be, e.g., * below +/- 327.68 meters (2^15) at a maximum resolution of 0.01m. * * This limitation enables the use of an efficient key generation * method which uses the binary representation of the data point * coordinates. * * \note You should probably not use this class directly, but * OcTreeBase or OccupancyOcTreeBase instead * * \tparam NODE Node class to be used in tree (usually derived from * OcTreeDataNode) * \tparam INTERFACE Interface to be derived from, should be either * AbstractOcTree or AbstractOccupancyOcTree */ template class OcTreeBaseImpl : public INTERFACE { public: /// Make the templated NODE type available from the outside typedef NODE NodeType; // the actual iterator implementation is included here // as a member from this file #include OcTreeBaseImpl(double resolution); virtual ~OcTreeBaseImpl(); /// Deep copy constructor OcTreeBaseImpl(const OcTreeBaseImpl& rhs); /** * Swap contents of two octrees, i.e., only the underlying * pointer / tree structure. You have to ensure yourself that the * metadata (resolution etc) matches. No memory is cleared * in this function */ void swapContent(OcTreeBaseImpl& rhs); /// Comparison between two octrees, all meta data, all /// nodes, and the structure must be identical bool operator== (const OcTreeBaseImpl& rhs) const; std::string getTreeType() const {return "OcTreeBaseImpl";} /// Change the resolution of the octree, scaling all voxels. /// This will not preserve the (metric) scale! void setResolution(double r); inline double getResolution() const { return resolution; } inline unsigned int getTreeDepth () const { return tree_depth; } inline double getNodeSize(unsigned depth) const {assert(depth <= tree_depth); return sizeLookupTable[depth];} /** * Clear KeyRay vector to minimize unneeded memory. This is only * useful for the StaticMemberInitializer classes, don't call it for * an octree that is actually used. */ void clearKeyRays(){ keyrays.clear(); } // -- Tree structure operations formerly contained in the nodes --- /// Creates (allocates) the i-th child of the node. @return ptr to newly create NODE NODE* createNodeChild(NODE* node, unsigned int childIdx); /// Deletes the i-th child of the node void deleteNodeChild(NODE* node, unsigned int childIdx); /// @return ptr to child number childIdx of node NODE* getNodeChild(NODE* node, unsigned int childIdx) const; /// @return const ptr to child number childIdx of node const NODE* getNodeChild(const NODE* node, unsigned int childIdx) const; /// A node is collapsible if all children exist, don't have children of their own /// and have the same occupancy value virtual bool isNodeCollapsible(const NODE* node) const; /** * Safe test if node has a child at index childIdx. * First tests if there are any children. Replaces node->childExists(...) * \return true if the child at childIdx exists */ bool nodeChildExists(const NODE* node, unsigned int childIdx) const; /** * Safe test if node has any children. Replaces node->hasChildren(...) * \return true if node has at least one child */ bool nodeHasChildren(const NODE* node) const; /** * Expands a node (reverse of pruning): All children are created and * their occupancy probability is set to the node's value. * * You need to verify that this is indeed a pruned node (i.e. not a * leaf at the lowest level) * */ virtual void expandNode(NODE* node); /** * Prunes a node when it is collapsible * @return true if pruning was successful */ virtual bool pruneNode(NODE* node); // -------- /** * \return Pointer to the root node of the tree. This pointer * should not be modified or deleted externally, the OcTree * manages its memory itself. In an empty tree, root is NULL. */ inline NODE* getRoot() const { return root; } /** * Search node at specified depth given a 3d point (depth=0: search full tree depth). * You need to check if the returned node is NULL, since it can be in unknown space. * @return pointer to node if found, NULL otherwise */ NODE* search(double x, double y, double z, unsigned int depth = 0) const; /** * Search node at specified depth given a 3d point (depth=0: search full tree depth) * You need to check if the returned node is NULL, since it can be in unknown space. * @return pointer to node if found, NULL otherwise */ NODE* search(const point3d& value, unsigned int depth = 0) const; /** * Search a node at specified depth given an addressing key (depth=0: search full tree depth) * You need to check if the returned node is NULL, since it can be in unknown space. * @return pointer to node if found, NULL otherwise */ NODE* search(const OcTreeKey& key, unsigned int depth = 0) const; /** * Delete a node (if exists) given a 3d point. Will always * delete at the lowest level unless depth !=0, and expand pruned inner nodes as needed. * Pruned nodes at level "depth" will directly be deleted as a whole. */ bool deleteNode(double x, double y, double z, unsigned int depth = 0); /** * Delete a node (if exists) given a 3d point. Will always * delete at the lowest level unless depth !=0, and expand pruned inner nodes as needed. * Pruned nodes at level "depth" will directly be deleted as a whole. */ bool deleteNode(const point3d& value, unsigned int depth = 0); /** * Delete a node (if exists) given an addressing key. Will always * delete at the lowest level unless depth !=0, and expand pruned inner nodes as needed. * Pruned nodes at level "depth" will directly be deleted as a whole. */ bool deleteNode(const OcTreeKey& key, unsigned int depth = 0); /// Deletes the complete tree structure void clear(); /** * Lossless compression of the octree: A node will replace all of its eight * children if they have identical values. You usually don't have to call * prune() after a regular occupancy update, updateNode() incrementally * prunes all affected nodes. */ virtual void prune(); /// Expands all pruned nodes (reverse of prune()) /// \note This is an expensive operation, especially when the tree is nearly empty! virtual void expand(); // -- statistics ---------------------- /// \return The number of nodes in the tree virtual inline size_t size() const { return tree_size; } /// \return Memory usage of the complete octree in bytes (may vary between architectures) virtual size_t memoryUsage() const; /// \return Memory usage of a single octree node virtual inline size_t memoryUsageNode() const {return sizeof(NODE); } /// \return Memory usage of a full grid of the same size as the OcTree in bytes (for comparison) /// \note this can be larger than the adressable memory - size_t may not be enough to hold it! unsigned long long memoryFullGrid() const; double volume(); /// Size of OcTree (all known space) in meters for x, y and z dimension virtual void getMetricSize(double& x, double& y, double& z); /// Size of OcTree (all known space) in meters for x, y and z dimension virtual void getMetricSize(double& x, double& y, double& z) const; /// minimum value of the bounding box of all known space in x, y, z virtual void getMetricMin(double& x, double& y, double& z); /// minimum value of the bounding box of all known space in x, y, z void getMetricMin(double& x, double& y, double& z) const; /// maximum value of the bounding box of all known space in x, y, z virtual void getMetricMax(double& x, double& y, double& z); /// maximum value of the bounding box of all known space in x, y, z void getMetricMax(double& x, double& y, double& z) const; /// Traverses the tree to calculate the total number of nodes size_t calcNumNodes() const; /// Traverses the tree to calculate the total number of leaf nodes size_t getNumLeafNodes() const; // -- access tree nodes ------------------ /// return centers of leafs that do NOT exist (but could) in a given bounding box void getUnknownLeafCenters(point3d_list& node_centers, point3d pmin, point3d pmax, unsigned int depth = 0) const; // -- raytracing ----------------------- /** * Traces a ray from origin to end (excluding), returning an * OcTreeKey of all nodes traversed by the beam. You still need to check * if a node at that coordinate exists (e.g. with search()). * * @param origin start coordinate of ray * @param end end coordinate of ray * @param ray KeyRay structure that holds the keys of all nodes traversed by the ray, excluding "end" * @return Success of operation. Returning false usually means that one of the coordinates is out of the OcTree's range */ bool computeRayKeys(const point3d& origin, const point3d& end, KeyRay& ray) const; /** * Traces a ray from origin to end (excluding), returning the * coordinates of all nodes traversed by the beam. You still need to check * if a node at that coordinate exists (e.g. with search()). * @note: use the faster computeRayKeys method if possible. * * @param origin start coordinate of ray * @param end end coordinate of ray * @param ray KeyRay structure that holds the keys of all nodes traversed by the ray, excluding "end" * @return Success of operation. Returning false usually means that one of the coordinates is out of the OcTree's range */ bool computeRay(const point3d& origin, const point3d& end, std::vector& ray); // file IO /** * Read all nodes from the input stream (without file header), * for this the tree needs to be already created. * For general file IO, you * should probably use AbstractOcTree::read() instead. */ std::istream& readData(std::istream &s); /// Write complete state of tree to stream (without file header) unmodified. /// Pruning the tree first produces smaller files (lossless compression) std::ostream& writeData(std::ostream &s) const; typedef leaf_iterator iterator; /// @return beginning of the tree as leaf iterator iterator begin(unsigned char maxDepth=0) const {return iterator(this, maxDepth);} /// @return end of the tree as leaf iterator const iterator end() const {return leaf_iterator_end;} // TODO: RVE? /// @return beginning of the tree as leaf iterator leaf_iterator begin_leafs(unsigned char maxDepth=0) const {return leaf_iterator(this, maxDepth);} /// @return end of the tree as leaf iterator const leaf_iterator end_leafs() const {return leaf_iterator_end;} /// @return beginning of the tree as leaf iterator in a bounding box leaf_bbx_iterator begin_leafs_bbx(const OcTreeKey& min, const OcTreeKey& max, unsigned char maxDepth=0) const { return leaf_bbx_iterator(this, min, max, maxDepth); } /// @return beginning of the tree as leaf iterator in a bounding box leaf_bbx_iterator begin_leafs_bbx(const point3d& min, const point3d& max, unsigned char maxDepth=0) const { return leaf_bbx_iterator(this, min, max, maxDepth); } /// @return end of the tree as leaf iterator in a bounding box const leaf_bbx_iterator end_leafs_bbx() const {return leaf_iterator_bbx_end;} /// @return beginning of the tree as iterator to all nodes (incl. inner) tree_iterator begin_tree(unsigned char maxDepth=0) const {return tree_iterator(this, maxDepth);} /// @return end of the tree as iterator to all nodes (incl. inner) const tree_iterator end_tree() const {return tree_iterator_end;} // // Key / coordinate conversion functions // /// Converts from a single coordinate into a discrete key inline key_type coordToKey(double coordinate) const{ return ((int) floor(resolution_factor * coordinate)) + tree_max_val; } /// Converts from a single coordinate into a discrete key at a given depth key_type coordToKey(double coordinate, unsigned depth) const; /// Converts from a 3D coordinate into a 3D addressing key inline OcTreeKey coordToKey(const point3d& coord) const{ return OcTreeKey(coordToKey(coord(0)), coordToKey(coord(1)), coordToKey(coord(2))); } /// Converts from a 3D coordinate into a 3D addressing key inline OcTreeKey coordToKey(double x, double y, double z) const{ return OcTreeKey(coordToKey(x), coordToKey(y), coordToKey(z)); } /// Converts from a 3D coordinate into a 3D addressing key at a given depth inline OcTreeKey coordToKey(const point3d& coord, unsigned depth) const{ if (depth == tree_depth) return coordToKey(coord); else return OcTreeKey(coordToKey(coord(0), depth), coordToKey(coord(1), depth), coordToKey(coord(2), depth)); } /// Converts from a 3D coordinate into a 3D addressing key at a given depth inline OcTreeKey coordToKey(double x, double y, double z, unsigned depth) const{ if (depth == tree_depth) return coordToKey(x,y,z); else return OcTreeKey(coordToKey(x, depth), coordToKey(y, depth), coordToKey(z, depth)); } /** * Adjusts a 3D key from the lowest level to correspond to a higher depth (by * shifting the key values) * * @param key Input key, at the lowest tree level * @param depth Target depth level for the new key * @return Key for the new depth level */ inline OcTreeKey adjustKeyAtDepth(const OcTreeKey& key, unsigned int depth) const{ if (depth == tree_depth) return key; assert(depth <= tree_depth); return OcTreeKey(adjustKeyAtDepth(key[0], depth), adjustKeyAtDepth(key[1], depth), adjustKeyAtDepth(key[2], depth)); } /** * Adjusts a single key value from the lowest level to correspond to a higher depth (by * shifting the key value) * * @param key Input key, at the lowest tree level * @param depth Target depth level for the new key * @return Key for the new depth level */ key_type adjustKeyAtDepth(key_type key, unsigned int depth) const; /** * Converts a 3D coordinate into a 3D OcTreeKey, with boundary checking. * * @param coord 3d coordinate of a point * @param key values that will be computed, an array of fixed size 3. * @return true if point is within the octree (valid), false otherwise */ bool coordToKeyChecked(const point3d& coord, OcTreeKey& key) const; /** * Converts a 3D coordinate into a 3D OcTreeKey at a certain depth, with boundary checking. * * @param coord 3d coordinate of a point * @param depth level of the key from the top * @param key values that will be computed, an array of fixed size 3. * @return true if point is within the octree (valid), false otherwise */ bool coordToKeyChecked(const point3d& coord, unsigned depth, OcTreeKey& key) const; /** * Converts a 3D coordinate into a 3D OcTreeKey, with boundary checking. * * @param x * @param y * @param z * @param key values that will be computed, an array of fixed size 3. * @return true if point is within the octree (valid), false otherwise */ bool coordToKeyChecked(double x, double y, double z, OcTreeKey& key) const; /** * Converts a 3D coordinate into a 3D OcTreeKey at a certain depth, with boundary checking. * * @param x * @param y * @param z * @param depth level of the key from the top * @param key values that will be computed, an array of fixed size 3. * @return true if point is within the octree (valid), false otherwise */ bool coordToKeyChecked(double x, double y, double z, unsigned depth, OcTreeKey& key) const; /** * Converts a single coordinate into a discrete addressing key, with boundary checking. * * @param coordinate 3d coordinate of a point * @param key discrete 16 bit adressing key, result * @return true if coordinate is within the octree bounds (valid), false otherwise */ bool coordToKeyChecked(double coordinate, key_type& key) const; /** * Converts a single coordinate into a discrete addressing key, with boundary checking. * * @param coordinate 3d coordinate of a point * @param depth level of the key from the top * @param key discrete 16 bit adressing key, result * @return true if coordinate is within the octree bounds (valid), false otherwise */ bool coordToKeyChecked(double coordinate, unsigned depth, key_type& key) const; /// converts from a discrete key at a given depth into a coordinate /// corresponding to the key's center double keyToCoord(key_type key, unsigned depth) const; /// converts from a discrete key at the lowest tree level into a coordinate /// corresponding to the key's center inline double keyToCoord(key_type key) const{ return (double( (int) key - (int) this->tree_max_val ) +0.5) * this->resolution; } /// converts from an addressing key at the lowest tree level into a coordinate /// corresponding to the key's center inline point3d keyToCoord(const OcTreeKey& key) const{ return point3d(float(keyToCoord(key[0])), float(keyToCoord(key[1])), float(keyToCoord(key[2]))); } /// converts from an addressing key at a given depth into a coordinate /// corresponding to the key's center inline point3d keyToCoord(const OcTreeKey& key, unsigned depth) const{ return point3d(float(keyToCoord(key[0], depth)), float(keyToCoord(key[1], depth)), float(keyToCoord(key[2], depth))); } protected: /// Constructor to enable derived classes to change tree constants. /// This usually requires a re-implementation of some core tree-traversal functions as well! OcTreeBaseImpl(double resolution, unsigned int tree_depth, unsigned int tree_max_val); /// initialize non-trivial members, helper for constructors void init(); /// recalculates min and max in x, y, z. Does nothing when tree size didn't change. void calcMinMax(); void calcNumNodesRecurs(NODE* node, size_t& num_nodes) const; /// recursive call of readData() std::istream& readNodesRecurs(NODE*, std::istream &s); /// recursive call of writeData() std::ostream& writeNodesRecurs(const NODE*, std::ostream &s) const; /// Recursively delete a node and all children. Deallocates memory /// but does NOT set the node ptr to NULL nor updates tree size. void deleteNodeRecurs(NODE* node); /// recursive call of deleteNode() bool deleteNodeRecurs(NODE* node, unsigned int depth, unsigned int max_depth, const OcTreeKey& key); /// recursive call of prune() void pruneRecurs(NODE* node, unsigned int depth, unsigned int max_depth, unsigned int& num_pruned); /// recursive call of expand() void expandRecurs(NODE* node, unsigned int depth, unsigned int max_depth); size_t getNumLeafNodesRecurs(const NODE* parent) const; private: /// Assignment operator is private: don't (re-)assign octrees /// (const-parameters can't be changed) - use the copy constructor instead. OcTreeBaseImpl& operator=(const OcTreeBaseImpl&); protected: void allocNodeChildren(NODE* node); NODE* root; ///< Pointer to the root NODE, NULL for empty tree // constants of the tree const unsigned int tree_depth; ///< Maximum tree depth is fixed to 16 currently const unsigned int tree_max_val; double resolution; ///< in meters double resolution_factor; ///< = 1. / resolution size_t tree_size; ///< number of nodes in tree /// flag to denote whether the octree extent changed (for lazy min/max eval) bool size_changed; point3d tree_center; // coordinate offset of tree double max_value[3]; ///< max in x, y, z double min_value[3]; ///< min in x, y, z /// contains the size of a voxel at level i (0: root node). tree_depth+1 levels (incl. 0) std::vector sizeLookupTable; /// data structure for ray casting, array for multithreading std::vector keyrays; const leaf_iterator leaf_iterator_end; const leaf_bbx_iterator leaf_iterator_bbx_end; const tree_iterator tree_iterator_end; }; } #include #endif