blob: 0d01660990b6675c621d62e182f795078ff3a821 [file] [log] [blame]
Brian Salomonab664fa2017-03-24 16:07:20 +00001/*
2 * Copyright 2017 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
Jim Van Verth8664a1d2018-06-28 16:26:50 -04008#include "SkPolyUtils.h"
Brian Salomonab664fa2017-03-24 16:07:20 +00009
Jim Van Verth00673692018-07-23 11:23:39 -040010#include <set>
Cary Clarkdf429f32017-11-08 11:44:31 -050011#include "SkPointPriv.h"
Jim Van Verth4db18ed2018-04-03 10:00:37 -040012#include "SkTArray.h"
Brian Salomonab664fa2017-03-24 16:07:20 +000013#include "SkTemplates.h"
Jim Van Verth4db18ed2018-04-03 10:00:37 -040014#include "SkTDPQueue.h"
Jim Van Verth8664a1d2018-06-28 16:26:50 -040015#include "SkTInternalLList.h"
16
17//////////////////////////////////////////////////////////////////////////////////
18// Helper data structures and functions
Brian Salomonab664fa2017-03-24 16:07:20 +000019
Jim Van Verth4db18ed2018-04-03 10:00:37 -040020struct OffsetSegment {
Brian Salomonab664fa2017-03-24 16:07:20 +000021 SkPoint fP0;
Jim Van Vertha6316832018-07-24 09:30:37 -040022 SkVector fV;
Brian Salomonab664fa2017-03-24 16:07:20 +000023};
24
Jim Van Verth47d9ee42018-08-07 18:36:41 +000025// Computes perpDot for point p compared to segment defined by origin s0 and vector v0.
Brian Salomonab664fa2017-03-24 16:07:20 +000026// A positive value means the point is to the left of the segment,
27// negative is to the right, 0 is collinear.
Jim Van Verth47d9ee42018-08-07 18:36:41 +000028static int compute_side(const SkPoint& s0, const SkVector& v0, const SkPoint& p) {
29 SkVector v1 = p - s0;
30 SkScalar perpDot = v0.cross(v1);
31 if (!SkScalarNearlyZero(perpDot)) {
Brian Salomonab664fa2017-03-24 16:07:20 +000032 return ((perpDot > 0) ? 1 : -1);
33 }
34
35 return 0;
36}
37
Jim Van Verth6784ffa2018-07-03 16:12:39 -040038// Returns 1 for cw, -1 for ccw and 0 if zero signed area (either degenerate or self-intersecting)
39int SkGetPolygonWinding(const SkPoint* polygonVerts, int polygonSize) {
40 if (polygonSize < 3) {
41 return 0;
42 }
43
Jim Van Verth8664a1d2018-06-28 16:26:50 -040044 // compute area and use sign to determine winding
45 SkScalar quadArea = 0;
Jim Van Verth6784ffa2018-07-03 16:12:39 -040046 SkVector v0 = polygonVerts[1] - polygonVerts[0];
47 for (int curr = 1; curr < polygonSize - 1; ++curr) {
Jim Van Verth8664a1d2018-06-28 16:26:50 -040048 int next = (curr + 1) % polygonSize;
Jim Van Verth6784ffa2018-07-03 16:12:39 -040049 SkVector v1 = polygonVerts[next] - polygonVerts[0];
50 quadArea += v0.cross(v1);
51 v0 = v1;
Brian Salomonab664fa2017-03-24 16:07:20 +000052 }
Jim Van Verth47d9ee42018-08-07 18:36:41 +000053 if (SkScalarNearlyZero(quadArea)) {
Jim Van Verth8664a1d2018-06-28 16:26:50 -040054 return 0;
55 }
56 // 1 == ccw, -1 == cw
57 return (quadArea > 0) ? 1 : -1;
Brian Salomonab664fa2017-03-24 16:07:20 +000058}
59
Jim Van Verthbdde4282018-06-14 09:09:18 -040060// Helper function to compute the individual vector for non-equal offsets
61inline void compute_offset(SkScalar d, const SkPoint& polyPoint, int side,
62 const SkPoint& outerTangentIntersect, SkVector* v) {
63 SkScalar dsq = d * d;
64 SkVector dP = outerTangentIntersect - polyPoint;
65 SkScalar dPlenSq = SkPointPriv::LengthSqd(dP);
Jim Van Verth47d9ee42018-08-07 18:36:41 +000066 if (SkScalarNearlyZero(dPlenSq)) {
Jim Van Verthbdde4282018-06-14 09:09:18 -040067 v->set(0, 0);
68 } else {
69 SkScalar discrim = SkScalarSqrt(dPlenSq - dsq);
70 v->fX = (dsq*dP.fX - side * d*dP.fY*discrim) / dPlenSq;
71 v->fY = (dsq*dP.fY + side * d*dP.fX*discrim) / dPlenSq;
72 }
73}
74
75// Compute difference vector to offset p0-p1 'd0' and 'd1' units in direction specified by 'side'
76bool compute_offset_vectors(const SkPoint& p0, const SkPoint& p1, SkScalar d0, SkScalar d1,
77 int side, SkPoint* vector0, SkPoint* vector1) {
Jim Van Verthda965502017-04-11 15:29:14 -040078 SkASSERT(side == -1 || side == 1);
Jim Van Verthda965502017-04-11 15:29:14 -040079 if (SkScalarNearlyEqual(d0, d1)) {
80 // if distances are equal, can just outset by the perpendicular
Jim Van Verthbdde4282018-06-14 09:09:18 -040081 SkVector perp = SkVector::Make(p0.fY - p1.fY, p1.fX - p0.fX);
Jim Van Verthda965502017-04-11 15:29:14 -040082 perp.setLength(d0*side);
Jim Van Verthbdde4282018-06-14 09:09:18 -040083 *vector0 = perp;
84 *vector1 = perp;
Jim Van Verthda965502017-04-11 15:29:14 -040085 } else {
Jim Van Verthbdde4282018-06-14 09:09:18 -040086 SkScalar d0abs = SkTAbs(d0);
87 SkScalar d1abs = SkTAbs(d1);
Jim Van Verthda965502017-04-11 15:29:14 -040088 // Otherwise we need to compute the outer tangent.
89 // See: http://www.ambrsoft.com/TrigoCalc/Circles2/Circles2Tangent_.htm
Jim Van Verthbdde4282018-06-14 09:09:18 -040090 if (d0abs < d1abs) {
Jim Van Verthda965502017-04-11 15:29:14 -040091 side = -side;
92 }
Jim Van Verthbdde4282018-06-14 09:09:18 -040093 SkScalar dD = d0abs - d1abs;
Jim Van Verthda965502017-04-11 15:29:14 -040094 // if one circle is inside another, we can't compute an offset
Cary Clarkdf429f32017-11-08 11:44:31 -050095 if (dD*dD >= SkPointPriv::DistanceToSqd(p0, p1)) {
Jim Van Verthda965502017-04-11 15:29:14 -040096 return false;
97 }
Jim Van Verthbdde4282018-06-14 09:09:18 -040098 SkPoint outerTangentIntersect = SkPoint::Make((p1.fX*d0abs - p0.fX*d1abs) / dD,
99 (p1.fY*d0abs - p0.fY*d1abs) / dD);
Jim Van Verthda965502017-04-11 15:29:14 -0400100
Jim Van Verthbdde4282018-06-14 09:09:18 -0400101 compute_offset(d0, p0, side, outerTangentIntersect, vector0);
102 compute_offset(d1, p1, side, outerTangentIntersect, vector1);
Jim Van Verthda965502017-04-11 15:29:14 -0400103 }
104
105 return true;
Brian Salomonab664fa2017-03-24 16:07:20 +0000106}
107
Jim Van Verthbdde4282018-06-14 09:09:18 -0400108// Offset line segment p0-p1 'd0' and 'd1' units in the direction specified by 'side'
109bool SkOffsetSegment(const SkPoint& p0, const SkPoint& p1, SkScalar d0, SkScalar d1,
110 int side, SkPoint* offset0, SkPoint* offset1) {
111 SkVector v0, v1;
112 if (!compute_offset_vectors(p0, p1, d0, d1, side, &v0, &v1)) {
113 return false;
114 }
115 *offset0 = p0 + v0;
116 *offset1 = p1 + v1;
117
118 return true;
119}
120
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000121// compute fraction of d along v
122static inline SkScalar compute_param(const SkVector& v, const SkVector& d) {
123 if (SkScalarNearlyZero(v.fX)) {
124 return d.fY / v.fY;
125 } else {
126 return d.fX / v.fX;
127 }
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400128}
129
Brian Salomonab664fa2017-03-24 16:07:20 +0000130// Compute the intersection 'p' between segments s0 and s1, if any.
131// 's' is the parametric value for the intersection along 's0' & 't' is the same for 's1'.
132// Returns false if there is no intersection.
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400133static bool compute_intersection(const OffsetSegment& s0, const OffsetSegment& s1,
Brian Salomonab664fa2017-03-24 16:07:20 +0000134 SkPoint* p, SkScalar* s, SkScalar* t) {
Jim Van Vertha6316832018-07-24 09:30:37 -0400135 const SkVector& v0 = s0.fV;
136 const SkVector& v1 = s1.fV;
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000137 SkVector d = s1.fP0 - s0.fP0;
138 SkScalar perpDot = v0.cross(v1);
139 SkScalar localS, localT;
140 if (SkScalarNearlyZero(perpDot)) {
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400141 // segments are parallel, but not collinear
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000142 if (!SkScalarNearlyZero(d.cross(v0)) || !SkScalarNearlyZero(d.cross(v1))) {
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400143 return false;
144 }
145
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000146 // Check for degenerate segments
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400147 if (!SkPointPriv::CanNormalize(v0.fX, v0.fY)) {
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000148 // Both are degenerate
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400149 if (!SkPointPriv::CanNormalize(v1.fX, v1.fY)) {
150 // Check if they're the same point
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000151 if (!SkPointPriv::CanNormalize(d.fX, d.fY)) {
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400152 *p = s0.fP0;
153 *s = 0;
154 *t = 0;
155 return true;
156 } else {
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400157 return false;
158 }
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400159 }
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000160 // Otherwise project onto segment1
161 localT = compute_param(v1, -d);
162 if (localT < 0 || localT > SK_Scalar1) {
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400163 return false;
164 }
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000165 localS = 0;
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400166 } else {
167 // Project segment1's endpoints onto segment0
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000168 localS = compute_param(v0, d);
169 localT = 0;
170 if (localS < 0 || localS > SK_Scalar1) {
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400171 // The first endpoint doesn't lie on segment0
172 // If segment1 is degenerate, then there's no collision
173 if (!SkPointPriv::CanNormalize(v1.fX, v1.fY)) {
174 return false;
175 }
176
177 // Otherwise try the other one
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000178 SkScalar oldLocalS = localS;
179 localS = compute_param(v0, d + v1);
180 localT = SK_Scalar1;
181 if (localS < 0 || localS > SK_Scalar1) {
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400182 // it's possible that segment1's interval surrounds segment0
183 // this is false if params have the same signs, and in that case no collision
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000184 if (localS*oldLocalS > 0) {
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400185 return false;
186 }
187 // otherwise project segment0's endpoint onto segment1 instead
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000188 localS = 0;
189 localT = compute_param(v1, -d);
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400190 }
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400191 }
192 }
193 } else {
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000194 localS = d.cross(v1) / perpDot;
195 if (localS < 0 || localS > SK_Scalar1) {
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400196 return false;
197 }
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000198 localT = d.cross(v0) / perpDot;
199 if (localT < 0 || localT > SK_Scalar1) {
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400200 return false;
201 }
Brian Salomonab664fa2017-03-24 16:07:20 +0000202 }
203
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400204 *p = s0.fP0 + v0*localS;
Brian Salomonab664fa2017-03-24 16:07:20 +0000205 *s = localS;
206 *t = localT;
207
208 return true;
209}
210
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400211bool SkIsConvexPolygon(const SkPoint* polygonVerts, int polygonSize) {
212 if (polygonSize < 3) {
213 return false;
Jim Van Verth0513f142017-03-24 14:28:57 -0400214 }
215
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400216 SkScalar lastArea = 0;
217 SkScalar lastPerpDot = 0;
Jim Van Verth0513f142017-03-24 14:28:57 -0400218
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400219 int prevIndex = polygonSize - 1;
220 int currIndex = 0;
221 int nextIndex = 1;
222 SkPoint origin = polygonVerts[0];
223 SkVector v0 = polygonVerts[currIndex] - polygonVerts[prevIndex];
224 SkVector v1 = polygonVerts[nextIndex] - polygonVerts[currIndex];
225 SkVector w0 = polygonVerts[currIndex] - origin;
226 SkVector w1 = polygonVerts[nextIndex] - origin;
227 for (int i = 0; i < polygonSize; ++i) {
Jim Van Verth061cc212018-07-11 14:09:09 -0400228 if (!polygonVerts[i].isFinite()) {
229 return false;
230 }
231
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400232 // Check that winding direction is always the same (otherwise we have a reflex vertex)
Jim Van Verth0513f142017-03-24 14:28:57 -0400233 SkScalar perpDot = v0.cross(v1);
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400234 if (lastPerpDot*perpDot < 0) {
Jim Van Verth0513f142017-03-24 14:28:57 -0400235 return false;
236 }
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400237 if (0 != perpDot) {
238 lastPerpDot = perpDot;
239 }
240
241 // If the signed area ever flips it's concave
242 // TODO: see if we can verify convexity only with signed area
243 SkScalar quadArea = w0.cross(w1);
244 if (quadArea*lastArea < 0) {
245 return false;
246 }
247 if (0 != quadArea) {
248 lastArea = quadArea;
249 }
250
251 prevIndex = currIndex;
252 currIndex = nextIndex;
253 nextIndex = (currIndex + 1) % polygonSize;
254 v0 = v1;
255 v1 = polygonVerts[nextIndex] - polygonVerts[currIndex];
256 w0 = w1;
257 w1 = polygonVerts[nextIndex] - origin;
Jim Van Verth0513f142017-03-24 14:28:57 -0400258 }
259
260 return true;
261}
Jim Van Verth0513f142017-03-24 14:28:57 -0400262
Jim Van Verth00673692018-07-23 11:23:39 -0400263struct OffsetEdge {
264 OffsetEdge* fPrev;
265 OffsetEdge* fNext;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400266 OffsetSegment fInset;
267 SkPoint fIntersection;
268 SkScalar fTValue;
Jim Van Verth872da6b2018-04-10 11:24:11 -0400269 uint16_t fIndex;
Jim Van Vertha6316832018-07-24 09:30:37 -0400270 uint16_t fEnd;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400271
Jim Van Verth00673692018-07-23 11:23:39 -0400272 void init(uint16_t start = 0, uint16_t end = 0) {
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400273 fIntersection = fInset.fP0;
274 fTValue = SK_ScalarMin;
Jim Van Verth872da6b2018-04-10 11:24:11 -0400275 fIndex = start;
Jim Van Vertha6316832018-07-24 09:30:37 -0400276 fEnd = end;
277 }
278
279 // special intersection check that looks for endpoint intersection
280 bool checkIntersection(const OffsetEdge* that,
281 SkPoint* p, SkScalar* s, SkScalar* t) {
282 if (this->fEnd == that->fIndex) {
283 SkPoint p1 = this->fInset.fP0 + this->fInset.fV;
284 if (SkPointPriv::EqualsWithinTolerance(p1, that->fInset.fP0)) {
285 *p = p1;
286 *s = SK_Scalar1;
287 *t = 0;
288 return true;
289 }
290 }
291
292 return compute_intersection(this->fInset, that->fInset, p, s, t);
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400293 }
Jim Van Vertheddb3d92018-08-02 10:56:26 -0400294
295 // computes the line intersection and then the distance from that to this
296 SkScalar computeCrossingDistance(const OffsetEdge* that) {
297 const OffsetSegment& s0 = this->fInset;
298 const OffsetSegment& s1 = that->fInset;
299 const SkVector& v0 = s0.fV;
300 const SkVector& v1 = s1.fV;
301
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000302 SkScalar perpDot = v0.cross(v1);
303 if (SkScalarNearlyZero(perpDot)) {
Jim Van Vertheddb3d92018-08-02 10:56:26 -0400304 // segments are parallel
305 return SK_ScalarMax;
306 }
307
308 SkVector d = s1.fP0 - s0.fP0;
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000309 SkScalar localS = d.cross(v1) / perpDot;
Jim Van Vertheddb3d92018-08-02 10:56:26 -0400310 if (localS < 0) {
311 localS = -localS;
312 } else {
313 localS -= SK_Scalar1;
314 }
315
316 localS *= v0.length();
317
318 return localS;
319 }
320
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400321};
322
Jim Van Verth00673692018-07-23 11:23:39 -0400323static void remove_node(const OffsetEdge* node, OffsetEdge** head) {
324 // remove from linked list
325 node->fPrev->fNext = node->fNext;
326 node->fNext->fPrev = node->fPrev;
327 if (node == *head) {
328 *head = (node->fNext == node) ? nullptr : node->fNext;
329 }
330}
331
Jim Van Verth8664a1d2018-06-28 16:26:50 -0400332//////////////////////////////////////////////////////////////////////////////////
333
Brian Salomonab664fa2017-03-24 16:07:20 +0000334// The objective here is to inset all of the edges by the given distance, and then
335// remove any invalid inset edges by detecting right-hand turns. In a ccw polygon,
336// we should only be making left-hand turns (for cw polygons, we use the winding
337// parameter to reverse this). We detect this by checking whether the second intersection
338// on an edge is closer to its tail than the first one.
339//
340// We might also have the case that there is no intersection between two neighboring inset edges.
341// In this case, one edge will lie to the right of the other and should be discarded along with
342// its previous intersection (if any).
343//
344// Note: the assumption is that inputPolygon is convex and has no coincident points.
345//
346bool SkInsetConvexPolygon(const SkPoint* inputPolygonVerts, int inputPolygonSize,
Jim Van Verthbdde4282018-06-14 09:09:18 -0400347 std::function<SkScalar(const SkPoint&)> insetDistanceFunc,
Jim Van Verthda965502017-04-11 15:29:14 -0400348 SkTDArray<SkPoint>* insetPolygon) {
Brian Salomonab664fa2017-03-24 16:07:20 +0000349 if (inputPolygonSize < 3) {
350 return false;
351 }
352
Jim Van Vertha6316832018-07-24 09:30:37 -0400353 // restrict this to match other routines
354 // practically we don't want anything bigger than this anyway
355 if (inputPolygonSize >= (1 << 16)) {
356 return false;
357 }
358
Jim Van Verth8664a1d2018-06-28 16:26:50 -0400359 // get winding direction
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400360 int winding = SkGetPolygonWinding(inputPolygonVerts, inputPolygonSize);
Brian Salomonab664fa2017-03-24 16:07:20 +0000361 if (0 == winding) {
362 return false;
363 }
364
365 // set up
Jim Van Verth00673692018-07-23 11:23:39 -0400366 SkAutoSTMalloc<64, OffsetEdge> edgeData(inputPolygonSize);
367 int prev = inputPolygonSize - 1;
368 for (int curr = 0; curr < inputPolygonSize; prev = curr, ++curr) {
369 int next = (curr + 1) % inputPolygonSize;
370 if (!inputPolygonVerts[curr].isFinite()) {
Jim Van Verth061cc212018-07-11 14:09:09 -0400371 return false;
372 }
Jim Van Verthb55eb282017-07-18 14:13:45 -0400373 // check for convexity just to be sure
Jim Van Vertha6316832018-07-24 09:30:37 -0400374 if (compute_side(inputPolygonVerts[prev], inputPolygonVerts[curr] - inputPolygonVerts[prev],
Jim Van Verth00673692018-07-23 11:23:39 -0400375 inputPolygonVerts[next])*winding < 0) {
Jim Van Verthb55eb282017-07-18 14:13:45 -0400376 return false;
377 }
Jim Van Vertha6316832018-07-24 09:30:37 -0400378 SkPoint p0, p1;
Jim Van Verth00673692018-07-23 11:23:39 -0400379 if (!SkOffsetSegment(inputPolygonVerts[curr], inputPolygonVerts[next],
380 insetDistanceFunc(inputPolygonVerts[curr]),
381 insetDistanceFunc(inputPolygonVerts[next]),
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400382 winding,
Jim Van Vertha6316832018-07-24 09:30:37 -0400383 &p0, &p1)) {
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400384 return false;
385 }
Jim Van Vertha6316832018-07-24 09:30:37 -0400386 edgeData[curr].fPrev = &edgeData[prev];
387 edgeData[curr].fNext = &edgeData[next];
388 edgeData[curr].fInset.fP0 = p0;
389 edgeData[curr].fInset.fV = p1 - p0;
Jim Van Verth00673692018-07-23 11:23:39 -0400390 edgeData[curr].init();
Brian Salomonab664fa2017-03-24 16:07:20 +0000391 }
392
Jim Van Verth00673692018-07-23 11:23:39 -0400393 OffsetEdge* head = &edgeData[0];
394 OffsetEdge* currEdge = head;
395 OffsetEdge* prevEdge = currEdge->fPrev;
Brian Salomonab664fa2017-03-24 16:07:20 +0000396 int insetVertexCount = inputPolygonSize;
Jim Van Verth796bc1d2018-06-19 15:00:28 -0400397 int iterations = 0;
Jim Van Verth00673692018-07-23 11:23:39 -0400398 while (head && prevEdge != currEdge) {
Jim Van Verth796bc1d2018-06-19 15:00:28 -0400399 ++iterations;
Jim Van Verth3645bb02018-06-26 14:58:58 -0400400 // we should check each edge against each other edge at most once
Jim Van Verth796bc1d2018-06-19 15:00:28 -0400401 if (iterations > inputPolygonSize*inputPolygonSize) {
402 return false;
403 }
404
Brian Salomonab664fa2017-03-24 16:07:20 +0000405 SkScalar s, t;
406 SkPoint intersection;
Jim Van Verth00673692018-07-23 11:23:39 -0400407 if (compute_intersection(prevEdge->fInset, currEdge->fInset,
Brian Salomonab664fa2017-03-24 16:07:20 +0000408 &intersection, &s, &t)) {
409 // if new intersection is further back on previous inset from the prior intersection
Jim Van Verth00673692018-07-23 11:23:39 -0400410 if (s < prevEdge->fTValue) {
Brian Salomonab664fa2017-03-24 16:07:20 +0000411 // no point in considering this one again
Jim Van Verth00673692018-07-23 11:23:39 -0400412 remove_node(prevEdge, &head);
Brian Salomonab664fa2017-03-24 16:07:20 +0000413 --insetVertexCount;
414 // go back one segment
Jim Van Verth00673692018-07-23 11:23:39 -0400415 prevEdge = prevEdge->fPrev;
Brian Salomonab664fa2017-03-24 16:07:20 +0000416 // we've already considered this intersection, we're done
Jim Van Verth00673692018-07-23 11:23:39 -0400417 } else if (currEdge->fTValue > SK_ScalarMin &&
Cary Clarkdf429f32017-11-08 11:44:31 -0500418 SkPointPriv::EqualsWithinTolerance(intersection,
Jim Van Verth00673692018-07-23 11:23:39 -0400419 currEdge->fIntersection,
Brian Salomonab664fa2017-03-24 16:07:20 +0000420 1.0e-6f)) {
421 break;
422 } else {
423 // add intersection
Jim Van Verth00673692018-07-23 11:23:39 -0400424 currEdge->fIntersection = intersection;
425 currEdge->fTValue = t;
Brian Salomonab664fa2017-03-24 16:07:20 +0000426
427 // go to next segment
Jim Van Verth00673692018-07-23 11:23:39 -0400428 prevEdge = currEdge;
429 currEdge = currEdge->fNext;
Brian Salomonab664fa2017-03-24 16:07:20 +0000430 }
431 } else {
432 // if prev to right side of curr
Jim Van Verth00673692018-07-23 11:23:39 -0400433 int side = winding*compute_side(currEdge->fInset.fP0,
Jim Van Vertha6316832018-07-24 09:30:37 -0400434 currEdge->fInset.fV,
435 prevEdge->fInset.fP0);
436 if (side < 0 &&
437 side == winding*compute_side(currEdge->fInset.fP0,
438 currEdge->fInset.fV,
439 prevEdge->fInset.fP0 + prevEdge->fInset.fV)) {
Brian Salomonab664fa2017-03-24 16:07:20 +0000440 // no point in considering this one again
Jim Van Verth00673692018-07-23 11:23:39 -0400441 remove_node(prevEdge, &head);
Brian Salomonab664fa2017-03-24 16:07:20 +0000442 --insetVertexCount;
443 // go back one segment
Jim Van Verth00673692018-07-23 11:23:39 -0400444 prevEdge = prevEdge->fPrev;
Brian Salomonab664fa2017-03-24 16:07:20 +0000445 } else {
446 // move to next segment
Jim Van Verth00673692018-07-23 11:23:39 -0400447 remove_node(currEdge, &head);
Brian Salomonab664fa2017-03-24 16:07:20 +0000448 --insetVertexCount;
Jim Van Verth00673692018-07-23 11:23:39 -0400449 currEdge = currEdge->fNext;
Brian Salomonab664fa2017-03-24 16:07:20 +0000450 }
451 }
452 }
453
Jim Van Verthda965502017-04-11 15:29:14 -0400454 // store all the valid intersections that aren't nearly coincident
455 // TODO: look at the main algorithm and see if we can detect these better
Brian Salomonab664fa2017-03-24 16:07:20 +0000456 insetPolygon->reset();
Jim Van Verth00673692018-07-23 11:23:39 -0400457 if (head) {
458 static constexpr SkScalar kCleanupTolerance = 0.01f;
459 if (insetVertexCount >= 0) {
460 insetPolygon->setReserve(insetVertexCount);
Brian Salomonab664fa2017-03-24 16:07:20 +0000461 }
Jim Van Verth00673692018-07-23 11:23:39 -0400462 int currIndex = 0;
463 OffsetEdge* currEdge = head;
464 *insetPolygon->push() = currEdge->fIntersection;
465 currEdge = currEdge->fNext;
466 while (currEdge != head) {
467 if (!SkPointPriv::EqualsWithinTolerance(currEdge->fIntersection,
468 (*insetPolygon)[currIndex],
469 kCleanupTolerance)) {
470 *insetPolygon->push() = currEdge->fIntersection;
471 currIndex++;
472 }
473 currEdge = currEdge->fNext;
474 }
475 // make sure the first and last points aren't coincident
476 if (currIndex >= 1 &&
477 SkPointPriv::EqualsWithinTolerance((*insetPolygon)[0], (*insetPolygon)[currIndex],
478 kCleanupTolerance)) {
479 insetPolygon->pop();
480 }
Jim Van Verthda965502017-04-11 15:29:14 -0400481 }
Brian Salomonab664fa2017-03-24 16:07:20 +0000482
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400483 return SkIsConvexPolygon(insetPolygon->begin(), insetPolygon->count());
Brian Salomonab664fa2017-03-24 16:07:20 +0000484}
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400485
Jim Van Verth8664a1d2018-06-28 16:26:50 -0400486///////////////////////////////////////////////////////////////////////////////////////////
487
488// compute the number of points needed for a circular join when offsetting a reflex vertex
Jim Van Verth66c5dc52018-08-06 14:38:31 -0400489bool SkComputeRadialSteps(const SkVector& v1, const SkVector& v2, SkScalar offset,
Jim Van Verth8664a1d2018-06-28 16:26:50 -0400490 SkScalar* rotSin, SkScalar* rotCos, int* n) {
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400491 const SkScalar kRecipPixelsPerArcSegment = 0.25f;
492
493 SkScalar rCos = v1.dot(v2);
Jim Van Verth061cc212018-07-11 14:09:09 -0400494 if (!SkScalarIsFinite(rCos)) {
495 return false;
496 }
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400497 SkScalar rSin = v1.cross(v2);
Jim Van Verth061cc212018-07-11 14:09:09 -0400498 if (!SkScalarIsFinite(rSin)) {
499 return false;
500 }
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400501 SkScalar theta = SkScalarATan2(rSin, rCos);
502
Jim Van Verth66c5dc52018-08-06 14:38:31 -0400503 SkScalar floatSteps = SkScalarAbs(offset*theta*kRecipPixelsPerArcSegment);
Jim Van Verth206dbe82018-07-23 11:48:31 -0400504 // limit the number of steps to at most max uint16_t (that's all we can index)
505 // knock one value off the top to account for rounding
506 if (floatSteps >= (1 << 16)-1) {
507 return false;
508 }
509 int steps = SkScalarRoundToInt(floatSteps);
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400510
Jim Van Verth061cc212018-07-11 14:09:09 -0400511 SkScalar dTheta = steps > 0 ? theta / steps : 0;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400512 *rotSin = SkScalarSinCos(dTheta, rotCos);
513 *n = steps;
Jim Van Verth061cc212018-07-11 14:09:09 -0400514 return true;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400515}
516
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400517///////////////////////////////////////////////////////////////////////////////////////////
518
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400519// a point is "left" to another if its x coordinate is less, or if equal, its y coordinate
520static bool left(const SkPoint& p0, const SkPoint& p1) {
Jim Van Verth061cc212018-07-11 14:09:09 -0400521 return p0.fX < p1.fX || (!(p0.fX > p1.fX) && p0.fY < p1.fY);
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400522}
523
524struct Vertex {
525 static bool Left(const Vertex& qv0, const Vertex& qv1) {
526 return left(qv0.fPosition, qv1.fPosition);
527 }
Jim Van Verth00673692018-07-23 11:23:39 -0400528
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400529 // packed to fit into 16 bytes (one cache line)
530 SkPoint fPosition;
531 uint16_t fIndex; // index in unsorted polygon
532 uint16_t fPrevIndex; // indices for previous and next vertex in unsorted polygon
533 uint16_t fNextIndex;
534 uint16_t fFlags;
535};
536
537enum VertexFlags {
538 kPrevLeft_VertexFlag = 0x1,
539 kNextLeft_VertexFlag = 0x2,
540};
541
Jim Van Verth00673692018-07-23 11:23:39 -0400542struct ActiveEdge {
Jim Van Vertha6316832018-07-24 09:30:37 -0400543 ActiveEdge(const SkPoint& p0, const SkPoint& p1, uint16_t index0, uint16_t index1)
544 : fSegment({p0, p1-p0})
Jim Van Verth00673692018-07-23 11:23:39 -0400545 , fIndex0(index0)
546 , fIndex1(index1) {}
547
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400548 // returns true if "this" is above "that"
Jim Van Verth00673692018-07-23 11:23:39 -0400549 bool above(const ActiveEdge& that) const {
550 SkASSERT(this->fSegment.fP0.fX <= that.fSegment.fP0.fX);
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000551 const SkScalar kTolerance = SK_ScalarNearlyZero * SK_ScalarNearlyZero;
Jim Van Vertha6316832018-07-24 09:30:37 -0400552 const SkVector& u = this->fSegment.fV;
553 SkVector dv = that.fSegment.fP0 - this->fSegment.fP0;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400554 // The idea here is that if the vector between the origins of the two segments (dv)
555 // rotates counterclockwise up to the vector representing the "this" segment (u),
556 // then we know that "this" is above that. If the result is clockwise we say it's below.
Jim Van Verth00673692018-07-23 11:23:39 -0400557 if (this->fIndex0 != that.fIndex0) {
Jim Van Verth00673692018-07-23 11:23:39 -0400558 SkScalar cross = dv.cross(u);
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000559 if (cross > kTolerance) {
Jim Van Verth00673692018-07-23 11:23:39 -0400560 return true;
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000561 } else if (cross < -kTolerance) {
Jim Van Verth00673692018-07-23 11:23:39 -0400562 return false;
563 }
564 } else if (this->fIndex1 == that.fIndex1) {
565 // they're the same edge
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400566 return false;
567 }
Jim Van Verth00673692018-07-23 11:23:39 -0400568 // At this point either the two origins are nearly equal or the origin of "that"
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400569 // lies on dv. So then we try the same for the vector from the tail of "this"
570 // to the head of "that". Again, ccw means "this" is above "that".
Jim Van Vertha6316832018-07-24 09:30:37 -0400571 // dv = that.P1 - this.P0
572 // = that.fP0 + that.fV - this.fP0
573 // = that.fP0 - this.fP0 + that.fV
574 // = old_dv + that.fV
575 dv += that.fSegment.fV;
Jim Van Verth00673692018-07-23 11:23:39 -0400576 SkScalar cross = dv.cross(u);
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000577 if (cross > kTolerance) {
Jim Van Verth00673692018-07-23 11:23:39 -0400578 return true;
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000579 } else if (cross < -kTolerance) {
Jim Van Verth00673692018-07-23 11:23:39 -0400580 return false;
581 }
582 // If the previous check fails, the two segments are nearly collinear
583 // First check y-coord of first endpoints
584 if (this->fSegment.fP0.fX < that.fSegment.fP0.fX) {
585 return (this->fSegment.fP0.fY >= that.fSegment.fP0.fY);
586 } else if (this->fSegment.fP0.fY > that.fSegment.fP0.fY) {
587 return true;
588 } else if (this->fSegment.fP0.fY < that.fSegment.fP0.fY) {
589 return false;
590 }
591 // The first endpoints are the same, so check the other endpoint
Jim Van Vertha6316832018-07-24 09:30:37 -0400592 SkPoint thisP1 = this->fSegment.fP0 + this->fSegment.fV;
593 SkPoint thatP1 = that.fSegment.fP0 + that.fSegment.fV;
594 if (thisP1.fX < thatP1.fX) {
595 return (thisP1.fY >= thatP1.fY);
Jim Van Verth00673692018-07-23 11:23:39 -0400596 } else {
Jim Van Vertha6316832018-07-24 09:30:37 -0400597 return (thisP1.fY > thatP1.fY);
Jim Van Verth00673692018-07-23 11:23:39 -0400598 }
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400599 }
600
Jim Van Verth00673692018-07-23 11:23:39 -0400601 bool intersect(const ActiveEdge& that) const {
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000602 SkPoint intersection;
603 SkScalar s, t;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400604 // check first to see if these edges are neighbors in the polygon
605 if (this->fIndex0 == that.fIndex0 || this->fIndex1 == that.fIndex0 ||
606 this->fIndex0 == that.fIndex1 || this->fIndex1 == that.fIndex1) {
607 return false;
608 }
Jim Van Verth47d9ee42018-08-07 18:36:41 +0000609 return compute_intersection(this->fSegment, that.fSegment, &intersection, &s, &t);
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400610 }
611
Jim Van Verth00673692018-07-23 11:23:39 -0400612 bool lessThan(const ActiveEdge& that) const {
613 if (this->fSegment.fP0.fX > that.fSegment.fP0.fX ||
614 (this->fSegment.fP0.fX == that.fSegment.fP0.fX &&
615 this->fSegment.fP0.fY < that.fSegment.fP0.fY)) {
616 return !that.above(*this);
617 }
618 return this->above(that);
619 }
620
621 bool operator<(const ActiveEdge& that) const {
622 SkASSERT(!this->lessThan(*this));
623 SkASSERT(!that.lessThan(that));
624 SkASSERT(!(this->lessThan(that) && that.lessThan(*this)));
625 return this->lessThan(that);
626 }
627
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400628 OffsetSegment fSegment;
Jim Van Vertha6316832018-07-24 09:30:37 -0400629 uint16_t fIndex0; // indices for previous and next vertex
630 uint16_t fIndex1;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400631};
632
Jim Van Verth00673692018-07-23 11:23:39 -0400633class ActiveEdgeList {
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400634public:
Jim Van Vertha6316832018-07-24 09:30:37 -0400635 bool insert(const SkPoint& p0, const SkPoint& p1, uint16_t index0, uint16_t index1) {
Jim Van Verth00673692018-07-23 11:23:39 -0400636 std::pair<Iterator, bool> result = fEdgeTree.emplace(p0, p1, index0, index1);
637 if (!result.second) {
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400638 return false;
639 }
640
Jim Van Verth00673692018-07-23 11:23:39 -0400641 Iterator& curr = result.first;
642 if (curr != fEdgeTree.begin() && curr->intersect(*std::prev(curr))) {
643 return false;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400644 }
Jim Van Verth00673692018-07-23 11:23:39 -0400645 Iterator next = std::next(curr);
646 if (next != fEdgeTree.end() && curr->intersect(*next)) {
647 return false;
648 }
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400649
650 return true;
651 }
652
Jim Van Verth00673692018-07-23 11:23:39 -0400653 bool remove(const ActiveEdge& edge) {
654 auto element = fEdgeTree.find(edge);
655 // this better not happen
656 if (element == fEdgeTree.end()) {
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400657 return false;
658 }
Jim Van Verth00673692018-07-23 11:23:39 -0400659 if (element != fEdgeTree.begin() && element->intersect(*std::prev(element))) {
660 return false;
661 }
662 Iterator next = std::next(element);
663 if (next != fEdgeTree.end() && element->intersect(*next)) {
664 return false;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400665 }
666
Jim Van Verth00673692018-07-23 11:23:39 -0400667 fEdgeTree.erase(element);
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400668 return true;
669 }
670
671private:
Jim Van Verth00673692018-07-23 11:23:39 -0400672 std::set<ActiveEdge> fEdgeTree;
673 typedef std::set<ActiveEdge>::iterator Iterator;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400674};
675
676// Here we implement a sweep line algorithm to determine whether the provided points
677// represent a simple polygon, i.e., the polygon is non-self-intersecting.
678// We first insert the vertices into a priority queue sorting horizontally from left to right.
679// Then as we pop the vertices from the queue we generate events which indicate that an edge
680// should be added or removed from an edge list. If any intersections are detected in the edge
681// list, then we know the polygon is self-intersecting and hence not simple.
Jim Van Verth8664a1d2018-06-28 16:26:50 -0400682bool SkIsSimplePolygon(const SkPoint* polygon, int polygonSize) {
Jim Van Verth061cc212018-07-11 14:09:09 -0400683 if (polygonSize < 3) {
684 return false;
685 }
686
Jim Van Vertha6316832018-07-24 09:30:37 -0400687 // need to be able to represent all the vertices in the 16-bit indices
688 if (polygonSize >= (1 << 16)) {
689 return false;
690 }
691
Jim Van Verth00673692018-07-23 11:23:39 -0400692 SkTDPQueue <Vertex, Vertex::Left> vertexQueue(polygonSize);
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400693 for (int i = 0; i < polygonSize; ++i) {
694 Vertex newVertex;
Jim Van Verth061cc212018-07-11 14:09:09 -0400695 if (!polygon[i].isFinite()) {
696 return false;
697 }
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400698 newVertex.fPosition = polygon[i];
699 newVertex.fIndex = i;
700 newVertex.fPrevIndex = (i - 1 + polygonSize) % polygonSize;
701 newVertex.fNextIndex = (i + 1) % polygonSize;
702 newVertex.fFlags = 0;
703 if (left(polygon[newVertex.fPrevIndex], polygon[i])) {
704 newVertex.fFlags |= kPrevLeft_VertexFlag;
705 }
706 if (left(polygon[newVertex.fNextIndex], polygon[i])) {
707 newVertex.fFlags |= kNextLeft_VertexFlag;
708 }
709 vertexQueue.insert(newVertex);
710 }
711
712 // pop each vertex from the queue and generate events depending on
713 // where it lies relative to its neighboring edges
Jim Van Verth00673692018-07-23 11:23:39 -0400714 ActiveEdgeList sweepLine;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400715 while (vertexQueue.count() > 0) {
716 const Vertex& v = vertexQueue.peek();
717
718 // check edge to previous vertex
719 if (v.fFlags & kPrevLeft_VertexFlag) {
Jim Van Verth00673692018-07-23 11:23:39 -0400720 ActiveEdge edge(polygon[v.fPrevIndex], v.fPosition, v.fPrevIndex, v.fIndex);
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400721 if (!sweepLine.remove(edge)) {
722 break;
723 }
724 } else {
Jim Van Verth00673692018-07-23 11:23:39 -0400725 if (!sweepLine.insert(v.fPosition, polygon[v.fPrevIndex], v.fIndex, v.fPrevIndex)) {
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400726 break;
727 }
728 }
729
730 // check edge to next vertex
731 if (v.fFlags & kNextLeft_VertexFlag) {
Jim Van Verth00673692018-07-23 11:23:39 -0400732 ActiveEdge edge(polygon[v.fNextIndex], v.fPosition, v.fNextIndex, v.fIndex);
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400733 if (!sweepLine.remove(edge)) {
734 break;
735 }
736 } else {
Jim Van Verth00673692018-07-23 11:23:39 -0400737 if (!sweepLine.insert(v.fPosition, polygon[v.fNextIndex], v.fIndex, v.fNextIndex)) {
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400738 break;
739 }
740 }
741
742 vertexQueue.pop();
743 }
744
745 return (vertexQueue.count() == 0);
746}
747
Jim Van Verth8664a1d2018-06-28 16:26:50 -0400748///////////////////////////////////////////////////////////////////////////////////////////
749
Jim Van Verth00673692018-07-23 11:23:39 -0400750// helper function for SkOffsetSimplePolygon
751static void setup_offset_edge(OffsetEdge* currEdge,
752 const SkPoint& endpoint0, const SkPoint& endpoint1,
Jim Van Vertheddb3d92018-08-02 10:56:26 -0400753 uint16_t startIndex, uint16_t endIndex) {
Jim Van Verth00673692018-07-23 11:23:39 -0400754 currEdge->fInset.fP0 = endpoint0;
Jim Van Vertha6316832018-07-24 09:30:37 -0400755 currEdge->fInset.fV = endpoint1 - endpoint0;
Jim Van Verth00673692018-07-23 11:23:39 -0400756 currEdge->init(startIndex, endIndex);
757}
758
Jim Van Verth98d33752018-08-03 15:59:46 -0400759static bool is_reflex_vertex(const SkPoint* inputPolygonVerts, int winding, SkScalar offset,
760 uint16_t prevIndex, uint16_t currIndex, uint16_t nextIndex) {
761 int side = compute_side(inputPolygonVerts[prevIndex],
762 inputPolygonVerts[currIndex] - inputPolygonVerts[prevIndex],
763 inputPolygonVerts[nextIndex]);
764 // if reflex point, we need to add extra edges
765 return (side*winding*offset < 0);
766}
767
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400768bool SkOffsetSimplePolygon(const SkPoint* inputPolygonVerts, int inputPolygonSize,
Jim Van Verthbdde4282018-06-14 09:09:18 -0400769 std::function<SkScalar(const SkPoint&)> offsetDistanceFunc,
770 SkTDArray<SkPoint>* offsetPolygon, SkTDArray<int>* polygonIndices) {
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400771 if (inputPolygonSize < 3) {
772 return false;
773 }
774
Jim Van Vertha6316832018-07-24 09:30:37 -0400775 // need to be able to represent all the vertices in the 16-bit indices
776 if (inputPolygonSize >= (1 << 16)) {
777 return false;
778 }
779
Jim Van Verth8664a1d2018-06-28 16:26:50 -0400780 // get winding direction
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400781 int winding = SkGetPolygonWinding(inputPolygonVerts, inputPolygonSize);
Jim Van Verth8664a1d2018-06-28 16:26:50 -0400782 if (0 == winding) {
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400783 return false;
784 }
785
Jim Van Verthbdde4282018-06-14 09:09:18 -0400786 // build normals
787 SkAutoSTMalloc<64, SkVector> normal0(inputPolygonSize);
788 SkAutoSTMalloc<64, SkVector> normal1(inputPolygonSize);
Jim Van Verth66c5dc52018-08-06 14:38:31 -0400789 SkAutoSTMalloc<64, SkScalar> offset(inputPolygonSize);
790 SkScalar currOffset = offsetDistanceFunc(inputPolygonVerts[0]);
Jim Van Verth061cc212018-07-11 14:09:09 -0400791 if (!SkScalarIsFinite(currOffset)) {
792 return false;
793 }
Jim Van Verth66c5dc52018-08-06 14:38:31 -0400794 offset[0] = currOffset;
Jim Van Verth98d33752018-08-03 15:59:46 -0400795 int numEdges = 0;
796 for (int currIndex = 0, prevIndex = inputPolygonSize - 1;
797 currIndex < inputPolygonSize;
798 prevIndex = currIndex, ++currIndex) {
799 if (!inputPolygonVerts[currIndex].isFinite()) {
Jim Van Verth061cc212018-07-11 14:09:09 -0400800 return false;
801 }
Jim Van Verth98d33752018-08-03 15:59:46 -0400802 int nextIndex = (currIndex + 1) % inputPolygonSize;
803 SkScalar nextOffset = offsetDistanceFunc(inputPolygonVerts[nextIndex]);
Jim Van Verth061cc212018-07-11 14:09:09 -0400804 if (!SkScalarIsFinite(nextOffset)) {
805 return false;
806 }
Jim Van Verth66c5dc52018-08-06 14:38:31 -0400807 offset[nextIndex] = nextOffset;
Jim Van Verth98d33752018-08-03 15:59:46 -0400808 if (!compute_offset_vectors(inputPolygonVerts[currIndex], inputPolygonVerts[nextIndex],
Jim Van Verthbdde4282018-06-14 09:09:18 -0400809 currOffset, nextOffset, winding,
Jim Van Verth98d33752018-08-03 15:59:46 -0400810 &normal0[currIndex], &normal1[nextIndex])) {
Jim Van Verthbdde4282018-06-14 09:09:18 -0400811 return false;
812 }
Jim Van Verth98d33752018-08-03 15:59:46 -0400813 if (currIndex > 0) {
814 // if reflex point, we need to add extra edges
Jim Van Verth66c5dc52018-08-06 14:38:31 -0400815 if (is_reflex_vertex(inputPolygonVerts, winding, currOffset,
Jim Van Verth98d33752018-08-03 15:59:46 -0400816 prevIndex, currIndex, nextIndex)) {
817 SkScalar rotSin, rotCos;
818 int numSteps;
Jim Van Verth66c5dc52018-08-06 14:38:31 -0400819 if (!SkComputeRadialSteps(normal1[currIndex], normal0[currIndex], currOffset,
Jim Van Verth98d33752018-08-03 15:59:46 -0400820 &rotSin, &rotCos, &numSteps)) {
821 return false;
822 }
823 numEdges += SkTMax(numSteps, 1);
824 }
825 }
826 numEdges++;
Jim Van Verthbdde4282018-06-14 09:09:18 -0400827 currOffset = nextOffset;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400828 }
Jim Van Verth98d33752018-08-03 15:59:46 -0400829 // finish up the edge counting
Jim Van Verth66c5dc52018-08-06 14:38:31 -0400830 if (is_reflex_vertex(inputPolygonVerts, winding, currOffset, inputPolygonSize-1, 0, 1)) {
Jim Van Verth98d33752018-08-03 15:59:46 -0400831 SkScalar rotSin, rotCos;
832 int numSteps;
833 if (!SkComputeRadialSteps(normal1[0], normal0[0], currOffset,
834 &rotSin, &rotCos, &numSteps)) {
835 return false;
836 }
837 numEdges += SkTMax(numSteps, 1);
838 }
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400839
840 // build initial offset edge list
Jim Van Verth98d33752018-08-03 15:59:46 -0400841 SkSTArray<64, OffsetEdge> edgeData(numEdges);
842 OffsetEdge* prevEdge = nullptr;
843 for (int currIndex = 0, prevIndex = inputPolygonSize - 1;
844 currIndex < inputPolygonSize;
845 prevIndex = currIndex, ++currIndex) {
846 int nextIndex = (currIndex + 1) % inputPolygonSize;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400847 // if reflex point, fill in curve
Jim Van Verth66c5dc52018-08-06 14:38:31 -0400848 if (is_reflex_vertex(inputPolygonVerts, winding, offset[currIndex],
Jim Van Verth98d33752018-08-03 15:59:46 -0400849 prevIndex, currIndex, nextIndex)) {
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400850 SkScalar rotSin, rotCos;
851 int numSteps;
Jim Van Verthbdde4282018-06-14 09:09:18 -0400852 SkVector prevNormal = normal1[currIndex];
Jim Van Verth66c5dc52018-08-06 14:38:31 -0400853 if (!SkComputeRadialSteps(prevNormal, normal0[currIndex], offset[currIndex],
Jim Van Verth061cc212018-07-11 14:09:09 -0400854 &rotSin, &rotCos, &numSteps)) {
855 return false;
856 }
Jim Van Verth00673692018-07-23 11:23:39 -0400857 auto currEdge = edgeData.push_back_n(SkTMax(numSteps, 1));
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400858 for (int i = 0; i < numSteps - 1; ++i) {
859 SkVector currNormal = SkVector::Make(prevNormal.fX*rotCos - prevNormal.fY*rotSin,
860 prevNormal.fY*rotCos + prevNormal.fX*rotSin);
Jim Van Verth00673692018-07-23 11:23:39 -0400861 setup_offset_edge(currEdge,
862 inputPolygonVerts[currIndex] + prevNormal,
863 inputPolygonVerts[currIndex] + currNormal,
864 currIndex, currIndex);
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400865 prevNormal = currNormal;
Jim Van Verth98d33752018-08-03 15:59:46 -0400866 currEdge->fPrev = prevEdge;
867 if (prevEdge) {
868 prevEdge->fNext = currEdge;
869 }
870 prevEdge = currEdge;
Jim Van Verth00673692018-07-23 11:23:39 -0400871 ++currEdge;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400872 }
Jim Van Verth00673692018-07-23 11:23:39 -0400873 setup_offset_edge(currEdge,
874 inputPolygonVerts[currIndex] + prevNormal,
875 inputPolygonVerts[currIndex] + normal0[currIndex],
876 currIndex, currIndex);
Jim Van Verth98d33752018-08-03 15:59:46 -0400877 currEdge->fPrev = prevEdge;
878 if (prevEdge) {
879 prevEdge->fNext = currEdge;
880 }
881 prevEdge = currEdge;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400882 }
883
884 // Add the edge
Jim Van Verth98d33752018-08-03 15:59:46 -0400885 auto currEdge = edgeData.push_back_n(1);
886 setup_offset_edge(currEdge,
Jim Van Verth00673692018-07-23 11:23:39 -0400887 inputPolygonVerts[currIndex] + normal0[currIndex],
888 inputPolygonVerts[nextIndex] + normal1[nextIndex],
889 currIndex, nextIndex);
Jim Van Verth98d33752018-08-03 15:59:46 -0400890 currEdge->fPrev = prevEdge;
891 if (prevEdge) {
892 prevEdge->fNext = currEdge;
893 }
894 prevEdge = currEdge;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400895 }
Jim Van Verth98d33752018-08-03 15:59:46 -0400896 // close up the linked list
897 SkASSERT(prevEdge);
898 prevEdge->fNext = &edgeData[0];
899 edgeData[0].fPrev = prevEdge;
Jim Van Verth00673692018-07-23 11:23:39 -0400900
901 // now clip edges
Jim Van Verth98d33752018-08-03 15:59:46 -0400902 SkASSERT(edgeData.count() == numEdges);
Jim Van Verth00673692018-07-23 11:23:39 -0400903 auto head = &edgeData[0];
904 auto currEdge = head;
Jim Van Verth98d33752018-08-03 15:59:46 -0400905 int offsetVertexCount = numEdges;
Jim Van Verth3645bb02018-06-26 14:58:58 -0400906 int iterations = 0;
Jim Van Verth00673692018-07-23 11:23:39 -0400907 while (head && prevEdge != currEdge) {
Jim Van Verth3645bb02018-06-26 14:58:58 -0400908 ++iterations;
909 // we should check each edge against each other edge at most once
Jim Van Verth98d33752018-08-03 15:59:46 -0400910 if (iterations > numEdges*numEdges) {
Jim Van Verth3645bb02018-06-26 14:58:58 -0400911 return false;
912 }
913
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400914 SkScalar s, t;
915 SkPoint intersection;
Jim Van Vertha6316832018-07-24 09:30:37 -0400916 if (prevEdge->checkIntersection(currEdge, &intersection, &s, &t)) {
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400917 // if new intersection is further back on previous inset from the prior intersection
Jim Van Verth00673692018-07-23 11:23:39 -0400918 if (s < prevEdge->fTValue) {
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400919 // no point in considering this one again
Jim Van Verth00673692018-07-23 11:23:39 -0400920 remove_node(prevEdge, &head);
921 --offsetVertexCount;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400922 // go back one segment
Jim Van Verth00673692018-07-23 11:23:39 -0400923 prevEdge = prevEdge->fPrev;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400924 // we've already considered this intersection, we're done
Jim Van Verth00673692018-07-23 11:23:39 -0400925 } else if (currEdge->fTValue > SK_ScalarMin &&
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400926 SkPointPriv::EqualsWithinTolerance(intersection,
Jim Van Verth00673692018-07-23 11:23:39 -0400927 currEdge->fIntersection,
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400928 1.0e-6f)) {
929 break;
930 } else {
931 // add intersection
Jim Van Verth00673692018-07-23 11:23:39 -0400932 currEdge->fIntersection = intersection;
933 currEdge->fTValue = t;
934 currEdge->fIndex = prevEdge->fEnd;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400935
936 // go to next segment
Jim Van Verth00673692018-07-23 11:23:39 -0400937 prevEdge = currEdge;
938 currEdge = currEdge->fNext;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400939 }
940 } else {
941 // If there is no intersection, we want to minimize the distance between
942 // the point where the segment lines cross and the segments themselves.
Jim Van Verth00673692018-07-23 11:23:39 -0400943 OffsetEdge* prevPrevEdge = prevEdge->fPrev;
944 OffsetEdge* currNextEdge = currEdge->fNext;
Jim Van Vertheddb3d92018-08-02 10:56:26 -0400945 SkScalar dist0 = currEdge->computeCrossingDistance(prevPrevEdge);
946 SkScalar dist1 = prevEdge->computeCrossingDistance(currNextEdge);
947 // if both lead to direct collision
948 if (dist0 < 0 && dist1 < 0) {
949 // check first to see if either represent parts of one contour
950 SkPoint p1 = prevPrevEdge->fInset.fP0 + prevPrevEdge->fInset.fV;
951 bool prevSameContour = SkPointPriv::EqualsWithinTolerance(p1,
952 prevEdge->fInset.fP0);
953 p1 = currEdge->fInset.fP0 + currEdge->fInset.fV;
954 bool currSameContour = SkPointPriv::EqualsWithinTolerance(p1,
955 currNextEdge->fInset.fP0);
956
957 // want to step along contour to find intersections rather than jump to new one
958 if (currSameContour && !prevSameContour) {
959 remove_node(currEdge, &head);
960 currEdge = currNextEdge;
961 --offsetVertexCount;
962 continue;
963 } else if (prevSameContour && !currSameContour) {
964 remove_node(prevEdge, &head);
965 prevEdge = prevPrevEdge;
966 --offsetVertexCount;
967 continue;
968 }
969 }
970
971 // otherwise minimize collision distance along segment
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400972 if (dist0 < dist1) {
Jim Van Verth00673692018-07-23 11:23:39 -0400973 remove_node(prevEdge, &head);
974 prevEdge = prevPrevEdge;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400975 } else {
Jim Van Verth00673692018-07-23 11:23:39 -0400976 remove_node(currEdge, &head);
977 currEdge = currNextEdge;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400978 }
Jim Van Verth00673692018-07-23 11:23:39 -0400979 --offsetVertexCount;
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400980 }
981 }
982
983 // store all the valid intersections that aren't nearly coincident
984 // TODO: look at the main algorithm and see if we can detect these better
Jim Van Verth4db18ed2018-04-03 10:00:37 -0400985 offsetPolygon->reset();
Jim Van Verth00673692018-07-23 11:23:39 -0400986 if (head) {
987 static constexpr SkScalar kCleanupTolerance = 0.01f;
988 if (offsetVertexCount >= 0) {
989 offsetPolygon->setReserve(offsetVertexCount);
Ben Wagnere9dd3162018-07-18 21:27:57 +0000990 }
Jim Van Verth00673692018-07-23 11:23:39 -0400991 int currIndex = 0;
992 OffsetEdge* currEdge = head;
993 *offsetPolygon->push() = currEdge->fIntersection;
Ben Wagnere9dd3162018-07-18 21:27:57 +0000994 if (polygonIndices) {
Jim Van Verth00673692018-07-23 11:23:39 -0400995 *polygonIndices->push() = currEdge->fIndex;
996 }
997 currEdge = currEdge->fNext;
998 while (currEdge != head) {
999 if (!SkPointPriv::EqualsWithinTolerance(currEdge->fIntersection,
1000 (*offsetPolygon)[currIndex],
1001 kCleanupTolerance)) {
1002 *offsetPolygon->push() = currEdge->fIntersection;
1003 if (polygonIndices) {
1004 *polygonIndices->push() = currEdge->fIndex;
1005 }
1006 currIndex++;
1007 }
1008 currEdge = currEdge->fNext;
1009 }
1010 // make sure the first and last points aren't coincident
1011 if (currIndex >= 1 &&
1012 SkPointPriv::EqualsWithinTolerance((*offsetPolygon)[0], (*offsetPolygon)[currIndex],
1013 kCleanupTolerance)) {
1014 offsetPolygon->pop();
1015 if (polygonIndices) {
1016 polygonIndices->pop();
1017 }
Jim Van Verth872da6b2018-04-10 11:24:11 -04001018 }
Jim Van Verth4db18ed2018-04-03 10:00:37 -04001019 }
1020
Jim Van Verth8664a1d2018-06-28 16:26:50 -04001021 // check winding of offset polygon (it should be same as the original polygon)
Jim Van Verth6784ffa2018-07-03 16:12:39 -04001022 SkScalar offsetWinding = SkGetPolygonWinding(offsetPolygon->begin(), offsetPolygon->count());
Jim Van Verth4db18ed2018-04-03 10:00:37 -04001023
Jim Van Verth8664a1d2018-06-28 16:26:50 -04001024 return (winding*offsetWinding > 0 &&
1025 SkIsSimplePolygon(offsetPolygon->begin(), offsetPolygon->count()));
Jim Van Verth4db18ed2018-04-03 10:00:37 -04001026}
1027
Jim Van Verth8664a1d2018-06-28 16:26:50 -04001028//////////////////////////////////////////////////////////////////////////////////////////
1029
1030struct TriangulationVertex {
1031 SK_DECLARE_INTERNAL_LLIST_INTERFACE(TriangulationVertex);
1032
1033 enum class VertexType { kConvex, kReflex };
1034
1035 SkPoint fPosition;
1036 VertexType fVertexType;
1037 uint16_t fIndex;
1038 uint16_t fPrevIndex;
1039 uint16_t fNextIndex;
1040};
1041
1042// test to see if point p is in triangle p0p1p2.
1043// for now assuming strictly inside -- if on the edge it's outside
1044static bool point_in_triangle(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
1045 const SkPoint& p) {
1046 SkVector v0 = p1 - p0;
1047 SkVector v1 = p2 - p1;
1048 SkScalar n = v0.cross(v1);
1049
1050 SkVector w0 = p - p0;
1051 if (n*v0.cross(w0) < SK_ScalarNearlyZero) {
1052 return false;
1053 }
1054
1055 SkVector w1 = p - p1;
1056 if (n*v1.cross(w1) < SK_ScalarNearlyZero) {
1057 return false;
1058 }
1059
1060 SkVector v2 = p0 - p2;
1061 SkVector w2 = p - p2;
1062 if (n*v2.cross(w2) < SK_ScalarNearlyZero) {
1063 return false;
1064 }
1065
1066 return true;
1067}
1068
1069// Data structure to track reflex vertices and check whether any are inside a given triangle
1070class ReflexHash {
1071public:
1072 void add(TriangulationVertex* v) {
1073 fReflexList.addToTail(v);
1074 }
1075
1076 void remove(TriangulationVertex* v) {
1077 fReflexList.remove(v);
1078 }
1079
Jim Van Verth061cc212018-07-11 14:09:09 -04001080 bool checkTriangle(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
1081 uint16_t ignoreIndex0, uint16_t ignoreIndex1) {
Jim Van Verth8664a1d2018-06-28 16:26:50 -04001082 for (SkTInternalLList<TriangulationVertex>::Iter reflexIter = fReflexList.begin();
1083 reflexIter != fReflexList.end(); ++reflexIter) {
1084 TriangulationVertex* reflexVertex = *reflexIter;
Jim Van Verth061cc212018-07-11 14:09:09 -04001085 if (reflexVertex->fIndex != ignoreIndex0 && reflexVertex->fIndex != ignoreIndex1 &&
1086 point_in_triangle(p0, p1, p2, reflexVertex->fPosition)) {
Jim Van Verth8664a1d2018-06-28 16:26:50 -04001087 return true;
1088 }
1089 }
1090
1091 return false;
1092 }
1093
1094private:
1095 // TODO: switch to an actual spatial hash
1096 SkTInternalLList<TriangulationVertex> fReflexList;
1097};
1098
1099// Check to see if a reflex vertex has become a convex vertex after clipping an ear
1100static void reclassify_vertex(TriangulationVertex* p, const SkPoint* polygonVerts,
1101 int winding, ReflexHash* reflexHash,
1102 SkTInternalLList<TriangulationVertex>* convexList) {
1103 if (TriangulationVertex::VertexType::kReflex == p->fVertexType) {
1104 SkVector v0 = p->fPosition - polygonVerts[p->fPrevIndex];
1105 SkVector v1 = polygonVerts[p->fNextIndex] - p->fPosition;
Jim Van Verth061cc212018-07-11 14:09:09 -04001106 if (winding*v0.cross(v1) > SK_ScalarNearlyZero*SK_ScalarNearlyZero) {
Jim Van Verth8664a1d2018-06-28 16:26:50 -04001107 p->fVertexType = TriangulationVertex::VertexType::kConvex;
1108 reflexHash->remove(p);
1109 p->fPrev = p->fNext = nullptr;
1110 convexList->addToTail(p);
1111 }
1112 }
1113}
1114
1115bool SkTriangulateSimplePolygon(const SkPoint* polygonVerts, uint16_t* indexMap, int polygonSize,
1116 SkTDArray<uint16_t>* triangleIndices) {
1117 if (polygonSize < 3) {
1118 return false;
1119 }
1120 // need to be able to represent all the vertices in the 16-bit indices
1121 if (polygonSize >= (1 << 16)) {
1122 return false;
1123 }
1124
1125 // get winding direction
1126 // TODO: we do this for all the polygon routines -- might be better to have the client
1127 // compute it and pass it in
Jim Van Verth6784ffa2018-07-03 16:12:39 -04001128 int winding = SkGetPolygonWinding(polygonVerts, polygonSize);
Jim Van Verth8664a1d2018-06-28 16:26:50 -04001129 if (0 == winding) {
1130 return false;
1131 }
1132
1133 // Classify initial vertices into a list of convex vertices and a hash of reflex vertices
1134 // TODO: possibly sort the convexList in some way to get better triangles
1135 SkTInternalLList<TriangulationVertex> convexList;
1136 ReflexHash reflexHash;
1137 SkAutoSTMalloc<64, TriangulationVertex> triangulationVertices(polygonSize);
1138 int prevIndex = polygonSize - 1;
1139 int currIndex = 0;
1140 int nextIndex = 1;
1141 SkVector v0 = polygonVerts[currIndex] - polygonVerts[prevIndex];
1142 SkVector v1 = polygonVerts[nextIndex] - polygonVerts[currIndex];
1143 for (int i = 0; i < polygonSize; ++i) {
1144 SkDEBUGCODE(memset(&triangulationVertices[currIndex], 0, sizeof(TriangulationVertex)));
1145 triangulationVertices[currIndex].fPosition = polygonVerts[currIndex];
1146 triangulationVertices[currIndex].fIndex = currIndex;
1147 triangulationVertices[currIndex].fPrevIndex = prevIndex;
1148 triangulationVertices[currIndex].fNextIndex = nextIndex;
Jim Van Verth061cc212018-07-11 14:09:09 -04001149 if (winding*v0.cross(v1) > SK_ScalarNearlyZero*SK_ScalarNearlyZero) {
Jim Van Verth8664a1d2018-06-28 16:26:50 -04001150 triangulationVertices[currIndex].fVertexType = TriangulationVertex::VertexType::kConvex;
1151 convexList.addToTail(&triangulationVertices[currIndex]);
1152 } else {
1153 // We treat near collinear vertices as reflex
1154 triangulationVertices[currIndex].fVertexType = TriangulationVertex::VertexType::kReflex;
1155 reflexHash.add(&triangulationVertices[currIndex]);
1156 }
1157
1158 prevIndex = currIndex;
1159 currIndex = nextIndex;
1160 nextIndex = (currIndex + 1) % polygonSize;
1161 v0 = v1;
1162 v1 = polygonVerts[nextIndex] - polygonVerts[currIndex];
1163 }
1164
1165 // The general concept: We are trying to find three neighboring vertices where
1166 // no other vertex lies inside the triangle (an "ear"). If we find one, we clip
1167 // that ear off, and then repeat on the new polygon. Once we get down to three vertices
1168 // we have triangulated the entire polygon.
1169 // In the worst case this is an n^2 algorithm. We can cut down the search space somewhat by
1170 // noting that only convex vertices can be potential ears, and we only need to check whether
1171 // any reflex vertices lie inside the ear.
1172 triangleIndices->setReserve(triangleIndices->count() + 3 * (polygonSize - 2));
1173 int vertexCount = polygonSize;
1174 while (vertexCount > 3) {
1175 bool success = false;
1176 TriangulationVertex* earVertex = nullptr;
1177 TriangulationVertex* p0 = nullptr;
1178 TriangulationVertex* p2 = nullptr;
1179 // find a convex vertex to clip
1180 for (SkTInternalLList<TriangulationVertex>::Iter convexIter = convexList.begin();
1181 convexIter != convexList.end(); ++convexIter) {
1182 earVertex = *convexIter;
1183 SkASSERT(TriangulationVertex::VertexType::kReflex != earVertex->fVertexType);
1184
1185 p0 = &triangulationVertices[earVertex->fPrevIndex];
1186 p2 = &triangulationVertices[earVertex->fNextIndex];
1187
1188 // see if any reflex vertices are inside the ear
1189 bool failed = reflexHash.checkTriangle(p0->fPosition, earVertex->fPosition,
Jim Van Verth061cc212018-07-11 14:09:09 -04001190 p2->fPosition, p0->fIndex, p2->fIndex);
Jim Van Verth8664a1d2018-06-28 16:26:50 -04001191 if (failed) {
1192 continue;
1193 }
1194
1195 // found one we can clip
1196 success = true;
1197 break;
1198 }
1199 // If we can't find any ears to clip, this probably isn't a simple polygon
1200 if (!success) {
1201 return false;
1202 }
1203
1204 // add indices
1205 auto indices = triangleIndices->append(3);
1206 indices[0] = indexMap[p0->fIndex];
1207 indices[1] = indexMap[earVertex->fIndex];
1208 indices[2] = indexMap[p2->fIndex];
1209
1210 // clip the ear
1211 convexList.remove(earVertex);
1212 --vertexCount;
1213
1214 // reclassify reflex verts
1215 p0->fNextIndex = earVertex->fNextIndex;
1216 reclassify_vertex(p0, polygonVerts, winding, &reflexHash, &convexList);
1217
1218 p2->fPrevIndex = earVertex->fPrevIndex;
1219 reclassify_vertex(p2, polygonVerts, winding, &reflexHash, &convexList);
1220 }
1221
1222 // output indices
1223 for (SkTInternalLList<TriangulationVertex>::Iter vertexIter = convexList.begin();
1224 vertexIter != convexList.end(); ++vertexIter) {
1225 TriangulationVertex* vertex = *vertexIter;
1226 *triangleIndices->push() = indexMap[vertex->fIndex];
1227 }
1228
1229 return true;
1230}