Program Listing for File OcTreeIterator.hxx
↰ Return to documentation for file (include/octomap/OcTreeIterator.hxx
)
/*
* 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_OCTREEITERATOR_HXX_
#define OCTOMAP_OCTREEITERATOR_HXX_
template<class NodeType>
class iterator_base{
public:
using iterator_category = std::forward_iterator_tag;
using value_type = NodeType;
using difference_type = NodeType;
using pointer = NodeType*;
using reference = NodeType&;
struct StackElement;
iterator_base() : tree(NULL), maxDepth(0){}
iterator_base(OcTreeBaseImpl<NodeType,INTERFACE> const* ptree, uint8_t depth=0)
: tree((ptree && ptree->root) ? ptree : NULL), maxDepth(depth)
{
if (ptree && maxDepth == 0)
maxDepth = ptree->getTreeDepth();
if (tree && tree->root){ // tree is not empty
StackElement s;
s.node = tree->root;
s.depth = 0;
s.key[0] = s.key[1] = s.key[2] = tree->tree_max_val;
stack.push(s);
} else{ // construct the same as "end"
tree = NULL;
this->maxDepth = 0;
}
}
iterator_base(const iterator_base& other)
: tree(other.tree), maxDepth(other.maxDepth), stack(other.stack) {}
bool operator==(const iterator_base& other) const {
return (tree ==other.tree && stack.size() == other.stack.size()
&& (stack.size()==0 || (stack.size() > 0 && (stack.top().node == other.stack.top().node
&& stack.top().depth == other.stack.top().depth
&& stack.top().key == other.stack.top().key ))));
}
bool operator!=(const iterator_base& other) const {
return (tree !=other.tree || stack.size() != other.stack.size()
|| (stack.size() > 0 && ((stack.top().node != other.stack.top().node
|| stack.top().depth != other.stack.top().depth
|| stack.top().key != other.stack.top().key ))));
}
iterator_base& operator=(const iterator_base& other){
tree = other.tree;
maxDepth = other.maxDepth;
stack = other.stack;
return *this;
}
NodeType const* operator->() const { return stack.top().node;}
NodeType* operator->() { return stack.top().node;}
const NodeType& operator*() const { return *(stack.top().node);}
NodeType& operator*() { return *(stack.top().node);}
point3d getCoordinate() const {
return tree->keyToCoord(stack.top().key, stack.top().depth);
}
double getX() const{
return tree->keyToCoord(stack.top().key[0], stack.top().depth);
}
double getY() const{
return tree->keyToCoord(stack.top().key[1], stack.top().depth);
}
double getZ() const{
return tree->keyToCoord(stack.top().key[2], stack.top().depth);
}
double getSize() const {return tree->getNodeSize(stack.top().depth); }
unsigned getDepth() const {return unsigned(stack.top().depth); }
const OcTreeKey& getKey() const {return stack.top().key;}
OcTreeKey getIndexKey() const {
return computeIndexKey(tree->getTreeDepth() - stack.top().depth, stack.top().key);
}
struct StackElement{
NodeType* node;
OcTreeKey key;
uint8_t depth;
};
protected:
OcTreeBaseImpl<NodeType,INTERFACE> const* tree;
uint8_t maxDepth;
std::stack<StackElement,std::vector<StackElement> > stack;
void singleIncrement(){
StackElement top = stack.top();
stack.pop();
if (top.depth == maxDepth)
return;
StackElement s;
s.depth = top.depth +1;
key_type center_offset_key = tree->tree_max_val >> s.depth;
// push on stack in reverse order
for (int i=7; i>=0; --i) {
if (tree->nodeChildExists(top.node,i)) {
computeChildKey(i, center_offset_key, top.key, s.key);
s.node = tree->getNodeChild(top.node, i);
//OCTOMAP_DEBUG_STR("Current depth: " << int(top.depth) << " new: "<< int(s.depth) << " child#" << i <<" ptr: "<<s.node);
stack.push(s);
assert(s.depth <= maxDepth);
}
}
}
};
class tree_iterator : public iterator_base<NodeType> {
public:
tree_iterator() : iterator_base<NodeType>(){}
tree_iterator(OcTreeBaseImpl<NodeType,INTERFACE> const* ptree, uint8_t depth=0) : iterator_base<NodeType>(ptree, depth) {}
tree_iterator operator++(int){
tree_iterator result = *this;
++(*this);
return result;
}
tree_iterator& operator++(){
if (!this->stack.empty()){
this->singleIncrement();
}
if (this->stack.empty()){
this->tree = NULL;
}
return *this;
}
bool isLeaf() const{
return (!this->tree->nodeHasChildren(this->stack.top().node) || this->stack.top().depth == this->maxDepth);
}
};
class leaf_iterator : public iterator_base<NodeType> {
public:
leaf_iterator() : iterator_base<NodeType>(){}
leaf_iterator(OcTreeBaseImpl<NodeType, INTERFACE> const* ptree, uint8_t depth=0) : iterator_base<NodeType>(ptree, depth) {
// tree could be empty (= no stack)
if (this->stack.size() > 0){
// skip forward to next valid leaf node:
// add root another time (one will be removed) and ++
this->stack.push(this->stack.top());
operator ++();
}
}
leaf_iterator(const leaf_iterator& other) : iterator_base<NodeType>(other) {}
leaf_iterator operator++(int){
leaf_iterator result = *this;
++(*this);
return result;
}
leaf_iterator& operator++(){
if (this->stack.empty()){
this->tree = NULL; // TODO check?
} else {
this->stack.pop();
// skip forward to next leaf
while(!this->stack.empty()
&& this->stack.top().depth < this->maxDepth
&& this->tree->nodeHasChildren(this->stack.top().node))
{
this->singleIncrement();
}
// done: either stack is empty (== end iterator) or a next leaf node is reached!
if (this->stack.empty())
this->tree = NULL;
}
return *this;
}
};
class leaf_bbx_iterator : public iterator_base<NodeType> {
public:
leaf_bbx_iterator() : iterator_base<NodeType>() {}
leaf_bbx_iterator(OcTreeBaseImpl<NodeType,INTERFACE> const* ptree, const point3d& min, const point3d& max, uint8_t depth=0)
: iterator_base<NodeType>(ptree, depth)
{
if (this->stack.size() > 0){
assert(ptree);
if (!this->tree->coordToKeyChecked(min, minKey) || !this->tree->coordToKeyChecked(max, maxKey)){
// coordinates invalid, set to end iterator
this->tree = NULL;
this->maxDepth = 0;
} else{ // else: keys are generated and stored
// advance from root to next valid leaf in bbx:
this->stack.push(this->stack.top());
this->operator ++();
}
}
}
leaf_bbx_iterator(OcTreeBaseImpl<NodeType,INTERFACE> const* ptree, const OcTreeKey& min, const OcTreeKey& max, uint8_t depth=0)
: iterator_base<NodeType>(ptree, depth), minKey(min), maxKey(max)
{
// tree could be empty (= no stack)
if (this->stack.size() > 0){
// advance from root to next valid leaf in bbx:
this->stack.push(this->stack.top());
this->operator ++();
}
}
leaf_bbx_iterator(const leaf_bbx_iterator& other) : iterator_base<NodeType>(other) {
minKey = other.minKey;
maxKey = other.maxKey;
}
leaf_bbx_iterator operator++(int){
leaf_bbx_iterator result = *this;
++(*this);
return result;
}
leaf_bbx_iterator& operator++(){
if (this->stack.empty()){
this->tree = NULL; // TODO check?
} else {
this->stack.pop();
// skip forward to next leaf
while(!this->stack.empty()
&& this->stack.top().depth < this->maxDepth
&& this->tree->nodeHasChildren(this->stack.top().node))
{
this->singleIncrement();
}
// done: either stack is empty (== end iterator) or a next leaf node is reached!
if (this->stack.empty())
this->tree = NULL;
}
return *this;
}
protected:
void singleIncrement(){
typename iterator_base<NodeType>::StackElement top = this->stack.top();
this->stack.pop();
typename iterator_base<NodeType>::StackElement s;
s.depth = top.depth +1;
key_type center_offset_key = this->tree->tree_max_val >> s.depth;
// push on stack in reverse order
for (int i=7; i>=0; --i) {
if (this->tree->nodeChildExists(top.node, i)) {
computeChildKey(i, center_offset_key, top.key, s.key);
// overlap of query bbx and child bbx?
if ((minKey[0] <= (s.key[0] + center_offset_key)) && (maxKey[0] >= (s.key[0] - center_offset_key))
&& (minKey[1] <= (s.key[1] + center_offset_key)) && (maxKey[1] >= (s.key[1] - center_offset_key))
&& (minKey[2] <= (s.key[2] + center_offset_key)) && (maxKey[2] >= (s.key[2] - center_offset_key)))
{
s.node = this->tree->getNodeChild(top.node, i);
this->stack.push(s);
assert(s.depth <= this->maxDepth);
}
}
}
}
OcTreeKey minKey;
OcTreeKey maxKey;
};
#endif /* OCTREEITERATOR_HXX_ */