xref: /aosp_15_r20/external/skia/modules/bentleyottmann/src/Contour.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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