| /* |
| * Copyright 2012 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| #include "CurveIntersection.h" |
| #include "CurveUtilities.h" |
| #include "LineParameters.h" |
| |
| // return false if unable to clip (e.g., unable to create implicit line) |
| // caller should subdivide, or create degenerate if the values are too small |
| bool bezier_clip(const Cubic& cubic1, const Cubic& cubic2, double& minT, double& maxT) { |
| minT = 1; |
| maxT = 0; |
| // determine normalized implicit line equation for pt[0] to pt[3] |
| // of the form ax + by + c = 0, where a*a + b*b == 1 |
| |
| // find the implicit line equation parameters |
| LineParameters endLine; |
| endLine.cubicEndPoints(cubic1); |
| if (!endLine.normalize()) { |
| printf("line cannot be normalized: need more code here\n"); |
| return false; |
| } |
| |
| double distance[2]; |
| distance[0] = endLine.controlPtDistance(cubic1, 1); |
| distance[1] = endLine.controlPtDistance(cubic1, 2); |
| |
| // find fat line |
| double top = distance[0]; |
| double bottom = distance[1]; |
| if (top > bottom) { |
| SkTSwap(top, bottom); |
| } |
| if (top * bottom >= 0) { |
| const double scale = 3/4.0; // http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf (13) |
| if (top < 0) { |
| top *= scale; |
| bottom = 0; |
| } else { |
| top = 0; |
| bottom *= scale; |
| } |
| } else { |
| const double scale = 4/9.0; // http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf (15) |
| top *= scale; |
| bottom *= scale; |
| } |
| |
| // compute intersecting candidate distance |
| Cubic distance2y; // points with X of (0, 1/3, 2/3, 1) |
| endLine.cubicDistanceY(cubic2, distance2y); |
| |
| int flags = 0; |
| if (approximately_lesser_or_equal(distance2y[0].y, top)) { |
| flags |= kFindTopMin; |
| } else if (approximately_greater_or_equal(distance2y[0].y, bottom)) { |
| flags |= kFindBottomMin; |
| } else { |
| minT = 0; |
| } |
| |
| if (approximately_lesser_or_equal(distance2y[3].y, top)) { |
| flags |= kFindTopMax; |
| } else if (approximately_greater_or_equal(distance2y[3].y, bottom)) { |
| flags |= kFindBottomMax; |
| } else { |
| maxT = 1; |
| } |
| // Find the intersection of distance convex hull and fat line. |
| char to_0[2]; |
| char to_3[2]; |
| bool do_1_2_edge = convex_x_hull(distance2y, to_0, to_3); |
| x_at(distance2y[0], distance2y[to_0[0]], top, bottom, flags, minT, maxT); |
| if (to_0[0] != to_0[1]) { |
| x_at(distance2y[0], distance2y[to_0[1]], top, bottom, flags, minT, maxT); |
| } |
| x_at(distance2y[to_3[0]], distance2y[3], top, bottom, flags, minT, maxT); |
| if (to_3[0] != to_3[1]) { |
| x_at(distance2y[to_3[1]], distance2y[3], top, bottom, flags, minT, maxT); |
| } |
| if (do_1_2_edge) { |
| x_at(distance2y[1], distance2y[2], top, bottom, flags, minT, maxT); |
| } |
| |
| return minT < maxT; // returns false if distance shows no intersection |
| } |