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/Contour.h"
5*c8dee2aaSAndroid Build Coastguard Worker
6*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
7*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "modules/bentleyottmann/include/Myers.h"
11*c8dee2aaSAndroid Build Coastguard Worker
12*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
13*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
14*c8dee2aaSAndroid Build Coastguard Worker
15*c8dee2aaSAndroid Build Coastguard Worker namespace contour {
Make(SkPath path)16*c8dee2aaSAndroid Build Coastguard Worker Contours Contours::Make(SkPath path) {
17*c8dee2aaSAndroid Build Coastguard Worker SkPoint pts[4];
18*c8dee2aaSAndroid Build Coastguard Worker SkPath::Iter iter(path, false);
19*c8dee2aaSAndroid Build Coastguard Worker SkPath::Verb verb;
20*c8dee2aaSAndroid Build Coastguard Worker Contours contours;
21*c8dee2aaSAndroid Build Coastguard Worker while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
22*c8dee2aaSAndroid Build Coastguard Worker switch (verb) {
23*c8dee2aaSAndroid Build Coastguard Worker case SkPath::kConic_Verb: {
24*c8dee2aaSAndroid Build Coastguard Worker SK_ABORT("Not implemented");
25*c8dee2aaSAndroid Build Coastguard Worker break;
26*c8dee2aaSAndroid Build Coastguard Worker }
27*c8dee2aaSAndroid Build Coastguard Worker case SkPath::kMove_Verb:
28*c8dee2aaSAndroid Build Coastguard Worker contours.closeContourIfNeeded();
29*c8dee2aaSAndroid Build Coastguard Worker contours.moveToStartOfContour(pts[0]);
30*c8dee2aaSAndroid Build Coastguard Worker break;
31*c8dee2aaSAndroid Build Coastguard Worker case SkPath::kLine_Verb: {
32*c8dee2aaSAndroid Build Coastguard Worker contours.addPointToCurrentContour(pts[1]);
33*c8dee2aaSAndroid Build Coastguard Worker break;
34*c8dee2aaSAndroid Build Coastguard Worker }
35*c8dee2aaSAndroid Build Coastguard Worker case SkPath::kQuad_Verb: {
36*c8dee2aaSAndroid Build Coastguard Worker SK_ABORT("Not implemented");
37*c8dee2aaSAndroid Build Coastguard Worker break;
38*c8dee2aaSAndroid Build Coastguard Worker }
39*c8dee2aaSAndroid Build Coastguard Worker case SkPath::kCubic_Verb: {
40*c8dee2aaSAndroid Build Coastguard Worker SK_ABORT("Not implemented");
41*c8dee2aaSAndroid Build Coastguard Worker break;
42*c8dee2aaSAndroid Build Coastguard Worker }
43*c8dee2aaSAndroid Build Coastguard Worker case SkPath::kClose_Verb: {
44*c8dee2aaSAndroid Build Coastguard Worker contours.closeContourIfNeeded();
45*c8dee2aaSAndroid Build Coastguard Worker break;
46*c8dee2aaSAndroid Build Coastguard Worker }
47*c8dee2aaSAndroid Build Coastguard Worker case SkPath::kDone_Verb:
48*c8dee2aaSAndroid Build Coastguard Worker SK_ABORT("The while loop above failed.");
49*c8dee2aaSAndroid Build Coastguard Worker }
50*c8dee2aaSAndroid Build Coastguard Worker }
51*c8dee2aaSAndroid Build Coastguard Worker
52*c8dee2aaSAndroid Build Coastguard Worker // Close the remaining contour.
53*c8dee2aaSAndroid Build Coastguard Worker contours.closeContourIfNeeded();
54*c8dee2aaSAndroid Build Coastguard Worker
55*c8dee2aaSAndroid Build Coastguard Worker return contours;
56*c8dee2aaSAndroid Build Coastguard Worker }
57*c8dee2aaSAndroid Build Coastguard Worker
segments() const58*c8dee2aaSAndroid Build Coastguard Worker std::vector<myers::Segment> Contours::segments() const {
59*c8dee2aaSAndroid Build Coastguard Worker SK_ABORT("Not implemented");
60*c8dee2aaSAndroid Build Coastguard Worker }
61*c8dee2aaSAndroid Build Coastguard Worker
extend_rect(SkIRect r,Point p)62*c8dee2aaSAndroid Build Coastguard Worker static SkIRect extend_rect(SkIRect r, Point p) {
63*c8dee2aaSAndroid Build Coastguard Worker int32_t left = std::min(p.x, r.fLeft),
64*c8dee2aaSAndroid Build Coastguard Worker top = std::min(p.y, r.fTop),
65*c8dee2aaSAndroid Build Coastguard Worker right = std::max(p.x, r.fRight),
66*c8dee2aaSAndroid Build Coastguard Worker bottom = std::max(p.y, r.fBottom);
67*c8dee2aaSAndroid Build Coastguard Worker return {left, top, right, bottom};
68*c8dee2aaSAndroid Build Coastguard Worker }
69*c8dee2aaSAndroid Build Coastguard Worker
RoundSkPoint(SkPoint p)70*c8dee2aaSAndroid Build Coastguard Worker Point Contours::RoundSkPoint(SkPoint p) {
71*c8dee2aaSAndroid Build Coastguard Worker return {SkScalarRoundToInt(p.x() * kScaleFactor), SkScalarRoundToInt(p.y() * kScaleFactor)};
72*c8dee2aaSAndroid Build Coastguard Worker }
73*c8dee2aaSAndroid Build Coastguard Worker
currentContourIsEmpty() const74*c8dee2aaSAndroid Build Coastguard Worker bool Contours::currentContourIsEmpty() const {
75*c8dee2aaSAndroid Build Coastguard Worker int32_t lastEnd = fContours.empty() ? 0 : fContours.back().end;
76*c8dee2aaSAndroid Build Coastguard Worker return lastEnd == SkToS32(fPoints.size());
77*c8dee2aaSAndroid Build Coastguard Worker }
78*c8dee2aaSAndroid Build Coastguard Worker
addPointToCurrentContour(SkPoint p)79*c8dee2aaSAndroid Build Coastguard Worker void Contours::addPointToCurrentContour(SkPoint p) {
80*c8dee2aaSAndroid Build Coastguard Worker if (this->currentContourIsEmpty()) {
81*c8dee2aaSAndroid Build Coastguard Worker fPoints.push_back(fContourStart);
82*c8dee2aaSAndroid Build Coastguard Worker fContourBounds = extend_rect(fContourBounds, fContourStart);
83*c8dee2aaSAndroid Build Coastguard Worker }
84*c8dee2aaSAndroid Build Coastguard Worker Point point = RoundSkPoint(p);
85*c8dee2aaSAndroid Build Coastguard Worker fPoints.push_back(point);
86*c8dee2aaSAndroid Build Coastguard Worker fContourBounds = extend_rect(fContourBounds, point);
87*c8dee2aaSAndroid Build Coastguard Worker }
88*c8dee2aaSAndroid Build Coastguard Worker
moveToStartOfContour(SkPoint p)89*c8dee2aaSAndroid Build Coastguard Worker void Contours::moveToStartOfContour(SkPoint p) {
90*c8dee2aaSAndroid Build Coastguard Worker fContourStart = RoundSkPoint(p);
91*c8dee2aaSAndroid Build Coastguard Worker }
92*c8dee2aaSAndroid Build Coastguard Worker
closeContourIfNeeded()93*c8dee2aaSAndroid Build Coastguard Worker void Contours::closeContourIfNeeded() {
94*c8dee2aaSAndroid Build Coastguard Worker if (this->currentContourIsEmpty()) {
95*c8dee2aaSAndroid Build Coastguard Worker // The current contour is empty. Don't record it.
96*c8dee2aaSAndroid Build Coastguard Worker return;
97*c8dee2aaSAndroid Build Coastguard Worker }
98*c8dee2aaSAndroid Build Coastguard Worker fContours.push_back({fContourBounds, SkToS32(fPoints.size())});
99*c8dee2aaSAndroid Build Coastguard Worker fContourBounds = kEmptyRect;
100*c8dee2aaSAndroid Build Coastguard Worker }
101*c8dee2aaSAndroid Build Coastguard Worker } // namespace contour
102