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" |
11 #include "SkPathOpsPoint.h" | 11 #include "SkPathOpsPoint.h" |
12 #include "SkPathOpsQuad.h" | 12 #include "SkPathOpsQuad.h" |
13 #include "SkPathOpsRect.h" | 13 #include "SkPathOpsRect.h" |
14 #include "SkReduceOrder.h" | 14 #include "SkReduceOrder.h" |
15 #include "SkTDArray.h" | |
16 #include "SkTSort.h" | 15 #include "SkTSort.h" |
17 | 16 |
18 #if ONE_OFF_DEBUG | 17 #if ONE_OFF_DEBUG |
19 static const double tLimits1[2][2] = {{0.36, 0.37}, {0.63, 0.64}}; | 18 static const double tLimits1[2][2] = {{0.36, 0.37}, {0.63, 0.64}}; |
20 static const double tLimits2[2][2] = {{-0.865211397, -0.865215212}, {-0.86520769
6, -0.865208078}}; | 19 static const double tLimits2[2][2] = {{-0.865211397, -0.865215212}, {-0.86520769
6, -0.865208078}}; |
21 #endif | 20 #endif |
22 | 21 |
23 #define DEBUG_QUAD_PART 0 | 22 #define DEBUG_QUAD_PART 0 |
24 #define SWAP_TOP_DEBUG 0 | 23 #define SWAP_TOP_DEBUG 0 |
25 | 24 |
| 25 static const int kCubicToQuadSubdivisionDepth = 8; // slots reserved for cubic t
o quads subdivision |
| 26 |
26 static int quadPart(const SkDCubic& cubic, double tStart, double tEnd, SkReduceO
rder* reducer) { | 27 static int quadPart(const SkDCubic& cubic, double tStart, double tEnd, SkReduceO
rder* reducer) { |
27 SkDCubic part = cubic.subDivide(tStart, tEnd); | 28 SkDCubic part = cubic.subDivide(tStart, tEnd); |
28 SkDQuad quad = part.toQuad(); | 29 SkDQuad quad = part.toQuad(); |
29 // FIXME: should reduceOrder be looser in this use case if quartic is going
to blow up on an | 30 // FIXME: should reduceOrder be looser in this use case if quartic is going
to blow up on an |
30 // extremely shallow quadratic? | 31 // extremely shallow quadratic? |
31 int order = reducer->reduce(quad, SkReduceOrder::kFill_Style); | 32 int order = reducer->reduce(quad, SkReduceOrder::kFill_Style); |
32 #if DEBUG_QUAD_PART | 33 #if DEBUG_QUAD_PART |
33 SkDebugf("%s cubic=(%1.17g,%1.17g %1.17g,%1.17g %1.17g,%1.17g %1.17g,%1.17g)
" | 34 SkDebugf("%s cubic=(%1.17g,%1.17g %1.17g,%1.17g %1.17g,%1.17g %1.17g,%1.17g)
" |
34 " t=(%1.17g,%1.17g)\n", __FUNCTION__, cubic[0].fX, cubic[0].fY, | 35 " t=(%1.17g,%1.17g)\n", __FUNCTION__, cubic[0].fX, cubic[0].fY, |
35 cubic[1].fX, cubic[1].fY, cubic[2].fX, cubic[2].fY, | 36 cubic[1].fX, cubic[1].fY, cubic[2].fX, cubic[2].fY, |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
67 } | 68 } |
68 } | 69 } |
69 | 70 |
70 // this flavor centers potential intersections recursively. In contrast, '2' may
inadvertently | 71 // this flavor centers potential intersections recursively. In contrast, '2' may
inadvertently |
71 // chase intersections near quadratic ends, requiring odd hacks to find them. | 72 // chase intersections near quadratic ends, requiring odd hacks to find them. |
72 static void intersect(const SkDCubic& cubic1, double t1s, double t1e, const SkDC
ubic& cubic2, | 73 static void intersect(const SkDCubic& cubic1, double t1s, double t1e, const SkDC
ubic& cubic2, |
73 double t2s, double t2e, double precisionScale, SkIntersections& i) { | 74 double t2s, double t2e, double precisionScale, SkIntersections& i) { |
74 i.upDepth(); | 75 i.upDepth(); |
75 SkDCubic c1 = cubic1.subDivide(t1s, t1e); | 76 SkDCubic c1 = cubic1.subDivide(t1s, t1e); |
76 SkDCubic c2 = cubic2.subDivide(t2s, t2e); | 77 SkDCubic c2 = cubic2.subDivide(t2s, t2e); |
77 SkTDArray<double> ts1; | 78 SkSTArray<kCubicToQuadSubdivisionDepth, double, true> ts1; |
78 // OPTIMIZE: if c1 == c2, call once (happens when detecting self-intersectio
n) | 79 // OPTIMIZE: if c1 == c2, call once (happens when detecting self-intersectio
n) |
79 c1.toQuadraticTs(c1.calcPrecision() * precisionScale, &ts1); | 80 c1.toQuadraticTs(c1.calcPrecision() * precisionScale, &ts1); |
80 SkTDArray<double> ts2; | 81 SkSTArray<kCubicToQuadSubdivisionDepth, double, true> ts2; |
81 c2.toQuadraticTs(c2.calcPrecision() * precisionScale, &ts2); | 82 c2.toQuadraticTs(c2.calcPrecision() * precisionScale, &ts2); |
82 double t1Start = t1s; | 83 double t1Start = t1s; |
83 int ts1Count = ts1.count(); | 84 int ts1Count = ts1.count(); |
84 for (int i1 = 0; i1 <= ts1Count; ++i1) { | 85 for (int i1 = 0; i1 <= ts1Count; ++i1) { |
85 const double tEnd1 = i1 < ts1Count ? ts1[i1] : 1; | 86 const double tEnd1 = i1 < ts1Count ? ts1[i1] : 1; |
86 const double t1 = t1s + (t1e - t1s) * tEnd1; | 87 const double t1 = t1s + (t1e - t1s) * tEnd1; |
87 SkReduceOrder s1; | 88 SkReduceOrder s1; |
88 int o1 = quadPart(cubic1, t1Start, t1, &s1); | 89 int o1 = quadPart(cubic1, t1Start, t1, &s1); |
89 double t2Start = t2s; | 90 double t2Start = t2s; |
90 int ts2Count = ts2.count(); | 91 int ts2Count = ts2.count(); |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
257 #define LINE_FRACTION 0.1 | 258 #define LINE_FRACTION 0.1 |
258 | 259 |
259 // intersect the end of the cubic with the other. Try lines from the end to cont
rol and opposite | 260 // intersect the end of the cubic with the other. Try lines from the end to cont
rol and opposite |
260 // end to determine range of t on opposite cubic. | 261 // end to determine range of t on opposite cubic. |
261 static void intersectEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cub
ic2, | 262 static void intersectEnd(const SkDCubic& cubic1, bool start, const SkDCubic& cub
ic2, |
262 const SkDRect& bounds2, SkIntersections& i) { | 263 const SkDRect& bounds2, SkIntersections& i) { |
263 SkDLine line; | 264 SkDLine line; |
264 int t1Index = start ? 0 : 3; | 265 int t1Index = start ? 0 : 3; |
265 // don't bother if the two cubics are connnected | 266 // don't bother if the two cubics are connnected |
266 #if 1 | 267 #if 1 |
267 SkTDArray<double> tVals; // OPTIMIZE: replace with hard-sized array | 268 static const int kPointsInCubic = 4; // FIXME: move to DCubic, replace '4' w
ith this |
| 269 static const int kMaxLineCubicIntersections = 3; |
| 270 SkSTArray<(kMaxLineCubicIntersections - 1) * kMaxLineCubicIntersections, dou
ble, true> tVals; |
268 line[0] = cubic1[t1Index]; | 271 line[0] = cubic1[t1Index]; |
269 // this variant looks for intersections with the end point and lines paralle
l to other points | 272 // this variant looks for intersections with the end point and lines paralle
l to other points |
270 for (int index = 0; index < 4; ++index) { | 273 for (int index = 0; index < kPointsInCubic; ++index) { |
271 if (index == t1Index) { | 274 if (index == t1Index) { |
272 continue; | 275 continue; |
273 } | 276 } |
274 SkDVector dxy1 = cubic1[index] - line[0]; | 277 SkDVector dxy1 = cubic1[index] - line[0]; |
275 dxy1 /= SkDCubic::gPrecisionUnit; | 278 dxy1 /= SkDCubic::gPrecisionUnit; |
276 line[1] = line[0] + dxy1; | 279 line[1] = line[0] + dxy1; |
277 SkDRect lineBounds; | 280 SkDRect lineBounds; |
278 lineBounds.setBounds(line); | 281 lineBounds.setBounds(line); |
279 if (!bounds2.intersects(&lineBounds)) { | 282 if (!bounds2.intersects(&lineBounds)) { |
280 continue; | 283 continue; |
281 } | 284 } |
282 SkIntersections local; | 285 SkIntersections local; |
283 if (!local.intersect(cubic2, line)) { | 286 if (!local.intersect(cubic2, line)) { |
284 continue; | 287 continue; |
285 } | 288 } |
286 for (int idx2 = 0; idx2 < local.used(); ++idx2) { | 289 for (int idx2 = 0; idx2 < local.used(); ++idx2) { |
287 double foundT = local[0][idx2]; | 290 double foundT = local[0][idx2]; |
288 if (approximately_less_than_zero(foundT) | 291 if (approximately_less_than_zero(foundT) |
289 || approximately_greater_than_one(foundT)) { | 292 || approximately_greater_than_one(foundT)) { |
290 continue; | 293 continue; |
291 } | 294 } |
292 if (local.pt(idx2).approximatelyEqual(line[0])) { | 295 if (local.pt(idx2).approximatelyEqual(line[0])) { |
293 if (i.swapped()) { // FIXME: insert should respect swap | 296 if (i.swapped()) { // FIXME: insert should respect swap |
294 i.insert(foundT, start ? 0 : 1, line[0]); | 297 i.insert(foundT, start ? 0 : 1, line[0]); |
295 } else { | 298 } else { |
296 i.insert(start ? 0 : 1, foundT, line[0]); | 299 i.insert(start ? 0 : 1, foundT, line[0]); |
297 } | 300 } |
298 } else { | 301 } else { |
299 *tVals.append() = foundT; | 302 tVals.push_back(foundT); |
300 } | 303 } |
301 } | 304 } |
302 } | 305 } |
303 if (tVals.count() == 0) { | 306 if (tVals.count() == 0) { |
304 return; | 307 return; |
305 } | 308 } |
306 SkTQSort<double>(tVals.begin(), tVals.end() - 1); | 309 SkTQSort<double>(tVals.begin(), tVals.end() - 1); |
307 double tMin1 = start ? 0 : 1 - LINE_FRACTION; | 310 double tMin1 = start ? 0 : 1 - LINE_FRACTION; |
308 double tMax1 = start ? LINE_FRACTION : 1; | 311 double tMax1 = start ? LINE_FRACTION : 1; |
309 int tIdx = 0; | 312 int tIdx = 0; |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
481 } | 484 } |
482 (void) intersect(c, c); | 485 (void) intersect(c, c); |
483 if (used() > 0) { | 486 if (used() > 0) { |
484 SkASSERT(used() == 1); | 487 SkASSERT(used() == 1); |
485 if (fT[0][0] > fT[1][0]) { | 488 if (fT[0][0] > fT[1][0]) { |
486 swapPts(); | 489 swapPts(); |
487 } | 490 } |
488 } | 491 } |
489 return used(); | 492 return used(); |
490 } | 493 } |
OLD | NEW |