NASA Astrobee Robot Software  0.19.1
Flight software for the Astrobee robots operating inside the International Space Station.
point_cloud.h
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2013, Open Source Robotics Foundation, Inc.
5  * Copyright (c) 2010-2012, Willow Garage, Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of Open Source Robotics Foundation, Inc. nor
19  * the names of its contributors may be used to endorse or promote
20  * products derived from this software without specific prior
21  * 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 
37 #ifndef MAPPER_POINT_CLOUD_H_
38 #define MAPPER_POINT_CLOUD_H_
39 
40 #include <mapper/pcl_conversions.h>
41 #include <pcl/conversions.h>
42 #include <pcl/for_each_type.h>
43 #include <pcl/point_cloud.h>
44 #include <pcl/point_traits.h>
45 #include <ros/ros.h>
46 #include <sensor_msgs/PointCloud2.h>
47 #include <boost/mpl/size.hpp>
48 #include <boost/ref.hpp>
49 
50 #include <vector>
51 #include <string>
52 
53 // subset of https://github.com/ros-perception/pcl_conversion/
54 // copied due to reduced overhead?
55 
56 namespace pcl {
57 namespace detail {
58 template <typename Stream, typename PointT>
59 struct FieldStreamer {
60  explicit FieldStreamer(Stream& stream) : stream_(stream) {}
61 
62  template <typename U>
63  void operator()() {
64  const char* name = traits::name<PointT, U>::value;
65  uint32_t name_length = strlen(name);
66  stream_.next(name_length);
67  if (name_length > 0)
68  memcpy(stream_.advance(name_length), name, name_length);
69 
70  uint32_t offset = traits::offset<PointT, U>::value;
71  stream_.next(offset);
72 
73  uint8_t datatype = traits::datatype<PointT, U>::value;
74  stream_.next(datatype);
75 
76  uint32_t count = traits::datatype<PointT, U>::size;
77  stream_.next(count);
78  }
79 
80  Stream& stream_;
81 };
82 
83 template <typename PointT>
84 struct FieldsLength {
85  FieldsLength() : length(0) {}
86 
87  template <typename U>
88  void operator()() {
89  uint32_t name_length = strlen(traits::name<PointT, U>::value);
90  length += name_length + 13;
91  }
92 
93  uint32_t length;
94 };
95 } // namespace detail
96 } // namespace pcl
97 
98 namespace ros {
99 // In ROS 1.3.1+, we can specialize the functor used to create PointCloud<T>
100 // objects
101 // on the subscriber side. This allows us to generate the mapping between
102 // message
103 // data and object fields only once and reuse it.
104 #if ROS_VERSION_MINIMUM(1, 3, 1)
105 template <typename T>
106 struct DefaultMessageCreator<pcl::PointCloud<T> > {
107  boost::shared_ptr<pcl::MsgFieldMap> mapping_;
108 
109  DefaultMessageCreator() : mapping_(boost::make_shared<pcl::MsgFieldMap>()) {}
110 
111  boost::shared_ptr<pcl::PointCloud<T> > operator()() {
112  boost::shared_ptr<pcl::PointCloud<T> > msg(new pcl::PointCloud<T>());
113  pcl::detail::getMapping(*msg) = mapping_;
114  return msg;
115  }
116 };
117 #endif
118 
119 namespace message_traits {
120 template <typename T>
121 struct MD5Sum<pcl::PointCloud<T> > {
122  static const char* value() {
123  return MD5Sum<sensor_msgs::PointCloud2>::value();
124  }
125  static const char* value(const pcl::PointCloud<T>&) { return value(); }
126 
127  static const uint64_t static_value1 =
128  MD5Sum<sensor_msgs::PointCloud2>::static_value1;
129  static const uint64_t static_value2 =
130  MD5Sum<sensor_msgs::PointCloud2>::static_value2;
131 
132  // If the definition of sensor_msgs/PointCloud2 changes, we'll get a compile
133  // error here.
134  ROS_STATIC_ASSERT(static_value1 == 0x1158d486dd51d683ULL);
135  ROS_STATIC_ASSERT(static_value2 == 0xce2f1be655c3c181ULL);
136 };
137 
138 template <typename T>
139 struct DataType<pcl::PointCloud<T> > {
140  static const char* value() {
141  return DataType<sensor_msgs::PointCloud2>::value();
142  }
143  static const char* value(const pcl::PointCloud<T>&) { return value(); }
144 };
145 
146 template <typename T>
147 struct Definition<pcl::PointCloud<T> > {
148  static const char* value() {
149  return Definition<sensor_msgs::PointCloud2>::value();
150  }
151  static const char* value(const pcl::PointCloud<T>&) { return value(); }
152 };
153 
154 // pcl point clouds message don't have a ROS compatible header
155 // the specialized meta functions below (TimeStamp and FrameId)
156 // can be used to get the header data.
157 template <typename T>
158 struct HasHeader<pcl::PointCloud<T> > : FalseType {};
159 
160 template <typename T>
161 struct TimeStamp<pcl::PointCloud<T> > {
162  // This specialization could be dangerous, but it's the best I can do.
163  // If this TimeStamp struct is destroyed before they are done with the
164  // pointer returned by the first functions may go out of scope, but there
165  // isn't a lot I can do about that. This is a good reason to refuse to
166  // returning pointers like this...
167  static ros::Time* pointer(typename pcl::PointCloud<T>& m) {
168  header_.reset(new std_msgs::Header());
169  pcl_conversions::fromPCL(m.header, *(header_));
170  return &(header_->stamp);
171  }
172  static ros::Time const* pointer(const typename pcl::PointCloud<T>& m) {
173  header_const_.reset(new std_msgs::Header());
174  pcl_conversions::fromPCL(m.header, *(header_const_));
175  return &(header_const_->stamp);
176  }
177  static ros::Time value(const typename pcl::PointCloud<T>& m) {
178  return pcl_conversions::fromPCL(m.header).stamp;
179  }
180 
181  private:
182  static boost::shared_ptr<std_msgs::Header> header_;
183  static boost::shared_ptr<std_msgs::Header> header_const_;
184 };
185 
186 template <typename T>
187 struct FrameId<pcl::PointCloud<T> > {
188  static std::string* pointer(pcl::PointCloud<T>& m) {
189  return &m.header.frame_id;
190  }
191  static std::string const* pointer(const pcl::PointCloud<T>& m) {
192  return &m.header.frame_id;
193  }
194  static std::string value(const pcl::PointCloud<T>& m) {
195  return m.header.frame_id;
196  }
197 };
198 
199 } // namespace message_traits
200 
201 namespace serialization {
202 template <typename T>
203 struct Serializer<pcl::PointCloud<T> > {
204  template <typename Stream>
205  inline static void write(Stream& stream, const pcl::PointCloud<T>& m) {
206  stream.next(m.header);
207 
208  // Ease the user's burden on specifying width/height for unorganized
209  // datasets
210  uint32_t height = m.height, width = m.width;
211  if (height == 0 && width == 0) {
212  width = m.points.size();
213  height = 1;
214  }
215  stream.next(height);
216  stream.next(width);
217 
218  // Stream out point field metadata
219  typedef typename pcl::traits::fieldList<T>::type FieldList;
220  uint32_t fields_size = boost::mpl::size<FieldList>::value;
221  stream.next(fields_size);
222  pcl::for_each_type<FieldList>(
224 
225  // Assume little-endian...
226  uint8_t is_bigendian = false;
227  stream.next(is_bigendian);
228 
229  // Write out point data as binary blob
230  uint32_t point_step = sizeof(T);
231  stream.next(point_step);
232  uint32_t row_step = point_step * width;
233  stream.next(row_step);
234  uint32_t data_size = row_step * height;
235  stream.next(data_size);
236  memcpy(stream.advance(data_size), &m.points[0], data_size);
237 
238  uint8_t is_dense = m.is_dense;
239  stream.next(is_dense);
240  }
241 
242  template <typename Stream>
243  inline static void read(Stream& stream, pcl::PointCloud<T>& m) {
244  std_msgs::Header header;
245  stream.next(header);
246  pcl_conversions::toPCL(header, m.header);
247  stream.next(m.height);
248  stream.next(m.width);
249 
251  std::vector<sensor_msgs::PointField> fields;
252  stream.next(fields);
253 
254  // Construct field mapping if deserializing for the first time
255  boost::shared_ptr<pcl::MsgFieldMap>& mapping_ptr =
256  pcl::detail::getMapping(m);
257  if (!mapping_ptr) {
258  // This normally should get allocated by DefaultMessageCreator, but just
259  // in case
260  mapping_ptr = boost::make_shared<pcl::MsgFieldMap>();
261  }
262  pcl::MsgFieldMap& mapping = *mapping_ptr;
263  if (mapping.empty()) pcl::createMapping<T>(fields, mapping);
264 
265  uint8_t is_bigendian;
266  stream.next(is_bigendian); // ignoring...
267  uint32_t point_step, row_step;
268  stream.next(point_step);
269  stream.next(row_step);
270 
271  // Copy point data
272  uint32_t data_size;
273  stream.next(data_size);
274  assert(data_size == m.height * m.width * point_step);
275  m.points.resize(m.height * m.width);
276  uint8_t* m_data = reinterpret_cast<uint8_t*>(&m.points[0]);
277  // If the data layouts match, can copy a whole row in one memcpy
278  if (mapping.size() == 1 && mapping[0].serialized_offset == 0 &&
279  mapping[0].struct_offset == 0 && point_step == sizeof(T)) {
280  uint32_t m_row_step = sizeof(T) * m.width;
281  // And if the row steps match, can copy whole point cloud in one memcpy
282  if (m_row_step == row_step) {
283  memcpy(m_data, stream.advance(data_size), data_size);
284  } else {
285  for (uint32_t i = 0; i < m.height; ++i, m_data += m_row_step)
286  memcpy(m_data, stream.advance(row_step), m_row_step);
287  }
288  } else {
289  // If not, do a lot of memcpys to copy over the fields
290  for (uint32_t row = 0; row < m.height; ++row) {
291  const uint8_t* stream_data = stream.advance(row_step);
292  for (uint32_t col = 0; col < m.width;
293  ++col, stream_data += point_step) {
294  BOOST_FOREACH(const pcl::detail::FieldMapping& fm, mapping) {
295  memcpy(m_data + fm.struct_offset,
296  stream_data + fm.serialized_offset, fm.size);
297  }
298  m_data += sizeof(T);
299  }
300  }
301  }
302 
303  uint8_t is_dense;
304  stream.next(is_dense);
305  m.is_dense = is_dense;
306  }
307 
308  inline static uint32_t serializedLength(const pcl::PointCloud<T>& m) {
309  uint32_t length = 0;
310 
311  length += serializationLength(m.header);
312  length += 8; // height/width
313 
315  typedef typename pcl::traits::fieldList<T>::type FieldList;
316  pcl::for_each_type<FieldList>(boost::ref(fl));
317  length += 4; // size of 'fields'
318  length += fl.length;
319 
320  length += 1; // is_bigendian
321  length += 4; // point_step
322  length += 4; // row_step
323  length += 4; // size of 'data'
324  length += m.points.size() * sizeof(T); // data
325  length += 1; // is_dense
326 
327  return length;
328  }
329 };
330 } // namespace serialization
331 
333 
334 } // namespace ros
335 
336 #endif // MAPPER_POINT_CLOUD_H_
pcl
Definition: correspondence_rejection_surface_normal2.h:45
ros::message_traits::FrameId< pcl::PointCloud< T > >::pointer
static std::string * pointer(pcl::PointCloud< T > &m)
Definition: point_cloud.h:188
ros::message_traits::TimeStamp< pcl::PointCloud< T > >::pointer
static ros::Time * pointer(typename pcl::PointCloud< T > &m)
Definition: point_cloud.h:167
ros
Definition: pcl_conversions.h:269
pcl::detail::FieldsLength::FieldsLength
FieldsLength()
Definition: point_cloud.h:85
pcl::detail::FieldStreamer::stream_
Stream & stream_
Definition: point_cloud.h:80
ros::message_traits::FrameId< pcl::PointCloud< T > >::pointer
static std::string const * pointer(const pcl::PointCloud< T > &m)
Definition: point_cloud.h:191
pcl::detail::FieldStreamer
Definition: point_cloud.h:59
point_cloud_common::PointCloud
pcl::PointCloud< PointType >::Ptr PointCloud(const std::vector< Eigen::Vector3d > &points)
Definition: test_utilities.h:65
ros::serialization::Serializer< pcl::PointCloud< T > >::read
static void read(Stream &stream, pcl::PointCloud< T > &m)
Definition: point_cloud.h:243
pcl::detail::FieldStreamer::FieldStreamer
FieldStreamer(Stream &stream)
Definition: point_cloud.h:60
ros::message_traits::Definition< pcl::PointCloud< T > >::value
static const char * value()
Definition: point_cloud.h:148
pcl_conversions::fromPCL
void fromPCL(const pcl::uint64_t &pcl_stamp, ros::Time &stamp)
Definition: pcl_conversions.h:67
ros::message_traits::DataType< pcl::PointCloud< T > >::value
static const char * value()
Definition: point_cloud.h:140
pcl::detail::FieldStreamer::operator()
void operator()()
Definition: point_cloud.h:63
ros::message_traits::DataType< pcl::PointCloud< T > >::value
static const char * value(const pcl::PointCloud< T > &)
Definition: point_cloud.h:143
ros::message_traits::MD5Sum< pcl::PointCloud< T > >::value
static const char * value()
Definition: point_cloud.h:122
ros::message_traits::FrameId< pcl::PointCloud< T > >::value
static std::string value(const pcl::PointCloud< T > &m)
Definition: point_cloud.h:194
name
std::string name
Definition: eps_simulator.cc:48
pcl_conversions::toPCL
void toPCL(const ros::Time &stamp, pcl::uint64_t &pcl_stamp)
Definition: pcl_conversions.h:71
ros::message_traits::MD5Sum< pcl::PointCloud< T > >::value
static const char * value(const pcl::PointCloud< T > &)
Definition: point_cloud.h:125
ros::message_traits::Definition< pcl::PointCloud< T > >::value
static const char * value(const pcl::PointCloud< T > &)
Definition: point_cloud.h:151
ros::message_traits::TimeStamp< pcl::PointCloud< T > >::value
static ros::Time value(const typename pcl::PointCloud< T > &m)
Definition: point_cloud.h:177
ros::message_traits::TimeStamp< pcl::PointCloud< T > >::pointer
static ros::Time const * pointer(const typename pcl::PointCloud< T > &m)
Definition: point_cloud.h:172
pcl::detail::FieldsLength
Definition: point_cloud.h:84
pcl_conversions.h
ros::serialization::Serializer< pcl::PointCloud< T > >::write
static void write(Stream &stream, const pcl::PointCloud< T > &m)
Definition: point_cloud.h:205
pcl::detail::FieldsLength::length
uint32_t length
Definition: point_cloud.h:93
ros::serialization::Serializer< pcl::PointCloud< T > >::serializedLength
static uint32_t serializedLength(const pcl::PointCloud< T > &m)
Definition: point_cloud.h:308
localization_common::Time
double Time
Definition: time.h:23
pcl::detail::FieldsLength::operator()
void operator()()
Definition: point_cloud.h:88