octomap 1.5.0
|
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