GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
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__ |
Generated by: GCOVR (Version 4.2) |