1 /*
2 * Software License Agreement (BSD License)
3 *
4 * Point Cloud Library (PCL) - www.pointclouds.org
5 * Copyright (c) 2010-2011, Willow Garage, Inc.
6 * Copyright (c) 2012-, Open Perception, Inc.
7 *
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * * Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer in the documentation and/or other materials provided
19 * with the distribution.
20 * * Neither the name of the copyright holder(s) nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 *
37 * $Id$
38 *
39 */
40
41 #pragma once
42
43 #include <pcl/conversions.h> // for FieldAdder
44 #include <pcl/common/concatenate.h>
45 #include <pcl/common/copy_point.h>
46 #include <pcl/common/io.h>
47 #include <pcl/point_types.h>
48
49
50 namespace pcl
51 {
52
53 template <typename PointT> int
getFieldIndex(const pcl::PointCloud<PointT> &,const std::string & field_name,std::vector<pcl::PCLPointField> & fields)54 getFieldIndex (const pcl::PointCloud<PointT> &,
55 const std::string &field_name,
56 std::vector<pcl::PCLPointField> &fields)
57 {
58 return getFieldIndex<PointT>(field_name, fields);
59 }
60
61
62 template <typename PointT> int
getFieldIndex(const std::string & field_name,std::vector<pcl::PCLPointField> & fields)63 getFieldIndex (const std::string &field_name,
64 std::vector<pcl::PCLPointField> &fields)
65 {
66 fields = getFields<PointT> ();
67 const auto& ref = fields;
68 return pcl::getFieldIndex<PointT> (field_name, ref);
69 }
70
71
72 template <typename PointT> int
getFieldIndex(const std::string & field_name,const std::vector<pcl::PCLPointField> & fields)73 getFieldIndex (const std::string &field_name,
74 const std::vector<pcl::PCLPointField> &fields)
75 {
76 const auto result = std::find_if(fields.begin (), fields.end (),
77 [&field_name](const auto& field) { return field.name == field_name; });
78 if (result == fields.end ())
79 return -1;
80 return std::distance(fields.begin (), result);
81 }
82
83
84 template <typename PointT> void
getFields(const pcl::PointCloud<PointT> &,std::vector<pcl::PCLPointField> & fields)85 getFields (const pcl::PointCloud<PointT> &, std::vector<pcl::PCLPointField> &fields)
86 {
87 fields = getFields<PointT> ();
88 }
89
90
91 template <typename PointT> void
getFields(std::vector<pcl::PCLPointField> & fields)92 getFields (std::vector<pcl::PCLPointField> &fields)
93 {
94 fields = getFields<PointT> ();
95 }
96
97
98 template <typename PointT> std::vector<pcl::PCLPointField>
getFields()99 getFields ()
100 {
101 std::vector<pcl::PCLPointField> fields;
102 // Get the fields list
103 pcl::for_each_type<typename pcl::traits::fieldList<PointT>::type>(pcl::detail::FieldAdder<PointT>(fields));
104 return fields;
105 }
106
107
108 template <typename PointT> std::string
getFieldsList(const pcl::PointCloud<PointT> &)109 getFieldsList (const pcl::PointCloud<PointT> &)
110 {
111 // Get the fields list
112 const auto fields = getFields<PointT>();
113 std::string result;
114 for (std::size_t i = 0; i < fields.size () - 1; ++i)
115 result += fields[i].name + " ";
116 result += fields[fields.size () - 1].name;
117 return (result);
118 }
119
120 namespace detail
121 {
122
123 template <typename PointInT, typename PointOutT> void
copyPointCloudMemcpy(const pcl::PointCloud<PointInT> & cloud_in,pcl::PointCloud<PointOutT> & cloud_out)124 copyPointCloudMemcpy (const pcl::PointCloud<PointInT> &cloud_in,
125 pcl::PointCloud<PointOutT> &cloud_out)
126 {
127 // Iterate over each point, if the point types of two clouds are different
128 for (std::size_t i = 0; i < cloud_in.size (); ++i)
129 copyPoint (cloud_in[i], cloud_out[i]);
130 }
131
132
133 template <typename PointT> void
copyPointCloudMemcpy(const pcl::PointCloud<PointT> & cloud_in,pcl::PointCloud<PointT> & cloud_out)134 copyPointCloudMemcpy (const pcl::PointCloud<PointT> &cloud_in,
135 pcl::PointCloud<PointT> &cloud_out)
136 {
137 // Use std::copy directly, if the point types of two clouds are same
138 std::copy (&cloud_in[0], (&cloud_in[0]) + cloud_in.size (), &cloud_out[0]);
139 }
140
141 } // namespace detail
142
143 template <typename PointInT, typename PointOutT> void
copyPointCloud(const pcl::PointCloud<PointInT> & cloud_in,pcl::PointCloud<PointOutT> & cloud_out)144 copyPointCloud (const pcl::PointCloud<PointInT> &cloud_in,
145 pcl::PointCloud<PointOutT> &cloud_out)
146 {
147 // Allocate enough space and copy the basics
148 cloud_out.header = cloud_in.header;
149 cloud_out.width = cloud_in.width;
150 cloud_out.height = cloud_in.height;
151 cloud_out.is_dense = cloud_in.is_dense;
152 cloud_out.sensor_orientation_ = cloud_in.sensor_orientation_;
153 cloud_out.sensor_origin_ = cloud_in.sensor_origin_;
154 cloud_out.resize (cloud_in.size ());
155
156 if (!cloud_in.empty ())
157 detail::copyPointCloudMemcpy (cloud_in, cloud_out);
158 }
159
160
161 template <typename PointT, typename IndicesVectorAllocator> void
copyPointCloud(const pcl::PointCloud<PointT> & cloud_in,const IndicesAllocator<IndicesVectorAllocator> & indices,pcl::PointCloud<PointT> & cloud_out)162 copyPointCloud (const pcl::PointCloud<PointT> &cloud_in,
163 const IndicesAllocator< IndicesVectorAllocator> &indices,
164 pcl::PointCloud<PointT> &cloud_out)
165 {
166 // Do we want to copy everything?
167 if (indices.size () == cloud_in.size ())
168 {
169 cloud_out = cloud_in;
170 return;
171 }
172
173 // Allocate enough space and copy the basics
174 cloud_out.clear ();
175 cloud_out.reserve (indices.size ());
176 cloud_out.header = cloud_in.header;
177 cloud_out.width = indices.size ();
178 cloud_out.height = 1;
179 cloud_out.is_dense = cloud_in.is_dense;
180 cloud_out.sensor_orientation_ = cloud_in.sensor_orientation_;
181 cloud_out.sensor_origin_ = cloud_in.sensor_origin_;
182
183 // Iterate over each point
184 for (const auto& index : indices)
185 cloud_out.transient_push_back (cloud_in[index]);
186 }
187
188
189 template <typename PointInT, typename PointOutT, typename IndicesVectorAllocator> void
copyPointCloud(const pcl::PointCloud<PointInT> & cloud_in,const IndicesAllocator<IndicesVectorAllocator> & indices,pcl::PointCloud<PointOutT> & cloud_out)190 copyPointCloud (const pcl::PointCloud<PointInT> &cloud_in,
191 const IndicesAllocator< IndicesVectorAllocator> &indices,
192 pcl::PointCloud<PointOutT> &cloud_out)
193 {
194 // Allocate enough space and copy the basics
195 cloud_out.resize (indices.size ());
196 cloud_out.header = cloud_in.header;
197 cloud_out.width = indices.size ();
198 cloud_out.height = 1;
199 cloud_out.is_dense = cloud_in.is_dense;
200 cloud_out.sensor_orientation_ = cloud_in.sensor_orientation_;
201 cloud_out.sensor_origin_ = cloud_in.sensor_origin_;
202
203 // Iterate over each point
204 for (std::size_t i = 0; i < indices.size (); ++i)
205 copyPoint (cloud_in[indices[i]], cloud_out[i]);
206 }
207
208
209 template <typename PointT> void
copyPointCloud(const pcl::PointCloud<PointT> & cloud_in,const pcl::PointIndices & indices,pcl::PointCloud<PointT> & cloud_out)210 copyPointCloud (const pcl::PointCloud<PointT> &cloud_in,
211 const pcl::PointIndices &indices,
212 pcl::PointCloud<PointT> &cloud_out)
213 {
214 copyPointCloud (cloud_in, indices.indices, cloud_out);
215 }
216
217
218 template <typename PointInT, typename PointOutT> void
copyPointCloud(const pcl::PointCloud<PointInT> & cloud_in,const pcl::PointIndices & indices,pcl::PointCloud<PointOutT> & cloud_out)219 copyPointCloud (const pcl::PointCloud<PointInT> &cloud_in,
220 const pcl::PointIndices &indices,
221 pcl::PointCloud<PointOutT> &cloud_out)
222 {
223 copyPointCloud (cloud_in, indices.indices, cloud_out);
224 }
225
226
227 template <typename PointT> void
copyPointCloud(const pcl::PointCloud<PointT> & cloud_in,const std::vector<pcl::PointIndices> & indices,pcl::PointCloud<PointT> & cloud_out)228 copyPointCloud (const pcl::PointCloud<PointT> &cloud_in,
229 const std::vector<pcl::PointIndices> &indices,
230 pcl::PointCloud<PointT> &cloud_out)
231 {
232 std::size_t nr_p = 0;
233 for (const auto &index : indices)
234 nr_p += index.indices.size ();
235
236 // Do we want to copy everything? Remember we assume UNIQUE indices
237 if (nr_p == cloud_in.size ())
238 {
239 cloud_out = cloud_in;
240 return;
241 }
242
243 // Allocate enough space and copy the basics
244 cloud_out.clear ();
245 cloud_out.reserve (nr_p);
246 cloud_out.header = cloud_in.header;
247 cloud_out.width = nr_p;
248 cloud_out.height = 1;
249 cloud_out.is_dense = cloud_in.is_dense;
250 cloud_out.sensor_orientation_ = cloud_in.sensor_orientation_;
251 cloud_out.sensor_origin_ = cloud_in.sensor_origin_;
252
253 // Iterate over each cluster
254 for (const auto &cluster_index : indices)
255 {
256 // Iterate over each idx
257 for (const auto &index : cluster_index.indices)
258 {
259 // Iterate over each dimension
260 cloud_out.transient_push_back (cloud_in[index]);
261 }
262 }
263 }
264
265
266 template <typename PointInT, typename PointOutT> void
copyPointCloud(const pcl::PointCloud<PointInT> & cloud_in,const std::vector<pcl::PointIndices> & indices,pcl::PointCloud<PointOutT> & cloud_out)267 copyPointCloud (const pcl::PointCloud<PointInT> &cloud_in,
268 const std::vector<pcl::PointIndices> &indices,
269 pcl::PointCloud<PointOutT> &cloud_out)
270 {
271 const auto nr_p = std::accumulate(indices.begin (), indices.end (), 0,
272 [](const auto& acc, const auto& index) { return index.indices.size() + acc; });
273
274 // Do we want to copy everything? Remember we assume UNIQUE indices
275 if (nr_p == cloud_in.size ())
276 {
277 copyPointCloud (cloud_in, cloud_out);
278 return;
279 }
280
281 // Allocate enough space and copy the basics
282 cloud_out.resize (nr_p);
283 cloud_out.header = cloud_in.header;
284 cloud_out.width = nr_p;
285 cloud_out.height = 1;
286 cloud_out.is_dense = cloud_in.is_dense;
287 cloud_out.sensor_orientation_ = cloud_in.sensor_orientation_;
288 cloud_out.sensor_origin_ = cloud_in.sensor_origin_;
289
290 // Iterate over each cluster
291 std::size_t cp = 0;
292 for (const auto &cluster_index : indices)
293 {
294 // Iterate over each idx
295 for (const auto &index : cluster_index.indices)
296 {
297 copyPoint (cloud_in[index], cloud_out[cp]);
298 ++cp;
299 }
300 }
301 }
302
303
304 template <typename PointIn1T, typename PointIn2T, typename PointOutT> void
concatenateFields(const pcl::PointCloud<PointIn1T> & cloud1_in,const pcl::PointCloud<PointIn2T> & cloud2_in,pcl::PointCloud<PointOutT> & cloud_out)305 concatenateFields (const pcl::PointCloud<PointIn1T> &cloud1_in,
306 const pcl::PointCloud<PointIn2T> &cloud2_in,
307 pcl::PointCloud<PointOutT> &cloud_out)
308 {
309 using FieldList1 = typename pcl::traits::fieldList<PointIn1T>::type;
310 using FieldList2 = typename pcl::traits::fieldList<PointIn2T>::type;
311
312 if (cloud1_in.size () != cloud2_in.size ())
313 {
314 PCL_ERROR ("[pcl::concatenateFields] The number of points in the two input datasets differs!\n");
315 return;
316 }
317
318 // Resize the output dataset
319 cloud_out.resize (cloud1_in.size ());
320 cloud_out.header = cloud1_in.header;
321 cloud_out.width = cloud1_in.width;
322 cloud_out.height = cloud1_in.height;
323 if (!cloud1_in.is_dense || !cloud2_in.is_dense)
324 cloud_out.is_dense = false;
325 else
326 cloud_out.is_dense = true;
327
328 // Iterate over each point
329 for (std::size_t i = 0; i < cloud_out.size (); ++i)
330 {
331 // Iterate over each dimension
332 pcl::for_each_type <FieldList1> (pcl::NdConcatenateFunctor <PointIn1T, PointOutT> (cloud1_in[i], cloud_out[i]));
333 pcl::for_each_type <FieldList2> (pcl::NdConcatenateFunctor <PointIn2T, PointOutT> (cloud2_in[i], cloud_out[i]));
334 }
335 }
336
337
338 template <typename PointT> void
copyPointCloud(const pcl::PointCloud<PointT> & cloud_in,pcl::PointCloud<PointT> & cloud_out,int top,int bottom,int left,int right,pcl::InterpolationType border_type,const PointT & value)339 copyPointCloud (const pcl::PointCloud<PointT> &cloud_in, pcl::PointCloud<PointT> &cloud_out,
340 int top, int bottom, int left, int right, pcl::InterpolationType border_type, const PointT& value)
341 {
342 if (top < 0 || left < 0 || bottom < 0 || right < 0)
343 {
344 std::string faulty = (top < 0) ? "top" : (left < 0) ? "left" : (bottom < 0) ? "bottom" : "right";
345 PCL_THROW_EXCEPTION (pcl::BadArgumentException, "[pcl::copyPointCloud] error: " << faulty << " must be positive!");
346 return;
347 }
348
349 if (top == 0 && left == 0 && bottom == 0 && right == 0)
350 cloud_out = cloud_in;
351 else
352 {
353 // Allocate enough space and copy the basics
354 cloud_out.header = cloud_in.header;
355 cloud_out.width = cloud_in.width + left + right;
356 cloud_out.height = cloud_in.height + top + bottom;
357 if (cloud_out.size () != cloud_out.width * cloud_out.height)
358 cloud_out.resize (cloud_out.width * cloud_out.height);
359 cloud_out.is_dense = cloud_in.is_dense;
360 cloud_out.sensor_orientation_ = cloud_in.sensor_orientation_;
361 cloud_out.sensor_origin_ = cloud_in.sensor_origin_;
362
363 if (border_type == pcl::BORDER_TRANSPARENT)
364 {
365 const PointT* in = &(cloud_in[0]);
366 PointT* out = &(cloud_out[0]);
367 PointT* out_inner = out + cloud_out.width*top + left;
368 for (std::uint32_t i = 0; i < cloud_in.height; i++, out_inner += cloud_out.width, in += cloud_in.width)
369 {
370 if (out_inner != in)
371 memcpy (out_inner, in, cloud_in.width * sizeof (PointT));
372 }
373 }
374 else
375 {
376 // Copy the data
377 if (border_type != pcl::BORDER_CONSTANT)
378 {
379 try
380 {
381 std::vector<int> padding (cloud_out.width - cloud_in.width);
382 int right = cloud_out.width - cloud_in.width - left;
383 int bottom = cloud_out.height - cloud_in.height - top;
384
385 for (int i = 0; i < left; i++)
386 padding[i] = pcl::interpolatePointIndex (i-left, cloud_in.width, border_type);
387
388 for (int i = 0; i < right; i++)
389 padding[i+left] = pcl::interpolatePointIndex (cloud_in.width+i, cloud_in.width, border_type);
390
391 const PointT* in = &(cloud_in[0]);
392 PointT* out = &(cloud_out[0]);
393 PointT* out_inner = out + cloud_out.width*top + left;
394
395 for (std::uint32_t i = 0; i < cloud_in.height; i++, out_inner += cloud_out.width, in += cloud_in.width)
396 {
397 if (out_inner != in)
398 memcpy (out_inner, in, cloud_in.width * sizeof (PointT));
399
400 for (int j = 0; j < left; j++)
401 out_inner[j - left] = in[padding[j]];
402
403 for (int j = 0; j < right; j++)
404 out_inner[j + cloud_in.width] = in[padding[j + left]];
405 }
406
407 for (int i = 0; i < top; i++)
408 {
409 int j = pcl::interpolatePointIndex (i - top, cloud_in.height, border_type);
410 memcpy (out + i*cloud_out.width,
411 out + (j+top) * cloud_out.width,
412 sizeof (PointT) * cloud_out.width);
413 }
414
415 for (int i = 0; i < bottom; i++)
416 {
417 int j = pcl::interpolatePointIndex (i + cloud_in.height, cloud_in.height, border_type);
418 memcpy (out + (i + cloud_in.height + top)*cloud_out.width,
419 out + (j+top)*cloud_out.width,
420 cloud_out.width * sizeof (PointT));
421 }
422 }
423 catch (pcl::BadArgumentException&)
424 {
425 PCL_ERROR ("[pcl::copyPointCloud] Unhandled interpolation type %d!\n", border_type);
426 }
427 }
428 else
429 {
430 int right = cloud_out.width - cloud_in.width - left;
431 int bottom = cloud_out.height - cloud_in.height - top;
432 std::vector<PointT> buff (cloud_out.width, value);
433 PointT* buff_ptr = &(buff[0]);
434 const PointT* in = &(cloud_in[0]);
435 PointT* out = &(cloud_out[0]);
436 PointT* out_inner = out + cloud_out.width*top + left;
437
438 for (std::uint32_t i = 0; i < cloud_in.height; i++, out_inner += cloud_out.width, in += cloud_in.width)
439 {
440 if (out_inner != in)
441 memcpy (out_inner, in, cloud_in.width * sizeof (PointT));
442
443 memcpy (out_inner - left, buff_ptr, left * sizeof (PointT));
444 memcpy (out_inner + cloud_in.width, buff_ptr, right * sizeof (PointT));
445 }
446
447 for (int i = 0; i < top; i++)
448 {
449 memcpy (out + i*cloud_out.width, buff_ptr, cloud_out.width * sizeof (PointT));
450 }
451
452 for (int i = 0; i < bottom; i++)
453 {
454 memcpy (out + (i + cloud_in.height + top)*cloud_out.width,
455 buff_ptr,
456 cloud_out.width * sizeof (PointT));
457 }
458 }
459 }
460 }
461 }
462
463 } // namespace pcl
464
465