LOTCircleAnimator.m 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. //
  2. // LOTCircleAnimator.m
  3. // Lottie
  4. //
  5. // Created by brandon_withrow on 7/19/17.
  6. // Copyright © 2017 Airbnb. All rights reserved.
  7. //
  8. #import "LOTCircleAnimator.h"
  9. #import "LOTPointInterpolator.h"
  10. const CGFloat kLOTEllipseControlPointPercentage = 0.55228;
  11. @implementation LOTCircleAnimator {
  12. LOTPointInterpolator *_centerInterpolator;
  13. LOTPointInterpolator *_sizeInterpolator;
  14. BOOL _reversed;
  15. }
  16. - (instancetype _Nonnull)initWithInputNode:(LOTAnimatorNode *_Nullable)inputNode
  17. shapeCircle:(LOTShapeCircle *_Nonnull)shapeCircle {
  18. self = [super initWithInputNode:inputNode keyName:shapeCircle.keyname];
  19. if (self) {
  20. _centerInterpolator = [[LOTPointInterpolator alloc] initWithKeyframes:shapeCircle.position.keyframes];
  21. _sizeInterpolator = [[LOTPointInterpolator alloc] initWithKeyframes:shapeCircle.size.keyframes];
  22. _reversed = shapeCircle.reversed;
  23. }
  24. return self;
  25. }
  26. - (NSDictionary *)valueInterpolators {
  27. return @{@"Size" : _sizeInterpolator,
  28. @"Position" : _centerInterpolator};
  29. }
  30. - (BOOL)needsUpdateForFrame:(NSNumber *)frame {
  31. return [_centerInterpolator hasUpdateForFrame:frame] || [_sizeInterpolator hasUpdateForFrame:frame];
  32. }
  33. - (void)performLocalUpdate {
  34. // Unfortunately we HAVE to manually build out the ellipse.
  35. // Every Apple method constructs from the 3 o-clock position
  36. // After effects constructs from the Noon position.
  37. // After effects does clockwise, but also has a flag for reversed.
  38. CGPoint center = [_centerInterpolator pointValueForFrame:self.currentFrame];
  39. CGPoint size = [_sizeInterpolator pointValueForFrame:self.currentFrame];
  40. CGFloat halfWidth = size.x / 2;
  41. CGFloat halfHeight = size.y / 2;
  42. if (_reversed) {
  43. halfWidth = halfWidth * -1;
  44. }
  45. CGPoint circleQ1 = CGPointMake(center.x, center.y - halfHeight);
  46. CGPoint circleQ2 = CGPointMake(center.x + halfWidth, center.y);
  47. CGPoint circleQ3 = CGPointMake(center.x, center.y + halfHeight);
  48. CGPoint circleQ4 = CGPointMake(center.x - halfWidth, center.y);
  49. CGFloat cpW = halfWidth * kLOTEllipseControlPointPercentage;
  50. CGFloat cpH = halfHeight * kLOTEllipseControlPointPercentage;
  51. LOTBezierPath *path = [[LOTBezierPath alloc] init];
  52. path.cacheLengths = self.pathShouldCacheLengths;
  53. [path LOT_moveToPoint:circleQ1];
  54. [path LOT_addCurveToPoint:circleQ2 controlPoint1:CGPointMake(circleQ1.x + cpW, circleQ1.y) controlPoint2:CGPointMake(circleQ2.x, circleQ2.y - cpH)];
  55. [path LOT_addCurveToPoint:circleQ3 controlPoint1:CGPointMake(circleQ2.x, circleQ2.y + cpH) controlPoint2:CGPointMake(circleQ3.x + cpW, circleQ3.y)];
  56. [path LOT_addCurveToPoint:circleQ4 controlPoint1:CGPointMake(circleQ3.x - cpW, circleQ3.y) controlPoint2:CGPointMake(circleQ4.x, circleQ4.y + cpH)];
  57. [path LOT_addCurveToPoint:circleQ1 controlPoint1:CGPointMake(circleQ4.x, circleQ4.y - cpH) controlPoint2:CGPointMake(circleQ1.x - cpW, circleQ1.y)];
  58. self.localPath = path;
  59. }
  60. @end