6#include <spdlog/spdlog.h>
7#include <boost/format.hpp>
10#include <gtsam_points/types/point_cloud.hpp>
11#include <glim/util/raw_points.hpp>
14#include <sensor_msgs/msg/point_cloud2.hpp>
16using PointCloud2 = sensor_msgs::msg::PointCloud2;
17using PointCloud2Ptr = sensor_msgs::msg::PointCloud2::SharedPtr;
18using PointCloud2ConstPtr = sensor_msgs::msg::PointCloud2::ConstSharedPtr;
19using PointField = sensor_msgs::msg::PointField;
21template <
typename Stamp>
22double to_sec(
const Stamp& stamp) {
23 return stamp.sec + stamp.nanosec / 1e9;
26inline builtin_interfaces::msg::Time from_sec(
const double time) {
27 builtin_interfaces::msg::Time stamp;
28 stamp.sec = std::floor(time);
29 stamp.nanosec = (time - stamp.sec) * 1e9;
35#include <sensor_msgs/PointCloud2.h>
37using PointCloud2 = sensor_msgs::PointCloud2;
38using PointCloud2Ptr = sensor_msgs::PointCloud2::Ptr;
39using PointCloud2ConstPtr = sensor_msgs::PointCloud2::ConstPtr;
40using PointField = sensor_msgs::PointField;
42template <
typename Stamp>
43double to_sec(
const Stamp& stamp) {
47inline ros::Time from_sec(
const double time) {
49 stamp.sec = std::floor(time);
50 stamp.nsec = (time - stamp.sec) * 1e9;
60Eigen::Vector4d get_vec4(
const void* x,
const void* y,
const void* z) {
61 return Eigen::Vector4d(*
reinterpret_cast<const T*
>(x), *
reinterpret_cast<const T*
>(y), *
reinterpret_cast<const T*
>(z), 1.0);
64static RawPoints::Ptr extract_raw_points(
const PointCloud2& points_msg,
const std::string& intensity_channel,
const std::string& ring_channel) {
65 int num_points = points_msg.width * points_msg.height;
71 int intensity_type = 0;
79 int intensity_offset = -1;
80 int color_offset = -1;
83 std::unordered_map<std::string, std::pair<int*, int*>> fields;
84 fields[
"x"] = std::make_pair(&x_type, &x_offset);
85 fields[
"y"] = std::make_pair(&y_type, &y_offset);
86 fields[
"z"] = std::make_pair(&z_type, &z_offset);
87 fields[
"t"] = std::make_pair(&time_type, &time_offset);
88 fields[
"time"] = std::make_pair(&time_type, &time_offset);
89 fields[
"time_stamp"] = std::make_pair(&time_type, &time_offset);
90 fields[
"timestamp"] = std::make_pair(&time_type, &time_offset);
91 fields[intensity_channel] = std::make_pair(&intensity_type, &intensity_offset);
92 fields[
"rgba"] = std::make_pair(&color_type, &color_offset);
93 fields[ring_channel] = std::make_pair(&ring_type, &ring_offset);
95 for (
const auto& field : points_msg.fields) {
96 auto found = fields.find(field.name);
97 if (found == fields.end()) {
101 *found->second.first = field.datatype;
102 *found->second.second = field.offset;
105 if (x_offset < 0 || y_offset < 0 || z_offset < 0) {
106 spdlog::warn(
"missing point coordinate fields");
110 if ((x_type != PointField::FLOAT32 && x_type != PointField::FLOAT64) || x_type != y_type || x_type != y_type) {
111 spdlog::warn(
"unsupported points type");
115 auto raw_points = std::make_shared<RawPoints>();
117 raw_points->points.resize(num_points);
119 if (x_type == PointField::FLOAT32 && y_offset == x_offset +
sizeof(
float) && z_offset == y_offset +
sizeof(
float)) {
121 for (
int i = 0; i < num_points; i++) {
122 const auto* x_ptr = &points_msg.data[points_msg.point_step * i + x_offset];
123 raw_points->points[i] << Eigen::Map<const Eigen::Vector3f>(
reinterpret_cast<const float*
>(x_ptr)).cast<
double>(), 1.0;
125 }
else if (x_type == PointField::FLOAT64 && y_offset == x_offset +
sizeof(
double) && z_offset == y_offset +
sizeof(double)) {
127 for (
int i = 0; i < num_points; i++) {
128 const auto* x_ptr = &points_msg.data[points_msg.point_step * i + x_offset];
129 raw_points->points[i] << Eigen::Map<const Eigen::Vector3d>(
reinterpret_cast<const double*
>(x_ptr)), 1.0;
132 for (
int i = 0; i < num_points; i++) {
133 const auto* x_ptr = &points_msg.data[points_msg.point_step * i + x_offset];
134 const auto* y_ptr = &points_msg.data[points_msg.point_step * i + y_offset];
135 const auto* z_ptr = &points_msg.data[points_msg.point_step * i + z_offset];
137 if (x_type == PointField::FLOAT32) {
138 raw_points->points[i] = get_vec4<float>(x_ptr, y_ptr, z_ptr);
140 raw_points->points[i] = get_vec4<double>(x_ptr, y_ptr, z_ptr);
145 if (time_offset >= 0) {
146 raw_points->times.resize(num_points);
148 for (
int i = 0; i < num_points; i++) {
149 const auto* time_ptr = &points_msg.data[points_msg.point_step * i + time_offset];
151 case PointField::UINT32:
152 raw_points->times[i] = *
reinterpret_cast<const uint32_t*
>(time_ptr) / 1e9;
154 case PointField::FLOAT32:
155 raw_points->times[i] = *
reinterpret_cast<const float*
>(time_ptr);
157 case PointField::FLOAT64:
158 raw_points->times[i] = *
reinterpret_cast<const double*
>(time_ptr);
161 spdlog::warn(
"unsupported time type {}", time_type);
167 if (intensity_offset >= 0) {
168 raw_points->intensities.resize(num_points);
170 for (
int i = 0; i < num_points; i++) {
171 const auto* intensity_ptr = &points_msg.data[points_msg.point_step * i + intensity_offset];
172 switch (intensity_type) {
173 case PointField::UINT8:
174 raw_points->intensities[i] = *
reinterpret_cast<const std::uint8_t*
>(intensity_ptr);
176 case PointField::UINT16:
177 raw_points->intensities[i] = *
reinterpret_cast<const std::uint16_t*
>(intensity_ptr);
179 case PointField::UINT32:
180 raw_points->intensities[i] = *
reinterpret_cast<const std::uint32_t*
>(intensity_ptr);
182 case PointField::FLOAT32:
183 raw_points->intensities[i] = *
reinterpret_cast<const float*
>(intensity_ptr);
185 case PointField::FLOAT64:
186 raw_points->intensities[i] = *
reinterpret_cast<const double*
>(intensity_ptr);
189 spdlog::warn(
"unsupported intensity type {}", intensity_type);
195 if (color_offset >= 0) {
196 if (color_type != PointField::UINT32) {
197 spdlog::warn(
"unsupported color type {}", color_type);
199 raw_points->colors.resize(num_points);
201 for (
int i = 0; i < num_points; i++) {
202 const auto* color_ptr = &points_msg.data[points_msg.point_step * i + color_offset];
203 raw_points->colors[i] = Eigen::Matrix<unsigned char, 4, 1>(
reinterpret_cast<const std::uint8_t*
>(color_ptr)).cast<
double>() / 255.0;
208 if (ring_offset >= 0) {
209 raw_points->rings.resize(num_points);
211 for (
int i = 0; i < num_points; i++) {
212 const auto* ring_ptr = &points_msg.data[points_msg.point_step * i + ring_offset];
214 case PointField::UINT8:
215 raw_points->rings[i] = *
reinterpret_cast<const std::uint8_t*
>(ring_ptr);
217 case PointField::UINT16:
218 raw_points->rings[i] = *
reinterpret_cast<const std::uint16_t*
>(ring_ptr);
220 case PointField::UINT32:
221 raw_points->rings[i] = *
reinterpret_cast<const std::uint32_t*
>(ring_ptr);
224 spdlog::warn(
"unsupported ring type {}", ring_type);
230 raw_points->stamp = to_sec(points_msg.header.stamp);
234static RawPoints::Ptr extract_raw_points(
const PointCloud2& points_msg,
const std::string& intensity_channel =
"intensity") {
235 return extract_raw_points(points_msg, intensity_channel,
"");
238static RawPoints::Ptr extract_raw_points(
const PointCloud2ConstPtr& points_msg,
const std::string& intensity_channel =
"intensity") {
239 return extract_raw_points(*points_msg, intensity_channel,
"");
242static PointCloud2ConstPtr frame_to_pointcloud2(
const std::string& frame_id,
const double stamp,
const gtsam_points::PointCloud& frame) {
243 PointCloud2Ptr msg(
new PointCloud2);
244 msg->header.frame_id = frame_id;
245 msg->header.stamp = from_sec(stamp);
247 msg->width = frame.size();
250 const auto create_field = [](
const std::string& name,
int offset,
int datatype,
int count) {
253 field.offset = offset;
254 field.datatype = datatype;
260 msg->fields.reserve(6);
262 msg->fields.emplace_back(create_field(
"x",
sizeof(
float) * 0, PointField::FLOAT32, 1));
263 msg->fields.emplace_back(create_field(
"y",
sizeof(
float) * 1, PointField::FLOAT32, 1));
264 msg->fields.emplace_back(create_field(
"z",
sizeof(
float) * 2, PointField::FLOAT32, 1));
265 point_step +=
sizeof(float) * 3;
268 msg->fields.emplace_back(create_field(
"t", point_step, PointField::FLOAT32, 1));
269 point_step +=
sizeof(float);
272 if (frame.intensities) {
273 msg->fields.emplace_back(create_field(
"intensity", point_step, PointField::FLOAT32, 1));
274 point_step +=
sizeof(float);
277 const Eigen::Vector4f* colors = frame.aux_attributes.count(
"colors") ? frame.aux_attribute<Eigen::Vector4f>(
"colors") : nullptr;
279 msg->fields.emplace_back(create_field(
"rgba", point_step, PointField::UINT32, 1));
280 point_step +=
sizeof(std::uint32_t);
283 msg->is_bigendian =
false;
284 msg->point_step = point_step;
285 msg->row_step = point_step * frame.size();
287 msg->data.resize(point_step * frame.size());
288 for (
int i = 0; i < frame.size(); i++) {
289 unsigned char* point_bytes = msg->data.data() + msg->point_step * i;
290 Eigen::Map<Eigen::Vector3f> xyz(
reinterpret_cast<float*
>(point_bytes));
291 xyz = frame.points[i].head<3>().cast<float>();
292 point_bytes +=
sizeof(float) * 3;
295 *
reinterpret_cast<float*
>(point_bytes) = frame.times[i];
296 point_bytes +=
sizeof(float);
299 if (frame.intensities) {
300 *
reinterpret_cast<float*
>(point_bytes) = frame.intensities[i];
301 point_bytes +=
sizeof(float);
305 const Eigen::Matrix<std::uint8_t, 4, 1> rgba = (colors[i].array() * 255.0f).min(255.0f).max(0.0f).cast<std::uint8_t>();
306 point_bytes[0] = rgba[0];
307 point_bytes[1] = rgba[1];
308 point_bytes[2] = rgba[2];
309 point_bytes[3] = rgba[3];
310 point_bytes +=
sizeof(std::uint32_t);
Definition loose_initial_state_estimation.hpp:9