Flutter Engine
The Flutter Engine
Classes | Functions
myers Namespace Reference

Classes

class  Crossing
 
class  CrossingAccumulator
 
struct  Event
 
class  EventQueue
 
struct  Point
 
class  Segment
 
class  SweepLine
 

Functions

constexpr bool operator< (const Point &p0, const Point &p1)
 
constexpr bool operator== (const Point &p0, const Point &p1)
 
constexpr bool operator!= (const Point &p0, const Point &p1)
 
constexpr bool operator< (const Segment &s0, const Segment &s1)
 
constexpr bool operator== (const Segment &s0, const Segment &s1)
 
constexpr bool operator!= (const Segment &s0, const Segment &s1)
 
template<size_t >
const myers::Pointget (const myers::Segment &)
 
template<>
const myers::Pointget< 0 > (const myers::Segment &s)
 
template<>
const myers::Pointget< 1 > (const myers::Segment &s)
 
bool operator< (const Crossing &c0, const Crossing &c1)
 
bool operator== (const Crossing &c0, const Crossing &c1)
 
std::vector< Crossingmyers_find_crossings (const SkSpan< const Segment > segments)
 
std::vector< Crossingbrute_force_crossings (SkSpan< Segment >)
 
Point operator- (const Point &p0, const Point &p1)
 
std::tuple< int64_t, int64_t > point_to_s64 (Point p)
 
int64_t cross (Point d0, Point d1)
 
int64_t compare_slopes (const Segment &s0, const Segment &s1)
 
bool slope_s0_less_than_slope_s1 (const Segment &s0, const Segment &s1)
 
int64_t compare_point_to_segment (Point p, const Segment &s)
 
bool segment_less_than_upper_to_insert (const Segment &segment, const Segment &to_insert)
 
bool s0_less_than_s1_at_y (const Segment &s0, const Segment &s1, int32_t y)
 
bool s0_intersects_s1 (const Segment &s0, const Segment &s1)
 

Function Documentation

◆ brute_force_crossings()

std::vector< Crossing > myers::brute_force_crossings ( SkSpan< Segment segments)

Definition at line 638 of file Myers.cpp.

638 {
639
640 auto isNonZeroSegment = [](const Segment& segment) {
641 return segment.upper() != segment.lower();
642 };
643 const auto zeroSegments = std::partition(segments.begin(), segments.end(), isNonZeroSegment);
644
645 std::sort(segments.begin(), zeroSegments);
646
647 const auto duplicateSegments = std::unique(segments.begin(), zeroSegments);
648
649 SkSpan<const Segment> cleanSegments =
650 SkSpan{segments.data(), std::distance(segments.begin(), duplicateSegments)};
651
652 CrossingAccumulator crossings;
653 if (cleanSegments.size() >= 2) {
654 for (auto i = cleanSegments.begin(); i != std::prev(cleanSegments.end()); ++i) {
655 for (auto j = std::next(i); j != cleanSegments.end(); ++j) {
656 if (s0_intersects_s1(*i, *j)) {
657 crossings.recordCrossing(*i, *j);
658 }
659 }
660 }
661 }
662 return crossings.finishAndReleaseCrossings();
663}
static float next(float f)
static float prev(float f)
static std::vector< SkPDFIndirectReference > sort(const THashSet< SkPDFIndirectReference > &src)
constexpr T * data() const
Definition: SkSpan_impl.h:94
constexpr T * begin() const
Definition: SkSpan_impl.h:90
constexpr T * end() const
Definition: SkSpan_impl.h:91
constexpr size_t size() const
Definition: SkSpan_impl.h:95
bool s0_intersects_s1(const Segment &s0, const Segment &s1)
Definition: Myers.cpp:577

◆ compare_point_to_segment()

int64_t myers::compare_point_to_segment ( Point  p,
const Segment s 
)

Definition at line 117 of file Myers.cpp.

117 {
118 const auto [u, l] = s;
119
120 // The segment must span p vertically.
121 SkASSERT(u.y <= p.y && p.y <= l.y);
122
123 // Check horizontal extents.
124 {
125 const auto [left, right] = std::minmax(u.x, l.x);
126 if (p.x < left) {
127 return -1;
128 }
129
130 if (right < p.x) {
131 return 1;
132 }
133 }
134
135 // If s is horizontal, then p is on the interval [u.x, l.x].
136 if (s.isHorizontal()) {
137 return 0;
138 }
139
140 // The point p < s when:
141 // p.x < u.x + (l.x - u.x)(p.y - u.y) / (l.y - u.y),
142 // p.x - u.x < (l.x - u.x)(p.y - u.y) / (l.y - u.y),
143 // (p.x - u.x)(l.y - u.y) < (l.x - u.x)(p.y - u.y),
144 // (p.x - u.x)(l.y - u.y) - (l.x - u.x)(p.y - u.y) < 0,
145 // (p - u) x (l - u) < 0,
146 // dUtoP x dS < 0.
147 // The other relations can be implemented in a similar way.
148 const Point dUToP = p - u;
149 const Point dS = l - u;
150
151 SkASSERT(dS.y > 0);
152 return cross(dUToP, dS);
153}
#define SkASSERT(cond)
Definition: SkAssert.h:116
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
struct MyStruct s
TPoint< Scalar > Point
Definition: point.h:322
int64_t cross(Point d0, Point d1)
Definition: Myers.cpp:55

◆ compare_slopes()

int64_t myers::compare_slopes ( const Segment s0,
const Segment s1 
)

Definition at line 67 of file Myers.cpp.

67 {
68 // Handle cases involving horizontal segments.
69 if (s0.isHorizontal() || s1.isHorizontal()) {
70 if (s0.isHorizontal() && s1.isHorizontal()) {
71 // slope(s0) == slope(s1)
72 return 0;
73 }
74 if (s0.isHorizontal()) {
75 // slope(s0) > slope(s1)
76 return 1;
77 } else {
78 // slope(s0) < slope(s1)
79 return -1;
80 }
81 }
82
83 const auto [u0, l0] = s0;
84 const auto [u1, l1] = s1;
85
86 const Point d0 = l0 - u0;
87 const Point d1 = l1 - u1;
88
89 // Since horizontal lines are handled separately and because of the ordering of points for
90 // a segment, then d0y and d1y should always be positive.
91 SkASSERT(d0.y > 0 && d1.y > 0);
92
93 // * slope(s0) = d0.x / d0.y
94 // * slope(s1) = d1.x / d1.y
95 // If we want to find d0.x / d0.y < d1.x / d1.y, then
96 // d0x * d1y < d1x * d0y
97 // d0x * d1y - d1x * d0y < 0.
98 //
99 // We know that d0.y and d1.y are both positive, therefore, we can do a cross multiply without
100 // worrying about changing the relation.
101 // We can define ==, and > in a similar way:
102 // * < - cross_of_slopes(s0, s1) < 0
103 // * == - cross_of_slopes(s0, s1) == 0
104 // * > - cross_of_slopes(s0, s1) > 0
105 return cross(d0, d1);
106}
bool isHorizontal() const
Definition: Myers.cpp:44

◆ cross()

int64_t myers::cross ( Point  d0,
Point  d1 
)

Definition at line 55 of file Myers.cpp.

55 {
56 const auto [d0x, d0y] = point_to_s64(d0);
57 const auto [d1x, d1y] = point_to_s64(d1);
58 return d0x * d1y - d1x * d0y;
59}
std::tuple< int64_t, int64_t > point_to_s64(Point p)
Definition: Myers.cpp:26

◆ get()

template<size_t >
const myers::Point & myers::get ( const myers::Segment )

◆ get< 0 >()

template<>
const myers::Point & myers::get< 0 > ( const myers::Segment s)
inline

Definition at line 80 of file Myers.h.

80{ return s.upper(); }

◆ get< 1 >()

template<>
const myers::Point & myers::get< 1 > ( const myers::Segment s)
inline

Definition at line 81 of file Myers.h.

81{ return s.lower(); }

◆ myers_find_crossings()

std::vector< Crossing > myers::myers_find_crossings ( const SkSpan< const Segment segments)

Definition at line 565 of file Myers.cpp.

565 {
566 const EventQueue eventQueue = EventQueue::Make(segments);
567 SweepLine sweepLine;
568
569 for (const Event& event : eventQueue) {
570 sweepLine.handleEvent(event);
571 }
572
573 return sweepLine.finishAndReleaseCrossings();
574}
std::vector< Crossing > finishAndReleaseCrossings()
Definition: Myers.cpp:463
void handleEvent(Event e)
Definition: Myers.cpp:452
FlKeyEvent * event
SK_API sk_sp< SkDocument > Make(SkWStream *dst, const SkSerialProcs *=nullptr, std::function< void(const SkPicture *)> onEndPage=nullptr)

◆ operator!=() [1/2]

constexpr bool myers::operator!= ( const Point p0,
const Point p1 
)
constexpr

Definition at line 33 of file Myers.h.

33 {
34 return std::tie(p0.x, p0.y) != std::tie(p1.x, p1.y);
35}
int32_t x
Definition: Myers.h:20
int32_t y
Definition: Myers.h:21

◆ operator!=() [2/2]

constexpr bool myers::operator!= ( const Segment s0,
const Segment s1 
)
constexpr

Definition at line 74 of file Myers.h.

74 {
75 return std::tie(s0.fUpper, s0.fLower) != std::tie(s1.fUpper, s1.fLower);
76}

◆ operator-()

Point myers::operator- ( const Point p0,
const Point p1 
)

Definition at line 22 of file Myers.cpp.

22 {
23 return {p0.x - p1.x, p0.y - p1.y};
24}

◆ operator<() [1/3]

bool myers::operator< ( const Crossing c0,
const Crossing c1 
)
inline

Definition at line 99 of file Myers.h.

99 {
100 return std::tie(c0.fHigher, c0.fLower) < std::tie(c1.fHigher, c1.fLower);
101}

◆ operator<() [2/3]

constexpr bool myers::operator< ( const Point p0,
const Point p1 
)
constexpr

Definition at line 25 of file Myers.h.

25 {
26 return std::tie(p0.y, p0.x) < std::tie(p1.y, p1.x);
27}

◆ operator<() [3/3]

constexpr bool myers::operator< ( const Segment s0,
const Segment s1 
)
constexpr

Definition at line 66 of file Myers.h.

66 {
67 return std::tie(s0.fUpper, s0.fLower) < std::tie(s1.fUpper, s1.fLower);
68}

◆ operator==() [1/3]

bool myers::operator== ( const Crossing c0,
const Crossing c1 
)
inline

Definition at line 103 of file Myers.h.

103 {
104 return std::tie(c0.fHigher, c0.fLower) == std::tie(c1.fHigher, c1.fLower);
105}

◆ operator==() [2/3]

constexpr bool myers::operator== ( const Point p0,
const Point p1 
)
constexpr

Definition at line 29 of file Myers.h.

29 {
30 return std::tie(p0.x, p0.y) == std::tie(p1.x, p1.y);
31}

◆ operator==() [3/3]

constexpr bool myers::operator== ( const Segment s0,
const Segment s1 
)
constexpr

Definition at line 70 of file Myers.h.

70 {
71 return std::tie(s0.fUpper, s0.fLower) == std::tie(s1.fUpper, s1.fLower);
72}

◆ point_to_s64()

std::tuple< int64_t, int64_t > myers::point_to_s64 ( Point  p)

Definition at line 26 of file Myers.cpp.

26 {
27 return std::make_tuple(SkToS64(p.x), SkToS64(p.y));
28}
constexpr int64_t SkToS64(S x)
Definition: SkTo.h:27

◆ s0_intersects_s1()

bool myers::s0_intersects_s1 ( const Segment s0,
const Segment s1 
)

Definition at line 577 of file Myers.cpp.

577 {
578 // Make sure that s0 upper is above s1 upper.
579 if (s1.upper().y < s0.upper().y
580 || ((s1.upper().y == s0.upper().y) && (s1.lower().y > s0.lower().y))) {
581
582 // Swap to put in the right orientation.
583 return s0_intersects_s1(s1, s0);
584 }
585
586 SkASSERT(s0.upper().y <= s1.upper().y);
587
588 { // If extents don't overlap then there is no intersection.
589 auto [left0, top0, right0, bottom0] = s0.bounds();
590 auto [left1, top1, right1, bottom1] = s1.bounds();
591 if (right1 < left0 || right0 < left1 || bottom1 < top0 || bottom0 < top1) {
592 return false;
593 }
594 }
595
596 auto [u0, l0] = s0;
597 auto [u1, l1] = s1;
598
599 const Point D0 = l0 - u0,
600 D1 = l1 - u1;
601
602 // If the vector from u0 to l0 (named D0) and the vector from u0 to u1 have an angle of 0
603 // between them, then u1 is on the segment u0 to l0 (named s0).
604 const Point U0toU1 = (u1 - u0);
605 const int64_t D0xU0toU1 = cross(D0, U0toU1);
606 if (D0xU0toU1 == 0) {
607 // u1 is on s0.
608 return true;
609 }
610
611 if (l1.y <= l0.y) {
612 // S1 is between the upper and lower points of S0.
613 const Point U0toL1 = (l1 - u0);
614 const int64_t D0xU0toL1 = cross(D0, U0toL1);
615 if (D0xU0toL1 == 0) {
616 // l1 is on s0.
617 return true;
618 }
619
620 // If U1 and L1 are on opposite sides of D0 then the segments cross.
621 return (D0xU0toU1 ^ D0xU0toL1) < 0;
622 } else {
623 // S1 extends past S0. It could be that S1 crosses the line of S0 (not the bound segment)
624 // beyond the endpoints of S0. Make sure that it crosses on the segment and not beyond.
625 const Point U1toL0 = (l0 - u1);
626 const int64_t D1xU1toL0 = cross(D1, U1toL0);
627 if (D1xU1toL0 == 0) {
628 return true;
629 }
630
631 // For D1 to cross D0, then D1 must be on the same side of U1toL0 as D0. D0xU0toU1
632 // describes the orientation of U0 compared to D0. The angle from D1 to U1toL0 must
633 // have the same direction as the angle from U0toU1 to D0.
634 return (D0xU0toU1 ^ D1xU1toL0) >= 0;
635 }
636}
const Point & upper() const
Definition: Myers.cpp:31
std::tuple< int32_t, int32_t, int32_t, int32_t > bounds() const
Definition: Myers.cpp:39
const Point & lower() const
Definition: Myers.cpp:35

◆ s0_less_than_s1_at_y()

bool myers::s0_less_than_s1_at_y ( const Segment s0,
const Segment s1,
int32_t  y 
)

Definition at line 166 of file Myers.cpp.

166 {
167 // Neither s0 nor s1 are horizontal because this is used during the sorting phase
168 SkASSERT(!s0.isHorizontal() && !s1.isHorizontal());
169
170 const auto [u0, l0] = s0;
171 const auto [u1, l1] = s1;
172
173 const auto [left0, right0] = std::minmax(u0.x, l0.x);
174 const auto [left1, right1] = std::minmax(u1.x, l1.x);
175
176 if (right0 < left1) {
177 return true;
178 } else if (right1 < left0) {
179 return false;
180 }
181
182 const Point d0 = l0 - u0;
183 const Point d1 = l1 - u1;
184
185 // Since horizontal lines are handled separately and the ordering of points for the segment,
186 // then there should always be positive Dy.
187 SkASSERT(d0.y > 0 && d1.y > 0);
188
189 namespace bo = bentleyottmann;
190 using Int96 = bo::Int96;
191
192 // Defining s0(y) and s1(y),
193 // s0(y) = u0.x + (y - u0.y) * d0.x / d0.y
194 // s1(y) = u1.x + (y - u1.y) * d1.x / d1.y
195 // Find the following
196 // s0(y) < s1(y)
197 // Substituting s0(y) and s1(y)
198 // u0.x + (y - u0.y) * d0.x / d0.y < u1.x + (y - u1.y) * d1.x / d1.y
199 // Factoring out the denominator.
200 // (u0.x * d0.y + (y - u0.y) * d0.x) / d0.y < (u1.x * d1.y + (y - u1.y) * d1.x) / d1.y
201 // Cross-multiplying the denominators. The sign will not switch because d0.y and d1.y are
202 // always positive.
203 // d1.y * (u0.x * d0.y + (y - u0.y) * d0.x) < d0.y * (u1.x * d1.y + (y - u1.y) * d1.x)
204 // If these are equal, then we use the slope to break the tie.
205 // d0.x / d0.y < d1.x / d1.y
206 // Cross multiplying leaves.
207 // d0.x * d1.y < d1.x * d0.y
208 const Int96 lhs = bo::multiply(d1.y, u0.x * SkToS64(d0.y) + (y - u0.y) * SkToS64(d0.x));
209 const Int96 rhs = bo::multiply(d0.y, u1.x * SkToS64(d1.y) + (y - u1.y) * SkToS64(d1.x));
210
211 return lhs < rhs || ((lhs == rhs) && slope_s0_less_than_slope_s1(s0, s1));
212}
double y
Int96 multiply(int64_t a, int32_t b)
Definition: Int96.cpp:41
bool slope_s0_less_than_slope_s1(const Segment &s0, const Segment &s1)
Definition: Myers.cpp:109

◆ segment_less_than_upper_to_insert()

bool myers::segment_less_than_upper_to_insert ( const Segment segment,
const Segment to_insert 
)

Definition at line 158 of file Myers.cpp.

158 {
159 const int64_t compare = compare_point_to_segment(to_insert.upper(), segment);
160
161 // compare > 0 when segment < to_insert.upper().
162 return (compare > 0) || ((compare == 0) && slope_s0_less_than_slope_s1(segment, to_insert));
163}
int64_t compare_point_to_segment(Point p, const Segment &s)
Definition: Myers.cpp:117
int compare(const void *untyped_lhs, const void *untyped_rhs)
Definition: skdiff.h:161

◆ slope_s0_less_than_slope_s1()

bool myers::slope_s0_less_than_slope_s1 ( const Segment s0,
const Segment s1 
)

Definition at line 109 of file Myers.cpp.

109 {
110 return compare_slopes(s0, s1) < 0;
111}
int64_t compare_slopes(const Segment &s0, const Segment &s1)
Definition: Myers.cpp:67