pcd_io.cpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Point Cloud Library (PCL) - www.pointclouds.org
00005  *  Copyright (c) 2010-2011, Willow Garage, Inc.
00006  *
00007  *  All rights reserved.
00008  *
00009  *  Redistribution and use in source and binary forms, with or without
00010  *  modification, are permitted provided that the following conditions
00011  *  are met:
00012  *
00013  *   * Redistributions of source code must retain the above copyright
00014  *     notice, this list of conditions and the following disclaimer.
00015  *   * Redistributions in binary form must reproduce the above
00016  *     copyright notice, this list of conditions and the following
00017  *     disclaimer in the documentation and/or other materials provided
00018  *     with the distribution.
00019  *   * Neither the name of Willow Garage, Inc. nor the names of its
00020  *     contributors may be used to endorse or promote products derived
00021  *     from this software without specific prior written permission.
00022  *
00023  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00026  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00027  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00028  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00029  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00031  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00033  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00034  *  POSSIBILITY OF SUCH DAMAGE.
00035  *
00036  * $Id: pcd_io.cpp 6122 2012-07-03 18:59:43Z aichim $
00037  *
00038  */
00039 
00040 #include <fstream>
00041 #include <fcntl.h>
00042 #include <string>
00043 #include <stdlib.h>
00044 #include <boost/algorithm/string.hpp>
00045 #include <pcl/common/io.h>
00046 #include <pcl/io/pcd_io.h>
00047 #include <pcl/io/lzf.h>
00048 
00049 #include <boost/filesystem.hpp>
00050 
00051 #include <cstring>
00052 #include <cerrno>
00053 
00054 #ifdef _WIN32
00055 # include <io.h>
00056 # include <windows.h>
00057 # define pcl_open                    _open
00058 # define pcl_close(fd)               _close(fd)
00059 # define pcl_lseek(fd,offset,origin) _lseek(fd,offset,origin)
00060 #else
00061 # include <sys/mman.h>
00062 # define pcl_open                    open
00063 # define pcl_close(fd)               close(fd)
00064 # define pcl_lseek(fd,offset,origin) lseek(fd,offset,origin)
00065 #endif
00066 
00068 int
00069 pcl::PCDReader::readHeader (const std::string &file_name, sensor_msgs::PointCloud2 &cloud, 
00070                             Eigen::Vector4f &origin, Eigen::Quaternionf &orientation, 
00071                             int &pcd_version, int &data_type, unsigned int &data_idx, const int offset)
00072 {
00073   // Default values
00074   data_idx = 0;
00075   data_type = 0;
00076   pcd_version = PCD_V6;
00077   origin      = Eigen::Vector4f::Zero ();
00078   orientation = Eigen::Quaternionf::Identity ();
00079   cloud.width = cloud.height = cloud.point_step = cloud.row_step = 0;
00080   cloud.data.clear ();
00081 
00082   // By default, assume that there are _no_ invalid (e.g., NaN) points
00083   //cloud.is_dense = true;
00084 
00085   int nr_points = 0;
00086   std::ifstream fs;
00087   std::string line;
00088 
00089   int specified_channel_count = 0;
00090 
00091   if (file_name == "" || !boost::filesystem::exists (file_name))
00092   {
00093     PCL_ERROR ("[pcl::PCDReader::readHeader] Could not find file '%s'.\n", file_name.c_str ());
00094     return (-1);
00095   }
00096   // Open file in binary mode to avoid problem of 
00097   // std::getline() corrupting the result of ifstream::tellg()
00098   fs.open (file_name.c_str (), std::ios::binary);
00099   if (!fs.is_open () || fs.fail ())
00100   {
00101     PCL_ERROR ("[pcl::PCDReader::readHeader] Could not open file '%s'! Error : %s\n", file_name.c_str (), strerror(errno)); 
00102     fs.close ();
00103     return (-1);
00104   }
00105 
00106   // Seek at the given offset
00107   fs.seekg (offset, std::ios::beg);
00108 
00109   // field_sizes represents the size of one element in a field (e.g., float = 4, char = 1)
00110   // field_counts represents the number of elements in a field (e.g., x = 1, normal_x = 1, fpfh = 33)
00111   std::vector<int> field_sizes, field_counts;
00112   // field_types represents the type of data in a field (e.g., F = float, U = unsigned)
00113   std::vector<char> field_types;
00114   std::vector<std::string> st;
00115 
00116   // Read the header and fill it in with wonderful values
00117   try
00118   {
00119     while (!fs.eof ())
00120     {
00121       getline (fs, line);
00122       // Ignore empty lines
00123       if (line == "")
00124         continue;
00125 
00126       // Tokenize the line
00127       boost::trim (line);
00128       boost::split (st, line, boost::is_any_of ("\t\r "), boost::token_compress_on);
00129 
00130       std::stringstream sstream (line);
00131       sstream.imbue (std::locale::classic ());
00132 
00133       std::string line_type;
00134       sstream >> line_type;
00135 
00136       // Ignore comments
00137       if (line_type.substr (0, 1) == "#")
00138         continue;
00139 
00140       // Version numbers are not needed for now, but we are checking to see if they're there
00141       if (line_type.substr (0, 7) == "VERSION")
00142         continue;
00143 
00144       // Get the field indices (check for COLUMNS too for backwards compatibility)
00145       if ( (line_type.substr (0, 6) == "FIELDS") || (line_type.substr (0, 7) == "COLUMNS") )
00146       {
00147         specified_channel_count = static_cast<int> (st.size () - 1);
00148 
00149         // Allocate enough memory to accommodate all fields
00150         cloud.fields.resize (specified_channel_count);
00151         for (int i = 0; i < specified_channel_count; ++i)
00152         {
00153           std::string col_type = st.at (i + 1);
00154           cloud.fields[i].name = col_type;
00155         }
00156 
00157         // Default the sizes and the types of each field to float32 to avoid crashes while using older PCD files
00158         int offset = 0;
00159         for (int i = 0; i < specified_channel_count; ++i, offset += 4)
00160         {
00161           cloud.fields[i].offset   = offset;
00162           cloud.fields[i].datatype = sensor_msgs::PointField::FLOAT32;
00163           cloud.fields[i].count    = 1;
00164         }
00165         cloud.point_step = offset;
00166         continue;
00167       }
00168 
00169       // Get the field sizes
00170       if (line_type.substr (0, 4) == "SIZE")
00171       {
00172         specified_channel_count = static_cast<int> (st.size () - 1);
00173 
00174         // Allocate enough memory to accommodate all fields
00175         if (specified_channel_count != static_cast<int> (cloud.fields.size ()))
00176           throw "The number of elements in <SIZE> differs than the number of elements in <FIELDS>!";
00177 
00178         // Resize to accommodate the number of values
00179         field_sizes.resize (specified_channel_count);
00180 
00181         int offset = 0;
00182         for (int i = 0; i < specified_channel_count; ++i)
00183         {
00184           int col_type ;
00185           sstream >> col_type;
00186           cloud.fields[i].offset = offset;                // estimate and save the data offsets
00187           offset += col_type;
00188           field_sizes[i] = col_type;                      // save a temporary copy
00189         }
00190         cloud.point_step = offset;
00191         //if (cloud.width != 0)
00192           //cloud.row_step   = cloud.point_step * cloud.width;
00193         continue;
00194       }
00195 
00196       // Get the field types
00197       if (line_type.substr (0, 4) == "TYPE")
00198       {
00199         if (field_sizes.empty ())
00200           throw "TYPE of FIELDS specified before SIZE in header!";
00201 
00202         specified_channel_count = static_cast<int> (st.size () - 1);
00203 
00204         // Allocate enough memory to accommodate all fields
00205         if (specified_channel_count != static_cast<int> (cloud.fields.size ()))
00206           throw "The number of elements in <TYPE> differs than the number of elements in <FIELDS>!";
00207 
00208         // Resize to accommodate the number of values
00209         field_types.resize (specified_channel_count);
00210 
00211         for (int i = 0; i < specified_channel_count; ++i)
00212         {
00213           field_types[i] = st.at (i + 1).c_str ()[0];
00214           cloud.fields[i].datatype = static_cast<uint8_t> (getFieldType (field_sizes[i], field_types[i]));
00215         }
00216         continue;
00217       }
00218 
00219       // Get the field counts
00220       if (line_type.substr (0, 5) == "COUNT")
00221       {
00222         if (field_sizes.empty () || field_types.empty ())
00223           throw "COUNT of FIELDS specified before SIZE or TYPE in header!";
00224 
00225         specified_channel_count = static_cast<int> (st.size () - 1);
00226 
00227         // Allocate enough memory to accommodate all fields
00228         if (specified_channel_count != static_cast<int> (cloud.fields.size ()))
00229           throw "The number of elements in <COUNT> differs than the number of elements in <FIELDS>!";
00230 
00231         field_counts.resize (specified_channel_count);
00232 
00233         int offset = 0;
00234         for (int i = 0; i < specified_channel_count; ++i)
00235         {
00236           cloud.fields[i].offset = offset;
00237           int col_count;
00238           sstream >> col_count;
00239           cloud.fields[i].count = col_count;
00240           offset += col_count * field_sizes[i];
00241         }
00242         // Adjust the offset for count (number of elements)
00243         cloud.point_step = offset;
00244         continue;
00245       }
00246 
00247       // Get the width of the data (organized point cloud dataset)
00248       if (line_type.substr (0, 5) == "WIDTH")
00249       {
00250         sstream >> cloud.width;
00251         if (cloud.point_step != 0)
00252           cloud.row_step = cloud.point_step * cloud.width;      // row_step only makes sense for organized datasets
00253         continue;
00254       }
00255 
00256       // Get the height of the data (organized point cloud dataset)
00257       if (line_type.substr (0, 6) == "HEIGHT")
00258       {
00259         sstream >> cloud.height;
00260         continue;
00261       }
00262 
00263       // Get the acquisition viewpoint
00264       if (line_type.substr (0, 9) == "VIEWPOINT")
00265       {
00266         pcd_version = PCD_V7;
00267         if (st.size () < 8)
00268           throw "Not enough number of elements in <VIEWPOINT>! Need 7 values (tx ty tz qw qx qy qz).";
00269 
00270         float x, y, z, w;
00271         sstream >> x >> y >> z ;
00272         origin      = Eigen::Vector4f (x, y, z, 0.0f);
00273         sstream >> w >> x >> y >> z;
00274         orientation = Eigen::Quaternionf (w, x, y, z);
00275         continue;
00276       }
00277 
00278       // Get the number of points
00279       if (line_type.substr (0, 6) == "POINTS")
00280       {
00281         sstream >> nr_points;
00282         // Need to allocate: N * point_step
00283         cloud.data.resize (nr_points * cloud.point_step);
00284         continue;
00285       }
00286 
00287       // Read the header + comments line by line until we get to <DATA>
00288       if (line_type.substr (0, 4) == "DATA")
00289       {
00290         data_idx = static_cast<int> (fs.tellg ());
00291         if (st.at (1).substr (0, 17) == "binary_compressed")
00292          data_type = 2;
00293         else
00294           if (st.at (1).substr (0, 6) == "binary")
00295             data_type = 1;
00296         continue;
00297       }
00298       break;
00299     }
00300   }
00301   catch (const char *exception)
00302   {
00303     PCL_ERROR ("[pcl::PCDReader::readHeader] %s\n", exception);
00304     fs.close ();
00305     return (-1);
00306   }
00307 
00308   // Exit early: if no points have been given, there's no sense to read or check anything anymore
00309   if (nr_points == 0)
00310   {
00311     PCL_ERROR ("[pcl::PCDReader::readHeader] No points to read\n");
00312     return (-1);
00313   }
00314   
00315   // Compatibility with older PCD file versions
00316   if (cloud.width == 0 && cloud.height == 0)
00317   {
00318     cloud.width  = nr_points;
00319     cloud.height = 1;
00320     cloud.row_step = cloud.point_step * cloud.width;      // row_step only makes sense for organized datasets
00321   }
00322   //assert (cloud.row_step != 0);       // If row_step = 0, either point_step was not set or width is 0
00323 
00324   // if both height/width are not given, assume an unorganized dataset
00325   if (cloud.height == 0)
00326   {
00327     cloud.height = 1;
00328     PCL_WARN ("[pcl::PCDReader::readHeader] no HEIGHT given, setting to 1 (unorganized).\n");
00329     if (cloud.width == 0)
00330       cloud.width  = nr_points;
00331   }
00332   else
00333   {
00334     if (cloud.width == 0 && nr_points != 0)
00335     {
00336       PCL_ERROR ("[pcl::PCDReader::readHeader] HEIGHT given (%d) but no WIDTH!\n", cloud.height);
00337       fs.close ();
00338       return (-1);
00339     }
00340   }
00341 
00342   if (int (cloud.width * cloud.height) != nr_points)
00343   {
00344     PCL_ERROR ("[pcl::PCDReader::readHeader] HEIGHT (%d) x WIDTH (%d) != number of points (%d)\n", cloud.height, cloud.width, nr_points);
00345     fs.close ();
00346     return (-1);
00347   }
00348 
00349   // Close file
00350   fs.close ();
00351 
00352   return (0);
00353 }
00354 
00356 int
00357 pcl::PCDReader::readHeader (const std::string &file_name, sensor_msgs::PointCloud2 &cloud, const int offset)
00358 {
00359   // Default values
00360   cloud.width = cloud.height = cloud.point_step = cloud.row_step = 0;
00361   cloud.data.clear ();
00362 
00363   // By default, assume that there are _no_ invalid (e.g., NaN) points
00364   //cloud.is_dense = true;
00365 
00366   int nr_points = 0;
00367   std::ifstream fs;
00368   std::string line;
00369 
00370   int specified_channel_count = 0;
00371 
00372   if (file_name == "" || !boost::filesystem::exists (file_name))
00373   {
00374     PCL_ERROR ("[pcl::PCDReader::readHeader] Could not find file '%s'.\n", file_name.c_str ());
00375     return (-1);
00376   }
00377   // Open file in binary mode to avoid problem of 
00378   // std::getline() corrupting the result of ifstream::tellg()
00379   fs.open (file_name.c_str (), std::ios::binary);
00380   if (!fs.is_open () || fs.fail ())
00381   {
00382     PCL_ERROR ("[pcl::PCDReader::readHeader] Could not open file '%s'! Error : %s\n", file_name.c_str (), strerror(errno)); 
00383     fs.close ();
00384     return (-1);
00385   }
00386 
00387   // Seek at the given offset
00388   fs.seekg (offset, std::ios::beg);
00389 
00390   // field_sizes represents the size of one element in a field (e.g., float = 4, char = 1)
00391   // field_counts represents the number of elements in a field (e.g., x = 1, normal_x = 1, fpfh = 33)
00392   std::vector<int> field_sizes, field_counts;
00393   // field_types represents the type of data in a field (e.g., F = float, U = unsigned)
00394   std::vector<char> field_types;
00395   std::vector<std::string> st;
00396 
00397   // Read the header and fill it in with wonderful values
00398   try
00399   {
00400     while (!fs.eof ())
00401     {
00402       getline (fs, line);
00403       // Ignore empty lines
00404       if (line == "")
00405         continue;
00406 
00407       // Tokenize the line
00408       boost::trim (line);
00409       boost::split (st, line, boost::is_any_of ("\t\r "), boost::token_compress_on);
00410 
00411       std::stringstream sstream (line);
00412       sstream.imbue (std::locale::classic ());
00413 
00414       std::string line_type;
00415       sstream >> line_type;
00416 
00417       // Ignore comments
00418       if (line_type.substr (0, 1) == "#")
00419         continue;
00420 
00421       // Version numbers are not needed for now, but we are checking to see if they're there
00422       if (line_type.substr (0, 7) == "VERSION")
00423         continue;
00424 
00425       // Get the field indices (check for COLUMNS too for backwards compatibility)
00426       if ( (line_type.substr (0, 6) == "FIELDS") || (line_type.substr (0, 7) == "COLUMNS") )
00427       {
00428         specified_channel_count = static_cast<int> (st.size () - 1);
00429 
00430         // Allocate enough memory to accommodate all fields
00431         cloud.fields.resize (specified_channel_count);
00432         for (int i = 0; i < specified_channel_count; ++i)
00433         {
00434           std::string col_type = st.at (i + 1);
00435           cloud.fields[i].name = col_type;
00436         }
00437 
00438         // Default the sizes and the types of each field to float32 to avoid crashes while using older PCD files
00439         int offset = 0;
00440         for (int i = 0; i < specified_channel_count; ++i, offset += 4)
00441         {
00442           cloud.fields[i].offset   = offset;
00443           cloud.fields[i].datatype = sensor_msgs::PointField::FLOAT32;
00444           cloud.fields[i].count    = 1;
00445         }
00446         cloud.point_step = offset;
00447         continue;
00448       }
00449 
00450       // Get the field sizes
00451       if (line_type.substr (0, 4) == "SIZE")
00452       {
00453         specified_channel_count = static_cast<int> (st.size () - 1);
00454 
00455         // Allocate enough memory to accommodate all fields
00456         if (specified_channel_count != static_cast<int> (cloud.fields.size ()))
00457           throw "The number of elements in <SIZE> differs than the number of elements in <FIELDS>!";
00458 
00459         // Resize to accommodate the number of values
00460         field_sizes.resize (specified_channel_count);
00461 
00462         int offset = 0;
00463         for (int i = 0; i < specified_channel_count; ++i)
00464         {
00465           int col_type ;
00466           sstream >> col_type;
00467           cloud.fields[i].offset = offset;                // estimate and save the data offsets
00468           offset += col_type;
00469           field_sizes[i] = col_type;                      // save a temporary copy
00470         }
00471         cloud.point_step = offset;
00472         //if (cloud.width != 0)
00473           //cloud.row_step   = cloud.point_step * cloud.width;
00474         continue;
00475       }
00476 
00477       // Get the field types
00478       if (line_type.substr (0, 4) == "TYPE")
00479       {
00480         if (field_sizes.empty ())
00481           throw "TYPE of FIELDS specified before SIZE in header!";
00482 
00483         specified_channel_count = static_cast<int> (st.size () - 1);
00484 
00485         // Allocate enough memory to accommodate all fields
00486         if (specified_channel_count != static_cast<int> (cloud.fields.size ()))
00487           throw "The number of elements in <TYPE> differs than the number of elements in <FIELDS>!";
00488 
00489         // Resize to accommodate the number of values
00490         field_types.resize (specified_channel_count);
00491 
00492         for (int i = 0; i < specified_channel_count; ++i)
00493         {
00494           field_types[i] = st.at (i + 1).c_str ()[0];
00495           cloud.fields[i].datatype = static_cast<uint8_t> (getFieldType (field_sizes[i], field_types[i]));
00496         }
00497         continue;
00498       }
00499 
00500       // Get the field counts
00501       if (line_type.substr (0, 5) == "COUNT")
00502       {
00503         if (field_sizes.empty () || field_types.empty ())
00504           throw "COUNT of FIELDS specified before SIZE or TYPE in header!";
00505 
00506         specified_channel_count = static_cast<int> (st.size () - 1);
00507 
00508         // Allocate enough memory to accommodate all fields
00509         if (specified_channel_count != static_cast<int> (cloud.fields.size ()))
00510           throw "The number of elements in <COUNT> differs than the number of elements in <FIELDS>!";
00511 
00512         field_counts.resize (specified_channel_count);
00513 
00514         int offset = 0;
00515         for (int i = 0; i < specified_channel_count; ++i)
00516         {
00517           cloud.fields[i].offset = offset;
00518           int col_count;
00519           sstream >> col_count;
00520           cloud.fields[i].count = col_count;
00521           offset += col_count * field_sizes[i];
00522         }
00523         // Adjust the offset for count (number of elements)
00524         cloud.point_step = offset;
00525         continue;
00526       }
00527 
00528       // Get the width of the data (organized point cloud dataset)
00529       if (line_type.substr (0, 5) == "WIDTH")
00530       {
00531         sstream >> cloud.width;
00532         if (cloud.point_step != 0)
00533           cloud.row_step = cloud.point_step * cloud.width;      // row_step only makes sense for organized datasets
00534         continue;
00535       }
00536 
00537       // Get the height of the data (organized point cloud dataset)
00538       if (line_type.substr (0, 6) == "HEIGHT")
00539       {
00540         sstream >> cloud.height;
00541         continue;
00542       }
00543 
00544       // Check the format of the acquisition viewpoint
00545       if (line_type.substr (0, 9) == "VIEWPOINT")
00546       {
00547         if (st.size () < 8)
00548           throw "Not enough number of elements in <VIEWPOINT>! Need 7 values (tx ty tz qw qx qy qz).";
00549         continue;
00550       }
00551 
00552       // Get the number of points
00553       if (line_type.substr (0, 6) == "POINTS")
00554       {
00555         sstream >> nr_points;
00556         // Need to allocate: N * point_step
00557         cloud.data.resize (nr_points * cloud.point_step);
00558         continue;
00559       }
00560       break;
00561     }
00562   }
00563   catch (const char *exception)
00564   {
00565     PCL_ERROR ("[pcl::PCDReader::readHeader] %s\n", exception);
00566     fs.close ();
00567     return (-1);
00568   }
00569 
00570   // Exit early: if no points have been given, there's no sense to read or check anything anymore
00571   if (nr_points == 0)
00572   {
00573     PCL_ERROR ("[pcl::PCDReader::readHeader] No points to read\n");
00574     return (-1);
00575   }
00576   
00577   // Compatibility with older PCD file versions
00578   if (cloud.width == 0 && cloud.height == 0)
00579   {
00580     cloud.width  = nr_points;
00581     cloud.height = 1;
00582     cloud.row_step = cloud.point_step * cloud.width;      // row_step only makes sense for organized datasets
00583   }
00584   //assert (cloud.row_step != 0);       // If row_step = 0, either point_step was not set or width is 0
00585 
00586   // if both height/width are not given, assume an unorganized dataset
00587   if (cloud.height == 0)
00588   {
00589     cloud.height = 1;
00590     PCL_WARN ("[pcl::PCDReader::readHeader] no HEIGHT given, setting to 1 (unorganized).\n");
00591     if (cloud.width == 0)
00592       cloud.width  = nr_points;
00593   }
00594   else
00595   {
00596     if (cloud.width == 0 && nr_points != 0)
00597     {
00598       PCL_ERROR ("[pcl::PCDReader::readHeader] HEIGHT given (%d) but no WIDTH!\n", cloud.height);
00599       fs.close ();
00600       return (-1);
00601     }
00602   }
00603 
00604   if (int (cloud.width * cloud.height) != nr_points)
00605   {
00606     PCL_ERROR ("[pcl::PCDReader::readHeader] HEIGHT (%d) x WIDTH (%d) != number of points (%d)\n", cloud.height, cloud.width, nr_points);
00607     fs.close ();
00608     return (-1);
00609   }
00610 
00611   // Close file
00612   fs.close ();
00613 
00614   return (0);
00615 }
00616 
00618 int
00619 pcl::PCDReader::readHeaderEigen (const std::string &file_name, pcl::PointCloud<Eigen::MatrixXf> &cloud, 
00620                                  int &pcd_version, int &data_type, unsigned int &data_idx, const int offset)
00621 {
00622   // Default values
00623   data_idx = 0;
00624   data_type = 0;
00625   pcd_version = PCD_V6;
00626   cloud.properties.sensor_origin      = Eigen::Vector4f::Zero ();
00627   cloud.properties.sensor_orientation = Eigen::Quaternionf::Identity ();
00628   cloud.width = cloud.height = 0;
00629   cloud.points.resize (0, 0);
00630 
00631   // By default, assume that there are _no_ invalid (e.g., NaN) points
00632   //cloud.is_dense = true;
00633 
00634   int nr_points = 0;
00635   std::ifstream fs;
00636   std::string line;
00637 
00638   int specified_channel_count = 0;
00639 
00640   if (file_name == "" || !boost::filesystem::exists (file_name))
00641   {
00642     PCL_ERROR ("[pcl::PCDReader::readHeader] Could not find file '%s'.\n", file_name.c_str ());
00643     return (-1);
00644   }
00645   // Open file in binary mode to avoid problem of 
00646   // std::getline() corrupting the result of ifstream::tellg()
00647   fs.open (file_name.c_str (), std::ios::binary);
00648   if (!fs.is_open () || fs.fail ())
00649   {
00650     PCL_ERROR ("[pcl::PCDReader::readHeader] Could not open file '%s'! Error : %s\n", file_name.c_str (), strerror(errno)); 
00651     return (-1);
00652   }
00653 
00654   // Seek at the given offset
00655   fs.seekg (offset, std::ios::beg);
00656 
00657   // field_sizes represents the size of one element in a field (e.g., float = 4, char = 1)
00658   // field_counts represents the number of elements in a field (e.g., x = 1, normal_x = 1, fpfh = 33)
00659   std::vector<int> field_sizes, field_counts;
00660   // field_types represents the type of data in a field (e.g., F = float, U = unsigned)
00661   std::vector<char> field_types;
00662   std::vector<std::string> st;
00663 
00664   std::vector<pcl::ChannelProperties> channels;
00665   int total_dimensions = 0;
00666   // Read the header and fill it in with wonderful values
00667   try
00668   {
00669     while (!fs.eof ())
00670     {
00671       getline (fs, line);
00672       // Ignore empty lines
00673       if (line == "")
00674         continue;
00675 
00676       // Tokenize the line
00677       boost::trim (line);
00678       boost::split (st, line, boost::is_any_of ("\t\r "), boost::token_compress_on);
00679 
00680       std::stringstream sstream (line);
00681       sstream.imbue (std::locale::classic ());
00682 
00683       std::string line_type;
00684       sstream >> line_type;
00685 
00686       // Ignore comments
00687       if (line_type.substr (0, 1) == "#")
00688         continue;
00689 
00690       // Version numbers are not needed for now, but we are checking to see if they're there
00691       if (line_type.substr (0, 7) == "VERSION")
00692         continue;
00693 
00694       // Get the field indices (check for COLUMNS too for backwards compatibility)
00695       if ( (line_type.substr (0, 6) == "FIELDS") || (line_type.substr (0, 7) == "COLUMNS") )
00696       {
00697         specified_channel_count = static_cast<int> (st.size () - 1);
00698 
00699         // Allocate enough memory to accommodate all fields
00700         channels.resize (specified_channel_count);
00701         for (int i = 0; i < specified_channel_count; ++i)
00702         {
00703           std::string col_type = st.at (i + 1);
00704           channels[i].name     = col_type;
00705           channels[i].size     = 4;
00706           channels[i].offset   = 0;
00707           channels[i].count    = 1;
00708           channels[i].datatype = sensor_msgs::PointField::FLOAT32;
00709         }
00710         continue;
00711       }
00712 
00713       // Get the field sizes
00714       if (line_type.substr (0, 4) == "SIZE")
00715       {
00716         specified_channel_count = static_cast<int> (st.size () - 1);
00717 
00718         // Allocate enough memory to accommodate all fields
00719         if (specified_channel_count != static_cast<int> (channels.size ()))
00720           throw "The number of elements in <SIZE> differs than the number of elements in <FIELDS>!";
00721 
00722         for (int i = 0; i < specified_channel_count; ++i)
00723         {
00724           int col_type;
00725           sstream >> col_type;
00726           if (col_type != 4)
00727             PCL_WARN ("[pcl::PCDReader::readHeaderEigen] Casting field size %d to 4.\n", col_type);
00728         }
00729         continue;
00730       }
00731 
00732       // Get the field types
00733       if (line_type.substr (0, 4) == "TYPE")
00734       {
00735         specified_channel_count = static_cast<int> (st.size () - 1);
00736 
00737         // Allocate enough memory to accommodate all fields
00738         if (specified_channel_count != static_cast<int> (channels.size ()))
00739           throw "The number of elements in <TYPE> differs than the number of elements in <FIELDS>!";
00740 
00741         for (int i = 0; i < specified_channel_count; ++i)
00742         {
00743           std::string field_type (st.at (i + 1).c_str ());
00744           if (field_type != "F")
00745             PCL_WARN ("[pcl::PCDReader::readHeaderEigen] Casting field type %s to FLOAT.\n", field_type.c_str ());
00746         }
00747         continue;
00748       }
00749 
00750       // Get the field counts
00751       if (line_type.substr (0, 5) == "COUNT")
00752       {
00753         specified_channel_count = static_cast<int> (st.size () - 1);
00754 
00755         // Allocate enough memory to accommodate all fields
00756         if (specified_channel_count != static_cast<int> (channels.size ()))
00757           throw "The number of elements in <COUNT> differs than the number of elements in <FIELDS>!";
00758 
00759         field_counts.resize (specified_channel_count);
00760 
00761         int offset = 0;
00762         for (int i = 0; i < specified_channel_count; ++i)
00763         {
00764           int col_count;
00765           sstream >> col_count;
00766           total_dimensions += col_count; 
00767           channels[i].count = col_count;
00768           channels[i].offset = offset;
00769           offset += col_count * 4;
00770         }
00771 
00772         for (size_t cc = 0; cc < channels.size (); ++cc)
00773           cloud.channels[channels[cc].name] = channels[cc];
00774         continue;
00775       }
00776 
00777       // Get the width of the data (organized point cloud dataset)
00778       if (line_type.substr (0, 5) == "WIDTH")
00779       {
00780         sstream >> cloud.width;
00781         continue;
00782       }
00783 
00784       // Get the height of the data (organized point cloud dataset)
00785       if (line_type.substr (0, 6) == "HEIGHT")
00786       {
00787         sstream >> cloud.height;
00788         continue;
00789       }
00790 
00791       // Get the acquisition viewpoint
00792       if (line_type.substr (0, 9) == "VIEWPOINT")
00793       {
00794         pcd_version = PCD_V7;
00795         if (st.size () < 8)
00796           throw "Not enough number of elements in <VIEWPOINT>! Need 7 values (tx ty tz qw qx qy qz).";
00797 
00798         float x, y, z, w;
00799         sstream >> x >> y >> z ;
00800         cloud.properties.sensor_origin      = Eigen::Vector4f (x, y, z, 0.0f);
00801         sstream >> w >> x >> y >> z;
00802         cloud.properties.sensor_orientation = Eigen::Quaternionf (w, x, y, z);
00803         continue;
00804       }
00805 
00806       // Get the number of points
00807       if (line_type.substr (0, 6) == "POINTS")
00808       {
00809         sstream >> nr_points;
00810         // Compute the number of columns
00811         int nr_cols = 0;
00812         for (std::map<std::string, pcl::ChannelProperties>::const_iterator it = cloud.channels.begin (); it != cloud.channels.end (); ++it)
00813           nr_cols += it->second.count;
00814         // Need to allocate: N * point_step
00815         cloud.points.resize (nr_points, nr_cols);
00816         continue;
00817       }
00818 
00819       // Read the header + comments line by line until we get to <DATA>
00820       if (line_type.substr (0, 4) == "DATA")
00821       {
00822         data_idx = static_cast<int> (fs.tellg ());
00823         if (st.at (1).substr (0, 17) == "binary_compressed")
00824          data_type = 2;
00825         else
00826           if (st.at (1).substr (0, 6) == "binary")
00827             data_type = 1;
00828         continue;
00829       }
00830       break;
00831     }
00832   }
00833   catch (const char *exception)
00834   {
00835     PCL_ERROR ("[pcl::PCDReader::readHeader] %s\n", exception);
00836     fs.close ();
00837     return (-1);
00838   }
00839 
00840   // Compatibility with older PCD file versions
00841   if (cloud.width == 0 && cloud.height == 0)
00842   {
00843     cloud.width  = nr_points;
00844     cloud.height = 1;
00845   }
00846   //assert (cloud.row_step != 0);       // If row_step = 0, either point_step was not set or width is 0
00847 
00848   // if both height/width are not given, assume an unorganized dataset
00849   if (cloud.height == 0)
00850   {
00851     cloud.height = 1;
00852     PCL_WARN ("[pcl::PCDReader::readHeader] no HEIGHT given, setting to 1 (unorganized).\n");
00853     if (cloud.width == 0)
00854       cloud.width  = nr_points;
00855   }
00856   else
00857   {
00858     if (cloud.width == 0 && nr_points != 0)
00859     {
00860       PCL_ERROR ("[pcl::PCDReader::readHeader] HEIGHT given (%d) but no WIDTH!\n", cloud.height);
00861       fs.close ();
00862       return (-1);
00863     }
00864   }
00865 
00866   if (int (cloud.width * cloud.height) != nr_points)
00867   {
00868     PCL_ERROR ("[pcl::PCDReader::readHeader] HEIGHT (%d) x WIDTH (%d) != number of points (%d)\n", cloud.height, cloud.width, nr_points);
00869     fs.close ();
00870     return (-1);
00871   }
00872 
00873   // Close file
00874   fs.close ();
00875 
00876   return (0);
00877 }
00878 
00880 int
00881 pcl::PCDReader::read (const std::string &file_name, sensor_msgs::PointCloud2 &cloud,
00882                       Eigen::Vector4f &origin, Eigen::Quaternionf &orientation, int &pcd_version, 
00883                       const int offset)
00884 {
00885   int data_type;
00886   unsigned int data_idx;
00887 
00888   int res = readHeader (file_name, cloud, origin, orientation, pcd_version, data_type, data_idx, offset);
00889 
00890   if (res < 0)
00891     return (res);
00892 
00893   unsigned int idx = 0;
00894 
00895   // Get the number of points the cloud should have
00896   unsigned int nr_points = cloud.width * cloud.height;
00897 
00898   // Setting the is_dense property to true by default
00899   cloud.is_dense = true;
00900 
00901   // if ascii
00902   if (data_type == 0)
00903   {
00904     // Re-open the file (readHeader closes it)
00905     std::ifstream fs;
00906     fs.open (file_name.c_str ());
00907     if (!fs.is_open () || fs.fail ())
00908     {
00909       PCL_ERROR ("[pcl::PCDReader::read] Could not open file %s.\n", file_name.c_str ());
00910       return (-1);
00911     }
00912 
00913     fs.seekg (data_idx);
00914 
00915     std::string line;
00916     std::vector<std::string> st;
00917 
00918     // Read the rest of the file
00919     try
00920     {
00921       while (idx < nr_points && !fs.eof ())
00922       {
00923         getline (fs, line);
00924         // Ignore empty lines
00925         if (line == "")
00926           continue;
00927 
00928         // Tokenize the line
00929         boost::trim (line);
00930         boost::split (st, line, boost::is_any_of ("\t\r "), boost::token_compress_on);
00931         
00932         if (idx >= nr_points)
00933         {
00934           PCL_WARN ("[pcl::PCDReader::read] input file %s has more points (%d) than advertised (%d)!\n", file_name.c_str (), idx, nr_points);
00935           break;
00936         }
00937 
00938         size_t total = 0;
00939         // Copy data
00940         for (unsigned int d = 0; d < static_cast<unsigned int> (cloud.fields.size ()); ++d)
00941         {
00942           // Ignore invalid padded dimensions that are inherited from binary data
00943           if (cloud.fields[d].name == "_")
00944           {
00945             total += cloud.fields[d].count; // jump over this many elements in the string token
00946             continue;
00947           }
00948           for (unsigned int c = 0; c < cloud.fields[d].count; ++c)
00949           {
00950             switch (cloud.fields[d].datatype)
00951             {
00952               case sensor_msgs::PointField::INT8:
00953               {
00954                 copyStringValue<pcl::traits::asType<sensor_msgs::PointField::INT8>::type> (
00955                     st.at (total + c), cloud, idx, d, c);
00956                 break;
00957               }
00958               case sensor_msgs::PointField::UINT8:
00959               {
00960                 copyStringValue<pcl::traits::asType<sensor_msgs::PointField::UINT8>::type> (
00961                     st.at (total + c), cloud, idx, d, c);
00962                 break;
00963               }
00964               case sensor_msgs::PointField::INT16:
00965               {
00966                 copyStringValue<pcl::traits::asType<sensor_msgs::PointField::INT16>::type> (
00967                     st.at (total + c), cloud, idx, d, c);
00968                 break;
00969               }
00970               case sensor_msgs::PointField::UINT16:
00971               {
00972                 copyStringValue<pcl::traits::asType<sensor_msgs::PointField::UINT16>::type> (
00973                     st.at (total + c), cloud, idx, d, c);
00974                 break;
00975               }
00976               case sensor_msgs::PointField::INT32:
00977               {
00978                 copyStringValue<pcl::traits::asType<sensor_msgs::PointField::INT32>::type> (
00979                     st.at (total + c), cloud, idx, d, c);
00980                 break;
00981               }
00982               case sensor_msgs::PointField::UINT32:
00983               {
00984                 copyStringValue<pcl::traits::asType<sensor_msgs::PointField::UINT32>::type> (
00985                     st.at (total + c), cloud, idx, d, c);
00986                 break;
00987               }
00988               case sensor_msgs::PointField::FLOAT32:
00989               {
00990                 copyStringValue<pcl::traits::asType<sensor_msgs::PointField::FLOAT32>::type> (
00991                     st.at (total + c), cloud, idx, d, c);
00992                 break;
00993               }
00994               case sensor_msgs::PointField::FLOAT64:
00995               {
00996                 copyStringValue<pcl::traits::asType<sensor_msgs::PointField::FLOAT64>::type> (
00997                     st.at (total + c), cloud, idx, d, c);
00998                 break;
00999               }
01000               default:
01001                 PCL_WARN ("[pcl::PCDReader::read] Incorrect field data type specified (%d)!\n",cloud.fields[d].datatype);
01002                 break;
01003             }
01004           }
01005           total += cloud.fields[d].count; // jump over this many elements in the string token
01006         }
01007         idx++;
01008       }
01009     }
01010     catch (const char *exception)
01011     {
01012       PCL_ERROR ("[pcl::PCDReader::read] %s\n", exception);
01013       return (-1);
01014     }
01015 
01016     // Close file
01017     fs.close ();
01018 
01019   }
01020   else 
01023   {
01024     // Open for reading
01025     int fd = pcl_open (file_name.c_str (), O_RDONLY);
01026     if (fd == -1)
01027     {
01028       PCL_ERROR ("[pcl::PCDReader::read] Failure to open file %s\n", file_name.c_str () );
01029       return (-1);
01030     }
01031     
01032     // Seek at the given offset
01033     int result = static_cast<int> (pcl_lseek (fd, offset, SEEK_SET));
01034     if (result < 0)
01035     {
01036       pcl_close (fd);
01037       PCL_ERROR ("[pcl::PCDReader::read] Error during lseek ()!\n");
01038       return (-1);
01039     }
01040     
01041     size_t data_size = data_idx + cloud.data.size ();
01042     // Prepare the map
01043 #ifdef _WIN32
01044     // map te whole file
01045     // As we don't know the real size of data (compressed or not), we set dwMaximumSizeHigh = dwMaximumSizeLow = 0
01046     // so as to map the whole file
01047     HANDLE fm = CreateFileMapping ((HANDLE) _get_osfhandle (fd), NULL, PAGE_READONLY, 0, 0, NULL);
01048     // As we don't know the real size of data (compressed or not), we set dwNumberOfBytesToMap = 0
01049     // so as to map the whole file
01050     char *map = static_cast<char*>(MapViewOfFile (fm, FILE_MAP_READ, 0, 0, 0));
01051     if (map == NULL)
01052     {
01053       CloseHandle (fm);
01054       pcl_close (fd);
01055       PCL_ERROR ("[pcl::PCDReader::read] Error mapping view of file, %s\n", file_name.c_str ());
01056       return (-1);
01057     }
01058 #else
01059     char *map = static_cast<char*> (mmap (0, data_size, PROT_READ, MAP_SHARED, fd, 0));
01060     if (map == reinterpret_cast<char*> (-1))    // MAP_FAILED
01061     {
01062       pcl_close (fd);
01063       PCL_ERROR ("[pcl::PCDReader::read] Error preparing mmap for binary PCD file.\n");
01064       return (-1);
01065     }
01066 #endif
01067 
01069     if (data_type == 2)
01070     {
01071       // Uncompress the data first
01072       unsigned int compressed_size, uncompressed_size;
01073       memcpy (&compressed_size, &map[data_idx + 0], sizeof (unsigned int));
01074       memcpy (&uncompressed_size, &map[data_idx + 4], sizeof (unsigned int));
01075       PCL_DEBUG ("[pcl::PCDReader::read] Read a binary compressed file with %u bytes compressed and %u original.\n", compressed_size, uncompressed_size);
01076       // For all those weird situations where the compressed data is actually LARGER than the uncompressed one
01077       // (we really ought to check this in the compressor and copy the original data in those cases)
01078       if (data_size < compressed_size)
01079       {
01080 #if _WIN32
01081         UnmapViewOfFile (map);
01082         data_size = compressed_size;
01083         map = static_cast<char*>(MapViewOfFile (fm, FILE_MAP_READ, 0, 0, data_size));
01084 #else
01085         munmap (map, data_size);
01086         data_size = compressed_size;
01087         map = static_cast<char*> (mmap (0, data_size, PROT_READ, MAP_SHARED, fd, 0));
01088 #endif
01089       }
01090 
01091       if (uncompressed_size != cloud.data.size ())
01092       {
01093         PCL_WARN ("[pcl::PCDReader::read] The estimated cloud.data size (%u) is different than the saved uncompressed value (%u)! Data corruption?\n", 
01094                   cloud.data.size (), uncompressed_size);
01095         cloud.data.resize (uncompressed_size);
01096       }
01097 
01098       char *buf = static_cast<char*> (malloc (data_size));
01099       // The size of the uncompressed data better be the same as what we stored in the header
01100       if (pcl::lzfDecompress (&map[data_idx + 8], compressed_size, buf, static_cast<unsigned int> (data_size)) != uncompressed_size)
01101       {
01102         free (buf);
01103         pcl_close (fd);
01104         PCL_ERROR ("[pcl::PCDReader::read] Size of decompressed lzf data does not match value stored in PCD header\n");
01105         return (-1);
01106       }
01107 
01108       // Get the fields sizes
01109       std::vector<sensor_msgs::PointField> fields (cloud.fields.size ());
01110       std::vector<int> fields_sizes (cloud.fields.size ());
01111       int nri = 0, fsize = 0;
01112       for (size_t i = 0; i < cloud.fields.size (); ++i)
01113       {
01114         if (cloud.fields[i].name == "_")
01115           continue;
01116         fields_sizes[nri] = cloud.fields[i].count * pcl::getFieldSize (cloud.fields[i].datatype);
01117         fsize += fields_sizes[nri];
01118         fields[nri] = cloud.fields[i];
01119         ++nri;
01120       }
01121       fields.resize (nri);
01122       fields_sizes.resize (nri);
01123 
01124       // Unpack the xxyyzz to xyz
01125       std::vector<char*> pters (fields.size ());
01126       int toff = 0;
01127       for (size_t i = 0; i < pters.size (); ++i)
01128       {
01129         pters[i] = &buf[toff];
01130         toff += fields_sizes[i] * cloud.width * cloud.height;
01131       }
01132       // Copy it to the cloud
01133       for (size_t i = 0; i < cloud.width * cloud.height; ++i)
01134       {
01135         for (size_t j = 0; j < pters.size (); ++j)
01136         {
01137           memcpy (&cloud.data[i * fsize + fields[j].offset], pters[j], fields_sizes[j]);
01138           // Increment the pointer
01139           pters[j] += fields_sizes[j];
01140         }
01141       }
01142       //memcpy (&cloud.data[0], &buf[0], uncompressed_size);
01143 
01144       free (buf);
01145     }
01146     else
01147       // Copy the data
01148       memcpy (&cloud.data[0], &map[0] + data_idx, cloud.data.size ());
01149 
01150     // Unmap the pages of memory
01151 #if _WIN32
01152     UnmapViewOfFile (map);
01153     CloseHandle (fm);
01154 #else
01155     if (munmap (map, data_size) == -1)
01156     {
01157       pcl_close (fd);
01158       PCL_ERROR ("[pcl::PCDReader::read] Munmap failure\n");
01159       return (-1);
01160     }
01161 #endif
01162     pcl_close (fd);
01163   }
01164 
01165   if ((idx != nr_points) && (data_type == 0))
01166   {
01167     PCL_ERROR ("[pcl::PCDReader::read] Number of points read (%d) is different than expected (%d)\n", idx, nr_points);
01168     return (-1);
01169   }
01170 
01171   // No need to do any extra checks if the data type is ASCII
01172   if (data_type == 0)
01173     return (0);
01174 
01175   int point_size = static_cast<int> (cloud.data.size () / (cloud.height * cloud.width));
01176   // Once copied, we need to go over each field and check if it has NaN/Inf values and assign cloud.is_dense to true or false
01177   for (uint32_t i = 0; i < cloud.width * cloud.height; ++i)
01178   {
01179     for (unsigned int d = 0; d < static_cast<unsigned int> (cloud.fields.size ()); ++d)
01180     {
01181       for (uint32_t c = 0; c < cloud.fields[d].count; ++c)
01182       {
01183         switch (cloud.fields[d].datatype)
01184         {
01185           case sensor_msgs::PointField::INT8:
01186           {
01187             if (!isValueFinite<pcl::traits::asType<sensor_msgs::PointField::INT8>::type>(cloud, i, point_size, d, c))
01188               cloud.is_dense = false;
01189             break;
01190           }
01191           case sensor_msgs::PointField::UINT8:
01192           {
01193             if (!isValueFinite<pcl::traits::asType<sensor_msgs::PointField::UINT8>::type>(cloud, i, point_size, d, c))
01194               cloud.is_dense = false;
01195             break;
01196           }
01197           case sensor_msgs::PointField::INT16:
01198           {
01199             if (!isValueFinite<pcl::traits::asType<sensor_msgs::PointField::INT16>::type>(cloud, i, point_size, d, c))
01200               cloud.is_dense = false;
01201             break;
01202           }
01203           case sensor_msgs::PointField::UINT16:
01204           {
01205             if (!isValueFinite<pcl::traits::asType<sensor_msgs::PointField::UINT16>::type>(cloud, i, point_size, d, c))
01206               cloud.is_dense = false;
01207             break;
01208           }
01209           case sensor_msgs::PointField::INT32:
01210           {
01211             if (!isValueFinite<pcl::traits::asType<sensor_msgs::PointField::INT32>::type>(cloud, i, point_size, d, c))
01212               cloud.is_dense = false;
01213             break;
01214           }
01215           case sensor_msgs::PointField::UINT32:
01216           {
01217             if (!isValueFinite<pcl::traits::asType<sensor_msgs::PointField::UINT32>::type>(cloud, i, point_size, d, c))
01218               cloud.is_dense = false;
01219             break;
01220           }
01221           case sensor_msgs::PointField::FLOAT32:
01222           {
01223             if (!isValueFinite<pcl::traits::asType<sensor_msgs::PointField::FLOAT32>::type>(cloud, i, point_size, d, c))
01224               cloud.is_dense = false;
01225             break;
01226           }
01227           case sensor_msgs::PointField::FLOAT64:
01228           {
01229             if (!isValueFinite<pcl::traits::asType<sensor_msgs::PointField::FLOAT64>::type>(cloud, i, point_size, d, c))
01230               cloud.is_dense = false;
01231             break;
01232           }
01233         }
01234       }
01235     }
01236   }
01237 
01238   return (0);
01239 }
01240 
01242 int
01243 pcl::PCDReader::readEigen (const std::string &file_name, pcl::PointCloud<Eigen::MatrixXf> &cloud, 
01244                            const int offset)
01245 {
01246   int data_type;
01247   unsigned int data_idx;
01248   int pcd_version;
01249   int res = readHeaderEigen (file_name, cloud, pcd_version, data_type, data_idx);
01250 
01251   if (res < 0)
01252     return (res);
01253 
01254   int idx = 0;
01255 
01256   // Get the number of points the cloud should have
01257   int nr_points = cloud.width * cloud.height;
01258 
01259   // Setting the is_dense property to true by default
01260   cloud.is_dense = true;
01261 
01262   // if ascii
01263   if (data_type == 0)
01264   {
01265     // Re-open the file (readHeader closes it)
01266     std::ifstream fs;
01267     fs.open (file_name.c_str ());
01268     if (!fs.is_open () || fs.fail ())
01269     {
01270       PCL_ERROR ("[pcl::PCDReader::read] Could not open file %s.\n", file_name.c_str ());
01271       return (-1);
01272     }
01273 
01274     fs.seekg (data_idx);
01275 
01276     std::string line;
01277     std::vector<std::string> st;
01278 
01279     // Read the rest of the file
01280     try
01281     {
01282       while (idx < nr_points && !fs.eof ())
01283       {
01284         getline (fs, line);
01285         // Ignore empty lines
01286         if (line == "")
01287           continue;
01288 
01289         // Tokenize the line
01290         boost::trim (line);
01291         boost::split (st, line, boost::is_any_of ("\t\r "), boost::token_compress_on);
01292         
01293         std::stringstream sstream (line);
01294         sstream.imbue (std::locale::classic ());
01295 
01296         if (idx >= nr_points)
01297         {
01298           PCL_WARN ("[pcl::PCDReader::read] input file %s has more points than advertised (%d)!\n", file_name.c_str (), nr_points);
01299           break;
01300         }
01301 
01302         for (size_t i = 0; i < st.size (); ++i)
01303           sstream >> cloud.points (idx, i);
01304         idx++;
01305       }
01306     }
01307     catch (const char *exception)
01308     {
01309       PCL_ERROR ("[pcl::PCDReader::readEigen] %s\n", exception);
01310       return (-1);
01311     }
01312 
01313     // Close file
01314     fs.close ();
01315 
01316   }
01317   else 
01320   {
01321     // Open for reading
01322     int fd = pcl_open (file_name.c_str (), O_RDONLY);
01323     if (fd == -1)
01324     {
01325       PCL_ERROR ("[pcl::PCDReader::readEigen] Failure to open file %s\n", file_name.c_str () );
01326       return (-1);
01327     }
01328     
01329 
01330     // Seek at the given offset
01331     int result = static_cast<int> (pcl_lseek (fd, offset, SEEK_SET));
01332     if (result < 0)
01333     {
01334       pcl_close (fd);
01335       PCL_ERROR ("[pcl::PCDReader::readEigen] Error during lseek ()!\n");
01336       return (-1);
01337     }
01338 
01339     size_t data_size = data_idx + cloud.points.rows () * cloud.points.cols () * sizeof (float);
01340     // Prepare the map
01341 #ifdef _WIN32
01342     // map te whole file
01343     // As we don't know the real size of data (compressed or not), we set dwMaximumSizeHigh = dwMaximumSizeLow = 0
01344     // so as to map the whole file
01345     HANDLE fm = CreateFileMapping ((HANDLE) _get_osfhandle (fd), NULL, PAGE_READONLY, 0, 0, NULL);
01346     // As we don't know the real size of data (compressed or not), we set dwNumberOfBytesToMap = 0
01347     // so as to map the whole file
01348     char *map = static_cast<char*>(MapViewOfFile (fm, FILE_MAP_READ, 0, 0, 0));
01349     if (map == NULL)
01350     {
01351       CloseHandle (fm);
01352       pcl_close (fd);
01353       PCL_ERROR ("[pcl::PCDReader::readEigen] Error mapping view of file\n");
01354       return (-1);
01355     }
01356 #else
01357     char *map = static_cast<char*> (mmap (0, data_size, PROT_READ, MAP_SHARED, fd, 0));
01358     if (map == reinterpret_cast<char*> (-1))    // MAP_FAILED
01359     {
01360       pcl_close (fd);
01361       PCL_ERROR ("[pcl::PCDReader::readEigen] Error preparing mmap for binary PCD file.\n");
01362       return (-1);
01363     }
01364 #endif
01365 
01367     if (data_type == 2)
01368       throw pcl::IOException ("[pcl::PCDReader::readEigen] PCD binary_compressed mode not implemented for Eigen::MatrixXf!");
01369     else
01370     {
01371       // Is the given matrix row major?
01372       if (cloud.points.Flags & Eigen::RowMajorBit)
01373         memcpy (&cloud.points.coeffRef (0), &map[0] + data_idx, cloud.points.cols () * cloud.points.rows () * sizeof (float));
01374       // Column major! We need to transpose-copy the data
01375       else
01376       {
01377         Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> pts (cloud.points.rows (), cloud.points.cols ());
01378         memcpy (&pts.coeffRef (0), &map[0] + data_idx, cloud.points.cols () * cloud.points.rows () * sizeof (float));
01379         pts.transposeInPlace ();
01380         memcpy (&cloud.points.coeffRef (0), &pts.coeffRef (0), cloud.points.cols () * cloud.points.rows () * sizeof (float));
01381       }
01382     }
01383 
01384     // Unmap the pages of memory
01385 #if _WIN32
01386     UnmapViewOfFile (map);
01387     CloseHandle (fm);
01388 #else
01389     if (munmap (map, data_size) == -1)
01390     {
01391       pcl_close (fd);
01392       PCL_ERROR ("[pcl::PCDReader::readEigen] Error during munmap ()!\n");
01393       return (-1);
01394     }
01395 #endif
01396     pcl_close (fd);
01397   }
01398 
01399   if ((idx != nr_points) && (data_type == 0))
01400   {
01401     PCL_ERROR ("[pcl::PCDReader::readEigen] Number of points read (%d) is different than expected (%d)\n", idx, nr_points);
01402     return (-1);
01403   }
01404 
01405   // No need to do any extra checks if the data type is ASCII
01406   if (data_type == 0)
01407     return (0);
01408 
01409   // Once copied, we need to go over each field and check if it has NaN/Inf values and assign cloud.is_dense to true or false
01410   for (int i = 0; i < cloud.points.rows (); ++i)
01411   {
01412     for (int j = 0; j < cloud.points.cols (); ++j)
01413     {
01414       if (!pcl_isfinite (cloud.points (i, j)))
01415       {
01416         cloud.is_dense = false;
01417         break;
01418       }
01419     }
01420   }
01421 
01422   return (0);
01423 }
01424 
01426 int
01427 pcl::PCDReader::read (const std::string &file_name, sensor_msgs::PointCloud2 &cloud, const int offset)
01428 {
01429   int pcd_version;
01430   Eigen::Vector4f origin;
01431   Eigen::Quaternionf orientation;
01432   // Load the data
01433   int res = read (file_name, cloud, origin, orientation, pcd_version, offset);
01434 
01435   if (res < 0)
01436     return (res);
01437 
01438   return (0);
01439 }
01440 
01442 std::string
01443 pcl::PCDWriter::generateHeaderASCII (const sensor_msgs::PointCloud2 &cloud, 
01444                                      const Eigen::Vector4f &origin, const Eigen::Quaternionf &orientation)
01445 {
01446   std::ostringstream oss;
01447   oss.imbue (std::locale::classic ());
01448 
01449   oss << "# .PCD v0.7 - Point Cloud Data file format"
01450          "\nVERSION 0.7"
01451          "\nFIELDS ";
01452 
01453   std::ostringstream stream;
01454   stream.imbue (std::locale::classic ());
01455   std::string result;
01456 
01457   for (size_t d = 0; d < cloud.fields.size () - 1; ++d)
01458   {
01459     // Ignore invalid padded dimensions that are inherited from binary data
01460     if (cloud.fields[d].name != "_")
01461       result += cloud.fields[d].name + " ";
01462   }
01463   // Ignore invalid padded dimensions that are inherited from binary data
01464   if (cloud.fields[cloud.fields.size () - 1].name != "_")
01465     result += cloud.fields[cloud.fields.size () - 1].name;
01466 
01467   // Remove trailing spaces
01468   boost::trim (result);
01469   oss << result << "\nSIZE ";
01470 
01471   stream.str ("");
01472   // Write the SIZE of each field
01473   for (size_t d = 0; d < cloud.fields.size () - 1; ++d)
01474   {
01475     // Ignore invalid padded dimensions that are inherited from binary data
01476     if (cloud.fields[d].name != "_")
01477       stream << pcl::getFieldSize (cloud.fields[d].datatype) << " ";
01478   }
01479   // Ignore invalid padded dimensions that are inherited from binary data
01480   if (cloud.fields[cloud.fields.size () - 1].name != "_")
01481     stream << pcl::getFieldSize (cloud.fields[cloud.fields.size () - 1].datatype);
01482 
01483   // Remove trailing spaces
01484   result = stream.str ();
01485   boost::trim (result);
01486   oss << result << "\nTYPE ";
01487 
01488   stream.str ("");
01489   // Write the TYPE of each field
01490   for (size_t d = 0; d < cloud.fields.size () - 1; ++d)
01491   {
01492     // Ignore invalid padded dimensions that are inherited from binary data
01493     if (cloud.fields[d].name != "_")
01494       stream << pcl::getFieldType (cloud.fields[d].datatype) << " ";
01495   }
01496   // Ignore invalid padded dimensions that are inherited from binary data
01497   if (cloud.fields[cloud.fields.size () - 1].name != "_")
01498     stream << pcl::getFieldType (cloud.fields[cloud.fields.size () - 1].datatype);
01499 
01500   // Remove trailing spaces
01501   result = stream.str ();
01502   boost::trim (result);
01503   oss << result << "\nCOUNT ";
01504   
01505   stream.str ("");
01506   // Write the TYPE of each field
01507   for (size_t d = 0; d < cloud.fields.size () - 1; ++d)
01508   {
01509     // Ignore invalid padded dimensions that are inherited from binary data
01510     if (cloud.fields[d].name == "_")
01511       continue;
01512     int count = abs (static_cast<int> (cloud.fields[d].count));
01513     if (count == 0) 
01514       count = 1;          // we simply cannot tolerate 0 counts (coming from older converter code)
01515   
01516     stream << count << " ";
01517   }
01518   // Ignore invalid padded dimensions that are inherited from binary data
01519   if (cloud.fields[cloud.fields.size () - 1].name != "_")
01520   {
01521     int count = abs (static_cast<int> (cloud.fields[cloud.fields.size () - 1].count));
01522     if (count == 0)
01523       count = 1;
01524 
01525     stream << count;
01526   }
01527 
01528   // Remove trailing spaces
01529   result = stream.str ();
01530   boost::trim (result);
01531   oss << result << "\nWIDTH " << cloud.width << "\nHEIGHT " << cloud.height << "\n";
01532 
01533   oss << "VIEWPOINT " << origin[0] << " " << origin[1] << " " << origin[2] << " " << orientation.w () << " " << 
01534                          orientation.x () << " " << orientation.y () << " " << orientation.z () << "\n";
01535   
01536   oss << "POINTS " << cloud.width * cloud.height << "\n";
01537 
01538   return (oss.str ());
01539 }
01540 
01542 std::string
01543 pcl::PCDWriter::generateHeaderBinary (const sensor_msgs::PointCloud2 &cloud, 
01544                                       const Eigen::Vector4f &origin, const Eigen::Quaternionf &orientation)
01545 {
01546   std::ostringstream oss;
01547   oss.imbue (std::locale::classic ());
01548 
01549   oss << "# .PCD v0.7 - Point Cloud Data file format"
01550          "\nVERSION 0.7"
01551          "\nFIELDS";
01552 
01553   // Compute the total size of the fields
01554   unsigned int fsize = 0;
01555   for (size_t i = 0; i < cloud.fields.size (); ++i)
01556     fsize += cloud.fields[i].count * getFieldSize (cloud.fields[i].datatype);
01557  
01558   // The size of the fields cannot be larger than point_step
01559   if (fsize > cloud.point_step)
01560   {
01561     PCL_ERROR ("[pcl::PCDWriter::generateHeaderBinary] The size of the fields (%d) is larger than point_step (%d)! Something is wrong here...\n", fsize, cloud.point_step);
01562     return ("");
01563   }
01564 
01565   std::stringstream field_names, field_types, field_sizes, field_counts;
01566   // Check if the size of the fields is smaller than the size of the point step
01567   unsigned int toffset = 0;
01568   for (size_t i = 0; i < cloud.fields.size (); ++i)
01569   {
01570     // If field offsets do not match, then we need to create fake fields
01571     if (toffset != cloud.fields[i].offset)
01572     {
01573       // If we're at the last "valid" field
01574       int fake_offset = (i == 0) ? 
01575         // Use the current_field offset
01576         (cloud.fields[i].offset)
01577         :
01578         // Else, do cur_field.offset - prev_field.offset + sizeof (prev_field)
01579         (cloud.fields[i].offset - 
01580         (cloud.fields[i-1].offset + 
01581          cloud.fields[i-1].count * getFieldSize (cloud.fields[i].datatype)));
01582       
01583       toffset += fake_offset;
01584 
01585       field_names << " _";  // By convention, _ is an invalid field name
01586       field_sizes << " 1";  // Make size = 1
01587       field_types << " U";  // Field type = unsigned byte (uint8)
01588       field_counts << " " << fake_offset;
01589     }
01590 
01591     // Add the regular dimension
01592     toffset += cloud.fields[i].count * getFieldSize (cloud.fields[i].datatype);
01593     field_names << " " << cloud.fields[i].name;
01594     field_sizes << " " << pcl::getFieldSize (cloud.fields[i].datatype);
01595     field_types << " " << pcl::getFieldType (cloud.fields[i].datatype);
01596     int count = abs (static_cast<int> (cloud.fields[i].count));
01597     if (count == 0) count = 1;  // check for 0 counts (coming from older converter code)
01598     field_counts << " " << count;
01599   }
01600   // Check extra padding
01601   if (toffset < cloud.point_step)
01602   {
01603     field_names << " _";  // By convention, _ is an invalid field name
01604     field_sizes << " 1";  // Make size = 1
01605     field_types << " U";  // Field type = unsigned byte (uint8)
01606     field_counts << " " << (cloud.point_step - toffset);
01607   }
01608   oss << field_names.str ();
01609   oss << "\nSIZE" << field_sizes.str () 
01610       << "\nTYPE" << field_types.str () 
01611       << "\nCOUNT" << field_counts.str ();
01612   oss << "\nWIDTH " << cloud.width << "\nHEIGHT " << cloud.height << "\n";
01613 
01614   oss << "VIEWPOINT " << origin[0] << " " << origin[1] << " " << origin[2] << " " << orientation.w () << " " << 
01615                          orientation.x () << " " << orientation.y () << " " << orientation.z () << "\n";
01616   
01617   oss << "POINTS " << cloud.width * cloud.height << "\n";
01618 
01619   return (oss.str ());
01620 }
01621 
01623 std::string
01624 pcl::PCDWriter::generateHeaderBinaryCompressed (const sensor_msgs::PointCloud2 &cloud, 
01625                                                 const Eigen::Vector4f &origin, 
01626                                                 const Eigen::Quaternionf &orientation)
01627 {
01628   std::ostringstream oss;
01629   oss.imbue (std::locale::classic ());
01630 
01631   oss << "# .PCD v0.7 - Point Cloud Data file format"
01632          "\nVERSION 0.7"
01633          "\nFIELDS";
01634 
01635   // Compute the total size of the fields
01636   unsigned int fsize = 0;
01637   for (size_t i = 0; i < cloud.fields.size (); ++i)
01638     fsize += cloud.fields[i].count * getFieldSize (cloud.fields[i].datatype);
01639  
01640   // The size of the fields cannot be larger than point_step
01641   if (fsize > cloud.point_step)
01642   {
01643     PCL_ERROR ("[pcl::PCDWriter::generateHeaderBinaryCompressed] The size of the fields (%d) is larger than point_step (%d)! Something is wrong here...\n", fsize, cloud.point_step);
01644     return ("");
01645   }
01646 
01647   std::stringstream field_names, field_types, field_sizes, field_counts;
01648   // Check if the size of the fields is smaller than the size of the point step
01649   for (size_t i = 0; i < cloud.fields.size (); ++i)
01650   {
01651     if (cloud.fields[i].name == "_")
01652       continue;
01653     // Add the regular dimension
01654     field_names << " " << cloud.fields[i].name;
01655     field_sizes << " " << pcl::getFieldSize (cloud.fields[i].datatype);
01656     field_types << " " << pcl::getFieldType (cloud.fields[i].datatype);
01657     int count = abs (static_cast<int> (cloud.fields[i].count));
01658     if (count == 0) count = 1;  // check for 0 counts (coming from older converter code)
01659     field_counts << " " << count;
01660   }
01661   oss << field_names.str ();
01662   oss << "\nSIZE" << field_sizes.str () 
01663       << "\nTYPE" << field_types.str () 
01664       << "\nCOUNT" << field_counts.str ();
01665   oss << "\nWIDTH " << cloud.width << "\nHEIGHT " << cloud.height << "\n";
01666 
01667   oss << "VIEWPOINT " << origin[0] << " " << origin[1] << " " << origin[2] << " " << orientation.w () << " " << 
01668                          orientation.x () << " " << orientation.y () << " " << orientation.z () << "\n";
01669   
01670   oss << "POINTS " << cloud.width * cloud.height << "\n";
01671 
01672   return (oss.str ());
01673 }
01674 
01676 int
01677 pcl::PCDWriter::writeASCII (const std::string &file_name, const sensor_msgs::PointCloud2 &cloud, 
01678                             const Eigen::Vector4f &origin, const Eigen::Quaternionf &orientation,
01679                             const int precision)
01680 {
01681   if (cloud.data.empty ())
01682   {
01683     PCL_ERROR ("[pcl::PCDWriter::writeASCII] Input point cloud has no data!\n");
01684     return (-1);
01685   }
01686 
01687   std::ofstream fs;
01688   fs.precision (precision);
01689   fs.imbue (std::locale::classic ());
01690   fs.open (file_name.c_str ());      // Open file
01691   if (!fs.is_open () || fs.fail ())
01692   {
01693     PCL_ERROR("[pcl::PCDWriter::writeASCII] Could not open file '%s' for writing! Error : %s\n", file_name.c_str (), strerror(errno)); 
01694     return (-1);
01695   }
01696 
01697   int nr_points  = cloud.width * cloud.height;
01698   int point_size = static_cast<int> (cloud.data.size () / nr_points);
01699 
01700   // Write the header information
01701   fs << generateHeaderASCII (cloud, origin, orientation) << "DATA ascii\n";
01702 
01703   std::ostringstream stream;
01704   stream.precision (precision);
01705   stream.imbue (std::locale::classic ());
01706 
01707   // Iterate through the points
01708   for (int i = 0; i < nr_points; ++i)
01709   {
01710     for (unsigned int d = 0; d < static_cast<unsigned int> (cloud.fields.size ()); ++d)
01711     {
01712       // Ignore invalid padded dimensions that are inherited from binary data
01713       if (cloud.fields[d].name == "_")
01714         continue;
01715 
01716       int count = cloud.fields[d].count;
01717       if (count == 0) 
01718         count = 1;          // we simply cannot tolerate 0 counts (coming from older converter code)
01719 
01720       for (int c = 0; c < count; ++c)
01721       {
01722         switch (cloud.fields[d].datatype)
01723         {
01724           case sensor_msgs::PointField::INT8:
01725           {
01726             copyValueString<pcl::traits::asType<sensor_msgs::PointField::INT8>::type>(cloud, i, point_size, d, c, stream);
01727             break;
01728           }
01729           case sensor_msgs::PointField::UINT8:
01730           {
01731             copyValueString<pcl::traits::asType<sensor_msgs::PointField::UINT8>::type>(cloud, i, point_size, d, c, stream);
01732             break;
01733           }
01734           case sensor_msgs::PointField::INT16:
01735           {
01736             copyValueString<pcl::traits::asType<sensor_msgs::PointField::INT16>::type>(cloud, i, point_size, d, c, stream);
01737             break;
01738           }
01739           case sensor_msgs::PointField::UINT16:
01740           {
01741             copyValueString<pcl::traits::asType<sensor_msgs::PointField::UINT16>::type>(cloud, i, point_size, d, c, stream);
01742             break;
01743           }
01744           case sensor_msgs::PointField::INT32:
01745           {
01746             copyValueString<pcl::traits::asType<sensor_msgs::PointField::INT32>::type>(cloud, i, point_size, d, c, stream);
01747             break;
01748           }
01749           case sensor_msgs::PointField::UINT32:
01750           {
01751             copyValueString<pcl::traits::asType<sensor_msgs::PointField::UINT32>::type>(cloud, i, point_size, d, c, stream);
01752             break;
01753           }
01754           case sensor_msgs::PointField::FLOAT32:
01755           {
01756             copyValueString<pcl::traits::asType<sensor_msgs::PointField::FLOAT32>::type>(cloud, i, point_size, d, c, stream);
01757             break;
01758           }
01759           case sensor_msgs::PointField::FLOAT64:
01760           {
01761             copyValueString<pcl::traits::asType<sensor_msgs::PointField::FLOAT64>::type>(cloud, i, point_size, d, c, stream);
01762             break;
01763           }
01764           default:
01765             PCL_WARN ("[pcl::PCDWriter::writeASCII] Incorrect field data type specified (%d)!\n", cloud.fields[d].datatype);
01766             break;
01767         }
01768 
01769         if (d < cloud.fields.size () - 1 || c < static_cast<int> (cloud.fields[d].count) - 1)
01770           stream << " ";
01771       }
01772     }
01773     // Copy the stream, trim it, and write it to disk
01774     std::string result = stream.str ();
01775     boost::trim (result);
01776     stream.str ("");
01777     fs << result << "\n";
01778   }
01779   fs.close ();              // Close file
01780   return (0);
01781 }
01782 
01784 int
01785 pcl::PCDWriter::writeBinary (const std::string &file_name, const sensor_msgs::PointCloud2 &cloud,
01786                              const Eigen::Vector4f &origin, const Eigen::Quaternionf &orientation)
01787 {
01788   if (cloud.data.empty ())
01789   {
01790     PCL_ERROR ("[pcl::PCDWriter::writeBinary] Input point cloud has no data!\n");
01791     return (-1);
01792   }
01793   std::streamoff data_idx = 0;
01794   std::ostringstream oss;
01795   oss.imbue (std::locale::classic ());
01796 
01797   oss << generateHeaderBinary (cloud, origin, orientation) << "DATA binary\n";
01798   oss.flush();
01799   data_idx = static_cast<unsigned int> (oss.tellp ());
01800 
01801 #if _WIN32
01802   HANDLE h_native_file = CreateFile (file_name.c_str (), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
01803   if(h_native_file == INVALID_HANDLE_VALUE)
01804   {
01805     PCL_ERROR ("[pcl::PCDWriter::writeBinary] Error during CreateFile (%s)!\n", file_name.c_str());
01806     return (-1);
01807   }
01808 #else
01809   int fd = pcl_open (file_name.c_str (), O_RDWR | O_CREAT | O_TRUNC, static_cast<mode_t> (0600));
01810   if (fd < 0)
01811   {
01812     PCL_ERROR ("[pcl::PCDWriter::writeBinary] Error during open (%s)!\n", file_name.c_str());
01813     return (-1);
01814   }
01815   // Stretch the file size to the size of the data
01816   int result = static_cast<int> (pcl_lseek (fd, getpagesize () + cloud.data.size () - 1, SEEK_SET));
01817   if (result < 0)
01818   {
01819     pcl_close (fd);
01820     PCL_ERROR ("[pcl::PCDWriter::writeBinary] Error during lseek ()!\n");
01821     return (-1);
01822   }
01823   // Write a bogus entry so that the new file size comes in effect
01824   result = static_cast<int> (::write (fd, "", 1));
01825   if (result != 1)
01826   {
01827     pcl_close (fd);
01828     PCL_ERROR ("[pcl::PCDWriter::writeBinary] Error during write ()!\n");
01829     return (-1);
01830   }
01831 #endif
01832   // Prepare the map
01833 #ifdef _WIN32
01834   HANDLE fm = CreateFileMapping (h_native_file, NULL, PAGE_READWRITE, 0, (DWORD) (data_idx + cloud.data.size ()), NULL);
01835   char *map = static_cast<char*>(MapViewOfFile (fm, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, data_idx + cloud.data.size ()));
01836   CloseHandle (fm);
01837 
01838 #else
01839   char *map = static_cast<char*> (mmap (0, static_cast<size_t> (data_idx + cloud.data.size ()), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
01840   if (map == reinterpret_cast<char*> (-1))    // MAP_FAILED
01841   {
01842     pcl_close (fd);
01843     PCL_ERROR ("[pcl::PCDWriter::writeBinary] Error during mmap ()!\n");
01844     return (-1);
01845   }
01846 #endif
01847 
01848   // copy header
01849   memcpy (&map[0], oss.str().c_str (), static_cast<size_t> (data_idx));
01850 
01851   // Copy the data
01852   memcpy (&map[0] + data_idx, &cloud.data[0], cloud.data.size ());
01853 
01854 #if !_WIN32
01855   // If the user set the synchronization flag on, call msync
01856   if (map_synchronization_)
01857     msync (map, static_cast<size_t> (data_idx + cloud.data.size ()), MS_SYNC);
01858 #endif
01859 
01860   // Unmap the pages of memory
01861 #if _WIN32
01862     UnmapViewOfFile (map);
01863 #else
01864   if (munmap (map, static_cast<size_t> (data_idx + cloud.data.size ())) == -1)
01865   {
01866     pcl_close (fd);
01867     PCL_ERROR ("[pcl::PCDWriter::writeBinary] Error during munmap ()!\n");
01868     return (-1);
01869   }
01870 #endif
01871   // Close file
01872 #if _WIN32
01873   CloseHandle(h_native_file);
01874 #else
01875   pcl_close (fd);
01876 #endif
01877   return (0);
01878 }
01879 
01881 int
01882 pcl::PCDWriter::writeBinaryCompressed (const std::string &file_name, const sensor_msgs::PointCloud2 &cloud,
01883                                        const Eigen::Vector4f &origin, const Eigen::Quaternionf &orientation)
01884 {
01885   if (cloud.data.empty ())
01886   {
01887     PCL_ERROR ("[pcl::PCDWriter::writeBinaryCompressed] Input point cloud has no data!\n");
01888     return (-1);
01889   }
01890   std::streamoff data_idx = 0;
01891   std::ostringstream oss;
01892   oss.imbue (std::locale::classic ());
01893 
01894   oss << generateHeaderBinaryCompressed (cloud, origin, orientation) << "DATA binary_compressed\n";
01895   oss.flush ();
01896   data_idx = oss.tellp ();
01897 
01898 #if _WIN32
01899   HANDLE h_native_file = CreateFile (file_name.c_str (), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
01900   if(h_native_file == INVALID_HANDLE_VALUE)
01901   {
01902     PCL_ERROR ("[pcl::PCDWriter::writeBinaryCompressed] Error during CreateFile (%s)!\n", file_name.c_str());
01903     return (-1);
01904   }
01905 #else
01906   int fd = pcl_open (file_name.c_str (), O_RDWR | O_CREAT | O_TRUNC, static_cast<mode_t> (0600));
01907   if (fd < 0)
01908   {
01909     PCL_ERROR ("[pcl::PCDWriter::writeBinaryCompressed] Error during open (%s)!\n", file_name.c_str());
01910     return (-1);
01911   }
01912 #endif
01913 
01914   size_t fsize = 0;
01915   size_t data_size = 0;
01916   size_t nri = 0;
01917   std::vector<sensor_msgs::PointField> fields (cloud.fields.size ());
01918   std::vector<int> fields_sizes (cloud.fields.size ());
01919   // Compute the total size of the fields
01920   for (size_t i = 0; i < cloud.fields.size (); ++i)
01921   {
01922     if (cloud.fields[i].name == "_")
01923       continue;
01924     
01925     fields_sizes[nri] = cloud.fields[i].count * pcl::getFieldSize (cloud.fields[i].datatype);
01926     fsize += fields_sizes[nri];
01927     fields[nri] = cloud.fields[i];
01928     ++nri;
01929   }
01930   fields_sizes.resize (nri);
01931   fields.resize (nri);
01932  
01933   // Compute the size of data
01934   data_size = cloud.width * cloud.height * fsize;
01935 
01937   // Empty array holding only the valid data
01938   // data_size = nr_points * point_size 
01939   //           = nr_points * (sizeof_field_1 + sizeof_field_2 + ... sizeof_field_n)
01940   //           = sizeof_field_1 * nr_points + sizeof_field_2 * nr_points + ... sizeof_field_n * nr_points
01941   char *only_valid_data = static_cast<char*> (malloc (data_size));
01942 
01943   // Convert the XYZRGBXYZRGB structure to XXYYZZRGBRGB to aid compression. For
01944   // this, we need a vector of fields.size () (4 in this case), which points to
01945   // each individual plane:
01946   //   pters[0] = &only_valid_data[offset_of_plane_x];
01947   //   pters[1] = &only_valid_data[offset_of_plane_y];
01948   //   pters[2] = &only_valid_data[offset_of_plane_z];
01949   //   pters[3] = &only_valid_data[offset_of_plane_RGB];
01950   //
01951   std::vector<char*> pters (fields.size ());
01952   int toff = 0;
01953   for (size_t i = 0; i < pters.size (); ++i)
01954   {
01955     pters[i] = &only_valid_data[toff];
01956     toff += fields_sizes[i] * cloud.width * cloud.height;
01957   }
01958   
01959   // Go over all the points, and copy the data in the appropriate places
01960   for (size_t i = 0; i < cloud.width * cloud.height; ++i)
01961   {
01962     for (size_t j = 0; j < pters.size (); ++j)
01963     {
01964       memcpy (pters[j], &cloud.data[i * cloud.point_step + fields[j].offset], fields_sizes[j]);
01965       // Increment the pointer
01966       pters[j] += fields_sizes[j];
01967     }
01968   }
01969 
01970   char* temp_buf = static_cast<char*> (malloc (static_cast<size_t> (static_cast<float> (data_size) * 1.5f + 8.0f)));
01971   // Compress the valid data
01972   unsigned int compressed_size = pcl::lzfCompress (only_valid_data, 
01973                                                    static_cast<unsigned int> (data_size), 
01974                                                    &temp_buf[8], 
01975                                                    static_cast<unsigned int> (static_cast<float> (data_size) * 1.5f));
01976   unsigned int compressed_final_size = 0;
01977   // Was the compression successful?
01978   if (compressed_size)
01979   {
01980     char *header = &temp_buf[0];
01981     memcpy (&header[0], &compressed_size, sizeof (unsigned int));
01982     memcpy (&header[4], &data_size, sizeof (unsigned int));
01983     data_size = compressed_size + 8;
01984     compressed_final_size = static_cast<unsigned int> (data_size + data_idx);
01985   }
01986   else
01987   {
01988 #if !_WIN32
01989     pcl_close (fd);
01990 #endif
01991     throw pcl::IOException ("[pcl::PCDWriter::writeBinaryCompressed] Error during compression!");
01992     return (-1);
01993   }
01994 
01995 #if !_WIN32
01996   // Stretch the file size to the size of the data
01997   int result = static_cast<int> (pcl_lseek (fd, getpagesize () + data_size - 1, SEEK_SET));
01998   if (result < 0)
01999   {
02000     pcl_close (fd);
02001     PCL_ERROR ("[pcl::PCDWriter::writeBinaryCompressed] Error during lseek ()!\n");
02002     return (-1);
02003   }
02004   // Write a bogus entry so that the new file size comes in effect
02005   result = static_cast<int> (::write (fd, "", 1));
02006   if (result != 1)
02007   {
02008     pcl_close (fd);
02009     PCL_ERROR ("[pcl::PCDWriter::writeBinaryCompressed] Error during write ()!\n");
02010     return (-1);
02011   }
02012 #endif
02013 
02014   // Prepare the map
02015 #ifdef _WIN32
02016   HANDLE fm = CreateFileMapping (h_native_file, NULL, PAGE_READWRITE, 0, compressed_final_size, NULL);
02017   char *map = static_cast<char*> (MapViewOfFile (fm, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, compressed_final_size));
02018   CloseHandle (fm);
02019 
02020 #else
02021   char *map = static_cast<char*> (mmap (0, compressed_final_size, PROT_WRITE, MAP_SHARED, fd, 0));
02022   if (map == reinterpret_cast<char*> (-1))    // MAP_FAILED
02023   {
02024     pcl_close (fd);
02025     PCL_ERROR ("[pcl::PCDWriter::writeBinaryCompressed] Error during mmap ()!\n");
02026     return (-1);
02027   }
02028 #endif
02029 
02030   // copy header
02031   memcpy (&map[0], oss.str ().c_str (), static_cast<size_t> (data_idx));
02032   // Copy the compressed data
02033   memcpy (&map[data_idx], temp_buf, data_size);
02034 
02035 #if !_WIN32
02036   // If the user set the synchronization flag on, call msync
02037   if (map_synchronization_)
02038     msync (map, compressed_final_size, MS_SYNC);
02039 #endif
02040 
02041   // Unmap the pages of memory
02042 #if _WIN32
02043     UnmapViewOfFile (map);
02044 #else
02045   if (munmap (map, (compressed_final_size)) == -1)
02046   {
02047     pcl_close (fd);
02048     PCL_ERROR ("[pcl::PCDWriter::writeBinaryCompressed] Error during munmap ()!\n");
02049     return (-1);
02050   }
02051 #endif
02052   // Close file
02053 #if _WIN32
02054   CloseHandle (h_native_file);
02055 #else
02056   pcl_close (fd);
02057 #endif
02058 
02059   free (only_valid_data);
02060   free (temp_buf);
02061   return (0);
02062 }
02063 
02065 std::string
02066 pcl::PCDWriter::generateHeaderEigen (const pcl::PointCloud<Eigen::MatrixXf> &cloud, 
02067                                      const int nr_points)
02068 {
02069   std::ostringstream oss;
02070   oss.imbue (std::locale::classic ());
02071 
02072   oss << "# .PCD v0.7 - Point Cloud Data file format"
02073          "\nVERSION 0.7"
02074          "\nFIELDS";
02075 
02076   std::stringstream field_names, field_types, field_sizes, field_counts;
02077   // Copy the channels into a vector and sort them according to the channel offset
02078   std::vector<pair_channel_properties> vec (cloud.channels.begin (), cloud.channels.end ());
02079   std::sort (vec.begin (), vec.end (), ChannelPropertiesComparator ());
02080 //  for (std::map<std::string, pcl::ChannelProperties>::const_iterator it = cloud.channels.begin (); it != cloud.channels.end (); ++it)
02081   for (std::vector<pair_channel_properties>::iterator it = vec.begin (); it != vec.end (); ++it)
02082   {
02083     // Add the regular dimension
02084     field_names << " " << it->second.name;
02085     field_sizes << " " << pcl::getFieldSize (it->second.datatype);
02086     field_types << " " << pcl::getFieldType (it->second.datatype);
02087     int count = abs (static_cast<int> (it->second.count));
02088     if (count == 0) count = 1;  // check for 0 counts (coming from older converter code)
02089     field_counts << " " << count;
02090   }
02091   oss << field_names.str ();
02092   oss << "\nSIZE" << field_sizes.str () 
02093       << "\nTYPE" << field_types.str () 
02094       << "\nCOUNT" << field_counts.str ();
02095   // If the user passes in a number of points value, use that instead
02096   if (nr_points != std::numeric_limits<int>::max ())
02097     oss << "\nWIDTH " << nr_points << "\nHEIGHT " << 1 << "\n";
02098   else
02099     oss << "\nWIDTH " << cloud.width << "\nHEIGHT " << cloud.height << "\n";
02100 
02101   oss << "VIEWPOINT " << cloud.properties.sensor_origin[0] << " " << 
02102                          cloud.properties.sensor_origin[1] << " " << 
02103                          cloud.properties.sensor_origin[2] << " " << 
02104                          cloud.properties.sensor_orientation.w () << " " << 
02105                          cloud.properties.sensor_orientation.x () << " " << 
02106                          cloud.properties.sensor_orientation.y () << " " << 
02107                          cloud.properties.sensor_orientation.z () << "\n";
02108   
02109   // If the user passes in a number of points value, use that instead
02110   if (nr_points != std::numeric_limits<int>::max ())
02111     oss << "POINTS " << nr_points << "\n";
02112   else
02113     oss << "POINTS " << cloud.points.rows () << "\n";
02114 
02115   return (oss.str ());
02116 }
02117 
02119 int
02120 pcl::PCDWriter::writeASCIIEigen (const std::string &file_name, const pcl::PointCloud<Eigen::MatrixXf> &cloud, 
02121                                  const int precision)
02122 {
02123   if (cloud.empty ())
02124   {
02125     throw pcl::IOException ("[pcl::PCDWriter::writeASCII] Input point cloud has no data!");
02126     return (-1);
02127   }
02128 
02129   if (static_cast<int> (cloud.width * cloud.height) != cloud.points.rows ())
02130   {
02131     throw pcl::IOException ("[pcl::PCDWriter::writeASCII] Number of points different than width * height!");
02132     return (-1);
02133   }
02134 
02135   std::ofstream fs;
02136   fs.open (file_name.c_str ());      // Open file
02137   
02138   if (!fs.is_open () || fs.fail ())
02139   {
02140     throw pcl::IOException ("[pcl::PCDWriter::writeASCII] Could not open file for writing!");
02141     return (-1);
02142   }
02143   
02144   fs.precision (precision);
02145   fs.imbue (std::locale::classic ());
02146 
02147   // Write the header information
02148   fs << generateHeaderEigen (cloud) << "DATA ascii\n";
02149 
02150   std::ostringstream stream;
02151   stream.precision (precision);
02152   stream.imbue (std::locale::classic ());
02153   // Iterate through the points
02154   for (int i = 0; i < cloud.points.rows (); ++i)
02155   {
02156     for (int j = 0; j < cloud.points.cols (); ++j)
02157     {
02158       stream << cloud.points.coeffRef (i, j);
02159       if (j < cloud.points.cols () - 1)
02160         stream << " ";
02161     }
02162     // Copy the stream, trim it, and write it to disk
02163     std::string result = stream.str ();
02164     boost::trim (result);
02165     stream.str ("");
02166     fs << result << "\n";
02167   }
02168   fs.close ();              // Close file
02169   return (0);
02170 }
02171 
02172 
02174 int
02175 pcl::PCDWriter::writeBinaryEigen (const std::string &file_name, 
02176                                   const pcl::PointCloud<Eigen::MatrixXf> &cloud)
02177 {
02178   if (cloud.points.rows () * cloud.points.cols () == 0)
02179   {
02180     throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Input point cloud has no data!");
02181     return (-1);
02182   }
02183   int data_idx = 0;
02184   std::ostringstream oss;
02185   oss << generateHeaderEigen (cloud) << "DATA binary\n";
02186   oss.flush ();
02187   data_idx = static_cast<int> (oss.tellp ());
02188 
02189 #if _WIN32
02190   HANDLE h_native_file = CreateFileA (file_name.c_str (), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
02191   if(h_native_file == INVALID_HANDLE_VALUE)
02192   {
02193     throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Error during CreateFile!");
02194     return (-1);
02195   }
02196 #else
02197   int fd = pcl_open (file_name.c_str (), O_RDWR | O_CREAT | O_TRUNC, static_cast<mode_t> (0600));
02198   if (fd < 0)
02199   {
02200     throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Error during open!");
02201     return (-1);
02202   }
02203 #endif
02204 
02205   size_t data_size = cloud.points.rows () * cloud.points.cols () * sizeof (float);
02206 
02207   // Prepare the map
02208 #if _WIN32
02209   HANDLE fm = CreateFileMappingA (h_native_file, NULL, PAGE_READWRITE, 0, (DWORD) (data_idx + data_size), NULL);
02210   char *map = static_cast<char*> (MapViewOfFile (fm, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, data_idx + data_size));
02211   CloseHandle (fm);
02212 
02213 #else
02214   // Stretch the file size to the size of the data
02215   int result = static_cast<int> (pcl_lseek (fd, getpagesize () + data_size - 1, SEEK_SET));
02216   if (result < 0)
02217   {
02218     pcl_close (fd);
02219     throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Error during lseek ()!");
02220     return (-1);
02221   }
02222   // Write a bogus entry so that the new file size comes in effect
02223   result = static_cast<int>(::write (fd, "", 1));
02224   if (result != 1)
02225   {
02226     pcl_close (fd);
02227     throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Error during write ()!");
02228     return (-1);
02229   }
02230 
02231   char *map = static_cast<char*> (mmap (0, data_idx + data_size, PROT_WRITE, MAP_SHARED, fd, 0));
02232   if (map == reinterpret_cast<char*> (-1))    // MAP_FAILED
02233   {
02234     pcl_close (fd);
02235     throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Error during mmap ()!");
02236     return (-1);
02237   }
02238 #endif
02239 
02240   // Copy the header
02241   memcpy (&map[0], oss.str ().c_str (), data_idx);
02242 
02243   Eigen::MatrixXf pts;
02244   // Transpose data if matrix is column major: we need its memory representation to be different
02245   if (!(cloud.points.Flags & Eigen::RowMajorBit))
02246     pts = cloud.points.transpose ();
02247   else
02248     pts = cloud.points;
02249   // Copy the data (_always_ stored as ROW major in the file!)
02250   memcpy (&map[0] + data_idx, reinterpret_cast<const char*> (pts.data ()), data_size);
02251 
02252   // If the user set the synchronization flag on, call msync
02253 #if !_WIN32
02254   if (map_synchronization_)
02255     msync (map, data_idx + data_size, MS_SYNC);
02256 #endif
02257 
02258   // Unmap the pages of memory
02259 #if _WIN32
02260     UnmapViewOfFile (map);
02261 #else
02262   if (munmap (map, (data_idx + data_size)) == -1)
02263   {
02264     pcl_close (fd);
02265     throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Error during munmap ()!");
02266     return (-1);
02267   }
02268 #endif
02269   // Close file
02270 #if _WIN32
02271   CloseHandle (h_native_file);
02272 #else
02273   pcl_close (fd);
02274 #endif
02275   return (0);
02276 }
02277 
02279 int
02280 pcl::PCDWriter::writeBinaryCompressedEigen (
02281     const std::string &file_name, 
02282     const pcl::PointCloud<Eigen::MatrixXf> &cloud)
02283 {
02284   if (cloud.points.rows () * cloud.points.cols () == 0)
02285   {
02286     throw pcl::IOException ("[pcl::PCDWriter::writeBinaryCompressed] Input point cloud has no data!");
02287     return (-1);
02288   }
02289   std::ostringstream::pos_type data_idx = 0;
02290   std::ostringstream oss;
02291   oss << generateHeaderEigen (cloud) << "DATA binary_compressed\n";
02292   oss.flush ();
02293   data_idx = oss.tellp ();
02294 
02295 #if _WIN32
02296   HANDLE h_native_file = CreateFileA (file_name.c_str (), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
02297   if(h_native_file == INVALID_HANDLE_VALUE)
02298   {
02299     throw pcl::IOException ("[pcl::PCDWriter::writeBinaryCompressed] Error during CreateFile!");
02300     return (-1);
02301   }
02302 #else
02303   int fd = pcl_open (file_name.c_str (), O_RDWR | O_CREAT | O_TRUNC, static_cast<mode_t> (0600));
02304   if (fd < 0)
02305   {
02306     throw pcl::IOException ("[pcl::PCDWriter::writeBinaryCompressed] Error during open!");
02307     return (-1);
02308   }
02309 #endif
02310 
02311   Eigen::MatrixXf pts;
02312   // Check if the matrix is row or column major
02313   if (cloud.points.Flags & Eigen::RowMajorBit)
02314     // Transpose data if matrix is column major
02315     pts = cloud.points.transpose ();
02316   else
02317     pts = cloud.points;
02318 
02319   // Compute the size of data
02320   size_t data_size = cloud.points.rows () * cloud.points.cols () * sizeof (float);
02321   char* temp_buf = static_cast<char*> (malloc (static_cast<size_t> (static_cast<float> (data_size) * 1.5f + 8.0f)));
02322   // Compress the valid data
02323   unsigned int compressed_size = pcl::lzfCompress (reinterpret_cast<char*> (pts.data ()), 
02324                                                    static_cast<unsigned int> (data_size), 
02325                                                    &temp_buf[8], 
02326                                                    static_cast<unsigned int> (static_cast<float> (data_size) * 1.5f));
02327   unsigned int compressed_final_size = 0;
02328   // Was the compression successful?
02329   if (compressed_size)
02330   {
02331     char *header = &temp_buf[0];
02332     memcpy (&header[0], &compressed_size, sizeof (unsigned int));
02333     memcpy (&header[4], &data_size, sizeof (unsigned int));
02334     data_size = compressed_size + 8;
02335     compressed_final_size = static_cast<unsigned int> (data_size + data_idx);
02336   }
02337   else
02338   {
02339 #if !_WIN32
02340     pcl_close (fd);
02341 #endif
02342     throw pcl::IOException ("[pcl::PCDWriter::writeBinaryCompressed] Error during compression!");
02343     return (-1);
02344   }
02345 
02346 #if !_WIN32
02347   // Stretch the file size to the size of the data
02348   int result = static_cast<int> (pcl_lseek (fd, getpagesize () + data_size - 1, SEEK_SET));
02349   if (result < 0)
02350   {
02351     pcl_close (fd);
02352     throw pcl::IOException ("[pcl::PCDWriter::writeBinaryCompressed] Error during lseek ()!");
02353     return (-1);
02354   }
02355   // Write a bogus entry so that the new file size comes in effect
02356   result = static_cast<int> (::write (fd, "", 1));
02357   if (result != 1)
02358   {
02359     pcl_close (fd);
02360     throw pcl::IOException ("[pcl::PCDWriter::writeBinaryCompressed] Error during write ()!");
02361     return (-1);
02362   }
02363 #endif
02364 
02365   // Prepare the map
02366 #if _WIN32
02367   HANDLE fm = CreateFileMapping (h_native_file, NULL, PAGE_READWRITE, 0, compressed_final_size, NULL);
02368   char *map = static_cast<char*> (MapViewOfFile (fm, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, compressed_final_size));
02369   CloseHandle (fm);
02370 
02371 #else
02372   char *map = static_cast<char*> (mmap (0, compressed_final_size, PROT_WRITE, MAP_SHARED, fd, 0));
02373   if (map == reinterpret_cast<char*> (-1))    // MAP_FAILED
02374   {
02375     pcl_close (fd);
02376     throw pcl::IOException ("[pcl::PCDWriter::writeBinaryCompressed] Error during mmap ()!");
02377     return (-1);
02378   }
02379 #endif
02380 
02381   // Copy the header
02382   memcpy (&map[0], oss.str ().c_str (), static_cast<size_t> (data_idx));
02383   // Copy the compressed data
02384   memcpy (&map[data_idx], temp_buf, static_cast<size_t> (data_size));
02385 
02386 #if !_WIN32
02387   // If the user set the synchronization flag on, call msync
02388   if (map_synchronization_)
02389     msync (map, compressed_final_size, MS_SYNC);
02390 #endif
02391 
02392   // Unmap the pages of memory
02393 #if _WIN32
02394     UnmapViewOfFile (map);
02395 #else
02396   if (munmap (map, (compressed_final_size)) == -1)
02397   {
02398     pcl_close (fd);
02399     throw pcl::IOException ("[pcl::PCDWriter::writeBinaryCompressed] Error during munmap ()!");
02400     return (-1);
02401   }
02402 #endif
02403   // Close file
02404 #if _WIN32
02405   CloseHandle (h_native_file);
02406 #else
02407   pcl_close (fd);
02408 #endif
02409 
02410   free (temp_buf);
02411   return (0);
02412 }
02413 
02414 


pcl
Author(s): Open Perception
autogenerated on Mon Oct 6 2014 03:16:24