| 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 |