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"
88dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com#include "CurveUtilities.h"
924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com#include "EdgeWalker_Test.h"
1027accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com#include "Intersection_Tests.h"
1127accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com#include "Intersections.h"
1227accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com#include "TestUtilities.h"
1327accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
1427accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comstruct lineQuad {
1527accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com    Quadratic quad;
1627accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com    _Line line;
1703f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com    int result;
1803f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com    _Point expected[2];
1927accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com} lineQuadTests[] = {
2003f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com    //        quad                    line                  results
2103f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com    {{{1, 1}, {2, 1}, {0, 2}},  {{0, 0}, {1, 1}},  1,  {{1, 1}        }},
2203f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com    {{{0, 0}, {1, 1}, {3, 1}},  {{0, 0}, {3, 1}},  2,  {{0, 0}, {3, 1}}},
2303f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com    {{{2, 0}, {1, 1}, {2, 2}},  {{0, 0}, {0, 2}},  0                   },
24d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    {{{4, 0}, {0, 1}, {4, 2}},  {{3, 1}, {4, 1}},  0,                  },
2503f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com    {{{0, 0}, {0, 1}, {1, 1}},  {{0, 1}, {1, 0}},  1,  {{.25, .75}    }},
2627accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com};
2727accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
2827accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comsize_t lineQuadTests_count = sizeof(lineQuadTests) / sizeof(lineQuadTests[0]);
2927accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
3027accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comconst int firstLineQuadIntersectionTest = 0;
3127accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com
3203f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.comstatic int doIntersect(Intersections& intersections, const Quadratic& quad, const _Line& line, bool& flipped) {
3303f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com    int result;
3403f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com    flipped = false;
3503f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com    if (line[0].x == line[1].x) {
3603f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        double top = line[0].y;
3703f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        double bottom = line[1].y;
3803f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        flipped = top > bottom;
3903f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        if (flipped) {
4003f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com            SkTSwap<double>(top, bottom);
4103f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        }
4203f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        result = verticalIntersect(quad, top, bottom, line[0].x, flipped, intersections);
4303f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com    } else if (line[0].y == line[1].y) {
4403f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        double left = line[0].x;
4503f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        double right = line[1].x;
4603f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        flipped = left > right;
4703f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        if (flipped) {
4803f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com            SkTSwap<double>(left, right);
4903f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        }
5003f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        result = horizontalIntersect(quad, left, right, line[0].y, flipped, intersections);
5103f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com    } else {
5203f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        intersect(quad, line, intersections);
5303f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        result = intersections.fUsed;
5403f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com    }
5503f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com    return result;
5603f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com}
5703f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com
580b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.comstatic struct oneLineQuad {
590b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com    Quadratic quad;
600b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com    _Line line;
610b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com} oneOffs[] = {
620b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com    {{{369.848602,145.680267}, {382.360413,121.298294}, {406.207703,121.298294}},
630b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com        {{406.207703,121.298294}, {348.781738,123.864815}}}
640b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com    };
650b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com
660b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.comstatic size_t oneOffs_count = sizeof(oneOffs) / sizeof(oneOffs[0]);
670b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com
680b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com
690b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.comstatic void testOneOffs() {
700b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com    Intersections intersections;
710b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com    bool flipped = false;
720b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com    for (size_t index = 0; index < oneOffs_count; ++index) {
730b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com        const Quadratic& quad = oneOffs[index].quad;
740b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com        const _Line& line = oneOffs[index].line;
750b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com        int result = doIntersect(intersections, quad, line, flipped);
760b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com        for (int inner = 0; inner < result; ++inner) {
770b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com            double quadT = intersections.fT[0][inner];
780b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com            double quadX, quadY;
790b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com            xy_at_t(quad, quadT, quadX, quadY);
800b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com            double lineT = intersections.fT[1][inner];
810b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com            double lineX, lineY;
820b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com            xy_at_t(line, lineT, lineX, lineY);
83aa35831d1d0e4c798a63fe772430adc4f3a038cdcaryclark@google.com            SkASSERT(AlmostEqualUlps(quadX, lineX)
846d0032a8ec680221c2a704cac2391f2a2d77546fcaryclark@google.com                    && AlmostEqualUlps(quadY, lineY));
850b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com        }
860b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com    }
870b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com}
880b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com
8927accef223a27fba437f5e825d99edbae20a045bcaryclark@google.comvoid LineQuadraticIntersection_Test() {
900b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com    if (1) {
910b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com        testOneOffs();
920b7da433fe0eaa2833d1b2900715b013b36d93dacaryclark@google.com    }
9327accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com    for (size_t index = firstLineQuadIntersectionTest; index < lineQuadTests_count; ++index) {
9427accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com        const Quadratic& quad = lineQuadTests[index].quad;
9527accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com        const _Line& line = lineQuadTests[index].line;
9627accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com        Quadratic reduce1;
9727accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com        _Line reduce2;
9847d73daa7a971e7eee5822def7922f7d43b2dc47caryclark@google.com        int order1 = reduceOrder(quad, reduce1, kReduceOrder_TreatAsFill);
9927accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com        int order2 = reduceOrder(line, reduce2);
10027accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com        if (order1 < 3) {
10103f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com            SkDebugf("%s [%d] quad order=%d\n", __FUNCTION__, (int) index, order1);
10203f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com            SkASSERT(0);
10327accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com        }
10427accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com        if (order2 < 2) {
10503f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com            SkDebugf("%s [%d] line order=%d\n", __FUNCTION__, (int) index, order2);
10603f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com            SkASSERT(0);
10703f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        }
10803f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        Intersections intersections;
10903f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        bool flipped = false;
11003f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        int result = doIntersect(intersections, quad, line, flipped);
11103f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        SkASSERT(result == lineQuadTests[index].result);
11203f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        if (!intersections.intersected()) {
11303f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com            continue;
11427accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com        }
11503f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com        for (int pt = 0; pt < result; ++pt) {
11603f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com            double tt1 = intersections.fT[0][pt];
11703f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com            SkASSERT(tt1 >= 0 && tt1 <= 1);
11803f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com            _Point t1, t2;
11903f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com            xy_at_t(quad, tt1, t1.x, t1.y);
12003f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com            double tt2 = intersections.fT[1][pt];
12103f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com            SkASSERT(tt2 >= 0 && tt2 <= 1);
12203f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com            xy_at_t(line, tt2, t2.x, t2.y);
1236d0032a8ec680221c2a704cac2391f2a2d77546fcaryclark@google.com            if (!AlmostEqualUlps(t1.x, t2.x)) {
12403f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com                SkDebugf("%s [%d,%d] x!= t1=%1.9g (%1.9g,%1.9g) t2=%1.9g (%1.9g,%1.9g)\n",
12503f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com                    __FUNCTION__, (int)index, pt, tt1, t1.x, t1.y, tt2, t2.x, t2.y);
12603f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com                SkASSERT(0);
12703f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com            }
1286d0032a8ec680221c2a704cac2391f2a2d77546fcaryclark@google.com            if (!AlmostEqualUlps(t1.y, t2.y)) {
12903f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com                SkDebugf("%s [%d,%d] y!= t1=%1.9g (%1.9g,%1.9g) t2=%1.9g (%1.9g,%1.9g)\n",
13003f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com                    __FUNCTION__, (int)index, pt, tt1, t1.x, t1.y, tt2, t2.x, t2.y);
13103f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com                SkASSERT(0);
13203f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com            }
13303f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com            if (!t1.approximatelyEqual(lineQuadTests[index].expected[0])
13403f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com                    && (lineQuadTests[index].result == 1
13503f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com                    || !t1.approximatelyEqual(lineQuadTests[index].expected[1]))) {
13603f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com                SkDebugf("%s t1=(%1.9g,%1.9g)\n", __FUNCTION__, t1.x, t1.y);
13703f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com                SkASSERT(0);
13827accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com            }
13927accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com        }
14027accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com    }
14127accef223a27fba437f5e825d99edbae20a045bcaryclark@google.com}
14224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com
143d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.comstatic void testLineIntersect(State4& state, const Quadratic& quad, const _Line& line,
14424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        const double x, const double y) {
14524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    char pathStr[1024];
14624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    bzero(pathStr, sizeof(pathStr));
14724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    char* str = pathStr;
14824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    str += sprintf(str, "    path.moveTo(%1.9g, %1.9g);\n", quad[0].x, quad[0].y);
14924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    str += sprintf(str, "    path.quadTo(%1.9g, %1.9g, %1.9g, %1.9g);\n", quad[1].x, quad[1].y, quad[2].x, quad[2].y);
15024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    str += sprintf(str, "    path.moveTo(%1.9g, %1.9g);\n", line[0].x, line[0].y);
15124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    str += sprintf(str, "    path.lineTo(%1.9g, %1.9g);\n", line[1].x, line[1].y);
152d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
15324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    Intersections intersections;
15424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    bool flipped = false;
15503f970652e07c6832cae41fa374cb68ca80d472ccaryclark@google.com    int result = doIntersect(intersections, quad, line, flipped);
15624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    bool found = false;
15724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    for (int index = 0; index < result; ++index) {
15824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        double quadT = intersections.fT[0][index];
15924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        double quadX, quadY;
16024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        xy_at_t(quad, quadT, quadX, quadY);
16124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        double lineT = intersections.fT[1][index];
16224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        double lineX, lineY;
16324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        xy_at_t(line, lineT, lineX, lineY);
16424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        if (fabs(quadX - lineX) < FLT_EPSILON && fabs(quadY - lineY) < FLT_EPSILON
16524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                && fabs(x - lineX) < FLT_EPSILON && fabs(y - lineY) < FLT_EPSILON) {
16624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            found = true;
16724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        }
16824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    }
16924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    SkASSERT(found);
17024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    state.testsRun++;
17124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com}
17224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com
17324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com
17424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com// find a point on a quad by choosing a t from 0 to 1
17524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com// create a vertical span above and below the point
17624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com// verify that intersecting the vertical span and the quad returns t
17724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com// verify that a vertical span starting at quad[0] intersects at t=0
17824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com// verify that a vertical span starting at quad[2] intersects at t=1
17924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.comstatic void* testQuadLineIntersectMain(void* data)
18024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com{
18124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    SkASSERT(data);
18224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    State4& state = *(State4*) data;
18324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    do {
18424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        int ax = state.a & 0x03;
18524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        int ay = state.a >> 2;
18624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        int bx = state.b & 0x03;
18724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        int by = state.b >> 2;
18824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        int cx = state.c & 0x03;
18924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        int cy = state.c >> 2;
19024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        Quadratic quad = {{ax, ay}, {bx, by}, {cx, cy}};
19124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        Quadratic reduced;
19247d73daa7a971e7eee5822def7922f7d43b2dc47caryclark@google.com        int order = reduceOrder(quad, reduced, kReduceOrder_TreatAsFill);
19324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        if (order < 3) {
19424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            continue; // skip degenerates
19524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        }
19624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        for (int tIndex = 0; tIndex <= 4; ++tIndex) {
19724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            double x, y;
19824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            xy_at_t(quad, tIndex / 4.0, x, y);
19924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            for (int h = -2; h <= 2; ++h) {
20024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                for (int v = -2; v <= 2; ++v) {
20124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                    if (h == v && abs(h) != 1) {
20224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                        continue;
20324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                    }
20424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                    _Line line = {{x - h, y - v}, {x, y}};
20524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                    testLineIntersect(state, quad, line, x, y);
20624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                    _Line line2 = {{x, y}, {x + h, y + v}};
20724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                    testLineIntersect(state, quad, line2, x, y);
20824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                    _Line line3 = {{x - h, y - v}, {x + h, y + v}};
20924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                    testLineIntersect(state, quad, line3, x, y);
21024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                }
21124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            }
21224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        }
21324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    } while (runNextTestSet(state));
21424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    return NULL;
21524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com}
21624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com
21724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.comvoid QuadLineIntersectThreaded_Test(int& testsRun)
21824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com{
21924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    SkDebugf("%s\n", __FUNCTION__);
22024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    const char testStr[] = "testQuadLineIntersect";
22124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    initializeTests(testStr, sizeof(testStr));
22224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    int testsStart = testsRun;
22324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    for (int a = 0; a < 16; ++a) {
22424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        for (int b = 0 ; b < 16; ++b) {
22524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            for (int c = 0 ; c < 16; ++c) {
22624bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                testsRun += dispatchTest4(testQuadLineIntersectMain,
22724bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com                        a, b, c, 0);
22824bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            }
22924bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com            if (!gRunTestsInOneThread) SkDebugf(".");
23024bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        }
23124bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com        if (!gRunTestsInOneThread) SkDebugf("%d", a);
23224bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    }
23324bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    testsRun += waitForCompletion();
23424bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com    SkDebugf("\n%s tests=%d total=%d\n", __FUNCTION__, testsRun - testsStart, testsRun);
23524bec79d6f3d71ff97b50db72461a3892bd4f6b5caryclark@google.com}
236