// Copyright 2023 Google LLC // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. #include "modules/bentleyottmann/include/SweepLine.h" #include "include/private/base/SkAssert.h" #include "modules/bentleyottmann/include/EventQueueInterface.h" #include "modules/bentleyottmann/include/Point.h" #include #include #include #include #include namespace bentleyottmann { SweepLine::SweepLine() { static constexpr Segment LeftSentinel = {{-std::numeric_limits::max(), -std::numeric_limits::max()}, {-std::numeric_limits::max(), std::numeric_limits::max()}}; static constexpr Segment RightSentinel = {{std::numeric_limits::max(), -std::numeric_limits::max()}, {std::numeric_limits::max(), std::numeric_limits::max()}}; fSweepLine.reserve(8); fSweepLine.push_back(LeftSentinel); fSweepLine.push_back(RightSentinel); } void SweepLine::verify(int32_t y) const { for(auto cursor = fSweepLine.begin(); (cursor + 1) != fSweepLine.end(); ++cursor) { [[maybe_unused]] const Segment& left = *cursor; [[maybe_unused]] const Segment& right = *(cursor + 1); SkASSERT(less_than_at(left, right, y)); } } void SweepLine::handleDeletions(Point eventPoint, const DeletionSegmentSet& removing) { std::vector::iterator newEnd; if (removing.empty()) { // Remove ending segments auto toRemove = [eventPoint](Segment s) { return s.lower() == eventPoint; }; newEnd = std::remove_if(fSweepLine.begin(), fSweepLine.end(), toRemove); } else { // Remove all ending and crossing segments. auto toRemove = [eventPoint, &removing](Segment s) { return s.lower() == eventPoint || removing.find(s) != removing.end(); }; newEnd = std::remove_if(fSweepLine.begin(), fSweepLine.end(), toRemove); } fSweepLine.erase(newEnd, fSweepLine.end()); } void SweepLine::handleInsertionsAndCheckForNewCrossings( Point eventPoint, const InsertionSegmentSet& inserting, EventQueueInterface* queue) { // The SlopeSegmentSet makes sure that these segments are in the right order for insertion. auto comp = [](const Segment& s, Point p) { return !point_less_than_segment_in_x(p, s); }; const auto rightOfInsertion = std::lower_bound( fSweepLine.begin(), fSweepLine.end(), eventPoint, comp); SkASSERT(rightOfInsertion != fSweepLine.begin()); const auto leftOfInsertion = rightOfInsertion - 1; if (inserting.empty()) { // There were deletions, but no insertions, so check if the two segments at the insertion // point cross. if (auto crossingPoint = intersect(*leftOfInsertion, *rightOfInsertion)) { queue->addCrossing(crossingPoint.value(), *leftOfInsertion, *rightOfInsertion); } } else { // Check if the left most inserted segment crosses the segment immediately to the left of // the insertion cursor. if (auto crossingPoint = intersect(*leftOfInsertion, *inserting.begin())) { queue->addCrossing(crossingPoint.value(), *leftOfInsertion, *inserting.begin()); } // Check if the right most inserted segment crosses the segment immediately to the right of // the insertion cursor. if (auto crossingPoint = intersect(*inserting.rbegin(), *rightOfInsertion)) { queue->addCrossing(crossingPoint.value(), *inserting.rbegin(), *rightOfInsertion); } // Insert the set in the sweep line. fSweepLine.insert(rightOfInsertion, inserting.begin(), inserting.end()); } } } // namespace bentleyottmann