1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2012 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h"
8cb93a386Sopenharmony_ci#include "src/pathops/SkIntersections.h"
9cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsConic.h"
10cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsLine.h"
11cb93a386Sopenharmony_ci#include "src/pathops/SkReduceOrder.h"
12cb93a386Sopenharmony_ci#include "tests/PathOpsExtendedTest.h"
13cb93a386Sopenharmony_ci#include "tests/PathOpsTestCommon.h"
14cb93a386Sopenharmony_ci#include "tests/Test.h"
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_ci#include <utility>
17cb93a386Sopenharmony_ci
18cb93a386Sopenharmony_cistatic struct lineConic {
19cb93a386Sopenharmony_ci    ConicPts conic;
20cb93a386Sopenharmony_ci    SkDLine line;
21cb93a386Sopenharmony_ci    int result;
22cb93a386Sopenharmony_ci    SkDPoint expected[2];
23cb93a386Sopenharmony_ci} lineConicTests[] = {
24cb93a386Sopenharmony_ci    {
25cb93a386Sopenharmony_ci     {{{{30.6499996,25.6499996}, {30.6499996,20.6499996}, {25.6499996,20.6499996}}}, 0.707107008f},
26cb93a386Sopenharmony_ci      {{{25.6499996,20.6499996}, {45.6500015,20.6499996}}},
27cb93a386Sopenharmony_ci          1,
28cb93a386Sopenharmony_ci       {{25.6499996,20.6499996}, {0,0}}
29cb93a386Sopenharmony_ci    },
30cb93a386Sopenharmony_ci};
31cb93a386Sopenharmony_ci
32cb93a386Sopenharmony_cistatic size_t lineConicTests_count = SK_ARRAY_COUNT(lineConicTests);
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_cistatic int doIntersect(SkIntersections& intersections, const SkDConic& conic, const SkDLine& line,
35cb93a386Sopenharmony_ci                       bool& flipped) {
36cb93a386Sopenharmony_ci    int result;
37cb93a386Sopenharmony_ci    flipped = false;
38cb93a386Sopenharmony_ci    if (line[0].fX == line[1].fX) {
39cb93a386Sopenharmony_ci        double top = line[0].fY;
40cb93a386Sopenharmony_ci        double bottom = line[1].fY;
41cb93a386Sopenharmony_ci        flipped = top > bottom;
42cb93a386Sopenharmony_ci        if (flipped) {
43cb93a386Sopenharmony_ci            using std::swap;
44cb93a386Sopenharmony_ci            swap(top, bottom);
45cb93a386Sopenharmony_ci        }
46cb93a386Sopenharmony_ci        result = intersections.vertical(conic, top, bottom, line[0].fX, flipped);
47cb93a386Sopenharmony_ci    } else if (line[0].fY == line[1].fY) {
48cb93a386Sopenharmony_ci        double left = line[0].fX;
49cb93a386Sopenharmony_ci        double right = line[1].fX;
50cb93a386Sopenharmony_ci        flipped = left > right;
51cb93a386Sopenharmony_ci        if (flipped) {
52cb93a386Sopenharmony_ci            using std::swap;
53cb93a386Sopenharmony_ci            swap(left, right);
54cb93a386Sopenharmony_ci        }
55cb93a386Sopenharmony_ci        result = intersections.horizontal(conic, left, right, line[0].fY, flipped);
56cb93a386Sopenharmony_ci    } else {
57cb93a386Sopenharmony_ci        intersections.intersect(conic, line);
58cb93a386Sopenharmony_ci        result = intersections.used();
59cb93a386Sopenharmony_ci    }
60cb93a386Sopenharmony_ci    return result;
61cb93a386Sopenharmony_ci}
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_cistatic struct oneLineConic {
64cb93a386Sopenharmony_ci    ConicPts conic;
65cb93a386Sopenharmony_ci    SkDLine line;
66cb93a386Sopenharmony_ci} oneOffs[] = {
67cb93a386Sopenharmony_ci    {{{{{30.6499996,25.6499996}, {30.6499996,20.6499996}, {25.6499996,20.6499996}}}, 0.707107008f},
68cb93a386Sopenharmony_ci      {{{25.6499996,20.6499996}, {45.6500015,20.6499996}}}}
69cb93a386Sopenharmony_ci};
70cb93a386Sopenharmony_ci
71cb93a386Sopenharmony_cistatic size_t oneOffs_count = SK_ARRAY_COUNT(oneOffs);
72cb93a386Sopenharmony_ci
73cb93a386Sopenharmony_cistatic void testOneOffs(skiatest::Reporter* reporter) {
74cb93a386Sopenharmony_ci    bool flipped = false;
75cb93a386Sopenharmony_ci    for (size_t index = 0; index < oneOffs_count; ++index) {
76cb93a386Sopenharmony_ci        const ConicPts& c = oneOffs[index].conic;
77cb93a386Sopenharmony_ci        SkDConic  conic;
78cb93a386Sopenharmony_ci        conic.debugSet(c.fPts.fPts, c.fWeight);
79cb93a386Sopenharmony_ci        SkASSERT(ValidConic(conic));
80cb93a386Sopenharmony_ci        const SkDLine& line = oneOffs[index].line;
81cb93a386Sopenharmony_ci        SkASSERT(ValidLine(line));
82cb93a386Sopenharmony_ci        SkIntersections intersections;
83cb93a386Sopenharmony_ci        int result = doIntersect(intersections, conic, line, flipped);
84cb93a386Sopenharmony_ci        for (int inner = 0; inner < result; ++inner) {
85cb93a386Sopenharmony_ci            double conicT = intersections[0][inner];
86cb93a386Sopenharmony_ci            SkDPoint conicXY = conic.ptAtT(conicT);
87cb93a386Sopenharmony_ci            double lineT = intersections[1][inner];
88cb93a386Sopenharmony_ci            SkDPoint lineXY = line.ptAtT(lineT);
89cb93a386Sopenharmony_ci            if (!conicXY.approximatelyEqual(lineXY)) {
90cb93a386Sopenharmony_ci                conicXY.approximatelyEqual(lineXY);
91cb93a386Sopenharmony_ci            }
92cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, conicXY.approximatelyEqual(lineXY));
93cb93a386Sopenharmony_ci        }
94cb93a386Sopenharmony_ci    }
95cb93a386Sopenharmony_ci}
96cb93a386Sopenharmony_ci
97cb93a386Sopenharmony_ciDEF_TEST(PathOpsConicLineIntersectionOneOff, reporter) {
98cb93a386Sopenharmony_ci    testOneOffs(reporter);
99cb93a386Sopenharmony_ci}
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_ciDEF_TEST(PathOpsConicLineIntersection, reporter) {
102cb93a386Sopenharmony_ci    for (size_t index = 0; index < lineConicTests_count; ++index) {
103cb93a386Sopenharmony_ci        int iIndex = static_cast<int>(index);
104cb93a386Sopenharmony_ci        const ConicPts& c = lineConicTests[index].conic;
105cb93a386Sopenharmony_ci        SkDConic conic;
106cb93a386Sopenharmony_ci        conic.debugSet(c.fPts.fPts, c.fWeight);
107cb93a386Sopenharmony_ci        SkASSERT(ValidConic(conic));
108cb93a386Sopenharmony_ci        const SkDLine& line = lineConicTests[index].line;
109cb93a386Sopenharmony_ci        SkASSERT(ValidLine(line));
110cb93a386Sopenharmony_ci        SkReduceOrder reducer;
111cb93a386Sopenharmony_ci        SkPoint pts[3] = { conic.fPts.fPts[0].asSkPoint(), conic.fPts.fPts[1].asSkPoint(),
112cb93a386Sopenharmony_ci            conic.fPts.fPts[2].asSkPoint() };
113cb93a386Sopenharmony_ci        SkPoint reduced[3];
114cb93a386Sopenharmony_ci        SkConic floatConic;
115cb93a386Sopenharmony_ci        floatConic.set(pts, conic.fWeight);
116cb93a386Sopenharmony_ci        SkPath::Verb order1 = SkReduceOrder::Conic(floatConic, reduced);
117cb93a386Sopenharmony_ci        if (order1 != SkPath::kConic_Verb) {
118cb93a386Sopenharmony_ci            SkDebugf("%s [%d] conic verb=%d\n", __FUNCTION__, iIndex, order1);
119cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, 0);
120cb93a386Sopenharmony_ci        }
121cb93a386Sopenharmony_ci        int order2 = reducer.reduce(line);
122cb93a386Sopenharmony_ci        if (order2 < 2) {
123cb93a386Sopenharmony_ci            SkDebugf("%s [%d] line order=%d\n", __FUNCTION__, iIndex, order2);
124cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, 0);
125cb93a386Sopenharmony_ci        }
126cb93a386Sopenharmony_ci        SkIntersections intersections;
127cb93a386Sopenharmony_ci        bool flipped = false;
128cb93a386Sopenharmony_ci        int result = doIntersect(intersections, conic, line, flipped);
129cb93a386Sopenharmony_ci        REPORTER_ASSERT(reporter, result == lineConicTests[index].result);
130cb93a386Sopenharmony_ci        if (intersections.used() <= 0) {
131cb93a386Sopenharmony_ci            continue;
132cb93a386Sopenharmony_ci        }
133cb93a386Sopenharmony_ci        for (int pt = 0; pt < result; ++pt) {
134cb93a386Sopenharmony_ci            double tt1 = intersections[0][pt];
135cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, tt1 >= 0 && tt1 <= 1);
136cb93a386Sopenharmony_ci            SkDPoint t1 = conic.ptAtT(tt1);
137cb93a386Sopenharmony_ci            double tt2 = intersections[1][pt];
138cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, tt2 >= 0 && tt2 <= 1);
139cb93a386Sopenharmony_ci            SkDPoint t2 = line.ptAtT(tt2);
140cb93a386Sopenharmony_ci            if (!t1.approximatelyEqual(t2)) {
141cb93a386Sopenharmony_ci                SkDebugf("%s [%d,%d] x!= t1=%1.9g (%1.9g,%1.9g) t2=%1.9g (%1.9g,%1.9g)\n",
142cb93a386Sopenharmony_ci                    __FUNCTION__, iIndex, pt, tt1, t1.fX, t1.fY, tt2, t2.fX, t2.fY);
143cb93a386Sopenharmony_ci                REPORTER_ASSERT(reporter, 0);
144cb93a386Sopenharmony_ci            }
145cb93a386Sopenharmony_ci            if (!t1.approximatelyEqual(lineConicTests[index].expected[0])
146cb93a386Sopenharmony_ci                    && (lineConicTests[index].result == 1
147cb93a386Sopenharmony_ci                    || !t1.approximatelyEqual(lineConicTests[index].expected[1]))) {
148cb93a386Sopenharmony_ci                SkDebugf("%s t1=(%1.9g,%1.9g)\n", __FUNCTION__, t1.fX, t1.fY);
149cb93a386Sopenharmony_ci                REPORTER_ASSERT(reporter, 0);
150cb93a386Sopenharmony_ci            }
151cb93a386Sopenharmony_ci        }
152cb93a386Sopenharmony_ci    }
153cb93a386Sopenharmony_ci}
154