se3.hpp 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081
  1. /// @file
  2. /// Special Euclidean group SE(3) - rotation and translation in 3d.
  3. #ifndef SOPHUS_SE3_HPP
  4. #define SOPHUS_SE3_HPP
  5. #include "so3.hpp"
  6. namespace Sophus {
  7. template <class Scalar_, int Options = 0>
  8. class SE3;
  9. using SE3d = SE3<double>;
  10. using SE3f = SE3<float>;
  11. } // namespace Sophus
  12. namespace Eigen {
  13. namespace internal {
  14. template <class Scalar_, int Options>
  15. struct traits<Sophus::SE3<Scalar_, Options>> {
  16. using Scalar = Scalar_;
  17. using TranslationType = Sophus::Vector3<Scalar, Options>;
  18. using SO3Type = Sophus::SO3<Scalar, Options>;
  19. };
  20. template <class Scalar_, int Options>
  21. struct traits<Map<Sophus::SE3<Scalar_>, Options>>
  22. : traits<Sophus::SE3<Scalar_, Options>> {
  23. using Scalar = Scalar_;
  24. using TranslationType = Map<Sophus::Vector3<Scalar>, Options>;
  25. using SO3Type = Map<Sophus::SO3<Scalar>, Options>;
  26. };
  27. template <class Scalar_, int Options>
  28. struct traits<Map<Sophus::SE3<Scalar_> const, Options>>
  29. : traits<Sophus::SE3<Scalar_, Options> const> {
  30. using Scalar = Scalar_;
  31. using TranslationType = Map<Sophus::Vector3<Scalar> const, Options>;
  32. using SO3Type = Map<Sophus::SO3<Scalar> const, Options>;
  33. };
  34. } // namespace internal
  35. } // namespace Eigen
  36. namespace Sophus {
  37. /// SE3 base type - implements SE3 class but is storage agnostic.
  38. ///
  39. /// SE(3) is the group of rotations and translation in 3d. It is the
  40. /// semi-direct product of SO(3) and the 3d Euclidean vector space. The class
  41. /// is represented using a composition of SO3 for rotation and a one 3-vector
  42. /// for translation.
  43. ///
  44. /// SE(3) is neither compact, nor a commutative group.
  45. ///
  46. /// See SO3 for more details of the rotation representation in 3d.
  47. ///
  48. template <class Derived>
  49. class SE3Base {
  50. public:
  51. using Scalar = typename Eigen::internal::traits<Derived>::Scalar;
  52. using TranslationType =
  53. typename Eigen::internal::traits<Derived>::TranslationType;
  54. using SO3Type = typename Eigen::internal::traits<Derived>::SO3Type;
  55. using QuaternionType = typename SO3Type::QuaternionType;
  56. /// Degrees of freedom of manifold, number of dimensions in tangent space
  57. /// (three for translation, three for rotation).
  58. static int constexpr DoF = 6;
  59. /// Number of internal parameters used (4-tuple for quaternion, three for
  60. /// translation).
  61. static int constexpr num_parameters = 7;
  62. /// Group transformations are 4x4 matrices.
  63. static int constexpr N = 4;
  64. using Transformation = Matrix<Scalar, N, N>;
  65. using Point = Vector3<Scalar>;
  66. using HomogeneousPoint = Vector4<Scalar>;
  67. using Line = ParametrizedLine3<Scalar>;
  68. using Tangent = Vector<Scalar, DoF>;
  69. using Adjoint = Matrix<Scalar, DoF, DoF>;
  70. /// For binary operations the return type is determined with the
  71. /// ScalarBinaryOpTraits feature of Eigen. This allows mixing concrete and Map
  72. /// types, as well as other compatible scalar types such as Ceres::Jet and
  73. /// double scalars with SE3 operations.
  74. template <typename OtherDerived>
  75. using ReturnScalar = typename Eigen::ScalarBinaryOpTraits<
  76. Scalar, typename OtherDerived::Scalar>::ReturnType;
  77. template <typename OtherDerived>
  78. using SE3Product = SE3<ReturnScalar<OtherDerived>>;
  79. template <typename PointDerived>
  80. using PointProduct = Vector3<ReturnScalar<PointDerived>>;
  81. template <typename HPointDerived>
  82. using HomogeneousPointProduct = Vector4<ReturnScalar<HPointDerived>>;
  83. /// Adjoint transformation
  84. ///
  85. /// This function return the adjoint transformation ``Ad`` of the group
  86. /// element ``A`` such that for all ``x`` it holds that
  87. /// ``hat(Ad_A * x) = A * hat(x) A^{-1}``. See hat-operator below.
  88. ///
  89. SOPHUS_FUNC Adjoint Adj() const {
  90. Sophus::Matrix3<Scalar> const R = so3().matrix();
  91. Adjoint res;
  92. res.block(0, 0, 3, 3) = R;
  93. res.block(3, 3, 3, 3) = R;
  94. res.block(0, 3, 3, 3) = SO3<Scalar>::hat(translation()) * R;
  95. res.block(3, 0, 3, 3) = Matrix3<Scalar>::Zero(3, 3);
  96. return res;
  97. }
  98. /// Extract rotation angle about canonical X-axis
  99. ///
  100. Scalar angleX() const { return so3().angleX(); }
  101. /// Extract rotation angle about canonical Y-axis
  102. ///
  103. Scalar angleY() const { return so3().angleY(); }
  104. /// Extract rotation angle about canonical Z-axis
  105. ///
  106. Scalar angleZ() const { return so3().angleZ(); }
  107. /// Returns copy of instance casted to NewScalarType.
  108. ///
  109. template <class NewScalarType>
  110. SOPHUS_FUNC SE3<NewScalarType> cast() const {
  111. return SE3<NewScalarType>(so3().template cast<NewScalarType>(),
  112. translation().template cast<NewScalarType>());
  113. }
  114. /// Returns derivative of this * exp(x) wrt x at x=0.
  115. ///
  116. SOPHUS_FUNC Matrix<Scalar, num_parameters, DoF> Dx_this_mul_exp_x_at_0()
  117. const {
  118. Matrix<Scalar, num_parameters, DoF> J;
  119. Eigen::Quaternion<Scalar> const q = unit_quaternion();
  120. Scalar const c0 = Scalar(0.5) * q.w();
  121. Scalar const c1 = Scalar(0.5) * q.z();
  122. Scalar const c2 = -c1;
  123. Scalar const c3 = Scalar(0.5) * q.y();
  124. Scalar const c4 = Scalar(0.5) * q.x();
  125. Scalar const c5 = -c4;
  126. Scalar const c6 = -c3;
  127. Scalar const c7 = q.w() * q.w();
  128. Scalar const c8 = q.x() * q.x();
  129. Scalar const c9 = q.y() * q.y();
  130. Scalar const c10 = -c9;
  131. Scalar const c11 = q.z() * q.z();
  132. Scalar const c12 = -c11;
  133. Scalar const c13 = Scalar(2) * q.w();
  134. Scalar const c14 = c13 * q.z();
  135. Scalar const c15 = Scalar(2) * q.x();
  136. Scalar const c16 = c15 * q.y();
  137. Scalar const c17 = c13 * q.y();
  138. Scalar const c18 = c15 * q.z();
  139. Scalar const c19 = c7 - c8;
  140. Scalar const c20 = c13 * q.x();
  141. Scalar const c21 = Scalar(2) * q.y() * q.z();
  142. J(0, 0) = 0;
  143. J(0, 1) = 0;
  144. J(0, 2) = 0;
  145. J(0, 3) = c0;
  146. J(0, 4) = c2;
  147. J(0, 5) = c3;
  148. J(1, 0) = 0;
  149. J(1, 1) = 0;
  150. J(1, 2) = 0;
  151. J(1, 3) = c1;
  152. J(1, 4) = c0;
  153. J(1, 5) = c5;
  154. J(2, 0) = 0;
  155. J(2, 1) = 0;
  156. J(2, 2) = 0;
  157. J(2, 3) = c6;
  158. J(2, 4) = c4;
  159. J(2, 5) = c0;
  160. J(3, 0) = 0;
  161. J(3, 1) = 0;
  162. J(3, 2) = 0;
  163. J(3, 3) = c5;
  164. J(3, 4) = c6;
  165. J(3, 5) = c2;
  166. J(4, 0) = c10 + c12 + c7 + c8;
  167. J(4, 1) = -c14 + c16;
  168. J(4, 2) = c17 + c18;
  169. J(4, 3) = 0;
  170. J(4, 4) = 0;
  171. J(4, 5) = 0;
  172. J(5, 0) = c14 + c16;
  173. J(5, 1) = c12 + c19 + c9;
  174. J(5, 2) = -c20 + c21;
  175. J(5, 3) = 0;
  176. J(5, 4) = 0;
  177. J(5, 5) = 0;
  178. J(6, 0) = -c17 + c18;
  179. J(6, 1) = c20 + c21;
  180. J(6, 2) = c10 + c11 + c19;
  181. J(6, 3) = 0;
  182. J(6, 4) = 0;
  183. J(6, 5) = 0;
  184. return J;
  185. }
  186. /// Returns group inverse.
  187. ///
  188. SOPHUS_FUNC SE3<Scalar> inverse() const {
  189. SO3<Scalar> invR = so3().inverse();
  190. return SE3<Scalar>(invR, invR * (translation() * Scalar(-1)));
  191. }
  192. /// Logarithmic map
  193. ///
  194. /// Computes the logarithm, the inverse of the group exponential which maps
  195. /// element of the group (rigid body transformations) to elements of the
  196. /// tangent space (twist).
  197. ///
  198. /// To be specific, this function computes ``vee(logmat(.))`` with
  199. /// ``logmat(.)`` being the matrix logarithm and ``vee(.)`` the vee-operator
  200. /// of SE(3).
  201. ///
  202. SOPHUS_FUNC Tangent log() const {
  203. // For the derivation of the logarithm of SE(3), see
  204. // J. Gallier, D. Xu, "Computing exponentials of skew symmetric matrices
  205. // and logarithms of orthogonal matrices", IJRA 2002.
  206. // https:///pdfs.semanticscholar.org/cfe3/e4b39de63c8cabd89bf3feff7f5449fc981d.pdf
  207. // (Sec. 6., pp. 8)
  208. using std::abs;
  209. using std::cos;
  210. using std::sin;
  211. Tangent upsilon_omega;
  212. auto omega_and_theta = so3().logAndTheta();
  213. Scalar theta = omega_and_theta.theta;
  214. upsilon_omega.template tail<3>() = omega_and_theta.tangent;
  215. Matrix3<Scalar> const Omega =
  216. SO3<Scalar>::hat(upsilon_omega.template tail<3>());
  217. if (abs(theta) < Constants<Scalar>::epsilon()) {
  218. Matrix3<Scalar> const V_inv = Matrix3<Scalar>::Identity() -
  219. Scalar(0.5) * Omega +
  220. Scalar(1. / 12.) * (Omega * Omega);
  221. upsilon_omega.template head<3>() = V_inv * translation();
  222. } else {
  223. Scalar const half_theta = Scalar(0.5) * theta;
  224. Matrix3<Scalar> const V_inv =
  225. (Matrix3<Scalar>::Identity() - Scalar(0.5) * Omega +
  226. (Scalar(1) -
  227. theta * cos(half_theta) / (Scalar(2) * sin(half_theta))) /
  228. (theta * theta) * (Omega * Omega));
  229. upsilon_omega.template head<3>() = V_inv * translation();
  230. }
  231. return upsilon_omega;
  232. }
  233. /// It re-normalizes the SO3 element.
  234. ///
  235. /// Note: Because of the class invariant of SO3, there is typically no need to
  236. /// call this function directly.
  237. ///
  238. SOPHUS_FUNC void normalize() { so3().normalize(); }
  239. /// Returns 4x4 matrix representation of the instance.
  240. ///
  241. /// It has the following form:
  242. ///
  243. /// | R t |
  244. /// | o 1 |
  245. ///
  246. /// where ``R`` is a 3x3 rotation matrix, ``t`` a translation 3-vector and
  247. /// ``o`` a 3-column vector of zeros.
  248. ///
  249. SOPHUS_FUNC Transformation matrix() const {
  250. Transformation homogenious_matrix;
  251. homogenious_matrix.template topLeftCorner<3, 4>() = matrix3x4();
  252. homogenious_matrix.row(3) =
  253. Matrix<Scalar, 1, 4>(Scalar(0), Scalar(0), Scalar(0), Scalar(1));
  254. return homogenious_matrix;
  255. }
  256. /// Returns the significant first three rows of the matrix above.
  257. ///
  258. SOPHUS_FUNC Matrix<Scalar, 3, 4> matrix3x4() const {
  259. Matrix<Scalar, 3, 4> matrix;
  260. matrix.template topLeftCorner<3, 3>() = rotationMatrix();
  261. matrix.col(3) = translation();
  262. return matrix;
  263. }
  264. /// Assignment operator.
  265. ///
  266. SOPHUS_FUNC SE3Base& operator=(SE3Base const& other) = default;
  267. /// Assignment-like operator from OtherDerived.
  268. ///
  269. template <class OtherDerived>
  270. SOPHUS_FUNC SE3Base<Derived>& operator=(SE3Base<OtherDerived> const& other) {
  271. so3() = other.so3();
  272. translation() = other.translation();
  273. return *this;
  274. }
  275. /// Group multiplication, which is rotation concatenation.
  276. ///
  277. template <typename OtherDerived>
  278. SOPHUS_FUNC SE3Product<OtherDerived> operator*(
  279. SE3Base<OtherDerived> const& other) const {
  280. return SE3Product<OtherDerived>(
  281. so3() * other.so3(), translation() + so3() * other.translation());
  282. }
  283. /// Group action on 3-points.
  284. ///
  285. /// This function rotates and translates a three dimensional point ``p`` by
  286. /// the SE(3) element ``bar_T_foo = (bar_R_foo, t_bar)`` (= rigid body
  287. /// transformation):
  288. ///
  289. /// ``p_bar = bar_R_foo * p_foo + t_bar``.
  290. ///
  291. template <typename PointDerived,
  292. typename = typename std::enable_if<
  293. IsFixedSizeVector<PointDerived, 3>::value>::type>
  294. SOPHUS_FUNC PointProduct<PointDerived> operator*(
  295. Eigen::MatrixBase<PointDerived> const& p) const {
  296. return so3() * p + translation();
  297. }
  298. /// Group action on homogeneous 3-points. See above for more details.
  299. ///
  300. template <typename HPointDerived,
  301. typename = typename std::enable_if<
  302. IsFixedSizeVector<HPointDerived, 4>::value>::type>
  303. SOPHUS_FUNC HomogeneousPointProduct<HPointDerived> operator*(
  304. Eigen::MatrixBase<HPointDerived> const& p) const {
  305. const PointProduct<HPointDerived> tp =
  306. so3() * p.template head<3>() + p(3) * translation();
  307. return HomogeneousPointProduct<HPointDerived>(tp(0), tp(1), tp(2), p(3));
  308. }
  309. /// Group action on lines.
  310. ///
  311. /// This function rotates and translates a parametrized line
  312. /// ``l(t) = o + t * d`` by the SE(3) element:
  313. ///
  314. /// Origin is transformed using SE(3) action
  315. /// Direction is transformed using rotation part
  316. ///
  317. SOPHUS_FUNC Line operator*(Line const& l) const {
  318. return Line((*this) * l.origin(), so3() * l.direction());
  319. }
  320. /// In-place group multiplication. This method is only valid if the return
  321. /// type of the multiplication is compatible with this SE3's Scalar type.
  322. ///
  323. template <typename OtherDerived,
  324. typename = typename std::enable_if<
  325. std::is_same<Scalar, ReturnScalar<OtherDerived>>::value>::type>
  326. SOPHUS_FUNC SE3Base<Derived>& operator*=(SE3Base<OtherDerived> const& other) {
  327. *static_cast<Derived*>(this) = *this * other;
  328. return *this;
  329. }
  330. /// Returns rotation matrix.
  331. ///
  332. SOPHUS_FUNC Matrix3<Scalar> rotationMatrix() const { return so3().matrix(); }
  333. /// Mutator of SO3 group.
  334. ///
  335. SOPHUS_FUNC SO3Type& so3() { return static_cast<Derived*>(this)->so3(); }
  336. /// Accessor of SO3 group.
  337. ///
  338. SOPHUS_FUNC SO3Type const& so3() const {
  339. return static_cast<const Derived*>(this)->so3();
  340. }
  341. /// Takes in quaternion, and normalizes it.
  342. ///
  343. /// Precondition: The quaternion must not be close to zero.
  344. ///
  345. SOPHUS_FUNC void setQuaternion(Eigen::Quaternion<Scalar> const& quat) {
  346. so3().setQuaternion(quat);
  347. }
  348. /// Sets ``so3`` using ``rotation_matrix``.
  349. ///
  350. /// Precondition: ``R`` must be orthogonal and ``det(R)=1``.
  351. ///
  352. SOPHUS_FUNC void setRotationMatrix(Matrix3<Scalar> const& R) {
  353. SOPHUS_ENSURE(isOrthogonal(R), "R is not orthogonal:\n %", R);
  354. SOPHUS_ENSURE(R.determinant() > Scalar(0), "det(R) is not positive: %",
  355. R.determinant());
  356. so3().setQuaternion(Eigen::Quaternion<Scalar>(R));
  357. }
  358. /// Returns internal parameters of SE(3).
  359. ///
  360. /// It returns (q.imag[0], q.imag[1], q.imag[2], q.real, t[0], t[1], t[2]),
  361. /// with q being the unit quaternion, t the translation 3-vector.
  362. ///
  363. SOPHUS_FUNC Sophus::Vector<Scalar, num_parameters> params() const {
  364. Sophus::Vector<Scalar, num_parameters> p;
  365. p << so3().params(), translation();
  366. return p;
  367. }
  368. /// Mutator of translation vector.
  369. ///
  370. SOPHUS_FUNC TranslationType& translation() {
  371. return static_cast<Derived*>(this)->translation();
  372. }
  373. /// Accessor of translation vector
  374. ///
  375. SOPHUS_FUNC TranslationType const& translation() const {
  376. return static_cast<Derived const*>(this)->translation();
  377. }
  378. /// Accessor of unit quaternion.
  379. ///
  380. SOPHUS_FUNC QuaternionType const& unit_quaternion() const {
  381. return this->so3().unit_quaternion();
  382. }
  383. };
  384. /// SE3 using default storage; derived from SE3Base.
  385. template <class Scalar_, int Options>
  386. class SE3 : public SE3Base<SE3<Scalar_, Options>> {
  387. using Base = SE3Base<SE3<Scalar_, Options>>;
  388. public:
  389. static int constexpr DoF = Base::DoF;
  390. static int constexpr num_parameters = Base::num_parameters;
  391. using Scalar = Scalar_;
  392. using Transformation = typename Base::Transformation;
  393. using Point = typename Base::Point;
  394. using HomogeneousPoint = typename Base::HomogeneousPoint;
  395. using Tangent = typename Base::Tangent;
  396. using Adjoint = typename Base::Adjoint;
  397. using SO3Member = SO3<Scalar, Options>;
  398. using TranslationMember = Vector3<Scalar, Options>;
  399. EIGEN_MAKE_ALIGNED_OPERATOR_NEW
  400. /// Default constructor initializes rigid body motion to the identity.
  401. ///
  402. SOPHUS_FUNC SE3();
  403. /// Copy constructor
  404. ///
  405. SOPHUS_FUNC SE3(SE3 const& other) = default;
  406. /// Copy-like constructor from OtherDerived.
  407. ///
  408. template <class OtherDerived>
  409. SOPHUS_FUNC SE3(SE3Base<OtherDerived> const& other)
  410. : so3_(other.so3()), translation_(other.translation()) {
  411. static_assert(std::is_same<typename OtherDerived::Scalar, Scalar>::value,
  412. "must be same Scalar type");
  413. }
  414. /// Constructor from SO3 and translation vector
  415. ///
  416. template <class OtherDerived, class D>
  417. SOPHUS_FUNC SE3(SO3Base<OtherDerived> const& so3,
  418. Eigen::MatrixBase<D> const& translation)
  419. : so3_(so3), translation_(translation) {
  420. static_assert(std::is_same<typename OtherDerived::Scalar, Scalar>::value,
  421. "must be same Scalar type");
  422. static_assert(std::is_same<typename D::Scalar, Scalar>::value,
  423. "must be same Scalar type");
  424. }
  425. /// Constructor from rotation matrix and translation vector
  426. ///
  427. /// Precondition: Rotation matrix needs to be orthogonal with determinant
  428. /// of 1.
  429. ///
  430. SOPHUS_FUNC
  431. SE3(Matrix3<Scalar> const& rotation_matrix, Point const& translation)
  432. : so3_(rotation_matrix), translation_(translation) {}
  433. /// Constructor from quaternion and translation vector.
  434. ///
  435. /// Precondition: ``quaternion`` must not be close to zero.
  436. ///
  437. SOPHUS_FUNC SE3(Eigen::Quaternion<Scalar> const& quaternion,
  438. Point const& translation)
  439. : so3_(quaternion), translation_(translation) {}
  440. /// Constructor from 4x4 matrix
  441. ///
  442. /// Precondition: Rotation matrix needs to be orthogonal with determinant
  443. /// of 1. The last row must be ``(0, 0, 0, 1)``.
  444. ///
  445. SOPHUS_FUNC explicit SE3(Matrix4<Scalar> const& T)
  446. : so3_(T.template topLeftCorner<3, 3>()),
  447. translation_(T.template block<3, 1>(0, 3)) {
  448. SOPHUS_ENSURE((T.row(3) - Matrix<Scalar, 1, 4>(Scalar(0), Scalar(0),
  449. Scalar(0), Scalar(1)))
  450. .squaredNorm() < Constants<Scalar>::epsilon(),
  451. "Last row is not (0,0,0,1), but (%).", T.row(3));
  452. }
  453. /// This provides unsafe read/write access to internal data. SO(3) is
  454. /// represented by an Eigen::Quaternion (four parameters). When using direct
  455. /// write access, the user needs to take care of that the quaternion stays
  456. /// normalized.
  457. ///
  458. SOPHUS_FUNC Scalar* data() {
  459. // so3_ and translation_ are laid out sequentially with no padding
  460. return so3_.data();
  461. }
  462. /// Const version of data() above.
  463. ///
  464. SOPHUS_FUNC Scalar const* data() const {
  465. // so3_ and translation_ are laid out sequentially with no padding
  466. return so3_.data();
  467. }
  468. /// Mutator of SO3
  469. ///
  470. SOPHUS_FUNC SO3Member& so3() { return so3_; }
  471. /// Accessor of SO3
  472. ///
  473. SOPHUS_FUNC SO3Member const& so3() const { return so3_; }
  474. /// Mutator of translation vector
  475. ///
  476. SOPHUS_FUNC TranslationMember& translation() { return translation_; }
  477. /// Accessor of translation vector
  478. ///
  479. SOPHUS_FUNC TranslationMember const& translation() const {
  480. return translation_;
  481. }
  482. /// Returns derivative of exp(x) wrt. x.
  483. ///
  484. SOPHUS_FUNC static Sophus::Matrix<Scalar, num_parameters, DoF> Dx_exp_x(
  485. Tangent const& upsilon_omega) {
  486. using std::cos;
  487. using std::pow;
  488. using std::sin;
  489. using std::sqrt;
  490. Sophus::Matrix<Scalar, num_parameters, DoF> J;
  491. Sophus::Vector<Scalar, 3> upsilon = upsilon_omega.template head<3>();
  492. Sophus::Vector<Scalar, 3> omega = upsilon_omega.template tail<3>();
  493. Scalar const c0 = omega[0] * omega[0];
  494. Scalar const c1 = omega[1] * omega[1];
  495. Scalar const c2 = omega[2] * omega[2];
  496. Scalar const c3 = c0 + c1 + c2;
  497. Scalar const o(0);
  498. Scalar const h(0.5);
  499. Scalar const i(1);
  500. if (c3 < Constants<Scalar>::epsilon()) {
  501. Scalar const ux = Scalar(0.5) * upsilon[0];
  502. Scalar const uy = Scalar(0.5) * upsilon[1];
  503. Scalar const uz = Scalar(0.5) * upsilon[2];
  504. /// clang-format off
  505. J << o, o, o, h, o, o, o, o, o, o, h, o, o, o, o, o, o, h, o, o, o, o, o,
  506. o, i, o, o, o, uz, -uy, o, i, o, -uz, o, ux, o, o, i, uy, -ux, o;
  507. /// clang-format on
  508. return J;
  509. }
  510. Scalar const c4 = sqrt(c3);
  511. Scalar const c5 = Scalar(1.0) / c4;
  512. Scalar const c6 = Scalar(0.5) * c4;
  513. Scalar const c7 = sin(c6);
  514. Scalar const c8 = c5 * c7;
  515. Scalar const c9 = pow(c3, -3.0L / 2.0L);
  516. Scalar const c10 = c7 * c9;
  517. Scalar const c11 = Scalar(1.0) / c3;
  518. Scalar const c12 = cos(c6);
  519. Scalar const c13 = Scalar(0.5) * c11 * c12;
  520. Scalar const c14 = c7 * c9 * omega[0];
  521. Scalar const c15 = Scalar(0.5) * c11 * c12 * omega[0];
  522. Scalar const c16 = -c14 * omega[1] + c15 * omega[1];
  523. Scalar const c17 = -c14 * omega[2] + c15 * omega[2];
  524. Scalar const c18 = omega[1] * omega[2];
  525. Scalar const c19 = -c10 * c18 + c13 * c18;
  526. Scalar const c20 = c5 * omega[0];
  527. Scalar const c21 = Scalar(0.5) * c7;
  528. Scalar const c22 = c5 * omega[1];
  529. Scalar const c23 = c5 * omega[2];
  530. Scalar const c24 = -c1;
  531. Scalar const c25 = -c2;
  532. Scalar const c26 = c24 + c25;
  533. Scalar const c27 = sin(c4);
  534. Scalar const c28 = -c27 + c4;
  535. Scalar const c29 = c28 * c9;
  536. Scalar const c30 = cos(c4);
  537. Scalar const c31 = -c30 + Scalar(1);
  538. Scalar const c32 = c11 * c31;
  539. Scalar const c33 = c32 * omega[2];
  540. Scalar const c34 = c29 * omega[0];
  541. Scalar const c35 = c34 * omega[1];
  542. Scalar const c36 = c32 * omega[1];
  543. Scalar const c37 = c34 * omega[2];
  544. Scalar const c38 = pow(c3, -5.0L / 2.0L);
  545. Scalar const c39 = Scalar(3) * c28 * c38 * omega[0];
  546. Scalar const c40 = c26 * c9;
  547. Scalar const c41 = -c20 * c30 + c20;
  548. Scalar const c42 = c27 * c9 * omega[0];
  549. Scalar const c43 = c42 * omega[1];
  550. Scalar const c44 = pow(c3, -2);
  551. Scalar const c45 = Scalar(2) * c31 * c44 * omega[0];
  552. Scalar const c46 = c45 * omega[1];
  553. Scalar const c47 = c29 * omega[2];
  554. Scalar const c48 = c43 - c46 + c47;
  555. Scalar const c49 = Scalar(3) * c0 * c28 * c38;
  556. Scalar const c50 = c9 * omega[0] * omega[2];
  557. Scalar const c51 = c41 * c50 - c49 * omega[2];
  558. Scalar const c52 = c9 * omega[0] * omega[1];
  559. Scalar const c53 = c41 * c52 - c49 * omega[1];
  560. Scalar const c54 = c42 * omega[2];
  561. Scalar const c55 = c45 * omega[2];
  562. Scalar const c56 = c29 * omega[1];
  563. Scalar const c57 = -c54 + c55 + c56;
  564. Scalar const c58 = Scalar(-2) * c56;
  565. Scalar const c59 = Scalar(3) * c28 * c38 * omega[1];
  566. Scalar const c60 = -c22 * c30 + c22;
  567. Scalar const c61 = -c18 * c39;
  568. Scalar const c62 = c32 + c61;
  569. Scalar const c63 = c27 * c9;
  570. Scalar const c64 = c1 * c63;
  571. Scalar const c65 = Scalar(2) * c31 * c44;
  572. Scalar const c66 = c1 * c65;
  573. Scalar const c67 = c50 * c60;
  574. Scalar const c68 = -c1 * c39 + c52 * c60;
  575. Scalar const c69 = c18 * c63;
  576. Scalar const c70 = c18 * c65;
  577. Scalar const c71 = c34 - c69 + c70;
  578. Scalar const c72 = Scalar(-2) * c47;
  579. Scalar const c73 = Scalar(3) * c28 * c38 * omega[2];
  580. Scalar const c74 = -c23 * c30 + c23;
  581. Scalar const c75 = -c32 + c61;
  582. Scalar const c76 = c2 * c63;
  583. Scalar const c77 = c2 * c65;
  584. Scalar const c78 = c52 * c74;
  585. Scalar const c79 = c34 + c69 - c70;
  586. Scalar const c80 = -c2 * c39 + c50 * c74;
  587. Scalar const c81 = -c0;
  588. Scalar const c82 = c25 + c81;
  589. Scalar const c83 = c32 * omega[0];
  590. Scalar const c84 = c18 * c29;
  591. Scalar const c85 = Scalar(-2) * c34;
  592. Scalar const c86 = c82 * c9;
  593. Scalar const c87 = c0 * c63;
  594. Scalar const c88 = c0 * c65;
  595. Scalar const c89 = c9 * omega[1] * omega[2];
  596. Scalar const c90 = c41 * c89;
  597. Scalar const c91 = c54 - c55 + c56;
  598. Scalar const c92 = -c1 * c73 + c60 * c89;
  599. Scalar const c93 = -c43 + c46 + c47;
  600. Scalar const c94 = -c2 * c59 + c74 * c89;
  601. Scalar const c95 = c24 + c81;
  602. Scalar const c96 = c9 * c95;
  603. J(0, 0) = o;
  604. J(0, 1) = o;
  605. J(0, 2) = o;
  606. J(0, 3) = -c0 * c10 + c0 * c13 + c8;
  607. J(0, 4) = c16;
  608. J(0, 5) = c17;
  609. J(1, 0) = o;
  610. J(1, 1) = o;
  611. J(1, 2) = o;
  612. J(1, 3) = c16;
  613. J(1, 4) = -c1 * c10 + c1 * c13 + c8;
  614. J(1, 5) = c19;
  615. J(2, 0) = o;
  616. J(2, 1) = o;
  617. J(2, 2) = o;
  618. J(2, 3) = c17;
  619. J(2, 4) = c19;
  620. J(2, 5) = -c10 * c2 + c13 * c2 + c8;
  621. J(3, 0) = o;
  622. J(3, 1) = o;
  623. J(3, 2) = o;
  624. J(3, 3) = -c20 * c21;
  625. J(3, 4) = -c21 * c22;
  626. J(3, 5) = -c21 * c23;
  627. J(4, 0) = c26 * c29 + Scalar(1);
  628. J(4, 1) = -c33 + c35;
  629. J(4, 2) = c36 + c37;
  630. J(4, 3) = upsilon[0] * (-c26 * c39 + c40 * c41) + upsilon[1] * (c53 + c57) +
  631. upsilon[2] * (c48 + c51);
  632. J(4, 4) = upsilon[0] * (-c26 * c59 + c40 * c60 + c58) +
  633. upsilon[1] * (c68 + c71) + upsilon[2] * (c62 + c64 - c66 + c67);
  634. J(4, 5) = upsilon[0] * (-c26 * c73 + c40 * c74 + c72) +
  635. upsilon[1] * (c75 - c76 + c77 + c78) + upsilon[2] * (c79 + c80);
  636. J(5, 0) = c33 + c35;
  637. J(5, 1) = c29 * c82 + Scalar(1);
  638. J(5, 2) = -c83 + c84;
  639. J(5, 3) = upsilon[0] * (c53 + c91) +
  640. upsilon[1] * (-c39 * c82 + c41 * c86 + c85) +
  641. upsilon[2] * (c75 - c87 + c88 + c90);
  642. J(5, 4) = upsilon[0] * (c68 + c79) + upsilon[1] * (-c59 * c82 + c60 * c86) +
  643. upsilon[2] * (c92 + c93);
  644. J(5, 5) = upsilon[0] * (c62 + c76 - c77 + c78) +
  645. upsilon[1] * (c72 - c73 * c82 + c74 * c86) +
  646. upsilon[2] * (c57 + c94);
  647. J(6, 0) = -c36 + c37;
  648. J(6, 1) = c83 + c84;
  649. J(6, 2) = c29 * c95 + Scalar(1);
  650. J(6, 3) = upsilon[0] * (c51 + c93) + upsilon[1] * (c62 + c87 - c88 + c90) +
  651. upsilon[2] * (-c39 * c95 + c41 * c96 + c85);
  652. J(6, 4) = upsilon[0] * (-c64 + c66 + c67 + c75) + upsilon[1] * (c48 + c92) +
  653. upsilon[2] * (c58 - c59 * c95 + c60 * c96);
  654. J(6, 5) = upsilon[0] * (c71 + c80) + upsilon[1] * (c91 + c94) +
  655. upsilon[2] * (-c73 * c95 + c74 * c96);
  656. return J;
  657. }
  658. /// Returns derivative of exp(x) wrt. x_i at x=0.
  659. ///
  660. SOPHUS_FUNC static Sophus::Matrix<Scalar, num_parameters, DoF>
  661. Dx_exp_x_at_0() {
  662. Sophus::Matrix<Scalar, num_parameters, DoF> J;
  663. Scalar const o(0);
  664. Scalar const h(0.5);
  665. Scalar const i(1);
  666. // clang-format off
  667. J << o, o, o, h, o, o, o,
  668. o, o, o, h, o, o, o,
  669. o, o, o, h, o, o, o,
  670. o, o, o, i, o, o, o,
  671. o, o, o, i, o, o, o,
  672. o, o, o, i, o, o, o;
  673. // clang-format on
  674. return J;
  675. }
  676. /// Returns derivative of exp(x).matrix() wrt. ``x_i at x=0``.
  677. ///
  678. SOPHUS_FUNC static Transformation Dxi_exp_x_matrix_at_0(int i) {
  679. return generator(i);
  680. }
  681. /// Group exponential
  682. ///
  683. /// This functions takes in an element of tangent space (= twist ``a``) and
  684. /// returns the corresponding element of the group SE(3).
  685. ///
  686. /// The first three components of ``a`` represent the translational part
  687. /// ``upsilon`` in the tangent space of SE(3), while the last three components
  688. /// of ``a`` represents the rotation vector ``omega``.
  689. /// To be more specific, this function computes ``expmat(hat(a))`` with
  690. /// ``expmat(.)`` being the matrix exponential and ``hat(.)`` the hat-operator
  691. /// of SE(3), see below.
  692. ///
  693. SOPHUS_FUNC static SE3<Scalar> exp(Tangent const& a) {
  694. using std::cos;
  695. using std::sin;
  696. Vector3<Scalar> const omega = a.template tail<3>();
  697. Scalar theta;
  698. SO3<Scalar> const so3 = SO3<Scalar>::expAndTheta(omega, &theta);
  699. Matrix3<Scalar> const Omega = SO3<Scalar>::hat(omega);
  700. Matrix3<Scalar> const Omega_sq = Omega * Omega;
  701. Matrix3<Scalar> V;
  702. if (theta < Constants<Scalar>::epsilon()) {
  703. V = so3.matrix();
  704. /// Note: That is an accurate expansion!
  705. } else {
  706. Scalar theta_sq = theta * theta;
  707. V = (Matrix3<Scalar>::Identity() +
  708. (Scalar(1) - cos(theta)) / (theta_sq)*Omega +
  709. (theta - sin(theta)) / (theta_sq * theta) * Omega_sq);
  710. }
  711. return SE3<Scalar>(so3, V * a.template head<3>());
  712. }
  713. /// Returns closest SE3 given arbirary 4x4 matrix.
  714. ///
  715. template <class S = Scalar>
  716. SOPHUS_FUNC static enable_if_t<std::is_floating_point<S>::value, SE3>
  717. fitToSE3(Matrix4<Scalar> const& T) {
  718. return SE3(SO3<Scalar>::fitToSO3(T.template block<3, 3>(0, 0)),
  719. T.template block<3, 1>(0, 3));
  720. }
  721. /// Returns the ith infinitesimal generators of SE(3).
  722. ///
  723. /// The infinitesimal generators of SE(3) are:
  724. ///
  725. /// ```
  726. /// | 0 0 0 1 |
  727. /// G_0 = | 0 0 0 0 |
  728. /// | 0 0 0 0 |
  729. /// | 0 0 0 0 |
  730. ///
  731. /// | 0 0 0 0 |
  732. /// G_1 = | 0 0 0 1 |
  733. /// | 0 0 0 0 |
  734. /// | 0 0 0 0 |
  735. ///
  736. /// | 0 0 0 0 |
  737. /// G_2 = | 0 0 0 0 |
  738. /// | 0 0 0 1 |
  739. /// | 0 0 0 0 |
  740. ///
  741. /// | 0 0 0 0 |
  742. /// G_3 = | 0 0 -1 0 |
  743. /// | 0 1 0 0 |
  744. /// | 0 0 0 0 |
  745. ///
  746. /// | 0 0 1 0 |
  747. /// G_4 = | 0 0 0 0 |
  748. /// | -1 0 0 0 |
  749. /// | 0 0 0 0 |
  750. ///
  751. /// | 0 -1 0 0 |
  752. /// G_5 = | 1 0 0 0 |
  753. /// | 0 0 0 0 |
  754. /// | 0 0 0 0 |
  755. /// ```
  756. ///
  757. /// Precondition: ``i`` must be in [0, 5].
  758. ///
  759. SOPHUS_FUNC static Transformation generator(int i) {
  760. SOPHUS_ENSURE(i >= 0 && i <= 5, "i should be in range [0,5].");
  761. Tangent e;
  762. e.setZero();
  763. e[i] = Scalar(1);
  764. return hat(e);
  765. }
  766. /// hat-operator
  767. ///
  768. /// It takes in the 6-vector representation (= twist) and returns the
  769. /// corresponding matrix representation of Lie algebra element.
  770. ///
  771. /// Formally, the hat()-operator of SE(3) is defined as
  772. ///
  773. /// ``hat(.): R^6 -> R^{4x4}, hat(a) = sum_i a_i * G_i`` (for i=0,...,5)
  774. ///
  775. /// with ``G_i`` being the ith infinitesimal generator of SE(3).
  776. ///
  777. /// The corresponding inverse is the vee()-operator, see below.
  778. ///
  779. SOPHUS_FUNC static Transformation hat(Tangent const& a) {
  780. Transformation Omega;
  781. Omega.setZero();
  782. Omega.template topLeftCorner<3, 3>() =
  783. SO3<Scalar>::hat(a.template tail<3>());
  784. Omega.col(3).template head<3>() = a.template head<3>();
  785. return Omega;
  786. }
  787. /// Lie bracket
  788. ///
  789. /// It computes the Lie bracket of SE(3). To be more specific, it computes
  790. ///
  791. /// ``[omega_1, omega_2]_se3 := vee([hat(omega_1), hat(omega_2)])``
  792. ///
  793. /// with ``[A,B] := AB-BA`` being the matrix commutator, ``hat(.)`` the
  794. /// hat()-operator and ``vee(.)`` the vee()-operator of SE(3).
  795. ///
  796. SOPHUS_FUNC static Tangent lieBracket(Tangent const& a, Tangent const& b) {
  797. Vector3<Scalar> const upsilon1 = a.template head<3>();
  798. Vector3<Scalar> const upsilon2 = b.template head<3>();
  799. Vector3<Scalar> const omega1 = a.template tail<3>();
  800. Vector3<Scalar> const omega2 = b.template tail<3>();
  801. Tangent res;
  802. res.template head<3>() = omega1.cross(upsilon2) + upsilon1.cross(omega2);
  803. res.template tail<3>() = omega1.cross(omega2);
  804. return res;
  805. }
  806. /// Construct x-axis rotation.
  807. ///
  808. static SOPHUS_FUNC SE3 rotX(Scalar const& x) {
  809. return SE3(SO3<Scalar>::rotX(x), Sophus::Vector3<Scalar>::Zero());
  810. }
  811. /// Construct y-axis rotation.
  812. ///
  813. static SOPHUS_FUNC SE3 rotY(Scalar const& y) {
  814. return SE3(SO3<Scalar>::rotY(y), Sophus::Vector3<Scalar>::Zero());
  815. }
  816. /// Construct z-axis rotation.
  817. ///
  818. static SOPHUS_FUNC SE3 rotZ(Scalar const& z) {
  819. return SE3(SO3<Scalar>::rotZ(z), Sophus::Vector3<Scalar>::Zero());
  820. }
  821. /// Draw uniform sample from SE(3) manifold.
  822. ///
  823. /// Translations are drawn component-wise from the range [-1, 1].
  824. ///
  825. template <class UniformRandomBitGenerator>
  826. static SE3 sampleUniform(UniformRandomBitGenerator& generator) {
  827. std::uniform_real_distribution<Scalar> uniform(Scalar(-1), Scalar(1));
  828. return SE3(SO3<Scalar>::sampleUniform(generator),
  829. Vector3<Scalar>(uniform(generator), uniform(generator),
  830. uniform(generator)));
  831. }
  832. /// Construct a translation only SE3 instance.
  833. ///
  834. template <class T0, class T1, class T2>
  835. static SOPHUS_FUNC SE3 trans(T0 const& x, T1 const& y, T2 const& z) {
  836. return SE3(SO3<Scalar>(), Vector3<Scalar>(x, y, z));
  837. }
  838. static SOPHUS_FUNC SE3 trans(Vector3<Scalar> const& xyz) {
  839. return SE3(SO3<Scalar>(), xyz);
  840. }
  841. /// Construct x-axis translation.
  842. ///
  843. static SOPHUS_FUNC SE3 transX(Scalar const& x) {
  844. return SE3::trans(x, Scalar(0), Scalar(0));
  845. }
  846. /// Construct y-axis translation.
  847. ///
  848. static SOPHUS_FUNC SE3 transY(Scalar const& y) {
  849. return SE3::trans(Scalar(0), y, Scalar(0));
  850. }
  851. /// Construct z-axis translation.
  852. ///
  853. static SOPHUS_FUNC SE3 transZ(Scalar const& z) {
  854. return SE3::trans(Scalar(0), Scalar(0), z);
  855. }
  856. /// vee-operator
  857. ///
  858. /// It takes 4x4-matrix representation ``Omega`` and maps it to the
  859. /// corresponding 6-vector representation of Lie algebra.
  860. ///
  861. /// This is the inverse of the hat()-operator, see above.
  862. ///
  863. /// Precondition: ``Omega`` must have the following structure:
  864. ///
  865. /// | 0 -f e a |
  866. /// | f 0 -d b |
  867. /// | -e d 0 c
  868. /// | 0 0 0 0 | .
  869. ///
  870. SOPHUS_FUNC static Tangent vee(Transformation const& Omega) {
  871. Tangent upsilon_omega;
  872. upsilon_omega.template head<3>() = Omega.col(3).template head<3>();
  873. upsilon_omega.template tail<3>() =
  874. SO3<Scalar>::vee(Omega.template topLeftCorner<3, 3>());
  875. return upsilon_omega;
  876. }
  877. protected:
  878. SO3Member so3_;
  879. TranslationMember translation_;
  880. };
  881. template <class Scalar, int Options>
  882. SE3<Scalar, Options>::SE3() : translation_(TranslationMember::Zero()) {
  883. static_assert(std::is_standard_layout<SE3>::value,
  884. "Assume standard layout for the use of offsetof check below.");
  885. static_assert(
  886. offsetof(SE3, so3_) + sizeof(Scalar) * SO3<Scalar>::num_parameters ==
  887. offsetof(SE3, translation_),
  888. "This class assumes packed storage and hence will only work "
  889. "correctly depending on the compiler (options) - in "
  890. "particular when using [this->data(), this-data() + "
  891. "num_parameters] to access the raw data in a contiguous fashion.");
  892. }
  893. } // namespace Sophus
  894. namespace Eigen {
  895. /// Specialization of Eigen::Map for ``SE3``; derived from SE3Base.
  896. ///
  897. /// Allows us to wrap SE3 objects around POD array.
  898. template <class Scalar_, int Options>
  899. class Map<Sophus::SE3<Scalar_>, Options>
  900. : public Sophus::SE3Base<Map<Sophus::SE3<Scalar_>, Options>> {
  901. public:
  902. using Base = Sophus::SE3Base<Map<Sophus::SE3<Scalar_>, Options>>;
  903. using Scalar = Scalar_;
  904. using Transformation = typename Base::Transformation;
  905. using Point = typename Base::Point;
  906. using HomogeneousPoint = typename Base::HomogeneousPoint;
  907. using Tangent = typename Base::Tangent;
  908. using Adjoint = typename Base::Adjoint;
  909. // LCOV_EXCL_START
  910. SOPHUS_INHERIT_ASSIGNMENT_OPERATORS(Map);
  911. // LCOV_EXCL_STOP
  912. using Base::operator*=;
  913. using Base::operator*;
  914. SOPHUS_FUNC Map(Scalar* coeffs)
  915. : so3_(coeffs),
  916. translation_(coeffs + Sophus::SO3<Scalar>::num_parameters) {}
  917. /// Mutator of SO3
  918. ///
  919. SOPHUS_FUNC Map<Sophus::SO3<Scalar>, Options>& so3() { return so3_; }
  920. /// Accessor of SO3
  921. ///
  922. SOPHUS_FUNC Map<Sophus::SO3<Scalar>, Options> const& so3() const {
  923. return so3_;
  924. }
  925. /// Mutator of translation vector
  926. ///
  927. SOPHUS_FUNC Map<Sophus::Vector3<Scalar, Options>>& translation() {
  928. return translation_;
  929. }
  930. /// Accessor of translation vector
  931. ///
  932. SOPHUS_FUNC Map<Sophus::Vector3<Scalar, Options>> const& translation() const {
  933. return translation_;
  934. }
  935. protected:
  936. Map<Sophus::SO3<Scalar>, Options> so3_;
  937. Map<Sophus::Vector3<Scalar>, Options> translation_;
  938. };
  939. /// Specialization of Eigen::Map for ``SE3 const``; derived from SE3Base.
  940. ///
  941. /// Allows us to wrap SE3 objects around POD array.
  942. template <class Scalar_, int Options>
  943. class Map<Sophus::SE3<Scalar_> const, Options>
  944. : public Sophus::SE3Base<Map<Sophus::SE3<Scalar_> const, Options>> {
  945. public:
  946. using Base = Sophus::SE3Base<Map<Sophus::SE3<Scalar_> const, Options>>;
  947. using Scalar = Scalar_;
  948. using Transformation = typename Base::Transformation;
  949. using Point = typename Base::Point;
  950. using HomogeneousPoint = typename Base::HomogeneousPoint;
  951. using Tangent = typename Base::Tangent;
  952. using Adjoint = typename Base::Adjoint;
  953. using Base::operator*=;
  954. using Base::operator*;
  955. SOPHUS_FUNC Map(Scalar const* coeffs)
  956. : so3_(coeffs),
  957. translation_(coeffs + Sophus::SO3<Scalar>::num_parameters) {}
  958. /// Accessor of SO3
  959. ///
  960. SOPHUS_FUNC Map<Sophus::SO3<Scalar> const, Options> const& so3() const {
  961. return so3_;
  962. }
  963. /// Accessor of translation vector
  964. ///
  965. SOPHUS_FUNC Map<Sophus::Vector3<Scalar> const, Options> const& translation()
  966. const {
  967. return translation_;
  968. }
  969. protected:
  970. Map<Sophus::SO3<Scalar> const, Options> const so3_;
  971. Map<Sophus::Vector3<Scalar> const, Options> const translation_;
  972. };
  973. } // namespace Eigen
  974. #endif