octree_base.hpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Point Cloud Library (PCL) - www.pointclouds.org
00005  *  Copyright (c) 2010-2011, Willow Garage, Inc.
00006  *
00007  *  All rights reserved.
00008  *
00009  *  Redistribution and use in source and binary forms, with or without
00010  *  modification, are permitted provided that the following conditions
00011  *  are met:
00012  *
00013  *   * Redistributions of source code must retain the above copyright
00014  *     notice, this list of conditions and the following disclaimer.
00015  *   * Redistributions in binary form must reproduce the above
00016  *     copyright notice, this list of conditions and the following
00017  *     disclaimer in the documentation and/or other materials provided
00018  *     with the distribution.
00019  *   * Neither the name of Willow Garage, Inc. nor the names of its
00020  *     contributors may be used to endorse or promote products derived
00021  *     from this software without specific prior written permission.
00022  *
00023  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00026  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00027  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00028  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00029  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00031  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00033  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00034  *  POSSIBILITY OF SUCH DAMAGE.
00035  *
00036  * $Id: octree_base.hpp 6119 2012-07-03 18:50:04Z aichim $
00037  */
00038 
00039 #ifndef OCTREE_BASE_HPP
00040 #define OCTREE_BASE_HPP
00041 
00042 #include <vector>
00043 
00044 #include <pcl/impl/instantiate.hpp>
00045 #include <pcl/point_types.h>
00046 #include <pcl/octree/octree.h>
00047 
00048 // maximum depth of octree as we are using "unsigned int" octree keys / bit masks
00049 #define OCT_MAXTREEDEPTH ( sizeof(size_t) * 8  )
00050 
00051 namespace pcl
00052 {
00053   namespace octree
00054   {
00056     template<typename DataT, typename LeafT, typename BranchT>
00057     OctreeBase<DataT, LeafT, BranchT>::OctreeBase () :
00058       leafCount_ (0),
00059       branchCount_ (1),
00060       objectCount_ (0),
00061       rootNode_ (new BranchNode ()),
00062       maxObjsPerLeaf_(0),
00063       depthMask_ (0),
00064       octreeDepth_ (0),
00065       maxKey_ (),
00066       branchNodePool_ (),
00067       leafNodePool_ ()
00068     {
00069     }
00070 
00072     template<typename DataT, typename LeafT, typename BranchT>
00073     OctreeBase<DataT, LeafT, BranchT>::~OctreeBase ()
00074     {
00075       // deallocate tree structure
00076       deleteTree ();
00077       delete (rootNode_);
00078       poolCleanUp ();
00079     }
00080 
00082     template<typename DataT, typename LeafT, typename BranchT> void
00083     OctreeBase<DataT, LeafT, BranchT>::setMaxVoxelIndex (unsigned int maxVoxelIndex_arg)
00084     {
00085       unsigned int treeDepth;
00086 
00087       assert (maxVoxelIndex_arg>0);
00088 
00089       // tree depth == amount of bits of maxVoxels
00090       treeDepth = std::max ((std::min (static_cast<unsigned int> (OCT_MAXTREEDEPTH), 
00091                                        static_cast<unsigned int> (std::ceil (Log2 (maxVoxelIndex_arg))))),
00092                                        static_cast<unsigned int> (0));
00093 
00094       // define depthMask_ by setting a single bit to 1 at bit position == tree depth
00095       depthMask_ = (1 << (treeDepth - 1));
00096     }
00097 
00099     template<typename DataT, typename LeafT, typename BranchT>
00100     void
00101     OctreeBase<DataT, LeafT, BranchT>::setTreeDepth (unsigned int depth_arg)
00102     {
00103       assert(depth_arg>0);
00104 
00105       // set octree depth
00106       octreeDepth_ = depth_arg;
00107 
00108       // define depthMask_ by setting a single bit to 1 at bit position == tree depth
00109       depthMask_ = (1 << (depth_arg - 1));
00110 
00111       // define max. keys
00112       maxKey_.x = maxKey_.y = maxKey_.z = (1 << depth_arg) - 1;
00113     }
00114 
00116     template<typename DataT, typename LeafT, typename BranchT> void
00117     OctreeBase<DataT, LeafT, BranchT>::addData (unsigned int idxX_arg, unsigned int idxY_arg,
00118                                    unsigned int idxZ_arg, const DataT& data_arg)
00119     {
00120       // generate key
00121       OctreeKey key (idxX_arg, idxY_arg, idxZ_arg);
00122 
00123       // add data_arg to octree
00124       addData (key, data_arg);
00125     }
00126 
00128     template<typename DataT, typename LeafT, typename BranchT>bool
00129     OctreeBase<DataT, LeafT, BranchT>::getData (unsigned int idxX_arg, unsigned int idxY_arg,
00130                                    unsigned int idxZ_arg, DataT& data_arg) const
00131     {
00132       // generate key
00133       OctreeKey key (idxX_arg, idxY_arg, idxZ_arg);
00134 
00135       // search for leaf at key
00136       LeafNode* leaf = findLeaf (key);
00137       if (leaf)
00138       {
00139         // if successful, decode data to data_arg
00140         leaf->getData (data_arg);
00141       }
00142 
00143       // returns true on success
00144       return (leaf != 0);
00145     }
00146 
00148     template<typename DataT, typename LeafT, typename BranchT> bool
00149     OctreeBase<DataT, LeafT, BranchT>::existLeaf (unsigned int idxX_arg, unsigned int idxY_arg,
00150                                          unsigned int idxZ_arg) const
00151     {
00152       // generate key
00153       OctreeKey key (idxX_arg, idxY_arg, idxZ_arg);
00154 
00155       // check if key exist in octree
00156       return ( existLeaf (key));
00157     }
00158 
00160     template<typename DataT, typename LeafT, typename BranchT> void
00161     OctreeBase<DataT, LeafT, BranchT>::removeLeaf (unsigned int idxX_arg, unsigned int idxY_arg,
00162                                           unsigned int idxZ_arg)
00163     {
00164       // generate key
00165       OctreeKey key (idxX_arg, idxY_arg, idxZ_arg);
00166 
00167       // check if key exist in octree
00168       deleteLeafRecursive (key, depthMask_, rootNode_);
00169     }
00170 
00172     template<typename DataT, typename LeafT, typename BranchT> void
00173     OctreeBase<DataT, LeafT, BranchT>::deleteTree (bool freeMemory_arg )
00174     {
00175 
00176       if (rootNode_)
00177       {
00178         // reset octree
00179         deleteBranch (*rootNode_);
00180         leafCount_ = 0;
00181         branchCount_ = 1;
00182         objectCount_ = 0;
00183 
00184       }
00185 
00186       // delete node pool
00187       if (freeMemory_arg)
00188         poolCleanUp ();
00189 
00190     }
00191 
00193     template<typename DataT, typename LeafT, typename BranchT> void
00194     OctreeBase<DataT, LeafT, BranchT>::serializeTree (std::vector<char>& binaryTreeOut_arg)
00195     {
00196       // serialization requires fixed octree depth
00197       // maxObjsPerLeaf_>0 indicates a dynamic octree structure
00198       assert (!maxObjsPerLeaf_);
00199 
00200       OctreeKey newKey;
00201 
00202       // clear binary vector
00203       binaryTreeOut_arg.clear ();
00204       binaryTreeOut_arg.reserve (this->branchCount_);
00205 
00206       serializeTreeRecursive (rootNode_, newKey, &binaryTreeOut_arg, 0 );
00207     }
00208 
00210     template<typename DataT, typename LeafT, typename BranchT> void
00211     OctreeBase<DataT, LeafT, BranchT>::serializeTree (std::vector<char>& binaryTreeOut_arg, std::vector<DataT>& dataVector_arg)
00212     {
00213       // serialization requires fixed octree depth
00214       // maxObjsPerLeaf_>0 indicates a dynamic octree structure
00215       assert (!maxObjsPerLeaf_);
00216 
00217       OctreeKey newKey;
00218 
00219       // clear output vectors
00220       binaryTreeOut_arg.clear ();
00221       dataVector_arg.clear ();
00222 
00223       dataVector_arg.reserve (this->objectCount_);
00224       binaryTreeOut_arg.reserve (this->branchCount_);
00225 
00226       serializeTreeRecursive (rootNode_, newKey, &binaryTreeOut_arg, &dataVector_arg );
00227     }
00228 
00230     template<typename DataT, typename LeafT, typename BranchT> void
00231     OctreeBase<DataT, LeafT, BranchT>::serializeLeafs (std::vector<DataT>& dataVector_arg)
00232     {
00233       // serialization requires fixed octree depth
00234       // maxObjsPerLeaf_>0 indicates a dynamic octree structure
00235       assert (!maxObjsPerLeaf_);
00236 
00237       OctreeKey newKey;
00238 
00239       // clear output vector
00240       dataVector_arg.clear ();
00241 
00242       dataVector_arg.reserve(this->objectCount_);
00243 
00244       serializeTreeRecursive (rootNode_, newKey, 0, &dataVector_arg );
00245     }
00246 
00248     template<typename DataT, typename LeafT, typename BranchT> void
00249     OctreeBase<DataT, LeafT, BranchT>::deserializeTree (std::vector<char>& binaryTreeIn_arg)
00250     {
00251       // serialization requires fixed octree depth
00252       // maxObjsPerLeaf_>0 indicates a dynamic octree structure
00253       assert (!maxObjsPerLeaf_);
00254 
00255       OctreeKey newKey;
00256 
00257       // free existing tree before tree rebuild
00258       deleteTree ();
00259 
00260       //iterator for binary tree structure vector
00261       std::vector<char>::const_iterator binaryTreeVectorIterator = binaryTreeIn_arg.begin ();
00262       std::vector<char>::const_iterator binaryTreeVectorIteratorEnd = binaryTreeIn_arg.end ();
00263 
00264       deserializeTreeRecursive (rootNode_, depthMask_, newKey,
00265           binaryTreeVectorIterator, binaryTreeVectorIteratorEnd, 0, 0);
00266 
00267     }
00268 
00270     template<typename DataT, typename LeafT, typename BranchT> void
00271     OctreeBase<DataT, LeafT, BranchT>::deserializeTree (std::vector<char>& binaryTreeIn_arg,
00272                                                std::vector<DataT>& dataVector_arg)
00273     {
00274       // serialization requires fixed octree depth
00275       // maxObjsPerLeaf_>0 indicates a dynamic octree structure
00276       assert (!maxObjsPerLeaf_);
00277 
00278       OctreeKey newKey;
00279 
00280       // set data iterator to first element
00281       typename std::vector<DataT>::const_iterator dataVectorIterator = dataVector_arg.begin ();
00282 
00283       // set data iterator to last element
00284       typename std::vector<DataT>::const_iterator dataVectorEndIterator = dataVector_arg.end ();
00285 
00286       // free existing tree before tree rebuild
00287       deleteTree ();
00288 
00289       //iterator for binary tree structure vector
00290       std::vector<char>::const_iterator binaryTreeVectorIterator = binaryTreeIn_arg.begin ();
00291       std::vector<char>::const_iterator binaryTreeVectorIteratorEnd = binaryTreeIn_arg.end ();
00292 
00293       deserializeTreeRecursive (rootNode_, depthMask_, newKey,
00294           binaryTreeVectorIterator, binaryTreeVectorIteratorEnd, &dataVectorIterator, &dataVectorEndIterator);
00295 
00296     }
00297 
00299     template<typename DataT, typename LeafT, typename BranchT> void OctreeBase<
00300         DataT, LeafT, BranchT>::addDataToLeafRecursive (
00301         const OctreeKey& key_arg, unsigned int depthMask_arg,
00302         const DataT& data_arg, BranchNode* branch_arg)
00303     {
00304       // index to branch child
00305       unsigned char childIdx;
00306 
00307       // find branch child from key
00308       childIdx = key_arg.getChildIdxWithDepthMask(depthMask_arg);
00309 
00310       // add data to branch node container
00311       branch_arg->setData (data_arg);
00312 
00313       OctreeNode* childNode = (*branch_arg)[childIdx];
00314 
00315       if (!childNode)
00316       {
00317         if ((!maxObjsPerLeaf_) && (depthMask_arg > 1)) {
00318           // if required branch does not exist -> create it
00319           BranchNode* childBranch;
00320           createBranchChild (*branch_arg, childIdx, childBranch);
00321 
00322           branchCount_++;
00323 
00324           // recursively proceed with indexed child branch
00325           addDataToLeafRecursive (key_arg, depthMask_arg / 2, data_arg, childBranch);
00326 
00327         } else {
00328           LeafNode* childLeaf;
00329 
00330           // if leaf node at childIdx does not exist
00331           createLeafChild (*branch_arg, childIdx, childLeaf);
00332           leafCount_++;
00333 
00334           // add data to leaf
00335           childLeaf->setData (data_arg);
00336           objectCount_++;
00337         }
00338       } else {
00339 
00340         // Node exists already
00341         switch (childNode->getNodeType()) {
00342           case BRANCH_NODE:
00343             // recursively proceed with indexed child branch
00344             addDataToLeafRecursive (key_arg, depthMask_arg / 2, data_arg, static_cast<BranchNode*> (childNode));
00345             break;
00346 
00347           case LEAF_NODE:
00348             LeafNode* childLeaf = static_cast<LeafNode*> (childNode);
00349 
00350             if ( (!maxObjsPerLeaf_) || (!depthMask_arg) )
00351             {
00352               // add data to leaf
00353               childLeaf->setData (data_arg);
00354               objectCount_++;
00355             } else {
00356               size_t leafObjCount = childLeaf->getSize();
00357 
00358               if (leafObjCount<maxObjsPerLeaf_) {
00359                 // add data to leaf
00360                 childLeaf->setData (data_arg);
00361                 objectCount_++;
00362               } else {
00363                 // leaf node needs to be expanded
00364 
00365                 // copy leaf data
00366                 std::vector<DataT> leafData;
00367                 leafData.reserve(leafObjCount);
00368 
00369                 childLeaf->getData (leafData);
00370 
00371                 // delete current leaf node
00372                 deleteBranchChild(*branch_arg,childIdx);
00373                 leafCount_ --;
00374 
00375                 // create new branch node
00376                 BranchNode* childBranch;
00377                 createBranchChild (*branch_arg, childIdx, childBranch);
00378                 branchCount_ ++;
00379 
00380                 typename std::vector<DataT>::const_iterator lData = leafData.begin();
00381                 typename std::vector<DataT>::const_iterator lDataEnd = leafData.end();
00382 
00383                 // add data to new branch
00384                 OctreeKey dataKey;
00385                 while (lData!=lDataEnd) {
00386                   // get data object
00387                   const DataT& data = *lData++;
00388 
00389                   // generate new key for data object
00390                   if (this->genOctreeKeyForDataT(data, dataKey)) {
00391                     addDataToLeafRecursive (dataKey, depthMask_arg / 2, data, childBranch);
00392                   }
00393                 }
00394 
00395                 // and add new DataT object
00396                 addDataToLeafRecursive (key_arg, depthMask_arg / 2, data_arg, childBranch);
00397 
00398                 // correct object counter
00399                 objectCount_ -= leafObjCount;
00400               }
00401             }
00402             break;
00403         }
00404       }
00405     }
00406 
00408     template<typename DataT, typename LeafT, typename BranchT> void
00409     OctreeBase<DataT, LeafT, BranchT>::findLeafRecursive (
00410         const OctreeKey& key_arg, unsigned int depthMask_arg, BranchNode* branch_arg, LeafNode*& result_arg) const
00411     {
00412       // index to branch child
00413       unsigned char childIdx;
00414 
00415       // find branch child from key
00416       childIdx = key_arg.getChildIdxWithDepthMask(depthMask_arg);
00417 
00418       OctreeNode* childNode = (*branch_arg)[childIdx];
00419 
00420       if (childNode) {
00421         switch (childNode->getNodeType()) {
00422           case BRANCH_NODE:
00423             // we have not reached maximum tree depth
00424             BranchNode* childBranch;
00425             childBranch = static_cast<BranchNode*> (childNode);
00426 
00427             findLeafRecursive (key_arg, depthMask_arg / 2, childBranch, result_arg);
00428             break;
00429 
00430           case LEAF_NODE:
00431             // return existing leaf node
00432             LeafNode* childLeaf;
00433             childLeaf =  static_cast<LeafNode*> (childNode);
00434             result_arg = childLeaf;
00435             break;
00436         }
00437       }
00438     }
00439 
00441     template<typename DataT, typename LeafT, typename BranchT> bool
00442     OctreeBase<DataT, LeafT, BranchT>::deleteLeafRecursive (const OctreeKey& key_arg, unsigned int depthMask_arg,
00443                                                             BranchNode* branch_arg)
00444     {
00445       // index to branch child
00446       unsigned char childIdx;
00447       // indicates if branch is empty and can be safely removed
00448       bool bNoChilds;
00449 
00450       // find branch child from key
00451       childIdx = key_arg.getChildIdxWithDepthMask(depthMask_arg);
00452 
00453       OctreeNode* childNode = (*branch_arg)[childIdx];
00454 
00455       if (childNode) {
00456         switch (childNode->getNodeType()) {
00457 
00458           case BRANCH_NODE:
00459             BranchNode* childBranch;
00460             childBranch = static_cast<BranchNode*> (childNode);
00461 
00462             // recursively explore the indexed child branch
00463             bNoChilds = deleteLeafRecursive (key_arg, depthMask_arg / 2, childBranch);
00464 
00465             if (!bNoChilds)
00466             {
00467               // child branch does not own any sub-child nodes anymore -> delete child branch
00468               deleteBranchChild(*branch_arg, childIdx);
00469               branchCount_--;
00470             }
00471             break;
00472 
00473           case LEAF_NODE:
00474             // return existing leaf node
00475 
00476             // our child is a leaf node -> delete it
00477             deleteBranchChild (*branch_arg, childIdx);
00478             leafCount_--;
00479             break;
00480         }
00481       }
00482 
00483       // check if current branch still owns childs
00484       bNoChilds = false;
00485       for (childIdx = 0; (!bNoChilds) && (childIdx < 8); childIdx++)
00486       {
00487         bNoChilds = branch_arg->hasChild(childIdx);
00488       }
00489       // return true if current branch can be deleted
00490       return (bNoChilds);
00491     }
00492 
00494     template<typename DataT, typename LeafT, typename BranchT> void OctreeBase<
00495         DataT, LeafT, BranchT>::serializeTreeRecursive (const BranchNode* branch_arg, OctreeKey& key_arg,
00496             std::vector<char>* binaryTreeOut_arg,
00497             typename std::vector<DataT>* dataVector_arg) const
00498     {
00499 
00500       // child iterator
00501       unsigned char childIdx;
00502       char nodeBitPattern;
00503 
00504       // branch occupancy bit pattern
00505       nodeBitPattern = getBranchBitPattern (*branch_arg);
00506 
00507       // write bit pattern to output vector
00508       if (binaryTreeOut_arg)
00509         binaryTreeOut_arg->push_back (nodeBitPattern);
00510 
00511       // iterate over all children
00512       for (childIdx = 0; childIdx < 8; childIdx++)
00513       {
00514 
00515         // if child exist
00516         if (branch_arg->hasChild(childIdx))
00517         {
00518           // add current branch voxel to key
00519           key_arg.pushBranch(childIdx);
00520 
00521           const OctreeNode *childNode = branch_arg->getChildPtr(childIdx);
00522 
00523           switch (childNode->getNodeType ())
00524           {
00525             case BRANCH_NODE:
00526             {
00527               // recursively proceed with indexed child branch
00528               serializeTreeRecursive (
00529                   static_cast<const BranchNode*> (childNode), key_arg,
00530                   binaryTreeOut_arg, dataVector_arg);
00531               break;
00532             }
00533             case LEAF_NODE:
00534             {
00535               const LeafNode* childLeaf = static_cast<const LeafNode*> (childNode);
00536 
00537               if (dataVector_arg)
00538                 childLeaf->getData (*dataVector_arg);
00539 
00540               // we reached a leaf node -> execute serialization callback
00541               serializeTreeCallback (*childLeaf, key_arg);
00542               break;
00543             }
00544             default:
00545               break;
00546            }
00547 
00548           // pop current branch voxel from key
00549           key_arg.popBranch();
00550         }
00551       }
00552     }
00553 
00554 
00555 
00557     template<typename DataT, typename LeafT, typename BranchT> void
00558     OctreeBase<DataT, LeafT, BranchT>::deserializeTreeRecursive (BranchNode* branch_arg,
00559         unsigned int depthMask_arg, OctreeKey& key_arg,
00560         typename std::vector<char>::const_iterator& binaryTreeIT_arg,
00561         typename std::vector<char>::const_iterator& binaryTreeIT_End_arg,
00562         typename std::vector<DataT>::const_iterator* dataVectorIterator_arg,
00563         typename std::vector<DataT>::const_iterator* dataVectorEndIterator_arg)
00564     {
00565       // child iterator
00566       unsigned char childIdx;
00567       char nodeBits;
00568 
00569       if (binaryTreeIT_arg != binaryTreeIT_End_arg ) {
00570         // read branch occupancy bit pattern from input vector
00571         nodeBits = (*binaryTreeIT_arg);
00572         binaryTreeIT_arg++;
00573 
00574         // iterate over all children
00575         for (childIdx = 0; childIdx < 8; childIdx++)
00576         {
00577           // if occupancy bit for childIdx is set..
00578           if (nodeBits & (1 << childIdx))
00579           {
00580             // add current branch voxel to key
00581             key_arg.pushBranch(childIdx);
00582 
00583             if (depthMask_arg > 1)
00584             {
00585               // we have not reached maximum tree depth
00586               BranchNode * newBranch;
00587 
00588               // create new child branch
00589               createBranchChild (*branch_arg, childIdx, newBranch);
00590 
00591               branchCount_++;
00592 
00593               // recursively proceed with new child branch
00594               deserializeTreeRecursive (newBranch, depthMask_arg / 2, key_arg, binaryTreeIT_arg,binaryTreeIT_End_arg,  dataVectorIterator_arg,
00595                                         dataVectorEndIterator_arg);
00596             }
00597             else
00598             {
00599               // we reached leaf node level
00600 
00601               LeafNode* childLeaf;
00602 
00603               // create leaf node
00604               createLeafChild (*branch_arg, childIdx, childLeaf);
00605 
00606               OctreeKey dataKey;
00607               bool bKeyBasedEncoding = false;
00608 
00609               if (dataVectorIterator_arg
00610                   && (*dataVectorIterator_arg != *dataVectorEndIterator_arg))
00611               {
00612 
00613                 // add DataT objects to octree leaf as long as their key fit to voxel
00614                 while ( ( (*dataVectorIterator_arg)
00615                     != (*dataVectorEndIterator_arg))
00616                     && (this->genOctreeKeyForDataT (**dataVectorIterator_arg,
00617                         dataKey) && (dataKey == key_arg)))
00618                 {
00619                   childLeaf->setData (**dataVectorIterator_arg);
00620                   (*dataVectorIterator_arg)++;
00621                   bKeyBasedEncoding = true;
00622                   objectCount_++;
00623                 }
00624 
00625                 // add single DataT object to octree if key-based encoding is disabled
00626                 if (!bKeyBasedEncoding)
00627                 {
00628                   childLeaf->setData (**dataVectorIterator_arg);
00629                   (*dataVectorIterator_arg)++;
00630                   objectCount_++;
00631                 }
00632               }
00633 
00634               leafCount_++;
00635 
00636               // execute deserialization callback
00637               deserializeTreeCallback (*childLeaf, key_arg);
00638             }
00639 
00640             // pop current branch voxel from key
00641             key_arg.popBranch();
00642           }
00643         }
00644       }
00645     }
00646 
00647   }
00648 }
00649 
00650 #define PCL_INSTANTIATE_OctreeBase(T) template class PCL_EXPORTS pcl::octree::OctreeBase<T>;
00651 
00652 #endif
00653 


pcl
Author(s): Open Perception
autogenerated on Mon Oct 6 2014 03:15:56