blob: a8e87ef6ea7d032ad4497f66cfbe2fe9d03bc947 [file] [log] [blame]
caryclark@google.comc6825902012-02-03 22:07:47 +00001#include "CurveIntersection.h"
caryclark@google.com639df892012-01-10 21:46:10 +00002#include "Intersections.h"
3#include "IntersectionUtilities.h"
4#include "LineIntersection.h"
5
6class QuadraticIntersections : public Intersections {
7public:
8
9QuadraticIntersections(const Quadratic& q1, const Quadratic& q2, Intersections& i)
10 : quad1(q1)
11 , quad2(q2)
12 , intersections(i)
13 , depth(0)
14 , splits(0) {
15}
16
17bool intersect() {
18 double minT1, minT2, maxT1, maxT2;
19 if (!bezier_clip(quad2, quad1, minT1, maxT1)) {
20 return false;
21 }
22 if (!bezier_clip(quad1, quad2, minT2, maxT2)) {
23 return false;
24 }
25 int split;
26 if (maxT1 - minT1 < maxT2 - minT2) {
27 intersections.swap();
28 minT2 = 0;
29 maxT2 = 1;
30 split = maxT1 - minT1 > tClipLimit;
31 } else {
32 minT1 = 0;
33 maxT1 = 1;
34 split = (maxT2 - minT2 > tClipLimit) << 1;
35 }
36 return chop(minT1, maxT1, minT2, maxT2, split);
37}
38
39protected:
40
41bool intersect(double minT1, double maxT1, double minT2, double maxT2) {
42 Quadratic smaller, larger;
43 // FIXME: carry last subdivide and reduceOrder result with quad
44 sub_divide(quad1, minT1, maxT1, intersections.swapped() ? larger : smaller);
45 sub_divide(quad2, minT2, maxT2, intersections.swapped() ? smaller : larger);
46 Quadratic smallResult;
47 if (reduceOrder(smaller, smallResult) <= 2) {
48 Quadratic largeResult;
49 if (reduceOrder(larger, largeResult) <= 2) {
caryclark@google.comc6825902012-02-03 22:07:47 +000050 double smallT[2], largeT[2];
caryclark@google.com639df892012-01-10 21:46:10 +000051 const _Line& smallLine = (const _Line&) smallResult;
52 const _Line& largeLine = (const _Line&) largeResult;
caryclark@google.comc6825902012-02-03 22:07:47 +000053 // FIXME: this doesn't detect or deal with coincident lines
54 if (!::intersect(smallLine, largeLine, smallT, largeT)) {
caryclark@google.com639df892012-01-10 21:46:10 +000055 return false;
56 }
caryclark@google.com639df892012-01-10 21:46:10 +000057 if (intersections.swapped()) {
caryclark@google.comc6825902012-02-03 22:07:47 +000058 smallT[0] = interp(minT2, maxT2, smallT[0]);
59 largeT[0] = interp(minT1, maxT1, largeT[0]);
caryclark@google.com639df892012-01-10 21:46:10 +000060 } else {
caryclark@google.comc6825902012-02-03 22:07:47 +000061 smallT[0] = interp(minT1, maxT1, smallT[0]);
62 largeT[0] = interp(minT2, maxT2, largeT[0]);
caryclark@google.com639df892012-01-10 21:46:10 +000063 }
caryclark@google.comc6825902012-02-03 22:07:47 +000064 intersections.add(smallT[0], largeT[0]);
caryclark@google.com639df892012-01-10 21:46:10 +000065 return true;
66 }
67 }
68 double minT, maxT;
69 if (!bezier_clip(smaller, larger, minT, maxT)) {
70 if (minT == maxT) {
71 if (intersections.swapped()) {
72 minT1 = (minT1 + maxT1) / 2;
73 minT2 = interp(minT2, maxT2, minT);
74 } else {
75 minT1 = interp(minT1, maxT1, minT);
76 minT2 = (minT2 + maxT2) / 2;
77 }
78 intersections.add(minT1, minT2);
79 return true;
80 }
81 return false;
82 }
83
84 int split;
85 if (intersections.swapped()) {
86 double newMinT1 = interp(minT1, maxT1, minT);
87 double newMaxT1 = interp(minT1, maxT1, maxT);
88 split = (newMaxT1 - newMinT1 > (maxT1 - minT1) * tClipLimit) << 1;
caryclark@google.com198e0542012-03-30 18:47:02 +000089#define VERBOSE 0
90#if VERBOSE
caryclark@google.com639df892012-01-10 21:46:10 +000091 printf("%s d=%d s=%d new1=(%g,%g) old1=(%g,%g) split=%d\n", __FUNCTION__, depth,
92 splits, newMinT1, newMaxT1, minT1, maxT1, split);
caryclark@google.com198e0542012-03-30 18:47:02 +000093#endif
caryclark@google.com639df892012-01-10 21:46:10 +000094 minT1 = newMinT1;
95 maxT1 = newMaxT1;
96 } else {
97 double newMinT2 = interp(minT2, maxT2, minT);
98 double newMaxT2 = interp(minT2, maxT2, maxT);
99 split = newMaxT2 - newMinT2 > (maxT2 - minT2) * tClipLimit;
caryclark@google.com198e0542012-03-30 18:47:02 +0000100#if VERBOSE
caryclark@google.com639df892012-01-10 21:46:10 +0000101 printf("%s d=%d s=%d new2=(%g,%g) old2=(%g,%g) split=%d\n", __FUNCTION__, depth,
102 splits, newMinT2, newMaxT2, minT2, maxT2, split);
caryclark@google.com198e0542012-03-30 18:47:02 +0000103#endif
caryclark@google.com639df892012-01-10 21:46:10 +0000104 minT2 = newMinT2;
105 maxT2 = newMaxT2;
106 }
107 return chop(minT1, maxT1, minT2, maxT2, split);
108}
109
110bool chop(double minT1, double maxT1, double minT2, double maxT2, int split) {
111 ++depth;
112 intersections.swap();
113 if (split) {
114 ++splits;
115 if (split & 2) {
116 double middle1 = (maxT1 + minT1) / 2;
117 intersect(minT1, middle1, minT2, maxT2);
118 intersect(middle1, maxT1, minT2, maxT2);
119 } else {
120 double middle2 = (maxT2 + minT2) / 2;
121 intersect(minT1, maxT1, minT2, middle2);
122 intersect(minT1, maxT1, middle2, maxT2);
123 }
124 --splits;
125 intersections.swap();
126 --depth;
127 return intersections.intersected();
128 }
129 bool result = intersect(minT1, maxT1, minT2, maxT2);
130 intersections.swap();
131 --depth;
132 return result;
133}
134
135private:
136
137static const double tClipLimit = 0.8; // http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf see Multiple intersections
138const Quadratic& quad1;
139const Quadratic& quad2;
140Intersections& intersections;
141int depth;
142int splits;
143};
144
caryclark@google.comc6825902012-02-03 22:07:47 +0000145bool intersect(const Quadratic& q1, const Quadratic& q2, Intersections& i) {
caryclark@google.comfa0588f2012-04-26 21:01:06 +0000146 if (implicit_matches(q1, q2)) {
147 // FIXME: compute T values
148 // compute the intersections of the ends to find the coincident span
149 bool useVertical = fabs(q1[0].x - q1[2].x) < fabs(q1[0].y - q1[2].y);
150 double t;
151 if ((t = axialIntersect(q1, q2[0], useVertical)) >= 0) {
152 i.fT[0][0] = t;
153 i.fT[1][0] = 0;
154 i.fUsed++;
155 }
156 if ((t = axialIntersect(q1, q2[2], useVertical)) >= 0) {
157 i.fT[0][i.fUsed] = t;
158 i.fT[1][i.fUsed] = 1;
159 i.fUsed++;
160 }
161 useVertical = fabs(q2[0].x - q2[2].x) < fabs(q2[0].y - q2[2].y);
162 if ((t = axialIntersect(q2, q1[0], useVertical)) >= 0) {
163 i.fT[0][i.fUsed] = 0;
164 i.fT[1][i.fUsed] = t;
165 i.fUsed++;
166 }
167 if ((t = axialIntersect(q2, q1[2], useVertical)) >= 0) {
168 i.fT[0][i.fUsed] = 1;
169 i.fT[1][i.fUsed] = t;
170 i.fUsed++;
171 }
172 assert(i.fUsed <= 2);
173 return i.fUsed > 0;
174 }
caryclark@google.com639df892012-01-10 21:46:10 +0000175 QuadraticIntersections q(q1, q2, i);
176 return q.intersect();
177}
178
179
180// Another approach is to start with the implicit form of one curve and solve
181// by substituting in the parametric form of the other.
182// The downside of this approach is that early rejects are difficult to come by.
183// http://planetmath.org/encyclopedia/GaloisTheoreticDerivationOfTheQuarticFormula.html#step
184/*
185given x^4 + ax^3 + bx^2 + cx + d
186the resolvent cubic is x^3 - 2bx^2 + (b^2 + ac - 4d)x + (c^2 + a^2d - abc)
187use the cubic formula (CubicRoots.cpp) to find the radical expressions t1, t2, and t3.
188
189(x - r1 r2) (x - r3 r4) = x^2 - (t2 + t3 - t1) / 2 x + d
190s = r1*r2 = ((t2 + t3 - t1) + sqrt((t2 + t3 - t1)^2 - 16*d)) / 4
191t = r3*r4 = ((t2 + t3 - t1) - sqrt((t2 + t3 - t1)^2 - 16*d)) / 4
192
193u = r1+r2 = (-a + sqrt(a^2 - 4*t1)) / 2
194v = r3+r4 = (-a - sqrt(a^2 - 4*t1)) / 2
195
196r1 = (u + sqrt(u^2 - 4*s)) / 2
197r2 = (u - sqrt(u^2 - 4*s)) / 2
198r3 = (v + sqrt(v^2 - 4*t)) / 2
199r4 = (v - sqrt(v^2 - 4*t)) / 2
200*/
201
202
203/* square root of complex number
204http://en.wikipedia.org/wiki/Square_root#Square_roots_of_negative_and_complex_numbers
205Algebraic formula
206When the number is expressed using Cartesian coordinates the following formula
207 can be used for the principal square root:[5][6]
208
209sqrt(x + iy) = sqrt((r + x) / 2) +/- i*sqrt((r - x) / 2)
210
211where the sign of the imaginary part of the root is taken to be same as the sign
212 of the imaginary part of the original number, and
213
214r = abs(x + iy) = sqrt(x^2 + y^2)
215
216is the absolute value or modulus of the original number. The real part of the
217principal value is always non-negative.
218The other square root is simply –1 times the principal square root; in other
219words, the two square roots of a number sum to 0.
220 */