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/base/Testable.h>
|
|
|
|
#include <gtsam/base/Lie.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)
|
2009-12-14 11:02:05 +08:00
|
|
|
*/
|
2010-01-10 07:15:06 +08:00
|
|
|
class Pose2: Testable<Pose2>, public Lie<Pose2> {
|
2010-08-20 04:03:06 +08:00
|
|
|
|
|
|
|
public:
|
|
|
|
static const size_t dimension = 3;
|
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) :
|
2010-03-03 13:34:08 +08:00
|
|
|
r_(Rot2::atan2(T(1, 0), T(0, 0))), t_(T(0, 2), T(1, 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
|
|
|
|
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; }
|
|
|
|
|
|
|
|
/** inverse of a pose */
|
|
|
|
Pose2 inverse() const;
|
|
|
|
|
|
|
|
/** compose with another pose */
|
|
|
|
inline Pose2 compose(const Pose2& p) const { return *this * p; }
|
|
|
|
|
2010-08-23 05:45:53 +08:00
|
|
|
/** syntactic sugar for transform_from */
|
|
|
|
inline Point2 operator*(const Point2& point) { return transform_from(point);}
|
|
|
|
|
2010-08-20 04:03:06 +08:00
|
|
|
/**
|
|
|
|
* Exponential map from se(2) to SE(2)
|
|
|
|
*/
|
|
|
|
static Pose2 Expmap(const Vector& v);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Inverse of exponential map, from SE(2) to se(2)
|
|
|
|
*/
|
|
|
|
static Vector Logmap(const Pose2& p);
|
|
|
|
|
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,
|
|
|
|
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,
|
|
|
|
boost::optional<Matrix&> H1=boost::none, boost::optional<Matrix&> H2=boost::none) const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calculate bearing to a landmark
|
|
|
|
* @param point 2D location of landmark
|
|
|
|
* @return 2D rotation \in SO(2)
|
|
|
|
*/
|
|
|
|
Rot2 bearing(const Point2& point,
|
|
|
|
boost::optional<Matrix&> H1=boost::none, boost::optional<Matrix&> H2=boost::none) const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calculate range to a landmark
|
|
|
|
* @param point 2D location of landmark
|
|
|
|
* @return range (double)
|
|
|
|
*/
|
|
|
|
double range(const Point2& point,
|
|
|
|
boost::optional<Matrix&> H1=boost::none, boost::optional<Matrix&> H2=boost::none) const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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 {
|
|
|
|
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(); }
|
|
|
|
|
|
|
|
inline const Point2& t() const { return t_; }
|
|
|
|
inline const Rot2& r() const { return r_; }
|
2009-12-15 08:00:02 +08:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* inverse transformation
|
|
|
|
*/
|
2010-08-20 23:17:13 +08:00
|
|
|
Pose2 inverse(const Pose2& pose, boost::optional<Matrix&> H1);
|
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
|
|
|
/**
|
|
|
|
* compose this transformation onto another (first p1 and then p2)
|
|
|
|
*/
|
2010-05-24 13:40:59 +08:00
|
|
|
Pose2 compose(const Pose2& p1, const Pose2& p2,
|
|
|
|
boost::optional<Matrix&> H1,
|
|
|
|
boost::optional<Matrix&> H2 = boost::none);
|
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
|
|
|
/**
|
|
|
|
* Return relative pose between p1 and p2, in p1 coordinate frame
|
|
|
|
*/
|
2010-01-16 09:16:59 +08:00
|
|
|
Pose2 between(const Pose2& p1, const Pose2& p2,
|
2010-03-02 10:27:09 +08:00
|
|
|
boost::optional<Matrix&> H1, boost::optional<Matrix&> H2);
|
2010-01-08 08:40:17 +08:00
|
|
|
|
2009-08-29 09:24:26 +08:00
|
|
|
} // namespace gtsam
|
2010-01-10 07:15:06 +08:00
|
|
|
|