octomap 1.5.0
include/octomap/OccupancyOcTreeBase.hxx
Go to the documentation of this file.
00001 // $Id: OccupancyOcTreeBase.hxx 408 2012-08-22 09:59:55Z ahornung $
00002 
00011 /*
00012  * Copyright (c) 2009-2011, K. M. Wurm, A. Hornung, University of Freiburg
00013  * All rights reserved.
00014  *
00015  * Redistribution and use in source and binary forms, with or without
00016  * modification, are permitted provided that the following conditions are met:
00017  *
00018  *     * Redistributions of source code must retain the above copyright
00019  *       notice, this list of conditions and the following disclaimer.
00020  *     * Redistributions in binary form must reproduce the above copyright
00021  *       notice, this list of conditions and the following disclaimer in the
00022  *       documentation and/or other materials provided with the distribution.
00023  *     * Neither the name of the University of Freiburg nor the names of its
00024  *       contributors may be used to endorse or promote products derived from
00025  *       this software without specific prior written permission.
00026  *
00027  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00028  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00029  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00030  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00031  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00032  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00033  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00034  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00035  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00036  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00037  * POSSIBILITY OF SUCH DAMAGE.
00038  */
00039 
00040 #include <bitset>
00041 
00042 namespace octomap {
00043 
00044   template <class NODE>
00045   OccupancyOcTreeBase<NODE>::OccupancyOcTreeBase(double resolution)
00046     : OcTreeBaseImpl<NODE,AbstractOccupancyOcTree>(resolution), use_bbx_limit(false), use_change_detection(false)
00047   {
00048 
00049   }
00050   
00051   template <class NODE>
00052   OccupancyOcTreeBase<NODE>::OccupancyOcTreeBase(double resolution, unsigned int tree_depth, unsigned int tree_max_val)
00053     : OcTreeBaseImpl<NODE,AbstractOccupancyOcTree>(resolution, tree_depth, tree_max_val), use_bbx_limit(false), use_change_detection(false)
00054   {
00055 
00056   }  
00057 
00058   template <class NODE>
00059   OccupancyOcTreeBase<NODE>::~OccupancyOcTreeBase(){
00060   }
00061 
00062   template <class NODE>
00063   OccupancyOcTreeBase<NODE>::OccupancyOcTreeBase(const OccupancyOcTreeBase<NODE>& rhs) :
00064   OcTreeBaseImpl<NODE,AbstractOccupancyOcTree>(rhs), use_bbx_limit(rhs.use_bbx_limit),
00065     bbx_min(rhs.bbx_min), bbx_max(rhs.bbx_max),
00066     bbx_min_key(rhs.bbx_min_key), bbx_max_key(rhs.bbx_max_key),
00067     use_change_detection(rhs.use_change_detection), changed_keys(rhs.changed_keys)
00068   {
00069     this->clamping_thres_min = rhs.clamping_thres_min;
00070     this->clamping_thres_max = rhs.clamping_thres_max;
00071     this->prob_hit_log = rhs.prob_hit_log;
00072     this->prob_miss_log = rhs.prob_miss_log;
00073     this->occ_prob_thres_log = rhs.occ_prob_thres_log;
00074 
00075 
00076   }
00077 
00078   // performs transformation to data and sensor origin first
00079   template <class NODE>
00080   void OccupancyOcTreeBase<NODE>::insertScan(const ScanNode& scan, double maxrange, bool pruning, bool lazy_eval) {
00081     Pointcloud& cloud = *(scan.scan);
00082     pose6d frame_origin = scan.pose;
00083     point3d sensor_origin = frame_origin.inv().transform(scan.pose.trans());
00084     insertScan(cloud, sensor_origin, frame_origin, maxrange, pruning, lazy_eval);
00085   }
00086 
00087 
00088   template <class NODE>
00089   void OccupancyOcTreeBase<NODE>::insertScan(const Pointcloud& scan, const octomap::point3d& sensor_origin, 
00090                                              double maxrange, bool pruning, bool lazy_eval) {
00091 
00092     KeySet free_cells, occupied_cells;
00093     computeUpdate(scan, sensor_origin, free_cells, occupied_cells, maxrange);    
00094 
00095     // insert data into tree  -----------------------
00096     for (KeySet::iterator it = free_cells.begin(); it != free_cells.end(); ++it) {
00097       updateNode(*it, false, lazy_eval);
00098     }
00099     for (KeySet::iterator it = occupied_cells.begin(); it != occupied_cells.end(); ++it) {
00100       updateNode(*it, true, lazy_eval);
00101     }
00102 
00103     // TODO: does pruning make sense if we used "lazy_eval"?
00104     if (pruning) this->prune();
00105   } 
00106 
00107   // performs transformation to data and sensor origin first
00108   template <class NODE>
00109   void OccupancyOcTreeBase<NODE>::insertScan(const Pointcloud& pc, const point3d& sensor_origin, const pose6d& frame_origin, 
00110                                              double maxrange, bool pruning, bool lazy_eval) {
00111     Pointcloud transformed_scan (pc);
00112     transformed_scan.transform(frame_origin);
00113     point3d transformed_sensor_origin = frame_origin.transform(sensor_origin);
00114     insertScan(transformed_scan, transformed_sensor_origin, maxrange, pruning, lazy_eval);
00115   }
00116 
00117 
00118   template <class NODE>
00119   void OccupancyOcTreeBase<NODE>::insertScanNaive(const Pointcloud& pc, const point3d& origin, double maxrange, bool pruning, bool lazy_eval) {
00120     if (pc.size() < 1)
00121       return;
00122 
00123     // integrate each single beam
00124     octomap::point3d p;
00125     for (octomap::Pointcloud::const_iterator point_it = pc.begin();
00126          point_it != pc.end(); point_it++) {
00127       this->insertRay(origin, *point_it, maxrange, lazy_eval);
00128     }
00129 
00130     if (pruning)
00131       this->prune();
00132   }
00133 
00134 
00135   template <class NODE>
00136   void OccupancyOcTreeBase<NODE>::computeUpdate(const Pointcloud& scan, const octomap::point3d& origin,
00137                                                 KeySet& free_cells, KeySet& occupied_cells,
00138                                                 double maxrange) {
00139 
00140     //#pragma omp parallel private (local_key_ray, point_it) 
00141     for (Pointcloud::const_iterator point_it = scan.begin(); point_it != scan.end(); point_it++) {
00142       const point3d& p = *point_it;
00143       if (!use_bbx_limit) {
00144         // -------------- no BBX specified ---------------
00145         if ((maxrange < 0.0) || ((p - origin).norm() <= maxrange) ) { // is not maxrange meas.
00146           // free cells
00147           if (this->computeRayKeys(origin, p, this->keyray)){
00148             free_cells.insert(this->keyray.begin(), this->keyray.end());
00149           }
00150           // occupied endpoint
00151           OcTreeKey key;
00152           if (this->coordToKeyChecked(p, key))
00153             occupied_cells.insert(key);
00154         } // end if NOT maxrange
00155 
00156         else { // user set a maxrange and this is reached
00157           point3d direction = (p - origin).normalized ();
00158           point3d new_end = origin + direction * (float) maxrange;
00159           if (this->computeRayKeys(origin, new_end, this->keyray)){
00160             free_cells.insert(this->keyray.begin(), this->keyray.end());
00161           }
00162         } // end if maxrange
00163       }
00164 
00165       // --- update limited by user specified BBX  -----
00166       else {
00167         // endpoint in bbx and not maxrange?
00168         if ( inBBX(p) && ((maxrange < 0.0) || ((p - origin).norm () <= maxrange) ) )  {
00169 
00170           // occupied endpoint
00171           OcTreeKey key;
00172           if (this->coordToKeyChecked(p, key))
00173             occupied_cells.insert(key);
00174 
00175           // update freespace, break as soon as bbx limit is reached
00176           if (this->computeRayKeys(origin, p, this->keyray)){
00177             for(KeyRay::reverse_iterator rit=this->keyray.rbegin(); rit != this->keyray.rend(); rit++) {
00178               if (inBBX(*rit)) {
00179                 free_cells.insert(*rit);
00180               }
00181               else break;
00182             }
00183           } // end if compute ray
00184         } // end if in BBX and not maxrange
00185       } // end bbx case
00186 
00187     } // end for all points
00188 
00189     // prefer occupied cells over free ones (and make sets disjunct)
00190     for(KeySet::iterator it = free_cells.begin(), end=free_cells.end(); it!= end; ){
00191       if (occupied_cells.find(*it) != occupied_cells.end()){
00192         it = free_cells.erase(it);
00193       } else {
00194         ++it;
00195       }
00196     }
00197   }
00198 
00199   template <class NODE>
00200   NODE* OccupancyOcTreeBase<NODE>::updateNode(const OcTreeKey& key, float log_odds_update, bool lazy_eval) {
00201     return updateNodeRecurs(this->root, false, key, 0, log_odds_update, lazy_eval);
00202   }
00203 
00204   template <class NODE>
00205   NODE* OccupancyOcTreeBase<NODE>::updateNode(const point3d& value, float log_odds_update, bool lazy_eval) {
00206     OcTreeKey key;
00207     if (!this->coordToKeyChecked(value, key)) return NULL;
00208     return updateNode(key, log_odds_update, lazy_eval);
00209   }
00210 
00211   template <class NODE>
00212   NODE* OccupancyOcTreeBase<NODE>::updateNode(const OcTreeKey& key, bool occupied, bool lazy_eval) {
00213     NODE* leaf = this->search(key);
00214     // no change: node already at threshold
00215     if (leaf && (this->isNodeAtThreshold(leaf)) && (this->isNodeOccupied(leaf) == occupied)) {
00216       return leaf;
00217     }
00218     if (occupied) return updateNodeRecurs(this->root, false, key, 0, this->prob_hit_log,  lazy_eval);
00219     else          return updateNodeRecurs(this->root, false, key, 0, this->prob_miss_log, lazy_eval);
00220   }
00221 
00222   template <class NODE>
00223   NODE* OccupancyOcTreeBase<NODE>::updateNode(const point3d& value, bool occupied, bool lazy_eval) {
00224     OcTreeKey key;
00225     if (!this->coordToKeyChecked(value, key)) return NULL;
00226     return updateNode(key, occupied, lazy_eval);
00227   }
00228 
00229   template <class NODE>
00230   NODE* OccupancyOcTreeBase<NODE>::updateNodeRecurs(NODE* node, bool node_just_created, const OcTreeKey& key,
00231                                                     unsigned int depth, const float& log_odds_update, bool lazy_eval) {
00232     unsigned int pos = computeChildIdx(key, this->tree_depth-1-depth);
00233     bool created_node = false;
00234 
00235     // follow down to last level
00236     if (depth < this->tree_depth) {
00237       if (!node->childExists(pos)) {
00238         // child does not exist, but maybe it's a pruned node?
00239         if ((!node->hasChildren()) && !node_just_created && (node != this->root)) {
00240           // current node does not have children AND it is not a new node 
00241           // AND its not the root node
00242           // -> expand pruned node
00243           node->expandNode();
00244           this->tree_size+=8;
00245           this->size_changed = true;
00246         }
00247         else {
00248           // not a pruned node, create requested child
00249           node->createChild(pos);
00250           this->tree_size++;
00251           this->size_changed = true;
00252           created_node = true;
00253         }
00254       }
00255 
00256       if (lazy_eval)
00257         return updateNodeRecurs(node->getChild(pos), created_node, key, depth+1, log_odds_update, lazy_eval);
00258       else {
00259         NODE* retval = updateNodeRecurs(node->getChild(pos), created_node, key, depth+1, log_odds_update, lazy_eval);
00260         // set own probability according to prob of children
00261         node->updateOccupancyChildren();
00262         return retval;
00263       }
00264     }
00265 
00266     // at last level, update node, end of recursion
00267     else {
00268       if (use_change_detection) {
00269         bool occBefore = isNodeOccupied(node);
00270         updateNodeLogOdds(node, log_odds_update); 
00271         if (node_just_created){  // new node
00272           changed_keys.insert(std::pair<OcTreeKey,bool>(key, true));
00273         } else if (occBefore != isNodeOccupied(node)) {  // occupancy changed, track it
00274           KeyBoolMap::iterator it = changed_keys.find(key);
00275           if (it == changed_keys.end())
00276             changed_keys.insert(std::pair<OcTreeKey,bool>(key, false));
00277           else if (it->second == false)
00278             changed_keys.erase(it);
00279         }
00280       }
00281       else {
00282         updateNodeLogOdds(node, log_odds_update); 
00283       }
00284       return node;
00285     }
00286   }
00287   
00288 
00289   template <class NODE>
00290   void OccupancyOcTreeBase<NODE>::calcNumThresholdedNodes(unsigned int& num_thresholded,
00291                                        unsigned int& num_other) const {
00292     num_thresholded = 0;
00293     num_other = 0;
00294     // TODO: The recursive call could be completely replaced with the new iterators
00295     calcNumThresholdedNodesRecurs(this->root, num_thresholded, num_other);
00296   }
00297 
00298   template <class NODE>
00299   void OccupancyOcTreeBase<NODE>::calcNumThresholdedNodesRecurs (NODE* node,
00300                                               unsigned int& num_thresholded,
00301                                               unsigned int& num_other) const {
00302     assert(node != NULL);
00303     for (unsigned int i=0; i<8; i++) {
00304       if (node->childExists(i)) {
00305         NODE* child_node = node->getChild(i);
00306         if (isNodeAtThreshold(child_node))
00307           num_thresholded++;
00308         else
00309           num_other++;
00310         calcNumThresholdedNodesRecurs(child_node, num_thresholded, num_other);
00311       } // end if child
00312     } // end for children
00313   }
00314 
00315   template <class NODE>
00316   void OccupancyOcTreeBase<NODE>::updateInnerOccupancy(){
00317     this->updateInnerOccupancyRecurs(this->root, 0);
00318   }
00319 
00320   template <class NODE>
00321   void OccupancyOcTreeBase<NODE>::updateInnerOccupancyRecurs(NODE* node, unsigned int depth){
00322     // only recurse and update for inner nodes:
00323     if (node->hasChildren()){
00324       // return early for last level:
00325       if (depth < this->tree_depth){
00326         for (unsigned int i=0; i<8; i++) {
00327           if (node->childExists(i)) {
00328             updateInnerOccupancyRecurs(node->getChild(i), depth+1);
00329           }
00330         }
00331       }
00332       node->updateOccupancyChildren();
00333     }
00334   }
00335 
00336   template <class NODE>
00337   void OccupancyOcTreeBase<NODE>::toMaxLikelihood() {
00338 
00339     // convert bottom up
00340     for (unsigned int depth=this->tree_depth; depth>0; depth--) {
00341       toMaxLikelihoodRecurs(this->root, 0, depth);
00342     }
00343 
00344     // convert root
00345     nodeToMaxLikelihood(this->root);
00346   }
00347 
00348   template <class NODE>
00349   void OccupancyOcTreeBase<NODE>::toMaxLikelihoodRecurs(NODE* node, unsigned int depth,
00350       unsigned int max_depth) {
00351 
00352     if (depth < max_depth) {
00353       for (unsigned int i=0; i<8; i++) {
00354         if (node->childExists(i)) {
00355           toMaxLikelihoodRecurs(node->getChild(i), depth+1, max_depth);
00356         }
00357       }
00358     }
00359 
00360     else { // max level reached
00361       nodeToMaxLikelihood(node);
00362     }
00363   }
00364   
00365   template <class NODE>
00366   bool OccupancyOcTreeBase<NODE>::castRay(const point3d& origin, const point3d& directionP, point3d& end, 
00367                                           bool ignoreUnknown, double maxRange) const {
00368 
00370 
00371     // Initialization phase -------------------------------------------------------
00372     OcTreeKey current_key;
00373     if ( !OcTreeBaseImpl<NODE,AbstractOccupancyOcTree>::coordToKeyChecked(origin, current_key) ) {
00374       OCTOMAP_WARNING_STR("Coordinates out of bounds during ray casting");
00375       return false;
00376     }
00377 
00378     NODE* startingNode = this->search(current_key);
00379     if (startingNode){
00380       if (isNodeOccupied(startingNode)){
00381         // Occupied node found at origin 
00382         // (need to convert from key, since origin does not need to be a voxel center)
00383         end = this->keyToCoord(current_key);
00384         return true;
00385       }
00386     } else if(!ignoreUnknown){
00387       OCTOMAP_ERROR_STR("Origin node at " << origin << " for raycasting not found, does the node exist?");
00388       end = this->keyToCoord(current_key);
00389       return false;
00390     }
00391 
00392     point3d direction = directionP.normalized();
00393     bool max_range_set = (maxRange > 0.0);
00394 
00395     int step[3]; 
00396     double tMax[3];
00397     double tDelta[3];
00398 
00399     for(unsigned int i=0; i < 3; ++i) {
00400       // compute step direction
00401       if (direction(i) > 0.0) step[i] =  1;
00402       else if (direction(i) < 0.0)   step[i] = -1;
00403       else step[i] = 0;
00404 
00405       // compute tMax, tDelta
00406       if (step[i] != 0) {
00407         // corner point of voxel (in direction of ray)
00408         double voxelBorder = this->keyToCoord(current_key[i]);
00409         voxelBorder += double(step[i] * this->resolution * 0.5);
00410 
00411         tMax[i] = ( voxelBorder - origin(i) ) / direction(i);
00412         tDelta[i] = this->resolution / fabs( direction(i) );
00413       }
00414       else {
00415         tMax[i] =  std::numeric_limits<double>::max();
00416         tDelta[i] = std::numeric_limits<double>::max();
00417       }
00418     }
00419 
00420     if (step[0] == 0 && step[1] == 0 && step[2] == 0){
00421       OCTOMAP_ERROR("Raycasting in direction (0,0,0) is not possible!");
00422       return false;
00423     }
00424 
00425     // for speedup:
00426     point3d origin_scaled = origin;  
00427     origin_scaled /= (float) this->resolution;  
00428     double maxrange_2 = maxRange / this->resolution;  // scale
00429     maxrange_2 = maxrange_2*maxrange_2; // squared dist
00430     double res_2 = this->resolution/2.;
00431     // Incremental phase  ---------------------------------------------------------
00432 
00433     bool done = false;
00434 
00435     while (!done) {
00436       unsigned int dim;
00437 
00438       // find minimum tMax:
00439       if (tMax[0] < tMax[1]){
00440         if (tMax[0] < tMax[2]) dim = 0;
00441         else                   dim = 2;
00442       }
00443       else {
00444         if (tMax[1] < tMax[2]) dim = 1;
00445         else                   dim = 2;
00446       }
00447 
00448       // check for overflow:
00449       if ((step[dim] < 0 && current_key[dim] == 0)
00450           || (step[dim] > 0 && current_key[dim] == 2* this->tree_max_val-1))
00451       {
00452         OCTOMAP_WARNING("Coordinate hit bounds in dim %d, aborting raycast\n", dim);
00453         // return border point nevertheless:
00454         end = this->keyToCoord(current_key);
00455         return false;
00456       }
00457 
00458       // advance in direction "dim"
00459       current_key[dim] += step[dim];
00460       tMax[dim] += tDelta[dim];
00461 
00462 
00463       // generate world coords from key
00464       double dist_from_origin(0);
00465       for (unsigned int j = 0; j < 3; j++) {
00466         double coord = (double) current_key[j] - (double) this->tree_max_val + res_2; // center of voxel
00467         dist_from_origin += (coord - origin_scaled(j)) * (coord - origin_scaled(j));
00468         end(j) = (float) (coord * this->resolution);
00469       }
00470 
00471       if (max_range_set && (dist_from_origin > maxrange_2) ) { // reached user specified maxrange
00472         return false;
00473       }
00474 
00475       NODE* currentNode = this->search(current_key);
00476       if (currentNode){
00477         if (isNodeOccupied(currentNode)) {
00478           done = true;
00479           break;
00480         }
00481         // otherwise: node is free and valid, raycasting continues
00482       }
00483       
00484       else if (!ignoreUnknown){ // no node found, this usually means we are in "unknown" areas
00485         OCTOMAP_WARNING_STR("Search failed in OcTree::castRay() => an unknown area was hit in the map: " << end);
00486         return false;
00487       }
00488     } // end while
00489 
00490     return true;
00491   }
00492 
00493 
00494   template <class NODE> inline bool 
00495   OccupancyOcTreeBase<NODE>::integrateMissOnRay(const point3d& origin, const point3d& end, bool lazy_eval) {
00496 
00497     if (!this->computeRayKeys(origin, end, this->keyray)) {
00498       return false;
00499     }
00500     
00501     for(KeyRay::iterator it=this->keyray.begin(); it != this->keyray.end(); it++) {
00502       updateNode(*it, false, lazy_eval); // insert freespace measurement
00503     }
00504   
00505     return true;
00506   }
00507 
00508   template <class NODE> bool 
00509   OccupancyOcTreeBase<NODE>::insertRay(const point3d& origin, const point3d& end, double maxrange, bool lazy_eval)
00510   {
00511     // cut ray at maxrange
00512     if ((maxrange > 0) && ((end - origin).norm () > maxrange)) 
00513       {
00514         point3d direction = (end - origin).normalized ();
00515         point3d new_end = origin + direction * (float) maxrange;
00516         return integrateMissOnRay(origin, new_end,lazy_eval);
00517       }
00518     // insert complete ray
00519     else 
00520       {
00521         if (!integrateMissOnRay(origin, end,lazy_eval))
00522           return false;
00523         updateNode(end, true, lazy_eval); // insert hit cell
00524         return true;
00525       }
00526   }
00527   
00528   template <class NODE>
00529   void OccupancyOcTreeBase<NODE>::getOccupied(point3d_list& node_centers, unsigned int max_depth) const {
00530 
00531     if (max_depth == 0)
00532       max_depth = this->tree_depth;
00533 
00534     for(typename OccupancyOcTreeBase<NODE>::leaf_iterator it = this->begin(max_depth),
00535         end=this->end(); it!= end; ++it)
00536     {
00537       if(this->isNodeOccupied(*it))
00538         node_centers.push_back(it.getCoordinate());
00539     }
00540   }
00541 
00542 
00543   template <class NODE>
00544   void OccupancyOcTreeBase<NODE>::getOccupied(std::list<OcTreeVolume>& occupied_nodes, unsigned int max_depth) const{
00545 
00546     if (max_depth == 0)
00547       max_depth = this->tree_depth;
00548 
00549     for(typename OccupancyOcTreeBase<NODE>::leaf_iterator it = this->begin(max_depth),
00550             end=this->end(); it!= end; ++it)
00551     {
00552       if(this->isNodeOccupied(*it))
00553         occupied_nodes.push_back(OcTreeVolume(it.getCoordinate(), it.getSize()));
00554     }
00555 
00556   }
00557 
00558   
00559   template <class NODE>
00560   void OccupancyOcTreeBase<NODE>::getOccupied(std::list<OcTreeVolume>& binary_nodes,
00561                                               std::list<OcTreeVolume>& delta_nodes,
00562                                               unsigned int max_depth) const{    
00563     if (max_depth == 0)
00564       max_depth = this->tree_depth;
00565 
00566     for(typename OccupancyOcTreeBase<NODE>::leaf_iterator it = this->begin(max_depth),
00567             end=this->end(); it!= end; ++it)
00568     {
00569       if(this->isNodeOccupied(*it)){
00570         if (it->getLogOdds() >= this->clamping_thres_max)
00571           binary_nodes.push_back(OcTreeVolume(it.getCoordinate(), it.getSize()));
00572         else
00573           delta_nodes.push_back(OcTreeVolume(it.getCoordinate(), it.getSize()));
00574       }
00575     }
00576   }
00577 
00578   template <class NODE>
00579   void OccupancyOcTreeBase<NODE>::getFreespace(std::list<OcTreeVolume>& free_nodes, unsigned int max_depth) const{
00580 
00581     if (max_depth == 0)
00582       max_depth = this->tree_depth;
00583 
00584     for(typename OccupancyOcTreeBase<NODE>::leaf_iterator it = this->begin(max_depth),
00585             end=this->end(); it!= end; ++it)
00586     {
00587       if(!this->isNodeOccupied(*it))
00588         free_nodes.push_back(OcTreeVolume(it.getCoordinate(), it.getSize()));
00589     }
00590   }
00591 
00592 
00593   template <class NODE>
00594   void OccupancyOcTreeBase<NODE>::getFreespace(std::list<OcTreeVolume>& binary_nodes,
00595                                                std::list<OcTreeVolume>& delta_nodes,
00596                                                unsigned int max_depth) const{
00597 
00598     if (max_depth == 0)
00599       max_depth = this->tree_depth;
00600 
00601     for(typename OccupancyOcTreeBase<NODE>::leaf_iterator it = this->begin(max_depth),
00602             end=this->end(); it!= end; ++it)
00603     {
00604       if(!this->isNodeOccupied(*it)){
00605         if (it->getLogOdds() <= this->clamping_thres_min)
00606           binary_nodes.push_back(OcTreeVolume(it.getCoordinate(), it.getSize()));
00607         else
00608           delta_nodes.push_back(OcTreeVolume(it.getCoordinate(), it.getSize()));
00609       }
00610     }
00611   }
00612 
00613   
00614   template <class NODE>
00615   void OccupancyOcTreeBase<NODE>::setBBXMin (point3d& min) { 
00616     bbx_min = min; 
00617     if (!this->genKey(bbx_min, bbx_min_key)) {
00618       OCTOMAP_ERROR("ERROR while generating bbx min key.\n");
00619     }
00620   }
00621 
00622   template <class NODE>
00623   void OccupancyOcTreeBase<NODE>::setBBXMax (point3d& max) {
00624     bbx_max = max; 
00625     if (!this->genKey(bbx_max, bbx_max_key)) {
00626       OCTOMAP_ERROR("ERROR while generating bbx max key.\n");
00627     }
00628   }
00629 
00630 
00631   template <class NODE>
00632   bool OccupancyOcTreeBase<NODE>::inBBX(const point3d& p) const {
00633     return ((p.x() >= bbx_min.x()) && (p.y() >= bbx_min.y()) && (p.z() >= bbx_min.z()) &&
00634             (p.x() <= bbx_max.x()) && (p.y() <= bbx_max.y()) && (p.z() <= bbx_max.z()) );
00635   }
00636 
00637 
00638   template <class NODE>
00639   bool OccupancyOcTreeBase<NODE>::inBBX(const OcTreeKey& key) const {
00640     return ((key[0] >= bbx_min_key[0]) && (key[1] >= bbx_min_key[1]) && (key[2] >= bbx_min_key[2]) &&
00641             (key[0] <= bbx_max_key[0]) && (key[1] <= bbx_max_key[1]) && (key[2] <= bbx_max_key[2]) );
00642   }
00643 
00644   template <class NODE>
00645   point3d OccupancyOcTreeBase<NODE>::getBBXBounds () const {
00646     octomap::point3d obj_bounds = (bbx_max - bbx_min);
00647     obj_bounds /= 2.;
00648     return obj_bounds;
00649   }
00650 
00651   template <class NODE>
00652   point3d OccupancyOcTreeBase<NODE>::getBBXCenter () const {
00653     octomap::point3d obj_bounds = (bbx_max - bbx_min);
00654     obj_bounds /= 2.;
00655     return bbx_min + obj_bounds;
00656   }
00657 
00658 
00659   template <class NODE>
00660   void OccupancyOcTreeBase<NODE>::getOccupiedLeafsBBX(point3d_list& node_centers, point3d min, point3d max) const {
00661 
00662     OcTreeKey root_key, min_key, max_key;
00663     root_key[0] = root_key[1] = root_key[2] = this->tree_max_val; 
00664     if (!this->genKey(min, min_key)) return;
00665     if (!this->genKey(max, max_key)) return;
00666     getOccupiedLeafsBBXRecurs(node_centers, this->tree_depth, this->root, 0, root_key, min_key, max_key);
00667   }
00668 
00669   
00670   template <class NODE>
00671   void OccupancyOcTreeBase<NODE>::getOccupiedLeafsBBXRecurs( point3d_list& node_centers, unsigned int max_depth, 
00672                                                              NODE* node, unsigned int depth, const OcTreeKey& parent_key, 
00673                                                              const OcTreeKey& min, const OcTreeKey& max) const {
00674     if (depth == max_depth) { // max level reached
00675       if (isNodeOccupied(node)) {
00676         node_centers.push_back(this->keyToCoords(parent_key, depth));
00677       }
00678     }
00679 
00680     if (!node->hasChildren()) return;
00681 
00682     unsigned short int center_offset_key = this->tree_max_val >> (depth + 1);
00683 
00684     OcTreeKey child_key;
00685 
00686     for (unsigned int i=0; i<8; ++i) {
00687       if (node->childExists(i)) {
00688 
00689         computeChildKey(i, center_offset_key, parent_key, child_key);
00690 
00691         // overlap of query bbx and child bbx?
00692         if (!( 
00693               ( min[0] > (child_key[0] + center_offset_key)) ||
00694               ( max[0] < (child_key[0] - center_offset_key)) ||
00695               ( min[1] > (child_key[1] + center_offset_key)) ||
00696               ( max[1] < (child_key[1] - center_offset_key)) ||
00697               ( min[2] > (child_key[2] + center_offset_key)) ||
00698               ( max[2] < (child_key[2] - center_offset_key))
00699                )) {
00700           getOccupiedLeafsBBXRecurs(node_centers, max_depth, node->getChild(i), depth+1, child_key, min, max);
00701         }
00702       }
00703     }
00704   }
00705 
00706   // -- I/O  -----------------------------------------
00707 
00708   template <class NODE>
00709   std::istream& OccupancyOcTreeBase<NODE>::readBinaryData(std::istream &s){
00710     this->readBinaryNode(s, this->root);
00711     this->size_changed = true;
00712     this->tree_size = OcTreeBaseImpl<NODE,AbstractOccupancyOcTree>::calcNumNodes();  // compute number of nodes    
00713     return s;
00714   }
00715 
00716   template <class NODE>
00717   std::ostream& OccupancyOcTreeBase<NODE>::writeBinaryData(std::ostream &s) const{
00718     OCTOMAP_DEBUG("Writing %zu nodes to output stream...", this->size());
00719     this->writeBinaryNode(s, this->root);
00720     return s;
00721   }
00722 
00723   template <class NODE>
00724   std::istream& OccupancyOcTreeBase<NODE>::readBinaryNode(std::istream &s, NODE* node) const {
00725 
00726     char child1to4_char;
00727     char child5to8_char;
00728     s.read((char*)&child1to4_char, sizeof(char));
00729     s.read((char*)&child5to8_char, sizeof(char));
00730 
00731     std::bitset<8> child1to4 ((unsigned long long) child1to4_char);
00732     std::bitset<8> child5to8 ((unsigned long long) child5to8_char);
00733 
00734     //     std::cout << "read:  "
00735     //        << child1to4.to_string<char,std::char_traits<char>,std::allocator<char> >() << " "
00736     //        << child5to8.to_string<char,std::char_traits<char>,std::allocator<char> >() << std::endl;
00737 
00738 
00739     // inner nodes default to occupied
00740     node->setLogOdds(this->clamping_thres_max);
00741 
00742     for (unsigned int i=0; i<4; i++) {
00743       if ((child1to4[i*2] == 1) && (child1to4[i*2+1] == 0)) {
00744         // child is free leaf
00745         node->createChild(i);
00746         node->getChild(i)->setLogOdds(this->clamping_thres_min);
00747       }
00748       else if ((child1to4[i*2] == 0) && (child1to4[i*2+1] == 1)) {
00749         // child is occupied leaf
00750         node->createChild(i);
00751         node->getChild(i)->setLogOdds(this->clamping_thres_max);
00752       }
00753       else if ((child1to4[i*2] == 1) && (child1to4[i*2+1] == 1)) {
00754         // child has children
00755         node->createChild(i);
00756         node->getChild(i)->setLogOdds(-200.); // child is unkown, we leave it uninitialized
00757       }
00758     }
00759     for (unsigned int i=0; i<4; i++) {
00760       if ((child5to8[i*2] == 1) && (child5to8[i*2+1] == 0)) {
00761         // child is free leaf
00762         node->createChild(i+4);
00763         node->getChild(i+4)->setLogOdds(this->clamping_thres_min);
00764       }
00765       else if ((child5to8[i*2] == 0) && (child5to8[i*2+1] == 1)) {
00766         // child is occupied leaf
00767         node->createChild(i+4);
00768         node->getChild(i+4)->setLogOdds(this->clamping_thres_max);
00769       }
00770       else if ((child5to8[i*2] == 1) && (child5to8[i*2+1] == 1)) {
00771         // child has children
00772         node->createChild(i+4);
00773         node->getChild(i+4)->setLogOdds(-200.); // set occupancy when all children have been read
00774       }
00775       // child is unkown, we leave it uninitialized
00776     }
00777 
00778     // read children's children and set the label
00779     for (unsigned int i=0; i<8; i++) {
00780       if (node->childExists(i)) {
00781         NODE* child = node->getChild(i);
00782         if (fabs(child->getLogOdds() + 200.)<1e-3) {
00783           readBinaryNode(s, child);
00784           child->setLogOdds(child->getMaxChildLogOdds());
00785         }
00786       } // end if child exists
00787     } // end for children
00788 
00789     return s;
00790   }
00791 
00792   template <class NODE>
00793   std::ostream& OccupancyOcTreeBase<NODE>::writeBinaryNode(std::ostream &s, const NODE* node) const{
00794 
00795     // 2 bits for each children, 8 children per node -> 16 bits
00796     std::bitset<8> child1to4;
00797     std::bitset<8> child5to8;
00798 
00799     // 10 : child is free node
00800     // 01 : child is occupied node
00801     // 00 : child is unkown node
00802     // 11 : child has children
00803 
00804 
00805     // speedup: only set bits to 1, rest is init with 0 anyway,
00806     //          can be one logic expression per bit
00807 
00808     for (unsigned int i=0; i<4; i++) {
00809       if (node->childExists(i)) {
00810         const NODE* child = node->getChild(i);
00811         if      (child->hasChildren())  { child1to4[i*2] = 1; child1to4[i*2+1] = 1; }
00812         else if (isNodeOccupied(child)) { child1to4[i*2] = 0; child1to4[i*2+1] = 1; }
00813         else                            { child1to4[i*2] = 1; child1to4[i*2+1] = 0; }
00814       }
00815       else {
00816         child1to4[i*2] = 0; child1to4[i*2+1] = 0;
00817       }
00818     }
00819 
00820     for (unsigned int i=0; i<4; i++) {
00821       if (node->childExists(i+4)) {
00822         const NODE* child = node->getChild(i+4);
00823         if      (child->hasChildren())  { child5to8[i*2] = 1; child5to8[i*2+1] = 1; }
00824         else if (isNodeOccupied(child)) { child5to8[i*2] = 0; child5to8[i*2+1] = 1; }
00825         else                            { child5to8[i*2] = 1; child5to8[i*2+1] = 0; }
00826       }
00827       else {
00828         child5to8[i*2] = 0; child5to8[i*2+1] = 0;
00829       }
00830     }
00831     //     std::cout << "wrote: "
00832     //        << child1to4.to_string<char,std::char_traits<char>,std::allocator<char> >() << " "
00833     //        << child5to8.to_string<char,std::char_traits<char>,std::allocator<char> >() << std::endl;
00834 
00835     char child1to4_char = (char) child1to4.to_ulong();
00836     char child5to8_char = (char) child5to8.to_ulong();
00837 
00838     s.write((char*)&child1to4_char, sizeof(char));
00839     s.write((char*)&child5to8_char, sizeof(char));
00840 
00841     // write children's children
00842     for (unsigned int i=0; i<8; i++) {
00843       if (node->childExists(i)) {
00844         const NODE* child = node->getChild(i);
00845         if (child->hasChildren()) {
00846           writeBinaryNode(s, child);
00847         }
00848       }
00849     }
00850 
00851     return s;
00852   }
00853 
00854   //-- Occupancy queries on nodes:
00855 
00856   template <class NODE>
00857   void OccupancyOcTreeBase<NODE>::updateNodeLogOdds(NODE* occupancyNode, const float& update) const {
00858     occupancyNode->addValue(update);
00859     if (occupancyNode->getLogOdds() < this->clamping_thres_min) {
00860       occupancyNode->setLogOdds(this->clamping_thres_min);
00861       return;
00862     }
00863     if (occupancyNode->getLogOdds() > this->clamping_thres_max) {
00864       occupancyNode->setLogOdds(this->clamping_thres_max);
00865     }
00866   }
00867 
00868   template <class NODE>
00869   void OccupancyOcTreeBase<NODE>::integrateHit(NODE* occupancyNode) const {
00870     updateNodeLogOdds(occupancyNode, this->prob_hit_log);
00871   }
00872 
00873   template <class NODE>
00874   void OccupancyOcTreeBase<NODE>::integrateMiss(NODE* occupancyNode) const {
00875     updateNodeLogOdds(occupancyNode, this->prob_miss_log);
00876   }
00877   
00878   template <class NODE>
00879   void OccupancyOcTreeBase<NODE>::nodeToMaxLikelihood(NODE* occupancyNode) const{
00880     if (isNodeOccupied(occupancyNode))
00881       occupancyNode->setLogOdds(this->clamping_thres_max);
00882     else
00883       occupancyNode->setLogOdds(this->clamping_thres_min);
00884   }
00885 
00886   template <class NODE>
00887   void OccupancyOcTreeBase<NODE>::nodeToMaxLikelihood(NODE& occupancyNode) const{
00888     if (isNodeOccupied(occupancyNode))
00889       occupancyNode.setLogOdds(this->clamping_thres_max);
00890     else
00891       occupancyNode.setLogOdds(this->clamping_thres_min);
00892   }
00893 
00894 } // namespace