You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

59 lines
2.0 KiB

2 years ago
  1. //
  2. // KeyframeGroup+Extensions.swift
  3. // Lottie
  4. //
  5. // Created by JT Bergman on 6/20/22.
  6. //
  7. import CoreGraphics
  8. import Foundation
  9. extension KeyframeGroup where T == Vector1D {
  10. /// Manually interpolates the keyframes so that they are defined linearly
  11. ///
  12. /// This method uses `UnitBezier` to perform the interpolation. It will create one keyframe
  13. /// for each frame of the animation. For instance, if it is given a keyframe at time 0 and a keyframe
  14. /// at time 10, it will create 10 interpolated keyframes. It is currently not optimized.
  15. func manuallyInterpolateKeyframes() -> ContiguousArray<Keyframe<T>> {
  16. guard keyframes.count > 1 else {
  17. return keyframes
  18. }
  19. var output = ContiguousArray<Keyframe<Vector1D>>()
  20. for idx in 1 ..< keyframes.count {
  21. let prev = keyframes[idx - 1]
  22. let curr = keyframes[idx]
  23. // The timing function is responsible for computing the expected progress
  24. let outTangent = prev.outTangent?.pointValue ?? .zero
  25. let inTangent = curr.inTangent?.pointValue ?? .init(x: 1, y: 1)
  26. let timingFunction = UnitBezier(controlPoint1: outTangent, controlPoint2: inTangent)
  27. // These values are used to compute new values in the adjusted keyframes
  28. let difference = curr.value.value - prev.value.value
  29. let startValue = prev.value.value
  30. let startTime = prev.time
  31. let duration = max(Int(curr.time - prev.time), 0)
  32. // Create one interpolated keyframe for each time in the duration
  33. for t in 0 ... duration {
  34. let progress = timingFunction.value(
  35. for: CGFloat(t) / CGFloat(duration),
  36. epsilon: 0.005)
  37. let value = startValue + Double(progress) * difference
  38. output.append(
  39. Keyframe<Vector1D>(
  40. value: Vector1D(value),
  41. time: startTime + CGFloat(t),
  42. isHold: false,
  43. inTangent: nil,
  44. outTangent: nil,
  45. spatialInTangent: nil,
  46. spatialOutTangent: nil))
  47. }
  48. }
  49. return output
  50. }
  51. }