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
|
|
|
|
|
|
|
|
|
|
* -------------------------------------------------------------------------- */
|
|
|
|
|
|
2009-08-29 09:24:26 +08:00
|
|
|
/**
|
|
|
|
|
* @file Pose2.h
|
2009-12-14 11:02:05 +08:00
|
|
|
* @brief 2D Pose
|
2009-08-29 09:24:26 +08:00
|
|
|
* @author: Frank Dellaert
|
2009-12-14 11:02:05 +08:00
|
|
|
* @author: Richard Roberts
|
2009-08-29 09:24:26 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// \callgraph
|
|
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
2010-01-12 10:08:41 +08:00
|
|
|
#include <boost/optional.hpp>
|
2010-08-20 01:23:19 +08:00
|
|
|
#include <gtsam/base/Matrix.h>
|
|
|
|
|
#include <gtsam/geometry/Point2.h>
|
|
|
|
|
#include <gtsam/geometry/Rot2.h>
|
2009-08-29 09:24:26 +08:00
|
|
|
|
|
|
|
|
namespace gtsam {
|
|
|
|
|
|
2009-12-14 11:02:05 +08:00
|
|
|
/**
|
2009-12-15 08:00:02 +08:00
|
|
|
* A 2D pose (Point2,Rot2)
|
2011-09-07 13:02:36 +08:00
|
|
|
* @ingroup geometry
|
2009-12-14 11:02:05 +08:00
|
|
|
*/
|
2011-11-05 05:44:29 +08:00
|
|
|
class Pose2 {
|
2010-08-20 04:03:06 +08:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
static const size_t dimension = 3;
|
2011-10-07 04:47:30 +08:00
|
|
|
|
|
|
|
|
/** Pose Concept requirements */
|
|
|
|
|
typedef Rot2 Rotation;
|
|
|
|
|
typedef Point2 Translation;
|
|
|
|
|
|
2009-12-15 08:00:02 +08:00
|
|
|
private:
|
|
|
|
|
Rot2 r_;
|
2010-03-20 04:32:19 +08:00
|
|
|
Point2 t_;
|
2009-12-15 08:00:02 +08:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
|
|
/** default constructor = origin */
|
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
|
|
|
Pose2() {} // default is origin
|
2009-12-15 08:00:02 +08:00
|
|
|
|
|
|
|
|
/** copy constructor */
|
2010-03-20 04:32:19 +08:00
|
|
|
Pose2(const Pose2& pose) : r_(pose.r_), t_(pose.t_) {}
|
2009-12-15 08:00:02 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* construct from (x,y,theta)
|
|
|
|
|
* @param x x coordinate
|
|
|
|
|
* @param y y coordinate
|
|
|
|
|
* @param theta angle with positive X-axis
|
|
|
|
|
*/
|
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
|
|
|
Pose2(double x, double y, double theta) :
|
2010-03-20 04:32:19 +08:00
|
|
|
r_(Rot2::fromAngle(theta)), t_(x, y) {
|
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
|
|
|
}
|
2009-12-15 08:00:02 +08:00
|
|
|
|
|
|
|
|
/** construct from rotation and translation */
|
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
|
|
|
Pose2(double theta, const Point2& t) :
|
2010-03-20 04:32:19 +08:00
|
|
|
r_(Rot2::fromAngle(theta)), t_(t) {
|
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
|
|
|
}
|
2010-03-20 04:32:19 +08:00
|
|
|
Pose2(const Rot2& r, const Point2& t) : r_(r), t_(t) {}
|
2009-12-15 08:00:02 +08:00
|
|
|
|
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
|
|
|
/** Constructor from 3*3 matrix */
|
|
|
|
|
Pose2(const Matrix &T) :
|
2011-11-04 14:10:20 +08:00
|
|
|
r_(Rot2::atan2(T(1, 0), T(0, 0))), t_(T(0, 2), T(1, 2)) {
|
|
|
|
|
assert(T.rows() == 3 && T.cols() == 3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Construct from canonical coordinates (Lie algebra) */
|
|
|
|
|
Pose2(const Vector& v) {
|
2011-11-04 22:30:11 +08:00
|
|
|
*this = Expmap(v);
|
2011-11-04 14:10:20 +08:00
|
|
|
}
|
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
|
|
|
|
2009-12-15 08:00:02 +08:00
|
|
|
/** print with optional string */
|
|
|
|
|
void print(const std::string& s = "") const;
|
|
|
|
|
|
|
|
|
|
/** assert equality up to a tolerance */
|
|
|
|
|
bool equals(const Pose2& pose, double tol = 1e-9) const;
|
|
|
|
|
|
2010-08-23 05:45:53 +08:00
|
|
|
/** compose syntactic sugar */
|
2010-08-20 04:03:06 +08:00
|
|
|
inline Pose2 operator*(const Pose2& p2) const {
|
|
|
|
|
return Pose2(r_*p2.r(), t_ + r_*p2.t());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** dimension of the variable - used to autodetect sizes */
|
|
|
|
|
inline static size_t Dim() { return dimension; }
|
|
|
|
|
|
|
|
|
|
/** Lie requirements */
|
|
|
|
|
|
|
|
|
|
/** return DOF, dimensionality of tangent space = 3 */
|
|
|
|
|
inline size_t dim() const { return dimension; }
|
|
|
|
|
|
2010-08-27 03:55:40 +08:00
|
|
|
/**
|
|
|
|
|
* inverse transformation with derivatives
|
|
|
|
|
*/
|
|
|
|
|
Pose2 inverse(boost::optional<Matrix&> H1=boost::none) const;
|
2010-08-20 04:03:06 +08:00
|
|
|
|
2010-08-27 03:55:40 +08:00
|
|
|
/**
|
|
|
|
|
* compose this transformation onto another (first *this and then p2)
|
|
|
|
|
* With optional derivatives
|
|
|
|
|
*/
|
|
|
|
|
Pose2 compose(const Pose2& p2,
|
|
|
|
|
boost::optional<Matrix&> H1 = boost::none,
|
|
|
|
|
boost::optional<Matrix&> H2 = boost::none) const;
|
2010-08-20 04:03:06 +08:00
|
|
|
|
2011-11-04 12:27:55 +08:00
|
|
|
/// MATLAB version returns shared pointer
|
|
|
|
|
boost::shared_ptr<Pose2> compose_(const Pose2& p2) {
|
|
|
|
|
return boost::shared_ptr<Pose2>(new Pose2(compose(p2)));
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-23 05:45:53 +08:00
|
|
|
/** syntactic sugar for transform_from */
|
2011-07-15 11:12:43 +08:00
|
|
|
inline Point2 operator*(const Point2& point) const { return transform_from(point);}
|
2010-08-23 05:45:53 +08:00
|
|
|
|
2010-08-20 04:03:06 +08:00
|
|
|
/**
|
2011-11-05 05:44:29 +08:00
|
|
|
* Retraction from se(2) to SE(2)
|
2010-08-20 04:03:06 +08:00
|
|
|
*/
|
2011-11-05 05:44:29 +08:00
|
|
|
static Pose2 Retract(const Vector& v);
|
2010-08-20 04:03:06 +08:00
|
|
|
|
|
|
|
|
/**
|
2011-11-05 05:44:29 +08:00
|
|
|
* Inverse of retraction, from SE(2) to se(2)
|
2010-08-20 04:03:06 +08:00
|
|
|
*/
|
2011-11-05 05:44:29 +08:00
|
|
|
static Vector Unretract(const Pose2& p);
|
2010-08-20 04:03:06 +08:00
|
|
|
|
2011-11-05 05:44:29 +08:00
|
|
|
/** Real versions of Expmap/Logmap */
|
|
|
|
|
static Pose2 Expmap(const Vector& xi);
|
|
|
|
|
static Vector Logmap(const Pose2& p);
|
2011-02-02 13:17:21 +08:00
|
|
|
|
2010-08-27 03:55:40 +08:00
|
|
|
/** default implementations of binary functions */
|
2011-11-05 05:44:29 +08:00
|
|
|
inline Pose2 retract(const Vector& v) const { return compose(Retract(v)); }
|
|
|
|
|
inline Vector unretract(const Pose2& p2) const { return Unretract(between(p2));}
|
2010-08-27 03:55:40 +08:00
|
|
|
|
2011-02-02 13:17:21 +08:00
|
|
|
/** non-approximated versions of expmap/logmap */
|
2011-11-05 05:44:29 +08:00
|
|
|
inline Pose2 expmap(const Vector& v) const { return compose(Expmap(v)); }
|
|
|
|
|
inline Vector logmap(const Pose2& p2) const { return Logmap(between(p2));}
|
2011-02-02 13:17:21 +08:00
|
|
|
|
2010-08-27 03:55:40 +08:00
|
|
|
/**
|
|
|
|
|
* Return relative pose between p1 and p2, in p1 coordinate frame
|
|
|
|
|
*/
|
|
|
|
|
Pose2 between(const Pose2& p2,
|
|
|
|
|
boost::optional<Matrix&> H1=boost::none,
|
|
|
|
|
boost::optional<Matrix&> H2=boost::none) const;
|
|
|
|
|
|
2011-11-04 05:44:25 +08:00
|
|
|
/// MATLAB version returns shared pointer
|
|
|
|
|
boost::shared_ptr<Pose2> between_(const Pose2& p2) {
|
|
|
|
|
return boost::shared_ptr<Pose2>(new Pose2(between(p2)));
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-19 00:27:01 +08:00
|
|
|
/** return transformation matrix */
|
|
|
|
|
Matrix matrix() const;
|
|
|
|
|
|
2010-08-21 05:47:30 +08:00
|
|
|
/**
|
|
|
|
|
* Return point coordinates in pose coordinate frame
|
|
|
|
|
*/
|
2010-08-23 05:45:53 +08:00
|
|
|
Point2 transform_to(const Point2& point,
|
2010-08-27 03:55:40 +08:00
|
|
|
boost::optional<Matrix&> H1=boost::none,
|
|
|
|
|
boost::optional<Matrix&> H2=boost::none) const;
|
2010-08-21 05:47:30 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return point coordinates in global frame
|
|
|
|
|
*/
|
2010-08-23 05:45:53 +08:00
|
|
|
Point2 transform_from(const Point2& point,
|
2010-08-27 03:55:40 +08:00
|
|
|
boost::optional<Matrix&> H1=boost::none,
|
|
|
|
|
boost::optional<Matrix&> H2=boost::none) const;
|
2010-08-23 05:45:53 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Calculate bearing to a landmark
|
|
|
|
|
* @param point 2D location of landmark
|
|
|
|
|
* @return 2D rotation \in SO(2)
|
|
|
|
|
*/
|
|
|
|
|
Rot2 bearing(const Point2& point,
|
2010-08-27 03:55:40 +08:00
|
|
|
boost::optional<Matrix&> H1=boost::none,
|
|
|
|
|
boost::optional<Matrix&> H2=boost::none) const;
|
2010-08-23 05:45:53 +08:00
|
|
|
|
2011-10-07 04:47:16 +08:00
|
|
|
/**
|
|
|
|
|
* Calculate bearing to another pose
|
|
|
|
|
* @param point SO(2) location of other pose
|
|
|
|
|
* @return 2D rotation \in SO(2)
|
|
|
|
|
*/
|
|
|
|
|
Rot2 bearing(const Pose2& point,
|
|
|
|
|
boost::optional<Matrix&> H1=boost::none,
|
|
|
|
|
boost::optional<Matrix&> H2=boost::none) const;
|
|
|
|
|
|
2010-08-23 05:45:53 +08:00
|
|
|
/**
|
|
|
|
|
* Calculate range to a landmark
|
|
|
|
|
* @param point 2D location of landmark
|
|
|
|
|
* @return range (double)
|
|
|
|
|
*/
|
|
|
|
|
double range(const Point2& point,
|
2010-08-27 03:55:40 +08:00
|
|
|
boost::optional<Matrix&> H1=boost::none,
|
|
|
|
|
boost::optional<Matrix&> H2=boost::none) const;
|
2010-08-23 05:45:53 +08:00
|
|
|
|
2011-10-07 02:10:45 +08:00
|
|
|
/**
|
|
|
|
|
* Calculate range to another pose
|
|
|
|
|
* @param point 2D location of other pose
|
|
|
|
|
* @return range (double)
|
|
|
|
|
*/
|
|
|
|
|
double range(const Pose2& point,
|
|
|
|
|
boost::optional<Matrix&> H1=boost::none,
|
|
|
|
|
boost::optional<Matrix&> H2=boost::none) const;
|
|
|
|
|
|
2010-08-23 05:45:53 +08:00
|
|
|
/**
|
|
|
|
|
* Calculate Adjoint map
|
|
|
|
|
* Ad_pose is 3*3 matrix that when applied to twist xi, returns Ad_pose(xi)
|
|
|
|
|
*/
|
|
|
|
|
Matrix AdjointMap() const;
|
|
|
|
|
inline Vector Adjoint(const Vector& xi) const {
|
2010-10-09 06:04:47 +08:00
|
|
|
assert(xi.size() == 3);
|
2010-08-23 05:45:53 +08:00
|
|
|
return AdjointMap()*xi;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* wedge for SE(2):
|
|
|
|
|
* @param xi 3-dim twist (v,omega) where
|
|
|
|
|
* omega is angular velocity
|
|
|
|
|
* v (vx,vy) = 2D velocity
|
|
|
|
|
* @return xihat, 3*3 element of Lie algebra that can be exponentiated
|
|
|
|
|
*/
|
|
|
|
|
static inline Matrix wedge(double vx, double vy, double w) {
|
|
|
|
|
return Matrix_(3,3,
|
|
|
|
|
0.,-w, vx,
|
|
|
|
|
w, 0., vy,
|
|
|
|
|
0., 0., 0.);
|
|
|
|
|
}
|
2010-08-21 05:47:30 +08:00
|
|
|
|
2009-12-15 08:00:02 +08:00
|
|
|
/** get functions for x, y, theta */
|
2010-02-24 14:14:43 +08:00
|
|
|
inline double x() const { return t_.x(); }
|
|
|
|
|
inline double y() const { return t_.y(); }
|
|
|
|
|
inline double theta() const { return r_.theta(); }
|
|
|
|
|
|
2011-10-07 04:47:30 +08:00
|
|
|
/** shorthand access functions */
|
2010-02-24 14:14:43 +08:00
|
|
|
inline const Point2& t() const { return t_; }
|
|
|
|
|
inline const Rot2& r() const { return r_; }
|
2009-12-15 08:00:02 +08:00
|
|
|
|
2011-10-07 04:47:30 +08:00
|
|
|
/** full access functions required by Pose concept */
|
|
|
|
|
inline const Point2& translation() const { return t_; }
|
|
|
|
|
inline const Rot2& rotation() const { return r_; }
|
|
|
|
|
|
2010-03-12 22:20:29 +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(t_);
|
|
|
|
|
ar & BOOST_SERIALIZATION_NVP(r_);
|
|
|
|
|
}
|
2010-01-08 08:40:17 +08:00
|
|
|
}; // Pose2
|
2009-12-18 08:09:54 +08:00
|
|
|
|
2010-08-23 05:45:53 +08:00
|
|
|
/** specialization for pose2 wedge function (generic template in Lie.h) */
|
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
|
|
|
template <>
|
|
|
|
|
inline Matrix wedge<Pose2>(const Vector& xi) {
|
2010-08-23 05:45:53 +08:00
|
|
|
return Pose2::wedge(xi(0),xi(1),xi(2));
|
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
|
|
|
}
|
|
|
|
|
|
2010-09-11 13:29:38 +08:00
|
|
|
/**
|
|
|
|
|
* Calculate pose between a vector of 2D point correspondences (p,q)
|
|
|
|
|
* where q = Pose2::transform_from(p) = t + R*p
|
|
|
|
|
*/
|
|
|
|
|
typedef std::pair<Point2,Point2> Point2Pair;
|
|
|
|
|
boost::optional<Pose2> align(const std::vector<Point2Pair>& pairs);
|
|
|
|
|
|
2009-08-29 09:24:26 +08:00
|
|
|
} // namespace gtsam
|
2010-01-10 07:15:06 +08:00
|
|
|
|