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 | 7 |
8 #include "SkIntersections.h" | 8 #include "SkIntersections.h" |
9 #include "SkPathOpsCubic.h" | 9 #include "SkPathOpsCubic.h" |
10 #include "SkPathOpsLine.h" | 10 #include "SkPathOpsLine.h" |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
107 && tLimits1[1][0] >= t2Start && tLimits1[1][1] <= t2) { | 107 && tLimits1[1][0] >= t2Start && tLimits1[1][1] <= t2) { |
108 SkDebugf("%.*s %s t1=(%1.9g,%1.9g) t2=(%1.9g,%1.9g)", i.depth()*
2, tab, | 108 SkDebugf("%.*s %s t1=(%1.9g,%1.9g) t2=(%1.9g,%1.9g)", i.depth()*
2, tab, |
109 __FUNCTION__, t1Start, t1, t2Start, t2); | 109 __FUNCTION__, t1Start, t1, t2Start, t2); |
110 SkIntersections xlocals; | 110 SkIntersections xlocals; |
111 intersectWithOrder(s1.fQuad, o1, s2.fQuad, o2, xlocals); | 111 intersectWithOrder(s1.fQuad, o1, s2.fQuad, o2, xlocals); |
112 SkDebugf(" xlocals.fUsed=%d\n", xlocals.used()); | 112 SkDebugf(" xlocals.fUsed=%d\n", xlocals.used()); |
113 } | 113 } |
114 #endif | 114 #endif |
115 SkIntersections locals; | 115 SkIntersections locals; |
116 intersectWithOrder(s1.fQuad, o1, s2.fQuad, o2, locals); | 116 intersectWithOrder(s1.fQuad, o1, s2.fQuad, o2, locals); |
117 double coStart[2] = { -1 }; | |
118 SkDPoint coPoint; | |
119 int tCount = locals.used(); | 117 int tCount = locals.used(); |
120 for (int tIdx = 0; tIdx < tCount; ++tIdx) { | 118 for (int tIdx = 0; tIdx < tCount; ++tIdx) { |
121 double to1 = t1Start + (t1 - t1Start) * locals[0][tIdx]; | 119 double to1 = t1Start + (t1 - t1Start) * locals[0][tIdx]; |
122 double to2 = t2Start + (t2 - t2Start) * locals[1][tIdx]; | 120 double to2 = t2Start + (t2 - t2Start) * locals[1][tIdx]; |
123 // if the computed t is not sufficiently precise, iterate | 121 // if the computed t is not sufficiently precise, iterate |
124 SkDPoint p1 = cubic1.xyAtT(to1); | 122 SkDPoint p1 = cubic1.ptAtT(to1); |
125 SkDPoint p2 = cubic2.xyAtT(to2); | 123 SkDPoint p2 = cubic2.ptAtT(to2); |
126 if (p1.approximatelyEqual(p2)) { | 124 if (p1.approximatelyEqual(p2)) { |
127 if (locals.isCoincident(tIdx)) { | 125 SkASSERT(!locals.isCoincident(tIdx)); |
128 if (coStart[0] < 0) { | 126 if (&cubic1 != &cubic2 || !approximately_equal(to1, to2)) { |
129 coStart[0] = to1; | |
130 coStart[1] = to2; | |
131 coPoint = p1; | |
132 } else { | |
133 i.insertCoincidentPair(coStart[0], to1, coStart[1],
to2, coPoint, p1); | |
134 coStart[0] = -1; | |
135 } | |
136 } else if (&cubic1 != &cubic2 || !approximately_equal(to1, t
o2)) { | |
137 if (i.swapped()) { // FIXME: insert should respect swa
p | 127 if (i.swapped()) { // FIXME: insert should respect swa
p |
138 i.insert(to2, to1, p1); | 128 i.insert(to2, to1, p1); |
139 } else { | 129 } else { |
140 i.insert(to1, to2, p1); | 130 i.insert(to1, to2, p1); |
141 } | 131 } |
142 } | 132 } |
143 } else { | 133 } else { |
144 double offset = precisionScale / 16; // FIME: const is arbi
trary: test, refine | 134 double offset = precisionScale / 16; // FIME: const is arbi
trary: test, refine |
145 double c1Bottom = tIdx == 0 ? 0 : | 135 double c1Bottom = tIdx == 0 ? 0 : |
146 (t1Start + (t1 - t1Start) * locals[0][tIdx - 1] + to
1) / 2; | 136 (t1Start + (t1 - t1Start) * locals[0][tIdx - 1] + to
1) / 2; |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 i.used(), i.used() > 0 ? i[0][i.used() - 1] : -1); | 233 i.used(), i.used() > 0 ? i[0][i.used() - 1] : -1); |
244 #endif | 234 #endif |
245 } | 235 } |
246 // intersect(cubic1, c1Min, c1Max, cubic2, c2Min, c2Max, offs
et, i); | 236 // intersect(cubic1, c1Min, c1Max, cubic2, c2Min, c2Max, offs
et, i); |
247 // FIXME: if no intersection is found, either quadratics int
ersected where | 237 // FIXME: if no intersection is found, either quadratics int
ersected where |
248 // cubics did not, or the intersection was missed. In the fo
rmer case, expect | 238 // cubics did not, or the intersection was missed. In the fo
rmer case, expect |
249 // the quadratics to be nearly parallel at the point of inte
rsection, and check | 239 // the quadratics to be nearly parallel at the point of inte
rsection, and check |
250 // for that. | 240 // for that. |
251 } | 241 } |
252 } | 242 } |
253 SkASSERT(coStart[0] == -1); | |
254 t2Start = t2; | 243 t2Start = t2; |
255 } | 244 } |
256 t1Start = t1; | 245 t1Start = t1; |
257 } | 246 } |
258 i.downDepth(); | 247 i.downDepth(); |
259 } | 248 } |
260 | 249 |
261 #define LINE_FRACTION 0.1 | 250 #define LINE_FRACTION 0.1 |
262 | 251 |
263 // intersect the end of the cubic with the other. Try lines from the end to cont
rol and opposite | 252 // intersect the end of the cubic with the other. Try lines from the end to cont
rol and opposite |
264 // end to determine range of t on opposite cubic. | 253 // end to determine range of t on opposite cubic. |
265 static void intersectEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cub
ic2, | 254 static void intersectEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cub
ic2, |
266 const SkDRect& bounds2, SkIntersections& i) { | 255 const SkDRect& bounds2, bool selfIntersect, SkIntersect
ions& i) { |
267 SkDLine line; | 256 SkDLine line; |
268 int t1Index = start ? 0 : 3; | 257 int t1Index = start ? 0 : 3; |
| 258 bool swap = i.swapped(); |
| 259 double testT = (double) !start; |
| 260 // quad/quad at this point checks to see if exact matches have already been
found |
| 261 // cubic/cubic can't reject so easily since cubics can intersect same point
more than once |
| 262 if (!selfIntersect) { |
| 263 SkDLine tmpLine; |
| 264 tmpLine[0] = tmpLine[1] = cubic2[t1Index]; |
| 265 tmpLine[1].fX += cubic2[2 - start].fY - cubic2[t1Index].fY; |
| 266 tmpLine[1].fY -= cubic2[2 - start].fX - cubic2[t1Index].fX; |
| 267 SkIntersections impTs; |
| 268 impTs.intersectRay(cubic1, tmpLine); |
| 269 for (int index = 0; index < impTs.used(); ++index) { |
| 270 SkDPoint realPt = impTs.pt(index); |
| 271 if (!tmpLine[0].approximatelyEqualHalf(realPt)) { |
| 272 continue; |
| 273 } |
| 274 if (swap) { |
| 275 i.insert(testT, impTs[0][index], tmpLine[0]); |
| 276 } else { |
| 277 i.insert(impTs[0][index], testT, tmpLine[0]); |
| 278 } |
| 279 return; |
| 280 } |
| 281 } |
269 // don't bother if the two cubics are connnected | 282 // don't bother if the two cubics are connnected |
270 #if 1 | |
271 static const int kPointsInCubic = 4; // FIXME: move to DCubic, replace '4' w
ith this | 283 static const int kPointsInCubic = 4; // FIXME: move to DCubic, replace '4' w
ith this |
272 static const int kMaxLineCubicIntersections = 3; | 284 static const int kMaxLineCubicIntersections = 3; |
273 SkSTArray<(kMaxLineCubicIntersections - 1) * kMaxLineCubicIntersections, dou
ble, true> tVals; | 285 SkSTArray<(kMaxLineCubicIntersections - 1) * kMaxLineCubicIntersections, dou
ble, true> tVals; |
274 line[0] = cubic1[t1Index]; | 286 line[0] = cubic1[t1Index]; |
275 // this variant looks for intersections with the end point and lines paralle
l to other points | 287 // this variant looks for intersections with the end point and lines paralle
l to other points |
276 for (int index = 0; index < kPointsInCubic; ++index) { | 288 for (int index = 0; index < kPointsInCubic; ++index) { |
277 if (index == t1Index) { | 289 if (index == t1Index) { |
278 continue; | 290 continue; |
279 } | 291 } |
280 SkDVector dxy1 = cubic1[index] - line[0]; | 292 SkDVector dxy1 = cubic1[index] - line[0]; |
281 dxy1 /= SkDCubic::gPrecisionUnit; | 293 dxy1 /= SkDCubic::gPrecisionUnit; |
282 line[1] = line[0] + dxy1; | 294 line[1] = line[0] + dxy1; |
283 SkDRect lineBounds; | 295 SkDRect lineBounds; |
284 lineBounds.setBounds(line); | 296 lineBounds.setBounds(line); |
285 if (!bounds2.intersects(&lineBounds)) { | 297 if (!bounds2.intersects(&lineBounds)) { |
286 continue; | 298 continue; |
287 } | 299 } |
288 SkIntersections local; | 300 SkIntersections local; |
289 if (!local.intersect(cubic2, line)) { | 301 if (!local.intersect(cubic2, line)) { |
290 continue; | 302 continue; |
291 } | 303 } |
292 for (int idx2 = 0; idx2 < local.used(); ++idx2) { | 304 for (int idx2 = 0; idx2 < local.used(); ++idx2) { |
293 double foundT = local[0][idx2]; | 305 double foundT = local[0][idx2]; |
294 if (approximately_less_than_zero(foundT) | 306 if (approximately_less_than_zero(foundT) |
295 || approximately_greater_than_one(foundT)) { | 307 || approximately_greater_than_one(foundT)) { |
296 continue; | 308 continue; |
297 } | 309 } |
298 if (local.pt(idx2).approximatelyEqual(line[0])) { | 310 if (local.pt(idx2).approximatelyEqual(line[0])) { |
299 if (i.swapped()) { // FIXME: insert should respect swap | 311 if (i.swapped()) { // FIXME: insert should respect swap |
300 i.insert(foundT, start ? 0 : 1, line[0]); | 312 i.insert(foundT, testT, line[0]); |
301 } else { | 313 } else { |
302 i.insert(start ? 0 : 1, foundT, line[0]); | 314 i.insert(testT, foundT, line[0]); |
303 } | 315 } |
304 } else { | 316 } else { |
305 tVals.push_back(foundT); | 317 tVals.push_back(foundT); |
306 } | 318 } |
307 } | 319 } |
308 } | 320 } |
309 if (tVals.count() == 0) { | 321 if (tVals.count() == 0) { |
310 return; | 322 return; |
311 } | 323 } |
312 SkTQSort<double>(tVals.begin(), tVals.end() - 1); | 324 SkTQSort<double>(tVals.begin(), tVals.end() - 1); |
313 double tMin1 = start ? 0 : 1 - LINE_FRACTION; | 325 double tMin1 = start ? 0 : 1 - LINE_FRACTION; |
314 double tMax1 = start ? LINE_FRACTION : 1; | 326 double tMax1 = start ? LINE_FRACTION : 1; |
315 int tIdx = 0; | 327 int tIdx = 0; |
316 do { | 328 do { |
317 int tLast = tIdx; | 329 int tLast = tIdx; |
318 while (tLast + 1 < tVals.count() && roughly_equal(tVals[tLast + 1], tVal
s[tIdx])) { | 330 while (tLast + 1 < tVals.count() && roughly_equal(tVals[tLast + 1], tVal
s[tIdx])) { |
319 ++tLast; | 331 ++tLast; |
320 } | 332 } |
321 double tMin2 = SkTMax(tVals[tIdx] - LINE_FRACTION, 0.0); | 333 double tMin2 = SkTMax(tVals[tIdx] - LINE_FRACTION, 0.0); |
322 double tMax2 = SkTMin(tVals[tLast] + LINE_FRACTION, 1.0); | 334 double tMax2 = SkTMin(tVals[tLast] + LINE_FRACTION, 1.0); |
323 int lastUsed = i.used(); | 335 int lastUsed = i.used(); |
324 intersect(cubic1, tMin1, tMax1, cubic2, tMin2, tMax2, 1, i); | 336 intersect(cubic1, tMin1, tMax1, cubic2, tMin2, tMax2, 1, i); |
325 if (lastUsed == i.used()) { | 337 if (lastUsed == i.used()) { |
326 tMin2 = SkTMax(tVals[tIdx] - (1.0 / SkDCubic::gPrecisionUnit), 0.0); | 338 tMin2 = SkTMax(tVals[tIdx] - (1.0 / SkDCubic::gPrecisionUnit), 0.0); |
327 tMax2 = SkTMin(tVals[tLast] + (1.0 / SkDCubic::gPrecisionUnit), 1.0)
; | 339 tMax2 = SkTMin(tVals[tLast] + (1.0 / SkDCubic::gPrecisionUnit), 1.0)
; |
328 intersect(cubic1, tMin1, tMax1, cubic2, tMin2, tMax2, 1, i); | 340 intersect(cubic1, tMin1, tMax1, cubic2, tMin2, tMax2, 1, i); |
329 } | 341 } |
330 tIdx = tLast + 1; | 342 tIdx = tLast + 1; |
331 } while (tIdx < tVals.count()); | 343 } while (tIdx < tVals.count()); |
332 #else | |
333 const SkDPoint& endPt = cubic1[t1Index]; | |
334 if (!bounds2.contains(endPt)) { | |
335 return; | |
336 } | |
337 // this variant looks for intersections within an 'x' of the endpoint | |
338 double delta = SkTMax(bounds2.width(), bounds2.height()); | |
339 for (int index = 0; index < 2; ++index) { | |
340 if (index == 0) { | |
341 line[0].fY = line[1].fY = endPt.fY; | |
342 line[0].fX = endPt.fX - delta; | |
343 line[1].fX = endPt.fX + delta; | |
344 } else { | |
345 line[0].fX = line[1].fX = cubic1[t1Index].fX; | |
346 line[0].fY = endPt.fY - delta; | |
347 line[1].fY = endPt.fY + delta; | |
348 } | |
349 SkIntersections local; | |
350 local.intersectRay(cubic2, line); // OPTIMIZE: special for horizontal/ve
rtical lines | |
351 int used = local.used(); | |
352 for (int index = 0; index < used; ++index) { | |
353 double foundT = local[0][index]; | |
354 if (approximately_less_than_zero(foundT) || approximately_greater_th
an_one(foundT)) { | |
355 continue; | |
356 } | |
357 if (!local.pt(index).approximatelyEqual(endPt)) { | |
358 continue; | |
359 } | |
360 if (i.swapped()) { // FIXME: insert should respect swap | |
361 i.insert(foundT, start ? 0 : 1, endPt); | |
362 } else { | |
363 i.insert(start ? 0 : 1, foundT, endPt); | |
364 } | |
365 return; | |
366 } | |
367 } | |
368 // the above doesn't catch when the end of the cubic missed the other cubic beca
use the quad | |
369 // approximation moved too far away, so something like the below is still needed
. The enabled | |
370 // code above tries to avoid this heavy lifting unless the convex hull intersect
ed the cubic. | |
371 double tMin1 = start ? 0 : 1 - LINE_FRACTION; | |
372 double tMax1 = start ? LINE_FRACTION : 1; | |
373 double tMin2 = SkTMax(foundT - LINE_FRACTION, 0.0); | |
374 double tMax2 = SkTMin(foundT + LINE_FRACTION, 1.0); | |
375 int lastUsed = i.used(); | |
376 intersect(cubic1, tMin1, tMax1, cubic2, tMin2, tMax2, 1, i); | |
377 if (lastUsed == i.used()) { | |
378 tMin2 = SkTMax(foundT - (1.0 / SkDCubic::gPrecisionUnit), 0.0); | |
379 tMax2 = SkTMin(foundT + (1.0 / SkDCubic::gPrecisionUnit), 1.0); | |
380 intersect(cubic1, tMin1, tMax1, cubic2, tMin2, tMax2, 1, i); | |
381 } | |
382 #endif | |
383 return; | 344 return; |
384 } | 345 } |
385 | 346 |
386 const double CLOSE_ENOUGH = 0.001; | 347 const double CLOSE_ENOUGH = 0.001; |
387 | 348 |
388 static bool closeStart(const SkDCubic& cubic, int cubicIndex, SkIntersections& i
, SkDPoint& pt) { | 349 static bool closeStart(const SkDCubic& cubic, int cubicIndex, SkIntersections& i
, SkDPoint& pt) { |
389 if (i[cubicIndex][0] != 0 || i[cubicIndex][1] > CLOSE_ENOUGH) { | 350 if (i[cubicIndex][0] != 0 || i[cubicIndex][1] > CLOSE_ENOUGH) { |
390 return false; | 351 return false; |
391 } | 352 } |
392 pt = cubic.xyAtT((i[cubicIndex][0] + i[cubicIndex][1]) / 2); | 353 pt = cubic.ptAtT((i[cubicIndex][0] + i[cubicIndex][1]) / 2); |
393 return true; | 354 return true; |
394 } | 355 } |
395 | 356 |
396 static bool closeEnd(const SkDCubic& cubic, int cubicIndex, SkIntersections& i,
SkDPoint& pt) { | 357 static bool closeEnd(const SkDCubic& cubic, int cubicIndex, SkIntersections& i,
SkDPoint& pt) { |
397 int last = i.used() - 1; | 358 int last = i.used() - 1; |
398 if (i[cubicIndex][last] != 1 || i[cubicIndex][last - 1] < 1 - CLOSE_ENOUGH)
{ | 359 if (i[cubicIndex][last] != 1 || i[cubicIndex][last - 1] < 1 - CLOSE_ENOUGH)
{ |
399 return false; | 360 return false; |
400 } | 361 } |
401 pt = cubic.xyAtT((i[cubicIndex][last] + i[cubicIndex][last - 1]) / 2); | 362 pt = cubic.ptAtT((i[cubicIndex][last] + i[cubicIndex][last - 1]) / 2); |
402 return true; | 363 return true; |
403 } | 364 } |
404 | 365 |
| 366 static bool only_end_pts_in_common(const SkDCubic& c1, const SkDCubic& c2) { |
| 367 // the idea here is to see at minimum do a quick reject by rotating all points |
| 368 // to either side of the line formed by connecting the endpoints |
| 369 // if the opposite curves points are on the line or on the other side, the |
| 370 // curves at most intersect at the endpoints |
| 371 for (int oddMan = 0; oddMan < 4; ++oddMan) { |
| 372 const SkDPoint* endPt[3]; |
| 373 for (int opp = 1; opp < 4; ++opp) { |
| 374 int end = oddMan ^ opp; // choose a value not equal to oddMan |
| 375 endPt[opp - 1] = &c1[end]; |
| 376 } |
| 377 for (int triTest = 0; triTest < 3; ++triTest) { |
| 378 double origX = endPt[triTest]->fX; |
| 379 double origY = endPt[triTest]->fY; |
| 380 int oppTest = triTest + 1; |
| 381 if (3 == oppTest) { |
| 382 oppTest = 0; |
| 383 } |
| 384 double adj = endPt[oppTest]->fX - origX; |
| 385 double opp = endPt[oppTest]->fY - origY; |
| 386 double sign = (c1[oddMan].fY - origY) * adj - (c1[oddMan].fX - origX
) * opp; |
| 387 if (approximately_zero(sign)) { |
| 388 goto tryNextHalfPlane; |
| 389 } |
| 390 for (int n = 0; n < 4; ++n) { |
| 391 double test = (c2[n].fY - origY) * adj - (c2[n].fX - origX) * op
p; |
| 392 if (test * sign > 0 && !precisely_zero(test)) { |
| 393 goto tryNextHalfPlane; |
| 394 } |
| 395 } |
| 396 } |
| 397 return true; |
| 398 tryNextHalfPlane: |
| 399 ; |
| 400 } |
| 401 return false; |
| 402 } |
| 403 |
405 int SkIntersections::intersect(const SkDCubic& c1, const SkDCubic& c2) { | 404 int SkIntersections::intersect(const SkDCubic& c1, const SkDCubic& c2) { |
406 ::intersect(c1, 0, 1, c2, 0, 1, 1, *this); | 405 bool selfIntersect = &c1 == &c2; |
| 406 if (selfIntersect) { |
| 407 if (c1[0].approximatelyEqualHalf(c1[3])) { |
| 408 insert(0, 1, c1[0]); |
| 409 } |
| 410 } else { |
| 411 for (int i1 = 0; i1 < 4; i1 += 3) { |
| 412 for (int i2 = 0; i2 < 4; i2 += 3) { |
| 413 if (c1[i1].approximatelyEqualHalf(c2[i2])) { |
| 414 insert(i1 >> 1, i2 >> 1, c1[i1]); |
| 415 } |
| 416 } |
| 417 } |
| 418 } |
| 419 SkASSERT(fUsed < 4); |
| 420 if (!selfIntersect) { |
| 421 if (only_end_pts_in_common(c1, c2)) { |
| 422 return fUsed; |
| 423 } |
| 424 if (only_end_pts_in_common(c2, c1)) { |
| 425 return fUsed; |
| 426 } |
| 427 } |
| 428 // quad/quad does linear test here -- cubic does not |
| 429 // cubics which are really lines should have been detected in reduce step ea
rlier |
| 430 SkDRect c1Bounds, c2Bounds; |
407 // FIXME: pass in cached bounds from caller | 431 // FIXME: pass in cached bounds from caller |
408 SkDRect c1Bounds, c2Bounds; | |
409 c1Bounds.setBounds(c1); // OPTIMIZE use setRawBounds ? | 432 c1Bounds.setBounds(c1); // OPTIMIZE use setRawBounds ? |
410 c2Bounds.setBounds(c2); | 433 c2Bounds.setBounds(c2); |
411 intersectEnd(c1, false, c2, c2Bounds, *this); | 434 intersectEnd(c1, false, c2, c2Bounds, selfIntersect, *this); |
412 intersectEnd(c1, true, c2, c2Bounds, *this); | 435 intersectEnd(c1, true, c2, c2Bounds, selfIntersect, *this); |
413 bool selfIntersect = &c1 == &c2; | 436 if (selfIntersect) { |
414 if (!selfIntersect) { | 437 if (fUsed) { |
| 438 return fUsed; |
| 439 } |
| 440 } else { |
415 swap(); | 441 swap(); |
416 intersectEnd(c2, false, c1, c1Bounds, *this); | 442 intersectEnd(c2, false, c1, c1Bounds, false, *this); |
417 intersectEnd(c2, true, c1, c1Bounds, *this); | 443 intersectEnd(c2, true, c1, c1Bounds, false, *this); |
418 swap(); | 444 swap(); |
419 } | 445 } |
| 446 // if two ends intersect, check middle for coincidence |
| 447 if (fUsed >= 2) { |
| 448 SkASSERT(!selfIntersect); |
| 449 int last = fUsed - 1; |
| 450 double tRange1 = fT[0][last] - fT[0][0]; |
| 451 double tRange2 = fT[1][last] - fT[1][0]; |
| 452 for (int index = 1; index < 5; ++index) { |
| 453 double testT1 = fT[0][0] + tRange1 * index / 5; |
| 454 double testT2 = fT[1][0] + tRange2 * index / 5; |
| 455 SkDPoint testPt1 = c1.ptAtT(testT1); |
| 456 SkDPoint testPt2 = c2.ptAtT(testT2); |
| 457 if (!testPt1.approximatelyEqual(testPt2)) { |
| 458 goto skipCoincidence; |
| 459 } |
| 460 } |
| 461 if (fUsed > 2) { |
| 462 fPt[1] = fPt[last]; |
| 463 fT[0][1] = fT[0][last]; |
| 464 fT[1][1] = fT[1][last]; |
| 465 fUsed = 2; |
| 466 } |
| 467 fIsCoincident[0] = fIsCoincident[1] = 0x03; |
| 468 return fUsed; |
| 469 } |
| 470 skipCoincidence: |
| 471 ::intersect(c1, 0, 1, c2, 0, 1, 1, *this); |
420 // If an end point and a second point very close to the end is returned, the
second | 472 // If an end point and a second point very close to the end is returned, the
second |
421 // point may have been detected because the approximate quads | 473 // point may have been detected because the approximate quads |
422 // intersected at the end and close to it. Verify that the second point is v
alid. | 474 // intersected at the end and close to it. Verify that the second point is v
alid. |
423 if (fUsed <= 1 || coincidentUsed()) { | 475 if (fUsed <= 1) { |
424 return fUsed; | 476 return fUsed; |
425 } | 477 } |
426 SkDPoint pt[2]; | 478 SkDPoint pt[2]; |
427 if (closeStart(c1, 0, *this, pt[0]) && closeStart(c2, 1, *this, pt[1]) | 479 if (closeStart(c1, 0, *this, pt[0]) && closeStart(c2, 1, *this, pt[1]) |
428 && pt[0].approximatelyEqual(pt[1])) { | 480 && pt[0].approximatelyEqual(pt[1])) { |
429 removeOne(1); | 481 removeOne(1); |
430 } | 482 } |
431 if (closeEnd(c1, 0, *this, pt[0]) && closeEnd(c2, 1, *this, pt[1]) | 483 if (closeEnd(c1, 0, *this, pt[0]) && closeEnd(c2, 1, *this, pt[1]) |
432 && pt[0].approximatelyEqual(pt[1])) { | 484 && pt[0].approximatelyEqual(pt[1])) { |
433 removeOne(used() - 2); | 485 removeOne(used() - 2); |
434 } | 486 } |
435 // vet the pairs of t values to see if the mid value is also on the curve. I
f so, mark | 487 // vet the pairs of t values to see if the mid value is also on the curve. I
f so, mark |
436 // the span as coincident | 488 // the span as coincident |
437 if (fUsed >= 2 && !coincidentUsed()) { | 489 if (fUsed >= 2 && !coincidentUsed()) { |
438 int last = fUsed - 1; | 490 int last = fUsed - 1; |
439 int match = 0; | 491 int match = 0; |
440 for (int index = 0; index < last; ++index) { | 492 for (int index = 0; index < last; ++index) { |
441 double mid1 = (fT[0][index] + fT[0][index + 1]) / 2; | 493 double mid1 = (fT[0][index] + fT[0][index + 1]) / 2; |
442 double mid2 = (fT[1][index] + fT[1][index + 1]) / 2; | 494 double mid2 = (fT[1][index] + fT[1][index + 1]) / 2; |
443 pt[0] = c1.xyAtT(mid1); | 495 pt[0] = c1.ptAtT(mid1); |
444 pt[1] = c2.xyAtT(mid2); | 496 pt[1] = c2.ptAtT(mid2); |
445 if (pt[0].approximatelyEqual(pt[1])) { | 497 if (pt[0].approximatelyEqual(pt[1])) { |
446 match |= 1 << index; | 498 match |= 1 << index; |
447 } | 499 } |
448 } | 500 } |
449 if (match) { | 501 if (match) { |
450 if (((match + 1) & match) != 0) { | 502 if (((match + 1) & match) != 0) { |
451 SkDebugf("%s coincident hole\n", __FUNCTION__); | 503 SkDebugf("%s coincident hole\n", __FUNCTION__); |
452 } | 504 } |
453 // for now, assume that everything from start to finish is coinciden
t | 505 // for now, assume that everything from start to finish is coinciden
t |
454 if (fUsed > 2) { | 506 if (fUsed > 2) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
487 } | 539 } |
488 (void) intersect(c, c); | 540 (void) intersect(c, c); |
489 if (used() > 0) { | 541 if (used() > 0) { |
490 SkASSERT(used() == 1); | 542 SkASSERT(used() == 1); |
491 if (fT[0][0] > fT[1][0]) { | 543 if (fT[0][0] > fT[1][0]) { |
492 swapPts(); | 544 swapPts(); |
493 } | 545 } |
494 } | 546 } |
495 return used(); | 547 return used(); |
496 } | 548 } |
OLD | NEW |