iMSTK
Interactive Medical Simulation Toolkit
imstkPbdConstraint.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 "imstkPbdConstraint.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  // Save constraint value
28  m_C = c;
29 
30  // Compute generalized inverse mass sum
31  double w = 0.0;
32  for (size_t i = 0; i < m_particles.size(); i++)
33  {
34  // Multiplication with dcdx here is important for non normalized
35  // constraint gradients
36  //w += bodies.getInvMass(m_particles[i]) * m_dcdx[i].squaredNorm();
37  w += computeGeneralizedInvMass(bodies, i) * m_dcdx[i].squaredNorm();
38  }
39  if (w == 0.0)
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  break;
56  }
57  m_lambda += dlambda;
58 
59  for (size_t i = 0; i < m_particles.size(); i++)
60  {
61  const double invMass = bodies.getInvMass(m_particles[i]);
62  if (invMass > 0.0)
63  {
64  bodies.getPosition(m_particles[i]) += invMass * dlambda * m_dcdx[i];
65  }
66  }
67 }
68 
69 void
71 {
72  if (!m_correctVelocity)
73  {
74  return;
75  }
76 
77  const double fricFrac = 1.0 - m_friction;
78  for (size_t i = 0; i < m_particles.size(); i++)
79  {
80  const double invMass = bodies.getInvMass(m_particles[i]);
81  // If immovable, don't bother.
82  // If no lambda was computed, constraint failed, or had no effect
83  if (invMass > 0.0 && m_lambda > 0.0)
84  {
85  const Vec3d n = m_dcdx[i].normalized();
86  Vec3d& v = bodies.getVelocity(m_particles[i]);
87 
88  // Separate velocity into normal and tangent components
89  const Vec3d vN = n.dot(v) * n;
90  const Vec3d vT = v - vN;
91 
92  // Put back together fractionally based on defined restitution and frictional coefficients
93  v = vN * m_restitution + vT * fricFrac;
94  }
95  }
96 }
97 } // namespace imstk
std::vector< Vec3d > m_dcdx
Normalized constraint gradients (per particle)
double m_lambda
Lagrange multiplier.
std::vector< PbdParticleId > m_particles
body, particle index
double computeGeneralizedInvMass(const PbdState &bodies, const size_t particleIndex) const
Compute generalized inverse mass of the particle. Note perf sensitive function. It has been intention...
Compound Geometry.
double m_compliance
used in xPBD, inverse of Stiffness
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.
double m_C
Constraint Value.
virtual void projectConstraint(PbdState &bodies, const double dt, const SolverType &type)
Update positions by projecting constraints.
virtual void correctVelocity(PbdState &bodies, const double dt)
Correct velocities according to friction and restitution Corrects according to the gradient direction...
Provides interface for accessing particles from a 2d array of PbdBody,Particles.
Definition: imstkPbdBody.h:229