1818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com/*
2818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com * Copyright 2012 Google Inc.
3818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com *
4818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com * Use of this source code is governed by a BSD-style license that can be
5818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com * found in the LICENSE file.
6818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com */
7818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com#include "PathOpsExtendedTest.h"
866089e4ec4f1702caf2154780471417872862148caryclark@google.com#include "PathOpsThreadedCommon.h"
9818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com#include "SkIntersections.h"
10818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com#include "SkPathOpsLine.h"
11818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com#include "SkPathOpsQuad.h"
12818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com#include "SkReduceOrder.h"
13818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com
14818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.comstatic int doIntersect(SkIntersections& intersections, const SkDQuad& quad, const SkDLine& line,
15818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com                       bool& flipped) {
16818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    int result;
17818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    flipped = false;
18818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    if (line[0].fX == line[1].fX) {
19818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        double top = line[0].fY;
20818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        double bottom = line[1].fY;
21818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        flipped = top > bottom;
22818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        if (flipped) {
23818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com            SkTSwap<double>(top, bottom);
24818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        }
25818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        result = intersections.vertical(quad, top, bottom, line[0].fX, flipped);
26818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    } else if (line[0].fY == line[1].fY) {
27818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        double left = line[0].fX;
28818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        double right = line[1].fX;
29818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        flipped = left > right;
30818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        if (flipped) {
31818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com            SkTSwap<double>(left, right);
32818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        }
33818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        result = intersections.horizontal(quad, left, right, line[0].fY, flipped);
34818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    } else {
35818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        intersections.intersect(quad, line);
36818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        result = intersections.used();
37818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    }
38818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    return result;
39818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com}
40818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com
41818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.comstatic void testLineIntersect(skiatest::Reporter* reporter, const SkDQuad& quad,
42818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com                              const SkDLine& line, const double x, const double y) {
43818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    char pathStr[1024];
44818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    sk_bzero(pathStr, sizeof(pathStr));
45818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    char* str = pathStr;
46818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    str += sprintf(str, "    path.moveTo(%1.9g, %1.9g);\n", quad[0].fX, quad[0].fY);
4766089e4ec4f1702caf2154780471417872862148caryclark@google.com    str += sprintf(str, "    path.quadTo(%1.9g, %1.9g, %1.9g, %1.9g);\n", quad[1].fX,
4866089e4ec4f1702caf2154780471417872862148caryclark@google.com            quad[1].fY, quad[2].fX, quad[2].fY);
49818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    str += sprintf(str, "    path.moveTo(%1.9g, %1.9g);\n", line[0].fX, line[0].fY);
50818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    str += sprintf(str, "    path.lineTo(%1.9g, %1.9g);\n", line[1].fX, line[1].fY);
51818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com
52818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    SkIntersections intersections;
53818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    bool flipped = false;
54818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    int result = doIntersect(intersections, quad, line, flipped);
55818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    bool found = false;
56818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    for (int index = 0; index < result; ++index) {
57818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        double quadT = intersections[0][index];
584fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com        SkDPoint quadXY = quad.ptAtT(quadT);
59818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        double lineT = intersections[1][index];
604fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com        SkDPoint lineXY = line.ptAtT(lineT);
61818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        if (quadXY.approximatelyEqual(lineXY)) {
62818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com            found = true;
63818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        }
64818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    }
65818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    REPORTER_ASSERT(reporter, found);
66818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com}
67818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com
68818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com// find a point on a quad by choosing a t from 0 to 1
69818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com// create a vertical span above and below the point
70818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com// verify that intersecting the vertical span and the quad returns t
71818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com// verify that a vertical span starting at quad[0] intersects at t=0
72818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com// verify that a vertical span starting at quad[2] intersects at t=1
7366089e4ec4f1702caf2154780471417872862148caryclark@google.comstatic void testQuadLineIntersectMain(PathOpsThreadState* data)
74818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com{
7566089e4ec4f1702caf2154780471417872862148caryclark@google.com    PathOpsThreadState& state = *data;
7666089e4ec4f1702caf2154780471417872862148caryclark@google.com    REPORTER_ASSERT(state.fReporter, data);
7766089e4ec4f1702caf2154780471417872862148caryclark@google.com    int ax = state.fA & 0x03;
7866089e4ec4f1702caf2154780471417872862148caryclark@google.com    int ay = state.fA >> 2;
7966089e4ec4f1702caf2154780471417872862148caryclark@google.com    int bx = state.fB & 0x03;
8066089e4ec4f1702caf2154780471417872862148caryclark@google.com    int by = state.fB >> 2;
8166089e4ec4f1702caf2154780471417872862148caryclark@google.com    int cx = state.fC & 0x03;
8266089e4ec4f1702caf2154780471417872862148caryclark@google.com    int cy = state.fC >> 2;
83db60de7cbe3ea9643a0471e1225a6abeac021de3caryclark@google.com    SkDQuad quad = {{{(double) ax, (double) ay}, {(double) bx, (double) by},
84db60de7cbe3ea9643a0471e1225a6abeac021de3caryclark@google.com            {(double) cx, (double) cy}}};
8566089e4ec4f1702caf2154780471417872862148caryclark@google.com    SkReduceOrder reducer;
86927b7028d44c46e9cbc18368f16ec2262d59d94dcaryclark@google.com    int order = reducer.reduce(quad);
8766089e4ec4f1702caf2154780471417872862148caryclark@google.com    if (order < 3) {
8866089e4ec4f1702caf2154780471417872862148caryclark@google.com        return;
8966089e4ec4f1702caf2154780471417872862148caryclark@google.com    }
9066089e4ec4f1702caf2154780471417872862148caryclark@google.com    for (int tIndex = 0; tIndex <= 4; ++tIndex) {
914fdbb229649caf74e5c1b55a1823926df903af34caryclark@google.com        SkDPoint xy = quad.ptAtT(tIndex / 4.0);
9266089e4ec4f1702caf2154780471417872862148caryclark@google.com        for (int h = -2; h <= 2; ++h) {
9366089e4ec4f1702caf2154780471417872862148caryclark@google.com            for (int v = -2; v <= 2; ++v) {
9466089e4ec4f1702caf2154780471417872862148caryclark@google.com                if (h == v && abs(h) != 1) {
9566089e4ec4f1702caf2154780471417872862148caryclark@google.com                    continue;
96818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com                }
9766089e4ec4f1702caf2154780471417872862148caryclark@google.com                double x = xy.fX;
9866089e4ec4f1702caf2154780471417872862148caryclark@google.com                double y = xy.fY;
9966089e4ec4f1702caf2154780471417872862148caryclark@google.com                SkDLine line = {{{x - h, y - v}, {x, y}}};
10066089e4ec4f1702caf2154780471417872862148caryclark@google.com                testLineIntersect(state.fReporter, quad, line, x, y);
10166089e4ec4f1702caf2154780471417872862148caryclark@google.com                state.fReporter->bumpTestCount();
10266089e4ec4f1702caf2154780471417872862148caryclark@google.com                SkDLine line2 = {{{x, y}, {x + h, y + v}}};
10366089e4ec4f1702caf2154780471417872862148caryclark@google.com                testLineIntersect(state.fReporter, quad, line2, x, y);
10466089e4ec4f1702caf2154780471417872862148caryclark@google.com                state.fReporter->bumpTestCount();
10566089e4ec4f1702caf2154780471417872862148caryclark@google.com                SkDLine line3 = {{{x - h, y - v}, {x + h, y + v}}};
10666089e4ec4f1702caf2154780471417872862148caryclark@google.com                testLineIntersect(state.fReporter, quad, line3, x, y);
10766089e4ec4f1702caf2154780471417872862148caryclark@google.com                state.fReporter->bumpTestCount();
108818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com            }
109818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        }
11066089e4ec4f1702caf2154780471417872862148caryclark@google.com    }
111818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com}
112818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com
11378e7b4e1b928fa69f672be3c743df6d6c3ecbcedtfarina@chromium.orgDEF_TEST(PathOpsQuadLineIntersectionThreaded, reporter) {
114406654be7a930b484159f5bca107d3b11d8a9edemtklein    initializeTests(reporter, "testQuadLineIntersect");
115406654be7a930b484159f5bca107d3b11d8a9edemtklein    PathOpsThreadedTestRunner testRunner(reporter);
116818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    for (int a = 0; a < 16; ++a) {
117818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        for (int b = 0 ; b < 16; ++b) {
118818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com            for (int c = 0 ; c < 16; ++c) {
11966089e4ec4f1702caf2154780471417872862148caryclark@google.com                    *testRunner.fRunnables.append() = SkNEW_ARGS(PathOpsThreadedRunnable,
12066089e4ec4f1702caf2154780471417872862148caryclark@google.com                            (&testQuadLineIntersectMain, a, b, c, 0, &testRunner));
121818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com            }
12266089e4ec4f1702caf2154780471417872862148caryclark@google.com            if (!reporter->allowExtendedTest()) goto finish;
123818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com        }
124818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com    }
125818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.comfinish:
12666089e4ec4f1702caf2154780471417872862148caryclark@google.com    testRunner.render();
127818b0cc1b8b0c4acc565e8e2cb8b0b61aa5a300ecaryclark@google.com}
128