GCC Code Coverage Report


Directory: ./
File: include/pinocchio/algorithm/constraints/coulomb-friction-cone.hpp
Date: 2025-02-12 21:03:38
Exec Total Coverage
Lines: 74 92 80.4%
Branches: 64 162 39.5%

Line Branch Exec Source
1 //
2 // Copyright (c) 2022 INRIA
3 //
4
5 #ifndef __pinocchio_algorithm_constraints_coulomb_friction_cone_hpp__
6 #define __pinocchio_algorithm_constraints_coulomb_friction_cone_hpp__
7
8 #include "pinocchio/algorithm/constraints/fwd.hpp"
9 #include "pinocchio/math/fwd.hpp"
10 #include "pinocchio/math/comparison-operators.hpp"
11
12 namespace pinocchio
13 {
14
15 template<typename Scalar>
16 struct DualCoulombFrictionConeTpl;
17
18 ///  \brief 3d Coulomb friction cone.
19 template<typename _Scalar>
20 struct CoulombFrictionConeTpl
21 {
22 typedef _Scalar Scalar;
23 typedef DualCoulombFrictionConeTpl<Scalar> DualCone;
24 typedef Eigen::Matrix<Scalar, 3, 1> Vector3;
25
26 /// \brief Default constructor
27 ///
28 /// \param[in] mu Friction coefficient
29 15 explicit CoulombFrictionConeTpl(const Scalar mu)
30 15 : mu(mu)
31 {
32
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 assert(mu >= 0 && "mu must be positive");
33 15 }
34
35 /// \brief Copy constructor.
36 CoulombFrictionConeTpl(const CoulombFrictionConeTpl & other) = default;
37
38 /// \brief Copy operator
39 CoulombFrictionConeTpl & operator=(const CoulombFrictionConeTpl & other) = default;
40
41 /// \brief Comparison operator
42 bool operator==(const CoulombFrictionConeTpl & other) const
43 {
44 return mu == other.mu;
45 }
46
47 /// \brief Difference operator
48 bool operator!=(const CoulombFrictionConeTpl & other) const
49 {
50 return !(*this == other);
51 }
52
53 /// \brief Check whether a vector x lies within the cone.
54 ///
55 /// \param[in] f vector to check (assimilated to a force vector).
56 ///
57 template<typename Vector3Like>
58 800002 bool isInside(const Eigen::MatrixBase<Vector3Like> & f, const Scalar prec = Scalar(0)) const
59 {
60
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 400001 times.
800002 assert(mu >= 0 && "mu must be positive");
61
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 400001 times.
800002 assert(prec >= 0 && "prec should be positive");
62 EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector3Like, 3);
63
2/4
✓ Branch 2 taken 400001 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 400001 times.
✗ Branch 6 not taken.
800002 return f.template head<2>().norm() <= mu * f[2] + prec;
64 }
65
66 /// \brief Project a vector x onto the cone.
67 ///
68 /// \param[in] x a 3d vector to project.
69 ///
70 template<typename Vector3Like>
71 typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like)
72 400010 project(const Eigen::MatrixBase<Vector3Like> & x) const
73 {
74
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 200009 times.
400010 assert(mu >= 0 && "mu must be positive");
75 EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector3Like, 3);
76 typedef typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like) Vector3Plain;
77
1/2
✓ Branch 1 taken 200009 times.
✗ Branch 2 not taken.
400010 const Scalar & z = x[2];
78 400010 const Scalar mu_z = mu * z;
79
80
2/4
✓ Branch 1 taken 200009 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 200009 times.
✗ Branch 5 not taken.
400010 const Eigen::Matrix<Scalar, 2, 1> t = x.template head<2>();
81
1/2
✓ Branch 1 taken 200009 times.
✗ Branch 2 not taken.
400010 const Scalar t_norm = t.norm();
82
83
2/2
✓ Branch 0 taken 69179 times.
✓ Branch 1 taken 130830 times.
400010 if (mu * t_norm <= -z)
84
2/4
✓ Branch 1 taken 69179 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 69179 times.
✗ Branch 5 not taken.
138350 return Vector3Plain::Zero();
85
2/2
✓ Branch 0 taken 54212 times.
✓ Branch 1 taken 76618 times.
261660 else if (t_norm <= mu_z)
86 {
87
1/2
✓ Branch 1 taken 54212 times.
✗ Branch 2 not taken.
108424 return x;
88 }
89 else
90 {
91
1/2
✓ Branch 1 taken 76618 times.
✗ Branch 2 not taken.
153236 Vector3Plain res;
92
3/6
✓ Branch 1 taken 76618 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 76618 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 76618 times.
✗ Branch 8 not taken.
153236 res.template head<2>() = (mu / t_norm) * t;
93
1/2
✓ Branch 1 taken 76618 times.
✗ Branch 2 not taken.
153236 res[2] = 1;
94
1/2
✓ Branch 1 taken 76618 times.
✗ Branch 2 not taken.
153236 res.normalize();
95
1/2
✓ Branch 1 taken 76618 times.
✗ Branch 2 not taken.
153236 const Scalar scale = x.dot(res);
96
1/2
✓ Branch 1 taken 76618 times.
✗ Branch 2 not taken.
153236 res *= scale;
97 153236 return res;
98 }
99 }
100
101 /// \brief Project a vector x onto the cone with a matric specified by the diagonal matrix R.
102 ///
103 /// \param[in] x a 3d vector to project.
104 /// \param[in] R a 3d vector representing the diagonal of the weights matrix. The tangential
105 /// components (the first two) of R should be equal.
106 ///
107 template<typename Vector3Like>
108 8 typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like) weightedProject(
109 const Eigen::MatrixBase<Vector3Like> & x, const Eigen::MatrixBase<Vector3Like> & R) const
110 {
111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 assert(mu >= 0 && "mu must be positive");
112 EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector3Like, 3);
113 typedef typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like) Vector3Plain;
114
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
8 assert(R(2) > 0 && "R(2) must be strictly positive");
115
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 Scalar weighted_mu = mu * math::sqrt(R(0) / R(2));
116 8 CoulombFrictionConeTpl weighted_cone(weighted_mu);
117
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 Vector3Plain R_sqrt = R.cwiseSqrt();
118
5/10
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 8 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 8 times.
✗ Branch 14 not taken.
8 Vector3Plain R_sqrt_times_x = (R_sqrt.array() * x.array()).matrix();
119
6/12
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 8 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 8 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 8 times.
✗ Branch 17 not taken.
8 Vector3Plain res = (weighted_cone.project(R_sqrt_times_x).array() / R_sqrt.array()).matrix();
120 16 return res;
121 }
122
123 /// \brief Compute the complementary shift associted to the Coulomb friction cone for
124 /// complementarity satisfaction in complementary problems.
125 ///
126 /// \param[in] v a dual vector.
127 ///
128 template<typename Vector3Like>
129 typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like)
130 8 computeNormalCorrection(const Eigen::MatrixBase<Vector3Like> & v) const
131 {
132 EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector3Like, 3);
133 typedef typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like) Vector3Plain;
134
135 8 Vector3Plain res;
136
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
8 res.template head<2>().setZero();
137
2/4
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
8 res[2] = mu * v.template head<2>().norm();
138
139 8 return res;
140 }
141
142 /// \brief Compute the radial projection associted to the Coulomb friction cone.
143 ///
144 /// \param[in] f a force vector.
145 ///
146 template<typename Vector3Like>
147 typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like)
148 200000 computeRadialProjection(const Eigen::MatrixBase<Vector3Like> & f) const
149 {
150 EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector3Like, 3);
151 typedef typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like) Vector3Plain;
152
153
1/2
✓ Branch 1 taken 200000 times.
✗ Branch 2 not taken.
200000 Vector3Plain res;
154
1/2
✓ Branch 1 taken 200000 times.
✗ Branch 2 not taken.
200000 const auto & ft = f.template head<2>();
155
1/2
✓ Branch 1 taken 200000 times.
✗ Branch 2 not taken.
200000 const Scalar ft_norm = ft.norm();
156
157
3/6
✓ Branch 1 taken 200000 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 200000 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 200000 times.
✗ Branch 8 not taken.
200000 res[2] = math::max(Scalar(0), f[2]);
158
1/2
✓ Branch 1 taken 200000 times.
✗ Branch 2 not taken.
200000 const Scalar mu_fz = mu * res[2];
159
2/2
✓ Branch 0 taken 107170 times.
✓ Branch 1 taken 92830 times.
200000 if (ft_norm > mu_fz)
160 {
161
3/6
✓ Branch 1 taken 107170 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 107170 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 107170 times.
✗ Branch 8 not taken.
107170 res.template head<2>() = Scalar(mu_fz / ft_norm) * ft;
162 }
163 else
164
2/4
✓ Branch 1 taken 92830 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 92830 times.
✗ Branch 5 not taken.
92830 res.template head<2>() = ft;
165
166 400000 return res;
167 }
168
169 template<typename Vector3Like1, typename Vector3Like2>
170 Scalar computeContactComplementarity(
171 const Eigen::MatrixBase<Vector3Like1> & v, const Eigen::MatrixBase<Vector3Like2> & f) const
172 {
173 typedef typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like1) Vector3Plain;
174 return math::fabs(f.dot(Vector3Plain(v + computeNormalCorrection(v))));
175 }
176
177 template<typename Vector3Like1, typename Vector3Like2>
178 Scalar computeConicComplementarity(
179 const Eigen::MatrixBase<Vector3Like1> & v, const Eigen::MatrixBase<Vector3Like2> & f) const
180 {
181 return math::fabs(f.dot(v));
182 }
183
184 /// \brief Returns the dual cone associated to this.
185 1 DualCone dual() const
186 {
187 1 return DualCone(mu);
188 }
189
190 /// \brief Returns the dimension of the cone.
191 static int dim()
192 {
193 return 3;
194 }
195
196 /// \var Friction coefficient
197 Scalar mu;
198 }; // CoulombFrictionConeTpl
199
200 ///  \brief Dual of the 3d Coulomb friction cone.
201 template<typename _Scalar>
202 struct DualCoulombFrictionConeTpl
203 {
204 typedef _Scalar Scalar;
205 typedef CoulombFrictionConeTpl<Scalar> DualCone;
206
207 /// \brief Default constructor
208 ///
209 /// \param[in] mu Friction coefficient
210 1 explicit DualCoulombFrictionConeTpl(const Scalar mu)
211 1 : mu(mu)
212 {
213
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 assert(mu >= 0 && "mu must be positive");
214 1 }
215
216 /// \brief Copy constructor.
217 DualCoulombFrictionConeTpl(const DualCoulombFrictionConeTpl & other) = default;
218
219 /// \brief Copy operator
220 DualCoulombFrictionConeTpl & operator=(const DualCoulombFrictionConeTpl & other) = default;
221
222 /// \brief Comparison operator
223 bool operator==(const DualCoulombFrictionConeTpl & other) const
224 {
225 return mu == other.mu;
226 }
227
228 /// \brief Difference operator
229 bool operator!=(const DualCoulombFrictionConeTpl & other) const
230 {
231 return !(*this == other);
232 }
233
234 /// \brief Check whether a vector v lies within the cone.
235 ///
236 /// \param[in] v vector to check (assimilated to a linear velocity).
237 ///
238 template<typename Vector3Like>
239 600002 bool isInside(const Eigen::MatrixBase<Vector3Like> & v, const Scalar prec = Scalar(0)) const
240 {
241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 300001 times.
600002 assert(mu >= 0 && "mu must be positive");
242 EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector3Like, 3);
243
2/4
✓ Branch 2 taken 300001 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 300001 times.
✗ Branch 6 not taken.
600002 return mu * v.template head<2>().norm() <= v[2] + prec;
244 }
245
246 /// \brief Project a vector x onto the cone
247 template<typename Vector3Like>
248 typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like)
249 200001 project(const Eigen::MatrixBase<Vector3Like> & x) const
250 {
251
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
200001 assert(mu >= 0 && "mu must be positive");
252 EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Vector3Like, 3);
253 typedef typename PINOCCHIO_EIGEN_PLAIN_TYPE(Vector3Like) Vector3Plain;
254
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
200001 const Scalar & z = x[2];
255
256
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
200001 const Eigen::Matrix<Scalar, 2, 1> t = x.template head<2>();
257
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
200001 const Scalar t_norm = t.norm();
258
259
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
200001 if (t_norm <= -mu * z)
260
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4045 return Vector3Plain::Zero();
261
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
195956 else if (mu * t_norm <= z)
262 {
263
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
116606 return x;
264 }
265 else
266 {
267
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
79350 Vector3Plain res;
268
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
79350 res.template head<2>() = t;
269
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
79350 res[2] = mu * t_norm;
270
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
79350 res.normalize();
271
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
79350 const Scalar scale = x.dot(res);
272
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
79350 res *= scale;
273 79350 return res;
274 }
275 }
276
277 /// \brief Returns the dimension of the cone.
278 static int dim()
279 {
280 return 3;
281 }
282
283 /// \brief Returns the dual cone associated to this. ///
284 DualCone dual() const
285 {
286 return DualCone(mu);
287 }
288
289 /// \var Friction coefficient
290 Scalar mu;
291
292 }; // DualCoulombFrictionConeTpl
293
294 } // namespace pinocchio
295
296 #endif // ifndef __pinocchio_algorithm_constraints_coulomb_friction_cone_hpp__
297