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 #include "src/utils/SkPolyUtils.h"
8 #include "tests/Test.h"
9 
DEF_TEST(PolyUtils,reporter)10 DEF_TEST(PolyUtils, reporter) {
11 
12     SkTDArray<SkPoint> poly;
13     // init simple index map
14     uint16_t indexMap[1024];
15     for (int i = 0; i < 1024; ++i) {
16         indexMap[i] = i;
17     }
18     SkTDArray<uint16_t> triangleIndices;
19 
20     // skinny triangle
21     *poly.push() = SkPoint::Make(-100, 55);
22     *poly.push() = SkPoint::Make(100, 55);
23     *poly.push() = SkPoint::Make(102.5f, 54.330127f);
24     REPORTER_ASSERT(reporter, SkGetPolygonWinding(poly.begin(), poly.count()) < 0);
25     REPORTER_ASSERT(reporter, SkIsConvexPolygon(poly.begin(), poly.count()));
26     REPORTER_ASSERT(reporter, SkIsSimplePolygon(poly.begin(), poly.count()));
27     REPORTER_ASSERT(reporter, SkTriangulateSimplePolygon(poly.begin(), indexMap, poly.count(),
28                                                          &triangleIndices));
29 
30     // switch winding
31     poly[2].set(102.5f, 55.330127f);
32     REPORTER_ASSERT(reporter, SkGetPolygonWinding(poly.begin(), poly.count()) > 0);
33     REPORTER_ASSERT(reporter, SkIsConvexPolygon(poly.begin(), poly.count()));
34     REPORTER_ASSERT(reporter, SkIsSimplePolygon(poly.begin(), poly.count()));
35     triangleIndices.rewind();
36     REPORTER_ASSERT(reporter, SkTriangulateSimplePolygon(poly.begin(), indexMap, poly.count(),
37                                                          &triangleIndices));
38 
39     // make degenerate
40     poly[2].set(100 + 2.5f, 55);
41     REPORTER_ASSERT(reporter, SkGetPolygonWinding(poly.begin(), poly.count()) == 0);
42     // TODO: should these fail?
43     REPORTER_ASSERT(reporter, SkIsConvexPolygon(poly.begin(), poly.count()));
44     REPORTER_ASSERT(reporter, SkIsSimplePolygon(poly.begin(), poly.count()));
45     triangleIndices.rewind();
46     REPORTER_ASSERT(reporter, !SkTriangulateSimplePolygon(poly.begin(), indexMap, poly.count(),
47                                                           &triangleIndices));
48 
49     // giant triangle
50     poly[0].set(-1.0e+37f, 1.0e+37f);
51     poly[1].set(1.0e+37f, 1.0e+37f);
52     poly[2].set(-1.0e+37f, -1.0e+37f);
53     REPORTER_ASSERT(reporter, SkGetPolygonWinding(poly.begin(), poly.count()) < 0);
54     REPORTER_ASSERT(reporter, SkIsConvexPolygon(poly.begin(), poly.count()));
55     REPORTER_ASSERT(reporter, SkIsSimplePolygon(poly.begin(), poly.count()));
56     triangleIndices.rewind();
57     REPORTER_ASSERT(reporter, SkTriangulateSimplePolygon(poly.begin(), indexMap, poly.count(),
58                                                          &triangleIndices));
59 
60     // teeny triangle
61     poly[0].set(-1.0e-38f, 1.0e-38f);
62     poly[1].set(-1.0e-38f, -1.0e-38f);
63     poly[2].set(1.0e-38f, 1.0e-38f);
64     REPORTER_ASSERT(reporter, SkGetPolygonWinding(poly.begin(), poly.count()) == 0);
65     // TODO: should these fail?
66     REPORTER_ASSERT(reporter, SkIsConvexPolygon(poly.begin(), poly.count()));
67     REPORTER_ASSERT(reporter, SkIsSimplePolygon(poly.begin(), poly.count()));
68     triangleIndices.rewind();
69     REPORTER_ASSERT(reporter, !SkTriangulateSimplePolygon(poly.begin(), indexMap, poly.count(),
70                                                           &triangleIndices));
71 
72     // triangle way off in space (relative to size so we don't completely obliterate values)
73     poly[0].set(-100 + 1.0e+9f, 55 - 1.0e+9f);
74     poly[1].set(100 + 1.0e+9f, 55 - 1.0e+9f);
75     poly[2].set(150 + 1.0e+9f, 100 - 1.0e+9f);
76     REPORTER_ASSERT(reporter, SkGetPolygonWinding(poly.begin(), poly.count()) > 0);
77     REPORTER_ASSERT(reporter, SkIsConvexPolygon(poly.begin(), poly.count()));
78     REPORTER_ASSERT(reporter, SkIsSimplePolygon(poly.begin(), poly.count()));
79     triangleIndices.rewind();
80     REPORTER_ASSERT(reporter, SkTriangulateSimplePolygon(poly.begin(), indexMap, poly.count(),
81                                                          &triangleIndices));
82 
83     ///////////////////////////////////////////////////////////////////////
84     // round rect
85     poly.rewind();
86     *poly.push() = SkPoint::Make(-100, 55);
87     *poly.push() = SkPoint::Make(100, 55);
88     *poly.push() = SkPoint::Make(100 + 2.5f, 50 + 4.330127f);
89     *poly.push() = SkPoint::Make(100 + 3.535534f, 50 + 3.535534f);
90     *poly.push() = SkPoint::Make(100 + 4.330127f, 50 + 2.5f);
91     *poly.push() = SkPoint::Make(105, 50);
92     *poly.push() = SkPoint::Make(105, -50);
93     *poly.push() = SkPoint::Make(100 + 4.330127f, -50 - 2.5f);
94     *poly.push() = SkPoint::Make(100 + 3.535534f, -50 - 3.535534f);
95     *poly.push() = SkPoint::Make(100 + 2.5f, -50 - 4.330127f);
96     *poly.push() = SkPoint::Make(100, -55);
97     *poly.push() = SkPoint::Make(-100, -55);
98     *poly.push() = SkPoint::Make(-100 - 2.5f, -50 - 4.330127f);
99     *poly.push() = SkPoint::Make(-100 - 3.535534f, -50 - 3.535534f);
100     *poly.push() = SkPoint::Make(-100 - 4.330127f, -50 - 2.5f);
101     *poly.push() = SkPoint::Make(-105, -50);
102     *poly.push() = SkPoint::Make(-105, 50);
103     *poly.push() = SkPoint::Make(-100 - 4.330127f, 50 + 2.5f);
104     *poly.push() = SkPoint::Make(-100 - 3.535534f, 50 + 3.535534f);
105     *poly.push() = SkPoint::Make(-100 - 2.5f, 50 + 4.330127f);
106     REPORTER_ASSERT(reporter, SkGetPolygonWinding(poly.begin(), poly.count()) < 0);
107     REPORTER_ASSERT(reporter, SkIsConvexPolygon(poly.begin(), poly.count()));
108     REPORTER_ASSERT(reporter, SkIsSimplePolygon(poly.begin(), poly.count()));
109     triangleIndices.rewind();
110     REPORTER_ASSERT(reporter, SkTriangulateSimplePolygon(poly.begin(), indexMap, poly.count(),
111                                                          &triangleIndices));
112 
113     // translate far enough to obliterate some low bits
114     for (int i = 0; i < poly.count(); ++i) {
115         poly[i].offset(1.0e+7f, 1.0e+7f);
116     }
117     REPORTER_ASSERT(reporter, SkGetPolygonWinding(poly.begin(), poly.count()) < 0);
118     // Due to floating point error it's no longer convex
119     REPORTER_ASSERT(reporter, !SkIsConvexPolygon(poly.begin(), poly.count()));
120     REPORTER_ASSERT(reporter, SkIsSimplePolygon(poly.begin(), poly.count()));
121     triangleIndices.rewind();
122     REPORTER_ASSERT(reporter, SkTriangulateSimplePolygon(poly.begin(), indexMap, poly.count(),
123                                                           &triangleIndices));
124 
125     // translate a little farther to create some coincident vertices
126     for (int i = 0; i < poly.count(); ++i) {
127         poly[i].offset(4.0e+7f, 4.0e+7f);
128     }
129     REPORTER_ASSERT(reporter, SkGetPolygonWinding(poly.begin(), poly.count()) < 0);
130     REPORTER_ASSERT(reporter, SkIsConvexPolygon(poly.begin(), poly.count()));
131     REPORTER_ASSERT(reporter, SkIsSimplePolygon(poly.begin(), poly.count()));
132     // This can't handle coincident vertices
133     triangleIndices.rewind();
134     REPORTER_ASSERT(reporter, !SkTriangulateSimplePolygon(poly.begin(), indexMap, poly.count(),
135                                                           &triangleIndices));
136 
137     // troublesome case -- clipped roundrect
138     poly.rewind();
139     *poly.push() = SkPoint::Make(335.928101f, 428.219055f);
140     *poly.push() = SkPoint::Make(330.414459f, 423.034912f);
141     *poly.push() = SkPoint::Make(325.749084f, 417.395508f);
142     *poly.push() = SkPoint::Make(321.931946f, 411.300842f);
143     *poly.push() = SkPoint::Make(318.963074f, 404.750977f);
144     *poly.push() = SkPoint::Make(316.842468f, 397.745850f);
145     *poly.push() = SkPoint::Make(315.570068f, 390.285522f);
146     *poly.push() = SkPoint::Make(315.145966f, 382.369965f);
147     *poly.push() = SkPoint::Make(315.570068f, 374.454346f);
148     *poly.push() = SkPoint::Make(316.842468f, 366.994019f);
149     *poly.push() = SkPoint::Make(318.963074f, 359.988892f);
150     *poly.push() = SkPoint::Make(321.931946f, 353.439056f);
151     *poly.push() = SkPoint::Make(325.749084f, 347.344421f);
152     *poly.push() = SkPoint::Make(330.414459f, 341.705017f);
153     *poly.push() = SkPoint::Make(335.928101f, 336.520813f);
154     *poly.push() = SkPoint::Make(342.289948f, 331.791901f);
155     *poly.push() = SkPoint::Make(377.312134f, 331.791901f);
156     *poly.push() = SkPoint::Make(381.195313f, 332.532593f);
157     *poly.push() = SkPoint::Make(384.464935f, 334.754700f);
158     *poly.push() = SkPoint::Make(386.687042f, 338.024292f);
159     *poly.push() = SkPoint::Make(387.427765f, 341.907532f);
160     *poly.push() = SkPoint::Make(387.427765f, 422.832367f);
161     *poly.push() = SkPoint::Make(386.687042f, 426.715576f);
162     *poly.push() = SkPoint::Make(384.464935f, 429.985168f);
163     *poly.push() = SkPoint::Make(381.195313f, 432.207275f);
164     *poly.push() = SkPoint::Make(377.312134f, 432.947998f);
165     *poly.push() = SkPoint::Make(342.289948f, 432.947998f);
166     REPORTER_ASSERT(reporter, SkGetPolygonWinding(poly.begin(), poly.count()) > 0);
167     REPORTER_ASSERT(reporter, SkIsConvexPolygon(poly.begin(), poly.count()));
168     REPORTER_ASSERT(reporter, SkIsSimplePolygon(poly.begin(), poly.count()));
169     triangleIndices.rewind();
170     REPORTER_ASSERT(reporter, SkTriangulateSimplePolygon(poly.begin(), indexMap, poly.count(),
171                                                          &triangleIndices));
172 
173     // a star is born
174     poly.rewind();
175     *poly.push() = SkPoint::Make(0.0f, -50.0f);
176     *poly.push() = SkPoint::Make(14.43f, -25.0f);
177     *poly.push() = SkPoint::Make(43.30f, -25.0f);
178     *poly.push() = SkPoint::Make(28.86f, 0.0f);
179     *poly.push() = SkPoint::Make(43.30f, 25.0f);
180     *poly.push() = SkPoint::Make(14.43f, 25.0f);
181     *poly.push() = SkPoint::Make(0.0f, 50.0f);
182     *poly.push() = SkPoint::Make(-14.43f, 25.0f);
183     *poly.push() = SkPoint::Make(-43.30f, 25.0f);
184     *poly.push() = SkPoint::Make(-28.86f, 0.0f);
185     *poly.push() = SkPoint::Make(-43.30f, -25.0f);
186     *poly.push() = SkPoint::Make(-14.43f, -25.0f);
187     REPORTER_ASSERT(reporter, SkGetPolygonWinding(poly.begin(), poly.count()) > 0);
188     REPORTER_ASSERT(reporter, !SkIsConvexPolygon(poly.begin(), poly.count()));
189     REPORTER_ASSERT(reporter, SkIsSimplePolygon(poly.begin(), poly.count()));
190     triangleIndices.rewind();
191     REPORTER_ASSERT(reporter, SkTriangulateSimplePolygon(poly.begin(), indexMap, poly.count(),
192                                                          &triangleIndices));
193 
194     // many spiked star
195     {
196         const SkScalar c = SkIntToScalar(45);
197         const SkScalar r1 = SkIntToScalar(20);
198         const SkScalar r2 = SkIntToScalar(3);
199         const int n = 500;
200         poly.rewind();
201         SkScalar rad = 0;
202         const SkScalar drad = SK_ScalarPI / n;
203         for (int i = 0; i < n; i++) {
204             *poly.push() = SkPoint::Make(c + SkScalarCos(rad) * r1, c + SkScalarSin(rad) * r1);
205             rad += drad;
206             *poly.push() = SkPoint::Make(c + SkScalarCos(rad) * r2, c + SkScalarSin(rad) * r2);
207             rad += drad;
208         }
209         REPORTER_ASSERT(reporter, SkGetPolygonWinding(poly.begin(), poly.count()) > 0);
210         REPORTER_ASSERT(reporter, !SkIsConvexPolygon(poly.begin(), poly.count()));
211         REPORTER_ASSERT(reporter, SkIsSimplePolygon(poly.begin(), poly.count()));
212         triangleIndices.rewind();
213         REPORTER_ASSERT(reporter, SkTriangulateSimplePolygon(poly.begin(), indexMap, poly.count(),
214                                                              &triangleIndices));
215     }
216 
217     // self-intersecting polygon
218     poly.rewind();
219     *poly.push() = SkPoint::Make(0.0f, -50.0f);
220     *poly.push() = SkPoint::Make(14.43f, -25.0f);
221     *poly.push() = SkPoint::Make(43.30f, -25.0f);
222     *poly.push() = SkPoint::Make(-28.86f, 0.0f);
223     *poly.push() = SkPoint::Make(43.30f, 25.0f);
224     *poly.push() = SkPoint::Make(14.43f, 25.0f);
225     *poly.push() = SkPoint::Make(0.0f, 50.0f);
226     *poly.push() = SkPoint::Make(-14.43f, 25.0f);
227     *poly.push() = SkPoint::Make(-43.30f, 25.0f);
228     *poly.push() = SkPoint::Make(28.86f, 0.0f);
229     *poly.push() = SkPoint::Make(-43.30f, -25.0f);
230     *poly.push() = SkPoint::Make(-14.43f, -25.0f);
231     REPORTER_ASSERT(reporter, SkGetPolygonWinding(poly.begin(), poly.count()) > 0);
232     REPORTER_ASSERT(reporter, !SkIsConvexPolygon(poly.begin(), poly.count()));
233     REPORTER_ASSERT(reporter, !SkIsSimplePolygon(poly.begin(), poly.count()));
234     triangleIndices.rewind();
235     // running this just to make sure it doesn't crash
236     // the fact that it succeeds doesn't mean anything since the input is not simple
237     REPORTER_ASSERT(reporter, SkTriangulateSimplePolygon(poly.begin(), indexMap, poly.count(),
238                                                          &triangleIndices));
239 
240     // self-intersecting polygon with coincident point
241     poly.rewind();
242     *poly.push() = SkPoint::Make(0.0f, 0.0f);
243     *poly.push() = SkPoint::Make(-50, -50);
244     *poly.push() = SkPoint::Make(50, -50);
245     *poly.push() = SkPoint::Make(0.00000001f, -0.00000001f);
246     *poly.push() = SkPoint::Make(-50, 50);
247     *poly.push() = SkPoint::Make(50, 50);
248     REPORTER_ASSERT(reporter, SkGetPolygonWinding(poly.begin(), poly.count()) == 0);
249     REPORTER_ASSERT(reporter, !SkIsConvexPolygon(poly.begin(), poly.count()));
250     REPORTER_ASSERT(reporter, !SkIsSimplePolygon(poly.begin(), poly.count()));
251     triangleIndices.rewind();
252     // running this just to make sure it doesn't crash
253     REPORTER_ASSERT(reporter, !SkTriangulateSimplePolygon(poly.begin(), indexMap, poly.count(),
254                                                           &triangleIndices));
255 }
256 
257 struct PtSet {
258     const SkPoint*  fPts;
259     int             fN;
260 };
261 
DEF_TEST(IsPolyConvex_experimental,r)262 DEF_TEST(IsPolyConvex_experimental, r) {
263     #define PTSET(array)    {array, SK_ARRAY_COUNT(array)}
264 
265     const SkPoint g0[] = { {0, 0}, {10, 0}, {10, 10}, {0, 10} };
266     const PtSet convex[] = { PTSET(g0) };
267     for (auto& set : convex) {
268         REPORTER_ASSERT(r, SkIsPolyConvex_experimental(set.fPts, set.fN));
269     }
270 
271     const SkPoint b0[] = { {0, 0}, {10, 0}, {0, 10}, {10, 10} };
272     const SkPoint b1[] = {
273         {24.8219f, 8.05052f},
274         {26.0616f, 24.4895f}, {8.49582f, 16.815f},
275         {27.3047f, 7.75211f},
276         {21.927f, 27.2051f},
277     };
278     const SkPoint b2[] = {
279         {20, 20}, {20, 50}, {80, 50}, {20, 50}, {20, 80},
280     };
281     const PtSet concave[] = { PTSET(b0), PTSET(b1), PTSET(b2) };
282     for (auto& set : concave) {
283         if (SkIsPolyConvex_experimental(set.fPts, set.fN)) {
284             REPORTER_ASSERT(r, !SkIsPolyConvex_experimental(set.fPts, set.fN));
285         }
286     }
287 
288 }
289 
290