SkIntersectionHelper.h revision d998bec91855b8830b01db2d2caf155ab077b91b
1/*
2 * Copyright 2012 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#include "SkOpContour.h"
8#include "SkPath.h"
9
10#ifdef SK_DEBUG
11#include "SkPathOpsPoint.h"
12#endif
13
14class SkIntersectionHelper {
15public:
16    enum SegmentType {
17        kHorizontalLine_Segment = -1,
18        kVerticalLine_Segment = 0,
19        kLine_Segment = SkPath::kLine_Verb,
20        kQuad_Segment = SkPath::kQuad_Verb,
21        kCubic_Segment = SkPath::kCubic_Verb,
22    };
23
24    bool addCoincident(SkIntersectionHelper& other, const SkIntersections& ts, bool swap) {
25        return fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap);
26    }
27
28    // FIXME: does it make sense to write otherIndex now if we're going to
29    // fix it up later?
30    void addOtherT(int index, double otherT, int otherIndex) {
31        fContour->addOtherT(fIndex, index, otherT, otherIndex);
32    }
33
34    bool addPartialCoincident(SkIntersectionHelper& other, const SkIntersections& ts, int index,
35            bool swap) {
36        return fContour->addPartialCoincident(fIndex, other.fContour, other.fIndex, ts, index,
37                swap);
38    }
39
40    // Avoid collapsing t values that are close to the same since
41    // we walk ts to describe consecutive intersections. Since a pair of ts can
42    // be nearly equal, any problems caused by this should be taken care
43    // of later.
44    // On the edge or out of range values are negative; add 2 to get end
45    int addT(const SkIntersectionHelper& other, const SkPoint& pt, double newT, bool isNear) {
46        return fContour->addT(fIndex, other.fContour, other.fIndex, pt, newT, isNear);
47    }
48
49    int addSelfT(const SkIntersectionHelper& other, const SkPoint& pt, double newT) {
50        return fContour->addSelfT(fIndex, other.fContour, other.fIndex, pt, newT);
51    }
52
53    bool advance() {
54        return ++fIndex < fLast;
55    }
56
57    SkScalar bottom() const {
58        return bounds().fBottom;
59    }
60
61    const SkPathOpsBounds& bounds() const {
62        return fContour->segments()[fIndex].bounds();
63    }
64
65    void init(SkOpContour* contour) {
66        fContour = contour;
67        fIndex = 0;
68        fLast = contour->segments().count();
69    }
70
71    bool isAdjacent(const SkIntersectionHelper& next) {
72        return fContour == next.fContour && fIndex + 1 == next.fIndex;
73    }
74
75    bool isFirstLast(const SkIntersectionHelper& next) {
76        return fContour == next.fContour && fIndex == 0
77                && next.fIndex == fLast - 1;
78    }
79
80    bool isNear(double t1, double t2, const SkDPoint& pt1, const SkDPoint& pt2) const {
81        const SkOpSegment& segment = fContour->segments()[fIndex];
82        double mid = (t1 + t2) / 2;
83        SkDPoint midPtByT = segment.dPtAtT(mid);
84        SkDPoint midPtByAvg = SkDPoint::Mid(pt1, pt2);
85        return midPtByT.approximatelyEqual(midPtByAvg);
86    }
87
88    bool isPartial(double t1, double t2, const SkDPoint& pt1, const SkDPoint& pt2) const {
89        const SkOpSegment& segment = fContour->segments()[fIndex];
90        double mid = (t1 + t2) / 2;
91        SkDPoint midPtByT = segment.dPtAtT(mid);
92        SkDPoint midPtByAvg = SkDPoint::Mid(pt1, pt2);
93        return midPtByT.approximatelyPEqual(midPtByAvg);
94    }
95
96    SkScalar left() const {
97        return bounds().fLeft;
98    }
99
100    const SkPoint* pts() const {
101        return fContour->segments()[fIndex].pts();
102    }
103
104    SkScalar right() const {
105        return bounds().fRight;
106    }
107
108    SegmentType segmentType() const {
109        const SkOpSegment& segment = fContour->segments()[fIndex];
110        SegmentType type = (SegmentType) segment.verb();
111        if (type != kLine_Segment) {
112            return type;
113        }
114        if (segment.isHorizontal()) {
115            return kHorizontalLine_Segment;
116        }
117        if (segment.isVertical()) {
118            return kVerticalLine_Segment;
119        }
120        return kLine_Segment;
121    }
122
123    bool startAfter(const SkIntersectionHelper& after) {
124        fIndex = after.fIndex;
125        return advance();
126    }
127
128    SkScalar top() const {
129        return bounds().fTop;
130    }
131
132    SkPath::Verb verb() const {
133        return fContour->segments()[fIndex].verb();
134    }
135
136    SkScalar x() const {
137        return bounds().fLeft;
138    }
139
140    bool xFlipped() const {
141        return x() != pts()[0].fX;
142    }
143
144    SkScalar y() const {
145        return bounds().fTop;
146    }
147
148    bool yFlipped() const {
149        return y() != pts()[0].fY;
150    }
151
152#ifdef SK_DEBUG
153    void dump() {
154        SkDPoint::dump(pts()[0]);
155        SkDPoint::dump(pts()[1]);
156        if (verb() >= SkPath::kQuad_Verb) {
157            SkDPoint::dump(pts()[2]);
158        }
159        if (verb() >= SkPath::kCubic_Verb) {
160            SkDPoint::dump(pts()[3]);
161        }
162    }
163#endif
164
165private:
166    SkOpContour* fContour;
167    int fIndex;
168    int fLast;
169};
170