blob: ad87d255ca315a8331589baaca9f1f1afc2249ae [file] [log] [blame]
senorblancod6ed19c2015-02-26 06:58:17 -08001/*
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 "SkCanvas.h"
bungemand3ebb482015-08-05 13:57:49 -070010#include "SkPath.h"
senorblancod6ed19c2015-02-26 06:58:17 -080011
12#define WIDTH 400
13#define HEIGHT 600
14
15namespace {
16// Concave test
17void test_concave(SkCanvas* canvas, const SkPaint& paint) {
18 SkPath path;
19 canvas->translate(0, 0);
20 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
21 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
22 path.lineTo(SkIntToScalar(30), SkIntToScalar(30));
23 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
24 canvas->drawPath(path, paint);
25}
26
27// Reverse concave test
28void test_reverse_concave(SkCanvas* canvas, const SkPaint& paint) {
29 SkPath path;
30 canvas->save();
31 canvas->translate(100, 0);
32 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
33 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
34 path.lineTo(SkIntToScalar(30), SkIntToScalar(30));
35 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
36 canvas->drawPath(path, paint);
37 canvas->restore();
38}
39
40// Bowtie (intersection)
41void test_bowtie(SkCanvas* canvas, const SkPaint& paint) {
42 SkPath path;
43 canvas->save();
44 canvas->translate(200, 0);
45 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
46 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
47 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
48 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
49 canvas->drawPath(path, paint);
50 canvas->restore();
51}
52
53// "fake" bowtie (concave, but no intersection)
54void test_fake_bowtie(SkCanvas* canvas, const SkPaint& paint) {
55 SkPath path;
56 canvas->save();
57 canvas->translate(300, 0);
58 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
59 path.lineTo(SkIntToScalar(50), SkIntToScalar(40));
60 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
61 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
62 path.lineTo(SkIntToScalar(50), SkIntToScalar(60));
63 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
64 canvas->drawPath(path, paint);
65 canvas->restore();
66}
67
68// Fish test (intersection/concave)
69void test_fish(SkCanvas* canvas, const SkPaint& paint) {
70 SkPath path;
71 canvas->save();
72 canvas->translate(0, 100);
73 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
74 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
75 path.lineTo(SkIntToScalar(70), SkIntToScalar(50));
76 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
77 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
78 path.lineTo(SkIntToScalar(0), SkIntToScalar(50));
79 canvas->drawPath(path, paint);
80 canvas->restore();
81}
82
83// Collinear edges
84void test_collinear_edges(SkCanvas* canvas, const SkPaint& paint) {
85 SkPath path;
86 canvas->save();
87 canvas->translate(100, 100);
88 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
89 path.lineTo(SkIntToScalar(50), SkIntToScalar(20));
90 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
91 path.lineTo(SkIntToScalar(50), SkIntToScalar(80));
92 canvas->drawPath(path, paint);
93 canvas->restore();
94}
95
96// Square polygon with a square hole.
97void test_hole(SkCanvas* canvas, const SkPaint& paint) {
98 SkPath path;
99 canvas->save();
100 canvas->translate(200, 100);
101 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
102 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
103 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
104 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
105 path.moveTo(SkIntToScalar(30), SkIntToScalar(30));
106 path.lineTo(SkIntToScalar(30), SkIntToScalar(70));
107 path.lineTo(SkIntToScalar(70), SkIntToScalar(70));
108 path.lineTo(SkIntToScalar(70), SkIntToScalar(30));
109 canvas->drawPath(path, paint);
110 canvas->restore();
111}
112
113// Star test (self-intersecting)
114void test_star(SkCanvas* canvas, const SkPaint& paint) {
115 SkPath path;
116 canvas->save();
117 canvas->translate(300, 100);
118 path.moveTo(30, 20);
119 path.lineTo(50, 80);
120 path.lineTo(70, 20);
121 path.lineTo(20, 57);
122 path.lineTo(80, 57);
123 path.close();
124 canvas->drawPath(path, paint);
125 canvas->restore();
126}
127
128// Stairstep with repeated vert (intersection)
129void test_stairstep(SkCanvas* canvas, const SkPaint& paint) {
130 SkPath path;
131 canvas->save();
132 canvas->translate(0, 200);
133 path.moveTo(SkIntToScalar(50), SkIntToScalar(50));
134 path.lineTo(SkIntToScalar(50), SkIntToScalar(20));
135 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
136 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
137 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
138 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
139 canvas->drawPath(path, paint);
140 canvas->restore();
141}
142
143void test_stairstep2(SkCanvas* canvas, const SkPaint& paint) {
144 SkPath path;
145 canvas->save();
146 canvas->translate(100, 200);
147 path.moveTo(20, 60);
148 path.lineTo(35, 80);
149 path.lineTo(50, 60);
150 path.lineTo(65, 80);
151 path.lineTo(80, 60);
152 canvas->drawPath(path, paint);
153 canvas->restore();
154}
155
156// Overlapping segments
157void test_overlapping(SkCanvas* canvas, const SkPaint& paint) {
158 SkPath path;
159 canvas->save();
160 canvas->translate(200, 200);
161 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
162 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
163 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
164 path.lineTo(SkIntToScalar(80), SkIntToScalar(30));
165 canvas->drawPath(path, paint);
166 canvas->restore();
167}
168
senorblanco531237e2016-06-02 11:36:48 -0700169// Two "island" triangles inside a containing rect.
170// This exercises the partnering code in the tessellator.
171void test_partners(SkCanvas* canvas, const SkPaint& paint) {
172 SkPath path;
173 canvas->save();
174 canvas->translate(300, 200);
175 path.moveTo(20, 80);
176 path.lineTo(80, 80);
177 path.lineTo(80, 20);
178 path.lineTo(20, 20);
179 path.moveTo(30, 30);
180 path.lineTo(45, 50);
181 path.lineTo(30, 70);
182 path.moveTo(70, 30);
183 path.lineTo(70, 70);
184 path.lineTo(55, 50);
185 canvas->drawPath(path, paint);
186 canvas->restore();
187}
188
senorblancod6ed19c2015-02-26 06:58:17 -0800189// Monotone test 1 (point in the middle)
190void test_monotone_1(SkCanvas* canvas, const SkPaint& paint) {
191 SkPath path;
192 canvas->save();
193 canvas->translate(0, 300);
194 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
195 path.quadTo(SkIntToScalar(20), SkIntToScalar(50),
196 SkIntToScalar(80), SkIntToScalar(50));
197 path.quadTo(SkIntToScalar(20), SkIntToScalar(50),
198 SkIntToScalar(20), SkIntToScalar(80));
199 canvas->drawPath(path, paint);
200 canvas->restore();
201}
202
203// Monotone test 2 (point at the top)
204void test_monotone_2(SkCanvas* canvas, const SkPaint& paint) {
205 SkPath path;
206 canvas->save();
207 canvas->translate(100, 300);
208 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
209 path.lineTo(SkIntToScalar(80), SkIntToScalar(30));
210 path.quadTo(SkIntToScalar(20), SkIntToScalar(20),
211 SkIntToScalar(20), SkIntToScalar(80));
212 canvas->drawPath(path, paint);
213 canvas->restore();
214}
215
216// Monotone test 3 (point at the bottom)
217void test_monotone_3(SkCanvas* canvas, const SkPaint& paint) {
218 SkPath path;
219 canvas->save();
220 canvas->translate(200, 300);
221 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
222 path.lineTo(SkIntToScalar(80), SkIntToScalar(70));
223 path.quadTo(SkIntToScalar(20), SkIntToScalar(80),
224 SkIntToScalar(20), SkIntToScalar(20));
225 canvas->drawPath(path, paint);
226 canvas->restore();
227}
228
229// Monotone test 4 (merging of two monotones)
230void test_monotone_4(SkCanvas* canvas, const SkPaint& paint) {
231 SkPath path;
232 canvas->save();
233 canvas->translate(300, 300);
234 path.moveTo(80, 25);
235 path.lineTo(50, 39);
236 path.lineTo(20, 25);
237 path.lineTo(40, 45);
238 path.lineTo(70, 50);
239 path.lineTo(80, 80);
240 canvas->drawPath(path, paint);
241 canvas->restore();
242}
243
244// Monotone test 5 (aborted merging of two monotones)
245void test_monotone_5(SkCanvas* canvas, const SkPaint& paint) {
246 SkPath path;
247 canvas->save();
248 canvas->translate(0, 400);
249 path.moveTo(50, 20);
250 path.lineTo(80, 80);
251 path.lineTo(50, 50);
252 path.lineTo(20, 80);
253 canvas->drawPath(path, paint);
254 canvas->restore();
255}
256// Degenerate intersection test
257void test_degenerate(SkCanvas* canvas, const SkPaint& paint) {
258 SkPath path;
259 canvas->save();
260 canvas->translate(100, 400);
261 path.moveTo(50, 20);
262 path.lineTo(70, 30);
263 path.lineTo(20, 50);
264 path.moveTo(50, 20);
265 path.lineTo(80, 80);
266 path.lineTo(50, 80);
267 canvas->drawPath(path, paint);
268 canvas->restore();
269}
270// Two triangles with a coincident edge.
271void test_coincident_edge(SkCanvas* canvas, const SkPaint& paint) {
272 SkPath path;
273 canvas->save();
274 canvas->translate(200, 400);
275
276 path.moveTo(80, 20);
277 path.lineTo(80, 80);
278 path.lineTo(20, 80);
279
280 path.moveTo(20, 20);
281 path.lineTo(80, 80);
282 path.lineTo(20, 80);
283
284 canvas->drawPath(path, paint);
285 canvas->restore();
286}
287// Bowtie with a coincident triangle (one triangle vertex coincident with the
288// bowtie's intersection).
289void test_bowtie_coincident_triangle(SkCanvas* canvas, const SkPaint& paint) {
290 SkPath path;
291 canvas->save();
292 canvas->translate(300, 400);
293 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
294 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
295 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
296 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
297 path.moveTo(SkIntToScalar(50), SkIntToScalar(50));
298 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
299 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
300 canvas->drawPath(path, paint);
301 canvas->restore();
302}
303
304// Coincident edges (big ones first, coincident vert on top).
305void test_coincident_edges_1(SkCanvas* canvas, const SkPaint& paint) {
306 SkPath path;
307 canvas->save();
308 canvas->translate(0, 500);
309 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
310 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
311 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
312 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
313 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
314 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
315 canvas->drawPath(path, paint);
316 canvas->restore();
317}
318// Coincident edges (small ones first, coincident vert on top).
319void test_coincident_edges_2(SkCanvas* canvas, const SkPaint& paint) {
320 SkPath path;
321 canvas->save();
322 canvas->translate(100, 500);
323 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
324 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
325 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
326 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
327 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
328 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
329 canvas->drawPath(path, paint);
330 canvas->restore();
331}
332// Coincident edges (small ones first, coincident vert on bottom).
333void test_coincident_edges_3(SkCanvas* canvas, const SkPaint& paint) {
334 SkPath path;
335 canvas->save();
336 canvas->translate(200, 500);
337 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
338 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
339 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
340 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
341 path.lineTo(SkIntToScalar(20), SkIntToScalar(20));
342 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
343 canvas->drawPath(path, paint);
344 canvas->restore();
345}
346// Coincident edges (big ones first, coincident vert on bottom).
347void test_coincident_edges_4(SkCanvas* canvas, const SkPaint& paint) {
348 SkPath path;
349 canvas->save();
350 canvas->translate(300, 500);
351 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
352 path.lineTo(SkIntToScalar(20), SkIntToScalar(20));
353 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
354 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
355 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
356 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
357 canvas->drawPath(path, paint);
358 canvas->restore();
359}
360
361};
362
363class ConcavePathsGM : public skiagm::GM {
364public:
365 ConcavePathsGM() {}
366
367protected:
mtklein36352bf2015-03-25 18:17:31 -0700368 SkString onShortName() override {
senorblancod6ed19c2015-02-26 06:58:17 -0800369 return SkString("concavepaths");
370 }
371
mtklein36352bf2015-03-25 18:17:31 -0700372 SkISize onISize() override {
senorblancod6ed19c2015-02-26 06:58:17 -0800373 return SkISize::Make(WIDTH, HEIGHT);
374 }
375
mtklein36352bf2015-03-25 18:17:31 -0700376 void onDraw(SkCanvas* canvas) override {
senorblancod6ed19c2015-02-26 06:58:17 -0800377 SkPaint paint;
378
379 paint.setAntiAlias(true);
380 paint.setStyle(SkPaint::kFill_Style);
381
382 test_concave(canvas, paint);
383 test_reverse_concave(canvas, paint);
384 test_bowtie(canvas, paint);
385 test_fake_bowtie(canvas, paint);
386 test_fish(canvas, paint);
387 test_collinear_edges(canvas, paint);
388 test_hole(canvas, paint);
389 test_star(canvas, paint);
390 test_stairstep(canvas, paint);
391 test_stairstep2(canvas, paint);
392 test_overlapping(canvas, paint);
senorblanco531237e2016-06-02 11:36:48 -0700393 test_partners(canvas, paint);
senorblancod6ed19c2015-02-26 06:58:17 -0800394 test_monotone_1(canvas, paint);
395 test_monotone_2(canvas, paint);
396 test_monotone_3(canvas, paint);
397 test_monotone_4(canvas, paint);
398 test_monotone_5(canvas, paint);
399 test_degenerate(canvas, paint);
400 test_coincident_edge(canvas, paint);
401 test_bowtie_coincident_triangle(canvas, paint);
402 test_coincident_edges_1(canvas, paint);
403 test_coincident_edges_2(canvas, paint);
404 test_coincident_edges_3(canvas, paint);
405 test_coincident_edges_4(canvas, paint);
406 }
407
408private:
409 typedef skiagm::GM INHERITED;
410};
411
scroggo96f16e82015-12-10 13:31:59 -0800412DEF_GM( return new ConcavePathsGM; )