2 * Copyright 2013 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
7 #ifndef SkOpContour_DEFINED
8 #define SkOpContour_DEFINED
10 #include "SkOpSegment.h"
13 #if defined(SK_DEBUG) || !FORCE_RELEASE
17 class SkIntersections;
21 struct SkCoincidence {
33 #if defined(SK_DEBUG) || !FORCE_RELEASE
34 fID = sk_atomic_inc(&SkPathOpsDebug::gContourID);
38 bool operator<(const SkOpContour& rh) const {
39 return fBounds.fTop == rh.fBounds.fTop
40 ? fBounds.fLeft < rh.fBounds.fLeft
41 : fBounds.fTop < rh.fBounds.fTop;
44 bool addCoincident(int index, SkOpContour* other, int otherIndex,
45 const SkIntersections& ts, bool swap);
46 void addCoincidentPoints();
48 void addCross(const SkOpContour* crosser) {
50 for (int index = 0; index < fCrosses.count(); ++index) {
51 SkASSERT(fCrosses[index] != crosser);
54 fCrosses.push_back(crosser);
57 void addCubic(const SkPoint pts[4]) {
58 fSegments.push_back().addCubic(pts, fOperand, fXor);
59 fContainsCurves = fContainsCubics = true;
62 int addLine(const SkPoint pts[2]) {
63 fSegments.push_back().addLine(pts, fOperand, fXor);
64 return fSegments.count();
67 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
68 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
71 bool addPartialCoincident(int index, SkOpContour* other, int otherIndex,
72 const SkIntersections& ts, int ptIndex, bool swap);
74 int addQuad(const SkPoint pts[3]) {
75 fSegments.push_back().addQuad(pts, fOperand, fXor);
76 fContainsCurves = true;
77 return fSegments.count();
80 int addT(int segIndex, SkOpContour* other, int otherIndex, const SkPoint& pt, double newT) {
81 setContainsIntercepts();
82 return fSegments[segIndex].addT(&other->fSegments[otherIndex], pt, newT);
85 int addSelfT(int segIndex, const SkPoint& pt, double newT) {
86 setContainsIntercepts();
87 return fSegments[segIndex].addSelfT(pt, newT);
90 void align(const SkOpSegment::AlignedSpan& aligned, bool swap, SkCoincidence* coincidence);
91 void alignCoincidence(const SkOpSegment::AlignedSpan& aligned,
92 SkTArray<SkCoincidence, true>* coincidences);
94 void alignCoincidence(const SkOpSegment::AlignedSpan& aligned) {
95 alignCoincidence(aligned, &fCoincidences);
96 alignCoincidence(aligned, &fPartialCoincidences);
99 void alignMultiples(SkTDArray<SkOpSegment::AlignedSpan>* aligned) {
100 int segmentCount = fSegments.count();
101 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
102 SkOpSegment& segment = fSegments[sIndex];
103 if (segment.hasMultiples()) {
104 segment.alignMultiples(aligned);
109 void alignTPt(int segmentIndex, const SkOpContour* other, int otherIndex,
110 bool swap, int tIndex, SkIntersections* ts, SkPoint* point) const;
112 const SkPathOpsBounds& bounds() const {
117 bool calcCoincidentWinding();
118 void calcPartialCoincidentWinding();
120 void checkDuplicates() {
121 int segmentCount = fSegments.count();
122 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
123 SkOpSegment& segment = fSegments[sIndex];
124 if (segment.count() > 2) {
125 segment.checkDuplicates();
131 if (!fContainsCurves) {
134 int segmentCount = fSegments.count();
135 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
136 SkOpSegment* segment = &fSegments[sIndex];
137 if (segment->verb() == SkPath::kLine_Verb) {
140 if (segment->done()) {
141 continue; // likely coincident, nothing to do
143 segment->checkEnds();
147 void checkMultiples() {
148 int segmentCount = fSegments.count();
149 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
150 SkOpSegment& segment = fSegments[sIndex];
151 if (segment.count() > 2) {
152 segment.checkMultiples();
153 fMultiples |= segment.hasMultiples();
159 int segmentCount = fSegments.count();
160 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
161 SkOpSegment& segment = fSegments[sIndex];
162 // OPTIMIZATION : skip segments that are done?
163 if (segment.hasSmall()) {
164 segment.checkSmall();
169 // if same point has different T values, choose a common T
171 int segmentCount = fSegments.count();
172 if (segmentCount <= 2) {
175 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
176 SkOpSegment& segment = fSegments[sIndex];
177 if (segment.hasTiny()) {
185 fContainsIntercepts = false;
188 bool containsCubics() const {
189 return fContainsCubics;
192 bool crosses(const SkOpContour* crosser) const {
193 for (int index = 0; index < fCrosses.count(); ++index) {
194 if (fCrosses[index] == crosser) {
205 const SkPoint& end() const {
206 const SkOpSegment& segment = fSegments.back();
207 return segment.pts()[SkPathOpsVerbToPoints(segment.verb())];
210 void fixOtherTIndex() {
211 int segmentCount = fSegments.count();
212 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
213 fSegments[sIndex].fixOtherTIndex();
217 bool hasMultiples() const {
221 void joinCoincidence() {
222 joinCoincidence(fCoincidences, false);
223 joinCoincidence(fPartialCoincidences, true);
226 SkOpSegment* nonVerticalSegment(int* start, int* end);
228 bool operand() const {
234 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
235 fContainsCurves = fContainsCubics = fContainsIntercepts = fDone = fMultiples = false;
238 void resolveNearCoincidence();
240 SkTArray<SkOpSegment>& segments() {
244 void setContainsIntercepts() {
245 fContainsIntercepts = true;
248 void setOperand(bool isOp) {
252 void setOppXor(bool isOppXor) {
254 int segmentCount = fSegments.count();
255 for (int test = 0; test < segmentCount; ++test) {
256 fSegments[test].setOppXor(isOppXor);
260 void setXor(bool isXor) {
267 const SkPoint& start() const {
268 return fSegments.front().pts()[0];
271 void toPath(SkPathWriter* path) const;
273 void toPartialBackward(SkPathWriter* path) const {
274 int segmentCount = fSegments.count();
275 for (int test = segmentCount - 1; test >= 0; --test) {
276 fSegments[test].addCurveTo(1, 0, path, true);
280 void toPartialForward(SkPathWriter* path) const {
281 int segmentCount = fSegments.count();
282 for (int test = 0; test < segmentCount; ++test) {
283 fSegments[test].addCurveTo(0, 1, path, true);
287 void topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY, SkOpSegment** topStart);
288 SkOpSegment* undoneSegment(int* start, int* end);
290 int updateSegment(int index, const SkPoint* pts) {
291 SkOpSegment& segment = fSegments[index];
292 segment.updatePts(pts);
293 return SkPathOpsVerbToPoints(segment.verb()) + 1;
297 SkTArray<SkOpSegment>& debugSegments() {
302 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
303 void debugShowActiveSpans() {
304 for (int index = 0; index < fSegments.count(); ++index) {
305 fSegments[index].debugShowActiveSpans();
310 #if DEBUG_SHOW_WINDING
311 int debugShowWindingValues(int totalSegments, int ofInterest);
312 static void debugShowWindingValues(const SkTArray<SkOpContour*, true>& contourList);
315 // available to test routines only
317 void dumpAngles() const;
318 void dumpCoincidence(const SkCoincidence& ) const;
319 void dumpCoincidences() const;
320 void dumpPt(int ) const;
321 void dumpPts() const;
322 void dumpSpan(int ) const;
323 void dumpSpans() const;
326 void alignPt(int index, SkPoint* point, int zeroPt) const;
327 int alignT(bool swap, int tIndex, SkIntersections* ts) const;
328 bool calcCommonCoincidentWinding(const SkCoincidence& );
329 void checkCoincidentPair(const SkCoincidence& oneCoin, int oneIdx,
330 const SkCoincidence& twoCoin, int twoIdx, bool partial);
331 void joinCoincidence(const SkTArray<SkCoincidence, true>& , bool partial);
334 SkTArray<SkOpSegment> fSegments;
335 SkTArray<SkOpSegment*, true> fSortedSegments;
337 SkTArray<SkCoincidence, true> fCoincidences;
338 SkTArray<SkCoincidence, true> fPartialCoincidences;
339 SkTArray<const SkOpContour*, true> fCrosses;
340 SkPathOpsBounds fBounds;
341 bool fContainsIntercepts; // FIXME: is this used by anybody?
342 bool fContainsCubics;
343 bool fContainsCurves;
345 bool fMultiples; // set if some segment has multiple identical intersections with other curves
346 bool fOperand; // true for the second argument to a binary operator
349 #if defined(SK_DEBUG) || !FORCE_RELEASE
350 int debugID() const { return fID; }
353 int debugID() const { return -1; }