caryclark@google.com | 9e49fb6 | 2012-08-27 14:11:33 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2012 Google Inc. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
caryclark@google.com | c682590 | 2012-02-03 22:07:47 +0000 | [diff] [blame] | 7 | #include "CurveIntersection.h" |
caryclark@google.com | 8dcf114 | 2012-07-02 20:27:02 +0000 | [diff] [blame] | 8 | #include "CurveUtilities.h" |
caryclark@google.com | 639df89 | 2012-01-10 21:46:10 +0000 | [diff] [blame] | 9 | #include "LineParameters.h" |
caryclark@google.com | 639df89 | 2012-01-10 21:46:10 +0000 | [diff] [blame] | 10 | |
| 11 | // return false if unable to clip (e.g., unable to create implicit line) |
| 12 | // caller should subdivide, or create degenerate if the values are too small |
| 13 | bool bezier_clip(const Cubic& cubic1, const Cubic& cubic2, double& minT, double& maxT) { |
| 14 | minT = 1; |
| 15 | maxT = 0; |
| 16 | // determine normalized implicit line equation for pt[0] to pt[3] |
| 17 | // of the form ax + by + c = 0, where a*a + b*b == 1 |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 18 | |
caryclark@google.com | 639df89 | 2012-01-10 21:46:10 +0000 | [diff] [blame] | 19 | // find the implicit line equation parameters |
| 20 | LineParameters endLine; |
| 21 | endLine.cubicEndPoints(cubic1); |
| 22 | if (!endLine.normalize()) { |
| 23 | printf("line cannot be normalized: need more code here\n"); |
| 24 | return false; |
| 25 | } |
| 26 | |
| 27 | double distance[2]; |
caryclark@google.com | 73ca624 | 2013-01-17 21:02:47 +0000 | [diff] [blame] | 28 | distance[0] = endLine.controlPtDistance(cubic1, 1); |
| 29 | distance[1] = endLine.controlPtDistance(cubic1, 2); |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 30 | |
caryclark@google.com | 639df89 | 2012-01-10 21:46:10 +0000 | [diff] [blame] | 31 | // find fat line |
| 32 | double top = distance[0]; |
| 33 | double bottom = distance[1]; |
| 34 | if (top > bottom) { |
caryclark@google.com | aa35831 | 2013-01-29 20:28:49 +0000 | [diff] [blame] | 35 | SkTSwap(top, bottom); |
caryclark@google.com | 639df89 | 2012-01-10 21:46:10 +0000 | [diff] [blame] | 36 | } |
| 37 | if (top * bottom >= 0) { |
| 38 | const double scale = 3/4.0; // http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf (13) |
| 39 | if (top < 0) { |
| 40 | top *= scale; |
| 41 | bottom = 0; |
| 42 | } else { |
| 43 | top = 0; |
| 44 | bottom *= scale; |
| 45 | } |
| 46 | } else { |
| 47 | const double scale = 4/9.0; // http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf (15) |
| 48 | top *= scale; |
| 49 | bottom *= scale; |
| 50 | } |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 51 | |
caryclark@google.com | 639df89 | 2012-01-10 21:46:10 +0000 | [diff] [blame] | 52 | // compute intersecting candidate distance |
| 53 | Cubic distance2y; // points with X of (0, 1/3, 2/3, 1) |
| 54 | endLine.cubicDistanceY(cubic2, distance2y); |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 55 | |
caryclark@google.com | 639df89 | 2012-01-10 21:46:10 +0000 | [diff] [blame] | 56 | int flags = 0; |
caryclark@google.com | 5e0500f | 2013-02-20 12:51:37 +0000 | [diff] [blame] | 57 | if (approximately_lesser_or_equal(distance2y[0].y, top)) { |
caryclark@google.com | 639df89 | 2012-01-10 21:46:10 +0000 | [diff] [blame] | 58 | flags |= kFindTopMin; |
caryclark@google.com | 5e0500f | 2013-02-20 12:51:37 +0000 | [diff] [blame] | 59 | } else if (approximately_greater_or_equal(distance2y[0].y, bottom)) { |
caryclark@google.com | 639df89 | 2012-01-10 21:46:10 +0000 | [diff] [blame] | 60 | flags |= kFindBottomMin; |
| 61 | } else { |
| 62 | minT = 0; |
| 63 | } |
| 64 | |
caryclark@google.com | 5e0500f | 2013-02-20 12:51:37 +0000 | [diff] [blame] | 65 | if (approximately_lesser_or_equal(distance2y[3].y, top)) { |
caryclark@google.com | 639df89 | 2012-01-10 21:46:10 +0000 | [diff] [blame] | 66 | flags |= kFindTopMax; |
caryclark@google.com | 5e0500f | 2013-02-20 12:51:37 +0000 | [diff] [blame] | 67 | } else if (approximately_greater_or_equal(distance2y[3].y, bottom)) { |
caryclark@google.com | 639df89 | 2012-01-10 21:46:10 +0000 | [diff] [blame] | 68 | flags |= kFindBottomMax; |
| 69 | } else { |
| 70 | maxT = 1; |
| 71 | } |
| 72 | // Find the intersection of distance convex hull and fat line. |
| 73 | char to_0[2]; |
| 74 | char to_3[2]; |
| 75 | bool do_1_2_edge = convex_x_hull(distance2y, to_0, to_3); |
| 76 | x_at(distance2y[0], distance2y[to_0[0]], top, bottom, flags, minT, maxT); |
| 77 | if (to_0[0] != to_0[1]) { |
| 78 | x_at(distance2y[0], distance2y[to_0[1]], top, bottom, flags, minT, maxT); |
| 79 | } |
| 80 | x_at(distance2y[to_3[0]], distance2y[3], top, bottom, flags, minT, maxT); |
| 81 | if (to_3[0] != to_3[1]) { |
| 82 | x_at(distance2y[to_3[1]], distance2y[3], top, bottom, flags, minT, maxT); |
| 83 | } |
| 84 | if (do_1_2_edge) { |
| 85 | x_at(distance2y[1], distance2y[2], top, bottom, flags, minT, maxT); |
| 86 | } |
rmistry@google.com | d6176b0 | 2012-08-23 18:14:13 +0000 | [diff] [blame] | 87 | |
caryclark@google.com | 639df89 | 2012-01-10 21:46:10 +0000 | [diff] [blame] | 88 | return minT < maxT; // returns false if distance shows no intersection |
| 89 | } |