1cb93a386Sopenharmony_ci// Copyright 2020 Google LLC. 2cb93a386Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. 3cb93a386Sopenharmony_ci#include "tools/fiddle/examples.h" 4cb93a386Sopenharmony_ciREG_FIDDLE(SmoothBezierSplineInterpolation, 1024, 1024, false, 0) { 5cb93a386Sopenharmony_ci// Smooth Bézier Spline Interpolation 6cb93a386Sopenharmony_ci 7cb93a386Sopenharmony_ciSkPath MakeCubicSplineInterpolation(const SkPoint* pts, size_t N) { 8cb93a386Sopenharmony_ci // Code borrowed from https://www.particleincell.com/2012/bezier-splines/ 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci SkPath path; 11cb93a386Sopenharmony_ci if (N < 2) { 12cb93a386Sopenharmony_ci return path; 13cb93a386Sopenharmony_ci } 14cb93a386Sopenharmony_ci if (N == 2) { 15cb93a386Sopenharmony_ci path.moveTo(pts[0]); 16cb93a386Sopenharmony_ci path.lineTo(pts[1]); 17cb93a386Sopenharmony_ci return path; 18cb93a386Sopenharmony_ci } 19cb93a386Sopenharmony_ci size_t n = N - 1; // number of segments 20cb93a386Sopenharmony_ci struct Scratch { 21cb93a386Sopenharmony_ci SkPoint a, b, c, r, p; 22cb93a386Sopenharmony_ci }; 23cb93a386Sopenharmony_ci // Can I do this will less allocation? 24cb93a386Sopenharmony_ci std::unique_ptr<Scratch[]> s(new Scratch[n]); 25cb93a386Sopenharmony_ci s[0].a = {0, 0}; 26cb93a386Sopenharmony_ci s[0].b = {2, 2}; 27cb93a386Sopenharmony_ci s[0].c = {1, 1}; 28cb93a386Sopenharmony_ci s[0].r = {pts[0].x() + 2 * pts[1].x(), pts[0].y() + 2 * pts[1].y()}; 29cb93a386Sopenharmony_ci for (size_t i = 1; i < n - 1; ++i) { 30cb93a386Sopenharmony_ci s[i].a = {1, 1}; 31cb93a386Sopenharmony_ci s[i].b = {4, 4}; 32cb93a386Sopenharmony_ci s[i].c = {1, 1}; 33cb93a386Sopenharmony_ci s[i].r = {4 * pts[i].x() + 2 * pts[i + 1].x(), 4 * pts[i].y() + 2 * pts[i + 1].y()}; 34cb93a386Sopenharmony_ci } 35cb93a386Sopenharmony_ci s[n - 1].a = {2, 2}; 36cb93a386Sopenharmony_ci s[n - 1].b = {7, 7}; 37cb93a386Sopenharmony_ci s[n - 1].c = {0, 0}; 38cb93a386Sopenharmony_ci s[n - 1].r = {8 * pts[n - 1].x() + pts[N - 1].x(), 8 * pts[n - 1].y() + pts[N - 1].y()}; 39cb93a386Sopenharmony_ci for (size_t i = 1; i < n; i++) { 40cb93a386Sopenharmony_ci float mx = s[i].a.x() / s[i - 1].b.x(); 41cb93a386Sopenharmony_ci float my = s[i].a.y() / s[i - 1].b.y(); 42cb93a386Sopenharmony_ci s[i].b -= {mx * s[i - 1].c.x(), my * s[i - 1].c.y()}; 43cb93a386Sopenharmony_ci s[i].r -= {mx * s[i - 1].r.x(), my * s[i - 1].r.y()}; 44cb93a386Sopenharmony_ci } 45cb93a386Sopenharmony_ci s[n - 1].p = {s[n - 1].r.x() / s[n - 1].b.x(), s[n - 1].r.y() / s[n - 1].b.y()}; 46cb93a386Sopenharmony_ci for (int i = (int)N - 3; i >= 0; --i) { 47cb93a386Sopenharmony_ci s[i].p = {(s[i].r.x() - s[i].c.x() * s[i + 1].p.fX) / s[i].b.x(), 48cb93a386Sopenharmony_ci (s[i].r.y() - s[i].c.y() * s[i + 1].p.fY) / s[i].b.y()}; 49cb93a386Sopenharmony_ci } 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ci path.moveTo(pts[0]); 52cb93a386Sopenharmony_ci for (size_t i = 0; i < n - 1; i++) { 53cb93a386Sopenharmony_ci SkPoint q = {2 * pts[i + 1].x() - s[i + 1].p.fX, 2 * pts[i + 1].y() - s[i + 1].p.fY}; 54cb93a386Sopenharmony_ci path.cubicTo(s[i].p, q, pts[i + 1]); 55cb93a386Sopenharmony_ci } 56cb93a386Sopenharmony_ci SkPoint q = {0.5f * (pts[N - 1].x() + s[n - 1].p.x()), 57cb93a386Sopenharmony_ci 0.5f * (pts[N - 1].y() + s[n - 1].p.y())}; 58cb93a386Sopenharmony_ci path.cubicTo(s[n - 1].p, q, pts[n]); 59cb93a386Sopenharmony_ci return path; 60cb93a386Sopenharmony_ci} 61cb93a386Sopenharmony_ci 62cb93a386Sopenharmony_civoid draw(SkCanvas* canvas) { 63cb93a386Sopenharmony_ci SkPaint p; 64cb93a386Sopenharmony_ci p.setColor(SK_ColorRED); 65cb93a386Sopenharmony_ci p.setAntiAlias(true); 66cb93a386Sopenharmony_ci p.setStyle(SkPaint::kStroke_Style); 67cb93a386Sopenharmony_ci p.setStrokeWidth(3); 68cb93a386Sopenharmony_ci p.setStrokeCap(SkPaint::kRound_Cap); 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_ci // randomly generated y values in range [12,1024]. 71cb93a386Sopenharmony_ci SkPoint pts[] = { 72cb93a386Sopenharmony_ci {62, 511}, {162, 605}, {262, 610}, {362, 402}, {462, 959}, 73cb93a386Sopenharmony_ci {562, 58}, {662, 272}, {762, 99}, {862, 759}, {962, 945}, 74cb93a386Sopenharmony_ci }; 75cb93a386Sopenharmony_ci 76cb93a386Sopenharmony_ci canvas->drawPath(MakeCubicSplineInterpolation(pts, SK_ARRAY_COUNT(pts)), p); 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_ci p.setStrokeWidth(10); 79cb93a386Sopenharmony_ci p.setColor(SK_ColorBLACK); 80cb93a386Sopenharmony_ci canvas->drawPoints(SkCanvas::kPoints_PointMode, SK_ARRAY_COUNT(pts), pts, p); 81cb93a386Sopenharmony_ci} 82cb93a386Sopenharmony_ci} // END FIDDLE 83