quaternion.hpp 10.2 KB
Newer Older
1
/*
2
 * Copyright 2014-2018, Nicolas Mansard, Justin Carpentier, LAAS-CNRS
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 *
 * This file is part of eigenpy.
 * eigenpy is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 * eigenpy is distributed in the hope that it will be
 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.  You should
 * have received a copy of the GNU Lesser General Public License along
 * with eigenpy.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __eigenpy_quaternion_hpp__
#define __eigenpy_quaternion_hpp__
Nicolas Mansard's avatar
Nicolas Mansard committed
19
20
21

#include <Eigen/Core>
#include <Eigen/Geometry>
jcarpent's avatar
jcarpent committed
22

23
#include "eigenpy/exception.hpp"
24
#include "eigenpy/registration.hpp"
Nicolas Mansard's avatar
Nicolas Mansard committed
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

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;

  template<typename Quaternion>
  class QuaternionVisitor
    :  public boost::python::def_visitor< QuaternionVisitor<Quaternion> >
  {
    typedef Eigen::QuaternionBase<Quaternion> QuaternionBase;

47
    typedef typename QuaternionBase::Scalar Scalar;
48
    typedef typename Quaternion::Coefficients Coefficients;
49
50
51
    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
52

53
    typedef typename QuaternionBase::AngleAxisType AngleAxis;
Nicolas Mansard's avatar
Nicolas Mansard committed
54
55
56
57
58
59
60

  public:

    template<class PyClass>
    void visit(PyClass& cl) const 
    {
      cl
61
62
63
64
      .def(bp::init<>("Default constructor"))
      .def(bp::init<Matrix3>((bp::arg("matrixRotation")),"Initialize from rotation matrix."))
      .def(bp::init<AngleAxis>((bp::arg("angleaxis")),"Initialize from angle axis."))
      .def(bp::init<Quaternion>((bp::arg("clone")),"Copy constructor."))
65
      .def("__init__",bp::make_constructor(&QuaternionVisitor::FromTwoVectors,
66
67
68
69
70
71
72
73
74
                                           bp::default_call_policies(),
                                           (bp::arg("u"),bp::arg("v"))),"Initialize from two vector u,v")
      .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",
75
                    &QuaternionVisitor::getCoeff<0>,
76
77
                    &QuaternionVisitor::setCoeff<0>,"The x coefficient.")
      .add_property("y",
78
                    &QuaternionVisitor::getCoeff<1>,
79
80
                    &QuaternionVisitor::setCoeff<1>,"The y coefficient.")
      .add_property("z",
81
                    &QuaternionVisitor::getCoeff<2>,
82
83
                    &QuaternionVisitor::setCoeff<2>,"The z coefficient.")
      .add_property("w",
84
                    &QuaternionVisitor::getCoeff<3>,
85
86
                    &QuaternionVisitor::setCoeff<3>,"The w coefficient.")
      
87
88
89
90
91
//      .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,
92
           "Returns true if *this is approximately equal to other.")
93
      .def("isApprox",(bool (*)(const Quaternion &, const Scalar prec))&isApprox,
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
           "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>())
      .def("matrix",&Quaternion::matrix,"Returns an equivalent rotation matrix")
      .def("toRotationMatrix ",&Quaternion::toRotationMatrix,"Returns an equivalent 3x3 rotation matrix.")
      
      .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.")
116
      .def("slerp",&slerp,bp::args("t","other"),
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
           "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)
      
136
137
138
//      .def("FromTwoVectors",&Quaternion::template FromTwoVectors<Vector3,Vector3>,
//           bp::args("a","b"),
//           "Returns the quaternion which transform a into b through a rotation.")
139
140
141
142
      .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>())
143
144
145
      .staticmethod("FromTwoVectors")
      .def("Identity",&Quaternion::Identity,"Returns a quaternion representing an identity rotation.")
      .staticmethod("Identity")
Nicolas Mansard's avatar
Nicolas Mansard committed
146
      
147
148
    
      ;
Nicolas Mansard's avatar
Nicolas Mansard committed
149
150
    }
  private:
151
152
153
154
    
    template<int i>
    static void setCoeff(Quaternion & self, Scalar value) { self.coeffs()[i] = value; }
    
155
156
157
    template<int i>
    static Scalar getCoeff(Quaternion & self) { return self.coeffs()[i]; }
    
158
159
160
161
162
163
164
    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; }

165
    static Quaternion* FromTwoVectors(const Vector3& u, const Vector3& v)
Nicolas Mansard's avatar
Nicolas Mansard committed
166
    { 
167
      Quaternion* q(new Quaternion); q->setFromTwoVectors(u,v);
Nicolas Mansard's avatar
Nicolas Mansard committed
168
169
      return q; 
    }
170
171
172
173
174
175
    
    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
176
  
177
    static bool __eq__(const Quaternion& u, const Quaternion& v)
Nicolas Mansard's avatar
Nicolas Mansard committed
178
179
180
    {
      return u.isApprox(v,1e-9);
    }
181
182
    
    static bool __ne__(const Quaternion& u, const Quaternion& v)
Nicolas Mansard's avatar
Nicolas Mansard committed
183
184
185
186
    {
      return !__eq__(u,v); 
    }

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

199
200
201
202
203
204
205
206
207
208
    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();
    }
209
210
211
    
    static Quaternion slerp(const Quaternion & self, const Scalar t, const Quaternion & other)
    { return self.slerp(t,other); }
Nicolas Mansard's avatar
Nicolas Mansard committed
212
213
214
215
216

  public:

    static void expose()
    {
217
218
      if(check_registration<Quaternion>()) return;
      
219
220
221
222
223
224
225
226
227
228
229
      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>())
      ;
230
   
Nicolas Mansard's avatar
Nicolas Mansard committed
231
232
233
234
235
236
    }

  };

} // namespace eigenpy

237
#endif // ifndef __eigenpy_quaternion_hpp__