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