blob: 500a91e0538a3532de7579d32bf65354345cb9e8 [file] [log] [blame]
caryclark@google.comc6825902012-02-03 22:07:47 +00001#include "CurveIntersection.h"
caryclark@google.com27accef2012-01-25 18:57:23 +00002#include "CubicUtilities.h"
3#include "Intersections.h"
4#include "LineUtilities.h"
5
6/*
7Find the interection of a line and cubic by solving for valid t values.
8
9Analogous to line-quadratic intersection, solve line-cubic intersection by
10representing the cubic as:
11 x = a(1-t)^3 + 2b(1-t)^2t + c(1-t)t^2 + dt^3
12 y = e(1-t)^3 + 2f(1-t)^2t + g(1-t)t^2 + ht^3
13and the line as:
14 y = i*x + j (if the line is more horizontal)
15or:
16 x = i*y + j (if the line is more vertical)
17
18Then using Mathematica, solve for the values of t where the cubic intersects the
19line:
20
21 (in) Resultant[
22 a*(1 - t)^3 + 3*b*(1 - t)^2*t + 3*c*(1 - t)*t^2 + d*t^3 - x,
caryclark@google.comc6825902012-02-03 22:07:47 +000023 e*(1 - t)^3 + 3*f*(1 - t)^2*t + 3*g*(1 - t)*t^2 + h*t^3 - i*x - j, x]
caryclark@google.com27accef2012-01-25 18:57:23 +000024 (out) -e + j +
25 3 e t - 3 f t -
26 3 e t^2 + 6 f t^2 - 3 g t^2 +
27 e t^3 - 3 f t^3 + 3 g t^3 - h t^3 +
28 i ( a -
29 3 a t + 3 b t +
30 3 a t^2 - 6 b t^2 + 3 c t^2 -
31 a t^3 + 3 b t^3 - 3 c t^3 + d t^3 )
32
33if i goes to infinity, we can rewrite the line in terms of x. Mathematica:
34
35 (in) Resultant[
36 a*(1 - t)^3 + 3*b*(1 - t)^2*t + 3*c*(1 - t)*t^2 + d*t^3 - i*y - j,
caryclark@google.comc6825902012-02-03 22:07:47 +000037 e*(1 - t)^3 + 3*f*(1 - t)^2*t + 3*g*(1 - t)*t^2 + h*t^3 - y, y]
caryclark@google.com27accef2012-01-25 18:57:23 +000038 (out) a - j -
39 3 a t + 3 b t +
40 3 a t^2 - 6 b t^2 + 3 c t^2 -
41 a t^3 + 3 b t^3 - 3 c t^3 + d t^3 -
42 i ( e -
43 3 e t + 3 f t +
44 3 e t^2 - 6 f t^2 + 3 g t^2 -
45 e t^3 + 3 f t^3 - 3 g t^3 + h t^3 )
46
47Solving this with Mathematica produces an expression with hundreds of terms;
48instead, use Numeric Solutions recipe to solve the cubic.
49
50The near-horizontal case, in terms of: Ax^3 + Bx^2 + Cx + D == 0
51 A = (-(-e + 3*f - 3*g + h) + i*(-a + 3*b - 3*c + d) )
52 B = 3*(-( e - 2*f + g ) + i*( a - 2*b + c ) )
53 C = 3*(-(-e + f ) + i*(-a + b ) )
54 D = (-( e ) + i*( a ) + j )
55
56The near-vertical case, in terms of: Ax^3 + Bx^2 + Cx + D == 0
57 A = ( (-a + 3*b - 3*c + d) - i*(-e + 3*f - 3*g + h) )
58 B = 3*( ( a - 2*b + c ) - i*( e - 2*f + g ) )
59 C = 3*( (-a + b ) - i*(-e + f ) )
60 D = ( ( a ) - i*( e ) - j )
caryclark@google.comc6825902012-02-03 22:07:47 +000061
62For horizontal lines:
63(in) Resultant[
64 a*(1 - t)^3 + 3*b*(1 - t)^2*t + 3*c*(1 - t)*t^2 + d*t^3 - j,
65 e*(1 - t)^3 + 3*f*(1 - t)^2*t + 3*g*(1 - t)*t^2 + h*t^3 - y, y]
66(out) e - j -
67 3 e t + 3 f t +
68 3 e t^2 - 6 f t^2 + 3 g t^2 -
69 e t^3 + 3 f t^3 - 3 g t^3 + h t^3
70So the cubic coefficients are:
71
caryclark@google.com27accef2012-01-25 18:57:23 +000072 */
73
74class LineCubicIntersections : public Intersections {
75public:
76
caryclark@google.comc6825902012-02-03 22:07:47 +000077LineCubicIntersections(const Cubic& c, const _Line& l, double r[3])
caryclark@google.com27accef2012-01-25 18:57:23 +000078 : cubic(c)
79 , line(l)
caryclark@google.comc6825902012-02-03 22:07:47 +000080 , range(r) {
caryclark@google.com27accef2012-01-25 18:57:23 +000081}
82
caryclark@google.comc6825902012-02-03 22:07:47 +000083int intersect() {
caryclark@google.com27accef2012-01-25 18:57:23 +000084 double slope;
85 double axisIntercept;
86 moreHorizontal = implicitLine(line, slope, axisIntercept);
caryclark@google.comc6825902012-02-03 22:07:47 +000087 double A, B, C, D;
88 coefficients(&cubic[0].x, A, B, C, D);
89 double E, F, G, H;
90 coefficients(&cubic[0].y, E, F, G, H);
caryclark@google.com27accef2012-01-25 18:57:23 +000091 if (moreHorizontal) {
92 A = A * slope - E;
93 B = B * slope - F;
94 C = C * slope - G;
95 D = D * slope - H + axisIntercept;
96 } else {
97 A = A - E * slope;
98 B = B - F * slope;
99 C = C - G * slope;
100 D = D - H * slope - axisIntercept;
101 }
caryclark@google.comc6825902012-02-03 22:07:47 +0000102 return cubicRoots(A, B, C, D, range);
caryclark@google.com27accef2012-01-25 18:57:23 +0000103}
104
caryclark@google.comc6825902012-02-03 22:07:47 +0000105int horizontalIntersect(double axisIntercept) {
106 double A, B, C, D;
107 coefficients(&cubic[0].y, A, B, C, D);
108 D -= axisIntercept;
109 return cubicRoots(A, B, C, D, range);
110}
111
caryclark@google.com27accef2012-01-25 18:57:23 +0000112double findLineT(double t) {
113 const double* cPtr;
114 const double* lPtr;
115 if (moreHorizontal) {
116 cPtr = &cubic[0].x;
117 lPtr = &line[0].x;
118 } else {
119 cPtr = &cubic[0].y;
120 lPtr = &line[0].y;
121 }
caryclark@google.comc6825902012-02-03 22:07:47 +0000122 // FIXME: should fold the following in with TestUtilities.cpp xy_at_t()
caryclark@google.com27accef2012-01-25 18:57:23 +0000123 double s = 1 - t;
124 double cubicVal = cPtr[0] * s * s * s + 3 * cPtr[2] * s * s * t
125 + 3 * cPtr[4] * s * t * t + cPtr[6] * t * t * t;
126 return (cubicVal - lPtr[0]) / (lPtr[2] - lPtr[0]);
127}
128
129private:
130
131const Cubic& cubic;
132const _Line& line;
caryclark@google.comc6825902012-02-03 22:07:47 +0000133double* range;
caryclark@google.com27accef2012-01-25 18:57:23 +0000134bool moreHorizontal;
135
136};
caryclark@google.comc6825902012-02-03 22:07:47 +0000137
138int horizontalIntersect(const Cubic& cubic, double y, double tRange[3]) {
139 LineCubicIntersections c(cubic, *((_Line*) 0), tRange);
140 return c.horizontalIntersect(y);
141}
caryclark@google.com27accef2012-01-25 18:57:23 +0000142
caryclark@google.comc6825902012-02-03 22:07:47 +0000143int intersect(const Cubic& cubic, const _Line& line, double cRange[3], double lRange[3]) {
144 LineCubicIntersections c(cubic, line, cRange);
145 int roots;
146 if (approximately_equal(line[0].y, line[1].y)) {
147 roots = c.horizontalIntersect(line[0].y);
148 } else {
149 roots = c.intersect();
150 }
151 for (int index = 0; index < roots; ++index) {
152 lRange[index] = c.findLineT(cRange[index]);
153 }
154 return roots;
caryclark@google.com27accef2012-01-25 18:57:23 +0000155}