reed@android.com | 161b00b | 2009-11-03 15:33:14 +0000 | [diff] [blame^] | 1 | #include "SkCubicInterval.h" |
| 2 | |
| 3 | static 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 | |
| 8 | static 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 | */ |
| 42 | SkScalar 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 | |