Index: src/pathops/SkOpAngle.cpp |
=================================================================== |
--- src/pathops/SkOpAngle.cpp (revision 9111) |
+++ src/pathops/SkOpAngle.cpp (working copy) |
@@ -6,12 +6,10 @@ |
*/ |
#include "SkIntersections.h" |
#include "SkOpAngle.h" |
+#include "SkOpSegment.h" |
#include "SkPathOpsCurve.h" |
#include "SkTSort.h" |
-#if DEBUG_SORT || DEBUG_SORT_SINGLE |
-#include "SkOpSegment.h" |
-#endif |
// FIXME: this is bogus for quads and cubics |
// if the quads and cubics' line from end pt to ctrl pt are coincident, |
@@ -31,7 +29,8 @@ |
maybe I could set up LineParameters lazily |
*/ |
-static int simple_compare(double x, double y, double rx, double ry) { |
+static int simple_compare(double x, double y, double rx, double ry, double error) { |
+ SkASSERT(error); |
if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ? |
return y < 0; |
} |
@@ -40,7 +39,7 @@ |
} |
double x_ry = x * ry; |
double rx_y = rx * y; |
- double cmp = x_ry - rx_y; |
+ double cmp = (x_ry - rx_y) * error; |
if (!approximately_zero(cmp)) { |
return cmp < 0; |
} |
@@ -51,12 +50,18 @@ |
return -1; |
} |
+static double gError[] = { |
+ 0, 1, 1.0/2, 1.0/3 |
+}; |
+ |
bool SkOpAngle::operator<(const SkOpAngle& rh) const { |
double x = dx(); |
double y = dy(); |
double rx = rh.dx(); |
double ry = rh.dy(); |
- int simple = simple_compare(x, y, rx, ry); |
+ SkPath::Verb verb = fSegment->verb(); |
+ SkPath::Verb rVerb = rh.fSegment->verb(); |
+ int simple = simple_compare(x, y, rx, ry, gError[verb] * gError[rVerb]); |
if (simple >= 0) { |
return simple; |
} |
@@ -70,16 +75,16 @@ |
return fSide < rh.fSide; |
} |
// see if either curve can be lengthened and try the tangent compare again |
- if (/* cmp && */ (*fSpans)[fEnd].fOther != rh.fSegment // tangents not absolutely identical |
- && (*rh.fSpans)[rh.fEnd].fOther != fSegment) { // and not intersecting |
+ if (fSegment->other(fEnd) != rh.fSegment // tangents not absolutely identical |
+ && rh.fSegment->other(rh.fEnd) != fSegment) { // and not intersecting |
SkOpAngle longer = *this; |
SkOpAngle rhLonger = rh; |
if (longer.lengthen() | rhLonger.lengthen()) { |
return longer < rhLonger; |
} |
} |
- if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y)) |
- || (rh.fVerb == SkPath::kLine_Verb |
+ if ((verb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y)) |
+ || (rVerb == SkPath::kLine_Verb |
&& approximately_zero(rx) && approximately_zero(ry))) { |
// See general unsortable comment below. This case can happen when |
// one line has a non-zero change in t but no change in x and y. |
@@ -87,14 +92,13 @@ |
rh.fUnsortable = true; |
return this < &rh; // even with no solution, return a stable sort |
} |
- if ((*rh.fSpans)[SkMin32(rh.fStart, rh.fEnd)].fTiny |
- || (*fSpans)[SkMin32(fStart, fEnd)].fTiny) { |
+ if (fSegment->isTiny(this) || rh.fSegment->isTiny(&rh)) { |
fUnsortable = true; |
rh.fUnsortable = true; |
return this < &rh; // even with no solution, return a stable sort |
} |
- SkASSERT(fVerb >= SkPath::kQuad_Verb); |
- SkASSERT(rh.fVerb >= SkPath::kQuad_Verb); |
+ SkASSERT(verb >= SkPath::kQuad_Verb); |
+ SkASSERT(rVerb >= SkPath::kQuad_Verb); |
// FIXME: until I can think of something better, project a ray from the |
// end of the shorter tangent to midway between the end points |
// through both curves and use the resulting angle to sort |
@@ -110,14 +114,14 @@ |
do { |
useThis = (len < rlen) ^ flip; |
const SkDCubic& part = useThis ? fCurvePart : rh.fCurvePart; |
- SkPath::Verb partVerb = useThis ? fVerb : rh.fVerb; |
+ SkPath::Verb partVerb = useThis ? verb : rVerb; |
ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(part[1]) ? |
part[2] : part[1]; |
ray[1].fX = (part[0].fX + part[partVerb].fX) / 2; |
ray[1].fY = (part[0].fY + part[partVerb].fY) / 2; |
SkASSERT(ray[0] != ray[1]); |
- roots = (i.*CurveRay[fVerb])(fPts, ray); |
- rroots = (ri.*CurveRay[rh.fVerb])(rh.fPts, ray); |
+ roots = (i.*CurveRay[verb])(fSegment->pts(), ray); |
+ rroots = (ri.*CurveRay[rVerb])(rh.fSegment->pts(), ray); |
} while ((roots == 0 || rroots == 0) && (flip ^= true)); |
if (roots == 0 || rroots == 0) { |
// FIXME: we don't have a solution in this case. The interim solution |
@@ -167,7 +171,7 @@ |
#if 0 |
SkDVector lRay = lLoc - fCurvePart[0]; |
SkDVector rRay = rLoc - fCurvePart[0]; |
- int rayDir = simple_compare(lRay.fX, lRay.fY, rRay.fX, rRay.fY); |
+ int rayDir = simple_compare(lRay.fX, lRay.fY, rRay.fX, rRay.fY, gError[verb] * gError[rVerb]); |
SkASSERT(rayDir >= 0); |
if (rayDir < 0) { |
fUnsortable = true; |
@@ -188,9 +192,13 @@ |
return leftLessThanRight; |
} |
+bool SkOpAngle::isHorizontal() const { |
+ return dy() == 0 && fSegment->verb() == SkPath::kLine_Verb; |
+} |
+ |
bool SkOpAngle::lengthen() { |
int newEnd = fEnd; |
- if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) { |
+ if (fStart < fEnd ? ++newEnd < fSegment->count() : --newEnd >= 0) { |
fEnd = newEnd; |
setSpans(); |
return true; |
@@ -203,7 +211,7 @@ |
return false; |
} |
int newEnd = fStart; |
- if (fStart > fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) { |
+ if (fStart > fEnd ? ++newEnd < fSegment->count() : --newEnd >= 0) { |
fEnd = newEnd; |
fReversed = true; |
setSpans(); |
@@ -217,9 +225,10 @@ |
fSegment = segment; |
fStart = start; |
fEnd = end; |
- fPts = orig; |
- fVerb = verb; |
- fSpans = &spans; |
+ if (fSegment->isTiny(this) && (start == 0 || end == fSegment->count() - 1)) { |
+ fUnsortable = true; |
+ return; |
+ } |
fReversed = false; |
fUnsortable = false; |
setSpans(); |
@@ -227,18 +236,15 @@ |
void SkOpAngle::setSpans() { |
- double startT = (*fSpans)[fStart].fT; |
- double endT = (*fSpans)[fEnd].fT; |
- switch (fVerb) { |
+ fSegment->subDivide(fStart, fEnd, &fCurvePart); |
+ switch (fSegment->verb()) { |
case SkPath::kLine_Verb: { |
- SkDLine l = SkDLine::SubDivide(fPts, startT, endT); |
// OPTIMIZATION: for pure line compares, we never need fTangent1.c |
- fTangent1.lineEndPoints(l); |
+ fTangent1.lineEndPoints(*SkTCast<SkDLine*>(&fCurvePart)); |
fSide = 0; |
} break; |
case SkPath::kQuad_Verb: { |
SkDQuad& quad = *SkTCast<SkDQuad*>(&fCurvePart); |
- quad = SkDQuad::SubDivide(fPts, startT, endT); |
fTangent1.quadEndPoints(quad, 0, 1); |
if (dx() == 0 && dy() == 0) { |
fTangent1.quadEndPoints(quad); |
@@ -247,7 +253,6 @@ |
} break; |
case SkPath::kCubic_Verb: { |
// int nextC = 2; |
- fCurvePart = SkDCubic::SubDivide(fPts, startT, endT); |
fTangent1.cubicEndPoints(fCurvePart, 0, 1); |
if (dx() == 0 && dy() == 0) { |
fTangent1.cubicEndPoints(fCurvePart, 0, 2); |
@@ -262,7 +267,10 @@ |
// } |
double testTs[4]; |
// OPTIMIZATION: keep inflections precomputed with cubic segment? |
- int testCount = SkDCubic::FindInflections(fPts, testTs); |
+ 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; |
for (index = 0; index < testCount; ++index) { |
@@ -287,7 +295,7 @@ |
testT = (testT + testTs[testIndex + 1]) / 2; |
} |
// OPTIMIZE: could avoid call for t == startT, endT |
- SkDPoint pt = dcubic_xy_at_t(fPts, testT); |
+ SkDPoint pt = dcubic_xy_at_t(pts, testT); |
double testSide = fTangent1.pointDistance(pt); |
if (fabs(bestSide) < fabs(testSide)) { |
bestSide = testSide; |
@@ -306,16 +314,16 @@ |
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 = (*fSpans)[index]; |
- const SkOpSpan& nextSpan = (*fSpans)[index + step]; |
+ 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 = (*CurvePointAtT[fVerb])(fPts, thisSpan.fT); |
- SkPoint ePt = (*CurvePointAtT[fVerb])(fPts, nextSpan.fT); |
+ 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); |
} |
@@ -330,8 +338,8 @@ |
} |
#if 1 |
#if DEBUG_UNSORTABLE |
- SkPoint iPt = (*CurvePointAtT[fVerb])(fPts, startT); |
- SkPoint ePt = (*CurvePointAtT[fVerb])(fPts, endT); |
+ 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 |