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" | 7 #include "SkIntersections.h" |
8 #include "SkOpAngle.h" | 8 #include "SkOpAngle.h" |
| 9 #include "SkOpSegment.h" |
9 #include "SkPathOpsCurve.h" | 10 #include "SkPathOpsCurve.h" |
10 #include "SkTSort.h" | 11 #include "SkTSort.h" |
11 | 12 |
12 #if DEBUG_SORT || DEBUG_SORT_SINGLE | |
13 #include "SkOpSegment.h" | |
14 #endif | |
15 | 13 |
16 // FIXME: this is bogus for quads and cubics | 14 // FIXME: this is bogus for quads and cubics |
17 // if the quads and cubics' line from end pt to ctrl pt are coincident, | 15 // if the quads and cubics' line from end pt to ctrl pt are coincident, |
18 // there's no obvious way to determine the curve ordering from the | 16 // there's no obvious way to determine the curve ordering from the |
19 // derivatives alone. In particular, if one quadratic's coincident tangent | 17 // derivatives alone. In particular, if one quadratic's coincident tangent |
20 // is longer than the other curve, the final control point can place the | 18 // is longer than the other curve, the final control point can place the |
21 // longer curve on either side of the shorter one. | 19 // longer curve on either side of the shorter one. |
22 // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf | 20 // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf |
23 // may provide some help, but nothing has been figured out yet. | 21 // may provide some help, but nothing has been figured out yet. |
24 | 22 |
25 /*( | 23 /*( |
26 for quads and cubics, set up a parameterized line (e.g. LineParameters ) | 24 for quads and cubics, set up a parameterized line (e.g. LineParameters ) |
27 for points [0] to [1]. See if point [2] is on that line, or on one side | 25 for points [0] to [1]. See if point [2] is on that line, or on one side |
28 or the other. If it both quads' end points are on the same side, choose | 26 or the other. If it both quads' end points are on the same side, choose |
29 the shorter tangent. If the tangents are equal, choose the better second | 27 the shorter tangent. If the tangents are equal, choose the better second |
30 tangent angle | 28 tangent angle |
31 | 29 |
32 maybe I could set up LineParameters lazily | 30 maybe I could set up LineParameters lazily |
33 */ | 31 */ |
34 static int simple_compare(double x, double y, double rx, double ry) { | 32 static int simple_compare(double x, double y, double rx, double ry, double error
) { |
| 33 SkASSERT(error); |
35 if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ? | 34 if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ? |
36 return y < 0; | 35 return y < 0; |
37 } | 36 } |
38 if (y == 0 && ry == 0 && x * rx < 0) { | 37 if (y == 0 && ry == 0 && x * rx < 0) { |
39 return x < rx; | 38 return x < rx; |
40 } | 39 } |
41 double x_ry = x * ry; | 40 double x_ry = x * ry; |
42 double rx_y = rx * y; | 41 double rx_y = rx * y; |
43 double cmp = x_ry - rx_y; | 42 double cmp = (x_ry - rx_y) * error; |
44 if (!approximately_zero(cmp)) { | 43 if (!approximately_zero(cmp)) { |
45 return cmp < 0; | 44 return cmp < 0; |
46 } | 45 } |
47 if (approximately_zero(x_ry) && approximately_zero(rx_y) | 46 if (approximately_zero(x_ry) && approximately_zero(rx_y) |
48 && !approximately_zero_squared(cmp)) { | 47 && !approximately_zero_squared(cmp)) { |
49 return cmp < 0; | 48 return cmp < 0; |
50 } | 49 } |
51 return -1; | 50 return -1; |
52 } | 51 } |
53 | 52 |
| 53 static double gError[] = { |
| 54 0, 1, 1.0/2, 1.0/3 |
| 55 }; |
| 56 |
54 bool SkOpAngle::operator<(const SkOpAngle& rh) const { | 57 bool SkOpAngle::operator<(const SkOpAngle& rh) const { |
55 double x = dx(); | 58 double x = dx(); |
56 double y = dy(); | 59 double y = dy(); |
57 double rx = rh.dx(); | 60 double rx = rh.dx(); |
58 double ry = rh.dy(); | 61 double ry = rh.dy(); |
59 int simple = simple_compare(x, y, rx, ry); | 62 SkPath::Verb verb = fSegment->verb(); |
| 63 SkPath::Verb rVerb = rh.fSegment->verb(); |
| 64 int simple = simple_compare(x, y, rx, ry, gError[verb] * gError[rVerb]); |
60 if (simple >= 0) { | 65 if (simple >= 0) { |
61 return simple; | 66 return simple; |
62 } | 67 } |
63 // at this point, the initial tangent line is coincident | 68 // at this point, the initial tangent line is coincident |
64 // see if edges curl away from each other | 69 // see if edges curl away from each other |
65 if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide) | 70 if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide) |
66 || !approximately_zero(rh.fSide))) { | 71 || !approximately_zero(rh.fSide))) { |
67 // FIXME: running demo will trigger this assertion | 72 // FIXME: running demo will trigger this assertion |
68 // (don't know if commenting out will trigger further assertion or not) | 73 // (don't know if commenting out will trigger further assertion or not) |
69 // commenting it out allows demo to run in release, though | 74 // commenting it out allows demo to run in release, though |
70 return fSide < rh.fSide; | 75 return fSide < rh.fSide; |
71 } | 76 } |
72 // see if either curve can be lengthened and try the tangent compare again | 77 // see if either curve can be lengthened and try the tangent compare again |
73 if (/* cmp && */ (*fSpans)[fEnd].fOther != rh.fSegment // tangents not abso
lutely identical | 78 if (fSegment->other(fEnd) != rh.fSegment // tangents not absolutely identic
al |
74 && (*rh.fSpans)[rh.fEnd].fOther != fSegment) { // and not intersect
ing | 79 && rh.fSegment->other(rh.fEnd) != fSegment) { // and not intersecti
ng |
75 SkOpAngle longer = *this; | 80 SkOpAngle longer = *this; |
76 SkOpAngle rhLonger = rh; | 81 SkOpAngle rhLonger = rh; |
77 if (longer.lengthen() | rhLonger.lengthen()) { | 82 if (longer.lengthen() | rhLonger.lengthen()) { |
78 return longer < rhLonger; | 83 return longer < rhLonger; |
79 } | 84 } |
80 } | 85 } |
81 if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_z
ero(y)) | 86 if ((verb == SkPath::kLine_Verb && approximately_zero(x) && approximately_ze
ro(y)) |
82 || (rh.fVerb == SkPath::kLine_Verb | 87 || (rVerb == SkPath::kLine_Verb |
83 && approximately_zero(rx) && approximately_zero(ry))) { | 88 && approximately_zero(rx) && approximately_zero(ry))) { |
84 // See general unsortable comment below. This case can happen when | 89 // See general unsortable comment below. This case can happen when |
85 // one line has a non-zero change in t but no change in x and y. | 90 // one line has a non-zero change in t but no change in x and y. |
86 fUnsortable = true; | 91 fUnsortable = true; |
87 rh.fUnsortable = true; | 92 rh.fUnsortable = true; |
88 return this < &rh; // even with no solution, return a stable sort | 93 return this < &rh; // even with no solution, return a stable sort |
89 } | 94 } |
90 if ((*rh.fSpans)[SkMin32(rh.fStart, rh.fEnd)].fTiny | 95 if (fSegment->isTiny(this) || rh.fSegment->isTiny(&rh)) { |
91 || (*fSpans)[SkMin32(fStart, fEnd)].fTiny) { | |
92 fUnsortable = true; | 96 fUnsortable = true; |
93 rh.fUnsortable = true; | 97 rh.fUnsortable = true; |
94 return this < &rh; // even with no solution, return a stable sort | 98 return this < &rh; // even with no solution, return a stable sort |
95 } | 99 } |
96 SkASSERT(fVerb >= SkPath::kQuad_Verb); | 100 SkASSERT(verb >= SkPath::kQuad_Verb); |
97 SkASSERT(rh.fVerb >= SkPath::kQuad_Verb); | 101 SkASSERT(rVerb >= SkPath::kQuad_Verb); |
98 // FIXME: until I can think of something better, project a ray from the | 102 // FIXME: until I can think of something better, project a ray from the |
99 // end of the shorter tangent to midway between the end points | 103 // end of the shorter tangent to midway between the end points |
100 // through both curves and use the resulting angle to sort | 104 // through both curves and use the resulting angle to sort |
101 // FIXME: some of this setup can be moved to set() if it works, or cached if
it's expensive | 105 // FIXME: some of this setup can be moved to set() if it works, or cached if
it's expensive |
102 double len = fTangent1.normalSquared(); | 106 double len = fTangent1.normalSquared(); |
103 double rlen = rh.fTangent1.normalSquared(); | 107 double rlen = rh.fTangent1.normalSquared(); |
104 SkDLine ray; | 108 SkDLine ray; |
105 SkIntersections i, ri; | 109 SkIntersections i, ri; |
106 int roots, rroots; | 110 int roots, rroots; |
107 bool flip = false; | 111 bool flip = false; |
108 bool useThis; | 112 bool useThis; |
109 bool leftLessThanRight = fSide > 0; | 113 bool leftLessThanRight = fSide > 0; |
110 do { | 114 do { |
111 useThis = (len < rlen) ^ flip; | 115 useThis = (len < rlen) ^ flip; |
112 const SkDCubic& part = useThis ? fCurvePart : rh.fCurvePart; | 116 const SkDCubic& part = useThis ? fCurvePart : rh.fCurvePart; |
113 SkPath::Verb partVerb = useThis ? fVerb : rh.fVerb; | 117 SkPath::Verb partVerb = useThis ? verb : rVerb; |
114 ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(p
art[1]) ? | 118 ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(p
art[1]) ? |
115 part[2] : part[1]; | 119 part[2] : part[1]; |
116 ray[1].fX = (part[0].fX + part[partVerb].fX) / 2; | 120 ray[1].fX = (part[0].fX + part[partVerb].fX) / 2; |
117 ray[1].fY = (part[0].fY + part[partVerb].fY) / 2; | 121 ray[1].fY = (part[0].fY + part[partVerb].fY) / 2; |
118 SkASSERT(ray[0] != ray[1]); | 122 SkASSERT(ray[0] != ray[1]); |
119 roots = (i.*CurveRay[fVerb])(fPts, ray); | 123 roots = (i.*CurveRay[verb])(fSegment->pts(), ray); |
120 rroots = (ri.*CurveRay[rh.fVerb])(rh.fPts, ray); | 124 rroots = (ri.*CurveRay[rVerb])(rh.fSegment->pts(), ray); |
121 } while ((roots == 0 || rroots == 0) && (flip ^= true)); | 125 } while ((roots == 0 || rroots == 0) && (flip ^= true)); |
122 if (roots == 0 || rroots == 0) { | 126 if (roots == 0 || rroots == 0) { |
123 // FIXME: we don't have a solution in this case. The interim solution | 127 // FIXME: we don't have a solution in this case. The interim solution |
124 // is to mark the edges as unsortable, exclude them from this and | 128 // is to mark the edges as unsortable, exclude them from this and |
125 // future computations, and allow the returned path to be fragmented | 129 // future computations, and allow the returned path to be fragmented |
126 fUnsortable = true; | 130 fUnsortable = true; |
127 rh.fUnsortable = true; | 131 rh.fUnsortable = true; |
128 return this < &rh; // even with no solution, return a stable sort | 132 return this < &rh; // even with no solution, return a stable sort |
129 } | 133 } |
130 SkASSERT(fSide != 0 && rh.fSide != 0); | 134 SkASSERT(fSide != 0 && rh.fSide != 0); |
(...skipping 29 matching lines...) Expand all Loading... |
160 best, dist, "><"[fSide < 0], rLoc.fX, rLoc.fY, dxy.fX, dxy.fY); | 164 best, dist, "><"[fSide < 0], rLoc.fX, rLoc.fY, dxy.fX, dxy.fY); |
161 #endif | 165 #endif |
162 if (best > dist) { | 166 if (best > dist) { |
163 flip = true; | 167 flip = true; |
164 break; | 168 break; |
165 } | 169 } |
166 } | 170 } |
167 #if 0 | 171 #if 0 |
168 SkDVector lRay = lLoc - fCurvePart[0]; | 172 SkDVector lRay = lLoc - fCurvePart[0]; |
169 SkDVector rRay = rLoc - fCurvePart[0]; | 173 SkDVector rRay = rLoc - fCurvePart[0]; |
170 int rayDir = simple_compare(lRay.fX, lRay.fY, rRay.fX, rRay.fY); | 174 int rayDir = simple_compare(lRay.fX, lRay.fY, rRay.fX, rRay.fY, gError[verb]
* gError[rVerb]); |
171 SkASSERT(rayDir >= 0); | 175 SkASSERT(rayDir >= 0); |
172 if (rayDir < 0) { | 176 if (rayDir < 0) { |
173 fUnsortable = true; | 177 fUnsortable = true; |
174 rh.fUnsortable = true; | 178 rh.fUnsortable = true; |
175 return this < &rh; // even with no solution, return a stable sort | 179 return this < &rh; // even with no solution, return a stable sort |
176 } | 180 } |
177 #endif | 181 #endif |
178 if (flip) { | 182 if (flip) { |
179 leftLessThanRight = !leftLessThanRight; | 183 leftLessThanRight = !leftLessThanRight; |
180 // rayDir = !rayDir; | 184 // rayDir = !rayDir; |
181 } | 185 } |
182 #if 0 && (DEBUG_SORT || DEBUG_SORT_SINGLE) | 186 #if 0 && (DEBUG_SORT || DEBUG_SORT_SINGLE) |
183 SkDebugf("%d %c %d (fSide %c 0) loc={{%1.9g,%1.9g}, {%1.9g,%1.9g}} flip=%d r
ayDir=%d\n", | 187 SkDebugf("%d %c %d (fSide %c 0) loc={{%1.9g,%1.9g}, {%1.9g,%1.9g}} flip=%d r
ayDir=%d\n", |
184 fSegment->debugID(), "><"[leftLessThanRight], rh.fSegment->debug
ID(), | 188 fSegment->debugID(), "><"[leftLessThanRight], rh.fSegment->debug
ID(), |
185 "<>"[fSide > 0], lLoc.fX, lLoc.fY, rLoc.fX, rLoc.fY, flip, rayDi
r); | 189 "<>"[fSide > 0], lLoc.fX, lLoc.fY, rLoc.fX, rLoc.fY, flip, rayDi
r); |
186 #endif | 190 #endif |
187 // SkASSERT(leftLessThanRight == (bool) rayDir); | 191 // SkASSERT(leftLessThanRight == (bool) rayDir); |
188 return leftLessThanRight; | 192 return leftLessThanRight; |
189 } | 193 } |
190 | 194 |
| 195 bool SkOpAngle::isHorizontal() const { |
| 196 return dy() == 0 && fSegment->verb() == SkPath::kLine_Verb; |
| 197 } |
| 198 |
191 bool SkOpAngle::lengthen() { | 199 bool SkOpAngle::lengthen() { |
192 int newEnd = fEnd; | 200 int newEnd = fEnd; |
193 if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) { | 201 if (fStart < fEnd ? ++newEnd < fSegment->count() : --newEnd >= 0) { |
194 fEnd = newEnd; | 202 fEnd = newEnd; |
195 setSpans(); | 203 setSpans(); |
196 return true; | 204 return true; |
197 } | 205 } |
198 return false; | 206 return false; |
199 } | 207 } |
200 | 208 |
201 bool SkOpAngle::reverseLengthen() { | 209 bool SkOpAngle::reverseLengthen() { |
202 if (fReversed) { | 210 if (fReversed) { |
203 return false; | 211 return false; |
204 } | 212 } |
205 int newEnd = fStart; | 213 int newEnd = fStart; |
206 if (fStart > fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) { | 214 if (fStart > fEnd ? ++newEnd < fSegment->count() : --newEnd >= 0) { |
207 fEnd = newEnd; | 215 fEnd = newEnd; |
208 fReversed = true; | 216 fReversed = true; |
209 setSpans(); | 217 setSpans(); |
210 return true; | 218 return true; |
211 } | 219 } |
212 return false; | 220 return false; |
213 } | 221 } |
214 | 222 |
215 void SkOpAngle::set(const SkPoint* orig, SkPath::Verb verb, const SkOpSegment* s
egment, | 223 void SkOpAngle::set(const SkPoint* orig, SkPath::Verb verb, const SkOpSegment* s
egment, |
216 int start, int end, const SkTDArray<SkOpSpan>& spans) { | 224 int start, int end, const SkTDArray<SkOpSpan>& spans) { |
217 fSegment = segment; | 225 fSegment = segment; |
218 fStart = start; | 226 fStart = start; |
219 fEnd = end; | 227 fEnd = end; |
220 fPts = orig; | 228 if (fSegment->isTiny(this) && (start == 0 || end == fSegment->count() - 1))
{ |
221 fVerb = verb; | 229 fUnsortable = true; |
222 fSpans = &spans; | 230 return; |
| 231 } |
223 fReversed = false; | 232 fReversed = false; |
224 fUnsortable = false; | 233 fUnsortable = false; |
225 setSpans(); | 234 setSpans(); |
226 } | 235 } |
227 | 236 |
228 | 237 |
229 void SkOpAngle::setSpans() { | 238 void SkOpAngle::setSpans() { |
230 double startT = (*fSpans)[fStart].fT; | 239 fSegment->subDivide(fStart, fEnd, &fCurvePart); |
231 double endT = (*fSpans)[fEnd].fT; | 240 switch (fSegment->verb()) { |
232 switch (fVerb) { | |
233 case SkPath::kLine_Verb: { | 241 case SkPath::kLine_Verb: { |
234 SkDLine l = SkDLine::SubDivide(fPts, startT, endT); | |
235 // OPTIMIZATION: for pure line compares, we never need fTangent1.c | 242 // OPTIMIZATION: for pure line compares, we never need fTangent1.c |
236 fTangent1.lineEndPoints(l); | 243 fTangent1.lineEndPoints(*SkTCast<SkDLine*>(&fCurvePart)); |
237 fSide = 0; | 244 fSide = 0; |
238 } break; | 245 } break; |
239 case SkPath::kQuad_Verb: { | 246 case SkPath::kQuad_Verb: { |
240 SkDQuad& quad = *SkTCast<SkDQuad*>(&fCurvePart); | 247 SkDQuad& quad = *SkTCast<SkDQuad*>(&fCurvePart); |
241 quad = SkDQuad::SubDivide(fPts, startT, endT); | |
242 fTangent1.quadEndPoints(quad, 0, 1); | 248 fTangent1.quadEndPoints(quad, 0, 1); |
243 if (dx() == 0 && dy() == 0) { | 249 if (dx() == 0 && dy() == 0) { |
244 fTangent1.quadEndPoints(quad); | 250 fTangent1.quadEndPoints(quad); |
245 } | 251 } |
246 fSide = -fTangent1.pointDistance(fCurvePart[2]); // not normalized -- c
ompare sign only | 252 fSide = -fTangent1.pointDistance(fCurvePart[2]); // not normalized -- c
ompare sign only |
247 } break; | 253 } break; |
248 case SkPath::kCubic_Verb: { | 254 case SkPath::kCubic_Verb: { |
249 // int nextC = 2; | 255 // int nextC = 2; |
250 fCurvePart = SkDCubic::SubDivide(fPts, startT, endT); | |
251 fTangent1.cubicEndPoints(fCurvePart, 0, 1); | 256 fTangent1.cubicEndPoints(fCurvePart, 0, 1); |
252 if (dx() == 0 && dy() == 0) { | 257 if (dx() == 0 && dy() == 0) { |
253 fTangent1.cubicEndPoints(fCurvePart, 0, 2); | 258 fTangent1.cubicEndPoints(fCurvePart, 0, 2); |
254 // nextC = 3; | 259 // nextC = 3; |
255 if (dx() == 0 && dy() == 0) { | 260 if (dx() == 0 && dy() == 0) { |
256 fTangent1.cubicEndPoints(fCurvePart, 0, 3); | 261 fTangent1.cubicEndPoints(fCurvePart, 0, 3); |
257 } | 262 } |
258 } | 263 } |
259 // fSide = -fTangent1.pointDistance(fCurvePart[nextC]); // compare sign on
ly | 264 // fSide = -fTangent1.pointDistance(fCurvePart[nextC]); // compare sign on
ly |
260 // if (nextC == 2 && approximately_zero(fSide)) { | 265 // if (nextC == 2 && approximately_zero(fSide)) { |
261 // fSide = -fTangent1.pointDistance(fCurvePart[3]); | 266 // fSide = -fTangent1.pointDistance(fCurvePart[3]); |
262 // } | 267 // } |
263 double testTs[4]; | 268 double testTs[4]; |
264 // OPTIMIZATION: keep inflections precomputed with cubic segment? | 269 // OPTIMIZATION: keep inflections precomputed with cubic segment? |
265 int testCount = SkDCubic::FindInflections(fPts, testTs); | 270 const SkPoint* pts = fSegment->pts(); |
| 271 int testCount = SkDCubic::FindInflections(pts, testTs); |
| 272 double startT = fSegment->t(fStart); |
| 273 double endT = fSegment->t(fEnd); |
266 double limitT = endT; | 274 double limitT = endT; |
267 int index; | 275 int index; |
268 for (index = 0; index < testCount; ++index) { | 276 for (index = 0; index < testCount; ++index) { |
269 if (!between(startT, testTs[index], limitT)) { | 277 if (!between(startT, testTs[index], limitT)) { |
270 testTs[index] = -1; | 278 testTs[index] = -1; |
271 } | 279 } |
272 } | 280 } |
273 testTs[testCount++] = startT; | 281 testTs[testCount++] = startT; |
274 testTs[testCount++] = endT; | 282 testTs[testCount++] = endT; |
275 SkTQSort<double>(testTs, &testTs[testCount - 1]); | 283 SkTQSort<double>(testTs, &testTs[testCount - 1]); |
276 double bestSide = 0; | 284 double bestSide = 0; |
277 int testCases = (testCount << 1) - 1; | 285 int testCases = (testCount << 1) - 1; |
278 index = 0; | 286 index = 0; |
279 while (testTs[index] < 0) { | 287 while (testTs[index] < 0) { |
280 ++index; | 288 ++index; |
281 } | 289 } |
282 index <<= 1; | 290 index <<= 1; |
283 for (; index < testCases; ++index) { | 291 for (; index < testCases; ++index) { |
284 int testIndex = index >> 1; | 292 int testIndex = index >> 1; |
285 double testT = testTs[testIndex]; | 293 double testT = testTs[testIndex]; |
286 if (index & 1) { | 294 if (index & 1) { |
287 testT = (testT + testTs[testIndex + 1]) / 2; | 295 testT = (testT + testTs[testIndex + 1]) / 2; |
288 } | 296 } |
289 // OPTIMIZE: could avoid call for t == startT, endT | 297 // OPTIMIZE: could avoid call for t == startT, endT |
290 SkDPoint pt = dcubic_xy_at_t(fPts, testT); | 298 SkDPoint pt = dcubic_xy_at_t(pts, testT); |
291 double testSide = fTangent1.pointDistance(pt); | 299 double testSide = fTangent1.pointDistance(pt); |
292 if (fabs(bestSide) < fabs(testSide)) { | 300 if (fabs(bestSide) < fabs(testSide)) { |
293 bestSide = testSide; | 301 bestSide = testSide; |
294 } | 302 } |
295 } | 303 } |
296 fSide = -bestSide; // compare sign only | 304 fSide = -bestSide; // compare sign only |
297 } break; | 305 } break; |
298 default: | 306 default: |
299 SkASSERT(0); | 307 SkASSERT(0); |
300 } | 308 } |
301 fUnsortable = dx() == 0 && dy() == 0; | 309 fUnsortable = dx() == 0 && dy() == 0; |
302 if (fUnsortable) { | 310 if (fUnsortable) { |
303 return; | 311 return; |
304 } | 312 } |
305 SkASSERT(fStart != fEnd); | 313 SkASSERT(fStart != fEnd); |
306 int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 t
ype macro? | 314 int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 t
ype macro? |
307 for (int index = fStart; index != fEnd; index += step) { | 315 for (int index = fStart; index != fEnd; index += step) { |
308 #if 1 | 316 #if 1 |
309 const SkOpSpan& thisSpan = (*fSpans)[index]; | 317 const SkOpSpan& thisSpan = fSegment->span(index); |
310 const SkOpSpan& nextSpan = (*fSpans)[index + step]; | 318 const SkOpSpan& nextSpan = fSegment->span(index + step); |
311 if (thisSpan.fTiny || precisely_equal(thisSpan.fT, nextSpan.fT)) { | 319 if (thisSpan.fTiny || precisely_equal(thisSpan.fT, nextSpan.fT)) { |
312 continue; | 320 continue; |
313 } | 321 } |
314 fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortabl
eEnd; | 322 fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortabl
eEnd; |
315 #if DEBUG_UNSORTABLE | 323 #if DEBUG_UNSORTABLE |
316 if (fUnsortable) { | 324 if (fUnsortable) { |
317 SkPoint iPt = (*CurvePointAtT[fVerb])(fPts, thisSpan.fT); | 325 SkPoint iPt = fSegment->xyAtT(index); |
318 SkPoint ePt = (*CurvePointAtT[fVerb])(fPts, nextSpan.fT); | 326 SkPoint ePt = fSegment->xyAtT(index + step); |
319 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __
FUNCTION__, | 327 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __
FUNCTION__, |
320 index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY); | 328 index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY); |
321 } | 329 } |
322 #endif | 330 #endif |
323 return; | 331 return; |
324 #else | 332 #else |
325 if ((*fSpans)[index].fUnsortableStart) { | 333 if ((*fSpans)[index].fUnsortableStart) { |
326 fUnsortable = true; | 334 fUnsortable = true; |
327 return; | 335 return; |
328 } | 336 } |
329 #endif | 337 #endif |
330 } | 338 } |
331 #if 1 | 339 #if 1 |
332 #if DEBUG_UNSORTABLE | 340 #if DEBUG_UNSORTABLE |
333 SkPoint iPt = (*CurvePointAtT[fVerb])(fPts, startT); | 341 SkPoint iPt = fSegment->xyAtT(fStart); |
334 SkPoint ePt = (*CurvePointAtT[fVerb])(fPts, endT); | 342 SkPoint ePt = fSegment->xyAtT(fEnd); |
335 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", _
_FUNCTION__, | 343 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", _
_FUNCTION__, |
336 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY); | 344 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY); |
337 #endif | 345 #endif |
338 fUnsortable = true; | 346 fUnsortable = true; |
339 #endif | 347 #endif |
340 } | 348 } |
OLD | NEW |