|
Point Cloud Library (PCL)
1.5.1
|
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.hpp 4085 2012-01-31 02:09:38Z rusu $ 00037 * 00038 */ 00039 00040 #ifndef PCL_IO_PCD_IO_IMPL_H_ 00041 #define PCL_IO_PCD_IO_IMPL_H_ 00042 00043 #include <fstream> 00044 #include <fcntl.h> 00045 #include <string> 00046 #include <stdlib.h> 00047 #include <boost/algorithm/string.hpp> 00048 #include <pcl/channel_properties.h> 00049 #include <pcl/console/print.h> 00050 #ifdef _WIN32 00051 # include <io.h> 00052 # ifndef WIN32_LEAN_AND_MEAN 00053 # define WIN32_LEAN_AND_MEAN 00054 # endif WIN32_LEAN_AND_MEAN 00055 # ifndef NOMINMAX 00056 # define NOMINMAX 00057 # endif NOMINMAX 00058 # include <windows.h> 00059 # define pcl_open _open 00060 # define pcl_close(fd) _close(fd) 00061 # define pcl_lseek(fd,offset,origin) _lseek(fd,offset,origin) 00062 #else 00063 # include <sys/mman.h> 00064 # define pcl_open open 00065 # define pcl_close(fd) close(fd) 00066 # define pcl_lseek(fd,offset,origin) lseek(fd,offset,origin) 00067 #endif 00068 00069 #include <pcl/io/lzf.h> 00070 00072 template <typename PointT> std::string 00073 pcl::PCDWriter::generateHeader (const pcl::PointCloud<PointT> &cloud, const int nr_points) 00074 { 00075 std::ostringstream oss; 00076 oss.imbue (std::locale::classic ()); 00077 00078 oss << "# .PCD v0.7 - Point Cloud Data file format" 00079 "\nVERSION 0.7" 00080 "\nFIELDS"; 00081 00082 std::vector<sensor_msgs::PointField> fields; 00083 pcl::getFields (cloud, fields); 00084 00085 std::stringstream field_names, field_types, field_sizes, field_counts; 00086 for (size_t i = 0; i < fields.size (); ++i) 00087 { 00088 if (fields[i].name == "_") 00089 continue; 00090 // Add the regular dimension 00091 field_names << " " << fields[i].name; 00092 field_sizes << " " << pcl::getFieldSize (fields[i].datatype); 00093 field_types << " " << pcl::getFieldType (fields[i].datatype); 00094 int count = abs ((int)fields[i].count); 00095 if (count == 0) count = 1; // check for 0 counts (coming from older converter code) 00096 field_counts << " " << count; 00097 } 00098 oss << field_names.str (); 00099 oss << "\nSIZE" << field_sizes.str () 00100 << "\nTYPE" << field_types.str () 00101 << "\nCOUNT" << field_counts.str (); 00102 // If the user passes in a number of points value, use that instead 00103 if (nr_points != std::numeric_limits<int>::max ()) 00104 oss << "\nWIDTH " << nr_points << "\nHEIGHT " << 1 << "\n"; 00105 else 00106 oss << "\nWIDTH " << cloud.width << "\nHEIGHT " << cloud.height << "\n"; 00107 00108 oss << "VIEWPOINT " << cloud.sensor_origin_[0] << " " << cloud.sensor_origin_[1] << " " << cloud.sensor_origin_[2] << " " << 00109 cloud.sensor_orientation_.w () << " " << 00110 cloud.sensor_orientation_.x () << " " << 00111 cloud.sensor_orientation_.y () << " " << 00112 cloud.sensor_orientation_.z () << "\n"; 00113 00114 // If the user passes in a number of points value, use that instead 00115 if (nr_points != std::numeric_limits<int>::max ()) 00116 oss << "POINTS " << nr_points << "\n"; 00117 else 00118 oss << "POINTS " << cloud.points.size () << "\n"; 00119 00120 return (oss.str ()); 00121 } 00122 00124 template <typename PointT> int 00125 pcl::PCDWriter::writeBinary (const std::string &file_name, 00126 const pcl::PointCloud<PointT> &cloud) 00127 { 00128 if (cloud.empty ()) 00129 { 00130 throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Input point cloud has no data!"); 00131 return (-1); 00132 } 00133 int data_idx = 0; 00134 std::ostringstream oss; 00135 oss << generateHeader<PointT> (cloud) << "DATA binary\n"; 00136 oss.flush (); 00137 data_idx = (int) oss.tellp (); 00138 00139 #if _WIN32 00140 HANDLE h_native_file = CreateFileA (file_name.c_str (), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 00141 if(h_native_file == INVALID_HANDLE_VALUE) 00142 { 00143 throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Error during CreateFile!"); 00144 return (-1); 00145 } 00146 #else 00147 int fd = pcl_open (file_name.c_str (), O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600); 00148 if (fd < 0) 00149 { 00150 throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Error during open!"); 00151 return (-1); 00152 } 00153 #endif 00154 00155 std::vector<sensor_msgs::PointField> fields; 00156 std::vector<int> fields_sizes; 00157 size_t fsize = 0; 00158 size_t data_size = 0; 00159 size_t nri = 0; 00160 pcl::getFields (cloud, fields); 00161 // Compute the total size of the fields 00162 for (size_t i = 0; i < fields.size (); ++i) 00163 { 00164 if (fields[i].name == "_") 00165 continue; 00166 00167 int fs = fields[i].count * getFieldSize (fields[i].datatype); 00168 fsize += fs; 00169 fields_sizes.push_back (fs); 00170 fields[nri++] = fields[i]; 00171 } 00172 fields.resize (nri); 00173 00174 data_size = cloud.points.size () * fsize; 00175 00176 // Prepare the map 00177 #if _WIN32 00178 HANDLE fm = CreateFileMappingA (h_native_file, NULL, PAGE_READWRITE, 0, (DWORD) (data_idx + data_size), NULL); 00179 char *map = static_cast<char*>(MapViewOfFile (fm, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, data_idx + data_size)); 00180 CloseHandle (fm); 00181 00182 #else 00183 // Stretch the file size to the size of the data 00184 int result = pcl_lseek (fd, getpagesize () + data_size - 1, SEEK_SET); 00185 if (result < 0) 00186 { 00187 pcl_close (fd); 00188 throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Error during lseek ()!"); 00189 return (-1); 00190 } 00191 // Write a bogus entry so that the new file size comes in effect 00192 result = ::write (fd, "", 1); 00193 if (result != 1) 00194 { 00195 pcl_close (fd); 00196 throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Error during write ()!"); 00197 return (-1); 00198 } 00199 00200 char *map = (char*)mmap (0, data_idx + data_size, PROT_WRITE, MAP_SHARED, fd, 0); 00201 if (map == MAP_FAILED) 00202 { 00203 pcl_close (fd); 00204 throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Error during mmap ()!"); 00205 return (-1); 00206 } 00207 #endif 00208 00209 // Copy the header 00210 memcpy (&map[0], oss.str ().c_str (), data_idx); 00211 00212 // Copy the data 00213 char *out = &map[0] + data_idx; 00214 for (size_t i = 0; i < cloud.points.size (); ++i) 00215 { 00216 int nrj = 0; 00217 for (size_t j = 0; j < fields.size (); ++j) 00218 { 00219 memcpy (out, (const char*)&cloud.points[i] + fields[j].offset, fields_sizes[nrj]); 00220 out += fields_sizes[nrj++]; 00221 } 00222 } 00223 00224 // If the user set the synchronization flag on, call msync 00225 #if !_WIN32 00226 if (map_synchronization_) 00227 msync (map, data_idx + data_size, MS_SYNC); 00228 #endif 00229 00230 // Unmap the pages of memory 00231 #if _WIN32 00232 UnmapViewOfFile (map); 00233 #else 00234 if (munmap (map, (data_idx + data_size)) == -1) 00235 { 00236 pcl_close (fd); 00237 throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Error during munmap ()!"); 00238 return (-1); 00239 } 00240 #endif 00241 // Close file 00242 #if _WIN32 00243 CloseHandle (h_native_file); 00244 #else 00245 pcl_close (fd); 00246 #endif 00247 return (0); 00248 } 00249 00251 template <typename PointT> int 00252 pcl::PCDWriter::writeBinaryCompressed (const std::string &file_name, 00253 const pcl::PointCloud<PointT> &cloud) 00254 { 00255 if (cloud.points.empty ()) 00256 { 00257 throw pcl::IOException ("[pcl::PCDWriter::writeBinaryCompressed] Input point cloud has no data!"); 00258 return (-1); 00259 } 00260 int data_idx = 0; 00261 std::ostringstream oss; 00262 oss << generateHeader<PointT> (cloud) << "DATA binary_compressed\n"; 00263 oss.flush (); 00264 data_idx = oss.tellp (); 00265 00266 #if _WIN32 00267 HANDLE h_native_file = CreateFileA (file_name.c_str (), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 00268 if(h_native_file == INVALID_HANDLE_VALUE) 00269 { 00270 throw pcl::IOException ("[pcl::PCDWriter::writeBinaryCompressed] Error during CreateFile!"); 00271 return (-1); 00272 } 00273 #else 00274 int fd = pcl_open (file_name.c_str (), O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600); 00275 if (fd < 0) 00276 { 00277 throw pcl::IOException ("[pcl::PCDWriter::writeBinaryCompressed] Error during open!"); 00278 return (-1); 00279 } 00280 #endif 00281 00282 std::vector<sensor_msgs::PointField> fields; 00283 size_t fsize = 0; 00284 size_t data_size = 0; 00285 size_t nri = 0; 00286 pcl::getFields (cloud, fields); 00287 std::vector<int> fields_sizes (fields.size ()); 00288 // Compute the total size of the fields 00289 for (size_t i = 0; i < fields.size (); ++i) 00290 { 00291 if (fields[i].name == "_") 00292 continue; 00293 00294 fields_sizes[nri] = fields[i].count * pcl::getFieldSize (fields[i].datatype); 00295 fsize += fields_sizes[nri]; 00296 fields[nri] = fields[i]; 00297 ++nri; 00298 } 00299 fields_sizes.resize (nri); 00300 fields.resize (nri); 00301 00302 // Compute the size of data 00303 data_size = cloud.points.size () * fsize; 00304 00306 // Empty array holding only the valid data 00307 // data_size = nr_points * point_size 00308 // = nr_points * (sizeof_field_1 + sizeof_field_2 + ... sizeof_field_n) 00309 // = sizeof_field_1 * nr_points + sizeof_field_2 * nr_points + ... sizeof_field_n * nr_points 00310 char *only_valid_data = (char*)malloc (data_size); 00311 00312 // Convert the XYZRGBXYZRGB structure to XXYYZZRGBRGB to aid compression. For 00313 // this, we need a vector of fields.size () (4 in this case), which points to 00314 // each individual plane: 00315 // pters[0] = &only_valid_data[offset_of_plane_x]; 00316 // pters[1] = &only_valid_data[offset_of_plane_y]; 00317 // pters[2] = &only_valid_data[offset_of_plane_z]; 00318 // pters[3] = &only_valid_data[offset_of_plane_RGB]; 00319 // 00320 std::vector<char*> pters (fields.size ()); 00321 int toff = 0; 00322 for (size_t i = 0; i < pters.size (); ++i) 00323 { 00324 pters[i] = &only_valid_data[toff]; 00325 toff += fields_sizes[i] * cloud.points.size (); 00326 } 00327 00328 // Go over all the points, and copy the data in the appropriate places 00329 for (size_t i = 0; i < cloud.points.size (); ++i) 00330 { 00331 for (size_t j = 0; j < fields.size (); ++j) 00332 { 00333 memcpy (pters[j], (const char*)&cloud.points[i] + fields[j].offset, fields_sizes[j]); 00334 // Increment the pointer 00335 pters[j] += fields_sizes[j]; 00336 } 00337 } 00338 00339 char* temp_buf = (char*)malloc (data_size * 1.5 + 8); 00340 // Compress the valid data 00341 unsigned int compressed_size = pcl::lzfCompress (only_valid_data, data_size, &temp_buf[8], data_size * 1.5); 00342 unsigned int compressed_final_size = 0; 00343 // Was the compression successful? 00344 if (compressed_size) 00345 { 00346 char *header = &temp_buf[0]; 00347 memcpy (&header[0], &compressed_size, sizeof (unsigned int)); 00348 memcpy (&header[4], &data_size, sizeof (unsigned int)); 00349 data_size = compressed_size + 8; 00350 compressed_final_size = data_size + data_idx; 00351 } 00352 else 00353 { 00354 #if !_WIN32 00355 pcl_close (fd); 00356 #endif 00357 throw pcl::IOException ("[pcl::PCDWriter::writeBinaryCompressed] Error during compression!"); 00358 return (-1); 00359 } 00360 00361 #if !_WIN32 00362 // Stretch the file size to the size of the data 00363 int result = pcl_lseek (fd, getpagesize () + data_size - 1, SEEK_SET); 00364 if (result < 0) 00365 { 00366 pcl_close (fd); 00367 throw pcl::IOException ("[pcl::PCDWriter::writeBinaryCompressed] Error during lseek ()!"); 00368 return (-1); 00369 } 00370 // Write a bogus entry so that the new file size comes in effect 00371 result = ::write (fd, "", 1); 00372 if (result != 1) 00373 { 00374 pcl_close (fd); 00375 throw pcl::IOException ("[pcl::PCDWriter::writeBinaryCompressed] Error during write ()!"); 00376 return (-1); 00377 } 00378 #endif 00379 00380 // Prepare the map 00381 #if _WIN32 00382 HANDLE fm = CreateFileMapping (h_native_file, NULL, PAGE_READWRITE, 0, compressed_final_size, NULL); 00383 char *map = static_cast<char*>(MapViewOfFile (fm, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, compressed_final_size)); 00384 CloseHandle (fm); 00385 00386 #else 00387 char *map = (char*)mmap (0, compressed_final_size, PROT_WRITE, MAP_SHARED, fd, 0); 00388 if (map == MAP_FAILED) 00389 { 00390 pcl_close (fd); 00391 throw pcl::IOException ("[pcl::PCDWriter::writeBinaryCompressed] Error during mmap ()!"); 00392 return (-1); 00393 } 00394 #endif 00395 00396 // Copy the header 00397 memcpy (&map[0], oss.str ().c_str (), data_idx); 00398 // Copy the compressed data 00399 memcpy (&map[data_idx], temp_buf, data_size); 00400 00401 #if !_WIN32 00402 // If the user set the synchronization flag on, call msync 00403 if (map_synchronization_) 00404 msync (map, compressed_final_size, MS_SYNC); 00405 #endif 00406 00407 // Unmap the pages of memory 00408 #if _WIN32 00409 UnmapViewOfFile (map); 00410 #else 00411 if (munmap (map, (compressed_final_size)) == -1) 00412 { 00413 pcl_close (fd); 00414 throw pcl::IOException ("[pcl::PCDWriter::writeBinaryCompressed] Error during munmap ()!"); 00415 return (-1); 00416 } 00417 #endif 00418 // Close file 00419 #if _WIN32 00420 CloseHandle (h_native_file); 00421 #else 00422 pcl_close (fd); 00423 #endif 00424 00425 free (only_valid_data); 00426 free (temp_buf); 00427 return (0); 00428 } 00429 00431 template <typename PointT> int 00432 pcl::PCDWriter::writeASCII (const std::string &file_name, const pcl::PointCloud<PointT> &cloud, 00433 const int precision) 00434 { 00435 if (cloud.empty ()) 00436 { 00437 throw pcl::IOException ("[pcl::PCDWriter::writeASCII] Input point cloud has no data!"); 00438 return (-1); 00439 } 00440 00441 if (cloud.width * cloud.height != cloud.points.size ()) 00442 { 00443 throw pcl::IOException ("[pcl::PCDWriter::writeASCII] Number of points different than width * height!"); 00444 return (-1); 00445 } 00446 00447 std::ofstream fs; 00448 fs.open (file_name.c_str ()); // Open file 00449 00450 if (!fs.is_open () || fs.fail ()) 00451 { 00452 throw pcl::IOException ("[pcl::PCDWriter::writeASCII] Could not open file for writing!"); 00453 return (-1); 00454 } 00455 00456 fs.precision (precision); 00457 fs.imbue (std::locale::classic ()); 00458 00459 std::vector<sensor_msgs::PointField> fields; 00460 pcl::getFields (cloud, fields); 00461 00462 // Write the header information 00463 fs << generateHeader<PointT> (cloud) << "DATA ascii\n"; 00464 00465 std::ostringstream stream; 00466 stream.precision (precision); 00467 stream.imbue (std::locale::classic ()); 00468 // Iterate through the points 00469 for (size_t i = 0; i < cloud.points.size (); ++i) 00470 { 00471 for (size_t d = 0; d < fields.size (); ++d) 00472 { 00473 // Ignore invalid padded dimensions that are inherited from binary data 00474 if (fields[d].name == "_") 00475 continue; 00476 00477 int count = fields[d].count; 00478 if (count == 0) 00479 count = 1; // we simply cannot tolerate 0 counts (coming from older converter code) 00480 00481 for (int c = 0; c < count; ++c) 00482 { 00483 switch (fields[d].datatype) 00484 { 00485 case sensor_msgs::PointField::INT8: 00486 { 00487 int8_t value; 00488 memcpy (&value, (const char*)&cloud.points[i] + fields[d].offset + c * sizeof (int8_t), sizeof (int8_t)); 00489 if (pcl_isnan (value)) 00490 stream << "nan"; 00491 else 00492 stream << boost::numeric_cast<uint32_t>(value); 00493 break; 00494 } 00495 case sensor_msgs::PointField::UINT8: 00496 { 00497 uint8_t value; 00498 memcpy (&value, (const char*)&cloud.points[i] + fields[d].offset + c * sizeof (uint8_t), sizeof (uint8_t)); 00499 if (pcl_isnan (value)) 00500 stream << "nan"; 00501 else 00502 stream << boost::numeric_cast<uint32_t>(value); 00503 break; 00504 } 00505 case sensor_msgs::PointField::INT16: 00506 { 00507 int16_t value; 00508 memcpy (&value, (const char*)&cloud.points[i] + fields[d].offset + c * sizeof (int16_t), sizeof (int16_t)); 00509 if (pcl_isnan (value)) 00510 stream << "nan"; 00511 else 00512 stream << boost::numeric_cast<int16_t>(value); 00513 break; 00514 } 00515 case sensor_msgs::PointField::UINT16: 00516 { 00517 uint16_t value; 00518 memcpy (&value, (const char*)&cloud.points[i] + fields[d].offset + c * sizeof (uint16_t), sizeof (uint16_t)); 00519 if (pcl_isnan (value)) 00520 stream << "nan"; 00521 else 00522 stream << boost::numeric_cast<uint16_t>(value); 00523 break; 00524 } 00525 case sensor_msgs::PointField::INT32: 00526 { 00527 int32_t value; 00528 memcpy (&value, (const char*)&cloud.points[i] + fields[d].offset + c * sizeof (int32_t), sizeof (int32_t)); 00529 if (pcl_isnan (value)) 00530 stream << "nan"; 00531 else 00532 stream << boost::numeric_cast<int32_t>(value); 00533 break; 00534 } 00535 case sensor_msgs::PointField::UINT32: 00536 { 00537 uint32_t value; 00538 memcpy (&value, (const char*)&cloud.points[i] + fields[d].offset + c * sizeof (uint32_t), sizeof (uint32_t)); 00539 if (pcl_isnan (value)) 00540 stream << "nan"; 00541 else 00542 stream << boost::numeric_cast<uint32_t>(value); 00543 break; 00544 } 00545 case sensor_msgs::PointField::FLOAT32: 00546 { 00547 float value; 00548 memcpy (&value, (const char*)&cloud.points[i] + fields[d].offset + c * sizeof (float), sizeof (float)); 00549 if (pcl_isnan (value)) 00550 stream << "nan"; 00551 else 00552 stream << boost::numeric_cast<float>(value); 00553 break; 00554 } 00555 case sensor_msgs::PointField::FLOAT64: 00556 { 00557 double value; 00558 memcpy (&value, (const char*)&cloud.points[i] + fields[d].offset + c * sizeof (double), sizeof (double)); 00559 if (pcl_isnan (value)) 00560 stream << "nan"; 00561 else 00562 stream << boost::numeric_cast<double>(value); 00563 break; 00564 } 00565 default: 00566 PCL_WARN ("[pcl::PCDWriter::writeASCII] Incorrect field data type specified (%d)!\n", fields[d].datatype); 00567 break; 00568 } 00569 00570 if (d < fields.size () - 1 || c < (int)fields[d].count - 1) 00571 stream << " "; 00572 } 00573 } 00574 // Copy the stream, trim it, and write it to disk 00575 std::string result = stream.str (); 00576 boost::trim (result); 00577 stream.str (""); 00578 fs << result << "\n"; 00579 } 00580 fs.close (); // Close file 00581 return (0); 00582 } 00583 00584 00586 template <typename PointT> int 00587 pcl::PCDWriter::writeBinary (const std::string &file_name, 00588 const pcl::PointCloud<PointT> &cloud, 00589 const std::vector<int> &indices) 00590 { 00591 if (cloud.points.empty () || indices.empty ()) 00592 { 00593 throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Input point cloud has no data or empty indices given!"); 00594 return (-1); 00595 } 00596 int data_idx = 0; 00597 std::ostringstream oss; 00598 oss << generateHeader<PointT> (cloud, indices.size ()) << "DATA binary\n"; 00599 oss.flush (); 00600 data_idx = oss.tellp (); 00601 00602 #if _WIN32 00603 HANDLE h_native_file = CreateFileA (file_name.c_str (), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 00604 if(h_native_file == INVALID_HANDLE_VALUE) 00605 { 00606 throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Error during CreateFile!"); 00607 return (-1); 00608 } 00609 #else 00610 int fd = pcl_open (file_name.c_str (), O_RDWR | O_CREAT | O_TRUNC, (mode_t)0600); 00611 if (fd < 0) 00612 { 00613 throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Error during open!"); 00614 return (-1); 00615 } 00616 #endif 00617 00618 std::vector<sensor_msgs::PointField> fields; 00619 std::vector<int> fields_sizes; 00620 size_t fsize = 0; 00621 size_t data_size = 0; 00622 size_t nri = 0; 00623 pcl::getFields (cloud, fields); 00624 // Compute the total size of the fields 00625 for (size_t i = 0; i < fields.size (); ++i) 00626 { 00627 if (fields[i].name == "_") 00628 continue; 00629 00630 int fs = fields[i].count * getFieldSize (fields[i].datatype); 00631 fsize += fs; 00632 fields_sizes.push_back (fs); 00633 fields[nri++] = fields[i]; 00634 } 00635 fields.resize (nri); 00636 00637 data_size = indices.size () * fsize; 00638 00639 // Prepare the map 00640 #if _WIN32 00641 HANDLE fm = CreateFileMapping (h_native_file, NULL, PAGE_READWRITE, 0, data_idx + data_size, NULL); 00642 char *map = static_cast<char*>(MapViewOfFile (fm, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, data_idx + data_size)); 00643 CloseHandle (fm); 00644 00645 #else 00646 // Stretch the file size to the size of the data 00647 int result = pcl_lseek (fd, getpagesize () + data_size - 1, SEEK_SET); 00648 if (result < 0) 00649 { 00650 pcl_close (fd); 00651 throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Error during lseek ()!"); 00652 return (-1); 00653 } 00654 // Write a bogus entry so that the new file size comes in effect 00655 result = ::write (fd, "", 1); 00656 if (result != 1) 00657 { 00658 pcl_close (fd); 00659 throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Error during write ()!"); 00660 return (-1); 00661 } 00662 00663 char *map = (char*)mmap (0, data_idx + data_size, PROT_WRITE, MAP_SHARED, fd, 0); 00664 if (map == MAP_FAILED) 00665 { 00666 pcl_close (fd); 00667 throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Error during mmap ()!"); 00668 return (-1); 00669 } 00670 #endif 00671 00672 // Copy the header 00673 memcpy (&map[0], oss.str ().c_str (), data_idx); 00674 00675 char *out = &map[0] + data_idx; 00676 // Copy the data 00677 for (size_t i = 0; i < indices.size (); ++i) 00678 { 00679 int nrj = 0; 00680 for (size_t j = 0; j < fields.size (); ++j) 00681 { 00682 memcpy (out, (const char*)&cloud.points[indices[i]] + fields[j].offset, fields_sizes[nrj]); 00683 out += fields_sizes[nrj++]; 00684 } 00685 } 00686 00687 #if !_WIN32 00688 // If the user set the synchronization flag on, call msync 00689 if (map_synchronization_) 00690 msync (map, data_idx + data_size, MS_SYNC); 00691 #endif 00692 00693 // Unmap the pages of memory 00694 #if _WIN32 00695 UnmapViewOfFile (map); 00696 #else 00697 if (munmap (map, (data_idx + data_size)) == -1) 00698 { 00699 pcl_close (fd); 00700 throw pcl::IOException ("[pcl::PCDWriter::writeBinary] Error during munmap ()!"); 00701 return (-1); 00702 } 00703 #endif 00704 // Close file 00705 #if _WIN32 00706 CloseHandle(h_native_file); 00707 #else 00708 pcl_close (fd); 00709 #endif 00710 return (0); 00711 } 00712 00714 template <typename PointT> int 00715 pcl::PCDWriter::writeASCII (const std::string &file_name, 00716 const pcl::PointCloud<PointT> &cloud, 00717 const std::vector<int> &indices, 00718 const int precision) 00719 { 00720 if (cloud.points.empty () || indices.empty ()) 00721 { 00722 throw pcl::IOException ("[pcl::PCDWriter::writeASCII] Input point cloud has no data or empty indices given!"); 00723 return (-1); 00724 } 00725 00726 if (cloud.width * cloud.height != cloud.points.size ()) 00727 { 00728 throw pcl::IOException ("[pcl::PCDWriter::writeASCII] Number of points different than width * height!"); 00729 return (-1); 00730 } 00731 00732 std::ofstream fs; 00733 fs.open (file_name.c_str ()); // Open file 00734 if (!fs.is_open () || fs.fail ()) 00735 { 00736 throw pcl::IOException ("[pcl::PCDWriter::writeASCII] Could not open file for writing!"); 00737 return (-1); 00738 } 00739 fs.precision (precision); 00740 fs.imbue (std::locale::classic ()); 00741 00742 std::vector<sensor_msgs::PointField> fields; 00743 pcl::getFields (cloud, fields); 00744 00745 // Write the header information 00746 fs << generateHeader<PointT> (cloud, indices.size ()) << "DATA ascii\n"; 00747 00748 std::ostringstream stream; 00749 stream.precision (precision); 00750 stream.imbue (std::locale::classic ()); 00751 00752 // Iterate through the points 00753 for (size_t i = 0; i < indices.size (); ++i) 00754 { 00755 for (size_t d = 0; d < fields.size (); ++d) 00756 { 00757 // Ignore invalid padded dimensions that are inherited from binary data 00758 if (fields[d].name == "_") 00759 continue; 00760 00761 int count = fields[d].count; 00762 if (count == 0) 00763 count = 1; // we simply cannot tolerate 0 counts (coming from older converter code) 00764 00765 for (int c = 0; c < count; ++c) 00766 { 00767 switch (fields[d].datatype) 00768 { 00769 case sensor_msgs::PointField::INT8: 00770 { 00771 int8_t value; 00772 memcpy (&value, (const char*)&cloud.points[indices[i]] + fields[d].offset + c * sizeof (int8_t), sizeof (int8_t)); 00773 if (pcl_isnan (value)) 00774 stream << "nan"; 00775 else 00776 stream << boost::numeric_cast<uint32_t>(value); 00777 break; 00778 } 00779 case sensor_msgs::PointField::UINT8: 00780 { 00781 uint8_t value; 00782 memcpy (&value, (const char*)&cloud.points[indices[i]] + fields[d].offset + c * sizeof (uint8_t), sizeof (uint8_t)); 00783 if (pcl_isnan (value)) 00784 stream << "nan"; 00785 else 00786 stream << boost::numeric_cast<uint32_t>(value); 00787 break; 00788 } 00789 case sensor_msgs::PointField::INT16: 00790 { 00791 int16_t value; 00792 memcpy (&value, (const char*)&cloud.points[indices[i]] + fields[d].offset + c * sizeof (int16_t), sizeof (int16_t)); 00793 if (pcl_isnan (value)) 00794 stream << "nan"; 00795 else 00796 stream << boost::numeric_cast<int16_t>(value); 00797 break; 00798 } 00799 case sensor_msgs::PointField::UINT16: 00800 { 00801 uint16_t value; 00802 memcpy (&value, (const char*)&cloud.points[indices[i]] + fields[d].offset + c * sizeof (uint16_t), sizeof (uint16_t)); 00803 if (pcl_isnan (value)) 00804 stream << "nan"; 00805 else 00806 stream << boost::numeric_cast<uint16_t>(value); 00807 break; 00808 } 00809 case sensor_msgs::PointField::INT32: 00810 { 00811 int32_t value; 00812 memcpy (&value, (const char*)&cloud.points[indices[i]] + fields[d].offset + c * sizeof (int32_t), sizeof (int32_t)); 00813 if (pcl_isnan (value)) 00814 stream << "nan"; 00815 else 00816 stream << boost::numeric_cast<int32_t>(value); 00817 break; 00818 } 00819 case sensor_msgs::PointField::UINT32: 00820 { 00821 uint32_t value; 00822 memcpy (&value, (const char*)&cloud.points[indices[i]] + fields[d].offset + c * sizeof (uint32_t), sizeof (uint32_t)); 00823 if (pcl_isnan (value)) 00824 stream << "nan"; 00825 else 00826 stream << boost::numeric_cast<uint32_t>(value); 00827 break; 00828 } 00829 case sensor_msgs::PointField::FLOAT32: 00830 { 00831 float value; 00832 memcpy (&value, (const char*)&cloud.points[indices[i]] + fields[d].offset + c * sizeof (float), sizeof (float)); 00833 if (pcl_isnan (value)) 00834 stream << "nan"; 00835 else 00836 stream << boost::numeric_cast<float>(value); 00837 break; 00838 } 00839 case sensor_msgs::PointField::FLOAT64: 00840 { 00841 double value; 00842 memcpy (&value, (const char*)&cloud.points[indices[i]] + fields[d].offset + c * sizeof (double), sizeof (double)); 00843 if (pcl_isnan (value)) 00844 stream << "nan"; 00845 else 00846 stream << boost::numeric_cast<double>(value); 00847 break; 00848 } 00849 default: 00850 PCL_WARN ("[pcl::PCDWriter::writeASCII] Incorrect field data type specified (%d)!\n", fields[d].datatype); 00851 break; 00852 } 00853 00854 if (d < fields.size () - 1 || c < (int)fields[d].count - 1) 00855 stream << " "; 00856 } 00857 } 00858 // Copy the stream, trim it, and write it to disk 00859 std::string result = stream.str (); 00860 boost::trim (result); 00861 stream.str (""); 00862 fs << result << "\n"; 00863 } 00864 fs.close (); // Close file 00865 return (0); 00866 } 00867 00868 #endif //#ifndef PCL_IO_PCD_IO_H_ 00869
1.8.0