Some reformatting, doxygen niceties...
parent
3d3d574325
commit
a34dae558a
|
@ -18,87 +18,90 @@
|
||||||
#include <gtsam/base/concepts.h>
|
#include <gtsam/base/concepts.h>
|
||||||
#include <gtsam/base/Matrix.h>
|
#include <gtsam/base/Matrix.h>
|
||||||
|
|
||||||
#define QUATERNION_TEMPLATE typename _Scalar, int _Options
|
|
||||||
#define QUATERNION_TYPE Eigen::Quaternion<_Scalar,_Options>
|
#define QUATERNION_TYPE Eigen::Quaternion<_Scalar,_Options>
|
||||||
|
|
||||||
namespace gtsam {
|
namespace gtsam {
|
||||||
|
|
||||||
// Define group traits
|
// Define traits
|
||||||
template<QUATERNION_TEMPLATE>
|
template<typename _Scalar, int _Options>
|
||||||
struct traits_x<QUATERNION_TYPE> {
|
struct traits_x<QUATERNION_TYPE> {
|
||||||
typedef QUATERNION_TYPE ManifoldType;
|
typedef QUATERNION_TYPE ManifoldType;
|
||||||
typedef QUATERNION_TYPE Q;
|
typedef QUATERNION_TYPE Q;
|
||||||
|
|
||||||
typedef lie_group_tag structure_category;
|
typedef lie_group_tag structure_category;
|
||||||
typedef multiplicative_group_tag group_flavor;
|
typedef multiplicative_group_tag group_flavor;
|
||||||
|
|
||||||
enum { dimension = 3 };
|
/// @name Basic Manifold traits
|
||||||
|
/// @{
|
||||||
static Q Identity() { return Q::Identity(); }
|
enum {
|
||||||
|
dimension = 3
|
||||||
// Define manifold traits
|
};
|
||||||
typedef Eigen::Matrix<_Scalar, 3, 1, _Options, 3, 1> TangentVector;
|
|
||||||
typedef OptionalJacobian<3, 3> ChartJacobian;
|
typedef OptionalJacobian<3, 3> ChartJacobian;
|
||||||
|
typedef Eigen::Matrix<_Scalar, 3, 1, _Options, 3, 1> TangentVector;
|
||||||
|
|
||||||
static Q Compose(const Q &g, const Q & h, ChartJacobian Hg=boost::none, ChartJacobian Hh=boost::none) {
|
/// @}
|
||||||
if (Hg) {
|
/// @name Lie group traits
|
||||||
//TODO : check Jacobian consistent with chart ( h.toRotationMatrix().transpose() ? )
|
/// @{
|
||||||
*Hg = h.toRotationMatrix().transpose();
|
static Q Identity() {
|
||||||
}
|
return Q::Identity();
|
||||||
if (Hh) {
|
}
|
||||||
//TODO : check Jacobian consistent with chart ( I(3)? )
|
|
||||||
*Hh = I_3x3;
|
static Q Compose(const Q &g, const Q & h, ChartJacobian Hg = boost::none,
|
||||||
}
|
ChartJacobian Hh = boost::none) {
|
||||||
|
if (Hg)
|
||||||
|
*Hg = h.toRotationMatrix().transpose(); // TODO : check Jacobian consistent with chart ( h.toRotationMatrix().transpose() ? )
|
||||||
|
if (Hh)
|
||||||
|
*Hh = I_3x3; // TODO : check Jacobian consistent with chart ( I(3)? )
|
||||||
return g * h;
|
return g * h;
|
||||||
}
|
}
|
||||||
static Q Between(const Q &g, const Q & h, ChartJacobian Hg=boost::none, ChartJacobian Hh=boost::none) {
|
|
||||||
|
static Q Between(const Q &g, const Q & h, ChartJacobian Hg = boost::none,
|
||||||
|
ChartJacobian Hh = boost::none) {
|
||||||
Q d = g.inverse() * h;
|
Q d = g.inverse() * h;
|
||||||
if (Hg) {
|
if (Hg)
|
||||||
//TODO : check Jacobian consistent with chart
|
*Hg = -d.toRotationMatrix().transpose(); // TODO : check Jacobian consistent with chart
|
||||||
*Hg = -d.toRotationMatrix().transpose();
|
if (Hh)
|
||||||
}
|
*Hh = I_3x3; // TODO : check Jacobian consistent with chart (my guess I(3) )
|
||||||
if (Hh) {
|
return d;
|
||||||
//TODO : check Jacobian consistent with chart (my guess I(3) )
|
|
||||||
*Hh = I_3x3;
|
|
||||||
}
|
|
||||||
return d;
|
|
||||||
}
|
}
|
||||||
static Q Inverse(const Q &g, ChartJacobian H=boost::none) {
|
|
||||||
if (H) {
|
static Q Inverse(const Q &g, ChartJacobian H = boost::none) {
|
||||||
//TODO : check Jacobian consistent with chart
|
if (H)
|
||||||
*H = -g.toRotationMatrix();
|
*H = -g.toRotationMatrix(); // TODO : check Jacobian consistent with chart
|
||||||
}
|
return g.inverse();
|
||||||
return g.inverse();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Exponential map, simply be converting omega to axis/angle representation
|
/// Exponential map, simply be converting omega to axis/angle representation
|
||||||
// TODO: implement Jacobian
|
static Q Expmap(const Eigen::Ref<const TangentVector>& omega,
|
||||||
static Q Expmap(const Eigen::Ref<const TangentVector >& omega, ChartJacobian H=boost::none) {
|
ChartJacobian H = boost::none) {
|
||||||
if (omega.isZero())
|
if (omega.isZero())
|
||||||
return Q::Identity();
|
return Q::Identity();
|
||||||
else {
|
else {
|
||||||
_Scalar angle = omega.norm();
|
_Scalar angle = omega.norm();
|
||||||
return Q(Eigen::AngleAxis<_Scalar>(angle, omega / angle));
|
return Q(Eigen::AngleAxis<_Scalar>(angle, omega / angle));
|
||||||
}
|
}
|
||||||
|
if (H)
|
||||||
|
throw std::runtime_error("TODO: implement Jacobian");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We use our own Logmap, as there is a slight bug in Eigen
|
/// We use our own Logmap, as there is a slight bug in Eigen
|
||||||
// TODO: implement Jacobian
|
static TangentVector Logmap(const Q& q, ChartJacobian H = boost::none) {
|
||||||
static TangentVector Logmap(const Q& q, ChartJacobian H=boost::none) {
|
|
||||||
using std::acos;
|
using std::acos;
|
||||||
using std::sqrt;
|
using std::sqrt;
|
||||||
static const double twoPi = 2.0 * M_PI,
|
|
||||||
// define these compile time constants to avoid std::abs:
|
// define these compile time constants to avoid std::abs:
|
||||||
NearlyOne = 1.0 - 1e-10, NearlyNegativeOne = -1.0 + 1e-10;
|
static const double twoPi = 2.0 * M_PI, NearlyOne = 1.0 - 1e-10,
|
||||||
|
NearlyNegativeOne = -1.0 + 1e-10;
|
||||||
|
|
||||||
const double qw = q.w();
|
const double qw = q.w();
|
||||||
if (qw > NearlyOne) {
|
if (qw > NearlyOne) {
|
||||||
// Taylor expansion of (angle / s) at 1
|
// Taylor expansion of (angle / s) at 1
|
||||||
//return (2 + 2 * (1-qw) / 3) * q.vec();
|
//return (2 + 2 * (1-qw) / 3) * q.vec();
|
||||||
return (8./3. - 2./3. * qw) * q.vec();
|
return (8. / 3. - 2. / 3. * qw) * q.vec();
|
||||||
} else if (qw < NearlyNegativeOne) {
|
} else if (qw < NearlyNegativeOne) {
|
||||||
// Taylor expansion of (angle / s) at -1
|
// Taylor expansion of (angle / s) at -1
|
||||||
//return (-2 - 2 * (1 + qw) / 3) * q.vec();
|
//return (-2 - 2 * (1 + qw) / 3) * q.vec();
|
||||||
return (-8./3 + 2./3 * qw) * q.vec();
|
return (-8. / 3 + 2. / 3 * qw) * q.vec();
|
||||||
} else {
|
} else {
|
||||||
// Normal, away from zero case
|
// Normal, away from zero case
|
||||||
double angle = 2 * acos(qw), s = sqrt(1 - qw * qw);
|
double angle = 2 * acos(qw), s = sqrt(1 - qw * qw);
|
||||||
|
@ -109,29 +112,39 @@ struct traits_x<QUATERNION_TYPE> {
|
||||||
angle += twoPi;
|
angle += twoPi;
|
||||||
return (angle / s) * q.vec();
|
return (angle / s) * q.vec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (H)
|
||||||
|
throw std::runtime_error("TODO: implement Jacobian");
|
||||||
}
|
}
|
||||||
|
|
||||||
static TangentVector Local(const Q& origin, const Q& other, ChartJacobian Horigin = boost::none, ChartJacobian Hother = boost::none) {
|
/// @}
|
||||||
return Logmap(Between(origin,other,Horigin,Hother));
|
/// @name Manifold traits
|
||||||
|
/// @{
|
||||||
|
static TangentVector Local(const Q& origin, const Q& other,
|
||||||
|
ChartJacobian Horigin = boost::none, ChartJacobian Hother = boost::none) {
|
||||||
|
return Logmap(Between(origin, other, Horigin, Hother));
|
||||||
// TODO: incorporate Jacobian of Logmap
|
// TODO: incorporate Jacobian of Logmap
|
||||||
}
|
}
|
||||||
static Q Retract(const Q& origin, const TangentVector& v, ChartJacobian Horigin = boost::none, ChartJacobian Hv = boost::none) {
|
static Q Retract(const Q& origin, const TangentVector& v,
|
||||||
|
ChartJacobian Horigin = boost::none, ChartJacobian Hv = boost::none) {
|
||||||
return Compose(origin, Expmap(v), Horigin, Hv);
|
return Compose(origin, Expmap(v), Horigin, Hv);
|
||||||
// TODO : incorporate Jacobian of Expmap
|
// TODO : incorporate Jacobian of Expmap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
/// @name Testable
|
||||||
|
/// @{
|
||||||
static void Print(const Q& q, const std::string& str = "") {
|
static void Print(const Q& q, const std::string& str = "") {
|
||||||
if(str.size() == 0) {
|
if (str.size() == 0)
|
||||||
std::cout << "Eigen::Quaternion: ";
|
std::cout << "Eigen::Quaternion: ";
|
||||||
} else {
|
else
|
||||||
std::cout << str << " ";
|
std::cout << str << " ";
|
||||||
}
|
|
||||||
std::cout << q.vec().transpose() << std::endl;
|
std::cout << q.vec().transpose() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Equals(const Q& q1, const Q& q2, double tol = 1e-8) {
|
static bool Equals(const Q& q1, const Q& q2, double tol = 1e-8) {
|
||||||
return Between(q1,q2).vec().array().abs().maxCoeff() < tol;
|
return Between(q1, q2).vec().array().abs().maxCoeff() < tol;
|
||||||
}
|
}
|
||||||
|
/// @}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Eigen::Quaternion<double, Eigen::DontAlign> Quaternion;
|
typedef Eigen::Quaternion<double, Eigen::DontAlign> Quaternion;
|
||||||
|
|
Loading…
Reference in New Issue