addarc.cpp revision f7834221ac5342a3446b9b299398ea3ff7976946
1/*
2 * Copyright 2015 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.h"
9#include "SkAnimTimer.h"
10#include "SkCanvas.h"
11#include "SkPathMeasure.h"
12#include "SkRandom.h"
13
14class AddArcGM : public skiagm::GM {
15public:
16    AddArcGM() : fRotate(0) {}
17
18protected:
19    SkString onShortName() override { return SkString("addarc"); }
20
21    SkISize onISize() override { return SkISize::Make(1040, 1040); }
22
23    void onDraw(SkCanvas* canvas) override {
24        canvas->translate(20, 20);
25
26        SkRect r = SkRect::MakeWH(1000, 1000);
27
28        SkPaint paint;
29        paint.setAntiAlias(true);
30        paint.setStyle(SkPaint::kStroke_Style);
31        paint.setStrokeWidth(15);
32
33        const SkScalar inset = paint.getStrokeWidth() + 4;
34        const SkScalar sweepAngle = 345;
35        SkRandom rand;
36
37        SkScalar sign = 1;
38        while (r.width() > paint.getStrokeWidth() * 3) {
39            paint.setColor(rand.nextU() | (0xFF << 24));
40            SkScalar startAngle = rand.nextUScalar1() * 360;
41
42            SkScalar speed = SkScalarSqrt(16 / r.width()) * 0.5f;
43            startAngle += fRotate * 360 * speed * sign;
44
45            SkPath path;
46            path.addArc(r, startAngle, sweepAngle);
47            canvas->drawPath(path, paint);
48
49            r.inset(inset, inset);
50            sign = -sign;
51        }
52    }
53
54    bool onAnimate(const SkAnimTimer& timer) override {
55        fRotate = timer.scaled(1, 360);
56        return true;
57    }
58
59private:
60    SkScalar fRotate;
61    typedef skiagm::GM INHERITED;
62};
63DEF_GM( return new AddArcGM; )
64
65///////////////////////////////////////////////////
66
67#define R   400
68
69class AddArcMeasGM : public skiagm::GM {
70public:
71    AddArcMeasGM() {}
72
73protected:
74    SkString onShortName() override { return SkString("addarc_meas"); }
75
76    SkISize onISize() override { return SkISize::Make(2*R + 40, 2*R + 40); }
77
78    void onDraw(SkCanvas* canvas) override {
79        canvas->translate(R + 20, R + 20);
80
81        SkPaint paint;
82        paint.setAntiAlias(true);
83        paint.setStyle(SkPaint::kStroke_Style);
84
85        SkPaint measPaint;
86        measPaint.setAntiAlias(true);
87        measPaint.setColor(SK_ColorRED);
88
89        const SkRect oval = SkRect::MakeLTRB(-R, -R, R, R);
90        canvas->drawOval(oval, paint);
91
92        for (SkScalar deg = 0; deg < 360; deg += 10) {
93            const SkScalar rad = SkDegreesToRadians(deg);
94            SkScalar rx = SkScalarCos(rad) * R;
95            SkScalar ry = SkScalarSin(rad) * R;
96
97            canvas->drawLine(0, 0, rx, ry, paint);
98
99            SkPath path;
100            path.addArc(oval, 0, deg);
101            SkPathMeasure meas(path, false);
102            SkScalar arcLen = rad * R;
103            SkPoint pos;
104            if (meas.getPosTan(arcLen, &pos, NULL)) {
105                canvas->drawLine(0, 0, pos.x(), pos.y(), measPaint);
106            }
107        }
108    }
109
110private:
111    typedef skiagm::GM INHERITED;
112};
113DEF_GM( return new AddArcMeasGM; )
114
115///////////////////////////////////////////////////
116
117// Emphasize drawing a stroked oval (containing conics) and then scaling the results up,
118// to ensure that we compute the stroke taking the CTM into account
119//
120class StrokeCircleGM : public skiagm::GM {
121public:
122    StrokeCircleGM() : fRotate(0) {}
123
124protected:
125    SkString onShortName() override { return SkString("strokecircle"); }
126
127    SkISize onISize() override { return SkISize::Make(520, 520); }
128
129    void onDraw(SkCanvas* canvas) override {
130        canvas->scale(20, 20);
131        canvas->translate(13, 13);
132
133        SkPaint paint;
134        paint.setAntiAlias(true);
135        paint.setStyle(SkPaint::kStroke_Style);
136        paint.setStrokeWidth(SK_Scalar1 / 2);
137
138        const SkScalar delta = paint.getStrokeWidth() * 3 / 2;
139        SkRect r = SkRect::MakeXYWH(-12, -12, 24, 24);
140        SkRandom rand;
141
142        SkScalar sign = 1;
143        while (r.width() > paint.getStrokeWidth() * 2) {
144            SkAutoCanvasRestore acr(canvas, true);
145            canvas->rotate(fRotate * sign);
146
147            paint.setColor(rand.nextU() | (0xFF << 24));
148            canvas->drawOval(r, paint);
149            r.inset(delta, delta);
150            sign = -sign;
151        }
152    }
153
154    bool onAnimate(const SkAnimTimer& timer) override {
155        fRotate = timer.scaled(60, 360);
156        return true;
157    }
158
159private:
160    SkScalar fRotate;
161
162    typedef skiagm::GM INHERITED;
163};
164DEF_GM( return new StrokeCircleGM; )
165
166//////////////////////
167
168static void html_canvas_arc(SkPath* path, SkScalar x, SkScalar y, SkScalar r, SkScalar start,
169                            SkScalar end, bool ccw) {
170    SkRect bounds = { x - r, y - r, x + r, y + r };
171    SkScalar sweep = ccw ? end - start : start - end;
172    path->arcTo(bounds, start, sweep, false);
173}
174
175// Lifted from canvas-arc-circumference-fill-diffs.html
176class ManyArcsGM : public skiagm::GM {
177public:
178    ManyArcsGM() {}
179
180protected:
181    SkString onShortName() override { return SkString("manyarcs"); }
182
183    SkISize onISize() override { return SkISize::Make(620, 330); }
184
185    void onDraw(SkCanvas* canvas) override {
186        SkPaint paint;
187        paint.setAntiAlias(true);
188        paint.setStyle(SkPaint::kStroke_Style);
189
190        canvas->translate(10, 10);
191
192        // 20 angles.
193        SkScalar sweepAngles[] = {
194                           -123.7f, -2.3f, -2, -1, -0.3f, -0.000001f, 0, 0.000001f, 0.3f, 0.7f,
195                           1, 1.3f, 1.5f, 1.7f, 1.99999f, 2, 2.00001f, 2.3f, 4.3f, 3934723942837.3f
196        };
197        for (size_t i = 0; i < SK_ARRAY_COUNT(sweepAngles); ++i) {
198            sweepAngles[i] *= 180;
199        }
200
201        SkScalar startAngles[] = { -1, -0.5f, 0, 0.5f };
202        for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles); ++i) {
203            startAngles[i] *= 180;
204        }
205
206        bool anticlockwise = false;
207        SkScalar sign = 1;
208        for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles) * 2; ++i) {
209            if (i == SK_ARRAY_COUNT(startAngles)) {
210                anticlockwise = true;
211                sign = -1;
212            }
213            SkScalar startAngle = startAngles[i % SK_ARRAY_COUNT(startAngles)] * sign;
214            canvas->save();
215            for (size_t j = 0; j < SK_ARRAY_COUNT(sweepAngles); ++j) {
216                SkPath path;
217                path.moveTo(0, 2);
218                html_canvas_arc(&path, 18, 15, 10, startAngle, startAngle + (sweepAngles[j] * sign),
219                                anticlockwise);
220                path.lineTo(0, 28);
221                canvas->drawPath(path, paint);
222                canvas->translate(30, 0);
223            }
224            canvas->restore();
225            canvas->translate(0, 40);
226        }
227    }
228
229private:
230    typedef skiagm::GM INHERITED;
231};
232DEF_GM( return new ManyArcsGM; )
233
234