19e49fb63d355446b91d20ff78ad78b297e89a50dcaryclark@google.com/*
29e49fb63d355446b91d20ff78ad78b297e89a50dcaryclark@google.com * Copyright 2012 Google Inc.
39e49fb63d355446b91d20ff78ad78b297e89a50dcaryclark@google.com *
49e49fb63d355446b91d20ff78ad78b297e89a50dcaryclark@google.com * Use of this source code is governed by a BSD-style license that can be
59e49fb63d355446b91d20ff78ad78b297e89a50dcaryclark@google.com * found in the LICENSE file.
69e49fb63d355446b91d20ff78ad78b297e89a50dcaryclark@google.com */
7c682590538a27d73489bc91c098e000fdfb07ccfcaryclark@google.com#include "CurveIntersection.h"
827accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com#include "Intersections.h"
927accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com#include "LineUtilities.h"
1027accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com#include "QuadraticUtilities.h"
1127accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
12d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com/*
1327accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comFind the interection of a line and quadratic by solving for valid t values.
1427accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
1527accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comFrom http://stackoverflow.com/questions/1853637/how-to-find-the-mathematical-function-defining-a-bezier-curve
1627accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
17d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com"A Bezier curve is a parametric function. A quadratic Bezier curve (i.e. three
18d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.comcontrol points) can be expressed as: F(t) = A(1 - t)^2 + B(1 - t)t + Ct^2 where
1927accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comA, B and C are points and t goes from zero to one.
2027accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
2127accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comThis will give you two equations:
2227accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
2327accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com  x = a(1 - t)^2 + b(1 - t)t + ct^2
2427accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com  y = d(1 - t)^2 + e(1 - t)t + ft^2
2527accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
26d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.comIf you add for instance the line equation (y = kx + m) to that, you'll end up
2727accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comwith three equations and three unknowns (x, y and t)."
2827accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
2927accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comSimilar to above, the quadratic is represented as
3027accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com  x = a(1-t)^2 + 2b(1-t)t + ct^2
3127accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com  y = d(1-t)^2 + 2e(1-t)t + ft^2
3227accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comand the line as
3327accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com  y = g*x + h
3427accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
3527accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comUsing Mathematica, solve for the values of t where the quadratic intersects the
3627accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comline:
3727accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
38d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com  (in)  t1 = Resultant[a*(1 - t)^2 + 2*b*(1 - t)*t + c*t^2 - x,
3927accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com                       d*(1 - t)^2 + 2*e*(1 - t)*t  + f*t^2 - g*x - h, x]
40d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com  (out) -d + h + 2 d t - 2 e t - d t^2 + 2 e t^2 - f t^2 +
4127accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com         g  (a - 2 a t + 2 b t + a t^2 - 2 b t^2 + c t^2)
4227accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com  (in)  Solve[t1 == 0, t]
4327accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com  (out) {
4427accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com    {t -> (-2 d + 2 e +   2 a g - 2 b g    -
45d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com      Sqrt[(2 d - 2 e -   2 a g + 2 b g)^2 -
4627accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com          4 (-d + 2 e - f + a g - 2 b g    + c g) (-d + a g + h)]) /
4727accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com         (2 (-d + 2 e - f + a g - 2 b g    + c g))
4827accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com         },
4927accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com    {t -> (-2 d + 2 e +   2 a g - 2 b g    +
50d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com      Sqrt[(2 d - 2 e -   2 a g + 2 b g)^2 -
5127accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com          4 (-d + 2 e - f + a g - 2 b g    + c g) (-d + a g + h)]) /
5227accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com         (2 (-d + 2 e - f + a g - 2 b g    + c g))
5327accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com         }
5427accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com        }
55d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
5627accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comUsing the results above (when the line tends towards horizontal)
5727accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com       A =   (-(d - 2*e + f) + g*(a - 2*b + c)     )
5827accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com       B = 2*( (d -   e    ) - g*(a -   b    )     )
5927accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com       C =   (-(d          ) + g*(a          ) + h )
6027accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
6127accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comIf g goes to infinity, we can rewrite the line in terms of x.
6227accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com  x = g'*y + h'
6327accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
6427accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comAnd solve accordingly in Mathematica:
6527accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
66d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com  (in)  t2 = Resultant[a*(1 - t)^2 + 2*b*(1 - t)*t + c*t^2 - g'*y - h',
6727accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com                       d*(1 - t)^2 + 2*e*(1 - t)*t  + f*t^2 - y, y]
68d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com  (out)  a - h' - 2 a t + 2 b t + a t^2 - 2 b t^2 + c t^2 -
6927accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com         g'  (d - 2 d t + 2 e t + d t^2 - 2 e t^2 + f t^2)
7027accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com  (in)  Solve[t2 == 0, t]
7127accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com  (out) {
7227accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com    {t -> (2 a - 2 b -   2 d g' + 2 e g'    -
73d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    Sqrt[(-2 a + 2 b +   2 d g' - 2 e g')^2 -
7427accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com          4 (a - 2 b + c - d g' + 2 e g' - f g') (a - d g' - h')]) /
7527accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com         (2 (a - 2 b + c - d g' + 2 e g' - f g'))
7627accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com         },
7727accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com    {t -> (2 a - 2 b -   2 d g' + 2 e g'    +
78d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    Sqrt[(-2 a + 2 b +   2 d g' - 2 e g')^2 -
7927accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com          4 (a - 2 b + c - d g' + 2 e g' - f g') (a - d g' - h')])/
8027accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com         (2 (a - 2 b + c - d g' + 2 e g' - f g'))
8127accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com         }
8227accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com        }
8327accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
8427accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comThus, if the slope of the line tends towards vertical, we use:
8527accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com       A =   ( (a - 2*b + c) - g'*(d  - 2*e + f)      )
8627accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com       B = 2*(-(a -   b    ) + g'*(d  -   e    )      )
8727accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com       C =   ( (a          ) - g'*(d           ) - h' )
8827accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com */
89d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
9027accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
91fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.comclass LineQuadraticIntersections {
9227accef223a27fba437f5e825d99edbae20a045bcaryclark@google.compublic:
9327accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
9427accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comLineQuadraticIntersections(const Quadratic& q, const _Line& l, Intersections& i)
9527accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com    : quad(q)
9627accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com    , line(l)
9727accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com    , intersections(i) {
9827accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com}
9927accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
100fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.comint intersectRay(double roots[2]) {
1013350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com/*
1023350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    solve by rotating line+quad so line is horizontal, then finding the roots
1033350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    set up matrix to rotate quad to x-axis
1043350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    |cos(a) -sin(a)|
1053350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    |sin(a)  cos(a)|
1063350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    note that cos(a) = A(djacent) / Hypoteneuse
1073350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com              sin(a) = O(pposite) / Hypoteneuse
1083350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    since we are computing Ts, we can ignore hypoteneuse, the scale factor:
1093350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    |  A     -O    |
1103350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    |  O      A    |
1113350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    A = line[1].x - line[0].x (adjacent side of the right triangle)
1123350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    O = line[1].y - line[0].y (opposite side of the right triangle)
1133350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    for each of the three points (e.g. n = 0 to 2)
1143350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    quad[n].y' = (quad[n].y - line[0].y) * A - (quad[n].x - line[0].x) * O
1153350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com*/
1163350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    double adj = line[1].x - line[0].x;
1173350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    double opp = line[1].y - line[0].y;
1183350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    double r[3];
1193350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    for (int n = 0; n < 3; ++n) {
1203350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        r[n] = (quad[n].y - line[0].y) * adj - (quad[n].x - line[0].x) * opp;
12127accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com    }
1223350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    double A = r[2];
1233350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    double B = r[1];
1243350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    double C = r[0];
1253350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    A += C - 2 * B; // A = a - 2*b + c
1263350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    B -= C; // B = -(b - c)
1279f60291c5375457f8adf228dbe6e8ff1186b13e1caryclark@google.com    return quadraticRootsValidT(A, 2 * B, C, roots);
128235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com}
129235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
130235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.comint intersect() {
131fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    addEndPoints();
132fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    double rootVals[2];
133fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    int roots = intersectRay(rootVals);
134fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    for (int index = 0; index < roots; ++index) {
135fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        double quadT = rootVals[index];
136fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        double lineT = findLineT(quadT);
137fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        if (pinTs(quadT, lineT)) {
13845a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com            _Point pt;
13945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com            xy_at_t(line, lineT, pt.x, pt.y);
14045a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com            intersections.insert(quadT, lineT, pt);
14124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        }
14224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    }
143fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    return intersections.fUsed;
14427accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com}
14527accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
146fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.comint horizontalIntersect(double axisIntercept, double roots[2]) {
147198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    double D = quad[2].y; // f
148198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    double E = quad[1].y; // e
149198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    double F = quad[0].y; // d
150198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    D += F - 2 * E; // D = d - 2*e + f
151198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    E -= F; // E = -(d - e)
152198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    F -= axisIntercept;
1539f60291c5375457f8adf228dbe6e8ff1186b13e1caryclark@google.com    return quadraticRootsValidT(D, 2 * E, F, roots);
154198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com}
155198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
156fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.comint horizontalIntersect(double axisIntercept, double left, double right, bool flipped) {
157fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    addHorizontalEndPoints(left, right, axisIntercept);
158fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    double rootVals[2];
159fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    int roots = horizontalIntersect(axisIntercept, rootVals);
160fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    for (int index = 0; index < roots; ++index) {
16145a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        _Point pt;
162fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        double quadT = rootVals[index];
16345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        xy_at_t(quad, quadT, pt.x, pt.y);
16445a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        double lineT = (pt.x - left) / (right - left);
165fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        if (pinTs(quadT, lineT)) {
16645a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com            intersections.insert(quadT, lineT, pt);
1673350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        }
1683350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    }
169fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    if (flipped) {
170fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        flip();
171fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    }
172fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    return intersections.fUsed;
1733350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com}
1743350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com
175fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.comint verticalIntersect(double axisIntercept, double roots[2]) {
176fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    double D = quad[2].x; // f
177fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    double E = quad[1].x; // e
178fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    double F = quad[0].x; // d
179fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    D += F - 2 * E; // D = d - 2*e + f
180fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    E -= F; // E = -(d - e)
181fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    F -= axisIntercept;
1829f60291c5375457f8adf228dbe6e8ff1186b13e1caryclark@google.com    return quadraticRootsValidT(D, 2 * E, F, roots);
183fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
184fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
185fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.comint verticalIntersect(double axisIntercept, double top, double bottom, bool flipped) {
186fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    addVerticalEndPoints(top, bottom, axisIntercept);
187fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    double rootVals[2];
188fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    int roots = verticalIntersect(axisIntercept, rootVals);
189fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    for (int index = 0; index < roots; ++index) {
19045a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        _Point pt;
191fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        double quadT = rootVals[index];
19245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        xy_at_t(quad, quadT, pt.x, pt.y);
19345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com        double lineT = (pt.y - top) / (bottom - top);
194fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        if (pinTs(quadT, lineT)) {
19545a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com            intersections.insert(quadT, lineT, pt);
1963350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        }
1973350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    }
198fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    if (flipped) {
199fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        flip();
200fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    }
201fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    return intersections.fUsed;
2023350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com}
2033350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com
20427accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comprotected:
205d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
206fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com// add endpoints first to get zero and one t values exactly
207fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.comvoid addEndPoints()
208fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com{
209fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    for (int qIndex = 0; qIndex < 3; qIndex += 2) {
210fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        for (int lIndex = 0; lIndex < 2; lIndex++) {
211fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com            if (quad[qIndex] == line[lIndex]) {
21245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com                intersections.insert(qIndex >> 1, lIndex, line[lIndex]);
213fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com            }
214fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        }
215fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    }
216fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com}
217fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com
218fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.comvoid addHorizontalEndPoints(double left, double right, double y)
219fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com{
220fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    for (int qIndex = 0; qIndex < 3; qIndex += 2) {
221fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        if (quad[qIndex].y != y) {
222fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com            continue;
223fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        }
224fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        if (quad[qIndex].x == left) {
22545a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com            intersections.insert(qIndex >> 1, 0, quad[qIndex]);
226fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        }
227fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        if (quad[qIndex].x == right) {
22845a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com            intersections.insert(qIndex >> 1, 1, quad[qIndex]);
229fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        }
230fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    }
231fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com}
232fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com
233fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.comvoid addVerticalEndPoints(double top, double bottom, double x)
234fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com{
235fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    for (int qIndex = 0; qIndex < 3; qIndex += 2) {
236fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        if (quad[qIndex].x != x) {
237fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com            continue;
238fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        }
239fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        if (quad[qIndex].y == top) {
24045a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com            intersections.insert(qIndex >> 1, 0, quad[qIndex]);
241fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        }
242fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        if (quad[qIndex].y == bottom) {
24345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com            intersections.insert(qIndex >> 1, 1, quad[qIndex]);
244fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        }
245fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    }
246fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com}
247fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com
24827accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comdouble findLineT(double t) {
249235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    double x, y;
250235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    xy_at_t(quad, t, x, y);
251235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    double dx = line[1].x - line[0].x;
252235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    double dy = line[1].y - line[0].y;
253235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    if (fabs(dx) > fabs(dy)) {
254235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com        return (x - line[0].x) / dx;
255235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    }
256235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    return (y - line[0].y) / dy;
25727accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com}
25827accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
259fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.comvoid flip() {
260fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    // OPTIMIZATION: instead of swapping, pass original line, use [1].y - [0].y
261fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    int roots = intersections.fUsed;
262fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    for (int index = 0; index < roots; ++index) {
263fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        intersections.fT[1][index] = 1 - intersections.fT[1][index];
264fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    }
265fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com}
266fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com
2671304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.comstatic bool pinTs(double& quadT, double& lineT) {
268fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    if (!approximately_one_or_less(lineT)) {
2693350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        return false;
2703350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    }
271fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    if (!approximately_zero_or_more(lineT)) {
272fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        return false;
273fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    }
2741304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    if (precisely_less_than_zero(quadT)) {
275fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        quadT = 0;
2761304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    } else if (precisely_greater_than_one(quadT)) {
277fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        quadT = 1;
278fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    }
2791304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    if (precisely_less_than_zero(lineT)) {
2803350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        lineT = 0;
2811304bb25aa3b0baa61fc2e2900fabcef88801b59caryclark@google.com    } else if (precisely_greater_than_one(lineT)) {
2823350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com        lineT = 1;
2833350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    }
2843350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com    return true;
2853350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com}
2863350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.com
28727accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comprivate:
28827accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
28927accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comconst Quadratic& quad;
29027accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comconst _Line& line;
29127accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comIntersections& intersections;
29227accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com};
293198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
294fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com// utility for pairs of coincident quads
295fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic double horizontalIntersect(const Quadratic& quad, const _Point& pt) {
296fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    LineQuadraticIntersections q(quad, *((_Line*) 0), *((Intersections*) 0));
297fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    double rootVals[2];
298fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    int roots = q.horizontalIntersect(pt.y, rootVals);
29932546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    for (int index = 0; index < roots; ++index) {
30032546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com        double x;
301fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        double t = rootVals[index];
30232546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com        xy_at_t(quad, t, x, *(double*) 0);
3036d0032a8ec680221c2a704cac2391f2a2d77546fcaryclark@google.com        if (AlmostEqualUlps(x, pt.x)) {
30432546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com            return t;
30532546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com        }
306fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
307fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    return -1;
308fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
309fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
310fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comstatic double verticalIntersect(const Quadratic& quad, const _Point& pt) {
311fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    LineQuadraticIntersections q(quad, *((_Line*) 0), *((Intersections*) 0));
312fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    double rootVals[2];
313fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    int roots = q.verticalIntersect(pt.x, rootVals);
31432546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com    for (int index = 0; index < roots; ++index) {
31532546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com        double y;
316fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        double t = rootVals[index];
31732546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com        xy_at_t(quad, t, *(double*) 0, y);
3186d0032a8ec680221c2a704cac2391f2a2d77546fcaryclark@google.com        if (AlmostEqualUlps(y, pt.y)) {
31932546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com            return t;
32032546db1494a6c6433a7919844133a6ff5b5c7b2caryclark@google.com        }
321fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
322fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    return -1;
323fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
324fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
325fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comdouble axialIntersect(const Quadratic& q1, const _Point& p, bool vertical) {
326fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    if (vertical) {
327fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        return verticalIntersect(q1, p);
328fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    }
329fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    return horizontalIntersect(q1, p);
330fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
331fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
332198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.comint horizontalIntersect(const Quadratic& quad, double left, double right,
333198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        double y, double tRange[2]) {
334fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    LineQuadraticIntersections q(quad, *((_Line*) 0), *((Intersections*) 0));
335fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    double rootVals[2];
336fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    int result = q.horizontalIntersect(y, rootVals);
337198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    int tCount = 0;
338198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    for (int index = 0; index < result; ++index) {
339198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        double x, y;
340fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        xy_at_t(quad, rootVals[index], x, y);
341198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        if (x < left || x > right) {
342198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com            continue;
343198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com        }
344fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com        tRange[tCount++] = rootVals[index];
345198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    }
346198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com    return tCount;
347198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com}
348198e054b33051a6cd5f606ccbc8d539cefc5631fcaryclark@google.com
349fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comint horizontalIntersect(const Quadratic& quad, double left, double right, double y,
350fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        bool flipped, Intersections& intersections) {
351fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    LineQuadraticIntersections q(quad, *((_Line*) 0), intersections);
352fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    return q.horizontalIntersect(y, left, right, flipped);
353fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
354fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
355fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comint verticalIntersect(const Quadratic& quad, double top, double bottom, double x,
356fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com        bool flipped, Intersections& intersections) {
357fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com    LineQuadraticIntersections q(quad, *((_Line*) 0), intersections);
358fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    return q.verticalIntersect(x, top, bottom, flipped);
359fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com}
360fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
3613350c3c68ab75cd08721da3a938b8d2b10096d70caryclark@google.comint intersect(const Quadratic& quad, const _Line& line, Intersections& i) {
36227accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com    LineQuadraticIntersections q(quad, line, i);
36327accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com    return q.intersect();
36427accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com}
365235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com
366235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.comint intersectRay(const Quadratic& quad, const _Line& line, Intersections& i) {
367235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com    LineQuadraticIntersections q(quad, line, i);
368fb51afb03e76c5701fffaa847584a8b7b2c18a7ecaryclark@google.com    return q.intersectRay(i.fT[0]);
369235f56a92f6eb6accbb243e11b3c45e3798f38f2caryclark@google.com}
370