blob: fcd41190979a643ab9f69d3e3a2593a4c4010f9c [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.com639df892012-01-10 21:46:10 +00008#include "Intersections.h"
caryclark@google.comc6825902012-02-03 22:07:47 +00009#include "IntersectionUtilities.h"
caryclark@google.com639df892012-01-10 21:46:10 +000010#include "LineIntersection.h"
11
caryclark@google.com0d3d09e2012-12-10 14:50:04 +000012static const double tClipLimit = 0.8; // http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf see Multiple intersections
13
caryclark@google.comc6825902012-02-03 22:07:47 +000014class CubicIntersections : public Intersections {
15public:
16
rmistry@google.comd6176b02012-08-23 18:14:13 +000017CubicIntersections(const Cubic& c1, const Cubic& c2, Intersections& i)
caryclark@google.comc6825902012-02-03 22:07:47 +000018 : cubic1(c1)
19 , cubic2(c2)
20 , intersections(i)
rmistry@google.comd6176b02012-08-23 18:14:13 +000021 , depth(0)
caryclark@google.comc6825902012-02-03 22:07:47 +000022 , splits(0) {
caryclark@google.com639df892012-01-10 21:46:10 +000023}
24
caryclark@google.comc6825902012-02-03 22:07:47 +000025bool intersect() {
caryclark@google.com639df892012-01-10 21:46:10 +000026 double minT1, minT2, maxT1, maxT2;
27 if (!bezier_clip(cubic2, cubic1, minT1, maxT1)) {
28 return false;
29 }
30 if (!bezier_clip(cubic1, cubic2, minT2, maxT2)) {
31 return false;
32 }
caryclark@google.comc6825902012-02-03 22:07:47 +000033 int split;
caryclark@google.com639df892012-01-10 21:46:10 +000034 if (maxT1 - minT1 < maxT2 - minT2) {
35 intersections.swap();
caryclark@google.comc6825902012-02-03 22:07:47 +000036 minT2 = 0;
37 maxT2 = 1;
38 split = maxT1 - minT1 > tClipLimit;
39 } else {
40 minT1 = 0;
41 maxT1 = 1;
42 split = (maxT2 - minT2 > tClipLimit) << 1;
43 }
44 return chop(minT1, maxT1, minT2, maxT2, split);
caryclark@google.com639df892012-01-10 21:46:10 +000045}
caryclark@google.comc6825902012-02-03 22:07:47 +000046
47protected:
rmistry@google.comd6176b02012-08-23 18:14:13 +000048
caryclark@google.comc6825902012-02-03 22:07:47 +000049bool intersect(double minT1, double maxT1, double minT2, double maxT2) {
50 Cubic smaller, larger;
rmistry@google.comd6176b02012-08-23 18:14:13 +000051 // FIXME: carry last subdivide and reduceOrder result with cubic
caryclark@google.comc6825902012-02-03 22:07:47 +000052 sub_divide(cubic1, minT1, maxT1, intersections.swapped() ? larger : smaller);
53 sub_divide(cubic2, minT2, maxT2, intersections.swapped() ? smaller : larger);
54 Cubic smallResult;
55 if (reduceOrder(smaller, smallResult,
56 kReduceOrder_NoQuadraticsAllowed) <= 2) {
57 Cubic largeResult;
58 if (reduceOrder(larger, largeResult,
59 kReduceOrder_NoQuadraticsAllowed) <= 2) {
60 const _Line& smallLine = (const _Line&) smallResult;
61 const _Line& largeLine = (const _Line&) largeResult;
62 double smallT[2];
63 double largeT[2];
64 // FIXME: this doesn't detect or deal with coincident lines
65 if (!::intersect(smallLine, largeLine, smallT, largeT)) {
66 return false;
67 }
68 if (intersections.swapped()) {
rmistry@google.comd6176b02012-08-23 18:14:13 +000069 smallT[0] = interp(minT2, maxT2, smallT[0]);
70 largeT[0] = interp(minT1, maxT1, largeT[0]);
caryclark@google.comc6825902012-02-03 22:07:47 +000071 } else {
rmistry@google.comd6176b02012-08-23 18:14:13 +000072 smallT[0] = interp(minT1, maxT1, smallT[0]);
73 largeT[0] = interp(minT2, maxT2, largeT[0]);
caryclark@google.comc6825902012-02-03 22:07:47 +000074 }
75 intersections.add(smallT[0], largeT[0]);
76 return true;
77 }
78 }
79 double minT, maxT;
80 if (!bezier_clip(smaller, larger, minT, maxT)) {
81 if (minT == maxT) {
82 if (intersections.swapped()) {
83 minT1 = (minT1 + maxT1) / 2;
84 minT2 = interp(minT2, maxT2, minT);
85 } else {
86 minT1 = interp(minT1, maxT1, minT);
87 minT2 = (minT2 + maxT2) / 2;
88 }
89 intersections.add(minT1, minT2);
90 return true;
91 }
92 return false;
93 }
rmistry@google.comd6176b02012-08-23 18:14:13 +000094
caryclark@google.comc6825902012-02-03 22:07:47 +000095 int split;
96 if (intersections.swapped()) {
97 double newMinT1 = interp(minT1, maxT1, minT);
98 double newMaxT1 = interp(minT1, maxT1, maxT);
99 split = (newMaxT1 - newMinT1 > (maxT1 - minT1) * tClipLimit) << 1;
100#define VERBOSE 0
101#if VERBOSE
102 printf("%s d=%d s=%d new1=(%g,%g) old1=(%g,%g) split=%d\n",
103 __FUNCTION__, depth, splits, newMinT1, newMaxT1, minT1, maxT1,
104 split);
105#endif
106 minT1 = newMinT1;
107 maxT1 = newMaxT1;
108 } else {
109 double newMinT2 = interp(minT2, maxT2, minT);
110 double newMaxT2 = interp(minT2, maxT2, maxT);
111 split = newMaxT2 - newMinT2 > (maxT2 - minT2) * tClipLimit;
112#if VERBOSE
113 printf("%s d=%d s=%d new2=(%g,%g) old2=(%g,%g) split=%d\n",
114 __FUNCTION__, depth, splits, newMinT2, newMaxT2, minT2, maxT2,
115 split);
116#endif
117 minT2 = newMinT2;
118 maxT2 = newMaxT2;
119 }
120 return chop(minT1, maxT1, minT2, maxT2, split);
121}
122
123bool chop(double minT1, double maxT1, double minT2, double maxT2, int split) {
124 ++depth;
125 intersections.swap();
126 if (split) {
127 ++splits;
128 if (split & 2) {
129 double middle1 = (maxT1 + minT1) / 2;
130 intersect(minT1, middle1, minT2, maxT2);
131 intersect(middle1, maxT1, minT2, maxT2);
132 } else {
133 double middle2 = (maxT2 + minT2) / 2;
134 intersect(minT1, maxT1, minT2, middle2);
135 intersect(minT1, maxT1, middle2, maxT2);
136 }
137 --splits;
138 intersections.swap();
139 --depth;
140 return intersections.intersected();
141 }
142 bool result = intersect(minT1, maxT1, minT2, maxT2);
143 intersections.swap();
144 --depth;
145 return result;
146}
147
148private:
149
caryclark@google.comc6825902012-02-03 22:07:47 +0000150const Cubic& cubic1;
151const Cubic& cubic2;
152Intersections& intersections;
153int depth;
154int splits;
155};
156
157bool intersect(const Cubic& c1, const Cubic& c2, Intersections& i) {
158 CubicIntersections c(c1, c2, i);
159 return c.intersect();
160}
161