| // 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/Contour.h" | |
| #include "include/core/SkPath.h" | |
| #include "include/core/SkPoint.h" | |
| #include "include/core/SkScalar.h" | |
| #include "include/private/SkTo.h" | |
| #include "modules/bentleyottmann/include/Myers.h" | |
| #include <algorithm> | |
| #include <vector> | |
| namespace contour { | |
| Contours Contours::Make(SkPath path) { | |
| SkPath::Iter iter(path, false); | |
| Contours contours; | |
| while (auto rec = iter.next()) { | |
| SkSpan<const SkPoint> pts = rec->fPoints; | |
| switch (rec->fVerb) { | |
| case SkPathVerb::kConic: { | |
| SK_ABORT("Not implemented"); | |
| break; | |
| } | |
| case SkPathVerb::kMove: | |
| contours.closeContourIfNeeded(); | |
| contours.moveToStartOfContour(pts[0]); | |
| break; | |
| case SkPathVerb::kLine: { | |
| contours.addPointToCurrentContour(pts[1]); | |
| break; | |
| } | |
| case SkPathVerb::kQuad: { | |
| SK_ABORT("Not implemented"); | |
| break; | |
| } | |
| case SkPathVerb::kCubic: { | |
| SK_ABORT("Not implemented"); | |
| break; | |
| } | |
| case SkPathVerb::kClose: { | |
| contours.closeContourIfNeeded(); | |
| break; | |
| } | |
| } | |
| } | |
| // Close the remaining contour. | |
| contours.closeContourIfNeeded(); | |
| return contours; | |
| } | |
| std::vector<myers::Segment> Contours::segments() const { | |
| SK_ABORT("Not implemented"); | |
| } | |
| static SkIRect extend_rect(SkIRect r, Point p) { | |
| int32_t left = std::min(p.x, r.fLeft), | |
| top = std::min(p.y, r.fTop), | |
| right = std::max(p.x, r.fRight), | |
| bottom = std::max(p.y, r.fBottom); | |
| return {left, top, right, bottom}; | |
| } | |
| Point Contours::RoundSkPoint(SkPoint p) { | |
| return {SkScalarRoundToInt(p.x() * kScaleFactor), SkScalarRoundToInt(p.y() * kScaleFactor)}; | |
| } | |
| bool Contours::currentContourIsEmpty() const { | |
| int32_t lastEnd = fContours.empty() ? 0 : fContours.back().end; | |
| return lastEnd == SkToS32(fPoints.size()); | |
| } | |
| void Contours::addPointToCurrentContour(SkPoint p) { | |
| if (this->currentContourIsEmpty()) { | |
| fPoints.push_back(fContourStart); | |
| fContourBounds = extend_rect(fContourBounds, fContourStart); | |
| } | |
| Point point = RoundSkPoint(p); | |
| fPoints.push_back(point); | |
| fContourBounds = extend_rect(fContourBounds, point); | |
| } | |
| void Contours::moveToStartOfContour(SkPoint p) { | |
| fContourStart = RoundSkPoint(p); | |
| } | |
| void Contours::closeContourIfNeeded() { | |
| if (this->currentContourIsEmpty()) { | |
| // The current contour is empty. Don't record it. | |
| return; | |
| } | |
| fContours.push_back({fContourBounds, SkToS32(fPoints.size())}); | |
| fContourBounds = kEmptyRect; | |
| } | |
| } // namespace contour |