Directory: | ./ |
---|---|
File: | include/multicontact-api/geometry/linear-cone.hpp |
Date: | 2025-03-10 16:17:01 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 44 | 88 | 50.0% |
Branches: | 33 | 126 | 26.2% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright (c) 2015-2018, CNRS | ||
2 | // Authors: Justin Carpentier <jcarpent@laas.fr> | ||
3 | |||
4 | #ifndef __multicontact_api_geometry_linear_cone_hpp__ | ||
5 | #define __multicontact_api_geometry_linear_cone_hpp__ | ||
6 | |||
7 | #include <Eigen/Dense> | ||
8 | #include <Eigen/Geometry> | ||
9 | #include <pinocchio/spatial/se3.hpp> | ||
10 | |||
11 | #include "multicontact-api/geometry/fwd.hpp" | ||
12 | #include "multicontact-api/serialization/archive.hpp" | ||
13 | #include "multicontact-api/serialization/eigen-matrix.hpp" | ||
14 | |||
15 | #define EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_ROWS_SIZE(TYPE, ROWS) \ | ||
16 | EIGEN_STATIC_ASSERT(TYPE::RowsAtCompileTime == ROWS, \ | ||
17 | THIS_METHOD_IS_ONLY_FOR_MATRICES_OF_A_SPECIFIC_SIZE) | ||
18 | |||
19 | namespace multicontact_api { | ||
20 | namespace geometry { | ||
21 | |||
22 | template <typename _Scalar, int _dim, int _Options> | ||
23 | struct LinearCone | ||
24 | : public serialization::Serializable<LinearCone<_Scalar, _dim, _Options> > { | ||
25 | EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||
26 | typedef _Scalar Scalar; | ||
27 | enum { dim = _dim, Options = _Options }; | ||
28 | typedef Eigen::Matrix<Scalar, dim, -1, Options> MatrixDx; | ||
29 | typedef Eigen::Matrix<Scalar, dim, dim, Options> MatrixD; | ||
30 | typedef Eigen::Matrix<Scalar, dim, 1, Options> VectorD; | ||
31 | typedef Eigen::DenseIndex Index; | ||
32 | |||
33 | /// \brief Default constructor | ||
34 | ✗ | LinearCone() : m_rays() {} | |
35 | |||
36 | /// \brief Constructor from a set of rays | ||
37 | template <typename EigenDerived> | ||
38 | 1 | explicit LinearCone(const Eigen::MatrixBase<EigenDerived>& rays) | |
39 | // : m_rays(_dim,rays.cols()) | ||
40 | 1 | : m_rays(rays) { | |
41 | // EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(EigenDerived,MatrixDx) | ||
42 | // for(int k=0; k<rays.cols(); ++k) | ||
43 | // m_rays.col(k) = rays.col(k).normalized(); | ||
44 | 1 | } | |
45 | |||
46 | /// \brief Contrustor from a given size. | ||
47 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
12 | explicit LinearCone(const Index size) : m_rays(_dim, size) {} |
48 | |||
49 | /// \brief Copy constructor | ||
50 | template <typename S2, int O2> | ||
51 | LinearCone(const LinearCone<S2, dim, O2>& other) : m_rays(other.m_rays) {} | ||
52 | |||
53 | void addRay(const VectorD& ray) { | ||
54 | m_rays.conservativeResize(Eigen::NoChange_t(), m_rays.cols() + 1); | ||
55 | m_rays.template rightCols<1>() = ray.normalized(); | ||
56 | } | ||
57 | |||
58 | template <typename EigenDerived> | ||
59 | ✗ | void stack(const Eigen::MatrixBase<EigenDerived>& rays) { | |
60 | EIGEN_STATIC_ASSERT_MATRIX_SPECIFIC_ROWS_SIZE(EigenDerived, dim); | ||
61 | ✗ | m_rays.conservativeResize(Eigen::NoChange_t(), m_rays.cols() + rays.cols()); | |
62 | ✗ | m_rays.rightCols(rays.cols()) = rays; | |
63 | } | ||
64 | |||
65 | template <typename S2, int O2> | ||
66 | ✗ | void stack(const LinearCone<S2, dim, O2>& other) { | |
67 | ✗ | stack(other.rays()); | |
68 | } | ||
69 | |||
70 | /// \returns the rays of the linear cone. | ||
71 | 60 | const MatrixDx& rays() const { return m_rays; } | |
72 | 34 | MatrixDx& rays() { return m_rays; } | |
73 | |||
74 | /// \returns the number of rays, i.e. the number of cols of m_rays | ||
75 | 74 | Index size() const { return m_rays.cols(); } | |
76 | |||
77 | template <typename S2, int O2> | ||
78 | ✗ | bool operator==(const LinearCone<S2, dim, O2>& other) const { | |
79 | ✗ | return m_rays == other.m_rays; | |
80 | } | ||
81 | |||
82 | template <typename S2, int O2> | ||
83 | ✗ | bool operator!=(const LinearCone<S2, dim, O2>& other) const { | |
84 | ✗ | return !(*this == other); | |
85 | } | ||
86 | |||
87 | template <typename S2, int O2> | ||
88 | 4 | bool isApprox( | |
89 | const LinearCone<S2, dim, O2>& other, | ||
90 | const Scalar& prec = Eigen::NumTraits<Scalar>::dummy_precision()) const { | ||
91 | 4 | return m_rays.isApprox(other.m_rays, prec); | |
92 | } | ||
93 | |||
94 | ✗ | void disp(std::ostream& os) const { os << "Rays:\n" << m_rays << std::endl; } | |
95 | |||
96 | ✗ | friend std::ostream& operator<<(std::ostream& os, const LinearCone& C) { | |
97 | ✗ | C.disp(os); | |
98 | ✗ | return os; | |
99 | } | ||
100 | |||
101 | protected: | ||
102 | /// \brief Rays of the linear cone | ||
103 | MatrixDx m_rays; | ||
104 | |||
105 | private: | ||
106 | // Serialization of the class | ||
107 | friend class boost::serialization::access; | ||
108 | |||
109 | template <class Archive> | ||
110 | 6 | void save(Archive& ar, const unsigned int /*version*/) const { | |
111 |
1/2✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | ar& boost::serialization::make_nvp("rays", m_rays); |
112 | 6 | } | |
113 | |||
114 | template <class Archive> | ||
115 | 6 | void load(Archive& ar, const unsigned int /*version*/) { | |
116 |
1/2✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
6 | ar >> boost::serialization::make_nvp("rays", m_rays); |
117 | 6 | } | |
118 | |||
119 | 12 | BOOST_SERIALIZATION_SPLIT_MEMBER() | |
120 | }; | ||
121 | |||
122 | template <typename _Scalar, int _Options> | ||
123 | struct ForceConeTpl : public LinearCone<_Scalar, 3, _Options> { | ||
124 | EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||
125 | |||
126 | typedef LinearCone<_Scalar, 3, _Options> Base; | ||
127 | typedef WrenchConeTpl<_Scalar, _Options> WrenchCone; | ||
128 | typedef pinocchio::SE3Tpl<_Scalar, _Options> SE3; | ||
129 | using typename Base::Scalar; | ||
130 | enum { dim = Base::dim }; | ||
131 | using Base::rays; | ||
132 | using Base::size; | ||
133 | using typename Base::Index; | ||
134 | using typename Base::MatrixD; | ||
135 | using typename Base::MatrixDx; | ||
136 | using typename Base::VectorD; | ||
137 | using Base::operator==; | ||
138 | using Base::operator!=; | ||
139 | // using Base::isApprox; // Leads to a bug with clang | ||
140 | |||
141 | typedef MatrixDx Matrix3x; | ||
142 | typedef VectorD Vector3; | ||
143 | typedef Eigen::AngleAxis<Scalar> AngleAxis; | ||
144 | |||
145 | /// \brief Default constructor | ||
146 | ✗ | ForceConeTpl() : Base() {} | |
147 | |||
148 | template <typename EigenDerived> | ||
149 | 1 | explicit ForceConeTpl(const Eigen::MatrixBase<EigenDerived>& rays) | |
150 | 1 | : Base(rays) {} | |
151 | |||
152 | 3 | explicit ForceConeTpl(const Index size) : Base(size) {} | |
153 | |||
154 | /// \returns a linear cone built from a friction coefficient and the number of | ||
155 | /// rays along the Z axis. | ||
156 | ✗ | static ForceConeTpl RegularCone(const Scalar mu, const VectorD& direction, | |
157 | const int num_rays) { | ||
158 | ✗ | return RegularCone(mu, direction, num_rays, 0.); | |
159 | } | ||
160 | |||
161 | ✗ | static ForceConeTpl RegularCone(const Scalar mu, const VectorD& direction, | |
162 | const int num_rays, | ||
163 | const Scalar theta_offset) { | ||
164 | ✗ | assert(mu >= 0. && "mu must be positive"); | |
165 | ✗ | assert(num_rays >= 1 && "The number of rays must be at least one"); | |
166 | |||
167 | ✗ | const VectorD normalized_direction(direction.normalized()); | |
168 | ✗ | ForceConeTpl cone(num_rays); | |
169 | |||
170 | ✗ | const Scalar angle = (2. * M_PI) / num_rays; | |
171 | |||
172 | ✗ | const MatrixD Po(MatrixD::Identity() - | |
173 | ✗ | normalized_direction * normalized_direction.transpose()); | |
174 | |||
175 | ✗ | const MatrixD rot_offset( | |
176 | ✗ | AngleAxis(theta_offset, normalized_direction).toRotationMatrix()); | |
177 | ✗ | const VectorD init_direction(rot_offset * | |
178 | (Po * VectorD::Ones()).normalized()); | ||
179 | ✗ | const MatrixD rot( | |
180 | ✗ | AngleAxis(angle, normalized_direction).toRotationMatrix()); | |
181 | |||
182 | ✗ | VectorD ray((direction + mu * init_direction).normalized()); | |
183 | |||
184 | ✗ | for (int k = 0; k < num_rays; ++k) { | |
185 | ✗ | cone.rays().col(k) = ray; | |
186 | ✗ | if (k != num_rays - 1) ray = rot * ray; | |
187 | } | ||
188 | |||
189 | ✗ | return cone; | |
190 | } | ||
191 | |||
192 | 2 | WrenchCone SE3ActOn(const SE3& M) const { | |
193 | 2 | WrenchCone res(size()); | |
194 | typedef typename WrenchCone::MatrixDx::ColXpr Col6Xpr; | ||
195 | typedef typename MatrixDx::ConstColXpr ConstCol3Xpr; | ||
196 | |||
197 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | const typename SE3::Matrix3& R = M.rotation(); |
198 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | const typename SE3::Vector3& t = M.translation(); |
199 | |||
200 |
2/2✓ Branch 1 taken 20 times.
✓ Branch 2 taken 2 times.
|
22 | for (Index k = 0; k < size(); ++k) { |
201 |
1/2✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
|
20 | ConstCol3Xpr in_col = rays().col(k); |
202 |
1/2✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
|
20 | Col6Xpr out_col = res.rays().col(k); |
203 | |||
204 |
3/6✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
|
20 | out_col.template head<3>() = R * in_col; |
205 |
4/8✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 20 times.
✗ Branch 11 not taken.
|
20 | out_col.template tail<3>() = t.cross(out_col.template head<3>()); |
206 | } | ||
207 | |||
208 | 2 | return res; | |
209 | } | ||
210 | |||
211 | template <typename S2, int O2> | ||
212 | 4 | bool isApprox( | |
213 | const ForceConeTpl<S2, O2>& other, | ||
214 | const Scalar& prec = Eigen::NumTraits<Scalar>::dummy_precision()) const { | ||
215 | 4 | return Base::isApprox(other, prec); | |
216 | } | ||
217 | |||
218 | operator WrenchCone() const { | ||
219 | WrenchCone res(size()); | ||
220 | res.rays().template topRows<3>() = rays(); | ||
221 | res.rays().template bottomRows<3>().setZero(); | ||
222 | return res; | ||
223 | } | ||
224 | }; | ||
225 | |||
226 | template <typename _Scalar, int _Options> | ||
227 | struct WrenchConeTpl : public LinearCone<_Scalar, 6, _Options> { | ||
228 | EIGEN_MAKE_ALIGNED_OPERATOR_NEW | ||
229 | |||
230 | typedef LinearCone<_Scalar, 6, _Options> Base; | ||
231 | typedef ForceConeTpl<_Scalar, _Options> ForceCone; | ||
232 | typedef pinocchio::SE3Tpl<_Scalar, _Options> SE3; | ||
233 | using typename Base::Scalar; | ||
234 | enum { dim = Base::dim }; | ||
235 | using Base::rays; | ||
236 | using Base::size; | ||
237 | using typename Base::Index; | ||
238 | using typename Base::MatrixDx; | ||
239 | using typename Base::VectorD; | ||
240 | using Base::operator==; | ||
241 | using Base::operator!=; | ||
242 | // using Base::isApprox; // Leads to a bug with clang | ||
243 | |||
244 | typedef MatrixDx Matrix6x; | ||
245 | typedef VectorD Vector6; | ||
246 | |||
247 | typedef typename ForceCone::Matrix3x Matrix3x; | ||
248 | |||
249 | typedef typename Matrix6x::template NRowsBlockXpr<3>::Type LinearBlock; | ||
250 | typedef | ||
251 | typename Matrix6x::template ConstNRowsBlockXpr<3>::Type ConstLinearBlock; | ||
252 | |||
253 | typedef LinearBlock AngularBlock; | ||
254 | typedef ConstLinearBlock ConstAngularBlock; | ||
255 | |||
256 | /// \brief Default constructor | ||
257 | ✗ | WrenchConeTpl() : Base() {} | |
258 | |||
259 | /// \brief Constructor from a set of rays. | ||
260 | template <typename EigenDerived> | ||
261 | ✗ | explicit WrenchConeTpl(const Eigen::MatrixBase<EigenDerived>& rays) | |
262 | ✗ | : Base(rays) {} | |
263 | |||
264 | /// \brief Constructs a WrenchCone of a given size. | ||
265 | 3 | explicit WrenchConeTpl(const Index size) : Base(size) {} | |
266 | |||
267 | /// \brief Constructs a WrenchCone of a given size. | ||
268 | template <typename S2, int O2> | ||
269 | ✗ | explicit WrenchConeTpl(const ForceConeTpl<S2, O2>& force_cone) | |
270 | ✗ | : Base(force_cone.size()) { | |
271 | ✗ | rays().template topRows<3>() = force_cone.rays(); | |
272 | ✗ | rays().template bottomRows<3>().setZero(); | |
273 | } | ||
274 | |||
275 | /// \brief Copy constructor | ||
276 | template <typename S2, int O2> | ||
277 | WrenchConeTpl(const WrenchConeTpl<S2, O2>& other) : Base(other) {} | ||
278 | |||
279 | 1 | WrenchConeTpl SE3ActOn(const SE3& M) const { | |
280 | 1 | WrenchConeTpl res(size()); | |
281 | typedef typename MatrixDx::ColXpr Col6Xpr; | ||
282 | typedef typename MatrixDx::ConstColXpr ConstCol6Xpr; | ||
283 | |||
284 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | const typename SE3::Matrix3& R = M.rotation(); |
285 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | const typename SE3::Vector3& t = M.translation(); |
286 | |||
287 |
2/2✓ Branch 1 taken 10 times.
✓ Branch 2 taken 1 times.
|
11 | for (Index k = 0; k < size(); ++k) { |
288 |
1/2✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
10 | ConstCol6Xpr in_col = rays().col(k); |
289 |
1/2✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
10 | Col6Xpr out_col = res.rays().col(k); |
290 | |||
291 |
4/8✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 10 times.
✗ Branch 11 not taken.
|
10 | out_col.template head<3>() = R * in_col.template head<3>(); |
292 |
4/8✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 10 times.
✗ Branch 11 not taken.
|
10 | out_col.template tail<3>() = |
293 |
3/6✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
|
20 | t.cross(out_col.template head<3>()) + R * in_col.template tail<3>(); |
294 | } | ||
295 | |||
296 | 1 | return res; | |
297 | } | ||
298 | |||
299 | template <typename S2, int O2> | ||
300 | bool isApprox( | ||
301 | const WrenchConeTpl<S2, O2>& other, | ||
302 | const Scalar& prec = Eigen::NumTraits<Scalar>::dummy_precision()) const { | ||
303 | return Base::isApprox(other, prec); | ||
304 | } | ||
305 | |||
306 | ✗ | ConstLinearBlock linear() const { return rays().template topRows<3>(); } | |
307 | 2 | LinearBlock linear() { return rays().template topRows<3>(); } | |
308 | |||
309 | ✗ | ConstAngularBlock angular() const { return rays().template bottomRows<3>(); } | |
310 | AngularBlock angular() { return rays().template bottomRows<3>(); } | ||
311 | |||
312 | ForceCone toForceCone() const { return ForceCone(linear()); } | ||
313 | }; | ||
314 | } // namespace geometry | ||
315 | } // namespace multicontact_api | ||
316 | |||
317 | #endif // ifndef __multicontact_api_geometry_linear_cone_hpp__ | ||
318 |