iMSTK
Interactive Medical Simulation Toolkit
imstkPbdAngularConstraint.cpp
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #include "imstkPbdAngularConstraint.h"
8 
9 namespace imstk
10 {
11 void
13  const double dt, const SolverType& solverType)
14 {
15  if (dt == 0.0)
16  {
17  return;
18  }
19 
20  double c = 0.0;
21  bool update = this->computeValueAndGradient(bodies, c, m_dcdx);
22  if (!update)
23  {
24  return;
25  }
26 
27  // Compute the generalized inverse mass w
28  double w = 0.0;
29  for (size_t i = 0; i < m_particles.size(); i++)
30  {
31  const Quatd& q = bodies.getOrientation(m_particles[i]);
32  const Mat3d& invInteria = bodies.getInvInertia(m_particles[i]);
33  const Vec3d l = q.inverse()._transformVector(m_dcdx[i]);
34  w += l[0] * l[0] * invInteria(0, 0) +
35  l[1] * l[1] * invInteria(1, 1) +
36  l[2] * l[2] * invInteria(2, 2);
37  }
38 
39  if (w < IMSTK_DOUBLE_EPS)
40  {
41  return;
42  }
43 
44  double dlambda = 0.0;
45  double alpha = 0.0;
46  switch (solverType)
47  {
48  case (SolverType::PBD):
49  dlambda = -c * m_stiffness / w;
50  break;
51  case (SolverType::xPBD):
52  default:
53  alpha = m_compliance / (dt * dt);
54  dlambda = -(c + alpha * m_lambda) / (w + alpha);
55  m_lambda += dlambda;
56  break;
57  }
58 
59  for (size_t i = 0; i < m_particles.size(); i++)
60  {
61  Quatd& q = bodies.getOrientation(m_particles[i]);
62  const Mat3d& invInteria = bodies.getInvInertia(m_particles[i]);
63 
64  // Transform to rest pose and apply inertia then back
65  const Vec3d p = dlambda * m_dcdx[i];
66  Vec3d rot = p;
67  rot = q.inverse()._transformVector(rot);
68  rot = invInteria * rot;
69  rot = q._transformVector(rot);
70 
71  double scale = 1.0;
72  const double phi = rot.norm();
73  if (phi > 0.5) // Max rot
74  {
75  scale = 0.5 / phi;
76  }
77 
78  const Quatd dq_quat = Quatd(0.0,
79  rot[0] * scale,
80  rot[1] * scale,
81  rot[2] * scale) * q;
82  q.coeffs() += dq_quat.coeffs() * 0.5;
83  q.normalize();
84  }
85 }
86 
87 void
88 PbdAngularHingeConstraint::initConstraint(
89  const PbdParticleId& pIdx0,
90  const Vec3d& hingeAxes,
91  const double compliance)
92 {
93  m_particles[0] = pIdx0;
94  m_hingeAxes = hingeAxes;
95  setCompliance(compliance);
96 }
97 
98 bool
100  double& c, std::vector<Vec3d>& dcdx)
101 {
102  // Is this the fastest way to get basis vectors?
103  const Vec3d localY = bodies.getOrientation(m_particles[0]).toRotationMatrix().col(1);
104 
105  // Gives rotation
106  Vec3d dir = m_hingeAxes.cross(localY);
107  dcdx[0] = dir.normalized();
108  c = dir.norm();
109 
110  return true;
111 }
112 
113 void
115  const PbdParticleId& p0,
116  const PbdParticleId& p1,
117  const double compliance)
118 {
119  m_particles[0] = p0;
120  m_particles[1] = p1;
121  setCompliance(compliance);
122 }
123 
124 void
126  const PbdState& bodies,
127  const PbdParticleId& p0,
128  const PbdParticleId& p1,
129  const double compliance)
130 {
131  m_particles[0] = p0;
132  m_particles[1] = p1;
133 
134  const Quatd& q0 = bodies.getOrientation(m_particles[0]);
135  const Quatd& q1 = bodies.getOrientation(m_particles[1]);
136 
137  m_offset = q0.inverse() * q1;
138 
139  setCompliance(compliance);
140 }
141 
142 void
144  const PbdParticleId& p0,
145  const PbdParticleId& p1,
146  const Quatd rotationalOffset,
147  const double compliance)
148 {
149  initConstraint(p0, p1, compliance);
150  m_offset = rotationalOffset;
151 }
152 
153 bool
155  double& c, std::vector<Vec3d>& dcdx)
156 {
157  const Quatd& q0 = bodies.getOrientation(m_particles[0]);
158  const Quatd& q1 = bodies.getOrientation(m_particles[1]);
159 
160  // Gives rotation from q0->q1 (ie: q1 = dq * q0)
161  const Quatd dq = q1 * (q0 * m_offset).inverse();
162  Eigen::AngleAxisd angleAxes(dq);
163  dcdx[0] = angleAxes.axis();
164  dcdx[1] = -dcdx[0];
165  c = -angleAxes.angle();
166 
167  return true;
168 }
169 } // namespace imstk
std::vector< Vec3d > m_dcdx
Normalized constraint gradients (per particle)
void projectConstraint(PbdState &bodies, const double dt, const SolverType &type) override
Update positions by projecting constraints.
std::pair< int, int > PbdParticleId
Index pair that refers to a particle in a PbdState. Index 0 is the body id, Index 1 is the particle i...
double m_lambda
Lagrange multiplier.
std::vector< PbdParticleId > m_particles
body, particle index
bool computeValueAndGradient(PbdState &bodies, double &c, std::vector< Vec3d > &dcdx) override
Compute value and gradient of constraint function.
Compound Geometry.
double m_compliance
used in xPBD, inverse of Stiffness
void initConstraintOffset(const PbdState &bodies, const PbdParticleId &p0, const PbdParticleId &p1, const double compliance)
Constrain p0 to match p1&#39;s orientation according to the the current rotational offset between them...
virtual bool computeValueAndGradient(PbdState &bodies, double &c, std::vector< Vec3d > &dcdx)=0
Compute value and gradient of the constraint.
double m_stiffness
used in PBD, [0, 1]
SolverType
Type of solvers.
Provides interface for accessing particles from a 2d array of PbdBody,Particles.
Definition: imstkPbdBody.h:229
bool computeValueAndGradient(PbdState &bodies, double &c, std::vector< Vec3d > &dcdx) override
Compute value and gradient of constraint function.
void initConstraint(const PbdParticleId &p0, const PbdParticleId &p1, const double compliance)
Constraint p0 to match p1, zero rotational offset.