Skip to content

Commit c629fef

Browse files
authored
feat(pl): Type conversions module (#62)
* Add in conversion module * Got vector conversions working as well! * Do it to genz as well * Clean up a few more pipelines with new conversions * Move all of binding conversion over to new convert function * Move conversions of iters and maps to separate methods
1 parent d91297a commit c629fef

File tree

10 files changed

+391
-370
lines changed

10 files changed

+391
-370
lines changed

cpp/bindings/pipelines/ct_icp.h

Lines changed: 67 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,45 @@
55

66
#include "ct_icp/odometry.hpp"
77
#include "ct_icp/types.hpp"
8+
#include "evalio/convert/base.h"
9+
#include "evalio/convert/eigen.h"
810
#include "evalio/pipeline.h"
911
#include "evalio/types.h"
1012

13+
namespace ev = evalio;
14+
15+
// ------------------------- Handle all conversions ------------------------- //
16+
namespace evalio {
17+
template<>
18+
inline evalio::Point convert(const ct_icp::Point3D& from) {
19+
return ev::Point {
20+
.x = from.raw_pt.x(),
21+
.y = from.raw_pt.y(),
22+
.z = from.raw_pt.z(),
23+
.intensity = 0.0,
24+
.t = ev::Duration::from_nsec(0),
25+
.row = 0,
26+
.col = 0,
27+
};
28+
}
29+
30+
template<>
31+
inline ct_icp::Point3D convert(const evalio::Point& from) {
32+
ct_icp::Point3D to;
33+
to.raw_pt = Eigen::Vector3d(from.x, from.y, from.z);
34+
to.pt = to.raw_pt;
35+
to.alpha_timestamp = from.t.to_sec();
36+
to.index_frame = 0;
37+
return to;
38+
}
39+
40+
template<>
41+
inline evalio::SE3 convert(const ct_icp::TrajectoryFrame& in) {
42+
return ev::SE3(ev::SO3::fromMat(in.begin_R), in.begin_t);
43+
}
44+
} // namespace evalio
45+
46+
// ------------------------- Actual Wrapper ------------------------- //
1147
// Simple enum wrapper to parse all strings -> enum options
1248
struct CTICPEnumParams {
1349
std::string motion_compensation;
@@ -91,44 +127,16 @@ struct CTICPEnumParams {
91127
}
92128
};
93129

94-
class CTICP: public evalio::Pipeline {
130+
class CTICP: public ev::Pipeline {
95131
private:
96132
std::unique_ptr<ct_icp::Odometry> ct_icp_;
97133
ct_icp::OdometryOptions config_ =
98134
ct_icp::OdometryOptions::DefaultDrivingProfile();
99135
CTICPEnumParams enum_params_;
100136

101-
evalio::SE3 lidar_T_imu_ = evalio::SE3::identity();
137+
ev::SE3 lidar_T_imu_ = ev::SE3::identity();
102138
size_t scan_idx_ = 0;
103139

104-
inline evalio::SE3 to_evalio_pose(const ct_icp::TrajectoryFrame& pose) const {
105-
return evalio::SE3(evalio::SO3::fromMat(pose.begin_R), pose.begin_t);
106-
}
107-
108-
inline evalio::Point to_evalio_point(const ct_icp::Point3D& point) const {
109-
return evalio::Point {
110-
.x = point.raw_pt.x(),
111-
.y = point.raw_pt.y(),
112-
.z = point.raw_pt.z(),
113-
.intensity = 0.0,
114-
.t = evalio::Duration::from_nsec(0),
115-
.row = 0,
116-
.col = 0,
117-
};
118-
}
119-
120-
inline evalio::Point to_evalio_point(const Eigen::Vector3d& point) const {
121-
return evalio::Point {
122-
.x = point.x(),
123-
.y = point.y(),
124-
.z = point.z(),
125-
.intensity = 0.0,
126-
.t = evalio::Duration::from_nsec(0),
127-
.row = 0,
128-
.col = 0,
129-
};
130-
}
131-
132140
public:
133141
CTICP() {
134142
config_.debug_print = false;
@@ -196,29 +204,24 @@ class CTICP: public evalio::Pipeline {
196204
// clang-format on
197205

198206
// Getters
199-
const evalio::SE3 pose() override {
207+
const ev::SE3 pose() override {
200208
const auto pose = ct_icp_->Trajectory().back();
201-
return to_evalio_pose(pose) * lidar_T_imu_;
209+
return ev::convert<ev::SE3>(pose) * lidar_T_imu_;
202210
}
203211

204-
const std::map<std::string, std::vector<evalio::Point>> map() override {
205-
const auto map = ct_icp_->GetLocalMap();
206-
std::vector<evalio::Point> ev_points;
207-
ev_points.reserve(map.size());
208-
for (const auto& point : map) {
209-
ev_points.push_back(to_evalio_point(point));
210-
}
211-
return {{"planar", std::move(ev_points)}};
212+
const std::map<std::string, std::vector<ev::Point>> map() override {
213+
auto map = ct_icp_->GetLocalMap();
214+
return ev::convert_map<decltype(map)>({{"planar", map}});
212215
}
213216

214217
// Setters
215-
void set_imu_params(evalio::ImuParams params) override {}
218+
void set_imu_params(ev::ImuParams params) override {}
216219

217-
void set_lidar_params(evalio::LidarParams params) override {
220+
void set_lidar_params(ev::LidarParams params) override {
218221
config_.max_distance = params.max_range;
219222
}
220223

221-
void set_imu_T_lidar(evalio::SE3 T) override {
224+
void set_imu_T_lidar(ev::SE3 T) override {
222225
lidar_T_imu_ = T.inverse();
223226
}
224227

@@ -228,49 +231,40 @@ class CTICP: public evalio::Pipeline {
228231
ct_icp_ = std::make_unique<ct_icp::Odometry>(config_);
229232
}
230233

231-
void add_imu(evalio::ImuMeasurement mm) override {}
234+
void add_imu(ev::ImuMeasurement mm) override {}
232235

233-
std::map<std::string, std::vector<evalio::Point>>
234-
add_lidar(evalio::LidarMeasurement mm) override {
235-
// Set everything up
236-
std::vector<ct_icp::Point3D> pc;
237-
pc.reserve(mm.points.size());
236+
std::map<std::string, std::vector<ev::Point>>
237+
add_lidar(ev::LidarMeasurement mm) override {
238+
// Convert
239+
auto pc = ev::convert_iter<std::vector<ct_icp::Point3D>>(mm.points);
238240

239-
// Figure out min/max timesteps
241+
// Normalize timestamps to [0, 1]
240242
const auto& [min, max] = std::minmax_element(
241-
mm.points.cbegin(),
242-
mm.points.cend(),
243-
[](const evalio::Point& a, const evalio::Point& b) { return a.t < b.t; }
243+
pc.cbegin(),
244+
pc.cend(),
245+
[](const ct_icp::Point3D& a, const ct_icp::Point3D& b) {
246+
return a.alpha_timestamp < b.alpha_timestamp;
247+
}
244248
);
245249

246-
const auto min_t = min->t.to_sec();
247-
const auto max_t = max->t.to_sec();
248-
const auto normalize = [min_t, max_t](evalio::Duration t) {
249-
return (t.to_sec() - min_t) / (max_t - min_t);
250+
const auto min_t = min->alpha_timestamp;
251+
const auto max_t = max->alpha_timestamp;
252+
const auto normalize = [min_t, max_t](double t) {
253+
return (t - min_t) / (max_t - min_t);
250254
};
251255

252256
// Copy
253-
for (const auto& point : mm.points) {
254-
ct_icp::Point3D p;
255-
p.raw_pt = Eigen::Vector3d(point.x, point.y, point.z);
256-
p.pt = p.raw_pt;
257-
p.alpha_timestamp = normalize(point.t);
258-
p.index_frame = scan_idx_;
259-
pc.push_back(p);
257+
for (auto& p : pc) {
258+
p.alpha_timestamp = normalize(p.alpha_timestamp);
260259
}
261260

262261
// Run through pipeline
263262
const auto summary = ct_icp_->RegisterFrame(pc);
264-
265-
// Return the used points
266-
std::vector<evalio::Point> ev_planar_points;
267-
ev_planar_points.reserve(summary.keypoints.size());
268-
for (const auto& point : summary.keypoints) {
269-
ev_planar_points.push_back(to_evalio_point(point));
270-
}
271-
272263
scan_idx_++;
273264

274-
return {{"planar", ev_planar_points}};
265+
// Return the used points
266+
return ev::convert_map<std::vector<ct_icp::Point3D>>(
267+
{{"planar", summary.keypoints}}
268+
);
275269
}
276270
};

cpp/bindings/pipelines/genz_icp.h

Lines changed: 41 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
#pragma once
22

3+
#include <algorithm>
34
#include <memory>
45

6+
#include "evalio/convert/base.h"
7+
#include "evalio/convert/eigen.h"
8+
#include "evalio/convert/sophus.h"
59
#include "evalio/pipeline.h"
610
#include "evalio/types.h"
711
#include "genz_icp/pipeline/GenZICP.hpp"
812

9-
class GenZICP: public evalio::Pipeline {
13+
namespace ev = evalio;
14+
15+
class GenZICP: public ev::Pipeline {
1016
public:
1117
GenZICP() : config_() {}
1218

@@ -46,109 +52,70 @@ class GenZICP: public evalio::Pipeline {
4652
// clang-format on
4753

4854
// Getters
49-
const evalio::SE3 pose() override {
55+
const ev::SE3 pose() override {
5056
const auto pose =
5157
!genz_icp_->poses().empty() ? genz_icp_->poses().back() : Sophus::SE3d();
52-
return to_evalio_se3(pose * lidar_T_imu_);
58+
return ev::convert<ev::SE3>(pose * lidar_T_imu_);
5359
}
5460

55-
const std::map<std::string, std::vector<evalio::Point>> map() override {
56-
std::vector<Eigen::Vector3d> map = genz_icp_->LocalMap();
57-
std::vector<evalio::Point> evalio_map;
58-
evalio_map.reserve(map.size());
59-
for (auto point : map) {
60-
evalio_map.push_back(to_evalio_point(point));
61-
}
62-
return {{"point", evalio_map}};
61+
const std::map<std::string, std::vector<ev::Point>> map() override {
62+
return ev::convert_map<std::vector<Eigen::Vector3d>>(
63+
{{"map", genz_icp_->LocalMap()}}
64+
);
6365
}
6466

6567
// Setters
66-
void set_imu_params(evalio::ImuParams params) override {}
68+
void set_imu_params(ev::ImuParams params) override {}
6769

68-
void set_lidar_params(evalio::LidarParams params) override {
70+
void set_lidar_params(ev::LidarParams params) override {
6971
config_.min_range = params.min_range;
7072
config_.max_range = params.max_range;
7173
config_.map_cleanup_radius = params.max_range;
7274
}
7375

74-
void set_imu_T_lidar(evalio::SE3 T) override {
75-
lidar_T_imu_ = to_sophus_se3(T).inverse();
76+
void set_imu_T_lidar(ev::SE3 T) override {
77+
lidar_T_imu_ = ev::convert<Sophus::SE3d>(T).inverse();
7678
}
7779

7880
// Doers
7981
void initialize() override {
8082
genz_icp_ = std::make_unique<genz_icp::pipeline::GenZICP>(config_);
8183
}
8284

83-
void add_imu(evalio::ImuMeasurement mm) override {}
85+
void add_imu(ev::ImuMeasurement mm) override {}
8486

85-
std::map<std::string, std::vector<evalio::Point>>
86-
add_lidar(evalio::LidarMeasurement mm) override {
87+
std::map<std::string, std::vector<ev::Point>>
88+
add_lidar(ev::LidarMeasurement mm) override {
8789
// Set everything up
88-
std::vector<Eigen::Vector3d> points;
89-
points.reserve(mm.points.size());
90-
std::vector<double> timestamps;
91-
timestamps.reserve(mm.points.size());
92-
93-
// Copy
94-
for (auto point : mm.points) {
95-
points.push_back(to_eigen_point(point));
96-
timestamps.push_back(point.t.to_sec());
97-
}
90+
auto points = ev::convert_iter<std::vector<Eigen::Vector3d>>(mm.points);
91+
auto timestamps = ev::convert_iter<std::vector<double>>(mm.points);
9892

9993
// Run through pipeline
100-
const auto& [planar_points, nonplanar_points] =
101-
genz_icp_->RegisterFrame(points, timestamps);
102-
const auto lidar_T_world = genz_icp_->poses().back().inverse();
94+
auto [planar, nonplanar] = genz_icp_->RegisterFrame(points, timestamps);
95+
auto lidar_T_world = genz_icp_->poses().back().inverse();
10396

104-
// Return the used points
10597
// These are all in the global frame, so we need to convert them
106-
std::vector<evalio::Point> ev_planar_points;
107-
ev_planar_points.reserve(planar_points.size());
108-
for (auto point : planar_points) {
109-
ev_planar_points.push_back(to_evalio_point(lidar_T_world * point));
110-
}
111-
112-
std::vector<evalio::Point> ev_nonplanar_points;
113-
ev_nonplanar_points.reserve(nonplanar_points.size());
114-
for (auto point : nonplanar_points) {
115-
ev_nonplanar_points.push_back(to_evalio_point(lidar_T_world * point));
116-
}
117-
118-
return {{"nonplanar", ev_nonplanar_points}, {"planar", ev_planar_points}};
98+
std::transform(
99+
planar.begin(),
100+
planar.end(),
101+
planar.begin(),
102+
[&](auto point) { return lidar_T_imu_ * point; }
103+
);
104+
std::transform(
105+
nonplanar.begin(),
106+
nonplanar.end(),
107+
nonplanar.begin(),
108+
[&](auto point) { return lidar_T_imu_ * point; }
109+
);
110+
111+
// Return the used points
112+
return ev::convert_map<std::vector<Eigen::Vector3d>>(
113+
{{"planar", planar}, {"nonplanar", nonplanar}}
114+
);
119115
}
120116

121117
private:
122118
std::unique_ptr<genz_icp::pipeline::GenZICP> genz_icp_;
123119
genz_icp::pipeline::GenZConfig config_;
124120
Sophus::SE3d lidar_T_imu_;
125-
126-
// Misc helpers
127-
inline evalio::Point to_evalio_point(Eigen::Vector3d point) {
128-
return {
129-
.x = point[0],
130-
.y = point[1],
131-
.z = point[2],
132-
.intensity = 0.0,
133-
.t = evalio::Duration::from_sec(0),
134-
.row = 0,
135-
.col = 0
136-
};
137-
}
138-
139-
inline Eigen::Vector3d to_eigen_point(evalio::Point point) {
140-
return {point.x, point.y, point.z};
141-
}
142-
143-
inline evalio::SE3 to_evalio_se3(Sophus::SE3d pose) {
144-
const auto t = pose.translation();
145-
const auto q = pose.unit_quaternion();
146-
const auto rot =
147-
evalio::SO3 {.qx = q.x(), .qy = q.y(), .qz = q.z(), .qw = q.w()};
148-
return evalio::SE3(rot, t);
149-
}
150-
151-
inline Sophus::SE3d to_sophus_se3(evalio::SE3 pose) {
152-
return Sophus::SE3d(Sophus::SO3d(pose.rot.toEigen()), pose.trans);
153-
}
154121
};

0 commit comments

Comments
 (0)