Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
point_cloud.h
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2010-2012, Willow Garage, Inc.
6  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * * Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * * Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  * * Neither the name of Willow Garage, Inc. nor the names of its
20  * contributors may be used to endorse or promote products derived
21  * from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  * $Id: point_cloud.h 6126 2012-07-03 20:19:58Z aichim $
37  *
38  */
39 
40 #ifndef PCL_POINT_CLOUD_H_
41 #define PCL_POINT_CLOUD_H_
42 
43 #include <pcl/common/eigen.h>
44 #include <cstddef>
45 #include <std_msgs/Header.h>
46 #include <pcl/pcl_macros.h>
47 #include <pcl/exceptions.h>
48 #include <pcl/cloud_properties.h>
49 #include <pcl/channel_properties.h>
50 #include <pcl/point_traits.h>
51 #include <pcl/for_each_type.h>
52 #include <boost/shared_ptr.hpp>
53 #include <map>
54 #include <boost/mpl/size.hpp>
55 
56 namespace pcl
57 {
58  namespace detail
59  {
60  struct FieldMapping
61  {
63  size_t struct_offset;
64  size_t size;
65  };
66  } // namespace detail
67 
68  // Forward declarations
69  template <typename PointT> class PointCloud;
70  typedef std::vector<detail::FieldMapping> MsgFieldMap;
71 
73 
74  template <typename PointOutT>
76  {
78 
83  NdCopyEigenPointFunctor (const Eigen::VectorXf &p1, PointOutT &p2)
84  : p1_ (p1),
85  p2_ (reinterpret_cast<Pod&>(p2)),
86  f_idx_ (0) { }
87 
89  template<typename Key> inline void
91  {
92  //boost::fusion::at_key<Key> (p2_) = p1_[f_idx_++];
94  uint8_t* data_ptr = reinterpret_cast<uint8_t*>(&p2_) + pcl::traits::offset<PointOutT, Key>::value;
95  *reinterpret_cast<T*>(data_ptr) = static_cast<T> (p1_[f_idx_++]);
96  }
97 
98  private:
99  const Eigen::VectorXf &p1_;
100  Pod &p2_;
101  int f_idx_;
102  public:
103  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
104  };
105 
107 
108  template <typename PointInT>
110  {
112 
117  NdCopyPointEigenFunctor (const PointInT &p1, Eigen::VectorXf &p2)
118  : p1_ (reinterpret_cast<const Pod&>(p1)), p2_ (p2), f_idx_ (0) { }
119 
121  template<typename Key> inline void
123  {
124  //p2_[f_idx_++] = boost::fusion::at_key<Key> (p1_);
126  const uint8_t* data_ptr = reinterpret_cast<const uint8_t*>(&p1_) + pcl::traits::offset<PointInT, Key>::value;
127  p2_[f_idx_++] = static_cast<float> (*reinterpret_cast<const T*>(data_ptr));
128  }
129 
130  private:
131  const Pod &p1_;
132  Eigen::VectorXf &p2_;
133  int f_idx_;
134  public:
135  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
136  };
137 
138  namespace detail
139  {
140  template <typename PointT> boost::shared_ptr<pcl::MsgFieldMap>&
142  } // namespace detail
143 
177  template <typename PointT>
178  class PointCloud
179  {
180  public:
186  header (), points (), width (0), height (0), is_dense (true),
187  sensor_origin_ (Eigen::Vector4f::Zero ()), sensor_orientation_ (Eigen::Quaternionf::Identity ()),
188  mapping_ ()
189  {}
190 
195  header (), points (), width (0), height (0), is_dense (true),
196  sensor_origin_ (Eigen::Vector4f::Zero ()), sensor_orientation_ (Eigen::Quaternionf::Identity ()),
197  mapping_ ()
198  {
199  *this = pc;
200  }
201 
206  header (), points (), width (0), height (0), is_dense (true),
207  sensor_origin_ (Eigen::Vector4f::Zero ()), sensor_orientation_ (Eigen::Quaternionf::Identity ()),
208  mapping_ ()
209  {
210  *this = pc;
211  }
212 
218  const std::vector<int> &indices) :
219  header (pc.header), points (indices.size ()), width (indices.size ()), height (1), is_dense (pc.is_dense),
221  mapping_ ()
222  {
223  // Copy the obvious
224  assert (indices.size () <= pc.size ());
225  for (size_t i = 0; i < indices.size (); i++)
226  points[i] = pc.points[indices[i]];
227  }
228 
234  PointCloud (uint32_t width_, uint32_t height_, const PointT& value_ = PointT ())
235  : header ()
236  , points (width_ * height_, value_)
237  , width (width_)
238  , height (height_)
239  , is_dense (true)
240  , sensor_origin_ (Eigen::Vector4f::Zero ())
241  , sensor_orientation_ (Eigen::Quaternionf::Identity ())
242  , mapping_ ()
243  {}
244 
246  virtual ~PointCloud () {}
247 
249 
253  inline PointCloud&
255  {
256  // Make the resultant point cloud take the newest stamp
257  if (rhs.header.stamp > header.stamp)
258  header.stamp = rhs.header.stamp;
259 
260  size_t nr_points = points.size ();
261  points.resize (nr_points + rhs.points.size ());
262  for (size_t i = nr_points; i < points.size (); ++i)
263  points[i] = rhs.points[i - nr_points];
264 
265  width = static_cast<uint32_t>(points.size ());
266  height = 1;
267  if (rhs.is_dense && is_dense)
268  is_dense = true;
269  else
270  is_dense = false;
271  return (*this);
272  }
273 
275 
279  inline const PointCloud
281  {
282  return (PointCloud (*this) += rhs);
283  }
284 
286 
291  inline const PointT&
292  at (int column, int row) const
293  {
294  if (this->height > 1)
295  return (points.at (row * this->width + column));
296  else
297  throw IsNotDenseException ("Can't use 2D indexing with a unorganized point cloud");
298  }
299 
305  inline PointT&
306  at (int column, int row)
307  {
308  if (this->height > 1)
309  return (points.at (row * this->width + column));
310  else
311  throw IsNotDenseException ("Can't use 2D indexing with a unorganized point cloud");
312  }
313 
315 
320  inline const PointT&
321  operator () (size_t column, size_t row) const
322  {
323  return (points[row * this->width + column]);
324  }
325 
331  inline PointT&
332  operator () (size_t column, size_t row)
333  {
334  return (points[row * this->width + column]);
335  }
336 
338 
341  inline bool
342  isOrganized () const
343  {
344  return (height != 1);
345  }
346 
348 
363  inline Eigen::Map<Eigen::MatrixXf, Eigen::Aligned, Eigen::OuterStride<> >
364  getMatrixXfMap (int dim, int stride, int offset)
365  {
366  if (Eigen::MatrixXf::Flags & Eigen::RowMajorBit)
367  return (Eigen::Map<Eigen::MatrixXf, Eigen::Aligned, Eigen::OuterStride<> >(reinterpret_cast<float*>(&points[0])+offset, points.size (), dim, Eigen::OuterStride<> (stride)));
368  else
369  return (Eigen::Map<Eigen::MatrixXf, Eigen::Aligned, Eigen::OuterStride<> >(reinterpret_cast<float*>(&points[0])+offset, dim, points.size (), Eigen::OuterStride<> (stride)));
370  }
371 
387  inline const Eigen::Map<const Eigen::MatrixXf, Eigen::Aligned, Eigen::OuterStride<> >
388  getMatrixXfMap (int dim, int stride, int offset) const
389  {
390  if (Eigen::MatrixXf::Flags & Eigen::RowMajorBit)
391  return (Eigen::Map<const Eigen::MatrixXf, Eigen::Aligned, Eigen::OuterStride<> >(reinterpret_cast<float*>(&points[0])+offset, points.size (), dim, Eigen::OuterStride<> (stride)));
392  else
393  return (Eigen::Map<const Eigen::MatrixXf, Eigen::Aligned, Eigen::OuterStride<> >(reinterpret_cast<float*>(&points[0])+offset, dim, points.size (), Eigen::OuterStride<> (stride)));
394  }
395 
397 
402  inline Eigen::Map<Eigen::MatrixXf, Eigen::Aligned, Eigen::OuterStride<> >
404  {
405  return (getMatrixXfMap (sizeof (PointT) / sizeof (float), sizeof (PointT) / sizeof (float), 0));
406  }
407 
413  inline const Eigen::Map<const Eigen::MatrixXf, Eigen::Aligned, Eigen::OuterStride<> >
414  getMatrixXfMap () const
415  {
416  return (getMatrixXfMap (sizeof (PointT) / sizeof (float), sizeof (PointT) / sizeof (float), 0));
417  }
418 
421 
423  std::vector<PointT, Eigen::aligned_allocator<PointT> > points;
424 
426  uint32_t width;
428  uint32_t height;
429 
431  bool is_dense;
432 
434  Eigen::Vector4f sensor_origin_;
436  Eigen::Quaternionf sensor_orientation_;
437 
438  typedef PointT PointType; // Make the template class available from the outside
439  typedef std::vector<PointT, Eigen::aligned_allocator<PointT> > VectorType;
440  typedef std::vector<PointCloud<PointT>, Eigen::aligned_allocator<PointCloud<PointT> > > CloudVectorType;
441  typedef boost::shared_ptr<PointCloud<PointT> > Ptr;
442  typedef boost::shared_ptr<const PointCloud<PointT> > ConstPtr;
443 
444  // iterators
445  typedef typename VectorType::iterator iterator;
446  typedef typename VectorType::const_iterator const_iterator;
447  inline iterator begin () { return (points.begin ()); }
448  inline iterator end () { return (points.end ()); }
449  inline const_iterator begin () const { return (points.begin ()); }
450  inline const_iterator end () const { return (points.end ()); }
451 
452  //capacity
453  inline size_t size () const { return (points.size ()); }
454  inline void reserve (size_t n) { points.reserve (n); }
455  inline bool empty () const { return points.empty (); }
456 
460  inline void resize (size_t n)
461  {
462  points.resize (n);
463  if (width * height != n)
464  {
465  width = static_cast<uint32_t> (n);
466  height = 1;
467  }
468  }
469 
470  //element access
471  inline const PointT& operator[] (size_t n) const { return (points[n]); }
472  inline PointT& operator[] (size_t n) { return (points[n]); }
473  inline const PointT& at (size_t n) const { return (points.at (n)); }
474  inline PointT& at (size_t n) { return (points.at (n)); }
475  inline const PointT& front () const { return (points.front ()); }
476  inline PointT& front () { return (points.front ()); }
477  inline const PointT& back () const { return (points.back ()); }
478  inline PointT& back () { return (points.back ()); }
479 
484  inline void
485  push_back (const PointT& pt)
486  {
487  points.push_back (pt);
488  width = static_cast<uint32_t> (points.size ());
489  height = 1;
490  }
491 
498  inline iterator
499  insert (iterator position, const PointT& pt)
500  {
501  iterator it = points.insert (position, pt);
502  width = static_cast<uint32_t> (points.size ());
503  height = 1;
504  return (it);
505  }
506 
513  inline void
514  insert (iterator position, size_t n, const PointT& pt)
515  {
516  points.insert (position, n, pt);
517  width = static_cast<uint32_t> (points.size ());
518  height = 1;
519  }
520 
527  template <class InputIterator> inline void
528  insert (iterator position, InputIterator first, InputIterator last)
529  {
530  points.insert (position, first, last);
531  width = static_cast<uint32_t> (points.size ());
532  height = 1;
533  }
534 
540  inline iterator
541  erase (iterator position)
542  {
543  iterator it = points.erase (position);
544  width = static_cast<uint32_t> (points.size ());
545  height = 1;
546  return (it);
547  }
548 
555  inline iterator
556  erase (iterator first, iterator last)
557  {
558  iterator it = points.erase (first, last);
559  width = static_cast<uint32_t> (points.size ());
560  height = 1;
561  return (it);
562  }
563 
567  inline void
569  {
570  this->points.swap (rhs.points);
571  std::swap (width, rhs.width);
572  std::swap (height, rhs.height);
573  std::swap (is_dense, rhs.is_dense);
574  std::swap (sensor_origin_, rhs.sensor_origin_);
575  std::swap (sensor_orientation_, rhs.sensor_orientation_);
576  }
577 
579  inline void
580  clear ()
581  {
582  points.clear ();
583  width = 0;
584  height = 0;
585  }
586 
592  inline Ptr
593  makeShared () const { return Ptr (new PointCloud<PointT> (*this)); }
594 
595  protected:
596  // This is motivated by ROS integration. Users should not need to access mapping_.
597  boost::shared_ptr<MsgFieldMap> mapping_;
598 
599  friend boost::shared_ptr<MsgFieldMap>& detail::getMapping<PointT>(pcl::PointCloud<PointT> &p);
600 
601  public:
602  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
603  };
604 
623  template <>
624  class PointCloud<Eigen::MatrixXf>
625  {
626  public:
631  properties (), points (Eigen::MatrixXf (0, 0)), channels (), width (0), height (0), is_dense (true)
632  {}
633 
638  properties (), points (Eigen::MatrixXf (0, 0)), channels (), width (0), height (0), is_dense (true)
639  {
640  *this = pc;
641  }
642 
646  template <typename PointT>
648  properties (), points (Eigen::MatrixXf (0, 0)), channels (),
649  width (pc.width), height (pc.height), is_dense (pc.is_dense)
650  {
651  // Copy the obvious
652  properties.acquisition_time = pc.header.stamp;
653  properties.sensor_origin = pc.sensor_origin_;//.head<3> ();
654  properties.sensor_orientation = pc.sensor_orientation_;
655 
656  typedef typename pcl::traits::fieldList<PointT>::type FieldList;
657  // Copy the fields
658  pcl::for_each_type <FieldList> (CopyFieldsChannelProperties <PointT> (channels));
659 
660  // Resize the array
661  points.resize (pc.points.size (), boost::mpl::size<FieldList>::value);
662 
663  for (size_t cp = 0; cp < pc.points.size (); ++cp)
664  pcl::for_each_type <FieldList> (NdCopyPointEigenFunctor<PointT, Eigen::MatrixXf::RowXpr> (pc.points[cp], points.row (cp)));
665  }
666 
671  properties (), points (Eigen::MatrixXf (0, 0)), channels (), width (0), height (0), is_dense (true)
672  {
673  *this = pc;
674  }
675 
679  template <typename PointT>
681  properties (), points (Eigen::MatrixXf (0, 0)), channels (),
682  width (pc.width), height (pc.height), is_dense (pc.is_dense)
683  {
684  // Copy the obvious
685  properties.acquisition_time = pc.header.stamp;
686  properties.sensor_origin = pc.sensor_origin_;//.head<3> ();
687  properties.sensor_orientation = pc.sensor_orientation_;
688 
689  typedef typename pcl::traits::fieldList<PointT>::type FieldList;
690 
691  // Copy the fields
692  pcl::for_each_type <FieldList> (CopyFieldsChannelProperties <PointT> (channels));
693 
694  // Resize the array
695  points.resize (pc.points.size (), boost::mpl::size<FieldList>::value);
696 
697  for (size_t cp = 0; cp < pc.points.size (); ++cp)
698  pcl::for_each_type <FieldList> (NdCopyPointEigenFunctor<PointT, Eigen::MatrixXf::RowXpr> (pc.points[cp], points.row (cp)));
699  }
700 
705  PointCloud (const PointCloud &pc,
706  const std::vector<int> &indices) :
707  properties (pc.properties),
708  points (Eigen::MatrixXf (indices.size (), pc.points.cols ())),
709  channels (pc.channels),
710  width (static_cast<uint32_t> (indices.size ())), height (1), is_dense (pc.is_dense)
711  {
712  // Copy the obvious
713  assert (static_cast<int>(indices.size ()) <= pc.points.rows ());
714  for (size_t i = 0; i < indices.size (); i++)
715  points.row (i) = pc.points.row (indices[i]);
716  }
717 
723  inline PointCloud (uint32_t _width, uint32_t _height, uint32_t _dim)
724  : properties ()
725  , points (Eigen::MatrixXf (_width * _height, _dim))
726  , channels ()
727  , width (_width)
728  , height (_height)
729  , is_dense (true)
730  {}
731 
736  inline PointCloud (uint32_t _num_points, uint32_t _dim)
737  : properties ()
738  , points (Eigen::MatrixXf (_num_points, _dim))
739  , channels ()
740  , width (_num_points)
741  , height (1)
742  , is_dense (true)
743  {}
744 
746  virtual ~PointCloud () {}
747 
749 
753  inline PointCloud&
755  {
756  if (rhs.properties.acquisition_time > properties.acquisition_time)
757  properties.acquisition_time = rhs.properties.acquisition_time;
758 
759  properties.sensor_origin = Eigen::Vector4f::Zero ();
760  properties.sensor_orientation = Eigen::Quaternionf::Identity ();
761 
762  int nr_points = static_cast<int>(points.rows ());
763  points.resize (nr_points + rhs.points.rows (), points.cols ());
764  for (int i = nr_points; i < points.rows (); ++i)
765  points.row (i) = rhs.points.row (i - nr_points);
766 
767  channels = rhs.channels;
768  width = static_cast<uint32_t>(points.rows ());
769  height = 1;
770  if (rhs.is_dense && is_dense)
771  is_dense = true;
772  else
773  is_dense = false;
774  return (*this);
775  }
776 
778 
782  inline const PointCloud
784  {
785  return (PointCloud (*this) += rhs);
786  }
787 
789 
794  inline Eigen::Map<Eigen::VectorXf>
795  at (int column, int row)
796  {
797  if (height > 1)
798  return (Eigen::VectorXf::Map (&points (row * width + column, 0), points.cols ()));
799  else
800  throw IsNotDenseException ("Can't use 2D indexing with a unorganized point cloud");
801  }
802 
804 
809  inline Eigen::Map<Eigen::VectorXf>
810  operator () (int column, int row)
811  {
812  return (Eigen::VectorXf::Map (&points (row * width + column, 0), points.cols ()));
813  }
814 
816 
819  inline bool
820  isOrganized () const
821  {
822  return (height != 1);
823  }
824 
826 
827  inline bool
828  empty () const
829  {
830  return (points.rows () == 0);
831  }
832 
835 
837  Eigen::MatrixXf points;
838 
840  std::map<std::string, pcl::ChannelProperties> channels;
841 
843  uint32_t width;
845  uint32_t height;
846 
848  bool is_dense;
849 
850  typedef boost::shared_ptr<PointCloud<Eigen::MatrixXf> > Ptr;
851  typedef boost::shared_ptr<const PointCloud<Eigen::MatrixXf> > ConstPtr;
852 
853  inline size_t size () const { return (points.rows ()); }
854 
858  inline void
860  {
861  std::swap (points, rhs.points);
862  std::swap (width, rhs.width);
863  std::swap (height, rhs.height);
864  std::swap (is_dense, rhs.is_dense);
865  std::swap (properties, rhs.properties);
866  std::swap (channels, rhs.channels);
867  }
868 
870  inline void
871  clear ()
872  {
873  points.resize (0, 0);
874  width = 0;
875  height = 0;
876  }
877 
883  inline Ptr
884  makeShared () { return Ptr (new PointCloud<Eigen::MatrixXf> (*this)); }
885 
890  inline ConstPtr
891  makeShared () const { return ConstPtr (new PointCloud<Eigen::MatrixXf> (*this)); }
892 
893  public:
894  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
895 
896  private:
898 
899  template <typename PointOutT, typename PointInT>
901  {
902  typedef typename traits::POD<PointOutT>::type Pod;
903 
908  NdCopyEigenPointFunctor (const PointInT p1, PointOutT &p2)
909  : p1_ (p1),
910  p2_ (reinterpret_cast<Pod&>(p2)),
911  f_idx_ (0) { }
912 
914  template<typename Key> inline void
915  operator() ()
916  {
917  //boost::fusion::at_key<Key> (p2_) = p1_[f_idx_++];
919  uint8_t* data_ptr = reinterpret_cast<uint8_t*>(&p2_) + pcl::traits::offset<PointOutT, Key>::value;
920  *reinterpret_cast<T*>(data_ptr) = p1_[f_idx_++];
921  }
922 
923  private:
924  const PointInT p1_;
925  Pod &p2_;
926  int f_idx_;
927  public:
928  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
929  };
930 
932 
933  template <typename PointInT, typename PointOutT>
934  struct NdCopyPointEigenFunctor
935  {
936  typedef typename traits::POD<PointInT>::type Pod;
937 
942  NdCopyPointEigenFunctor (const PointInT &p1, PointOutT p2)
943  : p1_ (reinterpret_cast<const Pod&>(p1)), p2_ (p2), f_idx_ (0) { }
944 
946  template<typename Key> inline void
947  operator() ()
948  {
949  //p2_[f_idx_++] = boost::fusion::at_key<Key> (p1_);
951  const uint8_t* data_ptr = reinterpret_cast<const uint8_t*>(&p1_) + pcl::traits::offset<PointInT, Key>::value;
952  p2_[f_idx_++] = *reinterpret_cast<const T*>(data_ptr);
953  }
954 
955  private:
956  const Pod &p1_;
957  PointOutT p2_;
958  int f_idx_;
959  public:
960  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
961  };
962 
964 
965  template <typename T>
966  struct CopyFieldsChannelProperties
967  {
971  CopyFieldsChannelProperties (std::map<std::string, pcl::ChannelProperties> &channels)
972  : channels_ (channels) {}
973 
975  template<typename U> inline void
976  operator() ()
977  {
978  //boost::fusion::at_key<Key> (p2_) = p1_[f_idx_++];
979  std::string name = pcl::traits::name<T, U>::value;
980  channels_[name].name = name;
981  channels_[name].offset = pcl::traits::offset<T, U>::value;
982  uint8_t datatype = pcl::traits::datatype<T, U>::value;
983  channels_[name].datatype = datatype;
985  channels_[name].count = count;
986  switch (datatype)
987  {
990  {
991  channels_[name].size = count;
992  break;
993  }
994 
997  {
998  channels_[name].size = count * 2;
999  break;
1000  }
1001 
1005  {
1006  channels_[name].size = count * 4;
1007  break;
1008  }
1009 
1011  {
1012  channels_[name].size = count * 8;
1013  break;
1014  }
1015  }
1016  }
1017 
1018  private:
1019  std::map<std::string, pcl::ChannelProperties> &channels_;
1020  };
1021  };
1022 
1024  namespace detail
1025  {
1026  template <typename PointT> boost::shared_ptr<pcl::MsgFieldMap>&
1028  {
1029  return (p.mapping_);
1030  }
1031  } // namespace detail
1032 
1033  template <typename PointT> std::ostream&
1034  operator << (std::ostream& s, const pcl::PointCloud<PointT> &p)
1035  {
1036  s << "points[]: " << p.points.size () << std::endl;
1037  s << "width: " << p.width << std::endl;
1038  s << "height: " << p.height << std::endl;
1039  s << "is_dense: " << p.is_dense << std::endl;
1040  return (s);
1041  }
1042 }
1043 
1044 #endif //#ifndef PCL_POINT_CLOUD_H_