Index: src/core/SkGeometry.cpp |
diff --git a/src/core/SkGeometry.cpp b/src/core/SkGeometry.cpp |
index 254f79bf04b7730589452c4c0cd9daf0eea26d4e..71e22ab10472b0a8460fba951d85d0933197cc51 100644 |
--- a/src/core/SkGeometry.cpp |
+++ b/src/core/SkGeometry.cpp |
@@ -654,6 +654,75 @@ int SkChopCubicAtInflections(const SkPoint src[], SkPoint dst[10]) { |
return count + 1; |
} |
+// See http://http.developer.nvidia.com/GPUGems3/gpugems3_ch25.html (from the book GPU Gems 3) |
+// discr(I) = d0^2 * (3*d1^2 - 4*d0*d2) |
+// Classification: |
+// discr(I) > 0 Serpentine |
+// discr(I) = 0 Cusp |
+// discr(I) < 0 Loop |
+// d0 = d1 = 0 Quadratic |
+// d0 = d1 = d2 = 0 Line |
+// p0 = p1 = p2 = p3 Point |
+static SkCubicType classify_cubic(const SkPoint p[4], const SkScalar d[3]) { |
+ if (p[0] == p[1] && p[0] == p[2] && p[0] == p[3]) { |
+ return kPoint_SkCubicType; |
+ } |
+ const SkScalar discr = d[0] * d[0] * (3.f * d[1] * d[1] - 4.f * d[0] * d[2]); |
+ if (discr > SK_ScalarNearlyZero) { |
+ return kSerpentine_SkCubicType; |
+ } else if (discr < -SK_ScalarNearlyZero) { |
+ return kLoop_SkCubicType; |
+ } else { |
+ if (0.f == d[0] && 0.f == d[1]) { |
+ return (0.f == d[2] ? kLine_SkCubicType : kQuadratic_SkCubicType); |
+ } else { |
+ return kCusp_SkCubicType; |
+ } |
+ } |
+} |
+ |
+// Assumes the third component of points is 1. |
+// Calcs p0 . (p1 x p2) |
+static SkScalar calc_dot_cross_cubic(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) { |
+ const SkScalar xComp = p0.fX * (p1.fY - p2.fY); |
+ const SkScalar yComp = p0.fY * (p2.fX - p1.fX); |
+ const SkScalar wComp = p1.fX * p2.fY - p1.fY * p2.fX; |
+ return (xComp + yComp + wComp); |
+} |
+ |
+// Calc coefficients of I(s,t) where roots of I are inflection points of curve |
+// I(s,t) = t*(3*d0*s^2 - 3*d1*s*t + d2*t^2) |
+// d0 = a1 - 2*a2+3*a3 |
+// d1 = -a2 + 3*a3 |
+// d2 = 3*a3 |
+// a1 = p0 . (p3 x p2) |
+// a2 = p1 . (p0 x p3) |
+// a3 = p2 . (p1 x p0) |
+// Places the values of d1, d2, d3 in array d passed in |
+static void calc_cubic_inflection_func(const SkPoint p[4], SkScalar d[3]) { |
+ SkScalar a1 = calc_dot_cross_cubic(p[0], p[3], p[2]); |
+ SkScalar a2 = calc_dot_cross_cubic(p[1], p[0], p[3]); |
+ SkScalar a3 = calc_dot_cross_cubic(p[2], p[1], p[0]); |
+ |
+ // need to scale a's or values in later calculations will grow to high |
+ SkScalar max = SkScalarAbs(a1); |
+ max = SkMaxScalar(max, SkScalarAbs(a2)); |
+ max = SkMaxScalar(max, SkScalarAbs(a3)); |
+ max = 1.f/max; |
+ a1 = a1 * max; |
+ a2 = a2 * max; |
+ a3 = a3 * max; |
+ |
+ d[2] = 3.f * a3; |
+ d[1] = d[2] - a2; |
+ d[0] = d[1] - a2 + a1; |
+} |
+ |
+SkCubicType SkClassifyCubic(const SkPoint src[4], SkScalar d[3]) { |
+ calc_cubic_inflection_func(src, d); |
+ return classify_cubic(src, d); |
+} |
+ |
template <typename T> void bubble_sort(T array[], int count) { |
for (int i = count - 1; i > 0; --i) |
for (int j = i; j > 0; --j) |