blob: 0060db2f30d3084930dae9a5836da4f452f7f59e [file] [log] [blame]
caryclark@google.com07393ca2013-04-08 11:47:37 +00001/*
2 * Copyright 2012 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 */
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +00007#include "SkAddIntersections.h"
caryclark54359292015-03-26 07:52:43 -07008#include "SkOpCoincidence.h"
caryclark@google.com07393ca2013-04-08 11:47:37 +00009#include "SkOpEdgeBuilder.h"
10#include "SkPathOpsCommon.h"
11#include "SkPathWriter.h"
commit-bot@chromium.orgb76d3b62013-04-22 19:55:19 +000012#include "SkTSort.h"
caryclark@google.com07393ca2013-04-08 11:47:37 +000013
caryclarkbca19f72015-05-13 08:23:48 -070014const SkOpAngle* AngleWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* windingPtr,
15 bool* sortablePtr) {
16 // find first angle, initialize winding to computed fWindSum
17 SkOpSegment* segment = start->segment();
18 const SkOpAngle* angle = segment->spanToAngle(start, end);
19 if (!angle) {
20 *windingPtr = SK_MinS32;
halcanary96fcdcc2015-08-27 07:41:13 -070021 return nullptr;
caryclarkbca19f72015-05-13 08:23:48 -070022 }
23 bool computeWinding = false;
24 const SkOpAngle* firstAngle = angle;
25 bool loop = false;
26 bool unorderable = false;
27 int winding = SK_MinS32;
28 do {
29 angle = angle->next();
30 unorderable |= angle->unorderable();
31 if ((computeWinding = unorderable || (angle == firstAngle && loop))) {
32 break; // if we get here, there's no winding, loop is unorderable
33 }
34 loop |= angle == firstAngle;
35 segment = angle->segment();
36 winding = segment->windSum(angle);
37 } while (winding == SK_MinS32);
38 // if the angle loop contains an unorderable span, the angle order may be useless
39 // directly compute the winding in this case for each span
40 if (computeWinding) {
41 firstAngle = angle;
42 winding = SK_MinS32;
43 do {
44 SkOpSpanBase* startSpan = angle->start();
45 SkOpSpanBase* endSpan = angle->end();
46 SkOpSpan* lesser = startSpan->starter(endSpan);
47 int testWinding = lesser->windSum();
48 if (testWinding == SK_MinS32) {
49 testWinding = lesser->computeWindSum();
50 }
51 if (testWinding != SK_MinS32) {
52 segment = angle->segment();
53 winding = testWinding;
54 }
55 angle = angle->next();
56 } while (angle != firstAngle);
57 }
58 *sortablePtr = !unorderable;
59 *windingPtr = winding;
60 return angle;
61}
62
caryclark624637c2015-05-11 07:21:27 -070063SkOpSegment* FindUndone(SkOpContourHead* contourList, SkOpSpanBase** startPtr,
caryclark54359292015-03-26 07:52:43 -070064 SkOpSpanBase** endPtr) {
caryclark@google.com07393ca2013-04-08 11:47:37 +000065 SkOpSegment* result;
caryclark624637c2015-05-11 07:21:27 -070066 SkOpContour* contour = contourList;
67 do {
caryclark54359292015-03-26 07:52:43 -070068 result = contour->undoneSegment(startPtr, endPtr);
caryclark@google.com07393ca2013-04-08 11:47:37 +000069 if (result) {
70 return result;
71 }
caryclark624637c2015-05-11 07:21:27 -070072 } while ((contour = contour->next()));
halcanary96fcdcc2015-08-27 07:41:13 -070073 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +000074}
75
caryclark54359292015-03-26 07:52:43 -070076SkOpSegment* FindChase(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** startPtr,
77 SkOpSpanBase** endPtr) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000078 while (chase->count()) {
caryclark54359292015-03-26 07:52:43 -070079 SkOpSpanBase* span;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000080 chase->pop(&span);
caryclark54359292015-03-26 07:52:43 -070081 SkOpSegment* segment = span->segment();
82 *startPtr = span->ptT()->next()->span();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000083 bool done = true;
halcanary96fcdcc2015-08-27 07:41:13 -070084 *endPtr = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -070085 if (SkOpAngle* last = segment->activeAngle(*startPtr, startPtr, endPtr, &done)) {
caryclark54359292015-03-26 07:52:43 -070086 *startPtr = last->start();
87 *endPtr = last->end();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000088 #if TRY_ROTATE
89 *chase->insert(0) = span;
90 #else
91 *chase->append() = span;
92 #endif
caryclark@google.com07393ca2013-04-08 11:47:37 +000093 return last->segment();
94 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000095 if (done) {
caryclark@google.com07393ca2013-04-08 11:47:37 +000096 continue;
97 }
caryclark65f55312014-11-13 06:58:52 -080098 // find first angle, initialize winding to computed wind sum
caryclarkbca19f72015-05-13 08:23:48 -070099 int winding;
100 bool sortable;
101 const SkOpAngle* angle = AngleWinding(*startPtr, *endPtr, &winding, &sortable);
caryclark54359292015-03-26 07:52:43 -0700102 if (winding == SK_MinS32) {
103 continue;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000104 }
caryclarkbca19f72015-05-13 08:23:48 -0700105 int sumWinding SK_INIT_TO_AVOID_WARNING;
106 if (sortable) {
107 segment = angle->segment();
108 sumWinding = segment->updateWindingReverse(angle);
109 }
halcanary96fcdcc2015-08-27 07:41:13 -0700110 SkOpSegment* first = nullptr;
caryclarkbca19f72015-05-13 08:23:48 -0700111 const SkOpAngle* firstAngle = angle;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000112 while ((angle = angle->next()) != firstAngle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000113 segment = angle->segment();
caryclark54359292015-03-26 07:52:43 -0700114 SkOpSpanBase* start = angle->start();
115 SkOpSpanBase* end = angle->end();
116 int maxWinding;
caryclarkbca19f72015-05-13 08:23:48 -0700117 if (sortable) {
118 segment->setUpWinding(start, end, &maxWinding, &sumWinding);
119 }
caryclark54359292015-03-26 07:52:43 -0700120 if (!segment->done(angle)) {
caryclarkbca19f72015-05-13 08:23:48 -0700121 if (!first && (sortable || start->starter(end)->windSum() != SK_MinS32)) {
caryclark54359292015-03-26 07:52:43 -0700122 first = segment;
123 *startPtr = start;
124 *endPtr = end;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000125 }
caryclark54359292015-03-26 07:52:43 -0700126 // OPTIMIZATION: should this also add to the chase?
caryclarkbca19f72015-05-13 08:23:48 -0700127 if (sortable) {
128 (void) segment->markAngle(maxWinding, sumWinding, angle);
129 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000130 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000131 }
caryclark54359292015-03-26 07:52:43 -0700132 if (first) {
133 #if TRY_ROTATE
134 *chase->insert(0) = span;
135 #else
136 *chase->append() = span;
137 #endif
138 return first;
139 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000140 }
halcanary96fcdcc2015-08-27 07:41:13 -0700141 return nullptr;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000142}
143
caryclark54359292015-03-26 07:52:43 -0700144#if DEBUG_ACTIVE_SPANS
caryclark624637c2015-05-11 07:21:27 -0700145void DebugShowActiveSpans(SkOpContourHead* contourList) {
146 SkOpContour* contour = contourList;
147 do {
148 contour->debugShowActiveSpans();
149 } while ((contour = contour->next()));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000150}
151#endif
152
caryclark624637c2015-05-11 07:21:27 -0700153bool SortContourList(SkOpContourHead** contourList, bool evenOdd, bool oppEvenOdd) {
154 SkTDArray<SkOpContour* > list;
155 SkOpContour* contour = *contourList;
caryclark54359292015-03-26 07:52:43 -0700156 do {
157 if (contour->count()) {
158 contour->setOppXor(contour->operand() ? evenOdd : oppEvenOdd);
159 *list.append() = contour;
160 }
161 } while ((contour = contour->next()));
caryclark624637c2015-05-11 07:21:27 -0700162 int count = list.count();
163 if (!count) {
164 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000165 }
caryclark624637c2015-05-11 07:21:27 -0700166 if (count > 1) {
167 SkTQSort<SkOpContour>(list.begin(), list.end() - 1);
168 }
169 contour = list[0];
170 SkOpContourHead* contourHead = static_cast<SkOpContourHead*>(contour);
171 contour->globalState()->setContourHead(contourHead);
172 *contourList = contourHead;
173 for (int index = 1; index < count; ++index) {
174 SkOpContour* next = list[index];
175 contour->setNext(next);
176 contour = next;
177 }
halcanary96fcdcc2015-08-27 07:41:13 -0700178 contour->setNext(nullptr);
caryclark624637c2015-05-11 07:21:27 -0700179 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000180}
181
commit-bot@chromium.orgb76d3b62013-04-22 19:55:19 +0000182class DistanceLessThan {
183public:
184 DistanceLessThan(double* distances) : fDistances(distances) { }
185 double* fDistances;
186 bool operator()(const int one, const int two) {
187 return fDistances[one] < fDistances[two];
188 }
189};
190
caryclark@google.com07393ca2013-04-08 11:47:37 +0000191 /*
192 check start and end of each contour
193 if not the same, record them
194 match them up
195 connect closest
196 reassemble contour pieces into new path
197 */
198void Assemble(const SkPathWriter& path, SkPathWriter* simple) {
caryclark54359292015-03-26 07:52:43 -0700199 SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune
caryclark624637c2015-05-11 07:21:27 -0700200 SkOpContourHead contour;
halcanary96fcdcc2015-08-27 07:41:13 -0700201 SkOpGlobalState globalState(nullptr, &contour SkDEBUGPARAMS(nullptr));
caryclark03b03ca2015-04-23 09:13:37 -0700202#if DEBUG_SHOW_TEST_NAME
203 SkDebugf("</div>\n");
204#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000205#if DEBUG_PATH_CONSTRUCTION
206 SkDebugf("%s\n", __FUNCTION__);
207#endif
caryclark54359292015-03-26 07:52:43 -0700208 SkOpEdgeBuilder builder(path, &contour, &allocator, &globalState);
209 builder.finish(&allocator);
210 SkTDArray<const SkOpContour* > runs; // indices of partial contours
211 const SkOpContour* eContour = builder.head();
212 do {
213 if (!eContour->count()) {
214 continue;
215 }
216 const SkPoint& eStart = eContour->start();
217 const SkPoint& eEnd = eContour->end();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000218#if DEBUG_ASSEMBLE
219 SkDebugf("%s contour", __FUNCTION__);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000220 if (!SkDPoint::ApproximatelyEqual(eStart, eEnd)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000221 SkDebugf("[%d]", runs.count());
222 } else {
223 SkDebugf(" ");
224 }
225 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n",
226 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY);
227#endif
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000228 if (SkDPoint::ApproximatelyEqual(eStart, eEnd)) {
caryclark54359292015-03-26 07:52:43 -0700229 eContour->toPath(simple);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000230 continue;
231 }
caryclark54359292015-03-26 07:52:43 -0700232 *runs.append() = eContour;
233 } while ((eContour = eContour->next()));
234 int count = runs.count();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000235 if (count == 0) {
236 return;
237 }
caryclark54359292015-03-26 07:52:43 -0700238 SkTDArray<int> sLink, eLink;
239 sLink.append(count);
240 eLink.append(count);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000241 int rIndex, iIndex;
242 for (rIndex = 0; rIndex < count; ++rIndex) {
243 sLink[rIndex] = eLink[rIndex] = SK_MaxS32;
244 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000245 const int ends = count * 2; // all starts and ends
246 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2
caryclark54359292015-03-26 07:52:43 -0700247 SkTDArray<double> distances;
248 distances.append(entries);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000249 for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
caryclark54359292015-03-26 07:52:43 -0700250 const SkOpContour* oContour = runs[rIndex >> 1];
251 const SkPoint& oPt = rIndex & 1 ? oContour->end() : oContour->start();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000252 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2)
253 * ends - rIndex - 1;
254 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) {
caryclark54359292015-03-26 07:52:43 -0700255 const SkOpContour* iContour = runs[iIndex >> 1];
256 const SkPoint& iPt = iIndex & 1 ? iContour->end() : iContour->start();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000257 double dx = iPt.fX - oPt.fX;
258 double dy = iPt.fY - oPt.fY;
259 double dist = dx * dx + dy * dy;
260 distances[row + iIndex] = dist; // oStart distance from iStart
261 }
262 }
caryclark54359292015-03-26 07:52:43 -0700263 SkTDArray<int> sortedDist;
264 sortedDist.append(entries);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000265 for (rIndex = 0; rIndex < entries; ++rIndex) {
266 sortedDist[rIndex] = rIndex;
267 }
commit-bot@chromium.orgb76d3b62013-04-22 19:55:19 +0000268 SkTQSort<int>(sortedDist.begin(), sortedDist.end() - 1, DistanceLessThan(distances.begin()));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000269 int remaining = count; // number of start/end pairs
270 for (rIndex = 0; rIndex < entries; ++rIndex) {
271 int pair = sortedDist[rIndex];
272 int row = pair / ends;
273 int col = pair - row * ends;
274 int thingOne = row < col ? row : ends - row - 2;
275 int ndxOne = thingOne >> 1;
276 bool endOne = thingOne & 1;
277 int* linkOne = endOne ? eLink.begin() : sLink.begin();
278 if (linkOne[ndxOne] != SK_MaxS32) {
279 continue;
280 }
281 int thingTwo = row < col ? col : ends - row + col - 1;
282 int ndxTwo = thingTwo >> 1;
283 bool endTwo = thingTwo & 1;
284 int* linkTwo = endTwo ? eLink.begin() : sLink.begin();
285 if (linkTwo[ndxTwo] != SK_MaxS32) {
286 continue;
287 }
288 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]);
289 bool flip = endOne == endTwo;
290 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo;
291 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne;
292 if (!--remaining) {
293 break;
294 }
295 }
296 SkASSERT(!remaining);
297#if DEBUG_ASSEMBLE
298 for (rIndex = 0; rIndex < count; ++rIndex) {
299 int s = sLink[rIndex];
300 int e = eLink[rIndex];
301 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e',
302 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e);
303 }
304#endif
305 rIndex = 0;
306 do {
307 bool forward = true;
308 bool first = true;
309 int sIndex = sLink[rIndex];
310 SkASSERT(sIndex != SK_MaxS32);
311 sLink[rIndex] = SK_MaxS32;
312 int eIndex;
313 if (sIndex < 0) {
314 eIndex = sLink[~sIndex];
315 sLink[~sIndex] = SK_MaxS32;
316 } else {
317 eIndex = eLink[sIndex];
318 eLink[sIndex] = SK_MaxS32;
319 }
320 SkASSERT(eIndex != SK_MaxS32);
321#if DEBUG_ASSEMBLE
322 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e',
323 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e',
324 eIndex < 0 ? ~eIndex : eIndex);
325#endif
326 do {
caryclark54359292015-03-26 07:52:43 -0700327 const SkOpContour* contour = runs[rIndex];
caryclark@google.com07393ca2013-04-08 11:47:37 +0000328 if (first) {
329 first = false;
caryclark54359292015-03-26 07:52:43 -0700330 const SkPoint* startPtr = &contour->start();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000331 simple->deferredMove(startPtr[0]);
332 }
333 if (forward) {
caryclark54359292015-03-26 07:52:43 -0700334 contour->toPartialForward(simple);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000335 } else {
caryclark54359292015-03-26 07:52:43 -0700336 contour->toPartialBackward(simple);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000337 }
338#if DEBUG_ASSEMBLE
339 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex,
340 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex,
341 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex));
342#endif
343 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) {
344 simple->close();
345 break;
346 }
347 if (forward) {
348 eIndex = eLink[rIndex];
349 SkASSERT(eIndex != SK_MaxS32);
350 eLink[rIndex] = SK_MaxS32;
351 if (eIndex >= 0) {
352 SkASSERT(sLink[eIndex] == rIndex);
353 sLink[eIndex] = SK_MaxS32;
354 } else {
355 SkASSERT(eLink[~eIndex] == ~rIndex);
356 eLink[~eIndex] = SK_MaxS32;
357 }
358 } else {
359 eIndex = sLink[rIndex];
360 SkASSERT(eIndex != SK_MaxS32);
361 sLink[rIndex] = SK_MaxS32;
362 if (eIndex >= 0) {
363 SkASSERT(eLink[eIndex] == rIndex);
364 eLink[eIndex] = SK_MaxS32;
365 } else {
366 SkASSERT(sLink[~eIndex] == ~rIndex);
367 sLink[~eIndex] = SK_MaxS32;
368 }
369 }
370 rIndex = eIndex;
371 if (rIndex < 0) {
372 forward ^= 1;
373 rIndex = ~rIndex;
374 }
375 } while (true);
376 for (rIndex = 0; rIndex < count; ++rIndex) {
377 if (sLink[rIndex] != SK_MaxS32) {
378 break;
379 }
380 }
381 } while (rIndex < count);
382#if DEBUG_ASSEMBLE
383 for (rIndex = 0; rIndex < count; ++rIndex) {
384 SkASSERT(sLink[rIndex] == SK_MaxS32);
385 SkASSERT(eLink[rIndex] == SK_MaxS32);
386 }
387#endif
388}
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000389
caryclark624637c2015-05-11 07:21:27 -0700390static void align(SkOpContourHead* contourList) {
391 SkOpContour* contour = contourList;
392 do {
caryclark54359292015-03-26 07:52:43 -0700393 contour->align();
caryclark624637c2015-05-11 07:21:27 -0700394 } while ((contour = contour->next()));
caryclark54359292015-03-26 07:52:43 -0700395}
396
caryclark27c8eb82015-07-06 11:38:33 -0700397static void addAlignIntersections(SkOpContourHead* contourList, SkChunkAlloc* allocator) {
398 SkOpContour* contour = contourList;
399 do {
400 contour->addAlignIntersections(contourList, allocator);
401 } while ((contour = contour->next()));
402}
403
caryclark624637c2015-05-11 07:21:27 -0700404static void calcAngles(SkOpContourHead* contourList, SkChunkAlloc* allocator) {
405 SkOpContour* contour = contourList;
406 do {
caryclark54359292015-03-26 07:52:43 -0700407 contour->calcAngles(allocator);
caryclark624637c2015-05-11 07:21:27 -0700408 } while ((contour = contour->next()));
caryclark54359292015-03-26 07:52:43 -0700409}
410
caryclarkd4349722015-07-23 12:40:22 -0700411static void findCollapsed(SkOpContourHead* contourList) {
412 SkOpContour* contour = contourList;
413 do {
414 contour->findCollapsed();
415 } while ((contour = contour->next()));
416}
417
caryclark27c8eb82015-07-06 11:38:33 -0700418static bool missingCoincidence(SkOpContourHead* contourList,
caryclark54359292015-03-26 07:52:43 -0700419 SkOpCoincidence* coincidence, SkChunkAlloc* allocator) {
caryclark624637c2015-05-11 07:21:27 -0700420 SkOpContour* contour = contourList;
caryclark27c8eb82015-07-06 11:38:33 -0700421 bool result = false;
caryclark624637c2015-05-11 07:21:27 -0700422 do {
caryclark27c8eb82015-07-06 11:38:33 -0700423 result |= contour->missingCoincidence(coincidence, allocator);
caryclark624637c2015-05-11 07:21:27 -0700424 } while ((contour = contour->next()));
caryclark27c8eb82015-07-06 11:38:33 -0700425 return result;
caryclark54359292015-03-26 07:52:43 -0700426}
427
caryclark624637c2015-05-11 07:21:27 -0700428static void moveMultiples(SkOpContourHead* contourList) {
429 SkOpContour* contour = contourList;
430 do {
caryclark08bc8482015-04-24 09:08:57 -0700431 contour->moveMultiples();
caryclark624637c2015-05-11 07:21:27 -0700432 } while ((contour = contour->next()));
caryclark08bc8482015-04-24 09:08:57 -0700433}
434
caryclark624637c2015-05-11 07:21:27 -0700435static void moveNearby(SkOpContourHead* contourList) {
436 SkOpContour* contour = contourList;
437 do {
caryclark08bc8482015-04-24 09:08:57 -0700438 contour->moveNearby();
caryclark624637c2015-05-11 07:21:27 -0700439 } while ((contour = contour->next()));
caryclark54359292015-03-26 07:52:43 -0700440}
441
caryclark624637c2015-05-11 07:21:27 -0700442static void sortAngles(SkOpContourHead* contourList) {
443 SkOpContour* contour = contourList;
444 do {
caryclark54359292015-03-26 07:52:43 -0700445 contour->sortAngles();
caryclark624637c2015-05-11 07:21:27 -0700446 } while ((contour = contour->next()));
caryclark54359292015-03-26 07:52:43 -0700447}
448
caryclark624637c2015-05-11 07:21:27 -0700449bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidence,
450 SkChunkAlloc* allocator) {
451 SkOpGlobalState* globalState = contourList->globalState();
caryclark08bc8482015-04-24 09:08:57 -0700452 // combine t values when multiple intersections occur on some segments but not others
caryclark26ad22a2015-10-16 09:03:38 -0700453 DEBUG_COINCIDENCE_HEALTH(contourList, "start");
caryclark08bc8482015-04-24 09:08:57 -0700454 moveMultiples(contourList);
caryclark26ad22a2015-10-16 09:03:38 -0700455 DEBUG_COINCIDENCE_HEALTH(contourList, "moveMultiples");
caryclarkd4349722015-07-23 12:40:22 -0700456 findCollapsed(contourList);
caryclark26ad22a2015-10-16 09:03:38 -0700457 DEBUG_COINCIDENCE_HEALTH(contourList, "findCollapsed");
caryclark54359292015-03-26 07:52:43 -0700458 // move t values and points together to eliminate small/tiny gaps
caryclark08bc8482015-04-24 09:08:57 -0700459 moveNearby(contourList);
caryclark26ad22a2015-10-16 09:03:38 -0700460 DEBUG_COINCIDENCE_HEALTH(contourList, "moveNearby");
caryclark54359292015-03-26 07:52:43 -0700461 align(contourList); // give all span members common values
caryclark26ad22a2015-10-16 09:03:38 -0700462 DEBUG_COINCIDENCE_HEALTH(contourList, "align");
caryclark27c8eb82015-07-06 11:38:33 -0700463 coincidence->fixAligned(); // aligning may have marked a coincidence pt-t deleted
caryclark26ad22a2015-10-16 09:03:38 -0700464 DEBUG_COINCIDENCE_HEALTH(contourList, "fixAligned");
caryclark54359292015-03-26 07:52:43 -0700465#if DEBUG_VALIDATE
466 globalState->setPhase(SkOpGlobalState::kIntersecting);
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000467#endif
caryclark27c8eb82015-07-06 11:38:33 -0700468 // look for intersections on line segments formed by moving end points
469 addAlignIntersections(contourList, allocator);
caryclark26ad22a2015-10-16 09:03:38 -0700470 DEBUG_COINCIDENCE_HEALTH(contourList, "addAlignIntersections");
471 if (coincidence->addMissing(allocator)) {
472 DEBUG_COINCIDENCE_HEALTH(contourList, "addMissing");
473 moveNearby(contourList);
474 DEBUG_COINCIDENCE_HEALTH(contourList, "moveNearby2");
475 align(contourList); // give all span members common values
476 DEBUG_COINCIDENCE_HEALTH(contourList, "align2");
477 coincidence->fixAligned(); // aligning may have marked a coincidence pt-t deleted
478 DEBUG_COINCIDENCE_HEALTH(contourList, "fixAligned2");
479 }
caryclark54359292015-03-26 07:52:43 -0700480#if DEBUG_VALIDATE
481 globalState->setPhase(SkOpGlobalState::kWalking);
482#endif
caryclark27c8eb82015-07-06 11:38:33 -0700483 // check to see if, loosely, coincident ranges may be expanded
484 if (coincidence->expand()) {
caryclark26ad22a2015-10-16 09:03:38 -0700485 DEBUG_COINCIDENCE_HEALTH(contourList, "expand1");
486 if (!coincidence->addExpanded(allocator PATH_OPS_DEBUG_VALIDATE_PARAMS(globalState))) {
487 return false;
488 }
caryclark65f55312014-11-13 06:58:52 -0800489 }
caryclark26ad22a2015-10-16 09:03:38 -0700490 DEBUG_COINCIDENCE_HEALTH(contourList, "expand2");
caryclark27c8eb82015-07-06 11:38:33 -0700491 // the expanded ranges may not align -- add the missing spans
492 coincidence->mark(); // mark spans of coincident segments as coincident
caryclark26ad22a2015-10-16 09:03:38 -0700493 DEBUG_COINCIDENCE_HEALTH(contourList, "mark1");
caryclark27c8eb82015-07-06 11:38:33 -0700494 // look for coincidence missed earlier
495 if (missingCoincidence(contourList, coincidence, allocator)) {
caryclark26ad22a2015-10-16 09:03:38 -0700496 DEBUG_COINCIDENCE_HEALTH(contourList, "missingCoincidence1");
caryclark27c8eb82015-07-06 11:38:33 -0700497 (void) coincidence->expand();
caryclark26ad22a2015-10-16 09:03:38 -0700498 DEBUG_COINCIDENCE_HEALTH(contourList, "expand3");
499 if (!coincidence->addExpanded(allocator PATH_OPS_DEBUG_VALIDATE_PARAMS(globalState))) {
500 return false;
501 }
502 DEBUG_COINCIDENCE_HEALTH(contourList, "addExpanded2");
caryclark27c8eb82015-07-06 11:38:33 -0700503 coincidence->mark();
504 }
caryclark26ad22a2015-10-16 09:03:38 -0700505 DEBUG_COINCIDENCE_HEALTH(contourList, "missingCoincidence2");
caryclark27c8eb82015-07-06 11:38:33 -0700506 SkOpCoincidence overlaps;
507 do {
508 SkOpCoincidence* pairs = overlaps.isEmpty() ? coincidence : &overlaps;
509 if (!pairs->apply()) { // adjust the winding value to account for coincident edges
510 return false;
511 }
caryclark26ad22a2015-10-16 09:03:38 -0700512 DEBUG_COINCIDENCE_HEALTH(contourList, "pairs->apply");
caryclark27c8eb82015-07-06 11:38:33 -0700513 // For each coincident pair that overlaps another, when the receivers (the 1st of the pair)
514 // are different, construct a new pair to resolve their mutual span
515 pairs->findOverlaps(&overlaps, allocator);
caryclark26ad22a2015-10-16 09:03:38 -0700516 DEBUG_COINCIDENCE_HEALTH(contourList, "pairs->findOverlaps");
caryclark27c8eb82015-07-06 11:38:33 -0700517 } while (!overlaps.isEmpty());
caryclark54359292015-03-26 07:52:43 -0700518 calcAngles(contourList, allocator);
reed0dc4dd62015-03-24 13:55:33 -0700519 sortAngles(contourList);
caryclark54359292015-03-26 07:52:43 -0700520 if (globalState->angleCoincidence()) {
caryclark27c8eb82015-07-06 11:38:33 -0700521 (void) missingCoincidence(contourList, coincidence, allocator);
caryclark54359292015-03-26 07:52:43 -0700522 if (!coincidence->apply()) {
523 return false;
524 }
525 }
526#if DEBUG_ACTIVE_SPANS
caryclark624637c2015-05-11 07:21:27 -0700527 coincidence->debugShowCoincidence();
528 DebugShowActiveSpans(contourList);
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000529#endif
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000530 return true;
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000531}