Point Cloud Library (PCL)  1.14.1-dev
octree_disk_container.h
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2010-2012, Willow Garage, Inc.
6  * Copyright (c) 2012, Urban Robotics, Inc.
7  *
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * * Redistributions of source code must retain the above copyright
15  * notice, this list of conditions and the following disclaimer.
16  * * Redistributions in binary form must reproduce the above
17  * copyright notice, this list of conditions and the following
18  * disclaimer in the documentation and/or other materials provided
19  * with the distribution.
20  * * Neither the name of Willow Garage, Inc. nor the names of its
21  * contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  *
37  * $Id: octree_disk_container.h 6927M 2012-08-24 13:26:40Z (local) $
38  */
39 
40 #pragma once
41 
42 // C++
43 #include <mutex>
44 #include <string>
45 
46 // Boost
47 #include <boost/random/mersenne_twister.hpp> // for boost::mt19937
48 #include <boost/uuid/random_generator.hpp>
49 
50 #include <pcl/common/utils.h> // pcl::utils::ignore
51 #include <pcl/outofcore/octree_abstract_node_container.h>
52 #include <pcl/io/pcd_io.h>
53 #include <pcl/PCLPointCloud2.h>
54 
55 //allows operation on POSIX
56 #if !defined _WIN32
57 #define _fseeki64 fseeko
58 #elif defined __MINGW32__
59 #define _fseeki64 fseeko64
60 #endif
61 
62 namespace pcl
63 {
64  namespace outofcore
65  {
66  /** \class OutofcoreOctreeDiskContainer
67  * \note Code was adapted from the Urban Robotics out of core octree implementation.
68  * Contact Jacob Schloss <jacob.schloss@urbanrobotics.net> with any questions.
69  * http://www.urbanrobotics.net/
70  *
71  * \brief Class responsible for serialization and deserialization of out of core point data
72  * \ingroup outofcore
73  * \author Jacob Schloss (jacob.schloss@urbanrobotics.net)
74  */
75  template<typename PointT = pcl::PointXYZ>
77  {
78 
79  public:
81 
82  /** \brief Empty constructor creates disk container and sets filename from random uuid string*/
84 
85  /** \brief Creates uuid named file or loads existing file
86  *
87  * If \b dir is a directory, this constructor will create a new
88  * uuid named file; if \b dir is an existing file, it will load the
89  * file metadata for accessing the tree.
90  *
91  * \param[in] dir Path to the tree. If it is a directory, it
92  * will create the metadata. If it is a file, it will load the metadata into memory.
93  */
94  OutofcoreOctreeDiskContainer (const boost::filesystem::path &dir);
95 
96  /** \brief flushes write buffer, then frees memory */
98 
99  /** \brief provides random access to points based on a linear index
100  */
101  inline PointT
102  operator[] (std::uint64_t idx) const override;
103 
104  /** \brief Adds a single point to the buffer to be written to disk when the buffer grows sufficiently large, the object is destroyed, or the write buffer is manually flushed */
105  inline void
106  push_back (const PointT& p);
107 
108  /** \brief Inserts a vector of points into the disk data structure */
109  void
110  insertRange (const AlignedPointTVector& src);
111 
112  /** \brief Inserts a PCLPointCloud2 object directly into the disk container */
113  void
114  insertRange (const pcl::PCLPointCloud2::Ptr &input_cloud);
115 
116  void
117  insertRange (const PointT* const * start, const std::uint64_t count) override;
118 
119  /** \brief This is the primary method for serialization of
120  * blocks of point data. This is called by the outofcore
121  * octree interface, opens the binary file for appending data,
122  * and writes it to disk.
123  *
124  * \param[in] start address of the first point to insert
125  * \param[in] count offset from start of the last point to insert
126  */
127  void
128  insertRange (const PointT* start, const std::uint64_t count) override;
129 
130  /** \brief Reads \b count points into memory from the disk container
131  *
132  * Reads \b count points into memory from the disk container, reading at most 2 million elements at a time
133  *
134  * \param[in] start index of first point to read from disk
135  * \param[in] count offset of last point to read from disk
136  * \param[out] dst std::vector as destination for points read from disk into memory
137  */
138  void
139  readRange (const std::uint64_t start, const std::uint64_t count, AlignedPointTVector &dst) override;
140 
141  void
142  readRange (const std::uint64_t, const std::uint64_t, pcl::PCLPointCloud2::Ptr &dst);
143 
144  /** \brief Reads the entire point contents from disk into \c output_cloud
145  * \param[out] output_cloud
146  */
147  int
148  read (pcl::PCLPointCloud2::Ptr &output_cloud);
149 
150  /** \brief grab percent*count random points. points are \b not guaranteed to be
151  * unique (could have multiple identical points!)
152  *
153  * \param[in] start The starting index of points to select
154  * \param[in] count The length of the range of points from which to randomly sample
155  * (i.e. from start to start+count)
156  * \param[in] percent The percentage of count that is enough points to make up this random sample
157  * \param[out] dst std::vector as destination for randomly sampled points; size will
158  * be percentage*count
159  */
160  void
161  readRangeSubSample (const std::uint64_t start, const std::uint64_t count, const double percent,
162  AlignedPointTVector &dst) override;
163 
164  /** \brief Use bernoulli trials to select points. All points selected will be unique.
165  *
166  * \param[in] start The starting index of points to select
167  * \param[in] count The length of the range of points from which to randomly sample
168  * (i.e. from start to start+count)
169  * \param[in] percent The percentage of count that is enough points to make up this random sample
170  * \param[out] dst std::vector as destination for randomly sampled points; size will
171  * be percentage*count
172  */
173  void
174  readRangeSubSample_bernoulli (const std::uint64_t start, const std::uint64_t count,
175  const double percent, AlignedPointTVector& dst);
176 
177  /** \brief Returns the total number of points for which this container is responsible, \c filelen_ + points in \c writebuff_ that have not yet been flushed to the disk
178  */
179  std::uint64_t
180  size () const override
181  {
182  return (filelen_ + writebuff_.size ());
183  }
184 
185  /** \brief STL-like empty test
186  * \return true if container has no data on disk or waiting to be written in \c writebuff_ */
187  inline bool
188  empty () const override
189  {
190  return ((filelen_ == 0) && writebuff_.empty ());
191  }
192 
193  /** \brief Exposed functionality for manually flushing the write buffer during tree creation */
194  void
195  flush (const bool force_cache_dealloc)
196  {
197  flushWritebuff (force_cache_dealloc);
198  }
199 
200  /** \brief Returns this objects path name */
201  inline std::string&
202  path ()
203  {
204  return (disk_storage_filename_);
205  }
206 
207  inline void
208  clear () override
209  {
210  //clear elements that have not yet been written to disk
211  writebuff_.clear ();
212  //remove the binary data in the directory
213  PCL_DEBUG ("[Octree Disk Container] Removing the point data from disk, in file %s\n", disk_storage_filename_.c_str ());
214  boost::filesystem::remove (static_cast<boost::filesystem::path> (disk_storage_filename_.c_str ()));
215  //reset the size-of-file counter
216  filelen_ = 0;
217  }
218 
219  /** \brief write points to disk as ascii
220  *
221  * \param[in] path
222  */
223  void
224  convertToXYZ (const boost::filesystem::path &path) override
225  {
226  if (boost::filesystem::exists (disk_storage_filename_))
227  {
228  FILE* fxyz = fopen (path.string ().c_str (), "we");
229 
230  FILE* f = fopen (disk_storage_filename_.c_str (), "rbe");
231  assert (f != nullptr);
232 
233  std::uint64_t num = size ();
234  PointT p;
235  char* loc = reinterpret_cast<char*> ( &p );
236 
237  for (std::uint64_t i = 0; i < num; i++)
238  {
239  int seekret = _fseeki64 (f, i * sizeof (PointT), SEEK_SET);
240  pcl::utils::ignore(seekret);
241  assert (seekret == 0);
242  std::size_t readlen = fread (loc, sizeof (PointT), 1, f);
243  pcl::utils::ignore(readlen);
244  assert (readlen == 1);
245 
246  //of << p.x << "\t" << p.y << "\t" << p.z << "\n";
247  std::stringstream ss;
248  ss << std::fixed;
249  ss.precision (16);
250  ss << p.x << "\t" << p.y << "\t" << p.z << "\n";
251 
252  fwrite (ss.str ().c_str (), 1, ss.str ().size (), fxyz);
253  }
254  int res = fclose (f);
255  pcl::utils::ignore(res);
256  assert (res == 0);
257  res = fclose (fxyz);
258  assert (res == 0);
259  }
260  }
261 
262  /** \brief Generate a universally unique identifier (UUID)
263  *
264  * A mutex lock happens to ensure uniqueness
265  *
266  */
267  static void
268  getRandomUUIDString (std::string &s);
269 
270  /** \brief Returns the number of points in the PCD file by reading the PCD header. */
271  std::uint64_t
272  getDataSize () const;
273 
274  private:
275  //no copy construction
277 
278 
280  operator= (const OutofcoreOctreeDiskContainer& /*rval*/) { }
281 
282  void
283  flushWritebuff (const bool force_cache_dealloc);
284 
285  /** \brief Name of the storage file on disk (i.e., the PCD file) */
286  std::string disk_storage_filename_;
287 
288  //--- possibly deprecated parameter variables --//
289 
290  //number of elements in file
291  std::uint64_t filelen_;
292 
293  /** \brief elements [0,...,size()-1] map to [filelen, ..., filelen + size()-1] */
294  AlignedPointTVector writebuff_;
295 
296  const static std::uint64_t READ_BLOCK_SIZE_;
297 
298  static const std::uint64_t WRITE_BUFF_MAX_;
299 
300  static std::mutex rng_mutex_;
301  static boost::mt19937 rand_gen_;
302  static boost::uuids::basic_random_generator<boost::mt19937> uuid_gen_;
303 
304  };
305  } //namespace outofcore
306 } //namespace pcl
std::vector< PointT, Eigen::aligned_allocator< PointT > > AlignedPointTVector
Class responsible for serialization and deserialization of out of core point data.
int read(pcl::PCLPointCloud2::Ptr &output_cloud)
Reads the entire point contents from disk into output_cloud.
void flush(const bool force_cache_dealloc)
Exposed functionality for manually flushing the write buffer during tree creation.
OutofcoreOctreeDiskContainer()
Empty constructor creates disk container and sets filename from random uuid string.
static void getRandomUUIDString(std::string &s)
Generate a universally unique identifier (UUID)
void insertRange(const AlignedPointTVector &src)
Inserts a vector of points into the disk data structure.
void readRangeSubSample_bernoulli(const std::uint64_t start, const std::uint64_t count, const double percent, AlignedPointTVector &dst)
Use bernoulli trials to select points.
void readRange(const std::uint64_t start, const std::uint64_t count, AlignedPointTVector &dst) override
Reads count points into memory from the disk container.
std::uint64_t getDataSize() const
Returns the number of points in the PCD file by reading the PCD header.
std::string & path()
Returns this objects path name.
typename OutofcoreAbstractNodeContainer< PointT >::AlignedPointTVector AlignedPointTVector
std::uint64_t size() const override
Returns the total number of points for which this container is responsible, filelen_ + points in writ...
void convertToXYZ(const boost::filesystem::path &path) override
write points to disk as ascii
void readRangeSubSample(const std::uint64_t start, const std::uint64_t count, const double percent, AlignedPointTVector &dst) override
grab percent*count random points.
bool empty() const override
STL-like empty test.
void push_back(const PointT &p)
Adds a single point to the buffer to be written to disk when the buffer grows sufficiently large,...
PointT operator[](std::uint64_t idx) const override
provides random access to points based on a linear index
~OutofcoreOctreeDiskContainer() override
flushes write buffer, then frees memory
void ignore(const T &...)
Utility function to eliminate unused variable warnings.
Definition: utils.h:62
shared_ptr< ::pcl::PCLPointCloud2 > Ptr
A point structure representing Euclidean xyz coordinates, and the RGB color.