gfx/skia/trunk/src/pathops/SkOpAngle.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /*
michael@0 2 * Copyright 2012 Google Inc.
michael@0 3 *
michael@0 4 * Use of this source code is governed by a BSD-style license that can be
michael@0 5 * found in the LICENSE file.
michael@0 6 */
michael@0 7 #include "SkIntersections.h"
michael@0 8 #include "SkOpAngle.h"
michael@0 9 #include "SkOpSegment.h"
michael@0 10 #include "SkPathOpsCurve.h"
michael@0 11 #include "SkTSort.h"
michael@0 12
michael@0 13 #if DEBUG_ANGLE
michael@0 14 #include "SkString.h"
michael@0 15
michael@0 16 static const char funcName[] = "SkOpSegment::operator<";
michael@0 17 static const int bugChar = strlen(funcName) + 1;
michael@0 18 #endif
michael@0 19
michael@0 20 /* Angles are sorted counterclockwise. The smallest angle has a positive x and the smallest
michael@0 21 positive y. The largest angle has a positive x and a zero y. */
michael@0 22
michael@0 23 #if DEBUG_ANGLE
michael@0 24 static bool CompareResult(SkString* bugOut, const char* append, bool compare) {
michael@0 25 bugOut->appendf("%s", append);
michael@0 26 bugOut->writable_str()[bugChar] = "><"[compare];
michael@0 27 SkDebugf("%s\n", bugOut->c_str());
michael@0 28 return compare;
michael@0 29 }
michael@0 30
michael@0 31 #define COMPARE_RESULT(append, compare) CompareResult(&bugOut, append, compare)
michael@0 32 #else
michael@0 33 #define COMPARE_RESULT(append, compare) compare
michael@0 34 #endif
michael@0 35
michael@0 36 bool SkOpAngle::calcSlop(double x, double y, double rx, double ry, bool* result) const{
michael@0 37 double absX = fabs(x);
michael@0 38 double absY = fabs(y);
michael@0 39 double length = absX < absY ? absX / 2 + absY : absX + absY / 2;
michael@0 40 int exponent;
michael@0 41 (void) frexp(length, &exponent);
michael@0 42 double epsilon = ldexp(FLT_EPSILON, exponent);
michael@0 43 SkPath::Verb verb = fSegment->verb();
michael@0 44 SkASSERT(verb == SkPath::kQuad_Verb || verb == SkPath::kCubic_Verb);
michael@0 45 // FIXME: the quad and cubic factors are made up ; determine actual values
michael@0 46 double slop = verb == SkPath::kQuad_Verb ? 4 * epsilon : 512 * epsilon;
michael@0 47 double xSlop = slop;
michael@0 48 double ySlop = x * y < 0 ? -xSlop : xSlop; // OPTIMIZATION: use copysign / _copysign ?
michael@0 49 double x1 = x - xSlop;
michael@0 50 double y1 = y + ySlop;
michael@0 51 double x_ry1 = x1 * ry;
michael@0 52 double rx_y1 = rx * y1;
michael@0 53 *result = x_ry1 < rx_y1;
michael@0 54 double x2 = x + xSlop;
michael@0 55 double y2 = y - ySlop;
michael@0 56 double x_ry2 = x2 * ry;
michael@0 57 double rx_y2 = rx * y2;
michael@0 58 bool less2 = x_ry2 < rx_y2;
michael@0 59 return *result == less2;
michael@0 60 }
michael@0 61
michael@0 62 /*
michael@0 63 for quads and cubics, set up a parameterized line (e.g. LineParameters )
michael@0 64 for points [0] to [1]. See if point [2] is on that line, or on one side
michael@0 65 or the other. If it both quads' end points are on the same side, choose
michael@0 66 the shorter tangent. If the tangents are equal, choose the better second
michael@0 67 tangent angle
michael@0 68
michael@0 69 FIXME: maybe I could set up LineParameters lazily
michael@0 70 */
michael@0 71 bool SkOpAngle::operator<(const SkOpAngle& rh) const { // this/lh: left-hand; rh: right-hand
michael@0 72 double y = dy();
michael@0 73 double ry = rh.dy();
michael@0 74 #if DEBUG_ANGLE
michael@0 75 SkString bugOut;
michael@0 76 bugOut.printf("%s _ id=%d segId=%d tStart=%1.9g tEnd=%1.9g"
michael@0 77 " | id=%d segId=%d tStart=%1.9g tEnd=%1.9g ", funcName,
michael@0 78 fID, fSegment->debugID(), fSegment->t(fStart), fSegment->t(fEnd),
michael@0 79 rh.fID, rh.fSegment->debugID(), rh.fSegment->t(rh.fStart), rh.fSegment->t(rh.fEnd));
michael@0 80 #endif
michael@0 81 double y_ry = y * ry;
michael@0 82 if (y_ry < 0) { // if y's are opposite signs, we can do a quick return
michael@0 83 return COMPARE_RESULT("1 y * ry < 0", y < 0);
michael@0 84 }
michael@0 85 // at this point, both y's must be the same sign, or one (or both) is zero
michael@0 86 double x = dx();
michael@0 87 double rx = rh.dx();
michael@0 88 if (x * rx < 0) { // if x's are opposite signs, use y to determine first or second half
michael@0 89 if (y < 0 && ry < 0) { // if y's are negative, lh x is smaller if positive
michael@0 90 return COMPARE_RESULT("2 x_rx < 0 && y < 0 ...", x > 0);
michael@0 91 }
michael@0 92 if (y >= 0 && ry >= 0) { // if y's are zero or positive, lh x is smaller if negative
michael@0 93 return COMPARE_RESULT("3 x_rx < 0 && y >= 0 ...", x < 0);
michael@0 94 }
michael@0 95 SkASSERT((y == 0) ^ (ry == 0)); // if one y is zero and one is negative, neg y is smaller
michael@0 96 return COMPARE_RESULT("4 x_rx < 0 && y == 0 ...", y < 0);
michael@0 97 }
michael@0 98 // at this point, both x's must be the same sign, or one (or both) is zero
michael@0 99 if (y_ry == 0) { // if either y is zero
michael@0 100 if (y + ry < 0) { // if the other y is less than zero, it must be smaller
michael@0 101 return COMPARE_RESULT("5 y_ry == 0 && y + ry < 0", y < 0);
michael@0 102 }
michael@0 103 if (y + ry > 0) { // if a y is greater than zero and an x is positive, non zero is smaller
michael@0 104 return COMPARE_RESULT("6 y_ry == 0 && y + ry > 0", (x + rx > 0) ^ (y == 0));
michael@0 105 }
michael@0 106 // at this point, both y's are zero, so lines are coincident or one is degenerate
michael@0 107 SkASSERT(x * rx != 0); // and a degenerate line should haven't gotten this far
michael@0 108 }
michael@0 109 // see if either curve can be lengthened before trying the tangent
michael@0 110 if (fSegment->other(fEnd) != rh.fSegment // tangents not absolutely identical
michael@0 111 && rh.fSegment->other(rh.fEnd) != fSegment
michael@0 112 && y != -DBL_EPSILON
michael@0 113 && ry != -DBL_EPSILON) { // and not intersecting
michael@0 114 SkOpAngle longer = *this;
michael@0 115 SkOpAngle rhLonger = rh;
michael@0 116 if ((longer.lengthen(rh) | rhLonger.lengthen(*this)) // lengthen both
michael@0 117 && (fUnorderable || !longer.fUnorderable)
michael@0 118 && (rh.fUnorderable || !rhLonger.fUnorderable)) {
michael@0 119 #if DEBUG_ANGLE
michael@0 120 bugOut.prepend(" ");
michael@0 121 #endif
michael@0 122 return COMPARE_RESULT("10 longer.lengthen(rh) ...", longer < rhLonger);
michael@0 123 }
michael@0 124 }
michael@0 125 SkPath::Verb verb = fSegment->verb();
michael@0 126 SkPath::Verb rVerb = rh.fSegment->verb();
michael@0 127 if (y_ry != 0) { // if they aren't coincident, look for a stable cross product
michael@0 128 // at this point, y's are the same sign, neither is zero
michael@0 129 // and x's are the same sign, or one (or both) is zero
michael@0 130 double x_ry = x * ry;
michael@0 131 double rx_y = rx * y;
michael@0 132 if (!fComputed && !rh.fComputed) {
michael@0 133 if (!SkDLine::NearRay(x, y, rx, ry) && x_ry != rx_y) {
michael@0 134 return COMPARE_RESULT("7 !fComputed && !rh.fComputed", x_ry < rx_y);
michael@0 135 }
michael@0 136 if (fSide2 == 0 && rh.fSide2 == 0) {
michael@0 137 return COMPARE_RESULT("7a !fComputed && !rh.fComputed", x_ry < rx_y);
michael@0 138 }
michael@0 139 } else {
michael@0 140 // if the vector was a result of subdividing a curve, see if it is stable
michael@0 141 bool sloppy1 = x_ry < rx_y;
michael@0 142 bool sloppy2 = !sloppy1;
michael@0 143 if ((!fComputed || calcSlop(x, y, rx, ry, &sloppy1))
michael@0 144 && (!rh.fComputed || rh.calcSlop(rx, ry, x, y, &sloppy2))
michael@0 145 && sloppy1 != sloppy2) {
michael@0 146 return COMPARE_RESULT("8 CalcSlop(x, y ...", sloppy1);
michael@0 147 }
michael@0 148 }
michael@0 149 }
michael@0 150 if (fSide2 * rh.fSide2 == 0) { // one is zero
michael@0 151 #if DEBUG_ANGLE
michael@0 152 if (fSide2 == rh.fSide2 && y_ry) { // both is zero; coincidence was undetected
michael@0 153 SkDebugf("%s coincidence!\n", __FUNCTION__);
michael@0 154 }
michael@0 155 #endif
michael@0 156 return COMPARE_RESULT("9a fSide2 * rh.fSide2 == 0 ...", fSide2 < rh.fSide2);
michael@0 157 }
michael@0 158 // at this point, the initial tangent line is nearly coincident
michael@0 159 // see if edges curl away from each other
michael@0 160 if (fSide * rh.fSide < 0 && (!approximately_zero(fSide) || !approximately_zero(rh.fSide))) {
michael@0 161 return COMPARE_RESULT("9b fSide * rh.fSide < 0 ...", fSide < rh.fSide);
michael@0 162 }
michael@0 163 if (fUnsortable || rh.fUnsortable) {
michael@0 164 // even with no solution, return a stable sort
michael@0 165 return COMPARE_RESULT("11 fUnsortable || rh.fUnsortable", this < &rh);
michael@0 166 }
michael@0 167 if ((verb == SkPath::kLine_Verb && approximately_zero(y) && approximately_zero(x))
michael@0 168 || (rVerb == SkPath::kLine_Verb
michael@0 169 && approximately_zero(ry) && approximately_zero(rx))) {
michael@0 170 // See general unsortable comment below. This case can happen when
michael@0 171 // one line has a non-zero change in t but no change in x and y.
michael@0 172 fUnsortable = true;
michael@0 173 return COMPARE_RESULT("12 verb == SkPath::kLine_Verb ...", this < &rh);
michael@0 174 }
michael@0 175 if (fSegment->isTiny(this) || rh.fSegment->isTiny(&rh)) {
michael@0 176 fUnsortable = true;
michael@0 177 return COMPARE_RESULT("13 verb == fSegment->isTiny(this) ...", this < &rh);
michael@0 178 }
michael@0 179 SkASSERT(verb >= SkPath::kQuad_Verb);
michael@0 180 SkASSERT(rVerb >= SkPath::kQuad_Verb);
michael@0 181 // FIXME: until I can think of something better, project a ray from the
michael@0 182 // end of the shorter tangent to midway between the end points
michael@0 183 // through both curves and use the resulting angle to sort
michael@0 184 // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
michael@0 185 double len = fTangentPart.normalSquared();
michael@0 186 double rlen = rh.fTangentPart.normalSquared();
michael@0 187 SkDLine ray;
michael@0 188 SkIntersections i, ri;
michael@0 189 int roots, rroots;
michael@0 190 bool flip = false;
michael@0 191 bool useThis;
michael@0 192 bool leftLessThanRight = fSide > 0;
michael@0 193 do {
michael@0 194 useThis = (len < rlen) ^ flip;
michael@0 195 const SkDCubic& part = useThis ? fCurvePart : rh.fCurvePart;
michael@0 196 SkPath::Verb partVerb = useThis ? verb : rVerb;
michael@0 197 ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(part[1]) ?
michael@0 198 part[2] : part[1];
michael@0 199 ray[1] = SkDPoint::Mid(part[0], part[SkPathOpsVerbToPoints(partVerb)]);
michael@0 200 SkASSERT(ray[0] != ray[1]);
michael@0 201 roots = (i.*CurveRay[SkPathOpsVerbToPoints(verb)])(fSegment->pts(), ray);
michael@0 202 rroots = (ri.*CurveRay[SkPathOpsVerbToPoints(rVerb)])(rh.fSegment->pts(), ray);
michael@0 203 } while ((roots == 0 || rroots == 0) && (flip ^= true));
michael@0 204 if (roots == 0 || rroots == 0) {
michael@0 205 // FIXME: we don't have a solution in this case. The interim solution
michael@0 206 // is to mark the edges as unsortable, exclude them from this and
michael@0 207 // future computations, and allow the returned path to be fragmented
michael@0 208 fUnsortable = true;
michael@0 209 return COMPARE_RESULT("roots == 0 || rroots == 0", this < &rh);
michael@0 210 }
michael@0 211 SkASSERT(fSide != 0 && rh.fSide != 0);
michael@0 212 if (fSide * rh.fSide < 0) {
michael@0 213 fUnsortable = true;
michael@0 214 return COMPARE_RESULT("14 fSide * rh.fSide < 0", this < &rh);
michael@0 215 }
michael@0 216 SkDPoint lLoc;
michael@0 217 double best = SK_ScalarInfinity;
michael@0 218 #if DEBUG_SORT
michael@0 219 SkDebugf("lh=%d rh=%d use-lh=%d ray={{%1.9g,%1.9g}, {%1.9g,%1.9g}} %c\n",
michael@0 220 fSegment->debugID(), rh.fSegment->debugID(), useThis, ray[0].fX, ray[0].fY,
michael@0 221 ray[1].fX, ray[1].fY, "-+"[fSide > 0]);
michael@0 222 #endif
michael@0 223 for (int index = 0; index < roots; ++index) {
michael@0 224 SkDPoint loc = i.pt(index);
michael@0 225 SkDVector dxy = loc - ray[0];
michael@0 226 double dist = dxy.lengthSquared();
michael@0 227 #if DEBUG_SORT
michael@0 228 SkDebugf("best=%1.9g dist=%1.9g loc={%1.9g,%1.9g} dxy={%1.9g,%1.9g}\n",
michael@0 229 best, dist, loc.fX, loc.fY, dxy.fX, dxy.fY);
michael@0 230 #endif
michael@0 231 if (best > dist) {
michael@0 232 lLoc = loc;
michael@0 233 best = dist;
michael@0 234 }
michael@0 235 }
michael@0 236 flip = false;
michael@0 237 SkDPoint rLoc;
michael@0 238 for (int index = 0; index < rroots; ++index) {
michael@0 239 rLoc = ri.pt(index);
michael@0 240 SkDVector dxy = rLoc - ray[0];
michael@0 241 double dist = dxy.lengthSquared();
michael@0 242 #if DEBUG_SORT
michael@0 243 SkDebugf("best=%1.9g dist=%1.9g %c=(fSide < 0) rLoc={%1.9g,%1.9g} dxy={%1.9g,%1.9g}\n",
michael@0 244 best, dist, "><"[fSide < 0], rLoc.fX, rLoc.fY, dxy.fX, dxy.fY);
michael@0 245 #endif
michael@0 246 if (best > dist) {
michael@0 247 flip = true;
michael@0 248 break;
michael@0 249 }
michael@0 250 }
michael@0 251 if (flip) {
michael@0 252 leftLessThanRight = !leftLessThanRight;
michael@0 253 }
michael@0 254 return COMPARE_RESULT("15 leftLessThanRight", leftLessThanRight);
michael@0 255 }
michael@0 256
michael@0 257 bool SkOpAngle::isHorizontal() const {
michael@0 258 return dy() == 0 && fSegment->verb() == SkPath::kLine_Verb;
michael@0 259 }
michael@0 260
michael@0 261 // lengthen cannot cross opposite angle
michael@0 262 bool SkOpAngle::lengthen(const SkOpAngle& opp) {
michael@0 263 if (fSegment->other(fEnd) == opp.fSegment) {
michael@0 264 return false;
michael@0 265 }
michael@0 266 // FIXME: make this a while loop instead and make it as large as possible?
michael@0 267 int newEnd = fEnd;
michael@0 268 if (fStart < fEnd ? ++newEnd < fSegment->count() : --newEnd >= 0) {
michael@0 269 fEnd = newEnd;
michael@0 270 setSpans();
michael@0 271 return true;
michael@0 272 }
michael@0 273 return false;
michael@0 274 }
michael@0 275
michael@0 276 void SkOpAngle::set(const SkOpSegment* segment, int start, int end) {
michael@0 277 fSegment = segment;
michael@0 278 fStart = start;
michael@0 279 fEnd = end;
michael@0 280 setSpans();
michael@0 281 }
michael@0 282
michael@0 283 void SkOpAngle::setSpans() {
michael@0 284 fUnorderable = fSegment->isTiny(this);
michael@0 285 fLastMarked = NULL;
michael@0 286 fUnsortable = false;
michael@0 287 const SkPoint* pts = fSegment->pts();
michael@0 288 if (fSegment->verb() != SkPath::kLine_Verb) {
michael@0 289 fComputed = fSegment->subDivide(fStart, fEnd, &fCurvePart);
michael@0 290 fSegment->subDivide(fStart, fStart < fEnd ? fSegment->count() - 1 : 0, &fCurveHalf);
michael@0 291 }
michael@0 292 // FIXME: slight errors in subdivision cause sort trouble later on. As an experiment, try
michael@0 293 // rounding the curve part to float precision here
michael@0 294 // fCurvePart.round(fSegment->verb());
michael@0 295 switch (fSegment->verb()) {
michael@0 296 case SkPath::kLine_Verb: {
michael@0 297 SkASSERT(fStart != fEnd);
michael@0 298 fCurvePart[0].set(pts[fStart > fEnd]);
michael@0 299 fCurvePart[1].set(pts[fStart < fEnd]);
michael@0 300 fComputed = false;
michael@0 301 // OPTIMIZATION: for pure line compares, we never need fTangentPart.c
michael@0 302 fTangentPart.lineEndPoints(*SkTCast<SkDLine*>(&fCurvePart));
michael@0 303 fSide = 0;
michael@0 304 fSide2 = 0;
michael@0 305 } break;
michael@0 306 case SkPath::kQuad_Verb: {
michael@0 307 fSide2 = -fTangentHalf.quadPart(*SkTCast<SkDQuad*>(&fCurveHalf));
michael@0 308 SkDQuad& quad = *SkTCast<SkDQuad*>(&fCurvePart);
michael@0 309 fTangentPart.quadEndPoints(quad);
michael@0 310 fSide = -fTangentPart.pointDistance(fCurvePart[2]); // not normalized -- compare sign only
michael@0 311 if (fComputed && dx() > 0 && approximately_zero(dy())) {
michael@0 312 SkDCubic origCurve; // can't use segment's curve in place since it may be flipped
michael@0 313 int last = fSegment->count() - 1;
michael@0 314 fSegment->subDivide(fStart < fEnd ? 0 : last, fStart < fEnd ? last : 0, &origCurve);
michael@0 315 SkLineParameters origTan;
michael@0 316 origTan.quadEndPoints(*SkTCast<SkDQuad*>(&origCurve));
michael@0 317 if (origTan.dx() <= 0
michael@0 318 || (dy() != origTan.dy() && dy() * origTan.dy() <= 0)) { // signs match?
michael@0 319 fUnorderable = true;
michael@0 320 return;
michael@0 321 }
michael@0 322 }
michael@0 323 } break;
michael@0 324 case SkPath::kCubic_Verb: {
michael@0 325 double startT = fSegment->t(fStart);
michael@0 326 fSide2 = -fTangentHalf.cubicPart(fCurveHalf);
michael@0 327 fTangentPart.cubicEndPoints(fCurvePart);
michael@0 328 double testTs[4];
michael@0 329 // OPTIMIZATION: keep inflections precomputed with cubic segment?
michael@0 330 int testCount = SkDCubic::FindInflections(pts, testTs);
michael@0 331 double endT = fSegment->t(fEnd);
michael@0 332 double limitT = endT;
michael@0 333 int index;
michael@0 334 for (index = 0; index < testCount; ++index) {
michael@0 335 if (!between(startT, testTs[index], limitT)) {
michael@0 336 testTs[index] = -1;
michael@0 337 }
michael@0 338 }
michael@0 339 testTs[testCount++] = startT;
michael@0 340 testTs[testCount++] = endT;
michael@0 341 SkTQSort<double>(testTs, &testTs[testCount - 1]);
michael@0 342 double bestSide = 0;
michael@0 343 int testCases = (testCount << 1) - 1;
michael@0 344 index = 0;
michael@0 345 while (testTs[index] < 0) {
michael@0 346 ++index;
michael@0 347 }
michael@0 348 index <<= 1;
michael@0 349 for (; index < testCases; ++index) {
michael@0 350 int testIndex = index >> 1;
michael@0 351 double testT = testTs[testIndex];
michael@0 352 if (index & 1) {
michael@0 353 testT = (testT + testTs[testIndex + 1]) / 2;
michael@0 354 }
michael@0 355 // OPTIMIZE: could avoid call for t == startT, endT
michael@0 356 SkDPoint pt = dcubic_xy_at_t(pts, testT);
michael@0 357 double testSide = fTangentPart.pointDistance(pt);
michael@0 358 if (fabs(bestSide) < fabs(testSide)) {
michael@0 359 bestSide = testSide;
michael@0 360 }
michael@0 361 }
michael@0 362 fSide = -bestSide; // compare sign only
michael@0 363 SkASSERT(fSide == 0 || fSide2 != 0);
michael@0 364 if (fComputed && dx() > 0 && approximately_zero(dy())) {
michael@0 365 SkDCubic origCurve; // can't use segment's curve in place since it may be flipped
michael@0 366 int last = fSegment->count() - 1;
michael@0 367 fSegment->subDivide(fStart < fEnd ? 0 : last, fStart < fEnd ? last : 0, &origCurve);
michael@0 368 SkDCubicPair split = origCurve.chopAt(startT);
michael@0 369 SkLineParameters splitTan;
michael@0 370 splitTan.cubicEndPoints(fStart < fEnd ? split.second() : split.first());
michael@0 371 if (splitTan.dx() <= 0) {
michael@0 372 fUnorderable = true;
michael@0 373 fUnsortable = fSegment->isTiny(this);
michael@0 374 return;
michael@0 375 }
michael@0 376 // if one is < 0 and the other is >= 0
michael@0 377 if (dy() * splitTan.dy() < 0) {
michael@0 378 fUnorderable = true;
michael@0 379 fUnsortable = fSegment->isTiny(this);
michael@0 380 return;
michael@0 381 }
michael@0 382 }
michael@0 383 } break;
michael@0 384 default:
michael@0 385 SkASSERT(0);
michael@0 386 }
michael@0 387 if ((fUnsortable = approximately_zero(dx()) && approximately_zero(dy()))) {
michael@0 388 return;
michael@0 389 }
michael@0 390 if (fSegment->verb() == SkPath::kLine_Verb) {
michael@0 391 return;
michael@0 392 }
michael@0 393 SkASSERT(fStart != fEnd);
michael@0 394 int smaller = SkMin32(fStart, fEnd);
michael@0 395 int larger = SkMax32(fStart, fEnd);
michael@0 396 while (smaller < larger && fSegment->span(smaller).fTiny) {
michael@0 397 ++smaller;
michael@0 398 }
michael@0 399 if (precisely_equal(fSegment->span(smaller).fT, fSegment->span(larger).fT)) {
michael@0 400 #if DEBUG_UNSORTABLE
michael@0 401 SkPoint iPt = fSegment->xyAtT(fStart);
michael@0 402 SkPoint ePt = fSegment->xyAtT(fEnd);
michael@0 403 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
michael@0 404 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
michael@0 405 #endif
michael@0 406 fUnsortable = true;
michael@0 407 return;
michael@0 408 }
michael@0 409 fUnsortable = fStart < fEnd ? fSegment->span(smaller).fUnsortableStart
michael@0 410 : fSegment->span(larger).fUnsortableEnd;
michael@0 411 #if DEBUG_UNSORTABLE
michael@0 412 if (fUnsortable) {
michael@0 413 SkPoint iPt = fSegment->xyAtT(smaller);
michael@0 414 SkPoint ePt = fSegment->xyAtT(larger);
michael@0 415 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__,
michael@0 416 smaller, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY);
michael@0 417 }
michael@0 418 #endif
michael@0 419 return;
michael@0 420 }
michael@0 421
michael@0 422 #ifdef SK_DEBUG
michael@0 423 void SkOpAngle::dump() const {
michael@0 424 const SkOpSpan& spanStart = fSegment->span(fStart);
michael@0 425 const SkOpSpan& spanEnd = fSegment->span(fEnd);
michael@0 426 const SkOpSpan& spanMin = fStart < fEnd ? spanStart : spanEnd;
michael@0 427 SkDebugf("id=%d (%1.9g,%1.9g) start=%d (%1.9g) end=%d (%1.9g) sumWind=",
michael@0 428 fSegment->debugID(), fSegment->xAtT(fStart), fSegment->yAtT(fStart),
michael@0 429 fStart, spanStart.fT, fEnd, spanEnd.fT);
michael@0 430 SkPathOpsDebug::WindingPrintf(spanMin.fWindSum);
michael@0 431 SkDebugf(" oppWind=");
michael@0 432 SkPathOpsDebug::WindingPrintf(spanMin.fOppSum),
michael@0 433 SkDebugf(" done=%d\n", spanMin.fDone);
michael@0 434 }
michael@0 435 #endif

mercurial