Welcome to mirror list, hosted at ThFree Co, Russian Federation.

MWMSpringAnimation.mm « Classes « Maps « iphone - github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: c9ae10c1e89b2f170544e315970c8af4c150d7cd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#import "MWMSpringAnimation.h"
#import "UIKitCategories.h"

@interface MWMSpringAnimation ()

@property (nonatomic) CGPoint velocity;
@property (nonatomic) CGPoint targetPoint;
@property (nonatomic) UIView * view;
@property (copy, nonatomic) MWMSpringAnimationCompletionBlock completion;

@end

@implementation MWMSpringAnimation

+ (instancetype)animationWithView:(UIView *)view target:(CGPoint)target velocity:(CGPoint)velocity completion:(MWMSpringAnimationCompletionBlock)completion
{
  return [[self alloc] initWithView:view target:target velocity:velocity completion:completion];
}

- (instancetype)initWithView:(UIView *)view target:(CGPoint)target velocity:(CGPoint)velocity completion:(MWMSpringAnimationCompletionBlock)completion
{
  self = [super init];
  if (self)
  {
    self.view = view;
    self.targetPoint = target;
    self.velocity = velocity;
    self.completion = completion;
  }
  return self;
}

- (void)animationTick:(CFTimeInterval)dt finished:(BOOL *)finished
{
  CGFloat const frictionConstant = 25.;
  CGFloat const springConstant = 300.;

  // friction force = velocity * friction constant
  CGPoint const frictionForce = CGPointMultiply(self.velocity, frictionConstant);
  // spring force = (target point - current position) * spring constant
  CGPoint const springForce = CGPointMultiply(CGPointSubtract(self.targetPoint, self.view.center), springConstant);
  // force = spring force - friction force
  CGPoint const force = CGPointSubtract(springForce, frictionForce);
  // velocity = current velocity + force * time / mass
  self.velocity = CGPointAdd(self.velocity, CGPointMultiply(force, dt));
  // position = current position + velocity * time
  self.view.center = CGPointAdd(self.view.center, CGPointMultiply(self.velocity, dt));

  CGFloat const speed = CGPointLength(self.velocity);
  CGFloat const distanceToGoal = CGPointLength(CGPointSubtract(self.targetPoint, self.view.center));
  if (speed < 0.05 && distanceToGoal < 1)
  {
    self.view.center = self.targetPoint;
    *finished = YES;
    if (self.completion)
      self.completion();
  }
}

+ (CGFloat)approxTargetFor:(CGFloat)startValue velocity:(CGFloat)velocity
{
  CGFloat const decelaration = (velocity > 0 ? -1.0 : 1.0) * 300.0;
  return startValue - (velocity * velocity) / (2.0 * decelaration);
}

@end