zoukankan      html  css  js  c++  java
  • 使用一元二次方程做实时动画

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

    效果:

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

    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

    注意:

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

  • 相关阅读:
    Java中的I/O 线程 网络
    20169214 2016-2017-2 《网络攻防实践》第六周学习总结
    20169214 2016-2017-2 《网络攻防实践》第五周学习总结
    20169214 2016-2017-2 《移动平台开发实践》第五周学习总结
    20169214 2016-2017-2 《移动平台开发实践》第四周学习总结
    20169214 2016-2017-2 《网络攻防实践》第四周学习总结
    20169214 2016-2017-2 《网络攻防实践》第三周学习总结
    20169214 2016-2017-2 《移动平台开发实践》第三周学习总结
    20169214 2016-2017-2《网络攻防实践》第二周学习总结
    Android开发设计 实验报告
  • 原文地址:https://www.cnblogs.com/YouXianMing/p/3805377.html
Copyright © 2011-2022 走看看