/home/runner/work/beluga/beluga/beluga_ros/include/beluga_ros/point_cloud.hpp Source File

/home/runner/work/beluga/beluga/beluga_ros/include/beluga_ros/point_cloud.hpp Source File#

Beluga ROS: /home/runner/work/beluga/beluga/beluga_ros/include/beluga_ros/point_cloud.hpp Source File
Beluga ROS
point_cloud.hpp
Go to the documentation of this file.
1 // Copyright 2024 Ekumen, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef BELUGA_ROS_POINT_CLOUD_HPP
16 #define BELUGA_ROS_POINT_CLOUD_HPP
17 
18 #include <range/v3/view/iota.hpp>
19 
22 #include <beluga_ros/messages.hpp>
23 
24 #include <sophus/se3.hpp>
25 
26 #include <Eigen/Dense>
27 
28 #include <beluga/eigen_compatibility.hpp>
29 #include <sensor_msgs/msg/point_cloud2.hpp>
30 #include <sensor_msgs/point_cloud2_iterator.hpp>
31 #include <sensor_msgs/point_field_conversion.hpp>
32 
47 namespace beluga_ros {
48 
50 
58 template <typename T, bool Strict = true>
59 class PointCloud3 : public beluga::BasePointCloud<PointCloud3<T>> {
60  public:
62  using Scalar = T;
63 
64  // Assert fields' type is floating point
65  static_assert(
66  std::is_same_v<Scalar, float> || std::is_same_v<Scalar, double>,
67  "Pointcloud3 only supports floating point types");
68 
74  explicit PointCloud3(sensor_msgs::msg::PointCloud2::ConstSharedPtr cloud, Sophus::SE3d origin = Sophus::SE3d())
75  : cloud_(std::move(cloud)), origin_(std::move(origin)) {
76  assert(cloud_ != nullptr);
77  if (cloud_->fields.size() != 3) {
78  throw std::invalid_argument("point cloud must have exactly 3 fields");
79  }
80  const auto& field_0 = cloud_->fields.at(0);
81  const auto& field_1 = cloud_->fields.at(1);
82  const auto& field_2 = cloud_->fields.at(2);
83  if (field_0.name != "x" || field_1.name != "y" || field_2.name != "z") {
84  throw std::invalid_argument("point cloud layout is not xyz");
85  }
86  if (field_0.datatype != field_1.datatype || field_1.datatype != field_2.datatype) {
87  throw std::invalid_argument("point cloud xyz datatypes are not all the same");
88  }
89  if constexpr (Strict) {
90  if (field_0.datatype != sensor_msgs::typeAsPointFieldType<Scalar>::value) {
91  throw std::invalid_argument("xyz datatype does not match the expected type");
92  }
93  } else {
94  if (field_0.datatype != sensor_msgs::typeAsPointFieldType<float>::value &&
95  field_0.datatype != sensor_msgs::typeAsPointFieldType<double>::value) {
96  throw std::invalid_argument("xyz datatype is not floating point");
97  }
98  }
99  constexpr auto float_datatype = sensor_msgs::typeAsPointFieldType<float>::value;
100  const auto size_of_datatype = field_0.datatype == float_datatype ? sizeof(float) : sizeof(double);
101  if (cloud_->point_step % size_of_datatype != 0) {
102  throw std::invalid_argument("point cloud is not dense");
103  }
104  }
105 
107  [[nodiscard]] const auto& origin() const { return origin_; }
108 
110  [[nodiscard]] auto points() const {
111  if constexpr (!Strict) {
112  const auto datatype = cloud_->fields.at(0).datatype;
113  if (datatype != sensor_msgs::typeAsPointFieldType<Scalar>::value) {
114  if (datatype == sensor_msgs::typeAsPointFieldType<float>::value) {
115  return Eigen::Matrix3X<Scalar>(points_matrix<float>(*cloud_).template cast<Scalar>());
116  }
117  assert(datatype == sensor_msgs::typeAsPointFieldType<double>::value);
118  return Eigen::Matrix3X<Scalar>(points_matrix<double>(*cloud_).template cast<Scalar>());
119  }
120  return Eigen::Matrix3X<Scalar>(points_matrix<Scalar>(*cloud_));
121  } else {
122  return points_matrix<Scalar>(*cloud_);
123  }
124  }
125 
126  private:
127  template <typename U>
128  static auto points_matrix(const sensor_msgs::msg::PointCloud2& cloud) {
129  const auto stride = static_cast<int>(cloud.point_step / sizeof(U));
130  const sensor_msgs::PointCloud2ConstIterator<U> iter_points(cloud, "x");
131  return Eigen::Map<const Eigen::Matrix3X<U>, 0, Eigen::OuterStride<>>(
132  &iter_points[0], 3, cloud.width * cloud.height, stride);
133  }
134 
135  sensor_msgs::msg::PointCloud2::ConstSharedPtr cloud_;
136  Sophus::SE3d origin_;
137 };
138 
141 
144 
145 } // namespace beluga_ros
146 
147 #endif // BELUGA_ROS_POINT_CLOUD_HPP
Thin wrapper type for 3D sensor_msgs/PointCloud2 messages with dense layouts.
Definition: point_cloud.hpp:59
auto points() const
Get cartesian points in the point cloud as a matrix.
Definition: point_cloud.hpp:110
T Scalar
Expected PointCloud2 fields type.
Definition: point_cloud.hpp:62
PointCloud3(sensor_msgs::msg::PointCloud2::ConstSharedPtr cloud, Sophus::SE3d origin=Sophus::SE3d())
Definition: point_cloud.hpp:74
const auto & origin() const
Get the point cloud frame origin in the filter frame.
Definition: point_cloud.hpp:107
The main Beluga ROS namespace.
Definition: amcl.hpp:47