ReUseX  0.0.5
3D Point Cloud Processing for Building Reuse
Loading...
Searching...
No Matches
transform_utils.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2025 Povl Filip Sonne-Frederiksen
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#pragma once
6
7#include <Eigen/Core>
8#include <Eigen/Geometry>
9
10#include <algorithm>
11#include <array>
12#include <cmath>
13
14namespace reusex::geometry {
15
17inline Eigen::Affine3f to_affine(const std::array<double, 16> &m) {
18 Eigen::Matrix4f mat;
19 for (int r = 0; r < 4; ++r)
20 for (int c = 0; c < 4; ++c)
21 mat(r, c) = static_cast<float>(m[r * 4 + c]);
22 Eigen::Affine3f aff;
23 aff.matrix() = mat;
24 return aff;
25}
26
28inline std::array<double, 16> to_array16(const Eigen::Affine3f &aff) {
29 std::array<double, 16> m{};
30 const Eigen::Matrix4f mat = aff.matrix();
31 for (int r = 0; r < 4; ++r)
32 for (int c = 0; c < 4; ++c)
33 m[r * 4 + c] = static_cast<double>(mat(r, c));
34 return m;
35}
36
43namespace se3 {
44
45using Vector6d = Eigen::Matrix<double, 6, 1>;
46
48inline Eigen::Matrix3d hat3(const Eigen::Vector3d &w) {
49 Eigen::Matrix3d s;
50 s << 0.0, -w.z(), w.y(), w.z(), 0.0, -w.x(), -w.y(), w.x(), 0.0;
51 return s;
52}
53
55inline Eigen::Matrix4d exp(const Vector6d &xi) {
56 const Eigen::Vector3d w = xi.head<3>();
57 const Eigen::Vector3d v = xi.tail<3>();
58 const double theta = w.norm();
59 const Eigen::Matrix3d W = hat3(w);
60 Eigen::Matrix3d R;
61 Eigen::Matrix3d V;
62 if (theta < 1e-12) {
63 R = Eigen::Matrix3d::Identity() + W;
64 V = Eigen::Matrix3d::Identity() + 0.5 * W;
65 } else {
66 const double t2 = theta * theta;
67 const double s = std::sin(theta);
68 const double c = std::cos(theta);
69 R = Eigen::Matrix3d::Identity() + (s / theta) * W +
70 ((1.0 - c) / t2) * (W * W);
71 V = Eigen::Matrix3d::Identity() + ((1.0 - c) / t2) * W +
72 ((theta - s) / (t2 * theta)) * (W * W);
73 }
74 Eigen::Matrix4d T = Eigen::Matrix4d::Identity();
75 T.block<3, 3>(0, 0) = R;
76 T.block<3, 1>(0, 3) = V * v;
77 return T;
78}
79
81inline Vector6d log(const Eigen::Matrix4d &T) {
82 const Eigen::Matrix3d R = T.block<3, 3>(0, 0);
83 const Eigen::Vector3d t = T.block<3, 1>(0, 3);
84 const double cos_theta = std::clamp((R.trace() - 1.0) * 0.5, -1.0, 1.0);
85 const double theta = std::acos(cos_theta);
86 Eigen::Vector3d w;
87 if (theta < 1e-12) {
88 w = 0.5 * Eigen::Vector3d(R(2, 1) - R(1, 2), R(0, 2) - R(2, 0),
89 R(1, 0) - R(0, 1));
90 } else {
91 const double s = std::sin(theta);
92 w = (theta / (2.0 * s)) * Eigen::Vector3d(R(2, 1) - R(1, 2),
93 R(0, 2) - R(2, 0),
94 R(1, 0) - R(0, 1));
95 }
96 const Eigen::Matrix3d W = hat3(w);
97 Eigen::Matrix3d Vinv;
98 if (theta < 1e-12) {
99 Vinv = Eigen::Matrix3d::Identity() - 0.5 * W;
100 } else {
101 const double a =
102 (1.0 / (theta * theta)) *
103 (1.0 - (theta * std::sin(theta)) / (2.0 * (1.0 - std::cos(theta))));
104 Vinv = Eigen::Matrix3d::Identity() - 0.5 * W + a * (W * W);
105 }
106 Vector6d xi;
107 xi.head<3>() = w;
108 xi.tail<3>() = Vinv * t;
109 return xi;
110}
111
112} // namespace se3
113} // namespace reusex::geometry
Minimal se(3) exp/log used by the joint pose optimizer.
Eigen::Matrix< double, 6, 1 > Vector6d
Eigen::Matrix3d hat3(const Eigen::Vector3d &w)
Skew-symmetric matrix [w]_x such that [w]_x v == w x v.
Eigen::Matrix4d exp(const Vector6d &xi)
Exponential map se(3) -> SE(3). xi = [omega; v].
Vector6d log(const Eigen::Matrix4d &T)
Logarithm map SE(3) -> se(3). Returns xi = [omega; v].
std::array< double, 16 > to_array16(const Eigen::Affine3f &aff)
Flatten a 4x4 Eigen affine (float) into a row-major double[16] array.
Eigen::Affine3f to_affine(const std::array< double, 16 > &m)
Build a 4x4 Eigen affine (float) from a row-major double[16] array.