blob: 7fad7a40e46637c62dd47c9c8b8b2ec332ef0d87 [file] [log] [blame]
caryclark@google.com07393ca2013-04-08 11:47:37 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7#ifndef SkOpContour_DEFINED
8#define SkOpContour_DEFINED
9
10#include "SkOpSegment.h"
11#include "SkTArray.h"
12
commit-bot@chromium.org0bcb8ca2014-04-25 13:42:21 +000013#if defined(SK_DEBUG) || !FORCE_RELEASE
14#include "SkThread.h"
15#endif
16
caryclark@google.com07393ca2013-04-08 11:47:37 +000017class SkIntersections;
18class SkOpContour;
19class SkPathWriter;
20
21struct SkCoincidence {
caryclark@google.com570863f2013-09-16 15:55:01 +000022 SkOpContour* fOther;
caryclark@google.com07393ca2013-04-08 11:47:37 +000023 int fSegments[2];
24 double fTs[2][2];
25 SkPoint fPts[2];
26};
27
28class SkOpContour {
29public:
30 SkOpContour() {
31 reset();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000032#if defined(SK_DEBUG) || !FORCE_RELEASE
commit-bot@chromium.org0bcb8ca2014-04-25 13:42:21 +000033 fID = sk_atomic_inc(&SkPathOpsDebug::gContourID);
caryclark@google.com07393ca2013-04-08 11:47:37 +000034#endif
35 }
36
37 bool operator<(const SkOpContour& rh) const {
38 return fBounds.fTop == rh.fBounds.fTop
39 ? fBounds.fLeft < rh.fBounds.fLeft
40 : fBounds.fTop < rh.fBounds.fTop;
41 }
42
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000043 bool addCoincident(int index, SkOpContour* other, int otherIndex,
caryclark@google.com07393ca2013-04-08 11:47:37 +000044 const SkIntersections& ts, bool swap);
45 void addCoincidentPoints();
46
47 void addCross(const SkOpContour* crosser) {
48#ifdef DEBUG_CROSS
49 for (int index = 0; index < fCrosses.count(); ++index) {
50 SkASSERT(fCrosses[index] != crosser);
51 }
52#endif
caryclark@google.comd892bd82013-06-17 14:10:36 +000053 fCrosses.push_back(crosser);
caryclark@google.com07393ca2013-04-08 11:47:37 +000054 }
55
56 void addCubic(const SkPoint pts[4]) {
57 fSegments.push_back().addCubic(pts, fOperand, fXor);
58 fContainsCurves = fContainsCubics = true;
59 }
60
61 int addLine(const SkPoint pts[2]) {
62 fSegments.push_back().addLine(pts, fOperand, fXor);
63 return fSegments.count();
64 }
65
66 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
67 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
68 }
69
caryclark@google.com7eaa53d2013-10-02 14:49:34 +000070 bool addPartialCoincident(int index, SkOpContour* other, int otherIndex,
caryclark@google.com570863f2013-09-16 15:55:01 +000071 const SkIntersections& ts, int ptIndex, bool swap);
72
caryclark@google.com07393ca2013-04-08 11:47:37 +000073 int addQuad(const SkPoint pts[3]) {
74 fSegments.push_back().addQuad(pts, fOperand, fXor);
75 fContainsCurves = true;
76 return fSegments.count();
77 }
78
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +000079 int addT(int segIndex, SkOpContour* other, int otherIndex, const SkPoint& pt, double newT) {
caryclark@google.com07393ca2013-04-08 11:47:37 +000080 setContainsIntercepts();
commit-bot@chromium.org866f4e32013-11-21 17:04:29 +000081 return fSegments[segIndex].addT(&other->fSegments[otherIndex], pt, newT);
caryclark@google.com07393ca2013-04-08 11:47:37 +000082 }
83
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000084 int addSelfT(int segIndex, const SkPoint& pt, double newT) {
caryclark@google.com07393ca2013-04-08 11:47:37 +000085 setContainsIntercepts();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000086 return fSegments[segIndex].addSelfT(pt, newT);
caryclark@google.com07393ca2013-04-08 11:47:37 +000087 }
88
caryclark@google.com07393ca2013-04-08 11:47:37 +000089 const SkPathOpsBounds& bounds() const {
90 return fBounds;
91 }
92
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000093 bool calcAngles();
caryclark@google.com07393ca2013-04-08 11:47:37 +000094 void calcCoincidentWinding();
caryclark@google.com570863f2013-09-16 15:55:01 +000095 void calcPartialCoincidentWinding();
caryclark@google.com07393ca2013-04-08 11:47:37 +000096
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000097 void checkDuplicates() {
98 int segmentCount = fSegments.count();
99 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
100 SkOpSegment& segment = fSegments[sIndex];
101 if (segment.count() > 2) {
102 segment.checkDuplicates();
103 }
104 }
105 }
106
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000107 void checkEnds() {
108 if (!fContainsCurves) {
109 return;
110 }
111 int segmentCount = fSegments.count();
112 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
113 SkOpSegment* segment = &fSegments[sIndex];
114 if (segment->verb() == SkPath::kLine_Verb) {
115 continue;
116 }
caryclark@google.com7eaa53d2013-10-02 14:49:34 +0000117 if (segment->done()) {
118 continue; // likely coincident, nothing to do
119 }
caryclark@google.com570863f2013-09-16 15:55:01 +0000120 segment->checkEnds();
121 }
122 }
123
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000124 void checkMultiples() {
125 int segmentCount = fSegments.count();
126 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
127 SkOpSegment& segment = fSegments[sIndex];
128 if (segment.count() > 2) {
129 segment.checkMultiples();
130 }
131 }
132 }
133
134 void checkSmall() {
135 int segmentCount = fSegments.count();
136 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
137 SkOpSegment& segment = fSegments[sIndex];
138 if (segment.hasSmall()) {
139 segment.checkSmall();
140 }
141 }
142 }
143
caryclark@google.com570863f2013-09-16 15:55:01 +0000144 // if same point has different T values, choose a common T
145 void checkTiny() {
146 int segmentCount = fSegments.count();
147 if (segmentCount <= 2) {
148 return;
149 }
150 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000151 SkOpSegment& segment = fSegments[sIndex];
152 if (segment.hasTiny()) {
153 segment.checkTiny();
154 }
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000155 }
156 }
157
caryclark@google.com07393ca2013-04-08 11:47:37 +0000158 void complete() {
159 setBounds();
160 fContainsIntercepts = false;
161 }
162
163 bool containsCubics() const {
164 return fContainsCubics;
165 }
166
167 bool crosses(const SkOpContour* crosser) const {
168 for (int index = 0; index < fCrosses.count(); ++index) {
169 if (fCrosses[index] == crosser) {
170 return true;
171 }
172 }
173 return false;
174 }
175
176 bool done() const {
177 return fDone;
178 }
179
180 const SkPoint& end() const {
181 const SkOpSegment& segment = fSegments.back();
reed@google.com277c3f82013-05-31 15:17:50 +0000182 return segment.pts()[SkPathOpsVerbToPoints(segment.verb())];
caryclark@google.com07393ca2013-04-08 11:47:37 +0000183 }
184
caryclark@google.com07393ca2013-04-08 11:47:37 +0000185 void fixOtherTIndex() {
186 int segmentCount = fSegments.count();
187 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
188 fSegments[sIndex].fixOtherTIndex();
189 }
190 }
191
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000192 void joinCoincidence() {
193 joinCoincidence(fCoincidences, false);
194 joinCoincidence(fPartialCoincidences, true);
195 }
196
caryclark@google.com07393ca2013-04-08 11:47:37 +0000197 SkOpSegment* nonVerticalSegment(int* start, int* end);
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000198
caryclark@google.com07393ca2013-04-08 11:47:37 +0000199 bool operand() const {
200 return fOperand;
201 }
202
203 void reset() {
204 fSegments.reset();
205 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
206 fContainsCurves = fContainsCubics = fContainsIntercepts = fDone = false;
207 }
208
209 SkTArray<SkOpSegment>& segments() {
210 return fSegments;
211 }
212
213 void setContainsIntercepts() {
214 fContainsIntercepts = true;
215 }
216
217 void setOperand(bool isOp) {
218 fOperand = isOp;
219 }
220
221 void setOppXor(bool isOppXor) {
222 fOppXor = isOppXor;
223 int segmentCount = fSegments.count();
224 for (int test = 0; test < segmentCount; ++test) {
225 fSegments[test].setOppXor(isOppXor);
226 }
227 }
228
229 void setXor(bool isXor) {
230 fXor = isXor;
231 }
232
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000233 void sortAngles();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000234 void sortSegments();
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000235
caryclark@google.com07393ca2013-04-08 11:47:37 +0000236 const SkPoint& start() const {
237 return fSegments.front().pts()[0];
238 }
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000239
caryclark@google.com07393ca2013-04-08 11:47:37 +0000240 void toPath(SkPathWriter* path) const;
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000241
caryclark@google.com07393ca2013-04-08 11:47:37 +0000242 void toPartialBackward(SkPathWriter* path) const {
243 int segmentCount = fSegments.count();
244 for (int test = segmentCount - 1; test >= 0; --test) {
245 fSegments[test].addCurveTo(1, 0, path, true);
246 }
247 }
248
249 void toPartialForward(SkPathWriter* path) const {
250 int segmentCount = fSegments.count();
251 for (int test = 0; test < segmentCount; ++test) {
252 fSegments[test].addCurveTo(0, 1, path, true);
253 }
254 }
255
256 void topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY, SkOpSegment** topStart);
257 SkOpSegment* undoneSegment(int* start, int* end);
258
259 int updateSegment(int index, const SkPoint* pts) {
260 SkOpSegment& segment = fSegments[index];
261 segment.updatePts(pts);
reed@google.com277c3f82013-05-31 15:17:50 +0000262 return SkPathOpsVerbToPoints(segment.verb()) + 1;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000263 }
264
265#if DEBUG_TEST
266 SkTArray<SkOpSegment>& debugSegments() {
267 return fSegments;
268 }
269#endif
270
caryclark@google.coma5e55922013-05-07 18:51:31 +0000271#if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
caryclark@google.com07393ca2013-04-08 11:47:37 +0000272 void debugShowActiveSpans() {
273 for (int index = 0; index < fSegments.count(); ++index) {
274 fSegments[index].debugShowActiveSpans();
275 }
276 }
277#endif
278
279#if DEBUG_SHOW_WINDING
280 int debugShowWindingValues(int totalSegments, int ofInterest);
caryclark@google.comd892bd82013-06-17 14:10:36 +0000281 static void debugShowWindingValues(const SkTArray<SkOpContour*, true>& contourList);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000282#endif
283
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000284 // available to test routines only
285 void dump() const;
286 void dumpAngles() const;
287 void dumpPts() const;
288 void dumpSpans() const;
289
caryclark@google.com07393ca2013-04-08 11:47:37 +0000290private:
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000291 void calcCommonCoincidentWinding(const SkCoincidence& );
292 void joinCoincidence(const SkTArray<SkCoincidence, true>& , bool partial);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000293 void setBounds();
294
295 SkTArray<SkOpSegment> fSegments;
caryclark@google.comd892bd82013-06-17 14:10:36 +0000296 SkTArray<SkOpSegment*, true> fSortedSegments;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000297 int fFirstSorted;
caryclark@google.comd892bd82013-06-17 14:10:36 +0000298 SkTArray<SkCoincidence, true> fCoincidences;
caryclark@google.com570863f2013-09-16 15:55:01 +0000299 SkTArray<SkCoincidence, true> fPartialCoincidences;
caryclark@google.comd892bd82013-06-17 14:10:36 +0000300 SkTArray<const SkOpContour*, true> fCrosses;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000301 SkPathOpsBounds fBounds;
302 bool fContainsIntercepts; // FIXME: is this used by anybody?
303 bool fContainsCubics;
304 bool fContainsCurves;
305 bool fDone;
306 bool fOperand; // true for the second argument to a binary operator
307 bool fXor;
308 bool fOppXor;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000309#if defined(SK_DEBUG) || !FORCE_RELEASE
310 int debugID() const { return fID; }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000311 int fID;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000312#else
313 int debugID() const { return -1; }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000314#endif
315};
316
317#endif