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 "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 Loading... |
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 Loading... |
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 } | |
OLD | NEW |