POPSpringAnimationInternal.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /**
  2. Copyright (c) 2014-present, Facebook, Inc.
  3. All rights reserved.
  4. This source code is licensed under the BSD-style license found in the
  5. LICENSE file in the root directory of this source tree. An additional grant
  6. of patent rights can be found in the PATENTS file in the same directory.
  7. */
  8. #import <cmath>
  9. #import "POPAnimationExtras.h"
  10. #import "POPPropertyAnimationInternal.h"
  11. struct _POPSpringAnimationState : _POPPropertyAnimationState
  12. {
  13. SpringSolver4d *solver;
  14. CGFloat springSpeed;
  15. CGFloat springBounciness; // normalized springiness
  16. CGFloat dynamicsTension; // tension
  17. CGFloat dynamicsFriction; // friction
  18. CGFloat dynamicsMass; // mass
  19. _POPSpringAnimationState(id __unsafe_unretained anim) : _POPPropertyAnimationState(anim),
  20. solver(nullptr),
  21. springSpeed(12.),
  22. springBounciness(4.),
  23. dynamicsTension(0),
  24. dynamicsFriction(0),
  25. dynamicsMass(0)
  26. {
  27. type = kPOPAnimationSpring;
  28. }
  29. bool hasConverged()
  30. {
  31. NSUInteger count = valueCount;
  32. if (shouldRound()) {
  33. return vec_equal(previous2Vec, previousVec) && vec_equal(previousVec, toVec);
  34. } else {
  35. if (!previousVec || !previous2Vec)
  36. return false;
  37. CGFloat t = dynamicsThreshold / 5;
  38. const CGFloat *toValues = toVec->data();
  39. const CGFloat *previousValues = previousVec->data();
  40. const CGFloat *previous2Values = previous2Vec->data();
  41. for (NSUInteger idx = 0; idx < count; idx++) {
  42. if ((std::abs(toValues[idx] - previousValues[idx]) >= t) || (std::abs(previous2Values[idx] - previousValues[idx]) >= t)) {
  43. return false;
  44. }
  45. }
  46. return true;
  47. }
  48. }
  49. bool isDone() {
  50. if (_POPPropertyAnimationState::isDone()) {
  51. return true;
  52. }
  53. return solver->started() && (hasConverged() || solver->hasConverged());
  54. }
  55. void updatedDynamics()
  56. {
  57. if (NULL != solver) {
  58. solver->setConstants(dynamicsTension, dynamicsFriction, dynamicsMass);
  59. }
  60. }
  61. void updatedDynamicsThreshold()
  62. {
  63. _POPPropertyAnimationState::updatedDynamicsThreshold();
  64. if (NULL != solver) {
  65. solver->setThreshold(dynamicsThreshold);
  66. }
  67. }
  68. void updatedBouncinessAndSpeed() {
  69. [POPSpringAnimation convertBounciness:springBounciness speed:springSpeed toTension:&dynamicsTension friction:&dynamicsFriction mass:&dynamicsMass];
  70. updatedDynamics();
  71. }
  72. bool advance(CFTimeInterval time, CFTimeInterval dt, id obj) {
  73. // advance past not yet initialized animations
  74. if (NULL == currentVec) {
  75. return false;
  76. }
  77. CFTimeInterval localTime = time - startTime;
  78. Vector4d value = vector4d(currentVec);
  79. Vector4d toValue = vector4d(toVec);
  80. Vector4d velocity = vector4d(velocityVec);
  81. SSState4d state;
  82. state.p = toValue - value;
  83. // the solver assumes a spring of size zero
  84. // flip the velocity from user perspective to solver perspective
  85. state.v = velocity * -1;
  86. solver->advance(state, localTime, dt);
  87. value = toValue - state.p;
  88. // flip velocity back to user perspective
  89. velocity = state.v * -1;
  90. *currentVec = value;
  91. if (velocityVec) {
  92. *velocityVec = velocity;
  93. }
  94. clampCurrentValue();
  95. return true;
  96. }
  97. virtual void reset(bool all) {
  98. _POPPropertyAnimationState::reset(all);
  99. if (solver) {
  100. solver->setConstants(dynamicsTension, dynamicsFriction, dynamicsMass);
  101. solver->reset();
  102. }
  103. }
  104. };
  105. typedef struct _POPSpringAnimationState POPSpringAnimationState;