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/SweepLine.h"
5*c8dee2aaSAndroid Build Coastguard Worker
6*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
7*c8dee2aaSAndroid Build Coastguard Worker #include "modules/bentleyottmann/include/EventQueueInterface.h"
8*c8dee2aaSAndroid Build Coastguard Worker #include "modules/bentleyottmann/include/Point.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
10*c8dee2aaSAndroid Build Coastguard Worker #include <iterator>
11*c8dee2aaSAndroid Build Coastguard Worker #include <limits>
12*c8dee2aaSAndroid Build Coastguard Worker #include <optional>
13*c8dee2aaSAndroid Build Coastguard Worker #include <set>
14*c8dee2aaSAndroid Build Coastguard Worker
15*c8dee2aaSAndroid Build Coastguard Worker
16*c8dee2aaSAndroid Build Coastguard Worker namespace bentleyottmann {
17*c8dee2aaSAndroid Build Coastguard Worker
SweepLine()18*c8dee2aaSAndroid Build Coastguard Worker SweepLine::SweepLine() {
19*c8dee2aaSAndroid Build Coastguard Worker static constexpr Segment LeftSentinel = {{-std::numeric_limits<int32_t>::max(),
20*c8dee2aaSAndroid Build Coastguard Worker -std::numeric_limits<int32_t>::max()},
21*c8dee2aaSAndroid Build Coastguard Worker {-std::numeric_limits<int32_t>::max(),
22*c8dee2aaSAndroid Build Coastguard Worker std::numeric_limits<int32_t>::max()}};
23*c8dee2aaSAndroid Build Coastguard Worker static constexpr Segment RightSentinel = {{std::numeric_limits<int32_t>::max(),
24*c8dee2aaSAndroid Build Coastguard Worker -std::numeric_limits<int32_t>::max()},
25*c8dee2aaSAndroid Build Coastguard Worker {std::numeric_limits<int32_t>::max(),
26*c8dee2aaSAndroid Build Coastguard Worker std::numeric_limits<int32_t>::max()}};
27*c8dee2aaSAndroid Build Coastguard Worker
28*c8dee2aaSAndroid Build Coastguard Worker fSweepLine.reserve(8);
29*c8dee2aaSAndroid Build Coastguard Worker fSweepLine.push_back(LeftSentinel);
30*c8dee2aaSAndroid Build Coastguard Worker fSweepLine.push_back(RightSentinel);
31*c8dee2aaSAndroid Build Coastguard Worker }
32*c8dee2aaSAndroid Build Coastguard Worker
verify(int32_t y) const33*c8dee2aaSAndroid Build Coastguard Worker void SweepLine::verify(int32_t y) const {
34*c8dee2aaSAndroid Build Coastguard Worker for(auto cursor = fSweepLine.begin(); (cursor + 1) != fSweepLine.end(); ++cursor) {
35*c8dee2aaSAndroid Build Coastguard Worker [[maybe_unused]] const Segment& left = *cursor;
36*c8dee2aaSAndroid Build Coastguard Worker [[maybe_unused]] const Segment& right = *(cursor + 1);
37*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(less_than_at(left, right, y));
38*c8dee2aaSAndroid Build Coastguard Worker }
39*c8dee2aaSAndroid Build Coastguard Worker }
40*c8dee2aaSAndroid Build Coastguard Worker
handleDeletions(Point eventPoint,const DeletionSegmentSet & removing)41*c8dee2aaSAndroid Build Coastguard Worker void SweepLine::handleDeletions(Point eventPoint, const DeletionSegmentSet& removing) {
42*c8dee2aaSAndroid Build Coastguard Worker std::vector<Segment>::iterator newEnd;
43*c8dee2aaSAndroid Build Coastguard Worker if (removing.empty()) {
44*c8dee2aaSAndroid Build Coastguard Worker // Remove ending segments
45*c8dee2aaSAndroid Build Coastguard Worker auto toRemove = [eventPoint](Segment s) {
46*c8dee2aaSAndroid Build Coastguard Worker return s.lower() == eventPoint;
47*c8dee2aaSAndroid Build Coastguard Worker };
48*c8dee2aaSAndroid Build Coastguard Worker newEnd = std::remove_if(fSweepLine.begin(), fSweepLine.end(), toRemove);
49*c8dee2aaSAndroid Build Coastguard Worker } else {
50*c8dee2aaSAndroid Build Coastguard Worker // Remove all ending and crossing segments.
51*c8dee2aaSAndroid Build Coastguard Worker auto toRemove = [eventPoint, &removing](Segment s) {
52*c8dee2aaSAndroid Build Coastguard Worker return s.lower() == eventPoint || removing.find(s) != removing.end();
53*c8dee2aaSAndroid Build Coastguard Worker };
54*c8dee2aaSAndroid Build Coastguard Worker newEnd = std::remove_if(fSweepLine.begin(), fSweepLine.end(), toRemove);
55*c8dee2aaSAndroid Build Coastguard Worker }
56*c8dee2aaSAndroid Build Coastguard Worker fSweepLine.erase(newEnd, fSweepLine.end());
57*c8dee2aaSAndroid Build Coastguard Worker }
58*c8dee2aaSAndroid Build Coastguard Worker
handleInsertionsAndCheckForNewCrossings(Point eventPoint,const InsertionSegmentSet & inserting,EventQueueInterface * queue)59*c8dee2aaSAndroid Build Coastguard Worker void SweepLine::handleInsertionsAndCheckForNewCrossings(
60*c8dee2aaSAndroid Build Coastguard Worker Point eventPoint, const InsertionSegmentSet& inserting, EventQueueInterface* queue) {
61*c8dee2aaSAndroid Build Coastguard Worker // The SlopeSegmentSet makes sure that these segments are in the right order for insertion.
62*c8dee2aaSAndroid Build Coastguard Worker auto comp = [](const Segment& s, Point p) {
63*c8dee2aaSAndroid Build Coastguard Worker return !point_less_than_segment_in_x(p, s);
64*c8dee2aaSAndroid Build Coastguard Worker };
65*c8dee2aaSAndroid Build Coastguard Worker
66*c8dee2aaSAndroid Build Coastguard Worker const auto rightOfInsertion = std::lower_bound(
67*c8dee2aaSAndroid Build Coastguard Worker fSweepLine.begin(), fSweepLine.end(), eventPoint, comp);
68*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(rightOfInsertion != fSweepLine.begin());
69*c8dee2aaSAndroid Build Coastguard Worker const auto leftOfInsertion = rightOfInsertion - 1;
70*c8dee2aaSAndroid Build Coastguard Worker
71*c8dee2aaSAndroid Build Coastguard Worker if (inserting.empty()) {
72*c8dee2aaSAndroid Build Coastguard Worker // There were deletions, but no insertions, so check if the two segments at the insertion
73*c8dee2aaSAndroid Build Coastguard Worker // point cross.
74*c8dee2aaSAndroid Build Coastguard Worker if (auto crossingPoint = intersect(*leftOfInsertion, *rightOfInsertion)) {
75*c8dee2aaSAndroid Build Coastguard Worker queue->addCrossing(crossingPoint.value(), *leftOfInsertion, *rightOfInsertion);
76*c8dee2aaSAndroid Build Coastguard Worker }
77*c8dee2aaSAndroid Build Coastguard Worker } else {
78*c8dee2aaSAndroid Build Coastguard Worker // Check if the left most inserted segment crosses the segment immediately to the left of
79*c8dee2aaSAndroid Build Coastguard Worker // the insertion cursor.
80*c8dee2aaSAndroid Build Coastguard Worker if (auto crossingPoint = intersect(*leftOfInsertion, *inserting.begin())) {
81*c8dee2aaSAndroid Build Coastguard Worker queue->addCrossing(crossingPoint.value(), *leftOfInsertion, *inserting.begin());
82*c8dee2aaSAndroid Build Coastguard Worker }
83*c8dee2aaSAndroid Build Coastguard Worker
84*c8dee2aaSAndroid Build Coastguard Worker // Check if the right most inserted segment crosses the segment immediately to the right of
85*c8dee2aaSAndroid Build Coastguard Worker // the insertion cursor.
86*c8dee2aaSAndroid Build Coastguard Worker if (auto crossingPoint = intersect(*inserting.rbegin(), *rightOfInsertion)) {
87*c8dee2aaSAndroid Build Coastguard Worker queue->addCrossing(crossingPoint.value(), *inserting.rbegin(), *rightOfInsertion);
88*c8dee2aaSAndroid Build Coastguard Worker }
89*c8dee2aaSAndroid Build Coastguard Worker
90*c8dee2aaSAndroid Build Coastguard Worker // Insert the set in the sweep line.
91*c8dee2aaSAndroid Build Coastguard Worker fSweepLine.insert(rightOfInsertion, inserting.begin(), inserting.end());
92*c8dee2aaSAndroid Build Coastguard Worker }
93*c8dee2aaSAndroid Build Coastguard Worker }
94*c8dee2aaSAndroid Build Coastguard Worker } // namespace bentleyottmann
95