Biorbd
WrappingCylinder.cpp
1 #define BIORBD_API_EXPORTS
2 #include "Muscles/WrappingCylinder.h"
3 
4 #include "Utils/String.h"
5 #include "Utils/RotoTrans.h"
6 #include "RigidBody/Joints.h"
7 
9  biorbd::muscles::WrappingObject (),
10  m_dia(std::make_shared<biorbd::utils::Scalar>(0)),
11  m_length(std::make_shared<biorbd::utils::Scalar>(0)),
12  m_isCylinderPositiveSign(std::make_shared<bool>(true)),
13  m_RTtoParent(std::make_shared<biorbd::utils::RotoTrans>()),
14  m_p1Wrap(std::make_shared<biorbd::utils::Vector3d>()),
15  m_p2Wrap(std::make_shared<biorbd::utils::Vector3d>()),
16  m_lengthAroundWrap(std::make_shared<biorbd::utils::Scalar>(0))
17 {
18  *m_typeOfNode = biorbd::utils::NODE_TYPE::WRAPPING_CYLINDER;
19 }
20 
22  const biorbd::utils::RotoTrans &rt,
23  const biorbd::utils::Scalar& diameter,
24  const biorbd::utils::Scalar& length,
25  bool isCylinderPositiveSign) :
26  biorbd::muscles::WrappingObject (rt.trans()),
27  m_dia(std::make_shared<biorbd::utils::Scalar>(diameter)),
28  m_length(std::make_shared<biorbd::utils::Scalar>(length)),
29  m_isCylinderPositiveSign(std::make_shared<bool>(isCylinderPositiveSign)),
30  m_RTtoParent(std::make_shared<biorbd::utils::RotoTrans>(rt)),
31  m_p1Wrap(std::make_shared<biorbd::utils::Vector3d>()),
32  m_p2Wrap(std::make_shared<biorbd::utils::Vector3d>()),
33  m_lengthAroundWrap(std::make_shared<biorbd::utils::Scalar>(0))
34 {
35  *m_typeOfNode = biorbd::utils::NODE_TYPE::WRAPPING_CYLINDER;
36 }
37 
39  const biorbd::utils::RotoTrans &rt,
40  const biorbd::utils::Scalar& diameter,
41  const biorbd::utils::Scalar& length,
42  bool isCylinderPositiveSign,
43  const biorbd::utils::String &name,
44  const biorbd::utils::String &parentName) :
45  biorbd::muscles::WrappingObject (rt.trans(), name, parentName),
46  m_dia(std::make_shared<biorbd::utils::Scalar>(diameter)),
47  m_length(std::make_shared<biorbd::utils::Scalar>(length)),
48  m_isCylinderPositiveSign(std::make_shared<bool>(isCylinderPositiveSign)),
49  m_RTtoParent(std::make_shared<biorbd::utils::RotoTrans>(rt)),
50  m_p1Wrap(std::make_shared<biorbd::utils::Vector3d>()),
51  m_p2Wrap(std::make_shared<biorbd::utils::Vector3d>()),
52  m_lengthAroundWrap(std::make_shared<biorbd::utils::Scalar>(0))
53 {
54  *m_typeOfNode = biorbd::utils::NODE_TYPE::WRAPPING_CYLINDER;
55 }
56 
58 {
60  copy.DeepCopy(*this);
61  return copy;
62 }
63 
65 {
67  *m_dia = *other.m_dia;
68  *m_length = *other.m_length;
69  *m_isCylinderPositiveSign = *other.m_isCylinderPositiveSign;
70  *m_RTtoParent = *other.m_RTtoParent;
71  *m_p1Wrap = other.m_p1Wrap->DeepCopy();
72  *m_p2Wrap = other.m_p2Wrap->DeepCopy();
73  *m_lengthAroundWrap = *other.m_lengthAroundWrap;
74 }
75 
77  const biorbd::utils::RotoTrans& rt,
78  const biorbd::utils::Vector3d& p1_bone,
79  const biorbd::utils::Vector3d& p2_bone,
82  biorbd::utils::Scalar *length)
83 {
84  // This function takes the position of the wrapping and finds the location where muscle 1 and 2 leave the wrapping object
85 
86  // Find the nodes in the RT reference (of the cylinder)
87  NodeMusclePair p_glob(p1_bone, p2_bone);
88  p_glob.m_p1->applyRT(rt.transpose());
89  p_glob.m_p2->applyRT(rt.transpose());
90 
91  // Find the tangents of these points to the circle (cylinder seen from above)
92  biorbd::utils::Vector3d p1_tan(0, 0, 0);
93  biorbd::utils::Vector3d p2_tan(0, 0, 0);
94  findTangentToCircle(*p_glob.m_p1, p1_tan);
95  findTangentToCircle(*p_glob.m_p2, p2_tan);
96 
97  // Find the vertical component
98  NodeMusclePair tanPoints(p1_tan, p2_tan);
99  findVerticalNode(p_glob, tanPoints);
100 
101  // If asked, compute the distance distance traveled on the periphery of the cylinder
102  // Apply pythagorus to the cercle arc
103  if (length != nullptr) // If it is not nullptr
104  *length = computeLength(tanPoints);
105 
106  // Reset the points in global (space)
107  tanPoints.m_p1->applyRT(rt);
108  tanPoints.m_p2->applyRT(rt);
109 
110  // Reset the desired values
111  p1 = *tanPoints.m_p1;
112  p2 = *tanPoints.m_p2;
113 
114  // Store the values for a futur call
115  m_p1Wrap = tanPoints.m_p1;
116  m_p2Wrap = tanPoints.m_p2;
117  if (length != nullptr) // If it is not nullptr
118  *m_lengthAroundWrap = *length;
119 }
120 
124  const biorbd::utils::Vector3d& p1_bone,
125  const biorbd::utils::Vector3d& p2_bone,
128  biorbd::utils::Scalar *length) {
129  // This function takes a model and a position of the model and returns the location where muscle 1 et 2 leave the wrapping object
130 
131  wrapPoints(RT(model,Q), p1_bone, p2_bone, p1, p2, length);
132 }
133 
137  biorbd::utils::Scalar *length){
138  p1 = *m_p1Wrap;
139  p2 = *m_p2Wrap;
140  if (length != nullptr)
141  *length = *m_lengthAroundWrap;
142 }
143 
147  bool updateKin)
148 {
149  if (updateKin) {
150  model.UpdateKinematicsCustom(&Q);
151  }
152 
153  // Get the RotoTrans matrix of the cylinder in space
154  *m_RT = model.globalJCS(*m_parentName) * *m_RTtoParent;
155  return *m_RT;
156 }
157 
159  const biorbd::utils::Scalar& val)
160 {
161  *m_dia = val;
162 }
163 
164 const biorbd::utils::Scalar& biorbd::muscles::WrappingCylinder::diameter() const
165 {
166  return *m_dia;
167 }
168 
169 biorbd::utils::Scalar biorbd::muscles::WrappingCylinder::radius() const
170 {
171  return *m_dia/2;
172 }
173 
175  const biorbd::utils::Scalar& val)
176 {
177  *m_length = val;
178 }
179 
180 const biorbd::utils::Scalar& biorbd::muscles::WrappingCylinder::length() const
181 {
182  return *m_length;
183 }
184 
186  const biorbd::utils::Vector3d& p,
187  biorbd::utils::Vector3d& p_tan) const {
188  biorbd::utils::Scalar p_dot = p.block(0,0,2,1).dot(p.block(0,0,2,1));
189 
190  const RigidBodyDynamics::Math::Vector2d& Q0(radius()*radius()/p_dot*p.block(0,0,2,1));
191  RigidBodyDynamics::Math::Matrix2d tp(RigidBodyDynamics::Math::Matrix2d::Zero());
192  tp(0, 1) = -1;
193  tp(1, 0) = 1;
194 
195  const RigidBodyDynamics::Math::Vector2d& T(
196  radius()/p_dot*std::sqrt(p_dot-radius()*radius()) * tp * p.block(0,0,2,1));
197 
198  // GEt the tangent on both sides
199  NodeMusclePair m(p,p);
200  m.m_p1->block(0,0,2,1) = Q0 + T;
201  m.m_p2->block(0,0,2,1) = Q0 - T;
202 
203  // Select on of the two tangents
204  selectTangents(m, p_tan);
205 }
206 
208  const NodeMusclePair &p1,
209  biorbd::utils::Vector3d &p_tan) const {
210  if (m_isCylinderPositiveSign){
211 #ifdef BIORBD_USE_CASADI_MATH
212  p_tan = casadi::MX::if_else(
213  casadi::MX::ge((*p1.m_p2)(0), (*p1.m_p1)(0)),
214  *p1.m_p2, *p1.m_p1);
215 #else
216  if ((*p1.m_p2)(0) >= (*p1.m_p1)(0))
217  p_tan = *p1.m_p2;
218  else
219  p_tan = *p1.m_p1;
220 #endif
221  } else {
222 #ifdef BIORBD_USE_CASADI_MATH
223  p_tan = casadi::MX::if_else(
224  casadi::MX::lt((*p1.m_p2)(0), (*p1.m_p1)(0)),
225  *p1.m_p2, *p1.m_p1);
226 #else
227  if ( (*p1.m_p2)(0) < (*p1.m_p1)(0))
228  p_tan = *p1.m_p2;
229  else
230  p_tan = *p1.m_p1;
231 #endif
232  }
233 
234 }
236  NodeMusclePair &pointsToWrap) const {
237  // Before eerything, make sure the point wrap
238 #ifdef BIORBD_USE_CASADI_MATH
239  if (checkIfWraps(pointsInGlobal, pointsToWrap).is_zero()){ // If it doesn't pass by the wrap, put NaN and stop
240 #else
241  if (!checkIfWraps(pointsInGlobal, pointsToWrap)){ // If it doesn't pass by the wrap, put NaN and stop
242 #endif
243  for (unsigned int i=0; i<3; ++i){
244  (*pointsToWrap.m_p1)(i) = static_cast<biorbd::utils::Scalar>(static_cast<double>(NAN));
245  (*pointsToWrap.m_p2)(i) = static_cast<biorbd::utils::Scalar>(static_cast<double>(NAN));
246  }
247  return false;
248  }
249  else{
250  // Make sure the z component won't cause any problem in the rotation computation
251  (*pointsToWrap.m_p1)(2) = 0;
252  (*pointsToWrap.m_p2)(2) = 0;
253  }
254 
255 
256  // Strategy : Find the matrix of the passage between the aligned points in x and the cylinder. Find the location where the points cross the cylinder
257 
258  // X is the straight line between the two points
259  biorbd::utils::Vector3d X(*pointsInGlobal.m_p2 - *pointsInGlobal.m_p1);
260  // Z is the empty axis of the cylinder
261  biorbd::utils::Vector3d Z(0,0,1);
262 
263  biorbd::utils::Vector3d Y(Z.cross(X));
264  // Re-compute X for it to be aligned with the cylinder
265  X = Y.cross(Z);
266  // Normalise everything
267  X = X/X.norm();
268  Y = Y/Y.norm();
269  Z = Z/Z.norm();
270  // Concatenate to get the rotation matrix
271  biorbd::utils::RotoTrans R(X(0), X(1), X(2), 0,
272  Y(0), Y(1), Y(2), 0,
273  Z(0), Z(1), Z(2), 0,
274  0, 0, 0, 1);
275 
276  // Turn the points in the R reference
277  biorbd::utils::Vector3d globA(*pointsInGlobal.m_p1);
278  biorbd::utils::Vector3d globB(*pointsInGlobal.m_p2);
279  biorbd::utils::Vector3d wrapA(*pointsToWrap.m_p1);
280  biorbd::utils::Vector3d wrapB(*pointsToWrap.m_p2);
281  globA.applyRT(R);
282  globB.applyRT(R);
283  wrapA.applyRT(R);
284  wrapB.applyRT(R);
285 
286  // The height depends on the relative distance
287  (*pointsToWrap.m_p1)(2) = biorbd::utils::Scalar(wrapA(0)-globB(0)) /
288  biorbd::utils::Scalar(globA(0)-globB(0)) *
289  ((*pointsInGlobal.m_p1)(2)-(*pointsInGlobal.m_p2)(2)) + (*pointsInGlobal.m_p2)(2);
290  (*pointsToWrap.m_p2)(2) = biorbd::utils::Scalar(wrapB(0)-globB(0)) /
291  biorbd::utils::Scalar(globA(0)-globB(0)) *
292  ((*pointsInGlobal.m_p1)(2)-(*pointsInGlobal.m_p2)(2)) + (*pointsInGlobal.m_p2)(2);
293 
294  return true;
295 }
296 #ifdef BIORBD_USE_CASADI_MATH
298  const NodeMusclePair &pointsInGlobal,
299  NodeMusclePair &pointsToWrap) const {
300  biorbd::utils::Scalar isWrap = 1;
301 
302  // If the straight line between the two points go through the cylinder,there is a wrap
303  return casadi::MX::if_else(
304  (casadi::MX::lt((*pointsToWrap.m_p1)(0), (*pointsToWrap.m_p2)(0)) &&
305  casadi::MX::gt((*pointsInGlobal.m_p1)(0), (*pointsInGlobal.m_p2)(0))) ||
306  (casadi::MX::gt((*pointsToWrap.m_p1)(0), (*pointsToWrap.m_p2)(0)) &&
307  casadi::MX::lt((*pointsInGlobal.m_p1)(0), (*pointsInGlobal.m_p2)(0))),
308  0, 1);
309 }
310 #else
312  const NodeMusclePair &pointsInGlobal,
313  NodeMusclePair &pointsToWrap) const {
314  bool isWrap = 1;
315  // It seems that all this function is ignored up to the last check... Once
316  // it is checked, validate the Casadi implementation
317 
318  // First quick tests
319  // if both points are on the left and we have to go left
320  if (m_isCylinderPositiveSign){
321  if ((*pointsInGlobal.m_p1)(0) > radius() && (*pointsInGlobal.m_p2)(0) > radius())
322  isWrap = false;
323  }
324  // if both points are on the right and we have to go right
325  else{
326  if ((*pointsInGlobal.m_p1)(0) < -radius() && (*pointsInGlobal.m_p2)(0) < -radius())
327  isWrap = false;
328  }
329 
330  // If we are on top of the wrap, it is impossible to determine because the wrap Si on est en haut du wrap*,
331  // is not a cylinder but a half-cylinder
332  // * en haut lorsque vue de dessus avec l'axe y pointant vers le haut...
333  if ( ( (*pointsInGlobal.m_p1)(1) > 0 && (*pointsInGlobal.m_p2)(1) > 0) || ( (*pointsInGlobal.m_p1)(1) < 0 && (*pointsInGlobal.m_p2)(1) < 0) )
334  isWrap = false;
335 
336  // If we have a height* smaller than the radius, there is a numerical aberation
337  // * en haut lorsque vue de dessus avec l'axe y pointant vers le haut...
338  if ( fabs( (*pointsInGlobal.m_p1)(1)) < radius() || fabs( (*pointsInGlobal.m_p2)(1)) < radius() )
339  isWrap = false;
340 
341  // If we have reached this stage, one test is left
342  // If the straight line between the two points go through the cylinder,there is a wrap
343  if ( ( (*pointsToWrap.m_p1)(0) < (*pointsToWrap.m_p2)(0) && (*pointsInGlobal.m_p1)(0) > (*pointsInGlobal.m_p2)(0)) ||
344  ( (*pointsToWrap.m_p1)(0) > (*pointsToWrap.m_p2)(0) && (*pointsInGlobal.m_p1)(0) < (*pointsInGlobal.m_p2)(0)) )
345  isWrap = false;
346  else
347  isWrap = true;
348 
349  // Return the answer
350  return isWrap;
351 }
352 #endif
354  biorbd::utils::Scalar arc = std::acos( ( (*p.m_p1)(0) * (*p.m_p2)(0) + (*p.m_p1)(1) * (*p.m_p2)(1))
355  /
356  std::sqrt( ((*p.m_p1)(0) * (*p.m_p1)(0) + (*p.m_p1)(1) * (*p.m_p1)(1)) *
357  ( (*p.m_p2)(0) * (*p.m_p2)(0) + (*p.m_p2)(1) * (*p.m_p2)(1)) )
358  ) * radius();
359 
360  return std::sqrt(arc*arc + ( (*p.m_p1)(2) - (*p.m_p2)(2)) * ( (*p.m_p1)(2) - (*p.m_p2)(2)) );
361 }
biorbd::muscles::WrappingCylinder::NodeMusclePair::m_p2
std::shared_ptr< biorbd::utils::Vector3d > m_p2
Point 2.
Definition: WrappingCylinder.h:172
biorbd::muscles::WrappingCylinder::m_RTtoParent
std::shared_ptr< biorbd::utils::RotoTrans > m_RTtoParent
RotoTrans matrix with the parent.
Definition: WrappingCylinder.h:229
biorbd::muscles::WrappingCylinder::checkIfWraps
bool checkIfWraps(const NodeMusclePair &pointsInGlobal, NodeMusclePair &pointsToWrap) const
Check if a wrapper has to be done.
Definition: WrappingCylinder.cpp:311
biorbd::muscles::WrappingCylinder::length
const biorbd::utils::Scalar & length() const
Return the length of the cylinder.
Definition: WrappingCylinder.cpp:180
biorbd::muscles::WrappingCylinder
Cylinder object that makes the muscle to wrap around.
Definition: WrappingCylinder.h:13
biorbd::muscles::WrappingCylinder::computeLength
biorbd::utils::Scalar computeLength(const NodeMusclePair &p) const
Compute the muscle length on the cylinder.
Definition: WrappingCylinder.cpp:353
biorbd::utils::Vector3d
Wrapper around Eigen Vector3d and attach it to a parent.
Definition: Vector3d.h:24
biorbd::muscles::WrappingCylinder::m_lengthAroundWrap
std::shared_ptr< biorbd::utils::Scalar > m_lengthAroundWrap
Length between p1 and p2.
Definition: WrappingCylinder.h:233
biorbd::muscles::WrappingCylinder::findVerticalNode
bool findVerticalNode(const NodeMusclePair &pointsInGlobal, NodeMusclePair &pointsToWrap) const
Find the height of both points.
Definition: WrappingCylinder.cpp:235
biorbd::muscles::WrappingCylinder::NodeMusclePair::m_p1
std::shared_ptr< biorbd::utils::Vector3d > m_p1
Point 1.
Definition: WrappingCylinder.h:171
biorbd::muscles::WrappingCylinder::setDiameter
void setDiameter(const biorbd::utils::Scalar &val)
Set the diameter of the wrapping cylinder.
Definition: WrappingCylinder.cpp:158
biorbd::utils::Vector3d::DeepCopy
biorbd::utils::Vector3d DeepCopy() const
Deep copy of a 3D vector.
Definition: Vector3d.cpp:82
biorbd::muscles::WrappingCylinder::m_p2Wrap
std::shared_ptr< biorbd::utils::Vector3d > m_p2Wrap
Second point of contact with the wrap.
Definition: WrappingCylinder.h:232
biorbd::utils::Vector3d::applyRT
biorbd::utils::Vector3d applyRT(const RotoTrans &rt) const
Apply a RotoTrans to the 3D vector.
Definition: Vector3d.cpp:95
biorbd::rigidbody::GeneralizedCoordinates
Class GeneralizedCoordinates.
Definition: GeneralizedCoordinates.h:15
biorbd::utils::RotoTrans::transpose
biorbd::utils::RotoTrans transpose() const
Return the tranposed matrix.
Definition: RotoTrans.cpp:83
biorbd::muscles::WrappingCylinder::findTangentToCircle
void findTangentToCircle(const biorbd::utils::Vector3d &p, biorbd::utils::Vector3d &p_tan) const
Find the two tangents of a point with a circle.
Definition: WrappingCylinder.cpp:185
biorbd::rigidbody::Joints::globalJCS
biorbd::utils::RotoTrans globalJCS(const biorbd::rigidbody::GeneralizedCoordinates &Q, const biorbd::utils::String &name)
Return the joint coordinate system (JCS) for the segment in global reference frame at a given Q.
Definition: Joints.cpp:267
biorbd::muscles::WrappingCylinder::m_p1Wrap
std::shared_ptr< biorbd::utils::Vector3d > m_p1Wrap
First point of contact with the wrap.
Definition: WrappingCylinder.h:231
biorbd::muscles::WrappingCylinder::m_length
std::shared_ptr< biorbd::utils::Scalar > m_length
Length of the cylinder.
Definition: WrappingCylinder.h:227
biorbd::rigidbody::Joints
This is the core of the musculoskeletal model in biorbd.
Definition: Joints.h:40
biorbd::muscles::WrappingCylinder::DeepCopy
biorbd::muscles::WrappingCylinder DeepCopy() const
Deep copy of the wrapping cylinder.
Definition: WrappingCylinder.cpp:57
biorbd::muscles::WrappingCylinder::radius
biorbd::utils::Scalar radius() const
Return the radius of the cylinder.
Definition: WrappingCylinder.cpp:169
biorbd::utils::RotoTrans
Homogenous matrix to describe translations and rotations simultaneously.
Definition: RotoTrans.h:34
biorbd::muscles::WrappingCylinder::wrapPoints
void wrapPoints(const biorbd::utils::RotoTrans &rt, const biorbd::utils::Vector3d &p1_bone, const biorbd::utils::Vector3d &p2_bone, biorbd::utils::Vector3d &p1, biorbd::utils::Vector3d &p2, biorbd::utils::Scalar *length=nullptr)
From the position of the cylinder, return the 2 locations where the muscle leaves the wrapping object...
Definition: WrappingCylinder.cpp:76
biorbd::muscles::WrappingCylinder::setLength
void setLength(const biorbd::utils::Scalar &val)
Set the length of the cylinder.
Definition: WrappingCylinder.cpp:174
biorbd::muscles::WrappingObject
Base class for the wrapping objects.
Definition: WrappingObject.h:23
biorbd::muscles::WrappingCylinder::selectTangents
void selectTangents(const NodeMusclePair &p, biorbd::utils::Vector3d &p_tan) const
Select between a set of nodes which ones to keep.
Definition: WrappingCylinder.cpp:207
biorbd::utils::String
Wrapper around the std::string class with augmented functionality.
Definition: String.h:17
biorbd::muscles::WrappingObject::RT
const biorbd::utils::RotoTrans & RT() const
Return the RotoTrans matrix of the wrapping object.
Definition: WrappingObject.cpp:58
biorbd::muscles::WrappingCylinder::m_isCylinderPositiveSign
std::shared_ptr< bool > m_isCylinderPositiveSign
orientation of the muscle passing
Definition: WrappingCylinder.h:228
biorbd::muscles::WrappingCylinder::WrappingCylinder
WrappingCylinder()
Construct a wrapping cylinder.
Definition: WrappingCylinder.cpp:8
biorbd::rigidbody::Joints::UpdateKinematicsCustom
void UpdateKinematicsCustom(const biorbd::rigidbody::GeneralizedCoordinates *Q=nullptr, const biorbd::rigidbody::GeneralizedVelocity *Qdot=nullptr, const biorbd::rigidbody::GeneralizedAcceleration *Qddot=nullptr)
Update the kinematic variables such as body velocities and accelerations in the model to reflect the ...
Definition: Joints.cpp:1063
biorbd::muscles::WrappingCylinder::m_dia
std::shared_ptr< biorbd::utils::Scalar > m_dia
Diameter of the cylinder diametre du cylindre.
Definition: WrappingCylinder.h:226
biorbd::utils::Node::m_typeOfNode
std::shared_ptr< biorbd::utils::NODE_TYPE > m_typeOfNode
The type of the node.
Definition: Node.h:93
biorbd::muscles::WrappingCylinder::NodeMusclePair
Pair of 2 muscles points.
Definition: WrappingCylinder.h:158
biorbd::muscles::WrappingCylinder::diameter
const biorbd::utils::Scalar & diameter() const
Return the diameter of the cylinder.
Definition: WrappingCylinder.cpp:164