00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <fstream>
00039 #include <fcntl.h>
00040 #include <string>
00041 #include <stdlib.h>
00042 #include <boost/algorithm/string.hpp>
00043 #include <boost/filesystem.hpp>
00044 #include <boost/numeric/conversion/cast.hpp>
00045 #include "pcl/io/io.h"
00046 #include "pcl/io/pcd_io.h"
00047
00048 #ifdef _WIN32
00049 # include <io.h>
00050 # include <windows.h>
00051 # define pcl_open(pathname,flags) _open(pathname,flags)
00052 # define pcl_close(fd) _close(fd)
00053 # define pcl_lseek(fd,offset,origin) _lseek(fd,offset,origin)
00054 #else
00055 # include <sys/mman.h>
00056 # define pcl_open(pathname,flags) open(pathname,flags)
00057 # define pcl_close(fd) close(fd)
00058 # define pcl_lseek(fd,offset,origin) lseek(fd,offset,origin)
00059 #endif
00060
00064 int
00065 pcl::PCDReader::readHeader (const std::string &file_name, sensor_msgs::PointCloud2 &cloud,
00066 Eigen::Vector4f &origin, Eigen::Quaternionf &orientation, int &pcd_version)
00067 {
00068
00069 pcd_version = PCD_V6;
00070 origin = Eigen::Vector4f::Zero ();
00071 orientation = Eigen::Quaternionf::Identity ();
00072 cloud.width = cloud.height = cloud.point_step = cloud.row_step = 0;
00073 cloud.data.clear ();
00074
00075
00076 cloud.is_dense = true;
00077
00078
00079 if (!boost::filesystem::exists (file_name))
00080 {
00081 ROS_ERROR ("[pcl::PCDReader::readHeader] Could not open file %s.", file_name.c_str ());
00082 return (-1);
00083 }
00084
00085 int nr_points = 0;
00086 std::ifstream fs;
00087 std::string line;
00088
00089 int specified_channel_count = 0;
00090
00091
00092 fs.open (file_name.c_str ());
00093 if (!fs.is_open () || fs.fail ())
00094 {
00095 ROS_ERROR ("[pcl::PCDReader::readHeader] Could not open file %s.", file_name.c_str ());
00096 return (-1);
00097 }
00098
00099
00100
00101 std::vector<int> field_sizes, field_counts;
00102
00103 std::vector<char> field_types;
00104 std::vector<std::string> st;
00105
00106
00107 try
00108 {
00109 while (!fs.eof ())
00110 {
00111 getline (fs, line);
00112
00113 if (line == "")
00114 continue;
00115
00116
00117 boost::trim (line);
00118 boost::split (st, line, boost::is_any_of ("\t\r "), boost::token_compress_on);
00119
00120 std::string line_type = st.at (0);
00121
00122
00123 if (line_type.substr (0, 1) == "#")
00124 continue;
00125
00126
00127 if ( (line_type.substr (0, 6) == "FIELDS") || (line_type.substr (0, 7) == "COLUMNS") )
00128 {
00129 specified_channel_count = st.size () - 1;
00130
00131
00132 cloud.fields.resize (specified_channel_count);
00133 for (int i = 0; i < specified_channel_count; ++i)
00134 {
00135 std::string col_type = st.at (i + 1);
00136 cloud.fields[i].name = col_type;
00137 }
00138
00139
00140 int offset = 0;
00141 for (int i = 0; i < specified_channel_count; ++i, offset += 4)
00142 {
00143 cloud.fields[i].offset = offset;
00144 cloud.fields[i].datatype = sensor_msgs::PointField::FLOAT32;
00145 cloud.fields[i].count = 1;
00146 }
00147 cloud.point_step = offset;
00148 continue;
00149 }
00150
00151
00152 if (line_type.substr (0, 4) == "SIZE")
00153 {
00154 specified_channel_count = st.size () - 1;
00155
00156
00157 if (specified_channel_count != (int)cloud.fields.size ())
00158 throw "The number of elements in <SIZE> differs than the number of elements in <FIELDS>!";
00159
00160
00161 field_sizes.resize (specified_channel_count);
00162
00163 int offset = 0;
00164 for (int i = 0; i < specified_channel_count; ++i)
00165 {
00166 int col_type = atoi (st.at (i + 1).c_str ());
00167 cloud.fields[i].offset = offset;
00168 offset += col_type;
00169 field_sizes[i] = col_type;
00170 }
00171 cloud.point_step = offset;
00172
00173
00174 continue;
00175 }
00176
00177
00178 if (line_type.substr (0, 4) == "TYPE")
00179 {
00180 if (field_sizes.empty ())
00181 throw "TYPE of FIELDS specified before SIZE in header!";
00182
00183 specified_channel_count = st.size () - 1;
00184
00185
00186 if (specified_channel_count != (int)cloud.fields.size ())
00187 throw "The number of elements in <TYPE> differs than the number of elements in <FIELDS>!";
00188
00189
00190 field_types.resize (specified_channel_count);
00191
00192 for (int i = 0; i < specified_channel_count; ++i)
00193 {
00194 field_types[i] = st.at (i + 1).c_str ()[0];
00195 cloud.fields[i].datatype = getFieldType (field_sizes[i], field_types[i]);
00196 }
00197 continue;
00198 }
00199
00200
00201 if (line_type.substr (0, 5) == "COUNT")
00202 {
00203 if (field_sizes.empty () || field_types.empty ())
00204 throw "COUNT of FIELDS specified before SIZE or TYPE in header!";
00205
00206 specified_channel_count = st.size () - 1;
00207
00208
00209 if (specified_channel_count != (int)cloud.fields.size ())
00210 throw "The number of elements in <COUNT> differs than the number of elements in <FIELDS>!";
00211
00212 field_counts.resize (specified_channel_count);
00213
00214 int offset = 0;
00215 for (int i = 0; i < specified_channel_count; ++i)
00216 {
00217 cloud.fields[i].offset = offset;
00218 int col_count = atoi (st.at (i + 1).c_str ());
00219 cloud.fields[i].count = col_count;
00220 offset += col_count * field_sizes[i];
00221 }
00222
00223 cloud.point_step = offset;
00224 continue;
00225 }
00226
00227
00228 if (line_type.substr (0, 5) == "WIDTH")
00229 {
00230 cloud.width = atoi (st.at (1).c_str ());
00231 if (cloud.point_step != 0)
00232 cloud.row_step = cloud.point_step * cloud.width;
00233 continue;
00234 }
00235
00236
00237 if (line_type.substr (0, 6) == "HEIGHT")
00238 {
00239 cloud.height = atoi (st.at (1).c_str ());
00240
00241
00242
00243
00244
00245 continue;
00246 }
00247
00248
00249 if (line_type.substr (0, 9) == "VIEWPOINT")
00250 {
00251 pcd_version = PCD_V7;
00252 if (st.size () < 8)
00253 throw "Not enough number of elements in <VIEWPOINT>! Need 7 values (tx ty tz qw qx qy qz).";
00254
00255 origin = Eigen::Vector4f (atof (st.at (1).c_str ()), atof (st.at (2).c_str ()), atof (st.at (3).c_str ()), 0);
00256 orientation = Eigen::Quaternionf (atof (st.at (4).c_str ()), atof (st.at (5).c_str ()), atof (st.at (6).c_str ()), atof (st.at (7).c_str ()));
00257 continue;
00258 }
00259
00260
00261 if (line_type.substr (0, 6) == "POINTS")
00262 {
00263 nr_points = atoi (st.at (1).c_str ());
00264
00265 cloud.data.resize (nr_points * cloud.point_step);
00266 continue;
00267 }
00268
00269 break;
00270 }
00271 }
00272 catch (const char *exception)
00273 {
00274 ROS_ERROR ("[pcl::PCDReader::readHeader] %s", exception);
00275 return (-1);
00276 }
00277
00278
00279 if (cloud.width == 0 && cloud.height == 0)
00280 {
00281 cloud.width = nr_points;
00282 cloud.height = 1;
00283 cloud.row_step = cloud.point_step * cloud.width;
00284 }
00285
00286
00287
00288 if (cloud.height == 0)
00289 {
00290 cloud.height = 1;
00291 ROS_WARN ("[pcl::PCDReader::readHeader] no HEIGHT given, setting to 1 (unorganized).");
00292 if (cloud.width == 0)
00293 cloud.width = nr_points;
00294 }
00295 else
00296 {
00297 if (cloud.width == 0)
00298 {
00299 ROS_ERROR ("[pcl::PCDReader::readHeader] HEIGHT given (%d) but no WIDTH!", cloud.height);
00300 return (-1);
00301 }
00302 }
00303
00304 if (int(cloud.width * cloud.height) != nr_points)
00305 {
00306 ROS_ERROR ("[pcl::PCDReader::readHeader] HEIGHT (%d) x WIDTH (%d) != number of points (%d)", cloud.height, cloud.width, nr_points);
00307 return (-1);
00308 }
00309
00310
00311 fs.close ();
00312
00313 return (0);
00314 }
00315
00317 int
00318 pcl::PCDReader::read (const std::string &file_name, sensor_msgs::PointCloud2 &cloud,
00319 Eigen::Vector4f &origin, Eigen::Quaternionf &orientation, int &pcd_version)
00320 {
00321 int res = readHeader (file_name, cloud, origin, orientation, pcd_version);
00322
00323 if (res < 0)
00324 return (res);
00325
00326
00327 bool binary_data = false, data_found = false;
00328 int idx = 0;
00329
00330
00331 int nr_points = cloud.width * cloud.height;
00332
00333
00334 std::ifstream fs;
00335 fs.open (file_name.c_str ());
00336 if (!fs.is_open () || fs.fail ())
00337 {
00338 ROS_ERROR ("[pcl::PCDReader::read] Could not open file %s.", file_name.c_str ());
00339 return (-1);
00340 }
00341
00342 std::string line;
00343 std::vector<std::string> st;
00344
00345
00346 try
00347 {
00348 while (!fs.eof ())
00349 {
00350 getline (fs, line);
00351
00352 if (line == "")
00353 continue;
00354
00355
00356 boost::trim (line);
00357 boost::split (st, line, boost::is_any_of ("\t\r "), boost::token_compress_on);
00358
00359 std::string line_type = st.at (0);
00360
00361
00362 if (line_type.substr (0, 4) == "DATA")
00363 {
00364 data_found = true;
00365 if (st.at (1).substr (0, 6) == "binary")
00366 {
00367 binary_data = true;
00368 break;
00369 }
00370 continue;
00371 }
00372 else if (!data_found)
00373 continue;
00374
00375
00376
00377
00378 if (idx >= nr_points)
00379 {
00380 ROS_WARN ("[pcl::PCDReader::read] input file %s has more points than advertised (%d)!", file_name.c_str (), nr_points);
00381 break;
00382 }
00383
00384
00385 for (size_t d = 0; d < cloud.fields.size (); ++d)
00386 {
00387 for (size_t c = 0; c < cloud.fields[d].count; ++c)
00388 {
00389 switch (cloud.fields[d].datatype)
00390 {
00391 case sensor_msgs::PointField::INT8:
00392 {
00393 char value = (char)atoi (st.at (d + c).c_str ());
00394 if (!pcl_isfinite (value))
00395 cloud.is_dense = false;
00396 memcpy (&cloud.data[idx * cloud.point_step + cloud.fields[d].offset + c * sizeof (char)], &value, sizeof (char));
00397 break;
00398 }
00399 case sensor_msgs::PointField::UINT8:
00400 {
00401 unsigned char value = atoi (st.at (d + c).c_str ());
00402 if (!pcl_isfinite (value))
00403 cloud.is_dense = false;
00404 memcpy (&cloud.data[idx * cloud.point_step + cloud.fields[d].offset + c * sizeof (unsigned char)], &value, sizeof (unsigned char));
00405 break;
00406 }
00407 case sensor_msgs::PointField::INT16:
00408 {
00409 short value = atoi (st.at (d + c).c_str ());
00410 if (!pcl_isfinite (value))
00411 cloud.is_dense = false;
00412 memcpy (&cloud.data[idx * cloud.point_step + cloud.fields[d].offset + c * sizeof (short)], &value, sizeof (short));
00413 break;
00414 }
00415 case sensor_msgs::PointField::UINT16:
00416 {
00417 unsigned short value = atoi (st.at (d + c).c_str ());
00418 if (!pcl_isfinite (value))
00419 cloud.is_dense = false;
00420 memcpy (&cloud.data[idx * cloud.point_step + cloud.fields[d].offset + c * sizeof (unsigned short)], &value, sizeof (unsigned short));
00421 break;
00422 }
00423 case sensor_msgs::PointField::INT32:
00424 {
00425 int value = atoi (st.at (d + c).c_str ());
00426 if (!pcl_isfinite (value))
00427 cloud.is_dense = false;
00428 memcpy (&cloud.data[idx * cloud.point_step + cloud.fields[d].offset + c * sizeof (int)], &value, sizeof (int));
00429 break;
00430 }
00431 case sensor_msgs::PointField::UINT32:
00432 {
00433 unsigned int value = atoi (st.at (d + c).c_str ());
00434 if (!pcl_isfinite (value))
00435 cloud.is_dense = false;
00436 memcpy (&cloud.data[idx * cloud.point_step + cloud.fields[d].offset + c * sizeof (unsigned int)], &value, sizeof (unsigned int));
00437 break;
00438 }
00439 case sensor_msgs::PointField::FLOAT32:
00440 {
00441 float value = atof (st.at (d + c).c_str ());
00442 if (!pcl_isfinite (value))
00443 cloud.is_dense = false;
00444 memcpy (&cloud.data[idx * cloud.point_step + cloud.fields[d].offset + c * sizeof (float)], &value, sizeof (float));
00445 break;
00446 }
00447 case sensor_msgs::PointField::FLOAT64:
00448 {
00449 double value = atof (st.at (d + c).c_str ());
00450 if (!pcl_isfinite (value))
00451 cloud.is_dense = false;
00452 memcpy (&cloud.data[idx * cloud.point_step + cloud.fields[d].offset + c * sizeof (double)], &value, sizeof (double));
00453 break;
00454 }
00455 default:
00456 ROS_WARN ("[pcl::PCDReader::read] Incorrect field data type specified (%d)!",cloud.fields[d].datatype);
00457 break;
00458 }
00459 }
00460 }
00461
00462 idx++;
00463 }
00464 }
00465 catch (const char *exception)
00466 {
00467 ROS_ERROR ("[pcl::PCDReader::read] %s", exception);
00468 return (-1);
00469 }
00470
00471
00472 cloud.is_bigendian = false;
00473
00474
00475 fs.close ();
00476
00479 if (binary_data)
00480 {
00481
00482 cloud.is_dense = false;
00483
00484 int fd = pcl_open (file_name.c_str (), O_RDONLY);
00485 if (fd == -1)
00486 return (-1);
00487
00488
00489 #ifdef _WIN32
00490
00491 HANDLE fm = CreateFileMapping ((HANDLE) _get_osfhandle (fd), NULL, PAGE_READONLY, 0, 0, NULL);
00492 char *map = static_cast<char*>(MapViewOfFile (fm, FILE_MAP_READ, 0, 0, cloud.data.size ()));
00493 CloseHandle (fm);
00494 #else
00495 char *map = (char*)mmap (0, cloud.data.size (), PROT_READ, MAP_SHARED, fd, getpagesize ());
00496 if (map == MAP_FAILED)
00497 {
00498 pcl_close (fd);
00499 return (-1);
00500 }
00501 #endif
00502
00503 memcpy (&cloud.data[0], &map[0], cloud.data.size ());
00504
00505
00506 #if _WIN32
00507 UnmapViewOfFile (map);
00508 #else
00509 if (munmap (map, cloud.data.size ()) == -1)
00510 {
00511 pcl_close (fd);
00512 return (-1);
00513 }
00514 #endif
00515 pcl_close (fd);
00516 }
00517
00518 if ( (idx != nr_points) && (!binary_data) )
00519 {
00520 ROS_ERROR ("[pcl::PCDReader::read] Number of points read (%d) is different than expected (%d)", idx, nr_points);
00521 return (-1);
00522 }
00523
00524 return 0;
00525 }
00526
00528 int
00529 pcl::PCDReader::read (const std::string &file_name, sensor_msgs::PointCloud2 &cloud)
00530 {
00531 int pcd_version;
00532 Eigen::Vector4f origin;
00533 Eigen::Quaternionf orientation;
00534
00535 int res = read (file_name, cloud, origin, orientation, pcd_version);
00536
00537 if (res < 0)
00538 return (res);
00539
00540 if (pcd_version != PCD_V6)
00541 ROS_WARN ("[pcl::PCDReader::read] PCD file > v.6 read from disk. Sensor origin/orientation is lost.");
00542
00543 return 0;
00544 }
00545
00549 std::string
00550 pcl::PCDWriter::generateHeaderASCII (const sensor_msgs::PointCloud2 &cloud,
00551 const Eigen::Vector4f &origin, const Eigen::Quaternionf &orientation)
00552 {
00553 std::ostringstream oss;
00554
00555 oss << "# .PCD v.7 - Point Cloud Data file format"
00556 "\nFIELDS ";
00557
00558 oss << getFieldsList (cloud);
00559 oss << "\nSIZE ";
00560
00561
00562 for (size_t d = 0; d < cloud.fields.size () - 1; ++d)
00563 oss << pcl::getFieldSize (cloud.fields[d].datatype) << " ";
00564 oss << pcl::getFieldSize (cloud.fields[cloud.fields.size () - 1].datatype) << "\nTYPE ";
00565
00566
00567 for (size_t d = 0; d < cloud.fields.size () - 1; ++d)
00568 oss << pcl::getFieldType (cloud.fields[d].datatype) << " ";
00569 oss << pcl::getFieldType (cloud.fields[cloud.fields.size () - 1].datatype) << "\nCOUNT ";
00570
00571
00572 for (size_t d = 0; d < cloud.fields.size () - 1; ++d)
00573 {
00574 int count = cloud.fields[d].count;
00575 if (count == 0)
00576 count = 1;
00577
00578 oss << count << " ";
00579 }
00580 int count = cloud.fields[cloud.fields.size () - 1].count;
00581 if (count == 0)
00582 count = 1;
00583
00584 oss << count << "\nWIDTH " << cloud.width << "\nHEIGHT " << cloud.height << "\n";
00585
00586 oss << "VIEWPOINT " << origin[0] << " " << origin[1] << " " << origin[2] << " " << orientation.w () << " " <<
00587 orientation.x () << " " << orientation.y () << " " << orientation.z () << "\n";
00588
00589 oss << "POINTS " << cloud.width * cloud.height << "\n";
00590
00591 return (oss.str ());
00592 }
00593
00595 std::string
00596 pcl::PCDWriter::generateHeaderBinary (const sensor_msgs::PointCloud2 &cloud,
00597 const Eigen::Vector4f &origin, const Eigen::Quaternionf &orientation)
00598 {
00599 std::ostringstream oss;
00600
00601 oss << "# .PCD v.7 - Point Cloud Data file format"
00602 "\nFIELDS";
00603
00604
00605 unsigned int fsize = 0;
00606 for (size_t i = 0; i < cloud.fields.size (); ++i)
00607 fsize += cloud.fields[i].count * getFieldSize (cloud.fields[i].datatype);
00608
00609
00610 if (fsize > cloud.point_step)
00611 {
00612 ROS_ERROR ("[pcl::PCDWriter::generateHeader] The size of the fields (%d) is larger than point_step (%d)! Something is wrong here...", fsize, cloud.point_step);
00613 return ("");
00614 }
00615
00616 std::stringstream field_names, field_types, field_sizes, field_counts;
00617
00618 unsigned int toffset = 0;
00619 for (size_t i = 0; i < cloud.fields.size (); ++i)
00620 {
00621
00622 if (toffset != cloud.fields[i].offset)
00623 {
00624
00625 int fake_offset = (i == 0) ?
00626
00627 (cloud.fields[i].offset)
00628 :
00629
00630 (cloud.fields[i].offset -
00631 (cloud.fields[i-1].offset +
00632 cloud.fields[i-1].count * getFieldSize (cloud.fields[i].datatype)));
00633
00634 toffset += fake_offset;
00635
00636 field_names << " _";
00637 field_sizes << " 1";
00638 field_types << " U";
00639 field_counts << " " << fake_offset;
00640 }
00641
00642
00643 toffset += cloud.fields[i].count * getFieldSize (cloud.fields[i].datatype);
00644 field_names << " " << cloud.fields[i].name;
00645 field_sizes << " " << pcl::getFieldSize (cloud.fields[i].datatype);
00646 field_types << " " << pcl::getFieldType (cloud.fields[i].datatype);
00647 int count = cloud.fields[i].count;
00648 if (count == 0) count = 1;
00649 field_counts << " " << count;
00650 }
00651
00652 if (toffset < cloud.point_step)
00653 {
00654 field_names << " _";
00655 field_sizes << " 1";
00656 field_types << " U";
00657 field_counts << " " << (cloud.point_step - toffset);
00658 }
00659 oss << field_names.str ();
00660 oss << "\nSIZE" << field_sizes.str ()
00661 << "\nTYPE" << field_types.str ()
00662 << "\nCOUNT" << field_counts.str ();
00663 oss << "\nWIDTH " << cloud.width << "\nHEIGHT " << cloud.height << "\n";
00664
00665 oss << "VIEWPOINT " << origin[0] << " " << origin[1] << " " << origin[2] << " " << orientation.w () << " " <<
00666 orientation.x () << " " << orientation.y () << " " << orientation.z () << "\n";
00667
00668 oss << "POINTS " << cloud.width * cloud.height << "\n";
00669
00670 return (oss.str ());
00671 }
00672
00674 int
00675 pcl::PCDWriter::writeASCII (const std::string &file_name, const sensor_msgs::PointCloud2 &cloud,
00676 const Eigen::Vector4f &origin, const Eigen::Quaternionf &orientation,
00677 int precision)
00678 {
00679 if (cloud.data.empty ())
00680 {
00681 ROS_ERROR ("[pcl::PCDWriter::writeASCII] Input point cloud has no data!");
00682 return (-1);
00683 }
00684
00685 std::ofstream fs;
00686 fs.precision (precision);
00687 fs.open (file_name.c_str ());
00688
00689 int nr_points = cloud.width * cloud.height;
00690 int point_size = cloud.data.size () / nr_points;
00691
00692
00693 fs << generateHeaderASCII (cloud, origin, orientation) << "DATA ascii\n";
00694
00695
00696 for (int i = 0; i < nr_points; ++i)
00697 {
00698 for (size_t d = 0; d < cloud.fields.size (); ++d)
00699 {
00700 int count = cloud.fields[d].count;
00701 if (count == 0)
00702 count = 1;
00703
00704 for (int c = 0; c < count; ++c)
00705 {
00706 switch (cloud.fields[d].datatype)
00707 {
00708 case sensor_msgs::PointField::INT8:
00709 {
00710 char value;
00711 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (char)], sizeof (char));
00712 fs << boost::numeric_cast<int>(value);
00713 break;
00714 }
00715 case sensor_msgs::PointField::UINT8:
00716 {
00717 unsigned char value;
00718 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned char)], sizeof (unsigned char));
00719 fs << boost::numeric_cast<int>(value);
00720 break;
00721 }
00722 case sensor_msgs::PointField::INT16:
00723 {
00724 short value;
00725 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (short)], sizeof (short));
00726 fs << boost::numeric_cast<int>(value);
00727 break;
00728 }
00729 case sensor_msgs::PointField::UINT16:
00730 {
00731 unsigned short value;
00732 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned short)], sizeof (unsigned short));
00733 fs << boost::numeric_cast<int>(value);
00734 break;
00735 }
00736 case sensor_msgs::PointField::INT32:
00737 {
00738 int value;
00739 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (int)], sizeof (int));
00740 fs << value;
00741 break;
00742 }
00743 case sensor_msgs::PointField::UINT32:
00744 {
00745 unsigned int value;
00746 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned int)], sizeof (unsigned int));
00747 fs << value;
00748 break;
00749 }
00750 case sensor_msgs::PointField::FLOAT32:
00751 {
00752 float value;
00753 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (float)], sizeof (float));
00754 fs << value;
00755 break;
00756 }
00757 case sensor_msgs::PointField::FLOAT64:
00758 {
00759 double value;
00760 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (double)], sizeof (double));
00761 fs << value;
00762 break;
00763 }
00764 default:
00765 ROS_WARN ("[pcl::PCDWriter::writeASCII] Incorrect field data type specified (%d)!", cloud.fields[d].datatype);
00766 break;
00767 }
00768
00769 if (d < cloud.fields.size () - 1 || c < (int)cloud.fields[d].count - 1)
00770 fs << " ";
00771 }
00772 }
00773 fs << std::endl;
00774 }
00775 fs.close ();
00776 return (0);
00777 }
00778
00780 int
00781 pcl::PCDWriter::writeBinary (const std::string &file_name, const sensor_msgs::PointCloud2 &cloud,
00782 const Eigen::Vector4f &origin, const Eigen::Quaternionf &orientation)
00783 {
00784 if (cloud.data.empty ())
00785 {
00786 ROS_ERROR ("[pcl::PCDWriter::writeBinary] Input point cloud has no data!");
00787 return (-1);
00788 }
00789 int data_idx = 0;
00790 std::ofstream fs;
00791
00792 fs.open (file_name.c_str ());
00793
00794
00795 fs << generateHeaderBinary (cloud, origin, orientation) << "DATA binary\n";
00796
00797 data_idx = fs.tellp ();
00798
00799 fs.close ();
00800
00801 #ifndef _WIN32
00802 if (data_idx > getpagesize ())
00803 {
00804 ROS_ERROR ("[pcl::PCDWriter::writeBinary] Header size (%d) is bigger than page size (%d)! Reduce the number of channels or save in ASCII format.", data_idx, getpagesize ());
00805 return (-1);
00806 }
00807 #endif
00808
00809
00810 int fd = pcl_open (file_name.c_str (), O_RDWR);
00811 if (fd < 0)
00812 {
00813 ROS_ERROR ("[pcl::PCDWriter::writeBinary] Error during open ()!");
00814 return (-1);
00815 }
00816
00817
00818 #ifdef _WIN32
00819 int result = pcl_lseek (fd, cloud.data.size () - 1, SEEK_SET);
00820 #else
00821 int result = pcl_lseek (fd, getpagesize () + cloud.data.size () - 1, SEEK_SET);
00822 #endif
00823 if (result < 0)
00824 {
00825 pcl_close (fd);
00826 ROS_ERROR ("[pcl::PCDWriter::writeBinary] Error during lseek ()!");
00827 return (-1);
00828 }
00829
00830 result = ::write (fd, "", 1);
00831 if (result != 1)
00832 {
00833 pcl_close (fd);
00834 ROS_ERROR ("[pcl::PCDWriter::writeBinary] Error during write ()!");
00835 return (-1);
00836 }
00837
00838
00839 #ifdef _WIN32
00840 HANDLE fm = CreateFileMapping ((HANDLE) _get_osfhandle (fd), NULL, PAGE_READWRITE, 0, 0, NULL);
00841 char *map = static_cast<char*>(MapViewOfFile (fm, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, cloud.data.size ()));
00842
00843 CloseHandle (fm);
00844 #else
00845 char *map = (char*)mmap (0, cloud.data.size (), PROT_READ | PROT_WRITE, MAP_SHARED, fd, getpagesize ());
00846 if (map == MAP_FAILED)
00847 {
00848 pcl_close (fd);
00849 ROS_ERROR ("[pcl::PCDWriter::writeBinary] Error during mmap ()!");
00850 return (-1);
00851 }
00852 #endif
00853
00854
00855 memcpy (&map[0], &cloud.data[0], cloud.data.size ());
00856
00857
00858 #if _WIN32
00859 UnmapViewOfFile (map);
00860 #else
00861 if (munmap (map, (cloud.data.size ())) == -1)
00862 {
00863 pcl_close (fd);
00864 ROS_ERROR ("[pcl::PCDWriter::writeBinary] Error during munmap ()!");
00865 return (-1);
00866 }
00867 #endif
00868
00869 pcl_close (fd);
00870 return (0);
00871 }