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

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

Issue 1111333002: compute initial winding from projected rays (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: add missing test reference 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"
11 #include "SkPathOpsCurve.h" 11 #include "SkPathOpsCurve.h"
12 #include "SkPathOpsLine.h" 12 #include "SkPathOpsLine.h"
13 #include "SkPathOpsQuad.h" 13 #include "SkPathOpsQuad.h"
14 #include "SkPathOpsRect.h" 14 #include "SkPathOpsRect.h"
15 #include "SkTSort.h" 15 #include "SkTSort.h"
16 16
17 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
18 18
19 void SkDCubic::align(int endIndex, int ctrlIndex, SkDPoint* dstPt) const {
20 if (fPts[endIndex].fX == fPts[ctrlIndex].fX) {
21 dstPt->fX = fPts[endIndex].fX;
22 }
23 if (fPts[endIndex].fY == fPts[ctrlIndex].fY) {
24 dstPt->fY = fPts[endIndex].fY;
25 }
26 }
27
19 // give up when changing t no longer moves point 28 // give up when changing t no longer moves point
20 // also, copy point rather than recompute it when it does change 29 // also, copy point rather than recompute it when it does change
21 double SkDCubic::binarySearch(double min, double max, double axisIntercept, 30 double SkDCubic::binarySearch(double min, double max, double axisIntercept,
22 SearchAxis xAxis) const { 31 SearchAxis xAxis) const {
23 double t = (min + max) / 2; 32 double t = (min + max) / 2;
24 double step = (t - min) / 2; 33 double step = (t - min) / 2;
25 SkDPoint cubicAtT = ptAtT(t); 34 SkDPoint cubicAtT = ptAtT(t);
26 double calcPos = (&cubicAtT.fX)[xAxis]; 35 double calcPos = (&cubicAtT.fX)[xAxis];
27 double calcDist = calcPos - axisIntercept; 36 double calcDist = calcPos - axisIntercept;
28 do { 37 do {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
68 77
69 // FIXME: cache keep the bounds and/or precision with the caller? 78 // FIXME: cache keep the bounds and/or precision with the caller?
70 double SkDCubic::calcPrecision() const { 79 double SkDCubic::calcPrecision() const {
71 SkDRect dRect; 80 SkDRect dRect;
72 dRect.setBounds(*this); // OPTIMIZATION: just use setRawBounds ? 81 dRect.setBounds(*this); // OPTIMIZATION: just use setRawBounds ?
73 double width = dRect.fRight - dRect.fLeft; 82 double width = dRect.fRight - dRect.fLeft;
74 double height = dRect.fBottom - dRect.fTop; 83 double height = dRect.fBottom - dRect.fTop;
75 return (width > height ? width : height) / gPrecisionUnit; 84 return (width > height ? width : height) / gPrecisionUnit;
76 } 85 }
77 86
78 bool SkDCubic::clockwise(const SkDCubic& whole, bool* swap) const { 87
79 SkDPoint lastPt = fPts[kPointLast]; 88 /* classic one t subdivision */
80 SkDPoint firstPt = fPts[0]; 89 static void interp_cubic_coords(const double* src, double* dst, double t) {
81 double sum = 0; 90 double ab = SkDInterp(src[0], src[2], t);
82 // pick the control point furthest from the line connecting the end points 91 double bc = SkDInterp(src[2], src[4], t);
83 SkLineParameters lineParameters; 92 double cd = SkDInterp(src[4], src[6], t);
84 lineParameters.cubicEndPoints(*this, 0, 3); 93 double abc = SkDInterp(ab, bc, t);
85 lineParameters.normalize(); 94 double bcd = SkDInterp(bc, cd, t);
86 double tiniest = SkTMin(SkTMin(SkTMin(SkTMin(SkTMin(SkTMin(SkTMin(fPts[0].fX , fPts[0].fY), 95 double abcd = SkDInterp(abc, bcd, t);
87 fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY), fPts[3].fX), fPt s[3].fY); 96
88 double largest = SkTMax(SkTMax(SkTMax(SkTMax(SkTMax(SkTMax(SkTMax(fPts[0].fX , fPts[0].fY), 97 dst[0] = src[0];
89 fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY), fPts[3].fX), fPt s[3].fY); 98 dst[2] = ab;
90 largest = SkTMax(largest, -tiniest); 99 dst[4] = abc;
91 double pt1dist = lineParameters.controlPtDistance(*this, 1); 100 dst[6] = abcd;
92 double pt2dist = lineParameters.controlPtDistance(*this, 2); 101 dst[8] = bcd;
93 #if DEBUG_SWAP_TOP 102 dst[10] = cd;
94 SkDebugf("%s pt1dist=%1.9g pt2dist=%1.9g\n", __FUNCTION__, pt1dist, pt2dist) ; 103 dst[12] = src[6];
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;
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() && !whole.monotonicInY();
109 return sum <= 0;
110 } 104 }
111 105
112 bool SkDCubic::Clockwise(const SkPoint* pts, double startT, double endT, bool* s wap) { 106 SkDCubicPair SkDCubic::chopAt(double t) const {
113 SkDCubic cubic; 107 SkDCubicPair dst;
114 cubic.set(pts); 108 if (t == 0.5) {
115 SkDCubic part = cubic.subDivide(startT, endT); 109 dst.pts[0] = fPts[0];
116 return part.clockwise(cubic, swap); 110 dst.pts[1].fX = (fPts[0].fX + fPts[1].fX) / 2;
111 dst.pts[1].fY = (fPts[0].fY + fPts[1].fY) / 2;
112 dst.pts[2].fX = (fPts[0].fX + 2 * fPts[1].fX + fPts[2].fX) / 4;
113 dst.pts[2].fY = (fPts[0].fY + 2 * fPts[1].fY + fPts[2].fY) / 4;
114 dst.pts[3].fX = (fPts[0].fX + 3 * (fPts[1].fX + fPts[2].fX) + fPts[3].fX ) / 8;
115 dst.pts[3].fY = (fPts[0].fY + 3 * (fPts[1].fY + fPts[2].fY) + fPts[3].fY ) / 8;
116 dst.pts[4].fX = (fPts[1].fX + 2 * fPts[2].fX + fPts[3].fX) / 4;
117 dst.pts[4].fY = (fPts[1].fY + 2 * fPts[2].fY + fPts[3].fY) / 4;
118 dst.pts[5].fX = (fPts[2].fX + fPts[3].fX) / 2;
119 dst.pts[5].fY = (fPts[2].fY + fPts[3].fY) / 2;
120 dst.pts[6] = fPts[3];
121 return dst;
122 }
123 interp_cubic_coords(&fPts[0].fX, &dst.pts[0].fX, t);
124 interp_cubic_coords(&fPts[0].fY, &dst.pts[0].fY, t);
125 return dst;
117 } 126 }
118 127
119 void SkDCubic::Coefficients(const double* src, double* A, double* B, double* C, double* D) { 128 void SkDCubic::Coefficients(const double* src, double* A, double* B, double* C, double* D) {
120 *A = src[6]; // d 129 *A = src[6]; // d
121 *B = src[4] * 3; // 3*c 130 *B = src[4] * 3; // 3*c
122 *C = src[2] * 3; // 3*b 131 *C = src[2] * 3; // 3*b
123 *D = src[0]; // a 132 *D = src[0]; // a
124 *A -= *D - *C + *B; // A = -a + 3*b - 3*c + d 133 *A -= *D - *C + *B; // A = -a + 3*b - 3*c + d
125 *B += 3 * *D - 2 * *C; // B = 3*a - 6*b + 3*c 134 *B += 3 * *D - 2 * *C; // B = 3*a - 6*b + 3*c
126 *C -= 3 * *D; // C = -3*a + 3*b 135 *C -= 3 * *D; // C = -3*a + 3*b
(...skipping 502 matching lines...) Expand 10 before | Expand all | Expand 10 after
629 double nx = fx * 27 - ax - dx * 8; 638 double nx = fx * 27 - ax - dx * 8;
630 double ny = fy * 27 - ay - dy * 8; 639 double ny = fy * 27 - ay - dy * 8;
631 /* bx = */ dst[1].fX = (mx * 2 - nx) / 18; 640 /* bx = */ dst[1].fX = (mx * 2 - nx) / 18;
632 /* by = */ dst[1].fY = (my * 2 - ny) / 18; 641 /* by = */ dst[1].fY = (my * 2 - ny) / 18;
633 /* cx = */ dst[2].fX = (nx * 2 - mx) / 18; 642 /* cx = */ dst[2].fX = (nx * 2 - mx) / 18;
634 /* cy = */ dst[2].fY = (ny * 2 - my) / 18; 643 /* cy = */ dst[2].fY = (ny * 2 - my) / 18;
635 // FIXME: call align() ? 644 // FIXME: call align() ?
636 return dst; 645 return dst;
637 } 646 }
638 647
639 void SkDCubic::align(int endIndex, int ctrlIndex, SkDPoint* dstPt) const {
640 if (fPts[endIndex].fX == fPts[ctrlIndex].fX) {
641 dstPt->fX = fPts[endIndex].fX;
642 }
643 if (fPts[endIndex].fY == fPts[ctrlIndex].fY) {
644 dstPt->fY = fPts[endIndex].fY;
645 }
646 }
647
648 void SkDCubic::subDivide(const SkDPoint& a, const SkDPoint& d, 648 void SkDCubic::subDivide(const SkDPoint& a, const SkDPoint& d,
649 double t1, double t2, SkDPoint dst[2]) const { 649 double t1, double t2, SkDPoint dst[2]) const {
650 SkASSERT(t1 != t2); 650 SkASSERT(t1 != t2);
651 // this approach assumes that the control points computed directly are accur ate enough 651 // this approach assumes that the control points computed directly are accur ate enough
652 SkDCubic sub = subDivide(t1, t2); 652 SkDCubic sub = subDivide(t1, t2);
653 dst[0] = sub[1] + (a - sub[0]); 653 dst[0] = sub[1] + (a - sub[0]);
654 dst[1] = sub[2] + (d - sub[3]); 654 dst[1] = sub[2] + (d - sub[3]);
655 if (t1 == 0 || t2 == 0) { 655 if (t1 == 0 || t2 == 0) {
656 align(0, 1, t1 == 0 ? &dst[0] : &dst[1]); 656 align(0, 1, t1 == 0 ? &dst[0] : &dst[1]);
657 } 657 }
658 if (t1 == 1 || t2 == 1) { 658 if (t1 == 1 || t2 == 1) {
659 align(3, 2, t1 == 1 ? &dst[0] : &dst[1]); 659 align(3, 2, t1 == 1 ? &dst[0] : &dst[1]);
660 } 660 }
661 if (AlmostBequalUlps(dst[0].fX, a.fX)) { 661 if (AlmostBequalUlps(dst[0].fX, a.fX)) {
662 dst[0].fX = a.fX; 662 dst[0].fX = a.fX;
663 } 663 }
664 if (AlmostBequalUlps(dst[0].fY, a.fY)) { 664 if (AlmostBequalUlps(dst[0].fY, a.fY)) {
665 dst[0].fY = a.fY; 665 dst[0].fY = a.fY;
666 } 666 }
667 if (AlmostBequalUlps(dst[1].fX, d.fX)) { 667 if (AlmostBequalUlps(dst[1].fX, d.fX)) {
668 dst[1].fX = d.fX; 668 dst[1].fX = d.fX;
669 } 669 }
670 if (AlmostBequalUlps(dst[1].fY, d.fY)) { 670 if (AlmostBequalUlps(dst[1].fY, d.fY)) {
671 dst[1].fY = d.fY; 671 dst[1].fY = d.fY;
672 } 672 }
673 } 673 }
674 674
675 /* classic one t subdivision */ 675 double SkDCubic::top(const SkDCubic& dCurve, double startT, double endT, SkDPoin t*topPt) const {
676 static void interp_cubic_coords(const double* src, double* dst, double t) { 676 double extremeTs[2];
677 double ab = SkDInterp(src[0], src[2], t); 677 double topT = -1;
678 double bc = SkDInterp(src[2], src[4], t); 678 int roots = SkDCubic::FindExtrema(&fPts[0].fY, extremeTs);
679 double cd = SkDInterp(src[4], src[6], t); 679 for (int index = 0; index < roots; ++index) {
680 double abc = SkDInterp(ab, bc, t); 680 double t = startT + (endT - startT) * extremeTs[index];
681 double bcd = SkDInterp(bc, cd, t); 681 SkDPoint mid = dCurve.ptAtT(t);
682 double abcd = SkDInterp(abc, bcd, t); 682 if (topPt->fY > mid.fY || (topPt->fY == mid.fY && topPt->fX > mid.fX)) {
683 683 topT = t;
684 dst[0] = src[0]; 684 *topPt = mid;
685 dst[2] = ab; 685 }
686 dst[4] = abc; 686 }
687 dst[6] = abcd; 687 return topT;
688 dst[8] = bcd;
689 dst[10] = cd;
690 dst[12] = src[6];
691 } 688 }
692
693 SkDCubicPair SkDCubic::chopAt(double t) const {
694 SkDCubicPair dst;
695 if (t == 0.5) {
696 dst.pts[0] = fPts[0];
697 dst.pts[1].fX = (fPts[0].fX + fPts[1].fX) / 2;
698 dst.pts[1].fY = (fPts[0].fY + fPts[1].fY) / 2;
699 dst.pts[2].fX = (fPts[0].fX + 2 * fPts[1].fX + fPts[2].fX) / 4;
700 dst.pts[2].fY = (fPts[0].fY + 2 * fPts[1].fY + fPts[2].fY) / 4;
701 dst.pts[3].fX = (fPts[0].fX + 3 * (fPts[1].fX + fPts[2].fX) + fPts[3].fX ) / 8;
702 dst.pts[3].fY = (fPts[0].fY + 3 * (fPts[1].fY + fPts[2].fY) + fPts[3].fY ) / 8;
703 dst.pts[4].fX = (fPts[1].fX + 2 * fPts[2].fX + fPts[3].fX) / 4;
704 dst.pts[4].fY = (fPts[1].fY + 2 * fPts[2].fY + fPts[3].fY) / 4;
705 dst.pts[5].fX = (fPts[2].fX + fPts[3].fX) / 2;
706 dst.pts[5].fY = (fPts[2].fY + fPts[3].fY) / 2;
707 dst.pts[6] = fPts[3];
708 return dst;
709 }
710 interp_cubic_coords(&fPts[0].fX, &dst.pts[0].fX, t);
711 interp_cubic_coords(&fPts[0].fY, &dst.pts[0].fY, t);
712 return dst;
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