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