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 "include/core/SkSpan.h"
7*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "modules/bentleyottmann/include/Int96.h"
10*c8dee2aaSAndroid Build Coastguard Worker
11*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
12*c8dee2aaSAndroid Build Coastguard Worker #include <climits>
13*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
14*c8dee2aaSAndroid Build Coastguard Worker #include <iterator>
15*c8dee2aaSAndroid Build Coastguard Worker #include <tuple>
16*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
17*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
18*c8dee2aaSAndroid Build Coastguard Worker
19*c8dee2aaSAndroid Build Coastguard Worker namespace myers {
20*c8dee2aaSAndroid Build Coastguard Worker
21*c8dee2aaSAndroid Build Coastguard Worker // -- Point ----------------------------------------------------------------------------------------
operator -(const Point & p0,const Point & p1)22*c8dee2aaSAndroid Build Coastguard Worker Point operator-(const Point& p0, const Point& p1) {
23*c8dee2aaSAndroid Build Coastguard Worker return {p0.x - p1.x, p0.y - p1.y};
24*c8dee2aaSAndroid Build Coastguard Worker }
25*c8dee2aaSAndroid Build Coastguard Worker
point_to_s64(Point p)26*c8dee2aaSAndroid Build Coastguard Worker std::tuple<int64_t, int64_t> point_to_s64(Point p) {
27*c8dee2aaSAndroid Build Coastguard Worker return std::make_tuple(SkToS64(p.x), SkToS64(p.y));
28*c8dee2aaSAndroid Build Coastguard Worker }
29*c8dee2aaSAndroid Build Coastguard Worker
30*c8dee2aaSAndroid Build Coastguard Worker // -- Segment --------------------------------------------------------------------------------------
upper() const31*c8dee2aaSAndroid Build Coastguard Worker const Point& Segment::upper() const {
32*c8dee2aaSAndroid Build Coastguard Worker return fUpper;
33*c8dee2aaSAndroid Build Coastguard Worker }
34*c8dee2aaSAndroid Build Coastguard Worker
lower() const35*c8dee2aaSAndroid Build Coastguard Worker const Point& Segment::lower() const {
36*c8dee2aaSAndroid Build Coastguard Worker return fLower;
37*c8dee2aaSAndroid Build Coastguard Worker }
38*c8dee2aaSAndroid Build Coastguard Worker
bounds() const39*c8dee2aaSAndroid Build Coastguard Worker std::tuple<int32_t, int32_t, int32_t, int32_t> Segment::bounds() const {
40*c8dee2aaSAndroid Build Coastguard Worker auto [left, right] = std::minmax(fUpper.x, fLower.x);
41*c8dee2aaSAndroid Build Coastguard Worker return std::make_tuple(left, fUpper.y, right, fLower.y);
42*c8dee2aaSAndroid Build Coastguard Worker }
43*c8dee2aaSAndroid Build Coastguard Worker
isHorizontal() const44*c8dee2aaSAndroid Build Coastguard Worker bool Segment::isHorizontal() const {
45*c8dee2aaSAndroid Build Coastguard Worker return fUpper.y == fLower.y;
46*c8dee2aaSAndroid Build Coastguard Worker }
47*c8dee2aaSAndroid Build Coastguard Worker
isVertical() const48*c8dee2aaSAndroid Build Coastguard Worker bool Segment::isVertical() const {
49*c8dee2aaSAndroid Build Coastguard Worker return fUpper.x == fLower.x;
50*c8dee2aaSAndroid Build Coastguard Worker }
51*c8dee2aaSAndroid Build Coastguard Worker
52*c8dee2aaSAndroid Build Coastguard Worker // Return:
53*c8dee2aaSAndroid Build Coastguard Worker // | d0x d1x |
54*c8dee2aaSAndroid Build Coastguard Worker // | d0y d1y |
cross(Point d0,Point d1)55*c8dee2aaSAndroid Build Coastguard Worker int64_t cross(Point d0, Point d1) {
56*c8dee2aaSAndroid Build Coastguard Worker const auto [d0x, d0y] = point_to_s64(d0);
57*c8dee2aaSAndroid Build Coastguard Worker const auto [d1x, d1y] = point_to_s64(d1);
58*c8dee2aaSAndroid Build Coastguard Worker return d0x * d1y - d1x * d0y;
59*c8dee2aaSAndroid Build Coastguard Worker }
60*c8dee2aaSAndroid Build Coastguard Worker
61*c8dee2aaSAndroid Build Coastguard Worker // compare_slopes returns a comparison of the slope of s0 to the slope of s1 where
62*c8dee2aaSAndroid Build Coastguard Worker // slope(s) = dx / dy
63*c8dee2aaSAndroid Build Coastguard Worker // instead of the regular dy / dx, and neither s0 nor s1 are horizontal.
64*c8dee2aaSAndroid Build Coastguard Worker //
65*c8dee2aaSAndroid Build Coastguard Worker // The slope for non-horizontal segments monotonically increases from the smallest along the
66*c8dee2aaSAndroid Build Coastguard Worker // negative x-axis increasing counterclockwise to the largest along the positive x-axis.
compare_slopes(const Segment & s0,const Segment & s1)67*c8dee2aaSAndroid Build Coastguard Worker int64_t compare_slopes(const Segment& s0, const Segment& s1) {
68*c8dee2aaSAndroid Build Coastguard Worker // Handle cases involving horizontal segments.
69*c8dee2aaSAndroid Build Coastguard Worker if (s0.isHorizontal() || s1.isHorizontal()) {
70*c8dee2aaSAndroid Build Coastguard Worker if (s0.isHorizontal() && s1.isHorizontal()) {
71*c8dee2aaSAndroid Build Coastguard Worker // slope(s0) == slope(s1)
72*c8dee2aaSAndroid Build Coastguard Worker return 0;
73*c8dee2aaSAndroid Build Coastguard Worker }
74*c8dee2aaSAndroid Build Coastguard Worker if (s0.isHorizontal()) {
75*c8dee2aaSAndroid Build Coastguard Worker // slope(s0) > slope(s1)
76*c8dee2aaSAndroid Build Coastguard Worker return 1;
77*c8dee2aaSAndroid Build Coastguard Worker } else {
78*c8dee2aaSAndroid Build Coastguard Worker // slope(s0) < slope(s1)
79*c8dee2aaSAndroid Build Coastguard Worker return -1;
80*c8dee2aaSAndroid Build Coastguard Worker }
81*c8dee2aaSAndroid Build Coastguard Worker }
82*c8dee2aaSAndroid Build Coastguard Worker
83*c8dee2aaSAndroid Build Coastguard Worker const auto [u0, l0] = s0;
84*c8dee2aaSAndroid Build Coastguard Worker const auto [u1, l1] = s1;
85*c8dee2aaSAndroid Build Coastguard Worker
86*c8dee2aaSAndroid Build Coastguard Worker const Point d0 = l0 - u0;
87*c8dee2aaSAndroid Build Coastguard Worker const Point d1 = l1 - u1;
88*c8dee2aaSAndroid Build Coastguard Worker
89*c8dee2aaSAndroid Build Coastguard Worker // Since horizontal lines are handled separately and because of the ordering of points for
90*c8dee2aaSAndroid Build Coastguard Worker // a segment, then d0y and d1y should always be positive.
91*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(d0.y > 0 && d1.y > 0);
92*c8dee2aaSAndroid Build Coastguard Worker
93*c8dee2aaSAndroid Build Coastguard Worker // * slope(s0) = d0.x / d0.y
94*c8dee2aaSAndroid Build Coastguard Worker // * slope(s1) = d1.x / d1.y
95*c8dee2aaSAndroid Build Coastguard Worker // If we want to find d0.x / d0.y < d1.x / d1.y, then
96*c8dee2aaSAndroid Build Coastguard Worker // d0x * d1y < d1x * d0y
97*c8dee2aaSAndroid Build Coastguard Worker // d0x * d1y - d1x * d0y < 0.
98*c8dee2aaSAndroid Build Coastguard Worker //
99*c8dee2aaSAndroid Build Coastguard Worker // We know that d0.y and d1.y are both positive, therefore, we can do a cross multiply without
100*c8dee2aaSAndroid Build Coastguard Worker // worrying about changing the relation.
101*c8dee2aaSAndroid Build Coastguard Worker // We can define ==, and > in a similar way:
102*c8dee2aaSAndroid Build Coastguard Worker // * < - cross_of_slopes(s0, s1) < 0
103*c8dee2aaSAndroid Build Coastguard Worker // * == - cross_of_slopes(s0, s1) == 0
104*c8dee2aaSAndroid Build Coastguard Worker // * > - cross_of_slopes(s0, s1) > 0
105*c8dee2aaSAndroid Build Coastguard Worker return cross(d0, d1);
106*c8dee2aaSAndroid Build Coastguard Worker }
107*c8dee2aaSAndroid Build Coastguard Worker
108*c8dee2aaSAndroid Build Coastguard Worker // Returns true of slope(s0) < slope(s1). See compare_slopes above for more information.
slope_s0_less_than_slope_s1(const Segment & s0,const Segment & s1)109*c8dee2aaSAndroid Build Coastguard Worker bool slope_s0_less_than_slope_s1(const Segment& s0, const Segment& s1) {
110*c8dee2aaSAndroid Build Coastguard Worker return compare_slopes(s0, s1) < 0;
111*c8dee2aaSAndroid Build Coastguard Worker }
112*c8dee2aaSAndroid Build Coastguard Worker
113*c8dee2aaSAndroid Build Coastguard Worker // compare_point_to_segment the relation between a point p and a segment s in the following way:
114*c8dee2aaSAndroid Build Coastguard Worker // * p < s if the cross product is negative.
115*c8dee2aaSAndroid Build Coastguard Worker // * p == s if the cross product is zero.
116*c8dee2aaSAndroid Build Coastguard Worker // * p > s if the cross product is positive.
compare_point_to_segment(Point p,const Segment & s)117*c8dee2aaSAndroid Build Coastguard Worker int64_t compare_point_to_segment(Point p, const Segment& s) {
118*c8dee2aaSAndroid Build Coastguard Worker const auto [u, l] = s;
119*c8dee2aaSAndroid Build Coastguard Worker
120*c8dee2aaSAndroid Build Coastguard Worker // The segment must span p vertically.
121*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(u.y <= p.y && p.y <= l.y);
122*c8dee2aaSAndroid Build Coastguard Worker
123*c8dee2aaSAndroid Build Coastguard Worker // Check horizontal extents.
124*c8dee2aaSAndroid Build Coastguard Worker {
125*c8dee2aaSAndroid Build Coastguard Worker const auto [left, right] = std::minmax(u.x, l.x);
126*c8dee2aaSAndroid Build Coastguard Worker if (p.x < left) {
127*c8dee2aaSAndroid Build Coastguard Worker return -1;
128*c8dee2aaSAndroid Build Coastguard Worker }
129*c8dee2aaSAndroid Build Coastguard Worker
130*c8dee2aaSAndroid Build Coastguard Worker if (right < p.x) {
131*c8dee2aaSAndroid Build Coastguard Worker return 1;
132*c8dee2aaSAndroid Build Coastguard Worker }
133*c8dee2aaSAndroid Build Coastguard Worker }
134*c8dee2aaSAndroid Build Coastguard Worker
135*c8dee2aaSAndroid Build Coastguard Worker // If s is horizontal, then p is on the interval [u.x, l.x].
136*c8dee2aaSAndroid Build Coastguard Worker if (s.isHorizontal()) {
137*c8dee2aaSAndroid Build Coastguard Worker return 0;
138*c8dee2aaSAndroid Build Coastguard Worker }
139*c8dee2aaSAndroid Build Coastguard Worker
140*c8dee2aaSAndroid Build Coastguard Worker // The point p < s when:
141*c8dee2aaSAndroid Build Coastguard Worker // p.x < u.x + (l.x - u.x)(p.y - u.y) / (l.y - u.y),
142*c8dee2aaSAndroid Build Coastguard Worker // p.x - u.x < (l.x - u.x)(p.y - u.y) / (l.y - u.y),
143*c8dee2aaSAndroid Build Coastguard Worker // (p.x - u.x)(l.y - u.y) < (l.x - u.x)(p.y - u.y),
144*c8dee2aaSAndroid Build Coastguard Worker // (p.x - u.x)(l.y - u.y) - (l.x - u.x)(p.y - u.y) < 0,
145*c8dee2aaSAndroid Build Coastguard Worker // (p - u) x (l - u) < 0,
146*c8dee2aaSAndroid Build Coastguard Worker // dUtoP x dS < 0.
147*c8dee2aaSAndroid Build Coastguard Worker // The other relations can be implemented in a similar way.
148*c8dee2aaSAndroid Build Coastguard Worker const Point dUToP = p - u;
149*c8dee2aaSAndroid Build Coastguard Worker const Point dS = l - u;
150*c8dee2aaSAndroid Build Coastguard Worker
151*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(dS.y > 0);
152*c8dee2aaSAndroid Build Coastguard Worker return cross(dUToP, dS);
153*c8dee2aaSAndroid Build Coastguard Worker }
154*c8dee2aaSAndroid Build Coastguard Worker
155*c8dee2aaSAndroid Build Coastguard Worker // segment_less_than_upper_to_insert is used with std::lower_bound to find the place to insert the
156*c8dee2aaSAndroid Build Coastguard Worker // segment to_insert in a vector. The signature of this function is crafted to work with
157*c8dee2aaSAndroid Build Coastguard Worker // lower_bound.
segment_less_than_upper_to_insert(const Segment & segment,const Segment & to_insert)158*c8dee2aaSAndroid Build Coastguard Worker bool segment_less_than_upper_to_insert(const Segment& segment, const Segment& to_insert) {
159*c8dee2aaSAndroid Build Coastguard Worker const int64_t compare = compare_point_to_segment(to_insert.upper(), segment);
160*c8dee2aaSAndroid Build Coastguard Worker
161*c8dee2aaSAndroid Build Coastguard Worker // compare > 0 when segment < to_insert.upper().
162*c8dee2aaSAndroid Build Coastguard Worker return (compare > 0) || ((compare == 0) && slope_s0_less_than_slope_s1(segment, to_insert));
163*c8dee2aaSAndroid Build Coastguard Worker }
164*c8dee2aaSAndroid Build Coastguard Worker
165*c8dee2aaSAndroid Build Coastguard Worker // Return true if s0(y) < s1(y) else if s0(y) == s1(y) then slope(s0) < slope(s1)
s0_less_than_s1_at_y(const Segment & s0,const Segment & s1,int32_t y)166*c8dee2aaSAndroid Build Coastguard Worker bool s0_less_than_s1_at_y(const Segment& s0, const Segment& s1, int32_t y) {
167*c8dee2aaSAndroid Build Coastguard Worker // Neither s0 nor s1 are horizontal because this is used during the sorting phase
168*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!s0.isHorizontal() && !s1.isHorizontal());
169*c8dee2aaSAndroid Build Coastguard Worker
170*c8dee2aaSAndroid Build Coastguard Worker const auto [u0, l0] = s0;
171*c8dee2aaSAndroid Build Coastguard Worker const auto [u1, l1] = s1;
172*c8dee2aaSAndroid Build Coastguard Worker
173*c8dee2aaSAndroid Build Coastguard Worker const auto [left0, right0] = std::minmax(u0.x, l0.x);
174*c8dee2aaSAndroid Build Coastguard Worker const auto [left1, right1] = std::minmax(u1.x, l1.x);
175*c8dee2aaSAndroid Build Coastguard Worker
176*c8dee2aaSAndroid Build Coastguard Worker if (right0 < left1) {
177*c8dee2aaSAndroid Build Coastguard Worker return true;
178*c8dee2aaSAndroid Build Coastguard Worker } else if (right1 < left0) {
179*c8dee2aaSAndroid Build Coastguard Worker return false;
180*c8dee2aaSAndroid Build Coastguard Worker }
181*c8dee2aaSAndroid Build Coastguard Worker
182*c8dee2aaSAndroid Build Coastguard Worker const Point d0 = l0 - u0;
183*c8dee2aaSAndroid Build Coastguard Worker const Point d1 = l1 - u1;
184*c8dee2aaSAndroid Build Coastguard Worker
185*c8dee2aaSAndroid Build Coastguard Worker // Since horizontal lines are handled separately and the ordering of points for the segment,
186*c8dee2aaSAndroid Build Coastguard Worker // then there should always be positive Dy.
187*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(d0.y > 0 && d1.y > 0);
188*c8dee2aaSAndroid Build Coastguard Worker
189*c8dee2aaSAndroid Build Coastguard Worker namespace bo = bentleyottmann;
190*c8dee2aaSAndroid Build Coastguard Worker using Int96 = bo::Int96;
191*c8dee2aaSAndroid Build Coastguard Worker
192*c8dee2aaSAndroid Build Coastguard Worker // Defining s0(y) and s1(y),
193*c8dee2aaSAndroid Build Coastguard Worker // s0(y) = u0.x + (y - u0.y) * d0.x / d0.y
194*c8dee2aaSAndroid Build Coastguard Worker // s1(y) = u1.x + (y - u1.y) * d1.x / d1.y
195*c8dee2aaSAndroid Build Coastguard Worker // Find the following
196*c8dee2aaSAndroid Build Coastguard Worker // s0(y) < s1(y)
197*c8dee2aaSAndroid Build Coastguard Worker // Substituting s0(y) and s1(y)
198*c8dee2aaSAndroid Build Coastguard Worker // u0.x + (y - u0.y) * d0.x / d0.y < u1.x + (y - u1.y) * d1.x / d1.y
199*c8dee2aaSAndroid Build Coastguard Worker // Factoring out the denominator.
200*c8dee2aaSAndroid Build Coastguard Worker // (u0.x * d0.y + (y - u0.y) * d0.x) / d0.y < (u1.x * d1.y + (y - u1.y) * d1.x) / d1.y
201*c8dee2aaSAndroid Build Coastguard Worker // Cross-multiplying the denominators. The sign will not switch because d0.y and d1.y are
202*c8dee2aaSAndroid Build Coastguard Worker // always positive.
203*c8dee2aaSAndroid Build Coastguard Worker // d1.y * (u0.x * d0.y + (y - u0.y) * d0.x) < d0.y * (u1.x * d1.y + (y - u1.y) * d1.x)
204*c8dee2aaSAndroid Build Coastguard Worker // If these are equal, then we use the slope to break the tie.
205*c8dee2aaSAndroid Build Coastguard Worker // d0.x / d0.y < d1.x / d1.y
206*c8dee2aaSAndroid Build Coastguard Worker // Cross multiplying leaves.
207*c8dee2aaSAndroid Build Coastguard Worker // d0.x * d1.y < d1.x * d0.y
208*c8dee2aaSAndroid Build Coastguard Worker const Int96 lhs = bo::multiply(d1.y, u0.x * SkToS64(d0.y) + (y - u0.y) * SkToS64(d0.x));
209*c8dee2aaSAndroid Build Coastguard Worker const Int96 rhs = bo::multiply(d0.y, u1.x * SkToS64(d1.y) + (y - u1.y) * SkToS64(d1.x));
210*c8dee2aaSAndroid Build Coastguard Worker
211*c8dee2aaSAndroid Build Coastguard Worker return lhs < rhs || ((lhs == rhs) && slope_s0_less_than_slope_s1(s0, s1));
212*c8dee2aaSAndroid Build Coastguard Worker }
213*c8dee2aaSAndroid Build Coastguard Worker
214*c8dee2aaSAndroid Build Coastguard Worker // -- Event ----------------------------------------------------------------------------------------
215*c8dee2aaSAndroid Build Coastguard Worker // Events are horizontal lines at a given y where segments are added, or they contain one or
216*c8dee2aaSAndroid Build Coastguard Worker // more horizontal lines, or segments end.
217*c8dee2aaSAndroid Build Coastguard Worker struct Event {
218*c8dee2aaSAndroid Build Coastguard Worker const int32_t y;
219*c8dee2aaSAndroid Build Coastguard Worker
220*c8dee2aaSAndroid Build Coastguard Worker // The set of segments that begin at y.
221*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const Segment> begin;
222*c8dee2aaSAndroid Build Coastguard Worker
223*c8dee2aaSAndroid Build Coastguard Worker // The set of segments that are horizontal on y.
224*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const Segment> horizontal;
225*c8dee2aaSAndroid Build Coastguard Worker
226*c8dee2aaSAndroid Build Coastguard Worker // The set of segments that end on y.
227*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const Segment> end;
228*c8dee2aaSAndroid Build Coastguard Worker };
229*c8dee2aaSAndroid Build Coastguard Worker
230*c8dee2aaSAndroid Build Coastguard Worker // -- EventQueue -----------------------------------------------------------------------------------
231*c8dee2aaSAndroid Build Coastguard Worker // The EventQueue produces Events. Events are never added to the queue after initial creation.
232*c8dee2aaSAndroid Build Coastguard Worker class EventQueue {
233*c8dee2aaSAndroid Build Coastguard Worker class Iterator {
234*c8dee2aaSAndroid Build Coastguard Worker public:
235*c8dee2aaSAndroid Build Coastguard Worker using value_type = Event;
236*c8dee2aaSAndroid Build Coastguard Worker using difference_type = ptrdiff_t;
237*c8dee2aaSAndroid Build Coastguard Worker using pointer = value_type*;
238*c8dee2aaSAndroid Build Coastguard Worker using reference = value_type;
239*c8dee2aaSAndroid Build Coastguard Worker using iterator_category = std::input_iterator_tag;
Iterator(const EventQueue & eventQueue,size_t index)240*c8dee2aaSAndroid Build Coastguard Worker Iterator(const EventQueue& eventQueue, size_t index)
241*c8dee2aaSAndroid Build Coastguard Worker : fEventQueue{eventQueue}
242*c8dee2aaSAndroid Build Coastguard Worker , fIndex{index} { }
Iterator(const Iterator & that)243*c8dee2aaSAndroid Build Coastguard Worker Iterator(const Iterator& that) : Iterator{ that.fEventQueue, that.fIndex } { }
operator ++()244*c8dee2aaSAndroid Build Coastguard Worker Iterator& operator++() { ++fIndex; return *this; }
operator ++(int)245*c8dee2aaSAndroid Build Coastguard Worker Iterator operator++(int) { Iterator tmp(*this); operator++(); return tmp; }
operator ==(const Iterator & rhs) const246*c8dee2aaSAndroid Build Coastguard Worker bool operator==(const Iterator& rhs) const { return fIndex == rhs.fIndex; }
operator !=(const Iterator & rhs) const247*c8dee2aaSAndroid Build Coastguard Worker bool operator!=(const Iterator& rhs) const { return fIndex != rhs.fIndex; }
operator *()248*c8dee2aaSAndroid Build Coastguard Worker value_type operator*() { return fEventQueue[fIndex]; }
operator -(Iterator lhs,Iterator rhs)249*c8dee2aaSAndroid Build Coastguard Worker friend difference_type operator-(Iterator lhs, Iterator rhs) {
250*c8dee2aaSAndroid Build Coastguard Worker return lhs.fIndex - rhs.fIndex;
251*c8dee2aaSAndroid Build Coastguard Worker }
252*c8dee2aaSAndroid Build Coastguard Worker
253*c8dee2aaSAndroid Build Coastguard Worker private:
254*c8dee2aaSAndroid Build Coastguard Worker const EventQueue& fEventQueue;
255*c8dee2aaSAndroid Build Coastguard Worker size_t fIndex = 0;
256*c8dee2aaSAndroid Build Coastguard Worker };
257*c8dee2aaSAndroid Build Coastguard Worker
258*c8dee2aaSAndroid Build Coastguard Worker // Events are stored using CompactEvent, Events are only passed back from nextEvent. start,
259*c8dee2aaSAndroid Build Coastguard Worker // endOfBegin, etc. are all indexes into fSegmentStorage. The beginning segments for the event
260*c8dee2aaSAndroid Build Coastguard Worker // are from start to endOfBegin, the horizontal segments are from endOfBegin to endOfStart, and
261*c8dee2aaSAndroid Build Coastguard Worker // the end segments are from endOfHorizontal to endOfEnd.
262*c8dee2aaSAndroid Build Coastguard Worker class CompactEvent {
263*c8dee2aaSAndroid Build Coastguard Worker public:
264*c8dee2aaSAndroid Build Coastguard Worker const int32_t y;
265*c8dee2aaSAndroid Build Coastguard Worker const int32_t start;
266*c8dee2aaSAndroid Build Coastguard Worker const int32_t endOfBegin;
267*c8dee2aaSAndroid Build Coastguard Worker const int32_t endOfHorizontal;
268*c8dee2aaSAndroid Build Coastguard Worker const int32_t endOfEnd;
269*c8dee2aaSAndroid Build Coastguard Worker };
270*c8dee2aaSAndroid Build Coastguard Worker
271*c8dee2aaSAndroid Build Coastguard Worker public:
272*c8dee2aaSAndroid Build Coastguard Worker // Given a list of segments make an EventQueue, and populate its queue with events.
Make(const SkSpan<const Segment> segments)273*c8dee2aaSAndroid Build Coastguard Worker static EventQueue Make(const SkSpan<const Segment> segments) {
274*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!segments.empty());
275*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(segments.size() < INT32_MAX);
276*c8dee2aaSAndroid Build Coastguard Worker
277*c8dee2aaSAndroid Build Coastguard Worker enum EventType {
278*c8dee2aaSAndroid Build Coastguard Worker kBegin = 0,
279*c8dee2aaSAndroid Build Coastguard Worker kHorizontal = 1,
280*c8dee2aaSAndroid Build Coastguard Worker kEnd = 2
281*c8dee2aaSAndroid Build Coastguard Worker };
282*c8dee2aaSAndroid Build Coastguard Worker
283*c8dee2aaSAndroid Build Coastguard Worker // A vector of SetupTuple when ordered will produce the events, and all the different
284*c8dee2aaSAndroid Build Coastguard Worker // sets of segments (beginning, etc.).
285*c8dee2aaSAndroid Build Coastguard Worker struct SetupTuple {
286*c8dee2aaSAndroid Build Coastguard Worker // The main ordering of events.
287*c8dee2aaSAndroid Build Coastguard Worker int32_t yOrdering;
288*c8dee2aaSAndroid Build Coastguard Worker
289*c8dee2aaSAndroid Build Coastguard Worker // Group together like event types together.
290*c8dee2aaSAndroid Build Coastguard Worker EventType type;
291*c8dee2aaSAndroid Build Coastguard Worker
292*c8dee2aaSAndroid Build Coastguard Worker // Break ties if yOrdering is the same.
293*c8dee2aaSAndroid Build Coastguard Worker int32_t xTieBreaker;
294*c8dee2aaSAndroid Build Coastguard Worker
295*c8dee2aaSAndroid Build Coastguard Worker // We want to sort the segments, but they are not part of the key.
296*c8dee2aaSAndroid Build Coastguard Worker Segment originalSegment;
297*c8dee2aaSAndroid Build Coastguard Worker
298*c8dee2aaSAndroid Build Coastguard Worker bool operator==(const SetupTuple& r) const {
299*c8dee2aaSAndroid Build Coastguard Worker return
300*c8dee2aaSAndroid Build Coastguard Worker std::tie(this->yOrdering, this->type, this->xTieBreaker, this->originalSegment)
301*c8dee2aaSAndroid Build Coastguard Worker == std::tie(r.yOrdering, r.type, r.xTieBreaker, r.originalSegment);
302*c8dee2aaSAndroid Build Coastguard Worker }
303*c8dee2aaSAndroid Build Coastguard Worker };
304*c8dee2aaSAndroid Build Coastguard Worker
305*c8dee2aaSAndroid Build Coastguard Worker std::vector<SetupTuple> eventOrdering;
306*c8dee2aaSAndroid Build Coastguard Worker for (const auto& s : segments) {
307*c8dee2aaSAndroid Build Coastguard Worker
308*c8dee2aaSAndroid Build Coastguard Worker // Exclude zero length segments.
309*c8dee2aaSAndroid Build Coastguard Worker if (s.upper() == s.lower()) {
310*c8dee2aaSAndroid Build Coastguard Worker continue;
311*c8dee2aaSAndroid Build Coastguard Worker }
312*c8dee2aaSAndroid Build Coastguard Worker
313*c8dee2aaSAndroid Build Coastguard Worker if (s.isHorizontal()) {
314*c8dee2aaSAndroid Build Coastguard Worker // Tag for the horizontal set.
315*c8dee2aaSAndroid Build Coastguard Worker eventOrdering.push_back(SetupTuple{s.upper().y, kHorizontal, -s.upper().x, s});
316*c8dee2aaSAndroid Build Coastguard Worker } else {
317*c8dee2aaSAndroid Build Coastguard Worker // Tag for the beginning and ending sets.
318*c8dee2aaSAndroid Build Coastguard Worker eventOrdering.push_back(SetupTuple{s.upper().y, kBegin, -s.upper().x, s});
319*c8dee2aaSAndroid Build Coastguard Worker eventOrdering.push_back(SetupTuple{s.lower().y, kEnd, -s.lower().x, s});
320*c8dee2aaSAndroid Build Coastguard Worker }
321*c8dee2aaSAndroid Build Coastguard Worker }
322*c8dee2aaSAndroid Build Coastguard Worker
323*c8dee2aaSAndroid Build Coastguard Worker // Order the tuples by y, then by set type, then by x value.
324*c8dee2aaSAndroid Build Coastguard Worker auto eventLess = [](const SetupTuple& l, const SetupTuple& r) {
325*c8dee2aaSAndroid Build Coastguard Worker return std::tie(l.yOrdering, l.type, l.xTieBreaker) <
326*c8dee2aaSAndroid Build Coastguard Worker std::tie(r.yOrdering, r.type, r.xTieBreaker);
327*c8dee2aaSAndroid Build Coastguard Worker };
328*c8dee2aaSAndroid Build Coastguard Worker
329*c8dee2aaSAndroid Build Coastguard Worker // Sort the events.
330*c8dee2aaSAndroid Build Coastguard Worker std::sort(eventOrdering.begin(), eventOrdering.end(), eventLess);
331*c8dee2aaSAndroid Build Coastguard Worker
332*c8dee2aaSAndroid Build Coastguard Worker // Remove duplicate segments.
333*c8dee2aaSAndroid Build Coastguard Worker auto eraseFrom = std::unique(eventOrdering.begin(), eventOrdering.end());
334*c8dee2aaSAndroid Build Coastguard Worker eventOrdering.erase(eraseFrom, eventOrdering.end());
335*c8dee2aaSAndroid Build Coastguard Worker
336*c8dee2aaSAndroid Build Coastguard Worker std::vector<CompactEvent> events;
337*c8dee2aaSAndroid Build Coastguard Worker std::vector<Segment> segmentStorage;
338*c8dee2aaSAndroid Build Coastguard Worker segmentStorage.reserve(eventOrdering.size());
339*c8dee2aaSAndroid Build Coastguard Worker
340*c8dee2aaSAndroid Build Coastguard Worker int32_t currentY = eventOrdering.front().yOrdering;
341*c8dee2aaSAndroid Build Coastguard Worker int32_t start = 0,
342*c8dee2aaSAndroid Build Coastguard Worker endOfBegin = 0,
343*c8dee2aaSAndroid Build Coastguard Worker endOfHorizontal = 0,
344*c8dee2aaSAndroid Build Coastguard Worker endOfEnd = 0;
345*c8dee2aaSAndroid Build Coastguard Worker for (const auto& [y, type, _, s] : eventOrdering) {
346*c8dee2aaSAndroid Build Coastguard Worker // If this is a new y then create the compact event.
347*c8dee2aaSAndroid Build Coastguard Worker if (currentY != y) {
348*c8dee2aaSAndroid Build Coastguard Worker events.push_back(CompactEvent{currentY,
349*c8dee2aaSAndroid Build Coastguard Worker start,
350*c8dee2aaSAndroid Build Coastguard Worker endOfBegin,
351*c8dee2aaSAndroid Build Coastguard Worker endOfHorizontal,
352*c8dee2aaSAndroid Build Coastguard Worker endOfEnd});
353*c8dee2aaSAndroid Build Coastguard Worker start = endOfBegin = endOfHorizontal = endOfEnd = segmentStorage.size();
354*c8dee2aaSAndroid Build Coastguard Worker currentY = y;
355*c8dee2aaSAndroid Build Coastguard Worker }
356*c8dee2aaSAndroid Build Coastguard Worker
357*c8dee2aaSAndroid Build Coastguard Worker segmentStorage.push_back(s);
358*c8dee2aaSAndroid Build Coastguard Worker
359*c8dee2aaSAndroid Build Coastguard Worker // Increment the various set indices.
360*c8dee2aaSAndroid Build Coastguard Worker const size_t segmentCount = segmentStorage.size();
361*c8dee2aaSAndroid Build Coastguard Worker switch (type) {
362*c8dee2aaSAndroid Build Coastguard Worker case kBegin: endOfBegin = segmentCount;
363*c8dee2aaSAndroid Build Coastguard Worker [[fallthrough]];
364*c8dee2aaSAndroid Build Coastguard Worker case kHorizontal: endOfHorizontal = segmentCount;
365*c8dee2aaSAndroid Build Coastguard Worker [[fallthrough]];
366*c8dee2aaSAndroid Build Coastguard Worker case kEnd: endOfEnd = segmentCount;
367*c8dee2aaSAndroid Build Coastguard Worker }
368*c8dee2aaSAndroid Build Coastguard Worker }
369*c8dee2aaSAndroid Build Coastguard Worker
370*c8dee2aaSAndroid Build Coastguard Worker // Store the last event.
371*c8dee2aaSAndroid Build Coastguard Worker events.push_back(CompactEvent{currentY,
372*c8dee2aaSAndroid Build Coastguard Worker start,
373*c8dee2aaSAndroid Build Coastguard Worker endOfBegin,
374*c8dee2aaSAndroid Build Coastguard Worker endOfHorizontal,
375*c8dee2aaSAndroid Build Coastguard Worker endOfEnd});
376*c8dee2aaSAndroid Build Coastguard Worker
377*c8dee2aaSAndroid Build Coastguard Worker return EventQueue{std::move(events), std::move(segmentStorage)};
378*c8dee2aaSAndroid Build Coastguard Worker }
379*c8dee2aaSAndroid Build Coastguard Worker
operator [](size_t i) const380*c8dee2aaSAndroid Build Coastguard Worker Event operator[](size_t i) const {
381*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(i < fEvents.size());
382*c8dee2aaSAndroid Build Coastguard Worker auto& [y, start, endOfBegin, endOfHorizontal, endOfEnd] = fEvents[i];
383*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const Segment> begin{&fSegmentStorage[start], endOfBegin - start};
384*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const Segment>
385*c8dee2aaSAndroid Build Coastguard Worker horizontal{&fSegmentStorage[endOfBegin], endOfHorizontal - endOfBegin};
386*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const Segment> end{&fSegmentStorage[endOfHorizontal], endOfEnd - endOfHorizontal};
387*c8dee2aaSAndroid Build Coastguard Worker return Event{y, begin, horizontal, end};
388*c8dee2aaSAndroid Build Coastguard Worker }
389*c8dee2aaSAndroid Build Coastguard Worker
begin() const390*c8dee2aaSAndroid Build Coastguard Worker Iterator begin() const {
391*c8dee2aaSAndroid Build Coastguard Worker return Iterator{*this, 0};
392*c8dee2aaSAndroid Build Coastguard Worker }
393*c8dee2aaSAndroid Build Coastguard Worker
end() const394*c8dee2aaSAndroid Build Coastguard Worker Iterator end() const {
395*c8dee2aaSAndroid Build Coastguard Worker return Iterator{*this, fEvents.size()};
396*c8dee2aaSAndroid Build Coastguard Worker }
397*c8dee2aaSAndroid Build Coastguard Worker
size() const398*c8dee2aaSAndroid Build Coastguard Worker size_t size() const {
399*c8dee2aaSAndroid Build Coastguard Worker return fEvents.size();
400*c8dee2aaSAndroid Build Coastguard Worker }
401*c8dee2aaSAndroid Build Coastguard Worker
empty() const402*c8dee2aaSAndroid Build Coastguard Worker bool empty() const {
403*c8dee2aaSAndroid Build Coastguard Worker return fEvents.empty();
404*c8dee2aaSAndroid Build Coastguard Worker }
405*c8dee2aaSAndroid Build Coastguard Worker
406*c8dee2aaSAndroid Build Coastguard Worker private:
EventQueue(std::vector<CompactEvent> && events,std::vector<Segment> && segmentStorage)407*c8dee2aaSAndroid Build Coastguard Worker EventQueue(std::vector<CompactEvent>&& events, std::vector<Segment>&& segmentStorage)
408*c8dee2aaSAndroid Build Coastguard Worker : fEvents{std::move(events)}
409*c8dee2aaSAndroid Build Coastguard Worker , fSegmentStorage{std::move(segmentStorage)} {}
410*c8dee2aaSAndroid Build Coastguard Worker
411*c8dee2aaSAndroid Build Coastguard Worker const std::vector<CompactEvent> fEvents;
412*c8dee2aaSAndroid Build Coastguard Worker const std::vector<Segment> fSegmentStorage;
413*c8dee2aaSAndroid Build Coastguard Worker };
414*c8dee2aaSAndroid Build Coastguard Worker
415*c8dee2aaSAndroid Build Coastguard Worker // -- CrossingAccumulator --------------------------------------------------------------------------
416*c8dee2aaSAndroid Build Coastguard Worker // Collect all the crossings, and reject endpoint-to-endpoint crossings as those intersections
417*c8dee2aaSAndroid Build Coastguard Worker // are already represented in the data.
418*c8dee2aaSAndroid Build Coastguard Worker class CrossingAccumulator {
419*c8dee2aaSAndroid Build Coastguard Worker public:
recordCrossing(const Segment & s0,const Segment & s1)420*c8dee2aaSAndroid Build Coastguard Worker void recordCrossing(const Segment& s0, const Segment& s1) {
421*c8dee2aaSAndroid Build Coastguard Worker // Endpoints with no possible interior overlap.
422*c8dee2aaSAndroid Build Coastguard Worker if (s0.upper() == s1.lower() || s0.lower() == s1.upper()) {
423*c8dee2aaSAndroid Build Coastguard Worker return;
424*c8dee2aaSAndroid Build Coastguard Worker }
425*c8dee2aaSAndroid Build Coastguard Worker
426*c8dee2aaSAndroid Build Coastguard Worker // Segments don't overlap if they are not collinear.
427*c8dee2aaSAndroid Build Coastguard Worker if ((s0.upper() == s1.upper() || s0.lower() == s1.lower()) && compare_slopes(s0, s1) != 0) {
428*c8dee2aaSAndroid Build Coastguard Worker return;
429*c8dee2aaSAndroid Build Coastguard Worker }
430*c8dee2aaSAndroid Build Coastguard Worker
431*c8dee2aaSAndroid Build Coastguard Worker fCrossings.emplace_back(s0, s1);
432*c8dee2aaSAndroid Build Coastguard Worker }
433*c8dee2aaSAndroid Build Coastguard Worker
finishAndReleaseCrossings()434*c8dee2aaSAndroid Build Coastguard Worker std::vector<Crossing> finishAndReleaseCrossings() {
435*c8dee2aaSAndroid Build Coastguard Worker return std::move(fCrossings);
436*c8dee2aaSAndroid Build Coastguard Worker }
437*c8dee2aaSAndroid Build Coastguard Worker
438*c8dee2aaSAndroid Build Coastguard Worker private:
439*c8dee2aaSAndroid Build Coastguard Worker std::vector<Crossing> fCrossings;
440*c8dee2aaSAndroid Build Coastguard Worker };
441*c8dee2aaSAndroid Build Coastguard Worker
442*c8dee2aaSAndroid Build Coastguard Worker class SweepLine {
443*c8dee2aaSAndroid Build Coastguard Worker static constexpr Segment kLeftStatusSentinel{{INT32_MIN, INT32_MIN}, {INT32_MIN, INT32_MAX}};
444*c8dee2aaSAndroid Build Coastguard Worker static constexpr Segment kRightStatusSentinel{{INT32_MAX, INT32_MIN}, {INT32_MAX, INT32_MAX}};
445*c8dee2aaSAndroid Build Coastguard Worker
446*c8dee2aaSAndroid Build Coastguard Worker public:
SweepLine()447*c8dee2aaSAndroid Build Coastguard Worker SweepLine() {
448*c8dee2aaSAndroid Build Coastguard Worker fStatus.push_back(kLeftStatusSentinel);
449*c8dee2aaSAndroid Build Coastguard Worker fStatus.push_back(kRightStatusSentinel);
450*c8dee2aaSAndroid Build Coastguard Worker }
451*c8dee2aaSAndroid Build Coastguard Worker
handleEvent(Event e)452*c8dee2aaSAndroid Build Coastguard Worker void handleEvent(Event e) {
453*c8dee2aaSAndroid Build Coastguard Worker auto& [y, beginnings, horizontals, endings] = e;
454*c8dee2aaSAndroid Build Coastguard Worker
455*c8dee2aaSAndroid Build Coastguard Worker // Things could be out of order from last event.
456*c8dee2aaSAndroid Build Coastguard Worker this->sortAndRecord(y);
457*c8dee2aaSAndroid Build Coastguard Worker
458*c8dee2aaSAndroid Build Coastguard Worker this->handleBeginnings(y, beginnings);
459*c8dee2aaSAndroid Build Coastguard Worker this->handleHorizontals(y, horizontals);
460*c8dee2aaSAndroid Build Coastguard Worker this->handleEndings(endings);
461*c8dee2aaSAndroid Build Coastguard Worker }
462*c8dee2aaSAndroid Build Coastguard Worker
finishAndReleaseCrossings()463*c8dee2aaSAndroid Build Coastguard Worker std::vector<Crossing> finishAndReleaseCrossings() {
464*c8dee2aaSAndroid Build Coastguard Worker // Only the sentinels should be left.
465*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->statusEmpty());
466*c8dee2aaSAndroid Build Coastguard Worker return fCrossings.finishAndReleaseCrossings();
467*c8dee2aaSAndroid Build Coastguard Worker }
468*c8dee2aaSAndroid Build Coastguard Worker
469*c8dee2aaSAndroid Build Coastguard Worker private:
470*c8dee2aaSAndroid Build Coastguard Worker using StatusLine = std::vector<Segment>;
471*c8dee2aaSAndroid Build Coastguard Worker
statusEmpty() const472*c8dee2aaSAndroid Build Coastguard Worker bool statusEmpty() const {
473*c8dee2aaSAndroid Build Coastguard Worker return fStatus.size() == 2;
474*c8dee2aaSAndroid Build Coastguard Worker }
475*c8dee2aaSAndroid Build Coastguard Worker
476*c8dee2aaSAndroid Build Coastguard Worker // Sort the status line, if items are swapped, then there is a crossing to record.
sortAndRecord(int32_t y)477*c8dee2aaSAndroid Build Coastguard Worker void sortAndRecord(int32_t y) {
478*c8dee2aaSAndroid Build Coastguard Worker // If there are only the sentinels or just 1 segment, then nothing to sort.
479*c8dee2aaSAndroid Build Coastguard Worker if (fStatus.size() <= 3) {
480*c8dee2aaSAndroid Build Coastguard Worker return;
481*c8dee2aaSAndroid Build Coastguard Worker }
482*c8dee2aaSAndroid Build Coastguard Worker
483*c8dee2aaSAndroid Build Coastguard Worker // Skip the first and last sentinels.
484*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 2; i < fStatus.size() - 1; ++i) {
485*c8dee2aaSAndroid Build Coastguard Worker const Segment t = fStatus[i];
486*c8dee2aaSAndroid Build Coastguard Worker size_t j = i;
487*c8dee2aaSAndroid Build Coastguard Worker for (; j > 1 && s0_less_than_s1_at_y(t, fStatus[j - 1], y); --j) {
488*c8dee2aaSAndroid Build Coastguard Worker // While t < the thing before it move it down.
489*c8dee2aaSAndroid Build Coastguard Worker fCrossings.recordCrossing(t, fStatus[j-1]);
490*c8dee2aaSAndroid Build Coastguard Worker fStatus[j] = fStatus[j-1];
491*c8dee2aaSAndroid Build Coastguard Worker }
492*c8dee2aaSAndroid Build Coastguard Worker fStatus[j] = t;
493*c8dee2aaSAndroid Build Coastguard Worker }
494*c8dee2aaSAndroid Build Coastguard Worker }
495*c8dee2aaSAndroid Build Coastguard Worker
496*c8dee2aaSAndroid Build Coastguard Worker // When inserting a starting point (either a beginning or a horizontal) check the segments to
497*c8dee2aaSAndroid Build Coastguard Worker // the left and the right checking nearby segments for crossings.
498*c8dee2aaSAndroid Build Coastguard Worker template <typename CrossingCheck>
checkCrossingsLeftAndRight(const Segment & segment,StatusLine::iterator insertionPoint,CrossingCheck check)499*c8dee2aaSAndroid Build Coastguard Worker void checkCrossingsLeftAndRight(
500*c8dee2aaSAndroid Build Coastguard Worker const Segment& segment, StatusLine::iterator insertionPoint, CrossingCheck check) {
501*c8dee2aaSAndroid Build Coastguard Worker
502*c8dee2aaSAndroid Build Coastguard Worker // Match to the left using the left sentinel to break the loop.
503*c8dee2aaSAndroid Build Coastguard Worker for (auto cursor = std::make_reverse_iterator(insertionPoint); check(*cursor); ++cursor) {
504*c8dee2aaSAndroid Build Coastguard Worker fCrossings.recordCrossing(segment, *cursor);
505*c8dee2aaSAndroid Build Coastguard Worker }
506*c8dee2aaSAndroid Build Coastguard Worker
507*c8dee2aaSAndroid Build Coastguard Worker // Match to the right using the right sentinel to break the loop.
508*c8dee2aaSAndroid Build Coastguard Worker for (auto cursor = insertionPoint; check(*cursor); ++cursor) {
509*c8dee2aaSAndroid Build Coastguard Worker fCrossings.recordCrossing(segment, *cursor);
510*c8dee2aaSAndroid Build Coastguard Worker }
511*c8dee2aaSAndroid Build Coastguard Worker }
512*c8dee2aaSAndroid Build Coastguard Worker
513*c8dee2aaSAndroid Build Coastguard Worker // Add segments that start on y excluding horizontals.
handleBeginnings(int32_t y,SkSpan<const Segment> inserting)514*c8dee2aaSAndroid Build Coastguard Worker void handleBeginnings(int32_t y, SkSpan<const Segment> inserting) {
515*c8dee2aaSAndroid Build Coastguard Worker for (const Segment& s : inserting) {
516*c8dee2aaSAndroid Build Coastguard Worker auto insertionPoint =
517*c8dee2aaSAndroid Build Coastguard Worker std::lower_bound(fStatus.begin(), fStatus.end(), s,
518*c8dee2aaSAndroid Build Coastguard Worker segment_less_than_upper_to_insert);
519*c8dee2aaSAndroid Build Coastguard Worker
520*c8dee2aaSAndroid Build Coastguard Worker // Checking intersections left and right checks if the point s.upper() lies on
521*c8dee2aaSAndroid Build Coastguard Worker // the nearby segment.
522*c8dee2aaSAndroid Build Coastguard Worker auto checkIntersect = [&](const Segment& toCheck) {
523*c8dee2aaSAndroid Build Coastguard Worker return compare_point_to_segment(s.upper(), toCheck) == 0;
524*c8dee2aaSAndroid Build Coastguard Worker };
525*c8dee2aaSAndroid Build Coastguard Worker this->checkCrossingsLeftAndRight(s, insertionPoint, checkIntersect);
526*c8dee2aaSAndroid Build Coastguard Worker
527*c8dee2aaSAndroid Build Coastguard Worker fStatus.insert(insertionPoint, s);
528*c8dee2aaSAndroid Build Coastguard Worker }
529*c8dee2aaSAndroid Build Coastguard Worker }
530*c8dee2aaSAndroid Build Coastguard Worker
531*c8dee2aaSAndroid Build Coastguard Worker // Horizontals on y are handled by checking for crossings by adding them, and then immediately
532*c8dee2aaSAndroid Build Coastguard Worker // removing them.
handleHorizontals(int32_t y,SkSpan<const Segment> horizontals)533*c8dee2aaSAndroid Build Coastguard Worker void handleHorizontals(int32_t y, SkSpan<const Segment> horizontals) {
534*c8dee2aaSAndroid Build Coastguard Worker for (const Segment& s : horizontals) {
535*c8dee2aaSAndroid Build Coastguard Worker auto insertionPoint =
536*c8dee2aaSAndroid Build Coastguard Worker std::lower_bound(fStatus.begin(), fStatus.end(), s,
537*c8dee2aaSAndroid Build Coastguard Worker segment_less_than_upper_to_insert);
538*c8dee2aaSAndroid Build Coastguard Worker
539*c8dee2aaSAndroid Build Coastguard Worker // Check if the nearby segment crosses the horizontal line.
540*c8dee2aaSAndroid Build Coastguard Worker auto checkIntersection = [&](const Segment& toCheck) {
541*c8dee2aaSAndroid Build Coastguard Worker return compare_point_to_segment(s.upper(), toCheck) <= 0 &&
542*c8dee2aaSAndroid Build Coastguard Worker compare_point_to_segment(s.lower(), toCheck) >= 0;
543*c8dee2aaSAndroid Build Coastguard Worker };
544*c8dee2aaSAndroid Build Coastguard Worker this->checkCrossingsLeftAndRight(s, insertionPoint, checkIntersection);
545*c8dee2aaSAndroid Build Coastguard Worker
546*c8dee2aaSAndroid Build Coastguard Worker fStatus.insert(insertionPoint, s);
547*c8dee2aaSAndroid Build Coastguard Worker }
548*c8dee2aaSAndroid Build Coastguard Worker
549*c8dee2aaSAndroid Build Coastguard Worker this->handleEndings(horizontals);
550*c8dee2aaSAndroid Build Coastguard Worker }
551*c8dee2aaSAndroid Build Coastguard Worker
552*c8dee2aaSAndroid Build Coastguard Worker // Remove all the segments ending on y.
handleEndings(SkSpan<const Segment> removing)553*c8dee2aaSAndroid Build Coastguard Worker void handleEndings(SkSpan<const Segment> removing) {
554*c8dee2aaSAndroid Build Coastguard Worker for (const Segment& s : removing) {
555*c8dee2aaSAndroid Build Coastguard Worker auto removedPoint = std::remove(fStatus.begin(), fStatus.end(), s);
556*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(removedPoint != fStatus.end());
557*c8dee2aaSAndroid Build Coastguard Worker fStatus.erase(removedPoint, fStatus.end());
558*c8dee2aaSAndroid Build Coastguard Worker }
559*c8dee2aaSAndroid Build Coastguard Worker }
560*c8dee2aaSAndroid Build Coastguard Worker
561*c8dee2aaSAndroid Build Coastguard Worker StatusLine fStatus;
562*c8dee2aaSAndroid Build Coastguard Worker CrossingAccumulator fCrossings;
563*c8dee2aaSAndroid Build Coastguard Worker };
564*c8dee2aaSAndroid Build Coastguard Worker
myers_find_crossings(const SkSpan<const Segment> segments)565*c8dee2aaSAndroid Build Coastguard Worker std::vector<Crossing> myers_find_crossings(const SkSpan<const Segment> segments) {
566*c8dee2aaSAndroid Build Coastguard Worker const EventQueue eventQueue = EventQueue::Make(segments);
567*c8dee2aaSAndroid Build Coastguard Worker SweepLine sweepLine;
568*c8dee2aaSAndroid Build Coastguard Worker
569*c8dee2aaSAndroid Build Coastguard Worker for (const Event& event : eventQueue) {
570*c8dee2aaSAndroid Build Coastguard Worker sweepLine.handleEvent(event);
571*c8dee2aaSAndroid Build Coastguard Worker }
572*c8dee2aaSAndroid Build Coastguard Worker
573*c8dee2aaSAndroid Build Coastguard Worker return sweepLine.finishAndReleaseCrossings();
574*c8dee2aaSAndroid Build Coastguard Worker }
575*c8dee2aaSAndroid Build Coastguard Worker
576*c8dee2aaSAndroid Build Coastguard Worker // This intersection algorithm is from "Robust Plane Sweep for Intersecting Segments" page 10.
s0_intersects_s1(const Segment & s0,const Segment & s1)577*c8dee2aaSAndroid Build Coastguard Worker bool s0_intersects_s1(const Segment& s0, const Segment& s1) {
578*c8dee2aaSAndroid Build Coastguard Worker // Make sure that s0 upper is above s1 upper.
579*c8dee2aaSAndroid Build Coastguard Worker if (s1.upper().y < s0.upper().y
580*c8dee2aaSAndroid Build Coastguard Worker || ((s1.upper().y == s0.upper().y) && (s1.lower().y > s0.lower().y))) {
581*c8dee2aaSAndroid Build Coastguard Worker
582*c8dee2aaSAndroid Build Coastguard Worker // Swap to put in the right orientation.
583*c8dee2aaSAndroid Build Coastguard Worker return s0_intersects_s1(s1, s0);
584*c8dee2aaSAndroid Build Coastguard Worker }
585*c8dee2aaSAndroid Build Coastguard Worker
586*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(s0.upper().y <= s1.upper().y);
587*c8dee2aaSAndroid Build Coastguard Worker
588*c8dee2aaSAndroid Build Coastguard Worker { // If extents don't overlap then there is no intersection.
589*c8dee2aaSAndroid Build Coastguard Worker auto [left0, top0, right0, bottom0] = s0.bounds();
590*c8dee2aaSAndroid Build Coastguard Worker auto [left1, top1, right1, bottom1] = s1.bounds();
591*c8dee2aaSAndroid Build Coastguard Worker if (right1 < left0 || right0 < left1 || bottom1 < top0 || bottom0 < top1) {
592*c8dee2aaSAndroid Build Coastguard Worker return false;
593*c8dee2aaSAndroid Build Coastguard Worker }
594*c8dee2aaSAndroid Build Coastguard Worker }
595*c8dee2aaSAndroid Build Coastguard Worker
596*c8dee2aaSAndroid Build Coastguard Worker auto [u0, l0] = s0;
597*c8dee2aaSAndroid Build Coastguard Worker auto [u1, l1] = s1;
598*c8dee2aaSAndroid Build Coastguard Worker
599*c8dee2aaSAndroid Build Coastguard Worker const Point D0 = l0 - u0,
600*c8dee2aaSAndroid Build Coastguard Worker D1 = l1 - u1;
601*c8dee2aaSAndroid Build Coastguard Worker
602*c8dee2aaSAndroid Build Coastguard Worker // If the vector from u0 to l0 (named D0) and the vector from u0 to u1 have an angle of 0
603*c8dee2aaSAndroid Build Coastguard Worker // between them, then u1 is on the segment u0 to l0 (named s0).
604*c8dee2aaSAndroid Build Coastguard Worker const Point U0toU1 = (u1 - u0);
605*c8dee2aaSAndroid Build Coastguard Worker const int64_t D0xU0toU1 = cross(D0, U0toU1);
606*c8dee2aaSAndroid Build Coastguard Worker if (D0xU0toU1 == 0) {
607*c8dee2aaSAndroid Build Coastguard Worker // u1 is on s0.
608*c8dee2aaSAndroid Build Coastguard Worker return true;
609*c8dee2aaSAndroid Build Coastguard Worker }
610*c8dee2aaSAndroid Build Coastguard Worker
611*c8dee2aaSAndroid Build Coastguard Worker if (l1.y <= l0.y) {
612*c8dee2aaSAndroid Build Coastguard Worker // S1 is between the upper and lower points of S0.
613*c8dee2aaSAndroid Build Coastguard Worker const Point U0toL1 = (l1 - u0);
614*c8dee2aaSAndroid Build Coastguard Worker const int64_t D0xU0toL1 = cross(D0, U0toL1);
615*c8dee2aaSAndroid Build Coastguard Worker if (D0xU0toL1 == 0) {
616*c8dee2aaSAndroid Build Coastguard Worker // l1 is on s0.
617*c8dee2aaSAndroid Build Coastguard Worker return true;
618*c8dee2aaSAndroid Build Coastguard Worker }
619*c8dee2aaSAndroid Build Coastguard Worker
620*c8dee2aaSAndroid Build Coastguard Worker // If U1 and L1 are on opposite sides of D0 then the segments cross.
621*c8dee2aaSAndroid Build Coastguard Worker return (D0xU0toU1 ^ D0xU0toL1) < 0;
622*c8dee2aaSAndroid Build Coastguard Worker } else {
623*c8dee2aaSAndroid Build Coastguard Worker // S1 extends past S0. It could be that S1 crosses the line of S0 (not the bound segment)
624*c8dee2aaSAndroid Build Coastguard Worker // beyond the endpoints of S0. Make sure that it crosses on the segment and not beyond.
625*c8dee2aaSAndroid Build Coastguard Worker const Point U1toL0 = (l0 - u1);
626*c8dee2aaSAndroid Build Coastguard Worker const int64_t D1xU1toL0 = cross(D1, U1toL0);
627*c8dee2aaSAndroid Build Coastguard Worker if (D1xU1toL0 == 0) {
628*c8dee2aaSAndroid Build Coastguard Worker return true;
629*c8dee2aaSAndroid Build Coastguard Worker }
630*c8dee2aaSAndroid Build Coastguard Worker
631*c8dee2aaSAndroid Build Coastguard Worker // For D1 to cross D0, then D1 must be on the same side of U1toL0 as D0. D0xU0toU1
632*c8dee2aaSAndroid Build Coastguard Worker // describes the orientation of U0 compared to D0. The angle from D1 to U1toL0 must
633*c8dee2aaSAndroid Build Coastguard Worker // have the same direction as the angle from U0toU1 to D0.
634*c8dee2aaSAndroid Build Coastguard Worker return (D0xU0toU1 ^ D1xU1toL0) >= 0;
635*c8dee2aaSAndroid Build Coastguard Worker }
636*c8dee2aaSAndroid Build Coastguard Worker }
637*c8dee2aaSAndroid Build Coastguard Worker
brute_force_crossings(SkSpan<Segment> segments)638*c8dee2aaSAndroid Build Coastguard Worker std::vector<Crossing> brute_force_crossings(SkSpan<Segment> segments) {
639*c8dee2aaSAndroid Build Coastguard Worker
640*c8dee2aaSAndroid Build Coastguard Worker auto isNonZeroSegment = [](const Segment& segment) {
641*c8dee2aaSAndroid Build Coastguard Worker return segment.upper() != segment.lower();
642*c8dee2aaSAndroid Build Coastguard Worker };
643*c8dee2aaSAndroid Build Coastguard Worker const auto zeroSegments = std::partition(segments.begin(), segments.end(), isNonZeroSegment);
644*c8dee2aaSAndroid Build Coastguard Worker
645*c8dee2aaSAndroid Build Coastguard Worker std::sort(segments.begin(), zeroSegments);
646*c8dee2aaSAndroid Build Coastguard Worker
647*c8dee2aaSAndroid Build Coastguard Worker const auto duplicateSegments = std::unique(segments.begin(), zeroSegments);
648*c8dee2aaSAndroid Build Coastguard Worker
649*c8dee2aaSAndroid Build Coastguard Worker SkSpan<const Segment> cleanSegments =
650*c8dee2aaSAndroid Build Coastguard Worker SkSpan{segments.data(), std::distance(segments.begin(), duplicateSegments)};
651*c8dee2aaSAndroid Build Coastguard Worker
652*c8dee2aaSAndroid Build Coastguard Worker CrossingAccumulator crossings;
653*c8dee2aaSAndroid Build Coastguard Worker if (cleanSegments.size() >= 2) {
654*c8dee2aaSAndroid Build Coastguard Worker for (auto i = cleanSegments.begin(); i != std::prev(cleanSegments.end()); ++i) {
655*c8dee2aaSAndroid Build Coastguard Worker for (auto j = std::next(i); j != cleanSegments.end(); ++j) {
656*c8dee2aaSAndroid Build Coastguard Worker if (s0_intersects_s1(*i, *j)) {
657*c8dee2aaSAndroid Build Coastguard Worker crossings.recordCrossing(*i, *j);
658*c8dee2aaSAndroid Build Coastguard Worker }
659*c8dee2aaSAndroid Build Coastguard Worker }
660*c8dee2aaSAndroid Build Coastguard Worker }
661*c8dee2aaSAndroid Build Coastguard Worker }
662*c8dee2aaSAndroid Build Coastguard Worker return crossings.finishAndReleaseCrossings();
663*c8dee2aaSAndroid Build Coastguard Worker }
664*c8dee2aaSAndroid Build Coastguard Worker } // namespace myers
665