2010-10-14 12:54:38 +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
|
|
|
|
|
|
|
|
|
|
* -------------------------------------------------------------------------- */
|
|
|
|
|
|
2011-09-07 13:02:36 +08:00
|
|
|
/**
|
|
|
|
|
* @file Rot2.h
|
|
|
|
|
* @brief 2D rotation
|
|
|
|
|
* @date Dec 9, 2009
|
|
|
|
|
* @author Frank Dellaert
|
2009-12-10 05:50:27 +08:00
|
|
|
*/
|
|
|
|
|
|
2011-06-14 00:55:31 +08:00
|
|
|
#pragma once
|
2009-12-10 05:50:27 +08:00
|
|
|
|
2010-08-20 01:23:19 +08:00
|
|
|
#include <gtsam/geometry/Point2.h>
|
2014-12-22 07:12:08 +08:00
|
|
|
#include <gtsam/base/Lie.h>
|
|
|
|
|
#include <boost/optional.hpp>
|
2009-12-10 05:50:27 +08:00
|
|
|
|
|
|
|
|
namespace gtsam {
|
|
|
|
|
|
2012-10-02 22:40:07 +08:00
|
|
|
/**
|
|
|
|
|
* Rotation matrix
|
|
|
|
|
* NOTE: the angle theta is in radians unless explicitly stated
|
|
|
|
|
* @addtogroup geometry
|
|
|
|
|
* \nosubgrouping
|
|
|
|
|
*/
|
2014-10-25 00:34:06 +08:00
|
|
|
class GTSAM_EXPORT Rot2 {
|
Rot2 "named constructors" (http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.8):
/** Named constructor from angle == exponential map at identity */
static Rot2 fromAngle(double theta) { return Rot2(cos(theta),sin(theta));}
/** Named constructor from cos(theta),sin(theta) pair, will *not* normalize! */
static Rot2 fromCosSin(double c, double s);
/** Named constructor that behaves as atan2, i.e., y,x order (!) and normalizes */
static Rot2 atan2(double y, double x);
which are a bit more verbose, but at least won't cause hours of bug-tracking :-(
I also made most compose, inverse, and rotate functions into methods, with the global functions mostly calling the methods. Methods have privileged access to members and hence are typically much more readable.
2010-03-03 11:31:53 +08:00
|
|
|
|
2012-10-02 22:40:07 +08:00
|
|
|
public:
|
|
|
|
|
/** get the dimension by the type */
|
|
|
|
|
static const size_t dimension = 1;
|
2010-08-20 04:03:06 +08:00
|
|
|
|
2012-10-02 22:40:07 +08:00
|
|
|
private:
|
Rot2 "named constructors" (http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.8):
/** Named constructor from angle == exponential map at identity */
static Rot2 fromAngle(double theta) { return Rot2(cos(theta),sin(theta));}
/** Named constructor from cos(theta),sin(theta) pair, will *not* normalize! */
static Rot2 fromCosSin(double c, double s);
/** Named constructor that behaves as atan2, i.e., y,x order (!) and normalizes */
static Rot2 atan2(double y, double x);
which are a bit more verbose, but at least won't cause hours of bug-tracking :-(
I also made most compose, inverse, and rotate functions into methods, with the global functions mostly calling the methods. Methods have privileged access to members and hence are typically much more readable.
2010-03-03 11:31:53 +08:00
|
|
|
|
2012-10-02 22:40:07 +08:00
|
|
|
/** we store cos(theta) and sin(theta) */
|
|
|
|
|
double c_, s_;
|
2009-12-15 08:00:02 +08:00
|
|
|
|
2012-01-10 02:52:39 +08:00
|
|
|
|
2012-10-02 22:40:07 +08:00
|
|
|
/** normalize to make sure cos and sin form unit vector */
|
|
|
|
|
Rot2& normalize();
|
2012-01-10 02:52:39 +08:00
|
|
|
|
2012-10-02 22:40:07 +08:00
|
|
|
/** private constructor from cos/sin */
|
|
|
|
|
inline Rot2(double c, double s) :
|
|
|
|
|
c_(c), s_(s) {
|
|
|
|
|
}
|
2010-01-08 08:40:17 +08:00
|
|
|
|
2012-10-02 22:40:07 +08:00
|
|
|
public:
|
Rot2 "named constructors" (http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.8):
/** Named constructor from angle == exponential map at identity */
static Rot2 fromAngle(double theta) { return Rot2(cos(theta),sin(theta));}
/** Named constructor from cos(theta),sin(theta) pair, will *not* normalize! */
static Rot2 fromCosSin(double c, double s);
/** Named constructor that behaves as atan2, i.e., y,x order (!) and normalizes */
static Rot2 atan2(double y, double x);
which are a bit more verbose, but at least won't cause hours of bug-tracking :-(
I also made most compose, inverse, and rotate functions into methods, with the global functions mostly calling the methods. Methods have privileged access to members and hence are typically much more readable.
2010-03-03 11:31:53 +08:00
|
|
|
|
2012-01-24 13:03:56 +08:00
|
|
|
/// @name Constructors and named constructors
|
|
|
|
|
/// @{
|
|
|
|
|
|
2012-10-02 22:40:07 +08:00
|
|
|
/** default constructor, zero rotation */
|
|
|
|
|
Rot2() :
|
|
|
|
|
c_(1.0), s_(0.0) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Constructor from angle in radians == exponential map at identity
|
|
|
|
|
Rot2(double theta) :
|
|
|
|
|
c_(cos(theta)), s_(sin(theta)) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Named constructor from angle in radians
|
|
|
|
|
static Rot2 fromAngle(double theta) {
|
|
|
|
|
return Rot2(theta);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Named constructor from angle in degrees
|
|
|
|
|
static Rot2 fromDegrees(double theta) {
|
|
|
|
|
const double degree = M_PI / 180;
|
|
|
|
|
return fromAngle(theta * degree);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Named constructor from cos(theta),sin(theta) pair, will *not* normalize!
|
|
|
|
|
static Rot2 fromCosSin(double c, double s);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Named constructor with derivative
|
|
|
|
|
* Calculate relative bearing to a landmark in local coordinate frame
|
|
|
|
|
* @param d 2D location of landmark
|
|
|
|
|
* @param H optional reference for Jacobian
|
|
|
|
|
* @return 2D rotation \f$ \in SO(2) \f$
|
|
|
|
|
*/
|
2014-12-01 00:59:32 +08:00
|
|
|
static Rot2 relativeBearing(const Point2& d, OptionalJacobian<1,2> H =
|
2012-10-02 22:40:07 +08:00
|
|
|
boost::none);
|
|
|
|
|
|
|
|
|
|
/** Named constructor that behaves as atan2, i.e., y,x order (!) and normalizes */
|
|
|
|
|
static Rot2 atan2(double y, double x);
|
|
|
|
|
|
|
|
|
|
/// @}
|
2011-11-26 12:46:22 +08:00
|
|
|
/// @name Testable
|
|
|
|
|
/// @{
|
|
|
|
|
|
2012-10-02 22:40:07 +08:00
|
|
|
/** print */
|
|
|
|
|
void print(const std::string& s = "theta") const;
|
|
|
|
|
|
|
|
|
|
/** equals with an tolerance */
|
|
|
|
|
bool equals(const Rot2& R, double tol = 1e-9) const;
|
|
|
|
|
|
|
|
|
|
/// @}
|
|
|
|
|
/// @name Group
|
|
|
|
|
/// @{
|
|
|
|
|
|
|
|
|
|
/** identity */
|
|
|
|
|
inline static Rot2 identity() { return Rot2(); }
|
|
|
|
|
|
|
|
|
|
/** The inverse rotation - negative angle */
|
2014-12-18 05:53:56 +08:00
|
|
|
Rot2 inverse(OptionalJacobian<1,1> H = boost::none) const {
|
|
|
|
|
if (H) *H = -I_1x1;
|
2012-10-02 22:40:07 +08:00
|
|
|
return Rot2(c_, -s_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Compose - make a new rotation by adding angles */
|
2014-12-23 06:42:52 +08:00
|
|
|
Rot2 operator*(const Rot2& R) const {
|
2013-06-06 07:40:05 +08:00
|
|
|
return fromCosSin(c_ * R.c_ - s_ * R.s_, s_ * R.c_ + c_ * R.s_);
|
2012-10-02 22:40:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Compose - make a new rotation by adding angles */
|
2014-12-23 06:42:52 +08:00
|
|
|
Rot2 compose(const Rot2& R, OptionalJacobian<1,1> H1 =
|
|
|
|
|
boost::none, OptionalJacobian<1,1> H2 = boost::none) const;
|
2012-10-02 22:40:07 +08:00
|
|
|
|
|
|
|
|
/** Between using the default implementation */
|
2014-12-23 06:42:52 +08:00
|
|
|
Rot2 between(const Rot2& R, OptionalJacobian<1,1> H1 =
|
|
|
|
|
boost::none, OptionalJacobian<1,1> H2 = boost::none) const;
|
2012-10-02 22:40:07 +08:00
|
|
|
|
|
|
|
|
/// @}
|
|
|
|
|
/// @name Manifold
|
|
|
|
|
/// @{
|
|
|
|
|
|
|
|
|
|
/// dimension of the variable - used to autodetect sizes
|
|
|
|
|
inline static size_t Dim() {
|
|
|
|
|
return dimension;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Dimensionality of the tangent space, DOF = 1
|
|
|
|
|
inline size_t dim() const {
|
|
|
|
|
return dimension;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Updates a with tangent space delta
|
2014-12-23 06:42:52 +08:00
|
|
|
Rot2 retract(const Vector& v, OptionalJacobian<1, 1> H1 = boost::none,
|
|
|
|
|
OptionalJacobian<1, 1> H2 = boost::none) const;
|
2012-10-02 22:40:07 +08:00
|
|
|
|
|
|
|
|
/// Returns inverse retraction
|
2014-12-23 06:42:52 +08:00
|
|
|
Vector1 localCoordinates(const Rot2& t2, OptionalJacobian<1, 1> H1 =
|
|
|
|
|
boost::none, OptionalJacobian<1, 1> H2 = boost::none) const;
|
2012-10-02 22:40:07 +08:00
|
|
|
|
|
|
|
|
/// @}
|
|
|
|
|
/// @name Lie Group
|
|
|
|
|
/// @{
|
|
|
|
|
|
2014-12-24 04:37:28 +08:00
|
|
|
/** Calculate Adjoint map */
|
|
|
|
|
Matrix1 AdjointMap() const { return I_1x1; }
|
|
|
|
|
|
2012-10-02 22:40:07 +08:00
|
|
|
///Exponential map at identity - create a rotation from canonical coordinates
|
2014-12-23 06:42:52 +08:00
|
|
|
static Rot2 Expmap(const Vector& v, OptionalJacobian<1, 1> H = boost::none);
|
2012-10-02 22:40:07 +08:00
|
|
|
|
|
|
|
|
///Log map at identity - return the canonical coordinates of this rotation
|
2014-12-23 06:42:52 +08:00
|
|
|
static Vector1 Logmap(const Rot2& r, OptionalJacobian<1, 1> H = boost::none);
|
2012-10-02 22:40:07 +08:00
|
|
|
|
2014-04-30 04:18:52 +08:00
|
|
|
/// Left-trivialized derivative of the exponential map
|
|
|
|
|
static Matrix dexpL(const Vector& v) {
|
|
|
|
|
return ones(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Left-trivialized derivative inverse of the exponential map
|
|
|
|
|
static Matrix dexpInvL(const Vector& v) {
|
|
|
|
|
return ones(1);
|
2012-10-02 22:40:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// @}
|
|
|
|
|
/// @name Group Action on Point2
|
|
|
|
|
/// @{
|
2011-11-05 05:44:29 +08:00
|
|
|
|
2012-01-24 13:03:56 +08:00
|
|
|
/**
|
2012-10-02 22:40:07 +08:00
|
|
|
* rotate point from rotated coordinate frame to world \f$ p^w = R_c^w p^c \f$
|
|
|
|
|
*/
|
2014-12-01 05:09:46 +08:00
|
|
|
Point2 rotate(const Point2& p, OptionalJacobian<2, 1> H1 = boost::none,
|
|
|
|
|
OptionalJacobian<2, 2> H2 = boost::none) const;
|
2012-10-02 22:40:07 +08:00
|
|
|
|
|
|
|
|
/** syntactic sugar for rotate */
|
|
|
|
|
inline Point2 operator*(const Point2& p) const {
|
|
|
|
|
return rotate(p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* rotate point from world to rotated frame \f$ p^c = (R_c^w)^T p^w \f$
|
|
|
|
|
*/
|
2014-12-01 05:09:46 +08:00
|
|
|
Point2 unrotate(const Point2& p, OptionalJacobian<2, 1> H1 = boost::none,
|
|
|
|
|
OptionalJacobian<2, 2> H2 = boost::none) const;
|
2012-10-02 22:40:07 +08:00
|
|
|
|
|
|
|
|
/// @}
|
|
|
|
|
/// @name Standard Interface
|
|
|
|
|
/// @{
|
|
|
|
|
|
|
|
|
|
/// Creates a unit vector as a Point2
|
|
|
|
|
inline Point2 unit() const {
|
|
|
|
|
return Point2(c_, s_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** return angle (RADIANS) */
|
|
|
|
|
double theta() const {
|
|
|
|
|
return ::atan2(s_, c_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** return angle (DEGREES) */
|
|
|
|
|
double degrees() const {
|
|
|
|
|
const double degree = M_PI / 180;
|
|
|
|
|
return theta() / degree;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** return cos */
|
|
|
|
|
inline double c() const {
|
|
|
|
|
return c_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** return sin */
|
|
|
|
|
inline double s() const {
|
|
|
|
|
return s_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** return 2*2 rotation matrix */
|
2014-11-30 21:32:52 +08:00
|
|
|
Matrix2 matrix() const;
|
2012-10-02 22:40:07 +08:00
|
|
|
|
|
|
|
|
/** return 2*2 transpose (inverse) rotation matrix */
|
2014-12-01 05:09:46 +08:00
|
|
|
Matrix2 transpose() const;
|
2012-10-02 22:40:07 +08:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
/** Serialization function */
|
|
|
|
|
friend class boost::serialization::access;
|
|
|
|
|
template<class ARCHIVE>
|
|
|
|
|
void serialize(ARCHIVE & ar, const unsigned int version) {
|
|
|
|
|
ar & BOOST_SERIALIZATION_NVP(c_);
|
|
|
|
|
ar & BOOST_SERIALIZATION_NVP(s_);
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-22 00:02:33 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<>
|
2014-12-24 08:34:33 +08:00
|
|
|
struct traits_x<Rot2> : public internal::LieGroupTraits<Rot2> {};
|
2010-01-08 08:40:17 +08:00
|
|
|
|
2009-12-10 05:50:27 +08:00
|
|
|
} // gtsam
|