121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com/*
221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com * Copyright 2012 Google Inc.
321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com *
421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com * Use of this source code is governed by a BSD-style license that can be
521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com * found in the LICENSE file.
621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com */
721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com#include "SkIntersections.h"
821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com#include "SkPathOpsLine.h"
921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com#include "SkPathOpsQuad.h"
1021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
1121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com/*
1221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comFind the interection of a line and quadratic by solving for valid t values.
1321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
1421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comFrom http://stackoverflow.com/questions/1853637/how-to-find-the-mathematical-function-defining-a-bezier-curve
1521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
1621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com"A Bezier curve is a parametric function. A quadratic Bezier curve (i.e. three
1721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comcontrol points) can be expressed as: F(t) = A(1 - t)^2 + B(1 - t)t + Ct^2 where
1821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comA, B and C are points and t goes from zero to one.
1921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
2021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comThis will give you two equations:
2121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
2221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com  x = a(1 - t)^2 + b(1 - t)t + ct^2
2321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com  y = d(1 - t)^2 + e(1 - t)t + ft^2
2421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
2521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comIf you add for instance the line equation (y = kx + m) to that, you'll end up
2621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comwith three equations and three unknowns (x, y and t)."
2721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
2821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comSimilar to above, the quadratic is represented as
2921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com  x = a(1-t)^2 + 2b(1-t)t + ct^2
3021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com  y = d(1-t)^2 + 2e(1-t)t + ft^2
3121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comand the line as
3221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com  y = g*x + h
3321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
3421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comUsing Mathematica, solve for the values of t where the quadratic intersects the
3521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comline:
3621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
3721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com  (in)  t1 = Resultant[a*(1 - t)^2 + 2*b*(1 - t)*t + c*t^2 - x,
3821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com                       d*(1 - t)^2 + 2*e*(1 - t)*t  + f*t^2 - g*x - h, x]
3921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com  (out) -d + h + 2 d t - 2 e t - d t^2 + 2 e t^2 - f t^2 +
4021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com         g  (a - 2 a t + 2 b t + a t^2 - 2 b t^2 + c t^2)
4121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com  (in)  Solve[t1 == 0, t]
4221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com  (out) {
4321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    {t -> (-2 d + 2 e +   2 a g - 2 b g    -
4421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com      Sqrt[(2 d - 2 e -   2 a g + 2 b g)^2 -
4521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com          4 (-d + 2 e - f + a g - 2 b g    + c g) (-d + a g + h)]) /
4621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com         (2 (-d + 2 e - f + a g - 2 b g    + c g))
4721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com         },
4821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    {t -> (-2 d + 2 e +   2 a g - 2 b g    +
4921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com      Sqrt[(2 d - 2 e -   2 a g + 2 b g)^2 -
5021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com          4 (-d + 2 e - f + a g - 2 b g    + c g) (-d + a g + h)]) /
5121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com         (2 (-d + 2 e - f + a g - 2 b g    + c g))
5221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com         }
5321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        }
5421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
5521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comUsing the results above (when the line tends towards horizontal)
5621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com       A =   (-(d - 2*e + f) + g*(a - 2*b + c)     )
5721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com       B = 2*( (d -   e    ) - g*(a -   b    )     )
5821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com       C =   (-(d          ) + g*(a          ) + h )
5921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
6021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comIf g goes to infinity, we can rewrite the line in terms of x.
6121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com  x = g'*y + h'
6221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
6321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comAnd solve accordingly in Mathematica:
6421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
6521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com  (in)  t2 = Resultant[a*(1 - t)^2 + 2*b*(1 - t)*t + c*t^2 - g'*y - h',
6621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com                       d*(1 - t)^2 + 2*e*(1 - t)*t  + f*t^2 - y, y]
6721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com  (out)  a - h' - 2 a t + 2 b t + a t^2 - 2 b t^2 + c t^2 -
6821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com         g'  (d - 2 d t + 2 e t + d t^2 - 2 e t^2 + f t^2)
6921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com  (in)  Solve[t2 == 0, t]
7021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com  (out) {
7121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    {t -> (2 a - 2 b -   2 d g' + 2 e g'    -
7221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    Sqrt[(-2 a + 2 b +   2 d g' - 2 e g')^2 -
7321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com          4 (a - 2 b + c - d g' + 2 e g' - f g') (a - d g' - h')]) /
7421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com         (2 (a - 2 b + c - d g' + 2 e g' - f g'))
7521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com         },
7621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    {t -> (2 a - 2 b -   2 d g' + 2 e g'    +
7721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    Sqrt[(-2 a + 2 b +   2 d g' - 2 e g')^2 -
7821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com          4 (a - 2 b + c - d g' + 2 e g' - f g') (a - d g' - h')])/
7921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com         (2 (a - 2 b + c - d g' + 2 e g' - f g'))
8021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com         }
8121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        }
8221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
8321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comThus, if the slope of the line tends towards vertical, we use:
8421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com       A =   ( (a - 2*b + c) - g'*(d  - 2*e + f)      )
8521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com       B = 2*(-(a -   b    ) + g'*(d  -   e    )      )
8621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com       C =   ( (a          ) - g'*(d           ) - h' )
8721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com */
8821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
8921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
9021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comclass LineQuadraticIntersections {
9121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.compublic:
921a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com    enum PinTPoint {
931a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        kPointUninitialized,
941a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        kPointInitialized
951a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com    };
961a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com
9721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    LineQuadraticIntersections(const SkDQuad& q, const SkDLine& l, SkIntersections* i)
981a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        : fQuad(q)
991a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        , fLine(l)
1001a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        , fIntersections(i)
1012607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com        , fAllowNear(true) {
1022607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com    }
1032607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com
1042607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com    void allowNear(bool allow) {
1052607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com        fAllowNear = allow;
10621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    }
10721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
10821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    int intersectRay(double roots[2]) {
10921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    /*
11021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        solve by rotating line+quad so line is horizontal, then finding the roots
11121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        set up matrix to rotate quad to x-axis
11221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        |cos(a) -sin(a)|
11321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        |sin(a)  cos(a)|
11421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        note that cos(a) = A(djacent) / Hypoteneuse
11521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com                  sin(a) = O(pposite) / Hypoteneuse
11621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        since we are computing Ts, we can ignore hypoteneuse, the scale factor:
11721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        |  A     -O    |
11821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        |  O      A    |
11921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        A = line[1].fX - line[0].fX (adjacent side of the right triangle)
12021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        O = line[1].fY - line[0].fY (opposite side of the right triangle)
12121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        for each of the three points (e.g. n = 0 to 2)
12221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        quad[n].fY' = (quad[n].fY - line[0].fY) * A - (quad[n].fX - line[0].fX) * O
12321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    */
1241a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        double adj = fLine[1].fX - fLine[0].fX;
1251a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        double opp = fLine[1].fY - fLine[0].fY;
12621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        double r[3];
12721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        for (int n = 0; n < 3; ++n) {
1281a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            r[n] = (fQuad[n].fY - fLine[0].fY) * adj - (fQuad[n].fX - fLine[0].fX) * opp;
12921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        }
13021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        double A = r[2];
13121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        double B = r[1];
13221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        double C = r[0];
13321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        A += C - 2 * B;  // A = a - 2*b + c
13421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        B -= C;  // B = -(b - c)
13521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        return SkDQuad::RootsValidT(A, 2 * B, C, roots);
13621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    }
13721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
13821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    int intersect() {
1392607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com        addExactEndPoints();
14021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        double rootVals[2];
14121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        int roots = intersectRay(rootVals);
14221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        for (int index = 0; index < roots; ++index) {
14321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com            double quadT = rootVals[index];
14421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com            double lineT = findLineT(quadT);
1451a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            SkDPoint pt;
1461a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            if (pinTs(&quadT, &lineT, &pt, kPointUninitialized)) {
1471a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com                fIntersections->insert(quadT, lineT, pt);
14821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com            }
14921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        }
1502607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com        if (fAllowNear) {
1512607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com            addNearEndPoints();
1522607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com        }
1531a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        return fIntersections->used();
15421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    }
15521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
15621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    int horizontalIntersect(double axisIntercept, double roots[2]) {
1571a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        double D = fQuad[2].fY;  // f
1581a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        double E = fQuad[1].fY;  // e
1591a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        double F = fQuad[0].fY;  // d
16021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        D += F - 2 * E;         // D = d - 2*e + f
16121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        E -= F;                 // E = -(d - e)
16221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        F -= axisIntercept;
16321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        return SkDQuad::RootsValidT(D, 2 * E, F, roots);
16421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    }
16521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
16621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    int horizontalIntersect(double axisIntercept, double left, double right, bool flipped) {
1672607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com        addExactHorizontalEndPoints(left, right, axisIntercept);
16821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        double rootVals[2];
16921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        int roots = horizontalIntersect(axisIntercept, rootVals);
17021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        for (int index = 0; index < roots; ++index) {
17121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com            double quadT = rootVals[index];
1721a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            SkDPoint pt = fQuad.ptAtT(quadT);
17321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com            double lineT = (pt.fX - left) / (right - left);
1741a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            if (pinTs(&quadT, &lineT, &pt, kPointInitialized)) {
1751a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com                fIntersections->insert(quadT, lineT, pt);
17621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com            }
17721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        }
1782607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com        if (fAllowNear) {
1792607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com            addNearHorizontalEndPoints(left, right, axisIntercept);
1802607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com        }
18121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        if (flipped) {
1821a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            fIntersections->flip();
18321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        }
1841a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        return fIntersections->used();
18521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    }
18621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
18721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    int verticalIntersect(double axisIntercept, double roots[2]) {
1881a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        double D = fQuad[2].fX;  // f
1891a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        double E = fQuad[1].fX;  // e
1901a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        double F = fQuad[0].fX;  // d
19121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        D += F - 2 * E;         // D = d - 2*e + f
19221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        E -= F;                 // E = -(d - e)
19321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        F -= axisIntercept;
19421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        return SkDQuad::RootsValidT(D, 2 * E, F, roots);
19521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    }
19621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
19721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    int verticalIntersect(double axisIntercept, double top, double bottom, bool flipped) {
1982607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com        addExactVerticalEndPoints(top, bottom, axisIntercept);
19921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        double rootVals[2];
20021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        int roots = verticalIntersect(axisIntercept, rootVals);
20121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        for (int index = 0; index < roots; ++index) {
20221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com            double quadT = rootVals[index];
2031a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            SkDPoint pt = fQuad.ptAtT(quadT);
20421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com            double lineT = (pt.fY - top) / (bottom - top);
2051a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            if (pinTs(&quadT, &lineT, &pt, kPointInitialized)) {
2061a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com                fIntersections->insert(quadT, lineT, pt);
20721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com            }
20821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        }
2092607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com        if (fAllowNear) {
2102607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com            addNearVerticalEndPoints(top, bottom, axisIntercept);
2112607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com        }
21221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        if (flipped) {
2131a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            fIntersections->flip();
21421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        }
2151a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        return fIntersections->used();
21621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    }
21721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
21821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comprotected:
21921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    // add endpoints first to get zero and one t values exactly
2202607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com    void addExactEndPoints() {
22121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        for (int qIndex = 0; qIndex < 3; qIndex += 2) {
2221a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            double lineT = fLine.exactPoint(fQuad[qIndex]);
2232607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com            if (lineT < 0) {
22446e3086c1837da6ab13b48f852bd7bfbab3dc44fcaryclark@google.com                continue;
22546e3086c1837da6ab13b48f852bd7bfbab3dc44fcaryclark@google.com            }
2262607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com            double quadT = (double) (qIndex >> 1);
2271a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            fIntersections->insert(quadT, lineT, fQuad[qIndex]);
2282607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com        }
2292607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com    }
2302607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com
2312607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com    void addNearEndPoints() {
2322607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com        for (int qIndex = 0; qIndex < 3; qIndex += 2) {
2332607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com            double quadT = (double) (qIndex >> 1);
2341a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            if (fIntersections->hasT(quadT)) {
23546e3086c1837da6ab13b48f852bd7bfbab3dc44fcaryclark@google.com                continue;
23646e3086c1837da6ab13b48f852bd7bfbab3dc44fcaryclark@google.com            }
2371a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            double lineT = fLine.nearPoint(fQuad[qIndex]);
2382607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com            if (lineT < 0) {
23946e3086c1837da6ab13b48f852bd7bfbab3dc44fcaryclark@google.com                continue;
24046e3086c1837da6ab13b48f852bd7bfbab3dc44fcaryclark@google.com            }
2411a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            fIntersections->insert(quadT, lineT, fQuad[qIndex]);
2422607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com        }
2432607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com        // FIXME: see if line end is nearly on quad
2442607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com    }
2452607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com
2462607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com    void addExactHorizontalEndPoints(double left, double right, double y) {
2472607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com        for (int qIndex = 0; qIndex < 3; qIndex += 2) {
2481a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            double lineT = SkDLine::ExactPointH(fQuad[qIndex], left, right, y);
2492607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com            if (lineT < 0) {
2502607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com                continue;
25146e3086c1837da6ab13b48f852bd7bfbab3dc44fcaryclark@google.com            }
2522607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com            double quadT = (double) (qIndex >> 1);
2531a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            fIntersections->insert(quadT, lineT, fQuad[qIndex]);
25421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        }
25521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    }
25621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
2572607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com    void addNearHorizontalEndPoints(double left, double right, double y) {
25821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        for (int qIndex = 0; qIndex < 3; qIndex += 2) {
2592607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com            double quadT = (double) (qIndex >> 1);
2601a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            if (fIntersections->hasT(quadT)) {
26121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com                continue;
26221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com            }
2631a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            double lineT = SkDLine::NearPointH(fQuad[qIndex], left, right, y);
2642607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com            if (lineT < 0) {
2652607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com                continue;
26621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com            }
2671a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            fIntersections->insert(quadT, lineT, fQuad[qIndex]);
26821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        }
2692607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com        // FIXME: see if line end is nearly on quad
27021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    }
27121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
2722607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com    void addExactVerticalEndPoints(double top, double bottom, double x) {
27321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        for (int qIndex = 0; qIndex < 3; qIndex += 2) {
2741a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            double lineT = SkDLine::ExactPointV(fQuad[qIndex], top, bottom, x);
2752607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com            if (lineT < 0) {
27621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com                continue;
27721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com            }
2782607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com            double quadT = (double) (qIndex >> 1);
2791a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            fIntersections->insert(quadT, lineT, fQuad[qIndex]);
2802607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com        }
2812607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com    }
2822607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com
2832607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com    void addNearVerticalEndPoints(double top, double bottom, double x) {
2842607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com        for (int qIndex = 0; qIndex < 3; qIndex += 2) {
2852607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com            double quadT = (double) (qIndex >> 1);
2861a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            if (fIntersections->hasT(quadT)) {
2872607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com                continue;
2882607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com            }
2891a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            double lineT = SkDLine::NearPointV(fQuad[qIndex], top, bottom, x);
2902607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com            if (lineT < 0) {
2912607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com                continue;
29221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com            }
2931a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            fIntersections->insert(quadT, lineT, fQuad[qIndex]);
29421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        }
2952607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com        // FIXME: see if line end is nearly on quad
29621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    }
29721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
29821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    double findLineT(double t) {
2991a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        SkDPoint xy = fQuad.ptAtT(t);
3001a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        double dx = fLine[1].fX - fLine[0].fX;
3011a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        double dy = fLine[1].fY - fLine[0].fY;
3021a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        double dxT = (xy.fX - fLine[0].fX) / dx;
3031a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        double dyT = (xy.fY - fLine[0].fY) / dy;
30446e3086c1837da6ab13b48f852bd7bfbab3dc44fcaryclark@google.com        if (!between(FLT_EPSILON, dxT, 1 - FLT_EPSILON) && between(0, dyT, 1)) {
30546e3086c1837da6ab13b48f852bd7bfbab3dc44fcaryclark@google.com            return dyT;
30646e3086c1837da6ab13b48f852bd7bfbab3dc44fcaryclark@google.com        }
30746e3086c1837da6ab13b48f852bd7bfbab3dc44fcaryclark@google.com        if (!between(FLT_EPSILON, dyT, 1 - FLT_EPSILON) && between(0, dxT, 1)) {
30846e3086c1837da6ab13b48f852bd7bfbab3dc44fcaryclark@google.com            return dxT;
30946e3086c1837da6ab13b48f852bd7bfbab3dc44fcaryclark@google.com        }
31046e3086c1837da6ab13b48f852bd7bfbab3dc44fcaryclark@google.com        return fabs(dx) > fabs(dy) ? dxT : dyT;
31121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    }
31221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
3131a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com    bool pinTs(double* quadT, double* lineT, SkDPoint* pt, PinTPoint ptSet) {
31421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        if (!approximately_one_or_less(*lineT)) {
31521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com            return false;
31621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        }
31721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        if (!approximately_zero_or_more(*lineT)) {
31821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com            return false;
31921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        }
3201a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        double qT = *quadT = SkPinT(*quadT);
3211a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        double lT = *lineT = SkPinT(*lineT);
3221a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        if (lT == 0 || lT == 1 || (ptSet == kPointUninitialized && qT != 0 && qT != 1)) {
3231a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            *pt = fLine.ptAtT(lT);
3241a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        } else if (ptSet == kPointUninitialized) {
3251a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com            *pt = fQuad.ptAtT(qT);
3261a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        }
32721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        return true;
32821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    }
32921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
33021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comprivate:
3311a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com    const SkDQuad& fQuad;
3321a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com    const SkDLine& fLine;
3331a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com    SkIntersections* fIntersections;
3342607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com    bool fAllowNear;
33521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com};
33621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
33721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com// utility for pairs of coincident quads
33821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comstatic double horizontalIntersect(const SkDQuad& quad, const SkDPoint& pt) {
33921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    LineQuadraticIntersections q(quad, *(static_cast<SkDLine*>(0)),
34021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com            static_cast<SkIntersections*>(0));
34121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    double rootVals[2];
34221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    int roots = q.horizontalIntersect(pt.fY, rootVals);
34321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    for (int index = 0; index < roots; ++index) {
34421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        double t = rootVals[index];
3451a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        SkDPoint qPt = quad.ptAtT(t);
34621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        if (AlmostEqualUlps(qPt.fX, pt.fX)) {
34721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com            return t;
34821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        }
34921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    }
35021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    return -1;
35121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com}
35221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
35321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comstatic double verticalIntersect(const SkDQuad& quad, const SkDPoint& pt) {
35421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    LineQuadraticIntersections q(quad, *(static_cast<SkDLine*>(0)),
35521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com            static_cast<SkIntersections*>(0));
35621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    double rootVals[2];
35721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    int roots = q.verticalIntersect(pt.fX, rootVals);
35821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    for (int index = 0; index < roots; ++index) {
35921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        double t = rootVals[index];
3601a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        SkDPoint qPt = quad.ptAtT(t);
36121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        if (AlmostEqualUlps(qPt.fY, pt.fY)) {
36221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com            return t;
36321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        }
36421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    }
36521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    return -1;
36621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com}
36721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
36821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comdouble SkIntersections::Axial(const SkDQuad& q1, const SkDPoint& p, bool vertical) {
36921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    if (vertical) {
37021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com        return verticalIntersect(q1, p);
37121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    }
37221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    return horizontalIntersect(q1, p);
37321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com}
37421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
37521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comint SkIntersections::horizontal(const SkDQuad& quad, double left, double right, double y,
37621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com                                bool flipped) {
3771a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com    SkDLine line = {{{ left, y }, { right, y }}};
3781a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com    LineQuadraticIntersections q(quad, line, this);
37921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    return q.horizontalIntersect(y, left, right, flipped);
38021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com}
38121c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
38221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comint SkIntersections::vertical(const SkDQuad& quad, double top, double bottom, double x,
38321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com                              bool flipped) {
3841a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com    SkDLine line = {{{ x, top }, { x, bottom }}};
3851a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com    LineQuadraticIntersections q(quad, line, this);
38621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    return q.verticalIntersect(x, top, bottom, flipped);
38721c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com}
38821c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
38921c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comint SkIntersections::intersect(const SkDQuad& quad, const SkDLine& line) {
39021c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    LineQuadraticIntersections q(quad, line, this);
3912607e2e5a8f13275d86e2242f9906f2106a2fa79caryclark@google.com    q.allowNear(fAllowNear);
39221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    return q.intersect();
39321c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com}
39421c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com
39521c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.comint SkIntersections::intersectRay(const SkDQuad& quad, const SkDLine& line) {
39621c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com    LineQuadraticIntersections q(quad, line, this);
3972274f123b56c02b1d0f195c6a980e6cfacc239bfcaryclark@google.com    fUsed = q.intersectRay(fT[0]);
3982274f123b56c02b1d0f195c6a980e6cfacc239bfcaryclark@google.com    for (int index = 0; index < fUsed; ++index) {
3991a4d09d786e54862a38f367490a7e4769f7e73adcaryclark@google.com        fPt[index] = quad.ptAtT(fT[0][index]);
4002274f123b56c02b1d0f195c6a980e6cfacc239bfcaryclark@google.com    }
4012274f123b56c02b1d0f195c6a980e6cfacc239bfcaryclark@google.com    return fUsed;
40221c2924b178f0d4c298d6631e568401473ed8d16caryclark@google.com}
403