| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 #include "SkGeometry.h" | 7 #include "SkGeometry.h" |
| 8 #include "SkLineParameters.h" | 8 #include "SkLineParameters.h" |
| 9 #include "SkPathOpsConic.h" | 9 #include "SkPathOpsConic.h" |
| 10 #include "SkPathOpsCubic.h" | 10 #include "SkPathOpsCubic.h" |
| 11 #include "SkPathOpsCurve.h" |
| 11 #include "SkPathOpsLine.h" | 12 #include "SkPathOpsLine.h" |
| 12 #include "SkPathOpsQuad.h" | 13 #include "SkPathOpsQuad.h" |
| 13 #include "SkPathOpsRect.h" | 14 #include "SkPathOpsRect.h" |
| 14 #include "SkTSort.h" | 15 #include "SkTSort.h" |
| 15 | 16 |
| 16 const int SkDCubic::gPrecisionUnit = 256; // FIXME: test different values in te
st framework | 17 const int SkDCubic::gPrecisionUnit = 256; // FIXME: test different values in te
st framework |
| 17 | 18 |
| 18 // give up when changing t no longer moves point | 19 // give up when changing t no longer moves point |
| 19 // also, copy point rather than recompute it when it does change | 20 // also, copy point rather than recompute it when it does change |
| 20 double SkDCubic::binarySearch(double min, double max, double axisIntercept, | 21 double SkDCubic::binarySearch(double min, double max, double axisIntercept, |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 67 | 68 |
| 68 // FIXME: cache keep the bounds and/or precision with the caller? | 69 // FIXME: cache keep the bounds and/or precision with the caller? |
| 69 double SkDCubic::calcPrecision() const { | 70 double SkDCubic::calcPrecision() const { |
| 70 SkDRect dRect; | 71 SkDRect dRect; |
| 71 dRect.setBounds(*this); // OPTIMIZATION: just use setRawBounds ? | 72 dRect.setBounds(*this); // OPTIMIZATION: just use setRawBounds ? |
| 72 double width = dRect.fRight - dRect.fLeft; | 73 double width = dRect.fRight - dRect.fLeft; |
| 73 double height = dRect.fBottom - dRect.fTop; | 74 double height = dRect.fBottom - dRect.fTop; |
| 74 return (width > height ? width : height) / gPrecisionUnit; | 75 return (width > height ? width : height) / gPrecisionUnit; |
| 75 } | 76 } |
| 76 | 77 |
| 77 bool SkDCubic::clockwise() const { | 78 bool SkDCubic::clockwise(bool* swap) const { |
| 78 double sum = (fPts[0].fX - fPts[3].fX) * (fPts[0].fY + fPts[3].fY); | 79 SkDPoint lastPt = fPts[kPointLast]; |
| 79 for (int idx = 0; idx < 3; ++idx) { | 80 SkDPoint firstPt = fPts[0]; |
| 80 sum += (fPts[idx + 1].fX - fPts[idx].fX) * (fPts[idx + 1].fY + fPts[idx]
.fY); | 81 double sum = 0; |
| 82 // pick the control point furthest from the line connecting the end points |
| 83 SkLineParameters lineParameters; |
| 84 lineParameters.cubicEndPoints(*this, 0, 3); |
| 85 lineParameters.normalize(); |
| 86 double tiniest = SkTMin(SkTMin(SkTMin(SkTMin(SkTMin(SkTMin(SkTMin(fPts[0].fX
, fPts[0].fY), |
| 87 fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY), fPts[3].fX), fPt
s[3].fY); |
| 88 double largest = SkTMax(SkTMax(SkTMax(SkTMax(SkTMax(SkTMax(SkTMax(fPts[0].fX
, fPts[0].fY), |
| 89 fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY), fPts[3].fX), fPt
s[3].fY); |
| 90 largest = SkTMax(largest, -tiniest); |
| 91 double pt1dist = lineParameters.controlPtDistance(*this, 1); |
| 92 double pt2dist = lineParameters.controlPtDistance(*this, 2); |
| 93 #if DEBUG_SWAP_TOP |
| 94 SkDebugf("%s pt1dist=%1.9g pt2dist=%1.9g\n", __FUNCTION__, pt1dist, pt2dist)
; |
| 95 #endif |
| 96 int furthest; |
| 97 if (!approximately_zero_when_compared_to(pt1dist, largest) |
| 98 && !approximately_zero_when_compared_to(pt2dist, largest) && pt1dist
* pt2dist < 0) { |
| 99 furthest = 2; |
| 100 } else { |
| 101 furthest = fabs(pt1dist) < fabs(pt2dist) ? 2 : 1; |
| 81 } | 102 } |
| 103 for (int idx = 1; idx <= 3; ++idx) { |
| 104 sum += (firstPt.fX - lastPt.fX) * (firstPt.fY + lastPt.fY); |
| 105 lastPt = firstPt; |
| 106 firstPt = idx == 1 ? fPts[furthest] : fPts[kPointLast]; |
| 107 } |
| 108 *swap = sum > 0 && !this->monotonicInY(); |
| 82 return sum <= 0; | 109 return sum <= 0; |
| 83 } | 110 } |
| 84 | 111 |
| 112 bool SkDCubic::Clockwise(const SkPoint* pts, double startT, double endT, bool* s
wap) { |
| 113 SkDCubic cubic; |
| 114 cubic.set(pts); |
| 115 #if 0 |
| 116 bool flip = startT > endT; |
| 117 double inflectionTs[2]; |
| 118 int inflections = cubic.findInflections(inflectionTs); |
| 119 for (int index = 0; index < inflections; ++index) { |
| 120 double inflectionT = inflectionTs[index]; |
| 121 if (between(startT, inflectionT, endT)) { |
| 122 if (flip) { |
| 123 if (!roughly_equal(inflectionT, endT)) { |
| 124 startT = inflectionT; |
| 125 } |
| 126 } else { |
| 127 if (!roughly_equal(inflectionT, startT)) { |
| 128 endT = inflectionT; |
| 129 } |
| 130 } |
| 131 } |
| 132 } |
| 133 #endif |
| 134 SkDCubic part = cubic.subDivide(startT, endT); |
| 135 return part.clockwise(swap); |
| 136 } |
| 137 |
| 85 void SkDCubic::Coefficients(const double* src, double* A, double* B, double* C,
double* D) { | 138 void SkDCubic::Coefficients(const double* src, double* A, double* B, double* C,
double* D) { |
| 86 *A = src[6]; // d | 139 *A = src[6]; // d |
| 87 *B = src[4] * 3; // 3*c | 140 *B = src[4] * 3; // 3*c |
| 88 *C = src[2] * 3; // 3*b | 141 *C = src[2] * 3; // 3*b |
| 89 *D = src[0]; // a | 142 *D = src[0]; // a |
| 90 *A -= *D - *C + *B; // A = -a + 3*b - 3*c + d | 143 *A -= *D - *C + *B; // A = -a + 3*b - 3*c + d |
| 91 *B += 3 * *D - 2 * *C; // B = 3*a - 6*b + 3*c | 144 *B += 3 * *D - 2 * *C; // B = 3*a - 6*b + 3*c |
| 92 *C -= 3 * *D; // C = -3*a + 3*b | 145 *C -= 3 * *D; // C = -3*a + 3*b |
| 93 } | 146 } |
| 94 | 147 |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 179 fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY), fPts[3].fX), fPt
s[3].fY); | 232 fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY), fPts[3].fX), fPt
s[3].fY); |
| 180 largest = SkTMax(largest, -tiniest); | 233 largest = SkTMax(largest, -tiniest); |
| 181 double distance = lineParameters.controlPtDistance(*this, 1); | 234 double distance = lineParameters.controlPtDistance(*this, 1); |
| 182 if (!approximately_zero_when_compared_to(distance, largest)) { | 235 if (!approximately_zero_when_compared_to(distance, largest)) { |
| 183 return false; | 236 return false; |
| 184 } | 237 } |
| 185 distance = lineParameters.controlPtDistance(*this, 2); | 238 distance = lineParameters.controlPtDistance(*this, 2); |
| 186 return approximately_zero_when_compared_to(distance, largest); | 239 return approximately_zero_when_compared_to(distance, largest); |
| 187 } | 240 } |
| 188 | 241 |
| 189 bool SkDCubic::ComplexBreak(const SkPoint pointsPtr[4], SkScalar* t) { | 242 bool SkDCubic::ComplexBreak(const SkPoint pointsPtr[4], SkScalar* t, CubicType*
resultType) { |
| 190 SkScalar d[3]; | 243 SkScalar d[3]; |
| 191 SkCubicType cubicType = SkClassifyCubic(pointsPtr, d); | 244 SkCubicType cubicType = SkClassifyCubic(pointsPtr, d); |
| 192 if (cubicType == kLoop_SkCubicType) { | 245 if (cubicType == kLoop_SkCubicType) { |
| 193 // crib code from gpu path utils that finds t values where loop self-int
ersects | 246 // crib code from gpu path utils that finds t values where loop self-int
ersects |
| 194 // use it to find mid of t values which should be a friendly place to ch
op | 247 // use it to find mid of t values which should be a friendly place to ch
op |
| 195 SkScalar tempSqrt = SkScalarSqrt(4.f * d[0] * d[2] - 3.f * d[1] * d[1]); | 248 SkScalar tempSqrt = SkScalarSqrt(4.f * d[0] * d[2] - 3.f * d[1] * d[1]); |
| 196 SkScalar ls = d[1] - tempSqrt; | 249 SkScalar ls = d[1] - tempSqrt; |
| 197 SkScalar lt = 2.f * d[0]; | 250 SkScalar lt = 2.f * d[0]; |
| 198 SkScalar ms = d[1] + tempSqrt; | 251 SkScalar ms = d[1] + tempSqrt; |
| 199 SkScalar mt = 2.f * d[0]; | 252 SkScalar mt = 2.f * d[0]; |
| 200 if (between(0, ls, lt) || between(0, ms, mt)) { | 253 if (between(0, ls, lt) || between(0, ms, mt)) { |
| 201 ls = ls / lt; | 254 ls = ls / lt; |
| 202 ms = ms / mt; | 255 ms = ms / mt; |
| 203 SkScalar smaller = SkTMax(0.f, SkTMin(ls, ms)); | 256 SkScalar smaller = SkTMax(0.f, SkTMin(ls, ms)); |
| 204 SkScalar larger = SkTMin(1.f, SkTMax(ls, ms)); | 257 SkScalar larger = SkTMin(1.f, SkTMax(ls, ms)); |
| 205 *t = (smaller + larger) / 2; | 258 *t = (smaller + larger) / 2; |
| 259 *resultType = kSplitAtLoop_SkDCubicType; |
| 206 return *t > 0 && *t < 1; | 260 return *t > 0 && *t < 1; |
| 207 } | 261 } |
| 208 } else if (kSerpentine_SkCubicType == cubicType || kCusp_SkCubicType == cubi
cType) { | 262 } else if (kSerpentine_SkCubicType == cubicType || kCusp_SkCubicType == cubi
cType) { |
| 209 SkDCubic cubic; | 263 SkDCubic cubic; |
| 210 cubic.set(pointsPtr); | 264 cubic.set(pointsPtr); |
| 211 double inflectionTs[2]; | 265 double inflectionTs[2]; |
| 212 int infTCount = cubic.findInflections(inflectionTs); | 266 int infTCount = cubic.findInflections(inflectionTs); |
| 213 if (infTCount == 2) { | 267 if (infTCount == 2) { |
| 214 double maxCurvature[3]; | 268 double maxCurvature[3]; |
| 215 int roots = cubic.findMaxCurvature(maxCurvature); | 269 int roots = cubic.findMaxCurvature(maxCurvature); |
| 270 #if DEBUG_CUBIC_SPLIT |
| 271 SkDebugf("%s\n", __FUNCTION__); |
| 272 cubic.dump(); |
| 273 for (int index = 0; index < infTCount; ++index) { |
| 274 SkDebugf("inflectionsTs[%d]=%1.9g ", index, inflectionTs[index])
; |
| 275 SkDPoint pt = cubic.ptAtT(inflectionTs[index]); |
| 276 SkDVector dPt = cubic.dxdyAtT(inflectionTs[index]); |
| 277 SkDLine perp = {{pt - dPt, pt + dPt}}; |
| 278 perp.dump(); |
| 279 } |
| 280 for (int index = 0; index < roots; ++index) { |
| 281 SkDebugf("maxCurvature[%d]=%1.9g ", index, maxCurvature[index]); |
| 282 SkDPoint pt = cubic.ptAtT(maxCurvature[index]); |
| 283 SkDVector dPt = cubic.dxdyAtT(maxCurvature[index]); |
| 284 SkDLine perp = {{pt - dPt, pt + dPt}}; |
| 285 perp.dump(); |
| 286 } |
| 287 #endif |
| 216 for (int index = 0; index < roots; ++index) { | 288 for (int index = 0; index < roots; ++index) { |
| 217 if (between(inflectionTs[0], maxCurvature[index], inflectionTs[1
])) { | 289 if (between(inflectionTs[0], maxCurvature[index], inflectionTs[1
])) { |
| 218 *t = maxCurvature[index]; | 290 *t = maxCurvature[index]; |
| 291 *resultType = kSplitAtMaxCurvature_SkDCubicType; |
| 219 return true; | 292 return true; |
| 220 } | 293 } |
| 221 } | 294 } |
| 222 } else if (infTCount == 1) { | 295 } else if (infTCount == 1) { |
| 223 *t = inflectionTs[0]; | 296 *t = inflectionTs[0]; |
| 297 *resultType = kSplitAtInflection_SkDCubicType; |
| 224 return *t > 0 && *t < 1; | 298 return *t > 0 && *t < 1; |
| 225 } | 299 } |
| 226 return false; | |
| 227 } | 300 } |
| 228 return false; | 301 return false; |
| 229 } | 302 } |
| 230 | 303 |
| 231 bool SkDCubic::monotonicInY() const { | 304 bool SkDCubic::monotonicInY() const { |
| 232 return between(fPts[0].fY, fPts[1].fY, fPts[3].fY) | 305 return between(fPts[0].fY, fPts[1].fY, fPts[3].fY) |
| 233 && between(fPts[0].fY, fPts[2].fY, fPts[3].fY); | 306 && between(fPts[0].fY, fPts[2].fY, fPts[3].fY); |
| 234 } | 307 } |
| 235 | 308 |
| 236 void SkDCubic::otherPts(int index, const SkDPoint* o1Pts[kPointCount - 1]) const
{ | 309 void SkDCubic::otherPts(int index, const SkDPoint* o1Pts[kPointCount - 1]) const
{ |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 439 double coeffX[4], coeffY[4]; | 512 double coeffX[4], coeffY[4]; |
| 440 int i; | 513 int i; |
| 441 formulate_F1DotF2(&fPts[0].fX, coeffX); | 514 formulate_F1DotF2(&fPts[0].fX, coeffX); |
| 442 formulate_F1DotF2(&fPts[0].fY, coeffY); | 515 formulate_F1DotF2(&fPts[0].fY, coeffY); |
| 443 for (i = 0; i < 4; i++) { | 516 for (i = 0; i < 4; i++) { |
| 444 coeffX[i] = coeffX[i] + coeffY[i]; | 517 coeffX[i] = coeffX[i] + coeffY[i]; |
| 445 } | 518 } |
| 446 return RootsValidT(coeffX[0], coeffX[1], coeffX[2], coeffX[3], tValues); | 519 return RootsValidT(coeffX[0], coeffX[1], coeffX[2], coeffX[3], tValues); |
| 447 } | 520 } |
| 448 | 521 |
| 449 SkDPoint SkDCubic::top(double startT, double endT) const { | 522 SkDPoint SkDCubic::top(double startT, double endT, double* topT) const { |
| 450 SkDCubic sub = subDivide(startT, endT); | 523 SkDCubic sub = subDivide(startT, endT); |
| 451 SkDPoint topPt = sub[0]; | 524 SkDPoint topPt = sub[0]; |
| 525 *topT = startT; |
| 452 if (topPt.fY > sub[3].fY || (topPt.fY == sub[3].fY && topPt.fX > sub[3].fX))
{ | 526 if (topPt.fY > sub[3].fY || (topPt.fY == sub[3].fY && topPt.fX > sub[3].fX))
{ |
| 527 *topT = endT; |
| 453 topPt = sub[3]; | 528 topPt = sub[3]; |
| 454 } | 529 } |
| 455 double extremeTs[2]; | 530 double extremeTs[2]; |
| 456 if (!sub.monotonicInY()) { | 531 if (!sub.monotonicInY()) { |
| 457 int roots = FindExtrema(sub[0].fY, sub[1].fY, sub[2].fY, sub[3].fY, extr
emeTs); | 532 int roots = FindExtrema(sub[0].fY, sub[1].fY, sub[2].fY, sub[3].fY, extr
emeTs); |
| 458 for (int index = 0; index < roots; ++index) { | 533 for (int index = 0; index < roots; ++index) { |
| 459 double t = startT + (endT - startT) * extremeTs[index]; | 534 double t = startT + (endT - startT) * extremeTs[index]; |
| 460 SkDPoint mid = ptAtT(t); | 535 SkDPoint mid = ptAtT(t); |
| 461 if (topPt.fY > mid.fY || (topPt.fY == mid.fY && topPt.fX > mid.fX))
{ | 536 if (topPt.fY > mid.fY || (topPt.fY == mid.fY && topPt.fX > mid.fX))
{ |
| 537 *topT = t; |
| 462 topPt = mid; | 538 topPt = mid; |
| 463 } | 539 } |
| 464 } | 540 } |
| 465 } | 541 } |
| 466 return topPt; | 542 return topPt; |
| 467 } | 543 } |
| 468 | 544 |
| 469 SkDPoint SkDCubic::ptAtT(double t) const { | 545 SkDPoint SkDCubic::ptAtT(double t) const { |
| 470 if (0 == t) { | 546 if (0 == t) { |
| 471 return fPts[0]; | 547 return fPts[0]; |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 639 dst.pts[4].fY = (fPts[1].fY + 2 * fPts[2].fY + fPts[3].fY) / 4; | 715 dst.pts[4].fY = (fPts[1].fY + 2 * fPts[2].fY + fPts[3].fY) / 4; |
| 640 dst.pts[5].fX = (fPts[2].fX + fPts[3].fX) / 2; | 716 dst.pts[5].fX = (fPts[2].fX + fPts[3].fX) / 2; |
| 641 dst.pts[5].fY = (fPts[2].fY + fPts[3].fY) / 2; | 717 dst.pts[5].fY = (fPts[2].fY + fPts[3].fY) / 2; |
| 642 dst.pts[6] = fPts[3]; | 718 dst.pts[6] = fPts[3]; |
| 643 return dst; | 719 return dst; |
| 644 } | 720 } |
| 645 interp_cubic_coords(&fPts[0].fX, &dst.pts[0].fX, t); | 721 interp_cubic_coords(&fPts[0].fX, &dst.pts[0].fX, t); |
| 646 interp_cubic_coords(&fPts[0].fY, &dst.pts[0].fY, t); | 722 interp_cubic_coords(&fPts[0].fY, &dst.pts[0].fY, t); |
| 647 return dst; | 723 return dst; |
| 648 } | 724 } |
| OLD | NEW |