blob: 825a7b961e792cf846700c99a9df10388efe166f [file] [log] [blame]
caryclark@google.com9e49fb62012-08-27 14:11:33 +00001/*
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.comc6825902012-02-03 22:07:47 +00007#include "CurveIntersection.h"
caryclark@google.com8dcf1142012-07-02 20:27:02 +00008#include "CurveUtilities.h"
caryclark@google.com639df892012-01-10 21:46:10 +00009#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
14bool 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.comd6176b02012-08-23 18:14:13 +000019
caryclark@google.com639df892012-01-10 21:46:10 +000020 // 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.com73ca6242013-01-17 21:02:47 +000029 distance[0] = endLine.controlPtDistance(cubic1, 1);
30 distance[1] = endLine.controlPtDistance(cubic1, 2);
rmistry@google.comd6176b02012-08-23 18:14:13 +000031
caryclark@google.com639df892012-01-10 21:46:10 +000032 // 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.comd6176b02012-08-23 18:14:13 +000052
caryclark@google.com639df892012-01-10 21:46:10 +000053 // compute intersecting candidate distance
54 Cubic distance2y; // points with X of (0, 1/3, 2/3, 1)
55 endLine.cubicDistanceY(cubic2, distance2y);
rmistry@google.comd6176b02012-08-23 18:14:13 +000056
caryclark@google.com639df892012-01-10 21:46:10 +000057 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.comd6176b02012-08-23 18:14:13 +000088
caryclark@google.com639df892012-01-10 21:46:10 +000089 return minT < maxT; // returns false if distance shows no intersection
90}