| 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 |