OLD | NEW |
| (Empty) |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "platform/animation/UnitBezier.h" | |
6 | |
7 namespace blink { | |
8 | |
9 const double UnitBezier::kBezierEpsilon = 1e-7; | |
10 | |
11 UnitBezier::UnitBezier(double p1x, double p1y, double p2x, double p2y) | |
12 { | |
13 initCoefficients(p1x, p1y, p2x, p2y); | |
14 initGradients(p1x, p1y, p2x, p2y); | |
15 initRange(p1y, p2y); | |
16 } | |
17 | |
18 void UnitBezier::initCoefficients(double p1x, double p1y, double p2x, double p2y
) | |
19 { | |
20 // Calculate the polynomial coefficients, implicit first and last control po
ints are (0,0) and (1,1). | |
21 cx = 3.0 * p1x; | |
22 bx = 3.0 * (p2x - p1x) - cx; | |
23 ax = 1.0 - cx -bx; | |
24 | |
25 cy = 3.0 * p1y; | |
26 by = 3.0 * (p2y - p1y) - cy; | |
27 ay = 1.0 - cy - by; | |
28 } | |
29 | |
30 void UnitBezier::initGradients(double p1x, double p1y, double p2x, double p2y) | |
31 { | |
32 // End-point gradients are used to calculate timing function results | |
33 // outside the range [0, 1]. | |
34 // | |
35 // There are three possibilities for the gradient at each end: | |
36 // (1) the closest control point is not horizontally coincident with regard
to | |
37 // (0, 0) or (1, 1). In this case the line between the end point and | |
38 // the control point is tangent to the bezier at the end point. | |
39 // (2) the closest control point is coincident with the end point. In | |
40 // this case the line between the end point and the far control | |
41 // point is tangent to the bezier at the end point. | |
42 // (3) the closest control point is horizontally coincident with the end | |
43 // point, but vertically distinct. In this case the gradient at the | |
44 // end point is Infinite. However, this causes issues when | |
45 // interpolating. As a result, we break down to a simple case of | |
46 // 0 gradient under these conditions. | |
47 | |
48 if (p1x > 0) | |
49 m_startGradient = p1y / p1x; | |
50 else if (!p1y && p2x > 0) | |
51 m_startGradient = p2y / p2x; | |
52 else | |
53 m_startGradient = 0; | |
54 | |
55 if (p2x < 1) | |
56 m_endGradient = (p2y - 1) / (p2x - 1); | |
57 else if (p2x == 1 && p1x < 1) | |
58 m_endGradient = (p1y - 1) / (p1x - 1); | |
59 else | |
60 m_endGradient = 0; | |
61 } | |
62 | |
63 void UnitBezier::initRange(double p1y, double p2y) | |
64 { | |
65 m_rangeMin = 0; | |
66 m_rangeMax = 1; | |
67 if (0 <= p1y && p1y < 1 && 0 <= p2y && p2y <= 1) | |
68 return; | |
69 | |
70 // Represent the function's derivative in the form at^2 + bt + c | |
71 // as in sampleCurveDerivativeY. | |
72 // (Technically this is (dy/dt)*(1/3), which is suitable for finding zeros | |
73 // but does not actually give the slope of the curve.) | |
74 const double a = 3.0 * ay; | |
75 const double b = 2.0 * by; | |
76 const double c = cy; | |
77 | |
78 // Check if the derivative is constant. | |
79 if (std::abs(a) < kBezierEpsilon && std::abs(b) < kBezierEpsilon) | |
80 return; | |
81 | |
82 // Zeros of the function's derivative. | |
83 double t1 = 0; | |
84 double t2 = 0; | |
85 | |
86 if (std::abs(a) < kBezierEpsilon) { | |
87 // The function's derivative is linear. | |
88 t1 = -c / b; | |
89 } else { | |
90 // The function's derivative is a quadratic. We find the zeros of this | |
91 // quadratic using the quadratic formula. | |
92 double discriminant = b * b - 4 * a * c; | |
93 if (discriminant < 0) | |
94 return; | |
95 double discriminantSqrt = sqrt(discriminant); | |
96 t1 = (-b + discriminantSqrt) / (2 * a); | |
97 t2 = (-b - discriminantSqrt) / (2 * a); | |
98 } | |
99 | |
100 double sol1 = 0; | |
101 double sol2 = 0; | |
102 | |
103 if (0 < t1 && t1 < 1) | |
104 sol1 = sampleCurveY(t1); | |
105 | |
106 if (0 < t2 && t2 < 1) | |
107 sol2 = sampleCurveY(t2); | |
108 | |
109 m_rangeMin = std::min(std::min(m_rangeMin, sol1), sol2); | |
110 m_rangeMax = std::max(std::max(m_rangeMax, sol1), sol2); | |
111 } | |
112 | |
113 } // namespace blink | |
OLD | NEW |