blob: ab552e01fc8b84ed152344dc502229b7ecbd6e72 [file] [log] [blame]
caryclark@google.com639df892012-01-10 21:46:10 +00001#include "CubicIntersection.h"
2#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) {
50 _Point pt;
51 const _Line& smallLine = (const _Line&) smallResult;
52 const _Line& largeLine = (const _Line&) largeResult;
53 if (!lineIntersect(smallLine, largeLine, &pt)) {
54 return false;
55 }
56 double smallT = t_at(smallLine, pt);
57 double largeT = t_at(largeLine, pt);
58 if (intersections.swapped()) {
59 smallT = interp(minT2, maxT2, smallT);
60 largeT = interp(minT1, maxT1, largeT);
61 } else {
62 smallT = interp(minT1, maxT1, smallT);
63 largeT = interp(minT2, maxT2, largeT);
64 }
65 intersections.add(smallT, largeT);
66 return true;
67 }
68 }
69 double minT, maxT;
70 if (!bezier_clip(smaller, larger, minT, maxT)) {
71 if (minT == maxT) {
72 if (intersections.swapped()) {
73 minT1 = (minT1 + maxT1) / 2;
74 minT2 = interp(minT2, maxT2, minT);
75 } else {
76 minT1 = interp(minT1, maxT1, minT);
77 minT2 = (minT2 + maxT2) / 2;
78 }
79 intersections.add(minT1, minT2);
80 return true;
81 }
82 return false;
83 }
84
85 int split;
86 if (intersections.swapped()) {
87 double newMinT1 = interp(minT1, maxT1, minT);
88 double newMaxT1 = interp(minT1, maxT1, maxT);
89 split = (newMaxT1 - newMinT1 > (maxT1 - minT1) * tClipLimit) << 1;
90 printf("%s d=%d s=%d new1=(%g,%g) old1=(%g,%g) split=%d\n", __FUNCTION__, depth,
91 splits, newMinT1, newMaxT1, minT1, maxT1, split);
92 minT1 = newMinT1;
93 maxT1 = newMaxT1;
94 } else {
95 double newMinT2 = interp(minT2, maxT2, minT);
96 double newMaxT2 = interp(minT2, maxT2, maxT);
97 split = newMaxT2 - newMinT2 > (maxT2 - minT2) * tClipLimit;
98 printf("%s d=%d s=%d new2=(%g,%g) old2=(%g,%g) split=%d\n", __FUNCTION__, depth,
99 splits, newMinT2, newMaxT2, minT2, maxT2, split);
100 minT2 = newMinT2;
101 maxT2 = newMaxT2;
102 }
103 return chop(minT1, maxT1, minT2, maxT2, split);
104}
105
106bool chop(double minT1, double maxT1, double minT2, double maxT2, int split) {
107 ++depth;
108 intersections.swap();
109 if (split) {
110 ++splits;
111 if (split & 2) {
112 double middle1 = (maxT1 + minT1) / 2;
113 intersect(minT1, middle1, minT2, maxT2);
114 intersect(middle1, maxT1, minT2, maxT2);
115 } else {
116 double middle2 = (maxT2 + minT2) / 2;
117 intersect(minT1, maxT1, minT2, middle2);
118 intersect(minT1, maxT1, middle2, maxT2);
119 }
120 --splits;
121 intersections.swap();
122 --depth;
123 return intersections.intersected();
124 }
125 bool result = intersect(minT1, maxT1, minT2, maxT2);
126 intersections.swap();
127 --depth;
128 return result;
129}
130
131private:
132
133static const double tClipLimit = 0.8; // http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf see Multiple intersections
134const Quadratic& quad1;
135const Quadratic& quad2;
136Intersections& intersections;
137int depth;
138int splits;
139};
140
141bool intersectStart(const Quadratic& q1, const Quadratic& q2, Intersections& i) {
142 QuadraticIntersections q(q1, q2, i);
143 return q.intersect();
144}
145
146
147// Another approach is to start with the implicit form of one curve and solve
148// by substituting in the parametric form of the other.
149// The downside of this approach is that early rejects are difficult to come by.
150// http://planetmath.org/encyclopedia/GaloisTheoreticDerivationOfTheQuarticFormula.html#step
151/*
152given x^4 + ax^3 + bx^2 + cx + d
153the resolvent cubic is x^3 - 2bx^2 + (b^2 + ac - 4d)x + (c^2 + a^2d - abc)
154use the cubic formula (CubicRoots.cpp) to find the radical expressions t1, t2, and t3.
155
156(x - r1 r2) (x - r3 r4) = x^2 - (t2 + t3 - t1) / 2 x + d
157s = r1*r2 = ((t2 + t3 - t1) + sqrt((t2 + t3 - t1)^2 - 16*d)) / 4
158t = r3*r4 = ((t2 + t3 - t1) - sqrt((t2 + t3 - t1)^2 - 16*d)) / 4
159
160u = r1+r2 = (-a + sqrt(a^2 - 4*t1)) / 2
161v = r3+r4 = (-a - sqrt(a^2 - 4*t1)) / 2
162
163r1 = (u + sqrt(u^2 - 4*s)) / 2
164r2 = (u - sqrt(u^2 - 4*s)) / 2
165r3 = (v + sqrt(v^2 - 4*t)) / 2
166r4 = (v - sqrt(v^2 - 4*t)) / 2
167*/
168
169
170/* square root of complex number
171http://en.wikipedia.org/wiki/Square_root#Square_roots_of_negative_and_complex_numbers
172Algebraic formula
173When the number is expressed using Cartesian coordinates the following formula
174 can be used for the principal square root:[5][6]
175
176sqrt(x + iy) = sqrt((r + x) / 2) +/- i*sqrt((r - x) / 2)
177
178where the sign of the imaginary part of the root is taken to be same as the sign
179 of the imaginary part of the original number, and
180
181r = abs(x + iy) = sqrt(x^2 + y^2)
182
183is the absolute value or modulus of the original number. The real part of the
184principal value is always non-negative.
185The other square root is simply –1 times the principal square root; in other
186words, the two square roots of a number sum to 0.
187 */