blob: 7a6084c4a391246d8d7f81eb967c4c24a6b69828 [file] [log] [blame]
reed@android.com161b00b2009-11-03 15:33:14 +00001#include "SkCubicInterval.h"
2
3static SkScalar eval_cubic(SkScalar c1, SkScalar c2, SkScalar c3,
4 SkScalar t) {
5 return SkScalarMul(SkScalarMul(SkScalarMul(c3, t) + c2, t) + c1, t);
6}
7
8static SkScalar find_cubic_t(SkScalar c1, SkScalar c2, SkScalar c3,
9 SkScalar targetX) {
10 SkScalar minT = 0;
11 SkScalar maxT = SK_Scalar1;
12 SkScalar t;
13
14 for (;;) {
15 t = SkScalarAve(minT, maxT);
16 SkScalar x = eval_cubic(c1, c2, c3, t);
17 if (SkScalarNearlyZero(x - targetX)) {
18 break;
19 }
20 // subdivide the range and try again
21 if (x < targetX) {
22 minT = t;
23 } else {
24 maxT = t;
25 }
26 }
27 return t;
28}
29
30/*
31 a(1-t)^3 + 3bt(1-t)^2 + 3ct^2(1-t) + dt^3
32 a: [0, 0]
33 d: [1, 1]
34
35 3bt - 6bt^2 + 3bt^3 + 3ct^2 - 3ct^3 + t^3
36 C1 = t^1: 3b
37 C2 = t^2: 3c - 6b
38 C3 = t^3: 3b - 3c + 1
39
40 ((C3*t + C2)*t + C1)*t
41 */
42SkScalar SkEvalCubicInterval(SkScalar x1, SkScalar y1,
43 SkScalar x2, SkScalar y2,
44 SkScalar unitX) {
45 x1 = SkScalarPin(x1, 0, SK_Scalar1);
46 x2 = SkScalarPin(x2, 0, SK_Scalar1);
47 unitX = SkScalarPin(unitX, 0, SK_Scalar1);
48
49 // First compute our coefficients in X
50 x1 *= 3;
51 x2 *= 3;
52
53 // now search for t given unitX
54 SkScalar t = find_cubic_t(x1, x2 - 2*x1, x1 - x2 + SK_Scalar1, unitX);
55
56 // now evaluate the cubic in Y
57 y1 *= 3;
58 y2 *= 3;
59 return eval_cubic(y1, y2 - 2*y1, y1 - y2 + SK_Scalar1, t);
60}
61