joint-planar.hpp 19 KB
Newer Older
1
//
2
// Copyright (c) 2015-2019 CNRS INRIA
3
// Copyright (c) 2015-2016 Wandercraft, 86 rue de Paris 91400 Orsay, France.
4
5
//

6
7
#ifndef __pinocchio_joint_planar_hpp__
#define __pinocchio_joint_planar_hpp__
8

9
#include "pinocchio/macros.hpp"
10
#include "pinocchio/multibody/joint/joint-base.hpp"
11
#include "pinocchio/spatial/cartesian-axis.hpp"
12
13
14
15
#include "pinocchio/multibody/constraint.hpp"
#include "pinocchio/spatial/motion.hpp"
#include "pinocchio/spatial/inertia.hpp"

16
namespace pinocchio
17
{
18
19
  
  template<typename Scalar, int Options = 0> struct MotionPlanarTpl;
20
21
  typedef MotionPlanarTpl<double> MotionPlanar;
  
22
23
  template<typename Scalar, int Options>
  struct SE3GroupAction< MotionPlanarTpl<Scalar,Options> >
24
  {
25
26
    typedef MotionTpl<Scalar,Options> ReturnType;
  };
27
  
28
29
30
31
32
33
  template<typename Scalar, int Options, typename MotionDerived>
  struct MotionAlgebraAction< MotionPlanarTpl<Scalar,Options>, MotionDerived>
  {
    typedef MotionTpl<Scalar,Options> ReturnType;
  };

34
35
  template<typename _Scalar, int _Options>
  struct traits< MotionPlanarTpl<_Scalar,_Options> >
36
  {
37
38
39
40
41
    typedef _Scalar Scalar;
    enum { Options = _Options };
    typedef Eigen::Matrix<Scalar,3,1,Options> Vector3;
    typedef Eigen::Matrix<Scalar,6,1,Options> Vector6;
    typedef Eigen::Matrix<Scalar,6,6,Options> Matrix6;
gabrielebndn's avatar
gabrielebndn committed
42
43
    typedef typename PINOCCHIO_EIGEN_REF_CONST_TYPE(Vector6) ToVectorConstReturnType;
    typedef typename PINOCCHIO_EIGEN_REF_TYPE(Vector6) ToVectorReturnType;
44
45
46
47
48
    typedef Vector3 AngularType;
    typedef Vector3 LinearType;
    typedef const Vector3 ConstAngularType;
    typedef const Vector3 ConstLinearType;
    typedef Matrix6 ActionMatrixType;
49
    typedef MotionTpl<Scalar,Options> MotionPlain;
50
    typedef MotionPlain PlainReturnType;
51
52
53
54
    enum {
      LINEAR = 0,
      ANGULAR = 3
    };
55
  }; // traits MotionPlanarTpl
56

57
  template<typename _Scalar, int _Options>
58
59
  struct MotionPlanarTpl
  : MotionBase< MotionPlanarTpl<_Scalar,_Options> >
60
  {
61
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
62
    MOTION_TYPEDEF_TPL(MotionPlanarTpl);
63
64
    
    typedef CartesianAxis<2> AxisZ;
65

66
    MotionPlanarTpl() {}
67
    
68
69
    MotionPlanarTpl(const Scalar & x_dot, const Scalar & y_dot,
                    const Scalar & theta_dot)
70
71
72
    {
      m_data << x_dot, y_dot, theta_dot;
    }
73
74
75
    
    template<typename Vector3Like>
    MotionPlanarTpl(const Eigen::MatrixBase<Vector3Like> & vj)
76
    : m_data(vj)
77
78
79
    {
      EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector3Like,3);
    }
80

81
82
    inline PlainReturnType plain() const
    {
83
84
      return PlainReturnType(typename PlainReturnType::Vector3(vx(),vy(),Scalar(0)),
                             typename PlainReturnType::Vector3(Scalar(0),Scalar(0),wz()));
85
    }
86
87
88
    
    template<typename Derived>
    void addTo(MotionDense<Derived> & other) const
89
    {
90
91
92
      other.linear()[0] += vx();
      other.linear()[1] += vy();
      other.angular()[2] += wz();
93
    }
94
    
95
96
    template<typename MotionDerived>
    void setTo(MotionDense<MotionDerived> & other) const
97
    {
98
99
      other.linear()  <<   vx(),   vy(),   (Scalar)0;
      other.angular() << (Scalar)0, (Scalar)0, wz();
100
    }
101
102
103
104
    
    template<typename S2, int O2, typename D2>
    void se3Action_impl(const SE3Tpl<S2,O2> & m, MotionDense<D2> & v) const
    {
105
106
107
      v.angular().noalias() = m.rotation().col(2) * wz();
      v.linear().noalias() = m.rotation().template leftCols<2>() * m_data.template head<2>();
      v.linear() += m.translation().cross(v.angular());
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
    }
    
    template<typename S2, int O2>
    MotionPlain se3Action_impl(const SE3Tpl<S2,O2> & m) const
    {
      MotionPlain res;
      se3Action_impl(m,res);
      return res;
    }
    
    template<typename S2, int O2, typename D2>
    void se3ActionInverse_impl(const SE3Tpl<S2,O2> & m, MotionDense<D2> & v) const
    {
      // Linear
      // TODO: use v.angular() as temporary variable
      Vector3 v3_tmp;
124
125
      AxisZ::alphaCross(wz(),m.translation(),v3_tmp);
      v3_tmp[0] += vx(); v3_tmp[1] += vy();
126
127
128
      v.linear().noalias() = m.rotation().transpose() * v3_tmp;
      
      // Angular
129
      v.angular().noalias() = m.rotation().transpose().col(2) * wz();
130
131
132
133
134
135
136
137
138
139
140
141
142
143
    }
    
    template<typename S2, int O2>
    MotionPlain se3ActionInverse_impl(const SE3Tpl<S2,O2> & m) const
    {
      MotionPlain res;
      se3ActionInverse_impl(m,res);
      return res;
    }
    
    template<typename M1, typename M2>
    void motionAction(const MotionDense<M1> & v, MotionDense<M2> & mout) const
    {
      // Linear
144
      AxisZ::alphaCross(-wz(),v.linear(),mout.linear());
145
146
147
148
      
      typename M1::ConstAngularType w_in = v.angular();
      typename M2::LinearType v_out = mout.linear();
      
149
150
151
      v_out[0] -= w_in[2] * vy();
      v_out[1] += w_in[2] * vx();
      v_out[2] += -w_in[1] * vx() + w_in[0] * vy() ;
152
153
      
      // Angular
154
      AxisZ::alphaCross(-wz(),v.angular(),mout.angular());
155
156
157
158
159
160
161
162
163
    }
    
    template<typename M1>
    MotionPlain motionAction(const MotionDense<M1> & v) const
    {
      MotionPlain res;
      motionAction(v,res);
      return res;
    }
164

165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
    const Scalar & vx() const { return m_data[0]; }
    Scalar & vx() { return m_data[0]; }
    
    const Scalar & vy() const { return m_data[1]; }
    Scalar & vy() { return m_data[1]; }
    
    const Scalar & wz() const { return m_data[2]; }
    Scalar & wz() { return m_data[2]; }
    
    const Vector3 & data() const { return m_data; }
    Vector3 & data() { return m_data; }
    
    bool isEqual_impl(const MotionPlanarTpl & other) const
    {
      return m_data == other.m_data;
    }
    
  protected:
    
    Vector3 m_data;
185
    
186
  }; // struct MotionPlanarTpl
187
  
188
189
190
  template<typename Scalar, int Options, typename MotionDerived>
  inline typename MotionDerived::MotionPlain
  operator+(const MotionPlanarTpl<Scalar,Options> & m1, const MotionDense<MotionDerived> & m2)
191
  {
192
    typename MotionDerived::MotionPlain result(m2);
193
194
    result.linear()[0] += m1.vx();
    result.linear()[1] += m1.vy();
195

196
    result.angular()[2] += m1.wz();
197

198
199
    return result;
  }
200

201
202
203
204
  template<typename Scalar, int Options> struct ConstraintPlanarTpl;
  
  template<typename _Scalar, int _Options>
  struct traits< ConstraintPlanarTpl<_Scalar,_Options> >
205
  {
206
207
    typedef _Scalar Scalar;
    enum { Options = _Options };
208
209
210
211
    enum {
      LINEAR = 0,
      ANGULAR = 3
    };
212
    typedef MotionPlanarTpl<Scalar,Options> JointMotion;
213
214
    typedef Eigen::Matrix<Scalar,3,1,Options> JointForce;
    typedef Eigen::Matrix<Scalar,6,3,Options> DenseBase;
215
216
    typedef DenseBase MatrixReturnType;
    typedef const DenseBase ConstMatrixReturnType;
217
  }; // struct traits ConstraintPlanarTpl
218

219
  template<typename _Scalar, int _Options>
220
221
  struct ConstraintPlanarTpl
  : ConstraintBase< ConstraintPlanarTpl<_Scalar,_Options> >
222
  {
223
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
224
    PINOCCHIO_CONSTRAINT_TYPEDEF_TPL(ConstraintPlanarTpl)
225
    
226
    enum { NV = 3 };
227
228
    
    ConstraintPlanarTpl() {};
229

230
231
232
233
234
235
    template<typename Vector3Like>
    JointMotion __mult__(const Eigen::MatrixBase<Vector3Like> & vj) const
    {
      EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector3Like,3);
      return JointMotion(vj);
    }
236

237
238
    int nv_impl() const { return NV; }

239
240
    struct ConstraintTranspose
    {
241
242
      const ConstraintPlanarTpl & ref;
      ConstraintTranspose(const ConstraintPlanarTpl & ref) : ref(ref) {}
243

244
245
      template<typename Derived>
      typename ForceDense<Derived>::Vector3 operator* (const ForceDense<Derived> & phi)
246
      {
247
248
        typedef typename ForceDense<Derived>::Vector3 Vector3;
        return Vector3(phi.linear()[0], phi.linear()[1], phi.angular()[2]);
249
250
      }

251
      /* [CRBA]  MatrixBase operator* (Constraint::Transpose S, ForceSet::Block) */
252
253
254
      template<typename Derived>
      friend typename Eigen::Matrix <typename Eigen::MatrixBase<Derived>::Scalar, 3, Derived::ColsAtCompileTime>
      operator*(const ConstraintTranspose &, const Eigen::MatrixBase<Derived> & F)
255
      {
256
257
        typedef typename Eigen::MatrixBase<Derived>::Scalar Scalar;
        typedef Eigen::Matrix<Scalar, 3, Derived::ColsAtCompileTime> MatrixReturnType;
258
        assert(F.rows()==6);
259

260
261
262
        MatrixReturnType result(3, F.cols ());
        result.template topRows<2>() = F.template topRows<2>();
        result.template bottomRows<1>() = F.template bottomRows<1>();
263
        return result;
264
      }
265
      
266
    }; // struct ConstraintTranspose
267

268
    ConstraintTranspose transpose () const { return ConstraintTranspose(*this); }
269

270
    DenseBase matrix_impl() const
271
    {
272
      DenseBase S;
273
274
275
276
277
      S.template block<3,3>(Inertia::LINEAR, 0).setZero ();
      S.template block<3,3>(Inertia::ANGULAR, 0).setZero ();
      S(Inertia::LINEAR + 0,0) = Scalar(1);
      S(Inertia::LINEAR + 1,1) = Scalar(1);
      S(Inertia::ANGULAR + 2,2) = Scalar(1);
278
      return S;
279
280
    }

281
282
    template<typename S1, int O1>
    DenseBase se3Action(const SE3Tpl<S1,O1> & m) const
283
    {
284
      DenseBase X_subspace;
285
286
      
      // LINEAR
287
      X_subspace.template block <3,2>(Motion::LINEAR, 0) = m.rotation ().template leftCols <2> ();
288
289
      X_subspace.template block <3,1>(Motion::LINEAR, 2).noalias()
      = m.translation().cross(m.rotation ().template rightCols<1>());
290

291
      // ANGULAR
292
293
      X_subspace.template block <3,2>(Motion::ANGULAR, 0).setZero ();
      X_subspace.template block <3,1>(Motion::ANGULAR, 2) = m.rotation ().template rightCols<1>();
294
295

      return X_subspace;
296
    }
297
298
299
300
301
302
303
304
    
    template<typename S1, int O1>
    DenseBase se3ActionInverse(const SE3Tpl<S1,O1> & m) const
    {
      DenseBase X_subspace;
      
      // LINEAR
      X_subspace.template block <3,2>(Motion::LINEAR, 0) = m.rotation().transpose().template leftCols <2>();
305
306
      X_subspace.template block <3,1>(Motion::ANGULAR,2).noalias() = m.rotation().transpose() * m.translation(); // tmp variable
      X_subspace.template block <3,1>(Motion::LINEAR, 2).noalias() = -X_subspace.template block <3,1>(Motion::ANGULAR,2).cross(m.rotation().transpose().template rightCols<1>());
307
308
309
310
311
312
313
      
      // ANGULAR
      X_subspace.template block <3,2>(Motion::ANGULAR, 0).setZero();
      X_subspace.template block <3,1>(Motion::ANGULAR, 2) = m.rotation().transpose().template rightCols<1>();
      
      return X_subspace;
    }
314

315
316
    template<typename MotionDerived>
    DenseBase motionAction(const MotionDense<MotionDerived> & m) const
317
    {
318
319
      const typename MotionDerived::ConstLinearType v = m.linear();
      const typename MotionDerived::ConstAngularType w = m.angular();
320
321
322
323
324
325
326
327
328
329
      DenseBase res(DenseBase::Zero());
      
      res(0,1) = -w[2]; res(0,2) = v[1];
      res(1,0) = w[2]; res(1,2) = -v[0];
      res(2,0) = -w[1]; res(2,1) = w[0];
      res(3,2) = w[1];
      res(4,2) = -w[0];
      
      return res;
    }
330
331
332
    
    bool isEqual(const ConstraintPlanarTpl &)  const { return true; }
    
333
  }; // struct ConstraintPlanarTpl
334

335
  template<typename MotionDerived, typename S2, int O2>
336
337
  inline typename MotionDerived::MotionPlain
  operator^(const MotionDense<MotionDerived> & m1, const MotionPlanarTpl<S2,O2> & m2)
338
  {
339
    return m2.motionAction(m1);
340
341
342
  }

  /* [CRBA] ForceSet operator* (Inertia Y,Constraint S) */
343
344
345
  template<typename S1, int O1, typename S2, int O2>
  inline typename Eigen::Matrix<S1,6,3,O1>
  operator*(const InertiaTpl<S1,O1> & Y, const ConstraintPlanarTpl<S2,O2> &)
346
  {
347
348
349
350
351
352
353
354
    typedef InertiaTpl<S1,O1> Inertia;
    typedef typename Inertia::Scalar Scalar;
    typedef Eigen::Matrix<S1,6,3,O1> ReturnType;
    
    ReturnType M;
    const Scalar mass = Y.mass();
    const typename Inertia::Vector3 & com = Y.lever();
    const typename Inertia::Symmetric3 & inertia = Y.inertia();
355

356
357
    M.template topLeftCorner<3,3>().setZero();
    M.template topLeftCorner<2,2>().diagonal().fill(mass);
358

359
360
    const typename Inertia::Vector3 mc(mass * com);
    M.template rightCols<1>().template head<2>() << -mc(1), mc(0);
361

362
    M.template bottomLeftCorner<3,2>() << (Scalar)0, -mc(2), mc(2), (Scalar)0, -mc(1), mc(0);
363
364
365
366
    M.template rightCols<1>().template tail<3>() = inertia.data().template tail<3>();
    M.template rightCols<1>()[3] -= mc(0)*com(2);
    M.template rightCols<1>()[4] -= mc(1)*com(2);
    M.template rightCols<1>()[5] += mass*(com(0)*com(0) + com(1)*com(1));
367
368
369

    return M;
  }
370
371
372
  
  /* [ABA] Y*S operator (Inertia Y,Constraint S) */
  //  inline Eigen::Matrix<double,6,1>
373
374
375
376
377
  
  template<typename M6Like, typename S2, int O2>
  inline Eigen::Matrix<S2,6,3,O2>
  operator*(const Eigen::MatrixBase<M6Like> & Y,
            const ConstraintPlanarTpl<S2,O2> &)
378
  {
379
380
    EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_SIZE(M6Like,6,6);
    typedef Eigen::Matrix<S2,6,3,O2> Matrix63;
381
    
382
383
384
    Matrix63 IS;
    IS.template leftCols<2>() = Y.template leftCols<2>();
    IS.template rightCols<1>() = Y.template rightCols<1>();
385
386
387
388
    
    return IS;
  }
  
389
390
391
392
393
394
395
  template<typename S1, int O1>
  struct SE3GroupAction< ConstraintPlanarTpl<S1,O1> >
  { typedef Eigen::Matrix<S1,6,3,O1> ReturnType; };
  
  template<typename S1, int O1, typename MotionDerived>
  struct MotionAlgebraAction< ConstraintPlanarTpl<S1,O1>,MotionDerived >
  { typedef Eigen::Matrix<S1,6,3,O1> ReturnType; };
396

397
398
399
400
  template<typename Scalar, int Options> struct JointPlanarTpl;
  
  template<typename _Scalar, int _Options>
  struct traits< JointPlanarTpl<_Scalar,_Options> >
401
  {
402
    enum {
403
      NQ = 4,
404
405
      NV = 3
    };
406
407
408
409
    enum { Options = _Options };
    typedef _Scalar Scalar;
    typedef JointDataPlanarTpl<Scalar,Options> JointDataDerived;
    typedef JointModelPlanarTpl<Scalar,Options> JointModelDerived;
410
    typedef ConstraintPlanarTpl<Scalar,Options> Constraint_t;
411
    typedef SE3Tpl<Scalar,Options> Transformation_t;
412
    typedef MotionPlanarTpl<Scalar,Options> Motion_t;
413
    typedef MotionZeroTpl<Scalar,Options> Bias_t;
Justin Carpentier's avatar
Justin Carpentier committed
414

415
    // [ABA]
416
417
418
    typedef Eigen::Matrix<Scalar,6,NV,Options> U_t;
    typedef Eigen::Matrix<Scalar,NV,NV,Options> D_t;
    typedef Eigen::Matrix<Scalar,6,NV,Options> UD_t;
419
    
Gabriele Buondonno's avatar
Gabriele Buondonno committed
420
    PINOCCHIO_JOINT_DATA_BASE_ACCESSOR_DEFAULT_RETURN_TYPE
421

422
423
    typedef Eigen::Matrix<Scalar,NQ,1,Options> ConfigVector_t;
    typedef Eigen::Matrix<Scalar,NV,1,Options> TangentVector_t;
424
  };
425
426
427
428
429
  
  template<typename Scalar, int Options>
  struct traits< JointDataPlanarTpl<Scalar,Options> > { typedef JointPlanarTpl<Scalar,Options> JointDerived; };
  template<typename Scalar, int Options>
  struct traits< JointModelPlanarTpl<Scalar,Options> > { typedef JointPlanarTpl<Scalar,Options> JointDerived; };
430

431
432
  template<typename _Scalar, int _Options>
  struct JointDataPlanarTpl : public JointDataBase< JointDataPlanarTpl<_Scalar,_Options> >
433
  {
434
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
435
    typedef JointPlanarTpl<_Scalar,_Options> JointDerived;
436
    PINOCCHIO_JOINT_DATA_TYPEDEF_TEMPLATE(JointDerived);
Gabriele Buondonno's avatar
Gabriele Buondonno committed
437
    PINOCCHIO_JOINT_DATA_BASE_DEFAULT_ACCESSOR
438
439
440
441
442
443
    
    Constraint_t S;
    Transformation_t M;
    Motion_t v;
    Bias_t c;

444
445
446
447
    // [ABA] specific data
    U_t U;
    D_t Dinv;
    UD_t UDinv;
448
449
    
    D_t StU;
450

451
    JointDataPlanarTpl ()
452
453
    : M(Transformation_t::Identity())
    , v(Motion_t::Vector3::Zero())
454
455
456
457
    , U(U_t::Zero())
    , Dinv(D_t::Zero())
    , UDinv(UD_t::Zero())
    {}
458

459
460
461
    static std::string classname() { return std::string("JointDataPlanar"); }
    std::string shortname() const { return classname(); }
    
462
  }; // struct JointDataPlanarTpl
463

Gabriele Buondonno's avatar
Gabriele Buondonno committed
464
  PINOCCHIO_JOINT_CAST_TYPE_SPECIALIZATION(JointModelPlanarTpl);
465
  template<typename _Scalar, int _Options>
jcarpent's avatar
jcarpent committed
466
467
  struct JointModelPlanarTpl
  : public JointModelBase< JointModelPlanarTpl<_Scalar,_Options> >
468
  {
469
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
470
    typedef JointPlanarTpl<_Scalar,_Options> JointDerived;
471
    PINOCCHIO_JOINT_TYPEDEF_TEMPLATE(JointDerived);
jcarpent's avatar
jcarpent committed
472
473
474
475
476
477
    
    typedef JointModelBase<JointModelPlanarTpl> Base;
    using Base::id;
    using Base::idx_q;
    using Base::idx_v;
    using Base::setIndexes;
478

479
    JointDataDerived createData() const { return JointDataDerived(); }
jcarpent's avatar
jcarpent committed
480
    
481
482
    template<typename ConfigVector>
    inline void forwardKinematics(Transformation_t & M, const Eigen::MatrixBase<ConfigVector> & q_joint) const
jcarpent's avatar
jcarpent committed
483
    {
484
485
486
      const Scalar
      & c_theta = q_joint(2),
      & s_theta = q_joint(3);
jcarpent's avatar
jcarpent committed
487
      
488
489
      M.rotation().template topLeftCorner<2,2>() << c_theta, -s_theta, s_theta, c_theta;
      M.translation().template head<2>() = q_joint.template head<2>();
jcarpent's avatar
jcarpent committed
490
    }
491

492
493
494
    template<typename ConfigVector>
    void calc(JointDataDerived & data,
              const typename Eigen::MatrixBase<ConfigVector> & qs) const
495
    {
496
497
      typedef typename ConfigVector::Scalar Scalar;
      typename ConfigVector::template ConstFixedSegmentReturnType<NQ>::Type & q = qs.template segment<NQ>(idx_q());
498

499
500
501
      const Scalar
      &c_theta = q(2),
      &s_theta = q(3);
502

503
504
      data.M.rotation().template topLeftCorner<2,2>() << c_theta, -s_theta, s_theta, c_theta;
      data.M.translation().template head<2>() = q.template head<2>();
505
506
507

    }

508
509
510
511
    template<typename ConfigVector, typename TangentVector>
    void calc(JointDataDerived & data,
              const typename Eigen::MatrixBase<ConfigVector> & qs,
              const typename Eigen::MatrixBase<TangentVector> & vs) const
512
    {
513
514
515
      calc(data,qs.derived());
      
      typename TangentVector::template ConstFixedSegmentReturnType<NV>::Type & q_dot = vs.template segment<NV>(idx_v ());
516

517
518
519
      data.v.vx() = q_dot(0);
      data.v.vy() = q_dot(1);
      data.v.wz() = q_dot(2);
520
    }
521
    
522
    template<typename Matrix6Like>
523
524
525
    void calc_aba(JointDataDerived & data,
                  const Eigen::MatrixBase<Matrix6Like> & I,
                  const bool update_I) const
526
    {
527
528
      data.U.template leftCols<2>() = I.template leftCols<2>();
      data.U.template rightCols<1>() = I.template rightCols<1>();
529
530
531

      data.StU.template leftCols<2>() = data.U.template topRows<2>().transpose();
      data.StU.template rightCols<1>() = data.U.template bottomRows<1>();
532
533
      
      // compute inverse
534
535
536
//      data.Dinv.setIdentity();
//      data.StU.llt().solveInPlace(data.Dinv);
      internal::PerformStYSInversion<Scalar>::run(data.StU,data.Dinv);
537
      
538
      data.UDinv.noalias() = data.U * data.Dinv;
539
      
540
541
      if(update_I)
        PINOCCHIO_EIGEN_CONST_CAST(Matrix6Like,I).noalias() -= data.UDinv * data.U.transpose();
542
    }
543
    
544
545
    static std::string classname() { return std::string("JointModelPlanar");}
    std::string shortname() const { return classname(); }
546
547
548
549
550
551
552
553
554
555
    
    /// \returns An expression of *this with the Scalar type casted to NewScalar.
    template<typename NewScalar>
    JointModelPlanarTpl<NewScalar,Options> cast() const
    {
      typedef JointModelPlanarTpl<NewScalar,Options> ReturnType;
      ReturnType res;
      res.setIndexes(id(),idx_q(),idx_v());
      return res;
    }
556

557
  }; // struct JointModelPlanarTpl
558

559
} // namespace pinocchio
560

561
562
563
564
565
#include <boost/type_traits.hpp>

namespace boost
{
  template<typename Scalar, int Options>
566
  struct has_nothrow_constructor< ::pinocchio::JointModelPlanarTpl<Scalar,Options> >
567
568
569
  : public integral_constant<bool,true> {};
  
  template<typename Scalar, int Options>
570
  struct has_nothrow_copy< ::pinocchio::JointModelPlanarTpl<Scalar,Options> >
571
572
573
  : public integral_constant<bool,true> {};
  
  template<typename Scalar, int Options>
574
  struct has_nothrow_constructor< ::pinocchio::JointDataPlanarTpl<Scalar,Options> >
575
576
577
  : public integral_constant<bool,true> {};
  
  template<typename Scalar, int Options>
578
  struct has_nothrow_copy< ::pinocchio::JointDataPlanarTpl<Scalar,Options> >
579
580
581
  : public integral_constant<bool,true> {};
}

582
#endif // ifndef __pinocchio_joint_planar_hpp__