1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2013 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 "include/utils/SkRandom.h"
8cb93a386Sopenharmony_ci#include "src/pathops/SkIntersections.h"
9cb93a386Sopenharmony_ci#include "src/pathops/SkOpContour.h"
10cb93a386Sopenharmony_ci#include "src/pathops/SkOpSegment.h"
11cb93a386Sopenharmony_ci#include "tests/PathOpsTestCommon.h"
12cb93a386Sopenharmony_ci#include "tests/Test.h"
13cb93a386Sopenharmony_ci
14cb93a386Sopenharmony_cistatic bool gDisableAngleTests = true;
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_cistatic float next(float f)
17cb93a386Sopenharmony_ci{
18cb93a386Sopenharmony_ci    int fBits = SkFloatAs2sCompliment(f);
19cb93a386Sopenharmony_ci    ++fBits;
20cb93a386Sopenharmony_ci    float fNext = Sk2sComplimentAsFloat(fBits);
21cb93a386Sopenharmony_ci    return fNext;
22cb93a386Sopenharmony_ci}
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_cistatic float prev(float f)
25cb93a386Sopenharmony_ci{
26cb93a386Sopenharmony_ci    int fBits = SkFloatAs2sCompliment(f);
27cb93a386Sopenharmony_ci    --fBits;
28cb93a386Sopenharmony_ci    float fNext = Sk2sComplimentAsFloat(fBits);
29cb93a386Sopenharmony_ci    return fNext;
30cb93a386Sopenharmony_ci}
31cb93a386Sopenharmony_ci
32cb93a386Sopenharmony_ciDEF_TEST(PathOpsAngleFindCrossEpsilon, reporter) {
33cb93a386Sopenharmony_ci    if (gDisableAngleTests) {
34cb93a386Sopenharmony_ci        return;
35cb93a386Sopenharmony_ci    }
36cb93a386Sopenharmony_ci    SkRandom ran;
37cb93a386Sopenharmony_ci    int maxEpsilon = 0;
38cb93a386Sopenharmony_ci    for (int index = 0; index < 10000000; ++index) {
39cb93a386Sopenharmony_ci        SkDLine line = {{{0, 0}, {ran.nextRangeF(0.0001f, 1000), ran.nextRangeF(0.0001f, 1000)}}};
40cb93a386Sopenharmony_ci        for (int inner = 0; inner < 10; ++inner) {
41cb93a386Sopenharmony_ci            float t = ran.nextRangeF(0.0001f, 1);
42cb93a386Sopenharmony_ci            SkDPoint dPt = line.ptAtT(t);
43cb93a386Sopenharmony_ci            SkPoint pt = dPt.asSkPoint();
44cb93a386Sopenharmony_ci            float xs[3] = { prev(pt.fX), pt.fX, next(pt.fX) };
45cb93a386Sopenharmony_ci            float ys[3] = { prev(pt.fY), pt.fY, next(pt.fY) };
46cb93a386Sopenharmony_ci            for (int xIdx = 0; xIdx < 3; ++xIdx) {
47cb93a386Sopenharmony_ci                for (int yIdx = 0; yIdx < 3; ++yIdx) {
48cb93a386Sopenharmony_ci                    SkPoint test = { xs[xIdx], ys[yIdx] };
49cb93a386Sopenharmony_ci                    float p1 = SkDoubleToScalar(line[1].fX * test.fY);
50cb93a386Sopenharmony_ci                    float p2 = SkDoubleToScalar(line[1].fY * test.fX);
51cb93a386Sopenharmony_ci                    int p1Bits = SkFloatAs2sCompliment(p1);
52cb93a386Sopenharmony_ci                    int p2Bits = SkFloatAs2sCompliment(p2);
53cb93a386Sopenharmony_ci                    int epsilon = SkTAbs(p1Bits - p2Bits);
54cb93a386Sopenharmony_ci                    if (maxEpsilon < epsilon) {
55cb93a386Sopenharmony_ci                        SkDebugf("line={{0, 0}, {%1.7g, %1.7g}} t=%1.7g pt={%1.7g, %1.7g}"
56cb93a386Sopenharmony_ci                            " epsilon=%d\n",
57cb93a386Sopenharmony_ci                            line[1].fX, line[1].fY, t, test.fX, test.fY, epsilon);
58cb93a386Sopenharmony_ci                        maxEpsilon = epsilon;
59cb93a386Sopenharmony_ci                    }
60cb93a386Sopenharmony_ci                }
61cb93a386Sopenharmony_ci            }
62cb93a386Sopenharmony_ci        }
63cb93a386Sopenharmony_ci    }
64cb93a386Sopenharmony_ci}
65cb93a386Sopenharmony_ci
66cb93a386Sopenharmony_ciDEF_TEST(PathOpsAngleFindQuadEpsilon, reporter) {
67cb93a386Sopenharmony_ci    if (gDisableAngleTests) {
68cb93a386Sopenharmony_ci        return;
69cb93a386Sopenharmony_ci    }
70cb93a386Sopenharmony_ci    SkRandom ran;
71cb93a386Sopenharmony_ci    int maxEpsilon = 0;
72cb93a386Sopenharmony_ci    double maxAngle = 0;
73cb93a386Sopenharmony_ci    for (int index = 0; index < 100000; ++index) {
74cb93a386Sopenharmony_ci        SkDLine line = {{{0, 0}, {ran.nextRangeF(0.0001f, 1000), ran.nextRangeF(0.0001f, 1000)}}};
75cb93a386Sopenharmony_ci        float t = ran.nextRangeF(0.0001f, 1);
76cb93a386Sopenharmony_ci        SkDPoint dPt = line.ptAtT(t);
77cb93a386Sopenharmony_ci        float t2 = ran.nextRangeF(0.0001f, 1);
78cb93a386Sopenharmony_ci        SkDPoint qPt = line.ptAtT(t2);
79cb93a386Sopenharmony_ci        float t3 = ran.nextRangeF(0.0001f, 1);
80cb93a386Sopenharmony_ci        SkDPoint qPt2 = line.ptAtT(t3);
81cb93a386Sopenharmony_ci        qPt.fX += qPt2.fY;
82cb93a386Sopenharmony_ci        qPt.fY -= qPt2.fX;
83cb93a386Sopenharmony_ci        QuadPts q = {{line[0], dPt, qPt}};
84cb93a386Sopenharmony_ci        SkDQuad quad;
85cb93a386Sopenharmony_ci        quad.debugSet(q.fPts);
86cb93a386Sopenharmony_ci        // binary search for maximum movement of quad[1] towards test that still has 1 intersection
87cb93a386Sopenharmony_ci        double moveT = 0.5f;
88cb93a386Sopenharmony_ci        double deltaT = moveT / 2;
89cb93a386Sopenharmony_ci        SkDPoint last;
90cb93a386Sopenharmony_ci        do {
91cb93a386Sopenharmony_ci            last = quad[1];
92cb93a386Sopenharmony_ci            quad[1].fX = dPt.fX - line[1].fY * moveT;
93cb93a386Sopenharmony_ci            quad[1].fY = dPt.fY + line[1].fX * moveT;
94cb93a386Sopenharmony_ci            SkIntersections i;
95cb93a386Sopenharmony_ci            i.intersect(quad, line);
96cb93a386Sopenharmony_ci            REPORTER_ASSERT(reporter, i.used() > 0);
97cb93a386Sopenharmony_ci            if (i.used() == 1) {
98cb93a386Sopenharmony_ci                moveT += deltaT;
99cb93a386Sopenharmony_ci            } else {
100cb93a386Sopenharmony_ci                moveT -= deltaT;
101cb93a386Sopenharmony_ci            }
102cb93a386Sopenharmony_ci            deltaT /= 2;
103cb93a386Sopenharmony_ci        } while (last.asSkPoint() != quad[1].asSkPoint());
104cb93a386Sopenharmony_ci        float p1 = SkDoubleToScalar(line[1].fX * last.fY);
105cb93a386Sopenharmony_ci        float p2 = SkDoubleToScalar(line[1].fY * last.fX);
106cb93a386Sopenharmony_ci        int p1Bits = SkFloatAs2sCompliment(p1);
107cb93a386Sopenharmony_ci        int p2Bits = SkFloatAs2sCompliment(p2);
108cb93a386Sopenharmony_ci        int epsilon = SkTAbs(p1Bits - p2Bits);
109cb93a386Sopenharmony_ci        if (maxEpsilon < epsilon) {
110cb93a386Sopenharmony_ci            SkDebugf("line={{0, 0}, {%1.7g, %1.7g}} t=%1.7g/%1.7g/%1.7g moveT=%1.7g"
111cb93a386Sopenharmony_ci                    " pt={%1.7g, %1.7g} epsilon=%d\n",
112cb93a386Sopenharmony_ci                    line[1].fX, line[1].fY, t, t2, t3, moveT, last.fX, last.fY, epsilon);
113cb93a386Sopenharmony_ci            maxEpsilon = epsilon;
114cb93a386Sopenharmony_ci        }
115cb93a386Sopenharmony_ci        double a1 = atan2(line[1].fY, line[1].fX);
116cb93a386Sopenharmony_ci        double a2 = atan2(last.fY, last.fX);
117cb93a386Sopenharmony_ci        double angle = fabs(a1 - a2);
118cb93a386Sopenharmony_ci        if (maxAngle < angle) {
119cb93a386Sopenharmony_ci            SkDebugf("line={{0, 0}, {%1.7g, %1.7g}} t=%1.7g/%1.7g/%1.7g moveT=%1.7g"
120cb93a386Sopenharmony_ci                    " pt={%1.7g, %1.7g} angle=%1.7g\n",
121cb93a386Sopenharmony_ci                    line[1].fX, line[1].fY, t, t2, t3, moveT, last.fX, last.fY, angle);
122cb93a386Sopenharmony_ci            maxAngle = angle;
123cb93a386Sopenharmony_ci        }
124cb93a386Sopenharmony_ci    }
125cb93a386Sopenharmony_ci}
126cb93a386Sopenharmony_ci
127cb93a386Sopenharmony_cistatic int find_slop(double x, double y, double rx, double ry) {
128cb93a386Sopenharmony_ci    int slopBits = 0;
129cb93a386Sopenharmony_ci    bool less1, less2;
130cb93a386Sopenharmony_ci    double absX = fabs(x);
131cb93a386Sopenharmony_ci    double absY = fabs(y);
132cb93a386Sopenharmony_ci    double length = absX < absY ? absX / 2 + absY : absX + absY / 2;
133cb93a386Sopenharmony_ci    int exponent;
134cb93a386Sopenharmony_ci    (void) frexp(length, &exponent);
135cb93a386Sopenharmony_ci    double epsilon = ldexp(FLT_EPSILON, exponent);
136cb93a386Sopenharmony_ci    do {
137cb93a386Sopenharmony_ci        // get the length as the larger plus half the smaller (both same signs)
138cb93a386Sopenharmony_ci        // find the ulps of the length
139cb93a386Sopenharmony_ci        // compute the offsets from there
140cb93a386Sopenharmony_ci        double xSlop = epsilon * slopBits;
141cb93a386Sopenharmony_ci        double ySlop = x * y < 0 ? -xSlop : xSlop; // OPTIMIZATION: use copysign / _copysign ?
142cb93a386Sopenharmony_ci        double x1 = x - xSlop;
143cb93a386Sopenharmony_ci        double y1 = y + ySlop;
144cb93a386Sopenharmony_ci        double x_ry1 = x1 * ry;
145cb93a386Sopenharmony_ci        double rx_y1 = rx * y1;
146cb93a386Sopenharmony_ci        less1 = x_ry1 < rx_y1;
147cb93a386Sopenharmony_ci        double x2 = x + xSlop;
148cb93a386Sopenharmony_ci        double y2 = y - ySlop;
149cb93a386Sopenharmony_ci        double x_ry2 = x2 * ry;
150cb93a386Sopenharmony_ci        double rx_y2 = rx * y2;
151cb93a386Sopenharmony_ci        less2 = x_ry2 < rx_y2;
152cb93a386Sopenharmony_ci    } while (less1 == less2 && ++slopBits);
153cb93a386Sopenharmony_ci    return slopBits;
154cb93a386Sopenharmony_ci}
155cb93a386Sopenharmony_ci
156cb93a386Sopenharmony_ci// from http://stackoverflow.com/questions/1427422/cheap-algorithm-to-find-measure-of-angle-between-vectors
157cb93a386Sopenharmony_cistatic double diamond_angle(double y, double x)
158cb93a386Sopenharmony_ci{
159cb93a386Sopenharmony_ci    if (y >= 0)
160cb93a386Sopenharmony_ci        return (x >= 0 ? y/(x+y) : 1-x/(-x+y));
161cb93a386Sopenharmony_ci    else
162cb93a386Sopenharmony_ci        return (x < 0 ? 2-y/(-x-y) : 3+x/(x-y));
163cb93a386Sopenharmony_ci}
164cb93a386Sopenharmony_ci
165cb93a386Sopenharmony_cistatic const double slopTests[][4] = {
166cb93a386Sopenharmony_ci   // x                      y                       rx                      ry
167cb93a386Sopenharmony_ci    {-0.058554756452593892, -0.18804585843827226, -0.018568569646021160, -0.059615294434479438},
168cb93a386Sopenharmony_ci    {-0.0013717412948608398, 0.0041152238845825195, -0.00045837944195925573, 0.0013753175735478074},
169cb93a386Sopenharmony_ci    {-2.1033774145221198, -1.4046019261273715e-008, -0.70062688352066704, -1.2706324683777995e-008},
170cb93a386Sopenharmony_ci};
171cb93a386Sopenharmony_ci
172cb93a386Sopenharmony_ciDEF_TEST(PathOpsAngleFindSlop, reporter) {
173cb93a386Sopenharmony_ci    if (gDisableAngleTests) {
174cb93a386Sopenharmony_ci        return;
175cb93a386Sopenharmony_ci    }
176cb93a386Sopenharmony_ci    for (int index = 0; index < (int) SK_ARRAY_COUNT(slopTests); ++index) {
177cb93a386Sopenharmony_ci        const double* slopTest = slopTests[index];
178cb93a386Sopenharmony_ci        double x = slopTest[0];
179cb93a386Sopenharmony_ci        double y = slopTest[1];
180cb93a386Sopenharmony_ci        double rx = slopTest[2];
181cb93a386Sopenharmony_ci        double ry = slopTest[3];
182cb93a386Sopenharmony_ci        SkDebugf("%s  xy %d=%d\n", __FUNCTION__, index, find_slop(x, y, rx, ry));
183cb93a386Sopenharmony_ci        SkDebugf("%s rxy %d=%d\n", __FUNCTION__, index, find_slop(rx, ry, x, y));
184cb93a386Sopenharmony_ci        double angle = diamond_angle(y, x);
185cb93a386Sopenharmony_ci        double rAngle = diamond_angle(ry, rx);
186cb93a386Sopenharmony_ci        double diff = fabs(angle - rAngle);
187cb93a386Sopenharmony_ci        SkDebugf("%s diamond xy=%1.9g rxy=%1.9g diff=%1.9g factor=%d\n", __FUNCTION__,
188cb93a386Sopenharmony_ci                angle, rAngle, diff, (int) (diff / FLT_EPSILON));
189cb93a386Sopenharmony_ci    }
190cb93a386Sopenharmony_ci}
191cb93a386Sopenharmony_ci
192cb93a386Sopenharmony_ciclass PathOpsAngleTester {
193cb93a386Sopenharmony_cipublic:
194cb93a386Sopenharmony_ci    static int After(SkOpAngle& lh, SkOpAngle& rh) {
195cb93a386Sopenharmony_ci        return lh.after(&rh);
196cb93a386Sopenharmony_ci    }
197cb93a386Sopenharmony_ci
198cb93a386Sopenharmony_ci    static int AllOnOneSide(SkOpAngle& lh, SkOpAngle& rh) {
199cb93a386Sopenharmony_ci        return lh.lineOnOneSide(&rh, false);
200cb93a386Sopenharmony_ci    }
201cb93a386Sopenharmony_ci
202cb93a386Sopenharmony_ci    static int ConvexHullOverlaps(SkOpAngle& lh, SkOpAngle& rh) {
203cb93a386Sopenharmony_ci        return lh.convexHullOverlaps(&rh);
204cb93a386Sopenharmony_ci    }
205cb93a386Sopenharmony_ci
206cb93a386Sopenharmony_ci    static int Orderable(SkOpAngle& lh, SkOpAngle& rh) {
207cb93a386Sopenharmony_ci        return lh.orderable(&rh);
208cb93a386Sopenharmony_ci    }
209cb93a386Sopenharmony_ci
210cb93a386Sopenharmony_ci    static int EndsIntersect(SkOpAngle& lh, SkOpAngle& rh) {
211cb93a386Sopenharmony_ci        return lh.endsIntersect(&rh);
212cb93a386Sopenharmony_ci    }
213cb93a386Sopenharmony_ci
214cb93a386Sopenharmony_ci    static void SetNext(SkOpAngle& lh, SkOpAngle& rh) {
215cb93a386Sopenharmony_ci        lh.fNext = &rh;
216cb93a386Sopenharmony_ci    }
217cb93a386Sopenharmony_ci};
218cb93a386Sopenharmony_ci
219cb93a386Sopenharmony_ciclass PathOpsSegmentTester {
220cb93a386Sopenharmony_cipublic:
221cb93a386Sopenharmony_ci    static void DebugReset(SkOpSegment* segment) {
222cb93a386Sopenharmony_ci        segment->debugReset();
223cb93a386Sopenharmony_ci    }
224cb93a386Sopenharmony_ci};
225cb93a386Sopenharmony_ci
226cb93a386Sopenharmony_cistruct CircleData {
227cb93a386Sopenharmony_ci    const CubicPts fPts;
228cb93a386Sopenharmony_ci    const int fPtCount;
229cb93a386Sopenharmony_ci    SkPoint fShortPts[4];
230cb93a386Sopenharmony_ci};
231cb93a386Sopenharmony_ci
232cb93a386Sopenharmony_cistatic CircleData circleDataSet[] = {
233cb93a386Sopenharmony_ci    { {{{313.0155029296875, 207.90290832519531}, {320.05078125, 227.58743286132812}}}, 2, {} },
234cb93a386Sopenharmony_ci    { {{{313.0155029296875, 207.90290832519531}, {313.98246891063195, 219.33615203830394},
235cb93a386Sopenharmony_ci            {320.05078125, 227.58743286132812}}}, 3, {} },
236cb93a386Sopenharmony_ci};
237cb93a386Sopenharmony_ci
238cb93a386Sopenharmony_cistatic const int circleDataSetSize = (int) SK_ARRAY_COUNT(circleDataSet);
239cb93a386Sopenharmony_ci
240cb93a386Sopenharmony_ciDEF_TEST(PathOpsAngleCircle, reporter) {
241cb93a386Sopenharmony_ci    SkSTArenaAlloc<4096> allocator;
242cb93a386Sopenharmony_ci    SkOpContourHead contour;
243cb93a386Sopenharmony_ci    SkOpGlobalState state(&contour, &allocator  SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr));
244cb93a386Sopenharmony_ci    contour.init(&state, false, false);
245cb93a386Sopenharmony_ci    for (int index = 0; index < circleDataSetSize; ++index) {
246cb93a386Sopenharmony_ci        CircleData& data = circleDataSet[index];
247cb93a386Sopenharmony_ci        for (int idx2 = 0; idx2 < data.fPtCount; ++idx2) {
248cb93a386Sopenharmony_ci            data.fShortPts[idx2] = data.fPts.fPts[idx2].asSkPoint();
249cb93a386Sopenharmony_ci        }
250cb93a386Sopenharmony_ci        switch (data.fPtCount) {
251cb93a386Sopenharmony_ci            case 2:
252cb93a386Sopenharmony_ci                contour.addLine(data.fShortPts);
253cb93a386Sopenharmony_ci                break;
254cb93a386Sopenharmony_ci            case 3:
255cb93a386Sopenharmony_ci                contour.addQuad(data.fShortPts);
256cb93a386Sopenharmony_ci                break;
257cb93a386Sopenharmony_ci            case 4:
258cb93a386Sopenharmony_ci                contour.addCubic(data.fShortPts);
259cb93a386Sopenharmony_ci                break;
260cb93a386Sopenharmony_ci        }
261cb93a386Sopenharmony_ci    }
262cb93a386Sopenharmony_ci    SkOpSegment* first = contour.first();
263cb93a386Sopenharmony_ci    first->debugAddAngle(0, 1);
264cb93a386Sopenharmony_ci    SkOpSegment* next = first->next();
265cb93a386Sopenharmony_ci    next->debugAddAngle(0, 1);
266cb93a386Sopenharmony_ci    PathOpsAngleTester::Orderable(*first->debugLastAngle(), *next->debugLastAngle());
267cb93a386Sopenharmony_ci}
268cb93a386Sopenharmony_ci
269cb93a386Sopenharmony_cistruct IntersectData {
270cb93a386Sopenharmony_ci    const CubicPts fPts;
271cb93a386Sopenharmony_ci    const int fPtCount;
272cb93a386Sopenharmony_ci    double fTStart;
273cb93a386Sopenharmony_ci    double fTEnd;
274cb93a386Sopenharmony_ci    SkPoint fShortPts[4];
275cb93a386Sopenharmony_ci};
276cb93a386Sopenharmony_ci
277cb93a386Sopenharmony_cistatic IntersectData intersectDataSet1[] = {
278cb93a386Sopenharmony_ci    { {{{322.935669,231.030273}, {312.832214,220.393295}, {312.832214,203.454178}}}, 3,
279cb93a386Sopenharmony_ci            0.865309956, 0.154740299, {} },
280cb93a386Sopenharmony_ci    { {{{322.12738,233.397751}, {295.718353,159.505829}}}, 2,
281cb93a386Sopenharmony_ci            0.345028807, 0.0786326511, {} },
282cb93a386Sopenharmony_ci    { {{{322.935669,231.030273}, {312.832214,220.393295}, {312.832214,203.454178}}}, 3,
283cb93a386Sopenharmony_ci            0.865309956, 1, {} },
284cb93a386Sopenharmony_ci    { {{{322.12738,233.397751}, {295.718353,159.505829}}}, 2,
285cb93a386Sopenharmony_ci            0.345028807, 1, {} },
286cb93a386Sopenharmony_ci};
287cb93a386Sopenharmony_ci
288cb93a386Sopenharmony_cistatic IntersectData intersectDataSet2[] = {
289cb93a386Sopenharmony_ci    { {{{364.390686,157.898193}, {375.281769,136.674606}, {396.039917,136.674606}}}, 3,
290cb93a386Sopenharmony_ci            0.578520747, 1, {} },
291cb93a386Sopenharmony_ci    { {{{364.390686,157.898193}, {375.281769,136.674606}, {396.039917,136.674606}}}, 3,
292cb93a386Sopenharmony_ci            0.578520747, 0.536512973, {} },
293cb93a386Sopenharmony_ci    { {{{366.608826,151.196014}, {378.803101,136.674606}, {398.164948,136.674606}}}, 3,
294cb93a386Sopenharmony_ci            0.490456543, 1, {} },
295cb93a386Sopenharmony_ci};
296cb93a386Sopenharmony_ci
297cb93a386Sopenharmony_cistatic IntersectData intersectDataSet3[] = {
298cb93a386Sopenharmony_ci    { {{{2.000000,0.000000}, {1.33333333,0.66666667}}}, 2, 1, 0, {} },
299cb93a386Sopenharmony_ci    { {{{1.33333333,0.66666667}, {0.000000,2.000000}}}, 2, 0, 0.25, {} },
300cb93a386Sopenharmony_ci    { {{{2.000000,2.000000}, {1.33333333,0.66666667}}}, 2, 1, 0, {} },
301cb93a386Sopenharmony_ci};
302cb93a386Sopenharmony_ci
303cb93a386Sopenharmony_cistatic IntersectData intersectDataSet4[] = {
304cb93a386Sopenharmony_ci    { {{{1.3333333,0.6666667}, {0.000,2.000}}}, 2, 0.250000006, 0, {} },
305cb93a386Sopenharmony_ci    { {{{1.000,0.000}, {1.000,1.000}}}, 2, 1, 0, {} },
306cb93a386Sopenharmony_ci    { {{{1.000,1.000}, {0.000,0.000}}}, 2, 0, 1, {} },
307cb93a386Sopenharmony_ci};
308cb93a386Sopenharmony_ci
309cb93a386Sopenharmony_cistatic IntersectData intersectDataSet5[] = {
310cb93a386Sopenharmony_ci    { {{{0.000,0.000}, {1.000,0.000}, {1.000,1.000}}}, 3, 1, 0.666666667, {} },
311cb93a386Sopenharmony_ci    { {{{0.000,0.000}, {2.000,1.000}, {0.000,2.000}}}, 3, 0.5, 1, {} },
312cb93a386Sopenharmony_ci    { {{{0.000,0.000}, {2.000,1.000}, {0.000,2.000}}}, 3, 0.5, 0, {} },
313cb93a386Sopenharmony_ci};
314cb93a386Sopenharmony_ci
315cb93a386Sopenharmony_cistatic IntersectData intersectDataSet6[] = { // pathops_visualizer.htm:3658
316cb93a386Sopenharmony_ci    { {{{0.000,1.000}, {3.000,4.000}, {1.000,0.000}, {3.000,0.000}}}, 4, 0.0925339054, 0, {} }, // pathops_visualizer.htm:3616
317cb93a386Sopenharmony_ci    { {{{0.000,1.000}, {0.000,3.000}, {1.000,0.000}, {4.000,3.000}}}, 4, 0.453872386, 0, {} }, // pathops_visualizer.htm:3616
318cb93a386Sopenharmony_ci    { {{{0.000,1.000}, {3.000,4.000}, {1.000,0.000}, {3.000,0.000}}}, 4, 0.0925339054, 0.417096368, {} }, // pathops_visualizer.htm:3616
319cb93a386Sopenharmony_ci};
320cb93a386Sopenharmony_ci
321cb93a386Sopenharmony_cistatic IntersectData intersectDataSet7[] = { // pathops_visualizer.htm:3748
322cb93a386Sopenharmony_ci    { {{{2.000,1.000}, {0.000,1.000}}}, 2, 0.5, 0, {} }, // pathops_visualizer.htm:3706
323cb93a386Sopenharmony_ci    { {{{2.000,0.000}, {0.000,2.000}}}, 2, 0.5, 1, {} }, // pathops_visualizer.htm:3706
324cb93a386Sopenharmony_ci    { {{{0.000,1.000}, {0.000,2.000}, {2.000,0.000}, {2.000,1.000}}}, 4, 0.5, 1, {} }, // pathops_visualizer.htm:3706
325cb93a386Sopenharmony_ci}; //
326cb93a386Sopenharmony_ci
327cb93a386Sopenharmony_cistatic IntersectData intersectDataSet8[] = { // pathops_visualizer.htm:4194
328cb93a386Sopenharmony_ci    { {{{0.000,1.000}, {2.000,3.000}, {5.000,1.000}, {4.000,3.000}}}, 4, 0.311007457, 0.285714286, {} }, // pathops_visualizer.htm:4152
329cb93a386Sopenharmony_ci    { {{{1.000,5.000}, {3.000,4.000}, {1.000,0.000}, {3.000,2.000}}}, 4, 0.589885081, 0.999982974, {} }, // pathops_visualizer.htm:4152
330cb93a386Sopenharmony_ci    { {{{1.000,5.000}, {3.000,4.000}, {1.000,0.000}, {3.000,2.000}}}, 4, 0.589885081, 0.576935809, {} }, // pathops_visualizer.htm:4152
331cb93a386Sopenharmony_ci}; //
332cb93a386Sopenharmony_ci
333cb93a386Sopenharmony_cistatic IntersectData intersectDataSet9[] = { // pathops_visualizer.htm:4142
334cb93a386Sopenharmony_ci    { {{{0.000,1.000}, {2.000,3.000}, {5.000,1.000}, {4.000,3.000}}}, 4, 0.476627072, 0.311007457, {} }, // pathops_visualizer.htm:4100
335cb93a386Sopenharmony_ci    { {{{1.000,5.000}, {3.000,4.000}, {1.000,0.000}, {3.000,2.000}}}, 4, 0.999982974, 1, {} }, // pathops_visualizer.htm:4100
336cb93a386Sopenharmony_ci    { {{{0.000,1.000}, {2.000,3.000}, {5.000,1.000}, {4.000,3.000}}}, 4, 0.476627072, 1, {} }, // pathops_visualizer.htm:4100
337cb93a386Sopenharmony_ci}; //
338cb93a386Sopenharmony_ci
339cb93a386Sopenharmony_cistatic IntersectData intersectDataSet10[] = { // pathops_visualizer.htm:4186
340cb93a386Sopenharmony_ci    { {{{0.000,1.000}, {1.000,6.000}, {1.000,0.000}, {1.000,0.000}}}, 4, 0.788195121, 0.726275769, {} }, // pathops_visualizer.htm:4144
341cb93a386Sopenharmony_ci    { {{{0.000,1.000}, {0.000,1.000}, {1.000,0.000}, {6.000,1.000}}}, 4, 0.473378977, 1, {} }, // pathops_visualizer.htm:4144
342cb93a386Sopenharmony_ci    { {{{0.000,1.000}, {1.000,6.000}, {1.000,0.000}, {1.000,0.000}}}, 4, 0.788195121, 1, {} }, // pathops_visualizer.htm:4144
343cb93a386Sopenharmony_ci}; //
344cb93a386Sopenharmony_ci
345cb93a386Sopenharmony_cistatic IntersectData intersectDataSet11[] = { // pathops_visualizer.htm:4704
346cb93a386Sopenharmony_ci    { {{{979.305,561.000}, {1036.695,291.000}}}, 2, 0.888888874, 0.11111108, {} }, // pathops_visualizer.htm:4662
347cb93a386Sopenharmony_ci    { {{{1006.695,291.000}, {1023.264,291.000}, {1033.840,304.431}, {1030.318,321.000}}}, 4, 1, 0, {} }, // pathops_visualizer.htm:4662
348cb93a386Sopenharmony_ci    { {{{979.305,561.000}, {1036.695,291.000}}}, 2, 0.888888874, 1, {} }, // pathops_visualizer.htm:4662
349cb93a386Sopenharmony_ci}; //
350cb93a386Sopenharmony_ci
351cb93a386Sopenharmony_cistatic IntersectData intersectDataSet12[] = { // pathops_visualizer.htm:5481
352cb93a386Sopenharmony_ci    { {{{67.000,912.000}, {67.000,913.000}}}, 2, 1, 0, {} }, // pathops_visualizer.htm:5439
353cb93a386Sopenharmony_ci    { {{{67.000,913.000}, {67.000,917.389}, {67.224,921.726}, {67.662,926.000}}}, 4, 0, 1, {} }, // pathops_visualizer.htm:5439
354cb93a386Sopenharmony_ci    { {{{194.000,1041.000}, {123.860,1041.000}, {67.000,983.692}, {67.000,913.000}}}, 4, 1, 0, {} }, // pathops_visualizer.htm:5439
355cb93a386Sopenharmony_ci}; //
356cb93a386Sopenharmony_ci
357cb93a386Sopenharmony_cistatic IntersectData intersectDataSet13[] = { // pathops_visualizer.htm:5735
358cb93a386Sopenharmony_ci    { {{{6.000,0.000}, {0.000,4.000}}}, 2, 0.625, 0.25, {} }, // pathops_visualizer.htm:5693
359cb93a386Sopenharmony_ci    { {{{0.000,1.000}, {0.000,6.000}, {4.000,0.000}, {6.000,1.000}}}, 4, 0.5, 0.833333333, {} }, // pathops_visualizer.htm:5693
360cb93a386Sopenharmony_ci    { {{{0.000,1.000}, {0.000,6.000}, {4.000,0.000}, {6.000,1.000}}}, 4, 0.5, 0.379043969, {} }, // pathops_visualizer.htm:5693
361cb93a386Sopenharmony_ci}; //
362cb93a386Sopenharmony_ci
363cb93a386Sopenharmony_cistatic IntersectData intersectDataSet14[] = { // pathops_visualizer.htm:5875
364cb93a386Sopenharmony_ci    { {{{0.000,1.000}, {4.000,6.000}, {2.000,1.000}, {2.000,0.000}}}, 4, 0.0756502183, 0.0594570973, {} }, // pathops_visualizer.htm:5833
365cb93a386Sopenharmony_ci    { {{{1.000,2.000}, {0.000,2.000}, {1.000,0.000}, {6.000,4.000}}}, 4, 0.0756502184, 0, {} }, // pathops_visualizer.htm:5833
366cb93a386Sopenharmony_ci    { {{{0.000,1.000}, {4.000,6.000}, {2.000,1.000}, {2.000,0.000}}}, 4, 0.0756502183, 0.531917258, {} }, // pathops_visualizer.htm:5833
367cb93a386Sopenharmony_ci}; //
368cb93a386Sopenharmony_ci
369cb93a386Sopenharmony_cistatic IntersectData intersectDataSet15[] = { // pathops_visualizer.htm:6580
370cb93a386Sopenharmony_ci    { {{{490.435,879.407}, {405.593,909.436}}}, 2, 0.500554405, 1, {} }, // pathops_visualizer.htm:6538
371cb93a386Sopenharmony_ci    { {{{447.967,894.438}, {448.007,894.424}, {448.014,894.422}}}, 3, 0, 1, {} }, // pathops_visualizer.htm:6538
372cb93a386Sopenharmony_ci    { {{{490.435,879.407}, {405.593,909.436}}}, 2, 0.500554405, 0.500000273, {} }, // pathops_visualizer.htm:6538
373cb93a386Sopenharmony_ci}; //
374cb93a386Sopenharmony_ci
375cb93a386Sopenharmony_cistatic IntersectData intersectDataSet16[] = { // pathops_visualizer.htm:7419
376cb93a386Sopenharmony_ci    { {{{1.000,4.000}, {4.000,5.000}, {3.000,2.000}, {6.000,3.000}}}, 4, 0.5, 0, {} }, // pathops_visualizer.htm:7377
377cb93a386Sopenharmony_ci    { {{{2.000,3.000}, {3.000,6.000}, {4.000,1.000}, {5.000,4.000}}}, 4, 0.5, 0.112701665, {} }, // pathops_visualizer.htm:7377
378cb93a386Sopenharmony_ci    { {{{5.000,4.000}, {2.000,3.000}}}, 2, 0.5, 0, {} }, // pathops_visualizer.htm:7377
379cb93a386Sopenharmony_ci}; //
380cb93a386Sopenharmony_ci
381cb93a386Sopenharmony_ci// from skpi_gino_com_16
382cb93a386Sopenharmony_cistatic IntersectData intersectDataSet17[] = {
383cb93a386Sopenharmony_ci    { /*seg=7*/ {{{270.974121f, 770.025879f}, {234.948273f, 734}, {184, 734}}}
384cb93a386Sopenharmony_ci        , 3, 0.74590454, 0.547660352, {} },
385cb93a386Sopenharmony_ci    { /*seg=8*/ {{{185, 734}, {252.93103f, 734}, {308, 789.06897f}, {308, 857}}}
386cb93a386Sopenharmony_ci        , 4, 0.12052623, 0, {} },
387cb93a386Sopenharmony_ci    { /*seg=7*/ {{{270.974121f, 770.025879f}, {234.948273f, 734}, {184, 734}}}
388cb93a386Sopenharmony_ci        , 3, 0.74590454, 1, {} },
389cb93a386Sopenharmony_ci};
390cb93a386Sopenharmony_ci
391cb93a386Sopenharmony_cistatic IntersectData intersectDataSet18[] = {
392cb93a386Sopenharmony_ci    { /*seg=7*/ {{{270.974121f, 770.025879f}, {234.948273f, 734}, {184, 734}}}
393cb93a386Sopenharmony_ci        , 3, 0.74590454, 1, {} },
394cb93a386Sopenharmony_ci    { /*seg=8*/ {{{185, 734}, {252.93103f, 734}, {308, 789.06897f}, {308, 857}}}
395cb93a386Sopenharmony_ci        , 4, 0.12052623, 0.217351928, {} },
396cb93a386Sopenharmony_ci    { /*seg=7*/ {{{270.974121f, 770.025879f}, {234.948273f, 734}, {184, 734}}}
397cb93a386Sopenharmony_ci        , 3, 0.74590454, 0.547660352, {} },
398cb93a386Sopenharmony_ci};
399cb93a386Sopenharmony_ci
400cb93a386Sopenharmony_cistatic IntersectData intersectDataSet19[] = {
401cb93a386Sopenharmony_ci    { /*seg=1*/ {{{0, 1}, {3, 5}, {2, 1}, {3, 1}}}
402cb93a386Sopenharmony_ci        , 4, 0.135148995, 0.134791946, {} },
403cb93a386Sopenharmony_ci    { /*seg=3*/ {{{1, 2}, {1, 2.15061641f}, {1, 2.21049166f}, {1.01366711f, 2.21379328f}}}
404cb93a386Sopenharmony_ci        , 4, 0.956740456, 0.894913214, {} },
405cb93a386Sopenharmony_ci    { /*seg=1*/ {{{0, 1}, {3, 5}, {2, 1}, {3, 1}}}
406cb93a386Sopenharmony_ci        , 4, 0.135148995, 0.551812363, {} },
407cb93a386Sopenharmony_ci};
408cb93a386Sopenharmony_ci
409cb93a386Sopenharmony_ci#define I(x) intersectDataSet##x
410cb93a386Sopenharmony_ci
411cb93a386Sopenharmony_cistatic IntersectData* intersectDataSets[] = {
412cb93a386Sopenharmony_ci    I(1), I(2), I(3), I(4), I(5), I(6), I(7), I(8), I(9), I(10),
413cb93a386Sopenharmony_ci    I(11), I(12), I(13), I(14), I(15), I(16), I(17), I(18), I(19),
414cb93a386Sopenharmony_ci};
415cb93a386Sopenharmony_ci
416cb93a386Sopenharmony_ci#undef I
417cb93a386Sopenharmony_ci#define I(x) (int) SK_ARRAY_COUNT(intersectDataSet##x)
418cb93a386Sopenharmony_ci
419cb93a386Sopenharmony_cistatic const int intersectDataSetSizes[] = {
420cb93a386Sopenharmony_ci    I(1), I(2), I(3), I(4), I(5), I(6), I(7), I(8), I(9), I(10),
421cb93a386Sopenharmony_ci    I(11), I(12), I(13), I(14), I(15), I(16), I(17), I(18), I(19),
422cb93a386Sopenharmony_ci};
423cb93a386Sopenharmony_ci
424cb93a386Sopenharmony_ci#undef I
425cb93a386Sopenharmony_ci
426cb93a386Sopenharmony_cistatic const int intersectDataSetsSize = (int) SK_ARRAY_COUNT(intersectDataSetSizes);
427cb93a386Sopenharmony_ci
428cb93a386Sopenharmony_cistruct FourPoints {
429cb93a386Sopenharmony_ci    SkPoint pts[4];
430cb93a386Sopenharmony_ci};
431cb93a386Sopenharmony_ci
432cb93a386Sopenharmony_ciDEF_TEST(PathOpsAngleAfter, reporter) {
433cb93a386Sopenharmony_ci    for (int index = intersectDataSetsSize - 1; index >= 0; --index) {
434cb93a386Sopenharmony_ci        IntersectData* dataArray = intersectDataSets[index];
435cb93a386Sopenharmony_ci        const int dataSize = intersectDataSetSizes[index];
436cb93a386Sopenharmony_ci        for (int index2 = 0; index2 < dataSize - 2; ++index2) {
437cb93a386Sopenharmony_ci            SkSTArenaAlloc<4096> alloc;
438cb93a386Sopenharmony_ci            SkOpContourHead contour;
439cb93a386Sopenharmony_ci            SkOpGlobalState state(&contour, &alloc  SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr));
440cb93a386Sopenharmony_ci            contour.init(&state, false, false);
441cb93a386Sopenharmony_ci            for (int index3 = 0; index3 < 3; ++index3) {
442cb93a386Sopenharmony_ci                IntersectData& data = dataArray[index2 + index3];
443cb93a386Sopenharmony_ci                SkPoint* temp = (SkPoint*) alloc.make<FourPoints>();
444cb93a386Sopenharmony_ci                for (int idx2 = 0; idx2 < data.fPtCount; ++idx2) {
445cb93a386Sopenharmony_ci                    temp[idx2] = data.fPts.fPts[idx2].asSkPoint();
446cb93a386Sopenharmony_ci                }
447cb93a386Sopenharmony_ci                switch (data.fPtCount) {
448cb93a386Sopenharmony_ci                    case 2: {
449cb93a386Sopenharmony_ci                        contour.addLine(temp);
450cb93a386Sopenharmony_ci                        } break;
451cb93a386Sopenharmony_ci                    case 3: {
452cb93a386Sopenharmony_ci                        contour.addQuad(temp);
453cb93a386Sopenharmony_ci                        } break;
454cb93a386Sopenharmony_ci                    case 4: {
455cb93a386Sopenharmony_ci                        contour.addCubic(temp);
456cb93a386Sopenharmony_ci                        } break;
457cb93a386Sopenharmony_ci                }
458cb93a386Sopenharmony_ci            }
459cb93a386Sopenharmony_ci            SkOpSegment* seg1 = contour.first();
460cb93a386Sopenharmony_ci            seg1->debugAddAngle(dataArray[index2 + 0].fTStart, dataArray[index2 + 0].fTEnd);
461cb93a386Sopenharmony_ci            SkOpSegment* seg2 = seg1->next();
462cb93a386Sopenharmony_ci            seg2->debugAddAngle(dataArray[index2 + 1].fTStart, dataArray[index2 + 1].fTEnd);
463cb93a386Sopenharmony_ci            SkOpSegment* seg3 = seg2->next();
464cb93a386Sopenharmony_ci            seg3->debugAddAngle(dataArray[index2 + 2].fTStart, dataArray[index2 + 2].fTEnd);
465cb93a386Sopenharmony_ci            SkOpAngle& angle1 = *seg1->debugLastAngle();
466cb93a386Sopenharmony_ci            SkOpAngle& angle2 = *seg2->debugLastAngle();
467cb93a386Sopenharmony_ci            SkOpAngle& angle3 = *seg3->debugLastAngle();
468cb93a386Sopenharmony_ci            PathOpsAngleTester::SetNext(angle1, angle3);
469cb93a386Sopenharmony_ci       // These data sets are seeded when the set itself fails, so likely the dataset does not
470cb93a386Sopenharmony_ci       // match the expected result. The tests above return 1 when first added, but
471cb93a386Sopenharmony_ci       // return 0 after the bug is fixed.
472cb93a386Sopenharmony_ci            SkDEBUGCODE(int result =) PathOpsAngleTester::After(angle2, angle1);
473cb93a386Sopenharmony_ci            SkASSERT(result == 0 || result == 1);
474cb93a386Sopenharmony_ci        }
475cb93a386Sopenharmony_ci    }
476cb93a386Sopenharmony_ci}
477cb93a386Sopenharmony_ci
478cb93a386Sopenharmony_civoid SkOpSegment::debugAddAngle(double startT, double endT) {
479cb93a386Sopenharmony_ci    SkOpPtT* startPtT = startT == 0 ? fHead.ptT() : startT == 1 ? fTail.ptT()
480cb93a386Sopenharmony_ci            : this->addT(startT);
481cb93a386Sopenharmony_ci    SkOpPtT* endPtT = endT == 0 ? fHead.ptT() : endT == 1 ? fTail.ptT()
482cb93a386Sopenharmony_ci            : this->addT(endT);
483cb93a386Sopenharmony_ci    SkOpAngle* angle = this->globalState()->allocator()->make<SkOpAngle>();
484cb93a386Sopenharmony_ci    SkOpSpanBase* startSpan = &fHead;
485cb93a386Sopenharmony_ci    while (startSpan->ptT() != startPtT) {
486cb93a386Sopenharmony_ci        startSpan = startSpan->upCast()->next();
487cb93a386Sopenharmony_ci    }
488cb93a386Sopenharmony_ci    SkOpSpanBase* endSpan = &fHead;
489cb93a386Sopenharmony_ci    while (endSpan->ptT() != endPtT) {
490cb93a386Sopenharmony_ci        endSpan = endSpan->upCast()->next();
491cb93a386Sopenharmony_ci    }
492cb93a386Sopenharmony_ci    angle->set(startSpan, endSpan);
493cb93a386Sopenharmony_ci    if (startT < endT) {
494cb93a386Sopenharmony_ci        startSpan->upCast()->setToAngle(angle);
495cb93a386Sopenharmony_ci        endSpan->setFromAngle(angle);
496cb93a386Sopenharmony_ci    } else {
497cb93a386Sopenharmony_ci        endSpan->upCast()->setToAngle(angle);
498cb93a386Sopenharmony_ci        startSpan->setFromAngle(angle);
499cb93a386Sopenharmony_ci    }
500cb93a386Sopenharmony_ci}
501cb93a386Sopenharmony_ci
502cb93a386Sopenharmony_ciDEF_TEST(PathOpsAngleAllOnOneSide, reporter) {
503cb93a386Sopenharmony_ci    SkSTArenaAlloc<4096> allocator;
504cb93a386Sopenharmony_ci    SkOpContourHead contour;
505cb93a386Sopenharmony_ci    SkOpGlobalState state(&contour, &allocator  SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr));
506cb93a386Sopenharmony_ci    contour.init(&state, false, false);
507cb93a386Sopenharmony_ci    SkPoint conicPts[3] = {{494.37100219726562f, 224.66200256347656f},
508cb93a386Sopenharmony_ci        {494.37360910682298f, 224.6729026561527f},
509cb93a386Sopenharmony_ci        {494.37600708007813f, 224.68400573730469f}};
510cb93a386Sopenharmony_ci    SkPoint linePts[2] = {{494.371002f, 224.662003f}, {494.375000f, 224.675995f}};
511cb93a386Sopenharmony_ci    for (int i = 10; i >= 0; --i) {
512cb93a386Sopenharmony_ci        SkPoint modLinePts[2] = { linePts[0], linePts[1] };
513cb93a386Sopenharmony_ci        modLinePts[1].fX += i * .1f;
514cb93a386Sopenharmony_ci        contour.addLine(modLinePts);
515cb93a386Sopenharmony_ci        contour.addQuad(conicPts);
516cb93a386Sopenharmony_ci   //     contour.addConic(conicPts, 0.999935746f, &allocator);
517cb93a386Sopenharmony_ci        SkOpSegment* first = contour.first();
518cb93a386Sopenharmony_ci        first->debugAddAngle(0, 1);
519cb93a386Sopenharmony_ci        SkOpSegment* next = first->next();
520cb93a386Sopenharmony_ci        next->debugAddAngle(0, 1);
521cb93a386Sopenharmony_ci        /* int result = */
522cb93a386Sopenharmony_ci            PathOpsAngleTester::AllOnOneSide(*first->debugLastAngle(), *next->debugLastAngle());
523cb93a386Sopenharmony_ci  //      SkDebugf("i=%d result=%d\n", i , result);
524cb93a386Sopenharmony_ci    }
525cb93a386Sopenharmony_ci}
526