ply_io.cpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2009, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of Willow Garage, Inc. nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *
00034  * $Id: ply_io.cpp 6122 2012-07-03 18:59:43Z aichim $
00035  *
00036  */
00037 
00038 #include <fstream>
00039 #include <fcntl.h>
00040 #include <string>
00041 #include <map>
00042 #include <stdlib.h>
00043 #include <pcl/point_types.h>
00044 #include <pcl/common/io.h>
00045 #include <pcl/io/ply_io.h>
00046 #include <sstream>
00047 #include <boost/algorithm/string.hpp>
00048 
00049 boost::tuple<boost::function<void ()>, boost::function<void ()> >
00050 pcl::PLYReader::elementDefinitionCallback (const std::string& element_name, std::size_t count)
00051 {
00052   if (element_name == "vertex")
00053   {
00054     cloud_->data.clear ();
00055     cloud_->fields.clear ();
00056     cloud_->width = static_cast<uint32_t> (count);
00057     cloud_->height = 1;
00058     cloud_->is_dense = false;
00059     cloud_->point_step = 0;
00060     cloud_->row_step = 0;
00061     vertex_count_ = 0;
00062     return (boost::tuple<boost::function<void ()>, boost::function<void ()> > (
00063               boost::bind (&pcl::PLYReader::vertexBeginCallback, this),
00064               boost::bind (&pcl::PLYReader::vertexEndCallback, this)));
00065   }
00066   // else if (element_name == "face")
00067   // {
00068   //   return (boost::tuple<boost::function<void ()>, boost::function<void ()> > (
00069   //             boost::bind (&pcl::PLYReader::faceBegin, this),
00070   //             boost::bind (&pcl::PLYReader::faceEnd, this)));
00071   // }
00072   else if (element_name == "camera")
00073   {
00074     cloud_->is_dense = true;
00075     return (boost::tuple<boost::function<void ()>, boost::function<void ()> > (0, 0));
00076   }
00077   else if (element_name == "range_grid")
00078   {
00079     (*range_grid_).resize (count);
00080     range_count_ = 0;
00081     return (boost::tuple<boost::function<void ()>, boost::function<void ()> > (
00082               boost::bind (&pcl::PLYReader::rangeGridBeginCallback, this),
00083               boost::bind (&pcl::PLYReader::rangeGridEndCallback, this)));
00084   }
00085   else
00086   {
00087     return (boost::tuple<boost::function<void ()>, boost::function<void ()> > (0, 0));
00088   }
00089 }
00090 
00091 bool
00092 pcl::PLYReader::endHeaderCallback ()
00093 {
00094   cloud_->data.resize (cloud_->point_step * cloud_->width * cloud_->height);
00095   return (cloud_->data.size () == cloud_->point_step * cloud_->width * cloud_->height);
00096 }
00097 
00098 void
00099 pcl::PLYReader::appendFloatProperty (const std::string& name, const size_t& size)
00100 {
00101   cloud_->fields.push_back (::sensor_msgs::PointField ());
00102   ::sensor_msgs::PointField &current_field = cloud_->fields.back ();
00103   current_field.name = name;
00104   current_field.offset = cloud_->point_step;
00105   current_field.datatype = ::sensor_msgs::PointField::FLOAT32;
00106   current_field.count = static_cast<uint32_t> (size);
00107   cloud_->point_step += static_cast<uint32_t> (pcl::getFieldSize (::sensor_msgs::PointField::FLOAT32) * size);
00108 }
00109 
00110 namespace pcl
00111 {
00112   template <>
00113   boost::function<void (pcl::io::ply::float32)>
00114   PLYReader::scalarPropertyDefinitionCallback (const std::string& element_name, const std::string& property_name)
00115   {
00116     if (element_name == "vertex")
00117     {
00118       appendFloatProperty (property_name, 1);
00119       return (boost::bind (&pcl::PLYReader::vertexFloatPropertyCallback, this, _1));
00120     }
00121     else if (element_name == "camera")
00122     {
00123       if (property_name == "view_px")
00124       {
00125         return boost::bind (&pcl::PLYReader::originXCallback, this, _1);
00126       }
00127       else if (property_name == "view_py")
00128       {
00129         return boost::bind (&pcl::PLYReader::originYCallback, this, _1);
00130       }
00131       else if (property_name == "view_pz")
00132       {
00133         return boost::bind (&pcl::PLYReader::originZCallback, this, _1);
00134       }
00135       else if (property_name == "x_axisx")
00136       {
00137         return boost::bind (&pcl::PLYReader::orientationXaxisXCallback, this, _1);
00138       }
00139       else if (property_name == "x_axisy")
00140       {
00141         return boost::bind (&pcl::PLYReader::orientationXaxisYCallback, this, _1);
00142       }
00143       else if (property_name == "x_axisz")
00144       {
00145         return boost::bind (&pcl::PLYReader::orientationXaxisZCallback, this, _1);
00146       }
00147       else if (property_name == "y_axisx")
00148       {
00149         return boost::bind (&pcl::PLYReader::orientationYaxisXCallback, this, _1);
00150       }
00151       else if (property_name == "y_axisy")
00152       {
00153         return boost::bind (&pcl::PLYReader::orientationYaxisYCallback, this, _1);
00154       }
00155       else if (property_name == "y_axisz")
00156       {
00157         return boost::bind (&pcl::PLYReader::orientationYaxisZCallback, this, _1);
00158       }
00159       else if (property_name == "z_axisx")
00160       {
00161         return boost::bind (&pcl::PLYReader::orientationZaxisXCallback, this, _1);
00162       }
00163       else if (property_name == "z_axisy")
00164       {
00165         return boost::bind (&pcl::PLYReader::orientationZaxisYCallback, this, _1);
00166       }
00167       else if (property_name == "z_axisz")
00168       {
00169         return boost::bind (&pcl::PLYReader::orientationZaxisZCallback, this, _1);
00170       }
00171       else
00172       {
00173         return (0);
00174       }
00175     }
00176     else
00177     {
00178       return (0);
00179     }
00180   }
00181 
00182   template <> boost::function<void (pcl::io::ply::uint8)>
00183   PLYReader::scalarPropertyDefinitionCallback (const std::string& element_name, const std::string& property_name)
00184   {
00185     if (element_name == "vertex")
00186     {
00187       if ((property_name == "red") || (property_name == "green") || (property_name == "blue") ||
00188           (property_name == "diffuse_red") || (property_name == "diffuse_green") || (property_name == "diffuse_blue") )
00189       {
00190         if ((property_name == "red") || (property_name == "diffuse_red"))
00191           appendFloatProperty ("rgb");
00192         return boost::bind (&pcl::PLYReader::vertexColorCallback, this, property_name, _1);
00193       }
00194       else if (property_name == "intensity")
00195       {
00196         appendFloatProperty (property_name);
00197         return boost::bind (&pcl::PLYReader::vertexIntensityCallback, this, _1);
00198       }
00199       else
00200         return (0);
00201     }
00202     else
00203       return (0);
00204   }
00205 
00206   template <> boost::function<void (pcl::io::ply::int32)>
00207   PLYReader::scalarPropertyDefinitionCallback (const std::string& element_name, const std::string& property_name)
00208   {
00209     if (element_name == "camera")
00210     {
00211       if (property_name == "viewportx")
00212       {
00213         return boost::bind (&pcl::PLYReader::cloudWidthCallback, this, _1);
00214       }
00215       else if (property_name == "viewporty")
00216       {
00217         return boost::bind (&pcl::PLYReader::cloudHeightCallback, this, _1);
00218       }
00219       else
00220       {
00221         return (0);
00222       }
00223     }
00224     else
00225       return (0);
00226   }
00227 
00228   template <>
00229   boost::tuple<boost::function<void (pcl::io::ply::uint8)>, boost::function<void (pcl::io::ply::int32)>, boost::function<void ()> >
00230   pcl::PLYReader::listPropertyDefinitionCallback (const std::string& element_name, const std::string& property_name)
00231   {
00232     if ((element_name == "range_grid") && (property_name == "vertex_indices")) {
00233       return boost::tuple<boost::function<void (pcl::io::ply::uint8)>, boost::function<void (pcl::io::ply::int32)>, boost::function<void ()> > (
00234         boost::bind (&pcl::PLYReader::rangeGridVertexIndicesBeginCallback, this, _1),
00235         boost::bind (&pcl::PLYReader::rangeGridVertexIndicesElementCallback, this, _1),
00236         boost::bind (&pcl::PLYReader::rangeGridVertexIndicesEndCallback, this)
00237       );
00238     }
00239     // else if ((element_name == "face") && (property_name == "vertex_indices")) {
00240     // return boost::tuple<boost::function<void (pcl::io::ply::uint8)>, boost::function<void (pcl::io::ply::int32)>, boost::function<void ()> > (
00241     //     boost::bind (&pcl::PLYReader::faceVertexIndicesBegin, this, _1),
00242     //     boost::bind (&pcl::PLYReader::faceVertexIndicesElement, this, _1),
00243     //     boost::bind (&pcl::PLYReader::faceVertexIndicesEnd, this)
00244     //   );
00245     // }
00246     else {
00247       return boost::tuple<boost::function<void (pcl::io::ply::uint8)>, boost::function<void (pcl::io::ply::int32)>, boost::function<void ()> > (0, 0, 0);
00248     }
00249   }
00250 }
00251 
00252 void
00253 pcl::PLYReader::vertexFloatPropertyCallback (pcl::io::ply::float32 value)
00254 {
00255   memcpy (&cloud_->data[vertex_count_ * cloud_->point_step + vertex_offset_before_],
00256           &value,
00257           sizeof (pcl::io::ply::float32));
00258   vertex_offset_before_ += static_cast<int> (sizeof (pcl::io::ply::float32));
00259 }
00260 
00261 void
00262 pcl::PLYReader::vertexColorCallback (const std::string& color_name, pcl::io::ply::uint8 color)
00263 {
00264   static int32_t r, g, b;
00265   if ((color_name == "red") || (color_name == "diffuse_red"))
00266   {
00267     r = int32_t (color);
00268     rgb_offset_before_ = vertex_offset_before_;
00269   }
00270   if ((color_name == "green") || (color_name == "diffuse_green"))
00271   {
00272     g = int32_t (color);
00273   }
00274   if ((color_name == "blue") || (color_name == "diffuse_blue"))
00275   {
00276     b = int32_t (color);
00277     int32_t rgb = r << 16 | g << 8 | b;
00278     memcpy (&cloud_->data[vertex_count_ * cloud_->point_step + rgb_offset_before_],
00279             &rgb,
00280             sizeof (int32_t));
00281     vertex_offset_before_ += static_cast<int> (sizeof (int32_t));
00282   }
00283 }
00284 
00285 void
00286 pcl::PLYReader::vertexIntensityCallback (pcl::io::ply::uint8 intensity)
00287 {
00288   pcl::io::ply::float32 intensity_ (intensity);
00289   memcpy (&cloud_->data[vertex_count_ * cloud_->point_step + vertex_offset_before_],
00290           &intensity_,
00291           sizeof (pcl::io::ply::float32));
00292   vertex_offset_before_ += static_cast<int> (sizeof (pcl::io::ply::float32));
00293 }
00294 
00295 void
00296 pcl::PLYReader::vertexBeginCallback ()
00297 {
00298   vertex_offset_before_ = 0;
00299 }
00300 
00301 void
00302 pcl::PLYReader::vertexEndCallback ()
00303 {
00304   ++vertex_count_;
00305 }
00306 
00307 void
00308 pcl::PLYReader::rangeGridBeginCallback () { }
00309 
00310 void
00311 pcl::PLYReader::rangeGridVertexIndicesBeginCallback (pcl::io::ply::uint8 size)
00312 {
00313   (*range_grid_)[range_count_].reserve (size);
00314 }
00315 
00316 void pcl::PLYReader::rangeGridVertexIndicesElementCallback (pcl::io::ply::int32 vertex_index)
00317 {
00318   (*range_grid_)[range_count_].push_back (vertex_index);
00319 }
00320 
00321 void
00322 pcl::PLYReader::rangeGridVertexIndicesEndCallback () { }
00323 
00324 void
00325 pcl::PLYReader::rangeGridEndCallback ()
00326 {
00327   ++range_count_;
00328 }
00329 
00330 void
00331 pcl::PLYReader::objInfoCallback (const std::string& line)
00332 {
00333   std::vector<std::string> st;
00334   boost::split (st, line, boost::is_any_of (std::string ( "\t\r ")), boost::token_compress_on);
00335   assert (st[0].substr (0, 8) == "obj_info");
00336   {
00337     assert (st.size () == 3);
00338     {
00339       if (st[1] == "num_cols")
00340         cloudWidthCallback (atoi (st[2].c_str ()));
00341       else if (st[1] == "num_rows")
00342         cloudHeightCallback (atoi (st[2].c_str ()));
00343       else if (st[1] == "echo_rgb_offset_x")
00344         originXCallback (static_cast<float> (atof (st[2].c_str ())));
00345       else if (st[1] == "echo_rgb_offset_y")
00346         originYCallback (static_cast<float> (atof (st[2].c_str ())));
00347       else if (st[1] == "echo_rgb_offset_z")
00348         originZCallback (static_cast<float> (atof (st[2].c_str ())));
00349     }
00350   }
00351 }
00352 
00353 bool
00354 pcl::PLYReader::parse (const std::string& istream_filename)
00355 {
00356   pcl::io::ply::ply_parser::flags_type ply_parser_flags = 0;
00357   pcl::io::ply::ply_parser ply_parser (ply_parser_flags);
00358 
00359   ply_parser.info_callback (boost::bind (&pcl::PLYReader::infoCallback, this, boost::ref (istream_filename), _1, _2));
00360   ply_parser.warning_callback (boost::bind (&pcl::PLYReader::warningCallback, this, boost::ref (istream_filename), _1, _2));
00361   ply_parser.error_callback (boost::bind (&pcl::PLYReader::errorCallback, this, boost::ref (istream_filename), _1, _2));
00362 
00363   ply_parser.element_definition_callback (boost::bind (&pcl::PLYReader::elementDefinitionCallback, this, _1, _2));
00364   ply_parser.end_header_callback (boost::bind (&pcl::PLYReader::endHeaderCallback, this));
00365 
00366   pcl::io::ply::ply_parser::scalar_property_definition_callbacks_type scalar_property_definition_callbacks;
00367   pcl::io::ply::at<pcl::io::ply::float32> (scalar_property_definition_callbacks) = boost::bind (&pcl::PLYReader::scalarPropertyDefinitionCallback<pcl::io::ply::float32>, this, _1, _2);
00368   pcl::io::ply::at<pcl::io::ply::uint8> (scalar_property_definition_callbacks) = boost::bind (&pcl::PLYReader::scalarPropertyDefinitionCallback<pcl::io::ply::uint8>, this, _1, _2);
00369   pcl::io::ply::at<pcl::io::ply::int32> (scalar_property_definition_callbacks) = boost::bind (&pcl::PLYReader::scalarPropertyDefinitionCallback<pcl::io::ply::int32>, this, _1, _2);
00370   ply_parser.scalar_property_definition_callbacks (scalar_property_definition_callbacks);
00371 
00372   pcl::io::ply::ply_parser::list_property_definition_callbacks_type list_property_definition_callbacks;
00373   pcl::io::ply::at<pcl::io::ply::uint8, pcl::io::ply::int32> (list_property_definition_callbacks) = boost::bind (&pcl::PLYReader::listPropertyDefinitionCallback<pcl::io::ply::uint8, pcl::io::ply::int32>, this, _1, _2);
00374   ply_parser.list_property_definition_callbacks (list_property_definition_callbacks);
00375 
00376   return ply_parser.parse (istream_filename);
00377 }
00378 
00380 int
00381 pcl::PLYReader::readHeader (const std::string &file_name, sensor_msgs::PointCloud2 &cloud,
00382                             Eigen::Vector4f &, Eigen::Quaternionf &,
00383                             int &, int &, unsigned int &, const int)
00384 {
00385   // Silence compiler warnings
00386   cloud_ = &cloud;
00387   range_grid_ = new std::vector<std::vector<int> >;
00388   if (!parse (file_name))
00389   {
00390     PCL_ERROR ("[pcl::PLYReader::read] problem parsing header!\n");
00391     return (-1);
00392   }
00393   cloud_->row_step = cloud_->point_step * cloud_->width;
00394   return 0;
00395 }
00396 
00398 int
00399 pcl::PLYReader::read (const std::string &file_name, sensor_msgs::PointCloud2 &cloud,
00400                       Eigen::Vector4f &origin, Eigen::Quaternionf &orientation, int &ply_version, const int)
00401 {
00402   // kept only for backward compatibility
00403   int data_type;
00404   unsigned int data_idx;
00405 
00406   if (this->readHeader (file_name, cloud, origin, orientation, ply_version, data_type, data_idx))
00407   {
00408     PCL_ERROR ("[pcl::PLYReader::read] problem parsing header!\n");
00409     return (-1);
00410   }
00411 
00412   // a range_grid element was found ?
00413   size_t r_size;
00414   if ((r_size  = (*range_grid_).size ()) > 0 && r_size != vertex_count_)
00415   {
00416     //cloud.header = cloud_->header;
00417     std::vector<pcl::uint8_t> data ((*range_grid_).size () * cloud.point_step);
00418     const static float f_nan = std::numeric_limits <float>::quiet_NaN ();
00419     const static double d_nan = std::numeric_limits <double>::quiet_NaN ();
00420     for (size_t r = 0; r < r_size; ++r)
00421     {
00422       if ((*range_grid_)[r].size () == 0)
00423       {
00424         for (size_t f = 0; f < cloud_->fields.size (); ++f)
00425           if (cloud_->fields[f].datatype == ::sensor_msgs::PointField::FLOAT32)
00426             //memcpy (&data[r * cloud_->point_step + cloud_->fields[f].offset + cloud_->fields[f].count * sizeof (float)],
00427             memcpy (&data[r * cloud_->point_step + cloud_->fields[f].offset],
00428                     reinterpret_cast<const char*> (&f_nan), sizeof (float));
00429           else if (cloud_->fields[f].datatype == ::sensor_msgs::PointField::FLOAT64)
00430             //memcpy (&data[r * cloud_->point_step + cloud_->fields[f].offset + cloud_->fields[f].count * sizeof (double)],
00431             memcpy (&data[r * cloud_->point_step + cloud_->fields[f].offset],
00432                     reinterpret_cast<const char*> (&d_nan), sizeof (double));
00433           else
00434             memset (&data[r * cloud_->point_step + cloud_->fields[f].offset], 0,
00435                     pcl::getFieldSize (cloud_->fields[f].datatype) * cloud_->fields[f].count);
00436       }
00437       else
00438         memcpy (&data[r* cloud_->point_step], &cloud_->data[(*range_grid_)[r][0] * cloud_->point_step], cloud_->point_step);
00439     }
00440     cloud_->data.swap (data);
00441     cloud_->is_dense = true;
00442   }
00443 
00444   orientation = Eigen::Quaternionf (orientation_);
00445   origin = origin_;
00446 
00447   return (0);
00448 }
00449 
00451 
00452 std::string
00453 pcl::PLYWriter::generateHeader (const sensor_msgs::PointCloud2 &cloud,
00454                                 const Eigen::Vector4f &origin,
00455                                 const Eigen::Quaternionf &,
00456                                 bool binary,
00457                                 bool use_camera,
00458                                 int valid_points)
00459 {
00460   std::ostringstream oss;
00461   // Begin header
00462   oss << "ply";
00463   if (!binary)
00464     oss << "\nformat ascii 1.0";
00465   else
00466   {
00467     if (cloud.is_bigendian)
00468       oss << "\nformat binary_big_endian 1.0";
00469     else
00470       oss << "\nformat binary_little_endian 1.0";
00471   }
00472   oss << "\ncomment PCL generated";
00473 
00474   if (!use_camera)
00475   {
00476     oss << "\nobj_info is_cyberware_data 0"
00477       "\nobj_info is_mesh 0"
00478       "\nobj_info is_warped 0"
00479       "\nobj_info is_interlaced 0";
00480     oss << "\nobj_info num_cols " << cloud.width;
00481     oss << "\nobj_info num_rows " << cloud.height;
00482     oss << "\nobj_info echo_rgb_offset_x " << origin[0];
00483     oss << "\nobj_info echo_rgb_offset_y " << origin[1];
00484     oss << "\nobj_info echo_rgb_offset_z " << origin[2];
00485     oss << "\nobj_info echo_rgb_frontfocus 0.0"
00486       "\nobj_info echo_rgb_backfocus 0.0"
00487       "\nobj_info echo_rgb_pixelsize 0.0"
00488       "\nobj_info echo_rgb_centerpixel 0"
00489       "\nobj_info echo_frames 1"
00490       "\nobj_info echo_lgincr 0.0";
00491   }
00492 
00493   const std::string &fields_list = getFieldsList (cloud);
00494 
00495   size_t xyz_found = fields_list.find ("x y z", 0);
00496   if (xyz_found != std::string::npos)
00497   {
00498     oss << "\nelement vertex "<< valid_points;
00499     oss << "\nproperty float x"
00500       "\nproperty float y"
00501       "\nproperty float z";
00502 
00503     xyz_found+=5;
00504     // Find intensity optional
00505     if (fields_list.find ("intensity", xyz_found) != std::string::npos)
00506       oss << "\nproperty float intensity";
00507 
00508     if (fields_list.find ("rgb", xyz_found) != std::string::npos)
00509       oss << "\nproperty uchar red"
00510         "\nproperty uchar green"
00511         "\nproperty uchar blue";
00512 
00513     if (fields_list.find ("rgba", xyz_found) != std::string::npos)
00514       oss << "\nproperty uchar alpha";
00515 
00516     if (fields_list.find ("normal_x normal_y normal_z", xyz_found) != std::string::npos)
00517       oss << "\nproperty float nx"
00518         "\nproperty float ny"
00519         "\nproperty float nz"
00520         "\nproperty float curvature";
00521 
00522     if (fields_list.find ("radius", xyz_found) != std::string::npos)
00523       oss << "\nproperty float radius";
00524 
00525     if (fields_list.find ("vp_x vp_y vp_z", xyz_found) != std::string::npos)
00526       oss << "\nproperty float vp_x"
00527         "\nproperty float vp_y"
00528         "\nproperty float vp_z";
00529 
00530     if (fields_list.find ("range", xyz_found) != std::string::npos)
00531       oss << "\nproperty float range";
00532 
00533     if (fields_list.find ("strength", xyz_found) != std::string::npos)
00534       oss << "\nproperty float strength";
00535 
00536     if (fields_list.find ("confidence", xyz_found) != std::string::npos)
00537       oss << "\nproperty float confidence";
00538   }
00539   else
00540   {
00541     if (fields_list.find ("normal_x normal_y normal_z", 0) != std::string::npos)
00542     {
00543       oss << "\nelement vertex "<< valid_points;
00544       oss << "\nproperty float nx"
00545         "\nproperty float ny"
00546         "\nproperty float nz"
00547         "\nproperty float curvature";
00548     }
00549     else
00550     {
00551       if (fields_list.find ("x y", 0) != std::string::npos)
00552       {
00553         oss << "\nelement vertex "<< valid_points;
00554         oss << "\nproperty float x"
00555           "\nproperty float y";
00556       }
00557       else
00558         PCL_ERROR ("[pcl::PLYWriter] PLY file format doesn't handle this kind of data: %s!\n", fields_list.c_str ());
00559     }
00560   }
00561 
00562   if (use_camera)
00563   {
00564     oss << "\nelement camera 1"
00565       "\nproperty float view_px"
00566       "\nproperty float view_py"
00567       "\nproperty float view_pz"
00568       "\nproperty float x_axisx"
00569       "\nproperty float x_axisy"
00570       "\nproperty float x_axisz"
00571       "\nproperty float y_axisx"
00572       "\nproperty float y_axisy"
00573       "\nproperty float y_axisz"
00574       "\nproperty float z_axisx"
00575       "\nproperty float z_axisy"
00576       "\nproperty float z_axisz"
00577       "\nproperty float focal"
00578       "\nproperty float scalex"
00579       "\nproperty float scaley"
00580       "\nproperty float centerx"
00581       "\nproperty float centery"
00582       "\nproperty int viewportx"
00583       "\nproperty int viewporty"
00584       "\nproperty float k1"
00585       "\nproperty float k2";
00586   }
00587   else
00588   {
00589     oss << "\nelement range_grid " << cloud.width * cloud.height;
00590     oss << "\nproperty list uchar int vertex_indices";
00591   }
00592 
00593   // End header
00594   oss << "\nend_header\n";
00595   return (oss.str ());
00596 }
00597 
00599 
00600 int
00601 pcl::PLYWriter::writeASCII (const std::string &file_name,
00602                             const sensor_msgs::PointCloud2 &cloud,
00603                             const Eigen::Vector4f &origin,
00604                             const Eigen::Quaternionf &orientation,
00605                             int precision,
00606                             bool use_camera)
00607 {
00608   if (cloud.data.empty ())
00609   {
00610     PCL_ERROR ("[pcl::PLYWriter::writeASCII] Input point cloud has no data!\n");
00611     return (-1);
00612   }
00613 
00614   std::ofstream fs;
00615   fs.precision (precision);
00616   // Open file
00617   fs.open (file_name.c_str ());
00618   if (!fs)
00619   {
00620     PCL_ERROR ("[pcl::PLYWriter::writeASCII] Error during opening (%s)!\n", file_name.c_str ());
00621     return (-1);
00622   }
00623 
00624   unsigned int nr_points  = cloud.width * cloud.height;
00625   unsigned int point_size = static_cast<unsigned int> (cloud.data.size () / nr_points);
00626 
00627   // Write the header information if available
00628   if (use_camera)
00629   {
00630     fs << generateHeader (cloud, origin, orientation, false, use_camera, nr_points);
00631     writeContentWithCameraASCII (nr_points, point_size, cloud, origin, orientation, fs);
00632   }
00633   else
00634   {
00635     std::ostringstream os;
00636     int nr_valid_points;
00637     writeContentWithRangeGridASCII (nr_points, point_size, cloud, os, nr_valid_points);
00638     fs << generateHeader (cloud, origin, orientation, false, use_camera, nr_valid_points);
00639     fs << os.str ();
00640   }
00641 
00642   // Close file
00643   fs.close ();
00644   return (0);
00645 }
00646 
00647 void
00648 pcl::PLYWriter::writeContentWithCameraASCII (int nr_points,
00649                                              int point_size,
00650                                              const sensor_msgs::PointCloud2 &cloud,
00651                                              const Eigen::Vector4f &origin,
00652                                              const Eigen::Quaternionf &orientation,
00653                                              std::ofstream& fs)
00654 {
00655   // Iterate through the points
00656   for (int i = 0; i < nr_points; ++i)
00657   {
00658     for (size_t d = 0; d < cloud.fields.size (); ++d)
00659     {
00660       int count = cloud.fields[d].count;
00661       if (count == 0)
00662         count = 1; //workaround
00663 
00664       for (int c = 0; c < count; ++c)
00665       {
00666         switch (cloud.fields[d].datatype)
00667         {
00668           case sensor_msgs::PointField::INT8:
00669           {
00670             char value;
00671             memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (char)], sizeof (char));
00672             fs << boost::numeric_cast<int> (value);
00673             break;
00674           }
00675           case sensor_msgs::PointField::UINT8:
00676           {
00677             unsigned char value;
00678             memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned char)], sizeof (unsigned char));
00679             fs << boost::numeric_cast<int> (value);
00680             break;
00681           }
00682           case sensor_msgs::PointField::INT16:
00683           {
00684             short value;
00685             memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (short)], sizeof (short));
00686             fs << boost::numeric_cast<int> (value);
00687             break;
00688           }
00689           case sensor_msgs::PointField::UINT16:
00690           {
00691             unsigned short value;
00692             memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned short)], sizeof (unsigned short));
00693             fs << boost::numeric_cast<int> (value);
00694             break;
00695           }
00696           case sensor_msgs::PointField::INT32:
00697           {
00698             int value;
00699             memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (int)], sizeof (int));
00700             fs << value;
00701             break;
00702           }
00703           case sensor_msgs::PointField::UINT32:
00704           {
00705             if (cloud.fields[d].name.find ("rgb") == std::string::npos)
00706             {
00707               unsigned int value;
00708               memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned int)], sizeof (unsigned int));
00709               fs << value;
00710             }
00711             else
00712             {
00713               pcl::RGB color;
00714               memcpy (&color, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned int)], sizeof (pcl::RGB));
00715               int r = color.r;
00716               int g = color.g;
00717               int b = color.b;
00718               fs << r << " " << g << " " << b;
00719               if (cloud.fields[d].name.find ("rgba") != std::string::npos)
00720               {
00721                 int a = color.a;
00722                 fs << " " << a;
00723               }
00724             }
00725             break;
00726           }
00727           case sensor_msgs::PointField::FLOAT32:
00728           {
00729             if (cloud.fields[d].name.find ("rgb") == std::string::npos)
00730             {
00731               float value;
00732               memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (float)], sizeof (float));
00733               fs << value;
00734             }
00735             else
00736             {
00737               pcl::RGB color;
00738               memcpy (&color, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (float)], sizeof (pcl::RGB));
00739               int r = color.r;
00740               int g = color.g;
00741               int b = color.b;
00742               fs << r << " " << g << " " << b;
00743               if (cloud.fields[d].name.find ("rgba") != std::string::npos)
00744               {
00745                 int a = color.a;
00746                 fs << " " << a;
00747               }
00748             }
00749             break;
00750           }
00751           case sensor_msgs::PointField::FLOAT64:
00752           {
00753             double value;
00754             memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (double)], sizeof (double));
00755             fs << value;
00756             break;
00757           }
00758           default:
00759             PCL_WARN ("[pcl::PLYWriter::writeASCII] Incorrect field data type specified (%d)!\n", cloud.fields[d].datatype);
00760             break;
00761         }
00762 
00763         if (d < cloud.fields.size () - 1 || c < static_cast<int> (cloud.fields[d].count) - 1)
00764           fs << " ";
00765       }
00766     }
00767     fs << std::endl;
00768   }
00769   // Append sensor information
00770   if (origin[3] != 0)
00771     fs << origin[0]/origin[3] << " " << origin[1]/origin[3] << " " << origin[2]/origin[3] << " ";
00772   else
00773     fs << origin[0] << " " << origin[1] << " " << origin[2] << " ";
00774 
00775   Eigen::Matrix3f R = orientation.toRotationMatrix ();
00776   fs << R (0,0) << " " << R (0,1) << " " << R (0,2) << " ";
00777   fs << R (1,0) << " " << R (1,1) << " " << R (1,2) << " ";
00778   fs << R (2,0) << " " << R (2,1) << " " << R (2,2) << " ";
00779   // No focal
00780   fs << 0 << " ";
00781   // No scale
00782   fs << 0 << " " << 0 << " ";
00783   // No center
00784   fs << 0 << " " << 0 << " ";
00785   // Viewport set to width x height
00786   fs << cloud.width << " " << cloud.height << " ";
00787   // No corrections
00788   fs << 0 << " " << 0;
00789   fs << std::endl;
00790   fs.flush ();
00791 }
00792 
00793 void
00794 pcl::PLYWriter::writeContentWithRangeGridASCII (int nr_points,
00795                                                 int point_size,
00796                                                 const sensor_msgs::PointCloud2 &cloud,
00797                                                 std::ostringstream& fs,
00798                                                 int& valid_points)
00799 {
00800   valid_points = 0;
00801   std::vector<std::vector <int> > grids (nr_points);
00802   // Iterate through the points
00803   for (int i = 0; i < nr_points; ++i)
00804   {
00805     std::ostringstream line;
00806     bool is_valid_line = true;
00807     for (size_t d = 0; d < cloud.fields.size (); ++d)
00808     {
00809       int count = cloud.fields[d].count;
00810       if (count == 0)
00811         count = 1; //workaround
00812       for (int c = 0; c < count; ++c)
00813       {
00814         switch (cloud.fields[d].datatype)
00815         {
00816           case sensor_msgs::PointField::INT8:
00817           {
00818             char value;
00819             memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (char)], sizeof (char));
00820             line << boost::numeric_cast<int> (value);
00821             break;
00822           }
00823           case sensor_msgs::PointField::UINT8:
00824           {
00825             unsigned char value;
00826             memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned char)], sizeof (unsigned char));
00827             line << boost::numeric_cast<int> (value);
00828             break;
00829           }
00830           case sensor_msgs::PointField::INT16:
00831           {
00832             short value;
00833             memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (short)], sizeof (short));
00834             line << boost::numeric_cast<int> (value);
00835             break;
00836           }
00837           case sensor_msgs::PointField::UINT16:
00838           {
00839             unsigned short value;
00840             memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned short)], sizeof (unsigned short));
00841             line << boost::numeric_cast<int> (value);
00842             break;
00843           }
00844           case sensor_msgs::PointField::INT32:
00845           {
00846             int value;
00847             memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (int)], sizeof (int));
00848             line << value;
00849             break;
00850           }
00851           case sensor_msgs::PointField::UINT32:
00852           {
00853             if (cloud.fields[d].name.find ("rgb") == std::string::npos)
00854             {
00855               unsigned int value;
00856               memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned int)], sizeof (unsigned int));
00857               line << value;
00858             }
00859             else
00860             {
00861               pcl::RGB color;
00862               memcpy (&color, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned int)], sizeof (pcl::RGB));
00863               int r = color.r;
00864               int g = color.g;
00865               int b = color.b;
00866               line << r << " " << g << " " << b;
00867               if (cloud.fields[d].name.find ("rgba") != std::string::npos)
00868               {
00869                 int a = color.a;
00870                 line << " " << a;
00871               }
00872             }
00873             break;
00874           }
00875           case sensor_msgs::PointField::FLOAT32:
00876           {
00877             if (cloud.fields[d].name.find ("rgb") == std::string::npos)
00878             {
00879               float value;
00880               memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (float)], sizeof (float));
00881               if ("x" == cloud.fields[d].name)
00882               {
00883                 if (value != value)
00884                   is_valid_line = false;
00885               }
00886               line << value;
00887             }
00888             else
00889             {
00890               pcl::RGB color;
00891               memcpy (&color, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (float)], sizeof (pcl::RGB));
00892               int r = color.r;
00893               int g = color.g;
00894               int b = color.b;
00895               line << r << " " << g << " " << b;
00896               if (cloud.fields[d].name.find ("rgba") != std::string::npos)
00897               {
00898                 int a = color.a;
00899                 line << " " << a;
00900               }
00901             }
00902             break;
00903           }
00904           case sensor_msgs::PointField::FLOAT64:
00905           {
00906             double value;
00907             memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (double)], sizeof (double));
00908             line << value;
00909             break;
00910           }
00911           default:
00912             PCL_WARN ("[pcl::PLYWriter::writeASCII] Incorrect field data type specified (%d)!\n", cloud.fields[d].datatype);
00913             break;
00914         }
00915 
00916         if (d < cloud.fields.size () - 1 || c < static_cast<int> (cloud.fields[d].count) - 1)
00917           line << " ";
00918       }
00919     }
00920 
00921     if (is_valid_line)
00922     {
00923       grids[i].push_back (valid_points);
00924       fs << line.str () << std::endl;
00925       ++valid_points;
00926     }
00927   }
00928 
00929   // Append range grid
00930   for (int i = 0; i < nr_points; ++i)
00931   {
00932     fs << grids [i].size ();
00933     for (std::vector <int>::const_iterator it = grids [i].begin ();
00934          it != grids [i].end ();
00935          ++it)
00936       fs << " " << *it;
00937     fs << std::endl;
00938   }
00939   fs.flush ();
00940 }
00941 
00943 int
00944 pcl::PLYWriter::writeBinary (const std::string &file_name,
00945                              const sensor_msgs::PointCloud2 &cloud,
00946                              const Eigen::Vector4f &origin,
00947                              const Eigen::Quaternionf &orientation)
00948 {
00949   if (cloud.data.empty ())
00950   {
00951     PCL_ERROR ("[pcl::PLYWriter::writeBinary] Input point cloud has no data!\n");
00952     return (-1);
00953   }
00954 
00955   std::ofstream fs;
00956   fs.open (file_name.c_str ());      // Open file
00957   if (!fs)
00958   {
00959     PCL_ERROR ("[pcl::PLYWriter::writeBinary] Error during opening (%s)!\n", file_name.c_str ());
00960     return (-1);
00961   }
00962 
00963   unsigned int nr_points  = cloud.width * cloud.height;
00964   unsigned int point_size = static_cast<unsigned int> (cloud.data.size () / nr_points);
00965 
00966   // Write the header information if available
00967   fs << generateHeader (cloud, origin, orientation, true, true, nr_points);
00968   // Close the file
00969   fs.close ();
00970   // Open file in binary appendable
00971   std::ofstream fpout (file_name.c_str (), std::ios::app | std::ios::binary);
00972   if (!fpout)
00973   {
00974     PCL_ERROR ("[pcl::PLYWriter::writeBinary] Error during reopening (%s)!\n", file_name.c_str ());
00975     return (-1);
00976   }
00977   // Unlike PCD format file, PLY doesn't like
00978   // Iterate through the points
00979   for (unsigned int i = 0; i < nr_points; ++i)
00980   {
00981     size_t total = 0;
00982     for (size_t d = 0; d < cloud.fields.size (); ++d)
00983     {
00984       int count = cloud.fields[d].count;
00985       if (count == 0)
00986         count = 1; //workaround
00987       // Ignore invalid padded dimensions that are inherited from binary data
00988       if (cloud.fields[d].name == "_")
00989       {
00990         total += cloud.fields[d].count; // jump over this many elements in the string token
00991         continue;
00992       }
00993 
00994       for (int c = 0; c < count; ++c)
00995       {
00996         switch (cloud.fields[d].datatype)
00997         {
00998           case sensor_msgs::PointField::INT8:
00999           {
01000             char value;
01001             memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (char)], sizeof (char));
01002             fpout.write (reinterpret_cast<const char*> (&value), sizeof (char));
01003             break;
01004           }
01005           case sensor_msgs::PointField::UINT8:
01006           {
01007             unsigned char value;
01008             memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (unsigned char)], sizeof (unsigned char));
01009             fpout.write (reinterpret_cast<const char*> (&value), sizeof (unsigned char));
01010             break;
01011           }
01012           case sensor_msgs::PointField::INT16:
01013           {
01014             short value;
01015             memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (short)], sizeof (short));
01016             fpout.write (reinterpret_cast<const char*> (&value), sizeof (short));
01017             break;
01018           }
01019           case sensor_msgs::PointField::UINT16:
01020           {
01021             unsigned short value;
01022             memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (unsigned short)], sizeof (unsigned short));
01023             fpout.write (reinterpret_cast<const char*> (&value), sizeof (unsigned short));
01024             break;
01025           }
01026           case sensor_msgs::PointField::INT32:
01027           {
01028             int value;
01029             memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (int)], sizeof (int));
01030             fpout.write (reinterpret_cast<const char*> (&value), sizeof (int));
01031             break;
01032           }
01033           case sensor_msgs::PointField::UINT32:
01034           {
01035             if (cloud.fields[d].name.find ("rgb") == std::string::npos)
01036             {
01037               unsigned int value;
01038               memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (unsigned int)], sizeof (unsigned int));
01039               fpout.write (reinterpret_cast<const char*> (&value), sizeof (unsigned int));
01040             }
01041             else
01042             {
01043               pcl::RGB color;
01044               memcpy (&color, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (unsigned int)], sizeof (pcl::RGB));
01045               unsigned char r = color.r;
01046               unsigned char g = color.g;
01047               unsigned char b = color.b;
01048               fpout.write (reinterpret_cast<const char*> (&r), sizeof (unsigned char));
01049               fpout.write (reinterpret_cast<const char*> (&g), sizeof (unsigned char));
01050               fpout.write (reinterpret_cast<const char*> (&b), sizeof (unsigned char));
01051               if (cloud.fields[d].name.find ("rgba") != std::string::npos)
01052               {
01053                 unsigned char a = color.a;
01054                 fpout.write (reinterpret_cast<const char*> (&a), sizeof (unsigned char));
01055               }
01056             }
01057             break;
01058           }
01059           case sensor_msgs::PointField::FLOAT32:
01060           {
01061             if (cloud.fields[d].name.find ("rgb") == std::string::npos)
01062             {
01063               float value;
01064               memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (float)], sizeof (float));
01065               fpout.write (reinterpret_cast<const char*> (&value), sizeof (float));
01066             }
01067             else
01068             {
01069               pcl::RGB color;
01070               memcpy (&color, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (float)], sizeof (pcl::RGB));
01071               unsigned char r = color.r;
01072               unsigned char g = color.g;
01073               unsigned char b = color.b;
01074               fpout.write (reinterpret_cast<const char*> (&r), sizeof (unsigned char));
01075               fpout.write (reinterpret_cast<const char*> (&g), sizeof (unsigned char));
01076               fpout.write (reinterpret_cast<const char*> (&b), sizeof (unsigned char));
01077               if (cloud.fields[d].name.find ("rgba") != std::string::npos)
01078               {
01079                 unsigned char a = color.a;
01080                 fpout.write (reinterpret_cast<const char*> (&a), sizeof (unsigned char));
01081               }
01082             }
01083             break;
01084           }
01085           case sensor_msgs::PointField::FLOAT64:
01086           {
01087             double value;
01088             memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (double)], sizeof (double));
01089             fpout.write (reinterpret_cast<const char*> (&value), sizeof (double));
01090             break;
01091           }
01092           default:
01093             PCL_WARN ("[pcl::PLYWriter::writeBinary] Incorrect field data type specified (%d)!\n", cloud.fields[d].datatype);
01094             break;
01095         }
01096       }
01097     }
01098   }
01099   // Append sensor information
01100   float t;
01101   for (int i = 0; i < 3; ++i)
01102   {
01103     if (origin[3] != 0)
01104       t = origin[i]/origin[3];
01105     else
01106       t = origin[i];
01107     fpout.write (reinterpret_cast<const char*> (&t), sizeof (float));
01108   }
01109   Eigen::Matrix3f R = orientation.toRotationMatrix ();
01110   for (int i = 0; i < 3; ++i)
01111     for (int j = 0; j < 3; ++j)
01112   {
01113     fpout.write (reinterpret_cast<const char*> (&R (i, j)),sizeof (float));
01114   }
01115 
01117 // Append those properties directly.               //
01118 // They are for perspective cameras so just put 0  //
01119 //                                                 //
01120 // property float focal                            //
01121 // property float scalex                           //
01122 // property float scaley                           //
01123 // property float centerx                          //
01124 // property float centery                          //
01125 // and later on                                    //
01126 // property float k1                               //
01127 // property float k2                               //
01129 
01130   const float zerof = 0;
01131   for (int i = 0; i < 5; ++i)
01132     fpout.write (reinterpret_cast<const char*> (&zerof), sizeof (float));
01133 
01134   // width and height
01135   int width = cloud.width;
01136   fpout.write (reinterpret_cast<const char*> (&width), sizeof (int));
01137 
01138   int height = cloud.height;
01139   fpout.write (reinterpret_cast<const char*> (&height), sizeof (int));
01140 
01141   for (int i = 0; i < 2; ++i)
01142     fpout.write (reinterpret_cast<const char*> (&zerof), sizeof (float));
01143 
01144   // Close file
01145   fpout.close ();
01146   return (0);
01147 }
01148 
01150 int
01151 pcl::io::savePLYFile (const std::string &file_name, const pcl::PolygonMesh &mesh, unsigned precision)
01152 {
01153   if (mesh.cloud.data.empty ())
01154   {
01155     PCL_ERROR ("[pcl::io::savePLYFile] Input point cloud has no data!\n");
01156     return (-1);
01157   }
01158   // Open file
01159   std::ofstream fs;
01160   fs.precision (precision);
01161   fs.open (file_name.c_str ());
01162   if (!fs)
01163   {
01164     PCL_ERROR ("[pcl::io::savePLYFile] Error during opening (%s)!\n", file_name.c_str ());
01165     return (-1);
01166   }
01167 
01168   // number of points
01169   size_t nr_points  = mesh.cloud.width * mesh.cloud.height;
01170   size_t point_size = mesh.cloud.data.size () / nr_points;
01171 
01172   // number of faces
01173   size_t nr_faces = mesh.polygons.size ();
01174 
01175   // Write header
01176   fs << "ply";
01177   fs << "\nformat ascii 1.0";
01178   fs << "\ncomment PCL generated";
01179   // Vertices
01180   fs << "\nelement vertex "<< mesh.cloud.width * mesh.cloud.height;
01181   fs << "\nproperty float x"
01182     "\nproperty float y"
01183     "\nproperty float z";
01184   // Check if we have color on vertices
01185   int rgb_index = getFieldIndex (mesh.cloud, "rgb"),
01186       rgba_index = getFieldIndex (mesh.cloud, "rgba");
01187   if (rgb_index != -1)
01188   {
01189     fs << "\nproperty uchar red"
01190           "\nproperty uchar green"
01191           "\nproperty uchar blue";
01192   }
01193   else if (rgba_index != -1)
01194   {
01195     fs << "\nproperty uchar red"
01196           "\nproperty uchar green"
01197           "\nproperty uchar blue"
01198           "\nproperty uchar alpha";
01199   }
01200 
01201   // Faces
01202   fs << "\nelement face "<< nr_faces;
01203   fs << "\nproperty list uchar int vertex_index";
01204   fs << "\nend_header\n";
01205 
01206   // Write down vertices
01207   for (size_t i = 0; i < nr_points; ++i)
01208   {
01209     int xyz = 0;
01210     for (size_t d = 0; d < mesh.cloud.fields.size (); ++d)
01211     {
01212       int count = mesh.cloud.fields[d].count;
01213       if (count == 0)
01214         count = 1;          // we simply cannot tolerate 0 counts (coming from older converter code)
01215       int c = 0;
01216 
01217       // adding vertex
01218       if ((mesh.cloud.fields[d].datatype == sensor_msgs::PointField::FLOAT32) && (
01219           mesh.cloud.fields[d].name == "x" ||
01220           mesh.cloud.fields[d].name == "y" ||
01221           mesh.cloud.fields[d].name == "z"))
01222       {
01223         float value;
01224         memcpy (&value, &mesh.cloud.data[i * point_size + mesh.cloud.fields[d].offset + c * sizeof (float)], sizeof (float));
01225         fs << value;
01226         // if (++xyz == 3)
01227         //   break;
01228         ++xyz;
01229       }
01230       else if (mesh.cloud.fields[d].datatype == sensor_msgs::PointField::FLOAT32 && mesh.cloud.fields[d].name.find ("rgb") != std::string::npos)
01231       {
01232         pcl::RGB color;
01233         if(rgb_index != -1)
01234         {
01235           memcpy (&color, &mesh.cloud.data[i * point_size + mesh.cloud.fields[rgb_index].offset + c * sizeof (float)], sizeof (RGB));
01236           fs << (int) color.r << " " << (int) color.g << " " << (int) color.b;
01237         }
01238         else
01239         {
01240           memcpy (&color, &mesh.cloud.data[i * point_size + mesh.cloud.fields[rgba_index].offset + c * sizeof (float)], sizeof (RGB));
01241           fs << (int) color.r << " " << (int) color.g << " " << (int) color.b << " " << (int) color.a;
01242         }
01243       }
01244       fs << " ";
01245     }
01246     if (xyz != 3)
01247     {
01248       PCL_ERROR ("[pcl::io::savePLYFile] Input point cloud has no XYZ data!\n");
01249       return (-2);
01250     }
01251     fs << std::endl;
01252   }
01253 
01254   // Write down faces
01255   for (size_t i = 0; i < nr_faces; i++)
01256   {
01257     fs << mesh.polygons[i].vertices.size () << " ";
01258     size_t j = 0;
01259     for (j = 0; j < mesh.polygons[i].vertices.size () - 1; ++j)
01260       fs << mesh.polygons[i].vertices[j] << " ";
01261     fs << mesh.polygons[i].vertices[j] << std::endl;
01262   }
01263 
01264   // Close file
01265   fs.close ();
01266   return (0);
01267 }


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