diff options
author | Chris Dalton <csmartdalton@google.com> | 2017-07-14 14:04:52 -0600 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-07-14 20:34:34 +0000 |
commit | 91982ee8d92a80193915d59760e2ba9ce6f46989 (patch) | |
tree | bd1831431ae7a862f6349313f785be4a0e78ed63 /src/core/SkGeometry.cpp | |
parent | 1e0779ba1120182c03f5d52a66df043d70efc376 (diff) |
Fix SkClassifyCubic for near-quadratics
Fixes the threshold logic for "0 ~= d1 && 0 ~= d2".
Previously, if d1 and d2 were both near zero, but on opposite sides
of the threshold, the curve could be misclassified as kCuspAtInfinity
and drawn incorrectly.
Bug: skia:
Change-Id: I65f30ddebf0a4a0b933610d8cc1a2f489efc99e4
Reviewed-on: https://skia-review.googlesource.com/22400
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Cary Clark <caryclark@google.com>
Diffstat (limited to 'src/core/SkGeometry.cpp')
-rw-r--r-- | src/core/SkGeometry.cpp | 107 |
1 files changed, 54 insertions, 53 deletions
diff --git a/src/core/SkGeometry.cpp b/src/core/SkGeometry.cpp index 46fd683512..a1e8419a41 100644 --- a/src/core/SkGeometry.cpp +++ b/src/core/SkGeometry.cpp @@ -601,62 +601,63 @@ static void sort_and_orient_t_s(double t[2], double s[2]) { // d1 = d2 = 0, d3 != 0 Quadratic // d1 = d2 = d3 = 0 Line or Point static SkCubicType classify_cubic(const double d[4], double t[2], double s[2]) { - double tolerance = SkTMax(fabs(d[1]), fabs(d[2])); - tolerance = SkTMax(tolerance, fabs(d[3])); - tolerance = tolerance * 1e-4; - if (fabs(d[1]) > tolerance) { - const double discr = 3 * d[2] * d[2] - 4 * d[1] * d[3]; - if (discr > 0) { - if (t && s) { - const double q = 3 * d[2] + copysign(sqrt(3 * discr), d[2]); - t[0] = q; - s[0] = 6 * d[1]; - t[1] = 2 * d[3]; - s[1] = q; - normalize_t_s(t, s, 2); - sort_and_orient_t_s(t, s); - } - return SkCubicType::kSerpentine; - } else if (discr < 0) { - if (t && s) { - const double q = d[2] + copysign(sqrt(-discr), d[2]); - t[0] = q; - s[0] = 2 * d[1]; - t[1] = 2 * (d[2] * d[2] - d[3] * d[1]); - s[1] = d[1] * q; - normalize_t_s(t, s, 2); - sort_and_orient_t_s(t, s); - } - return SkCubicType::kLoop; - } else { - SkASSERT(0 == discr); // Detect NaN. - if (t && s) { - t[0] = d[2]; - s[0] = 2 * d[1]; - normalize_t_s(t, s, 1); - t[1] = t[0]; - s[1] = s[0]; - sort_and_orient_t_s(t, s); - } - return SkCubicType::kLocalCusp; + // Check for degenerate cubics (quadratics, lines, and points). + // This also attempts to detect near-quadratics in a resolution independent fashion, however it + // is still up to the caller to check for almost-linear curves if needed. + if (fabs(d[1]) + fabs(d[2]) <= fabs(d[3]) * 1e-3) { + if (t && s) { + t[0] = t[1] = 1; + s[0] = s[1] = 0; // infinity + } + return 0 == d[3] ? SkCubicType::kLineOrPoint : SkCubicType::kQuadratic; + } + + if (0 == d[1]) { + SkASSERT(0 != d[2]); // captured in check for degeneracy above. + if (t && s) { + t[0] = d[3]; + s[0] = 3 * d[2]; + normalize_t_s(t, s, 1); + t[1] = 1; + s[1] = 0; // infinity } + return SkCubicType::kCuspAtInfinity; + } + + const double discr = 3 * d[2] * d[2] - 4 * d[1] * d[3]; + if (discr > 0) { + if (t && s) { + const double q = 3 * d[2] + copysign(sqrt(3 * discr), d[2]); + t[0] = q; + s[0] = 6 * d[1]; + t[1] = 2 * d[3]; + s[1] = q; + normalize_t_s(t, s, 2); + sort_and_orient_t_s(t, s); + } + return SkCubicType::kSerpentine; + } else if (discr < 0) { + if (t && s) { + const double q = d[2] + copysign(sqrt(-discr), d[2]); + t[0] = q; + s[0] = 2 * d[1]; + t[1] = 2 * (d[2] * d[2] - d[3] * d[1]); + s[1] = d[1] * q; + normalize_t_s(t, s, 2); + sort_and_orient_t_s(t, s); + } + return SkCubicType::kLoop; } else { - if (fabs(d[2]) > tolerance) { - if (t && s) { - t[0] = d[3]; - s[0] = 3 * d[2]; - normalize_t_s(t, s, 1); - t[1] = 1; - s[1] = 0; // infinity - } - return SkCubicType::kCuspAtInfinity; - } else { - if (t && s) { - t[0] = t[1] = 1; - s[0] = s[1] = 0; // infinity - } - return fabs(d[3]) > tolerance ? SkCubicType::kQuadratic : SkCubicType::kLineOrPoint; + SkASSERT(0 == discr); // Detect NaN. + if (t && s) { + t[0] = d[2]; + s[0] = 2 * d[1]; + normalize_t_s(t, s, 1); + t[1] = t[0]; + s[1] = s[0]; + sort_and_orient_t_s(t, s); } + return SkCubicType::kLocalCusp; } } |