Last active
December 13, 2015 17:19
-
-
Save jstn/4947040 to your computer and use it in GitHub Desktop.
iOS tweening, adapted from Webkit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "JXBezier.h" | |
#include <math.h> | |
JXUnitBezier JXUnitBezierMake(double p1x, double p1y, double p2x, double p2y) { | |
JXUnitBezier bezier; | |
bezier.cx = 3.0 * p1x; | |
bezier.bx = 3.0 * (p2x - p1x) - bezier.cx; | |
bezier.ax = 1.0 - bezier.cx - bezier.bx; | |
bezier.cy = 3.0 * p1y; | |
bezier.by = 3.0 * (p2y - p1y) - bezier.cy; | |
bezier.ay = 1.0 - bezier.cy - bezier.by; | |
return bezier; | |
} | |
double JXBezierEpsilon(double duration) { | |
return 1.0 / (200.0 * duration); | |
} | |
double JXUnitBezierSampleCurveDerivativeX(JXUnitBezier b, double t) { | |
return (3.0 * b.ax * t + 2.0 * b.bx) * t + b.cx; | |
} | |
double JXUnitBezierSampleCurveX(JXUnitBezier b, double t) { | |
return ((b.ax * t + b.bx) * t + b.cx) * t; | |
} | |
double JXUnitBezierSampleCurveY(JXUnitBezier b, double t) { | |
return ((b.ay * t + b.by) * t + b.cy) * t; | |
} | |
double JXUnitBezierSolveCurveX(JXUnitBezier b, double x, double epsilon) { | |
double t0; | |
double t1; | |
double t2; | |
double x2; | |
double d2; | |
int i; | |
for (t2 = x, i = 0; i < 8; i++) { | |
x2 = JXUnitBezierSampleCurveX(b, t2) - x; | |
if (fabs(x2) < epsilon) | |
return t2; | |
d2 = JXUnitBezierSampleCurveDerivativeX(b, t2); | |
if (fabs(d2) < 1e-6) | |
break; | |
t2 = t2 - x2 / d2; | |
} | |
t0 = 0.0; | |
t1 = 1.0; | |
t2 = x; | |
if (t2 < t0) | |
return t0; | |
if (t2 > t1) | |
return t1; | |
while (t0 < t1) { | |
x2 = JXUnitBezierSampleCurveX(b, t2); | |
if (fabs(x2 - x) < epsilon) | |
return t2; | |
if (x > x2) | |
t0 = t2; | |
else | |
t1 = t2; | |
t2 = (t1 - t0) * .5 + t0; | |
} | |
return t2; | |
} | |
double JXUnitBezierSolve(JXUnitBezier b, double x, double epsilon) { | |
return JXUnitBezierSampleCurveY(b, JXUnitBezierSolveCurveX(b, x, epsilon)); | |
} | |
double JXCubicBezierSolve(double p1x, double p1y, double p2x, double p2y, double t, double duration) { | |
JXUnitBezier bezier = JXUnitBezierMake(p1x, p1y, p2x, p2y); | |
return JXUnitBezierSolve(bezier, t, JXBezierEpsilon(duration)); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef _JXBEZIER_H_ | |
#define _JXBEZIER_H_ | |
typedef struct { | |
double ax; | |
double bx; | |
double cx; | |
double ay; | |
double by; | |
double cy; | |
} JXUnitBezier; | |
JXUnitBezier JXUnitBezierMake(double p1x, double p1y, double p2x, double p2y); | |
double JXBezierEpsilon(double duration); | |
double JXUnitBezierSampleCurveDerivativeX(JXUnitBezier b, double t); | |
double JXUnitBezierSampleCurveX(JXUnitBezier b, double t); | |
double JXUnitBezierSampleCurveY(JXUnitBezier b, double t); | |
double JXUnitBezierSolveCurveX(JXUnitBezier b, double x, double epsilon); | |
double JXUnitBezierSolve(JXUnitBezier b, double x, double epsilon); | |
double JXCubicBezierSolve(double p1x, double p1y, double p2x, double p2y, double t, double duration); | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <QuartzCore/QuartzCore.h> | |
@interface JXTween : NSObject | |
@property (strong, nonatomic) CAMediaTimingFunction *timingFunction; | |
@property (assign, nonatomic) double startTime; | |
@property (assign, nonatomic) double duration; | |
@property (assign, nonatomic) double startValue; | |
@property (assign, nonatomic) double endValue; | |
+ (instancetype)tweenWithFunction:(CAMediaTimingFunction *)tf | |
startTime:(double)st | |
duration:(double)du | |
startValue:(double)sv | |
endValue:(double)ev; | |
- (double)valueAtTime:(double)now; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "JXTween.h" | |
#import "JXBezier.h" | |
@interface JXTween () | |
@property (assign, nonatomic) double p1x; | |
@property (assign, nonatomic) double p1y; | |
@property (assign, nonatomic) double p2x; | |
@property (assign, nonatomic) double p2y; | |
@end | |
@implementation JXTween | |
+ (instancetype)tweenWithFunction:(CAMediaTimingFunction *)tf | |
startTime:(double)st | |
duration:(double)du | |
startValue:(double)sv | |
endValue:(double)ev | |
{ | |
JXTween *t = [[JXTween alloc] init]; | |
t.timingFunction = tf; | |
t.startTime = st; | |
t.duration = du; | |
t.startValue = sv; | |
t.endValue = ev; | |
return t; | |
} | |
- (void)setTimingFunction:(CAMediaTimingFunction *)function | |
{ | |
_timingFunction = function; | |
float p1[2]; | |
[_timingFunction getControlPointAtIndex:1 values:p1]; | |
float p2[2]; | |
[_timingFunction getControlPointAtIndex:2 values:p2]; | |
_p1x = (double)p1[0]; | |
_p1y = (double)p1[1]; | |
_p2x = (double)p2[0]; | |
_p2y = (double)p2[1]; | |
} | |
- (double)valueAtTime:(double)now | |
{ | |
double elapsed = now - _startTime; | |
if (elapsed >= _duration) | |
return _endValue; | |
double fractionalTime = elapsed / _duration; | |
double solution = JXCubicBezierSolve(_p1x, _p1y, _p2x, _p2y, fractionalTime, _duration); | |
double delta = _endValue - _startValue; | |
double value = _startValue + (solution * delta); | |
return value; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment