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