add computation for error in conic-as-quad
authormike@reedtribe.org <mike@reedtribe.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Sat, 27 Apr 2013 18:23:16 +0000 (18:23 +0000)
committermike@reedtribe.org <mike@reedtribe.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Sat, 27 Apr 2013 18:23:16 +0000 (18:23 +0000)
git-svn-id: http://skia.googlecode.com/svn/trunk@8887 2bbb7eff-a529-9590-31e7-b0007b416f81

include/core/SkGeometry.h
src/core/SkGeometry.cpp

index d540d34..97997c4 100644 (file)
@@ -220,6 +220,14 @@ struct SkConic {
     void chopAt(SkScalar t, SkConic dst[2]) const;
     void chop(SkConic dst[2]) const;
 
+    /**
+     *  Return the max difference between the conic and its framing quadratic
+     *  in err and return true. If the conic is degenerate (a line between
+     *  pts[0] and pts[2]) or has a negative weight, return false and ignore
+     *  the diff parameter.
+     */
+    bool computeErrorAsQuad(SkVector* err) const;
+
     int computeQuadPOW2(SkScalar tol) const;
     int chopIntoQuadsPOW2(SkPoint pts[], int pow2) const;
 
index 6b525fa..6be6218 100644 (file)
@@ -1543,21 +1543,32 @@ void SkConic::chop(SkConic dst[2]) const {
     dst[0].fW = dst[1].fW = subdivide_w_value(fW);
 }
 
-int SkConic::computeQuadPOW2(SkScalar tol) const {
-    if (fW <= SK_ScalarNearlyZero) {
-        return 0;   // treat as a line
+/*
+ *  "High order approximation of conic sections by quadratic splines"
+ *      by Michael Floater, 1993
+ */
+bool SkConic::computeErrorAsQuad(SkVector* err) const {
+    if (fW <= 0) {
+        return false;
     }
+    SkScalar a = fW - 1;
+    SkScalar k = a / (4 * (2 + a));
+    err->set(k * (fPts[0].fX - 2 * fPts[1].fX + fPts[2].fX),
+             k * (fPts[0].fY - 2 * fPts[1].fY + fPts[2].fY));
+    return true;
+}
 
-    tol = SkScalarAbs(tol);
-    SkScalar w = fW;
-    int i = 0;
-    for (; i < 8; ++i) {
-        if (SkScalarAbs(w - 1) <= tol) {
-            break;
-        }
-        w = subdivide_w_value(w);
+int SkConic::computeQuadPOW2(SkScalar tol) const {
+    SkVector diff;
+    if (!this->computeErrorAsQuad(&diff)) {
+        return 0;
     }
-    return i;
+
+    // the error reduces by 4 with each subdivision, so return the subdivision
+    // count needed.
+    SkScalar error = diff.length() - SkScalarAbs(tol);
+    uint32_t ierr = (uint32_t)error;
+    return (33 - SkCLZ(ierr)) >> 1;
 }
 
 static SkPoint* subdivide(const SkConic& src, SkPoint pts[], int level) {
@@ -1655,12 +1666,3 @@ void SkConic::computeFastBounds(SkRect* bounds) const {
     bounds->set(fPts, 3);
 }
 
-/*
- *  "High order approximation of conic sections by quadratic splines"
- *      by Michael Floater, 1993
- *
- *  Max error between conic and simple quad is bounded by this equation
- *
- *  a <-- w - 1 (where w >= 0)
- *  diff <-- a * (p0 - 2p1 + p2) / (4*(2 + a))
- */