https://github.com/YouXianMing

使用一元二次方程做实时动画

使用一元二次方程做实时动画

效果:

原理(图中坐标略有错误,仅供参考-_-!!):

 

YXMath.h + YXMath.m

//
//  YXMath.h
//
//  http://home.cnblogs.com/u/YouXianMing/
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface YXMath : NSObject

/*---- 计算一元一次方程 ----

    y = kX + b
 
 ------------------------*/
@property (nonatomic, assign, readonly) CGFloat  k;
@property (nonatomic, assign, readonly) CGFloat  b;
- (instancetype)initWithLinearFunctionPointA:(CGPoint)pointA
                                      pointB:(CGPoint)pointB;


/*---- 计算一元二次方程普通式 ----

 y = aX^2 + bX + c
 
 ----------------------------*/
@property (nonatomic, assign, readonly) CGFloat  A;
@property (nonatomic, assign, readonly) CGFloat  B;
@property (nonatomic, assign, readonly) CGFloat  C;
- (instancetype)initWithQuadraticFunctionPointA:(CGPoint)pointA
                                         pointB:(CGPoint)pointB
                                         pointC:(CGPoint)pointC;

/*---- 计算一元二次方程顶点式 ----
 
 y = a(X - h)^2 + k
 注意:顶点为(h, k)
 
 ----------------------------*/
@property (nonatomic, assign, readonly) CGFloat  a;
- (instancetype)initWithQuadraticFunctionPointApex:(CGPoint)apex
                                             point:(CGPoint)point;


@end
//
//  YXMath.m
//
//  http://home.cnblogs.com/u/YouXianMing/
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import "YXMath.h"

@implementation YXMath

- (instancetype)initWithQuadraticFunctionPointA:(CGPoint)pointA
                                         pointB:(CGPoint)pointB
                                         pointC:(CGPoint)pointC
{
    self = [super init];
    if (self)
    {
        CGFloat x1 = pointA.x; CGFloat y1 = pointA.y;
        CGFloat x2 = pointB.x; CGFloat y2 = pointB.y;
        CGFloat x3 = pointC.x; CGFloat y3 = pointC.y;
        
        _A = calculateA(x1, y1, x2, y2, x3, y3);
        _B = calculateB(x1, y1, x2, y2, x3, y3);
        _C = calculateC(x1, y1, x2, y2, x3, y3);
    }
    return self;
}

- (instancetype)initWithLinearFunctionPointA:(CGPoint)pointA
                                        pointB:(CGPoint)pointB
{
    self = [super init];
    if (self)
    {
        CGFloat x1 = pointA.x; CGFloat y1 = pointA.y;
        CGFloat x2 = pointB.x; CGFloat y2 = pointB.y;
        
        _k = calculateSlope(x1, y1, x2, y2);
        _b = calculateConstant(x1, y1, x2, y2);
    }
    return self;
}

- (instancetype)initWithQuadraticFunctionPointApex:(CGPoint)apex
                                             point:(CGPoint)point
{
    self = [super init];
    if (self)
    {
        CGFloat h  = apex.x; CGFloat   k = apex.y;
        CGFloat x  = point.x; CGFloat  y = point.y;
        
        _a = (y - k)/((x - h)*(x - h));
    }
    return self;
}

#pragma mark - 计算常数a b c
CGFloat calculateA(CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2, CGFloat x3, CGFloat y3)
{
    return ((y2 - y1)/(x2 - x1) - (y3 - y2)/(x3 - x2))/(x1 - x3);
}

CGFloat calculateB(CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2, CGFloat x3, CGFloat y3)
{
    return (y2 - y1)/(x2 - x1) - (((y2 - y1)/(x2 - x1) - (y3 - y2)/(x3 - x2))/(x1 - x3));
}

CGFloat calculateC(CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2, CGFloat x3, CGFloat y3)
{
    CGFloat a = calculateA(x1, y1, x2, y2, x3, y3);
    CGFloat b = calculateB(x1, y1, x2, y2, x3, y3);
    return y1 - a*x1*x1 - b*x1;
}

#pragma mark - 计算斜率 k
CGFloat calculateSlope(CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2)
{
    return (y2 - y1) / (x2 - x1);
}

#pragma mark - 计算常数 b
CGFloat calculateConstant(CGFloat x1, CGFloat y1, CGFloat x2, CGFloat y2)
{
    return (y1*(x2 - x1) - x1*(y2 - y1)) / (x2 - x1);
}


@end

RootViewController.m

//
//  RootViewController.m
//  Line
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import "RootViewController.h"
#import "YXMath.h"

@interface RootViewController ()<UIScrollViewDelegate>

{
    UIView    *_circle;
    YXMath    *_parabola;
    YXMath    *_line;
}

@end

@implementation RootViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    UIScrollView *rootScrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
    rootScrollView.contentSize = CGSizeMake(self.view.bounds.size.width*2,
                                            self.view.bounds.size.height);
    rootScrollView.pagingEnabled = YES;
    rootScrollView.delegate = self;
    [self.view addSubview:rootScrollView];
    
    // 计算一元二次方程顶点式
    _parabola = [[YXMath alloc] initWithQuadraticFunctionPointApex:CGPointMake(20, 20)
                                                             point:CGPointMake(340, 600)];
    
    // 计算一元一次方程
    _line     = [[YXMath alloc] initWithLinearFunctionPointA:CGPointMake(0, 20)
                                                      pointB:CGPointMake(320, 620)];
    
    
    _circle = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 10, 10)];
    _circle.layer.cornerRadius = 5.f;
    _circle.backgroundColor = [UIColor redColor];
    [rootScrollView addSubview:_circle];
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    NSLog(@"%f", scrollView.contentOffset.x);
    CGRect tmp = _circle.frame;
    tmp.origin.y = _parabola.a*(tmp.origin.x - 20)*(tmp.origin.x - 20) + 20;
    tmp.origin.x = _line.k*scrollView.contentOffset.x + _line.b;
    _circle.frame = tmp;
}

@end

注意:

动态设置动画都是需要精确计算的,按照线性关系,或者抛物线关系等等,需要精确计算.

 

 

posted @ 2014-06-24 09:11  YouXianMing  阅读(582)  评论(1编辑  收藏  举报