API Docs for: 0.6.1
Show:

File: src/solver/GSSolver.js

  1. module.exports = GSSolver;
  2.  
  3. var Vec3 = require('../math/Vec3');
  4. var Quaternion = require('../math/Quaternion');
  5. var Solver = require('./Solver');
  6.  
  7. /**
  8. * Constraint equation Gauss-Seidel solver.
  9. * @class GSSolver
  10. * @constructor
  11. * @todo The spook parameters should be specified for each constraint, not globally.
  12. * @author schteppe / https://github.com/schteppe
  13. * @see https://www8.cs.umu.se/kurser/5DV058/VT09/lectures/spooknotes.pdf
  14. * @extends Solver
  15. */
  16. function GSSolver(){
  17. Solver.call(this);
  18.  
  19. /**
  20. * The number of solver iterations determines quality of the constraints in the world. The more iterations, the more correct simulation. More iterations need more computations though. If you have a large gravity force in your world, you will need more iterations.
  21. * @property iterations
  22. * @type {Number}
  23. * @todo write more about solver and iterations in the wiki
  24. */
  25. this.iterations = 10;
  26.  
  27. /**
  28. * When tolerance is reached, the system is assumed to be converged.
  29. * @property tolerance
  30. * @type {Number}
  31. */
  32. this.tolerance = 1e-7;
  33. }
  34. GSSolver.prototype = new Solver();
  35.  
  36. var GSSolver_solve_lambda = []; // Just temporary number holders that we want to reuse each solve.
  37. var GSSolver_solve_invCs = [];
  38. var GSSolver_solve_Bs = [];
  39. GSSolver.prototype.solve = function(dt,world){
  40. var iter = 0,
  41. maxIter = this.iterations,
  42. tolSquared = this.tolerance*this.tolerance,
  43. equations = this.equations,
  44. Neq = equations.length,
  45. bodies = world.bodies,
  46. Nbodies = bodies.length,
  47. h = dt,
  48. q, B, invC, deltalambda, deltalambdaTot, GWlambda, lambdaj;
  49.  
  50. // Update solve mass
  51. if(Neq !== 0){
  52. for(var i=0; i!==Nbodies; i++){
  53. bodies[i].updateSolveMassProperties();
  54. }
  55. }
  56.  
  57. // Things that does not change during iteration can be computed once
  58. var invCs = GSSolver_solve_invCs,
  59. Bs = GSSolver_solve_Bs,
  60. lambda = GSSolver_solve_lambda;
  61. invCs.length = Neq;
  62. Bs.length = Neq;
  63. lambda.length = Neq;
  64. for(var i=0; i!==Neq; i++){
  65. var c = equations[i];
  66. lambda[i] = 0.0;
  67. Bs[i] = c.computeB(h);
  68. invCs[i] = 1.0 / c.computeC();
  69. }
  70.  
  71. if(Neq !== 0){
  72.  
  73. // Reset vlambda
  74. for(var i=0; i!==Nbodies; i++){
  75. var b=bodies[i],
  76. vlambda=b.vlambda,
  77. wlambda=b.wlambda;
  78. vlambda.set(0,0,0);
  79. if(wlambda){
  80. wlambda.set(0,0,0);
  81. }
  82. }
  83.  
  84. // Iterate over equations
  85. for(iter=0; iter!==maxIter; iter++){
  86.  
  87. // Accumulate the total error for each iteration.
  88. deltalambdaTot = 0.0;
  89.  
  90. for(var j=0; j!==Neq; j++){
  91.  
  92. var c = equations[j];
  93.  
  94. // Compute iteration
  95. B = Bs[j];
  96. invC = invCs[j];
  97. lambdaj = lambda[j];
  98. GWlambda = c.computeGWlambda();
  99. deltalambda = invC * ( B - GWlambda - c.eps * lambdaj );
  100.  
  101. // Clamp if we are not within the min/max interval
  102. if(lambdaj + deltalambda < c.minForce){
  103. deltalambda = c.minForce - lambdaj;
  104. } else if(lambdaj + deltalambda > c.maxForce){
  105. deltalambda = c.maxForce - lambdaj;
  106. }
  107. lambda[j] += deltalambda;
  108.  
  109. deltalambdaTot += deltalambda > 0.0 ? deltalambda : -deltalambda; // abs(deltalambda)
  110.  
  111. c.addToWlambda(deltalambda);
  112. }
  113.  
  114. // If the total error is small enough - stop iterate
  115. if(deltalambdaTot*deltalambdaTot < tolSquared){
  116. break;
  117. }
  118. }
  119.  
  120. // Add result to velocity
  121. for(var i=0; i!==Nbodies; i++){
  122. var b=bodies[i],
  123. v=b.velocity,
  124. w=b.angularVelocity;
  125. v.vadd(b.vlambda, v);
  126. if(w){
  127. w.vadd(b.wlambda, w);
  128. }
  129. }
  130. }
  131.  
  132. return iter;
  133. };
  134.