40 #ifndef PCL_OUTOFCORE_OCTREE_BASE_IMPL_H_
41 #define PCL_OUTOFCORE_OCTREE_BASE_IMPL_H_
44 #include <pcl/outofcore/octree_base.h>
47 #include <pcl/pcl_config.h>
48 #if defined(HAVE_CJSON)
49 #include <cjson/cJSON.h>
51 #include <pcl/outofcore/cJSON.h>
54 #include <pcl/filters/random_sample.h>
55 #include <pcl/filters/extract_indices.h>
73 template<
typename ContainerT,
typename Po
intT>
76 template<
typename ContainerT,
typename Po
intT>
81 template<
typename ContainerT,
typename Po
intT>
84 , read_write_mutex_ ()
86 , sample_percent_ (0.125)
92 PCL_THROW_EXCEPTION (
PCLException,
"[pcl::outofcore::OutofcoreOctreeBase] Bad extension. Outofcore Octrees must have a root node ending in .oct_idx\n");
101 boost::filesystem::path treepath = root_name.parent_path () / (root_name.stem ().string () +
TREE_EXTENSION_);
104 metadata_->loadMetadataFromDisk (treepath);
109 template<
typename ContainerT,
typename Po
intT>
112 , read_write_mutex_ ()
114 , sample_percent_ (0.125)
118 Eigen::Vector3d tmp_min = min;
119 Eigen::Vector3d tmp_max = max;
120 this->enlargeToCube (tmp_min, tmp_max);
123 std::uint64_t depth = this->calculateDepth (tmp_min, tmp_max, resolution_arg);
126 this->
init (depth, tmp_min, tmp_max, root_node_name, coord_sys);
131 template<
typename ContainerT,
typename Po
intT>
134 , read_write_mutex_ ()
136 , sample_percent_ (0.125)
140 this->
init (max_depth, min, max, root_node_name, coord_sys);
144 template<
typename ContainerT,
typename Po
intT>
void
148 if (!this->checkExtension (root_name))
150 PCL_THROW_EXCEPTION (
PCLException,
"[pcl::outofcore::OutofcoreOctreeBase] Bad extension. Outofcore Octrees must have a root node ending in .oct_idx\n");
154 if (boost::filesystem::exists (root_name.parent_path ()))
156 PCL_ERROR (
"[pcl::outofcore::OutofcoreOctreeBase] A dir named %s already exists. Overwriting an existing tree is not supported.\n", root_name.parent_path ().c_str () );
157 PCL_THROW_EXCEPTION (
PCLException,
"[pcl::outofcore::OutofcoreOctreeBase] Directory exists; Overwriting an existing tree is not supported\n");
161 boost::filesystem::path dir = root_name.parent_path ();
163 if (!boost::filesystem::exists (dir))
165 boost::filesystem::create_directory (dir);
168 Eigen::Vector3d tmp_min = min;
169 Eigen::Vector3d tmp_max = max;
170 this->enlargeToCube (tmp_min, tmp_max);
174 root_node_->m_tree_ =
this;
177 boost::filesystem::path treepath = dir / (root_name.stem ().string () + TREE_EXTENSION_);
180 metadata_->setCoordinateSystem (coord_sys);
181 metadata_->setDepth (depth);
182 metadata_->setLODPoints (depth+1);
183 metadata_->setMetadataFilename (treepath);
184 metadata_->setOutofcoreVersion (OUTOFCORE_VERSION_);
188 metadata_->serializeMetadataToDisk ();
193 template<
typename ContainerT,
typename Po
intT>
196 root_node_->flushToDiskRecursive ();
204 template<
typename ContainerT,
typename Po
intT>
void
207 this->metadata_->serializeMetadataToDisk ();
212 template<
typename ContainerT,
typename Po
intT> std::uint64_t
215 std::unique_lock < std::shared_timed_mutex > lock (read_write_mutex_);
217 constexpr
bool _FORCE_BB_CHECK =
true;
219 std::uint64_t pt_added = root_node_->addDataToLeaf (p, _FORCE_BB_CHECK);
221 assert (p.size () == pt_added);
228 template<
typename ContainerT,
typename Po
intT> std::uint64_t
231 return (addDataToLeaf (point_cloud->points));
236 template<
typename ContainerT,
typename Po
intT> std::uint64_t
239 std::uint64_t pt_added = this->root_node_->addPointCloud (input_cloud, skip_bb_check) ;
247 template<
typename ContainerT,
typename Po
intT> std::uint64_t
251 std::unique_lock < std::shared_timed_mutex > lock (read_write_mutex_);
252 std::uint64_t pt_added = root_node_->addDataToLeaf_and_genLOD (point_cloud->points,
false);
258 template<
typename ContainerT,
typename Po
intT> std::uint64_t
262 std::unique_lock < std::shared_timed_mutex > lock (read_write_mutex_);
263 std::uint64_t pt_added = root_node_->addPointCloud_and_genLOD (input_cloud);
265 PCL_DEBUG (
"[pcl::outofcore::OutofcoreOctreeBase::%s] Points added %lu, points in input cloud, %lu\n",__FUNCTION__, pt_added, input_cloud->width*input_cloud->height );
267 assert ( input_cloud->width*input_cloud->height == pt_added );
274 template<
typename ContainerT,
typename Po
intT> std::uint64_t
278 std::unique_lock < std::shared_timed_mutex > lock (read_write_mutex_);
279 std::uint64_t pt_added = root_node_->addDataToLeaf_and_genLOD (src,
false);
285 template<
typename Container,
typename Po
intT>
void
288 std::shared_lock < std::shared_timed_mutex > lock (read_write_mutex_);
289 root_node_->queryFrustum (planes, file_names, this->getTreeDepth());
294 template<
typename Container,
typename Po
intT>
void
297 std::shared_lock < std::shared_timed_mutex > lock (read_write_mutex_);
298 root_node_->queryFrustum (planes, file_names, query_depth);
303 template<
typename Container,
typename Po
intT>
void
305 const double *planes,
306 const Eigen::Vector3d &eye,
307 const Eigen::Matrix4d &view_projection_matrix,
308 std::list<std::string>& file_names,
309 const std::uint32_t query_depth)
const
311 std::shared_lock < std::shared_timed_mutex > lock (read_write_mutex_);
312 root_node_->queryFrustum (planes, eye, view_projection_matrix, file_names, query_depth);
317 template<
typename ContainerT,
typename Po
intT>
void
320 std::shared_lock < std::shared_timed_mutex > lock (read_write_mutex_);
322 PCL_DEBUG (
"[pcl::outofcore::OutofcoreOctreeBaseNode] Querying Bounding Box %.2lf %.2lf %.2lf, %.2lf %.2lf %.2lf", min[0], min[1], min[2], max[0], max[1], max[2]);
323 root_node_->queryBBIncludes (min, max, query_depth, dst);
328 template<
typename ContainerT,
typename Po
intT>
void
331 std::shared_lock < std::shared_timed_mutex > lock (read_write_mutex_);
333 dst_blob->data.clear ();
337 root_node_->queryBBIncludes ( min, max, query_depth, dst_blob );
342 template<
typename ContainerT,
typename Po
intT>
void
345 std::shared_lock < std::shared_timed_mutex > lock (read_write_mutex_);
347 root_node_->queryBBIncludes_subsample (min, max, query_depth, percent, dst);
351 template<
typename ContainerT,
typename Po
intT>
void
356 root_node_->queryBBIncludes (min, max, query_depth, dst_blob);
360 root_node_->queryBBIncludes_subsample (min, max, query_depth, dst_blob, percent);
366 template<
typename ContainerT,
typename Po
intT>
bool
369 if (root_node_!=
nullptr)
371 root_node_->getBoundingBox (min, max);
379 template<
typename ContainerT,
typename Po
intT>
void
382 std::shared_lock < std::shared_timed_mutex > lock (read_write_mutex_);
383 root_node_->printBoundingBox (query_depth);
388 template<
typename ContainerT,
typename Po
intT>
void
391 std::shared_lock < std::shared_timed_mutex > lock (read_write_mutex_);
392 if (query_depth > metadata_->getDepth ())
394 root_node_->getOccupiedVoxelCentersRecursive (voxel_centers, metadata_->getDepth ());
398 root_node_->getOccupiedVoxelCentersRecursive (voxel_centers, query_depth);
404 template<
typename ContainerT,
typename Po
intT>
void
407 std::shared_lock < std::shared_timed_mutex > lock (read_write_mutex_);
408 if (query_depth > metadata_->getDepth ())
410 root_node_->getOccupiedVoxelCentersRecursive (voxel_centers, metadata_->getDepth ());
414 root_node_->getOccupiedVoxelCentersRecursive (voxel_centers, query_depth);
420 template<
typename ContainerT,
typename Po
intT>
void
423 std::shared_lock < std::shared_timed_mutex > lock (read_write_mutex_);
426 #pragma warning(push)
427 #pragma warning(disable : 4267)
429 root_node_->queryBBIntersects (min, max, query_depth, bin_name);
437 template<
typename ContainerT,
typename Po
intT>
void
440 std::ofstream f (filename.c_str ());
442 f <<
"from visual import *\n\n";
444 root_node_->writeVPythonVisual (f);
449 template<
typename ContainerT,
typename Po
intT>
void
452 root_node_->flushToDisk ();
457 template<
typename ContainerT,
typename Po
intT>
void
460 root_node_->flushToDiskLazy ();
465 template<
typename ContainerT,
typename Po
intT>
void
469 root_node_->convertToXYZ ();
474 template<
typename ContainerT,
typename Po
intT>
void
477 DeAllocEmptyNodeCache (root_node_);
482 template<
typename ContainerT,
typename Po
intT>
void
485 if (current ==
nullptr)
486 current = root_node_;
488 if (current->
size () == 0)
490 current->flush_DeAlloc_this_only ();
493 for (
int i = 0; i < current->numchildren (); i++)
495 DeAllocEmptyNodeCache (current->children[i]);
500 template<
typename ContainerT,
typename Po
intT> OutofcoreOctreeBaseNode<ContainerT, PointT>*
510 return (lod_filter_ptr_);
518 return (lod_filter_ptr_);
523 template<
typename ContainerT,
typename Po
intT>
void
526 lod_filter_ptr_ = std::static_pointer_cast<decltype(lod_filter_ptr_)>(filter_arg);
531 template<
typename ContainerT,
typename Po
intT>
bool
534 if (root_node_==
nullptr)
541 Eigen::Vector3d min, max;
542 this->getBoundingBox (min, max);
544 double depth =
static_cast<double> (metadata_->getDepth ());
545 Eigen::Vector3d diff = max-min;
547 y = diff[1] * pow (.5, depth);
548 x = diff[0] * pow (.5, depth);
555 template<
typename ContainerT,
typename Po
intT>
double
558 Eigen::Vector3d min, max;
559 this->getBoundingBox (min, max);
560 double result = (max[0] - min[0]) * pow (.5,
static_cast<double> (metadata_->getDepth ())) *
static_cast<double> (1 << (metadata_->getDepth () - depth));
566 template<
typename ContainerT,
typename Po
intT>
void
569 if (root_node_==
nullptr)
571 PCL_ERROR (
"Root node is null; aborting buildLOD.\n");
575 std::unique_lock < std::shared_timed_mutex > lock (read_write_mutex_);
577 constexpr
int number_of_nodes = 1;
579 std::vector<BranchNode*> current_branch (number_of_nodes,
static_cast<BranchNode*
>(
nullptr));
580 current_branch[0] = root_node_;
581 assert (current_branch.back () !=
nullptr);
582 this->buildLODRecursive (current_branch);
587 template<
typename ContainerT,
typename Po
intT>
void
590 Eigen::Vector3d min, max;
591 node.getBoundingBox (min,max);
592 PCL_INFO (
"[pcl::outofcore::OutofcoreOctreeBase::%s] min(%lf,%lf,%lf), max(%lf,%lf,%lf)\n", __FUNCTION__, min[0], min[1], min[2], max[0], max[1], max[2]);
598 template<
typename ContainerT,
typename Po
intT>
void
601 PCL_DEBUG (
"%s Building LOD at depth %d",__PRETTY_FUNCTION__, current_branch.size ());
603 if (!current_branch.back ())
610 assert (current_branch.back ()->getDepth () == this->getDepth ());
617 assert (leaf_input_cloud->width*leaf_input_cloud->height > 0);
620 for (
auto level =
static_cast<std::int64_t
>(current_branch.size ()-1); level >= 1; level--)
622 BranchNode* target_parent = current_branch[level-1];
623 assert (target_parent !=
nullptr);
624 double exponent =
static_cast<double>(current_branch.size () - target_parent->
getDepth ());
625 double current_depth_sample_percent = pow (sample_percent_, exponent);
627 assert (current_depth_sample_percent > 0.0);
634 lod_filter_ptr_->setInputCloud (leaf_input_cloud);
637 auto sample_size =
static_cast<std::uint64_t
> (
static_cast<double> (leaf_input_cloud->width*leaf_input_cloud->height) * current_depth_sample_percent);
639 if (sample_size == 0)
642 lod_filter_ptr_->setSample (
static_cast<unsigned int>(sample_size));
649 lod_filter_ptr_->filter (*downsampled_cloud_indices);
654 extractor.
setIndices (downsampled_cloud_indices);
655 extractor.
filter (*downsampled_cloud);
658 if (downsampled_cloud->width*downsampled_cloud->height > 0)
660 target_parent->
payload_->insertRange (downsampled_cloud);
661 this->incrementPointsInLOD (target_parent->
getDepth (), downsampled_cloud->width*downsampled_cloud->height);
668 current_branch.back ()->clearData ();
670 std::vector<BranchNode*> next_branch (current_branch);
672 if (current_branch.back ()->hasUnloadedChildren ())
674 current_branch.back ()->loadChildren (
false);
677 for (std::size_t i = 0; i < 8; i++)
679 next_branch.push_back (current_branch.back ()->getChildPtr (i));
681 if (next_branch.back () !=
nullptr)
682 buildLODRecursive (next_branch);
684 next_branch.pop_back ();
690 template<
typename ContainerT,
typename Po
intT>
void
693 if (std::numeric_limits<std::uint64_t>::max () - metadata_->getLODPoints (depth) < new_point_count)
695 PCL_ERROR (
"[pcl::outofcore::OutofcoreOctreeBase::incrementPointsInLOD] Overflow error. Too many points in depth %d of outofcore octree with root at %s\n", depth, metadata_->getMetadataFilename().c_str());
699 metadata_->setLODPoints (depth, new_point_count,
true );
704 template<
typename ContainerT,
typename Po
intT>
bool
718 template<
typename ContainerT,
typename Po
intT>
void
721 Eigen::Vector3d diff = bb_max - bb_min;
722 assert (diff[0] > 0);
723 assert (diff[1] > 0);
724 assert (diff[2] > 0);
725 Eigen::Vector3d center = (bb_max + bb_min)/2.0;
727 double max_sidelength = std::max (std::max (std::abs (diff[0]), std::abs (diff[1])), std::abs (diff[2]));
728 assert (max_sidelength > 0);
729 bb_min = center - Eigen::Vector3d (1.0, 1.0, 1.0)*(max_sidelength/2.0);
730 bb_max = center + Eigen::Vector3d (1.0, 1.0, 1.0)*(max_sidelength/2.0);
735 template<
typename ContainerT,
typename Po
intT> std::uint64_t
736 OutofcoreOctreeBase<ContainerT, PointT>::calculateDepth (
const Eigen::Vector3d& min_bb,
const Eigen::Vector3d& max_bb,
const double leaf_resolution)
739 double side_length = max_bb[0] - min_bb[0];
741 if (side_length < leaf_resolution)
744 auto res =
static_cast<std::uint64_t
> (std::ceil (std::log2 (side_length / leaf_resolution)));
746 PCL_DEBUG (
"[pcl::outofcore::OutofcoreOctreeBase::calculateDepth] Setting depth to %d\n",res);
Filter represents the base filter class.
void filter(Indices &indices)
Calls the filtering method and returns the filtered point cloud indices.
void setIndices(const IndicesPtr &indices)
Provide a pointer to the vector of indices that represents the input data.
void setInputCloud(const PCLPointCloud2ConstPtr &cloud)
Provide a pointer to the input dataset.
A base class for all pcl exceptions which inherits from std::runtime_error.
RandomSample applies a random sampling with uniform probability.
This code defines the octree used for point storage at Urban Robotics.
void DeAllocEmptyNodeCache()
Flush empty nodes only.
OutofcoreOctreeBaseMetadata::Ptr metadata_
std::uint64_t addDataToLeaf(const AlignedPointTVector &p)
Recursively add points to the tree.
void incrementPointsInLOD(std::uint64_t depth, std::uint64_t inc)
Increment current depths (LOD for branch nodes) point count; called by addDataAtMaxDepth in Outofcore...
void queryFrustum(const double *planes, std::list< std::string > &file_names) const
std::uint64_t addPointCloud_and_genLOD(pcl::PCLPointCloud2::Ptr &input_cloud)
Recursively add points to the tree.
void convertToXYZ()
Save each .bin file as an XYZ file.
OutofcoreOctreeBase(const boost::filesystem::path &root_node_name, const bool load_all)
Load an existing tree.
void getOccupiedVoxelCenters(AlignedPointTVector &voxel_centers, std::size_t query_depth) const
Returns the voxel centers of all existing voxels at query_depth.
void writeVPythonVisual(const boost::filesystem::path &filename)
Write a python script using the vpython module containing all the bounding boxes.
void buildLOD()
Generate multi-resolution LODs for the tree, which are a uniform random sampling all child leafs belo...
void queryBBIncludes(const Eigen::Vector3d &min, const Eigen::Vector3d &max, const std::uint64_t query_depth, AlignedPointTVector &dst) const
Get Points in BB, only points inside BB.
void queryBBIntersects(const Eigen::Vector3d &min, const Eigen::Vector3d &max, const std::uint32_t query_depth, std::list< std::string > &bin_name) const
Get a list of file paths at query_depth that intersect with your bounding box specified by min and ma...
bool getBoundingBox(Eigen::Vector3d &min, Eigen::Vector3d &max) const
Get the overall bounding box of the outofcore octree; this is the same as the bounding box of the roo...
double getVoxelSideLength() const
Gets the smallest (assumed) cubic voxel side lengths.
void flushToDiskLazy()
Flush all non leaf nodes' cache.
virtual void queryBoundingBox(const Eigen::Vector3d &min, const Eigen::Vector3d &max, const int query_depth, const pcl::PCLPointCloud2::Ptr &dst_blob, double percent=1.0)
Query all points falling within the input bounding box at query_depth and return a PCLPointCloud2 obj...
bool checkExtension(const boost::filesystem::path &path_name)
Auxiliary function to validate path_name extension is .octree.
std::uint64_t addDataToLeaf_and_genLOD(AlignedPointTVector &p)
Recursively add points to the tree subsampling LODs on the way.
bool getBinDimension(double &x, double &y) const
Computes the expected voxel dimensions at the leaves.
std::vector< PointT, Eigen::aligned_allocator< PointT > > AlignedPointTVector
void flushToDisk()
Flush all nodes' cache.
void printBoundingBox() const
Prints size of the bounding boxes to stdou.
void buildLODRecursive(const std::vector< BranchNode * > ¤t_branch)
recursive portion of lod builder
static const std::string TREE_EXTENSION_
defined as ".octree" to append to treepath files
OutofcoreNodeType * getBranchChildPtr(const BranchNode &branch_arg, unsigned char childIdx_arg) const
friend class OutofcoreOctreeBaseNode< ContainerT, PointT >
void queryBBIncludes_subsample(const Eigen::Vector3d &min, const Eigen::Vector3d &max, std::uint64_t query_depth, const double percent, AlignedPointTVector &dst) const
Returns a random subsample of points within the given bounding box at query_depth.
std::uint64_t addPointCloud(PointCloudConstPtr point_cloud)
Copies the points from the point_cloud falling within the bounding box of the octree to the out-of-co...
void init(const std::uint64_t &depth, const Eigen::Vector3d &min, const Eigen::Vector3d &max, const boost::filesystem::path &root_name, const std::string &coord_sys)
void saveToFile()
Write octree definition ".octree" (defined by octree_extension_) to disk.
typename PointCloud::ConstPtr PointCloudConstPtr
void setLODFilter(const pcl::Filter< pcl::PCLPointCloud2 >::Ptr &filter_arg)
Sets the filter to use when building the levels of depth.
OutofcoreNodeType * root_node_
Pointer to the root node of the octree data structure.
pcl::Filter< pcl::PCLPointCloud2 >::Ptr getLODFilter()
virtual ~OutofcoreOctreeBase()
OutofcoreOctreeBaseNode Class internally representing nodes of an outofcore octree,...
OutofcoreOctreeBase< ContainerT, PointT > * m_tree_
The tree we belong to.
std::shared_ptr< ContainerT > payload_
what holds the points.
virtual int read(pcl::PCLPointCloud2::Ptr &output_cloud)
std::uint64_t size() const
Number of points in the payload.
virtual std::size_t getDepth() const
virtual OutofcoreOctreeBaseNode * getChildPtr(std::size_t index_arg) const
Returns a pointer to the child in octant index_arg.
IndicesAllocator<> Indices
Type used for indices in PCL.
shared_ptr< Indices > IndicesPtr
shared_ptr< ::pcl::PCLPointCloud2 > Ptr