| Index: src/pathops/SkOpAngle.cpp
|
| diff --git a/src/pathops/SkOpAngle.cpp b/src/pathops/SkOpAngle.cpp
|
| index 0dd0d65f79553506e54edd4c9b98f33a97cc5fe8..c1e2eae831062c8abb337b100baeeb8e1d7a1200 100644
|
| --- a/src/pathops/SkOpAngle.cpp
|
| +++ b/src/pathops/SkOpAngle.cpp
|
| @@ -120,13 +120,15 @@ bool SkOpAngle::operator<(const SkOpAngle& rh) const { // this/lh: left-hand; r
|
| return COMPARE_RESULT("10 longer.lengthen(rh) ...", longer < rhLonger);
|
| }
|
| }
|
| + SkPath::Verb verb = fSegment->verb();
|
| + SkPath::Verb rVerb = rh.fSegment->verb();
|
| if (y_ry != 0) { // if they aren't coincident, look for a stable cross product
|
| // at this point, y's are the same sign, neither is zero
|
| // and x's are the same sign, or one (or both) is zero
|
| double x_ry = x * ry;
|
| double rx_y = rx * y;
|
| if (!fComputed && !rh.fComputed) {
|
| - if (!AlmostEqualUlps(x_ry, rx_y)) {
|
| + if (!SkDLine::NearRay(x, y, rx, ry) && x_ry != rx_y) {
|
| return COMPARE_RESULT("7 !fComputed && !rh.fComputed", x_ry < rx_y);
|
| }
|
| } else {
|
| @@ -140,9 +142,9 @@ bool SkOpAngle::operator<(const SkOpAngle& rh) const { // this/lh: left-hand; r
|
| }
|
| }
|
| }
|
| - if (fSide * rh.fSide == 0) {
|
| - SkASSERT(fSide + rh.fSide != 0); // hitting this assert means coincidence was undetected
|
| - return COMPARE_RESULT("9 fSide * rh.fSide == 0 ...", fSide < rh.fSide);
|
| + if (fSide2 * rh.fSide2 == 0) {
|
| +// SkASSERT(fSide2 + rh.fSide2 != 0); // hitting this assert means coincidence was undetected
|
| + return COMPARE_RESULT("9a fSide2 * rh.fSide2 == 0 ...", fSide2 < rh.fSide2);
|
| }
|
| // at this point, the initial tangent line is nearly coincident
|
| // see if edges curl away from each other
|
| @@ -153,8 +155,6 @@ bool SkOpAngle::operator<(const SkOpAngle& rh) const { // this/lh: left-hand; r
|
| // even with no solution, return a stable sort
|
| return COMPARE_RESULT("11 fUnsortable || rh.fUnsortable", this < &rh);
|
| }
|
| - SkPath::Verb verb = fSegment->verb();
|
| - SkPath::Verb rVerb = rh.fSegment->verb();
|
| if ((verb == SkPath::kLine_Verb && approximately_zero(y) && approximately_zero(x))
|
| || (rVerb == SkPath::kLine_Verb
|
| && approximately_zero(ry) && approximately_zero(rx))) {
|
| @@ -173,8 +173,8 @@ bool SkOpAngle::operator<(const SkOpAngle& rh) const { // this/lh: left-hand; r
|
| // end of the shorter tangent to midway between the end points
|
| // through both curves and use the resulting angle to sort
|
| // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
|
| - double len = fTangent1.normalSquared();
|
| - double rlen = rh.fTangent1.normalSquared();
|
| + double len = fTangentPart.normalSquared();
|
| + double rlen = rh.fTangentPart.normalSquared();
|
| SkDLine ray;
|
| SkIntersections i, ri;
|
| int roots, rroots;
|
| @@ -269,62 +269,53 @@ void SkOpAngle::set(const SkOpSegment* segment, int start, int end) {
|
| }
|
|
|
| void SkOpAngle::setSpans() {
|
| - fUnorderable = false;
|
| - if (fSegment->verb() == SkPath::kLine_Verb) {
|
| - fUnsortable = false;
|
| - } else {
|
| - // if start-1 exists and is tiny, then start pt may have moved
|
| - int smaller = SkMin32(fStart, fEnd);
|
| - int tinyCheck = smaller;
|
| - while (tinyCheck > 0 && fSegment->isTiny(tinyCheck - 1)) {
|
| - --tinyCheck;
|
| - }
|
| - if ((fUnsortable = smaller > 0 && tinyCheck == 0)) {
|
| - return;
|
| - }
|
| - int larger = SkMax32(fStart, fEnd);
|
| - tinyCheck = larger;
|
| - int max = fSegment->count() - 1;
|
| - while (tinyCheck < max && fSegment->isTiny(tinyCheck + 1)) {
|
| - ++tinyCheck;
|
| - }
|
| - if ((fUnsortable = larger < max && tinyCheck == max)) {
|
| - return;
|
| - }
|
| + fUnorderable = fSegment->isTiny(this);
|
| + fLastMarked = NULL;
|
| + fUnsortable = false;
|
| + const SkPoint* pts = fSegment->pts();
|
| + if (fSegment->verb() != SkPath::kLine_Verb) {
|
| + fComputed = fSegment->subDivide(fStart, fEnd, &fCurvePart);
|
| + fSegment->subDivide(fStart, fStart < fEnd ? fSegment->count() - 1 : 0, &fCurveHalf);
|
| }
|
| - fComputed = fSegment->subDivide(fStart, fEnd, &fCurvePart);
|
| // FIXME: slight errors in subdivision cause sort trouble later on. As an experiment, try
|
| // rounding the curve part to float precision here
|
| // fCurvePart.round(fSegment->verb());
|
| switch (fSegment->verb()) {
|
| case SkPath::kLine_Verb: {
|
| - // OPTIMIZATION: for pure line compares, we never need fTangent1.c
|
| - fTangent1.lineEndPoints(*SkTCast<SkDLine*>(&fCurvePart));
|
| + SkASSERT(fStart != fEnd);
|
| + fCurvePart[0].set(pts[fStart > fEnd]);
|
| + fCurvePart[1].set(pts[fStart < fEnd]);
|
| + fComputed = false;
|
| + // OPTIMIZATION: for pure line compares, we never need fTangentPart.c
|
| + fTangentPart.lineEndPoints(*SkTCast<SkDLine*>(&fCurvePart));
|
| fSide = 0;
|
| + fSide2 = 0;
|
| } break;
|
| case SkPath::kQuad_Verb: {
|
| + fSide2 = -fTangentHalf.quadPart(*SkTCast<SkDQuad*>(&fCurveHalf));
|
| SkDQuad& quad = *SkTCast<SkDQuad*>(&fCurvePart);
|
| - fTangent1.quadEndPoints(quad);
|
| - fSide = -fTangent1.pointDistance(fCurvePart[2]); // not normalized -- compare sign only
|
| + fTangentPart.quadEndPoints(quad);
|
| + fSide = -fTangentPart.pointDistance(fCurvePart[2]); // not normalized -- compare sign only
|
| if (fComputed && dx() > 0 && approximately_zero(dy())) {
|
| SkDCubic origCurve; // can't use segment's curve in place since it may be flipped
|
| int last = fSegment->count() - 1;
|
| fSegment->subDivide(fStart < fEnd ? 0 : last, fStart < fEnd ? last : 0, &origCurve);
|
| SkLineParameters origTan;
|
| origTan.quadEndPoints(*SkTCast<SkDQuad*>(&origCurve));
|
| - if ((fUnorderable = origTan.dx() <= 0
|
| - || (dy() != origTan.dy() && dy() * origTan.dy() <= 0))) { // signs match?
|
| + if (origTan.dx() <= 0
|
| + || (dy() != origTan.dy() && dy() * origTan.dy() <= 0)) { // signs match?
|
| + fUnorderable = true;
|
| return;
|
| }
|
| }
|
| } break;
|
| case SkPath::kCubic_Verb: {
|
| - fTangent1.cubicEndPoints(fCurvePart);
|
| + double startT = fSegment->t(fStart);
|
| + fSide2 = -fTangentHalf.cubicPart(fCurveHalf);
|
| + fTangentPart.cubicEndPoints(fCurvePart);
|
| double testTs[4];
|
| // OPTIMIZATION: keep inflections precomputed with cubic segment?
|
| - const SkPoint* pts = fSegment->pts();
|
| int testCount = SkDCubic::FindInflections(pts, testTs);
|
| - double startT = fSegment->t(fStart);
|
| double endT = fSegment->t(fEnd);
|
| double limitT = endT;
|
| int index;
|
| @@ -351,36 +342,28 @@ void SkOpAngle::setSpans() {
|
| }
|
| // OPTIMIZE: could avoid call for t == startT, endT
|
| SkDPoint pt = dcubic_xy_at_t(pts, testT);
|
| - double testSide = fTangent1.pointDistance(pt);
|
| + double testSide = fTangentPart.pointDistance(pt);
|
| if (fabs(bestSide) < fabs(testSide)) {
|
| bestSide = testSide;
|
| }
|
| }
|
| fSide = -bestSide; // compare sign only
|
| + SkASSERT(fSide == 0 || fSide2 != 0);
|
| if (fComputed && dx() > 0 && approximately_zero(dy())) {
|
| SkDCubic origCurve; // can't use segment's curve in place since it may be flipped
|
| int last = fSegment->count() - 1;
|
| fSegment->subDivide(fStart < fEnd ? 0 : last, fStart < fEnd ? last : 0, &origCurve);
|
| - SkLineParameters origTan;
|
| - origTan.cubicEndPoints(origCurve);
|
| - if ((fUnorderable = origTan.dx() <= 0)) {
|
| - fUnsortable = fSegment->isTiny(this);
|
| - return;
|
| - }
|
| - // if one is < 0 and the other is >= 0
|
| - if ((fUnorderable = (dy() < 0) ^ (origTan.dy() < 0))) {
|
| - fUnsortable = fSegment->isTiny(this);
|
| - return;
|
| - }
|
| SkDCubicPair split = origCurve.chopAt(startT);
|
| SkLineParameters splitTan;
|
| splitTan.cubicEndPoints(fStart < fEnd ? split.second() : split.first());
|
| - if ((fUnorderable = splitTan.dx() <= 0)) {
|
| + if (splitTan.dx() <= 0) {
|
| + fUnorderable = true;
|
| fUnsortable = fSegment->isTiny(this);
|
| return;
|
| }
|
| // if one is < 0 and the other is >= 0
|
| - if ((fUnorderable = (dy() < 0) ^ (splitTan.dy() < 0))) {
|
| + if (dy() * splitTan.dy() < 0) {
|
| + fUnorderable = true;
|
| fUnsortable = fSegment->isTiny(this);
|
| return;
|
| }
|
| @@ -392,39 +375,42 @@ void SkOpAngle::setSpans() {
|
| if ((fUnsortable = approximately_zero(dx()) && approximately_zero(dy()))) {
|
| return;
|
| }
|
| + if (fSegment->verb() == SkPath::kLine_Verb) {
|
| + return;
|
| + }
|
| SkASSERT(fStart != fEnd);
|
| - int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 type macro?
|
| - for (int index = fStart; index != fEnd; index += step) {
|
| -#if 1
|
| - const SkOpSpan& thisSpan = fSegment->span(index);
|
| - const SkOpSpan& nextSpan = fSegment->span(index + step);
|
| - if (thisSpan.fTiny || precisely_equal(thisSpan.fT, nextSpan.fT)) {
|
| - continue;
|
| - }
|
| - fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortableEnd;
|
| -#if DEBUG_UNSORTABLE
|
| - if (fUnsortable) {
|
| - SkPoint iPt = fSegment->xyAtT(index);
|
| - SkPoint ePt = fSegment->xyAtT(index + step);
|
| - SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
|
| - index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
|
| - }
|
| -#endif
|
| + int smaller = SkMin32(fStart, fEnd);
|
| + int larger = SkMax32(fStart, fEnd);
|
| + while (smaller < larger && fSegment->span(smaller).fTiny) {
|
| + ++smaller;
|
| + }
|
| + if (precisely_equal(fSegment->span(smaller).fT, fSegment->span(larger).fT)) {
|
| + #if DEBUG_UNSORTABLE
|
| + SkPoint iPt = fSegment->xyAtT(fStart);
|
| + SkPoint ePt = fSegment->xyAtT(fEnd);
|
| + SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
|
| + fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
|
| + #endif
|
| + fUnsortable = true;
|
| return;
|
| -#else
|
| - if ((*fSpans)[index].fUnsortableStart) {
|
| - fUnsortable = true;
|
| - return;
|
| - }
|
| -#endif
|
| }
|
| -#if 1
|
| + fUnsortable = fStart < fEnd ? fSegment->span(smaller).fUnsortableStart
|
| + : fSegment->span(larger).fUnsortableEnd;
|
| #if DEBUG_UNSORTABLE
|
| - SkPoint iPt = fSegment->xyAtT(fStart);
|
| - SkPoint ePt = fSegment->xyAtT(fEnd);
|
| - SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
|
| - fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
|
| -#endif
|
| - fUnsortable = true;
|
| + if (fUnsortable) {
|
| + SkPoint iPt = fSegment->xyAtT(smaller);
|
| + SkPoint ePt = fSegment->xyAtT(larger);
|
| + SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
|
| + smaller, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
|
| + }
|
| #endif
|
| + return;
|
| +}
|
| +
|
| +#ifdef SK_DEBUG
|
| +void SkOpAngle::dump() const {
|
| + SkDebugf("id=%d (%1.9g,%1.9g) start=%d (%1.9g) end=%d (%1.9g)\n", fSegment->debugID(),
|
| + fSegment->xAtT(fStart), fSegment->yAtT(fStart), fStart, fSegment->span(fStart).fT,
|
| + fEnd, fSegment->span(fEnd).fT);
|
| }
|
| +#endif
|
|
|