blob: f8c43b5e5d57d25a551de07bc28e67fd3a64ea2e [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#define VERBOSE 0
101#if VERBOSE
caryclark@google.com639df892012-01-10 21:46:10 +0000102 printf("%s d=%d s=%d new2=(%g,%g) old2=(%g,%g) split=%d\n", __FUNCTION__, depth,
103 splits, newMinT2, newMaxT2, minT2, maxT2, split);
caryclark@google.com198e0542012-03-30 18:47:02 +0000104#endif
caryclark@google.com639df892012-01-10 21:46:10 +0000105 minT2 = newMinT2;
106 maxT2 = newMaxT2;
107 }
108 return chop(minT1, maxT1, minT2, maxT2, split);
109}
110
111bool chop(double minT1, double maxT1, double minT2, double maxT2, int split) {
112 ++depth;
113 intersections.swap();
114 if (split) {
115 ++splits;
116 if (split & 2) {
117 double middle1 = (maxT1 + minT1) / 2;
118 intersect(minT1, middle1, minT2, maxT2);
119 intersect(middle1, maxT1, minT2, maxT2);
120 } else {
121 double middle2 = (maxT2 + minT2) / 2;
122 intersect(minT1, maxT1, minT2, middle2);
123 intersect(minT1, maxT1, middle2, maxT2);
124 }
125 --splits;
126 intersections.swap();
127 --depth;
128 return intersections.intersected();
129 }
130 bool result = intersect(minT1, maxT1, minT2, maxT2);
131 intersections.swap();
132 --depth;
133 return result;
134}
135
136private:
137
138static const double tClipLimit = 0.8; // http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf see Multiple intersections
139const Quadratic& quad1;
140const Quadratic& quad2;
141Intersections& intersections;
142int depth;
143int splits;
144};
145
caryclark@google.comc6825902012-02-03 22:07:47 +0000146bool intersect(const Quadratic& q1, const Quadratic& q2, Intersections& i) {
caryclark@google.com639df892012-01-10 21:46:10 +0000147 QuadraticIntersections q(q1, q2, i);
148 return q.intersect();
149}
150
151
152// Another approach is to start with the implicit form of one curve and solve
153// by substituting in the parametric form of the other.
154// The downside of this approach is that early rejects are difficult to come by.
155// http://planetmath.org/encyclopedia/GaloisTheoreticDerivationOfTheQuarticFormula.html#step
156/*
157given x^4 + ax^3 + bx^2 + cx + d
158the resolvent cubic is x^3 - 2bx^2 + (b^2 + ac - 4d)x + (c^2 + a^2d - abc)
159use the cubic formula (CubicRoots.cpp) to find the radical expressions t1, t2, and t3.
160
161(x - r1 r2) (x - r3 r4) = x^2 - (t2 + t3 - t1) / 2 x + d
162s = r1*r2 = ((t2 + t3 - t1) + sqrt((t2 + t3 - t1)^2 - 16*d)) / 4
163t = r3*r4 = ((t2 + t3 - t1) - sqrt((t2 + t3 - t1)^2 - 16*d)) / 4
164
165u = r1+r2 = (-a + sqrt(a^2 - 4*t1)) / 2
166v = r3+r4 = (-a - sqrt(a^2 - 4*t1)) / 2
167
168r1 = (u + sqrt(u^2 - 4*s)) / 2
169r2 = (u - sqrt(u^2 - 4*s)) / 2
170r3 = (v + sqrt(v^2 - 4*t)) / 2
171r4 = (v - sqrt(v^2 - 4*t)) / 2
172*/
173
174
175/* square root of complex number
176http://en.wikipedia.org/wiki/Square_root#Square_roots_of_negative_and_complex_numbers
177Algebraic formula
178When the number is expressed using Cartesian coordinates the following formula
179 can be used for the principal square root:[5][6]
180
181sqrt(x + iy) = sqrt((r + x) / 2) +/- i*sqrt((r - x) / 2)
182
183where the sign of the imaginary part of the root is taken to be same as the sign
184 of the imaginary part of the original number, and
185
186r = abs(x + iy) = sqrt(x^2 + y^2)
187
188is the absolute value or modulus of the original number. The real part of the
189principal value is always non-negative.
190The other square root is simply –1 times the principal square root; in other
191words, the two square roots of a number sum to 0.
192 */