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 "SkIntersections.h" | |
8 #include "SkOpAngle.h" | 7 #include "SkOpAngle.h" |
9 #include "SkOpSegment.h" | 8 #include "SkOpSegment.h" |
10 #include "SkPathOpsCurve.h" | 9 #include "SkPathOpsCurve.h" |
11 #include "SkTSort.h" | 10 #include "SkTSort.h" |
12 | 11 |
13 #if DEBUG_ANGLE | |
14 #include "SkString.h" | |
15 #endif | |
16 | |
17 /* Angles are sorted counterclockwise. The smallest angle has a positive x and t
he smallest | 12 /* Angles are sorted counterclockwise. The smallest angle has a positive x and t
he smallest |
18 positive y. The largest angle has a positive x and a zero y. */ | 13 positive y. The largest angle has a positive x and a zero y. */ |
19 | 14 |
20 #if DEBUG_ANGLE | 15 #if DEBUG_ANGLE |
21 static bool CompareResult(SkString* bugOut, int append, bool compare) { | 16 static bool CompareResult(const char* func, SkString* bugOut, SkString* bugP
art, int append, |
| 17 bool compare) { |
22 SkDebugf("%s %c %d\n", bugOut->c_str(), compare ? 'T' : 'F', append); | 18 SkDebugf("%s %c %d\n", bugOut->c_str(), compare ? 'T' : 'F', append); |
| 19 SkDebugf("%sPart %s\n", func, bugPart[0].c_str()); |
| 20 SkDebugf("%sPart %s\n", func, bugPart[1].c_str()); |
| 21 SkDebugf("%sPart %s\n", func, bugPart[2].c_str()); |
23 return compare; | 22 return compare; |
24 } | 23 } |
25 | 24 |
26 #define COMPARE_RESULT(append, compare) CompareResult(&bugOut, append, compa
re) | 25 #define COMPARE_RESULT(append, compare) CompareResult(__FUNCTION__, &bugOut,
bugPart, append, \ |
| 26 compare) |
27 #else | 27 #else |
28 #define COMPARE_RESULT(append, compare) compare | 28 #define COMPARE_RESULT(append, compare) compare |
29 #endif | 29 #endif |
30 | 30 |
31 /* quarter angle values for sector | 31 /* quarter angle values for sector |
32 | 32 |
33 31 x > 0, y == 0 horizontal line (to the right) | 33 31 x > 0, y == 0 horizontal line (to the right) |
34 0 x > 0, y == epsilon quad/cubic horizontal tangent eventually going +
y | 34 0 x > 0, y == epsilon quad/cubic horizontal tangent eventually going +
y |
35 1 x > 0, y > 0, x > y nearer horizontal angle | 35 1 x > 0, y > 0, x > y nearer horizontal angle |
36 2 x + e == y quad/cubic 45 going horiz | 36 2 x + e == y quad/cubic 45 going horiz |
(...skipping 14 matching lines...) Expand all Loading... |
51 16 | 30 | 51 16 | 30 |
52 17 | 29 | 52 17 | 29 |
53 18 / | \ 28 | 53 18 / | \ 28 |
54 19 | 27 | 54 19 | 27 |
55 20 | 26 | 55 20 | 26 |
56 21 | 25 | 56 21 | 25 |
57 22 23 24 | 57 22 23 24 |
58 */ | 58 */ |
59 | 59 |
60 // return true if lh < this < rh | 60 // return true if lh < this < rh |
61 bool SkOpAngle::after(const SkOpAngle* test) const { | 61 bool SkOpAngle::after(SkOpAngle* test) { |
62 const SkOpAngle& lh = *test; | 62 SkOpAngle* lh = test; |
63 const SkOpAngle& rh = *lh.fNext; | 63 SkOpAngle* rh = lh->fNext; |
64 SkASSERT(&lh != &rh); | 64 SkASSERT(lh != rh); |
65 #if DEBUG_ANGLE | 65 #if DEBUG_ANGLE |
66 SkString bugOut; | 66 SkString bugOut; |
67 bugOut.printf("%s [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g" | 67 bugOut.printf("%s [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g" |
68 " < [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g" | 68 " < [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g" |
69 " < [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g ", __FUNCTION__, | 69 " < [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g ", __FUNCTION__, |
70 lh.fSegment->debugID(), lh.debugID(), lh.fSectorStart, lh.fSectorEnd
, | 70 lh->segment()->debugID(), lh->debugID(), lh->fSectorStart, lh->fSect
orEnd, |
71 lh.fSegment->t(lh.fStart), lh.fSegment->t(lh.fEnd), | 71 lh->fStart->t(), lh->fEnd->t(), |
72 fSegment->debugID(), debugID(), fSectorStart, fSectorEnd, fSegment->
t(fStart), | 72 segment()->debugID(), debugID(), fSectorStart, fSectorEnd, fStart->t
(), fEnd->t(), |
73 fSegment->t(fEnd), | 73 rh->segment()->debugID(), rh->debugID(), rh->fSectorStart, rh->fSect
orEnd, |
74 rh.fSegment->debugID(), rh.debugID(), rh.fSectorStart, rh.fSectorEnd
, | 74 rh->fStart->t(), rh->fEnd->t()); |
75 rh.fSegment->t(rh.fStart), rh.fSegment->t(rh.fEnd)); | 75 SkString bugPart[3] = { lh->debugPart(), this->debugPart(), rh->debugPart()
}; |
76 #endif | 76 #endif |
77 if (lh.fComputeSector && !const_cast<SkOpAngle&>(lh).computeSector()) { | 77 if (lh->fComputeSector && !lh->computeSector()) { |
78 return COMPARE_RESULT(1, true); | 78 return COMPARE_RESULT(1, true); |
79 } | 79 } |
80 if (fComputeSector && !const_cast<SkOpAngle*>(this)->computeSector()) { | 80 if (fComputeSector && !this->computeSector()) { |
81 return COMPARE_RESULT(2, true); | 81 return COMPARE_RESULT(2, true); |
82 } | 82 } |
83 if (rh.fComputeSector && !const_cast<SkOpAngle&>(rh).computeSector()) { | 83 if (rh->fComputeSector && !rh->computeSector()) { |
84 return COMPARE_RESULT(3, true); | 84 return COMPARE_RESULT(3, true); |
85 } | 85 } |
86 #if DEBUG_ANGLE // reset bugOut with computed sectors | 86 #if DEBUG_ANGLE // reset bugOut with computed sectors |
87 bugOut.printf("%s [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g" | 87 bugOut.printf("%s [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g" |
88 " < [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g" | 88 " < [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g" |
89 " < [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g ", __FUNCTION__, | 89 " < [%d/%d] %d/%d tStart=%1.9g tEnd=%1.9g ", __FUNCTION__, |
90 lh.fSegment->debugID(), lh.debugID(), lh.fSectorStart, lh.fSectorEnd
, | 90 lh->segment()->debugID(), lh->debugID(), lh->fSectorStart, lh->fSect
orEnd, |
91 lh.fSegment->t(lh.fStart), lh.fSegment->t(lh.fEnd), | 91 lh->fStart->t(), lh->fEnd->t(), |
92 fSegment->debugID(), debugID(), fSectorStart, fSectorEnd, fSegment->
t(fStart), | 92 segment()->debugID(), debugID(), fSectorStart, fSectorEnd, fStart->t
(), fEnd->t(), |
93 fSegment->t(fEnd), | 93 rh->segment()->debugID(), rh->debugID(), rh->fSectorStart, rh->fSect
orEnd, |
94 rh.fSegment->debugID(), rh.debugID(), rh.fSectorStart, rh.fSectorEnd
, | 94 rh->fStart->t(), rh->fEnd->t()); |
95 rh.fSegment->t(rh.fStart), rh.fSegment->t(rh.fEnd)); | |
96 #endif | 95 #endif |
97 bool ltrOverlap = (lh.fSectorMask | rh.fSectorMask) & fSectorMask; | 96 bool ltrOverlap = (lh->fSectorMask | rh->fSectorMask) & fSectorMask; |
98 bool lrOverlap = lh.fSectorMask & rh.fSectorMask; | 97 bool lrOverlap = lh->fSectorMask & rh->fSectorMask; |
99 int lrOrder; // set to -1 if either order works | 98 int lrOrder; // set to -1 if either order works |
100 if (!lrOverlap) { // no lh/rh sector overlap | 99 if (!lrOverlap) { // no lh/rh sector overlap |
101 if (!ltrOverlap) { // no lh/this/rh sector overlap | 100 if (!ltrOverlap) { // no lh/this/rh sector overlap |
102 return COMPARE_RESULT(4, (lh.fSectorEnd > rh.fSectorStart) | 101 return COMPARE_RESULT(4, (lh->fSectorEnd > rh->fSectorStart) |
103 ^ (fSectorStart > lh.fSectorEnd) ^ (fSectorStart > rh.fSecto
rStart)); | 102 ^ (fSectorStart > lh->fSectorEnd) ^ (fSectorStart > rh->fSec
torStart)); |
104 } | 103 } |
105 int lrGap = (rh.fSectorStart - lh.fSectorStart + 32) & 0x1f; | 104 int lrGap = (rh->fSectorStart - lh->fSectorStart + 32) & 0x1f; |
106 /* A tiny change can move the start +/- 4. The order can only be determi
ned if | 105 /* A tiny change can move the start +/- 4. The order can only be determi
ned if |
107 lr gap is not 12 to 20 or -12 to -20. | 106 lr gap is not 12 to 20 or -12 to -20. |
108 -31 ..-21 1 | 107 -31 ..-21 1 |
109 -20 ..-12 -1 | 108 -20 ..-12 -1 |
110 -11 .. -1 0 | 109 -11 .. -1 0 |
111 0 shouldn't get here | 110 0 shouldn't get here |
112 11 .. 1 1 | 111 11 .. 1 1 |
113 12 .. 20 -1 | 112 12 .. 20 -1 |
114 21 .. 31 0 | 113 21 .. 31 0 |
115 */ | 114 */ |
116 lrOrder = lrGap > 20 ? 0 : lrGap > 11 ? -1 : 1; | 115 lrOrder = lrGap > 20 ? 0 : lrGap > 11 ? -1 : 1; |
117 } else { | 116 } else { |
118 lrOrder = (int) lh.orderable(rh); | 117 lrOrder = (int) lh->orderable(rh); |
119 if (!ltrOverlap) { | 118 if (!ltrOverlap) { |
120 return COMPARE_RESULT(5, !lrOrder); | 119 return COMPARE_RESULT(5, !lrOrder); |
121 } | 120 } |
122 } | 121 } |
123 int ltOrder; | 122 int ltOrder; |
124 SkASSERT((lh.fSectorMask & fSectorMask) || (rh.fSectorMask & fSectorMask)); | 123 SkASSERT((lh->fSectorMask & fSectorMask) || (rh->fSectorMask & fSectorMask))
; |
125 if (lh.fSectorMask & fSectorMask) { | 124 if (lh->fSectorMask & fSectorMask) { |
126 ltOrder = (int) lh.orderable(*this); | 125 ltOrder = (int) lh->orderable(this); |
127 } else { | 126 } else { |
128 int ltGap = (fSectorStart - lh.fSectorStart + 32) & 0x1f; | 127 int ltGap = (fSectorStart - lh->fSectorStart + 32) & 0x1f; |
129 ltOrder = ltGap > 20 ? 0 : ltGap > 11 ? -1 : 1; | 128 ltOrder = ltGap > 20 ? 0 : ltGap > 11 ? -1 : 1; |
130 } | 129 } |
131 int trOrder; | 130 int trOrder; |
132 if (rh.fSectorMask & fSectorMask) { | 131 if (rh->fSectorMask & fSectorMask) { |
133 trOrder = (int) orderable(rh); | 132 trOrder = (int) orderable(rh); |
134 } else { | 133 } else { |
135 int trGap = (rh.fSectorStart - fSectorStart + 32) & 0x1f; | 134 int trGap = (rh->fSectorStart - fSectorStart + 32) & 0x1f; |
136 trOrder = trGap > 20 ? 0 : trGap > 11 ? -1 : 1; | 135 trOrder = trGap > 20 ? 0 : trGap > 11 ? -1 : 1; |
137 } | 136 } |
138 if (lrOrder >= 0 && ltOrder >= 0 && trOrder >= 0) { | 137 if (lrOrder >= 0 && ltOrder >= 0 && trOrder >= 0) { |
139 return COMPARE_RESULT(7, lrOrder ? (ltOrder & trOrder) : (ltOrder | trOr
der)); | 138 return COMPARE_RESULT(7, lrOrder ? (ltOrder & trOrder) : (ltOrder | trOr
der)); |
140 } | 139 } |
141 SkASSERT(lrOrder >= 0 || ltOrder >= 0 || trOrder >= 0); | 140 SkASSERT(lrOrder >= 0 || ltOrder >= 0 || trOrder >= 0); |
142 // There's not enough information to sort. Get the pairs of angles in opposite p
lanes. | 141 // There's not enough information to sort. Get the pairs of angles in opposite p
lanes. |
143 // If an order is < 0, the pair is already in an opposite plane. Check the remai
ning pairs. | 142 // If an order is < 0, the pair is already in an opposite plane. Check the remai
ning pairs. |
144 // FIXME : once all variants are understood, rewrite this more simply | 143 // FIXME : once all variants are understood, rewrite this more simply |
145 if (ltOrder == 0 && lrOrder == 0) { | 144 if (ltOrder == 0 && lrOrder == 0) { |
146 SkASSERT(trOrder < 0); | 145 SkASSERT(trOrder < 0); |
147 // FIXME : once this is verified to work, remove one opposite angle call | 146 // FIXME : once this is verified to work, remove one opposite angle call |
148 SkDEBUGCODE(bool lrOpposite = lh.oppositePlanes(rh)); | 147 SkDEBUGCODE(bool lrOpposite = lh->oppositePlanes(rh)); |
149 bool ltOpposite = lh.oppositePlanes(*this); | 148 bool ltOpposite = lh->oppositePlanes(this); |
150 SkASSERT(lrOpposite != ltOpposite); | 149 SkASSERT(lrOpposite != ltOpposite); |
151 return COMPARE_RESULT(8, ltOpposite); | 150 return COMPARE_RESULT(8, ltOpposite); |
152 } else if (ltOrder == 1 && trOrder == 0) { | 151 } else if (ltOrder == 1 && trOrder == 0) { |
153 SkASSERT(lrOrder < 0); | 152 SkASSERT(lrOrder < 0); |
154 SkDEBUGCODE(bool ltOpposite = lh.oppositePlanes(*this)); | 153 SkDEBUGCODE(bool ltOpposite = lh->oppositePlanes(this)); |
155 bool trOpposite = oppositePlanes(rh); | 154 bool trOpposite = oppositePlanes(rh); |
156 SkASSERT(ltOpposite != trOpposite); | 155 SkASSERT(ltOpposite != trOpposite); |
157 return COMPARE_RESULT(9, trOpposite); | 156 return COMPARE_RESULT(9, trOpposite); |
158 } else if (lrOrder == 1 && trOrder == 1) { | 157 } else if (lrOrder == 1 && trOrder == 1) { |
159 SkASSERT(ltOrder < 0); | 158 SkASSERT(ltOrder < 0); |
160 SkDEBUGCODE(bool trOpposite = oppositePlanes(rh)); | 159 SkDEBUGCODE(bool trOpposite = oppositePlanes(rh)); |
161 bool lrOpposite = lh.oppositePlanes(rh); | 160 bool lrOpposite = lh->oppositePlanes(rh); |
162 SkASSERT(lrOpposite != trOpposite); | 161 SkASSERT(lrOpposite != trOpposite); |
163 return COMPARE_RESULT(10, lrOpposite); | 162 return COMPARE_RESULT(10, lrOpposite); |
164 } | 163 } |
165 if (lrOrder < 0) { | 164 if (lrOrder < 0) { |
166 if (ltOrder < 0) { | 165 if (ltOrder < 0) { |
167 return COMPARE_RESULT(11, trOrder); | 166 return COMPARE_RESULT(11, trOrder); |
168 } | 167 } |
169 return COMPARE_RESULT(12, ltOrder); | 168 return COMPARE_RESULT(12, ltOrder); |
170 } | 169 } |
171 return COMPARE_RESULT(13, !lrOrder); | 170 return COMPARE_RESULT(13, !lrOrder); |
172 } | 171 } |
173 | 172 |
174 // given a line, see if the opposite curve's convex hull is all on one side | 173 // given a line, see if the opposite curve's convex hull is all on one side |
175 // returns -1=not on one side 0=this CW of test 1=this CCW of test | 174 // returns -1=not on one side 0=this CW of test 1=this CCW of test |
176 int SkOpAngle::allOnOneSide(const SkOpAngle& test) const { | 175 int SkOpAngle::allOnOneSide(const SkOpAngle* test) { |
177 SkASSERT(!fIsCurve); | 176 SkASSERT(!fIsCurve); |
178 SkASSERT(test.fIsCurve); | 177 SkASSERT(test->fIsCurve); |
179 const SkDPoint& origin = test.fCurvePart[0]; | 178 const SkDPoint& origin = test->fCurvePart[0]; |
180 SkVector line; | 179 SkVector line; |
181 if (fSegment->verb() == SkPath::kLine_Verb) { | 180 if (segment()->verb() == SkPath::kLine_Verb) { |
182 const SkPoint* linePts = fSegment->pts(); | 181 const SkPoint* linePts = segment()->pts(); |
183 int lineStart = fStart < fEnd ? 0 : 1; | 182 int lineStart = fStart->t() < fEnd->t() ? 0 : 1; |
184 line = linePts[lineStart ^ 1] - linePts[lineStart]; | 183 line = linePts[lineStart ^ 1] - linePts[lineStart]; |
185 } else { | 184 } else { |
186 SkPoint shortPts[2] = { fCurvePart[0].asSkPoint(), fCurvePart[1].asSkPoi
nt() }; | 185 SkPoint shortPts[2] = { fCurvePart[0].asSkPoint(), fCurvePart[1].asSkPoi
nt() }; |
187 line = shortPts[1] - shortPts[0]; | 186 line = shortPts[1] - shortPts[0]; |
188 } | 187 } |
189 float crosses[3]; | 188 float crosses[3]; |
190 SkPath::Verb testVerb = test.fSegment->verb(); | 189 SkPath::Verb testVerb = test->segment()->verb(); |
191 int iMax = SkPathOpsVerbToPoints(testVerb); | 190 int iMax = SkPathOpsVerbToPoints(testVerb); |
192 // SkASSERT(origin == test.fCurveHalf[0]); | 191 // SkASSERT(origin == test.fCurveHalf[0]); |
193 const SkDCubic& testCurve = test.fCurvePart; | 192 const SkDCubic& testCurve = test->fCurvePart; |
194 // do { | 193 for (int index = 1; index <= iMax; ++index) { |
195 for (int index = 1; index <= iMax; ++index) { | 194 float xy1 = (float) (line.fX * (testCurve[index].fY - origin.fY)); |
196 float xy1 = (float) (line.fX * (testCurve[index].fY - origin.fY)); | 195 float xy2 = (float) (line.fY * (testCurve[index].fX - origin.fX)); |
197 float xy2 = (float) (line.fY * (testCurve[index].fX - origin.fX)); | 196 crosses[index - 1] = AlmostEqualUlps(xy1, xy2) ? 0 : xy1 - xy2; |
198 crosses[index - 1] = AlmostEqualUlps(xy1, xy2) ? 0 : xy1 - xy2; | 197 } |
199 } | 198 if (crosses[0] * crosses[1] < 0) { |
200 if (crosses[0] * crosses[1] < 0) { | 199 return -1; |
| 200 } |
| 201 if (SkPath::kCubic_Verb == testVerb) { |
| 202 if (crosses[0] * crosses[2] < 0 || crosses[1] * crosses[2] < 0) { |
201 return -1; | 203 return -1; |
202 } | 204 } |
203 if (SkPath::kCubic_Verb == testVerb) { | 205 } |
204 if (crosses[0] * crosses[2] < 0 || crosses[1] * crosses[2] < 0) { | 206 if (crosses[0]) { |
205 return -1; | 207 return crosses[0] < 0; |
206 } | 208 } |
207 } | 209 if (crosses[1]) { |
208 if (crosses[0]) { | 210 return crosses[1] < 0; |
209 return crosses[0] < 0; | 211 } |
210 } | 212 if (SkPath::kCubic_Verb == testVerb && crosses[2]) { |
211 if (crosses[1]) { | 213 return crosses[2] < 0; |
212 return crosses[1] < 0; | 214 } |
213 } | |
214 if (SkPath::kCubic_Verb == testVerb && crosses[2]) { | |
215 return crosses[2] < 0; | |
216 } | |
217 fUnorderable = true; | 215 fUnorderable = true; |
218 return -1; | 216 return -1; |
219 } | 217 } |
220 | 218 |
221 bool SkOpAngle::calcSlop(double x, double y, double rx, double ry, bool* result)
const { | |
222 double absX = fabs(x); | |
223 double absY = fabs(y); | |
224 double length = absX < absY ? absX / 2 + absY : absX + absY / 2; | |
225 int exponent; | |
226 (void) frexp(length, &exponent); | |
227 double epsilon = ldexp(FLT_EPSILON, exponent); | |
228 SkPath::Verb verb = fSegment->verb(); | |
229 SkASSERT(verb == SkPath::kQuad_Verb || verb == SkPath::kCubic_Verb); | |
230 // FIXME: the quad and cubic factors are made up ; determine actual values | |
231 double slop = verb == SkPath::kQuad_Verb ? 4 * epsilon : 512 * epsilon; | |
232 double xSlop = slop; | |
233 double ySlop = x * y < 0 ? -xSlop : xSlop; // OPTIMIZATION: use copysign / _
copysign ? | |
234 double x1 = x - xSlop; | |
235 double y1 = y + ySlop; | |
236 double x_ry1 = x1 * ry; | |
237 double rx_y1 = rx * y1; | |
238 *result = x_ry1 < rx_y1; | |
239 double x2 = x + xSlop; | |
240 double y2 = y - ySlop; | |
241 double x_ry2 = x2 * ry; | |
242 double rx_y2 = rx * y2; | |
243 bool less2 = x_ry2 < rx_y2; | |
244 return *result == less2; | |
245 } | |
246 | |
247 bool SkOpAngle::checkCrossesZero() const { | 219 bool SkOpAngle::checkCrossesZero() const { |
248 int start = SkTMin(fSectorStart, fSectorEnd); | 220 int start = SkTMin(fSectorStart, fSectorEnd); |
249 int end = SkTMax(fSectorStart, fSectorEnd); | 221 int end = SkTMax(fSectorStart, fSectorEnd); |
250 bool crossesZero = end - start > 16; | 222 bool crossesZero = end - start > 16; |
251 return crossesZero; | 223 return crossesZero; |
252 } | 224 } |
253 | 225 |
254 bool SkOpAngle::checkParallel(const SkOpAngle& rh) const { | 226 // loop looking for a pair of angle parts that are too close to be sorted |
| 227 /* This is called after other more simple intersection and angle sorting tests h
ave been exhausted. |
| 228 This should be rarely called -- the test below is thorough and time consuming
. |
| 229 This checks the distance between start points; the distance between |
| 230 */ |
| 231 void SkOpAngle::checkNearCoincidence() { |
| 232 SkOpAngle* test = this; |
| 233 do { |
| 234 SkOpSegment* testSegment = test->segment(); |
| 235 double testStartT = test->start()->t(); |
| 236 SkDPoint testStartPt = testSegment->dPtAtT(testStartT); |
| 237 double testEndT = test->end()->t(); |
| 238 SkDPoint testEndPt = testSegment->dPtAtT(testEndT); |
| 239 double testLenSq = testStartPt.distanceSquared(testEndPt); |
| 240 if (0) { |
| 241 SkDebugf("%s testLenSq=%1.9g id=%d\n", __FUNCTION__, testLenSq, test
Segment->debugID()); |
| 242 } |
| 243 double testMidT = (testStartT + testEndT) / 2; |
| 244 SkOpAngle* next = test; |
| 245 while ((next = next->fNext) != this) { |
| 246 SkOpSegment* nextSegment = next->segment(); |
| 247 double testMidDistSq = testSegment->distSq(testMidT, next); |
| 248 double testEndDistSq = testSegment->distSq(testEndT, next); |
| 249 double nextStartT = next->start()->t(); |
| 250 SkDPoint nextStartPt = nextSegment->dPtAtT(nextStartT); |
| 251 double distSq = testStartPt.distanceSquared(nextStartPt); |
| 252 double nextEndT = next->end()->t(); |
| 253 double nextMidT = (nextStartT + nextEndT) / 2; |
| 254 double nextMidDistSq = nextSegment->distSq(nextMidT, test); |
| 255 double nextEndDistSq = nextSegment->distSq(nextEndT, test); |
| 256 if (0) { |
| 257 SkDebugf("%s distSq=%1.9g testId=%d nextId=%d\n", __FUNCTION__,
distSq, |
| 258 testSegment->debugID(), nextSegment->debugID()); |
| 259 SkDebugf("%s testMidDistSq=%1.9g\n", __FUNCTION__, testMidDistSq
); |
| 260 SkDebugf("%s testEndDistSq=%1.9g\n", __FUNCTION__, testEndDistSq
); |
| 261 SkDebugf("%s nextMidDistSq=%1.9g\n", __FUNCTION__, nextMidDistSq
); |
| 262 SkDebugf("%s nextEndDistSq=%1.9g\n", __FUNCTION__, nextEndDistSq
); |
| 263 SkDPoint nextEndPt = nextSegment->dPtAtT(nextEndT); |
| 264 double nextLenSq = nextStartPt.distanceSquared(nextEndPt); |
| 265 SkDebugf("%s nextLenSq=%1.9g\n", __FUNCTION__, nextLenSq); |
| 266 SkDebugf("\n"); |
| 267 } |
| 268 } |
| 269 test = test->fNext; |
| 270 } while (test->fNext != this); |
| 271 } |
| 272 |
| 273 bool SkOpAngle::checkParallel(SkOpAngle* rh) { |
255 SkDVector scratch[2]; | 274 SkDVector scratch[2]; |
256 const SkDVector* sweep, * tweep; | 275 const SkDVector* sweep, * tweep; |
257 if (!fUnorderedSweep) { | 276 if (!this->fUnorderedSweep) { |
258 sweep = fSweep; | 277 sweep = this->fSweep; |
259 } else { | 278 } else { |
260 scratch[0] = fCurvePart[1] - fCurvePart[0]; | 279 scratch[0] = this->fCurvePart[1] - this->fCurvePart[0]; |
261 sweep = &scratch[0]; | 280 sweep = &scratch[0]; |
262 } | 281 } |
263 if (!rh.fUnorderedSweep) { | 282 if (!rh->fUnorderedSweep) { |
264 tweep = rh.fSweep; | 283 tweep = rh->fSweep; |
265 } else { | 284 } else { |
266 scratch[1] = rh.fCurvePart[1] - rh.fCurvePart[0]; | 285 scratch[1] = rh->fCurvePart[1] - rh->fCurvePart[0]; |
267 tweep = &scratch[1]; | 286 tweep = &scratch[1]; |
268 } | 287 } |
269 double s0xt0 = sweep->crossCheck(*tweep); | 288 double s0xt0 = sweep->crossCheck(*tweep); |
270 if (tangentsDiverge(rh, s0xt0)) { | 289 if (tangentsDiverge(rh, s0xt0)) { |
271 return s0xt0 < 0; | 290 return s0xt0 < 0; |
272 } | 291 } |
273 SkDVector m0 = fSegment->dPtAtT(midT()) - fCurvePart[0]; | 292 // compute the perpendicular to the endpoints and see where it intersects th
e opposite curve |
274 SkDVector m1 = rh.fSegment->dPtAtT(rh.midT()) - rh.fCurvePart[0]; | 293 // if the intersections within the t range, do a cross check on those |
| 294 bool inside; |
| 295 if (this->endToSide(rh, &inside)) { |
| 296 return inside; |
| 297 } |
| 298 if (rh->endToSide(this, &inside)) { |
| 299 return !inside; |
| 300 } |
| 301 if (this->midToSide(rh, &inside)) { |
| 302 return inside; |
| 303 } |
| 304 if (rh->midToSide(this, &inside)) { |
| 305 return !inside; |
| 306 } |
| 307 // compute the cross check from the mid T values (last resort) |
| 308 SkDVector m0 = segment()->dPtAtT(this->midT()) - this->fCurvePart[0]; |
| 309 SkDVector m1 = rh->segment()->dPtAtT(rh->midT()) - rh->fCurvePart[0]; |
275 double m0xm1 = m0.crossCheck(m1); | 310 double m0xm1 = m0.crossCheck(m1); |
276 if (m0xm1 == 0) { | 311 if (m0xm1 == 0) { |
277 fUnorderable = true; | 312 this->fUnorderable = true; |
278 rh.fUnorderable = true; | 313 rh->fUnorderable = true; |
279 return true; | 314 return true; |
280 } | 315 } |
281 return m0xm1 < 0; | 316 return m0xm1 < 0; |
282 } | 317 } |
283 | 318 |
284 // the original angle is too short to get meaningful sector information | 319 // the original angle is too short to get meaningful sector information |
285 // lengthen it until it is long enough to be meaningful or leave it unset if len
gthening it | 320 // lengthen it until it is long enough to be meaningful or leave it unset if len
gthening it |
286 // would cause it to intersect one of the adjacent angles | 321 // would cause it to intersect one of the adjacent angles |
287 bool SkOpAngle::computeSector() { | 322 bool SkOpAngle::computeSector() { |
288 if (fComputedSector) { | 323 if (fComputedSector) { |
289 return !fUnorderable; | 324 return !fUnorderable; |
290 } | 325 } |
291 // SkASSERT(fSegment->verb() != SkPath::kLine_Verb && small()); | |
292 fComputedSector = true; | 326 fComputedSector = true; |
293 int step = fStart < fEnd ? 1 : -1; | 327 bool stepUp = fStart->t() < fEnd->t(); |
294 int limit = step > 0 ? fSegment->count() : -1; | 328 const SkOpSpanBase* checkEnd = fEnd; |
295 int checkEnd = fEnd; | 329 if (checkEnd->final() && stepUp) { |
| 330 fUnorderable = true; |
| 331 return false; |
| 332 } |
296 do { | 333 do { |
297 // advance end | 334 // advance end |
298 const SkOpSpan& span = fSegment->span(checkEnd); | 335 const SkOpSegment* other = checkEnd->segment(); |
299 const SkOpSegment* other = span.fOther; | 336 const SkOpSpanBase* oSpan = other->head(); |
300 int oCount = other->count(); | 337 do { |
301 for (int oIndex = 0; oIndex < oCount; ++oIndex) { | 338 if (oSpan->segment() != segment()) { |
302 const SkOpSpan& oSpan = other->span(oIndex); | |
303 if (oSpan.fOther != fSegment) { | |
304 continue; | 339 continue; |
305 } | 340 } |
306 if (oSpan.fOtherIndex == checkEnd) { | 341 if (oSpan == checkEnd) { |
307 continue; | 342 continue; |
308 } | 343 } |
309 if (!approximately_equal(oSpan.fOtherT, span.fT)) { | 344 if (!approximately_equal(oSpan->t(), checkEnd->t())) { |
310 continue; | 345 continue; |
311 } | 346 } |
312 goto recomputeSector; | 347 goto recomputeSector; |
313 } | 348 } while (!oSpan->final() && (oSpan = oSpan->upCast()->next())); |
314 checkEnd += step; | 349 checkEnd = stepUp ? !checkEnd->final() |
315 } while (checkEnd != limit); | 350 ? checkEnd->upCast()->next() : NULL |
| 351 : checkEnd->prev(); |
| 352 } while (checkEnd); |
316 recomputeSector: | 353 recomputeSector: |
317 if (checkEnd == fEnd || checkEnd - step == fEnd) { | 354 SkOpSpanBase* computedEnd = stepUp ? checkEnd ? checkEnd->prev() : fEnd->seg
ment()->head() |
| 355 : checkEnd ? checkEnd->upCast()->next() : fEnd->segment()->tail(); |
| 356 if (checkEnd == fEnd || computedEnd == fEnd || computedEnd == fStart) { |
318 fUnorderable = true; | 357 fUnorderable = true; |
319 return false; | 358 return false; |
320 } | 359 } |
321 int saveEnd = fEnd; | 360 SkOpSpanBase* saveEnd = fEnd; |
322 fComputedEnd = fEnd = checkEnd - step; | 361 fComputedEnd = fEnd = computedEnd; |
323 setSpans(); | 362 setSpans(); |
324 setSector(); | 363 setSector(); |
325 fEnd = saveEnd; | 364 fEnd = saveEnd; |
326 return !fUnorderable; | 365 return !fUnorderable; |
327 } | 366 } |
328 | 367 |
329 // returns -1 if overlaps 0 if no overlap cw 1 if no overlap ccw | 368 int SkOpAngle::convexHullOverlaps(const SkOpAngle* rh) const { |
330 int SkOpAngle::convexHullOverlaps(const SkOpAngle& rh) const { | 369 const SkDVector* sweep = this->fSweep; |
331 const SkDVector* sweep = fSweep; | 370 const SkDVector* tweep = rh->fSweep; |
332 const SkDVector* tweep = rh.fSweep; | |
333 double s0xs1 = sweep[0].crossCheck(sweep[1]); | 371 double s0xs1 = sweep[0].crossCheck(sweep[1]); |
334 double s0xt0 = sweep[0].crossCheck(tweep[0]); | 372 double s0xt0 = sweep[0].crossCheck(tweep[0]); |
335 double s1xt0 = sweep[1].crossCheck(tweep[0]); | 373 double s1xt0 = sweep[1].crossCheck(tweep[0]); |
336 bool tBetweenS = s0xs1 > 0 ? s0xt0 > 0 && s1xt0 < 0 : s0xt0 < 0 && s1xt0 > 0
; | 374 bool tBetweenS = s0xs1 > 0 ? s0xt0 > 0 && s1xt0 < 0 : s0xt0 < 0 && s1xt0 > 0
; |
337 double s0xt1 = sweep[0].crossCheck(tweep[1]); | 375 double s0xt1 = sweep[0].crossCheck(tweep[1]); |
338 double s1xt1 = sweep[1].crossCheck(tweep[1]); | 376 double s1xt1 = sweep[1].crossCheck(tweep[1]); |
339 tBetweenS |= s0xs1 > 0 ? s0xt1 > 0 && s1xt1 < 0 : s0xt1 < 0 && s1xt1 > 0; | 377 tBetweenS |= s0xs1 > 0 ? s0xt1 > 0 && s1xt1 < 0 : s0xt1 < 0 && s1xt1 > 0; |
340 double t0xt1 = tweep[0].crossCheck(tweep[1]); | 378 double t0xt1 = tweep[0].crossCheck(tweep[1]); |
341 if (tBetweenS) { | 379 if (tBetweenS) { |
342 return -1; | 380 return -1; |
343 } | 381 } |
344 if ((s0xt0 == 0 && s1xt1 == 0) || (s1xt0 == 0 && s0xt1 == 0)) { // s0 to s1
equals t0 to t1 | 382 if ((s0xt0 == 0 && s1xt1 == 0) || (s1xt0 == 0 && s0xt1 == 0)) { // s0 to s1
equals t0 to t1 |
345 return -1; | 383 return -1; |
346 } | 384 } |
347 bool sBetweenT = t0xt1 > 0 ? s0xt0 < 0 && s0xt1 > 0 : s0xt0 > 0 && s0xt1 < 0
; | 385 bool sBetweenT = t0xt1 > 0 ? s0xt0 < 0 && s0xt1 > 0 : s0xt0 > 0 && s0xt1 < 0
; |
348 sBetweenT |= t0xt1 > 0 ? s1xt0 < 0 && s1xt1 > 0 : s1xt0 > 0 && s1xt1 < 0; | 386 sBetweenT |= t0xt1 > 0 ? s1xt0 < 0 && s1xt1 > 0 : s1xt0 > 0 && s1xt1 < 0; |
349 if (sBetweenT) { | 387 if (sBetweenT) { |
350 return -1; | 388 return -1; |
351 } | 389 } |
352 // if all of the sweeps are in the same half plane, then the order of any pa
ir is enough | 390 // if all of the sweeps are in the same half plane, then the order of any pa
ir is enough |
353 if (s0xt0 >= 0 && s0xt1 >= 0 && s1xt0 >= 0 && s1xt1 >= 0) { | 391 if (s0xt0 >= 0 && s0xt1 >= 0 && s1xt0 >= 0 && s1xt1 >= 0) { |
354 return 0; | 392 return 0; |
355 } | 393 } |
356 if (s0xt0 <= 0 && s0xt1 <= 0 && s1xt0 <= 0 && s1xt1 <= 0) { | 394 if (s0xt0 <= 0 && s0xt1 <= 0 && s1xt0 <= 0 && s1xt1 <= 0) { |
357 return 1; | 395 return 1; |
358 } | 396 } |
359 // if the outside sweeps are greater than 180 degress: | 397 // if the outside sweeps are greater than 180 degress: |
360 // first assume the inital tangents are the ordering | 398 // first assume the inital tangents are the ordering |
361 // if the midpoint direction matches the inital order, that is enough | 399 // if the midpoint direction matches the inital order, that is enough |
362 SkDVector m0 = fSegment->dPtAtT(midT()) - fCurvePart[0]; | 400 SkDVector m0 = this->segment()->dPtAtT(this->midT()) - this->fCurvePart[0]; |
363 SkDVector m1 = rh.fSegment->dPtAtT(rh.midT()) - rh.fCurvePart[0]; | 401 SkDVector m1 = rh->segment()->dPtAtT(rh->midT()) - rh->fCurvePart[0]; |
364 double m0xm1 = m0.crossCheck(m1); | 402 double m0xm1 = m0.crossCheck(m1); |
365 if (s0xt0 > 0 && m0xm1 > 0) { | 403 if (s0xt0 > 0 && m0xm1 > 0) { |
366 return 0; | 404 return 0; |
367 } | 405 } |
368 if (s0xt0 < 0 && m0xm1 < 0) { | 406 if (s0xt0 < 0 && m0xm1 < 0) { |
369 return 1; | 407 return 1; |
370 } | 408 } |
371 if (tangentsDiverge(rh, s0xt0)) { | 409 if (tangentsDiverge(rh, s0xt0)) { |
372 return s0xt0 < 0; | 410 return s0xt0 < 0; |
373 } | 411 } |
(...skipping 13 matching lines...) Expand all Loading... |
387 } | 425 } |
388 SkDVector v; | 426 SkDVector v; |
389 v.set(pts[idx2] - pts[idx1]); | 427 v.set(pts[idx2] - pts[idx1]); |
390 double lenSq = v.lengthSquared(); | 428 double lenSq = v.lengthSquared(); |
391 longest = SkTMax(longest, lenSq); | 429 longest = SkTMax(longest, lenSq); |
392 } | 430 } |
393 } | 431 } |
394 return sqrt(longest) / dist; | 432 return sqrt(longest) / dist; |
395 } | 433 } |
396 | 434 |
397 bool SkOpAngle::endsIntersect(const SkOpAngle& rh) const { | 435 bool SkOpAngle::endsIntersect(SkOpAngle* rh) { |
398 SkPath::Verb lVerb = fSegment->verb(); | 436 SkPath::Verb lVerb = this->segment()->verb(); |
399 SkPath::Verb rVerb = rh.fSegment->verb(); | 437 SkPath::Verb rVerb = rh->segment()->verb(); |
400 int lPts = SkPathOpsVerbToPoints(lVerb); | 438 int lPts = SkPathOpsVerbToPoints(lVerb); |
401 int rPts = SkPathOpsVerbToPoints(rVerb); | 439 int rPts = SkPathOpsVerbToPoints(rVerb); |
402 SkDLine rays[] = {{{fCurvePart[0], rh.fCurvePart[rPts]}}, | 440 SkDLine rays[] = {{{this->fCurvePart[0], rh->fCurvePart[rPts]}}, |
403 {{fCurvePart[0], fCurvePart[lPts]}}}; | 441 {{this->fCurvePart[0], this->fCurvePart[lPts]}}}; |
404 if (rays[0][1] == rays[1][1]) { | 442 if (rays[0][1] == rays[1][1]) { |
405 return checkParallel(rh); | 443 return checkParallel(rh); |
406 } | 444 } |
407 double smallTs[2] = {-1, -1}; | 445 double smallTs[2] = {-1, -1}; |
408 bool limited[2] = {false, false}; | 446 bool limited[2] = {false, false}; |
409 for (int index = 0; index < 2; ++index) { | 447 for (int index = 0; index < 2; ++index) { |
410 const SkOpSegment& segment = index ? *rh.fSegment : *fSegment; | |
411 SkIntersections i; | |
412 int cPts = index ? rPts : lPts; | 448 int cPts = index ? rPts : lPts; |
413 (*CurveIntersectRay[cPts])(segment.pts(), rays[index], &i); | |
414 // if the curve is a line, then the line and the ray intersect only at t
heir crossing | 449 // if the curve is a line, then the line and the ray intersect only at t
heir crossing |
415 if (cPts == 1) { // line | 450 if (cPts == 1) { // line |
416 continue; | 451 continue; |
417 } | 452 } |
418 // SkASSERT(i.used() >= 1); | 453 const SkOpSegment& segment = index ? *rh->segment() : *this->segment(); |
419 // if (i.used() <= 1) { | 454 SkIntersections i; |
420 // continue; | 455 (*CurveIntersectRay[cPts])(segment.pts(), rays[index], &i); |
421 // } | 456 double tStart = index ? rh->fStart->t() : this->fStart->t(); |
422 double tStart = segment.t(index ? rh.fStart : fStart); | 457 double tEnd = index ? rh->fComputedEnd->t() : this->fComputedEnd->t(); |
423 double tEnd = segment.t(index ? rh.fComputedEnd : fComputedEnd); | 458 bool testAscends = tStart < (index ? rh->fComputedEnd->t() : this->fComp
utedEnd->t()); |
424 bool testAscends = index ? rh.fStart < rh.fComputedEnd : fStart < fCompu
tedEnd; | |
425 double t = testAscends ? 0 : 1; | 459 double t = testAscends ? 0 : 1; |
426 for (int idx2 = 0; idx2 < i.used(); ++idx2) { | 460 for (int idx2 = 0; idx2 < i.used(); ++idx2) { |
427 double testT = i[0][idx2]; | 461 double testT = i[0][idx2]; |
428 if (!approximately_between_orderable(tStart, testT, tEnd)) { | 462 if (!approximately_between_orderable(tStart, testT, tEnd)) { |
429 continue; | 463 continue; |
430 } | 464 } |
431 if (approximately_equal_orderable(tStart, testT)) { | 465 if (approximately_equal_orderable(tStart, testT)) { |
432 continue; | 466 continue; |
433 } | 467 } |
434 smallTs[index] = t = testAscends ? SkTMax(t, testT) : SkTMin(t, test
T); | 468 smallTs[index] = t = testAscends ? SkTMax(t, testT) : SkTMin(t, test
T); |
435 limited[index] = approximately_equal_orderable(t, tEnd); | 469 limited[index] = approximately_equal_orderable(t, tEnd); |
436 } | 470 } |
437 } | 471 } |
438 #if 0 | |
439 if (smallTs[0] < 0 && smallTs[1] < 0) { // if neither ray intersects, do en
dpoint sort | |
440 double m0xm1 = 0; | |
441 if (lVerb == SkPath::kLine_Verb) { | |
442 SkASSERT(rVerb != SkPath::kLine_Verb); | |
443 SkDVector m0 = rays[1][1] - fCurvePart[0]; | |
444 SkDPoint endPt; | |
445 endPt.set(rh.fSegment->pts()[rh.fStart < rh.fEnd ? rPts : 0]); | |
446 SkDVector m1 = endPt - fCurvePart[0]; | |
447 m0xm1 = m0.crossCheck(m1); | |
448 } | |
449 if (rVerb == SkPath::kLine_Verb) { | |
450 SkDPoint endPt; | |
451 endPt.set(fSegment->pts()[fStart < fEnd ? lPts : 0]); | |
452 SkDVector m0 = endPt - fCurvePart[0]; | |
453 SkDVector m1 = rays[0][1] - fCurvePart[0]; | |
454 m0xm1 = m0.crossCheck(m1); | |
455 } | |
456 if (m0xm1 != 0) { | |
457 return m0xm1 < 0; | |
458 } | |
459 } | |
460 #endif | |
461 bool sRayLonger = false; | 472 bool sRayLonger = false; |
462 SkDVector sCept = {0, 0}; | 473 SkDVector sCept = {0, 0}; |
463 double sCeptT = -1; | 474 double sCeptT = -1; |
464 int sIndex = -1; | 475 int sIndex = -1; |
465 bool useIntersect = false; | 476 bool useIntersect = false; |
466 for (int index = 0; index < 2; ++index) { | 477 for (int index = 0; index < 2; ++index) { |
467 if (smallTs[index] < 0) { | 478 if (smallTs[index] < 0) { |
468 continue; | 479 continue; |
469 } | 480 } |
470 const SkOpSegment& segment = index ? *rh.fSegment : *fSegment; | 481 const SkOpSegment& segment = index ? *rh->segment() : *this->segment(); |
471 const SkDPoint& dPt = segment.dPtAtT(smallTs[index]); | 482 const SkDPoint& dPt = segment.dPtAtT(smallTs[index]); |
472 SkDVector cept = dPt - rays[index][0]; | 483 SkDVector cept = dPt - rays[index][0]; |
473 // If this point is on the curve, it should have been detected earlier b
y ordinary | 484 // If this point is on the curve, it should have been detected earlier b
y ordinary |
474 // curve intersection. This may be hard to determine in general, but for
lines, | 485 // curve intersection. This may be hard to determine in general, but for
lines, |
475 // the point could be close to or equal to its end, but shouldn't be nea
r the start. | 486 // the point could be close to or equal to its end, but shouldn't be nea
r the start. |
476 if ((index ? lPts : rPts) == 1) { | 487 if ((index ? lPts : rPts) == 1) { |
477 SkDVector total = rays[index][1] - rays[index][0]; | 488 SkDVector total = rays[index][1] - rays[index][0]; |
478 if (cept.lengthSquared() * 2 < total.lengthSquared()) { | 489 if (cept.lengthSquared() * 2 < total.lengthSquared()) { |
479 continue; | 490 continue; |
480 } | 491 } |
(...skipping 10 matching lines...) Expand all Loading... |
491 sRayLonger = rayLonger; | 502 sRayLonger = rayLonger; |
492 sCept = cept; | 503 sCept = cept; |
493 sCeptT = smallTs[index]; | 504 sCeptT = smallTs[index]; |
494 sIndex = index; | 505 sIndex = index; |
495 break; | 506 break; |
496 } | 507 } |
497 double delta = fabs(rayDist - endDist); | 508 double delta = fabs(rayDist - endDist); |
498 double minX, minY, maxX, maxY; | 509 double minX, minY, maxX, maxY; |
499 minX = minY = SK_ScalarInfinity; | 510 minX = minY = SK_ScalarInfinity; |
500 maxX = maxY = -SK_ScalarInfinity; | 511 maxX = maxY = -SK_ScalarInfinity; |
501 const SkDCubic& curve = index ? rh.fCurvePart : fCurvePart; | 512 const SkDCubic& curve = index ? rh->fCurvePart : this->fCurvePart; |
502 int ptCount = index ? rPts : lPts; | 513 int ptCount = index ? rPts : lPts; |
503 for (int idx2 = 0; idx2 <= ptCount; ++idx2) { | 514 for (int idx2 = 0; idx2 <= ptCount; ++idx2) { |
504 minX = SkTMin(minX, curve[idx2].fX); | 515 minX = SkTMin(minX, curve[idx2].fX); |
505 minY = SkTMin(minY, curve[idx2].fY); | 516 minY = SkTMin(minY, curve[idx2].fY); |
506 maxX = SkTMax(maxX, curve[idx2].fX); | 517 maxX = SkTMax(maxX, curve[idx2].fX); |
507 maxY = SkTMax(maxY, curve[idx2].fY); | 518 maxY = SkTMax(maxY, curve[idx2].fY); |
508 } | 519 } |
509 double maxWidth = SkTMax(maxX - minX, maxY - minY); | 520 double maxWidth = SkTMax(maxX - minX, maxY - minY); |
510 delta /= maxWidth; | 521 delta /= maxWidth; |
511 if (delta > 1e-4 && (useIntersect ^= true)) { // FIXME: move this magic
number | 522 if (delta > 1e-3 && (useIntersect ^= true)) { // FIXME: move this magic
number |
512 sRayLonger = rayLonger; | 523 sRayLonger = rayLonger; |
513 sCept = cept; | 524 sCept = cept; |
514 sCeptT = smallTs[index]; | 525 sCeptT = smallTs[index]; |
515 sIndex = index; | 526 sIndex = index; |
516 } | 527 } |
517 } | 528 } |
518 if (useIntersect) { | 529 if (useIntersect) { |
519 const SkDCubic& curve = sIndex ? rh.fCurvePart : fCurvePart; | 530 const SkDCubic& curve = sIndex ? rh->fCurvePart : this->fCurvePart; |
520 const SkOpSegment& segment = sIndex ? *rh.fSegment : *fSegment; | 531 const SkOpSegment& segment = sIndex ? *rh->segment() : *this->segment(); |
521 double tStart = segment.t(sIndex ? rh.fStart : fStart); | 532 double tStart = sIndex ? rh->fStart->t() : fStart->t(); |
522 SkDVector mid = segment.dPtAtT(tStart + (sCeptT - tStart) / 2) - curve[0
]; | 533 SkDVector mid = segment.dPtAtT(tStart + (sCeptT - tStart) / 2) - curve[0
]; |
523 double septDir = mid.crossCheck(sCept); | 534 double septDir = mid.crossCheck(sCept); |
524 if (!septDir) { | 535 if (!septDir) { |
525 return checkParallel(rh); | 536 return checkParallel(rh); |
526 } | 537 } |
527 return sRayLonger ^ (sIndex == 0) ^ (septDir < 0); | 538 return sRayLonger ^ (sIndex == 0) ^ (septDir < 0); |
528 } else { | 539 } else { |
529 return checkParallel(rh); | 540 return checkParallel(rh); |
530 } | 541 } |
531 } | 542 } |
532 | 543 |
| 544 bool SkOpAngle::endToSide(const SkOpAngle* rh, bool* inside) const { |
| 545 const SkOpSegment* segment = this->segment(); |
| 546 SkPath::Verb verb = segment->verb(); |
| 547 int pts = SkPathOpsVerbToPoints(verb); |
| 548 SkDLine rayEnd; |
| 549 rayEnd[0].set(this->fEnd->pt()); |
| 550 rayEnd[1] = rayEnd[0]; |
| 551 SkDVector slopeAtEnd = (*CurveDSlopeAtT[pts])(segment->pts(), this->fEnd->t(
)); |
| 552 rayEnd[1].fX += slopeAtEnd.fY; |
| 553 rayEnd[1].fY -= slopeAtEnd.fX; |
| 554 SkIntersections iEnd; |
| 555 const SkOpSegment* oppSegment = rh->segment(); |
| 556 SkPath::Verb oppVerb = oppSegment->verb(); |
| 557 int oppPts = SkPathOpsVerbToPoints(oppVerb); |
| 558 (*CurveIntersectRay[oppPts])(oppSegment->pts(), rayEnd, &iEnd); |
| 559 double endDist; |
| 560 int closestEnd = iEnd.closestTo(rh->fStart->t(), rh->fEnd->t(), rayEnd[0], &
endDist); |
| 561 if (closestEnd < 0) { |
| 562 return false; |
| 563 } |
| 564 if (!endDist) { |
| 565 return false; |
| 566 } |
| 567 SkDPoint start; |
| 568 start.set(this->fStart->pt()); |
| 569 // OPTIMIZATION: multiple times in the code we find the max scalar |
| 570 double minX, minY, maxX, maxY; |
| 571 minX = minY = SK_ScalarInfinity; |
| 572 maxX = maxY = -SK_ScalarInfinity; |
| 573 const SkDCubic& curve = rh->fCurvePart; |
| 574 for (int idx2 = 0; idx2 <= oppPts; ++idx2) { |
| 575 minX = SkTMin(minX, curve[idx2].fX); |
| 576 minY = SkTMin(minY, curve[idx2].fY); |
| 577 maxX = SkTMax(maxX, curve[idx2].fX); |
| 578 maxY = SkTMax(maxY, curve[idx2].fY); |
| 579 } |
| 580 double maxWidth = SkTMax(maxX - minX, maxY - minY); |
| 581 endDist /= maxWidth; |
| 582 if (endDist < 5e-11) { // empirically found |
| 583 return false; |
| 584 } |
| 585 const SkDPoint* endPt = &rayEnd[0]; |
| 586 SkDPoint oppPt = iEnd.pt(closestEnd); |
| 587 SkDVector vLeft = *endPt - start; |
| 588 SkDVector vRight = oppPt - start; |
| 589 double dir = vLeft.crossCheck(vRight); |
| 590 if (!dir) { |
| 591 return false; |
| 592 } |
| 593 *inside = dir < 0; |
| 594 return true; |
| 595 } |
| 596 |
533 // Most of the time, the first one can be found trivially by detecting the small
est sector value. | 597 // Most of the time, the first one can be found trivially by detecting the small
est sector value. |
534 // If all angles have the same sector value, actual sorting is required. | 598 // If all angles have the same sector value, actual sorting is required. |
535 const SkOpAngle* SkOpAngle::findFirst() const { | 599 SkOpAngle* SkOpAngle::findFirst() { |
536 const SkOpAngle* best = this; | 600 SkOpAngle* best = this; |
537 int bestStart = SkTMin(fSectorStart, fSectorEnd); | 601 int bestStart = SkTMin(fSectorStart, fSectorEnd); |
538 const SkOpAngle* angle = this; | 602 SkOpAngle* angle = this; |
539 while ((angle = angle->fNext) != this) { | 603 while ((angle = angle->fNext) != this) { |
540 int angleEnd = SkTMax(angle->fSectorStart, angle->fSectorEnd); | 604 int angleEnd = SkTMax(angle->fSectorStart, angle->fSectorEnd); |
541 if (angleEnd < bestStart) { | 605 if (angleEnd < bestStart) { |
542 return angle; // we wrapped around | 606 return angle; // we wrapped around |
543 } | 607 } |
544 int angleStart = SkTMin(angle->fSectorStart, angle->fSectorEnd); | 608 int angleStart = SkTMin(angle->fSectorStart, angle->fSectorEnd); |
545 if (bestStart > angleStart) { | 609 if (bestStart > angleStart) { |
546 best = angle; | 610 best = angle; |
547 bestStart = angleStart; | 611 bestStart = angleStart; |
548 } | 612 } |
549 } | 613 } |
550 // back up to the first possible angle | 614 // back up to the first possible angle |
551 const SkOpAngle* firstBest = best; | 615 SkOpAngle* firstBest = best; |
552 angle = best; | 616 angle = best; |
553 int bestEnd = SkTMax(best->fSectorStart, best->fSectorEnd); | 617 int bestEnd = SkTMax(best->fSectorStart, best->fSectorEnd); |
554 while ((angle = angle->previous()) != firstBest) { | 618 while ((angle = angle->previous()) != firstBest) { |
555 if (angle->fStop) { | 619 if (angle->fStop) { |
556 break; | 620 break; |
557 } | 621 } |
558 int angleStart = SkTMin(angle->fSectorStart, angle->fSectorEnd); | 622 int angleStart = SkTMin(angle->fSectorStart, angle->fSectorEnd); |
559 // angles that are smaller by one aren't necessary better, since the lar
ger may be a line | 623 // angles that are smaller by one aren't necessary better, since the lar
ger may be a line |
560 // and the smaller may be a curve that curls to the other side of the li
ne. | 624 // and the smaller may be a curve that curls to the other side of the li
ne. |
561 if (bestEnd + 1 < angleStart) { | 625 if (bestEnd + 1 < angleStart) { |
562 return best; | 626 return best; |
563 } | 627 } |
564 best = angle; | 628 best = angle; |
565 bestEnd = SkTMax(angle->fSectorStart, angle->fSectorEnd); | 629 bestEnd = SkTMax(angle->fSectorStart, angle->fSectorEnd); |
566 } | 630 } |
567 // in the case where all angles are nearly in the same sector, check the ord
er to find the best | 631 // in the case where all angles are nearly in the same sector, check the ord
er to find the best |
568 firstBest = best; | 632 firstBest = best; |
569 angle = best; | 633 angle = best; |
570 do { | 634 do { |
571 angle = angle->fNext; | 635 angle = angle->fNext; |
572 if (angle->fStop) { | 636 if (angle->fStop) { |
573 return firstBest; | 637 return firstBest; |
574 } | 638 } |
575 bool orderable = best->orderable(*angle); // note: may return an unorde
rable angle | 639 bool orderable = best->orderable(angle); // note: may return an unorder
able angle |
576 if (orderable == 0) { | 640 if (orderable == 0) { |
577 return angle; | 641 return angle; |
578 } | 642 } |
579 best = angle; | 643 best = angle; |
580 } while (angle != firstBest); | 644 } while (angle != firstBest); |
581 // if the angles are equally ordered, fall back on the initial tangent | 645 // if the angles are equally ordered, fall back on the initial tangent |
582 bool foundBelow = false; | 646 bool foundBelow = false; |
583 while ((angle = angle->fNext)) { | 647 while ((angle = angle->fNext)) { |
584 SkDVector scratch[2]; | 648 SkDVector scratch[2]; |
585 const SkDVector* sweep; | 649 const SkDVector* sweep; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
632 // x<0 x==0 x>0 x<0 x==0 x>0 x<0 x==0 x>0 | 696 // x<0 x==0 x>0 x<0 x==0 x>0 x<0 x==0 x>0 |
633 {{ 4, 3, 2}, { 7, -1, 15}, {10, 11, 12}}, // abs(x) < abs(y) | 697 {{ 4, 3, 2}, { 7, -1, 15}, {10, 11, 12}}, // abs(x) < abs(y) |
634 {{ 5, -1, 1}, {-1, -1, -1}, { 9, -1, 13}}, // abs(x) == abs(y) | 698 {{ 5, -1, 1}, {-1, -1, -1}, { 9, -1, 13}}, // abs(x) == abs(y) |
635 {{ 6, 3, 0}, { 7, -1, 15}, { 8, 11, 14}}, // abs(x) > abs(y) | 699 {{ 6, 3, 0}, { 7, -1, 15}, { 8, 11, 14}}, // abs(x) > abs(y) |
636 }; | 700 }; |
637 int sector = sedecimant[(xy >= 0) + (xy > 0)][(y >= 0) + (y > 0)][(x >= 0) +
(x > 0)] * 2 + 1; | 701 int sector = sedecimant[(xy >= 0) + (xy > 0)][(y >= 0) + (y > 0)][(x >= 0) +
(x > 0)] * 2 + 1; |
638 // SkASSERT(SkPath::kLine_Verb == verb || sector >= 0); | 702 // SkASSERT(SkPath::kLine_Verb == verb || sector >= 0); |
639 return sector; | 703 return sector; |
640 } | 704 } |
641 | 705 |
| 706 SkOpGlobalState* SkOpAngle::globalState() const { |
| 707 return this->segment()->globalState(); |
| 708 } |
| 709 |
| 710 |
642 // OPTIMIZE: if this loops to only one other angle, after first compare fails, i
nsert on other side | 711 // OPTIMIZE: if this loops to only one other angle, after first compare fails, i
nsert on other side |
643 // OPTIMIZE: return where insertion succeeded. Then, start next insertion on opp
osite side | 712 // OPTIMIZE: return where insertion succeeded. Then, start next insertion on opp
osite side |
644 void SkOpAngle::insert(SkOpAngle* angle) { | 713 void SkOpAngle::insert(SkOpAngle* angle) { |
645 if (angle->fNext) { | 714 if (angle->fNext) { |
646 if (loopCount() >= angle->loopCount()) { | 715 if (loopCount() >= angle->loopCount()) { |
647 if (!merge(angle)) { | 716 if (!merge(angle)) { |
648 return; | 717 return; |
649 } | 718 } |
650 } else if (fNext) { | 719 } else if (fNext) { |
651 if (!angle->merge(this)) { | 720 if (!angle->merge(this)) { |
652 return; | 721 return; |
653 } | 722 } |
654 } else { | 723 } else { |
655 angle->insert(this); | 724 angle->insert(this); |
656 } | 725 } |
657 return; | 726 return; |
658 } | 727 } |
659 bool singleton = NULL == fNext; | 728 bool singleton = NULL == fNext; |
660 if (singleton) { | 729 if (singleton) { |
661 fNext = this; | 730 fNext = this; |
662 } | 731 } |
663 SkOpAngle* next = fNext; | 732 SkOpAngle* next = fNext; |
664 if (next->fNext == this) { | 733 if (next->fNext == this) { |
665 if (angle->overlap(*this)) { // angles are essentially coincident | |
666 return; | |
667 } | |
668 if (singleton || angle->after(this)) { | 734 if (singleton || angle->after(this)) { |
669 this->fNext = angle; | 735 this->fNext = angle; |
670 angle->fNext = next; | 736 angle->fNext = next; |
671 } else { | 737 } else { |
672 next->fNext = angle; | 738 next->fNext = angle; |
673 angle->fNext = this; | 739 angle->fNext = this; |
674 } | 740 } |
675 debugValidateNext(); | 741 debugValidateNext(); |
676 return; | 742 return; |
677 } | 743 } |
678 SkOpAngle* last = this; | 744 SkOpAngle* last = this; |
679 do { | 745 do { |
680 SkASSERT(last->fNext == next); | 746 SkASSERT(last->fNext == next); |
681 if (angle->overlap(*last) || angle->overlap(*next)) { | |
682 return; | |
683 } | |
684 if (angle->after(last)) { | 747 if (angle->after(last)) { |
685 last->fNext = angle; | 748 last->fNext = angle; |
686 angle->fNext = next; | 749 angle->fNext = next; |
687 debugValidateNext(); | 750 debugValidateNext(); |
688 return; | 751 return; |
689 } | 752 } |
690 last = next; | 753 last = next; |
691 next = next->fNext; | 754 next = next->fNext; |
692 if (last == this && next->fUnorderable) { | 755 if (last == this) { |
693 fUnorderable = true; | 756 if (next->fUnorderable) { |
| 757 fUnorderable = true; |
| 758 } else { |
| 759 globalState()->setAngleCoincidence(); |
| 760 this->fNext = angle; |
| 761 angle->fNext = next; |
| 762 angle->fCheckCoincidence = true; |
| 763 } |
694 return; | 764 return; |
695 } | 765 } |
696 SkASSERT(last != this); | |
697 } while (true); | 766 } while (true); |
698 } | 767 } |
699 | 768 |
700 bool SkOpAngle::isHorizontal() const { | 769 SkOpSpanBase* SkOpAngle::lastMarked() const { |
701 return !fIsCurve && fSweep[0].fY == 0; | |
702 } | |
703 | |
704 SkOpSpan* SkOpAngle::lastMarked() const { | |
705 if (fLastMarked) { | 770 if (fLastMarked) { |
706 if (fLastMarked->fChased) { | 771 if (fLastMarked->chased()) { |
707 return NULL; | 772 return NULL; |
708 } | 773 } |
709 fLastMarked->fChased = true; | 774 fLastMarked->setChased(true); |
710 } | 775 } |
711 return fLastMarked; | 776 return fLastMarked; |
712 } | 777 } |
713 | 778 |
714 bool SkOpAngle::loopContains(const SkOpAngle& test) const { | 779 bool SkOpAngle::loopContains(const SkOpAngle* angle) const { |
715 if (!fNext) { | 780 if (!fNext) { |
716 return false; | 781 return false; |
717 } | 782 } |
718 const SkOpAngle* first = this; | 783 const SkOpAngle* first = this; |
719 const SkOpAngle* loop = this; | 784 const SkOpAngle* loop = this; |
720 const SkOpSegment* tSegment = test.fSegment; | 785 const SkOpSegment* tSegment = angle->fStart->segment(); |
721 double tStart = tSegment->span(test.fStart).fT; | 786 double tStart = angle->fStart->t(); |
722 double tEnd = tSegment->span(test.fEnd).fT; | 787 double tEnd = angle->fEnd->t(); |
723 do { | 788 do { |
724 const SkOpSegment* lSegment = loop->fSegment; | 789 const SkOpSegment* lSegment = loop->fStart->segment(); |
725 // FIXME : use precisely_equal ? or compare points exactly ? | |
726 if (lSegment != tSegment) { | 790 if (lSegment != tSegment) { |
727 continue; | 791 continue; |
728 } | 792 } |
729 double lStart = lSegment->span(loop->fStart).fT; | 793 double lStart = loop->fStart->t(); |
730 if (lStart != tEnd) { | 794 if (lStart != tEnd) { |
731 continue; | 795 continue; |
732 } | 796 } |
733 double lEnd = lSegment->span(loop->fEnd).fT; | 797 double lEnd = loop->fEnd->t(); |
734 if (lEnd == tStart) { | 798 if (lEnd == tStart) { |
735 return true; | 799 return true; |
736 } | 800 } |
737 } while ((loop = loop->fNext) != first); | 801 } while ((loop = loop->fNext) != first); |
738 return false; | 802 return false; |
739 } | 803 } |
740 | 804 |
741 int SkOpAngle::loopCount() const { | 805 int SkOpAngle::loopCount() const { |
742 int count = 0; | 806 int count = 0; |
743 const SkOpAngle* first = this; | 807 const SkOpAngle* first = this; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
775 } | 839 } |
776 working = working->fNext; | 840 working = working->fNext; |
777 } while (working != angle); | 841 } while (working != angle); |
778 do { | 842 do { |
779 SkOpAngle* next = working->fNext; | 843 SkOpAngle* next = working->fNext; |
780 working->fNext = NULL; | 844 working->fNext = NULL; |
781 insert(working); | 845 insert(working); |
782 working = next; | 846 working = next; |
783 } while (working != angle); | 847 } while (working != angle); |
784 // it's likely that a pair of the angles are unorderable | 848 // it's likely that a pair of the angles are unorderable |
785 #if 0 && DEBUG_ANGLE | |
786 SkOpAngle* last = angle; | |
787 working = angle->fNext; | |
788 do { | |
789 SkASSERT(last->fNext == working); | |
790 last->fNext = working->fNext; | |
791 SkASSERT(working->after(last)); | |
792 last->fNext = working; | |
793 last = working; | |
794 working = working->fNext; | |
795 } while (last != angle); | |
796 #endif | |
797 debugValidateNext(); | 849 debugValidateNext(); |
798 return true; | 850 return true; |
799 } | 851 } |
800 | 852 |
801 double SkOpAngle::midT() const { | 853 double SkOpAngle::midT() const { |
802 return (fSegment->t(fStart) + fSegment->t(fEnd)) / 2; | 854 return (fStart->t() + fEnd->t()) / 2; |
803 } | 855 } |
804 | 856 |
805 bool SkOpAngle::oppositePlanes(const SkOpAngle& rh) const { | 857 bool SkOpAngle::midToSide(const SkOpAngle* rh, bool* inside) const { |
806 int startSpan = abs(rh.fSectorStart - fSectorStart); | 858 const SkOpSegment* segment = this->segment(); |
| 859 SkPath::Verb verb = segment->verb(); |
| 860 int pts = SkPathOpsVerbToPoints(verb); |
| 861 const SkPoint& startPt = this->fStart->pt(); |
| 862 const SkPoint& endPt = this->fEnd->pt(); |
| 863 SkDPoint dStartPt; |
| 864 dStartPt.set(startPt); |
| 865 SkDLine rayMid; |
| 866 rayMid[0].fX = (startPt.fX + endPt.fX) / 2; |
| 867 rayMid[0].fY = (startPt.fY + endPt.fY) / 2; |
| 868 rayMid[1].fX = rayMid[0].fX + (endPt.fY - startPt.fY); |
| 869 rayMid[1].fY = rayMid[0].fY - (endPt.fX - startPt.fX); |
| 870 SkIntersections iMid; |
| 871 (*CurveIntersectRay[pts])(segment->pts(), rayMid, &iMid); |
| 872 int iOutside = iMid.mostOutside(this->fStart->t(), this->fEnd->t(), dStartPt
); |
| 873 if (iOutside < 0) { |
| 874 return false; |
| 875 } |
| 876 const SkOpSegment* oppSegment = rh->segment(); |
| 877 SkPath::Verb oppVerb = oppSegment->verb(); |
| 878 int oppPts = SkPathOpsVerbToPoints(oppVerb); |
| 879 SkIntersections oppMid; |
| 880 (*CurveIntersectRay[oppPts])(oppSegment->pts(), rayMid, &oppMid); |
| 881 int oppOutside = oppMid.mostOutside(rh->fStart->t(), rh->fEnd->t(), dStartPt
); |
| 882 if (oppOutside < 0) { |
| 883 return false; |
| 884 } |
| 885 SkDVector iSide = iMid.pt(iOutside) - dStartPt; |
| 886 SkDVector oppSide = oppMid.pt(oppOutside) - dStartPt; |
| 887 double dir = iSide.crossCheck(oppSide); |
| 888 if (!dir) { |
| 889 return false; |
| 890 } |
| 891 *inside = dir < 0; |
| 892 return true; |
| 893 } |
| 894 |
| 895 bool SkOpAngle::oppositePlanes(const SkOpAngle* rh) const { |
| 896 int startSpan = abs(rh->fSectorStart - fSectorStart); |
807 return startSpan >= 8; | 897 return startSpan >= 8; |
808 } | 898 } |
809 | 899 |
810 bool SkOpAngle::orderable(const SkOpAngle& rh) const { | 900 bool SkOpAngle::orderable(SkOpAngle* rh) { |
811 int result; | 901 int result; |
812 if (!fIsCurve) { | 902 if (!fIsCurve) { |
813 if (!rh.fIsCurve) { | 903 if (!rh->fIsCurve) { |
814 double leftX = fTangentHalf.dx(); | 904 double leftX = fTangentHalf.dx(); |
815 double leftY = fTangentHalf.dy(); | 905 double leftY = fTangentHalf.dy(); |
816 double rightX = rh.fTangentHalf.dx(); | 906 double rightX = rh->fTangentHalf.dx(); |
817 double rightY = rh.fTangentHalf.dy(); | 907 double rightY = rh->fTangentHalf.dy(); |
818 double x_ry = leftX * rightY; | 908 double x_ry = leftX * rightY; |
819 double rx_y = rightX * leftY; | 909 double rx_y = rightX * leftY; |
820 if (x_ry == rx_y) { | 910 if (x_ry == rx_y) { |
821 if (leftX * rightX < 0 || leftY * rightY < 0) { | 911 if (leftX * rightX < 0 || leftY * rightY < 0) { |
822 return true; // exactly 180 degrees apart | 912 return true; // exactly 180 degrees apart |
823 } | 913 } |
824 goto unorderable; | 914 goto unorderable; |
825 } | 915 } |
826 SkASSERT(x_ry != rx_y); // indicates an undetected coincidence -- wo
rth finding earlier | 916 SkASSERT(x_ry != rx_y); // indicates an undetected coincidence -- wo
rth finding earlier |
827 return x_ry < rx_y; | 917 return x_ry < rx_y; |
828 } | 918 } |
829 if ((result = allOnOneSide(rh)) >= 0) { | 919 if ((result = allOnOneSide(rh)) >= 0) { |
830 return result; | 920 return result; |
831 } | 921 } |
832 if (fUnorderable || approximately_zero(rh.fSide)) { | 922 if (fUnorderable || approximately_zero(rh->fSide)) { |
833 goto unorderable; | 923 goto unorderable; |
834 } | 924 } |
835 } else if (!rh.fIsCurve) { | 925 } else if (!rh->fIsCurve) { |
836 if ((result = rh.allOnOneSide(*this)) >= 0) { | 926 if ((result = rh->allOnOneSide(this)) >= 0) { |
837 return !result; | 927 return !result; |
838 } | 928 } |
839 if (rh.fUnorderable || approximately_zero(fSide)) { | 929 if (rh->fUnorderable || approximately_zero(fSide)) { |
840 goto unorderable; | 930 goto unorderable; |
841 } | 931 } |
842 } | 932 } |
843 if ((result = convexHullOverlaps(rh)) >= 0) { | 933 if ((result = convexHullOverlaps(rh)) >= 0) { |
844 return result; | 934 return result; |
845 } | 935 } |
846 return endsIntersect(rh); | 936 return endsIntersect(rh); |
847 unorderable: | 937 unorderable: |
848 fUnorderable = true; | 938 fUnorderable = true; |
849 rh.fUnorderable = true; | 939 rh->fUnorderable = true; |
850 return true; | 940 return true; |
851 } | 941 } |
852 | 942 |
853 bool SkOpAngle::overlap(const SkOpAngle& other) const { | |
854 int min = SkTMin(fStart, fEnd); | |
855 const SkOpSpan& span = fSegment->span(min); | |
856 const SkOpSegment* oSeg = other.fSegment; | |
857 int oMin = SkTMin(other.fStart, other.fEnd); | |
858 const SkOpSpan& oSpan = oSeg->span(oMin); | |
859 if (!span.fSmall && !oSpan.fSmall) { | |
860 return false; | |
861 } | |
862 if (fSegment->span(fStart).fPt != oSeg->span(other.fStart).fPt) { | |
863 return false; | |
864 } | |
865 // see if small span is contained by opposite span | |
866 return span.fSmall ? oSeg->containsPt(fSegment->span(fEnd).fPt, other.fEnd,
other.fStart) | |
867 : fSegment->containsPt(oSeg->span(other.fEnd).fPt, fEnd, fStart); | |
868 } | |
869 | |
870 // OPTIMIZE: if this shows up in a profile, add a previous pointer | 943 // OPTIMIZE: if this shows up in a profile, add a previous pointer |
871 // as is, this should be rarely called | 944 // as is, this should be rarely called |
872 SkOpAngle* SkOpAngle::previous() const { | 945 SkOpAngle* SkOpAngle::previous() const { |
873 SkOpAngle* last = fNext; | 946 SkOpAngle* last = fNext; |
874 do { | 947 do { |
875 SkOpAngle* next = last->fNext; | 948 SkOpAngle* next = last->fNext; |
876 if (next == this) { | 949 if (next == this) { |
877 return last; | 950 return last; |
878 } | 951 } |
879 last = next; | 952 last = next; |
880 } while (true); | 953 } while (true); |
881 } | 954 } |
882 | 955 |
883 void SkOpAngle::set(const SkOpSegment* segment, int start, int end) { | 956 SkOpSegment* SkOpAngle::segment() const { |
884 fSegment = segment; | 957 return fStart->segment(); |
| 958 } |
| 959 |
| 960 void SkOpAngle::set(SkOpSpanBase* start, SkOpSpanBase* end) { |
885 fStart = start; | 961 fStart = start; |
886 fComputedEnd = fEnd = end; | 962 fComputedEnd = fEnd = end; |
| 963 SkASSERT(start != end); |
887 fNext = NULL; | 964 fNext = NULL; |
888 fComputeSector = fComputedSector = false; | 965 fComputeSector = fComputedSector = fCheckCoincidence = false; |
889 fStop = false; | 966 fStop = false; |
890 setSpans(); | 967 setSpans(); |
891 setSector(); | 968 setSector(); |
| 969 PATH_OPS_DEBUG_CODE(fID = start->globalState()->nextAngleID()); |
892 } | 970 } |
893 | 971 |
894 void SkOpAngle::setCurveHullSweep() { | 972 void SkOpAngle::setCurveHullSweep() { |
895 fUnorderedSweep = false; | 973 fUnorderedSweep = false; |
896 fSweep[0] = fCurvePart[1] - fCurvePart[0]; | 974 fSweep[0] = fCurvePart[1] - fCurvePart[0]; |
897 if (SkPath::kLine_Verb == fSegment->verb()) { | 975 const SkOpSegment* segment = fStart->segment(); |
| 976 if (SkPath::kLine_Verb == segment->verb()) { |
898 fSweep[1] = fSweep[0]; | 977 fSweep[1] = fSweep[0]; |
899 return; | 978 return; |
900 } | 979 } |
901 fSweep[1] = fCurvePart[2] - fCurvePart[0]; | 980 fSweep[1] = fCurvePart[2] - fCurvePart[0]; |
902 if (SkPath::kCubic_Verb != fSegment->verb()) { | 981 if (SkPath::kCubic_Verb != segment->verb()) { |
903 if (!fSweep[0].fX && !fSweep[0].fY) { | 982 if (!fSweep[0].fX && !fSweep[0].fY) { |
904 fSweep[0] = fSweep[1]; | 983 fSweep[0] = fSweep[1]; |
905 } | 984 } |
906 return; | 985 return; |
907 } | 986 } |
908 SkDVector thirdSweep = fCurvePart[3] - fCurvePart[0]; | 987 SkDVector thirdSweep = fCurvePart[3] - fCurvePart[0]; |
909 if (fSweep[0].fX == 0 && fSweep[0].fY == 0) { | 988 if (fSweep[0].fX == 0 && fSweep[0].fY == 0) { |
910 fSweep[0] = fSweep[1]; | 989 fSweep[0] = fSweep[1]; |
911 fSweep[1] = thirdSweep; | 990 fSweep[1] = thirdSweep; |
912 if (fSweep[0].fX == 0 && fSweep[0].fY == 0) { | 991 if (fSweep[0].fX == 0 && fSweep[0].fY == 0) { |
(...skipping 13 matching lines...) Expand all Loading... |
926 // probably such wide sweeps should be artificially subdivided earlier so th
at never happens | 1005 // probably such wide sweeps should be artificially subdivided earlier so th
at never happens |
927 SkASSERT(s1x3 * s2x1 < 0 || s1x3 * s3x2 < 0); | 1006 SkASSERT(s1x3 * s2x1 < 0 || s1x3 * s3x2 < 0); |
928 if (s3x2 * s2x1 < 0) { | 1007 if (s3x2 * s2x1 < 0) { |
929 SkASSERT(s2x1 * s1x3 > 0); | 1008 SkASSERT(s2x1 * s1x3 > 0); |
930 fSweep[0] = fSweep[1]; | 1009 fSweep[0] = fSweep[1]; |
931 fUnorderedSweep = true; | 1010 fUnorderedSweep = true; |
932 } | 1011 } |
933 fSweep[1] = thirdSweep; | 1012 fSweep[1] = thirdSweep; |
934 } | 1013 } |
935 | 1014 |
936 void SkOpAngle::setSector() { | |
937 SkPath::Verb verb = fSegment->verb(); | |
938 if (SkPath::kLine_Verb != verb && small()) { | |
939 goto deferTilLater; | |
940 } | |
941 fSectorStart = findSector(verb, fSweep[0].fX, fSweep[0].fY); | |
942 if (fSectorStart < 0) { | |
943 goto deferTilLater; | |
944 } | |
945 if (!fIsCurve) { // if it's a line or line-like, note that both sectors are
the same | |
946 SkASSERT(fSectorStart >= 0); | |
947 fSectorEnd = fSectorStart; | |
948 fSectorMask = 1 << fSectorStart; | |
949 return; | |
950 } | |
951 SkASSERT(SkPath::kLine_Verb != verb); | |
952 fSectorEnd = findSector(verb, fSweep[1].fX, fSweep[1].fY); | |
953 if (fSectorEnd < 0) { | |
954 deferTilLater: | |
955 fSectorStart = fSectorEnd = -1; | |
956 fSectorMask = 0; | |
957 fComputeSector = true; // can't determine sector until segment length c
an be found | |
958 return; | |
959 } | |
960 if (fSectorEnd == fSectorStart) { | |
961 SkASSERT((fSectorStart & 3) != 3); // if the sector has no span, it can
't be an exact angle | |
962 fSectorMask = 1 << fSectorStart; | |
963 return; | |
964 } | |
965 bool crossesZero = checkCrossesZero(); | |
966 int start = SkTMin(fSectorStart, fSectorEnd); | |
967 bool curveBendsCCW = (fSectorStart == start) ^ crossesZero; | |
968 // bump the start and end of the sector span if they are on exact compass po
ints | |
969 if ((fSectorStart & 3) == 3) { | |
970 fSectorStart = (fSectorStart + (curveBendsCCW ? 1 : 31)) & 0x1f; | |
971 } | |
972 if ((fSectorEnd & 3) == 3) { | |
973 fSectorEnd = (fSectorEnd + (curveBendsCCW ? 31 : 1)) & 0x1f; | |
974 } | |
975 crossesZero = checkCrossesZero(); | |
976 start = SkTMin(fSectorStart, fSectorEnd); | |
977 int end = SkTMax(fSectorStart, fSectorEnd); | |
978 if (!crossesZero) { | |
979 fSectorMask = (unsigned) -1 >> (31 - end + start) << start; | |
980 } else { | |
981 fSectorMask = (unsigned) -1 >> (31 - start) | (-1 << end); | |
982 } | |
983 } | |
984 | |
985 void SkOpAngle::setSpans() { | 1015 void SkOpAngle::setSpans() { |
986 fUnorderable = fSegment->isTiny(this); | 1016 fUnorderable = false; |
987 fLastMarked = NULL; | 1017 fLastMarked = NULL; |
988 const SkPoint* pts = fSegment->pts(); | 1018 const SkOpSegment* segment = fStart->segment(); |
| 1019 const SkPoint* pts = segment->pts(); |
989 SkDEBUGCODE(fCurvePart[2].fX = fCurvePart[2].fY = fCurvePart[3].fX = fCurveP
art[3].fY | 1020 SkDEBUGCODE(fCurvePart[2].fX = fCurvePart[2].fY = fCurvePart[3].fX = fCurveP
art[3].fY |
990 = SK_ScalarNaN); | 1021 = SK_ScalarNaN); |
991 fSegment->subDivide(fStart, fEnd, &fCurvePart); | 1022 segment->subDivide(fStart, fEnd, &fCurvePart); |
992 setCurveHullSweep(); | 1023 setCurveHullSweep(); |
993 const SkPath::Verb verb = fSegment->verb(); | 1024 const SkPath::Verb verb = segment->verb(); |
994 if (verb != SkPath::kLine_Verb | 1025 if (verb != SkPath::kLine_Verb |
995 && !(fIsCurve = fSweep[0].crossCheck(fSweep[1]) != 0)) { | 1026 && !(fIsCurve = fSweep[0].crossCheck(fSweep[1]) != 0)) { |
996 SkDLine lineHalf; | 1027 SkDLine lineHalf; |
997 lineHalf[0].set(fCurvePart[0].asSkPoint()); | 1028 lineHalf[0].set(fCurvePart[0].asSkPoint()); |
998 lineHalf[1].set(fCurvePart[SkPathOpsVerbToPoints(verb)].asSkPoint()); | 1029 lineHalf[1].set(fCurvePart[SkPathOpsVerbToPoints(verb)].asSkPoint()); |
999 fTangentHalf.lineEndPoints(lineHalf); | 1030 fTangentHalf.lineEndPoints(lineHalf); |
1000 fSide = 0; | 1031 fSide = 0; |
1001 } | 1032 } |
1002 switch (verb) { | 1033 switch (verb) { |
1003 case SkPath::kLine_Verb: { | 1034 case SkPath::kLine_Verb: { |
1004 SkASSERT(fStart != fEnd); | 1035 SkASSERT(fStart != fEnd); |
1005 const SkPoint& cP1 = pts[fStart < fEnd]; | 1036 const SkPoint& cP1 = pts[fStart->t() < fEnd->t()]; |
1006 SkDLine lineHalf; | 1037 SkDLine lineHalf; |
1007 lineHalf[0].set(fSegment->span(fStart).fPt); | 1038 lineHalf[0].set(fStart->pt()); |
1008 lineHalf[1].set(cP1); | 1039 lineHalf[1].set(cP1); |
1009 fTangentHalf.lineEndPoints(lineHalf); | 1040 fTangentHalf.lineEndPoints(lineHalf); |
1010 fSide = 0; | 1041 fSide = 0; |
1011 fIsCurve = false; | 1042 fIsCurve = false; |
1012 } return; | 1043 } return; |
1013 case SkPath::kQuad_Verb: { | 1044 case SkPath::kQuad_Verb: { |
1014 SkLineParameters tangentPart; | 1045 SkLineParameters tangentPart; |
1015 SkDQuad& quad2 = *SkTCast<SkDQuad*>(&fCurvePart); | 1046 SkDQuad& quad2 = *SkTCast<SkDQuad*>(&fCurvePart); |
1016 (void) tangentPart.quadEndPoints(quad2); | 1047 (void) tangentPart.quadEndPoints(quad2); |
1017 fSide = -tangentPart.pointDistance(fCurvePart[2]); // not normalized --
compare sign only | 1048 fSide = -tangentPart.pointDistance(fCurvePart[2]); // not normalized --
compare sign only |
1018 } break; | 1049 } break; |
1019 case SkPath::kCubic_Verb: { | 1050 case SkPath::kCubic_Verb: { |
1020 SkLineParameters tangentPart; | 1051 SkLineParameters tangentPart; |
1021 (void) tangentPart.cubicPart(fCurvePart); | 1052 (void) tangentPart.cubicPart(fCurvePart); |
1022 fSide = -tangentPart.pointDistance(fCurvePart[3]); | 1053 fSide = -tangentPart.pointDistance(fCurvePart[3]); |
1023 double testTs[4]; | 1054 double testTs[4]; |
1024 // OPTIMIZATION: keep inflections precomputed with cubic segment? | 1055 // OPTIMIZATION: keep inflections precomputed with cubic segment? |
1025 int testCount = SkDCubic::FindInflections(pts, testTs); | 1056 int testCount = SkDCubic::FindInflections(pts, testTs); |
1026 double startT = fSegment->t(fStart); | 1057 double startT = fStart->t(); |
1027 double endT = fSegment->t(fEnd); | 1058 double endT = fEnd->t(); |
1028 double limitT = endT; | 1059 double limitT = endT; |
1029 int index; | 1060 int index; |
1030 for (index = 0; index < testCount; ++index) { | 1061 for (index = 0; index < testCount; ++index) { |
1031 if (!::between(startT, testTs[index], limitT)) { | 1062 if (!::between(startT, testTs[index], limitT)) { |
1032 testTs[index] = -1; | 1063 testTs[index] = -1; |
1033 } | 1064 } |
1034 } | 1065 } |
1035 testTs[testCount++] = startT; | 1066 testTs[testCount++] = startT; |
1036 testTs[testCount++] = endT; | 1067 testTs[testCount++] = endT; |
1037 SkTQSort<double>(testTs, &testTs[testCount - 1]); | 1068 SkTQSort<double>(testTs, &testTs[testCount - 1]); |
(...skipping 19 matching lines...) Expand all Loading... |
1057 bestSide = testSide; | 1088 bestSide = testSide; |
1058 } | 1089 } |
1059 } | 1090 } |
1060 fSide = -bestSide; // compare sign only | 1091 fSide = -bestSide; // compare sign only |
1061 } break; | 1092 } break; |
1062 default: | 1093 default: |
1063 SkASSERT(0); | 1094 SkASSERT(0); |
1064 } | 1095 } |
1065 } | 1096 } |
1066 | 1097 |
1067 bool SkOpAngle::small() const { | 1098 void SkOpAngle::setSector() { |
1068 int min = SkMin32(fStart, fEnd); | 1099 const SkOpSegment* segment = fStart->segment(); |
1069 int max = SkMax32(fStart, fEnd); | 1100 SkPath::Verb verb = segment->verb(); |
1070 for (int index = min; index < max; ++index) { | 1101 fSectorStart = this->findSector(verb, fSweep[0].fX, fSweep[0].fY); |
1071 const SkOpSpan& mSpan = fSegment->span(index); | 1102 if (fSectorStart < 0) { |
1072 if (!mSpan.fSmall) { | 1103 goto deferTilLater; |
1073 return false; | |
1074 } | |
1075 } | 1104 } |
1076 return true; | 1105 if (!fIsCurve) { // if it's a line or line-like, note that both sectors are
the same |
| 1106 SkASSERT(fSectorStart >= 0); |
| 1107 fSectorEnd = fSectorStart; |
| 1108 fSectorMask = 1 << fSectorStart; |
| 1109 return; |
| 1110 } |
| 1111 SkASSERT(SkPath::kLine_Verb != verb); |
| 1112 fSectorEnd = this->findSector(verb, fSweep[1].fX, fSweep[1].fY); |
| 1113 if (fSectorEnd < 0) { |
| 1114 deferTilLater: |
| 1115 fSectorStart = fSectorEnd = -1; |
| 1116 fSectorMask = 0; |
| 1117 fComputeSector = true; // can't determine sector until segment length c
an be found |
| 1118 return; |
| 1119 } |
| 1120 if (fSectorEnd == fSectorStart |
| 1121 && (fSectorStart & 3) != 3) { // if the sector has no span, it can't
be an exact angle |
| 1122 fSectorMask = 1 << fSectorStart; |
| 1123 return; |
| 1124 } |
| 1125 bool crossesZero = this->checkCrossesZero(); |
| 1126 int start = SkTMin(fSectorStart, fSectorEnd); |
| 1127 bool curveBendsCCW = (fSectorStart == start) ^ crossesZero; |
| 1128 // bump the start and end of the sector span if they are on exact compass po
ints |
| 1129 if ((fSectorStart & 3) == 3) { |
| 1130 fSectorStart = (fSectorStart + (curveBendsCCW ? 1 : 31)) & 0x1f; |
| 1131 } |
| 1132 if ((fSectorEnd & 3) == 3) { |
| 1133 fSectorEnd = (fSectorEnd + (curveBendsCCW ? 31 : 1)) & 0x1f; |
| 1134 } |
| 1135 crossesZero = this->checkCrossesZero(); |
| 1136 start = SkTMin(fSectorStart, fSectorEnd); |
| 1137 int end = SkTMax(fSectorStart, fSectorEnd); |
| 1138 if (!crossesZero) { |
| 1139 fSectorMask = (unsigned) -1 >> (31 - end + start) << start; |
| 1140 } else { |
| 1141 fSectorMask = (unsigned) -1 >> (31 - start) | (-1 << end); |
| 1142 } |
1077 } | 1143 } |
1078 | 1144 |
1079 bool SkOpAngle::tangentsDiverge(const SkOpAngle& rh, double s0xt0) const { | 1145 int SkOpAngle::sign() const { |
| 1146 SkASSERT(fStart->t() != fEnd->t()); |
| 1147 return fStart->t() < fEnd->t() ? -1 : 1; |
| 1148 } |
| 1149 |
| 1150 SkOpSpan* SkOpAngle::starter() { |
| 1151 return fStart->starter(fEnd); |
| 1152 } |
| 1153 |
| 1154 bool SkOpAngle::tangentsDiverge(const SkOpAngle* rh, double s0xt0) const { |
1080 if (s0xt0 == 0) { | 1155 if (s0xt0 == 0) { |
1081 return false; | 1156 return false; |
1082 } | 1157 } |
1083 // if the ctrl tangents are not nearly parallel, use them | 1158 // if the ctrl tangents are not nearly parallel, use them |
1084 // solve for opposite direction displacement scale factor == m | 1159 // solve for opposite direction displacement scale factor == m |
1085 // initial dir = v1.cross(v2) == v2.x * v1.y - v2.y * v1.x | 1160 // initial dir = v1.cross(v2) == v2.x * v1.y - v2.y * v1.x |
1086 // displacement of q1[1] : dq1 = { -m * v1.y, m * v1.x } + q1[1] | 1161 // displacement of q1[1] : dq1 = { -m * v1.y, m * v1.x } + q1[1] |
1087 // straight angle when : v2.x * (dq1.y - q1[0].y) == v2.y * (dq1.x - q1[0].x
) | 1162 // straight angle when : v2.x * (dq1.y - q1[0].y) == v2.y * (dq1.x - q1[0].x
) |
1088 // v2.x * (m * v1.x + v1.y) == v2.y * (-m * v1.y + v1.
x) | 1163 // v2.x * (m * v1.x + v1.y) == v2.y * (-m * v1.y + v1.
x) |
1089 // - m * (v2.x * v1.x + v2.y * v1.y) == v2.x * v1.y - v2.y * v1.x | 1164 // - m * (v2.x * v1.x + v2.y * v1.y) == v2.x * v1.y - v2.y * v1.x |
1090 // m = (v2.y * v1.x - v2.x * v1.y) / (v2.x * v1.x + v2.y * v1.y) | 1165 // m = (v2.y * v1.x - v2.x * v1.y) / (v2.x * v1.x + v2.y * v1.y) |
1091 // m = v1.cross(v2) / v1.dot(v2) | 1166 // m = v1.cross(v2) / v1.dot(v2) |
1092 const SkDVector* sweep = fSweep; | 1167 const SkDVector* sweep = fSweep; |
1093 const SkDVector* tweep = rh.fSweep; | 1168 const SkDVector* tweep = rh->fSweep; |
1094 double s0dt0 = sweep[0].dot(tweep[0]); | 1169 double s0dt0 = sweep[0].dot(tweep[0]); |
1095 if (!s0dt0) { | 1170 if (!s0dt0) { |
1096 return true; | 1171 return true; |
1097 } | 1172 } |
1098 SkASSERT(s0dt0 != 0); | 1173 SkASSERT(s0dt0 != 0); |
1099 double m = s0xt0 / s0dt0; | 1174 double m = s0xt0 / s0dt0; |
1100 double sDist = sweep[0].length() * m; | 1175 double sDist = sweep[0].length() * m; |
1101 double tDist = tweep[0].length() * m; | 1176 double tDist = tweep[0].length() * m; |
1102 bool useS = fabs(sDist) < fabs(tDist); | 1177 bool useS = fabs(sDist) < fabs(tDist); |
1103 double mFactor = fabs(useS ? distEndRatio(sDist) : rh.distEndRatio(tDist)); | 1178 double mFactor = fabs(useS ? this->distEndRatio(sDist) : rh->distEndRatio(tD
ist)); |
1104 return mFactor < 5000; // empirically found limit | 1179 return mFactor < 5000; // empirically found limit |
1105 } | 1180 } |
1106 | |
1107 SkOpAngleSet::SkOpAngleSet() | |
1108 : fAngles(NULL) | |
1109 #if DEBUG_ANGLE | |
1110 , fCount(0) | |
1111 #endif | |
1112 { | |
1113 } | |
1114 | |
1115 SkOpAngleSet::~SkOpAngleSet() { | |
1116 SkDELETE(fAngles); | |
1117 } | |
1118 | |
1119 SkOpAngle& SkOpAngleSet::push_back() { | |
1120 if (!fAngles) { | |
1121 fAngles = SkNEW_ARGS(SkChunkAlloc, (2)); | |
1122 } | |
1123 void* ptr = fAngles->allocThrow(sizeof(SkOpAngle)); | |
1124 SkOpAngle* angle = (SkOpAngle*) ptr; | |
1125 #if DEBUG_ANGLE | |
1126 angle->setID(++fCount); | |
1127 #endif | |
1128 return *angle; | |
1129 } | |
1130 | |
1131 void SkOpAngleSet::reset() { | |
1132 if (fAngles) { | |
1133 fAngles->reset(); | |
1134 } | |
1135 } | |
OLD | NEW |