add SkEvalCubicInterval
authorreed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 3 Nov 2009 15:33:14 +0000 (15:33 +0000)
committerreed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 3 Nov 2009 15:33:14 +0000 (15:33 +0000)
git-svn-id: http://skia.googlecode.com/svn/trunk@416 2bbb7eff-a529-9590-31e7-b0007b416f81

include/utils/SkCubicInterval.h [new file with mode: 0644]
samplecode/SampleApp.cpp
samplecode/SampleUnitMapper.cpp [new file with mode: 0644]
src/utils/SkCubicInterval.cpp [new file with mode: 0644]

diff --git a/include/utils/SkCubicInterval.h b/include/utils/SkCubicInterval.h
new file mode 100644 (file)
index 0000000..bd6fc5f
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef SkCubicInterval_DEFINED
+#define SkCubicInterval_DEFINED
+
+#include "SkPoint.h"
+
+SkScalar SkEvalCubicInterval(SkScalar x1, SkScalar y1,
+                             SkScalar x2, SkScalar y2,
+                             SkScalar unitX);
+
+static inline SkScalar SkEvalCubicInterval(const SkPoint pts[2], SkScalar x) {
+    return SkEvalCubicInterval(pts[0].fX, pts[0].fY,
+                               pts[1].fX, pts[1].fY, x);
+}
+
+#endif
+
index 4000ed7e6c7f98abf9ee0f5a3759ef4f87922518..7ba069cca1a1deb62e46881e4245b57c68d1f6ff 100644 (file)
@@ -10,6 +10,8 @@
 
 #include "SampleCode.h"
 
+#define SHOW_OVERVIEW    false
+
 SkView* create_overview(int, const SkViewFactory*);
 
 //#define SK_SUPPORT_GL
@@ -229,7 +231,11 @@ SampleWindow::SampleWindow(void* hwnd) : INHERITED(hwnd) {
         }
     }
     fCurrIndex = 0;
-    this->loadView(NULL);
+    if (SHOW_OVERVIEW) {
+        this->loadView(NULL);
+    } else {
+        this->loadView(fSamples[fCurrIndex]());
+    }
 }
 
 SampleWindow::~SampleWindow() {
diff --git a/samplecode/SampleUnitMapper.cpp b/samplecode/SampleUnitMapper.cpp
new file mode 100644 (file)
index 0000000..cca233a
--- /dev/null
@@ -0,0 +1,119 @@
+#include "SampleCode.h"
+#include "SkView.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkPaint.h"
+#include "SkUnitMappers.h"
+#include "SkCubicInterval.h"
+
+class UnitMapperView : public SkView {
+    SkPoint fPts[4];
+    SkMatrix fMatrix;
+public:
+    UnitMapperView() {
+        fPts[0].set(0, 0);
+        fPts[1].set(SK_Scalar1 / 3, SK_Scalar1 / 3);
+        fPts[2].set(SK_Scalar1 * 2 / 3, SK_Scalar1 * 2 / 3);
+        fPts[3].set(SK_Scalar1, SK_Scalar1);
+
+        fMatrix.setScale(SK_Scalar1 * 200, -SK_Scalar1 * 200);
+        fMatrix.postTranslate(SkIntToScalar(100), SkIntToScalar(300));
+    }
+    
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "UnitMapper");
+            return true;
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+    
+    void drawBG(SkCanvas* canvas) {
+        canvas->drawColor(SK_ColorWHITE);
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) {
+        this->drawBG(canvas);
+
+        SkPaint paint;
+        paint.setAntiAlias(true);
+        paint.setColor(0xFF8888FF);
+
+        SkRect r = { 0, 0, SK_Scalar1, SK_Scalar1 };
+        
+        canvas->concat(fMatrix);
+        canvas->drawRect(r, paint);
+
+        paint.setColor(SK_ColorBLACK);
+        paint.setStyle(SkPaint::kStroke_Style);
+        paint.setStrokeWidth(0);
+        paint.setStrokeCap(SkPaint::kRound_Cap);
+        
+        SkPath path;
+        path.moveTo(fPts[0]);
+        path.cubicTo(fPts[1], fPts[2], fPts[3]);
+        canvas->drawPath(path, paint);
+
+        paint.setColor(SK_ColorRED);
+        paint.setStrokeWidth(0);
+        canvas->drawLine(0, 0, SK_Scalar1, SK_Scalar1, paint);
+
+        paint.setColor(SK_ColorBLUE);
+        paint.setStrokeWidth(SK_Scalar1 / 60);
+        for (int i = 0; i < 50; i++) {
+            SkScalar x = i * SK_Scalar1 / 49;
+            canvas->drawPoint(x, SkEvalCubicInterval(&fPts[1], x), paint);
+        }
+
+        paint.setStrokeWidth(SK_Scalar1 / 20);
+        paint.setColor(SK_ColorGREEN);
+        canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, &fPts[1], paint);
+    }
+
+    SkPoint invertPt(SkScalar x, SkScalar y) {
+        SkPoint pt;
+        SkMatrix m;
+        fMatrix.invert(&m);
+        m.mapXY(x, y, &pt);
+        return pt;
+    }
+
+    SkPoint* hittest(SkScalar x, SkScalar y) {
+        SkPoint target = { x, y };
+        SkPoint pts[2] = { fPts[1], fPts[2] };
+        fMatrix.mapPoints(pts, 2);
+        for (int i = 0; i < 2; i++) {
+            if (SkPoint::Distance(pts[i], target) < SkIntToScalar(4)) {
+                return &fPts[i + 1];
+            }
+        }
+        return NULL;
+    }
+
+    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
+        fDragPt = hittest(x, y);
+        return fDragPt ? new Click(this) : NULL;
+    }
+    
+    virtual bool onClick(Click* click) {
+        if (fDragPt) {
+            *fDragPt = invertPt(click->fCurr.fX, click->fCurr.fY);
+            this->inval(NULL);
+            return true;
+        }
+        return false;
+    }
+    
+private:
+    SkPoint* fDragPt;
+
+    typedef SkView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() { return new UnitMapperView; }
+static SkViewRegister reg(MyFactory);
+
diff --git a/src/utils/SkCubicInterval.cpp b/src/utils/SkCubicInterval.cpp
new file mode 100644 (file)
index 0000000..7a6084c
--- /dev/null
@@ -0,0 +1,61 @@
+#include "SkCubicInterval.h"
+
+static SkScalar eval_cubic(SkScalar c1, SkScalar c2, SkScalar c3,
+                           SkScalar t) {
+    return SkScalarMul(SkScalarMul(SkScalarMul(c3, t) + c2, t) + c1, t);
+}
+
+static SkScalar find_cubic_t(SkScalar c1, SkScalar c2, SkScalar c3,
+                             SkScalar targetX) {
+    SkScalar minT = 0;
+    SkScalar maxT = SK_Scalar1;
+    SkScalar t;
+
+    for (;;) {
+        t = SkScalarAve(minT, maxT);
+        SkScalar x = eval_cubic(c1, c2, c3, t);
+        if (SkScalarNearlyZero(x - targetX)) {
+            break;
+        }
+        // subdivide the range and try again
+        if (x < targetX) {
+            minT = t;
+        } else {
+            maxT = t;
+        }
+    }
+    return t;
+}
+
+/*
+    a(1-t)^3 + 3bt(1-t)^2 + 3ct^2(1-t) + dt^3
+    a: [0, 0]
+    d: [1, 1]
+
+    3bt - 6bt^2 + 3bt^3 + 3ct^2 - 3ct^3 + t^3
+    C1 = t^1: 3b
+    C2 = t^2: 3c - 6b
+    C3 = t^3: 3b - 3c + 1
+
+    ((C3*t + C2)*t + C1)*t
+ */
+SkScalar SkEvalCubicInterval(SkScalar x1, SkScalar y1,
+                             SkScalar x2, SkScalar y2,
+                             SkScalar unitX) {
+    x1 = SkScalarPin(x1, 0, SK_Scalar1);
+    x2 = SkScalarPin(x2, 0, SK_Scalar1);
+    unitX = SkScalarPin(unitX, 0, SK_Scalar1);
+
+    // First compute our coefficients in X
+    x1 *= 3;
+    x2 *= 3;
+
+    // now search for t given unitX
+    SkScalar t = find_cubic_t(x1, x2 - 2*x1, x1 - x2 + SK_Scalar1, unitX);
+    
+    // now evaluate the cubic in Y
+    y1 *= 3;
+    y2 *= 3;
+    return eval_cubic(y1, y2 - 2*y1, y1 - y2 + SK_Scalar1, t);
+}
+