GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: include/pinocchio/bindings/python/spatial/inertia.hpp Lines: 49 81 60.5 %
Date: 2024-04-26 13:14:21 Branches: 72 240 30.0 %

Line Branch Exec Source
1
//
2
// Copyright (c) 2015-2023 CNRS INRIA
3
// Copyright (c) 2016 Wandercraft, 86 rue de Paris 91400 Orsay, France.
4
//
5
6
#ifndef __pinocchio_python_spatial_inertia_hpp__
7
#define __pinocchio_python_spatial_inertia_hpp__
8
9
#include <eigenpy/exception.hpp>
10
#include <eigenpy/eigenpy.hpp>
11
#include <eigenpy/memory.hpp>
12
#include <boost/python/tuple.hpp>
13
14
#include "pinocchio/spatial/inertia.hpp"
15
#include "pinocchio/bindings/python/fwd.hpp"
16
#include "pinocchio/bindings/python/utils/copyable.hpp"
17
#include "pinocchio/bindings/python/utils/printable.hpp"
18
19
#if EIGENPY_VERSION_AT_MOST(2,8,1)
20
EIGENPY_DEFINE_STRUCT_ALLOCATOR_SPECIALIZATION(pinocchio::Inertia)
21
#endif
22
23
namespace pinocchio
24
{
25
  namespace python
26
  {
27
    namespace bp = boost::python;
28
29
    template<typename T> struct call;
30
31
    template<typename Scalar, int Options>
32
    struct call< InertiaTpl<Scalar,Options> >
33
    {
34
      typedef InertiaTpl<Scalar,Options> Inertia;
35
36
      static bool isApprox(const Inertia & self, const Inertia & other,
37
                           const Scalar & prec = Eigen::NumTraits<Scalar>::dummy_precision())
38
      {
39
        return self.isApprox(other,prec);
40
      }
41
42
      static bool isZero(const Inertia & self,
43
                         const Scalar & prec = Eigen::NumTraits<Scalar>::dummy_precision())
44
      {
45
        return self.isZero(prec);
46
      }
47
    };
48
49
✗✗
38
    BOOST_PYTHON_FUNCTION_OVERLOADS(isApproxInertia_overload,call<Inertia>::isApprox,2,3)
50
    BOOST_PYTHON_FUNCTION_OVERLOADS(isZero_overload,call<Inertia>::isZero,1,2)
51
52
    template<typename Inertia>
53
    struct InertiaPythonVisitor
54
      : public boost::python::def_visitor< InertiaPythonVisitor<Inertia> >
55
    {
56
57
      typedef typename Inertia::Scalar Scalar;
58
      typedef typename Inertia::Vector3 Vector3;
59
      typedef typename Inertia::Matrix3 Matrix3;
60
      typedef typename Inertia::Vector6 Vector6;
61
      typedef typename Inertia::Matrix6 Matrix6;
62
63
    public:
64
65
      template<class PyClass>
66
19
      void visit(PyClass& cl) const
67
      {
68
        cl
69
        .def("__init__",
70
             bp::make_constructor(&InertiaPythonVisitor::makeFromMCI,
71
                                  bp::default_call_policies(),
72
                                  bp::args("mass","lever","inertia")),
73
             "Initialize from mass, lever and 3d inertia.")
74
✓✗✓✗
38
        .def(bp::init<Inertia>(bp::args("self","other"),"Copy constructor."))
75
76
✓✗✓✗
✓✗
38
        .add_property("mass",
77
                      &InertiaPythonVisitor::getMass,
78
                      &InertiaPythonVisitor::setMass,
79
                      "Mass of the Spatial Inertia.")
80
✓✗
19
        .add_property("lever",
81
                      bp::make_function((typename Inertia::Vector3 & (Inertia::*)())&Inertia::lever,
82
                                        bp::return_internal_reference<>()),
83
                      &InertiaPythonVisitor::setLever,
84
                      "Center of mass location of the Spatial Inertia. It corresponds to the location of the center of mass regarding to the frame where the Spatial Inertia is expressed.")
85
✓✗✓✗
38
        .add_property("inertia",
86
                      &InertiaPythonVisitor::getInertia,
87
                      &InertiaPythonVisitor::setInertia,
88
                      "Rotational part of the Spatial Inertia, i.e. a symmetric matrix representing the rotational inertia around the center of mass.")
89
90
✓✗
19
        .def("matrix",&Inertia::matrix,bp::arg("self"))
91
✓✗
38
        .def("se3Action",&Inertia::se3Action,
92
             bp::args("self","M"),"Returns the result of the action of M on *this.")
93
✓✗✓✗
38
        .def("se3ActionInverse",&Inertia::se3ActionInverse,
94
             bp::args("self","M"),"Returns the result of the action of the inverse of M on *this.")
95
96
✓✗✓✗
38
        .def("setIdentity",&Inertia::setIdentity,bp::arg("self"),
97
             "Set *this to be the Identity inertia.")
98
✓✗✓✗
38
        .def("setZero",&Inertia::setZero,bp::arg("self"),
99
             "Set all the components of *this to zero.")
100
✓✗✓✗
38
        .def("setRandom",&Inertia::setRandom,bp::arg("self"),
101
             "Set all the components of *this to random values.")
102
103
✓✗✓✗
57
        .def(bp::self + bp::self)
104
✓✗✓✗
38
        .def(bp::self * bp::other<Motion>() )
105
✓✗
19
        .add_property("np",&Inertia::matrix)
106
38
        .def("vxiv",&Inertia::vxiv,bp::args("self","v"),"Returns the result of v x Iv.")
107
✓✗✓✗
38
        .def("vtiv",&Inertia::vtiv,bp::args("self","v"),"Returns the result of v.T * Iv.")
108
✓✗✓✗
38
        .def("vxi",(Matrix6 (Inertia::*)(const Motion &) const)&Inertia::vxi,
109
             bp::args("self","v"),
110
             "Returns the result of v x* I, a 6x6 matrix.")
111
✓✗✓✗
38
        .def("ivx",(Matrix6 (Inertia::*)(const Motion &) const)&Inertia::ivx,
112
             bp::args("self","v"),
113
             "Returns the result of I vx, a 6x6 matrix.")
114
✓✗✓✗
38
        .def("variation",(Matrix6 (Inertia::*)(const Motion &) const)&Inertia::variation,
115
             bp::args("self","v"),
116
             "Returns the time derivative of the inertia.")
117
118
✓✗✓✗
✓✗
38
        .def(bp::self == bp::self)
119
✓✗
19
        .def(bp::self != bp::self)
120
121
✓✗
19
        .def("isApprox",
122
             call<Inertia>::isApprox,
123
             isApproxInertia_overload(bp::args("self","other","prec"),
124
                                      "Returns true if *this is approximately equal to other, within the precision given by prec."))
125
126
✓✗✓✗
✓✗
38
        .def("isZero",
127
             call<Inertia>::isZero,
128
             isZero_overload(bp::args("self","prec"),
129
                             "Returns true if *this is approximately equal to the zero Inertia, within the precision given by prec."))
130
131
✓✗✓✗
✓✗
38
        .def("Identity",&Inertia::Identity,"Returns the identity Inertia.")
132
✓✗
19
        .staticmethod("Identity")
133
✓✗
19
        .def("Zero",&Inertia::Zero,"Returns the null Inertia.")
134
✓✗
19
        .staticmethod("Zero")
135
✓✗
19
        .def("Random",&Inertia::Random,"Returns a random Inertia.")
136
✓✗
19
        .staticmethod("Random")
137
138
✓✗
19
        .def("toDynamicParameters",&InertiaPythonVisitor::toDynamicParameters_proxy,bp::arg("self"),
139
             "Returns the representation of the matrix as a vector of dynamic parameters."
140
              "\nThe parameters are given as v = [m, mc_x, mc_y, mc_z, I_{xx}, I_{xy}, I_{yy}, I_{xz}, I_{yz}, I_{zz}]^T "
141
              "where I = I_C + mS^T(c)S(c) and I_C has its origin at the barycenter"
142
        )
143
✓✗✓✗
38
        .def("FromDynamicParameters",&Inertia::template FromDynamicParameters<Eigen::VectorXd>,
144
              bp::args("dynamic_parameters"),
145
              "Builds and inertia matrix from a vector of dynamic parameters."
146
              "\nThe parameters are given as dynamic_parameters = [m, mc_x, mc_y, mc_z, I_{xx}, I_{xy}, I_{yy}, I_{xz}, I_{yz}, I_{zz}]^T "
147
              "where I = I_C + mS^T(c)S(c) and I_C has its origin at the barycenter."
148
        )
149
✓✗✓✗
38
        .staticmethod("FromDynamicParameters")
150
151
✓✗
19
        .def("FromSphere", &Inertia::FromSphere,
152
             bp::args("mass","radius"),
153
             "Returns the Inertia of a sphere defined by a given mass and radius.")
154
✓✗✓✗
38
        .staticmethod("FromSphere")
155
✓✗
19
        .def("FromEllipsoid", &Inertia::FromEllipsoid,
156
             bp::args("mass","length_x","length_y","length_z"),
157
             "Returns the Inertia of an ellipsoid shape defined by a mass and given dimensions the semi-axis of values length_{x,y,z}.")
158
✓✗✓✗
38
        .staticmethod("FromEllipsoid")
159
✓✗
19
        .def("FromCylinder", &Inertia::FromCylinder,
160
             bp::args("mass","radius","length"),
161
             "Returns the Inertia of a cylinder defined by its mass, radius and length along the Z axis.")
162
✓✗✓✗
38
        .staticmethod("FromCylinder")
163
✓✗
19
        .def("FromBox", &Inertia::FromBox,
164
             bp::args("mass","length_x","length_y","length_z"),
165
             "Returns the Inertia of a box shape with a mass and of dimension the semi axis of length_{x,y,z}.")
166
✓✗✓✗
38
        .staticmethod("FromBox")
167
168
✓✗
19
        .def("__array__",&Inertia::matrix)
169
170
✓✗✓✗
19
        .def_pickle(Pickle())
171
        ;
172
19
      }
173
174
      static Scalar getMass( const Inertia & self ) { return self.mass(); }
175
      static void setMass( Inertia & self, Scalar mass ) { self.mass() = mass; }
176
177
      static void setLever( Inertia & self, const Vector3 & lever ) { self.lever() = lever; }
178
179
      static Matrix3 getInertia( const Inertia & self ) { return self.inertia().matrix(); }
180
//      static void setInertia(Inertia & self, const Vector6 & minimal_inertia) { self.inertia().data() = minimal_inertia; }
181
      static void setInertia(Inertia & self, const Matrix3 & symmetric_inertia)
182
      {
183
        assert(symmetric_inertia.isApprox(symmetric_inertia.transpose()));
184
        self.inertia().data() <<
185
        symmetric_inertia(0,0),
186
        symmetric_inertia(1,0),
187
        symmetric_inertia(1,1),
188
        symmetric_inertia(0,2),
189
        symmetric_inertia(1,2),
190
        symmetric_inertia(2,2);
191
      }
192
193
      static Eigen::VectorXd toDynamicParameters_proxy(const Inertia & self)
194
      {
195
        return self.toDynamicParameters();
196
      }
197
198
      static Inertia* makeFromMCI(const double & mass,
199
                                  const Vector3 & lever,
200
                                  const Matrix3 & inertia)
201
      {
202
        if(! inertia.isApprox(inertia.transpose()) )
203
          throw eigenpy::Exception("The 3d inertia should be symmetric.");
204
        if( (Eigen::Vector3d::UnitX().transpose()*inertia*Eigen::Vector3d::UnitX()<0)
205
           || (Eigen::Vector3d::UnitY().transpose()*inertia*Eigen::Vector3d::UnitY()<0)
206
           || (Eigen::Vector3d::UnitZ().transpose()*inertia*Eigen::Vector3d::UnitZ()<0) )
207
          throw eigenpy::Exception("The 3d inertia should be positive.");
208
        return new Inertia(mass,lever,inertia);
209
           }
210
211
19
      static void expose()
212
      {
213
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 6 && EIGENPY_VERSION_AT_LEAST(2,9,0)
214
    typedef PINOCCHIO_SHARED_PTR_HOLDER_TYPE(Inertia) HolderType;
215
#else
216
    typedef ::boost::python::detail::not_specified HolderType;
217
#endif
218
        bp::class_<Inertia,HolderType>("Inertia",
219
                            "This class represenses a sparse version of a Spatial Inertia and its is defined by its mass, its center of mass location and the rotational inertia expressed around this center of mass.\n\n"
220
                            "Supported operations ...",
221
                            bp::init<>(bp::arg("self"),"Default constructor."))
222
        .def(InertiaPythonVisitor<Inertia>())
223
✓✗✓✗
✓✗
38
        .def(CopyableVisitor<Inertia>())
224
✓✗✓✗
19
        .def(PrintableVisitor<Inertia>())
225
        ;
226
227
19
      }
228
229
    private:
230
231
      struct Pickle : bp::pickle_suite
232
      {
233
        static
234
        boost::python::tuple
235
        getinitargs(const Inertia & I)
236
        { return bp::make_tuple(I.mass(),(Vector3)I.lever(),I.inertia().matrix()); }
237
238
19
        static bool getstate_manages_dict() { return true; }
239
      };
240
241
242
    }; // struct InertiaPythonVisitor
243
244
  } // namespace python
245
} // namespace pinocchio
246
247
#endif // ifndef __pinocchio_python_spatial_inertia_hpp__