Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef UI_GFX_GEOMETRY_CUBIC_BEZIER_H_ | 5 #ifndef UI_GFX_GEOMETRY_CUBIC_BEZIER_H_ |
| 6 #define UI_GFX_GEOMETRY_CUBIC_BEZIER_H_ | 6 #define UI_GFX_GEOMETRY_CUBIC_BEZIER_H_ |
| 7 | 7 |
| 8 #include <algorithm> | |
| 9 #include <cmath> | |
| 10 | |
| 11 #include "base/logging.h" | |
| 8 #include "base/macros.h" | 12 #include "base/macros.h" |
| 9 #include "ui/gfx/gfx_export.h" | 13 #include "ui/gfx/gfx_export.h" |
| 10 | 14 |
| 11 namespace gfx { | 15 namespace gfx { |
| 12 | 16 |
| 13 class GFX_EXPORT CubicBezier { | 17 class GFX_EXPORT CubicBezier { |
| 14 public: | 18 public: |
| 15 CubicBezier(double x1, double y1, double x2, double y2); | 19 CubicBezier(double p1x, double p1y, double p2x, double p2y); |
| 16 ~CubicBezier(); | |
| 17 | 20 |
| 18 // Returns an approximation of y at the given x. | 21 static double GetDefaultEpsilon(); |
| 19 double Solve(double x) const; | 22 |
| 23 double SampleCurveX(double t) const { | |
| 24 // `ax t^3 + bx t^2 + cx t' expanded using Horner's rule. | |
| 25 return ((ax * t + bx) * t + cx) * t; | |
| 26 } | |
| 27 | |
| 28 double SampleCurveY(double t) const { return ((ay * t + by) * t + cy) * t; } | |
| 29 | |
| 30 double SampleCurveDerivativeX(double t) const { | |
| 31 return (3.0 * ax * t + 2.0 * bx) * t + cx; | |
| 32 } | |
| 33 | |
| 34 double SampleCurveDerivativeY(double t) const { | |
| 35 return (3.0 * ay * t + 2.0 * by) * t + cy; | |
| 36 } | |
| 37 | |
| 38 // Given an x value, find a parametric value it came from. | |
| 39 double SolveCurveX(double x, double epsilon) const { | |
|
danakj
2016/04/01 01:35:58
Put this in the .cc file.
loyso (OOO)
2016/04/01 04:40:06
Done.
| |
| 40 DCHECK(x >= 0.0); | |
|
danakj
2016/04/01 01:35:58
DCHECK_GE
loyso (OOO)
2016/04/01 04:40:06
Done.
| |
| 41 DCHECK(x <= 1.0); | |
| 42 | |
| 43 double t0; | |
| 44 double t1; | |
| 45 double t2; | |
| 46 double x2; | |
| 47 double d2; | |
| 48 int i; | |
| 49 | |
| 50 // First try a few iterations of Newton's method -- normally very fast. | |
| 51 for (t2 = x, i = 0; i < 8; i++) { | |
| 52 x2 = SampleCurveX(t2) - x; | |
| 53 if (fabs(x2) < epsilon) | |
| 54 return t2; | |
| 55 d2 = SampleCurveDerivativeX(t2); | |
| 56 if (fabs(d2) < 1e-6) | |
| 57 break; | |
| 58 t2 = t2 - x2 / d2; | |
| 59 } | |
| 60 | |
| 61 // Fall back to the bisection method for reliability. | |
| 62 t0 = 0.0; | |
| 63 t1 = 1.0; | |
| 64 t2 = x; | |
| 65 | |
| 66 while (t0 < t1) { | |
| 67 x2 = SampleCurveX(t2); | |
| 68 if (fabs(x2 - x) < epsilon) | |
| 69 return t2; | |
| 70 if (x > x2) | |
| 71 t0 = t2; | |
| 72 else | |
| 73 t1 = t2; | |
| 74 t2 = (t1 - t0) * .5 + t0; | |
| 75 } | |
| 76 | |
| 77 // Failure. | |
| 78 return t2; | |
| 79 } | |
| 80 | |
| 81 // Evaluates y at the given x. | |
| 82 double Solve(double x) const { | |
| 83 return SolveWithEpsilon(x, GetDefaultEpsilon()); | |
| 84 } | |
| 85 | |
| 86 // Evaluates y at the given x. The epsilon parameter provides a hint as to the | |
| 87 // required | |
| 88 // accuracy and is not guaranteed. | |
| 89 double SolveWithEpsilon(double x, double epsilon) const { | |
| 90 if (x < 0.0) | |
| 91 return 0.0 + start_gradient_ * x; | |
| 92 if (x > 1.0) | |
| 93 return 1.0 + end_gradient_ * (x - 1.0); | |
| 94 return SampleCurveY(SolveCurveX(x, epsilon)); | |
| 95 } | |
| 20 | 96 |
| 21 // Returns an approximation of dy/dx at the given x. | 97 // Returns an approximation of dy/dx at the given x. |
| 22 double Slope(double x) const; | 98 double Slope(double x) const { |
| 99 return SlopeWithEpsilon(x, GetDefaultEpsilon()); | |
| 100 } | |
| 101 | |
| 102 double SlopeWithEpsilon(double x, double epsilon) const { | |
| 103 double t = SolveCurveX(x, epsilon); | |
| 104 double dx = SampleCurveDerivativeX(t); | |
| 105 double dy = SampleCurveDerivativeY(t); | |
| 106 return dy / dx; | |
| 107 } | |
| 23 | 108 |
| 24 // Sets |min| and |max| to the bezier's minimum and maximium y values in the | 109 // Sets |min| and |max| to the bezier's minimum and maximium y values in the |
| 25 // interval [0, 1]. | 110 // interval [0, 1]. |
| 26 void Range(double* min, double* max) const; | 111 void Range(double* min, double* max) const { |
|
danakj
2016/04/01 01:35:58
Just make 2 getters, minimum() and maximum()?
loyso (OOO)
2016/04/01 02:58:03
It would affect the call sites. Can we change the
danakj
2016/04/01 19:26:17
Sure yep. Put a TODO?
danakj
2016/04/01 19:54:33
Or, make the blink wrapper use the min/max accesso
loyso (OOO)
2016/04/04 03:39:58
Done. It's CC-only for now.
| |
| 112 *min = range_min_; | |
| 113 *max = range_max_; | |
| 114 } | |
| 27 | 115 |
| 28 private: | 116 private: |
| 29 void InitGradients(); | 117 void InitCoefficients(double p1x, double p1y, double p2x, double p2y); |
| 118 void InitGradients(double p1x, double p1y, double p2x, double p2y); | |
| 119 void InitRange(double p1y, double p2y); | |
| 30 | 120 |
| 31 double x1_; | 121 double ax; |
| 32 double y1_; | 122 double bx; |
| 33 double x2_; | 123 double cx; |
| 34 double y2_; | 124 |
| 125 double ay; | |
| 126 double by; | |
| 127 double cy; | |
| 35 | 128 |
| 36 double start_gradient_; | 129 double start_gradient_; |
| 37 double end_gradient_; | 130 double end_gradient_; |
| 38 | 131 |
| 132 double range_min_; | |
| 133 double range_max_; | |
| 134 | |
| 39 DISALLOW_ASSIGN(CubicBezier); | 135 DISALLOW_ASSIGN(CubicBezier); |
| 40 }; | 136 }; |
| 41 | 137 |
| 42 } // namespace gfx | 138 } // namespace gfx |
| 43 | 139 |
| 44 #endif // UI_GFX_GEOMETRY_CUBIC_BEZIER_H_ | 140 #endif // UI_GFX_GEOMETRY_CUBIC_BEZIER_H_ |
| OLD | NEW |