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 <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 <pcl/io/boost.h>
00047 #include <sstream>
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
00057 if (cloud_->width == 0 || cloud_->height == 0)
00058 {
00059 cloud_->width = static_cast<uint32_t> (count);
00060 cloud_->height = 1;
00061 }
00062 cloud_->is_dense = false;
00063 cloud_->point_step = 0;
00064 cloud_->row_step = 0;
00065 vertex_count_ = 0;
00066 return (boost::tuple<boost::function<void ()>, boost::function<void ()> > (
00067 boost::bind (&pcl::PLYReader::vertexBeginCallback, this),
00068 boost::bind (&pcl::PLYReader::vertexEndCallback, this)));
00069 }
00070
00071
00072
00073
00074
00075
00076 else if (element_name == "camera")
00077 {
00078 cloud_->is_dense = true;
00079 return (boost::tuple<boost::function<void ()>, boost::function<void ()> > (0, 0));
00080 }
00081 else if (element_name == "range_grid")
00082 {
00083 (*range_grid_).resize (count);
00084 range_count_ = 0;
00085 return (boost::tuple<boost::function<void ()>, boost::function<void ()> > (
00086 boost::bind (&pcl::PLYReader::rangeGridBeginCallback, this),
00087 boost::bind (&pcl::PLYReader::rangeGridEndCallback, this)));
00088 }
00089 else
00090 {
00091 return (boost::tuple<boost::function<void ()>, boost::function<void ()> > (0, 0));
00092 }
00093 }
00094
00095 bool
00096 pcl::PLYReader::endHeaderCallback ()
00097 {
00098 cloud_->data.resize (cloud_->point_step * cloud_->width * cloud_->height);
00099 return (cloud_->data.size () == cloud_->point_step * cloud_->width * cloud_->height);
00100 }
00101
00102 void
00103 pcl::PLYReader::appendFloatProperty (const std::string& name, const size_t& size)
00104 {
00105 cloud_->fields.push_back (::pcl::PCLPointField ());
00106 ::pcl::PCLPointField ¤t_field = cloud_->fields.back ();
00107 current_field.name = name;
00108 current_field.offset = cloud_->point_step;
00109 current_field.datatype = ::pcl::PCLPointField::FLOAT32;
00110 current_field.count = static_cast<uint32_t> (size);
00111 cloud_->point_step += static_cast<uint32_t> (pcl::getFieldSize (::pcl::PCLPointField::FLOAT32) * size);
00112 }
00113
00114 void
00115 pcl::PLYReader::amendProperty (const std::string& old_name, const std::string& new_name, uint8_t new_datatype)
00116 {
00117 std::vector< ::pcl::PCLPointField>::reverse_iterator finder = cloud_->fields.rbegin ();
00118 for (; finder != cloud_->fields.rend (); ++finder)
00119 if (finder->name == old_name)
00120 break;
00121 assert (finder != cloud_->fields.rend ());
00122 finder->name = new_name;
00123 if (new_datatype > 0 && new_datatype != finder->datatype)
00124 finder->datatype = new_datatype;
00125 }
00126
00127 void
00128 pcl::PLYReader::appendUnsignedIntProperty (const std::string& name, const size_t& size)
00129 {
00130 cloud_->fields.push_back (::pcl::PCLPointField ());
00131 ::pcl::PCLPointField ¤t_field = cloud_->fields.back ();
00132 current_field.name = name;
00133 current_field.offset = cloud_->point_step;
00134 current_field.datatype = ::pcl::PCLPointField::UINT32;
00135 current_field.count = static_cast<uint32_t> (size);
00136 cloud_->point_step += static_cast<uint32_t> (pcl::getFieldSize (::pcl::PCLPointField::UINT32) * size);
00137 }
00138
00139 void
00140 pcl::PLYReader::appendIntProperty (const std::string& name, const size_t& size)
00141 {
00142 cloud_->fields.push_back (pcl::PCLPointField ());
00143 pcl::PCLPointField ¤t_field = cloud_->fields.back ();
00144 current_field.name = name;
00145 current_field.offset = cloud_->point_step;
00146 current_field.datatype = pcl::PCLPointField::INT32;
00147 current_field.count = static_cast<uint32_t> (size);
00148 cloud_->point_step += static_cast<uint32_t> (pcl::getFieldSize (pcl::PCLPointField::INT32) * size);
00149 }
00150
00151 void
00152 pcl::PLYReader::appendDoubleProperty (const std::string& name, const size_t& size)
00153 {
00154 cloud_->fields.push_back (pcl::PCLPointField ());
00155 pcl::PCLPointField ¤t_field = cloud_->fields.back ();
00156 current_field.name = name;
00157 current_field.offset = cloud_->point_step;
00158 current_field.datatype = pcl::PCLPointField::FLOAT64;
00159 current_field.count = static_cast<uint32_t> (size);
00160 cloud_->point_step += static_cast<uint32_t> (pcl::getFieldSize (pcl::PCLPointField::FLOAT64) * size);
00161 }
00162
00163 void
00164 pcl::PLYReader::appendUnsignedCharProperty (const std::string& name, const size_t& size)
00165 {
00166 cloud_->fields.push_back (pcl::PCLPointField ());
00167 pcl::PCLPointField ¤t_field = cloud_->fields.back ();
00168 current_field.name = name;
00169 current_field.offset = cloud_->point_step;
00170 current_field.datatype = pcl::PCLPointField::UINT8;
00171 current_field.count = static_cast<uint32_t> (size);
00172 cloud_->point_step += static_cast<uint32_t> (pcl::getFieldSize (pcl::PCLPointField::UINT8) * size);
00173 }
00174
00175 void
00176 pcl::PLYReader::appendCharProperty (const std::string& name, const size_t& size)
00177 {
00178 cloud_->fields.push_back (pcl::PCLPointField ());
00179 pcl::PCLPointField ¤t_field = cloud_->fields.back ();
00180 current_field.name = name;
00181 current_field.offset = cloud_->point_step;
00182 current_field.datatype = pcl::PCLPointField::INT8;
00183 current_field.count = static_cast<uint32_t> (size);
00184 cloud_->point_step += static_cast<uint32_t> (pcl::getFieldSize (pcl::PCLPointField::INT8) * size);
00185 }
00186
00187 void
00188 pcl::PLYReader::appendUnsignedShortProperty (const std::string& name, const size_t& size)
00189 {
00190 cloud_->fields.push_back (pcl::PCLPointField ());
00191 pcl::PCLPointField ¤t_field = cloud_->fields.back ();
00192 current_field.name = name;
00193 current_field.offset = cloud_->point_step;
00194 current_field.datatype = pcl::PCLPointField::UINT16;
00195 current_field.count = static_cast<uint32_t> (size);
00196 cloud_->point_step += static_cast<uint32_t> (pcl::getFieldSize (pcl::PCLPointField::UINT16) * size);
00197 }
00198
00199 void
00200 pcl::PLYReader::appendShortProperty (const std::string& name, const size_t& size)
00201 {
00202 cloud_->fields.push_back (pcl::PCLPointField ());
00203 pcl::PCLPointField ¤t_field = cloud_->fields.back ();
00204 current_field.name = name;
00205 current_field.offset = cloud_->point_step;
00206 current_field.datatype = pcl::PCLPointField::INT16;
00207 current_field.count = static_cast<uint32_t> (size);
00208 cloud_->point_step += static_cast<uint32_t> (pcl::getFieldSize (pcl::PCLPointField::INT16) * size);
00209 }
00210
00211 namespace pcl
00212 {
00213 template <>
00214 boost::function<void (pcl::io::ply::float32)>
00215 PLYReader::scalarPropertyDefinitionCallback (const std::string& element_name, const std::string& property_name)
00216 {
00217 if (element_name == "vertex")
00218 {
00219 appendFloatProperty (property_name, 1);
00220 return (boost::bind (&pcl::PLYReader::vertexFloatPropertyCallback, this, _1));
00221 }
00222 else if (element_name == "camera")
00223 {
00224 if (property_name == "view_px")
00225 {
00226 return boost::bind (&pcl::PLYReader::originXCallback, this, _1);
00227 }
00228 else if (property_name == "view_py")
00229 {
00230 return boost::bind (&pcl::PLYReader::originYCallback, this, _1);
00231 }
00232 else if (property_name == "view_pz")
00233 {
00234 return boost::bind (&pcl::PLYReader::originZCallback, this, _1);
00235 }
00236 else if (property_name == "x_axisx")
00237 {
00238 return boost::bind (&pcl::PLYReader::orientationXaxisXCallback, this, _1);
00239 }
00240 else if (property_name == "x_axisy")
00241 {
00242 return boost::bind (&pcl::PLYReader::orientationXaxisYCallback, this, _1);
00243 }
00244 else if (property_name == "x_axisz")
00245 {
00246 return boost::bind (&pcl::PLYReader::orientationXaxisZCallback, this, _1);
00247 }
00248 else if (property_name == "y_axisx")
00249 {
00250 return boost::bind (&pcl::PLYReader::orientationYaxisXCallback, this, _1);
00251 }
00252 else if (property_name == "y_axisy")
00253 {
00254 return boost::bind (&pcl::PLYReader::orientationYaxisYCallback, this, _1);
00255 }
00256 else if (property_name == "y_axisz")
00257 {
00258 return boost::bind (&pcl::PLYReader::orientationYaxisZCallback, this, _1);
00259 }
00260 else if (property_name == "z_axisx")
00261 {
00262 return boost::bind (&pcl::PLYReader::orientationZaxisXCallback, this, _1);
00263 }
00264 else if (property_name == "z_axisy")
00265 {
00266 return boost::bind (&pcl::PLYReader::orientationZaxisYCallback, this, _1);
00267 }
00268 else if (property_name == "z_axisz")
00269 {
00270 return boost::bind (&pcl::PLYReader::orientationZaxisZCallback, this, _1);
00271 }
00272 else
00273 {
00274 return (0);
00275 }
00276 }
00277 else
00278 {
00279 return (0);
00280 }
00281 }
00282
00283 template <> boost::function<void (pcl::io::ply::uint8)>
00284 PLYReader::scalarPropertyDefinitionCallback (const std::string& element_name, const std::string& property_name)
00285 {
00286 if (element_name == "vertex")
00287 {
00288 if ((property_name == "red") || (property_name == "green") || (property_name == "blue") ||
00289 (property_name == "diffuse_red") || (property_name == "diffuse_green") || (property_name == "diffuse_blue"))
00290 {
00291 if ((property_name == "red") || (property_name == "diffuse_red"))
00292 appendFloatProperty ("rgb");
00293 return boost::bind (&pcl::PLYReader::vertexColorCallback, this, property_name, _1);
00294 }
00295 else if (property_name == "alpha")
00296 {
00297 amendProperty ("rgb", "rgba", pcl::PCLPointField::UINT32);
00298 return boost::bind (&pcl::PLYReader::vertexAlphaCallback, this, _1);
00299 }
00300 else if (property_name == "intensity")
00301 {
00302 appendFloatProperty (property_name);
00303 return boost::bind (&pcl::PLYReader::vertexIntensityCallback, this, _1);
00304 }
00305 else
00306 {
00307 appendUnsignedCharProperty (property_name);
00308 return boost::bind (&pcl::PLYReader::vertexUnsignedCharPropertyCallback, this, _1);
00309 }
00310 }
00311 else
00312 return (0);
00313 }
00314
00315 template <> boost::function<void (pcl::io::ply::int32)>
00316 PLYReader::scalarPropertyDefinitionCallback (const std::string& element_name, const std::string& property_name)
00317 {
00318 if (element_name == "vertex")
00319 {
00320 appendIntProperty (property_name, 1);
00321 return (boost::bind (&pcl::PLYReader::vertexIntPropertyCallback, this, _1));
00322 }
00323 if (element_name == "camera")
00324 {
00325 if (property_name == "viewportx")
00326 {
00327 return boost::bind (&pcl::PLYReader::cloudWidthCallback, this, _1);
00328 }
00329 else if (property_name == "viewporty")
00330 {
00331 return boost::bind (&pcl::PLYReader::cloudHeightCallback, this, _1);
00332 }
00333 else
00334 {
00335 appendIntProperty (property_name, 1);
00336 return (boost::bind (&pcl::PLYReader::vertexIntPropertyCallback, this, _1));
00337 }
00338 }
00339 else
00340 return (0);
00341 }
00342
00343 template <> boost::function<void (pcl::io::ply::uint32)>
00344 PLYReader::scalarPropertyDefinitionCallback (const std::string& element_name, const std::string& property_name)
00345 {
00346 if (element_name == "vertex")
00347 {
00348 appendUnsignedIntProperty (property_name, 1);
00349 return (boost::bind (&pcl::PLYReader::vertexUnsignedIntPropertyCallback, this, _1));
00350 }
00351 return (0);
00352 }
00353
00354 template <> boost::function<void (pcl::io::ply::float64)>
00355 PLYReader::scalarPropertyDefinitionCallback (const std::string& element_name, const std::string& property_name)
00356 {
00357 if (element_name == "vertex")
00358 {
00359 appendDoubleProperty (property_name, 1);
00360 return (boost::bind (&pcl::PLYReader::vertexDoublePropertyCallback, this, _1));
00361 }
00362 return (0);
00363 }
00364
00365 template <> boost::function<void (pcl::io::ply::uint16)>
00366 PLYReader::scalarPropertyDefinitionCallback (const std::string& element_name, const std::string& property_name)
00367 {
00368 if (element_name == "vertex")
00369 {
00370 appendUnsignedShortProperty (property_name, 1);
00371 return (boost::bind (&pcl::PLYReader::vertexUnsignedShortPropertyCallback, this, _1));
00372 }
00373 return (0);
00374 }
00375
00376 template <> boost::function<void (pcl::io::ply::int16)>
00377 PLYReader::scalarPropertyDefinitionCallback (const std::string& element_name, const std::string& property_name)
00378 {
00379 if (element_name == "vertex")
00380 {
00381 appendShortProperty (property_name, 1);
00382 return (boost::bind (&pcl::PLYReader::vertexShortPropertyCallback, this, _1));
00383 }
00384 return (0);
00385 }
00386
00387
00388 template <> boost::function<void (pcl::io::ply::int8)>
00389 PLYReader::scalarPropertyDefinitionCallback (const std::string& element_name, const std::string& property_name)
00390 {
00391 if (element_name == "vertex")
00392 {
00393 appendCharProperty (property_name, 1);
00394 return (boost::bind (&pcl::PLYReader::vertexCharPropertyCallback, this, _1));
00395 }
00396 return (0);
00397 }
00398
00399 template <typename SizeType> void
00400 PLYReader::vertexListPropertyBeginCallback (const std::string& name, SizeType size)
00401 {
00402
00403 if (vertex_count_ == 0)
00404 {
00405 std::vector< pcl::PCLPointField>::reverse_iterator finder = cloud_->fields.rbegin ();
00406 for (; finder != cloud_->fields.rend (); ++finder)
00407 if (finder->name == name)
00408 break;
00409 assert (finder != cloud_->fields.rend ());
00410 finder->count = size;
00411 }
00412 }
00413
00414 template<typename ContentType> void
00415 PLYReader::vertexListPropertyContentCallback (ContentType value)
00416 {
00417 memcpy (&cloud_->data[vertex_count_ * cloud_->point_step + vertex_offset_before_],
00418 &value,
00419 sizeof (ContentType));
00420 vertex_offset_before_ += static_cast<int> (sizeof (ContentType));
00421 }
00422
00423 template <>
00424 boost::tuple<boost::function<void (pcl::io::ply::uint8)>, boost::function<void (pcl::io::ply::int32)>, boost::function<void ()> >
00425 pcl::PLYReader::listPropertyDefinitionCallback (const std::string& element_name, const std::string& property_name)
00426 {
00427 if ((element_name == "range_grid") && (property_name == "vertex_indices"))
00428 {
00429 return boost::tuple<boost::function<void (pcl::io::ply::uint8)>, boost::function<void (pcl::io::ply::int32)>, boost::function<void ()> > (
00430 boost::bind (&pcl::PLYReader::rangeGridVertexIndicesBeginCallback, this, _1),
00431 boost::bind (&pcl::PLYReader::rangeGridVertexIndicesElementCallback, this, _1),
00432 boost::bind (&pcl::PLYReader::rangeGridVertexIndicesEndCallback, this)
00433 );
00434 }
00435 else if (element_name == "vertex")
00436 {
00437 cloud_->fields.push_back (pcl::PCLPointField ());
00438 pcl::PCLPointField ¤t_field = cloud_->fields.back ();
00439 current_field.name = property_name;
00440 current_field.offset = cloud_->point_step;
00441 current_field.datatype = pcl::traits::asEnum<pcl::io::ply::int32>::value;
00442 current_field.count = std::numeric_limits<pcl::io::ply::uint8>::max ();
00443 if (current_field.count * sizeof (pcl::io::ply::int32) + cloud_->point_step < std::numeric_limits<uint32_t>::max ())
00444 cloud_->point_step += static_cast<uint32_t> (current_field.count * sizeof (pcl::io::ply::int32));
00445 else
00446 cloud_->point_step = static_cast<uint32_t> (std::numeric_limits<uint32_t>::max ());
00447 do_resize_ = true;
00448 return boost::tuple<boost::function<void (pcl::io::ply::uint8)>, boost::function<void (pcl::io::ply::int32)>, boost::function<void ()> > (
00449 boost::bind (&pcl::PLYReader::vertexListPropertyBeginCallback<pcl::io::ply::uint8>, this, property_name, _1),
00450 boost::bind (&pcl::PLYReader::vertexListPropertyContentCallback<pcl::io::ply::int32>, this, _1),
00451 boost::bind (&pcl::PLYReader::vertexListPropertyEndCallback, this)
00452 );
00453 }
00454 else
00455 {
00456 return boost::tuple<boost::function<void (pcl::io::ply::uint8)>, boost::function<void (pcl::io::ply::int32)>, boost::function<void ()> > (0, 0, 0);
00457 }
00458 }
00459
00460 template <typename SizeType, typename ContentType>
00461 boost::tuple<boost::function<void (SizeType)>, boost::function<void (ContentType)>, boost::function<void ()> >
00462 pcl::PLYReader::listPropertyDefinitionCallback (const std::string& element_name, const std::string& property_name)
00463 {
00464 if (element_name == "vertex")
00465 {
00466 cloud_->fields.push_back (pcl::PCLPointField ());
00467 pcl::PCLPointField ¤t_field = cloud_->fields.back ();
00468 current_field.name = property_name;
00469 current_field.offset = cloud_->point_step;
00470 current_field.datatype = pcl::traits::asEnum<ContentType>::value;
00471 current_field.count = std::numeric_limits<SizeType>::max ();
00472 if (current_field.count * sizeof (ContentType) + cloud_->point_step < std::numeric_limits<uint32_t>::max ())
00473 cloud_->point_step += static_cast<uint32_t> (current_field.count * sizeof (ContentType));
00474 else
00475 cloud_->point_step = static_cast<uint32_t> (std::numeric_limits<uint32_t>::max ());
00476 do_resize_ = true;
00477 return boost::tuple<boost::function<void (SizeType)>, boost::function<void (ContentType)>, boost::function<void ()> > (
00478 boost::bind (&pcl::PLYReader::vertexListPropertyBeginCallback<SizeType>, this, property_name, _1),
00479 boost::bind (&pcl::PLYReader::vertexListPropertyContentCallback<ContentType>, this, _1),
00480 boost::bind (&pcl::PLYReader::vertexListPropertyEndCallback, this)
00481 );
00482 }
00483 else
00484 {
00485 return boost::tuple<boost::function<void (SizeType)>, boost::function<void (ContentType)>, boost::function<void ()> > (0, 0, 0);
00486 }
00487 }
00488
00489 }
00490
00491 void
00492 pcl::PLYReader::vertexFloatPropertyCallback (pcl::io::ply::float32 value)
00493 {
00494 memcpy (&cloud_->data[vertex_count_ * cloud_->point_step + vertex_offset_before_],
00495 &value,
00496 sizeof (pcl::io::ply::float32));
00497 vertex_offset_before_ += static_cast<int> (sizeof (pcl::io::ply::float32));
00498 }
00499
00500 void
00501 pcl::PLYReader::vertexDoublePropertyCallback (pcl::io::ply::float64 value)
00502 {
00503 memcpy (&cloud_->data[vertex_count_ * cloud_->point_step + vertex_offset_before_],
00504 &value,
00505 sizeof (pcl::io::ply::float64));
00506 vertex_offset_before_ += static_cast<int> (sizeof (pcl::io::ply::float64));
00507 }
00508
00509 void
00510 pcl::PLYReader::vertexUnsignedIntPropertyCallback (pcl::io::ply::uint32 value)
00511 {
00512 memcpy (&cloud_->data[vertex_count_ * cloud_->point_step + vertex_offset_before_],
00513 &value,
00514 sizeof (pcl::io::ply::uint32));
00515 vertex_offset_before_ += static_cast<int> (sizeof (pcl::io::ply::uint32));
00516 }
00517
00518 void
00519 pcl::PLYReader::vertexIntPropertyCallback (pcl::io::ply::int32 value)
00520 {
00521 memcpy (&cloud_->data[vertex_count_ * cloud_->point_step + vertex_offset_before_],
00522 &value,
00523 sizeof (pcl::io::ply::int32));
00524 vertex_offset_before_ += static_cast<int> (sizeof (pcl::io::ply::int32));
00525 }
00526
00527 void
00528 pcl::PLYReader::vertexUnsignedShortPropertyCallback (pcl::io::ply::uint16 value)
00529 {
00530 memcpy (&cloud_->data[vertex_count_ * cloud_->point_step + vertex_offset_before_],
00531 &value,
00532 sizeof (pcl::io::ply::uint16));
00533 vertex_offset_before_ += static_cast<int> (sizeof (pcl::io::ply::uint16));
00534 }
00535
00536 void
00537 pcl::PLYReader::vertexShortPropertyCallback (pcl::io::ply::int16 value)
00538 {
00539 memcpy (&cloud_->data[vertex_count_ * cloud_->point_step + vertex_offset_before_],
00540 &value,
00541 sizeof (pcl::io::ply::int16));
00542 vertex_offset_before_ += static_cast<int> (sizeof (pcl::io::ply::int16));
00543 }
00544
00545 void
00546 pcl::PLYReader::vertexUnsignedCharPropertyCallback (pcl::io::ply::uint8 value)
00547 {
00548 memcpy (&cloud_->data[vertex_count_ * cloud_->point_step + vertex_offset_before_],
00549 &value,
00550 sizeof (pcl::io::ply::uint8));
00551 vertex_offset_before_ += static_cast<int> (sizeof (pcl::io::ply::uint8));
00552 }
00553
00554 void
00555 pcl::PLYReader::vertexCharPropertyCallback (pcl::io::ply::int8 value)
00556 {
00557 memcpy (&cloud_->data[vertex_count_ * cloud_->point_step + vertex_offset_before_],
00558 &value,
00559 sizeof (pcl::io::ply::int8));
00560 vertex_offset_before_ += static_cast<int> (sizeof (pcl::io::ply::int8));
00561 }
00562
00563 void
00564 pcl::PLYReader::vertexColorCallback (const std::string& color_name, pcl::io::ply::uint8 color)
00565 {
00566 static int32_t r, g, b;
00567 if ((color_name == "red") || (color_name == "diffuse_red"))
00568 {
00569 r = int32_t (color);
00570 rgb_offset_before_ = vertex_offset_before_;
00571 }
00572 if ((color_name == "green") || (color_name == "diffuse_green"))
00573 {
00574 g = int32_t (color);
00575 }
00576 if ((color_name == "blue") || (color_name == "diffuse_blue"))
00577 {
00578 b = int32_t (color);
00579 int32_t rgb = r << 16 | g << 8 | b;
00580 memcpy (&cloud_->data[vertex_count_ * cloud_->point_step + rgb_offset_before_],
00581 &rgb,
00582 sizeof (pcl::io::ply::float32));
00583 vertex_offset_before_ += static_cast<int> (sizeof (pcl::io::ply::float32));
00584 }
00585 }
00586
00587 void
00588 pcl::PLYReader::vertexAlphaCallback (pcl::io::ply::uint8 alpha)
00589 {
00590 static uint32_t a, rgba;
00591 a = uint32_t (alpha);
00592
00593 memcpy (&rgba,
00594 &cloud_->data[vertex_count_ * cloud_->point_step + rgb_offset_before_],
00595 sizeof (pcl::io::ply::float32));
00596
00597 rgba = rgba | a << 24;
00598
00599 memcpy (&cloud_->data[vertex_count_ * cloud_->point_step + rgb_offset_before_],
00600 &rgba,
00601 sizeof (uint32_t));
00602 }
00603
00604 void
00605 pcl::PLYReader::vertexIntensityCallback (pcl::io::ply::uint8 intensity)
00606 {
00607 pcl::io::ply::float32 intensity_ (intensity);
00608 memcpy (&cloud_->data[vertex_count_ * cloud_->point_step + vertex_offset_before_],
00609 &intensity_,
00610 sizeof (pcl::io::ply::float32));
00611 vertex_offset_before_ += static_cast<int> (sizeof (pcl::io::ply::float32));
00612 }
00613
00614 void
00615 pcl::PLYReader::vertexBeginCallback ()
00616 {
00617 vertex_offset_before_ = 0;
00618 }
00619
00620 void
00621 pcl::PLYReader::vertexEndCallback ()
00622 {
00623
00624 if (vertex_count_ == 0 && do_resize_)
00625 {
00626 cloud_->point_step = vertex_offset_before_;
00627 cloud_->row_step = cloud_->point_step * cloud_->width;
00628 cloud_->data.resize (cloud_->point_step * cloud_->width * cloud_->height);
00629 }
00630 ++vertex_count_;
00631 }
00632
00633 void
00634 pcl::PLYReader::rangeGridBeginCallback () { }
00635
00636 void
00637 pcl::PLYReader::rangeGridVertexIndicesBeginCallback (pcl::io::ply::uint8 size)
00638 {
00639 (*range_grid_)[range_count_].reserve (size);
00640 }
00641
00642 void pcl::PLYReader::rangeGridVertexIndicesElementCallback (pcl::io::ply::int32 vertex_index)
00643 {
00644 (*range_grid_)[range_count_].push_back (vertex_index);
00645 }
00646
00647 void
00648 pcl::PLYReader::rangeGridVertexIndicesEndCallback () { }
00649
00650 void
00651 pcl::PLYReader::rangeGridEndCallback ()
00652 {
00653 ++range_count_;
00654 }
00655
00656 void
00657 pcl::PLYReader::objInfoCallback (const std::string& line)
00658 {
00659 std::vector<std::string> st;
00660 boost::split (st, line, boost::is_any_of (std::string ( "\t ")), boost::token_compress_on);
00661 assert (st[0].substr (0, 8) == "obj_info");
00662 {
00663 assert (st.size () == 3);
00664 {
00665 if (st[1] == "num_cols")
00666 cloudWidthCallback (atoi (st[2].c_str ()));
00667 else if (st[1] == "num_rows")
00668 cloudHeightCallback (atoi (st[2].c_str ()));
00669 else if (st[1] == "echo_rgb_offset_x")
00670 originXCallback (static_cast<float> (atof (st[2].c_str ())));
00671 else if (st[1] == "echo_rgb_offset_y")
00672 originYCallback (static_cast<float> (atof (st[2].c_str ())));
00673 else if (st[1] == "echo_rgb_offset_z")
00674 originZCallback (static_cast<float> (atof (st[2].c_str ())));
00675 }
00676 }
00677 }
00678
00679 void
00680 pcl::PLYReader::vertexListPropertyEndCallback () {}
00681
00682 bool
00683 pcl::PLYReader::parse (const std::string& istream_filename)
00684 {
00685 pcl::io::ply::ply_parser::flags_type ply_parser_flags = 0;
00686 pcl::io::ply::ply_parser ply_parser (ply_parser_flags);
00687
00688 ply_parser.info_callback (boost::bind (&pcl::PLYReader::infoCallback, this, boost::ref (istream_filename), _1, _2));
00689 ply_parser.warning_callback (boost::bind (&pcl::PLYReader::warningCallback, this, boost::ref (istream_filename), _1, _2));
00690 ply_parser.error_callback (boost::bind (&pcl::PLYReader::errorCallback, this, boost::ref (istream_filename), _1, _2));
00691
00692 ply_parser.obj_info_callback (boost::bind (&pcl::PLYReader::objInfoCallback, this, _1));
00693 ply_parser.element_definition_callback (boost::bind (&pcl::PLYReader::elementDefinitionCallback, this, _1, _2));
00694 ply_parser.end_header_callback (boost::bind (&pcl::PLYReader::endHeaderCallback, this));
00695
00696 pcl::io::ply::ply_parser::scalar_property_definition_callbacks_type scalar_property_definition_callbacks;
00697 pcl::io::ply::at<pcl::io::ply::float64> (scalar_property_definition_callbacks) = boost::bind (&pcl::PLYReader::scalarPropertyDefinitionCallback<pcl::io::ply::float64>, this, _1, _2);
00698 pcl::io::ply::at<pcl::io::ply::float32> (scalar_property_definition_callbacks) = boost::bind (&pcl::PLYReader::scalarPropertyDefinitionCallback<pcl::io::ply::float32>, this, _1, _2);
00699 pcl::io::ply::at<pcl::io::ply::int8> (scalar_property_definition_callbacks) = boost::bind (&pcl::PLYReader::scalarPropertyDefinitionCallback<pcl::io::ply::int8>, this, _1, _2);
00700 pcl::io::ply::at<pcl::io::ply::uint8> (scalar_property_definition_callbacks) = boost::bind (&pcl::PLYReader::scalarPropertyDefinitionCallback<pcl::io::ply::uint8>, this, _1, _2);
00701 pcl::io::ply::at<pcl::io::ply::int32> (scalar_property_definition_callbacks) = boost::bind (&pcl::PLYReader::scalarPropertyDefinitionCallback<pcl::io::ply::int32>, this, _1, _2);
00702 pcl::io::ply::at<pcl::io::ply::uint32> (scalar_property_definition_callbacks) = boost::bind (&pcl::PLYReader::scalarPropertyDefinitionCallback<pcl::io::ply::uint32>, this, _1, _2);
00703 pcl::io::ply::at<pcl::io::ply::int16> (scalar_property_definition_callbacks) = boost::bind (&pcl::PLYReader::scalarPropertyDefinitionCallback<pcl::io::ply::int16>, this, _1, _2);
00704 pcl::io::ply::at<pcl::io::ply::uint16> (scalar_property_definition_callbacks) = boost::bind (&pcl::PLYReader::scalarPropertyDefinitionCallback<pcl::io::ply::uint16>, this, _1, _2);
00705 ply_parser.scalar_property_definition_callbacks (scalar_property_definition_callbacks);
00706
00707 pcl::io::ply::ply_parser::list_property_definition_callbacks_type list_property_definition_callbacks;
00708 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);
00709 pcl::io::ply::at<pcl::io::ply::uint32, pcl::io::ply::float64> (list_property_definition_callbacks) = boost::bind (&pcl::PLYReader::listPropertyDefinitionCallback<pcl::io::ply::uint32, pcl::io::ply::float64>, this, _1, _2);
00710 pcl::io::ply::at<pcl::io::ply::uint32, pcl::io::ply::float32> (list_property_definition_callbacks) = boost::bind (&pcl::PLYReader::listPropertyDefinitionCallback<pcl::io::ply::uint32, pcl::io::ply::float32>, this, _1, _2);
00711 pcl::io::ply::at<pcl::io::ply::uint32, pcl::io::ply::uint32> (list_property_definition_callbacks) = boost::bind (&pcl::PLYReader::listPropertyDefinitionCallback<pcl::io::ply::uint32, pcl::io::ply::uint32>, this, _1, _2);
00712 pcl::io::ply::at<pcl::io::ply::uint32, pcl::io::ply::int32> (list_property_definition_callbacks) = boost::bind (&pcl::PLYReader::listPropertyDefinitionCallback<pcl::io::ply::uint32, pcl::io::ply::int32>, this, _1, _2);
00713 pcl::io::ply::at<pcl::io::ply::uint32, pcl::io::ply::uint16> (list_property_definition_callbacks) = boost::bind (&pcl::PLYReader::listPropertyDefinitionCallback<pcl::io::ply::uint32, pcl::io::ply::uint16>, this, _1, _2);
00714 pcl::io::ply::at<pcl::io::ply::uint32, pcl::io::ply::int16> (list_property_definition_callbacks) = boost::bind (&pcl::PLYReader::listPropertyDefinitionCallback<pcl::io::ply::uint32, pcl::io::ply::int16>, this, _1, _2);
00715 pcl::io::ply::at<pcl::io::ply::uint32, pcl::io::ply::uint8> (list_property_definition_callbacks) = boost::bind (&pcl::PLYReader::listPropertyDefinitionCallback<pcl::io::ply::uint32, pcl::io::ply::uint8>, this, _1, _2);
00716 pcl::io::ply::at<pcl::io::ply::uint32, pcl::io::ply::int8> (list_property_definition_callbacks) = boost::bind (&pcl::PLYReader::listPropertyDefinitionCallback<pcl::io::ply::uint32, pcl::io::ply::int8>, this, _1, _2);
00717 ply_parser.list_property_definition_callbacks (list_property_definition_callbacks);
00718
00719 return ply_parser.parse (istream_filename);
00720 }
00721
00723 int
00724 pcl::PLYReader::readHeader (const std::string &file_name, pcl::PCLPointCloud2 &cloud,
00725 Eigen::Vector4f &, Eigen::Quaternionf &,
00726 int &, int &, unsigned int &, const int)
00727 {
00728
00729 cloud_ = &cloud;
00730 range_grid_ = new std::vector<std::vector<int> >;
00731 cloud_->width = cloud_->height = 0;
00732 if (!parse (file_name))
00733 {
00734 PCL_ERROR ("[pcl::PLYReader::read] problem parsing header!\n");
00735 return (-1);
00736 }
00737 cloud_->row_step = cloud_->point_step * cloud_->width;
00738 return 0;
00739 }
00740
00742 int
00743 pcl::PLYReader::read (const std::string &file_name, pcl::PCLPointCloud2 &cloud,
00744 Eigen::Vector4f &origin, Eigen::Quaternionf &orientation, int &ply_version, const int)
00745 {
00746
00747 int data_type;
00748 unsigned int data_idx;
00749
00750 if (this->readHeader (file_name, cloud, origin, orientation, ply_version, data_type, data_idx))
00751 {
00752 PCL_ERROR ("[pcl::PLYReader::read] problem parsing header!\n");
00753 return (-1);
00754 }
00755
00756
00757 size_t r_size;
00758 if ((r_size = (*range_grid_).size ()) > 0 && r_size != vertex_count_)
00759 {
00760
00761 std::vector<pcl::uint8_t> data ((*range_grid_).size () * cloud.point_step);
00762 const static float f_nan = std::numeric_limits <float>::quiet_NaN ();
00763 const static double d_nan = std::numeric_limits <double>::quiet_NaN ();
00764 for (size_t r = 0; r < r_size; ++r)
00765 {
00766 if ((*range_grid_)[r].size () == 0)
00767 {
00768 for (size_t f = 0; f < cloud_->fields.size (); ++f)
00769 if (cloud_->fields[f].datatype == ::pcl::PCLPointField::FLOAT32)
00770 memcpy (&data[r * cloud_->point_step + cloud_->fields[f].offset],
00771 reinterpret_cast<const char*> (&f_nan), sizeof (float));
00772 else if (cloud_->fields[f].datatype == ::pcl::PCLPointField::FLOAT64)
00773 memcpy (&data[r * cloud_->point_step + cloud_->fields[f].offset],
00774 reinterpret_cast<const char*> (&d_nan), sizeof (double));
00775 else
00776 memset (&data[r * cloud_->point_step + cloud_->fields[f].offset], 0,
00777 pcl::getFieldSize (cloud_->fields[f].datatype) * cloud_->fields[f].count);
00778 }
00779 else
00780 memcpy (&data[r* cloud_->point_step], &cloud_->data[(*range_grid_)[r][0] * cloud_->point_step], cloud_->point_step);
00781 }
00782 cloud_->data.swap (data);
00783 }
00784
00785 orientation = Eigen::Quaternionf (orientation_);
00786 origin = origin_;
00787
00788 for (size_t i = 0; i < cloud_->fields.size (); ++i)
00789 {
00790 if (cloud_->fields[i].name == "nx")
00791 cloud_->fields[i].name = "normal_x";
00792 if (cloud_->fields[i].name == "ny")
00793 cloud_->fields[i].name = "normal_y";
00794 if (cloud_->fields[i].name == "nz")
00795 cloud_->fields[i].name = "normal_z";
00796 }
00797 return (0);
00798 }
00799
00801
00802 std::string
00803 pcl::PLYWriter::generateHeader (const pcl::PCLPointCloud2 &cloud,
00804 const Eigen::Vector4f &origin,
00805 const Eigen::Quaternionf &,
00806 bool binary,
00807 bool use_camera,
00808 int valid_points)
00809 {
00810 std::ostringstream oss;
00811
00812 oss << "ply";
00813 if (!binary)
00814 oss << "\nformat ascii 1.0";
00815 else
00816 {
00817 if (cloud.is_bigendian)
00818 oss << "\nformat binary_big_endian 1.0";
00819 else
00820 oss << "\nformat binary_little_endian 1.0";
00821 }
00822 oss << "\ncomment PCL generated";
00823
00824 if (!use_camera)
00825 {
00826 oss << "\nobj_info is_cyberware_data 0"
00827 "\nobj_info is_mesh 0"
00828 "\nobj_info is_warped 0"
00829 "\nobj_info is_interlaced 0";
00830 oss << "\nobj_info num_cols " << cloud.width;
00831 oss << "\nobj_info num_rows " << cloud.height;
00832 oss << "\nobj_info echo_rgb_offset_x " << origin[0];
00833 oss << "\nobj_info echo_rgb_offset_y " << origin[1];
00834 oss << "\nobj_info echo_rgb_offset_z " << origin[2];
00835 oss << "\nobj_info echo_rgb_frontfocus 0.0"
00836 "\nobj_info echo_rgb_backfocus 0.0"
00837 "\nobj_info echo_rgb_pixelsize 0.0"
00838 "\nobj_info echo_rgb_centerpixel 0"
00839 "\nobj_info echo_frames 1"
00840 "\nobj_info echo_lgincr 0.0";
00841 }
00842
00843 oss << "\nelement vertex "<< valid_points;
00844
00845 for (std::size_t i = 0; i < cloud.fields.size (); ++i)
00846 {
00847 if (cloud.fields[i].name == "normal_x")
00848 {
00849 oss << "\nproperty float nx";
00850 }
00851 else if (cloud.fields[i].name == "normal_y")
00852 {
00853 oss << "\nproperty float ny";
00854 }
00855 else if (cloud.fields[i].name == "normal_z")
00856 {
00857 oss << "\nproperty float nz";
00858 }
00859 else if (cloud.fields[i].name == "rgb")
00860 {
00861 oss << "\nproperty uchar red"
00862 "\nproperty uchar green"
00863 "\nproperty uchar blue";
00864 }
00865 else if (cloud.fields[i].name == "rgba")
00866 {
00867 oss << "\nproperty uchar red"
00868 "\nproperty uchar green"
00869 "\nproperty uchar blue"
00870 "\nproperty uchar alpha";
00871 }
00872 else
00873 {
00874 oss << "\nproperty";
00875 if (cloud.fields[i].count != 1)
00876 oss << " list uint";
00877 switch (cloud.fields[i].datatype)
00878 {
00879 case pcl::PCLPointField::INT8 : oss << " char "; break;
00880 case pcl::PCLPointField::UINT8 : oss << " uchar "; break;
00881 case pcl::PCLPointField::INT16 : oss << " short "; break;
00882 case pcl::PCLPointField::UINT16 : oss << " ushort "; break;
00883 case pcl::PCLPointField::INT32 : oss << " int "; break;
00884 case pcl::PCLPointField::UINT32 : oss << " uint "; break;
00885 case pcl::PCLPointField::FLOAT32 : oss << " float "; break;
00886 case pcl::PCLPointField::FLOAT64 : oss << " double "; break;
00887 default :
00888 {
00889 PCL_ERROR ("[pcl::PLYWriter::generateHeader] unknown data field type!");
00890 return ("");
00891 }
00892 }
00893 oss << cloud.fields[i].name;
00894 }
00895 }
00896
00897 if (use_camera)
00898 {
00899 oss << "\nelement camera 1"
00900 "\nproperty float view_px"
00901 "\nproperty float view_py"
00902 "\nproperty float view_pz"
00903 "\nproperty float x_axisx"
00904 "\nproperty float x_axisy"
00905 "\nproperty float x_axisz"
00906 "\nproperty float y_axisx"
00907 "\nproperty float y_axisy"
00908 "\nproperty float y_axisz"
00909 "\nproperty float z_axisx"
00910 "\nproperty float z_axisy"
00911 "\nproperty float z_axisz"
00912 "\nproperty float focal"
00913 "\nproperty float scalex"
00914 "\nproperty float scaley"
00915 "\nproperty float centerx"
00916 "\nproperty float centery"
00917 "\nproperty int viewportx"
00918 "\nproperty int viewporty"
00919 "\nproperty float k1"
00920 "\nproperty float k2";
00921 }
00922 else if (cloud.height > 1)
00923 {
00924 oss << "\nelement range_grid " << cloud.width * cloud.height;
00925 oss << "\nproperty list uchar int vertex_indices";
00926 }
00927
00928
00929 oss << "\nend_header\n";
00930 return (oss.str ());
00931 }
00932
00934
00935 int
00936 pcl::PLYWriter::writeASCII (const std::string &file_name,
00937 const pcl::PCLPointCloud2 &cloud,
00938 const Eigen::Vector4f &origin,
00939 const Eigen::Quaternionf &orientation,
00940 int precision,
00941 bool use_camera)
00942 {
00943 if (cloud.data.empty ())
00944 {
00945 PCL_ERROR ("[pcl::PLYWriter::writeASCII] Input point cloud has no data!\n");
00946 return (-1);
00947 }
00948
00949 std::ofstream fs;
00950 fs.precision (precision);
00951
00952 fs.open (file_name.c_str ());
00953 if (!fs)
00954 {
00955 PCL_ERROR ("[pcl::PLYWriter::writeASCII] Error during opening (%s)!\n", file_name.c_str ());
00956 return (-1);
00957 }
00958
00959 unsigned int nr_points = cloud.width * cloud.height;
00960 unsigned int point_size = static_cast<unsigned int> (cloud.data.size () / nr_points);
00961
00962
00963 if (use_camera)
00964 {
00965 fs << generateHeader (cloud, origin, orientation, false, use_camera, nr_points);
00966 writeContentWithCameraASCII (nr_points, point_size, cloud, origin, orientation, fs);
00967 }
00968 else
00969 {
00970 std::ostringstream os;
00971 int nr_valid_points;
00972 writeContentWithRangeGridASCII (nr_points, point_size, cloud, os, nr_valid_points);
00973 fs << generateHeader (cloud, origin, orientation, false, use_camera, nr_valid_points);
00974 fs << os.str ();
00975 }
00976
00977
00978 fs.close ();
00979 return (0);
00980 }
00981
00982 void
00983 pcl::PLYWriter::writeContentWithCameraASCII (int nr_points,
00984 int point_size,
00985 const pcl::PCLPointCloud2 &cloud,
00986 const Eigen::Vector4f &origin,
00987 const Eigen::Quaternionf &orientation,
00988 std::ofstream& fs)
00989 {
00990
00991 for (int i = 0; i < nr_points; ++i)
00992 {
00993 for (size_t d = 0; d < cloud.fields.size (); ++d)
00994 {
00995 int count = cloud.fields[d].count;
00996 if (count == 0)
00997 count = 1;
00998
00999 if (count > 1)
01000 fs << count << " ";
01001 for (int c = 0; c < count; ++c)
01002 {
01003 switch (cloud.fields[d].datatype)
01004 {
01005 case pcl::PCLPointField::INT8:
01006 {
01007 char value;
01008 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (char)], sizeof (char));
01009 fs << boost::numeric_cast<int> (value);
01010 break;
01011 }
01012 case pcl::PCLPointField::UINT8:
01013 {
01014 unsigned char value;
01015 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned char)], sizeof (unsigned char));
01016 fs << boost::numeric_cast<int> (value);
01017 break;
01018 }
01019 case pcl::PCLPointField::INT16:
01020 {
01021 short value;
01022 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (short)], sizeof (short));
01023 fs << boost::numeric_cast<int> (value);
01024 break;
01025 }
01026 case pcl::PCLPointField::UINT16:
01027 {
01028 unsigned short value;
01029 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned short)], sizeof (unsigned short));
01030 fs << boost::numeric_cast<int> (value);
01031 break;
01032 }
01033 case pcl::PCLPointField::INT32:
01034 {
01035 int value;
01036 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (int)], sizeof (int));
01037 fs << value;
01038 break;
01039 }
01040 case pcl::PCLPointField::UINT32:
01041 {
01042 if (cloud.fields[d].name.find ("rgba") == std::string::npos)
01043 {
01044 unsigned int value;
01045 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned int)], sizeof (unsigned int));
01046 fs << value;
01047 }
01048 else
01049 {
01050 pcl::RGB color;
01051 memcpy (&color, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned int)], sizeof (pcl::RGB));
01052 int r = color.r;
01053 int g = color.g;
01054 int b = color.b;
01055 int a = color.a;
01056 fs << r << " " << g << " " << b << " " << a;
01057 }
01058 break;
01059 }
01060 case pcl::PCLPointField::FLOAT32:
01061 {
01062 if (cloud.fields[d].name.find ("rgb") == std::string::npos)
01063 {
01064 float value;
01065 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (float)], sizeof (float));
01066 fs << value;
01067 }
01068 else
01069 {
01070 pcl::RGB color;
01071 memcpy (&color, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (float)], sizeof (pcl::RGB));
01072 int r = color.r;
01073 int g = color.g;
01074 int b = color.b;
01075 fs << r << " " << g << " " << b;
01076 }
01077 break;
01078 }
01079 case pcl::PCLPointField::FLOAT64:
01080 {
01081 double value;
01082 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (double)], sizeof (double));
01083 fs << value;
01084 break;
01085 }
01086 default:
01087 PCL_WARN ("[pcl::PLYWriter::writeASCII] Incorrect field data type specified (%d)!\n", cloud.fields[d].datatype);
01088 break;
01089 }
01090
01091 if (d < cloud.fields.size () - 1 || c < static_cast<int> (cloud.fields[d].count) - 1)
01092 fs << " ";
01093 }
01094 }
01095 fs << std::endl;
01096 }
01097
01098 if (origin[3] != 0)
01099 fs << origin[0]/origin[3] << " " << origin[1]/origin[3] << " " << origin[2]/origin[3] << " ";
01100 else
01101 fs << origin[0] << " " << origin[1] << " " << origin[2] << " ";
01102
01103 Eigen::Matrix3f R = orientation.toRotationMatrix ();
01104 fs << R (0,0) << " " << R (0,1) << " " << R (0,2) << " ";
01105 fs << R (1,0) << " " << R (1,1) << " " << R (1,2) << " ";
01106 fs << R (2,0) << " " << R (2,1) << " " << R (2,2) << " ";
01107
01108 fs << 0 << " ";
01109
01110 fs << 0 << " " << 0 << " ";
01111
01112 fs << 0 << " " << 0 << " ";
01113
01114 fs << cloud.width << " " << cloud.height << " ";
01115
01116 fs << 0 << " " << 0;
01117 fs << std::endl;
01118 fs.flush ();
01119 }
01120
01121 void
01122 pcl::PLYWriter::writeContentWithRangeGridASCII (int nr_points,
01123 int point_size,
01124 const pcl::PCLPointCloud2 &cloud,
01125 std::ostringstream& fs,
01126 int& valid_points)
01127 {
01128 valid_points = 0;
01129 std::vector<std::vector <int> > grids (nr_points);
01130
01131 for (int i = 0; i < nr_points; ++i)
01132 {
01133 std::ostringstream line;
01134 bool is_valid_line = true;
01135 for (size_t d = 0; d < cloud.fields.size (); ++d)
01136 {
01137 int count = cloud.fields[d].count;
01138 if (count == 0)
01139 count = 1;
01140 if (count > 1)
01141 fs << count << " ";
01142 for (int c = 0; c < count; ++c)
01143 {
01144 switch (cloud.fields[d].datatype)
01145 {
01146 case pcl::PCLPointField::INT8:
01147 {
01148 char value;
01149 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (char)], sizeof (char));
01150 line << boost::numeric_cast<int> (value);
01151 break;
01152 }
01153 case pcl::PCLPointField::UINT8:
01154 {
01155 unsigned char value;
01156 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned char)], sizeof (unsigned char));
01157 line << boost::numeric_cast<int> (value);
01158 break;
01159 }
01160 case pcl::PCLPointField::INT16:
01161 {
01162 short value;
01163 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (short)], sizeof (short));
01164 line << boost::numeric_cast<int> (value);
01165 break;
01166 }
01167 case pcl::PCLPointField::UINT16:
01168 {
01169 unsigned short value;
01170 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned short)], sizeof (unsigned short));
01171 line << boost::numeric_cast<int> (value);
01172 break;
01173 }
01174 case pcl::PCLPointField::INT32:
01175 {
01176 int value;
01177 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (int)], sizeof (int));
01178 line << value;
01179 break;
01180 }
01181 case pcl::PCLPointField::UINT32:
01182 {
01183 if (cloud.fields[d].name.find ("rgba") == std::string::npos)
01184 {
01185 unsigned int value;
01186 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned int)], sizeof (unsigned int));
01187 line << value;
01188 }
01189 else
01190 {
01191 pcl::RGB color;
01192 memcpy (&color, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (unsigned int)], sizeof (pcl::RGB));
01193 int r = color.r;
01194 int g = color.g;
01195 int b = color.b;
01196 int a = color.a;
01197 line << r << " " << g << " " << b << " " << a;
01198 }
01199 break;
01200 }
01201 case pcl::PCLPointField::FLOAT32:
01202 {
01203 if (cloud.fields[d].name.find ("rgb") == std::string::npos)
01204 {
01205 float value;
01206 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (float)], sizeof (float));
01207
01208 if ("x" == cloud.fields[d].name)
01209 {
01210 if (!pcl_isfinite(value))
01211 is_valid_line = false;
01212 }
01213 line << value;
01214 }
01215 else
01216 {
01217 pcl::RGB color;
01218 memcpy (&color, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (float)], sizeof (pcl::RGB));
01219 int r = color.r;
01220 int g = color.g;
01221 int b = color.b;
01222 line << r << " " << g << " " << b;
01223 }
01224 break;
01225 }
01226 case pcl::PCLPointField::FLOAT64:
01227 {
01228 double value;
01229 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + c * sizeof (double)], sizeof (double));
01230 line << value;
01231 break;
01232 }
01233 default:
01234 PCL_WARN ("[pcl::PLYWriter::writeASCII] Incorrect field data type specified (%d)!\n", cloud.fields[d].datatype);
01235 break;
01236 }
01237
01238 if (d < cloud.fields.size () - 1 || c < static_cast<int> (cloud.fields[d].count) - 1)
01239 line << " ";
01240 }
01241 }
01242
01243 if (is_valid_line)
01244 {
01245 grids[i].push_back (valid_points);
01246 fs << line.str () << std::endl;
01247 ++valid_points;
01248 }
01249 }
01250
01251
01252 if (cloud.height > 1)
01253 {
01254 for (int i = 0; i < nr_points; ++i)
01255 {
01256 fs << grids [i].size ();
01257 for (std::vector <int>::const_iterator it = grids [i].begin ();
01258 it != grids [i].end ();
01259 ++it)
01260 fs << " " << *it;
01261 fs << std::endl;
01262 }
01263 }
01264
01265 fs.flush ();
01266 }
01267
01269 int
01270 pcl::PLYWriter::writeBinary (const std::string &file_name,
01271 const pcl::PCLPointCloud2 &cloud,
01272 const Eigen::Vector4f &origin,
01273 const Eigen::Quaternionf &orientation,
01274 bool use_camera)
01275 {
01276 if (cloud.data.empty ())
01277 {
01278 PCL_ERROR ("[pcl::PLYWriter::writeBinary] Input point cloud has no data!\n");
01279 return (-1);
01280 }
01281
01282 std::ofstream fs;
01283 fs.open (file_name.c_str ());
01284 if (!fs)
01285 {
01286 PCL_ERROR ("[pcl::PLYWriter::writeBinary] Error during opening (%s)!\n", file_name.c_str ());
01287 return (-1);
01288 }
01289
01290 unsigned int nr_points = cloud.width * cloud.height;
01291 unsigned int point_size = static_cast<unsigned int> (cloud.data.size () / nr_points);
01292
01293
01294 bool doRangeGrid = !use_camera && cloud.height > 1;
01295 std::vector<pcl::io::ply::int32> rangegrid (nr_points);
01296 if (doRangeGrid)
01297 {
01298 unsigned int valid_points = 0;
01299
01300
01301 int xfield = pcl::getFieldIndex (cloud, "x");
01302 if (xfield >= 0 && cloud.fields[xfield].datatype != pcl::PCLPointField::FLOAT32)
01303 xfield = -1;
01304
01305
01306 if (xfield < 0)
01307 {
01308 for (unsigned int i=0; i < nr_points; ++i)
01309 rangegrid[i] = i;
01310 valid_points = nr_points;
01311 }
01312
01313 else
01314 {
01315 for (size_t i=0; i < nr_points; ++i)
01316 {
01317 float value;
01318 memcpy(&value, &cloud.data[i * point_size + cloud.fields[xfield].offset], sizeof(float));
01319 if (pcl_isfinite(value))
01320 {
01321 rangegrid[i] = valid_points;
01322 ++valid_points;
01323 }
01324 else
01325 rangegrid[i] = -1;
01326 }
01327 }
01328 fs << generateHeader (cloud, origin, orientation, true, use_camera, valid_points);
01329 }
01330 else
01331 {
01332 fs << generateHeader (cloud, origin, orientation, true, use_camera, nr_points);
01333 }
01334
01335
01336 fs.close ();
01337
01338 std::ofstream fpout (file_name.c_str (), std::ios::app | std::ios::binary);
01339 if (!fpout)
01340 {
01341 PCL_ERROR ("[pcl::PLYWriter::writeBinary] Error during reopening (%s)!\n", file_name.c_str ());
01342 return (-1);
01343 }
01344
01345
01346 for (unsigned int i = 0; i < nr_points; ++i)
01347 {
01348
01349 if (doRangeGrid && rangegrid[i] < 0)
01350 continue;
01351
01352 size_t total = 0;
01353 for (size_t d = 0; d < cloud.fields.size (); ++d)
01354 {
01355 int count = cloud.fields[d].count;
01356 if (count == 0)
01357 count = 1;
01358 if (count > 1)
01359 {
01360 static unsigned int ucount (count);
01361 fpout.write (reinterpret_cast<const char*> (&ucount), sizeof (unsigned int));
01362 }
01363
01364 if (cloud.fields[d].name == "_")
01365 {
01366 total += cloud.fields[d].count;
01367 continue;
01368 }
01369
01370 for (int c = 0; c < count; ++c)
01371 {
01372 switch (cloud.fields[d].datatype)
01373 {
01374 case pcl::PCLPointField::INT8:
01375 {
01376 char value;
01377 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (char)], sizeof (char));
01378 fpout.write (reinterpret_cast<const char*> (&value), sizeof (char));
01379 break;
01380 }
01381 case pcl::PCLPointField::UINT8:
01382 {
01383 unsigned char value;
01384 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (unsigned char)], sizeof (unsigned char));
01385 fpout.write (reinterpret_cast<const char*> (&value), sizeof (unsigned char));
01386 break;
01387 }
01388 case pcl::PCLPointField::INT16:
01389 {
01390 short value;
01391 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (short)], sizeof (short));
01392 fpout.write (reinterpret_cast<const char*> (&value), sizeof (short));
01393 break;
01394 }
01395 case pcl::PCLPointField::UINT16:
01396 {
01397 unsigned short value;
01398 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (unsigned short)], sizeof (unsigned short));
01399 fpout.write (reinterpret_cast<const char*> (&value), sizeof (unsigned short));
01400 break;
01401 }
01402 case pcl::PCLPointField::INT32:
01403 {
01404 int value;
01405 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (int)], sizeof (int));
01406 fpout.write (reinterpret_cast<const char*> (&value), sizeof (int));
01407 break;
01408 }
01409 case pcl::PCLPointField::UINT32:
01410 {
01411 if (cloud.fields[d].name.find ("rgba") == std::string::npos)
01412 {
01413 unsigned int value;
01414 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (unsigned int)], sizeof (unsigned int));
01415 fpout.write (reinterpret_cast<const char*> (&value), sizeof (unsigned int));
01416 }
01417 else
01418 {
01419 pcl::RGB color;
01420 memcpy (&color, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (unsigned int)], sizeof (pcl::RGB));
01421 unsigned char r = color.r;
01422 unsigned char g = color.g;
01423 unsigned char b = color.b;
01424 unsigned char a = color.a;
01425 fpout.write (reinterpret_cast<const char*> (&r), sizeof (unsigned char));
01426 fpout.write (reinterpret_cast<const char*> (&g), sizeof (unsigned char));
01427 fpout.write (reinterpret_cast<const char*> (&b), sizeof (unsigned char));
01428 fpout.write (reinterpret_cast<const char*> (&a), sizeof (unsigned char));
01429 }
01430 break;
01431 }
01432 case pcl::PCLPointField::FLOAT32:
01433 {
01434 if (cloud.fields[d].name.find ("rgb") == std::string::npos)
01435 {
01436 float value;
01437 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (float)], sizeof (float));
01438 fpout.write (reinterpret_cast<const char*> (&value), sizeof (float));
01439 }
01440 else
01441 {
01442 pcl::RGB color;
01443 memcpy (&color, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (float)], sizeof (pcl::RGB));
01444 unsigned char r = color.r;
01445 unsigned char g = color.g;
01446 unsigned char b = color.b;
01447 fpout.write (reinterpret_cast<const char*> (&r), sizeof (unsigned char));
01448 fpout.write (reinterpret_cast<const char*> (&g), sizeof (unsigned char));
01449 fpout.write (reinterpret_cast<const char*> (&b), sizeof (unsigned char));
01450 }
01451 break;
01452 }
01453 case pcl::PCLPointField::FLOAT64:
01454 {
01455 double value;
01456 memcpy (&value, &cloud.data[i * point_size + cloud.fields[d].offset + (total + c) * sizeof (double)], sizeof (double));
01457 fpout.write (reinterpret_cast<const char*> (&value), sizeof (double));
01458 break;
01459 }
01460 default:
01461 PCL_WARN ("[pcl::PLYWriter::writeBinary] Incorrect field data type specified (%d)!\n", cloud.fields[d].datatype);
01462 break;
01463 }
01464 }
01465 }
01466 }
01467
01468 if (use_camera)
01469 {
01470
01471 float t;
01472 for (int i = 0; i < 3; ++i)
01473 {
01474 if (origin[3] != 0)
01475 t = origin[i]/origin[3];
01476 else
01477 t = origin[i];
01478 fpout.write (reinterpret_cast<const char*> (&t), sizeof (float));
01479 }
01480 Eigen::Matrix3f R = orientation.toRotationMatrix ();
01481 for (int i = 0; i < 3; ++i)
01482 for (int j = 0; j < 3; ++j)
01483 {
01484 fpout.write (reinterpret_cast<const char*> (&R (i, j)),sizeof (float));
01485 }
01486
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01500
01501 const float zerof = 0;
01502 for (int i = 0; i < 5; ++i)
01503 fpout.write (reinterpret_cast<const char*> (&zerof), sizeof (float));
01504
01505
01506 int width = cloud.width;
01507 fpout.write (reinterpret_cast<const char*> (&width), sizeof (int));
01508
01509 int height = cloud.height;
01510 fpout.write (reinterpret_cast<const char*> (&height), sizeof (int));
01511
01512 for (int i = 0; i < 2; ++i)
01513 fpout.write (reinterpret_cast<const char*> (&zerof), sizeof (float));
01514 }
01515 else if (doRangeGrid)
01516 {
01517
01518 for (size_t i=0; i < nr_points; ++i)
01519 {
01520 pcl::io::ply::uint8 listlen;
01521
01522 if (rangegrid[i] >= 0)
01523 {
01524 listlen = 1;
01525 fpout.write (reinterpret_cast<const char*> (&listlen), sizeof (pcl::io::ply::uint8));
01526 fpout.write (reinterpret_cast<const char*> (&rangegrid[i]), sizeof (pcl::io::ply::int32));
01527 }
01528 else
01529 {
01530 listlen = 0;
01531 fpout.write (reinterpret_cast<const char*> (&listlen), sizeof (pcl::io::ply::uint8));
01532 }
01533 }
01534 }
01535
01536
01537 fpout.close ();
01538 return (0);
01539 }
01540
01542 int
01543 pcl::io::savePLYFile (const std::string &file_name, const pcl::PolygonMesh &mesh, unsigned precision)
01544 {
01545 if (mesh.cloud.data.empty ())
01546 {
01547 PCL_ERROR ("[pcl::io::savePLYFile] Input point cloud has no data!\n");
01548 return (-1);
01549 }
01550
01551 std::ofstream fs;
01552 fs.precision (precision);
01553 fs.open (file_name.c_str ());
01554 if (!fs)
01555 {
01556 PCL_ERROR ("[pcl::io::savePLYFile] Error during opening (%s)!\n", file_name.c_str ());
01557 return (-1);
01558 }
01559
01560
01561 size_t nr_points = mesh.cloud.width * mesh.cloud.height;
01562 size_t point_size = mesh.cloud.data.size () / nr_points;
01563
01564
01565 size_t nr_faces = mesh.polygons.size ();
01566
01567
01568 fs << "ply";
01569 fs << "\nformat ascii 1.0";
01570 fs << "\ncomment PCL generated";
01571
01572 fs << "\nelement vertex "<< mesh.cloud.width * mesh.cloud.height;
01573 fs << "\nproperty float x"
01574 "\nproperty float y"
01575 "\nproperty float z";
01576
01577 int rgba_index = getFieldIndex (mesh.cloud, "rgba"),
01578 rgb_index = getFieldIndex (mesh.cloud, "rgb");
01579 if (rgba_index != -1)
01580 {
01581 fs << "\nproperty uchar red"
01582 "\nproperty uchar green"
01583 "\nproperty uchar blue"
01584 "\nproperty uchar alpha";
01585 }
01586 else if (rgb_index != -1)
01587 {
01588 fs << "\nproperty uchar red"
01589 "\nproperty uchar green"
01590 "\nproperty uchar blue";
01591 }
01592
01593 fs << "\nelement face "<< nr_faces;
01594 fs << "\nproperty list uchar int vertex_index";
01595 fs << "\nend_header\n";
01596
01597
01598 for (size_t i = 0; i < nr_points; ++i)
01599 {
01600 int xyz = 0;
01601 for (size_t d = 0; d < mesh.cloud.fields.size (); ++d)
01602 {
01603 int count = mesh.cloud.fields[d].count;
01604 if (count == 0)
01605 count = 1;
01606 int c = 0;
01607
01608
01609 if ((mesh.cloud.fields[d].datatype == pcl::PCLPointField::FLOAT32) && (
01610 mesh.cloud.fields[d].name == "x" ||
01611 mesh.cloud.fields[d].name == "y" ||
01612 mesh.cloud.fields[d].name == "z"))
01613 {
01614 float value;
01615 memcpy (&value, &mesh.cloud.data[i * point_size + mesh.cloud.fields[d].offset + c * sizeof (float)], sizeof (float));
01616 fs << value;
01617
01618
01619 ++xyz;
01620 }
01621 else if ((mesh.cloud.fields[d].datatype == pcl::PCLPointField::FLOAT32) &&
01622 (mesh.cloud.fields[d].name == "rgb"))
01623
01624 {
01625 pcl::RGB color;
01626 memcpy (&color, &mesh.cloud.data[i * point_size + mesh.cloud.fields[rgb_index].offset + c * sizeof (float)], sizeof (RGB));
01627 fs << int (color.r) << " " << int (color.g) << " " << int (color.b);
01628 }
01629 else if ((mesh.cloud.fields[d].datatype == pcl::PCLPointField::UINT32) &&
01630 (mesh.cloud.fields[d].name == "rgba"))
01631 {
01632 pcl::RGB color;
01633 memcpy (&color, &mesh.cloud.data[i * point_size + mesh.cloud.fields[rgba_index].offset + c * sizeof (uint32_t)], sizeof (RGB));
01634 fs << int (color.r) << " " << int (color.g) << " " << int (color.b) << " " << int (color.a);
01635 }
01636 fs << " ";
01637 }
01638 if (xyz != 3)
01639 {
01640 PCL_ERROR ("[pcl::io::savePLYFile] Input point cloud has no XYZ data!\n");
01641 return (-2);
01642 }
01643 fs << std::endl;
01644 }
01645
01646
01647 for (size_t i = 0; i < nr_faces; i++)
01648 {
01649 fs << mesh.polygons[i].vertices.size () << " ";
01650 size_t j = 0;
01651 for (j = 0; j < mesh.polygons[i].vertices.size () - 1; ++j)
01652 fs << mesh.polygons[i].vertices[j] << " ";
01653 fs << mesh.polygons[i].vertices[j] << std::endl;
01654 }
01655
01656
01657 fs.close ();
01658 return (0);
01659 }
01660
01662 int
01663 pcl::io::savePLYFileBinary (const std::string &file_name, const pcl::PolygonMesh &mesh)
01664 {
01665 if (mesh.cloud.data.empty ())
01666 {
01667 PCL_ERROR ("[pcl::io::savePLYFile] Input point cloud has no data!\n");
01668 return (-1);
01669 }
01670
01671 std::ofstream fs;
01672 fs.open (file_name.c_str ());
01673 if (!fs)
01674 {
01675 PCL_ERROR ("[pcl::io::savePLYFile] Error during opening (%s)!\n", file_name.c_str ());
01676 return (-1);
01677 }
01678
01679
01680 size_t nr_points = mesh.cloud.width * mesh.cloud.height;
01681 size_t point_size = mesh.cloud.data.size () / nr_points;
01682
01683
01684 size_t nr_faces = mesh.polygons.size ();
01685
01686
01687 fs << "ply";
01688 fs << "\nformat " << (mesh.cloud.is_bigendian ? "binary_big_endian" : "binary_little_endian") << " 1.0";
01689 fs << "\ncomment PCL generated";
01690
01691 fs << "\nelement vertex "<< mesh.cloud.width * mesh.cloud.height;
01692 fs << "\nproperty float x"
01693 "\nproperty float y"
01694 "\nproperty float z";
01695
01696 int rgba_index = getFieldIndex (mesh.cloud, "rgba"),
01697 rgb_index = getFieldIndex (mesh.cloud, "rgb");
01698 if (rgba_index != -1)
01699 {
01700 fs << "\nproperty uchar red"
01701 "\nproperty uchar green"
01702 "\nproperty uchar blue"
01703 "\nproperty uchar alpha";
01704 }
01705 else if (rgb_index != -1)
01706 {
01707 fs << "\nproperty uchar red"
01708 "\nproperty uchar green"
01709 "\nproperty uchar blue";
01710 }
01711
01712 fs << "\nelement face "<< nr_faces;
01713 fs << "\nproperty list uchar int vertex_index";
01714 fs << "\nend_header\n";
01715
01716
01717 fs.close ();
01718
01719 std::ofstream fpout (file_name.c_str (), std::ios::app | std::ios::binary);
01720 if (!fpout)
01721 {
01722 PCL_ERROR ("[pcl::io::writePLYFileBinary] Error during reopening (%s)!\n", file_name.c_str ());
01723 return (-1);
01724 }
01725
01726
01727 for (size_t i = 0; i < nr_points; ++i)
01728 {
01729 int xyz = 0;
01730 for (size_t d = 0; d < mesh.cloud.fields.size (); ++d)
01731 {
01732 int count = mesh.cloud.fields[d].count;
01733 if (count == 0)
01734 count = 1;
01735 int c = 0;
01736
01737
01738 if ((mesh.cloud.fields[d].datatype == pcl::PCLPointField::FLOAT32) && (
01739 mesh.cloud.fields[d].name == "x" ||
01740 mesh.cloud.fields[d].name == "y" ||
01741 mesh.cloud.fields[d].name == "z"))
01742 {
01743 float value;
01744 memcpy (&value, &mesh.cloud.data[i * point_size + mesh.cloud.fields[d].offset + c * sizeof (float)], sizeof (float));
01745 fpout.write (reinterpret_cast<const char*> (&value), sizeof (float));
01746
01747
01748 ++xyz;
01749 }
01750 else if ((mesh.cloud.fields[d].datatype == pcl::PCLPointField::FLOAT32) &&
01751 (mesh.cloud.fields[d].name == "rgb"))
01752
01753 {
01754 pcl::RGB color;
01755 memcpy (&color, &mesh.cloud.data[i * point_size + mesh.cloud.fields[rgb_index].offset + c * sizeof (float)], sizeof (RGB));
01756 fpout.write (reinterpret_cast<const char*> (&color.r), sizeof (unsigned char));
01757 fpout.write (reinterpret_cast<const char*> (&color.g), sizeof (unsigned char));
01758 fpout.write (reinterpret_cast<const char*> (&color.b), sizeof (unsigned char));
01759 }
01760 else if ((mesh.cloud.fields[d].datatype == pcl::PCLPointField::UINT32) &&
01761 (mesh.cloud.fields[d].name == "rgba"))
01762 {
01763 pcl::RGB color;
01764 memcpy (&color, &mesh.cloud.data[i * point_size + mesh.cloud.fields[rgba_index].offset + c * sizeof (uint32_t)], sizeof (RGB));
01765 fpout.write (reinterpret_cast<const char*> (&color.r), sizeof (unsigned char));
01766 fpout.write (reinterpret_cast<const char*> (&color.g), sizeof (unsigned char));
01767 fpout.write (reinterpret_cast<const char*> (&color.b), sizeof (unsigned char));
01768 fpout.write (reinterpret_cast<const char*> (&color.a), sizeof (unsigned char));
01769 }
01770 }
01771 if (xyz != 3)
01772 {
01773 PCL_ERROR ("[pcl::io::savePLYFile] Input point cloud has no XYZ data!\n");
01774 return (-2);
01775 }
01776 }
01777
01778
01779 for (size_t i = 0; i < nr_faces; i++)
01780 {
01781 unsigned char value = static_cast<unsigned char> (mesh.polygons[i].vertices.size ());
01782 fpout.write (reinterpret_cast<const char*> (&value), sizeof (unsigned char));
01783 size_t j = 0;
01784 for (j = 0; j < mesh.polygons[i].vertices.size (); ++j)
01785 {
01786
01787 int value = mesh.polygons[i].vertices[j];
01788 fpout.write (reinterpret_cast<const char*> (&value), sizeof (int));
01789 }
01790 }
01791
01792
01793 fs.close ();
01794 return (0);
01795 }