xref: /aosp_15_r20/external/skia/modules/bentleyottmann/src/Segment.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/Segment.h"
5*c8dee2aaSAndroid Build Coastguard Worker 
6*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
7*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
8*c8dee2aaSAndroid Build Coastguard Worker #include "modules/bentleyottmann/include/Int96.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
11*c8dee2aaSAndroid Build Coastguard Worker #include <cmath>
12*c8dee2aaSAndroid Build Coastguard Worker 
13*c8dee2aaSAndroid Build Coastguard Worker namespace bentleyottmann {
14*c8dee2aaSAndroid Build Coastguard Worker 
15*c8dee2aaSAndroid Build Coastguard Worker // -- Segment --------------------------------------------------------------------------------------
upper() const16*c8dee2aaSAndroid Build Coastguard Worker Point Segment::upper() const {
17*c8dee2aaSAndroid Build Coastguard Worker     return std::min(p0, p1);
18*c8dee2aaSAndroid Build Coastguard Worker }
19*c8dee2aaSAndroid Build Coastguard Worker 
lower() const20*c8dee2aaSAndroid Build Coastguard Worker Point Segment::lower() const {
21*c8dee2aaSAndroid Build Coastguard Worker     return std::max(p0, p1);
22*c8dee2aaSAndroid Build Coastguard Worker }
23*c8dee2aaSAndroid Build Coastguard Worker 
24*c8dee2aaSAndroid Build Coastguard Worker // Use auto [l, t, r, b] = s.bounds();
bounds() const25*c8dee2aaSAndroid Build Coastguard Worker std::tuple<int32_t, int32_t, int32_t, int32_t> Segment::bounds() const {
26*c8dee2aaSAndroid Build Coastguard Worker     auto [l, r] = std::minmax(p0.x, p1.x);
27*c8dee2aaSAndroid Build Coastguard Worker     auto [t, b] = std::minmax(p0.y, p1.y);
28*c8dee2aaSAndroid Build Coastguard Worker     return std::make_tuple(l, t, r, b);
29*c8dee2aaSAndroid Build Coastguard Worker }
30*c8dee2aaSAndroid Build Coastguard Worker 
operator ==(const Segment & s0,const Segment & s1)31*c8dee2aaSAndroid Build Coastguard Worker bool operator==(const Segment& s0, const Segment& s1) {
32*c8dee2aaSAndroid Build Coastguard Worker     return s0.upper() == s1.upper() && s0.lower() == s1.lower();
33*c8dee2aaSAndroid Build Coastguard Worker }
34*c8dee2aaSAndroid Build Coastguard Worker 
operator <(const Segment & s0,const Segment & s1)35*c8dee2aaSAndroid Build Coastguard Worker bool operator<(const Segment& s0, const Segment& s1) {
36*c8dee2aaSAndroid Build Coastguard Worker     return std::make_tuple(s0.upper(), s0.lower()) < std::make_tuple(s1.upper(), s1.lower());
37*c8dee2aaSAndroid Build Coastguard Worker }
38*c8dee2aaSAndroid Build Coastguard Worker 
no_intersection_by_bounding_box(const Segment & s0,const Segment & s1)39*c8dee2aaSAndroid Build Coastguard Worker bool no_intersection_by_bounding_box(const Segment& s0, const Segment& s1) {
40*c8dee2aaSAndroid Build Coastguard Worker     auto [left0, top0, right0, bottom0] = s0.bounds();
41*c8dee2aaSAndroid Build Coastguard Worker     auto [left1, top1, right1, bottom1] = s1.bounds();
42*c8dee2aaSAndroid Build Coastguard Worker     // If the sides of the box touch, then there is no new intersection.
43*c8dee2aaSAndroid Build Coastguard Worker     return right0 <= left1 || right1 <= left0 || bottom0 <= top1 || bottom1 <= top0;
44*c8dee2aaSAndroid Build Coastguard Worker }
45*c8dee2aaSAndroid Build Coastguard Worker 
46*c8dee2aaSAndroid Build Coastguard Worker // Derivation of Intersection
47*c8dee2aaSAndroid Build Coastguard Worker // The intersection point I = (X, Y) of the two segments (x0, y0) -> (x1, y1)
48*c8dee2aaSAndroid Build Coastguard Worker // and (x2, y2) -> (x3, y3).
49*c8dee2aaSAndroid Build Coastguard Worker //    X = x0 + s(x1 - x0) = x2 + t(x3 - x2)
50*c8dee2aaSAndroid Build Coastguard Worker //    Y = y0 + s(y1 - y0) = y2 + t(y3 - y2)
51*c8dee2aaSAndroid Build Coastguard Worker //
52*c8dee2aaSAndroid Build Coastguard Worker // Solve for s in terms of x.
53*c8dee2aaSAndroid Build Coastguard Worker //    x0 + s(x1 - x0) = x2 + t(x3 - x2)
54*c8dee2aaSAndroid Build Coastguard Worker //    s(x1 - x0) = x2 - x0 + t(x3 - x2)
55*c8dee2aaSAndroid Build Coastguard Worker //    s = (x2 - x0 + t(x3 - x2)) / (x1 - x0)
56*c8dee2aaSAndroid Build Coastguard Worker //
57*c8dee2aaSAndroid Build Coastguard Worker // Back substitute s into the equation for Y.
58*c8dee2aaSAndroid Build Coastguard Worker //    y0 + ((x2 - x0 + t(x3 - x2)) / (x1 - x0))(y1 - y0) = y2 + t(y3 - y2)
59*c8dee2aaSAndroid Build Coastguard Worker //    (x2 - x0 + t(x3 - x2)) / (x1 - x0) = (y2 - y0 + t(y3 - y2)) / (y1 - y0)
60*c8dee2aaSAndroid Build Coastguard Worker //    (y1 - y0)(x2 - x0 + t(x3 - x2)) = (x1 - x0)(y2 - y0 + t(y3 - y2))
61*c8dee2aaSAndroid Build Coastguard Worker //    (y1 - y0)(x2 - x0) + t(y1 - y0)(x3 - x2) = (x1 - x0)(y2 - y0) + t(x1 - x0)(y3 - y2)
62*c8dee2aaSAndroid Build Coastguard Worker // Collecting t's on one side, and constants on the other.
63*c8dee2aaSAndroid Build Coastguard Worker //    t((y1 - y0)(x3 - x2) - (x1 - x0)(y3 - y2)) = (x1 - x0)(y2 - y0) - (y1 - y0)(x2 - x0)
64*c8dee2aaSAndroid Build Coastguard Worker //
65*c8dee2aaSAndroid Build Coastguard Worker // Solve for t in terms of x.
66*c8dee2aaSAndroid Build Coastguard Worker //    x0 + s(x1 - x0) = x2 + t(x3 - x2)
67*c8dee2aaSAndroid Build Coastguard Worker //    x0 - x2 + s(x1 - x0) = t(x3 - x2)
68*c8dee2aaSAndroid Build Coastguard Worker //    (x0 - x2 + s(x1 - x0)) / (x3 - x2) = t
69*c8dee2aaSAndroid Build Coastguard Worker // Back substitute t into the equation for Y.
70*c8dee2aaSAndroid Build Coastguard Worker //    y0 + s(y1 - y0) = y2 + ((x0 - x2 + s(x1 - x0)) / (x3 - x2))(y3 - y2)
71*c8dee2aaSAndroid Build Coastguard Worker //    (y0 - y2 + s(y1 - y0)) / (y3 - y2) = (x0 - x2 + s(x1 - x0)) / (x3 - x2)
72*c8dee2aaSAndroid Build Coastguard Worker //    (x3 - x2)(y0 - y2 + s(y1 - y0)) = (y3 - y2)(x0 - x2 + s(x1 - x0))
73*c8dee2aaSAndroid Build Coastguard Worker //    (x3 - x2)(y0 - y2) + s(x3 - x2)(y1 - y0) = (y3 - y2)(x0 - x2) + s(y3 - y2)(x1 - x0)
74*c8dee2aaSAndroid Build Coastguard Worker // Collecting s's on on side and constants on the other.
75*c8dee2aaSAndroid Build Coastguard Worker //    s((x3 - x2)(y1 - y0) - (y3 - y2)(x1 - x0)) = (y3 - y2)(x0 - x2) - (x3 - x2)(y0 - y2)
76*c8dee2aaSAndroid Build Coastguard Worker 
77*c8dee2aaSAndroid Build Coastguard Worker // Assign names and vectors to extract the cross products. The vector (x0, y0) -> (x1, y1) is
78*c8dee2aaSAndroid Build Coastguard Worker // P0 -> P1, and is named Q = (x1 - x0, y1 - y0) = P1 - P0. The following vectors are defined in
79*c8dee2aaSAndroid Build Coastguard Worker // a similar way.
80*c8dee2aaSAndroid Build Coastguard Worker //  * Q: P1 - P0
81*c8dee2aaSAndroid Build Coastguard Worker //  * R: P2 - P0
82*c8dee2aaSAndroid Build Coastguard Worker //  * T: P3 - P2
83*c8dee2aaSAndroid Build Coastguard Worker // Extracting cross products from above for t.
84*c8dee2aaSAndroid Build Coastguard Worker //    t((P3 - P2) x (P1 - P0)) = (P1 - P0) x (P2 - P0)
85*c8dee2aaSAndroid Build Coastguard Worker //    t(T x Q) = Q x R
86*c8dee2aaSAndroid Build Coastguard Worker //    t = (Q x R) / (T x Q)
87*c8dee2aaSAndroid Build Coastguard Worker // Extracting cross products from above for t.
88*c8dee2aaSAndroid Build Coastguard Worker //    s((P3 - P2) x (P1 - P0)) = (P0 - P2) x (P3 - P2)
89*c8dee2aaSAndroid Build Coastguard Worker //    s(T x Q) = -R x T
90*c8dee2aaSAndroid Build Coastguard Worker //    s = (T x R) / (T x Q)
91*c8dee2aaSAndroid Build Coastguard Worker //
92*c8dee2aaSAndroid Build Coastguard Worker // There is an intersection only if t and s are on [0, 1].
93*c8dee2aaSAndroid Build Coastguard Worker //
94*c8dee2aaSAndroid Build Coastguard Worker // This method of calculating the intersection only uses 8 multiplies, and 1 division. It also
95*c8dee2aaSAndroid Build Coastguard Worker // determines if the two segments cross with no round-off error and is always correct using 6
96*c8dee2aaSAndroid Build Coastguard Worker // multiplies. However, the actual crossing point is rounded to fit back into the int32_t.
intersect(const Segment & s0,const Segment & s1)97*c8dee2aaSAndroid Build Coastguard Worker std::optional<Point> intersect(const Segment& s0, const Segment& s1) {
98*c8dee2aaSAndroid Build Coastguard Worker 
99*c8dee2aaSAndroid Build Coastguard Worker     // Check if the bounds intersect.
100*c8dee2aaSAndroid Build Coastguard Worker     if (no_intersection_by_bounding_box(s0, s1)) {
101*c8dee2aaSAndroid Build Coastguard Worker         return std::nullopt;
102*c8dee2aaSAndroid Build Coastguard Worker     }
103*c8dee2aaSAndroid Build Coastguard Worker 
104*c8dee2aaSAndroid Build Coastguard Worker     // Create the end Points for s0 and s1
105*c8dee2aaSAndroid Build Coastguard Worker     const Point P0 = s0.upper(),
106*c8dee2aaSAndroid Build Coastguard Worker                 P1 = s0.lower(),
107*c8dee2aaSAndroid Build Coastguard Worker                 P2 = s1.upper(),
108*c8dee2aaSAndroid Build Coastguard Worker                 P3 = s1.lower();
109*c8dee2aaSAndroid Build Coastguard Worker 
110*c8dee2aaSAndroid Build Coastguard Worker     if (P0 == P2 || P1 == P3 || P1 == P2 || P3 == P0) {
111*c8dee2aaSAndroid Build Coastguard Worker         // Lines don't intersect if they share an end point.
112*c8dee2aaSAndroid Build Coastguard Worker         return std::nullopt;
113*c8dee2aaSAndroid Build Coastguard Worker     }
114*c8dee2aaSAndroid Build Coastguard Worker 
115*c8dee2aaSAndroid Build Coastguard Worker     // Create the Q, R, and T.
116*c8dee2aaSAndroid Build Coastguard Worker     const Point Q = P1 - P0,
117*c8dee2aaSAndroid Build Coastguard Worker                 R = P2 - P0,
118*c8dee2aaSAndroid Build Coastguard Worker                 T = P3 - P2;
119*c8dee2aaSAndroid Build Coastguard Worker 
120*c8dee2aaSAndroid Build Coastguard Worker     // 64-bit cross product.
121*c8dee2aaSAndroid Build Coastguard Worker     auto cross = [](const Point& v0, const Point& v1) {
122*c8dee2aaSAndroid Build Coastguard Worker         int64_t x0 = SkToS64(v0.x),
123*c8dee2aaSAndroid Build Coastguard Worker                 y0 = SkToS64(v0.y),
124*c8dee2aaSAndroid Build Coastguard Worker                 x1 = SkToS64(v1.x),
125*c8dee2aaSAndroid Build Coastguard Worker                 y1 = SkToS64(v1.y);
126*c8dee2aaSAndroid Build Coastguard Worker         return x0 * y1 - y0 * x1;
127*c8dee2aaSAndroid Build Coastguard Worker     };
128*c8dee2aaSAndroid Build Coastguard Worker 
129*c8dee2aaSAndroid Build Coastguard Worker     // Calculate the cross products needed for calculating s and t.
130*c8dee2aaSAndroid Build Coastguard Worker     const int64_t QxR = cross(Q, R),
131*c8dee2aaSAndroid Build Coastguard Worker                   TxR = cross(T, R),
132*c8dee2aaSAndroid Build Coastguard Worker                   TxQ = cross(T, Q);
133*c8dee2aaSAndroid Build Coastguard Worker 
134*c8dee2aaSAndroid Build Coastguard Worker     if (TxQ == 0) {
135*c8dee2aaSAndroid Build Coastguard Worker         // Both t and s are either < 0 or > 1 because the denominator is 0.
136*c8dee2aaSAndroid Build Coastguard Worker         return std::nullopt;
137*c8dee2aaSAndroid Build Coastguard Worker     }
138*c8dee2aaSAndroid Build Coastguard Worker 
139*c8dee2aaSAndroid Build Coastguard Worker     // t = (Q x R) / (T x Q). s = (T x R) / (T x Q). Check that t & s are on [0, 1]
140*c8dee2aaSAndroid Build Coastguard Worker     if ((QxR ^ TxQ) < 0 || (TxR ^ TxQ) < 0) {
141*c8dee2aaSAndroid Build Coastguard Worker         // The division is negative and t or s < 0.
142*c8dee2aaSAndroid Build Coastguard Worker         return std::nullopt;
143*c8dee2aaSAndroid Build Coastguard Worker     }
144*c8dee2aaSAndroid Build Coastguard Worker 
145*c8dee2aaSAndroid Build Coastguard Worker     if (TxQ > 0) {
146*c8dee2aaSAndroid Build Coastguard Worker         if (QxR > TxQ || TxR > TxQ) {
147*c8dee2aaSAndroid Build Coastguard Worker             // t or s is greater than 1.
148*c8dee2aaSAndroid Build Coastguard Worker             return std::nullopt;
149*c8dee2aaSAndroid Build Coastguard Worker         }
150*c8dee2aaSAndroid Build Coastguard Worker     } else {
151*c8dee2aaSAndroid Build Coastguard Worker         if (QxR < TxQ || TxR < TxQ) {
152*c8dee2aaSAndroid Build Coastguard Worker             // t or s is greater than 1.
153*c8dee2aaSAndroid Build Coastguard Worker             return std::nullopt;
154*c8dee2aaSAndroid Build Coastguard Worker         }
155*c8dee2aaSAndroid Build Coastguard Worker     }
156*c8dee2aaSAndroid Build Coastguard Worker 
157*c8dee2aaSAndroid Build Coastguard Worker     // Calculate the intersection using doubles.
158*c8dee2aaSAndroid Build Coastguard Worker     // TODO: This is just a placeholder approximation for calculating x and y should use big math
159*c8dee2aaSAndroid Build Coastguard Worker     // above.
160*c8dee2aaSAndroid Build Coastguard Worker     const double t = static_cast<double>(QxR) / static_cast<double>(TxQ);
161*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(0 <= t && t <= 1);
162*c8dee2aaSAndroid Build Coastguard Worker     const int32_t x = std::round(t * (P3.x - P2.x) + P2.x),
163*c8dee2aaSAndroid Build Coastguard Worker                   y = std::round(t * (P3.y - P2.y) + P2.y);
164*c8dee2aaSAndroid Build Coastguard Worker 
165*c8dee2aaSAndroid Build Coastguard Worker     return Point{x, y};
166*c8dee2aaSAndroid Build Coastguard Worker }
167*c8dee2aaSAndroid Build Coastguard Worker 
168*c8dee2aaSAndroid Build Coastguard Worker // The comparison is:
169*c8dee2aaSAndroid Build Coastguard Worker //     x0 + (y - y0)(x1 - x0) / (y1 - y0) <? x2 + (y - y2)(x3 - x2) / (y3 - y2)
170*c8dee2aaSAndroid Build Coastguard Worker // Factor out numerators:
171*c8dee2aaSAndroid Build Coastguard Worker //    [x0(y1 - y0) + (y - y0)(x1 - x0)] / (y1 - y0) <? [x2(y3 - y2) + (y - y2)(x3 -x 2)] / (y3 - y2)
172*c8dee2aaSAndroid Build Coastguard Worker // Removing the divides by cross multiplying.
173*c8dee2aaSAndroid Build Coastguard Worker //   [x0(y1 - y0) + (y - y0)(x1 - x0)] (y3 - y2) <? [x2(y3 - y2) + (y - y2)(x3 - x2)] (y1 - y0)
174*c8dee2aaSAndroid Build Coastguard Worker // This is a 64-bit int x0 + (y - y0) (x1 - x0) times a 32-int (y3 - y2) resulting in a 96-bit int,
175*c8dee2aaSAndroid Build Coastguard Worker // and the same applies to the other side of the <?. Because y0 <= y1 and y2 <= y3, then the
176*c8dee2aaSAndroid Build Coastguard Worker // differences of (y1 - y0) and (y3 - y2) are positive allowing us to multiply through without
177*c8dee2aaSAndroid Build Coastguard Worker // worrying about sign changes.
less_than_at(const Segment & s0,const Segment & s1,int32_t y)178*c8dee2aaSAndroid Build Coastguard Worker bool less_than_at(const Segment& s0, const Segment& s1, int32_t y) {
179*c8dee2aaSAndroid Build Coastguard Worker     auto [l0, t0, r0, b0] = s0.bounds();
180*c8dee2aaSAndroid Build Coastguard Worker     auto [l1, t1, r1, b1] = s1.bounds();
181*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(t0 <= y && y <= b0);
182*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(t1 <= y && y <= b1);
183*c8dee2aaSAndroid Build Coastguard Worker 
184*c8dee2aaSAndroid Build Coastguard Worker     // Return true if the bounding box of s0 is fully to the left of s1.
185*c8dee2aaSAndroid Build Coastguard Worker     if (r0 < l1) {
186*c8dee2aaSAndroid Build Coastguard Worker         return true;
187*c8dee2aaSAndroid Build Coastguard Worker     }
188*c8dee2aaSAndroid Build Coastguard Worker 
189*c8dee2aaSAndroid Build Coastguard Worker     // Return false if the bounding box of s0 is fully to the right of s1.
190*c8dee2aaSAndroid Build Coastguard Worker     if (r1 < l0) {
191*c8dee2aaSAndroid Build Coastguard Worker         return false;
192*c8dee2aaSAndroid Build Coastguard Worker     }
193*c8dee2aaSAndroid Build Coastguard Worker 
194*c8dee2aaSAndroid Build Coastguard Worker     // Check the x intercepts along the horizontal line at y.
195*c8dee2aaSAndroid Build Coastguard Worker     // Make s0 be (x0, y0) -> (x1, y1) and s1 be (x2, y2) -> (x3, y3).
196*c8dee2aaSAndroid Build Coastguard Worker     auto [x0, y0] = s0.upper();
197*c8dee2aaSAndroid Build Coastguard Worker     auto [x1, y1] = s0.lower();
198*c8dee2aaSAndroid Build Coastguard Worker     auto [x2, y2] = s1.upper();
199*c8dee2aaSAndroid Build Coastguard Worker     auto [x3, y3] = s1.lower();
200*c8dee2aaSAndroid Build Coastguard Worker 
201*c8dee2aaSAndroid Build Coastguard Worker     int64_t s0YDiff = y - y0,
202*c8dee2aaSAndroid Build Coastguard Worker             s1YDiff = y - y2,
203*c8dee2aaSAndroid Build Coastguard Worker             s0YDelta = y1 - y0,
204*c8dee2aaSAndroid Build Coastguard Worker             s1YDelta = y3 - y2,
205*c8dee2aaSAndroid Build Coastguard Worker             x0Offset = x0 * s0YDelta + s0YDiff * (x1 - x0),
206*c8dee2aaSAndroid Build Coastguard Worker             x2Offset = x2 * s1YDelta + s1YDiff * (x3 - x2);
207*c8dee2aaSAndroid Build Coastguard Worker 
208*c8dee2aaSAndroid Build Coastguard Worker     Int96 s0Factor = multiply(x0Offset, y3 - y2),
209*c8dee2aaSAndroid Build Coastguard Worker           s1Factor = multiply(x2Offset, y1 - y0);
210*c8dee2aaSAndroid Build Coastguard Worker 
211*c8dee2aaSAndroid Build Coastguard Worker     return s0Factor < s1Factor;
212*c8dee2aaSAndroid Build Coastguard Worker }
213*c8dee2aaSAndroid Build Coastguard Worker 
point_less_than_segment_in_x(Point p,const Segment & segment)214*c8dee2aaSAndroid Build Coastguard Worker bool point_less_than_segment_in_x(Point p, const Segment& segment) {
215*c8dee2aaSAndroid Build Coastguard Worker     auto [l, t, r, b] = segment.bounds();
216*c8dee2aaSAndroid Build Coastguard Worker 
217*c8dee2aaSAndroid Build Coastguard Worker     // Ensure that the segment intersects the horizontal sweep line
218*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(t <= p.y && p.y <= b);
219*c8dee2aaSAndroid Build Coastguard Worker 
220*c8dee2aaSAndroid Build Coastguard Worker     // Fast answers using bounding boxes.
221*c8dee2aaSAndroid Build Coastguard Worker     if (p.x < l) {
222*c8dee2aaSAndroid Build Coastguard Worker         return true;
223*c8dee2aaSAndroid Build Coastguard Worker     } else if (p.x >= r) {
224*c8dee2aaSAndroid Build Coastguard Worker         return false;
225*c8dee2aaSAndroid Build Coastguard Worker     }
226*c8dee2aaSAndroid Build Coastguard Worker 
227*c8dee2aaSAndroid Build Coastguard Worker     auto [x0, y0] = segment.upper();
228*c8dee2aaSAndroid Build Coastguard Worker     auto [x1, y1] = segment.lower();
229*c8dee2aaSAndroid Build Coastguard Worker     auto [x2, y2] = p;
230*c8dee2aaSAndroid Build Coastguard Worker 
231*c8dee2aaSAndroid Build Coastguard Worker     // For a point and a segment the comparison is:
232*c8dee2aaSAndroid Build Coastguard Worker     //    x2 < x0 + (y2 - y0)(x1 - x0) / (y1 - y0)
233*c8dee2aaSAndroid Build Coastguard Worker     // becomes
234*c8dee2aaSAndroid Build Coastguard Worker     //    (x2 - x0)(y1 - y0) < (x1 - x0)(y2 - y0)
235*c8dee2aaSAndroid Build Coastguard Worker     // We don't need to worry about the signs changing in the cross multiply because (y1 - y0) is
236*c8dee2aaSAndroid Build Coastguard Worker     // always positive. Manipulating a little further derives predicate 2 from "Robust Plane
237*c8dee2aaSAndroid Build Coastguard Worker     // Sweep for Intersecting Segments" page 9.
238*c8dee2aaSAndroid Build Coastguard Worker     //    0 < (x1 - x0)(y2 - y0) - (x2 - x0)(y1 - y0)
239*c8dee2aaSAndroid Build Coastguard Worker     // becomes
240*c8dee2aaSAndroid Build Coastguard Worker     //        | x1-x0   x2-x0 |
241*c8dee2aaSAndroid Build Coastguard Worker     //   0 <  | y1-y0   y2-y0 |
242*c8dee2aaSAndroid Build Coastguard Worker     return SkToS64(x2 - x0) * SkToS64(y1 - y0) < SkToS64(y2 - y0) * SkToS64(x1 - x0);
243*c8dee2aaSAndroid Build Coastguard Worker }
244*c8dee2aaSAndroid Build Coastguard Worker 
245*c8dee2aaSAndroid Build Coastguard Worker // The design of this function allows its use with std::lower_bound. lower_bound returns the
246*c8dee2aaSAndroid Build Coastguard Worker // iterator to the first segment where rounded_point_less_than_segment_in_x_lower returns false.
247*c8dee2aaSAndroid Build Coastguard Worker // Therefore, we want s(y) < (x - ½) to return true, then start returning false when s(y) ≥ (x - ½).
rounded_point_less_than_segment_in_x_lower(const Segment & s,Point p)248*c8dee2aaSAndroid Build Coastguard Worker bool rounded_point_less_than_segment_in_x_lower(const Segment& s, Point p) {
249*c8dee2aaSAndroid Build Coastguard Worker     const auto [l, t, r, b] = s.bounds();
250*c8dee2aaSAndroid Build Coastguard Worker     const auto [x, y] = p;
251*c8dee2aaSAndroid Build Coastguard Worker 
252*c8dee2aaSAndroid Build Coastguard Worker     // Ensure that the segment intersects the horizontal sweep line
253*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(t <= y && y <= b);
254*c8dee2aaSAndroid Build Coastguard Worker 
255*c8dee2aaSAndroid Build Coastguard Worker     // In the comparisons below, x is really x - ½
256*c8dee2aaSAndroid Build Coastguard Worker     if (r < x) {
257*c8dee2aaSAndroid Build Coastguard Worker         // s is entirely < p.
258*c8dee2aaSAndroid Build Coastguard Worker         return true;
259*c8dee2aaSAndroid Build Coastguard Worker     } else if (x <= l) {
260*c8dee2aaSAndroid Build Coastguard Worker         // s is entirely > p. This also handles vertical lines, so we don't have to handle them
261*c8dee2aaSAndroid Build Coastguard Worker         // below.
262*c8dee2aaSAndroid Build Coastguard Worker         return false;
263*c8dee2aaSAndroid Build Coastguard Worker     }
264*c8dee2aaSAndroid Build Coastguard Worker 
265*c8dee2aaSAndroid Build Coastguard Worker     const auto [x0, y0] = s.upper();
266*c8dee2aaSAndroid Build Coastguard Worker     const auto [x1, y1] = s.lower();
267*c8dee2aaSAndroid Build Coastguard Worker 
268*c8dee2aaSAndroid Build Coastguard Worker     // Horizontal - from the guards above we know that p is on s.
269*c8dee2aaSAndroid Build Coastguard Worker     if (y0 == y1) {
270*c8dee2aaSAndroid Build Coastguard Worker         return false;
271*c8dee2aaSAndroid Build Coastguard Worker     }
272*c8dee2aaSAndroid Build Coastguard Worker 
273*c8dee2aaSAndroid Build Coastguard Worker     // s is not horizontal or vertical.
274*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(x0 != x1 && y0 != y1);
275*c8dee2aaSAndroid Build Coastguard Worker 
276*c8dee2aaSAndroid Build Coastguard Worker     // Given the segment upper = (x0, y0) and lower = (x1, y1)
277*c8dee2aaSAndroid Build Coastguard Worker     // x0 + (x1 - x0)(y - y0) / (y1 - y0) < x - ½
278*c8dee2aaSAndroid Build Coastguard Worker     // (x1 - x0)(y - y0) / (y1 - y0) < x - x0 - ½
279*c8dee2aaSAndroid Build Coastguard Worker     // Because (y1 - y0) is always positive we can multiply through the inequality without
280*c8dee2aaSAndroid Build Coastguard Worker     // worrying about sign changes.
281*c8dee2aaSAndroid Build Coastguard Worker     // (x1 - x0)(y - y0) < (x - x0 - ½)(y1 - y0)
282*c8dee2aaSAndroid Build Coastguard Worker     // (x1 - x0)(y - y0) < ½(2x - 2x0 - 1)(y1 - y0)
283*c8dee2aaSAndroid Build Coastguard Worker     // 2(x1 - x0)(y - y0) < (2(x - x0) - 1)(y1 - y0)
284*c8dee2aaSAndroid Build Coastguard Worker     return 2 * SkToS64(x1 - x0) * SkToS64(y - y0) < (2 * SkToS64(x - x0) - 1) * SkToS64(y1 - y0);
285*c8dee2aaSAndroid Build Coastguard Worker }
286*c8dee2aaSAndroid Build Coastguard Worker 
287*c8dee2aaSAndroid Build Coastguard Worker // The design of this function allows use with std::lower_bound. lower_bound returns the iterator
288*c8dee2aaSAndroid Build Coastguard Worker // to the first segment where rounded_point_less_than_segment_in_x_upper is false. This function
289*c8dee2aaSAndroid Build Coastguard Worker // implements s(y) < (x + ½).
rounded_point_less_than_segment_in_x_upper(const Segment & s,Point p)290*c8dee2aaSAndroid Build Coastguard Worker bool rounded_point_less_than_segment_in_x_upper(const Segment& s, Point p) {
291*c8dee2aaSAndroid Build Coastguard Worker     const auto [l, t, r, b] = s.bounds();
292*c8dee2aaSAndroid Build Coastguard Worker     const auto [x, y] = p;
293*c8dee2aaSAndroid Build Coastguard Worker 
294*c8dee2aaSAndroid Build Coastguard Worker     // Ensure that the segment intersects the horizontal sweep line
295*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(t <= y && y <= b);
296*c8dee2aaSAndroid Build Coastguard Worker 
297*c8dee2aaSAndroid Build Coastguard Worker     // In the comparisons below, x is really x + ½
298*c8dee2aaSAndroid Build Coastguard Worker     if (r <= x) {
299*c8dee2aaSAndroid Build Coastguard Worker         // s is entirely < p.
300*c8dee2aaSAndroid Build Coastguard Worker         return true;
301*c8dee2aaSAndroid Build Coastguard Worker     } else if (x < l) {
302*c8dee2aaSAndroid Build Coastguard Worker         // s is entirely > p. This also handles vertical lines, so we don't have to handle them
303*c8dee2aaSAndroid Build Coastguard Worker         // below.
304*c8dee2aaSAndroid Build Coastguard Worker         return false;
305*c8dee2aaSAndroid Build Coastguard Worker     }
306*c8dee2aaSAndroid Build Coastguard Worker 
307*c8dee2aaSAndroid Build Coastguard Worker     const auto [x0, y0] = s.upper();
308*c8dee2aaSAndroid Build Coastguard Worker     const auto [x1, y1] = s.lower();
309*c8dee2aaSAndroid Build Coastguard Worker 
310*c8dee2aaSAndroid Build Coastguard Worker     // Horizontal - from the guards above we know that p is on s.
311*c8dee2aaSAndroid Build Coastguard Worker     if (y0 == y1) {
312*c8dee2aaSAndroid Build Coastguard Worker         return false;
313*c8dee2aaSAndroid Build Coastguard Worker     }
314*c8dee2aaSAndroid Build Coastguard Worker 
315*c8dee2aaSAndroid Build Coastguard Worker     // s is not horizontal or vertical.
316*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(x0 != x1 && y0 != y1);
317*c8dee2aaSAndroid Build Coastguard Worker 
318*c8dee2aaSAndroid Build Coastguard Worker     // Given the segment upper = (x0, y0) and lower = (x1, y1)
319*c8dee2aaSAndroid Build Coastguard Worker     // x0 + (x1 - x0)(y - y0) / (y1 - y0) < x + ½
320*c8dee2aaSAndroid Build Coastguard Worker     // (x1 - x0)(y - y0) / (y1 - y0) < x - x0 + ½
321*c8dee2aaSAndroid Build Coastguard Worker     // Because (y1 - y0) is always positive we can multiply through the inequality without
322*c8dee2aaSAndroid Build Coastguard Worker     // worrying about sign changes.
323*c8dee2aaSAndroid Build Coastguard Worker     // (x1 - x0)(y - y0) < (x - x0 + ½)(y1 - y0)
324*c8dee2aaSAndroid Build Coastguard Worker     // (x1 - x0)(y - y0) < ½(2x - 2x0 + 1)(y1 - y0)
325*c8dee2aaSAndroid Build Coastguard Worker     // 2(x1 - x0)(y - y0) < (2(x - x0) + 1)(y1 - y0)
326*c8dee2aaSAndroid Build Coastguard Worker     return 2 * SkToS64(x1 - x0) * SkToS64(y - y0) < (2 * SkToS64(x - x0) + 1) * SkToS64(y1 - y0);
327*c8dee2aaSAndroid Build Coastguard Worker }
328*c8dee2aaSAndroid Build Coastguard Worker 
compare_slopes(const Segment & s0,const Segment & s1)329*c8dee2aaSAndroid Build Coastguard Worker int compare_slopes(const Segment& s0, const Segment& s1) {
330*c8dee2aaSAndroid Build Coastguard Worker     Point s0Delta = s0.lower() - s0.upper(),
331*c8dee2aaSAndroid Build Coastguard Worker           s1Delta = s1.lower() - s1.upper();
332*c8dee2aaSAndroid Build Coastguard Worker 
333*c8dee2aaSAndroid Build Coastguard Worker     // Handle the horizontal cases to avoid dealing with infinities.
334*c8dee2aaSAndroid Build Coastguard Worker     if (s0Delta.y == 0 || s1Delta.y == 0) {
335*c8dee2aaSAndroid Build Coastguard Worker         if (s0Delta.y != 0) {
336*c8dee2aaSAndroid Build Coastguard Worker             return -1;
337*c8dee2aaSAndroid Build Coastguard Worker         } else if (s1Delta.y != 0) {
338*c8dee2aaSAndroid Build Coastguard Worker             return 1;
339*c8dee2aaSAndroid Build Coastguard Worker         } else {
340*c8dee2aaSAndroid Build Coastguard Worker             return 0;
341*c8dee2aaSAndroid Build Coastguard Worker         }
342*c8dee2aaSAndroid Build Coastguard Worker     }
343*c8dee2aaSAndroid Build Coastguard Worker 
344*c8dee2aaSAndroid Build Coastguard Worker     // Compare s0Delta.x / s0Delta.y ? s1Delta.x / s1Delta.y. I used the alternate slope form for
345*c8dee2aaSAndroid Build Coastguard Worker     // two reasons.
346*c8dee2aaSAndroid Build Coastguard Worker     // * no change of sign - since the delta ys are always positive, then I don't need to worry
347*c8dee2aaSAndroid Build Coastguard Worker     //                       about the change in sign with the cross-multiply.
348*c8dee2aaSAndroid Build Coastguard Worker     // * proper slope ordering - the slope monotonically increases from the smallest along the
349*c8dee2aaSAndroid Build Coastguard Worker     //                           negative x-axis increasing counterclockwise to the largest along
350*c8dee2aaSAndroid Build Coastguard Worker     //                           the positive x-axis.
351*c8dee2aaSAndroid Build Coastguard Worker     int64_t lhs = SkToS64(s0Delta.x) * SkToS64(s1Delta.y),
352*c8dee2aaSAndroid Build Coastguard Worker             rhs = SkToS64(s1Delta.x) * SkToS64(s0Delta.y);
353*c8dee2aaSAndroid Build Coastguard Worker 
354*c8dee2aaSAndroid Build Coastguard Worker     if (lhs < rhs) {
355*c8dee2aaSAndroid Build Coastguard Worker         return -1;
356*c8dee2aaSAndroid Build Coastguard Worker     } else if (lhs > rhs) {
357*c8dee2aaSAndroid Build Coastguard Worker         return 1;
358*c8dee2aaSAndroid Build Coastguard Worker     } else {
359*c8dee2aaSAndroid Build Coastguard Worker         return 0;
360*c8dee2aaSAndroid Build Coastguard Worker     }
361*c8dee2aaSAndroid Build Coastguard Worker }
362*c8dee2aaSAndroid Build Coastguard Worker }  // namespace bentleyottmann
363