xref: /aosp_15_r20/external/skia/modules/bentleyottmann/tests/MyersTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker // Copyright 2023 Google LLC
2*c8dee2aaSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3*c8dee2aaSAndroid Build Coastguard Worker 
4*c8dee2aaSAndroid Build Coastguard Worker #include "modules/bentleyottmann/include/Myers.h"
5*c8dee2aaSAndroid Build Coastguard Worker 
6*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
7*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
8*c8dee2aaSAndroid Build Coastguard Worker 
9*c8dee2aaSAndroid Build Coastguard Worker #include <chrono>
10*c8dee2aaSAndroid Build Coastguard Worker #include <cinttypes>
11*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
12*c8dee2aaSAndroid Build Coastguard Worker 
13*c8dee2aaSAndroid Build Coastguard Worker namespace myers {
14*c8dee2aaSAndroid Build Coastguard Worker bool slope_s0_less_than_slope_s1(const Segment& s0, const Segment& s1);
15*c8dee2aaSAndroid Build Coastguard Worker bool segment_less_than_upper_to_insert(const Segment& segment, const Segment& to_insert);
16*c8dee2aaSAndroid Build Coastguard Worker bool s0_less_than_s1_at_y(const Segment& s0, const Segment& s1, int32_t y);
17*c8dee2aaSAndroid Build Coastguard Worker bool s0_intersects_s1(const Segment& s0, const Segment& s1);
18*c8dee2aaSAndroid Build Coastguard Worker }  // namespace myers
19*c8dee2aaSAndroid Build Coastguard Worker 
20*c8dee2aaSAndroid Build Coastguard Worker using namespace myers;
21*c8dee2aaSAndroid Build Coastguard Worker 
operator ==(std::pair<const Point &,const Point &> l,std::tuple<Point,Point> r)22*c8dee2aaSAndroid Build Coastguard Worker static bool operator==(std::pair<const Point &, const Point &> l, std::tuple<Point, Point> r) {
23*c8dee2aaSAndroid Build Coastguard Worker     return std::get<0>(l) == std::get<0>(r) && std::get<1>(l) == std::get<1>(r);
24*c8dee2aaSAndroid Build Coastguard Worker }
25*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MFC_order_segment_points,r)26*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MFC_order_segment_points, r) {
27*c8dee2aaSAndroid Build Coastguard Worker     {
28*c8dee2aaSAndroid Build Coastguard Worker         Point p0 = {0, 0},
29*c8dee2aaSAndroid Build Coastguard Worker               p1 = {1, 1};
30*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, std::minmax(p0, p1) == std::make_tuple(p0, p1));
31*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, std::minmax(p1, p0) == std::make_tuple(p0, p1));
32*c8dee2aaSAndroid Build Coastguard Worker     }
33*c8dee2aaSAndroid Build Coastguard Worker     {
34*c8dee2aaSAndroid Build Coastguard Worker         Point p0 = {0, 0},
35*c8dee2aaSAndroid Build Coastguard Worker               p1 = {-1, 1};
36*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, std::minmax(p0, p1) == std::make_tuple(p0, p1));
37*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, std::minmax(p1, p0) == std::make_tuple(p0, p1));
38*c8dee2aaSAndroid Build Coastguard Worker     }
39*c8dee2aaSAndroid Build Coastguard Worker     {
40*c8dee2aaSAndroid Build Coastguard Worker         Point p0 = {0, 0},
41*c8dee2aaSAndroid Build Coastguard Worker               p1 = {0, 1};
42*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, std::minmax(p0, p1) == std::make_tuple(p0, p1));
43*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, std::minmax(p1, p0) == std::make_tuple(p0, p1));
44*c8dee2aaSAndroid Build Coastguard Worker     }
45*c8dee2aaSAndroid Build Coastguard Worker }
46*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MFC_segment_ctor,r)47*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MFC_segment_ctor, r) {
48*c8dee2aaSAndroid Build Coastguard Worker     {
49*c8dee2aaSAndroid Build Coastguard Worker         Point p0 = {0, 0},
50*c8dee2aaSAndroid Build Coastguard Worker               p1 = {1, 1};
51*c8dee2aaSAndroid Build Coastguard Worker         Segment s = {p1, p0};
52*c8dee2aaSAndroid Build Coastguard Worker         const auto [u, l] = s;
53*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, u == s.upper() && u == p0);
54*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, l == s.lower() && l == p1);
55*c8dee2aaSAndroid Build Coastguard Worker     }
56*c8dee2aaSAndroid Build Coastguard Worker 
57*c8dee2aaSAndroid Build Coastguard Worker     {
58*c8dee2aaSAndroid Build Coastguard Worker         Point p0 = {0, 0},
59*c8dee2aaSAndroid Build Coastguard Worker               p1 = {0, 1};
60*c8dee2aaSAndroid Build Coastguard Worker         Segment s = {p1, p0};
61*c8dee2aaSAndroid Build Coastguard Worker         const auto [u, l] = s;
62*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, u == s.upper() && u == p0);
63*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, l == s.lower() && l == p1);
64*c8dee2aaSAndroid Build Coastguard Worker     }
65*c8dee2aaSAndroid Build Coastguard Worker }
66*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MFC_slope_less_than,r)67*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MFC_slope_less_than, r) {
68*c8dee2aaSAndroid Build Coastguard Worker     {
69*c8dee2aaSAndroid Build Coastguard Worker         Segment s0 = {{0, 0}, {1, 1}},
70*c8dee2aaSAndroid Build Coastguard Worker                 s1 = {{0, 0}, {-1, 1}};
71*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, !slope_s0_less_than_slope_s1(s0, s1));
72*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, slope_s0_less_than_slope_s1(s1, s0));
73*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, !slope_s0_less_than_slope_s1(s0, s0));
74*c8dee2aaSAndroid Build Coastguard Worker     }
75*c8dee2aaSAndroid Build Coastguard Worker     {
76*c8dee2aaSAndroid Build Coastguard Worker         Segment s = {{0, 0}, {0,1}};
77*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, !slope_s0_less_than_slope_s1(s, s));
78*c8dee2aaSAndroid Build Coastguard Worker     }
79*c8dee2aaSAndroid Build Coastguard Worker     {  // Check slopes for horizontals.
80*c8dee2aaSAndroid Build Coastguard Worker         Segment s0 = {{-2, 0}, {1, 0}},
81*c8dee2aaSAndroid Build Coastguard Worker                 s1 = {{-1, 0}, {2, 0}};
82*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, !slope_s0_less_than_slope_s1(s0, s1));
83*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, !slope_s0_less_than_slope_s1(s1, s0));
84*c8dee2aaSAndroid Build Coastguard Worker     }
85*c8dee2aaSAndroid Build Coastguard Worker     {  // Check slopes for horizontals.
86*c8dee2aaSAndroid Build Coastguard Worker         Segment s0 = {{-2, 0}, {1, 0}},
87*c8dee2aaSAndroid Build Coastguard Worker                 s1 = {{0, 0}, {1, 1}};
88*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, !slope_s0_less_than_slope_s1(s0, s1));
89*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, slope_s0_less_than_slope_s1(s1, s0));
90*c8dee2aaSAndroid Build Coastguard Worker     }
91*c8dee2aaSAndroid Build Coastguard Worker }
92*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MFC_segment_less_than_upper_to_insert,r)93*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MFC_segment_less_than_upper_to_insert, r) {
94*c8dee2aaSAndroid Build Coastguard Worker     Segment s0 = {{-10, -10}, {10, 10}},
95*c8dee2aaSAndroid Build Coastguard Worker             s1 = {{10, -10}, {-10, 10}},
96*c8dee2aaSAndroid Build Coastguard Worker             to_insert = {{0, 0}, {0, 3}};
97*c8dee2aaSAndroid Build Coastguard Worker 
98*c8dee2aaSAndroid Build Coastguard Worker     // Above y = 0, the sweepLine is {s0, s1}, but at y=0 s1 and s0 swap because of their slopes.
99*c8dee2aaSAndroid Build Coastguard Worker     std::vector<Segment> sweepLine = {s1, s0};
100*c8dee2aaSAndroid Build Coastguard Worker 
101*c8dee2aaSAndroid Build Coastguard Worker     auto insertionPoint = std::lower_bound(sweepLine.begin(), sweepLine.end(), to_insert,
102*c8dee2aaSAndroid Build Coastguard Worker                                            segment_less_than_upper_to_insert);
103*c8dee2aaSAndroid Build Coastguard Worker 
104*c8dee2aaSAndroid Build Coastguard Worker     // The insertion point is between s1 and s0.
105*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, *insertionPoint == s0);
106*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, *(insertionPoint-1) == s1);
107*c8dee2aaSAndroid Build Coastguard Worker }
108*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MFC_less_than_at_y,r)109*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MFC_less_than_at_y, r) {
110*c8dee2aaSAndroid Build Coastguard Worker     {
111*c8dee2aaSAndroid Build Coastguard Worker         Segment s0 = {{0, 0}, {2, 2}},
112*c8dee2aaSAndroid Build Coastguard Worker                 s1 = {{0, 0}, {-2, 2}};
113*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, !s0_less_than_s1_at_y(s0, s1, 1));
114*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, s0_less_than_s1_at_y(s1, s0, 1));
115*c8dee2aaSAndroid Build Coastguard Worker     }
116*c8dee2aaSAndroid Build Coastguard Worker     {  // cross at 0 use slope to break tie.
117*c8dee2aaSAndroid Build Coastguard Worker         Segment s0 = {{-2, -2}, {2, 2}},
118*c8dee2aaSAndroid Build Coastguard Worker                 s1 = {{2, -2}, {-2, 2}};
119*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, s0_less_than_s1_at_y(s0, s1, -1));
120*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, !s0_less_than_s1_at_y(s1, s0, -1));
121*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, !s0_less_than_s1_at_y(s0, s1, 0));
122*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, s0_less_than_s1_at_y(s1, s0, 0));
123*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, !s0_less_than_s1_at_y(s0, s1, 1));
124*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, s0_less_than_s1_at_y(s1, s0, 1));
125*c8dee2aaSAndroid Build Coastguard Worker     }
126*c8dee2aaSAndroid Build Coastguard Worker     {
127*c8dee2aaSAndroid Build Coastguard Worker         Segment s0 = {{-2, -100}, {-2, 89}},
128*c8dee2aaSAndroid Build Coastguard Worker                 s1 = {{6, -70}, {-2, 72}};
129*c8dee2aaSAndroid Build Coastguard Worker 
130*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, !s0_less_than_s1_at_y(s0, s1, 72));
131*c8dee2aaSAndroid Build Coastguard Worker     }
132*c8dee2aaSAndroid Build Coastguard Worker }
133*c8dee2aaSAndroid Build Coastguard Worker 
swap_ends(const Segment & s)134*c8dee2aaSAndroid Build Coastguard Worker static Segment swap_ends(const Segment& s) {
135*c8dee2aaSAndroid Build Coastguard Worker     return {s.lower(), s.upper()};
136*c8dee2aaSAndroid Build Coastguard Worker }
137*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MFC_has_inner_intersection,r)138*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MFC_has_inner_intersection, r) {
139*c8dee2aaSAndroid Build Coastguard Worker     auto checkIntersection = [&](Segment s0, Segment s1) {
140*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, s0_intersects_s1(s0, s1));
141*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, s0_intersects_s1(s1, s0));
142*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, s0_intersects_s1(swap_ends(s0), swap_ends(s1)));
143*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, s0_intersects_s1(swap_ends(s1), swap_ends(s0)));
144*c8dee2aaSAndroid Build Coastguard Worker     };
145*c8dee2aaSAndroid Build Coastguard Worker 
146*c8dee2aaSAndroid Build Coastguard Worker     {
147*c8dee2aaSAndroid Build Coastguard Worker         Segment s0 = {{-1, 0}, {1,  0}},
148*c8dee2aaSAndroid Build Coastguard Worker                 s1 = {{ 0, 1}, {0, -1}};
149*c8dee2aaSAndroid Build Coastguard Worker 
150*c8dee2aaSAndroid Build Coastguard Worker         checkIntersection(s0, s1);
151*c8dee2aaSAndroid Build Coastguard Worker     }
152*c8dee2aaSAndroid Build Coastguard Worker     {
153*c8dee2aaSAndroid Build Coastguard Worker         Segment s0 = {{-1, 0}, {5,  0}},
154*c8dee2aaSAndroid Build Coastguard Worker                 s1 = {{ 0, 1}, {0, -1}};
155*c8dee2aaSAndroid Build Coastguard Worker 
156*c8dee2aaSAndroid Build Coastguard Worker         checkIntersection(s0, s1);
157*c8dee2aaSAndroid Build Coastguard Worker     }
158*c8dee2aaSAndroid Build Coastguard Worker 
159*c8dee2aaSAndroid Build Coastguard Worker     {
160*c8dee2aaSAndroid Build Coastguard Worker         Segment s0 = {{5, 0}, {-1,  0}},
161*c8dee2aaSAndroid Build Coastguard Worker                 s1 = {{ 0, -1}, {0, 1}};
162*c8dee2aaSAndroid Build Coastguard Worker 
163*c8dee2aaSAndroid Build Coastguard Worker         checkIntersection(s0, s1);
164*c8dee2aaSAndroid Build Coastguard Worker     }
165*c8dee2aaSAndroid Build Coastguard Worker 
166*c8dee2aaSAndroid Build Coastguard Worker     {
167*c8dee2aaSAndroid Build Coastguard Worker         Segment s0 = {{-5, -5}, {5, 5}},
168*c8dee2aaSAndroid Build Coastguard Worker                 s1 = {{-5, 5}, {5, -5}};
169*c8dee2aaSAndroid Build Coastguard Worker 
170*c8dee2aaSAndroid Build Coastguard Worker         checkIntersection(s0, s1);
171*c8dee2aaSAndroid Build Coastguard Worker     }
172*c8dee2aaSAndroid Build Coastguard Worker 
173*c8dee2aaSAndroid Build Coastguard Worker     // Test very close segments (x0, 0) -> (x1, 1) & (x2, 0) -> (x3, 1)
174*c8dee2aaSAndroid Build Coastguard Worker     for (int32_t x0 = -10; x0 <= 10; x0++) {
175*c8dee2aaSAndroid Build Coastguard Worker         for (int32_t x1 = -10; x1 <= 10; x1++) {
176*c8dee2aaSAndroid Build Coastguard Worker             for (int32_t x2 = -10; x2 <= 10; x2++) {
177*c8dee2aaSAndroid Build Coastguard Worker                 for (int32_t x3 = -10; x3 <= 10; x3++) {
178*c8dee2aaSAndroid Build Coastguard Worker                     Point P0 = {x0, 0},
179*c8dee2aaSAndroid Build Coastguard Worker                           P1 = {x1, 1},
180*c8dee2aaSAndroid Build Coastguard Worker                           P2 = {x2, 0},
181*c8dee2aaSAndroid Build Coastguard Worker                           P3 = {x3, 1};
182*c8dee2aaSAndroid Build Coastguard Worker                     bool actual = s0_intersects_s1({P0, P1}, {P2, P3});
183*c8dee2aaSAndroid Build Coastguard Worker                     bool expected = (x0 <= x2 && x3 <= x1) || (x2 <= x0 && x1 <= x3);
184*c8dee2aaSAndroid Build Coastguard Worker                     if (actual != expected) {
185*c8dee2aaSAndroid Build Coastguard Worker                         s0_intersects_s1({P0, P1}, {P2, P3});
186*c8dee2aaSAndroid Build Coastguard Worker                         REPORTER_ASSERT(r, actual == expected);
187*c8dee2aaSAndroid Build Coastguard Worker                     }
188*c8dee2aaSAndroid Build Coastguard Worker                 }
189*c8dee2aaSAndroid Build Coastguard Worker             }
190*c8dee2aaSAndroid Build Coastguard Worker         }
191*c8dee2aaSAndroid Build Coastguard Worker     }
192*c8dee2aaSAndroid Build Coastguard Worker 
193*c8dee2aaSAndroid Build Coastguard Worker     {
194*c8dee2aaSAndroid Build Coastguard Worker         Segment s0 = {{0, -100}, {0, -50}},
195*c8dee2aaSAndroid Build Coastguard Worker                 s1 = {{100, -100}, {-100, 100}};  // goes through (0,0)
196*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, !s0_intersects_s1(s0, s1));
197*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, !s0_intersects_s1(s1, s0));
198*c8dee2aaSAndroid Build Coastguard Worker     }
199*c8dee2aaSAndroid Build Coastguard Worker     {
200*c8dee2aaSAndroid Build Coastguard Worker         Segment s0 = {{0, 100}, {0, 50}},
201*c8dee2aaSAndroid Build Coastguard Worker                 s1 = {{100, -100}, {-100, 100}};  // goes through (0,0)
202*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, !s0_intersects_s1(s0, s1));
203*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, !s0_intersects_s1(s1, s0));
204*c8dee2aaSAndroid Build Coastguard Worker     }
205*c8dee2aaSAndroid Build Coastguard Worker     {
206*c8dee2aaSAndroid Build Coastguard Worker         Segment s0 = {{0, -101}, {0, -50}},
207*c8dee2aaSAndroid Build Coastguard Worker                 s1 = {{100, -100}, {-100, 100}};  // goes through (0,0)
208*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, !s0_intersects_s1(s0, s1));
209*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, !s0_intersects_s1(s1, s0));
210*c8dee2aaSAndroid Build Coastguard Worker     }
211*c8dee2aaSAndroid Build Coastguard Worker }
212*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(MFC_myers_brute_force_comparison,r)213*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MFC_myers_brute_force_comparison, r) {
214*c8dee2aaSAndroid Build Coastguard Worker     const std::vector<Segment> tests[] = {
215*c8dee2aaSAndroid Build Coastguard Worker             {{{-58, -100}, {75, 105}}, {{149, -58}, {-156, 49}}, {{-34, -55}, {37, 49}}, {{-58, -100}, {75, 105}}, {{-147, -229}, {143, 220}}},
216*c8dee2aaSAndroid Build Coastguard Worker             {{{-57, -138}, {56, 178}}, {{14, -146}, {-22, 132}}},
217*c8dee2aaSAndroid Build Coastguard Worker             {{{-4, -23}, {-11, 11}}, {{6, -2}, {-11, 11}}, {{159, -244}, {-159, 233}}},
218*c8dee2aaSAndroid Build Coastguard Worker             {{{-7, -22}, {10, 14}}, {{-7, -71}, {-7, 80}}, {{-7, -22}, {-4, 5}}},
219*c8dee2aaSAndroid Build Coastguard Worker             {{{91, -22}, {-93, 24}}, {{31, -18}, {-25, 7}}, {{-25, 7}, {33, 12}}, {{-26, -24}, {18, 20}}},
220*c8dee2aaSAndroid Build Coastguard Worker             {{{2, -21}, {-16, 7}}, {{-45, -28}, {51, 35}}, {{39, -48}, {-53, 44}}, {{-16, 7}, {26, 7}}},
221*c8dee2aaSAndroid Build Coastguard Worker             {{{142, -82}, {-128, 64}}, {{208, -16}, {-217, -3}}, {{91, -22}, {-93, 24}}, {{31, -18}, {-25, 7}}, {{-25, 7}, {33, 12}}},
222*c8dee2aaSAndroid Build Coastguard Worker             {{{-159, -101}, {167, 91}}, {{-96, -117}, {99, 117}}, {{-16, -21}, {12, 35}}, {{-48, -55}, {33, 63}}, {{-16, -21}, {26, 41}}},
223*c8dee2aaSAndroid Build Coastguard Worker             {{{-51, -18}, {34, 1}}, {{189, -169}, {-171, 150}}, {{24, -8}, {-5, 7}}, {{24, -8}, {-26, 16}}, {{54, -22}, {-36, 20}}},
224*c8dee2aaSAndroid Build Coastguard Worker             {{{-29, -3}, {15, -3}}, {{-28, -7}, {15, -3}}},
225*c8dee2aaSAndroid Build Coastguard Worker             {{{20, -149}, {-32, 130}}, {{-29, -3}, {15, -3}}, {{-28, -7}, {15, -3}}},
226*c8dee2aaSAndroid Build Coastguard Worker             {{{-32, -8}, {16, -8}}, {{-28, -104}, {23, 88}}, {{-17, -11}, {16, -8}}},
227*c8dee2aaSAndroid Build Coastguard Worker             {{{-59, -9}, {48, 11}}, {{-59, -9}, {75, -9}}, {{173, -20}, {-178, 13}}},
228*c8dee2aaSAndroid Build Coastguard Worker             {{{-11, 1}, {12, 1}}, {{-42, -35}, {54, 29}}},
229*c8dee2aaSAndroid Build Coastguard Worker             {{{14, -11}, {-15, -2}}, {{-9, -2}, {13, -2}}}, // both end same s0 horz s1 < s0
230*c8dee2aaSAndroid Build Coastguard Worker             {{{-38, 7}, {47, 7}}, {{-148, 6}, {166, 7}}},  // just sort of s0 along s1
231*c8dee2aaSAndroid Build Coastguard Worker             {{{-26, -22}, {9, 21}}, {{-32, -28}, {13, 17}}}, // s1 endpoint on s0
232*c8dee2aaSAndroid Build Coastguard Worker             {{{23, -2}, {-12, 3}}, {{22, -13}, {-5, 2}}},   // s1 endpoint on s0
233*c8dee2aaSAndroid Build Coastguard Worker             {{{-2, -100}, {-2, 89}}, {{6, -70}, {-2, 72}}},
234*c8dee2aaSAndroid Build Coastguard Worker             {{{8, -1}, {-8, 19}}, {{-130, -93}, {137, 85}}},  // Endpoint of s0 lies on s1
235*c8dee2aaSAndroid Build Coastguard Worker             {{{-39, -111}, {25, 119}}, {{-26, -112}, {25, 119}}}, // Same end points
236*c8dee2aaSAndroid Build Coastguard Worker             {{{-9, -5}, {16, -5}}, {{90, -134}, {-71, 144}}},  // Diag crossing horizontal
237*c8dee2aaSAndroid Build Coastguard Worker             {{{-1, -1}, {1, 1}}, {{1, -1}, {-1, 1}}},  // Crossing
238*c8dee2aaSAndroid Build Coastguard Worker             {{{-1, -1}, {-1, 1}}, {{1, -1}, {1, 1}}},  // Two vertical lines
239*c8dee2aaSAndroid Build Coastguard Worker             {{{-1, -1}, {1, -1}}, {{-1, 1}, {1, 1}}},  // Two horizontal lines
240*c8dee2aaSAndroid Build Coastguard Worker             {{{-2, 1}, {1, 1}}, {{-1, 1}, {2, 1}}},  // Overlapping horizontal lines
241*c8dee2aaSAndroid Build Coastguard Worker             {{{0, -100}, {0, -50}}, {{100, -100}, {-100, 100}}},
242*c8dee2aaSAndroid Build Coastguard Worker             {{{0, 100}, {0, 50}}, {{100, -100}, {-100, 100}}},
243*c8dee2aaSAndroid Build Coastguard Worker             {{{0, -101}, {0, -50}}, {{100, -100}, {-100, 100}}},
244*c8dee2aaSAndroid Build Coastguard Worker             {{{0, 0}, {0, 50}}, {{100, -100}, {-100, 100}}},
245*c8dee2aaSAndroid Build Coastguard Worker             {{{-10, -10}, {10, 10}}, {{-10, -10}, {11, 11}}, {{10, -10}, {-10, 10}}},
246*c8dee2aaSAndroid Build Coastguard Worker             {{{10, -10}, {-10, 10}}, {{10, -10}, {-11, 11}}, {{-10, -10}, {10, 10}}},
247*c8dee2aaSAndroid Build Coastguard Worker             {{{-11, -11}, {10, 10}}, {{-10, -10}, {11, 11}}, {{10, -10}, {-10, 10}}},
248*c8dee2aaSAndroid Build Coastguard Worker     };
249*c8dee2aaSAndroid Build Coastguard Worker 
250*c8dee2aaSAndroid Build Coastguard Worker     for (const auto& segments : tests) {
251*c8dee2aaSAndroid Build Coastguard Worker         std::vector<Segment> myersSegments = segments;
252*c8dee2aaSAndroid Build Coastguard Worker         std::vector<Segment> bruteSegments = segments;
253*c8dee2aaSAndroid Build Coastguard Worker         auto myersResponse = myers_find_crossings(myersSegments);
254*c8dee2aaSAndroid Build Coastguard Worker         auto bruteResponse = brute_force_crossings(bruteSegments);
255*c8dee2aaSAndroid Build Coastguard Worker 
256*c8dee2aaSAndroid Build Coastguard Worker         std::sort(myersResponse.begin(), myersResponse.end());
257*c8dee2aaSAndroid Build Coastguard Worker         std::sort(bruteResponse.begin(), bruteResponse.end());
258*c8dee2aaSAndroid Build Coastguard Worker 
259*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, myersResponse.size() == bruteResponse.size());
260*c8dee2aaSAndroid Build Coastguard Worker #if 0
261*c8dee2aaSAndroid Build Coastguard Worker         if (myersResponse.size() != bruteResponse.size()) {
262*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(false);
263*c8dee2aaSAndroid Build Coastguard Worker         }
264*c8dee2aaSAndroid Build Coastguard Worker #endif
265*c8dee2aaSAndroid Build Coastguard Worker         // There should be no duplicate crossings.
266*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r,
267*c8dee2aaSAndroid Build Coastguard Worker                         std::unique(myersResponse.begin(), myersResponse.end()) ==
268*c8dee2aaSAndroid Build Coastguard Worker                             myersResponse.end());
269*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r,
270*c8dee2aaSAndroid Build Coastguard Worker                         std::unique(bruteResponse.begin(), bruteResponse.end()) ==
271*c8dee2aaSAndroid Build Coastguard Worker                             bruteResponse.end());
272*c8dee2aaSAndroid Build Coastguard Worker 
273*c8dee2aaSAndroid Build Coastguard Worker         // Both should be equal.
274*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(r, std::equal(myersResponse.begin(), myersResponse.end(),
275*c8dee2aaSAndroid Build Coastguard Worker                                       bruteResponse.begin(), bruteResponse.end()));
276*c8dee2aaSAndroid Build Coastguard Worker     }
277*c8dee2aaSAndroid Build Coastguard Worker }
278*c8dee2aaSAndroid Build Coastguard Worker 
279*c8dee2aaSAndroid Build Coastguard Worker class StopWatch {
280*c8dee2aaSAndroid Build Coastguard Worker public:
start()281*c8dee2aaSAndroid Build Coastguard Worker     void start() {
282*c8dee2aaSAndroid Build Coastguard Worker         fStart = std::chrono::high_resolution_clock::now();
283*c8dee2aaSAndroid Build Coastguard Worker     }
284*c8dee2aaSAndroid Build Coastguard Worker 
stop()285*c8dee2aaSAndroid Build Coastguard Worker     void stop() {
286*c8dee2aaSAndroid Build Coastguard Worker         std::chrono::high_resolution_clock::time_point stop =
287*c8dee2aaSAndroid Build Coastguard Worker                 std::chrono::high_resolution_clock::now();
288*c8dee2aaSAndroid Build Coastguard Worker 
289*c8dee2aaSAndroid Build Coastguard Worker         fAccumulatedTime += std::chrono::duration_cast<std::chrono::microseconds>(stop - fStart);
290*c8dee2aaSAndroid Build Coastguard Worker         fCount += 1;
291*c8dee2aaSAndroid Build Coastguard Worker     }
292*c8dee2aaSAndroid Build Coastguard Worker 
print()293*c8dee2aaSAndroid Build Coastguard Worker     void print() {
294*c8dee2aaSAndroid Build Coastguard Worker         int64_t average = fAccumulatedTime.count() / fCount;
295*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("average time: %" PRId64 " µs\n", average);
296*c8dee2aaSAndroid Build Coastguard Worker     }
297*c8dee2aaSAndroid Build Coastguard Worker 
298*c8dee2aaSAndroid Build Coastguard Worker private:
299*c8dee2aaSAndroid Build Coastguard Worker     int fCount = 0;
300*c8dee2aaSAndroid Build Coastguard Worker     std::chrono::high_resolution_clock::time_point fStart;
301*c8dee2aaSAndroid Build Coastguard Worker     std::chrono::microseconds fAccumulatedTime = std::chrono::microseconds::zero();
302*c8dee2aaSAndroid Build Coastguard Worker };
303*c8dee2aaSAndroid Build Coastguard Worker 
304*c8dee2aaSAndroid Build Coastguard Worker constexpr bool kRunRandomTest = false;
DEF_TEST(MFC_myers_brute_force_random_comparison,r)305*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(MFC_myers_brute_force_random_comparison, r) {
306*c8dee2aaSAndroid Build Coastguard Worker     if constexpr (!kRunRandomTest) {
307*c8dee2aaSAndroid Build Coastguard Worker         return;
308*c8dee2aaSAndroid Build Coastguard Worker     }
309*c8dee2aaSAndroid Build Coastguard Worker     const int n = 200;
310*c8dee2aaSAndroid Build Coastguard Worker     const int boxSize = 20000;
311*c8dee2aaSAndroid Build Coastguard Worker     SkRandom random{n + boxSize};
312*c8dee2aaSAndroid Build Coastguard Worker     std::vector<Segment> segments;
313*c8dee2aaSAndroid Build Coastguard Worker 
314*c8dee2aaSAndroid Build Coastguard Worker     StopWatch myersStopWatch;
315*c8dee2aaSAndroid Build Coastguard Worker     StopWatch bruteStopWatch;
316*c8dee2aaSAndroid Build Coastguard Worker 
317*c8dee2aaSAndroid Build Coastguard Worker     for (int trials = 0; trials < 100'000; trials++) {
318*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < n; ++i) {
319*c8dee2aaSAndroid Build Coastguard Worker         float x = random.nextRangeF(-boxSize, boxSize),
320*c8dee2aaSAndroid Build Coastguard Worker               y = random.nextRangeF(-boxSize, boxSize);
321*c8dee2aaSAndroid Build Coastguard Worker 
322*c8dee2aaSAndroid Build Coastguard Worker         float angle = random.nextF() * SK_FloatPI;
323*c8dee2aaSAndroid Build Coastguard Worker         float distance = random.nextRangeF(10, 300);
324*c8dee2aaSAndroid Build Coastguard Worker 
325*c8dee2aaSAndroid Build Coastguard Worker         Point p0 = {sk_float_round2int(x + cos(angle) * distance),
326*c8dee2aaSAndroid Build Coastguard Worker                     sk_float_round2int(y + sin(angle) * distance)};
327*c8dee2aaSAndroid Build Coastguard Worker         Point p1 = {sk_float_round2int(x - cos(angle) * distance),
328*c8dee2aaSAndroid Build Coastguard Worker                     sk_float_round2int(y - sin(angle) * distance)};
329*c8dee2aaSAndroid Build Coastguard Worker 
330*c8dee2aaSAndroid Build Coastguard Worker         segments.emplace_back(p0, p1);
331*c8dee2aaSAndroid Build Coastguard Worker     }
332*c8dee2aaSAndroid Build Coastguard Worker 
333*c8dee2aaSAndroid Build Coastguard Worker     std::vector<Segment> myersSegments = segments;
334*c8dee2aaSAndroid Build Coastguard Worker     std::vector<Segment> bruteSegments = segments;
335*c8dee2aaSAndroid Build Coastguard Worker     myersStopWatch.start();
336*c8dee2aaSAndroid Build Coastguard Worker     auto myersResponse = myers_find_crossings(myersSegments);
337*c8dee2aaSAndroid Build Coastguard Worker     myersStopWatch.stop();
338*c8dee2aaSAndroid Build Coastguard Worker     bruteStopWatch.start();
339*c8dee2aaSAndroid Build Coastguard Worker     auto bruteResponse = brute_force_crossings(bruteSegments);
340*c8dee2aaSAndroid Build Coastguard Worker     bruteStopWatch.stop();
341*c8dee2aaSAndroid Build Coastguard Worker 
342*c8dee2aaSAndroid Build Coastguard Worker     std::sort(myersResponse.begin(), myersResponse.end());
343*c8dee2aaSAndroid Build Coastguard Worker     std::sort(bruteResponse.begin(), bruteResponse.end());
344*c8dee2aaSAndroid Build Coastguard Worker 
345*c8dee2aaSAndroid Build Coastguard Worker     //SkDebugf("myers size: %zu brute size: %zu\n", myersResponse.size(), bruteResponse.size());
346*c8dee2aaSAndroid Build Coastguard Worker 
347*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, myersResponse.size() == bruteResponse.size());
348*c8dee2aaSAndroid Build Coastguard Worker     if (myersResponse.size() != bruteResponse.size()) {
349*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("myers size: %zu brute size: %zu\n", myersResponse.size(), bruteResponse.size());
350*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("{");
351*c8dee2aaSAndroid Build Coastguard Worker         for (const Segment& s : segments) {
352*c8dee2aaSAndroid Build Coastguard Worker             const auto [u, l] = s;
353*c8dee2aaSAndroid Build Coastguard Worker             SkDebugf("{{%d, %d}, {%d, %d}}, ", u.x, u.y, l.x, l.y);
354*c8dee2aaSAndroid Build Coastguard Worker         }
355*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf("},\n");
356*c8dee2aaSAndroid Build Coastguard Worker     }
357*c8dee2aaSAndroid Build Coastguard Worker 
358*c8dee2aaSAndroid Build Coastguard Worker     // There should be no duplicate crossings.
359*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r,
360*c8dee2aaSAndroid Build Coastguard Worker                     std::unique(myersResponse.begin(), myersResponse.end()) ==
361*c8dee2aaSAndroid Build Coastguard Worker                     myersResponse.end());
362*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r,
363*c8dee2aaSAndroid Build Coastguard Worker                     std::unique(bruteResponse.begin(), bruteResponse.end()) ==
364*c8dee2aaSAndroid Build Coastguard Worker                     bruteResponse.end());
365*c8dee2aaSAndroid Build Coastguard Worker 
366*c8dee2aaSAndroid Build Coastguard Worker     // Both should be equal.
367*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(r, std::equal(myersResponse.begin(), myersResponse.end(),
368*c8dee2aaSAndroid Build Coastguard Worker                                   bruteResponse.begin(), bruteResponse.end()));
369*c8dee2aaSAndroid Build Coastguard Worker     segments.clear();
370*c8dee2aaSAndroid Build Coastguard Worker     }
371*c8dee2aaSAndroid Build Coastguard Worker     SkDebugf("myers ");
372*c8dee2aaSAndroid Build Coastguard Worker     myersStopWatch.print();
373*c8dee2aaSAndroid Build Coastguard Worker     SkDebugf("brute ");
374*c8dee2aaSAndroid Build Coastguard Worker     bruteStopWatch.print();
375*c8dee2aaSAndroid Build Coastguard Worker }
376