Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(661)

Side by Side Diff: src/pathops/SkPathOpsCubic.cpp

Issue 1107353004: align top and bounds computations (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: clean up code Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/pathops/SkPathOpsCubic.h ('k') | src/pathops/SkPathOpsCurve.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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"
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
68 68
69 // FIXME: cache keep the bounds and/or precision with the caller? 69 // FIXME: cache keep the bounds and/or precision with the caller?
70 double SkDCubic::calcPrecision() const { 70 double SkDCubic::calcPrecision() const {
71 SkDRect dRect; 71 SkDRect dRect;
72 dRect.setBounds(*this); // OPTIMIZATION: just use setRawBounds ? 72 dRect.setBounds(*this); // OPTIMIZATION: just use setRawBounds ?
73 double width = dRect.fRight - dRect.fLeft; 73 double width = dRect.fRight - dRect.fLeft;
74 double height = dRect.fBottom - dRect.fTop; 74 double height = dRect.fBottom - dRect.fTop;
75 return (width > height ? width : height) / gPrecisionUnit; 75 return (width > height ? width : height) / gPrecisionUnit;
76 } 76 }
77 77
78 bool SkDCubic::clockwise(bool* swap) const { 78 bool SkDCubic::clockwise(const SkDCubic& whole, bool* swap) const {
79 SkDPoint lastPt = fPts[kPointLast]; 79 SkDPoint lastPt = fPts[kPointLast];
80 SkDPoint firstPt = fPts[0]; 80 SkDPoint firstPt = fPts[0];
81 double sum = 0; 81 double sum = 0;
82 // pick the control point furthest from the line connecting the end points 82 // pick the control point furthest from the line connecting the end points
83 SkLineParameters lineParameters; 83 SkLineParameters lineParameters;
84 lineParameters.cubicEndPoints(*this, 0, 3); 84 lineParameters.cubicEndPoints(*this, 0, 3);
85 lineParameters.normalize(); 85 lineParameters.normalize();
86 double tiniest = SkTMin(SkTMin(SkTMin(SkTMin(SkTMin(SkTMin(SkTMin(fPts[0].fX , fPts[0].fY), 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); 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), 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); 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); 90 largest = SkTMax(largest, -tiniest);
91 double pt1dist = lineParameters.controlPtDistance(*this, 1); 91 double pt1dist = lineParameters.controlPtDistance(*this, 1);
92 double pt2dist = lineParameters.controlPtDistance(*this, 2); 92 double pt2dist = lineParameters.controlPtDistance(*this, 2);
93 #if DEBUG_SWAP_TOP 93 #if DEBUG_SWAP_TOP
94 SkDebugf("%s pt1dist=%1.9g pt2dist=%1.9g\n", __FUNCTION__, pt1dist, pt2dist) ; 94 SkDebugf("%s pt1dist=%1.9g pt2dist=%1.9g\n", __FUNCTION__, pt1dist, pt2dist) ;
95 #endif 95 #endif
96 int furthest; 96 int furthest;
97 if (!approximately_zero_when_compared_to(pt1dist, largest) 97 if (!approximately_zero_when_compared_to(pt1dist, largest)
98 && !approximately_zero_when_compared_to(pt2dist, largest) && pt1dist * pt2dist < 0) { 98 && !approximately_zero_when_compared_to(pt2dist, largest) && pt1dist * pt2dist < 0) {
99 furthest = 2; 99 furthest = 2;
100 } else { 100 } else {
101 furthest = fabs(pt1dist) < fabs(pt2dist) ? 2 : 1; 101 furthest = fabs(pt1dist) < fabs(pt2dist) ? 2 : 1;
102 } 102 }
103 for (int idx = 1; idx <= 3; ++idx) { 103 for (int idx = 1; idx <= 3; ++idx) {
104 sum += (firstPt.fX - lastPt.fX) * (firstPt.fY + lastPt.fY); 104 sum += (firstPt.fX - lastPt.fX) * (firstPt.fY + lastPt.fY);
105 lastPt = firstPt; 105 lastPt = firstPt;
106 firstPt = idx == 1 ? fPts[furthest] : fPts[kPointLast]; 106 firstPt = idx == 1 ? fPts[furthest] : fPts[kPointLast];
107 } 107 }
108 *swap = sum > 0 && !this->monotonicInY(); 108 *swap = sum > 0 && !this->monotonicInY() && !whole.monotonicInY();
109 return sum <= 0; 109 return sum <= 0;
110 } 110 }
111 111
112 bool SkDCubic::Clockwise(const SkPoint* pts, double startT, double endT, bool* s wap) { 112 bool SkDCubic::Clockwise(const SkPoint* pts, double startT, double endT, bool* s wap) {
113 SkDCubic cubic; 113 SkDCubic cubic;
114 cubic.set(pts); 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); 115 SkDCubic part = cubic.subDivide(startT, endT);
135 return part.clockwise(swap); 116 return part.clockwise(cubic, swap);
136 } 117 }
137 118
138 void SkDCubic::Coefficients(const double* src, double* A, double* B, double* C, double* D) { 119 void SkDCubic::Coefficients(const double* src, double* A, double* B, double* C, double* D) {
139 *A = src[6]; // d 120 *A = src[6]; // d
140 *B = src[4] * 3; // 3*c 121 *B = src[4] * 3; // 3*c
141 *C = src[2] * 3; // 3*b 122 *C = src[2] * 3; // 3*b
142 *D = src[0]; // a 123 *D = src[0]; // a
143 *A -= *D - *C + *B; // A = -a + 3*b - 3*c + d 124 *A -= *D - *C + *B; // A = -a + 3*b - 3*c + d
144 *B += 3 * *D - 2 * *C; // B = 3*a - 6*b + 3*c 125 *B += 3 * *D - 2 * *C; // B = 3*a - 6*b + 3*c
145 *C -= 3 * *D; // C = -3*a + 3*b 126 *C -= 3 * *D; // C = -3*a + 3*b
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 } 275 }
295 } else if (infTCount == 1) { 276 } else if (infTCount == 1) {
296 *t = inflectionTs[0]; 277 *t = inflectionTs[0];
297 *resultType = kSplitAtInflection_SkDCubicType; 278 *resultType = kSplitAtInflection_SkDCubicType;
298 return *t > 0 && *t < 1; 279 return *t > 0 && *t < 1;
299 } 280 }
300 } 281 }
301 return false; 282 return false;
302 } 283 }
303 284
285 bool SkDCubic::monotonicInX() const {
286 return precisely_between(fPts[0].fX, fPts[1].fX, fPts[3].fX)
287 && precisely_between(fPts[0].fX, fPts[2].fX, fPts[3].fX);
288 }
289
304 bool SkDCubic::monotonicInY() const { 290 bool SkDCubic::monotonicInY() const {
305 return between(fPts[0].fY, fPts[1].fY, fPts[3].fY) 291 return precisely_between(fPts[0].fY, fPts[1].fY, fPts[3].fY)
306 && between(fPts[0].fY, fPts[2].fY, fPts[3].fY); 292 && precisely_between(fPts[0].fY, fPts[2].fY, fPts[3].fY);
307 } 293 }
308 294
309 void SkDCubic::otherPts(int index, const SkDPoint* o1Pts[kPointCount - 1]) const { 295 void SkDCubic::otherPts(int index, const SkDPoint* o1Pts[kPointCount - 1]) const {
310 int offset = (int) !SkToBool(index); 296 int offset = (int) !SkToBool(index);
311 o1Pts[0] = &fPts[offset]; 297 o1Pts[0] = &fPts[offset];
312 o1Pts[1] = &fPts[++offset]; 298 o1Pts[1] = &fPts[++offset];
313 o1Pts[2] = &fPts[++offset]; 299 o1Pts[2] = &fPts[++offset];
314 } 300 }
315 301
316 int SkDCubic::searchRoots(double extremeTs[6], int extrema, double axisIntercept , 302 int SkDCubic::searchRoots(double extremeTs[6], int extrema, double axisIntercept ,
(...skipping 19 matching lines...) Expand all
336 322
337 // cubic roots 323 // cubic roots
338 324
339 static const double PI = 3.141592653589793; 325 static const double PI = 3.141592653589793;
340 326
341 // from SkGeometry.cpp (and Numeric Solutions, 5.6) 327 // from SkGeometry.cpp (and Numeric Solutions, 5.6)
342 int SkDCubic::RootsValidT(double A, double B, double C, double D, double t[3]) { 328 int SkDCubic::RootsValidT(double A, double B, double C, double D, double t[3]) {
343 double s[3]; 329 double s[3];
344 int realRoots = RootsReal(A, B, C, D, s); 330 int realRoots = RootsReal(A, B, C, D, s);
345 int foundRoots = SkDQuad::AddValidTs(s, realRoots, t); 331 int foundRoots = SkDQuad::AddValidTs(s, realRoots, t);
332 for (int index = 0; index < realRoots; ++index) {
333 double tValue = s[index];
334 if (!approximately_one_or_less(tValue) && between(1, tValue, 1.00005)) {
335 for (int idx2 = 0; idx2 < foundRoots; ++idx2) {
336 if (approximately_equal(t[idx2], 1)) {
337 goto nextRoot;
338 }
339 }
340 SkASSERT(foundRoots < 3);
341 t[foundRoots++] = 1;
342 } else if (!approximately_zero_or_more(tValue) && between(-0.00005, tVal ue, 0)) {
343 for (int idx2 = 0; idx2 < foundRoots; ++idx2) {
344 if (approximately_equal(t[idx2], 0)) {
345 goto nextRoot;
346 }
347 }
348 SkASSERT(foundRoots < 3);
349 t[foundRoots++] = 0;
350 }
351 nextRoot:
352 ;
353 }
346 return foundRoots; 354 return foundRoots;
347 } 355 }
348 356
349 int SkDCubic::RootsReal(double A, double B, double C, double D, double s[3]) { 357 int SkDCubic::RootsReal(double A, double B, double C, double D, double s[3]) {
350 #ifdef SK_DEBUG 358 #ifdef SK_DEBUG
351 // create a string mathematica understands 359 // create a string mathematica understands
352 // GDB set print repe 15 # if repeated digits is a bother 360 // GDB set print repe 15 # if repeated digits is a bother
353 // set print elements 400 # if line doesn't fit 361 // set print elements 400 # if line doesn't fit
354 char str[1024]; 362 char str[1024];
355 sk_bzero(str, sizeof(str)); 363 sk_bzero(str, sizeof(str));
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
480 coeff[2] = 2 * b * b + c * a; 488 coeff[2] = 2 * b * b + c * a;
481 coeff[3] = a * b; 489 coeff[3] = a * b;
482 } 490 }
483 491
484 /** SkDCubic'(t) = At^2 + Bt + C, where 492 /** SkDCubic'(t) = At^2 + Bt + C, where
485 A = 3(-a + 3(b - c) + d) 493 A = 3(-a + 3(b - c) + d)
486 B = 6(a - 2b + c) 494 B = 6(a - 2b + c)
487 C = 3(b - a) 495 C = 3(b - a)
488 Solve for t, keeping only those that fit between 0 < t < 1 496 Solve for t, keeping only those that fit between 0 < t < 1
489 */ 497 */
490 int SkDCubic::FindExtrema(double a, double b, double c, double d, double tValues [2]) { 498 int SkDCubic::FindExtrema(const double src[], double tValues[2]) {
491 // we divide A,B,C by 3 to simplify 499 // we divide A,B,C by 3 to simplify
492 double A = d - a + 3*(b - c); 500 double a = src[0];
493 double B = 2*(a - b - b + c); 501 double b = src[2];
502 double c = src[4];
503 double d = src[6];
504 double A = d - a + 3 * (b - c);
505 double B = 2 * (a - b - b + c);
494 double C = b - a; 506 double C = b - a;
495 507
496 return SkDQuad::RootsValidT(A, B, C, tValues); 508 return SkDQuad::RootsValidT(A, B, C, tValues);
497 } 509 }
498 510
499 /* from SkGeometry.cpp 511 /* from SkGeometry.cpp
500 Looking for F' dot F'' == 0 512 Looking for F' dot F'' == 0
501 513
502 A = b - a 514 A = b - a
503 B = c - 2b + a 515 B = c - 2b + a
504 C = d - 3c + 3b - a 516 C = d - 3c + 3b - a
505 517
506 F' = 3Ct^2 + 6Bt + 3A 518 F' = 3Ct^2 + 6Bt + 3A
507 F'' = 6Ct + 6B 519 F'' = 6Ct + 6B
508 520
509 F' dot F'' -> CCt^3 + 3BCt^2 + (2BB + CA)t + AB 521 F' dot F'' -> CCt^3 + 3BCt^2 + (2BB + CA)t + AB
510 */ 522 */
511 int SkDCubic::findMaxCurvature(double tValues[]) const { 523 int SkDCubic::findMaxCurvature(double tValues[]) const {
512 double coeffX[4], coeffY[4]; 524 double coeffX[4], coeffY[4];
513 int i; 525 int i;
514 formulate_F1DotF2(&fPts[0].fX, coeffX); 526 formulate_F1DotF2(&fPts[0].fX, coeffX);
515 formulate_F1DotF2(&fPts[0].fY, coeffY); 527 formulate_F1DotF2(&fPts[0].fY, coeffY);
516 for (i = 0; i < 4; i++) { 528 for (i = 0; i < 4; i++) {
517 coeffX[i] = coeffX[i] + coeffY[i]; 529 coeffX[i] = coeffX[i] + coeffY[i];
518 } 530 }
519 return RootsValidT(coeffX[0], coeffX[1], coeffX[2], coeffX[3], tValues); 531 return RootsValidT(coeffX[0], coeffX[1], coeffX[2], coeffX[3], tValues);
520 } 532 }
521 533
522 SkDPoint SkDCubic::top(double startT, double endT, double* topT) const {
523 SkDCubic sub = subDivide(startT, endT);
524 SkDPoint topPt = sub[0];
525 *topT = startT;
526 if (topPt.fY > sub[3].fY || (topPt.fY == sub[3].fY && topPt.fX > sub[3].fX)) {
527 *topT = endT;
528 topPt = sub[3];
529 }
530 double extremeTs[2];
531 if (!sub.monotonicInY()) {
532 int roots = FindExtrema(sub[0].fY, sub[1].fY, sub[2].fY, sub[3].fY, extr emeTs);
533 for (int index = 0; index < roots; ++index) {
534 double t = startT + (endT - startT) * extremeTs[index];
535 SkDPoint mid = ptAtT(t);
536 if (topPt.fY > mid.fY || (topPt.fY == mid.fY && topPt.fX > mid.fX)) {
537 *topT = t;
538 topPt = mid;
539 }
540 }
541 }
542 return topPt;
543 }
544
545 SkDPoint SkDCubic::ptAtT(double t) const { 534 SkDPoint SkDCubic::ptAtT(double t) const {
546 if (0 == t) { 535 if (0 == t) {
547 return fPts[0]; 536 return fPts[0];
548 } 537 }
549 if (1 == t) { 538 if (1 == t) {
550 return fPts[3]; 539 return fPts[3];
551 } 540 }
552 double one_t = 1 - t; 541 double one_t = 1 - t;
553 double one_t2 = one_t * one_t; 542 double one_t2 = one_t * one_t;
554 double a = one_t2 * one_t; 543 double a = one_t2 * one_t;
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
715 dst.pts[4].fY = (fPts[1].fY + 2 * fPts[2].fY + fPts[3].fY) / 4; 704 dst.pts[4].fY = (fPts[1].fY + 2 * fPts[2].fY + fPts[3].fY) / 4;
716 dst.pts[5].fX = (fPts[2].fX + fPts[3].fX) / 2; 705 dst.pts[5].fX = (fPts[2].fX + fPts[3].fX) / 2;
717 dst.pts[5].fY = (fPts[2].fY + fPts[3].fY) / 2; 706 dst.pts[5].fY = (fPts[2].fY + fPts[3].fY) / 2;
718 dst.pts[6] = fPts[3]; 707 dst.pts[6] = fPts[3];
719 return dst; 708 return dst;
720 } 709 }
721 interp_cubic_coords(&fPts[0].fX, &dst.pts[0].fX, t); 710 interp_cubic_coords(&fPts[0].fX, &dst.pts[0].fX, t);
722 interp_cubic_coords(&fPts[0].fY, &dst.pts[0].fY, t); 711 interp_cubic_coords(&fPts[0].fY, &dst.pts[0].fY, t);
723 return dst; 712 return dst;
724 } 713 }
OLDNEW
« no previous file with comments | « src/pathops/SkPathOpsCubic.h ('k') | src/pathops/SkPathOpsCurve.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698