|
1 /* |
|
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 |
|
13 class SkIntersections; |
|
14 class SkOpContour; |
|
15 class SkPathWriter; |
|
16 |
|
17 struct SkCoincidence { |
|
18 SkOpContour* fOther; |
|
19 int fSegments[2]; |
|
20 double fTs[2][2]; |
|
21 SkPoint fPts[2]; |
|
22 }; |
|
23 |
|
24 class SkOpContour { |
|
25 public: |
|
26 SkOpContour() { |
|
27 reset(); |
|
28 #ifdef SK_DEBUG |
|
29 fID = ++SkPathOpsDebug::gContourID; |
|
30 #endif |
|
31 } |
|
32 |
|
33 bool operator<(const SkOpContour& rh) const { |
|
34 return fBounds.fTop == rh.fBounds.fTop |
|
35 ? fBounds.fLeft < rh.fBounds.fLeft |
|
36 : fBounds.fTop < rh.fBounds.fTop; |
|
37 } |
|
38 |
|
39 bool addCoincident(int index, SkOpContour* other, int otherIndex, |
|
40 const SkIntersections& ts, bool swap); |
|
41 void addCoincidentPoints(); |
|
42 |
|
43 void addCross(const SkOpContour* crosser) { |
|
44 #ifdef DEBUG_CROSS |
|
45 for (int index = 0; index < fCrosses.count(); ++index) { |
|
46 SkASSERT(fCrosses[index] != crosser); |
|
47 } |
|
48 #endif |
|
49 fCrosses.push_back(crosser); |
|
50 } |
|
51 |
|
52 void addCubic(const SkPoint pts[4]) { |
|
53 fSegments.push_back().addCubic(pts, fOperand, fXor); |
|
54 fContainsCurves = fContainsCubics = true; |
|
55 } |
|
56 |
|
57 int addLine(const SkPoint pts[2]) { |
|
58 fSegments.push_back().addLine(pts, fOperand, fXor); |
|
59 return fSegments.count(); |
|
60 } |
|
61 |
|
62 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) { |
|
63 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex); |
|
64 } |
|
65 |
|
66 bool addPartialCoincident(int index, SkOpContour* other, int otherIndex, |
|
67 const SkIntersections& ts, int ptIndex, bool swap); |
|
68 |
|
69 int addQuad(const SkPoint pts[3]) { |
|
70 fSegments.push_back().addQuad(pts, fOperand, fXor); |
|
71 fContainsCurves = true; |
|
72 return fSegments.count(); |
|
73 } |
|
74 |
|
75 int addT(int segIndex, SkOpContour* other, int otherIndex, const SkPoint& pt, double newT) { |
|
76 setContainsIntercepts(); |
|
77 return fSegments[segIndex].addT(&other->fSegments[otherIndex], pt, newT); |
|
78 } |
|
79 |
|
80 int addSelfT(int segIndex, SkOpContour* other, int otherIndex, const SkPoint& pt, double newT) { |
|
81 setContainsIntercepts(); |
|
82 return fSegments[segIndex].addSelfT(&other->fSegments[otherIndex], pt, newT); |
|
83 } |
|
84 |
|
85 const SkPathOpsBounds& bounds() const { |
|
86 return fBounds; |
|
87 } |
|
88 |
|
89 void calcCoincidentWinding(); |
|
90 void calcPartialCoincidentWinding(); |
|
91 |
|
92 void checkEnds() { |
|
93 if (!fContainsCurves) { |
|
94 return; |
|
95 } |
|
96 int segmentCount = fSegments.count(); |
|
97 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) { |
|
98 SkOpSegment* segment = &fSegments[sIndex]; |
|
99 if (segment->verb() == SkPath::kLine_Verb) { |
|
100 continue; |
|
101 } |
|
102 if (segment->done()) { |
|
103 continue; // likely coincident, nothing to do |
|
104 } |
|
105 segment->checkEnds(); |
|
106 } |
|
107 } |
|
108 |
|
109 // if same point has different T values, choose a common T |
|
110 void checkTiny() { |
|
111 int segmentCount = fSegments.count(); |
|
112 if (segmentCount <= 2) { |
|
113 return; |
|
114 } |
|
115 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) { |
|
116 fSegments[sIndex].checkTiny(); |
|
117 } |
|
118 } |
|
119 |
|
120 void complete() { |
|
121 setBounds(); |
|
122 fContainsIntercepts = false; |
|
123 } |
|
124 |
|
125 bool containsCubics() const { |
|
126 return fContainsCubics; |
|
127 } |
|
128 |
|
129 bool crosses(const SkOpContour* crosser) const { |
|
130 for (int index = 0; index < fCrosses.count(); ++index) { |
|
131 if (fCrosses[index] == crosser) { |
|
132 return true; |
|
133 } |
|
134 } |
|
135 return false; |
|
136 } |
|
137 |
|
138 bool done() const { |
|
139 return fDone; |
|
140 } |
|
141 |
|
142 const SkPoint& end() const { |
|
143 const SkOpSegment& segment = fSegments.back(); |
|
144 return segment.pts()[SkPathOpsVerbToPoints(segment.verb())]; |
|
145 } |
|
146 |
|
147 void fixOtherTIndex() { |
|
148 int segmentCount = fSegments.count(); |
|
149 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) { |
|
150 fSegments[sIndex].fixOtherTIndex(); |
|
151 } |
|
152 } |
|
153 |
|
154 void joinCoincidence() { |
|
155 joinCoincidence(fCoincidences, false); |
|
156 joinCoincidence(fPartialCoincidences, true); |
|
157 } |
|
158 |
|
159 SkOpSegment* nonVerticalSegment(int* start, int* end); |
|
160 |
|
161 bool operand() const { |
|
162 return fOperand; |
|
163 } |
|
164 |
|
165 void reset() { |
|
166 fSegments.reset(); |
|
167 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax); |
|
168 fContainsCurves = fContainsCubics = fContainsIntercepts = fDone = false; |
|
169 } |
|
170 |
|
171 SkTArray<SkOpSegment>& segments() { |
|
172 return fSegments; |
|
173 } |
|
174 |
|
175 void setContainsIntercepts() { |
|
176 fContainsIntercepts = true; |
|
177 } |
|
178 |
|
179 void setOperand(bool isOp) { |
|
180 fOperand = isOp; |
|
181 } |
|
182 |
|
183 void setOppXor(bool isOppXor) { |
|
184 fOppXor = isOppXor; |
|
185 int segmentCount = fSegments.count(); |
|
186 for (int test = 0; test < segmentCount; ++test) { |
|
187 fSegments[test].setOppXor(isOppXor); |
|
188 } |
|
189 } |
|
190 |
|
191 void setXor(bool isXor) { |
|
192 fXor = isXor; |
|
193 } |
|
194 |
|
195 void sortSegments(); |
|
196 |
|
197 const SkPoint& start() const { |
|
198 return fSegments.front().pts()[0]; |
|
199 } |
|
200 |
|
201 void toPath(SkPathWriter* path) const; |
|
202 |
|
203 void toPartialBackward(SkPathWriter* path) const { |
|
204 int segmentCount = fSegments.count(); |
|
205 for (int test = segmentCount - 1; test >= 0; --test) { |
|
206 fSegments[test].addCurveTo(1, 0, path, true); |
|
207 } |
|
208 } |
|
209 |
|
210 void toPartialForward(SkPathWriter* path) const { |
|
211 int segmentCount = fSegments.count(); |
|
212 for (int test = 0; test < segmentCount; ++test) { |
|
213 fSegments[test].addCurveTo(0, 1, path, true); |
|
214 } |
|
215 } |
|
216 |
|
217 void topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY, SkOpSegment** topStart); |
|
218 SkOpSegment* undoneSegment(int* start, int* end); |
|
219 |
|
220 int updateSegment(int index, const SkPoint* pts) { |
|
221 SkOpSegment& segment = fSegments[index]; |
|
222 segment.updatePts(pts); |
|
223 return SkPathOpsVerbToPoints(segment.verb()) + 1; |
|
224 } |
|
225 |
|
226 #if DEBUG_TEST |
|
227 SkTArray<SkOpSegment>& debugSegments() { |
|
228 return fSegments; |
|
229 } |
|
230 #endif |
|
231 |
|
232 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY |
|
233 void debugShowActiveSpans() { |
|
234 for (int index = 0; index < fSegments.count(); ++index) { |
|
235 fSegments[index].debugShowActiveSpans(); |
|
236 } |
|
237 } |
|
238 #endif |
|
239 |
|
240 #if DEBUG_SHOW_WINDING |
|
241 int debugShowWindingValues(int totalSegments, int ofInterest); |
|
242 static void debugShowWindingValues(const SkTArray<SkOpContour*, true>& contourList); |
|
243 #endif |
|
244 |
|
245 private: |
|
246 void calcCommonCoincidentWinding(const SkCoincidence& ); |
|
247 void joinCoincidence(const SkTArray<SkCoincidence, true>& , bool partial); |
|
248 void setBounds(); |
|
249 |
|
250 SkTArray<SkOpSegment> fSegments; |
|
251 SkTArray<SkOpSegment*, true> fSortedSegments; |
|
252 int fFirstSorted; |
|
253 SkTArray<SkCoincidence, true> fCoincidences; |
|
254 SkTArray<SkCoincidence, true> fPartialCoincidences; |
|
255 SkTArray<const SkOpContour*, true> fCrosses; |
|
256 SkPathOpsBounds fBounds; |
|
257 bool fContainsIntercepts; // FIXME: is this used by anybody? |
|
258 bool fContainsCubics; |
|
259 bool fContainsCurves; |
|
260 bool fDone; |
|
261 bool fOperand; // true for the second argument to a binary operator |
|
262 bool fXor; |
|
263 bool fOppXor; |
|
264 #ifdef SK_DEBUG |
|
265 int fID; |
|
266 #endif |
|
267 }; |
|
268 |
|
269 #endif |