@@ -361,86 +361,6 @@ PointCloudColorHandlerHSVField<PointT>::getColor () const
361
361
return scalars;
362
362
}
363
363
364
-
365
- template <typename PointT> void
366
- PointCloudColorHandlerGenericField<PointT>::setInputCloud (
367
- const PointCloudConstPtr &cloud)
368
- {
369
- PointCloudColorHandler<PointT>::setInputCloud (cloud);
370
- field_idx_ = pcl::getFieldIndex<PointT> (field_name_, fields_);
371
- if (field_idx_ == -1 ) {
372
- capable_ = false ;
373
- return ;
374
- }
375
- if (fields_[field_idx_].datatype != pcl::PCLPointField::PointFieldTypes::FLOAT32) {
376
- capable_ = false ;
377
- PCL_ERROR (" [pcl::PointCloudColorHandlerGenericField::setInputCloud] This currently only works with float32 fields, but field %s has a different type.\n " , field_name_.c_str ());
378
- return ;
379
- }
380
- capable_ = true ;
381
- }
382
-
383
-
384
- template <typename PointT> vtkSmartPointer<vtkDataArray>
385
- PointCloudColorHandlerGenericField<PointT>::getColor () const
386
- {
387
- if (!capable_ || !cloud_)
388
- return nullptr ;
389
-
390
- auto scalars = vtkSmartPointer<vtkFloatArray>::New ();
391
- scalars->SetNumberOfComponents (1 );
392
-
393
- vtkIdType nr_points = cloud_->size ();
394
- scalars->SetNumberOfTuples (nr_points);
395
-
396
- using FieldList = typename pcl::traits::fieldList<PointT>::type;
397
-
398
- float * colors = new float [nr_points];
399
- float field_data;
400
-
401
- int j = 0 ;
402
- // If XYZ present, check if the points are invalid
403
- int x_idx = -1 ;
404
- for (std::size_t d = 0 ; d < fields_.size (); ++d)
405
- if (fields_[d].name == " x" )
406
- x_idx = static_cast <int > (d);
407
-
408
- if (x_idx != -1 )
409
- {
410
- // Color every point
411
- for (vtkIdType cp = 0 ; cp < nr_points; ++cp)
412
- {
413
- // Copy the value at the specified field
414
- if (!pcl::isXYZFinite ((*cloud_)[cp]))
415
- continue ;
416
-
417
- const std::uint8_t * pt_data = reinterpret_cast <const std::uint8_t *> (&(*cloud_)[cp]);
418
- memcpy (&field_data, pt_data + fields_[field_idx_].offset , pcl::getFieldSize (fields_[field_idx_].datatype ));
419
-
420
- colors[j] = field_data;
421
- j++;
422
- }
423
- }
424
- else
425
- {
426
- // Color every point
427
- for (vtkIdType cp = 0 ; cp < nr_points; ++cp)
428
- {
429
- const std::uint8_t * pt_data = reinterpret_cast <const std::uint8_t *> (&(*cloud_)[cp]);
430
- memcpy (&field_data, pt_data + fields_[field_idx_].offset , pcl::getFieldSize (fields_[field_idx_].datatype ));
431
-
432
- if (!std::isfinite (field_data))
433
- continue ;
434
-
435
- colors[j] = field_data;
436
- j++;
437
- }
438
- }
439
- scalars->SetArray (colors, j, 0 , vtkFloatArray::VTK_DATA_ARRAY_DELETE);
440
- return scalars;
441
- }
442
-
443
-
444
364
template <typename PointT> void
445
365
PointCloudColorHandlerRGBAField<PointT>::setInputCloud (
446
366
const PointCloudConstPtr &cloud)
@@ -564,6 +484,177 @@ PointCloudColorHandlerLabelField<PointT>::getColor () const
564
484
return scalars;
565
485
}
566
486
487
+ // ----
488
+ // template specializations for PointCloud and PCLPointCloud2 to access certain
489
+ // data from PointCloudColorHandlerGenericField without needing to know the
490
+ // cloud type
491
+
492
+ // Get point fields from cloud. Could not get it to work with existing
493
+ // pcl::getFields
494
+ inline template <typename CloudT> std::vector<pcl::PCLPointField>
495
+ getFields (const CloudT& cloud)
496
+ {
497
+ return pcl::getFields<typename CloudT::PointType>();
498
+ }
499
+
500
+ // Get point step. Does not directly exist in pcl::PointCloud
501
+ inline template <typename CloudT> int getPointStep (const CloudT&)
502
+ {
503
+ return sizeof (typename CloudT::PointType);
504
+ }
505
+
506
+ // Get cloud data blob
507
+ inline template <typename CloudT> const std::uint8_t * getCloudData (const CloudT& cloud)
508
+ {
509
+ return reinterpret_cast <const std::uint8_t *>(cloud.points .data ());
510
+ }
511
+
512
+ inline const std::uint8_t * getCloudData (const typename pcl::PCLPointCloud2& cloud)
513
+ {
514
+ return reinterpret_cast <const std::uint8_t *>(cloud.data .data ());
515
+ }
516
+
517
+ // copy of pcl::getFieldIndex() from impl/io.hpp, without the unused template
518
+ // parameter
519
+ static int getFieldIndex (const std::string& field_name,
520
+ const std::vector<pcl::PCLPointField>& fields)
521
+ {
522
+ const auto result =
523
+ std::find_if (fields.begin (), fields.end (), [&field_name](const auto & field) {
524
+ return field.name == field_name;
525
+ });
526
+ if (result == fields.end ()) {
527
+ return -1 ;
528
+ }
529
+ return std::distance (fields.begin (), result);
530
+ }
531
+
532
+ template <typename DType, typename RType> RType reinterpret_and_cast (const std::uint8_t * p)
533
+ {
534
+ return static_cast <RType>(*reinterpret_cast <const DType*>(p));
535
+ }
536
+
537
+ /* *
538
+ * @brief Get the value of a point field from raw data pointer and field type.
539
+ *
540
+ * @tparam T return type the field will be cast as
541
+ * @param data data pointer
542
+ * @param type point field type
543
+ *
544
+ * @return field value
545
+ */
546
+ template <typename T> T point_field_as (const std::uint8_t * data, const std::uint8_t type)
547
+ {
548
+ switch (type) {
549
+ case pcl::PCLPointField::PointFieldTypes::FLOAT32:
550
+ return reinterpret_and_cast<float , T>(data);
551
+ break ;
552
+ case pcl::PCLPointField::PointFieldTypes::UINT8:
553
+ return reinterpret_and_cast<std::uint8_t , T>(data);
554
+ break ;
555
+ case pcl::PCLPointField::PointFieldTypes::UINT16:
556
+ return reinterpret_and_cast<std::uint16_t , T>(data);
557
+ break ;
558
+ case pcl::PCLPointField::PointFieldTypes::UINT32:
559
+ return reinterpret_and_cast<std::uint32_t , T>(data);
560
+ break ;
561
+ case pcl::PCLPointField::PointFieldTypes::UINT64:
562
+ return reinterpret_and_cast<std::uint64_t , T>(data);
563
+ break ;
564
+ case pcl::PCLPointField::PointFieldTypes::BOOL:
565
+ return reinterpret_and_cast<bool , T>(data);
566
+ break ;
567
+ case pcl::PCLPointField::PointFieldTypes::FLOAT64:
568
+ return reinterpret_and_cast<double , T>(data);
569
+ break ;
570
+ case pcl::PCLPointField::PointFieldTypes::INT16:
571
+ return reinterpret_and_cast<std::int16_t , T>(data);
572
+ break ;
573
+ case pcl::PCLPointField::PointFieldTypes::INT32:
574
+ return reinterpret_and_cast<std::int32_t , T>(data);
575
+ break ;
576
+ case pcl::PCLPointField::PointFieldTypes::INT64:
577
+ return reinterpret_and_cast<std::int64_t , T>(data);
578
+ break ;
579
+ default :
580
+ return 0 ;
581
+ break ;
582
+ }
583
+ }
584
+
585
+ template <typename PointT>
586
+ PointCloudColorHandlerGenericField<PointT>::PointCloudColorHandlerGenericField(
587
+ const PointCloudConstPtr& cloud, const std::string& field_name)
588
+ : PointCloudColorHandler<PointT>(cloud), field_name_(field_name)
589
+ {
590
+ this ->fields_ = getFields (*cloud);
591
+ this ->setInputCloud (cloud);
592
+ }
593
+
594
+ template <typename PointT> void PointCloudColorHandlerGenericField<PointT>::setInputCloud(
595
+ const PointCloudConstPtr& cloud)
596
+ {
597
+ PointCloudColorHandler<PointT>::setInputCloud (cloud);
598
+ this ->field_idx_ = getFieldIndex (field_name_, this ->fields_ );
599
+ this ->capable_ = this ->field_idx_ != -1 ;
600
+ }
601
+
602
+ template <typename PointT> std::string PointCloudColorHandlerGenericField<PointT>::getFieldName() const
603
+ {
604
+ return field_name_;
605
+ }
606
+
607
+ template <typename PointT> vtkSmartPointer<vtkDataArray> PointCloudColorHandlerGenericField<PointT>::getColor() const
608
+ {
609
+ if (!this ->capable_ || !this ->cloud_ ) {
610
+ return nullptr ;
611
+ }
612
+
613
+ auto scalars = vtkSmartPointer<vtkFloatArray>::New ();
614
+ scalars->SetNumberOfComponents (1 );
615
+
616
+ const vtkIdType nr_points = this ->cloud_ ->width * this ->cloud_ ->height ;
617
+ scalars->SetNumberOfTuples (nr_points);
618
+
619
+ // per-point color as a float value. vtk turns that into rgb somehow
620
+ float * colors = new float [nr_points];
621
+
622
+ // Find X channel
623
+ int x_channel_idx = -1 ;
624
+ for (std::size_t channel_idx = 0 ; channel_idx < this ->fields_ .size (); ++channel_idx) {
625
+ if (this ->fields_ [channel_idx].name == " x" ) {
626
+ x_channel_idx = static_cast <int >(channel_idx);
627
+ }
628
+ }
629
+
630
+ int point_offset = this ->fields_ [this ->field_idx_ ].offset ;
631
+ const int point_step = getPointStep<PointCloud>(*this ->cloud_ );
632
+ const std::uint8_t * p_data = getCloudData<PointCloud>(*this ->cloud_ );
633
+ const std::uint8_t field_type = this ->fields_ [this ->field_idx_ ].datatype ;
634
+
635
+ // current index into colors array
636
+ int pt_idx = 0 ;
637
+
638
+ // Color every point
639
+ for (vtkIdType cp = 0 ; cp < nr_points; ++cp, point_offset += point_step) {
640
+
641
+ if (x_channel_idx != -1 && !pcl::isXYZFinite ((*this ->cloud_ )[cp])) {
642
+ // no x channel in the cloud, or point is infinite
643
+ continue ;
644
+ } else {
645
+ // point data at index, field offset already baked into point_offset
646
+ const std::uint8_t * pt_data = &p_data[point_offset];
647
+
648
+ colors[pt_idx] = point_field_as<float >(pt_data, field_type);
649
+
650
+ }
651
+
652
+ ++pt_idx;
653
+ }
654
+
655
+ scalars->SetArray (colors, pt_idx, 0 , vtkFloatArray::VTK_DATA_ARRAY_DELETE);
656
+ return scalars;
657
+ }
658
+
567
659
} // namespace visualization
568
660
} // namespace pcl
569
-
0 commit comments