2014-12-09 06:58:54 +08:00
|
|
|
/* ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
* GTSAM Copyright 2010, Georgia Tech Research Corporation,
|
|
|
|
|
* Atlanta, Georgia 30332-0415
|
|
|
|
|
* All Rights Reserved
|
|
|
|
|
* Authors: Frank Dellaert, et al. (see THANKS for the full author list)
|
|
|
|
|
|
|
|
|
|
* See LICENSE for the license information
|
|
|
|
|
|
|
|
|
|
* -------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @file SO3.h
|
2014-12-09 07:52:53 +08:00
|
|
|
* @brief 3*3 matrix representation of SO(3)
|
2014-12-09 06:58:54 +08:00
|
|
|
* @author Frank Dellaert
|
2016-02-01 15:29:51 +08:00
|
|
|
* @author Luca Carlone
|
|
|
|
|
* @author Duy Nguyen Ta
|
2014-12-09 06:58:54 +08:00
|
|
|
* @date December 2014
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
2014-12-22 07:12:08 +08:00
|
|
|
#include <gtsam/base/Lie.h>
|
2019-04-30 20:47:34 +08:00
|
|
|
#include <gtsam/base/Matrix.h>
|
2014-12-09 06:58:54 +08:00
|
|
|
|
|
|
|
|
#include <cmath>
|
2016-11-02 03:11:57 +08:00
|
|
|
#include <iosfwd>
|
2014-12-09 06:58:54 +08:00
|
|
|
|
|
|
|
|
namespace gtsam {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* True SO(3), i.e., 3*3 matrix subgroup
|
|
|
|
|
* We guarantee (all but first) constructors only generate from sub-manifold.
|
|
|
|
|
* However, round-off errors in repeated composition could move off it...
|
|
|
|
|
*/
|
2019-05-06 23:07:09 +08:00
|
|
|
class SO3 : public Matrix3, public LieGroup<SO3, 3> {
|
2019-04-30 20:47:34 +08:00
|
|
|
public:
|
2019-04-17 11:45:27 +08:00
|
|
|
enum { N = 3 };
|
|
|
|
|
enum { dimension = 3 };
|
2015-02-11 03:14:59 +08:00
|
|
|
|
|
|
|
|
/// @name Constructors
|
|
|
|
|
/// @{
|
2014-12-09 06:58:54 +08:00
|
|
|
|
2019-04-17 11:45:27 +08:00
|
|
|
/// Default constructor creates identity
|
2019-04-30 20:47:34 +08:00
|
|
|
SO3() : Matrix3(I_3x3) {}
|
2014-12-27 20:37:15 +08:00
|
|
|
|
2014-12-09 06:58:54 +08:00
|
|
|
/// Constructor from Eigen Matrix
|
2019-04-30 20:47:34 +08:00
|
|
|
template <typename Derived>
|
|
|
|
|
SO3(const MatrixBase<Derived>& R) : Matrix3(R.eval()) {}
|
2014-12-09 06:58:54 +08:00
|
|
|
|
|
|
|
|
/// Constructor from AngleAxisd
|
2019-04-30 20:47:34 +08:00
|
|
|
SO3(const Eigen::AngleAxisd& angleAxis) : Matrix3(angleAxis) {}
|
2014-12-22 09:52:31 +08:00
|
|
|
|
2019-04-17 11:45:27 +08:00
|
|
|
/// Static, named constructor. TODO(dellaert): think about relation with above
|
2019-07-15 23:43:54 +08:00
|
|
|
GTSAM_EXPORT static SO3 AxisAngle(const Vector3& axis, double theta);
|
2015-02-11 03:14:59 +08:00
|
|
|
|
2019-04-17 11:45:27 +08:00
|
|
|
/// Static, named constructor that finds SO(3) matrix closest to M in Frobenius norm.
|
|
|
|
|
static SO3 ClosestTo(const Matrix3& M);
|
|
|
|
|
|
|
|
|
|
/// Static, named constructor that finds chordal mean = argmin_R \sum sqr(|R-R_i|_F).
|
|
|
|
|
static SO3 ChordalMean(const std::vector<SO3>& rotations);
|
|
|
|
|
|
2015-02-11 03:14:59 +08:00
|
|
|
/// @}
|
|
|
|
|
/// @name Testable
|
|
|
|
|
/// @{
|
|
|
|
|
|
2019-07-15 23:43:54 +08:00
|
|
|
GTSAM_EXPORT void print(const std::string& s) const;
|
2014-12-23 21:27:11 +08:00
|
|
|
|
|
|
|
|
bool equals(const SO3 & R, double tol) const {
|
|
|
|
|
return equal_with_abs_tol(*this, R, tol);
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-11 03:14:59 +08:00
|
|
|
/// @}
|
|
|
|
|
/// @name Group
|
|
|
|
|
/// @{
|
|
|
|
|
|
|
|
|
|
/// identity rotation for group operation
|
|
|
|
|
static SO3 identity() {
|
|
|
|
|
return I_3x3;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// inverse of a rotation = transpose
|
|
|
|
|
SO3 inverse() const {
|
2019-04-17 11:45:27 +08:00
|
|
|
return this->transpose();
|
2015-02-11 03:14:59 +08:00
|
|
|
}
|
2014-12-27 20:37:15 +08:00
|
|
|
|
2015-02-11 03:14:59 +08:00
|
|
|
/// @}
|
|
|
|
|
/// @name Lie Group
|
|
|
|
|
/// @{
|
|
|
|
|
|
2019-04-17 11:45:27 +08:00
|
|
|
static Matrix3 Hat(const Vector3 &xi); ///< make skew symmetric matrix
|
|
|
|
|
static Vector3 Vee(const Matrix3 &X); ///< inverse of Hat
|
|
|
|
|
|
2015-02-11 03:14:59 +08:00
|
|
|
/**
|
|
|
|
|
* Exponential map at identity - create a rotation from canonical coordinates
|
2015-07-06 05:03:42 +08:00
|
|
|
* \f$ [R_x,R_y,R_z] \f$ using Rodrigues' formula
|
2015-02-11 03:14:59 +08:00
|
|
|
*/
|
2019-07-15 23:43:54 +08:00
|
|
|
GTSAM_EXPORT static SO3 Expmap(const Vector3& omega, ChartJacobian H = boost::none);
|
2015-02-11 03:14:59 +08:00
|
|
|
|
2016-02-01 15:29:51 +08:00
|
|
|
/// Derivative of Expmap
|
2019-07-15 23:43:54 +08:00
|
|
|
GTSAM_EXPORT static Matrix3 ExpmapDerivative(const Vector3& omega);
|
2016-02-01 15:29:51 +08:00
|
|
|
|
2015-02-11 03:14:59 +08:00
|
|
|
/**
|
|
|
|
|
* Log map at identity - returns the canonical coordinates
|
|
|
|
|
* \f$ [R_x,R_y,R_z] \f$ of this rotation
|
|
|
|
|
*/
|
2019-07-15 23:43:54 +08:00
|
|
|
GTSAM_EXPORT static Vector3 Logmap(const SO3& R, ChartJacobian H = boost::none);
|
2014-12-27 20:37:15 +08:00
|
|
|
|
2015-02-11 03:14:59 +08:00
|
|
|
/// Derivative of Logmap
|
2019-07-15 23:43:54 +08:00
|
|
|
GTSAM_EXPORT static Matrix3 LogmapDerivative(const Vector3& omega);
|
2015-02-11 03:14:59 +08:00
|
|
|
|
|
|
|
|
Matrix3 AdjointMap() const {
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
2014-12-27 20:37:15 +08:00
|
|
|
|
|
|
|
|
// Chart at origin
|
|
|
|
|
struct ChartAtOrigin {
|
2015-02-11 03:14:59 +08:00
|
|
|
static SO3 Retract(const Vector3& omega, ChartJacobian H = boost::none) {
|
|
|
|
|
return Expmap(omega, H);
|
2014-12-27 20:37:15 +08:00
|
|
|
}
|
|
|
|
|
static Vector3 Local(const SO3& R, ChartJacobian H = boost::none) {
|
2015-02-11 03:14:59 +08:00
|
|
|
return Logmap(R, H);
|
2014-12-27 20:37:15 +08:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2015-02-11 03:14:59 +08:00
|
|
|
using LieGroup<SO3, 3>::inverse;
|
2014-12-27 20:37:15 +08:00
|
|
|
|
2015-02-11 03:14:59 +08:00
|
|
|
/// @}
|
2019-04-17 11:45:27 +08:00
|
|
|
/// @name Other methods
|
|
|
|
|
/// @{
|
|
|
|
|
|
|
|
|
|
/// Vectorize
|
|
|
|
|
Vector9 vec(OptionalJacobian<9, 3> H = boost::none) const;
|
|
|
|
|
|
|
|
|
|
/// Return matrix (for wrapper)
|
|
|
|
|
const Matrix3& matrix() const { return *this;}
|
|
|
|
|
|
|
|
|
|
/// @
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
|
|
/** Serialization function */
|
|
|
|
|
friend class boost::serialization::access;
|
|
|
|
|
template<class ARCHIVE>
|
|
|
|
|
void serialize(ARCHIVE & ar, const unsigned int /*version*/)
|
|
|
|
|
{
|
|
|
|
|
ar & boost::serialization::make_nvp("R11", (*this)(0,0));
|
|
|
|
|
ar & boost::serialization::make_nvp("R12", (*this)(0,1));
|
|
|
|
|
ar & boost::serialization::make_nvp("R13", (*this)(0,2));
|
|
|
|
|
ar & boost::serialization::make_nvp("R21", (*this)(1,0));
|
|
|
|
|
ar & boost::serialization::make_nvp("R22", (*this)(1,1));
|
|
|
|
|
ar & boost::serialization::make_nvp("R23", (*this)(1,2));
|
|
|
|
|
ar & boost::serialization::make_nvp("R31", (*this)(2,0));
|
|
|
|
|
ar & boost::serialization::make_nvp("R32", (*this)(2,1));
|
|
|
|
|
ar & boost::serialization::make_nvp("R33", (*this)(2,2));
|
|
|
|
|
}
|
2014-12-09 06:58:54 +08:00
|
|
|
};
|
|
|
|
|
|
2016-02-02 01:47:57 +08:00
|
|
|
namespace so3 {
|
|
|
|
|
|
2019-04-17 11:45:27 +08:00
|
|
|
/**
|
|
|
|
|
* Compose general matrix with an SO(3) element.
|
|
|
|
|
* We only provide the 9*9 derivative in the first argument M.
|
|
|
|
|
*/
|
|
|
|
|
Matrix3 compose(const Matrix3& M, const SO3& R,
|
|
|
|
|
OptionalJacobian<9, 9> H = boost::none);
|
|
|
|
|
|
|
|
|
|
/// (constant) Jacobian of compose wrpt M
|
|
|
|
|
Matrix99 Dcompose(const SO3& R);
|
|
|
|
|
|
|
|
|
|
// Below are two functors that allow for saving computation when exponential map
|
|
|
|
|
// and its derivatives are needed at the same location in so<3>. The second
|
|
|
|
|
// functor also implements dedicated methods to apply dexp and/or inv(dexp).
|
|
|
|
|
|
2016-02-02 01:47:57 +08:00
|
|
|
/// Functor implementing Exponential map
|
2018-11-05 03:32:29 +08:00
|
|
|
class GTSAM_EXPORT ExpmapFunctor {
|
2016-02-02 01:47:57 +08:00
|
|
|
protected:
|
|
|
|
|
const double theta2;
|
|
|
|
|
Matrix3 W, K, KK;
|
|
|
|
|
bool nearZero;
|
|
|
|
|
double theta, sin_theta, one_minus_cos; // only defined if !nearZero
|
|
|
|
|
|
2016-02-02 15:51:33 +08:00
|
|
|
void init(bool nearZeroApprox = false);
|
2016-02-02 01:47:57 +08:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
/// Constructor with element of Lie algebra so(3)
|
2016-02-02 15:51:33 +08:00
|
|
|
ExpmapFunctor(const Vector3& omega, bool nearZeroApprox = false);
|
2016-02-02 01:47:57 +08:00
|
|
|
|
|
|
|
|
/// Constructor with axis-angle
|
2016-02-02 15:51:33 +08:00
|
|
|
ExpmapFunctor(const Vector3& axis, double angle, bool nearZeroApprox = false);
|
2016-02-02 01:47:57 +08:00
|
|
|
|
2016-02-02 04:43:05 +08:00
|
|
|
/// Rodrigues formula
|
2016-02-02 01:47:57 +08:00
|
|
|
SO3 expmap() const;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// Functor that implements Exponential map *and* its derivatives
|
2019-07-18 17:09:08 +08:00
|
|
|
class DexpFunctor : public ExpmapFunctor {
|
2016-02-02 01:47:57 +08:00
|
|
|
const Vector3 omega;
|
|
|
|
|
double a, b;
|
2016-02-02 04:43:05 +08:00
|
|
|
Matrix3 dexp_;
|
2016-02-02 01:47:57 +08:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
/// Constructor with element of Lie algebra so(3)
|
2019-07-18 17:09:08 +08:00
|
|
|
GTSAM_EXPORT DexpFunctor(const Vector3& omega, bool nearZeroApprox = false);
|
2016-02-02 01:47:57 +08:00
|
|
|
|
|
|
|
|
// NOTE(luca): Right Jacobian for Exponential map in SO(3) - equation
|
|
|
|
|
// (10.86) and following equations in G.S. Chirikjian, "Stochastic Models,
|
|
|
|
|
// Information Theory, and Lie Groups", Volume 2, 2008.
|
|
|
|
|
// expmap(omega + v) \approx expmap(omega) * expmap(dexp * v)
|
|
|
|
|
// This maps a perturbation v in the tangent space to
|
|
|
|
|
// a perturbation on the manifold Expmap(dexp * v) */
|
2016-02-02 04:43:05 +08:00
|
|
|
const Matrix3& dexp() const { return dexp_; }
|
2016-02-02 01:47:57 +08:00
|
|
|
|
|
|
|
|
/// Multiplies with dexp(), with optional derivatives
|
2019-07-18 17:09:08 +08:00
|
|
|
GTSAM_EXPORT Vector3 applyDexp(const Vector3& v, OptionalJacobian<3, 3> H1 = boost::none,
|
2016-02-02 04:43:05 +08:00
|
|
|
OptionalJacobian<3, 3> H2 = boost::none) const;
|
|
|
|
|
|
|
|
|
|
/// Multiplies with dexp().inverse(), with optional derivatives
|
2019-07-18 17:09:08 +08:00
|
|
|
GTSAM_EXPORT Vector3 applyInvDexp(const Vector3& v,
|
2016-02-02 04:43:05 +08:00
|
|
|
OptionalJacobian<3, 3> H1 = boost::none,
|
|
|
|
|
OptionalJacobian<3, 3> H2 = boost::none) const;
|
2016-02-02 01:47:57 +08:00
|
|
|
};
|
|
|
|
|
} // namespace so3
|
|
|
|
|
|
2014-12-18 05:53:56 +08:00
|
|
|
template<>
|
2015-05-26 13:04:04 +08:00
|
|
|
struct traits<SO3> : public internal::LieGroup<SO3> {
|
2015-02-11 03:14:59 +08:00
|
|
|
};
|
2014-12-18 05:53:56 +08:00
|
|
|
|
2015-01-22 02:02:35 +08:00
|
|
|
template<>
|
2015-05-26 13:04:04 +08:00
|
|
|
struct traits<const SO3> : public internal::LieGroup<SO3> {
|
2015-02-11 03:14:59 +08:00
|
|
|
};
|
2014-12-09 06:58:54 +08:00
|
|
|
} // end namespace gtsam
|
|
|
|
|
|