| /* | 
 |  * Copyright 2012 Google Inc. | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 | add unit test for quadratic horizontal intersection | 
 | add unit test for cubic horizontal intersection with left/right | 
 | add unit test for ActiveEdge::calcLeft (can currently loop forever) | 
 | does ActiveEdge::isCoincidentWith need to support quad, cubic? | 
 | figure out why variation in ActiveEdge::tooCloseToCall isn't better | 
 | why does 'lastPtr - 2' in addIntersectingTs break testSimplifyTriangle22? | 
 | add code to promote quad to cubic, or add quad/cubic intersection | 
 | figure out why testSimplifySkinnyTriangle13 fails | 
 |  | 
 | for quadratics and cubics, once various T values are added, see if consecutive | 
 | Ts have ys that go up instead of down. If so, the edge needs to be broken. | 
 |  | 
 | when splitting curves at inflection pts, should I retain the original curve | 
 | data and note that the first/last T are no longer 0/1 ? | 
 | I need to figure this out before I can proceed | 
 |  | 
 | would it make sense to leave the InEdge alone, and add multiple copies of | 
 | ActiveEdge, pointing to the same InEdge, where the copy has only the subset | 
 | of Ts that need to be walked in reverse order? | 
 |  | 
 |  | 
 | -- A Digression Which Shows Why Resolving Coincidence Does Not Make Sense -- | 
 |  | 
 | Consider the following fine ASCII art: | 
 |  | 
 |   +------>-------+       +------>-------+ | 
 |   |              |       |              | | 
 |   ^              V       ^              V | 
 |   |              |       |              | | 
 |   +------<-------+       +------<-------+ | 
 |   +------>-------+       +------<-------+ | 
 |   |              |       |              | | 
 |   ^              V       V              ^ | 
 |   |              |       |              | | 
 |   +------<-------+       +------>-------+ | 
 |  | 
 | (assume the bottom and top of the stacked rectangles are coincident) | 
 |  | 
 | Simplifying said rectangles, regardless of rectangle direction, and regardless | 
 | of winding or even/odd, eliminates the coincident edge, i.e., the result is | 
 | always: | 
 |  | 
 |   +------>-------+ | 
 |   |              | | 
 |   |              | | 
 |   |              | | 
 |   ^              V | 
 |   |              | | 
 |   |              | | 
 |   |              | | 
 |   +------<-------+ | 
 |  | 
 | But when the rectangles are enclosed in a larger rectangle: | 
 |  | 
 | +-------->---------+    +-------->---------+ | 
 | | +------>-------+ |    | +------>-------+ | | 
 | | |              | |    | |              | | | 
 | | ^              V |    | ^              V | | 
 | | |              | |    | |              | | | 
 | | +------<-------+ |    | +------<-------+ | | 
 | | +------>-------+ |    | +------<-------+ | | 
 | | |              | |    | |              | | | 
 | | ^              V |    | V              ^ | | 
 | | |              | |    | |              | | | 
 | | +------<-------+ |    | +------>-------+ | | 
 | +--------<---------+    +--------<---------+ | 
 |  | 
 | Simplifying them gives different results depending on the winding setting: | 
 |  | 
 | winding: | 
 | +-------->---------+    +-------->---------+ | 
 | |                  |    |                  | | 
 | |                  |    |                  | | 
 | |                  |    |                  | | 
 | |                  |    |                  | | 
 | |                  |    | +------<-------+ | | 
 | |                  |    | |              | | | 
 | |                  |    | V              ^ | | 
 | |                  |    | |              | | | 
 | |                  |    | +------>-------+ | | 
 | +--------<---------+    +--------<---------+ | 
 |  | 
 | even odd: | 
 | +-------->---------+    +-------->---------+ | 
 | | +------<-------+ |    | +------<-------+ | | 
 | | |              | |    | |              | | | 
 | | |              | |    | |              | | | 
 | | |              | |    | |              | | | 
 | | |              | |    | |              | | | 
 | | V              ^ |    | V              ^ | | 
 | | |              | |    | |              | | | 
 | | |              | |    | |              | | | 
 | | |              | |    | |              | | | 
 | | +------>-------+ |    | +------>-------+ | | 
 | +--------<---------+    +--------<---------+ | 
 |  | 
 | So, given the inner rectangles alone (e.g., given coincident pairs in some local | 
 | context), we can't know whether to keep the coincident edges or not. | 
 |  | 
 |  | 
 | -- Thoughts About Sortless Ops -- | 
 |  | 
 | I can't come up with anything truly sortless. It seems that the crossings need | 
 | to be sorted to know which segment is next on the outside, although sometimes | 
 | we can use that it is not coincident just to follow the direction. | 
 |  | 
 | If it is coincident or if there's more than two crossing segments, sorting | 
 | seems inevitable. | 
 |  | 
 | Likewise, to resolve whether one contour is inside another, it seems that | 
 | sorting is required. Given a pair of segments on different contours, to know | 
 | if one is inside of the other, I need to know for each which side of the edge | 
 | is the inside/filled side. When the outer contour is walked, it seems like I | 
 | could record the inside info. I guess when the inner contour is found, its | 
 | inside sense is reversed (inside is above the top). But how do I know if the | 
 | next contour is inside another? Maybe shoot out a line and brute-force | 
 | intersect it with all the segments in all the other contours? If every contour | 
 | has an extra segment when the intersections are computed, this may not be as | 
 | crazy as it seems. | 
 |  | 
 | Suppose each contour has one extra segment shooting straight up from the top | 
 | (or straight up from any point on the segment). This ray is not intersected | 
 | with the home contour, but is intersected with all other contours as part of | 
 | the normal intersection engine. If it is possible to get from the T values to | 
 | the other segments to the other contours, it would be straightforward to | 
 | count the contour crossings and determine if the home contour is in another | 
 | contour or not (if the count is even, not, if odd, is inside). By itself that | 
 | doesn't tell us about winding, but it's a start. | 
 |  | 
 |  | 
 | Since intersecting these rays is unrelated to computing other intersections, | 
 | it can be lazily done once the contour is found. | 
 |  | 
 | So | 
 | repeat the following | 
 | find the top segment of all contours | 
 | trace the outside, marking touching first and last segments as inside | 
 | continue tracing the touched segments with reversed outside/inside sense | 
 | once the edges are exhausted, remaining must be disjoint contours | 
 | send a ray from a disjoint point through all other contours | 
 | count the crossings, determine if disjoint is inside or outside, then continue | 
 |  | 
 | === | 
 |  | 
 | On Quadratic (and Cubic) Intersections | 
 |  | 
 | Currently, if only the end points touch, QuadracticIntersections does a lot of | 
 | work to figure that out. Can I test for that up front, then short circuit the | 
 | recursive search for the end points? | 
 |  | 
 | Or, is there something defective in the current approach that makes the end | 
 | point recursion go so deep? I'm seeing 56 stack frames (about 28 divides, but | 
 | thankfully, no splits) to find one matching endpoint. | 
 |  | 
 |  | 
 | Bezier curve focus may allow more quickly determining that end points with | 
 | identical tangents are practically coicident for some range of T, but I don't | 
 | understand the math yet to know. | 
 |  | 
 | Another approach is to determine how flat the curve is to make good guesses | 
 | about how far to move away in T before doing the intersection for the remainder | 
 | and/or to determine whether one curve is to the inside or outside of another. | 
 | According to Mike/Rob, the flatness for quadratics increases by 4 for each | 
 | subdivision, and a crude guess of the curvature can be had by comparing P1 to | 
 | (P0+P2)/2. By looking at the ULPS of the numbers, I can guess what value of | 
 | T may be far enough that the curves diverge but don't cross. | 
 |  | 
 | ==== | 
 |  | 
 | Code I May Not Need Any More | 
 |  | 
 |     static bool CoincidentCandidate(const Angle* current) { | 
 |         const Segment* segment = current->segment(); | 
 |         int min = SkMin32(current->start(), current->end()); | 
 |         do { | 
 |             const Span& span = segment->fTs[min]; | 
 |             if (span.fCoincident == Span::kStart_Coincidence) { | 
 |                 return true; | 
 |             } | 
 |         } while (--min >= 0); | 
 |         return false; | 
 |     } | 
 |  | 
 |     static bool CoincidentHalf(const Angle* current, const Angle* next) { | 
 |         const Segment* other = next->segment(); | 
 |         const Segment* segment = current->segment(); | 
 |         int min = SkMin32(current->start(), current->end()); | 
 |         const Span& minSpan = segment->fTs[min]; | 
 |         if (minSpan.fOther == other) { | 
 |             return minSpan.fCoincident == Span::kStart_Coincidence; | 
 |         } | 
 |         int index = min; | 
 |         int spanCount = segment->fTs.count(); | 
 |         while (++index < spanCount) { | 
 |             const Span& span = segment->fTs[index]; | 
 |             if (minSpan.fT != span.fT) { | 
 |                 break; | 
 |             } | 
 |             if (span.fOther != other) { | 
 |                 continue; | 
 |             } | 
 |             return span.fCoincident == Span::kStart_Coincidence; | 
 |         } | 
 |         index = min; | 
 |         while (--index >= 0) { | 
 |             const Span& span = segment->fTs[index]; | 
 |             if (span.fOther != other) { | 
 |                 continue; | 
 |             } | 
 |             return span.fCoincident == Span::kStart_Coincidence; | 
 |         } | 
 |         return false; | 
 |     } | 
 |      | 
 |     static bool Coincident(const Angle* current, const Angle* next) { | 
 |         return CoincidentHalf(current, next) && | 
 |                 CoincidentHalf(next, current); | 
 |     } | 
 |  | 
 |     // If three lines cancel in a - b - c order, a - b may or may not | 
 |     // eliminate the edge that describes the b - c cancellation. Check done to | 
 |     // determine this. | 
 |     static bool CoincidentCancels(const Angle* current, const Angle* next) { | 
 |         int curMin = SkMin32(current->start(), current->end()); | 
 |         if (current->segment()->fTs[curMin].fDone) { | 
 |             return false; | 
 |         } | 
 |         int nextMin = SkMin32(next->start(), next->end()); | 
 |         if (next->segment()->fTs[nextMin].fDone) { | 
 |             return false; | 
 |         } | 
 |         return SkSign32(current->start() - current->end()) | 
 |                 != SkSign32(next->start() - next->end()); | 
 |     } | 
 |  | 
 |     // FIXME: at this point, just have two functions for the different steps | 
 |     int coincidentEnd(int from, int step) const { | 
 |         double fromT = fTs[from].fT; | 
 |         int count = fTs.count(); | 
 |         int to = from; | 
 |         while (step > 0 ? ++to < count : --to >= 0) { | 
 |             const Span& span = fTs[to]; | 
 |             if ((step > 0 ? span.fT - fromT : fromT - span.fT) >= FLT_EPSILON ) { | 
 |                 // FIXME: we assume that if the T changes, we don't care about  | 
 |                 // coincident -- but in nextSpan, we require that both the T | 
 |                 // and actual loc change to represent a span. This asymettry may | 
 |                 // be OK or may be trouble -- if trouble, probably will need to | 
 |                 // detect coincidence earlier or sort differently  | 
 |                 break; | 
 |             } | 
 | #if 01 | 
 |             if (span.fCoincident == (step < 0 ? Span::kStart_Coincidence : | 
 |                     Span::kEnd_Coincidence)) { | 
 |                 from = to; | 
 |             } | 
 | #else | 
 |             from = to; | 
 | #endif | 
 |         } | 
 |         return from; | 
 |     } | 
 |  | 
 |     // once past current span, if step>0, look for coicident==1 | 
 |     // if step<0, look for coincident==-1 | 
 |     int nextSpanEnd(int from, int step) const { | 
 |         int result = nextSpan(from, step); | 
 |         if (result < 0) { | 
 |             return result; | 
 |         } | 
 |         return coincidentEnd(result, step); | 
 |     } | 
 |  | 
 |      | 
 |     void adjustFirst(const SkTDArray<Angle*>& sorted, int& first, int& winding, | 
 |             bool outside) { | 
 |         int firstIndex = first; | 
 |         int angleCount = sorted.count(); | 
 |         if (true || outside) { | 
 |             const Angle* angle = sorted[firstIndex]; | 
 |             int prior = firstIndex; | 
 |             do { | 
 |                 if (--prior < 0) { | 
 |                     prior = angleCount - 1; | 
 |                 } | 
 |                 if (prior == firstIndex) { // all are coincident with each other | 
 |                     return; | 
 |                 } | 
 |                 if (!Coincident(sorted[prior], sorted[first])) { | 
 |                     return; | 
 |                 } | 
 |                 winding += angle->sign(); | 
 |                 first = prior; | 
 |                 angle = sorted[prior]; | 
 |                 winding -= angle->sign(); | 
 |             } while (true); | 
 |         } | 
 |         do { | 
 |             int next = first + 1; | 
 |             if (next == angleCount) { | 
 |                 next = 0; | 
 |             } | 
 |             if (next == firstIndex) { // all are coincident with each other | 
 |                 return; | 
 |             } | 
 |             if (!Coincident(sorted[first], sorted[next])) { | 
 |                 return; | 
 |             } | 
 |             first = next; | 
 |         } while (true); | 
 |     } | 
 |  | 
 |             bool nextIsCoincident = CoincidentCandidate(nextAngle); | 
 |             bool finalOrNoCoincident = true; | 
 |             bool pairCoincides = false; | 
 |             bool pairCancels = false; | 
 |             if (nextIsCoincident) { | 
 |                 int followIndex = nextIndex + 1; | 
 |                 if (followIndex == angleCount) { | 
 |                     followIndex = 0; | 
 |                 } | 
 |                 const Angle* followAngle = sorted[followIndex]; | 
 |                 finalOrNoCoincident = !Coincident(nextAngle, followAngle); | 
 |                 if ((pairCoincides = Coincident(angle, nextAngle))) { | 
 |                     pairCancels = CoincidentCancels(angle, nextAngle); | 
 |                 } | 
 |             } | 
 |             if (pairCancels && !foundAngle && !nextSegment->done()) { | 
 |                 Segment* aSeg = angle->segment(); | 
 |       //          alreadyMarked |= aSeg == sorted[firstIndex]->segment(); | 
 |                 aSeg->markAndChaseCoincident(angle->start(), angle->end(), | 
 |                         nextSegment); | 
 |                 if (firstEdge) { | 
 |                     return NULL; | 
 |                 } | 
 |             } | 
 |             if (pairCoincides) { | 
 |                 if (pairCancels) { | 
 |                     goto doNext; | 
 |                 } | 
 |                 int minT = SkMin32(nextAngle->start(), nextAngle->end()); | 
 |                 bool markNext = abs(maxWinding) < abs(winding); | 
 |                 if (markNext) { | 
 |                     nextSegment->markDone(minT, winding); | 
 |                 }  | 
 |                 int oldMinT = SkMin32(angle->start(), angle->end()); | 
 |                 if (true || !foundAngle) { | 
 |                  //   SkASSERT(0); // do we ever get here? | 
 |                     Segment* aSeg = angle->segment(); | 
 |         //            alreadyMarked |= aSeg == sorted[firstIndex]->segment(); | 
 |                     aSeg->markDone(oldMinT, maxWinding); | 
 |                 } | 
 |             } | 
 |  | 
 |     // OPTIMIZATION: uses tail recursion. Unwise? | 
 |     void innerCoincidentChase(int step, Segment* other) { | 
 |         // find other at index | 
 |    //     SkASSERT(!done()); | 
 |         const Span* start = NULL; | 
 |         const Span* end = NULL; | 
 |         int index, startIndex, endIndex; | 
 |         int count = fTs.count(); | 
 |         for (index = 0; index < count; ++index) { | 
 |             const Span& span = fTs[index]; | 
 |             if (!span.fCoincident || span.fOther != other) { | 
 |                 continue; | 
 |             } | 
 |             if (!start) { | 
 |                 startIndex = index; | 
 |                 start = &span; | 
 |             } else { | 
 |                 SkASSERT(!end); | 
 |                 endIndex = index; | 
 |                 end = &span; | 
 |             } | 
 |         } | 
 |         if (!end) { | 
 |             return; | 
 |         } | 
 |         bool thisDone = fTs[SkMin32(startIndex, endIndex)].fDone; | 
 |         bool otherDone = other->fTs[SkMin32(start->fOtherIndex, | 
 |                 end->fOtherIndex)].fDone; | 
 |         if (thisDone && otherDone) { | 
 |             return; | 
 |         } | 
 |         Segment* next; | 
 |         Segment* nextOther; | 
 |         if (step < 0) { | 
 |             next = start->fT == 0 ? NULL : this; | 
 |             nextOther = other->fTs[start->fOtherIndex].fT > 1 - FLT_EPSILON ? NULL : other; | 
 |         } else { | 
 |             next = end->fT == 1 ? NULL : this; | 
 |             nextOther = other->fTs[end->fOtherIndex].fT < FLT_EPSILON ? NULL : other; | 
 |         } | 
 |         SkASSERT(!next || !nextOther); | 
 |         for (index = 0; index < count; ++index) { | 
 |             const Span& span = fTs[index]; | 
 |             if (span.fCoincident || span.fOther == other) { | 
 |                 continue; | 
 |             } | 
 |             bool checkNext = !next && (step < 0 ? span.fT < FLT_EPSILON | 
 |                 && span.fOtherT > 1 - FLT_EPSILON : span.fT > 1 - FLT_EPSILON | 
 |                 && span.fOtherT < FLT_EPSILON); | 
 |             bool checkOther = !nextOther && (step < 0 ? fabs(span.fT - start->fT) < FLT_EPSILON | 
 |                 && span.fOtherT < FLT_EPSILON : fabs(span.fT - end->fT) < FLT_EPSILON | 
 |                 && span.fOtherT > 1 - FLT_EPSILON); | 
 |             if (!checkNext && !checkOther) { | 
 |                 continue; | 
 |             } | 
 |             Segment* oSegment = span.fOther; | 
 |             if (oSegment->done()) { | 
 |                 continue; | 
 |             } | 
 |             int oCount = oSegment->fTs.count(); | 
 |             for (int oIndex = 0; oIndex < oCount; ++oIndex) { | 
 |                 const Span& oSpan = oSegment->fTs[oIndex]; | 
 |                 if (oSpan.fT >= FLT_EPSILON && oSpan.fT <= 1 - FLT_EPSILON) { | 
 |                     continue; | 
 |                 } | 
 |                 if (!oSpan.fCoincident) { | 
 |                     continue; | 
 |                 } | 
 |                 if (checkNext && (oSpan.fT < FLT_EPSILON ^ step < 0)) {  | 
 |                     next = oSegment; | 
 |                     checkNext = false; | 
 |                 } | 
 |                 if (checkOther && (oSpan.fT > 1 - FLT_EPSILON ^ step < 0)) { | 
 |                     nextOther = oSegment; | 
 |                     checkOther = false; | 
 |                 } | 
 |             } | 
 |         } | 
 |         // this needs to walk both spans in lock step, skipping edges that | 
 |         // are already marked done on one or the other | 
 |         markCanceled(startIndex, endIndex); | 
 |         if (next && nextOther) { | 
 |             next->innerCoincidentChase(step, nextOther); | 
 |         } | 
 |     } | 
 |  | 
 |     // cancel coincident edges in lock step | 
 |     void markCanceled(int start, int end) { | 
 |         if (done()) { | 
 |             return; | 
 |         } | 
 |         Segment* other = fTs[start].fOther; | 
 |         if (other->done()) { | 
 |             return; | 
 |         } | 
 |         if (start > end) { | 
 |             SkTSwap<int>(start, end); | 
 |         } | 
 |         double maxT = fTs[end].fT - FLT_EPSILON; | 
 |         int spanCount = fTs.count(); | 
 |         // since these cancel, this walks up and other walks down | 
 |         int oStart = fTs[start].fOtherIndex; | 
 |         double oStartT = other->fTs[oStart].fT; | 
 |         while (oStartT - other->fTs[--oStart].fT < FLT_EPSILON) | 
 |             ; | 
 |         double startT = fTs[start].fT; | 
 |         while (start > 0 && startT - fTs[start - 1].fT < FLT_EPSILON) { | 
 |             --start; | 
 |         } | 
 |         do { | 
 |             Span* span = &fTs[start]; | 
 |             Span* oSpan = &other->fTs[oStart]; | 
 |             // find start of each, and see if both are not done | 
 |             bool markDone = !span->fDone && !oSpan->fDone; | 
 |             double spanT = span->fT; | 
 |             do { | 
 |                 if (markDone) { | 
 |                     span->fCanceled = true; | 
 |                 #if DEBUG_MARK_DONE | 
 |                     const SkPoint& pt = xyAtT(span); | 
 |                     SkDebugf("%s segment=%d index=%d t=%1.9g pt=(%1.9g,%1.9g)\n", | 
 |                             __FUNCTION__, fID, start, span->fT, pt.fX, pt.fY); | 
 |                 #endif | 
 |                     SkASSERT(!span->fDone); | 
 |                     span->fDone = true; | 
 |                     span->fWinding = 0; | 
 |                     fDoneSpans++; | 
 |                 } | 
 |                 if (++start == spanCount) { | 
 |                     break; | 
 |                 } | 
 |                 span = &fTs[start]; | 
 |             } while (span->fT - spanT < FLT_EPSILON); | 
 |             double oSpanT = oSpan->fT; | 
 |             do { | 
 |                 if (markDone) { | 
 |                     oSpan->fCanceled = true; | 
 |                 #if DEBUG_MARK_DONE | 
 |                     const SkPoint& oPt = xyAtT(oSpan); | 
 |                     SkDebugf("%s segment=%d index=%d t=%1.9g pt=(%1.9g,%1.9g)\n", | 
 |                             __FUNCTION__, other->fID, oStart, oSpan->fT, | 
 |                             oPt.fX, oPt.fY); | 
 |                 #endif | 
 |                     SkASSERT(!oSpan->fDone); | 
 |                     oSpan->fDone = true; | 
 |                     oSpan->fWinding = 0; | 
 |                     other->fDoneSpans++; | 
 |                 } | 
 |                 if (--oStart < 0) { | 
 |                     break; | 
 |                 } | 
 |                 oSpan = &other->fTs[oStart]; | 
 |             } while (oSpanT - oSpan->fT < FLT_EPSILON); | 
 |         } while (fTs[start].fT <= maxT); | 
 |     } | 
 |  | 
 |     bool canceled(int start, int end) const { | 
 |         int min = SkMin32(start, end); | 
 |         return fTs[min].fCanceled; | 
 |     } | 
 |  | 
 |     void markAndChaseCoincident(int index, int endIndex, Segment* other) { | 
 |         int step = SkSign32(endIndex - index); | 
 |         innerCoincidentChase(step, other); | 
 |     } | 
 |  |