OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 #include "SkAddIntersections.h" | 7 #include "SkAddIntersections.h" |
8 #include "SkOpEdgeBuilder.h" | 8 #include "SkOpEdgeBuilder.h" |
9 #include "SkPathOpsCommon.h" | 9 #include "SkPathOpsCommon.h" |
10 #include "SkPathWriter.h" | 10 #include "SkPathWriter.h" |
11 #include "SkTSort.h" | 11 #include "SkTSort.h" |
12 | 12 |
| 13 static void alignMultiples(SkTArray<SkOpContour*, true>* contourList, |
| 14 SkTDArray<SkOpSegment::AlignedSpan>* aligned) { |
| 15 int contourCount = (*contourList).count(); |
| 16 for (int cTest = 0; cTest < contourCount; ++cTest) { |
| 17 SkOpContour* contour = (*contourList)[cTest]; |
| 18 if (contour->hasMultiples()) { |
| 19 contour->alignMultiples(aligned); |
| 20 } |
| 21 } |
| 22 } |
| 23 |
| 24 static void alignCoincidence(SkTArray<SkOpContour*, true>* contourList, |
| 25 const SkTDArray<SkOpSegment::AlignedSpan>& aligned) { |
| 26 int contourCount = (*contourList).count(); |
| 27 for (int cTest = 0; cTest < contourCount; ++cTest) { |
| 28 SkOpContour* contour = (*contourList)[cTest]; |
| 29 int count = aligned.count(); |
| 30 for (int index = 0; index < count; ++index) { |
| 31 contour->alignCoincidence(aligned[index]); |
| 32 } |
| 33 } |
| 34 } |
| 35 |
13 static int contourRangeCheckY(const SkTArray<SkOpContour*, true>& contourList, S
kOpSegment** currentPtr, | 36 static int contourRangeCheckY(const SkTArray<SkOpContour*, true>& contourList, S
kOpSegment** currentPtr, |
14 int* indexPtr, int* endIndexPtr, double* bestHit,
SkScalar* bestDx, | 37 int* indexPtr, int* endIndexPtr, double* bestHit,
SkScalar* bestDx, |
15 bool* tryAgain, double* midPtr, bool opp) { | 38 bool* tryAgain, double* midPtr, bool opp) { |
16 const int index = *indexPtr; | 39 const int index = *indexPtr; |
17 const int endIndex = *endIndexPtr; | 40 const int endIndex = *endIndexPtr; |
18 const double mid = *midPtr; | 41 const double mid = *midPtr; |
19 const SkOpSegment* current = *currentPtr; | 42 const SkOpSegment* current = *currentPtr; |
20 double tAtMid = current->tAtMid(index, endIndex, mid); | 43 double tAtMid = current->tAtMid(index, endIndex, mid); |
21 SkPoint basePt = current->ptAtT(tAtMid); | 44 SkPoint basePt = current->ptAtT(tAtMid); |
22 int contourCount = contourList.count(); | 45 int contourCount = contourList.count(); |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
178 *endIndex = angle->end(); | 201 *endIndex = angle->end(); |
179 int lesser = SkMin32(*tIndex, *endIndex); | 202 int lesser = SkMin32(*tIndex, *endIndex); |
180 const SkOpSpan& nextSpan = segment->span(lesser); | 203 const SkOpSpan& nextSpan = segment->span(lesser); |
181 if (!nextSpan.fDone) { | 204 if (!nextSpan.fDone) { |
182 // FIXME: this be wrong? assign startWinding if edge is in | 205 // FIXME: this be wrong? assign startWinding if edge is in |
183 // same direction. If the direction is opposite, winding to | 206 // same direction. If the direction is opposite, winding to |
184 // assign is flipped sign or +/- 1? | 207 // assign is flipped sign or +/- 1? |
185 if (SkOpSegment::UseInnerWinding(maxWinding, winding)) { | 208 if (SkOpSegment::UseInnerWinding(maxWinding, winding)) { |
186 maxWinding = winding; | 209 maxWinding = winding; |
187 } | 210 } |
188 segment->markAndChaseWinding(angle, maxWinding, 0); | 211 (void) segment->markAndChaseWinding(angle, maxWinding, 0); |
189 break; | 212 break; |
190 } | 213 } |
191 } | 214 } |
192 *chase->insert(0) = span; | 215 *chase->insert(0) = span; |
193 return segment; | 216 return segment; |
194 } | 217 } |
195 return NULL; | 218 return NULL; |
196 } | 219 } |
197 | 220 |
198 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY | 221 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY |
199 void DebugShowActiveSpans(SkTArray<SkOpContour*, true>& contourList) { | 222 void DebugShowActiveSpans(SkTArray<SkOpContour*, true>& contourList) { |
200 int index; | 223 int index; |
201 for (index = 0; index < contourList.count(); ++ index) { | 224 for (index = 0; index < contourList.count(); ++ index) { |
202 contourList[index]->debugShowActiveSpans(); | 225 contourList[index]->debugShowActiveSpans(); |
203 } | 226 } |
204 } | 227 } |
205 #endif | 228 #endif |
206 | 229 |
207 static SkOpSegment* findSortableTop(const SkTArray<SkOpContour*, true>& contourL
ist, | 230 static SkOpSegment* findTopSegment(const SkTArray<SkOpContour*, true>& contourLi
st, int* index, |
208 int* index, int* endIndex, SkPoint* topLeft,
bool* unsortable, | 231 int* endIndex, SkPoint* topLeft, bool* unsortable, bool* done, bool firs
tPass) { |
209 bool* done, bool firstPass) { | |
210 SkOpSegment* result; | 232 SkOpSegment* result; |
211 const SkOpSegment* lastTopStart = NULL; | 233 const SkOpSegment* lastTopStart = NULL; |
212 int lastIndex = -1, lastEndIndex = -1; | 234 int lastIndex = -1, lastEndIndex = -1; |
213 do { | 235 do { |
214 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax}; | 236 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax}; |
215 int contourCount = contourList.count(); | 237 int contourCount = contourList.count(); |
216 SkOpSegment* topStart = NULL; | 238 SkOpSegment* topStart = NULL; |
217 *done = true; | 239 *done = true; |
218 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { | 240 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { |
219 SkOpContour* contour = contourList[cIndex]; | 241 SkOpContour* contour = contourList[cIndex]; |
(...skipping 22 matching lines...) Expand all Loading... |
242 if (!result) { | 264 if (!result) { |
243 if (lastTopStart == topStart && lastIndex == *index && lastEndIndex
== *endIndex) { | 265 if (lastTopStart == topStart && lastIndex == *index && lastEndIndex
== *endIndex) { |
244 *done = true; | 266 *done = true; |
245 return NULL; | 267 return NULL; |
246 } | 268 } |
247 lastTopStart = topStart; | 269 lastTopStart = topStart; |
248 lastIndex = *index; | 270 lastIndex = *index; |
249 lastEndIndex = *endIndex; | 271 lastEndIndex = *endIndex; |
250 } | 272 } |
251 } while (!result); | 273 } while (!result); |
252 #if 0 | |
253 if (result) { | |
254 *unsortable = false; | |
255 } | |
256 #endif | |
257 return result; | 274 return result; |
258 } | 275 } |
259 | 276 |
260 static int rightAngleWinding(const SkTArray<SkOpContour*, true>& contourList, | 277 static int rightAngleWinding(const SkTArray<SkOpContour*, true>& contourList, |
261 SkOpSegment** current, int* index, int* endIndex, d
ouble* tHit, | 278 SkOpSegment** currentPtr, int* indexPtr, int* endIndexPtr, double* tHit, |
262 SkScalar* hitDx, bool* tryAgain, bool opp) { | 279 SkScalar* hitDx, bool* tryAgain, bool* onlyVertical, bool opp) { |
263 double test = 0.9; | 280 double test = 0.9; |
264 int contourWinding; | 281 int contourWinding; |
265 do { | 282 do { |
266 contourWinding = contourRangeCheckY(contourList, current, index, endInde
x, tHit, hitDx, | 283 contourWinding = contourRangeCheckY(contourList, currentPtr, indexPtr, e
ndIndexPtr, |
267 tryAgain, &test, opp); | 284 tHit, hitDx, tryAgain, &test, opp); |
268 if (contourWinding != SK_MinS32 || *tryAgain) { | 285 if (contourWinding != SK_MinS32 || *tryAgain) { |
269 return contourWinding; | 286 return contourWinding; |
270 } | 287 } |
| 288 if (*currentPtr && (*currentPtr)->isVertical()) { |
| 289 *onlyVertical = true; |
| 290 return contourWinding; |
| 291 } |
271 test /= 2; | 292 test /= 2; |
272 } while (!approximately_negative(test)); | 293 } while (!approximately_negative(test)); |
273 SkASSERT(0); // should be OK to comment out, but interested when this hits | 294 SkASSERT(0); // FIXME: incomplete functionality |
274 return contourWinding; | 295 return contourWinding; |
275 } | 296 } |
276 | 297 |
277 static void skipVertical(const SkTArray<SkOpContour*, true>& contourList, | 298 static void skipVertical(const SkTArray<SkOpContour*, true>& contourList, |
278 SkOpSegment** current, int* index, int* endIndex) { | 299 SkOpSegment** current, int* index, int* endIndex) { |
279 if (!(*current)->isVertical(*index, *endIndex)) { | 300 if (!(*current)->isVertical(*index, *endIndex)) { |
280 return; | 301 return; |
281 } | 302 } |
282 int contourCount = contourList.count(); | 303 int contourCount = contourList.count(); |
283 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { | 304 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { |
284 SkOpContour* contour = contourList[cIndex]; | 305 SkOpContour* contour = contourList[cIndex]; |
285 if (contour->done()) { | 306 if (contour->done()) { |
286 continue; | 307 continue; |
287 } | 308 } |
288 SkOpSegment* nonVertical = contour->nonVerticalSegment(index, endIndex); | 309 SkOpSegment* nonVertical = contour->nonVerticalSegment(index, endIndex); |
289 if (nonVertical) { | 310 if (nonVertical) { |
290 *current = nonVertical; | 311 *current = nonVertical; |
291 return; | 312 return; |
292 } | 313 } |
293 } | 314 } |
294 return; | 315 return; |
295 } | 316 } |
296 | 317 |
297 SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList, | 318 SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList, |
298 SkOpAngle::IncludeType angleIncludeType, bool* firstContour, int* indexP
tr, | 319 SkOpAngle::IncludeType angleIncludeType, bool* firstContour, int* indexP
tr, |
299 int* endIndexPtr, SkPoint* topLeft, bool* unsortable, bool* done, bool f
irstPass) { | 320 int* endIndexPtr, SkPoint* topLeft, bool* unsortable, bool* done, bool*
onlyVertical, |
300 SkOpSegment* current = findSortableTop(contourList, indexPtr, endIndexPtr, t
opLeft, unsortable, | 321 bool firstPass) { |
| 322 SkOpSegment* current = findTopSegment(contourList, indexPtr, endIndexPtr, to
pLeft, unsortable, |
301 done, firstPass); | 323 done, firstPass); |
302 if (!current) { | 324 if (!current) { |
303 return NULL; | 325 return NULL; |
304 } | 326 } |
305 const int index = *indexPtr; | 327 const int startIndex = *indexPtr; |
306 const int endIndex = *endIndexPtr; | 328 const int endIndex = *endIndexPtr; |
307 if (*firstContour) { | 329 if (*firstContour) { |
308 current->initWinding(index, endIndex, angleIncludeType); | 330 current->initWinding(startIndex, endIndex, angleIncludeType); |
309 *firstContour = false; | 331 *firstContour = false; |
310 return current; | 332 return current; |
311 } | 333 } |
312 int minIndex = SkMin32(index, endIndex); | 334 int minIndex = SkMin32(startIndex, endIndex); |
313 int sumWinding = current->windSum(minIndex); | 335 int sumWinding = current->windSum(minIndex); |
314 if (sumWinding != SK_MinS32) { | 336 if (sumWinding == SK_MinS32) { |
315 return current; | 337 int index = endIndex; |
| 338 int oIndex = startIndex; |
| 339 do { |
| 340 const SkOpSpan& span = current->span(index); |
| 341 if ((oIndex < index ? span.fFromAngle : span.fToAngle) == NULL) { |
| 342 current->addSimpleAngle(index); |
| 343 } |
| 344 sumWinding = current->computeSum(oIndex, index, angleIncludeType); |
| 345 SkTSwap(index, oIndex); |
| 346 } while (sumWinding == SK_MinS32 && index == startIndex); |
316 } | 347 } |
317 SkASSERT(current->windSum(SkMin32(index, endIndex)) == SK_MinS32); | |
318 const SkOpSpan& span = current->span(endIndex); | |
319 if ((index < endIndex ? span.fFromAngleIndex : span.fToAngleIndex) < 0) { | |
320 current->addSimpleAngle(endIndex); | |
321 } | |
322 sumWinding = current->computeSum(index, endIndex, angleIncludeType); | |
323 if (sumWinding != SK_MinS32 && sumWinding != SK_NaN32) { | 348 if (sumWinding != SK_MinS32 && sumWinding != SK_NaN32) { |
324 return current; | 349 return current; |
325 } | 350 } |
326 int contourWinding; | 351 int contourWinding; |
327 int oppContourWinding = 0; | 352 int oppContourWinding = 0; |
328 // the simple upward projection of the unresolved points hit unsortable angl
es | 353 // the simple upward projection of the unresolved points hit unsortable angl
es |
329 // shoot rays at right angles to the segment to find its winding, ignoring a
ngle cases | 354 // shoot rays at right angles to the segment to find its winding, ignoring a
ngle cases |
330 bool tryAgain; | 355 bool tryAgain; |
331 double tHit; | 356 double tHit; |
332 SkScalar hitDx = 0; | 357 SkScalar hitDx = 0; |
333 SkScalar hitOppDx = 0; | 358 SkScalar hitOppDx = 0; |
334 do { | 359 do { |
335 // if current is vertical, find another candidate which is not | 360 // if current is vertical, find another candidate which is not |
336 // if only remaining candidates are vertical, then they can be marked do
ne | 361 // if only remaining candidates are vertical, then they can be marked do
ne |
337 SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >=
0); | 362 SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >=
0); |
338 skipVertical(contourList, ¤t, indexPtr, endIndexPtr); | 363 skipVertical(contourList, ¤t, indexPtr, endIndexPtr); |
339 SkASSERT(current); // FIXME: if null, all remaining are vertical | 364 SkASSERT(current); // FIXME: if null, all remaining are vertical |
340 SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >=
0); | 365 SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >=
0); |
341 tryAgain = false; | 366 tryAgain = false; |
342 contourWinding = rightAngleWinding(contourList, ¤t, indexPtr, endI
ndexPtr, &tHit, | 367 contourWinding = rightAngleWinding(contourList, ¤t, indexPtr, endI
ndexPtr, &tHit, |
343 &hitDx, &tryAgain, false); | 368 &hitDx, &tryAgain, onlyVertical, false); |
| 369 if (*onlyVertical) { |
| 370 return current; |
| 371 } |
344 if (tryAgain) { | 372 if (tryAgain) { |
345 continue; | 373 continue; |
346 } | 374 } |
347 if (angleIncludeType < SkOpAngle::kBinarySingle) { | 375 if (angleIncludeType < SkOpAngle::kBinarySingle) { |
348 break; | 376 break; |
349 } | 377 } |
350 oppContourWinding = rightAngleWinding(contourList, ¤t, indexPtr, e
ndIndexPtr, &tHit, | 378 oppContourWinding = rightAngleWinding(contourList, ¤t, indexPtr, e
ndIndexPtr, &tHit, |
351 &hitOppDx, &tryAgain, true); | 379 &hitOppDx, &tryAgain, NULL, true); |
352 } while (tryAgain); | 380 } while (tryAgain); |
353 current->initWinding(*indexPtr, *endIndexPtr, tHit, contourWinding, hitDx, o
ppContourWinding, | 381 current->initWinding(*indexPtr, *endIndexPtr, tHit, contourWinding, hitDx, o
ppContourWinding, |
354 hitOppDx); | 382 hitOppDx); |
355 if (current->done()) { | 383 if (current->done()) { |
356 return NULL; | 384 return NULL; |
357 } | 385 } |
358 return current; | 386 return current; |
359 } | 387 } |
360 | 388 |
361 static bool calcAngles(SkTArray<SkOpContour*, true>* contourList) { | 389 static bool calcAngles(SkTArray<SkOpContour*, true>* contourList) { |
(...skipping 18 matching lines...) Expand all Loading... |
380 static void checkEnds(SkTArray<SkOpContour*, true>* contourList) { | 408 static void checkEnds(SkTArray<SkOpContour*, true>* contourList) { |
381 // it's hard to determine if the end of a cubic or conic nearly intersects a
nother curve. | 409 // it's hard to determine if the end of a cubic or conic nearly intersects a
nother curve. |
382 // instead, look to see if the connecting curve intersected at that same end
. | 410 // instead, look to see if the connecting curve intersected at that same end
. |
383 int contourCount = (*contourList).count(); | 411 int contourCount = (*contourList).count(); |
384 for (int cTest = 0; cTest < contourCount; ++cTest) { | 412 for (int cTest = 0; cTest < contourCount; ++cTest) { |
385 SkOpContour* contour = (*contourList)[cTest]; | 413 SkOpContour* contour = (*contourList)[cTest]; |
386 contour->checkEnds(); | 414 contour->checkEnds(); |
387 } | 415 } |
388 } | 416 } |
389 | 417 |
390 static void checkMultiples(SkTArray<SkOpContour*, true>* contourList) { | 418 static bool checkMultiples(SkTArray<SkOpContour*, true>* contourList) { |
391 // it's hard to determine if the end of a cubic or conic nearly intersects a
nother curve. | 419 bool hasMultiples = false; |
392 // instead, look to see if the connecting curve intersected at that same end
. | |
393 int contourCount = (*contourList).count(); | 420 int contourCount = (*contourList).count(); |
394 for (int cTest = 0; cTest < contourCount; ++cTest) { | 421 for (int cTest = 0; cTest < contourCount; ++cTest) { |
395 SkOpContour* contour = (*contourList)[cTest]; | 422 SkOpContour* contour = (*contourList)[cTest]; |
396 contour->checkMultiples(); | 423 contour->checkMultiples(); |
| 424 hasMultiples |= contour->hasMultiples(); |
397 } | 425 } |
| 426 return hasMultiples; |
398 } | 427 } |
399 | 428 |
400 // A small interval of a pair of curves may collapse to lines for each, triggeri
ng coincidence | 429 // A small interval of a pair of curves may collapse to lines for each, triggeri
ng coincidence |
401 static void checkSmall(SkTArray<SkOpContour*, true>* contourList) { | 430 static void checkSmall(SkTArray<SkOpContour*, true>* contourList) { |
402 int contourCount = (*contourList).count(); | 431 int contourCount = (*contourList).count(); |
403 for (int cTest = 0; cTest < contourCount; ++cTest) { | 432 for (int cTest = 0; cTest < contourCount; ++cTest) { |
404 SkOpContour* contour = (*contourList)[cTest]; | 433 SkOpContour* contour = (*contourList)[cTest]; |
405 contour->checkSmall(); | 434 contour->checkSmall(); |
406 } | 435 } |
407 } | 436 } |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
668 | 697 |
669 bool HandleCoincidence(SkTArray<SkOpContour*, true>* contourList, int total) { | 698 bool HandleCoincidence(SkTArray<SkOpContour*, true>* contourList, int total) { |
670 #if DEBUG_SHOW_WINDING | 699 #if DEBUG_SHOW_WINDING |
671 SkOpContour::debugShowWindingValues(contourList); | 700 SkOpContour::debugShowWindingValues(contourList); |
672 #endif | 701 #endif |
673 CoincidenceCheck(contourList, total); | 702 CoincidenceCheck(contourList, total); |
674 #if DEBUG_SHOW_WINDING | 703 #if DEBUG_SHOW_WINDING |
675 SkOpContour::debugShowWindingValues(contourList); | 704 SkOpContour::debugShowWindingValues(contourList); |
676 #endif | 705 #endif |
677 fixOtherTIndex(contourList); | 706 fixOtherTIndex(contourList); |
678 checkEnds(contourList); | 707 checkEnds(contourList); // check if connecting curve intersected at the sam
e end |
679 checkMultiples(contourList); | 708 bool hasM = checkMultiples(contourList); // check if intersections agree on
t and point values |
680 checkDuplicates(contourList); | 709 SkTDArray<SkOpSegment::AlignedSpan> aligned; |
681 checkTiny(contourList); | 710 if (hasM) { |
682 checkSmall(contourList); | 711 alignMultiples(contourList, &aligned); // align pairs of identical poin
ts |
683 joinCoincidence(contourList); | 712 alignCoincidence(contourList, aligned); |
| 713 } |
| 714 checkDuplicates(contourList); // check if spans have the same number on the
other end |
| 715 checkTiny(contourList); // if pair have the same end points, mark them as p
arallel |
| 716 checkSmall(contourList); // a pair of curves with a small span may turn int
o coincident lines |
| 717 joinCoincidence(contourList); // join curves that connect to a coincident p
air |
684 sortSegments(contourList); | 718 sortSegments(contourList); |
685 if (!calcAngles(contourList)) { | 719 if (!calcAngles(contourList)) { |
686 return false; | 720 return false; |
687 } | 721 } |
688 sortAngles(contourList); | 722 sortAngles(contourList); |
689 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY | 723 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY |
690 DebugShowActiveSpans(*contourList); | 724 DebugShowActiveSpans(*contourList); |
691 #endif | 725 #endif |
692 return true; | 726 return true; |
693 } | 727 } |
OLD | NEW |