xref: /aosp_15_r20/external/skia/modules/bentleyottmann/tests/EventQueueTest.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/EventQueue.h"
5*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
6*c8dee2aaSAndroid Build Coastguard Worker 
7*c8dee2aaSAndroid Build Coastguard Worker namespace bentleyottmann {
8*c8dee2aaSAndroid Build Coastguard Worker class EventQueueTestingPeer {
9*c8dee2aaSAndroid Build Coastguard Worker public:
NextEvent(EventQueue * eq)10*c8dee2aaSAndroid Build Coastguard Worker     static Event NextEvent(EventQueue* eq) {
11*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(eq->hasMoreEvents());
12*c8dee2aaSAndroid Build Coastguard Worker 
13*c8dee2aaSAndroid Build Coastguard Worker         auto firstElement = eq->fQueue.begin();
14*c8dee2aaSAndroid Build Coastguard Worker 
15*c8dee2aaSAndroid Build Coastguard Worker         // Extract event at the beginning of the queue.
16*c8dee2aaSAndroid Build Coastguard Worker         Event event = *firstElement;
17*c8dee2aaSAndroid Build Coastguard Worker 
18*c8dee2aaSAndroid Build Coastguard Worker         // Remove the beginning element from the queue.
19*c8dee2aaSAndroid Build Coastguard Worker         eq->fQueue.erase(firstElement);
20*c8dee2aaSAndroid Build Coastguard Worker 
21*c8dee2aaSAndroid Build Coastguard Worker         return event;
22*c8dee2aaSAndroid Build Coastguard Worker     }
23*c8dee2aaSAndroid Build Coastguard Worker };
24*c8dee2aaSAndroid Build Coastguard Worker }  // namespace bentleyottmann
25*c8dee2aaSAndroid Build Coastguard Worker 
26*c8dee2aaSAndroid Build Coastguard Worker using namespace bentleyottmann;
27*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(BO_EventQueueOrdering,reporter)28*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(BO_EventQueueOrdering, reporter) {
29*c8dee2aaSAndroid Build Coastguard Worker     { // Check that event types are ordered correctly.
30*c8dee2aaSAndroid Build Coastguard Worker         EventQueue::Queue q;
31*c8dee2aaSAndroid Build Coastguard Worker 
32*c8dee2aaSAndroid Build Coastguard Worker         // Insert the events in reverse order.
33*c8dee2aaSAndroid Build Coastguard Worker         Point eventPoint = {100, 100};
34*c8dee2aaSAndroid Build Coastguard Worker         Segment s = {{100, 100}, {200, 200}};
35*c8dee2aaSAndroid Build Coastguard Worker         q.insert(Event{eventPoint, Upper{s}});
36*c8dee2aaSAndroid Build Coastguard Worker         Segment s0 = {{50, 50}, {150, 150}},
37*c8dee2aaSAndroid Build Coastguard Worker                 s1 = {{150, 50}, {50, 150}};
38*c8dee2aaSAndroid Build Coastguard Worker         q.insert(Event{eventPoint, Cross{s0, s1}});
39*c8dee2aaSAndroid Build Coastguard Worker         q.insert(Event{eventPoint, Lower{}});
40*c8dee2aaSAndroid Build Coastguard Worker 
41*c8dee2aaSAndroid Build Coastguard Worker         // Make sure that the events are in the right order.
42*c8dee2aaSAndroid Build Coastguard Worker         auto cursor = q.begin();
43*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, std::holds_alternative<Lower>(cursor->type));
44*c8dee2aaSAndroid Build Coastguard Worker         ++cursor;
45*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, std::holds_alternative<Cross>(cursor->type));
46*c8dee2aaSAndroid Build Coastguard Worker         ++cursor;
47*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, std::holds_alternative<Upper>(cursor->type));
48*c8dee2aaSAndroid Build Coastguard Worker     }
49*c8dee2aaSAndroid Build Coastguard Worker }
50*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(BO_EventQueueBasic,reporter)51*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(BO_EventQueueBasic, reporter) {
52*c8dee2aaSAndroid Build Coastguard Worker     {
53*c8dee2aaSAndroid Build Coastguard Worker         EventQueue::Queue q;
54*c8dee2aaSAndroid Build Coastguard Worker         EventQueue eq{std::move(q)};
55*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !eq.hasMoreEvents());
56*c8dee2aaSAndroid Build Coastguard Worker     }
57*c8dee2aaSAndroid Build Coastguard Worker     {
58*c8dee2aaSAndroid Build Coastguard Worker         EventQueue::Queue q;
59*c8dee2aaSAndroid Build Coastguard Worker         Point eventPoint = {100, 100};
60*c8dee2aaSAndroid Build Coastguard Worker         q.insert({eventPoint, Lower{} });
61*c8dee2aaSAndroid Build Coastguard Worker         EventQueue eq{std::move(q)};
62*c8dee2aaSAndroid Build Coastguard Worker         {
63*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, eq.hasMoreEvents());
64*c8dee2aaSAndroid Build Coastguard Worker             Event e = EventQueueTestingPeer::NextEvent(&eq);
65*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, e.where == eventPoint);
66*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !eq.hasMoreEvents());
67*c8dee2aaSAndroid Build Coastguard Worker         }
68*c8dee2aaSAndroid Build Coastguard Worker     }
69*c8dee2aaSAndroid Build Coastguard Worker     { // Check that Lower events are de-duplicated.
70*c8dee2aaSAndroid Build Coastguard Worker         EventQueue::Queue q;
71*c8dee2aaSAndroid Build Coastguard Worker         Point eventPoint = {100, 100};
72*c8dee2aaSAndroid Build Coastguard Worker         q.insert({eventPoint, Lower{}});
73*c8dee2aaSAndroid Build Coastguard Worker         q.insert({eventPoint, Lower{}});
74*c8dee2aaSAndroid Build Coastguard Worker         EventQueue eq{std::move(q)};
75*c8dee2aaSAndroid Build Coastguard Worker         {
76*c8dee2aaSAndroid Build Coastguard Worker             // There should be only one lower because of queue de-duplication
77*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, eq.hasMoreEvents());
78*c8dee2aaSAndroid Build Coastguard Worker             auto [p, _] = EventQueueTestingPeer::NextEvent(&eq);
79*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, p == eventPoint);
80*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !eq.hasMoreEvents());
81*c8dee2aaSAndroid Build Coastguard Worker         }
82*c8dee2aaSAndroid Build Coastguard Worker     }
83*c8dee2aaSAndroid Build Coastguard Worker     { // Check that Lower distinct Lower events are distinct.
84*c8dee2aaSAndroid Build Coastguard Worker         EventQueue::Queue q;
85*c8dee2aaSAndroid Build Coastguard Worker         Point eventPoint1 = {100, 100};
86*c8dee2aaSAndroid Build Coastguard Worker         Point eventPoint2 = {100, 101};
87*c8dee2aaSAndroid Build Coastguard Worker 
88*c8dee2aaSAndroid Build Coastguard Worker         q.insert({eventPoint1, Lower{}});
89*c8dee2aaSAndroid Build Coastguard Worker         q.insert({eventPoint2, Lower{}});
90*c8dee2aaSAndroid Build Coastguard Worker         EventQueue eq{std::move(q)};
91*c8dee2aaSAndroid Build Coastguard Worker         {
92*c8dee2aaSAndroid Build Coastguard Worker             // There should be only one lower because of queue de-duplication
93*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, eq.hasMoreEvents());
94*c8dee2aaSAndroid Build Coastguard Worker             auto [p, _] = EventQueueTestingPeer::NextEvent(&eq);
95*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, p == eventPoint1);
96*c8dee2aaSAndroid Build Coastguard Worker         }
97*c8dee2aaSAndroid Build Coastguard Worker         {
98*c8dee2aaSAndroid Build Coastguard Worker             // There should be only one lower because of queue de-duplication
99*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, eq.hasMoreEvents());
100*c8dee2aaSAndroid Build Coastguard Worker             auto [p, _] = EventQueueTestingPeer::NextEvent(&eq);
101*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, p == eventPoint2);
102*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !eq.hasMoreEvents());
103*c8dee2aaSAndroid Build Coastguard Worker         }
104*c8dee2aaSAndroid Build Coastguard Worker     }
105*c8dee2aaSAndroid Build Coastguard Worker     { // Check that non-Lower events are separate.
106*c8dee2aaSAndroid Build Coastguard Worker         EventQueue::Queue q;
107*c8dee2aaSAndroid Build Coastguard Worker         Segment s0 {{0, 0}, {100, 100}};
108*c8dee2aaSAndroid Build Coastguard Worker         Segment s1 {{0, 0}, {-100, 100}};
109*c8dee2aaSAndroid Build Coastguard Worker         q.insert({Point{0, 0}, Upper{s0}});
110*c8dee2aaSAndroid Build Coastguard Worker         q.insert({Point{0, 0}, Upper{s1}});
111*c8dee2aaSAndroid Build Coastguard Worker         EventQueue eq{std::move(q)};
112*c8dee2aaSAndroid Build Coastguard Worker         {
113*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, eq.hasMoreEvents());
114*c8dee2aaSAndroid Build Coastguard Worker             Event e = EventQueueTestingPeer::NextEvent(&eq);
115*c8dee2aaSAndroid Build Coastguard Worker             Point upperPt = Point{0, 0};
116*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, e.where == upperPt);
117*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, e.type.index() == 2);
118*c8dee2aaSAndroid Build Coastguard Worker             Upper upper = std::get<Upper>(e.type);
119*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !(upper < Upper{s1}) && !(Upper{s1} < upper));
120*c8dee2aaSAndroid Build Coastguard Worker             Event e2 = EventQueueTestingPeer::NextEvent(&eq);
121*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, e2.where == upperPt);
122*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, e2.type.index() == 2);
123*c8dee2aaSAndroid Build Coastguard Worker             Upper upper2 = std::get<Upper>(e2.type);
124*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !(upper2 < Upper{s0}) && !(Upper{s0} < upper2));
125*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !eq.hasMoreEvents());
126*c8dee2aaSAndroid Build Coastguard Worker         }
127*c8dee2aaSAndroid Build Coastguard Worker     }
128*c8dee2aaSAndroid Build Coastguard Worker }
129*c8dee2aaSAndroid Build Coastguard Worker 
130*c8dee2aaSAndroid Build Coastguard Worker enum HasDeletions {
131*c8dee2aaSAndroid Build Coastguard Worker     kHasDeletions,   // The handleDeletions call should be called.
132*c8dee2aaSAndroid Build Coastguard Worker     kHasNoDeletions  // The handleDeletions call should not be called.
133*c8dee2aaSAndroid Build Coastguard Worker };
134*c8dee2aaSAndroid Build Coastguard Worker 
135*c8dee2aaSAndroid Build Coastguard Worker struct TestEventHandler : public SweepLineInterface {
TestEventHandlerTestEventHandler136*c8dee2aaSAndroid Build Coastguard Worker     TestEventHandler(skiatest::Reporter*r,
137*c8dee2aaSAndroid Build Coastguard Worker                      Point eventPoint,
138*c8dee2aaSAndroid Build Coastguard Worker                      SkSpan<const Segment> deletions,
139*c8dee2aaSAndroid Build Coastguard Worker                      SkSpan<const Segment> insertions,
140*c8dee2aaSAndroid Build Coastguard Worker                      SkSpan<const Crossing> crossings,
141*c8dee2aaSAndroid Build Coastguard Worker                      HasDeletions hasDeletions = kHasDeletions)
142*c8dee2aaSAndroid Build Coastguard Worker         : fR(r)
143*c8dee2aaSAndroid Build Coastguard Worker         , fCandidateEventPoint{eventPoint}
144*c8dee2aaSAndroid Build Coastguard Worker         , fDeletions{deletions.begin(), deletions.end()}
145*c8dee2aaSAndroid Build Coastguard Worker         , fInsertions{insertions.begin(), insertions.end()}
146*c8dee2aaSAndroid Build Coastguard Worker         , fCrossings{crossings.begin(), crossings.end()}
147*c8dee2aaSAndroid Build Coastguard Worker         , fHasDeletions{hasDeletions} {}
148*c8dee2aaSAndroid Build Coastguard Worker 
handleDeletionsTestEventHandler149*c8dee2aaSAndroid Build Coastguard Worker     void handleDeletions(Point eventPoint,
150*c8dee2aaSAndroid Build Coastguard Worker                          const DeletionSegmentSet& removing) override {
151*c8dee2aaSAndroid Build Coastguard Worker         if (fHasDeletions == kHasNoDeletions) {
152*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(fR, false, "There should be no deletions.");
153*c8dee2aaSAndroid Build Coastguard Worker             return;
154*c8dee2aaSAndroid Build Coastguard Worker         }
155*c8dee2aaSAndroid Build Coastguard Worker 
156*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(fR, eventPoint == fCandidateEventPoint);
157*c8dee2aaSAndroid Build Coastguard Worker 
158*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(fR, removing.size() == fDeletions.size());
159*c8dee2aaSAndroid Build Coastguard Worker 
160*c8dee2aaSAndroid Build Coastguard Worker         for (const Segment& s : fDeletions) {
161*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(fR, removing.find(s) != removing.end());
162*c8dee2aaSAndroid Build Coastguard Worker         }
163*c8dee2aaSAndroid Build Coastguard Worker     }
164*c8dee2aaSAndroid Build Coastguard Worker 
165*c8dee2aaSAndroid Build Coastguard Worker     void
handleInsertionsAndCheckForNewCrossingsTestEventHandler166*c8dee2aaSAndroid Build Coastguard Worker     handleInsertionsAndCheckForNewCrossings(Point eventPoint,
167*c8dee2aaSAndroid Build Coastguard Worker                                             const InsertionSegmentSet& inserting,
168*c8dee2aaSAndroid Build Coastguard Worker                                             EventQueueInterface* queue) override {
169*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(fR, eventPoint == fCandidateEventPoint);
170*c8dee2aaSAndroid Build Coastguard Worker 
171*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(fR, inserting.size() == fInsertions.size());
172*c8dee2aaSAndroid Build Coastguard Worker 
173*c8dee2aaSAndroid Build Coastguard Worker         for (const Segment& s : fInsertions) {
174*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(fR, inserting.find(s) != inserting.end());
175*c8dee2aaSAndroid Build Coastguard Worker         }
176*c8dee2aaSAndroid Build Coastguard Worker 
177*c8dee2aaSAndroid Build Coastguard Worker         for (const Crossing& crossing : fCrossings) {
178*c8dee2aaSAndroid Build Coastguard Worker             auto [s0, s1, pt] = crossing;
179*c8dee2aaSAndroid Build Coastguard Worker             queue->addCrossing(pt, s0, s1);
180*c8dee2aaSAndroid Build Coastguard Worker         }
181*c8dee2aaSAndroid Build Coastguard Worker     }
182*c8dee2aaSAndroid Build Coastguard Worker 
183*c8dee2aaSAndroid Build Coastguard Worker     skiatest::Reporter* const fR;
184*c8dee2aaSAndroid Build Coastguard Worker     const Point fCandidateEventPoint;
185*c8dee2aaSAndroid Build Coastguard Worker     std::vector<Segment> fDeletions;
186*c8dee2aaSAndroid Build Coastguard Worker     std::vector<Segment> fInsertions;
187*c8dee2aaSAndroid Build Coastguard Worker     std::vector<Crossing> fCrossings;
188*c8dee2aaSAndroid Build Coastguard Worker     const HasDeletions fHasDeletions;
189*c8dee2aaSAndroid Build Coastguard Worker };
190*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(BO_EventQueueHandlerInterface,reporter)191*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(BO_EventQueueHandlerInterface, reporter) {
192*c8dee2aaSAndroid Build Coastguard Worker     { // Check that a Lower event is added while processing the Upper event.
193*c8dee2aaSAndroid Build Coastguard Worker         EventQueue::Queue q;
194*c8dee2aaSAndroid Build Coastguard Worker         static constexpr Point eventPoint = {100, 100};
195*c8dee2aaSAndroid Build Coastguard Worker         static constexpr Point endPoint = {200, 200};
196*c8dee2aaSAndroid Build Coastguard Worker         static constexpr Segment s = {eventPoint, endPoint};
197*c8dee2aaSAndroid Build Coastguard Worker         q.insert(Event{eventPoint, Upper{s}});
198*c8dee2aaSAndroid Build Coastguard Worker         EventQueue eq{std::move(q)};
199*c8dee2aaSAndroid Build Coastguard Worker 
200*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, eq.hasMoreEvents());
201*c8dee2aaSAndroid Build Coastguard Worker 
202*c8dee2aaSAndroid Build Coastguard Worker 
203*c8dee2aaSAndroid Build Coastguard Worker         TestEventHandler eh1{reporter, eventPoint, {}, {s}, {}, kHasNoDeletions};
204*c8dee2aaSAndroid Build Coastguard Worker         eq.handleNextEventPoint(&eh1);
205*c8dee2aaSAndroid Build Coastguard Worker 
206*c8dee2aaSAndroid Build Coastguard Worker         TestEventHandler eh2{reporter, endPoint, {}, {}, {}};
207*c8dee2aaSAndroid Build Coastguard Worker         eq.handleNextEventPoint(&eh2);
208*c8dee2aaSAndroid Build Coastguard Worker 
209*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !eq.hasMoreEvents());
210*c8dee2aaSAndroid Build Coastguard Worker     }
211*c8dee2aaSAndroid Build Coastguard Worker 
212*c8dee2aaSAndroid Build Coastguard Worker     { // Check an entire crossing event.
213*c8dee2aaSAndroid Build Coastguard Worker         EventQueue::Queue q;
214*c8dee2aaSAndroid Build Coastguard Worker         static constexpr Point b0 = {100, 100};
215*c8dee2aaSAndroid Build Coastguard Worker         static constexpr Point e0 = {200, 200};
216*c8dee2aaSAndroid Build Coastguard Worker         static constexpr Segment s0 = {b0, e0};
217*c8dee2aaSAndroid Build Coastguard Worker         static constexpr Point b1 = {200, 100};
218*c8dee2aaSAndroid Build Coastguard Worker         static constexpr Point e1 = {100, 200};
219*c8dee2aaSAndroid Build Coastguard Worker         static constexpr Segment s1 = {b1, e1};
220*c8dee2aaSAndroid Build Coastguard Worker         static constexpr Point crossingPoint = {150, 150};
221*c8dee2aaSAndroid Build Coastguard Worker 
222*c8dee2aaSAndroid Build Coastguard Worker         // Load crossing segments into the queue
223*c8dee2aaSAndroid Build Coastguard Worker         q.insert(Event{b0, Upper{s0}});
224*c8dee2aaSAndroid Build Coastguard Worker         q.insert(Event{b1, Upper{s1}});
225*c8dee2aaSAndroid Build Coastguard Worker         EventQueue eq{std::move(q)};
226*c8dee2aaSAndroid Build Coastguard Worker 
227*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, eq.hasMoreEvents());
228*c8dee2aaSAndroid Build Coastguard Worker 
229*c8dee2aaSAndroid Build Coastguard Worker         TestEventHandler eh1{reporter, b0, {}, {s0}, {}, kHasNoDeletions};
230*c8dee2aaSAndroid Build Coastguard Worker         eq.handleNextEventPoint(&eh1);
231*c8dee2aaSAndroid Build Coastguard Worker 
232*c8dee2aaSAndroid Build Coastguard Worker         TestEventHandler eh2{reporter, b1, {}, {s1}, {{s0, s1, crossingPoint}}, kHasNoDeletions};
233*c8dee2aaSAndroid Build Coastguard Worker         eq.handleNextEventPoint(&eh2);
234*c8dee2aaSAndroid Build Coastguard Worker 
235*c8dee2aaSAndroid Build Coastguard Worker         TestEventHandler eh3{reporter, crossingPoint, {s0, s1}, {s0, s1}, {}};
236*c8dee2aaSAndroid Build Coastguard Worker         eq.handleNextEventPoint(&eh3);
237*c8dee2aaSAndroid Build Coastguard Worker 
238*c8dee2aaSAndroid Build Coastguard Worker         TestEventHandler eh4{reporter, e1, {}, {}, {}};
239*c8dee2aaSAndroid Build Coastguard Worker         eq.handleNextEventPoint(&eh4);
240*c8dee2aaSAndroid Build Coastguard Worker 
241*c8dee2aaSAndroid Build Coastguard Worker         TestEventHandler eh5{reporter, e0, {}, {}, {}};
242*c8dee2aaSAndroid Build Coastguard Worker         eq.handleNextEventPoint(&eh5);
243*c8dee2aaSAndroid Build Coastguard Worker 
244*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !eq.hasMoreEvents());
245*c8dee2aaSAndroid Build Coastguard Worker     }
246*c8dee2aaSAndroid Build Coastguard Worker }
247*c8dee2aaSAndroid Build Coastguard Worker 
248