add routines to compute error between conic and quad
authormike@reedtribe.org <mike@reedtribe.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 30 Apr 2013 02:14:58 +0000 (02:14 +0000)
committermike@reedtribe.org <mike@reedtribe.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 30 Apr 2013 02:14:58 +0000 (02:14 +0000)
git-svn-id: http://skia.googlecode.com/svn/trunk@8916 2bbb7eff-a529-9590-31e7-b0007b416f81

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

index dc95ea6..6ef78cc 100644 (file)
@@ -15,7 +15,6 @@
 #include "SkString.h"
 #include "SkTArray.h"
 
-
 enum Flags {
     kStroke_Flag = 1 << 0,
     kBig_Flag    = 1 << 1
@@ -908,22 +907,120 @@ public:
         fRQ.fPts[2].set(100, 100);
         fRQ.fW = SkScalarCos(SK_ScalarPI/4);
     }
-
+    
 private:
     virtual const char* onGetName() SK_OVERRIDE {
         return "ratquad-chop-half";
     }
-
+    
     virtual void onDraw(SkCanvas*) SK_OVERRIDE {
         SkConic dst[2];
         for (int i = 0; i < N; ++i) {
             fRQ.chop(dst);
         }
     }
+    
+    typedef SkBenchmark INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
 
+static void rand_conic(SkConic* conic, SkRandom& rand) {
+    for (int i = 0; i < 3; ++i) {
+        conic->fPts[i].set(rand.nextUScalar1() * 100, rand.nextUScalar1() * 100);
+    }
+    if (rand.nextUScalar1() > 0.5f) {
+        conic->fW = rand.nextUScalar1();
+    } else {
+        conic->fW = 1 + rand.nextUScalar1() * 4;
+    }
+}
+
+class ConicBench : public SkBenchmark {
+public:
+    ConicBench(void* param) : INHERITED(param) {
+        SkRandom rand;
+        for (int i = 0; i < CONICS; ++i) {
+            rand_conic(&fConics[i], rand);
+        }
+        fIsRendering = false;
+    }
+    
+protected:
+    enum {
+        N = 20000,
+        CONICS = 100
+    };
+    SkConic fConics[CONICS];
+    
+private:
     typedef SkBenchmark INHERITED;
 };
 
+class ConicBench_ComputeError : public ConicBench {
+public:
+    ConicBench_ComputeError(void* param) : INHERITED(param) {}
+    
+protected:
+    virtual const char* onGetName() SK_OVERRIDE {
+        return "conic-compute-error";
+    }
+    
+    virtual void onDraw(SkCanvas*) SK_OVERRIDE {
+        SkVector err;
+        for (int i = 0; i < N; ++i) {
+            for (int j = 0; j < CONICS; ++j) {
+                fConics[j].computeAsQuadError(&err);
+            }
+        }
+    }
+    
+private:
+    typedef ConicBench INHERITED;
+};
+
+class ConicBench_asQuadTol : public ConicBench {
+public:
+    ConicBench_asQuadTol(void* param) : INHERITED(param) {}
+    
+protected:
+    virtual const char* onGetName() SK_OVERRIDE {
+        return "conic-asQuadTol";
+    }
+    
+    virtual void onDraw(SkCanvas*) SK_OVERRIDE {
+        for (int i = 0; i < N; ++i) {
+            for (int j = 0; j < CONICS; ++j) {
+                fConics[j].asQuadTol(SK_ScalarHalf);
+            }
+        }
+    }
+    
+private:
+    typedef ConicBench INHERITED;
+};
+
+class ConicBench_quadPow2 : public ConicBench {
+public:
+    ConicBench_quadPow2(void* param) : INHERITED(param) {}
+
+protected:
+    virtual const char* onGetName() SK_OVERRIDE {
+        return "conic-quadPow2";
+    }
+    
+    virtual void onDraw(SkCanvas*) SK_OVERRIDE {
+        for (int i = 0; i < N; ++i) {
+            for (int j = 0; j < CONICS; ++j) {
+                fConics[j].computeQuadPOW2(SK_ScalarHalf);
+            }
+        }
+    }
+    
+private:
+    typedef ConicBench INHERITED;
+};
+
 ///////////////////////////////////////////////////////////////////////////////
 
 const SkRect ConservativelyContainsBench::kBounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
@@ -983,3 +1080,7 @@ DEF_BENCH( return new ConservativelyContainsBench(p, ConservativelyContainsBench
 
 DEF_BENCH( return new ConicBench_Chop5(p) )
 DEF_BENCH( return new ConicBench_ChopHalf(p) )
+DEF_BENCH( return new ConicBench_ComputeError(p) )
+DEF_BENCH( return new ConicBench_asQuadTol(p) )
+DEF_BENCH( return new ConicBench_quadPow2(p) )
+
index 97997c4..1251fcf 100644 (file)
@@ -220,13 +220,8 @@ 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;
+    void computeAsQuadError(SkVector* err) const;
+    bool asQuadTol(SkScalar tol) const;
 
     int computeQuadPOW2(SkScalar tol) const;
     int chopIntoQuadsPOW2(SkPoint pts[], int pow2) const;
index dcdbf9c..b6b23bc 100644 (file)
@@ -1547,32 +1547,36 @@ void SkConic::chop(SkConic dst[2]) const {
  *  "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;
+#define AS_QUAD_ERROR_SETUP                                         \
+    SkScalar a = fW - 1;                                            \
+    SkScalar k = a / (4 * (2 + a));                                 \
+    SkScalar x = k * (fPts[0].fX - 2 * fPts[1].fX + fPts[2].fX);    \
+    SkScalar y = k * (fPts[0].fY - 2 * fPts[1].fY + fPts[2].fY);
+
+void SkConic::computeAsQuadError(SkVector* err) const {
+    AS_QUAD_ERROR_SETUP
+    err->set(x, y);
+}
+
+bool SkConic::asQuadTol(SkScalar tol) const {
+    AS_QUAD_ERROR_SETUP
+    return (x * x + y * y) <= tol * tol;
 }
 
 int SkConic::computeQuadPOW2(SkScalar tol) const {
-    SkVector diff;
-    if (!this->computeErrorAsQuad(&diff)) {
+    AS_QUAD_ERROR_SETUP
+    SkScalar error = SkScalarSqrt(x * x + y * y) - tol;
+
+    if (error <= 0) {
         return 0;
     }
-
-    // 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;
+    return (34 - SkCLZ(ierr)) >> 1;
 }
 
 static SkPoint* subdivide(const SkConic& src, SkPoint pts[], int level) {
     SkASSERT(level >= 0);
+
     if (0 == level) {
         memcpy(pts, &src.fPts[1], 2 * sizeof(SkPoint));
         return pts + 2;
@@ -1586,22 +1590,7 @@ static SkPoint* subdivide(const SkConic& src, SkPoint pts[], int level) {
 }
 
 int SkConic::chopIntoQuadsPOW2(SkPoint pts[], int pow2) const {
-    if (pow2 < 0) {
-        return 0;
-    }
-    if (0 == pow2) {
-        memcpy(pts, fPts, 3 * sizeof(SkPoint));
-        return 1;
-    }
-    if (1 == pow2) {
-        SkConic dst[2];
-        this->chop(dst);
-        memcpy(pts, dst[0].fPts, 3 * sizeof(SkPoint));
-        pts += 3;
-        memcpy(pts, dst[1].fPts + 1, 2 * sizeof(SkPoint));
-        return 2;
-    }
-
+    SkASSERT(pow2 >= 0);
     *pts = fPts[0];
     SkDEBUGCODE(SkPoint* endPts =) subdivide(*this, pts + 1, pow2);
     SkASSERT(endPts - pts == (2 * (1 << pow2) + 1));