00001 /* 00002 * Software License Agreement (BSD License) 00003 * 00004 * Point Cloud Library (PCL) - www.pointclouds.org 00005 * Copyright (c) 2010-2012, Willow Garage, Inc. 00006 * Copyright (c) 2012, Urban Robotics, Inc. 00007 * 00008 * All rights reserved. 00009 * 00010 * Redistribution and use in source and binary forms, with or without 00011 * modification, are permitted provided that the following conditions 00012 * are met: 00013 * 00014 * * Redistributions of source code must retain the above copyright 00015 * notice, this list of conditions and the following disclaimer. 00016 * * Redistributions in binary form must reproduce the above 00017 * copyright notice, this list of conditions and the following 00018 * disclaimer in the documentation and/or other materials provided 00019 * with the distribution. 00020 * * Neither the name of Willow Garage, Inc. nor the names of its 00021 * contributors may be used to endorse or promote products derived 00022 * from this software without specific prior written permission. 00023 * 00024 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00025 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00026 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00027 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00028 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00029 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00030 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00031 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00032 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00033 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00034 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00035 * POSSIBILITY OF SUCH DAMAGE. 00036 * 00037 * $Id$ 00038 * 00039 */ 00040 00041 #ifndef PCL_OUTOFCORE_OCTREE_BASE_NODE_IMPL_H_ 00042 #define PCL_OUTOFCORE_OCTREE_BASE_NODE_IMPL_H_ 00043 00044 // C++ 00045 #include <iostream> 00046 #include <fstream> 00047 #include <sstream> 00048 #include <string> 00049 #include <exception> 00050 00051 #include <pcl/common/common.h> 00052 #include <pcl/visualization/common/common.h> 00053 #include <pcl/outofcore/octree_base_node.h> 00054 #include <pcl/filters/random_sample.h> 00055 #include <pcl/filters/extract_indices.h> 00056 00057 // JSON 00058 #include <pcl/outofcore/cJSON.h> 00059 00060 namespace pcl 00061 { 00062 namespace outofcore 00063 { 00064 00065 template<typename ContainerT, typename PointT> 00066 const std::string OutofcoreOctreeBaseNode<ContainerT, PointT>::node_index_basename = "node"; 00067 00068 template<typename ContainerT, typename PointT> 00069 const std::string OutofcoreOctreeBaseNode<ContainerT, PointT>::node_container_basename = "node"; 00070 00071 template<typename ContainerT, typename PointT> 00072 const std::string OutofcoreOctreeBaseNode<ContainerT, PointT>::node_index_extension = ".oct_idx"; 00073 00074 template<typename ContainerT, typename PointT> 00075 const std::string OutofcoreOctreeBaseNode<ContainerT, PointT>::node_container_extension = ".oct_dat"; 00076 00077 template<typename ContainerT, typename PointT> 00078 boost::mutex OutofcoreOctreeBaseNode<ContainerT, PointT>::rng_mutex_; 00079 00080 template<typename ContainerT, typename PointT> 00081 boost::mt19937 OutofcoreOctreeBaseNode<ContainerT, PointT>::rand_gen_; 00082 00083 template<typename ContainerT, typename PointT> 00084 const double OutofcoreOctreeBaseNode<ContainerT, PointT>::sample_percent_ = .125; 00085 00086 template<typename ContainerT, typename PointT> 00087 const std::string OutofcoreOctreeBaseNode<ContainerT, PointT>::pcd_extension = ".pcd"; 00088 00089 template<typename ContainerT, typename PointT> 00090 OutofcoreOctreeBaseNode<ContainerT, PointT>::OutofcoreOctreeBaseNode () 00091 : m_tree_ () 00092 , root_node_ (NULL) 00093 , parent_ (NULL) 00094 , depth_ (0) 00095 , children_ (std::vector <OutofcoreOctreeBaseNode<ContainerT, PointT>*> (8,static_cast<OutofcoreOctreeBaseNode<ContainerT, PointT>*>(0))) 00096 , num_children_ (0) 00097 , num_loaded_children_ (0) 00098 , payload_ () 00099 , node_metadata_ () 00100 { 00101 node_metadata_ = boost::shared_ptr<OutofcoreOctreeNodeMetadata> (new OutofcoreOctreeNodeMetadata ()); 00102 node_metadata_->setOutofcoreVersion (3); 00103 } 00104 00105 //////////////////////////////////////////////////////////////////////////////// 00106 00107 template<typename ContainerT, typename PointT> 00108 OutofcoreOctreeBaseNode<ContainerT, PointT>::OutofcoreOctreeBaseNode (const boost::filesystem::path& directory_path, OutofcoreOctreeBaseNode<ContainerT, PointT>* super, bool load_all) 00109 : m_tree_ () 00110 , root_node_ () 00111 , parent_ (super) 00112 , depth_ () 00113 , children_ (std::vector <OutofcoreOctreeBaseNode<ContainerT, PointT>*> (8,static_cast<OutofcoreOctreeBaseNode<ContainerT, PointT>*>(0))) 00114 , num_children_ (0) 00115 , num_loaded_children_ (0) 00116 , payload_ () 00117 , node_metadata_ () 00118 { 00119 node_metadata_ = boost::shared_ptr<OutofcoreOctreeNodeMetadata> (new OutofcoreOctreeNodeMetadata ()); 00120 node_metadata_->setOutofcoreVersion (3); 00121 00122 //Check if this is the first node created/loaded (this is true if super, i.e. node's parent is NULL) 00123 if (super == NULL) 00124 { 00125 node_metadata_->setDirectoryPathname (directory_path.parent_path ()); 00126 node_metadata_->setMetadataFilename (directory_path); 00127 depth_ = 0; 00128 root_node_ = this; 00129 00130 //Check if the specified directory to load currently exists; if not, don't continue 00131 if (!boost::filesystem::exists (node_metadata_->getDirectoryPathname ())) 00132 { 00133 PCL_ERROR ("[pcl::outofcore::OutofcoreOctreeBaseNode] Could not find dir %s\n", 00134 #if ! defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION < 3 00135 node_metadata_->getDirectoryPathname ().filename().c_str ()); 00136 #else 00137 node_metadata_->getDirectoryPathname ().c_str ()); 00138 #endif 00139 PCL_THROW_EXCEPTION (PCLException, "[pcl::outofcore::OutofcoreOctreeBaseNode] Outofcore Exception: missing directory"); 00140 } 00141 } 00142 else 00143 { 00144 node_metadata_->setDirectoryPathname (directory_path); 00145 depth_ = super->getDepth () + 1; 00146 root_node_ = super->root_node_; 00147 00148 boost::filesystem::directory_iterator directory_it_end; //empty constructor creates end of iterator 00149 00150 //flag to test if the desired metadata file was found 00151 bool b_loaded = 0; 00152 00153 for (boost::filesystem::directory_iterator directory_it (node_metadata_->getDirectoryPathname ()); directory_it != directory_it_end; ++directory_it) 00154 { 00155 const boost::filesystem::path& file = *directory_it; 00156 00157 if (!boost::filesystem::is_directory (file)) 00158 { 00159 if (boost::filesystem::extension (file) == node_index_extension) 00160 { 00161 b_loaded = node_metadata_->loadMetadataFromDisk (file); 00162 break; 00163 } 00164 } 00165 } 00166 00167 if (!b_loaded) 00168 { 00169 PCL_ERROR ("[pcl::outofcore::OutofcoreOctreeBaseNode] Could not find index\n"); 00170 PCL_THROW_EXCEPTION (PCLException, "[pcl::outofcore::OutofcoreOctreeBaseNode] Outofcore: Could not find node index"); 00171 } 00172 } 00173 00174 //load the metadata 00175 loadFromFile (node_metadata_->getMetadataFilename (), super); 00176 00177 //set the number of children in this node 00178 num_children_ = this->countNumChildren (); 00179 00180 if (load_all) 00181 { 00182 loadChildren (true); 00183 } 00184 } 00185 //////////////////////////////////////////////////////////////////////////////// 00186 00187 template<typename ContainerT, typename PointT> 00188 OutofcoreOctreeBaseNode<ContainerT, PointT>::OutofcoreOctreeBaseNode (const Eigen::Vector3d& bb_min, const Eigen::Vector3d& bb_max, OutofcoreOctreeBase<ContainerT, PointT> * const tree, const boost::filesystem::path& root_name) 00189 : m_tree_ (tree) 00190 , root_node_ () 00191 , parent_ () 00192 , depth_ () 00193 , children_ (std::vector <OutofcoreOctreeBaseNode<ContainerT, PointT>*> (8,static_cast<OutofcoreOctreeBaseNode<ContainerT, PointT>*> (0))) 00194 , num_children_ (0) 00195 , num_loaded_children_ (0) 00196 , payload_ () 00197 , node_metadata_ (new OutofcoreOctreeNodeMetadata ()) 00198 { 00199 assert (tree != NULL); 00200 node_metadata_->setOutofcoreVersion (3); 00201 init_root_node (bb_min, bb_max, tree, root_name); 00202 } 00203 00204 //////////////////////////////////////////////////////////////////////////////// 00205 00206 template<typename ContainerT, typename PointT> void 00207 OutofcoreOctreeBaseNode<ContainerT, PointT>::init_root_node (const Eigen::Vector3d& bb_min, const Eigen::Vector3d& bb_max, OutofcoreOctreeBase<ContainerT, PointT> * const tree, const boost::filesystem::path& root_name) 00208 { 00209 assert (tree != NULL); 00210 00211 parent_ = NULL; 00212 root_node_ = this; 00213 m_tree_ = tree; 00214 depth_ = 0; 00215 00216 //Mark the children as unallocated 00217 num_children_ = 0; 00218 00219 Eigen::Vector3d tmp_max = bb_max; 00220 Eigen::Vector3d tmp_min = bb_min; 00221 00222 // Need to make the bounding box slightly bigger so points that fall on the max side aren't excluded 00223 double epsilon = 1e-8; 00224 tmp_max = tmp_max + epsilon*Eigen::Vector3d (1.0, 1.0, 1.0); 00225 00226 node_metadata_->setBoundingBox (tmp_min, tmp_max); 00227 node_metadata_->setDirectoryPathname (root_name.parent_path ()); 00228 node_metadata_->setOutofcoreVersion (3); 00229 00230 // If the root directory doesn't exist create it 00231 if (!boost::filesystem::exists (node_metadata_->getDirectoryPathname ())) 00232 { 00233 boost::filesystem::create_directory (node_metadata_->getDirectoryPathname ()); 00234 } 00235 // If the root directory is a file, do not continue 00236 else if (!boost::filesystem::is_directory (node_metadata_->getDirectoryPathname ())) 00237 { 00238 PCL_ERROR ("[pcl::outofcore::OutofcoreOctreeBaseNode] Need empty directory structure. Dir %s exists and is a file.\n", 00239 #if ! defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION < 3 00240 node_metadata_->getDirectoryPathname ().filename().c_str ()); 00241 #else 00242 node_metadata_->getDirectoryPathname ().c_str ()); 00243 #endif 00244 PCL_THROW_EXCEPTION (PCLException, "[pcl::outofcore::OutofcoreOctreeBaseNode] Bad Path: Directory Already Exists"); 00245 } 00246 00247 // Create a unique id for node file name 00248 std::string uuid; 00249 00250 OutofcoreOctreeDiskContainer<PointT>::getRandomUUIDString (uuid); 00251 00252 std::string node_container_name; 00253 00254 node_container_name = uuid + std::string ("_") + node_container_basename + pcd_extension; 00255 00256 node_metadata_->setMetadataFilename (node_metadata_->getDirectoryPathname () / root_name.filename ()); 00257 node_metadata_->setPCDFilename (node_metadata_->getDirectoryPathname () / boost::filesystem::path (node_container_name)); 00258 00259 boost::filesystem::create_directory (node_metadata_->getDirectoryPathname ()); 00260 node_metadata_->serializeMetadataToDisk (); 00261 00262 // Create data container, ie octree_disk_container, octree_ram_container 00263 payload_ = boost::shared_ptr<ContainerT> (new ContainerT (node_metadata_->getPCDFilename ())); 00264 } 00265 00266 //////////////////////////////////////////////////////////////////////////////// 00267 00268 template<typename ContainerT, typename PointT> 00269 OutofcoreOctreeBaseNode<ContainerT, PointT>::~OutofcoreOctreeBaseNode () 00270 { 00271 // Recursively delete all children and this nodes data 00272 recFreeChildren (); 00273 } 00274 00275 //////////////////////////////////////////////////////////////////////////////// 00276 00277 template<typename ContainerT, typename PointT> size_t 00278 OutofcoreOctreeBaseNode<ContainerT, PointT>::countNumChildren () const 00279 { 00280 size_t child_count = 0; 00281 00282 for(size_t i=0; i<8; i++) 00283 { 00284 boost::filesystem::path child_path = this->node_metadata_->getDirectoryPathname () / boost::filesystem::path (boost::lexical_cast<std::string> (i)); 00285 if (boost::filesystem::exists (child_path)) 00286 child_count++; 00287 } 00288 return (child_count); 00289 } 00290 00291 //////////////////////////////////////////////////////////////////////////////// 00292 00293 template<typename ContainerT, typename PointT> void 00294 OutofcoreOctreeBaseNode<ContainerT, PointT>::saveIdx (bool recursive) 00295 { 00296 node_metadata_->serializeMetadataToDisk (); 00297 00298 if (recursive) 00299 { 00300 for (size_t i = 0; i < 8; i++) 00301 { 00302 if (children_[i]) 00303 children_[i]->saveIdx (true); 00304 } 00305 } 00306 } 00307 00308 //////////////////////////////////////////////////////////////////////////////// 00309 00310 template<typename ContainerT, typename PointT> bool 00311 OutofcoreOctreeBaseNode<ContainerT, PointT>::hasUnloadedChildren () const 00312 { 00313 if (this->getNumLoadedChildren () < this->getNumChildren ()) 00314 return (true); 00315 else 00316 return (false); 00317 } 00318 //////////////////////////////////////////////////////////////////////////////// 00319 00320 template<typename ContainerT, typename PointT> void 00321 OutofcoreOctreeBaseNode<ContainerT, PointT>::loadChildren (bool recursive) 00322 { 00323 //if we have fewer children loaded than exist on disk, load them 00324 if (num_loaded_children_ < this->getNumChildren ()) 00325 { 00326 //check all 8 possible child directories 00327 for (int i = 0; i < 8; i++) 00328 { 00329 boost::filesystem::path child_dir = node_metadata_->getDirectoryPathname () / boost::filesystem::path (boost::lexical_cast<std::string> (i)); 00330 //if the directory exists and the child hasn't been created (set to 0 by this node's constructor) 00331 if (boost::filesystem::exists (child_dir) && this->children_[i] == 0) 00332 { 00333 //load the child node 00334 this->children_[i] = new OutofcoreOctreeBaseNode<ContainerT, PointT> (child_dir, this, recursive); 00335 //keep track of the children loaded 00336 num_loaded_children_++; 00337 } 00338 } 00339 } 00340 assert (num_loaded_children_ == this->getNumChildren ()); 00341 } 00342 //////////////////////////////////////////////////////////////////////////////// 00343 00344 template<typename ContainerT, typename PointT> void 00345 OutofcoreOctreeBaseNode<ContainerT, PointT>::recFreeChildren () 00346 { 00347 if (num_children_ == 0) 00348 { 00349 return; 00350 } 00351 00352 for (size_t i = 0; i < 8; i++) 00353 { 00354 if (children_[i]) 00355 { 00356 OutofcoreOctreeBaseNode<ContainerT, PointT>* current = children_[i]; 00357 delete (current); 00358 } 00359 } 00360 children_.resize (8, static_cast<OutofcoreOctreeBaseNode<ContainerT, PointT>* > (0)); 00361 num_children_ = 0; 00362 } 00363 //////////////////////////////////////////////////////////////////////////////// 00364 00365 template<typename ContainerT, typename PointT> uint64_t 00366 OutofcoreOctreeBaseNode<ContainerT, PointT>::addDataToLeaf (const AlignedPointTVector& p, const bool skip_bb_check) 00367 { 00368 //quit if there are no points to add 00369 if (p.empty ()) 00370 { 00371 return (0); 00372 } 00373 00374 //if this depth is the max depth of the tree, then add the points 00375 if (this->depth_ == this->root_node_->m_tree_->getDepth ()) 00376 return (addDataAtMaxDepth( p, skip_bb_check)); 00377 00378 if (hasUnloadedChildren ()) 00379 loadChildren (false); 00380 00381 std::vector < std::vector<const PointT*> > c; 00382 c.resize (8); 00383 for (size_t i = 0; i < 8; i++) 00384 { 00385 c[i].reserve (p.size () / 8); 00386 } 00387 00388 const size_t len = p.size (); 00389 for (size_t i = 0; i < len; i++) 00390 { 00391 const PointT& pt = p[i]; 00392 00393 if (!skip_bb_check) 00394 { 00395 if (!this->pointInBoundingBox (pt)) 00396 { 00397 PCL_ERROR ( "[pcl::outofcore::OutofcoreOctreeBaseNode::%s] Failed to place point within bounding box\n", __FUNCTION__ ); 00398 continue; 00399 } 00400 } 00401 00402 uint8_t box = 0; 00403 Eigen::Vector3d mid_xyz = node_metadata_->getVoxelCenter (); 00404 00405 box = static_cast<uint8_t>(((pt.z >= mid_xyz[2]) << 2) | ((pt.y >= mid_xyz[1]) << 1) | ((pt.x >= mid_xyz[0]) << 0)); 00406 c[static_cast<size_t>(box)].push_back (&pt); 00407 } 00408 00409 boost::uint64_t points_added = 0; 00410 for (size_t i = 0; i < 8; i++) 00411 { 00412 if (c[i].empty ()) 00413 continue; 00414 if (!children_[i]) 00415 createChild (i); 00416 points_added += children_[i]->addDataToLeaf (c[i], true); 00417 c[i].clear (); 00418 } 00419 return (points_added); 00420 } 00421 //////////////////////////////////////////////////////////////////////////////// 00422 00423 00424 template<typename ContainerT, typename PointT> boost::uint64_t 00425 OutofcoreOctreeBaseNode<ContainerT, PointT>::addDataToLeaf (const std::vector<const PointT*>& p, const bool skip_bb_check) 00426 { 00427 if (p.empty ()) 00428 { 00429 return (0); 00430 } 00431 00432 if (this->depth_ == this->root_node_->m_tree_->getDepth ()) 00433 { 00434 //trust me, just add the points 00435 if (skip_bb_check) 00436 { 00437 root_node_->m_tree_->incrementPointsInLOD (this->depth_, p.size ()); 00438 00439 payload_->insertRange (p.data (), p.size ()); 00440 00441 return (p.size ()); 00442 } 00443 else//check which points belong to this node, throw away the rest 00444 { 00445 std::vector<const PointT*> buff; 00446 BOOST_FOREACH(const PointT* pt, p) 00447 { 00448 if(pointInBoundingBox(*pt)) 00449 { 00450 buff.push_back(pt); 00451 } 00452 } 00453 00454 if (!buff.empty ()) 00455 { 00456 root_node_->m_tree_->incrementPointsInLOD (this->depth_, buff.size ()); 00457 payload_->insertRange (buff.data (), buff.size ()); 00458 // payload_->insertRange ( buff ); 00459 00460 } 00461 return (buff.size ()); 00462 } 00463 } 00464 else 00465 { 00466 if (this->hasUnloadedChildren ()) 00467 { 00468 loadChildren (false); 00469 } 00470 00471 std::vector < std::vector<const PointT*> > c; 00472 c.resize (8); 00473 for (size_t i = 0; i < 8; i++) 00474 { 00475 c[i].reserve (p.size () / 8); 00476 } 00477 00478 const size_t len = p.size (); 00479 for (size_t i = 0; i < len; i++) 00480 { 00481 //const PointT& pt = p[i]; 00482 if (!skip_bb_check) 00483 { 00484 if (!this->pointInBoundingBox (*p[i])) 00485 { 00486 // std::cerr << "failed to place point!!!" << std::endl; 00487 continue; 00488 } 00489 } 00490 00491 uint8_t box = 00; 00492 Eigen::Vector3d mid_xyz = node_metadata_->getVoxelCenter (); 00493 //hash each coordinate to the appropriate octant 00494 box = static_cast<uint8_t> (((p[i]->z >= mid_xyz[2]) << 2) | ((p[i]->y >= mid_xyz[1]) << 1) | ((p[i]->x >= mid_xyz[0] ))); 00495 //3 bit, 8 octants 00496 c[box].push_back (p[i]); 00497 } 00498 00499 boost::uint64_t points_added = 0; 00500 for (size_t i = 0; i < 8; i++) 00501 { 00502 if (c[i].empty ()) 00503 continue; 00504 if (!children_[i]) 00505 createChild (i); 00506 points_added += children_[i]->addDataToLeaf (c[i], true); 00507 c[i].clear (); 00508 } 00509 return (points_added); 00510 } 00511 // std::cerr << "failed to place point!!!" << std::endl; 00512 return (0); 00513 } 00514 //////////////////////////////////////////////////////////////////////////////// 00515 00516 00517 template<typename ContainerT, typename PointT> boost::uint64_t 00518 OutofcoreOctreeBaseNode<ContainerT, PointT>::addPointCloud (const typename pcl::PCLPointCloud2::Ptr& input_cloud, const bool skip_bb_check) 00519 { 00520 assert (this->root_node_->m_tree_ != NULL); 00521 00522 if (input_cloud->height*input_cloud->width == 0) 00523 return (0); 00524 00525 if (this->depth_ == this->root_node_->m_tree_->getDepth ()) 00526 return (addDataAtMaxDepth (input_cloud, true)); 00527 00528 if( num_children_ < 8 ) 00529 if(hasUnloadedChildren ()) 00530 loadChildren (false); 00531 00532 if( skip_bb_check == false ) 00533 { 00534 00535 //indices to store the points for each bin 00536 //these lists will be used to copy data to new point clouds and pass down recursively 00537 std::vector < std::vector<int> > indices; 00538 indices.resize (8); 00539 00540 this->sortOctantIndices (input_cloud, indices, node_metadata_->getVoxelCenter ()); 00541 00542 for(size_t k=0; k<indices.size (); k++) 00543 { 00544 PCL_DEBUG ("[pcl::outofcore::OutofcoreOctreeBaseNode::%s] Computed %d indices in octact %d\n", __FUNCTION__, indices[k].size (), k); 00545 } 00546 00547 boost::uint64_t points_added = 0; 00548 00549 for(size_t i=0; i<8; i++) 00550 { 00551 if ( indices[i].empty () ) 00552 continue; 00553 00554 if ( children_[i] == false ) 00555 { 00556 createChild (i); 00557 } 00558 00559 pcl::PCLPointCloud2::Ptr dst_cloud (new pcl::PCLPointCloud2 () ); 00560 00561 PCL_DEBUG ( "[pcl::outofcore::OutofcoreOctreeBaseNode::%s] Extracting indices to bins\n", __FUNCTION__); 00562 00563 //copy the points from extracted indices from input cloud to destination cloud 00564 pcl::copyPointCloud ( *input_cloud, indices[i], *dst_cloud ) ; 00565 00566 //recursively add the new cloud to the data 00567 points_added += children_[i]->addPointCloud (dst_cloud, false); 00568 indices[i].clear (); 00569 } 00570 00571 return (points_added); 00572 } 00573 00574 PCL_ERROR ("[pcl::outofcore::OutofcoreOctreeBaseNode] Skipped bounding box check. Points not inserted\n"); 00575 00576 return 0; 00577 } 00578 00579 00580 //////////////////////////////////////////////////////////////////////////////// 00581 template<typename ContainerT, typename PointT> void 00582 OutofcoreOctreeBaseNode<ContainerT, PointT>::randomSample(const AlignedPointTVector& p, AlignedPointTVector& insertBuff, const bool skip_bb_check) 00583 { 00584 assert (this->root_node_->m_tree_ != NULL); 00585 00586 AlignedPointTVector sampleBuff; 00587 if (!skip_bb_check) 00588 { 00589 BOOST_FOREACH (const PointT& pt, p) 00590 if(pointInBoundingBox(pt)) 00591 sampleBuff.push_back(pt); 00592 } 00593 else 00594 { 00595 sampleBuff = p; 00596 } 00597 00598 // Derive percentage from specified sample_percent and tree depth 00599 const double percent = pow(sample_percent_, double((this->root_node_->m_tree_->getDepth () - depth_))); 00600 const uint64_t samplesize = static_cast<uint64_t>(percent * static_cast<double>(sampleBuff.size())); 00601 const uint64_t inputsize = sampleBuff.size(); 00602 00603 if(samplesize > 0) 00604 { 00605 // Resize buffer to sample size 00606 insertBuff.resize(samplesize); 00607 00608 // Create random number generator 00609 boost::mutex::scoped_lock lock(rng_mutex_); 00610 boost::uniform_int<boost::uint64_t> buffdist(0, inputsize-1); 00611 boost::variate_generator<boost::mt19937&, boost::uniform_int<boost::uint64_t> > buffdie(rand_gen_, buffdist); 00612 00613 // Randomly pick sampled points 00614 for(boost::uint64_t i = 0; i < samplesize; ++i) 00615 { 00616 boost::uint64_t buffstart = buffdie(); 00617 insertBuff[i] = ( sampleBuff[buffstart] ); 00618 } 00619 } 00620 // Have to do it the slow way 00621 else 00622 { 00623 boost::mutex::scoped_lock lock(rng_mutex_); 00624 boost::bernoulli_distribution<double> buffdist(percent); 00625 boost::variate_generator<boost::mt19937&, boost::bernoulli_distribution<double> > buffcoin(rand_gen_, buffdist); 00626 00627 for(boost::uint64_t i = 0; i < inputsize; ++i) 00628 if(buffcoin()) 00629 insertBuff.push_back( p[i] ); 00630 } 00631 } 00632 //////////////////////////////////////////////////////////////////////////////// 00633 00634 template<typename ContainerT, typename PointT> boost::uint64_t 00635 OutofcoreOctreeBaseNode<ContainerT, PointT>::addDataAtMaxDepth (const AlignedPointTVector& p, const bool skip_bb_check) 00636 { 00637 assert (this->root_node_->m_tree_ != NULL); 00638 00639 // Trust me, just add the points 00640 if (skip_bb_check) 00641 { 00642 // Increment point count for node 00643 root_node_->m_tree_->incrementPointsInLOD (this->depth_, p.size ()); 00644 00645 // Insert point data 00646 payload_->insertRange ( p ); 00647 00648 return (p.size ()); 00649 } 00650 00651 // Add points found within the current node's bounding box 00652 else 00653 { 00654 AlignedPointTVector buff; 00655 const size_t len = p.size (); 00656 00657 for (size_t i = 0; i < len; i++) 00658 { 00659 if (pointInBoundingBox (p[i])) 00660 { 00661 buff.push_back (p[i]); 00662 } 00663 } 00664 00665 if (!buff.empty ()) 00666 { 00667 root_node_->m_tree_->incrementPointsInLOD (this->depth_, buff.size ()); 00668 payload_->insertRange ( buff ); 00669 00670 } 00671 return (buff.size ()); 00672 } 00673 } 00674 //////////////////////////////////////////////////////////////////////////////// 00675 template<typename ContainerT, typename PointT> boost::uint64_t 00676 OutofcoreOctreeBaseNode<ContainerT, PointT>::addDataAtMaxDepth (const pcl::PCLPointCloud2::Ptr input_cloud, const bool skip_bb_check) 00677 { 00678 //this assumes data is already in the correct bin 00679 if(skip_bb_check == true) 00680 { 00681 PCL_DEBUG ("[pcl::outofcore::OutofcoreOctreeBaseNode::%s] Adding %u points at max depth, %u\n",__FUNCTION__, input_cloud->width*input_cloud->height, this->depth_); 00682 00683 this->root_node_->m_tree_->incrementPointsInLOD (this->depth_, input_cloud->width*input_cloud->height ); 00684 payload_->insertRange (input_cloud); 00685 00686 return (input_cloud->width*input_cloud->height); 00687 } 00688 else 00689 { 00690 PCL_ERROR ("[pcl::outofcore::OutofcoreOctreeBaseNode] Not implemented\n"); 00691 return (0); 00692 } 00693 } 00694 00695 00696 //////////////////////////////////////////////////////////////////////////////// 00697 template<typename ContainerT, typename PointT> void 00698 OutofcoreOctreeBaseNode<ContainerT, PointT>::subdividePoints (const AlignedPointTVector &p, std::vector< AlignedPointTVector > &c, const bool skip_bb_check) 00699 { 00700 // Reserve space for children nodes 00701 c.resize(8); 00702 for(size_t i = 0; i < 8; i++) 00703 c[i].reserve(p.size() / 8); 00704 00705 const size_t len = p.size(); 00706 for(size_t i = 0; i < len; i++) 00707 { 00708 const PointT& pt = p[i]; 00709 00710 if(!skip_bb_check) 00711 if(!this->pointInBoundingBox(pt)) 00712 continue; 00713 00714 subdividePoint (pt, c); 00715 } 00716 } 00717 //////////////////////////////////////////////////////////////////////////////// 00718 00719 template<typename ContainerT, typename PointT> void 00720 OutofcoreOctreeBaseNode<ContainerT, PointT>::subdividePoint (const PointT& point, std::vector< AlignedPointTVector >& c) 00721 { 00722 Eigen::Vector3d mid_xyz = node_metadata_->getVoxelCenter (); 00723 size_t octant = 0; 00724 octant = ((point.z >= mid_xyz[2]) << 2) | ((point.y >= mid_xyz[1]) << 1) | ((point.x >= mid_xyz[0]) << 0); 00725 c[octant].push_back (point); 00726 } 00727 00728 //////////////////////////////////////////////////////////////////////////////// 00729 template<typename ContainerT, typename PointT> boost::uint64_t 00730 OutofcoreOctreeBaseNode<ContainerT, PointT>::addPointCloud_and_genLOD (const pcl::PCLPointCloud2::Ptr input_cloud) //, const bool skip_bb_check = false ) 00731 { 00732 boost::uint64_t points_added = 0; 00733 00734 if ( input_cloud->width * input_cloud->height == 0 ) 00735 { 00736 return (0); 00737 } 00738 00739 if ( this->depth_ == this->root_node_->m_tree_->getDepth () || input_cloud->width*input_cloud->height < 8 ) 00740 { 00741 uint64_t points_added = addDataAtMaxDepth (input_cloud, true); 00742 assert (points_added > 0); 00743 return (points_added); 00744 } 00745 00746 if (num_children_ < 8 ) 00747 { 00748 if ( hasUnloadedChildren () ) 00749 { 00750 loadChildren (false); 00751 } 00752 } 00753 00754 //------------------------------------------------------------ 00755 //subsample data: 00756 // 1. Get indices from a random sample 00757 // 2. Extract those indices with the extract indices class (in order to also get the complement) 00758 //------------------------------------------------------------ 00759 pcl::RandomSample<pcl::PCLPointCloud2> random_sampler; 00760 random_sampler.setInputCloud (input_cloud); 00761 00762 //set sample size to 1/8 of total points (12.5%) 00763 uint64_t sample_size = input_cloud->width*input_cloud->height / 8; 00764 random_sampler.setSample (static_cast<unsigned int> (sample_size)); 00765 00766 //create our destination 00767 pcl::PCLPointCloud2::Ptr downsampled_cloud ( new pcl::PCLPointCloud2 () ); 00768 00769 //create destination for indices 00770 pcl::IndicesPtr downsampled_cloud_indices ( new std::vector< int > () ); 00771 random_sampler.filter (*downsampled_cloud_indices); 00772 00773 //extract the "random subset", size by setSampleSize 00774 pcl::ExtractIndices<pcl::PCLPointCloud2> extractor; 00775 extractor.setInputCloud (input_cloud); 00776 extractor.setIndices (downsampled_cloud_indices); 00777 extractor.filter (*downsampled_cloud); 00778 00779 //extract the complement of those points (i.e. everything remaining) 00780 pcl::PCLPointCloud2::Ptr remaining_points ( new pcl::PCLPointCloud2 () ); 00781 extractor.setNegative (true); 00782 extractor.filter (*remaining_points); 00783 00784 PCL_DEBUG ( "[pcl::outofcore::OutofcoreOctreeBaseNode::%s] Random sampled: %lu of %lu\n", __FUNCTION__, downsampled_cloud->width * downsampled_cloud->height, input_cloud->width * input_cloud->height ); 00785 00786 //insert subsampled data to the node's disk container payload 00787 if ( downsampled_cloud->width * downsampled_cloud->height != 0 ) 00788 { 00789 root_node_->m_tree_->incrementPointsInLOD ( this->depth_, downsampled_cloud->width * downsampled_cloud->height ); 00790 payload_->insertRange (downsampled_cloud); 00791 points_added += downsampled_cloud->width*downsampled_cloud->height ; 00792 } 00793 00794 PCL_DEBUG ("[pcl::outofcore::OutofcoreOctreeBaseNode::%s] Remaining points are %u\n",__FUNCTION__, remaining_points->width*remaining_points->height); 00795 00796 //subdivide remaining data by destination octant 00797 std::vector<std::vector<int> > indices; 00798 indices.resize (8); 00799 00800 this->sortOctantIndices (remaining_points, indices, node_metadata_->getVoxelCenter ()); 00801 00802 //pass each set of points to the appropriate child octant 00803 for(size_t i=0; i<8; i++) 00804 { 00805 00806 if(indices[i].empty ()) 00807 continue; 00808 00809 if( children_[i] == false ) 00810 { 00811 assert (i < 8); 00812 createChild (i); 00813 } 00814 00815 //copy correct indices into a temporary cloud 00816 pcl::PCLPointCloud2::Ptr tmp_local_point_cloud (new pcl::PCLPointCloud2 ()); 00817 pcl::copyPointCloud (*remaining_points, indices[i], *tmp_local_point_cloud); 00818 00819 //recursively add points and keep track of how many were successfully added to the tree 00820 points_added += children_[i]->addPointCloud_and_genLOD (tmp_local_point_cloud); 00821 PCL_DEBUG ("[pcl::outofcore::OutofcoreOctreeBaseNode::%s] points_added: %lu, indices[i].size: %lu, tmp_local_point_cloud size: %lu\n", __FUNCTION__, points_added, indices[i].size (), tmp_local_point_cloud->width*tmp_local_point_cloud->height); 00822 00823 } 00824 assert (points_added == input_cloud->width*input_cloud->height); 00825 return (points_added); 00826 } 00827 //////////////////////////////////////////////////////////////////////////////// 00828 00829 template<typename ContainerT, typename PointT> boost::uint64_t 00830 OutofcoreOctreeBaseNode<ContainerT, PointT>::addDataToLeaf_and_genLOD (const AlignedPointTVector& p, const bool skip_bb_check) 00831 { 00832 // If there are no points return 00833 if (p.empty ()) 00834 return (0); 00835 00836 // when adding data and generating sampled LOD 00837 // If the max depth has been reached 00838 assert (this->root_node_->m_tree_ != NULL ); 00839 00840 if (this->depth_ == this->root_node_->m_tree_->getDepth ()) 00841 { 00842 PCL_DEBUG ("[pcl::outofcore::OutofcoreOctreeBaseNode::addDataToLeaf_and_genLOD] Adding data to the leaves\n"); 00843 return (addDataAtMaxDepth(p, false)); 00844 } 00845 00846 // Create child nodes of the current node but not grand children+ 00847 if (this->hasUnloadedChildren ()) 00848 loadChildren (false /*no recursive loading*/); 00849 00850 // Randomly sample data 00851 AlignedPointTVector insertBuff; 00852 randomSample(p, insertBuff, skip_bb_check); 00853 00854 if(!insertBuff.empty()) 00855 { 00856 // Increment point count for node 00857 root_node_->m_tree_->incrementPointsInLOD (this->depth_, insertBuff.size()); 00858 // Insert sampled point data 00859 payload_->insertRange (insertBuff); 00860 00861 } 00862 00863 //subdivide vec to pass data down lower 00864 std::vector<AlignedPointTVector> c; 00865 subdividePoints(p, c, skip_bb_check); 00866 00867 boost::uint64_t points_added = 0; 00868 for(size_t i = 0; i < 8; i++) 00869 { 00870 // If child doesn't have points 00871 if(c[i].empty()) 00872 continue; 00873 00874 // If child doesn't exist 00875 if(!children_[i]) 00876 createChild(i); 00877 00878 // Recursively build children 00879 points_added += children_[i]->addDataToLeaf_and_genLOD(c[i], true); 00880 c[i].clear(); 00881 } 00882 00883 return (points_added); 00884 } 00885 //////////////////////////////////////////////////////////////////////////////// 00886 00887 template<typename ContainerT, typename PointT> void 00888 OutofcoreOctreeBaseNode<ContainerT, PointT>::createChild (const size_t idx) 00889 { 00890 assert (idx < 8); 00891 00892 //if already has 8 children, return 00893 if (children_[idx] || (num_children_ == 8)) 00894 { 00895 PCL_ERROR ("[pcl::outofcore::OutofcoreOctreeBaseNode::createChild] Not allowed to create a 9th child of %s", 00896 #if ! defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION < 3 00897 this->node_metadata_->getMetadataFilename ().filename().c_str ()); 00898 #else 00899 this->node_metadata_->getMetadataFilename ().c_str ()); 00900 #endif 00901 return; 00902 } 00903 00904 Eigen::Vector3d start = node_metadata_->getBoundingBoxMin (); 00905 Eigen::Vector3d step = (node_metadata_->getBoundingBoxMax () - start)/static_cast<double>(2.0); 00906 00907 Eigen::Vector3d childbb_min; 00908 Eigen::Vector3d childbb_max; 00909 00910 int x, y, z; 00911 if (idx > 3) 00912 { 00913 x = ((idx == 5) || (idx == 7)) ? 1 : 0; 00914 y = ((idx == 6) || (idx == 7)) ? 1 : 0; 00915 z = 1; 00916 } 00917 else 00918 { 00919 x = ((idx == 1) || (idx == 3)) ? 1 : 0; 00920 y = ((idx == 2) || (idx == 3)) ? 1 : 0; 00921 z = 0; 00922 } 00923 00924 childbb_min[2] = start[2] + static_cast<double> (z) * step[2]; 00925 childbb_max[2] = start[2] + static_cast<double> (z + 1) * step[2]; 00926 00927 childbb_min[1] = start[1] + static_cast<double> (y) * step[1]; 00928 childbb_max[1] = start[1] + static_cast<double> (y + 1) * step[1]; 00929 00930 childbb_min[0] = start[0] + static_cast<double> (x) * step[0]; 00931 childbb_max[0] = start[0] + static_cast<double> (x + 1) * step[0]; 00932 00933 boost::filesystem::path childdir = node_metadata_->getDirectoryPathname () / boost::filesystem::path (boost::lexical_cast<std::string> (idx)); 00934 children_[idx] = new OutofcoreOctreeBaseNode<ContainerT, PointT> (childbb_min, childbb_max, childdir.string ().c_str (), this); 00935 00936 num_children_++; 00937 } 00938 //////////////////////////////////////////////////////////////////////////////// 00939 00940 template<typename ContainerT, typename PointT> bool 00941 pointInBoundingBox (const Eigen::Vector3d& min_bb, const Eigen::Vector3d& max_bb, const Eigen::Vector3d& point) 00942 { 00943 if (((min_bb[0] <= point[0]) && (point[0] < max_bb[0])) && 00944 ((min_bb[1] <= point[1]) && (point[1] < max_bb[1])) && 00945 ((min_bb[2] <= point[2]) && (point[2] < max_bb[2]))) 00946 { 00947 return (true); 00948 00949 } 00950 return (false); 00951 } 00952 00953 00954 //////////////////////////////////////////////////////////////////////////////// 00955 template<typename ContainerT, typename PointT> bool 00956 OutofcoreOctreeBaseNode<ContainerT, PointT>::pointInBoundingBox (const PointT& p) const 00957 { 00958 const Eigen::Vector3d& min = node_metadata_->getBoundingBoxMin (); 00959 const Eigen::Vector3d& max = node_metadata_->getBoundingBoxMax (); 00960 00961 if (((min[0] <= p.x) && (p.x < max[0])) && 00962 ((min[1] <= p.y) && (p.y < max[1])) && 00963 ((min[2] <= p.z) && (p.z < max[2]))) 00964 { 00965 return (true); 00966 00967 } 00968 return (false); 00969 } 00970 00971 //////////////////////////////////////////////////////////////////////////////// 00972 template<typename ContainerT, typename PointT> void 00973 OutofcoreOctreeBaseNode<ContainerT, PointT>::printBoundingBox (const size_t query_depth) const 00974 { 00975 Eigen::Vector3d min; 00976 Eigen::Vector3d max; 00977 node_metadata_->getBoundingBox (min, max); 00978 00979 if (this->depth_ < query_depth){ 00980 for (size_t i = 0; i < this->depth_; i++) 00981 std::cout << " "; 00982 00983 std::cout << "[" << min[0] << ", " << min[1] << ", " << min[2] << "] - "; 00984 std::cout << "[" << max[0] << ", " << max[1] << ", " << max[2] << "] - "; 00985 std::cout << "[" << max[0] - min[0] << ", " << max[1] - min[1]; 00986 std::cout << ", " << max[2] - min[2] << "]" << std::endl; 00987 00988 if (num_children_ > 0) 00989 { 00990 for (size_t i = 0; i < 8; i++) 00991 { 00992 if (children_[i]) 00993 children_[i]->printBoundingBox (query_depth); 00994 } 00995 } 00996 } 00997 } 00998 00999 //////////////////////////////////////////////////////////////////////////////// 01000 template<typename ContainerT, typename PointT> void 01001 OutofcoreOctreeBaseNode<ContainerT, PointT>::getOccupiedVoxelCentersRecursive (AlignedPointTVector &voxel_centers, const size_t query_depth) 01002 { 01003 if (this->depth_ < query_depth){ 01004 if (num_children_ > 0) 01005 { 01006 for (size_t i = 0; i < 8; i++) 01007 { 01008 if (children_[i]) 01009 children_[i]->getOccupiedVoxelCentersRecursive (voxel_centers, query_depth); 01010 } 01011 } 01012 } 01013 else 01014 { 01015 PointT voxel_center; 01016 Eigen::Vector3d mid_xyz = node_metadata_->getVoxelCenter (); 01017 voxel_center.x = static_cast<float>(mid_xyz[0]); 01018 voxel_center.y = static_cast<float>(mid_xyz[1]); 01019 voxel_center.z = static_cast<float>(mid_xyz[2]); 01020 01021 voxel_centers.push_back(voxel_center); 01022 } 01023 } 01024 01025 //////////////////////////////////////////////////////////////////////////////// 01026 // Eigen::Vector3d cornerOffsets[] = 01027 // { 01028 // Eigen::Vector3d(-1.0, -1.0, -1.0), // - - - 01029 // Eigen::Vector3d( 1.0, -1.0, -1.0), // - - + 01030 // Eigen::Vector3d(-1.0, 1.0, -1.0), // - + - 01031 // Eigen::Vector3d( 1.0, 1.0, -1.0), // - + + 01032 // Eigen::Vector3d(-1.0, -1.0, 1.0), // + - - 01033 // Eigen::Vector3d( 1.0, -1.0, 1.0), // + - + 01034 // Eigen::Vector3d(-1.0, 1.0, 1.0), // + + - 01035 // Eigen::Vector3d( 1.0, 1.0, 1.0) // + + + 01036 // }; 01037 // 01038 // // Note that the input vector must already be negated when using this code for halfplane tests 01039 // int 01040 // vectorToIndex(Eigen::Vector3d normal) 01041 // { 01042 // int index = 0; 01043 // 01044 // if (normal.z () >= 0) index |= 1; 01045 // if (normal.y () >= 0) index |= 2; 01046 // if (normal.x () >= 0) index |= 4; 01047 // 01048 // return index; 01049 // } 01050 // 01051 // void 01052 // get_np_vertices(Eigen::Vector3d normal, Eigen::Vector3d &p_vertex, Eigen::Vector3d &n_vertex, Eigen::Vector3d min_bb, Eigen::Vector3d max_bb) 01053 // { 01054 // 01055 // p_vertex = min_bb; 01056 // n_vertex = max_bb; 01057 // 01058 // if (normal.x () >= 0) 01059 // { 01060 // n_vertex.x () = min_bb.x (); 01061 // p_vertex.x () = max_bb.x (); 01062 // } 01063 // 01064 // if (normal.y () >= 0) 01065 // { 01066 // n_vertex.y () = min_bb.y (); 01067 // p_vertex.y () = max_bb.y (); 01068 // } 01069 // 01070 // if (normal.z () >= 0) 01071 // { 01072 // p_vertex.z () = max_bb.z (); 01073 // n_vertex.z () = min_bb.z (); 01074 // } 01075 // } 01076 01077 template<typename Container, typename PointT> void 01078 OutofcoreOctreeBaseNode<Container, PointT>::queryFrustum (const double planes[24], std::list<std::string>& file_names) 01079 { 01080 queryFrustum(planes, file_names, this->m_tree_->getTreeDepth()); 01081 } 01082 01083 template<typename Container, typename PointT> void 01084 OutofcoreOctreeBaseNode<Container, PointT>::queryFrustum (const double planes[24], std::list<std::string>& file_names, const boost::uint32_t query_depth, const bool skip_vfc_check) 01085 { 01086 01087 enum {INSIDE, INTERSECT, OUTSIDE}; 01088 01089 int result = INSIDE; 01090 01091 if (this->depth_ > query_depth) 01092 { 01093 return; 01094 } 01095 01096 // if (this->depth_ > query_depth) 01097 // return; 01098 01099 if (!skip_vfc_check) 01100 { 01101 for(int i =0; i < 6; i++){ 01102 double a = planes[(i*4)]; 01103 double b = planes[(i*4)+1]; 01104 double c = planes[(i*4)+2]; 01105 double d = planes[(i*4)+3]; 01106 01107 //cout << i << ": " << a << "x + " << b << "y + " << c << "z + " << d << endl; 01108 01109 Eigen::Vector3d normal(a, b, c); 01110 01111 Eigen::Vector3d min_bb; 01112 Eigen::Vector3d max_bb; 01113 node_metadata_->getBoundingBox(min_bb, max_bb); 01114 01115 // Basic VFC algorithm 01116 Eigen::Vector3d center = node_metadata_->getVoxelCenter(); 01117 Eigen::Vector3d radius (fabs (static_cast<double> (max_bb.x () - center.x ())), 01118 fabs (static_cast<double> (max_bb.y () - center.y ())), 01119 fabs (static_cast<double> (max_bb.z () - center.z ()))); 01120 01121 double m = (center.x () * a) + (center.y () * b) + (center.z () * c) + d; 01122 double n = (radius.x () * fabs(a)) + (radius.y () * fabs(b)) + (radius.z () * fabs(c)); 01123 01124 if (m + n < 0){ 01125 result = OUTSIDE; 01126 break; 01127 } 01128 01129 if (m - n < 0) result = INTERSECT; 01130 01131 // // n-p implementation 01132 // Eigen::Vector3d p_vertex; //pos vertex 01133 // Eigen::Vector3d n_vertex; //neg vertex 01134 // get_np_vertices(normal, p_vertex, n_vertex, min_bb, max_bb); 01135 // 01136 // cout << "n_vertex: " << n_vertex.x () << ", " << n_vertex.y () << ", " << n_vertex.z () << endl; 01137 // cout << "p_vertex: " << p_vertex.x () << ", " << p_vertex.y () << ", " << p_vertex.z () << endl; 01138 01139 // is the positive vertex outside? 01140 // if (pl[i].distance(b.getVertexP(pl[i].normal)) < 0) 01141 // { 01142 // result = OUTSIDE; 01143 // } 01144 // // is the negative vertex outside? 01145 // else if (pl[i].distance(b.getVertexN(pl[i].normal)) < 0) 01146 // { 01147 // result = INTERSECT; 01148 // } 01149 01150 // 01151 // 01152 // // This should be the same as below 01153 // if (normal.dot(n_vertex) + d > 0) 01154 // { 01155 // result = OUTSIDE; 01156 // } 01157 // 01158 // if (normal.dot(p_vertex) + d >= 0) 01159 // { 01160 // result = INTERSECT; 01161 // } 01162 01163 // This should be the same as above 01164 // double m = (a * n_vertex.x ()) + (b * n_vertex.y ()) + (c * n_vertex.z ()); 01165 // cout << "m = " << m << endl; 01166 // if (m > -d) 01167 // { 01168 // result = OUTSIDE; 01169 // } 01170 // 01171 // double n = (a * p_vertex.x ()) + (b * p_vertex.y ()) + (c * p_vertex.z ()); 01172 // cout << "n = " << n << endl; 01173 // if (n > -d) 01174 // { 01175 // result = INTERSECT; 01176 // } 01177 } 01178 } 01179 01180 if (result == OUTSIDE) 01181 { 01182 return; 01183 } 01184 01185 // switch(result){ 01186 // case OUTSIDE: 01187 // //cout << this->depth_ << " [OUTSIDE]: " << node_metadata_->getPCDFilename() << endl; 01188 // return; 01189 // case INTERSECT: 01190 // //cout << this->depth_ << " [INTERSECT]: " << node_metadata_->getPCDFilename() << endl; 01191 // break; 01192 // case INSIDE: 01193 // //cout << this->depth_ << " [INSIDE]: " << node_metadata_->getPCDFilename() << endl; 01194 // break; 01195 // } 01196 01197 // Add files breadth first 01198 if (this->depth_ == query_depth && payload_->getDataSize () > 0) 01199 //if (payload_->getDataSize () > 0) 01200 { 01201 file_names.push_back (this->node_metadata_->getMetadataFilename ().string ()); 01202 } 01203 01204 if (hasUnloadedChildren ()) 01205 { 01206 loadChildren (false); 01207 } 01208 01209 if (this->getNumChildren () > 0) 01210 { 01211 for (size_t i = 0; i < 8; i++) 01212 { 01213 if (children_[i]) 01214 children_[i]->queryFrustum (planes, file_names, query_depth, (result == INSIDE) /*skip_vfc_check*/); 01215 } 01216 } 01217 // else if (hasUnloadedChildren ()) 01218 // { 01219 // loadChildren (false); 01220 // 01221 // for (size_t i = 0; i < 8; i++) 01222 // { 01223 // if (children_[i]) 01224 // children_[i]->queryFrustum (planes, file_names, query_depth); 01225 // } 01226 // } 01227 //} 01228 } 01229 01230 //////////////////////////////////////////////////////////////////////////////// 01231 01232 template<typename Container, typename PointT> void 01233 OutofcoreOctreeBaseNode<Container, PointT>::queryFrustum (const double planes[24], const Eigen::Vector3d &eye, const Eigen::Matrix4d &view_projection_matrix, std::list<std::string>& file_names, const boost::uint32_t query_depth, const bool skip_vfc_check) 01234 { 01235 01236 // If we're above our query depth 01237 if (this->depth_ > query_depth) 01238 { 01239 return; 01240 } 01241 01242 // Bounding Box 01243 Eigen::Vector3d min_bb; 01244 Eigen::Vector3d max_bb; 01245 node_metadata_->getBoundingBox(min_bb, max_bb); 01246 01247 // Frustum Culling 01248 enum {INSIDE, INTERSECT, OUTSIDE}; 01249 01250 int result = INSIDE; 01251 01252 if (!skip_vfc_check) 01253 { 01254 for(int i =0; i < 6; i++){ 01255 double a = planes[(i*4)]; 01256 double b = planes[(i*4)+1]; 01257 double c = planes[(i*4)+2]; 01258 double d = planes[(i*4)+3]; 01259 01260 //cout << i << ": " << a << "x + " << b << "y + " << c << "z + " << d << endl; 01261 01262 Eigen::Vector3d normal(a, b, c); 01263 01264 // Basic VFC algorithm 01265 Eigen::Vector3d center = node_metadata_->getVoxelCenter(); 01266 Eigen::Vector3d radius (fabs (static_cast<double> (max_bb.x () - center.x ())), 01267 fabs (static_cast<double> (max_bb.y () - center.y ())), 01268 fabs (static_cast<double> (max_bb.z () - center.z ()))); 01269 01270 double m = (center.x () * a) + (center.y () * b) + (center.z () * c) + d; 01271 double n = (radius.x () * fabs(a)) + (radius.y () * fabs(b)) + (radius.z () * fabs(c)); 01272 01273 if (m + n < 0){ 01274 result = OUTSIDE; 01275 break; 01276 } 01277 01278 if (m - n < 0) result = INTERSECT; 01279 01280 } 01281 } 01282 01283 if (result == OUTSIDE) 01284 { 01285 return; 01286 } 01287 01288 // Bounding box projection 01289 // 3--------2 01290 // /| /| Y 0 = xmin, ymin, zmin 01291 // / | / | | 6 = xmax, ymax. zmax 01292 // 7--------6 | | 01293 // | | | | | 01294 // | 0-----|--1 +------X 01295 // | / | / / 01296 // |/ |/ / 01297 // 4--------5 Z 01298 01299 // bounding_box[0] = Eigen::Vector4d(min_bb.x (), min_bb.y (), min_bb.z (), 1.0); 01300 // bounding_box[1] = Eigen::Vector4d(max_bb.x (), min_bb.y (), min_bb.z (), 1.0); 01301 // bounding_box[2] = Eigen::Vector4d(max_bb.x (), max_bb.y (), min_bb.z (), 1.0); 01302 // bounding_box[3] = Eigen::Vector4d(min_bb.x (), max_bb.y (), min_bb.z (), 1.0); 01303 // bounding_box[4] = Eigen::Vector4d(min_bb.x (), min_bb.y (), max_bb.z (), 1.0); 01304 // bounding_box[5] = Eigen::Vector4d(max_bb.x (), min_bb.y (), max_bb.z (), 1.0); 01305 // bounding_box[6] = Eigen::Vector4d(max_bb.x (), max_bb.y (), max_bb.z (), 1.0); 01306 // bounding_box[7] = Eigen::Vector4d(min_bb.x (), max_bb.y (), max_bb.z (), 1.0); 01307 01308 int width = 500; 01309 int height = 500; 01310 01311 float coverage = pcl::visualization::viewScreenArea(eye, min_bb, max_bb, view_projection_matrix, width, height); 01312 //float coverage = pcl::visualization::viewScreenArea(eye, bounding_box, view_projection_matrix); 01313 01314 // for (int i=0; i < this->depth_; i++) std::cout << " "; 01315 // std::cout << this->depth_ << ": " << coverage << std::endl; 01316 01317 // Add files breadth first 01318 if (this->depth_ <= query_depth && payload_->getDataSize () > 0) 01319 //if (payload_->getDataSize () > 0) 01320 { 01321 file_names.push_back (this->node_metadata_->getMetadataFilename ().string ()); 01322 } 01323 01324 //if (coverage <= 0.075) 01325 if (coverage <= 10000) 01326 return; 01327 01328 if (hasUnloadedChildren ()) 01329 { 01330 loadChildren (false); 01331 } 01332 01333 if (this->getNumChildren () > 0) 01334 { 01335 for (size_t i = 0; i < 8; i++) 01336 { 01337 if (children_[i]) 01338 children_[i]->queryFrustum (planes, eye, view_projection_matrix, file_names, query_depth, (result == INSIDE) /*skip_vfc_check*/); 01339 } 01340 } 01341 } 01342 01343 //////////////////////////////////////////////////////////////////////////////// 01344 template<typename ContainerT, typename PointT> void 01345 OutofcoreOctreeBaseNode<ContainerT, PointT>::getOccupiedVoxelCentersRecursive (std::vector<Eigen::Vector3d, Eigen::aligned_allocator<Eigen::Vector3d> > &voxel_centers, const size_t query_depth) 01346 { 01347 if (this->depth_ < query_depth){ 01348 if (num_children_ > 0) 01349 { 01350 for (size_t i = 0; i < 8; i++) 01351 { 01352 if (children_[i]) 01353 children_[i]->getOccupiedVoxelCentersRecursive (voxel_centers, query_depth); 01354 } 01355 } 01356 } 01357 else 01358 { 01359 Eigen::Vector3d voxel_center = node_metadata_->getVoxelCenter (); 01360 voxel_centers.push_back(voxel_center); 01361 } 01362 } 01363 01364 01365 //////////////////////////////////////////////////////////////////////////////// 01366 01367 template<typename ContainerT, typename PointT> void 01368 OutofcoreOctreeBaseNode<ContainerT, PointT>::queryBBIntersects (const Eigen::Vector3d& min_bb, const Eigen::Vector3d& max_bb, const boost::uint32_t query_depth, std::list<std::string>& file_names) 01369 { 01370 01371 Eigen::Vector3d my_min = min_bb; 01372 Eigen::Vector3d my_max = max_bb; 01373 01374 if (intersectsWithBoundingBox (my_min, my_max)) 01375 { 01376 if (this->depth_ < query_depth) 01377 { 01378 if (this->getNumChildren () > 0) 01379 { 01380 for (size_t i = 0; i < 8; i++) 01381 { 01382 if (children_[i]) 01383 children_[i]->queryBBIntersects (my_min, my_max, query_depth, file_names); 01384 } 01385 } 01386 else if (hasUnloadedChildren ()) 01387 { 01388 loadChildren (false); 01389 01390 for (size_t i = 0; i < 8; i++) 01391 { 01392 if (children_[i]) 01393 children_[i]->queryBBIntersects (my_min, my_max, query_depth, file_names); 01394 } 01395 } 01396 return; 01397 } 01398 01399 if (payload_->getDataSize () > 0) 01400 { 01401 file_names.push_back (this->node_metadata_->getMetadataFilename ().string ()); 01402 } 01403 } 01404 } 01405 //////////////////////////////////////////////////////////////////////////////// 01406 01407 template<typename ContainerT, typename PointT> void 01408 OutofcoreOctreeBaseNode<ContainerT, PointT>::queryBBIncludes (const Eigen::Vector3d& min_bb, const Eigen::Vector3d& max_bb, size_t query_depth, const pcl::PCLPointCloud2::Ptr& dst_blob) 01409 { 01410 uint64_t startingSize = dst_blob->width*dst_blob->height; 01411 PCL_DEBUG ("[pcl::outofcore::OutofcoreOctreeBaseNode::%s] Starting points in destination blob: %ul\n", __FUNCTION__, startingSize ); 01412 01413 // If the queried bounding box has any intersection with this node's bounding box 01414 if (intersectsWithBoundingBox (min_bb, max_bb)) 01415 { 01416 // If we aren't at the max desired depth 01417 if (this->depth_ < query_depth) 01418 { 01419 //if this node doesn't have any children, we are at the max depth for this query 01420 if ((num_children_ == 0) && (hasUnloadedChildren ())) 01421 loadChildren (false); 01422 01423 //if this node has children 01424 if (num_children_ > 0) 01425 { 01426 //recursively store any points that fall into the queried bounding box into v and return 01427 for (size_t i = 0; i < 8; i++) 01428 { 01429 if (children_[i]) 01430 children_[i]->queryBBIncludes (min_bb, max_bb, query_depth, dst_blob); 01431 } 01432 PCL_DEBUG ( "[pcl::outofcore::OutofcoreOctreeBaseNode::%s] Points in dst_blob: %ul\n", __FUNCTION__, dst_blob->width*dst_blob->height ); 01433 return; 01434 } 01435 } 01436 else //otherwise if we are at the max depth 01437 { 01438 //get all the points from the payload and return (easy with PCLPointCloud2) 01439 pcl::PCLPointCloud2::Ptr tmp_blob (new pcl::PCLPointCloud2 ()); 01440 pcl::PCLPointCloud2::Ptr tmp_dst_blob (new pcl::PCLPointCloud2 ()); 01441 //load all the data in this node from disk 01442 payload_->readRange (0, payload_->size (), tmp_blob); 01443 01444 if( tmp_blob->width*tmp_blob->height == 0 ) 01445 return; 01446 01447 //if this node's bounding box falls completely within the queried bounding box, keep all the points 01448 if (inBoundingBox (min_bb, max_bb)) 01449 { 01450 //concatenate all of what was just read into the main dst_blob 01451 //(is it safe to do in place?) 01452 01453 //if there is already something in the destination blob (remember this method is recursive) 01454 if( dst_blob->width*dst_blob->height != 0 ) 01455 { 01456 PCL_DEBUG ("[pcl::outofocre::OutofcoreOctreeBaseNode::%s] Size of cloud before: %lu\n", __FUNCTION__, dst_blob->width*dst_blob->height ); 01457 PCL_DEBUG ("[pcl::outofcore::OutofcoreOctreeBaseNode::%s] Concatenating point cloud\n", __FUNCTION__); 01458 int res = pcl::concatenatePointCloud (*dst_blob, *tmp_blob, *dst_blob); 01459 (void)res; 01460 assert (res == 1); 01461 01462 PCL_DEBUG ("[pcl::outofocre::OutofcoreOctreeBaseNode::%s] Size of cloud after: %lu\n", __FUNCTION__, dst_blob->width*dst_blob->height ); 01463 } 01464 //otherwise, just copy the tmp_blob into the dst_blob 01465 else 01466 { 01467 PCL_DEBUG ( "[pcl::outofcore::OutofcoreOctreeBaseNode] Copying point cloud into the destination blob\n"); 01468 pcl::copyPointCloud (*tmp_blob, *dst_blob); 01469 assert (tmp_blob->width*tmp_blob->height == dst_blob->width*dst_blob->height); 01470 } 01471 PCL_DEBUG ( "[pcl::outofcore::OutofcoreOctreeBaseNode::%s] Points in dst_blob: %ul\n", __FUNCTION__, dst_blob->width*dst_blob->height ); 01472 return; 01473 } 01474 else 01475 { 01476 //otherwise queried bounding box only partially intersects this 01477 //node's bounding box, so we have to check all the points in 01478 //this box for intersection with queried bounding box 01479 01480 01481 // PCL_DEBUG ("[pcl::outofcore::OutofcoreOctreeBaseNode::%s] Partial extraction of points in bounding box. Desired: %.2lf %.2lf %2lf, %.2lf %.2lf %.2lf; This node BB: %.2lf %.2lf %.2lf, %.2lf %.2lf %.2lf\n", __FUNCTION__, min_bb[0], min_bb[1], min_bb[2], max_bb[0], max_bb[1], max_bb[2], min_[0], min_[1], min_[2], max_[0], max_[1], max_[2] ); 01482 01483 //put the ros message into a pointxyz point cloud (just to get the indices by using getPointsInBox) 01484 typename pcl::PointCloud<PointT>::Ptr tmp_cloud ( new pcl::PointCloud<PointT> () ); 01485 pcl::fromPCLPointCloud2 ( *tmp_blob, *tmp_cloud ); 01486 assert (tmp_blob->width*tmp_blob->height == tmp_cloud->width*tmp_cloud->height ); 01487 01488 Eigen::Vector4f min_pt ( static_cast<float> ( min_bb[0] ), static_cast<float> ( min_bb[1] ), static_cast<float> ( min_bb[2] ), 1.0f); 01489 Eigen::Vector4f max_pt ( static_cast<float> ( max_bb[0] ), static_cast<float> ( max_bb[1] ) , static_cast<float>( max_bb[2] ), 1.0f ); 01490 01491 std::vector<int> indices; 01492 01493 pcl::getPointsInBox ( *tmp_cloud, min_pt, max_pt, indices ); 01494 PCL_DEBUG ( "[pcl::outofcore::OutofcoreOctreeBaseNode::%s] Points in box: %d\n", __FUNCTION__, indices.size () ); 01495 PCL_DEBUG ( "[pcl::outofcore::OutofcoreOctreeBaseNode::%s] Points remaining: %d\n", __FUNCTION__, tmp_cloud->width*tmp_cloud->height - indices.size () ); 01496 01497 if ( indices.size () > 0 ) 01498 { 01499 if( dst_blob->width*dst_blob->height > 0 ) 01500 { 01501 //need a new tmp destination with extracted points within BB 01502 pcl::PCLPointCloud2::Ptr tmp_blob_within_bb (new pcl::PCLPointCloud2 ()); 01503 01504 //copy just the points marked in indices 01505 pcl::copyPointCloud ( *tmp_blob, indices, *tmp_blob_within_bb ); 01506 assert ( tmp_blob_within_bb->width*tmp_blob_within_bb->height == indices.size () ); 01507 assert ( tmp_blob->fields.size () == tmp_blob_within_bb->fields.size () ); 01508 //concatenate those points into the returned dst_blob 01509 PCL_DEBUG ("[pcl::outofcore::OutofcoreOctreeBaseNode::%s] Concatenating point cloud in place\n", __FUNCTION__); 01510 boost::uint64_t orig_points_in_destination = dst_blob->width*dst_blob->height; 01511 (void)orig_points_in_destination; 01512 int res = pcl::concatenatePointCloud (*dst_blob, *tmp_blob_within_bb, *dst_blob); 01513 (void)res; 01514 assert (res == 1); 01515 assert (dst_blob->width*dst_blob->height == indices.size () + orig_points_in_destination); 01516 01517 } 01518 else 01519 { 01520 pcl::copyPointCloud ( *tmp_blob, indices, *dst_blob ); 01521 assert ( dst_blob->width*dst_blob->height == indices.size () ); 01522 } 01523 } 01524 } 01525 } 01526 } 01527 01528 PCL_DEBUG ("[pcl::outofcore::OutofcoreOctreeBaseNode::%s] Points added by function call: %ul\n", __FUNCTION__, dst_blob->width*dst_blob->height - startingSize ); 01529 } 01530 01531 template<typename ContainerT, typename PointT> void 01532 OutofcoreOctreeBaseNode<ContainerT, PointT>::queryBBIncludes (const Eigen::Vector3d& min_bb, const Eigen::Vector3d& max_bb, size_t query_depth, AlignedPointTVector& v) 01533 { 01534 01535 //if the queried bounding box has any intersection with this node's bounding box 01536 if (intersectsWithBoundingBox (min_bb, max_bb)) 01537 { 01538 //if we aren't at the max desired depth 01539 if (this->depth_ < query_depth) 01540 { 01541 //if this node doesn't have any children, we are at the max depth for this query 01542 if (this->hasUnloadedChildren ()) 01543 { 01544 this->loadChildren (false); 01545 } 01546 01547 //if this node has children 01548 if (getNumChildren () > 0) 01549 { 01550 if(hasUnloadedChildren ()) 01551 loadChildren (false); 01552 01553 //recursively store any points that fall into the queried bounding box into v and return 01554 for (size_t i = 0; i < 8; i++) 01555 { 01556 if (children_[i]) 01557 children_[i]->queryBBIncludes (min_bb, max_bb, query_depth, v); 01558 } 01559 return; 01560 } 01561 } 01562 //otherwise if we are at the max depth 01563 else 01564 { 01565 //if this node's bounding box falls completely within the queried bounding box 01566 if (inBoundingBox (min_bb, max_bb)) 01567 { 01568 //get all the points from the payload and return 01569 AlignedPointTVector payload_cache; 01570 payload_->readRange (0, payload_->size (), payload_cache); 01571 v.insert (v.end (), payload_cache.begin (), payload_cache.end ()); 01572 return; 01573 } 01574 //otherwise queried bounding box only partially intersects this 01575 //node's bounding box, so we have to check all the points in 01576 //this box for intersection with queried bounding box 01577 else 01578 { 01579 //read _all_ the points in from the disk container 01580 AlignedPointTVector payload_cache; 01581 payload_->readRange (0, payload_->size (), payload_cache); 01582 01583 uint64_t len = payload_->size (); 01584 //iterate through each of them 01585 for (uint64_t i = 0; i < len; i++) 01586 { 01587 const PointT& p = payload_cache[i]; 01588 //if it falls within this bounding box 01589 if (pointInBoundingBox (min_bb, max_bb, p)) 01590 { 01591 //store it in the list 01592 v.push_back (p); 01593 } 01594 else 01595 { 01596 PCL_DEBUG ("[pcl::outofcore::queryBBIncludes] Point %.2lf %.2lf %.2lf not in bounding box %.2lf %.2lf %.2lf", p.x, p.y, p.z, min_bb[0], min_bb[1], min_bb[2], max_bb[0], max_bb[1], max_bb[2]); 01597 } 01598 } 01599 } 01600 } 01601 } 01602 } 01603 01604 //////////////////////////////////////////////////////////////////////////////// 01605 template<typename ContainerT, typename PointT> void 01606 OutofcoreOctreeBaseNode<ContainerT, PointT>::queryBBIncludes_subsample (const Eigen::Vector3d& min_bb, const Eigen::Vector3d& max_bb, boost::uint64_t query_depth, const pcl::PCLPointCloud2::Ptr& dst_blob, double percent) 01607 { 01608 if (intersectsWithBoundingBox (min_bb, max_bb)) 01609 { 01610 if (this->depth_ < query_depth) 01611 { 01612 if (this->hasUnloadedChildren ()) 01613 this->loadChildren (false); 01614 01615 if (this->getNumChildren () > 0) 01616 { 01617 for (size_t i=0; i<8; i++) 01618 { 01619 //recursively traverse (depth first) 01620 if (children_[i]!=0) 01621 children_[i]->queryBBIncludes_subsample (min_bb, max_bb, query_depth, dst_blob, percent); 01622 } 01623 return; 01624 } 01625 } 01626 //otherwise, at max depth --> read from disk, subsample, concatenate 01627 else 01628 { 01629 01630 if (inBoundingBox (min_bb, max_bb)) 01631 { 01632 pcl::PCLPointCloud2::Ptr tmp_blob; 01633 this->payload_->read (tmp_blob); 01634 uint64_t num_pts = tmp_blob->width*tmp_blob->height; 01635 01636 double sample_points = static_cast<double>(num_pts) * percent; 01637 if (num_pts > 0) 01638 { 01639 //always sample at least one point 01640 sample_points = sample_points > 0 ? sample_points : 1; 01641 } 01642 else 01643 { 01644 return; 01645 } 01646 01647 01648 pcl::RandomSample<pcl::PCLPointCloud2> random_sampler; 01649 random_sampler.setInputCloud (tmp_blob); 01650 01651 pcl::PCLPointCloud2::Ptr downsampled_points (new pcl::PCLPointCloud2 ()); 01652 01653 //set sample size as percent * number of points read 01654 random_sampler.setSample (static_cast<unsigned int> (sample_points)); 01655 01656 pcl::ExtractIndices<pcl::PCLPointCloud2> extractor; 01657 01658 pcl::IndicesPtr downsampled_cloud_indices (new std::vector<int> ()); 01659 random_sampler.filter (*downsampled_cloud_indices); 01660 extractor.setIndices (downsampled_cloud_indices); 01661 extractor.filter (*downsampled_points); 01662 01663 //concatenate the result into the destination cloud 01664 pcl::concatenatePointCloud (*dst_blob, *downsampled_points, *dst_blob); 01665 } 01666 } 01667 } 01668 } 01669 01670 01671 //////////////////////////////////////////////////////////////////////////////// 01672 template<typename ContainerT, typename PointT> void 01673 OutofcoreOctreeBaseNode<ContainerT, PointT>::queryBBIncludes_subsample (const Eigen::Vector3d& min_bb, const Eigen::Vector3d& max_bb, boost::uint64_t query_depth, const double percent, AlignedPointTVector& dst) 01674 { 01675 //check if the queried bounding box has any intersection with this node's bounding box 01676 if (intersectsWithBoundingBox (min_bb, max_bb)) 01677 { 01678 //if we are not at the max depth for queried nodes 01679 if (this->depth_ < query_depth) 01680 { 01681 //check if we don't have children 01682 if ((num_children_ == 0) && (hasUnloadedChildren ())) 01683 { 01684 loadChildren (false); 01685 } 01686 //if we do have children 01687 if (num_children_ > 0) 01688 { 01689 //recursively add their valid points within the queried bounding box to the list v 01690 for (size_t i = 0; i < 8; i++) 01691 { 01692 if (children_[i]) 01693 children_[i]->queryBBIncludes_subsample (min_bb, max_bb, query_depth, percent, dst); 01694 } 01695 return; 01696 } 01697 } 01698 //otherwise we are at the max depth, so we add all our points or some of our points 01699 else 01700 { 01701 //if this node's bounding box falls completely within the queried bounding box 01702 if (inBoundingBox (min_bb, max_bb)) 01703 { 01704 //add a random sample of all the points 01705 AlignedPointTVector payload_cache; 01706 payload_->readRangeSubSample (0, payload_->size (), percent, payload_cache); 01707 dst.insert (dst.end (), payload_cache.begin (), payload_cache.end ()); 01708 return; 01709 } 01710 //otherwise the queried bounding box only partially intersects with this node's bounding box 01711 else 01712 { 01713 //brute force selection of all valid points 01714 AlignedPointTVector payload_cache_within_region; 01715 { 01716 AlignedPointTVector payload_cache; 01717 payload_->readRange (0, payload_->size (), payload_cache); 01718 for (size_t i = 0; i < payload_->size (); i++) 01719 { 01720 const PointT& p = payload_cache[i]; 01721 if (pointInBoundingBox (min_bb, max_bb, p)) 01722 { 01723 payload_cache_within_region.push_back (p); 01724 } 01725 } 01726 }//force the payload cache to deconstruct here 01727 01728 //use STL random_shuffle and push back a random selection of the points onto our list 01729 std::random_shuffle (payload_cache_within_region.begin (), payload_cache_within_region.end ()); 01730 size_t numpick = static_cast<size_t> (percent * static_cast<double> (payload_cache_within_region.size ()));; 01731 01732 for (size_t i = 0; i < numpick; i++) 01733 { 01734 dst.push_back (payload_cache_within_region[i]); 01735 } 01736 } 01737 } 01738 } 01739 } 01740 //////////////////////////////////////////////////////////////////////////////// 01741 01742 //dir is current level. we put this nodes files into it 01743 template<typename ContainerT, typename PointT> 01744 OutofcoreOctreeBaseNode<ContainerT, PointT>::OutofcoreOctreeBaseNode (const Eigen::Vector3d& bb_min, const Eigen::Vector3d& bb_max, const char* dir, OutofcoreOctreeBaseNode<ContainerT,PointT>* super) 01745 : m_tree_ () 01746 , root_node_ () 01747 , parent_ () 01748 , depth_ () 01749 , children_ (std::vector <OutofcoreOctreeBaseNode<ContainerT, PointT>*> (8,static_cast<OutofcoreOctreeBaseNode<ContainerT, PointT>*>(0))) 01750 , num_children_ () 01751 , num_loaded_children_ (0) 01752 , payload_ () 01753 , node_metadata_ () 01754 { 01755 node_metadata_ = boost::shared_ptr<OutofcoreOctreeNodeMetadata> (new OutofcoreOctreeNodeMetadata ()); 01756 node_metadata_->setOutofcoreVersion (3); 01757 01758 if (super == NULL) 01759 { 01760 PCL_ERROR ( "[pc::outofcore::OutofcoreOctreeBaseNode] Super is null - don't make a root node this way!\n" ); 01761 PCL_THROW_EXCEPTION (PCLException, "[pcl::outofcore::OutofcoreOctreeBaseNode] Outofcore Exception: Bad parent"); 01762 } 01763 01764 this->parent_ = super; 01765 root_node_ = super->root_node_; 01766 m_tree_ = super->root_node_->m_tree_; 01767 assert (m_tree_ != NULL); 01768 01769 depth_ = super->depth_ + 1; 01770 num_children_ = 0; 01771 01772 node_metadata_->setBoundingBox (bb_min, bb_max); 01773 01774 std::string uuid_idx; 01775 std::string uuid_cont; 01776 OutofcoreOctreeDiskContainer<PointT>::getRandomUUIDString (uuid_idx); 01777 OutofcoreOctreeDiskContainer<PointT>::getRandomUUIDString (uuid_cont); 01778 01779 std::string node_index_name = uuid_idx + std::string ("_") + node_index_basename + node_index_extension; 01780 01781 std::string node_container_name; 01782 node_container_name = uuid_cont + std::string ("_") + node_container_basename + pcd_extension; 01783 01784 node_metadata_->setDirectoryPathname (boost::filesystem::path (dir)); 01785 node_metadata_->setPCDFilename (node_metadata_->getDirectoryPathname () / boost::filesystem::path (node_container_name)); 01786 node_metadata_->setMetadataFilename ( node_metadata_->getDirectoryPathname ()/boost::filesystem::path (node_index_name)); 01787 01788 boost::filesystem::create_directory (node_metadata_->getDirectoryPathname ()); 01789 01790 payload_ = boost::shared_ptr<ContainerT> (new ContainerT (node_metadata_->getPCDFilename ())); 01791 this->saveIdx (false); 01792 } 01793 01794 //////////////////////////////////////////////////////////////////////////////// 01795 01796 template<typename ContainerT, typename PointT> void 01797 OutofcoreOctreeBaseNode<ContainerT, PointT>::copyAllCurrentAndChildPointsRec (std::list<PointT>& v) 01798 { 01799 if ((num_children_ == 0) && (hasUnloadedChildren ())) 01800 { 01801 loadChildren (false); 01802 } 01803 01804 for (size_t i = 0; i < num_children_; i++) 01805 { 01806 children_[i]->copyAllCurrentAndChildPointsRec (v); 01807 } 01808 01809 AlignedPointTVector payload_cache; 01810 payload_->readRange (0, payload_->size (), payload_cache); 01811 01812 { 01813 //boost::mutex::scoped_lock lock(queryBBIncludes_vector_mutex); 01814 v.insert (v.end (), payload_cache.begin (), payload_cache.end ()); 01815 } 01816 } 01817 01818 //////////////////////////////////////////////////////////////////////////////// 01819 01820 template<typename ContainerT, typename PointT> void 01821 OutofcoreOctreeBaseNode<ContainerT, PointT>::copyAllCurrentAndChildPointsRec_sub (std::list<PointT>& v, const double percent) 01822 { 01823 if ((num_children_ == 0) && (hasUnloadedChildren ())) 01824 { 01825 loadChildren (false); 01826 } 01827 01828 for (size_t i = 0; i < 8; i++) 01829 { 01830 if (children_[i]) 01831 children_[i]->copyAllCurrentAndChildPointsRec_sub (v, percent); 01832 } 01833 01834 std::vector<PointT> payload_cache; 01835 payload_->readRangeSubSample (0, payload_->size (), percent, payload_cache); 01836 01837 for (size_t i = 0; i < payload_cache.size (); i++) 01838 { 01839 v.push_back (payload_cache[i]); 01840 } 01841 } 01842 01843 //////////////////////////////////////////////////////////////////////////////// 01844 01845 template<typename ContainerT, typename PointT> inline bool 01846 OutofcoreOctreeBaseNode<ContainerT, PointT>::intersectsWithBoundingBox (const Eigen::Vector3d& min_bb, const Eigen::Vector3d& max_bb) const 01847 { 01848 Eigen::Vector3d min, max; 01849 node_metadata_->getBoundingBox (min, max); 01850 01851 //Check whether any portion of min_bb, max_bb falls within min,max 01852 if (((min[0] <= min_bb[0]) && (min_bb[0] <= max[0])) || ((min_bb[0] <= min[0]) && (min[0] <= max_bb[0]))) 01853 { 01854 if (((min[1] <= min_bb[1]) && (min_bb[1] <= max[1])) || ((min_bb[1] <= min[1]) && (min[1] <= max_bb[1]))) 01855 { 01856 if (((min[2] <= min_bb[2]) && (min_bb[2] <= max[2])) || ((min_bb[2] <= min[2]) && (min[2] <= max_bb[2]))) 01857 { 01858 return (true); 01859 } 01860 } 01861 } 01862 01863 return (false); 01864 } 01865 //////////////////////////////////////////////////////////////////////////////// 01866 01867 template<typename ContainerT, typename PointT> inline bool 01868 OutofcoreOctreeBaseNode<ContainerT, PointT>::inBoundingBox (const Eigen::Vector3d& min_bb, const Eigen::Vector3d& max_bb) const 01869 { 01870 Eigen::Vector3d min, max; 01871 01872 node_metadata_->getBoundingBox (min, max); 01873 01874 if ((min_bb[0] <= min[0]) && (max[0] <= max_bb[0])) 01875 { 01876 if ((min_bb[1] <= min[1]) && (max[1] <= max_bb[1])) 01877 { 01878 if ((min_bb[2] <= min[2]) && (max[2] <= max_bb[2])) 01879 { 01880 return (true); 01881 } 01882 } 01883 } 01884 01885 return (false); 01886 } 01887 //////////////////////////////////////////////////////////////////////////////// 01888 01889 template<typename ContainerT, typename PointT> inline bool 01890 OutofcoreOctreeBaseNode<ContainerT, PointT>::pointInBoundingBox (const Eigen::Vector3d& min_bb, const Eigen::Vector3d& max_bb, 01891 const PointT& p) 01892 { 01893 //by convention, minimum boundary is included; maximum boundary is not 01894 if ((min_bb[0] <= p.x) && (p.x < max_bb[0])) 01895 { 01896 if ((min_bb[1] <= p.y) && (p.y < max_bb[1])) 01897 { 01898 if ((min_bb[2] <= p.z) && (p.z < max_bb[2])) 01899 { 01900 return (true); 01901 } 01902 } 01903 } 01904 return (false); 01905 } 01906 01907 //////////////////////////////////////////////////////////////////////////////// 01908 01909 template<typename ContainerT, typename PointT> void 01910 OutofcoreOctreeBaseNode<ContainerT, PointT>::writeVPythonVisual (std::ofstream& file) 01911 { 01912 Eigen::Vector3d min; 01913 Eigen::Vector3d max; 01914 node_metadata_->getBoundingBox (min, max); 01915 01916 double l = max[0] - min[0]; 01917 double h = max[1] - min[1]; 01918 double w = max[2] - min[2]; 01919 file << "box( pos=(" << min[0] << ", " << min[1] << ", " << min[2] << "), length=" << l << ", height=" << h 01920 << ", width=" << w << " )\n"; 01921 01922 for (size_t i = 0; i < num_children_; i++) 01923 { 01924 children_[i]->writeVPythonVisual (file); 01925 } 01926 } 01927 01928 //////////////////////////////////////////////////////////////////////////////// 01929 01930 template<typename ContainerT, typename PointT> int 01931 OutofcoreOctreeBaseNode<ContainerT, PointT>::read (pcl::PCLPointCloud2::Ptr &output_cloud) 01932 { 01933 return (this->payload_->read (output_cloud)); 01934 } 01935 01936 //////////////////////////////////////////////////////////////////////////////// 01937 01938 template<typename ContainerT, typename PointT> OutofcoreOctreeBaseNode<ContainerT, PointT>* 01939 OutofcoreOctreeBaseNode<ContainerT, PointT>::getChildPtr (size_t index_arg) const 01940 { 01941 PCL_DEBUG ("[pcl::outofcore::OutofcoreOctreeBaseNode::%s] %d", __FUNCTION__, index_arg); 01942 return (children_[index_arg]); 01943 } 01944 01945 //////////////////////////////////////////////////////////////////////////////// 01946 template<typename ContainerT, typename PointT> boost::uint64_t 01947 OutofcoreOctreeBaseNode<ContainerT, PointT>::getDataSize () const 01948 { 01949 return (this->payload_->getDataSize ()); 01950 } 01951 01952 //////////////////////////////////////////////////////////////////////////////// 01953 01954 template<typename ContainerT, typename PointT> size_t 01955 OutofcoreOctreeBaseNode<ContainerT, PointT>::countNumLoadedChildren () const 01956 { 01957 size_t loaded_children_count = 0; 01958 01959 for (size_t i=0; i<8; i++) 01960 { 01961 if (children_[i] != 0) 01962 loaded_children_count++; 01963 } 01964 01965 return (loaded_children_count); 01966 } 01967 01968 //////////////////////////////////////////////////////////////////////////////// 01969 01970 template<typename ContainerT, typename PointT> void 01971 OutofcoreOctreeBaseNode<ContainerT, PointT>::loadFromFile (const boost::filesystem::path& path, OutofcoreOctreeBaseNode<ContainerT, PointT>* super) 01972 { 01973 PCL_DEBUG ("[pcl:outofcore::OutofcoreOctreeBaseNode] Loading metadata from %s\n", path.filename ().c_str ()); 01974 node_metadata_->loadMetadataFromDisk (path); 01975 01976 //this shouldn't be part of 'loadFromFile' 01977 this->parent_ = super; 01978 01979 if (num_children_ > 0) 01980 recFreeChildren (); 01981 01982 this->num_children_ = 0; 01983 this->payload_ = boost::shared_ptr<ContainerT> (new ContainerT (node_metadata_->getPCDFilename ())); 01984 } 01985 01986 //////////////////////////////////////////////////////////////////////////////// 01987 01988 template<typename ContainerT, typename PointT> void 01989 OutofcoreOctreeBaseNode<ContainerT, PointT>::convertToXYZRecursive () 01990 { 01991 std::string fname = boost::filesystem::basename (node_metadata_->getPCDFilename ()) + std::string (".dat.xyz"); 01992 boost::filesystem::path xyzfile = node_metadata_->getDirectoryPathname () / fname; 01993 payload_->convertToXYZ (xyzfile); 01994 01995 if (hasUnloadedChildren ()) 01996 { 01997 loadChildren (false); 01998 } 01999 02000 for (size_t i = 0; i < 8; i++) 02001 { 02002 if (children_[i]) 02003 children_[i]->convertToXYZ (); 02004 } 02005 } 02006 02007 //////////////////////////////////////////////////////////////////////////////// 02008 02009 template<typename ContainerT, typename PointT> void 02010 OutofcoreOctreeBaseNode<ContainerT, PointT>::flushToDiskRecursive () 02011 { 02012 for (size_t i = 0; i < 8; i++) 02013 { 02014 if (children_[i]) 02015 children_[i]->flushToDiskRecursive (); 02016 } 02017 } 02018 02019 //////////////////////////////////////////////////////////////////////////////// 02020 02021 template<typename ContainerT, typename PointT> void 02022 OutofcoreOctreeBaseNode<ContainerT, PointT>::sortOctantIndices (const pcl::PCLPointCloud2::Ptr &input_cloud, std::vector< std::vector<int> > &indices, const Eigen::Vector3d &mid_xyz) 02023 { 02024 if (indices.size () < 8) 02025 indices.resize (8); 02026 02027 int x_idx = pcl::getFieldIndex (*input_cloud , std::string ("x") ); 02028 int y_idx = pcl::getFieldIndex (*input_cloud, std::string ("y") ); 02029 int z_idx = pcl::getFieldIndex (*input_cloud, std::string ("z") ); 02030 02031 int x_offset = input_cloud->fields[x_idx].offset; 02032 int y_offset = input_cloud->fields[y_idx].offset; 02033 int z_offset = input_cloud->fields[z_idx].offset; 02034 02035 for ( size_t point_idx =0; point_idx < input_cloud->data.size (); point_idx +=input_cloud->point_step ) 02036 { 02037 PointT local_pt; 02038 02039 local_pt.x = * (reinterpret_cast<float*>(&input_cloud->data[point_idx + x_offset])); 02040 local_pt.y = * (reinterpret_cast<float*>(&input_cloud->data[point_idx + y_offset])); 02041 local_pt.z = * (reinterpret_cast<float*>(&input_cloud->data[point_idx + z_offset])); 02042 02043 if (!pcl_isfinite (local_pt.x) || !pcl_isfinite (local_pt.y) || !pcl_isfinite (local_pt.z)) 02044 continue; 02045 02046 if(!this->pointInBoundingBox (local_pt)) 02047 { 02048 PCL_ERROR ("pcl::outofcore::OutofcoreOctreeBaseNode::%s] Point %2.lf %.2lf %.2lf not in bounding box", __FUNCTION__, local_pt.x, local_pt.y, local_pt.z); 02049 } 02050 02051 assert (this->pointInBoundingBox (local_pt) == true); 02052 02053 //compute the box we are in 02054 size_t box = 0; 02055 box = ((local_pt.z >= mid_xyz[2]) << 2) | ((local_pt.y >= mid_xyz[1]) << 1) | ((local_pt.x >= mid_xyz[0]) << 0); 02056 assert (box < 8); 02057 02058 //insert to the vector of indices 02059 indices[box].push_back (static_cast<int> (point_idx/input_cloud->point_step)); 02060 } 02061 } 02062 //////////////////////////////////////////////////////////////////////////////// 02063 02064 #if 0 //A bunch of non-class methods left from the Urban Robotics code that has been deactivated 02065 template<typename ContainerT, typename PointT> OutofcoreOctreeBaseNode<ContainerT, PointT>* 02066 makenode_norec (const boost::filesystem::path& path, OutofcoreOctreeBaseNode<ContainerT, PointT>* super) 02067 { 02068 OutofcoreOctreeBaseNode<ContainerT, PointT>* thisnode = new OutofcoreOctreeBaseNode<OutofcoreOctreeDiskContainer < PointT > , PointT > (); 02069 //octree_disk_node (); 02070 02071 if (super == NULL) 02072 { 02073 thisnode->thisdir_ = path.parent_path (); 02074 02075 if (!boost::filesystem::exists (thisnode->thisdir_)) 02076 { 02077 PCL_ERROR ( "[pcl::outofcore::OutofcoreOctreeBaseNode] could not find dir %s\n",thisnode->thisdir_.c_str () ); 02078 PCL_THROW_EXCEPTION (PCLException, "[pcl::outofcore::OutofcoreOctreeBaseNode] Outofcore Octree Exception: Could not find directory"); 02079 } 02080 02081 thisnode->thisnodeindex_ = path; 02082 02083 thisnode->depth_ = 0; 02084 thisnode->root_node_ = thisnode; 02085 } 02086 else 02087 { 02088 thisnode->thisdir_ = path; 02089 thisnode->depth_ = super->depth_ + 1; 02090 thisnode->root_node_ = super->root_node_; 02091 02092 if (thisnode->depth_ > thisnode->root->max_depth_) 02093 { 02094 thisnode->root->max_depth_ = thisnode->depth_; 02095 } 02096 02097 boost::filesystem::directory_iterator diterend; 02098 bool loaded = false; 02099 for (boost::filesystem::directory_iterator diter (thisnode->thisdir_); diter != diterend; ++diter) 02100 { 02101 const boost::filesystem::path& file = *diter; 02102 if (!boost::filesystem::is_directory (file)) 02103 { 02104 if (boost::filesystem::extension (file) == OutofcoreOctreeBaseNode<ContainerT, PointT>::node_index_extension) 02105 { 02106 thisnode->thisnodeindex_ = file; 02107 loaded = true; 02108 break; 02109 } 02110 } 02111 } 02112 02113 if (!loaded) 02114 { 02115 PCL_ERROR ("[pcl::outofcore::OutofcoreOctreeBaseNode] Could not find index!\n"); 02116 PCL_THROW_EXCEPTION (PCLException, "[pcl::outofcore::OutofcoreOctreeBaseNode] Could not find node metadata index file"); 02117 } 02118 02119 } 02120 thisnode->max_depth_ = 0; 02121 02122 { 02123 std::ifstream f (thisnode->thisnodeindex_.string ().c_str (), std::ios::in); 02124 02125 f >> thisnode->min_[0]; 02126 f >> thisnode->min_[1]; 02127 f >> thisnode->min_[2]; 02128 f >> thisnode->max_[0]; 02129 f >> thisnode->max_[1]; 02130 f >> thisnode->max_[2]; 02131 02132 std::string filename; 02133 f >> filename; 02134 thisnode->thisnodestorage_ = thisnode->thisdir_ / filename; 02135 02136 f.close (); 02137 02138 thisnode->payload_ = boost::shared_ptr<ContainerT> (new ContainerT (thisnode->thisnodestorage_)); 02139 } 02140 02141 thisnode->parent_ = super; 02142 children_.clear (); 02143 children_.resize (8, static_cast<OutofcoreOctreeBaseNode<ContainerT, PointT>* > (0)); 02144 thisnode->num_children_ = 0; 02145 02146 return (thisnode); 02147 } 02148 02149 //////////////////////////////////////////////////////////////////////////////// 02150 02151 //accelerate search 02152 template<typename ContainerT, typename PointT> void 02153 queryBBIntersects_noload (const boost::filesystem::path& root_node, const Eigen::Vector3d& min, const Eigen::Vector3d& max, const boost::uint32_t query_depth, std::list<std::string>& bin_name) 02154 { 02155 OutofcoreOctreeBaseNode<ContainerT, PointT>* root = makenode_norec<ContainerT, PointT> (root_node, NULL); 02156 if (root == NULL) 02157 { 02158 std::cout << "test"; 02159 } 02160 if (root->intersectsWithBoundingBox (min, max)) 02161 { 02162 if (query_depth == root->max_depth_) 02163 { 02164 if (!root->payload_->empty ()) 02165 { 02166 bin_name.push_back (root->thisnodestorage_.string ()); 02167 } 02168 return; 02169 } 02170 02171 for (int i = 0; i < 8; i++) 02172 { 02173 boost::filesystem::path child_dir = root->thisdir_ 02174 / boost::filesystem::path (boost::lexical_cast<std::string> (i)); 02175 if (boost::filesystem::exists (child_dir)) 02176 { 02177 root->children_[i] = makenode_norec (child_dir, root); 02178 root->num_children_++; 02179 queryBBIntersects_noload (root->children_[i], min, max, root->max_depth_ - query_depth, bin_name); 02180 } 02181 } 02182 } 02183 delete root; 02184 } 02185 02186 //////////////////////////////////////////////////////////////////////////////// 02187 02188 template<typename ContainerT, typename PointT> void 02189 queryBBIntersects_noload (OutofcoreOctreeBaseNode<ContainerT, PointT>* current, const Eigen::Vector3d& min, const Eigen::Vector3d& max, const boost::uint32_t query_depth, std::list<std::string>& bin_name) 02190 { 02191 if (current->intersectsWithBoundingBox (min, max)) 02192 { 02193 if (current->depth_ == query_depth) 02194 { 02195 if (!current->payload_->empty ()) 02196 { 02197 bin_name.push_back (current->thisnodestorage_.string ()); 02198 } 02199 } 02200 else 02201 { 02202 for (int i = 0; i < 8; i++) 02203 { 02204 boost::filesystem::path child_dir = current->thisdir_ / boost::filesystem::path (boost::lexical_cast<std::string> (i)); 02205 if (boost::filesystem::exists (child_dir)) 02206 { 02207 current->children_[i] = makenode_norec<ContainerT, PointT> (child_dir, current); 02208 current->num_children_++; 02209 queryBBIntersects_noload (current->children_[i], min, max, query_depth, bin_name); 02210 } 02211 } 02212 } 02213 } 02214 } 02215 #endif 02216 //////////////////////////////////////////////////////////////////////////////// 02217 02218 }//namespace outofcore 02219 }//namespace pcl 02220 02221 //#define PCL_INSTANTIATE.... 02222 02223 #endif //PCL_OUTOFCORE_OCTREE_BASE_NODE_IMPL_H_
Except where otherwise noted, the PointClouds.org web pages are licensed under Creative Commons Attribution 3.0.
Pages generated on Wed Mar 25 00:24:35 2015