1 /*
2  * Software License Agreement (BSD License)
3  *
4  *  Point Cloud Library (PCL) - www.pointclouds.org
5  *  Copyright (c) 2010-2011, Willow Garage, Inc.
6  *
7  *  All rights reserved.
8  *
9  *  Redistribution and use in source and binary forms, with or without
10  *  modification, are permitted provided that the following conditions
11  *  are met:
12  *
13  *   * Redistributions of source code must retain the above copyright
14  *     notice, this list of conditions and the following disclaimer.
15  *   * Redistributions in binary form must reproduce the above
16  *     copyright notice, this list of conditions and the following
17  *     disclaimer in the documentation and/or other materials provided
18  *     with the distribution.
19  *   * Neither the name of the copyright holder(s) nor the names of its
20  *     contributors may be used to endorse or promote products derived
21  *     from this software without specific prior written permission.
22  *
23  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  *  POSSIBILITY OF SUCH DAMAGE.
35  *
36  * $Id$
37  *
38  */
39 
40 #pragma once
41 
42 #include <pcl/memory.h>
43 #include <pcl/pcl_macros.h>
44 #include <pcl/point_cloud.h>
45 #include <pcl/io/file_io.h>
46 #include <boost/interprocess/sync/file_lock.hpp> // for file_lock
47 
48 namespace pcl
49 {
50   /** \brief Point Cloud Data (PCD) file format reader.
51     * \author Radu B. Rusu
52     * \ingroup io
53     */
54   class PCL_EXPORTS PCDReader : public FileReader
55   {
56     public:
57       /** Empty constructor */
PCDReader()58       PCDReader () {}
59       /** Empty destructor */
~PCDReader()60       ~PCDReader () {}
61 
62       /** \brief Various PCD file versions.
63         *
64         * PCD_V6 represents PCD files with version 0.6, which contain the following fields:
65         *   - lines beginning with # are treated as comments
66         *   - FIELDS ...
67         *   - SIZE ...
68         *   - TYPE ...
69         *   - COUNT ...
70         *   - WIDTH ...
71         *   - HEIGHT ...
72         *   - POINTS ...
73         *   - DATA ascii/binary
74         *
75         * Everything that follows \b DATA is interpreted as data points and
76         * will be read accordingly.
77         *
78         * PCD_V7 represents PCD files with version 0.7 and has an important
79         * addon: it adds sensor origin/orientation (aka viewpoint) information
80         * to a dataset through the use of a new header field:
81         *   - VIEWPOINT tx ty tz qw qx qy qz
82         */
83       enum
84       {
85         PCD_V6 = 0,
86         PCD_V7 = 1
87       };
88 
89       /** \brief Read a point cloud data header from a PCD-formatted, binary istream.
90         *
91         * Load only the meta information (number of points, their types, etc),
92         * and not the points themselves, from a given PCD stream. Useful for fast
93         * evaluation of the underlying data structure.
94         *
95         * \attention The PCD data is \b always stored in ROW major format! The
96         * read/write PCD methods will detect column major input and automatically convert it.
97         *
98         * \param[in] binary_istream a std::istream with openmode set to std::ios::binary.
99         * \param[out] cloud the resultant point cloud dataset (only these
100         *             members will be filled: width, height, point_step,
101         *             row_step, fields[]; data is resized but not written)
102         * \param[out] origin the sensor acquisition origin (only for > PCD_V7 - null if not present)
103         * \param[out] orientation the sensor acquisition orientation (only for > PCD_V7 - identity if not present)
104         * \param[out] pcd_version the PCD version of the file (i.e., PCD_V6, PCD_V7)
105         * \param[out] data_type the type of data (0 = ASCII, 1 = Binary, 2 = Binary compressed)
106         * \param[out] data_idx the offset of cloud data within the file
107         *
108         * \return
109         *  * < 0 (-1) on error
110         *  * == 0 on success
111         */
112       int
113       readHeader (std::istream &binary_istream, pcl::PCLPointCloud2 &cloud,
114                   Eigen::Vector4f &origin, Eigen::Quaternionf &orientation, int &pcd_version,
115                   int &data_type, unsigned int &data_idx);
116 
117       /** \brief Read a point cloud data header from a PCD file.
118         *
119         * Load only the meta information (number of points, their types, etc),
120         * and not the points themselves, from a given PCD file. Useful for fast
121         * evaluation of the underlying data structure.
122         *
123         * \attention The PCD data is \b always stored in ROW major format! The
124         * read/write PCD methods will detect column major input and automatically convert it.
125         *
126         * \param[in] file_name the name of the file to load
127         * \param[out] cloud the resultant point cloud dataset (only these
128         *             members will be filled: width, height, point_step,
129         *             row_step, fields[]; data is resized but not written)
130         * \param[out] origin the sensor acquisition origin (only for > PCD_V7 - null if not present)
131         * \param[out] orientation the sensor acquisition orientation (only for > PCD_V7 - identity if not present)
132         * \param[out] pcd_version the PCD version of the file (i.e., PCD_V6, PCD_V7)
133         * \param[out] data_type the type of data (0 = ASCII, 1 = Binary, 2 = Binary compressed)
134         * \param[out] data_idx the offset of cloud data within the file
135         * \param[in] offset the offset of where to expect the PCD Header in the
136         * file (optional parameter). One usage example for setting the offset
137         * parameter is for reading data from a TAR "archive containing multiple
138         * PCD files: TAR files always add a 512 byte header in front of the
139         * actual file, so set the offset to the next byte after the header
140         * (e.g., 513).
141         *
142         * \return
143         *  * < 0 (-1) on error
144         *  * == 0 on success
145         */
146       int
147       readHeader (const std::string &file_name, pcl::PCLPointCloud2 &cloud,
148                   Eigen::Vector4f &origin, Eigen::Quaternionf &orientation, int &pcd_version,
149                   int &data_type, unsigned int &data_idx, const int offset = 0) override;
150 
151 
152       /** \brief Read a point cloud data header from a PCD file.
153         *
154         * Load only the meta information (number of points, their types, etc),
155         * and not the points themselves, from a given PCD file. Useful for fast
156         * evaluation of the underlying data structure.
157         *
158         * \attention The PCD data is \b always stored in ROW major format! The
159         * read/write PCD methods will detect column major input and automatically convert it.
160         *
161         * \param[in] file_name the name of the file to load
162         * \param[out] cloud the resultant point cloud dataset (only these
163         *             members will be filled: width, height, point_step,
164         *             row_step, fields[]; data is resized but not written)
165         * \param[in] offset the offset of where to expect the PCD Header in the
166         * file (optional parameter). One usage example for setting the offset
167         * parameter is for reading data from a TAR "archive containing multiple
168         * PCD files: TAR files always add a 512 byte header in front of the
169         * actual file, so set the offset to the next byte after the header
170         * (e.g., 513).
171         *
172         * \return
173         *  * < 0 (-1) on error
174         *  * == 0 on success
175         */
176       int
177       readHeader (const std::string &file_name, pcl::PCLPointCloud2 &cloud, const int offset = 0);
178 
179       /** \brief Read the point cloud data (body) from a PCD stream.
180         *
181         * Reads the cloud points from a text-formatted stream.  For use after
182         * readHeader(), when the resulting data_type == 0.
183         *
184         * \attention This assumes the stream has been seeked to the position
185         * indicated by the data_idx result of readHeader().
186         *
187         * \param[in] stream the stream from which to read the body.
188         * \param[out] cloud the resultant point cloud dataset to be filled.
189         * \param[in] pcd_version the PCD version of the stream (from readHeader()).
190         *
191         * \return
192         *  * < 0 (-1) on error
193         *  * == 0 on success
194         */
195       int
196       readBodyASCII (std::istream &stream, pcl::PCLPointCloud2 &cloud, int pcd_version);
197 
198       /** \brief Read the point cloud data (body) from a block of memory.
199         *
200         * Reads the cloud points from a binary-formatted memory block.  For use
201         * after readHeader(), when the resulting data_type is nonzero.
202         *
203         * \param[in] data the memory location from which to read the body.
204         * \param[out] cloud the resultant point cloud dataset to be filled.
205         * \param[in] pcd_version the PCD version of the stream (from readHeader()).
206         * \param[in] compressed indicates whether the PCD block contains compressed
207         * data.  This should be true if the data_type returne by readHeader() == 2.
208         * \param[in] data_idx the offset of the body, as reported by readHeader().
209         *
210         * \return
211         *  * < 0 (-1) on error
212         *  * == 0 on success
213         */
214       int
215       readBodyBinary (const unsigned char *data, pcl::PCLPointCloud2 &cloud,
216                        int pcd_version, bool compressed, unsigned int data_idx);
217 
218       /** \brief Read a point cloud data from a PCD file and store it into a pcl/PCLPointCloud2.
219         * \param[in] file_name the name of the file containing the actual PointCloud data
220         * \param[out] cloud the resultant PointCloud message read from disk
221         * \param[out] origin the sensor acquisition origin (only for > PCD_V7 - null if not present)
222         * \param[out] orientation the sensor acquisition orientation (only for > PCD_V7 - identity if not present)
223         * \param[out] pcd_version the PCD version of the file (either PCD_V6 or PCD_V7)
224         * \param[in] offset the offset of where to expect the PCD Header in the
225         * file (optional parameter). One usage example for setting the offset
226         * parameter is for reading data from a TAR "archive containing multiple
227         * PCD files: TAR files always add a 512 byte header in front of the
228         * actual file, so set the offset to the next byte after the header
229         * (e.g., 513).
230         *
231         * \return
232         *  * < 0 (-1) on error
233         *  * == 0 on success
234         */
235       int
236       read (const std::string &file_name, pcl::PCLPointCloud2 &cloud,
237             Eigen::Vector4f &origin, Eigen::Quaternionf &orientation, int &pcd_version, const int offset = 0) override;
238 
239       /** \brief Read a point cloud data from a PCD (PCD_V6) and store it into a pcl/PCLPointCloud2.
240         *
241         * \note This function is provided for backwards compatibility only and
242         * it can only read PCD_V6 files correctly, as pcl::PCLPointCloud2
243         * does not contain a sensor origin/orientation. Reading any file
244         * > PCD_V6 will generate a warning.
245         *
246         * \param[in] file_name the name of the file containing the actual PointCloud data
247         * \param[out] cloud the resultant PointCloud message read from disk
248         * \param[in] offset the offset of where to expect the PCD Header in the
249         * file (optional parameter). One usage example for setting the offset
250         * parameter is for reading data from a TAR "archive containing multiple
251         * PCD files: TAR files always add a 512 byte header in front of the
252         * actual file, so set the offset to the next byte after the header
253         * (e.g., 513).
254         *
255         * \return
256         *  * < 0 (-1) on error
257         *  * == 0 on success
258         */
259       int
260       read (const std::string &file_name, pcl::PCLPointCloud2 &cloud, const int offset = 0);
261 
262       /** \brief Read a point cloud data from any PCD file, and convert it to the given template format.
263         * \param[in] file_name the name of the file containing the actual PointCloud data
264         * \param[out] cloud the resultant PointCloud message read from disk
265         * \param[in] offset the offset of where to expect the PCD Header in the
266         * file (optional parameter). One usage example for setting the offset
267         * parameter is for reading data from a TAR "archive containing multiple
268         * PCD files: TAR files always add a 512 byte header in front of the
269         * actual file, so set the offset to the next byte after the header
270         * (e.g., 513).
271         *
272         * \return
273         *  * < 0 (-1) on error
274         *  * == 0 on success
275         */
276       template<typename PointT> int
277       read (const std::string &file_name, pcl::PointCloud<PointT> &cloud, const int offset = 0)
278       {
279         pcl::PCLPointCloud2 blob;
280         int pcd_version;
281         int res = read (file_name, blob, cloud.sensor_origin_, cloud.sensor_orientation_,
282                         pcd_version, offset);
283 
284         // If no error, convert the data
285         if (res == 0)
286           pcl::fromPCLPointCloud2 (blob, cloud);
287         return (res);
288       }
289 
290       PCL_MAKE_ALIGNED_OPERATOR_NEW
291   };
292 
293   /** \brief Point Cloud Data (PCD) file format writer.
294     * \author Radu Bogdan Rusu
295     * \ingroup io
296     */
297   class PCL_EXPORTS PCDWriter : public FileWriter
298   {
299     public:
PCDWriter()300       PCDWriter() : map_synchronization_(false) {}
~PCDWriter()301       ~PCDWriter() {}
302 
303       /** \brief Set whether mmap() synchornization via msync() is desired before munmap() calls.
304         * Setting this to true could prevent NFS data loss (see
305         * http://www.pcl-developers.org/PCD-IO-consistency-on-NFS-msync-needed-td4885942.html).
306         * Default: false
307         * \note This option should be used by advanced users only!
308         * \note Please note that using msync() on certain systems can reduce the I/O performance by up to 80%!
309         * \param[in] sync set to true if msync() should be called before munmap()
310         */
311       void
setMapSynchronization(bool sync)312       setMapSynchronization (bool sync)
313       {
314         map_synchronization_ = sync;
315       }
316 
317       /** \brief Generate the header of a PCD file format
318         * \param[in] cloud the point cloud data message
319         * \param[in] origin the sensor acquisition origin
320         * \param[in] orientation the sensor acquisition orientation
321         */
322       std::string
323       generateHeaderBinary (const pcl::PCLPointCloud2 &cloud,
324                             const Eigen::Vector4f &origin,
325                             const Eigen::Quaternionf &orientation);
326 
327       /** \brief Generate the header of a BINARY_COMPRESSED PCD file format
328         * \param[out] os the stream into which to write the header
329         * \param[in] cloud the point cloud data message
330         * \param[in] origin the sensor acquisition origin
331         * \param[in] orientation the sensor acquisition orientation
332         *
333         * \return
334         *  * < 0 (-1) on error
335         *  * == 0 on success
336         */
337       int
338       generateHeaderBinaryCompressed (std::ostream &os,
339                                       const pcl::PCLPointCloud2 &cloud,
340                                       const Eigen::Vector4f &origin,
341                                       const Eigen::Quaternionf &orientation);
342 
343       /** \brief Generate the header of a BINARY_COMPRESSED PCD file format
344         * \param[in] cloud the point cloud data message
345         * \param[in] origin the sensor acquisition origin
346         * \param[in] orientation the sensor acquisition orientation
347         */
348       std::string
349       generateHeaderBinaryCompressed (const pcl::PCLPointCloud2 &cloud,
350                                       const Eigen::Vector4f &origin,
351                                       const Eigen::Quaternionf &orientation);
352 
353       /** \brief Generate the header of a PCD file format
354         * \param[in] cloud the point cloud data message
355         * \param[in] origin the sensor acquisition origin
356         * \param[in] orientation the sensor acquisition orientation
357         */
358       std::string
359       generateHeaderASCII (const pcl::PCLPointCloud2 &cloud,
360                            const Eigen::Vector4f &origin,
361                            const Eigen::Quaternionf &orientation);
362 
363       /** \brief Generate the header of a PCD file format
364         * \param[in] cloud the point cloud data message
365         * \param[in] nr_points if given, use this to fill in WIDTH, HEIGHT (=1), and POINTS in the header
366         * By default, nr_points is set to INTMAX, and the data in the header is used instead.
367         */
368       template <typename PointT> static std::string
369       generateHeader (const pcl::PointCloud<PointT> &cloud,
370                       const int nr_points = std::numeric_limits<int>::max ());
371 
372       /** \brief Save point cloud data to a PCD file containing n-D points, in ASCII format
373         * \param[in] file_name the output file name
374         * \param[in] cloud the point cloud data message
375         * \param[in] origin the sensor acquisition origin
376         * \param[in] orientation the sensor acquisition orientation
377         * \param[in] precision the specified output numeric stream precision (default: 8)
378         *
379         * Caution: PointCloud structures containing an RGB field have
380         * traditionally used packed float values to store RGB data. Storing a
381         * float as ASCII can introduce variations to the smallest bits, and
382         * thus significantly alter the data. This is a known issue, and the fix
383         * involves switching RGB data to be stored as a packed integer in
384         * future versions of PCL.
385         *
386         * As an intermediary solution, precision 8 is used, which guarantees lossless storage for RGB.
387         */
388       int
389       writeASCII (const std::string &file_name, const pcl::PCLPointCloud2 &cloud,
390                   const Eigen::Vector4f &origin = Eigen::Vector4f::Zero (),
391                   const Eigen::Quaternionf &orientation = Eigen::Quaternionf::Identity (),
392                   const int precision = 8);
393 
394       /** \brief Save point cloud data to a PCD file containing n-D points, in BINARY format
395         * \param[in] file_name the output file name
396         * \param[in] cloud the point cloud data message
397         * \param[in] origin the sensor acquisition origin
398         * \param[in] orientation the sensor acquisition orientation
399         */
400       int
401       writeBinary (const std::string &file_name, const pcl::PCLPointCloud2 &cloud,
402                    const Eigen::Vector4f &origin = Eigen::Vector4f::Zero (),
403                    const Eigen::Quaternionf &orientation = Eigen::Quaternionf::Identity ());
404 
405       /** \brief Save point cloud data to a PCD file containing n-D points, in BINARY_COMPRESSED format
406         * \param[in] file_name the output file name
407         * \param[in] cloud the point cloud data message
408         * \param[in] origin the sensor acquisition origin
409         * \param[in] orientation the sensor acquisition orientation
410         * \return
411         * (-1) for a general error
412         * (-2) if the input cloud is too large for the file format
413         * 0 on success
414         */
415       int
416       writeBinaryCompressed (const std::string &file_name, const pcl::PCLPointCloud2 &cloud,
417                              const Eigen::Vector4f &origin = Eigen::Vector4f::Zero (),
418                              const Eigen::Quaternionf &orientation = Eigen::Quaternionf::Identity ());
419 
420       /** \brief Save point cloud data to a std::ostream containing n-D points, in BINARY_COMPRESSED format
421         * \param[out] os the stream into which to write the data
422         * \param[in] cloud the point cloud data message
423         * \param[in] origin the sensor acquisition origin
424         * \param[in] orientation the sensor acquisition orientation
425         * \return
426         * (-1) for a general error
427         * (-2) if the input cloud is too large for the file format
428         * 0 on success
429         */
430       int
431       writeBinaryCompressed (std::ostream &os, const pcl::PCLPointCloud2 &cloud,
432                              const Eigen::Vector4f &origin = Eigen::Vector4f::Zero (),
433                              const Eigen::Quaternionf &orientation = Eigen::Quaternionf::Identity ());
434 
435       /** \brief Save point cloud data to a PCD file containing n-D points
436         * \param[in] file_name the output file name
437         * \param[in] cloud the point cloud data message
438         * \param[in] origin the sensor acquisition origin
439         * \param[in] orientation the sensor acquisition orientation
440         * \param[in] binary set to true if the file is to be written in a binary
441         * PCD format, false (default) for ASCII
442         *
443         * Caution: PointCloud structures containing an RGB field have
444         * traditionally used packed float values to store RGB data. Storing a
445         * float as ASCII can introduce variations to the smallest bits, and
446         * thus significantly alter the data. This is a known issue, and the fix
447         * involves switching RGB data to be stored as a packed integer in
448         * future versions of PCL.
449         *
450         * As an intermediary solution, precision 8 is used, which guarantees lossless storage for RGB.
451         */
452       inline int
453       write (const std::string &file_name, const pcl::PCLPointCloud2 &cloud,
454              const Eigen::Vector4f &origin = Eigen::Vector4f::Zero (),
455              const Eigen::Quaternionf &orientation = Eigen::Quaternionf::Identity (),
456              const bool binary = false) override
457       {
458         if (binary)
459           return (writeBinary (file_name, cloud, origin, orientation));
460         return (writeASCII (file_name, cloud, origin, orientation, 8));
461       }
462 
463       /** \brief Save point cloud data to a PCD file containing n-D points
464         * \param[in] file_name the output file name
465         * \param[in] cloud the point cloud data message (boost shared pointer)
466         * \param[in] binary set to true if the file is to be written in a binary PCD format,
467         * false (default) for ASCII
468         * \param[in] origin the sensor acquisition origin
469         * \param[in] orientation the sensor acquisition orientation
470         *
471         * Caution: PointCloud structures containing an RGB field have
472         * traditionally used packed float values to store RGB data. Storing a
473         * float as ASCII can introduce variations to the smallest bits, and
474         * thus significantly alter the data. This is a known issue, and the fix
475         * involves switching RGB data to be stored as a packed integer in
476         * future versions of PCL.
477         */
478       inline int
479       write (const std::string &file_name, const pcl::PCLPointCloud2::ConstPtr &cloud,
480              const Eigen::Vector4f &origin = Eigen::Vector4f::Zero (),
481              const Eigen::Quaternionf &orientation = Eigen::Quaternionf::Identity (),
482              const bool binary = false)
483       {
484         return (write (file_name, *cloud, origin, orientation, binary));
485       }
486 
487       /** \brief Save point cloud data to a PCD file containing n-D points, in BINARY format
488         * \param[in] file_name the output file name
489         * \param[in] cloud the point cloud data message
490         */
491       template <typename PointT> int
492       writeBinary (const std::string &file_name,
493                    const pcl::PointCloud<PointT> &cloud);
494 
495       /** \brief Save point cloud data to a binary comprssed PCD file
496         * \param[in] file_name the output file name
497         * \param[in] cloud the point cloud data message
498         * \return
499         * (-1) for a general error
500         * (-2) if the input cloud is too large for the file format
501         * 0 on success
502         */
503       template <typename PointT> int
504       writeBinaryCompressed (const std::string &file_name,
505                              const pcl::PointCloud<PointT> &cloud);
506 
507       /** \brief Save point cloud data to a PCD file containing n-D points, in BINARY format
508         * \param[in] file_name the output file name
509         * \param[in] cloud the point cloud data message
510         * \param[in] indices the set of point indices that we want written to disk
511         */
512       template <typename PointT> int
513       writeBinary (const std::string &file_name,
514                    const pcl::PointCloud<PointT> &cloud,
515                    const pcl::Indices &indices);
516 
517       /** \brief Save point cloud data to a PCD file containing n-D points, in ASCII format
518         * \param[in] file_name the output file name
519         * \param[in] cloud the point cloud data message
520         * \param[in] precision the specified output numeric stream precision (default: 8)
521         */
522       template <typename PointT> int
523       writeASCII (const std::string &file_name,
524                   const pcl::PointCloud<PointT> &cloud,
525                   const int precision = 8);
526 
527        /** \brief Save point cloud data to a PCD file containing n-D points, in ASCII format
528         * \param[in] file_name the output file name
529         * \param[in] cloud the point cloud data message
530         * \param[in] indices the set of point indices that we want written to disk
531         * \param[in] precision the specified output numeric stream precision (default: 8)
532         */
533       template <typename PointT> int
534       writeASCII (const std::string &file_name,
535                   const pcl::PointCloud<PointT> &cloud,
536                   const pcl::Indices &indices,
537                   const int precision = 8);
538 
539       /** \brief Save point cloud data to a PCD file containing n-D points
540         * \param[in] file_name the output file name
541         * \param[in] cloud the pcl::PointCloud data
542         * \param[in] binary set to true if the file is to be written in a binary
543         * PCD format, false (default) for ASCII
544         *
545         * Caution: PointCloud structures containing an RGB field have
546         * traditionally used packed float values to store RGB data. Storing a
547         * float as ASCII can introduce variations to the smallest bits, and
548         * thus significantly alter the data. This is a known issue, and the fix
549         * involves switching RGB data to be stored as a packed integer in
550         * future versions of PCL.
551         */
552       template<typename PointT> inline int
553       write (const std::string &file_name,
554              const pcl::PointCloud<PointT> &cloud,
555              const bool binary = false)
556       {
557         if (binary)
558           return (writeBinary<PointT> (file_name, cloud));
559         return (writeASCII<PointT> (file_name, cloud));
560       }
561 
562       /** \brief Save point cloud data to a PCD file containing n-D points
563         * \param[in] file_name the output file name
564         * \param[in] cloud the pcl::PointCloud data
565         * \param[in] indices the set of point indices that we want written to disk
566         * \param[in] binary set to true if the file is to be written in a binary
567         * PCD format, false (default) for ASCII
568         *
569         * Caution: PointCloud structures containing an RGB field have
570         * traditionally used packed float values to store RGB data. Storing a
571         * float as ASCII can introduce variations to the smallest bits, and
572         * thus significantly alter the data. This is a known issue, and the fix
573         * involves switching RGB data to be stored as a packed integer in
574         * future versions of PCL.
575         */
576       template<typename PointT> inline int
577       write (const std::string &file_name,
578              const pcl::PointCloud<PointT> &cloud,
579              const pcl::Indices &indices,
580              bool binary = false)
581       {
582         if (binary)
583           return (writeBinary<PointT> (file_name, cloud, indices));
584         return (writeASCII<PointT> (file_name, cloud, indices));
585       }
586 
587     protected:
588       /** \brief Set permissions for file locking (Boost 1.49+).
589         * \param[in] file_name the file name to set permission for file locking
590         * \param[in,out] lock the file lock
591         */
592       void
593       setLockingPermissions (const std::string &file_name,
594                              boost::interprocess::file_lock &lock);
595 
596       /** \brief Reset permissions for file locking (Boost 1.49+).
597         * \param[in] file_name the file name to reset permission for file locking
598         * \param[in,out] lock the file lock
599         */
600       void
601       resetLockingPermissions (const std::string &file_name,
602                                boost::interprocess::file_lock &lock);
603 
604     private:
605       /** \brief Set to true if msync() should be called before munmap(). Prevents data loss on NFS systems. */
606       bool map_synchronization_;
607   };
608 
609   namespace io
610   {
611     /** \brief Load a PCD v.6 file into a templated PointCloud type.
612       *
613       * Any PCD files > v.6 will generate a warning as a
614       * pcl/PCLPointCloud2 message cannot hold the sensor origin.
615       *
616       * \param[in] file_name the name of the file to load
617       * \param[out] cloud the resultant templated point cloud
618       * \ingroup io
619       */
620     inline int
loadPCDFile(const std::string & file_name,pcl::PCLPointCloud2 & cloud)621     loadPCDFile (const std::string &file_name, pcl::PCLPointCloud2 &cloud)
622     {
623       pcl::PCDReader p;
624       return (p.read (file_name, cloud));
625     }
626 
627     /** \brief Load any PCD file into a templated PointCloud type.
628       * \param[in] file_name the name of the file to load
629       * \param[out] cloud the resultant templated point cloud
630       * \param[out] origin the sensor acquisition origin (only for > PCD_V7 - null if not present)
631       * \param[out] orientation the sensor acquisition orientation (only for >
632       * PCD_V7 - identity if not present)
633       * \ingroup io
634       */
635     inline int
loadPCDFile(const std::string & file_name,pcl::PCLPointCloud2 & cloud,Eigen::Vector4f & origin,Eigen::Quaternionf & orientation)636     loadPCDFile (const std::string &file_name, pcl::PCLPointCloud2 &cloud,
637                  Eigen::Vector4f &origin, Eigen::Quaternionf &orientation)
638     {
639       pcl::PCDReader p;
640       int pcd_version;
641       return (p.read (file_name, cloud, origin, orientation, pcd_version));
642     }
643 
644     /** \brief Load any PCD file into a templated PointCloud type
645       * \param[in] file_name the name of the file to load
646       * \param[out] cloud the resultant templated point cloud
647       * \ingroup io
648       */
649     template<typename PointT> inline int
loadPCDFile(const std::string & file_name,pcl::PointCloud<PointT> & cloud)650     loadPCDFile (const std::string &file_name, pcl::PointCloud<PointT> &cloud)
651     {
652       pcl::PCDReader p;
653       return (p.read (file_name, cloud));
654     }
655 
656     /** \brief Save point cloud data to a PCD file containing n-D points
657       * \param[in] file_name the output file name
658       * \param[in] cloud the point cloud data message
659       * \param[in] origin the sensor acquisition origin
660       * \param[in] orientation the sensor acquisition orientation
661       * \param[in] binary_mode true for binary mode, false (default) for ASCII
662       *
663       * Caution: PointCloud structures containing an RGB field have
664       * traditionally used packed float values to store RGB data. Storing a
665       * float as ASCII can introduce variations to the smallest bits, and
666       * thus significantly alter the data. This is a known issue, and the fix
667       * involves switching RGB data to be stored as a packed integer in
668       * future versions of PCL.
669       * \ingroup io
670       */
671     inline int
672     savePCDFile (const std::string &file_name, const pcl::PCLPointCloud2 &cloud,
673                  const Eigen::Vector4f &origin = Eigen::Vector4f::Zero (),
674                  const Eigen::Quaternionf &orientation = Eigen::Quaternionf::Identity (),
675                  const bool binary_mode = false)
676     {
677       PCDWriter w;
678       return (w.write (file_name, cloud, origin, orientation, binary_mode));
679     }
680 
681     /** \brief Templated version for saving point cloud data to a PCD file
682       * containing a specific given cloud format
683       * \param[in] file_name the output file name
684       * \param[in] cloud the point cloud data message
685       * \param[in] binary_mode true for binary mode, false (default) for ASCII
686       *
687       * Caution: PointCloud structures containing an RGB field have
688       * traditionally used packed float values to store RGB data. Storing a
689       * float as ASCII can introduce variations to the smallest bits, and
690       * thus significantly alter the data. This is a known issue, and the fix
691       * involves switching RGB data to be stored as a packed integer in
692       * future versions of PCL.
693       * \ingroup io
694       */
695     template<typename PointT> inline int
696     savePCDFile (const std::string &file_name, const pcl::PointCloud<PointT> &cloud, bool binary_mode = false)
697     {
698       PCDWriter w;
699       return (w.write<PointT> (file_name, cloud, binary_mode));
700     }
701 
702     /**
703       * \brief Templated version for saving point cloud data to a PCD file
704       * containing a specific given cloud format.
705       *
706       *      This version is to retain backwards compatibility.
707       * \param[in] file_name the output file name
708       * \param[in] cloud the point cloud data message
709       *
710       * Caution: PointCloud structures containing an RGB field have
711       * traditionally used packed float values to store RGB data. Storing a
712       * float as ASCII can introduce variations to the smallest bits, and
713       * thus significantly alter the data. This is a known issue, and the fix
714       * involves switching RGB data to be stored as a packed integer in
715       * future versions of PCL.
716       * \ingroup io
717       */
718     template<typename PointT> inline int
savePCDFileASCII(const std::string & file_name,const pcl::PointCloud<PointT> & cloud)719     savePCDFileASCII (const std::string &file_name, const pcl::PointCloud<PointT> &cloud)
720     {
721       PCDWriter w;
722       return (w.write<PointT> (file_name, cloud, false));
723     }
724 
725     /**
726       * \brief Templated version for saving point cloud data to a PCD file
727       * containing a specific given cloud format. The resulting file will be an uncompressed binary.
728       *
729       *      This version is to retain backwards compatibility.
730       * \param[in] file_name the output file name
731       * \param[in] cloud the point cloud data message
732       * \ingroup io
733       */
734     template<typename PointT> inline int
savePCDFileBinary(const std::string & file_name,const pcl::PointCloud<PointT> & cloud)735     savePCDFileBinary (const std::string &file_name, const pcl::PointCloud<PointT> &cloud)
736     {
737       PCDWriter w;
738       return (w.write<PointT> (file_name, cloud, true));
739     }
740 
741     /**
742       * \brief Templated version for saving point cloud data to a PCD file
743       * containing a specific given cloud format
744       *
745       * \param[in] file_name the output file name
746       * \param[in] cloud the point cloud data message
747       * \param[in] indices the set of indices to save
748       * \param[in] binary_mode true for binary mode, false (default) for ASCII
749       *
750       * Caution: PointCloud structures containing an RGB field have
751       * traditionally used packed float values to store RGB data. Storing a
752       * float as ASCII can introduce variations to the smallest bits, and
753       * thus significantly alter the data. This is a known issue, and the fix
754       * involves switching RGB data to be stored as a packed integer in
755       * future versions of PCL.
756       * \ingroup io
757       */
758     template<typename PointT> int
759     savePCDFile (const std::string &file_name,
760                  const pcl::PointCloud<PointT> &cloud,
761                  const pcl::Indices &indices,
762                  const bool binary_mode = false)
763     {
764       // Save the data
765       PCDWriter w;
766       return (w.write<PointT> (file_name, cloud, indices, binary_mode));
767     }
768 
769 
770     /**
771       * \brief Templated version for saving point cloud data to a PCD file
772       * containing a specific given cloud format. This method will write a compressed binary file.
773       *
774       *      This version is to retain backwards compatibility.
775       * \param[in] file_name the output file name
776       * \param[in] cloud the point cloud data message
777       * \ingroup io
778       */
779     template<typename PointT> inline int
savePCDFileBinaryCompressed(const std::string & file_name,const pcl::PointCloud<PointT> & cloud)780     savePCDFileBinaryCompressed (const std::string &file_name, const pcl::PointCloud<PointT> &cloud)
781     {
782       PCDWriter w;
783       return (w.writeBinaryCompressed<PointT> (file_name, cloud));
784     }
785 
786   }
787 }
788 
789 #include <pcl/io/impl/pcd_io.hpp>
790