Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
mandoline.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "gm/gm.h"
12#include "include/core/SkPath.h"
15#include "include/core/SkSize.h"
18#include "src/base/SkRandom.h"
19#include "src/core/SkGeometry.h"
20
21#include <math.h>
22
23namespace skiagm {
24
25// Slices paths into sliver-size contours shaped like ice cream cones.
27public:
28 inline static constexpr int kDefaultSubdivisions = 10;
29
32 fPath.setIsVolatile(true);
33 this->reset(anchorPt);
34 }
35
36 void reset(SkPoint anchorPt) {
37 fPath.reset();
38 fLastPt = fAnchorPt = anchorPt;
39 }
40
41 void sliceLine(SkPoint pt, int numSubdivisions = kDefaultSubdivisions) {
42 if (numSubdivisions <= 0) {
43 fPath.moveTo(fAnchorPt);
44 fPath.lineTo(fLastPt);
45 fPath.lineTo(pt);
46 fPath.close();
47 fLastPt = pt;
48 return;
49 }
50 float T = this->chooseChopT(numSubdivisions);
51 if (0 == T) {
52 return;
53 }
54 SkPoint midpt = fLastPt * (1 - T) + pt * T;
55 this->sliceLine(midpt, numSubdivisions - 1);
56 this->sliceLine(pt, numSubdivisions - 1);
57 }
58
59 void sliceQuadratic(SkPoint p1, SkPoint p2, int numSubdivisions = kDefaultSubdivisions) {
60 if (numSubdivisions <= 0) {
61 fPath.moveTo(fAnchorPt);
62 fPath.lineTo(fLastPt);
63 fPath.quadTo(p1, p2);
64 fPath.close();
65 fLastPt = p2;
66 return;
67 }
68 float T = this->chooseChopT(numSubdivisions);
69 if (0 == T) {
70 return;
71 }
72 SkPoint P[3] = {fLastPt, p1, p2}, PP[5];
73 SkChopQuadAt(P, PP, T);
74 this->sliceQuadratic(PP[1], PP[2], numSubdivisions - 1);
75 this->sliceQuadratic(PP[3], PP[4], numSubdivisions - 1);
76 }
77
79 int numSubdivisions = kDefaultSubdivisions) {
80 if (numSubdivisions <= 0) {
81 fPath.moveTo(fAnchorPt);
82 fPath.lineTo(fLastPt);
83 fPath.cubicTo(p1, p2, p3);
84 fPath.close();
85 fLastPt = p3;
86 return;
87 }
88 float T = this->chooseChopT(numSubdivisions);
89 if (0 == T) {
90 return;
91 }
92 SkPoint P[4] = {fLastPt, p1, p2, p3}, PP[7];
93 SkChopCubicAt(P, PP, T);
94 this->sliceCubic(PP[1], PP[2], PP[3], numSubdivisions - 1);
95 this->sliceCubic(PP[4], PP[5], PP[6], numSubdivisions - 1);
96 }
97
98 void sliceConic(SkPoint p1, SkPoint p2, float w, int numSubdivisions = kDefaultSubdivisions) {
99 if (numSubdivisions <= 0) {
100 fPath.moveTo(fAnchorPt);
101 fPath.lineTo(fLastPt);
102 fPath.conicTo(p1, p2, w);
103 fPath.close();
104 fLastPt = p2;
105 return;
106 }
107 float T = this->chooseChopT(numSubdivisions);
108 if (0 == T) {
109 return;
110 }
111 SkConic conic(fLastPt, p1, p2, w), halves[2];
112 if (!conic.chopAt(T, halves)) {
113 SK_ABORT("SkConic::chopAt failed");
114 }
115 this->sliceConic(halves[0].fPts[1], halves[0].fPts[2], halves[0].fW, numSubdivisions - 1);
116 this->sliceConic(halves[1].fPts[1], halves[1].fPts[2], halves[1].fW, numSubdivisions - 1);
117 }
118
119 const SkPath& path() const { return fPath; }
120
121private:
122 float chooseChopT(int numSubdivisions) {
123 SkASSERT(numSubdivisions > 0);
124 if (numSubdivisions > 1) {
125 return .5f;
126 }
127 float T = (0 == fRand.nextU() % 10) ? 0 : scalbnf(1, -(int)fRand.nextRangeU(10, 149));
128 SkASSERT(T >= 0 && T < 1);
129 return T;
130 }
131
132 SkRandom fRand;
133 SkPath fPath;
134 SkPoint fAnchorPt;
135 SkPoint fLastPt;
136};
137
138class SliverPathsGM : public GM {
139public:
143
144protected:
145 SkString getName() const override { return SkString("mandoline"); }
146
147 SkISize getISize() override { return SkISize::Make(560, 475); }
148
149 void onDraw(SkCanvas* canvas) override {
151 paint.setColor(SK_ColorWHITE);
152 paint.setAntiAlias(true);
153
154 MandolineSlicer mandoline({41, 43});
155 mandoline.sliceCubic({5, 277}, {381, -74}, {243, 162});
156 mandoline.sliceLine({41, 43});
157 canvas->drawPath(mandoline.path(), paint);
158
159 mandoline.reset({357.049988f, 446.049988f});
160 mandoline.sliceCubic({472.750000f, -71.950012f}, {639.750000f, 531.950012f},
161 {309.049988f, 347.950012f});
162 mandoline.sliceLine({309.049988f, 419});
163 mandoline.sliceLine({357.049988f, 446.049988f});
164 canvas->drawPath(mandoline.path(), paint);
165
166 canvas->save();
167 canvas->translate(421, 105);
168 canvas->scale(100, 81);
169 mandoline.reset({-cosf(SkDegreesToRadians(-60)), sinf(SkDegreesToRadians(-60))});
170 mandoline.sliceConic({-2, 0},
171 {-cosf(SkDegreesToRadians(60)), sinf(SkDegreesToRadians(60))}, .5f);
172 mandoline.sliceConic({-cosf(SkDegreesToRadians(120))*2, sinf(SkDegreesToRadians(120))*2},
173 {1, 0}, .5f);
174 mandoline.sliceLine({0, 0});
175 mandoline.sliceLine({-cosf(SkDegreesToRadians(-60)), sinf(SkDegreesToRadians(-60))});
176 canvas->drawPath(mandoline.path(), paint);
177 canvas->restore();
178
179 canvas->save();
180 canvas->translate(150, 300);
181 canvas->scale(75, 75);
182 mandoline.reset({1, 0});
183 constexpr int nquads = 5;
184 for (int i = 0; i < nquads; ++i) {
185 float theta1 = 2*SK_ScalarPI/nquads * (i + .5f);
186 float theta2 = 2*SK_ScalarPI/nquads * (i + 1);
187 mandoline.sliceQuadratic({cosf(theta1)*2, sinf(theta1)*2},
188 {cosf(theta2), sinf(theta2)});
189 }
190 canvas->drawPath(mandoline.path(), paint);
191 canvas->restore();
192 }
193};
194
195DEF_GM(return new SliverPathsGM;)
196
197} // namespace skiagm
SkPoint fPts[2]
m reset()
#define SK_ABORT(message,...)
Definition SkAssert.h:70
#define SkASSERT(cond)
Definition SkAssert.h:116
constexpr SkColor SK_ColorBLACK
Definition SkColor.h:103
constexpr SkColor SK_ColorWHITE
Definition SkColor.h:122
void SkChopQuadAt(const SkPoint src[3], SkPoint dst[5], SkScalar t)
void SkChopCubicAt(const SkPoint src[4], SkPoint dst[7], SkScalar t)
#define SkDegreesToRadians(degrees)
Definition SkScalar.h:77
#define SK_ScalarPI
Definition SkScalar.h:21
Type::kYUV Type::kRGBA() int(0.7 *637)
void restore()
Definition SkCanvas.cpp:465
void translate(SkScalar dx, SkScalar dy)
int save()
Definition SkCanvas.cpp:451
void drawPath(const SkPath &path, const SkPaint &paint)
void scale(SkScalar sx, SkScalar sy)
SkPath & moveTo(SkScalar x, SkScalar y)
Definition SkPath.cpp:678
void setFillType(SkPathFillType ft)
Definition SkPath.h:235
SkPath & lineTo(SkScalar x, SkScalar y)
Definition SkPath.cpp:718
SkPath & setIsVolatile(bool isVolatile)
Definition SkPath.h:370
SkPath & reset()
Definition SkPath.cpp:360
SkPath & quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
Definition SkPath.cpp:736
SkPath & cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3)
Definition SkPath.cpp:789
SkPath & conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w)
Definition SkPath.cpp:756
SkPath & close()
Definition SkPath.cpp:813
uint32_t nextU()
Definition SkRandom.h:42
void setBGColor(SkColor)
Definition gm.cpp:159
const SkPath & path() const
static constexpr int kDefaultSubdivisions
Definition mandoline.cpp:28
void sliceQuadratic(SkPoint p1, SkPoint p2, int numSubdivisions=kDefaultSubdivisions)
Definition mandoline.cpp:59
void reset(SkPoint anchorPt)
Definition mandoline.cpp:36
MandolineSlicer(SkPoint anchorPt)
Definition mandoline.cpp:30
void sliceConic(SkPoint p1, SkPoint p2, float w, int numSubdivisions=kDefaultSubdivisions)
Definition mandoline.cpp:98
void sliceCubic(SkPoint p1, SkPoint p2, SkPoint p3, int numSubdivisions=kDefaultSubdivisions)
Definition mandoline.cpp:78
void sliceLine(SkPoint pt, int numSubdivisions=kDefaultSubdivisions)
Definition mandoline.cpp:41
void onDraw(SkCanvas *canvas) override
SkString getName() const override
SkISize getISize() override
const Paint & paint
#define DEF_GM(CODE)
Definition gm.h:40
SkScalar w
#define T
static constexpr SkISize Make(int32_t w, int32_t h)
Definition SkSize.h:20