show cubic error-vectors anchored on pt(s) of max deviation

Bug: skia:
Change-Id: I59a6a218ddbf46bc5d7ebea6303701b5182eafa7
Reviewed-on: https://skia-review.googlesource.com/121427
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Mike Reed <reed@google.com>
diff --git a/samplecode/SamplePath.cpp b/samplecode/SamplePath.cpp
index f523fe6..61098d2 100644
--- a/samplecode/SamplePath.cpp
+++ b/samplecode/SamplePath.cpp
@@ -581,6 +581,21 @@
     return a * (1 - t) + b * t;
 }
 
+static int find_max_deviation_cubic(const SkPoint src[4], SkScalar ts[2]) {
+    // deviation = F' x (d - a) == 0, solve for t(s)
+    // F = At^3 + Bt^2 + Ct + D
+    // F' = 3At^2 + 2Bt + C
+    // Z = d - a
+    // F' x Z = 3(A x Z)t^2 + 2(B x Z)t + (C x Z)
+    //
+    SkVector A = src[3] + (src[1] - src[2]) * 3 - src[0];
+    SkVector B = (src[2] - src[1] - src[1] + src[0]) * 3;
+    SkVector C = (src[1] - src[0]) * 3;
+    SkVector Z = src[3] - src[0];
+    // now forumlate the quadratic coefficients we need to solve for t : F' x Z
+    return SkFindUnitQuadRoots(3 * A.cross(Z), 2 * B.cross(Z), C.cross(Z), ts);
+}
+
 class CubicCurve2 : public SampleView {
 public:
     enum {
@@ -591,6 +606,7 @@
     SkScalar fT = 0.5f;
     bool fShowSub = false;
     bool fShowFlatness = false;
+    SkScalar fScale = 0.75;
 
     CubicCurve2() {
         fPts[0] = { 90, 300 };
@@ -663,12 +679,23 @@
         pts[1] = (fQuad[0] + fQuad[2]) * 0.5;
         canvas->drawLine(pts[0], pts[1], paint);
 
-        SkVector v = fPts[0] - fPts[1] - fPts[1] + fPts[2];
-        v = v * 0.75;
-        canvas->drawLine(fPts[1], fPts[1] + v, paint);
-        v = fPts[1] - fPts[2] - fPts[2] + fPts[3];
-        v = v * 0.75;
-        canvas->drawLine(fPts[2], fPts[2] + v, paint);
+        // cubic
+
+        SkVector v0 = (fPts[0] - fPts[1] - fPts[1] + fPts[2]) * fScale;
+        SkVector v1 = (fPts[1] - fPts[2] - fPts[2] + fPts[3]) * fScale;
+
+        SkPoint anchor;
+        SkScalar ts[2];
+        int n = find_max_deviation_cubic(fPts, ts);
+        if (n > 0) {
+            SkEvalCubicAt(fPts, ts[0], &anchor, nullptr, nullptr);
+            canvas->drawLine(anchor, anchor + v0, paint);
+            if (n == 2) {
+                SkEvalCubicAt(fPts, ts[1], &anchor, nullptr, nullptr);
+            }
+            canvas->drawLine(anchor, anchor + v1, paint);
+        }
+        // not sure we can get here
     }
 
     void onDrawContent(SkCanvas* canvas) override {