blob: c48a7eef68926a50721c3f2a3f4974f98753f277 [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"
caryclark@google.com07393ca2013-04-08 11:47:37 +00008#include "SkOpEdgeBuilder.h"
9#include "SkPathOpsCommon.h"
10#include "SkPathWriter.h"
commit-bot@chromium.orgb76d3b62013-04-22 19:55:19 +000011#include "SkTSort.h"
caryclark@google.com07393ca2013-04-08 11:47:37 +000012
caryclark@google.comd892bd82013-06-17 14:10:36 +000013static int contourRangeCheckY(const SkTArray<SkOpContour*, true>& contourList, SkOpSegment** currentPtr,
caryclark@google.com07393ca2013-04-08 11:47:37 +000014 int* indexPtr, int* endIndexPtr, double* bestHit, SkScalar* bestDx,
15 bool* tryAgain, double* midPtr, bool opp) {
16 const int index = *indexPtr;
17 const int endIndex = *endIndexPtr;
18 const double mid = *midPtr;
19 const SkOpSegment* current = *currentPtr;
20 double tAtMid = current->tAtMid(index, endIndex, mid);
caryclark@google.com4fdbb222013-07-23 15:27:41 +000021 SkPoint basePt = current->ptAtT(tAtMid);
caryclark@google.com07393ca2013-04-08 11:47:37 +000022 int contourCount = contourList.count();
23 SkScalar bestY = SK_ScalarMin;
24 SkOpSegment* bestSeg = NULL;
caryclark@google.com3e475dc2013-04-11 14:09:50 +000025 int bestTIndex = 0;
caryclark@google.com07393ca2013-04-08 11:47:37 +000026 bool bestOpp;
27 bool hitSomething = false;
28 for (int cTest = 0; cTest < contourCount; ++cTest) {
29 SkOpContour* contour = contourList[cTest];
30 bool testOpp = contour->operand() ^ current->operand() ^ opp;
31 if (basePt.fY < contour->bounds().fTop) {
32 continue;
33 }
34 if (bestY > contour->bounds().fBottom) {
35 continue;
36 }
37 int segmentCount = contour->segments().count();
38 for (int test = 0; test < segmentCount; ++test) {
39 SkOpSegment* testSeg = &contour->segments()[test];
40 SkScalar testY = bestY;
41 double testHit;
42 int testTIndex = testSeg->crossedSpanY(basePt, &testY, &testHit, &hitSomething, tAtMid,
43 testOpp, testSeg == current);
44 if (testTIndex < 0) {
45 if (testTIndex == SK_MinS32) {
46 hitSomething = true;
47 bestSeg = NULL;
48 goto abortContours; // vertical encountered, return and try different point
49 }
50 continue;
51 }
52 if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
53 double baseT = current->t(index);
54 double endT = current->t(endIndex);
55 double newMid = (testHit - baseT) / (endT - baseT);
56#if DEBUG_WINDING
57 double midT = current->tAtMid(index, endIndex, mid);
58 SkPoint midXY = current->xyAtT(midT);
59 double newMidT = current->tAtMid(index, endIndex, newMid);
60 SkPoint newXY = current->xyAtT(newMidT);
61 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
62 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
63 current->debugID(), mid, newMid,
64 baseT, current->xAtT(index), current->yAtT(index),
65 baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
66 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
67 endT, current->xAtT(endIndex), current->yAtT(endIndex));
68#endif
69 *midPtr = newMid * 2; // calling loop with divide by 2 before continuing
70 return SK_MinS32;
71 }
72 bestSeg = testSeg;
73 *bestHit = testHit;
74 bestOpp = testOpp;
75 bestTIndex = testTIndex;
76 bestY = testY;
77 }
78 }
79abortContours:
80 int result;
81 if (!bestSeg) {
82 result = hitSomething ? SK_MinS32 : 0;
83 } else {
84 if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
85 *currentPtr = bestSeg;
86 *indexPtr = bestTIndex;
87 *endIndexPtr = bestSeg->nextSpan(bestTIndex, 1);
88 SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0);
89 *tryAgain = true;
90 return 0;
91 }
92 result = bestSeg->windingAtT(*bestHit, bestTIndex, bestOpp, bestDx);
caryclark@google.comf11a5af2013-04-10 18:55:11 +000093 SkASSERT(result == SK_MinS32 || *bestDx);
caryclark@google.com07393ca2013-04-08 11:47:37 +000094 }
95 double baseT = current->t(index);
96 double endT = current->t(endIndex);
97 *bestHit = baseT + mid * (endT - baseT);
98 return result;
99}
100
caryclark@google.comd892bd82013-06-17 14:10:36 +0000101SkOpSegment* FindUndone(SkTArray<SkOpContour*, true>& contourList, int* start, int* end) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000102 int contourCount = contourList.count();
103 SkOpSegment* result;
104 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
105 SkOpContour* contour = contourList[cIndex];
106 result = contour->undoneSegment(start, end);
107 if (result) {
108 return result;
109 }
110 }
111 return NULL;
112}
113
114SkOpSegment* FindChase(SkTDArray<SkOpSpan*>& chase, int& tIndex, int& endIndex) {
115 while (chase.count()) {
116 SkOpSpan* span;
117 chase.pop(&span);
118 const SkOpSpan& backPtr = span->fOther->span(span->fOtherIndex);
119 SkOpSegment* segment = backPtr.fOther;
120 tIndex = backPtr.fOtherIndex;
caryclark@google.comd892bd82013-06-17 14:10:36 +0000121 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000122 int done = 0;
123 if (segment->activeAngle(tIndex, &done, &angles)) {
124 SkOpAngle* last = angles.end() - 1;
125 tIndex = last->start();
126 endIndex = last->end();
127 #if TRY_ROTATE
128 *chase.insert(0) = span;
129 #else
130 *chase.append() = span;
131 #endif
132 return last->segment();
133 }
134 if (done == angles.count()) {
135 continue;
136 }
caryclark@google.comd892bd82013-06-17 14:10:36 +0000137 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
caryclark@google.comcffbcc32013-06-04 17:59:42 +0000138 bool sortable = SkOpSegment::SortAngles(angles, &sorted,
139 SkOpSegment::kMayBeUnordered_SortAngleKind);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000140 int angleCount = sorted.count();
141#if DEBUG_SORT
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000142 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000143#endif
144 if (!sortable) {
145 continue;
146 }
147 // find first angle, initialize winding to computed fWindSum
148 int firstIndex = -1;
149 const SkOpAngle* angle;
150 int winding;
151 do {
152 angle = sorted[++firstIndex];
153 segment = angle->segment();
154 winding = segment->windSum(angle);
155 } while (winding == SK_MinS32);
156 int spanWinding = segment->spanSign(angle->start(), angle->end());
157 #if DEBUG_WINDING
158 SkDebugf("%s winding=%d spanWinding=%d\n",
159 __FUNCTION__, winding, spanWinding);
160 #endif
161 // turn span winding into contour winding
162 if (spanWinding * winding < 0) {
163 winding += spanWinding;
164 }
165 #if DEBUG_SORT
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000166 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0, sortable);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000167 #endif
168 // we care about first sign and whether wind sum indicates this
169 // edge is inside or outside. Maybe need to pass span winding
170 // or first winding or something into this function?
171 // advance to first undone angle, then return it and winding
172 // (to set whether edges are active or not)
173 int nextIndex = firstIndex + 1;
174 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
175 angle = sorted[firstIndex];
176 winding -= angle->segment()->spanSign(angle);
177 do {
178 SkASSERT(nextIndex != firstIndex);
179 if (nextIndex == angleCount) {
180 nextIndex = 0;
181 }
182 angle = sorted[nextIndex];
183 segment = angle->segment();
184 int maxWinding = winding;
185 winding -= segment->spanSign(angle);
186 #if DEBUG_SORT
187 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
188 segment->debugID(), maxWinding, winding, angle->sign());
189 #endif
190 tIndex = angle->start();
191 endIndex = angle->end();
192 int lesser = SkMin32(tIndex, endIndex);
193 const SkOpSpan& nextSpan = segment->span(lesser);
194 if (!nextSpan.fDone) {
195 // FIXME: this be wrong? assign startWinding if edge is in
196 // same direction. If the direction is opposite, winding to
197 // assign is flipped sign or +/- 1?
198 if (SkOpSegment::UseInnerWinding(maxWinding, winding)) {
199 maxWinding = winding;
200 }
201 segment->markAndChaseWinding(angle, maxWinding, 0);
202 break;
203 }
204 } while (++nextIndex != lastIndex);
205 *chase.insert(0) = span;
206 return segment;
207 }
208 return NULL;
209}
210
caryclark@google.coma5e55922013-05-07 18:51:31 +0000211#if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
caryclark@google.comd892bd82013-06-17 14:10:36 +0000212void DebugShowActiveSpans(SkTArray<SkOpContour*, true>& contourList) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000213 int index;
214 for (index = 0; index < contourList.count(); ++ index) {
215 contourList[index]->debugShowActiveSpans();
216 }
217}
218#endif
219
caryclark@google.comd892bd82013-06-17 14:10:36 +0000220static SkOpSegment* findSortableTop(const SkTArray<SkOpContour*, true>& contourList,
caryclark@google.com07393ca2013-04-08 11:47:37 +0000221 int* index, int* endIndex, SkPoint* topLeft, bool* unsortable,
222 bool* done, bool onlySortable) {
223 SkOpSegment* result;
224 do {
225 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
226 int contourCount = contourList.count();
227 SkOpSegment* topStart = NULL;
228 *done = true;
229 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
230 SkOpContour* contour = contourList[cIndex];
231 if (contour->done()) {
232 continue;
233 }
234 const SkPathOpsBounds& bounds = contour->bounds();
235 if (bounds.fBottom < topLeft->fY) {
236 *done = false;
237 continue;
238 }
239 if (bounds.fBottom == topLeft->fY && bounds.fRight < topLeft->fX) {
240 *done = false;
241 continue;
242 }
243 contour->topSortableSegment(*topLeft, &bestXY, &topStart);
244 if (!contour->done()) {
245 *done = false;
246 }
247 }
248 if (!topStart) {
249 return NULL;
250 }
251 *topLeft = bestXY;
252 result = topStart->findTop(index, endIndex, unsortable, onlySortable);
253 } while (!result);
caryclark@google.com570863f2013-09-16 15:55:01 +0000254 if (result) {
255 *unsortable = false;
256 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000257 return result;
258}
259
caryclark@google.comd892bd82013-06-17 14:10:36 +0000260static int rightAngleWinding(const SkTArray<SkOpContour*, true>& contourList,
caryclark@google.com07393ca2013-04-08 11:47:37 +0000261 SkOpSegment** current, int* index, int* endIndex, double* tHit,
262 SkScalar* hitDx, bool* tryAgain, bool opp) {
263 double test = 0.9;
264 int contourWinding;
265 do {
266 contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx,
267 tryAgain, &test, opp);
268 if (contourWinding != SK_MinS32 || *tryAgain) {
269 return contourWinding;
270 }
271 test /= 2;
272 } while (!approximately_negative(test));
273 SkASSERT(0); // should be OK to comment out, but interested when this hits
274 return contourWinding;
275}
276
caryclark@google.comd892bd82013-06-17 14:10:36 +0000277static void skipVertical(const SkTArray<SkOpContour*, true>& contourList,
caryclark@google.com07393ca2013-04-08 11:47:37 +0000278 SkOpSegment** current, int* index, int* endIndex) {
279 if (!(*current)->isVertical(*index, *endIndex)) {
280 return;
281 }
282 int contourCount = contourList.count();
283 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
284 SkOpContour* contour = contourList[cIndex];
285 if (contour->done()) {
286 continue;
287 }
288 *current = contour->nonVerticalSegment(index, endIndex);
289 if (*current) {
290 return;
291 }
292 }
293}
294
caryclark@google.com570863f2013-09-16 15:55:01 +0000295SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList,
296 SkOpAngle::IncludeType angleIncludeType, bool* firstContour, int* indexPtr,
297 int* endIndexPtr, SkPoint* topLeft, bool* unsortable, bool* done) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000298 SkOpSegment* current = findSortableTop(contourList, indexPtr, endIndexPtr, topLeft, unsortable,
299 done, true);
300 if (!current) {
301 return NULL;
302 }
303 const int index = *indexPtr;
304 const int endIndex = *endIndexPtr;
305 if (*firstContour) {
306 current->initWinding(index, endIndex);
307 *firstContour = false;
308 return current;
309 }
310 int minIndex = SkMin32(index, endIndex);
311 int sumWinding = current->windSum(minIndex);
312 if (sumWinding != SK_MinS32) {
313 return current;
314 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000315 SkASSERT(current->windSum(SkMin32(index, endIndex)) == SK_MinS32);
316 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
317 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
318 sumWinding = current->computeSum(index, endIndex, angleIncludeType, &angles, &sorted);
319 if (sumWinding != SK_MinS32 && sumWinding != SK_NaN32) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000320 return current;
321 }
322 int contourWinding;
323 int oppContourWinding = 0;
324 // the simple upward projection of the unresolved points hit unsortable angles
325 // shoot rays at right angles to the segment to find its winding, ignoring angle cases
326 bool tryAgain;
327 double tHit;
328 SkScalar hitDx = 0;
329 SkScalar hitOppDx = 0;
330 do {
331 // if current is vertical, find another candidate which is not
332 // if only remaining candidates are vertical, then they can be marked done
333 SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0);
334 skipVertical(contourList, &current, indexPtr, endIndexPtr);
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000335
caryclark@google.com07393ca2013-04-08 11:47:37 +0000336 SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0);
337 tryAgain = false;
338 contourWinding = rightAngleWinding(contourList, &current, indexPtr, endIndexPtr, &tHit,
339 &hitDx, &tryAgain, false);
340 if (tryAgain) {
341 continue;
342 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000343 if (angleIncludeType < SkOpAngle::kBinarySingle) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000344 break;
345 }
346 oppContourWinding = rightAngleWinding(contourList, &current, indexPtr, endIndexPtr, &tHit,
347 &hitOppDx, &tryAgain, true);
348 } while (tryAgain);
349 current->initWinding(*indexPtr, *endIndexPtr, tHit, contourWinding, hitDx, oppContourWinding,
350 hitOppDx);
351 return current;
352}
353
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000354static void checkEnds(SkTArray<SkOpContour*, true>* contourList) {
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000355 // it's hard to determine if the end of a cubic or conic nearly intersects another curve.
356 // instead, look to see if the connecting curve intersected at that same end.
357 int contourCount = (*contourList).count();
358 for (int cTest = 0; cTest < contourCount; ++cTest) {
359 SkOpContour* contour = (*contourList)[cTest];
360 contour->checkEnds();
361 }
362}
363
caryclark@google.com570863f2013-09-16 15:55:01 +0000364// A tiny interval may indicate an undiscovered coincidence. Find and fix.
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000365static void checkTiny(SkTArray<SkOpContour*, true>* contourList) {
caryclark@google.com570863f2013-09-16 15:55:01 +0000366 int contourCount = (*contourList).count();
367 for (int cTest = 0; cTest < contourCount; ++cTest) {
368 SkOpContour* contour = (*contourList)[cTest];
369 contour->checkTiny();
370 }
371}
372
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000373static void fixOtherTIndex(SkTArray<SkOpContour*, true>* contourList) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000374 int contourCount = (*contourList).count();
375 for (int cTest = 0; cTest < contourCount; ++cTest) {
376 SkOpContour* contour = (*contourList)[cTest];
377 contour->fixOtherTIndex();
378 }
379}
380
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000381static void joinCoincidence(SkTArray<SkOpContour*, true>* contourList) {
382 int contourCount = (*contourList).count();
383 for (int cTest = 0; cTest < contourCount; ++cTest) {
384 SkOpContour* contour = (*contourList)[cTest];
385 contour->joinCoincidence();
386 }
387}
388
389static void sortSegments(SkTArray<SkOpContour*, true>* contourList) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000390 int contourCount = (*contourList).count();
391 for (int cTest = 0; cTest < contourCount; ++cTest) {
392 SkOpContour* contour = (*contourList)[cTest];
393 contour->sortSegments();
394 }
395}
396
caryclark@google.comd892bd82013-06-17 14:10:36 +0000397void MakeContourList(SkTArray<SkOpContour>& contours, SkTArray<SkOpContour*, true>& list,
caryclark@google.com07393ca2013-04-08 11:47:37 +0000398 bool evenOdd, bool oppEvenOdd) {
399 int count = contours.count();
400 if (count == 0) {
401 return;
402 }
403 for (int index = 0; index < count; ++index) {
404 SkOpContour& contour = contours[index];
405 contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd);
caryclark@google.comd892bd82013-06-17 14:10:36 +0000406 list.push_back(&contour);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000407 }
commit-bot@chromium.orgb76d3b62013-04-22 19:55:19 +0000408 SkTQSort<SkOpContour>(list.begin(), list.end() - 1);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000409}
410
commit-bot@chromium.orgb76d3b62013-04-22 19:55:19 +0000411class DistanceLessThan {
412public:
413 DistanceLessThan(double* distances) : fDistances(distances) { }
414 double* fDistances;
415 bool operator()(const int one, const int two) {
416 return fDistances[one] < fDistances[two];
417 }
418};
419
caryclark@google.com07393ca2013-04-08 11:47:37 +0000420 /*
421 check start and end of each contour
422 if not the same, record them
423 match them up
424 connect closest
425 reassemble contour pieces into new path
426 */
427void Assemble(const SkPathWriter& path, SkPathWriter* simple) {
428#if DEBUG_PATH_CONSTRUCTION
429 SkDebugf("%s\n", __FUNCTION__);
430#endif
431 SkTArray<SkOpContour> contours;
432 SkOpEdgeBuilder builder(path, contours);
433 builder.finish();
434 int count = contours.count();
435 int outer;
caryclark@google.comd892bd82013-06-17 14:10:36 +0000436 SkTArray<int, true> runs(count); // indices of partial contours
caryclark@google.com07393ca2013-04-08 11:47:37 +0000437 for (outer = 0; outer < count; ++outer) {
438 const SkOpContour& eContour = contours[outer];
439 const SkPoint& eStart = eContour.start();
440 const SkPoint& eEnd = eContour.end();
441#if DEBUG_ASSEMBLE
442 SkDebugf("%s contour", __FUNCTION__);
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000443 if (!SkDPoint::ApproximatelyEqual(eStart, eEnd)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000444 SkDebugf("[%d]", runs.count());
445 } else {
446 SkDebugf(" ");
447 }
448 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n",
449 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY);
450#endif
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000451 if (SkDPoint::ApproximatelyEqual(eStart, eEnd)) {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000452 eContour.toPath(simple);
453 continue;
454 }
caryclark@google.comd892bd82013-06-17 14:10:36 +0000455 runs.push_back(outer);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000456 }
457 count = runs.count();
458 if (count == 0) {
459 return;
460 }
caryclark@google.comd892bd82013-06-17 14:10:36 +0000461 SkTArray<int, true> sLink, eLink;
462 sLink.push_back_n(count);
463 eLink.push_back_n(count);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000464 int rIndex, iIndex;
465 for (rIndex = 0; rIndex < count; ++rIndex) {
466 sLink[rIndex] = eLink[rIndex] = SK_MaxS32;
467 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000468 const int ends = count * 2; // all starts and ends
469 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2
caryclark@google.comd892bd82013-06-17 14:10:36 +0000470 SkTArray<double, true> distances;
471 distances.push_back_n(entries);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000472 for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
473 outer = runs[rIndex >> 1];
474 const SkOpContour& oContour = contours[outer];
475 const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start();
476 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2)
477 * ends - rIndex - 1;
478 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) {
479 int inner = runs[iIndex >> 1];
480 const SkOpContour& iContour = contours[inner];
481 const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start();
482 double dx = iPt.fX - oPt.fX;
483 double dy = iPt.fY - oPt.fY;
484 double dist = dx * dx + dy * dy;
485 distances[row + iIndex] = dist; // oStart distance from iStart
486 }
487 }
caryclark@google.comd892bd82013-06-17 14:10:36 +0000488 SkTArray<int, true> sortedDist;
489 sortedDist.push_back_n(entries);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000490 for (rIndex = 0; rIndex < entries; ++rIndex) {
491 sortedDist[rIndex] = rIndex;
492 }
commit-bot@chromium.orgb76d3b62013-04-22 19:55:19 +0000493 SkTQSort<int>(sortedDist.begin(), sortedDist.end() - 1, DistanceLessThan(distances.begin()));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000494 int remaining = count; // number of start/end pairs
495 for (rIndex = 0; rIndex < entries; ++rIndex) {
496 int pair = sortedDist[rIndex];
497 int row = pair / ends;
498 int col = pair - row * ends;
499 int thingOne = row < col ? row : ends - row - 2;
500 int ndxOne = thingOne >> 1;
501 bool endOne = thingOne & 1;
502 int* linkOne = endOne ? eLink.begin() : sLink.begin();
503 if (linkOne[ndxOne] != SK_MaxS32) {
504 continue;
505 }
506 int thingTwo = row < col ? col : ends - row + col - 1;
507 int ndxTwo = thingTwo >> 1;
508 bool endTwo = thingTwo & 1;
509 int* linkTwo = endTwo ? eLink.begin() : sLink.begin();
510 if (linkTwo[ndxTwo] != SK_MaxS32) {
511 continue;
512 }
513 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]);
514 bool flip = endOne == endTwo;
515 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo;
516 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne;
517 if (!--remaining) {
518 break;
519 }
520 }
521 SkASSERT(!remaining);
522#if DEBUG_ASSEMBLE
523 for (rIndex = 0; rIndex < count; ++rIndex) {
524 int s = sLink[rIndex];
525 int e = eLink[rIndex];
526 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e',
527 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e);
528 }
529#endif
530 rIndex = 0;
531 do {
532 bool forward = true;
533 bool first = true;
534 int sIndex = sLink[rIndex];
535 SkASSERT(sIndex != SK_MaxS32);
536 sLink[rIndex] = SK_MaxS32;
537 int eIndex;
538 if (sIndex < 0) {
539 eIndex = sLink[~sIndex];
540 sLink[~sIndex] = SK_MaxS32;
541 } else {
542 eIndex = eLink[sIndex];
543 eLink[sIndex] = SK_MaxS32;
544 }
545 SkASSERT(eIndex != SK_MaxS32);
546#if DEBUG_ASSEMBLE
547 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e',
548 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e',
549 eIndex < 0 ? ~eIndex : eIndex);
550#endif
551 do {
552 outer = runs[rIndex];
553 const SkOpContour& contour = contours[outer];
554 if (first) {
555 first = false;
556 const SkPoint* startPtr = &contour.start();
557 simple->deferredMove(startPtr[0]);
558 }
559 if (forward) {
560 contour.toPartialForward(simple);
561 } else {
562 contour.toPartialBackward(simple);
563 }
564#if DEBUG_ASSEMBLE
565 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex,
566 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex,
567 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex));
568#endif
569 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) {
570 simple->close();
571 break;
572 }
573 if (forward) {
574 eIndex = eLink[rIndex];
575 SkASSERT(eIndex != SK_MaxS32);
576 eLink[rIndex] = SK_MaxS32;
577 if (eIndex >= 0) {
578 SkASSERT(sLink[eIndex] == rIndex);
579 sLink[eIndex] = SK_MaxS32;
580 } else {
581 SkASSERT(eLink[~eIndex] == ~rIndex);
582 eLink[~eIndex] = SK_MaxS32;
583 }
584 } else {
585 eIndex = sLink[rIndex];
586 SkASSERT(eIndex != SK_MaxS32);
587 sLink[rIndex] = SK_MaxS32;
588 if (eIndex >= 0) {
589 SkASSERT(eLink[eIndex] == rIndex);
590 eLink[eIndex] = SK_MaxS32;
591 } else {
592 SkASSERT(sLink[~eIndex] == ~rIndex);
593 sLink[~eIndex] = SK_MaxS32;
594 }
595 }
596 rIndex = eIndex;
597 if (rIndex < 0) {
598 forward ^= 1;
599 rIndex = ~rIndex;
600 }
601 } while (true);
602 for (rIndex = 0; rIndex < count; ++rIndex) {
603 if (sLink[rIndex] != SK_MaxS32) {
604 break;
605 }
606 }
607 } while (rIndex < count);
608#if DEBUG_ASSEMBLE
609 for (rIndex = 0; rIndex < count; ++rIndex) {
610 SkASSERT(sLink[rIndex] == SK_MaxS32);
611 SkASSERT(eLink[rIndex] == SK_MaxS32);
612 }
613#endif
614}
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000615
616void HandleCoincidence(SkTArray<SkOpContour*, true>* contourList, int total) {
617#if DEBUG_SHOW_WINDING
618 SkOpContour::debugShowWindingValues(contourList);
619#endif
620 CoincidenceCheck(contourList, total);
621#if DEBUG_SHOW_WINDING
622 SkOpContour::debugShowWindingValues(contourList);
623#endif
624 fixOtherTIndex(contourList);
625 checkEnds(contourList);
626 checkTiny(contourList);
627 joinCoincidence(contourList);
628 sortSegments(contourList);
629#if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
630 DebugShowActiveSpans(*contourList);
631#endif
632}