| Index: src/pathops/SkOpSegment.cpp
|
| diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp
|
| index 462cff60cf639cc37738ff0732a5b40c48126310..fd8ab65acd200f5f534ee01ebfe322dcdb0da23d 100644
|
| --- a/src/pathops/SkOpSegment.cpp
|
| +++ b/src/pathops/SkOpSegment.cpp
|
| @@ -159,6 +159,87 @@ bool SkOpSegment::activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sum
|
| return result;
|
| }
|
|
|
| +void SkOpSegment::addAlignIntersection(SkOpPtT& endPtT, SkPoint& oldPt,
|
| + SkOpContourHead* contourList, SkChunkAlloc* allocator) {
|
| + const SkPoint& newPt = endPtT.fPt;
|
| + if (newPt == oldPt) {
|
| + return;
|
| + }
|
| + SkPoint line[2] = { newPt, oldPt };
|
| + SkPathOpsBounds lineBounds;
|
| + lineBounds.setBounds(line, 2);
|
| + SkDLine aLine;
|
| + aLine.set(line);
|
| + SkOpContour* current = contourList;
|
| + do {
|
| + if (!SkPathOpsBounds::Intersects(current->bounds(), lineBounds)) {
|
| + continue;
|
| + }
|
| + SkOpSegment* segment = current->first();
|
| + do {
|
| + if (!SkPathOpsBounds::Intersects(segment->bounds(), lineBounds)) {
|
| + continue;
|
| + }
|
| + if (newPt == segment->fPts[0]) {
|
| + continue;
|
| + }
|
| + if (newPt == segment->fPts[SkPathOpsVerbToPoints(segment->fVerb)]) {
|
| + continue;
|
| + }
|
| + if (oldPt == segment->fPts[0]) {
|
| + continue;
|
| + }
|
| + if (oldPt == segment->fPts[SkPathOpsVerbToPoints(segment->fVerb)]) {
|
| + continue;
|
| + }
|
| + if (endPtT.contains(segment)) {
|
| + continue;
|
| + }
|
| + SkIntersections i;
|
| + switch (segment->fVerb) {
|
| + case SkPath::kLine_Verb: {
|
| + SkDLine bLine;
|
| + bLine.set(segment->fPts);
|
| + i.intersect(bLine, aLine);
|
| + } break;
|
| + case SkPath::kQuad_Verb: {
|
| + SkDQuad bQuad;
|
| + bQuad.set(segment->fPts);
|
| + i.intersect(bQuad, aLine);
|
| + } break;
|
| + case SkPath::kConic_Verb: {
|
| + SkDConic bConic;
|
| + bConic.set(segment->fPts, segment->fWeight);
|
| + i.intersect(bConic, aLine);
|
| + } break;
|
| + case SkPath::kCubic_Verb: {
|
| + SkDCubic bCubic;
|
| + bCubic.set(segment->fPts);
|
| + i.intersect(bCubic, aLine);
|
| + } break;
|
| + default:
|
| + SkASSERT(0);
|
| + }
|
| + if (i.used()) {
|
| + SkASSERT(i.used() == 1);
|
| + SkASSERT(!zero_or_one(i[0][0]));
|
| + SkOpSpanBase* checkSpan = fHead.next();
|
| + while (!checkSpan->final()) {
|
| + if (checkSpan->contains(segment)) {
|
| + goto nextSegment;
|
| + }
|
| + checkSpan = checkSpan->upCast()->next();
|
| + }
|
| + SkOpPtT* ptT = segment->addT(i[0][0], SkOpSegment::kAllowAlias, allocator);
|
| + ptT->fPt = newPt;
|
| + endPtT.addOpp(ptT);
|
| + }
|
| + nextSegment:
|
| + ;
|
| + } while ((segment = segment->next()));
|
| + } while ((current = current->next()));
|
| +}
|
| +
|
| void SkOpSegment::addCurveTo(const SkOpSpanBase* start, const SkOpSpanBase* end,
|
| SkPathWriter* path, bool active) const {
|
| SkOpCurve edge;
|
| @@ -770,7 +851,7 @@ SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** n
|
| SkASSERT(start != endNear);
|
| SkASSERT((start->t() < endNear->t()) ^ (step < 0));
|
| SkOpAngle* angle = this->spanToAngle(end, start);
|
| - if (angle->unorderable()) {
|
| + if (!angle || angle->unorderable()) {
|
| *unsortable = true;
|
| markDone(start->starter(end));
|
| return NULL;
|
| @@ -817,6 +898,8 @@ SkOpGlobalState* SkOpSegment::globalState() const {
|
| void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkPath::Verb verb) {
|
| fContour = contour;
|
| fNext = NULL;
|
| + fOriginal[0] = pts[0];
|
| + fOriginal[1] = pts[SkPathOpsVerbToPoints(verb)];
|
| fPts = pts;
|
| fWeight = weight;
|
| fVerb = verb;
|
| @@ -1113,12 +1196,12 @@ static void clear_visited(SkOpSpanBase* span) {
|
| // curve/curve intersection should now do a pretty good job of finding coincident runs so
|
| // this may be only be necessary for line/curve pairs -- so skip unless this is a line and the
|
| // the opp is not a line
|
| -void SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc* allocator) {
|
| +bool SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc* allocator) {
|
| if (this->verb() != SkPath::kLine_Verb) {
|
| - return;
|
| + return false;
|
| }
|
| if (this->done()) {
|
| - return;
|
| + return false;
|
| }
|
| SkOpSpan* prior = NULL;
|
| SkOpSpanBase* spanBase = &fHead;
|
| @@ -1186,34 +1269,7 @@ void SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc
|
| if (coincidences->contains(priorPtT, ptT, oppStart, oppEnd, flipped)) {
|
| goto swapBack;
|
| }
|
| - {
|
| - // average t, find mid pt
|
| - double midT = (prior->t() + spanBase->t()) / 2;
|
| - SkPoint midPt = this->ptAtT(midT);
|
| - coincident = true;
|
| - // if the mid pt is not near either end pt, project perpendicular through opp seg
|
| - if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
|
| - && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
|
| - coincident = false;
|
| - SkIntersections i;
|
| - SkVector dxdy = (*CurveSlopeAtT[fVerb])(this->pts(), this->weight(), midT);
|
| - SkDLine ray = {{{midPt.fX, midPt.fY},
|
| - {midPt.fX + dxdy.fY, midPt.fY - dxdy.fX}}};
|
| - (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), ray, &i);
|
| - // measure distance and see if it's small enough to denote coincidence
|
| - for (int index = 0; index < i.used(); ++index) {
|
| - SkDPoint oppPt = i.pt(index);
|
| - if (oppPt.approximatelyEqual(midPt)) {
|
| - SkVector oppDxdy = (*CurveSlopeAtT[opp->verb()])(opp->pts(),
|
| - opp->weight(), i[index][0]);
|
| - oppDxdy.normalize();
|
| - dxdy.normalize();
|
| - SkScalar flatness = SkScalarAbs(dxdy.cross(oppDxdy) / FLT_EPSILON);
|
| - coincident |= flatness < 5000; // FIXME: replace with tuned value
|
| - }
|
| - }
|
| - }
|
| - }
|
| + coincident = testForCoincidence(priorPtT, ptT, prior, spanBase, opp, 5000);
|
| if (coincident) {
|
| // mark coincidence
|
| if (!coincidences->extend(priorPtT, ptT, oppStart, oppEnd)
|
| @@ -1221,7 +1277,7 @@ void SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc
|
| coincidences->add(priorPtT, ptT, oppStart, oppEnd, allocator);
|
| }
|
| clear_visited(&fHead);
|
| - return;
|
| + return true;
|
| }
|
| swapBack:
|
| if (swapped) {
|
| @@ -1230,6 +1286,7 @@ void SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc
|
| }
|
| } while ((spanBase = spanBase->final() ? NULL : spanBase->upCast()->next()));
|
| clear_visited(&fHead);
|
| + return false;
|
| }
|
|
|
| // if a span has more than one intersection, merge the other segments' span as needed
|
| @@ -1607,6 +1664,37 @@ bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
|
| return true;
|
| }
|
|
|
| +bool SkOpSegment::testForCoincidence(const SkOpPtT* priorPtT, const SkOpPtT* ptT,
|
| + const SkOpSpanBase* prior, const SkOpSpanBase* spanBase, const SkOpSegment* opp,
|
| + SkScalar flatnessLimit) const {
|
| + // average t, find mid pt
|
| + double midT = (prior->t() + spanBase->t()) / 2;
|
| + SkPoint midPt = this->ptAtT(midT);
|
| + bool coincident = true;
|
| + // if the mid pt is not near either end pt, project perpendicular through opp seg
|
| + if (!SkDPoint::ApproximatelyEqual(priorPtT->fPt, midPt)
|
| + && !SkDPoint::ApproximatelyEqual(ptT->fPt, midPt)) {
|
| + coincident = false;
|
| + SkIntersections i;
|
| + SkVector dxdy = (*CurveSlopeAtT[fVerb])(this->pts(), this->weight(), midT);
|
| + SkDLine ray = {{{midPt.fX, midPt.fY}, {midPt.fX + dxdy.fY, midPt.fY - dxdy.fX}}};
|
| + (*CurveIntersectRay[opp->verb()])(opp->pts(), opp->weight(), ray, &i);
|
| + // measure distance and see if it's small enough to denote coincidence
|
| + for (int index = 0; index < i.used(); ++index) {
|
| + SkDPoint oppPt = i.pt(index);
|
| + if (oppPt.approximatelyEqual(midPt)) {
|
| + SkVector oppDxdy = (*CurveSlopeAtT[opp->verb()])(opp->pts(),
|
| + opp->weight(), i[index][0]);
|
| + oppDxdy.normalize();
|
| + dxdy.normalize();
|
| + SkScalar flatness = SkScalarAbs(dxdy.cross(oppDxdy) / FLT_EPSILON);
|
| + coincident |= flatness < flatnessLimit;
|
| + }
|
| + }
|
| + }
|
| + return coincident;
|
| +}
|
| +
|
| void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) {
|
| SkOpSpan* span = this->head();
|
| do {
|
|
|