quaternion.hpp 9.99 KB
Newer Older
1
/*
2
3
 * Copyright 2014-2019, CNRS
 * Copyright 2018-2019, INRIA
4
5
6
7
 */

#ifndef __eigenpy_quaternion_hpp__
#define __eigenpy_quaternion_hpp__
Nicolas Mansard's avatar
Nicolas Mansard committed
8

9
10
#include "eigenpy/fwd.hpp"

Nicolas Mansard's avatar
Nicolas Mansard committed
11
12
#include <Eigen/Core>
#include <Eigen/Geometry>
jcarpent's avatar
jcarpent committed
13

14
#include "eigenpy/exception.hpp"
15
#include "eigenpy/registration.hpp"
Nicolas Mansard's avatar
Nicolas Mansard committed
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

namespace eigenpy
{

  class ExceptionIndex : public Exception
  {
  public:
    ExceptionIndex(int index,int imin,int imax) : Exception("")
    {
      std::ostringstream oss; oss << "Index " << index << " out of range " << imin << ".."<< imax <<".";
      message = oss.str();
    }
  };

  namespace bp = boost::python;

32
33
  template<typename QuaternionDerived> class QuaternionVisitor;
  
34
35
  template<typename Scalar, int Options>
  struct call< Eigen::Quaternion<Scalar,Options> >
36
  {
37
38
    typedef Eigen::Quaternion<Scalar,Options> Quaternion;
    static inline void expose()
39
    {
40
41
42
43
      QuaternionVisitor<Quaternion>::expose();
    }
  };

Nicolas Mansard's avatar
Nicolas Mansard committed
44
45
  template<typename Quaternion>
  class QuaternionVisitor
46
  :  public bp::def_visitor< QuaternionVisitor<Quaternion> >
Nicolas Mansard's avatar
Nicolas Mansard committed
47
48
49
  {
    typedef Eigen::QuaternionBase<Quaternion> QuaternionBase;

50
    typedef typename QuaternionBase::Scalar Scalar;
51
    typedef typename Quaternion::Coefficients Coefficients;
52
53
54
    typedef typename QuaternionBase::Vector3 Vector3;
    typedef typename Eigen::Matrix<Scalar,4,1> Vector4;
    typedef typename QuaternionBase::Matrix3 Matrix3;
Nicolas Mansard's avatar
Nicolas Mansard committed
55

56
    typedef typename QuaternionBase::AngleAxisType AngleAxis;
Nicolas Mansard's avatar
Nicolas Mansard committed
57
58
59
60
61
62
63

  public:

    template<class PyClass>
    void visit(PyClass& cl) const 
    {
      cl
64
      .def(bp::init<>("Default constructor"))
65
      .def(bp::init<Vector4>((bp::arg("Vec4: a 4D vector representing quaternion coefficients")),"Initialize from a vector 4D."))
Justin Carpentier's avatar
Justin Carpentier committed
66
67
68
      .def(bp::init<Matrix3>((bp::arg("R: a rotation matrix")),"Initialize from rotation matrix."))
      .def(bp::init<AngleAxis>((bp::arg("aa: angle axis")),"Initialize from an angle axis."))
      .def(bp::init<Quaternion>((bp::arg("quaternion")),"Copy constructor."))
69
      .def("__init__",bp::make_constructor(&QuaternionVisitor::FromTwoVectors,
70
                                           bp::default_call_policies(),
Justin Carpentier's avatar
Justin Carpentier committed
71
                                           (bp::arg("u: a 3D vector"),bp::arg("v: a 3D vector"))),"Initialize from two vectors u andv")
72
73
74
75
76
77
78
      .def(bp::init<Scalar,Scalar,Scalar,Scalar>
           ((bp::arg("w"),bp::arg("x"),bp::arg("y"),bp::arg("z")),
            "Initialize from coefficients.\n\n"
            "... note:: The order of coefficients is *w*, *x*, *y*, *z*. "
            "The [] operator numbers them differently, 0...4 for *x* *y* *z* *w*!"))
      
      .add_property("x",
79
                    &QuaternionVisitor::getCoeff<0>,
80
81
                    &QuaternionVisitor::setCoeff<0>,"The x coefficient.")
      .add_property("y",
82
                    &QuaternionVisitor::getCoeff<1>,
83
84
                    &QuaternionVisitor::setCoeff<1>,"The y coefficient.")
      .add_property("z",
85
                    &QuaternionVisitor::getCoeff<2>,
86
87
                    &QuaternionVisitor::setCoeff<2>,"The z coefficient.")
      .add_property("w",
88
                    &QuaternionVisitor::getCoeff<3>,
89
90
                    &QuaternionVisitor::setCoeff<3>,"The w coefficient.")
      
91
92
93
94
95
//      .def("isApprox",(bool (Quaternion::*)(const Quaternion &))&Quaternion::template isApprox<Quaternion>,
//           "Returns true if *this is approximately equal to other.")
//      .def("isApprox",(bool (Quaternion::*)(const Quaternion &, const Scalar prec))&Quaternion::template isApprox<Quaternion>,
//           "Returns true if *this is approximately equal to other, within the precision determined by prec..")
      .def("isApprox",(bool (*)(const Quaternion &))&isApprox,
96
           "Returns true if *this is approximately equal to other.")
97
      .def("isApprox",(bool (*)(const Quaternion &, const Scalar prec))&isApprox,
98
99
100
101
102
           "Returns true if *this is approximately equal to other, within the precision determined by prec..")
      
      /* --- Methods --- */
      .def("coeffs",(const Vector4 & (Quaternion::*)()const)&Quaternion::coeffs,
           bp::return_value_policy<bp::copy_const_reference>())
Justin Carpentier's avatar
Justin Carpentier committed
103
      .def("matrix",&Quaternion::matrix,"Returns an equivalent 3x3 rotation matrix. Similar to toRotationMatrix.")
104
      .def("toRotationMatrix",&Quaternion::toRotationMatrix,"Returns an equivalent 3x3 rotation matrix.")
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
      
      .def("setFromTwoVectors",&setFromTwoVectors,((bp::arg("a"),bp::arg("b"))),"Set *this to be the quaternion which transform a into b through a rotation."
           ,bp::return_self<>())
      .def("conjugate",&Quaternion::conjugate,"Returns the conjugated quaternion. The conjugate of a quaternion represents the opposite rotation.")
      .def("inverse",&Quaternion::inverse,"Returns the quaternion describing the inverse rotation.")
      .def("setIdentity",&Quaternion::setIdentity,bp::return_self<>(),"Set *this to the idendity rotation.")
      .def("norm",&Quaternion::norm,"Returns the norm of the quaternion's coefficients.")
      .def("normalize",&Quaternion::normalize,"Normalizes the quaternion *this.")
      .def("normalized",&Quaternion::normalized,"Returns a normalized copy of *this.")
      .def("squaredNorm",&Quaternion::squaredNorm,"Returns the squared norm of the quaternion's coefficients.")
      .def("dot",&Quaternion::template dot<Quaternion>,bp::arg("other"),"Returns the dot product of *this with other"
           "Geometrically speaking, the dot product of two unit quaternions corresponds to the cosine of half the angle between the two rotations.")
      .def("_transformVector",&Quaternion::_transformVector,bp::arg("vector"),"Rotation of a vector by a quaternion.")
      .def("vec",&vec,"Returns a vector expression of the imaginary part (x,y,z).")
      .def("angularDistance",&Quaternion::template angularDistance<Quaternion>,"Returns the angle (in radian) between two rotations.")
120
      .def("slerp",&slerp,bp::args("t","other"),
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
           "Returns the spherical linear interpolation between the two quaternions *this and other at the parameter t in [0;1].")

      /* --- Operators --- */
      .def(bp::self * bp::self)
      .def(bp::self *= bp::self)
      .def(bp::self * bp::other<Vector3>())
      .def("__eq__",&QuaternionVisitor::__eq__)
      .def("__ne__",&QuaternionVisitor::__ne__)
      .def("__abs__",&Quaternion::norm)
      .def("__len__",&QuaternionVisitor::__len__).staticmethod("__len__")
      .def("__setitem__",&QuaternionVisitor::__setitem__)
      .def("__getitem__",&QuaternionVisitor::__getitem__)
      .def("assign",&assign<Quaternion>,
           bp::arg("quat"),"Set *this from an quaternion quat and returns a reference to *this.",bp::return_self<>())
      .def("assign",(Quaternion & (Quaternion::*)(const AngleAxis &))&Quaternion::operator=,
           bp::arg("aa"),"Set *this from an angle-axis aa and returns a reference to *this.",bp::return_self<>())
      .def("__str__",&print)
      .def("__repr__",&print)
      
140
141
142
//      .def("FromTwoVectors",&Quaternion::template FromTwoVectors<Vector3,Vector3>,
//           bp::args("a","b"),
//           "Returns the quaternion which transform a into b through a rotation.")
143
144
145
146
      .def("FromTwoVectors",&FromTwoVectors,
           bp::args("a","b"),
           "Returns the quaternion which transform a into b through a rotation.",
           bp::return_value_policy<bp::manage_new_object>())
147
148
149
      .staticmethod("FromTwoVectors")
      .def("Identity",&Quaternion::Identity,"Returns a quaternion representing an identity rotation.")
      .staticmethod("Identity")
Nicolas Mansard's avatar
Nicolas Mansard committed
150
      
151
152
    
      ;
Nicolas Mansard's avatar
Nicolas Mansard committed
153
154
    }
  private:
155
156
157
158
    
    template<int i>
    static void setCoeff(Quaternion & self, Scalar value) { self.coeffs()[i] = value; }
    
159
160
161
    template<int i>
    static Scalar getCoeff(Quaternion & self) { return self.coeffs()[i]; }
    
162
163
164
165
166
167
168
    static Quaternion & setFromTwoVectors(Quaternion & self, const Vector3 & a, const Vector3 & b)
    { return self.setFromTwoVectors(a,b); }
    
    template<typename OtherQuat>
    static Quaternion & assign(Quaternion & self, const OtherQuat & quat)
    { return self = quat; }

169
    static Quaternion* FromTwoVectors(const Vector3& u, const Vector3& v)
Nicolas Mansard's avatar
Nicolas Mansard committed
170
    { 
171
      Quaternion* q(new Quaternion); q->setFromTwoVectors(u,v);
Nicolas Mansard's avatar
Nicolas Mansard committed
172
173
      return q; 
    }
174
175
176
177
178
179
    
    static bool isApprox(const Quaternion & self, const Quaternion & other,
                         const Scalar prec = Eigen::NumTraits<Scalar>::dummy_precision)
    {
      return self.isApprox(other,prec);
    }
Nicolas Mansard's avatar
Nicolas Mansard committed
180
  
181
    static bool __eq__(const Quaternion& u, const Quaternion& v)
Nicolas Mansard's avatar
Nicolas Mansard committed
182
183
184
    {
      return u.isApprox(v,1e-9);
    }
185
186
    
    static bool __ne__(const Quaternion& u, const Quaternion& v)
Nicolas Mansard's avatar
Nicolas Mansard committed
187
188
189
190
    {
      return !__eq__(u,v); 
    }

191
    static Scalar __getitem__(const Quaternion & self, int idx)
Nicolas Mansard's avatar
Nicolas Mansard committed
192
    { 
193
194
      if((idx<0) || (idx>=4)) throw eigenpy::ExceptionIndex(idx,0,3);
      return self.coeffs()[idx];
Nicolas Mansard's avatar
Nicolas Mansard committed
195
196
    }
  
197
    static void __setitem__(Quaternion& self, int idx, const Scalar value)
Nicolas Mansard's avatar
Nicolas Mansard committed
198
    { 
199
200
      if((idx<0) || (idx>=4)) throw eigenpy::ExceptionIndex(idx,0,3);
      self.coeffs()[idx] = value;
Nicolas Mansard's avatar
Nicolas Mansard committed
201
202
    }

203
204
205
206
207
208
209
210
211
212
    static int __len__() {  return 4;  }
    static Vector3 vec(const Quaternion & self) { return self.vec(); }
    
    static std::string print(const Quaternion & self)
    {
      std::stringstream ss;
      ss << "(x,y,z,w) = " << self.coeffs().transpose() << std::endl;
      
      return ss.str();
    }
213
214
215
    
    static Quaternion slerp(const Quaternion & self, const Scalar t, const Quaternion & other)
    { return self.slerp(t,other); }
Nicolas Mansard's avatar
Nicolas Mansard committed
216
217
218
219
220

  public:

    static void expose()
    {
221
222
223
224
225
226
227
228
229
230
231
      bp::class_<Quaternion>("Quaternion",
                             "Quaternion representing rotation.\n\n"
                             "Supported operations "
                             "('q is a Quaternion, 'v' is a Vector3): "
                             "'q*q' (rotation composition), "
                             "'q*=q', "
                             "'q*v' (rotating 'v' by 'q'), "
                             "'q==q', 'q!=q', 'q[0..3]'.",
                             bp::no_init)
      .def(QuaternionVisitor<Quaternion>())
      ;
232
   
Nicolas Mansard's avatar
Nicolas Mansard committed
233
234
235
236
237
238
    }

  };

} // namespace eigenpy

239
#endif // ifndef __eigenpy_quaternion_hpp__