Three more constructors for SO3
parent
dea6b995e5
commit
3193af9698
|
@ -104,9 +104,9 @@ Matrix43 stiefel(const SO4& Q, OptionalJacobian<12, 6> H = boost::none);
|
|||
*/
|
||||
|
||||
template <>
|
||||
struct traits<SO4> : Testable<SO4>, internal::LieGroupTraits<SO4> {};
|
||||
struct traits<SO4> : public internal::LieGroup<SO4> {};
|
||||
|
||||
template <>
|
||||
struct traits<const SO4> : Testable<SO4>, internal::LieGroupTraits<SO4> {};
|
||||
struct traits<const SO4> : public internal::LieGroup<SO4> {};
|
||||
|
||||
} // end namespace gtsam
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace gtsam {
|
||||
|
||||
|
@ -91,6 +92,17 @@ class SO : public LieGroup<SO<N>, internal::DimensionSO(N)> {
|
|||
template <int N_ = N, typename = IsSO3<N_>>
|
||||
SO(const Eigen::AngleAxisd& angleAxis) : matrix_(angleAxis) {}
|
||||
|
||||
/// Constructor from axis and angle. Only defined for SO3
|
||||
static SO AxisAngle(const Vector3& axis, double theta);
|
||||
|
||||
/// Named constructor that finds SO(n) matrix closest to M in Frobenius norm,
|
||||
/// currently only defined for SO3.
|
||||
static SO ClosestTo(const MatrixNN& M);
|
||||
|
||||
/// Named constructor that finds chordal mean = argmin_R \sum sqr(|R-R_i|_F),
|
||||
/// currently only defined for SO3.
|
||||
static SO ChordalMean(const std::vector<SO>& rotations);
|
||||
|
||||
/// Random SO(n) element (no big claims about uniformity)
|
||||
template <int N_ = N, typename = IsDynamic<N_>>
|
||||
static SO Random(boost::mt19937& rng, size_t n = 0) {
|
||||
|
|
|
@ -134,29 +134,33 @@ Vector3 DexpFunctor::applyInvDexp(const Vector3& v, OptionalJacobian<3, 3> H1,
|
|||
} // namespace sot
|
||||
|
||||
//******************************************************************************
|
||||
// SO3 SO3::AxisAngle(const Vector3& axis, double theta) {
|
||||
// return sot::ExpmapFunctor(axis, theta).expmap();
|
||||
// }
|
||||
template <>
|
||||
SO3 SO3::AxisAngle(const Vector3& axis, double theta) {
|
||||
return sot::ExpmapFunctor(axis, theta).expmap();
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// SO3 SO3::ClosestTo(const Matrix3& M) {
|
||||
// Eigen::JacobiSVD<Matrix3> svd(M, Eigen::ComputeFullU |
|
||||
// Eigen::ComputeFullV); const auto& U = svd.matrixU(); const auto& V =
|
||||
// svd.matrixV(); const double det = (U * V.transpose()).determinant(); return
|
||||
// U * Vector3(1, 1, det).asDiagonal() * V.transpose();
|
||||
// }
|
||||
template <>
|
||||
SO3 SO3::ClosestTo(const Matrix3& M) {
|
||||
Eigen::JacobiSVD<Matrix3> svd(M, Eigen::ComputeFullU | Eigen::ComputeFullV);
|
||||
const auto& U = svd.matrixU();
|
||||
const auto& V = svd.matrixV();
|
||||
const double det = (U * V.transpose()).determinant();
|
||||
return SO3(U * Vector3(1, 1, det).asDiagonal() * V.transpose());
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// SO3 SO3::ChordalMean(const std::vector<SO3>& rotations) {
|
||||
// // See Hartley13ijcv:
|
||||
// // Cost function C(R) = \sum sqr(|R-R_i|_F)
|
||||
// // Closed form solution = ClosestTo(C_e), where C_e = \sum R_i !!!!
|
||||
// Matrix3 C_e{Z_3x3};
|
||||
// for (const auto& R_i : rotations) {
|
||||
// C_e += R_i;
|
||||
// }
|
||||
// return ClosestTo(C_e);
|
||||
// }
|
||||
template <>
|
||||
SO3 SO3::ChordalMean(const std::vector<SO3>& rotations) {
|
||||
// See Hartley13ijcv:
|
||||
// Cost function C(R) = \sum sqr(|R-R_i|_F)
|
||||
// Closed form solution = ClosestTo(C_e), where C_e = \sum R_i !!!!
|
||||
Matrix3 C_e{Z_3x3};
|
||||
for (const auto& R_i : rotations) {
|
||||
C_e += R_i.matrix();
|
||||
}
|
||||
return ClosestTo(C_e);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
template <>
|
||||
|
|
|
@ -33,15 +33,18 @@ namespace gtsam {
|
|||
|
||||
using SO3 = SO<3>;
|
||||
|
||||
// /// 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);
|
||||
|
||||
// Below are all declarations of SO<3> specializations.
|
||||
// They are *defined* in SO3.cpp.
|
||||
|
||||
template <>
|
||||
SO3 SO3::AxisAngle(const Vector3& axis, double theta);
|
||||
|
||||
template <>
|
||||
SO3 SO3::ClosestTo(const Matrix3& M);
|
||||
|
||||
template <>
|
||||
SO3 SO3::ChordalMean(const std::vector<SO3>& rotations);
|
||||
|
||||
template <>
|
||||
Matrix3 SO3::Hat(const Vector3& xi); ///< make skew symmetric matrix
|
||||
|
||||
|
|
|
@ -40,7 +40,30 @@ TEST(SO3, Concept) {
|
|||
}
|
||||
|
||||
//******************************************************************************
|
||||
TEST(SO3, Constructor) { SO3 q(Eigen::AngleAxisd(1, Vector3(0, 0, 1))); }
|
||||
TEST(SO3, Constructors) {
|
||||
const Vector3 axis(0, 0, 1);
|
||||
const double angle = 2.5;
|
||||
SO3 Q(Eigen::AngleAxisd(angle, axis));
|
||||
SO3 R = SO3::AxisAngle(axis, angle);
|
||||
EXPECT(assert_equal(Q, R));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(SO3, ClosestTo) {
|
||||
// Example top-left of SO(4) matrix not quite on SO(3) manifold
|
||||
Matrix3 M;
|
||||
M << 0.79067393, 0.6051136, -0.0930814, //
|
||||
0.4155925, -0.64214347, -0.64324489, //
|
||||
-0.44948549, 0.47046326, -0.75917576;
|
||||
|
||||
Matrix expected(3, 3);
|
||||
expected << 0.790687, 0.605096, -0.0931312, //
|
||||
0.415746, -0.642355, -0.643844, //
|
||||
-0.449411, 0.47036, -0.759468;
|
||||
|
||||
auto actual = SO3::ClosestTo(3 * M);
|
||||
EXPECT(assert_equal(expected, actual.matrix(), 1e-6));
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
SO3 id;
|
||||
|
@ -48,6 +71,12 @@ Vector3 z_axis(0, 0, 1), v2(1, 2, 0), v3(1, 2, 3);
|
|||
SO3 R1(Eigen::AngleAxisd(0.1, z_axis));
|
||||
SO3 R2(Eigen::AngleAxisd(0.2, z_axis));
|
||||
|
||||
/* ************************************************************************* */
|
||||
TEST(SO3, ChordalMean) {
|
||||
std::vector<SO3> rotations = {R1, R1.inverse()};
|
||||
EXPECT(assert_equal(SO3(), SO3::ChordalMean(rotations)));
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
TEST(SO3, Hat) {
|
||||
// Check that Hat specialization is equal to dynamic version
|
||||
|
|
Loading…
Reference in New Issue