SaDVIO
geometry.h
Go to the documentation of this file.
1 #ifndef GEOMETRY_H
2 #define GEOMETRY_H
3 
4 #include <cmath>
5 #include <limits>
6 
7 #include <Eigen/Eigenvalues>
8 #include <opencv2/core.hpp>
9 
10 #include "isaeslam/typedefs.h"
11 
12 namespace isae {
13 
14 //< 3D geometry utilities
15 namespace geometry {
16 
20 template <typename Derived> inline Eigen::Matrix3d skewMatrix(const Eigen::MatrixBase<Derived> &w) {
21  Eigen::Matrix3d skew;
22  skew << 0, -w[2], w[1], //
23  w[2], 0, -w[0], //
24  -w[1], w[0], 0; //
25  return skew;
26 }
27 
31 inline Eigen::Vector3d FromskewMatrix(const Eigen::Matrix3d &skew) {
32  Eigen::Vector3d w(skew(2, 1), skew(0, 2), skew(1, 0));
33  return w;
34 }
35 
42 inline Eigen::Matrix3d so3_rightJacobian(const Eigen::Vector3d &w) {
43  double w_norm = w.norm();
44  Eigen::Matrix3d w_skew = skewMatrix(w);
45  if (w_norm < 1e-5)
46  return Eigen::Matrix3d::Identity();
47  return Eigen::Matrix3d::Identity() - ((1 - cos(w_norm)) / (w_norm * w_norm)) * w_skew +
48  ((w_norm - sin(w_norm)) / (w_norm * w_norm * w_norm)) * w_skew * w_skew;
49 }
50 
57 inline Eigen::Matrix3d so3_leftJacobian(const Eigen::Vector3d &w) {
58  Eigen::Matrix3d Jl;
59  double w_norm = w.norm();
60  Eigen::Vector3d a = w / w_norm;
61  Jl = sin(w_norm) / w_norm * Eigen::Matrix3d::Identity() + (1 - sin(w_norm) / w_norm) * a * a.transpose() +
62  (1 - cos(w_norm)) / w_norm * skewMatrix(a);
63  return Jl;
64 }
65 
69 inline Eigen::Vector3d rotationMatrixToEulerAnglesEigen(Eigen::Matrix3d R) {
70 
71  float sy = sqrt(R(0, 0) * R(0, 0) + R(1, 0) * R(1, 0));
72 
73  bool singular = sy < 1e-6; // If
74 
75  float x, y, z;
76  if (!singular) {
77  x = atan2(R(2, 1), R(2, 2));
78  y = atan2(-R(2, 0), sy);
79  z = atan2(R(1, 0), R(0, 0));
80  } else {
81  x = atan2(-R(1, 2), R(1, 1));
82  y = atan2(-R(2, 0), sy);
83  z = 0;
84  }
85  return Eigen::Vector3d(x * 180 / 3.1416, y * 180 / 3.1416, z * 180 / 3.1416);
86 }
87 
91 inline Eigen::Matrix3d xFront2zFront() {
92  Eigen::Matrix3d xF2zF;
93  xF2zF << 0., -1., 0., //
94  0., 0., -1., //
95  1., 0., 0.; //
96  return xF2zF;
97 }
98 
102 inline Eigen::Matrix3d zFront2xFront() {
103  Eigen::Matrix3d zF2xF;
104  zF2xF << 0, 0, 1, //
105  -1, 0, 0, //
106  0, -1, 0; //
107  return zF2xF;
108 }
109 
113 inline Eigen::Matrix3d xRight2xFront() {
114  Eigen::Matrix3d xR2xF;
115  xR2xF << 0., 1., 0., //
116  -1., 0., 0., //
117  0., 0., 1.; //
118  return xR2xF;
119 }
120 
121 
125 inline Eigen::Matrix3d directionVector2Rotation(Eigen::Vector3d v,
126  const Eigen::Vector3d &reference_vector = Eigen::Vector3d(1, 0, 0)) {
127 
128  // v = R*reference
129  // Rodrigues's rotation formula gives the result of a rotation of a unit vector a about an axis of
130  // rotation k through the angle θ. We can make use of this by realizing that, in order to bring
131  // a normalized vector a into coincidence with another normalized vector b, we simply need to
132  // rotate a about k=(a+b)/2 by the angle pi.
133  v = v.normalized(); // assure v is normalized
134  Eigen::Vector3d sum = v + reference_vector;
135  Eigen::Matrix3d R = 2.0 * (sum * sum.transpose()) / (sum.transpose() * sum) - Eigen::Matrix3d::Identity();
136  return R;
137 }
138 
142 inline Eigen::Vector3d Rotation2directionVector(const Eigen::Matrix3d &R,
143  const Eigen::Vector3d &reference_vector = Eigen::Vector3d(1, 0, 0)) {
144  Eigen::Vector3d v = R * reference_vector;
145  return v.normalized(); // assure v is normalized (should already be)
146 }
147 
154 inline Eigen::Matrix3d exp_so3(const Eigen::Vector3d &v) {
155 
156  double tolerance = 1e-9;
157  double angle = v.norm();
158 
159  Eigen::Matrix3d Rot;
160  if (angle < tolerance) {
161  // Near |phi|==0, use first order Taylor expansion
162  Rot = Eigen::Matrix3d::Identity() + geometry::skewMatrix(v);
163  } else {
164  Eigen::Vector3d axis = v / angle;
165  Eigen::Matrix3d skew = geometry::skewMatrix(axis);
166  Rot = Eigen::Matrix3d::Identity() + (1. - cos(angle)) * skew * skew +
167  sin(angle) * skew;
168  }
169  return Rot;
170 }
171 
178 inline Eigen::Vector3d log_so3(const Eigen::Matrix3d &M) {
179  double tolerance = 1e-9;
180  double cos_angle = 0.5 * M.trace() - 0.5;
181 
182  // Clip cos(angle) to its proper domain to avoid NaNs from rounding errors
183  cos_angle = std::min(std::max(cos_angle, -1.), 1.);
184  double angle = acos(cos_angle);
185 
186  Eigen::Vector3d phi;
187  // If angle is close to zero, use first-order Taylor expansion
188  if (std::fabs(sin(angle)) < tolerance || angle < tolerance)
189  phi = 0.5 * geometry::FromskewMatrix(M - M.transpose());
190  else {
191  // Otherwise take the matrix logarithm and return the rotation vector
192  phi = (0.5 * angle / sin(angle)) * geometry::FromskewMatrix(M - M.transpose());
193  }
194  return phi;
195 }
196 
203 inline Vector6d se3_RTtoVec6d(Eigen::Affine3d RT) {
204  Vector6d pose;
205  Eigen::Vector3d w = log_so3(RT.linear());
206  pose(0) = w(0);
207  pose(1) = w(1);
208  pose(2) = w(2);
209  Eigen::Vector3d t = RT.translation();
210  pose(3) = t(0);
211  pose(4) = t(1);
212  pose(5) = t(2);
213  return pose;
214 }
215 
222 inline Eigen::Affine3d se3_Vec6dtoRT(Vector6d pose) {
223  Eigen::Affine3d RT;
224  Eigen::Vector3d w, t;
225  w << pose(0), pose(1), pose(2);
226  t << pose(3), pose(4), pose(5);
227  RT.linear() = exp_so3(w);
228  RT.translation() = t;
229  return RT;
230 }
231 
238 inline Eigen::Affine3d se3_doubleVec6dtoRT(const double *pose) {
239  Eigen::Affine3d RT;
240  RT.linear() = exp_so3(Eigen::Vector3d(pose[0], pose[1], pose[2]));
241  RT.translation() << pose[3], pose[4], pose[5];
242  return RT;
243 }
244 
245 
249 inline Eigen::Affine3d se3_doubleVec3dtoRT(const double *p3d) {
250  Eigen::Affine3d RT;
251  RT.linear() = Eigen::Matrix3d::Identity();
252  RT.translation() << p3d[0], p3d[1], p3d[2];
253  return RT;
254 }
255 
262 template <typename T> inline Eigen::Transform<T, 3, 4> se3_doubleVec6dtoRT(const T *pose) {
263  Eigen::Transform<T, 3, 4> RT;
264  // Eigen::Affine3d RT;
265  Eigen::Matrix<T, 3, 1> w, t;
266  // Eigen::Vector3d w, t;
267  w << pose[0], pose[1], pose[2];
268  t << pose[3], pose[4], pose[5];
269  RT.linear() = exp_so3(w);
270  RT.translation() = t;
271  return RT;
272 }
273 
277 inline double getAngle(Eigen::Vector3d p, Eigen::Vector3d p1, Eigen::Vector3d p2) {
278  Eigen::Vector3d u1 = p - p1;
279  Eigen::Vector3d u2 = p - p2;
280 
281  return std::acos(u1.dot(u2) / (u1.norm() * u2.norm()));
282 }
283 
289 template <typename Derived = Eigen::VectorXd> inline bool pointInTriangle(Derived pt, std::vector<Derived> triangle) {
290  // Compute vectors
291  Derived v0 = triangle.at(2) - triangle.at(0);
292  Derived v1 = triangle.at(1) - triangle.at(0);
293  Derived v2 = pt - triangle.at(0);
294 
295  // Compute dot products
296  double dot00 = v0.dot(v0);
297  double dot01 = v0.dot(v1);
298  double dot02 = v0.dot(v2);
299  double dot11 = v1.dot(v1);
300  double dot12 = v1.dot(v2);
301 
302  // Compute barycentric coordinates
303  double inv_denom = 1 / (dot00 * dot11 - dot01 * dot01);
304  double u = (dot11 * dot02 - dot01 * dot12) * inv_denom;
305  double v = (dot00 * dot12 - dot01 * dot02) * inv_denom;
306 
307  // Check if point is in triangle
308  return (u >= 0) && (v >= 0) && (u + v < 1);
309 }
310 
316 inline Eigen::Matrix2d cov2dTriangle(std::vector<Eigen::Vector2d> triangle) {
317 
318  // Compute transformation
319  Eigen::Vector2d x0 = triangle.at(0);
320  Eigen::Matrix2d At;
321  At << triangle.at(1).x() - x0.x(), triangle.at(2).x() - x0.x(), triangle.at(1).y() - x0.y(),
322  triangle.at(2).y() - x0.y();
323  Eigen::Vector2d barycenter = (1.0 / 3.0) * (x0 + triangle.at(1) + triangle.at(2));
324 
325  // Primitive covariance
326  Eigen::Matrix2d Mot;
327  Mot << 1.0 / 12, 1.0 / 24, 1.0 / 24, 1.0 / 12;
328  Eigen::Matrix2d M = 2 * At * Mot * At.transpose() +
329  (barycenter * x0.transpose() + x0 * barycenter.transpose() - x0 * x0.transpose()) -
330  barycenter * barycenter.transpose();
331 
332  return M;
333 }
334 
338 inline double areaTriangle(std::vector<Eigen::Vector2d> triangle) {
339 
340  Eigen::Vector2d x0 = triangle.at(0);
341  Eigen::Matrix2d At;
342  At << triangle.at(1).x() - x0.x(), triangle.at(2).x() - x0.x(), triangle.at(1).y() - x0.y(),
343  triangle.at(2).y() - x0.y();
344 
345  return At.determinant() / 2;
346 
347 }
348 
349 inline Eigen::MatrixXd J_norm(Eigen::Vector3d X){
350  return X.transpose()/X.norm();
351 }
352 
353 inline Eigen::Matrix3d J_normalization(Eigen::Vector3d X){
354  return (Eigen::Matrix3d::Identity() - X*X.transpose())/X.norm();
355 }
356 
357 inline Eigen::Matrix3d J_XcrossA(Eigen::Vector3d A){
358  return geometry::skewMatrix(A);
359 }
360 
361 inline Eigen::Matrix3d J_AcrossX(Eigen::Vector3d A){
362  return -geometry::skewMatrix(A);
363 }
364 
365 inline Eigen::Matrix3d J_Rexpwt(Eigen::Matrix3d R, Eigen::Matrix3d expw, Eigen::Vector3d t){
366  return -R*expw*geometry::skewMatrix(t)*Eigen::Matrix3d::Identity()*geometry::so3_rightJacobian(geometry::log_so3(expw));
367 }
368 
369 
370 } // namespace geometry
371 } // namespace isae
372 
373 #endif // GEOMETRY_H
isae::geometry::log_so3
Eigen::Vector3d log_so3(const Eigen::Matrix3d &M)
Compute the logarithm of the SO(3) manifold.
Definition: geometry.h:178
isae::geometry::directionVector2Rotation
Eigen::Matrix3d directionVector2Rotation(Eigen::Vector3d v, const Eigen::Vector3d &reference_vector=Eigen::Vector3d(1, 0, 0))
Gives the rotation matrix from a direction vector.
Definition: geometry.h:125
isae::geometry::FromskewMatrix
Eigen::Vector3d FromskewMatrix(const Eigen::Matrix3d &skew)
Computes the 3D vector from a given skew matrix.
Definition: geometry.h:31
isae::geometry::se3_doubleVec3dtoRT
Eigen::Affine3d se3_doubleVec3dtoRT(const double *p3d)
Turns a point 3d in double* into an Affine3d with Id rotation.
Definition: geometry.h:249
isae::geometry::se3_doubleVec6dtoRT
Eigen::Affine3d se3_doubleVec6dtoRT(const double *pose)
Compute the Exponential of the SO(3)xT(3) composite manifold from a double*.
Definition: geometry.h:238
isae::geometry::J_XcrossA
Eigen::Matrix3d J_XcrossA(Eigen::Vector3d A)
Definition: geometry.h:357
isae::geometry::xFront2zFront
Eigen::Matrix3d xFront2zFront()
Rotation matrix that rotates a right handed frame with X front to a frame with Z front.
Definition: geometry.h:91
isae::geometry::skewMatrix
Eigen::Matrix3d skewMatrix(const Eigen::MatrixBase< Derived > &w)
Computes the skew matrix of a given 3D vector.
Definition: geometry.h:20
isae::geometry::cov2dTriangle
Eigen::Matrix2d cov2dTriangle(std::vector< Eigen::Vector2d > triangle)
Computes the covariance of a 2D triangle according to CGAL library.
Definition: geometry.h:316
isae::geometry::exp_so3
Eigen::Matrix3d exp_so3(const Eigen::Vector3d &v)
Compute the exponential of the SO(3) manifold.
Definition: geometry.h:154
isae::geometry::J_norm
Eigen::MatrixXd J_norm(Eigen::Vector3d X)
Definition: geometry.h:349
isae::geometry::J_normalization
Eigen::Matrix3d J_normalization(Eigen::Vector3d X)
Definition: geometry.h:353
isae::geometry::rotationMatrixToEulerAnglesEigen
Eigen::Vector3d rotationMatrixToEulerAnglesEigen(Eigen::Matrix3d R)
Compute the Euler angle representation of a rotation matrix.
Definition: geometry.h:69
isae::geometry::pointInTriangle
bool pointInTriangle(Derived pt, std::vector< Derived > triangle)
Check if a point is in a triangle with the barycentric technique.
Definition: geometry.h:289
typedefs.h
isae::geometry::zFront2xFront
Eigen::Matrix3d zFront2xFront()
Rotation matrix that rotates a right handed frame with Z front to a frame with X front.
Definition: geometry.h:102
isae::geometry::se3_RTtoVec6d
Vector6d se3_RTtoVec6d(Eigen::Affine3d RT)
Compute the logarithm of the SO(3)xT(3) composite manifold.
Definition: geometry.h:203
isae
Definition: AFeature2D.h:8
isae::geometry::xRight2xFront
Eigen::Matrix3d xRight2xFront()
Rotation matrix that rotates a right handed frame with X right to a frame with X front.
Definition: geometry.h:113
isae::Vector6d
Eigen::Matrix< double, 6, 1 > Vector6d
A double Eigen vector in 6D.
Definition: typedefs.h:16
isae::geometry::so3_rightJacobian
Eigen::Matrix3d so3_rightJacobian(const Eigen::Vector3d &w)
Compute the right jacobian on SO(3) manifold.
Definition: geometry.h:42
isae::geometry::J_Rexpwt
Eigen::Matrix3d J_Rexpwt(Eigen::Matrix3d R, Eigen::Matrix3d expw, Eigen::Vector3d t)
Definition: geometry.h:365
isae::geometry::areaTriangle
double areaTriangle(std::vector< Eigen::Vector2d > triangle)
Compute the area of a 2D triangle.
Definition: geometry.h:338
isae::geometry::getAngle
double getAngle(Eigen::Vector3d p, Eigen::Vector3d p1, Eigen::Vector3d p2)
Get the angle formed by the segments p-p1 and p-p2.
Definition: geometry.h:277
isae::geometry::so3_leftJacobian
Eigen::Matrix3d so3_leftJacobian(const Eigen::Vector3d &w)
Compute the left jacobian on SO(3) manifold.
Definition: geometry.h:57
isae::geometry::Rotation2directionVector
Eigen::Vector3d Rotation2directionVector(const Eigen::Matrix3d &R, const Eigen::Vector3d &reference_vector=Eigen::Vector3d(1, 0, 0))
Gives the direction vector from a rotation matrix.
Definition: geometry.h:142
isae::geometry::se3_Vec6dtoRT
Eigen::Affine3d se3_Vec6dtoRT(Vector6d pose)
Compute the Exponential of the SO(3)xT(3) composite manifold.
Definition: geometry.h:222
isae::geometry::J_AcrossX
Eigen::Matrix3d J_AcrossX(Eigen::Vector3d A)
Definition: geometry.h:361