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