LOTValueInterpolator.m 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. //
  2. // LOTValueInterpolator.m
  3. // Pods
  4. //
  5. // Created by brandon_withrow on 7/10/17.
  6. //
  7. //
  8. #import "LOTValueInterpolator.h"
  9. #import "CGGeometry+LOTAdditions.h"
  10. @interface LOTValueInterpolator ()
  11. @property (nonatomic, strong) NSArray<LOTKeyframe *> *keyframes;
  12. @end
  13. @implementation LOTValueInterpolator
  14. - (instancetype)initWithKeyframes:(NSArray <LOTKeyframe *> *)keyframes {
  15. self = [super init];
  16. if (self) {
  17. _keyframes = keyframes;
  18. }
  19. return self;
  20. }
  21. - (BOOL)hasUpdateForFrame:(NSNumber *)frame {
  22. if (self.hasDelegateOverride) {
  23. return YES;
  24. }
  25. /*
  26. Cases we dont update keyframe
  27. if time is in span and leading keyframe is hold
  28. if trailing keyframe is nil and time is after leading
  29. if leading keyframe is nil and time is before trailing
  30. */
  31. if (self.leadingKeyframe &&
  32. self.trailingKeyframe == nil &&
  33. self.leadingKeyframe.keyframeTime.floatValue < frame.floatValue) {
  34. // Frame is after bounds of keyframes. Clip
  35. return NO;
  36. }
  37. if (self.trailingKeyframe &&
  38. self.leadingKeyframe == nil &&
  39. self.trailingKeyframe.keyframeTime.floatValue > frame.floatValue) {
  40. // Frame is before keyframes bounds. Clip.
  41. return NO;
  42. }
  43. if (self.leadingKeyframe && self.trailingKeyframe &&
  44. self.leadingKeyframe.isHold &&
  45. self.leadingKeyframe.keyframeTime.floatValue < frame.floatValue &&
  46. self.trailingKeyframe.keyframeTime.floatValue > frame.floatValue) {
  47. // Frame is in span and current span is a hold keyframe
  48. return NO;
  49. }
  50. return YES;
  51. }
  52. - (void)updateKeyframeSpanForFrame:(NSNumber *)frame {
  53. if (self.leadingKeyframe == nil &&
  54. self.trailingKeyframe == nil) {
  55. // Set Initial Keyframes
  56. LOTKeyframe *first = _keyframes.firstObject;
  57. if (first.keyframeTime.floatValue > 0) {
  58. self.trailingKeyframe = first;
  59. } else {
  60. self.leadingKeyframe = first;
  61. if (_keyframes.count > 1) {
  62. self.trailingKeyframe = _keyframes[1];
  63. }
  64. }
  65. }
  66. if (self.trailingKeyframe && frame.floatValue >= self.trailingKeyframe.keyframeTime.floatValue) {
  67. // Frame is after current span, can move forward
  68. NSInteger index = [_keyframes indexOfObject:self.trailingKeyframe];
  69. BOOL keyframeFound = NO;
  70. LOTKeyframe *testLeading = self.trailingKeyframe;
  71. LOTKeyframe *testTrailing = nil;
  72. while (keyframeFound == NO) {
  73. index ++;
  74. if (index < _keyframes.count) {
  75. testTrailing = _keyframes[index];
  76. if (frame.floatValue < testTrailing.keyframeTime.floatValue) {
  77. // This is the span.
  78. keyframeFound = YES;
  79. } else {
  80. testLeading = testTrailing;
  81. }
  82. } else {
  83. // Leading is Last object
  84. testTrailing = nil;
  85. keyframeFound = YES;
  86. }
  87. }
  88. self.leadingKeyframe = testLeading;
  89. self.trailingKeyframe = testTrailing;
  90. } else if (self.leadingKeyframe && frame.floatValue < self.leadingKeyframe.keyframeTime.floatValue) {
  91. // Frame is before current span, can move back a span
  92. NSInteger index = [_keyframes indexOfObject:self.leadingKeyframe];
  93. BOOL keyframeFound = NO;
  94. LOTKeyframe *testLeading = nil;
  95. LOTKeyframe *testTrailing = self.leadingKeyframe;
  96. while (keyframeFound == NO) {
  97. index --;
  98. if (index >= 0) {
  99. testLeading = _keyframes[index];
  100. if (frame.floatValue >= testLeading.keyframeTime.floatValue) {
  101. // This is the span.
  102. keyframeFound = YES;
  103. } else {
  104. testTrailing = testLeading;
  105. }
  106. } else {
  107. // Trailing is first object
  108. testLeading = nil;
  109. keyframeFound = YES;
  110. }
  111. }
  112. self.leadingKeyframe = testLeading;
  113. self.trailingKeyframe = testTrailing;
  114. }
  115. }
  116. - (CGFloat)progressForFrame:(NSNumber *)frame {
  117. [self updateKeyframeSpanForFrame:frame];
  118. // At this point frame definitely exists between leading and trailing keyframes
  119. if (self.leadingKeyframe.keyframeTime == frame) {
  120. // Frame is leading keyframe
  121. return 0;
  122. }
  123. if (self.trailingKeyframe == nil) {
  124. // Frame is after end of keyframe timeline
  125. return 0;
  126. }
  127. if (self.leadingKeyframe.isHold) {
  128. // Hold Keyframe
  129. return 0;
  130. }
  131. if (self.leadingKeyframe == nil) {
  132. // Frame is before start of keyframe timeline
  133. return 1;
  134. }
  135. CGFloat progression = LOT_RemapValue(frame.floatValue, self.leadingKeyframe.keyframeTime.floatValue, self.trailingKeyframe.keyframeTime.floatValue, 0, 1);
  136. if ((self.leadingKeyframe.outTangent.x != self.leadingKeyframe.outTangent.y ||
  137. self.trailingKeyframe.inTangent.x != self.trailingKeyframe.inTangent.y) &&
  138. (!LOT_CGPointIsZero(self.leadingKeyframe.outTangent) &&
  139. !LOT_CGPointIsZero(self.trailingKeyframe.inTangent))) {
  140. // Bezier Time Curve
  141. progression = LOT_CubicBezierInterpolate(CGPointMake(0, 0), self.leadingKeyframe.outTangent, self.trailingKeyframe.inTangent, CGPointMake(1, 1), progression);
  142. }
  143. return progression;
  144. }
  145. - (void)setValueDelegate:(id<LOTValueDelegate> _Nonnull)delegate {
  146. NSAssert((NO), @"Interpolator does not support value callbacks");
  147. }
  148. @end