SkIntersectionHelper.h revision d998bec91855b8830b01db2d2caf155ab077b91b
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright 2012 Google Inc.
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Use of this source code is governed by a BSD-style license that can be
58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * found in the LICENSE file.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt */
7c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#include "SkOpContour.h"
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "SkPath.h"
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef SK_DEBUG
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "SkPathOpsPoint.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtclass SkIntersectionHelper {
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtpublic:
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    enum SegmentType {
17b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt        kHorizontalLine_Segment = -1,
18cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt        kVerticalLine_Segment = 0,
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        kLine_Segment = SkPath::kLine_Verb,
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        kQuad_Segment = SkPath::kQuad_Verb,
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        kCubic_Segment = SkPath::kCubic_Verb,
221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt    };
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    bool addCoincident(SkIntersectionHelper& other, const SkIntersections& ts, bool swap) {
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap);
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // FIXME: does it make sense to write otherIndex now if we're going to
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // fix it up later?
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    void addOtherT(int index, double otherT, int otherIndex) {
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        fContour->addOtherT(fIndex, index, otherT, otherIndex);
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    bool addPartialCoincident(SkIntersectionHelper& other, const SkIntersections& ts, int index,
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            bool swap) {
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return fContour->addPartialCoincident(fIndex, other.fContour, other.fIndex, ts, index,
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt                swap);
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // Avoid collapsing t values that are close to the same since
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // we walk ts to describe consecutive intersections. Since a pair of ts can
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // be nearly equal, any problems caused by this should be taken care
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // of later.
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    // On the edge or out of range values are negative; add 2 to get end
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    int addT(const SkIntersectionHelper& other, const SkPoint& pt, double newT, bool isNear) {
4668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt        return fContour->addT(fIndex, other.fContour, other.fIndex, pt, newT, isNear);
4768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt    }
4868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
4968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt    int addSelfT(const SkIntersectionHelper& other, const SkPoint& pt, double newT) {
5068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt        return fContour->addSelfT(fIndex, other.fContour, other.fIndex, pt, newT);
5168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt    }
5268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
5368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt    bool advance() {
5468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt        return ++fIndex < fLast;
5568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt    }
5668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
5768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt    SkScalar bottom() const {
5868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt        return bounds().fBottom;
5968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt    }
6068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
6168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt    const SkPathOpsBounds& bounds() const {
6268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt        return fContour->segments()[fIndex].bounds();
6368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt    }
6468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
6568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt    void init(SkOpContour* contour) {
6668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt        fContour = contour;
6768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt        fIndex = 0;
6868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt        fLast = contour->segments().count();
6968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt    }
7068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
7168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt    bool isAdjacent(const SkIntersectionHelper& next) {
7268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt        return fContour == next.fContour && fIndex + 1 == next.fIndex;
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    bool isFirstLast(const SkIntersectionHelper& next) {
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return fContour == next.fContour && fIndex == 0
77cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt                && next.fIndex == fLast - 1;
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    bool isNear(double t1, double t2, const SkDPoint& pt1, const SkDPoint& pt2) const {
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        const SkOpSegment& segment = fContour->segments()[fIndex];
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        double mid = (t1 + t2) / 2;
83b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt        SkDPoint midPtByT = segment.dPtAtT(mid);
84b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt        SkDPoint midPtByAvg = SkDPoint::Mid(pt1, pt2);
85b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt        return midPtByT.approximatelyEqual(midPtByAvg);
86b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt    }
87b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
88b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt    bool isPartial(double t1, double t2, const SkDPoint& pt1, const SkDPoint& pt2) const {
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        const SkOpSegment& segment = fContour->segments()[fIndex];
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        double mid = (t1 + t2) / 2;
91c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt        SkDPoint midPtByT = segment.dPtAtT(mid);
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        SkDPoint midPtByAvg = SkDPoint::Mid(pt1, pt2);
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        return midPtByT.approximatelyPEqual(midPtByAvg);
94c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt    }
95c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt
961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt    SkScalar left() const {
971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt        return bounds().fLeft;
98c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt    }
991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
100c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt    const SkPoint* pts() const {
1011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt        return fContour->segments()[fIndex].pts();
102c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt    }
10304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
1041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt    SkScalar right() const {
1051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt        return bounds().fRight;
1061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt    }
107c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt
108c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt    SegmentType segmentType() const {
109c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt        const SkOpSegment& segment = fContour->segments()[fIndex];
11004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        SegmentType type = (SegmentType) segment.verb();
11104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        if (type != kLine_Segment) {
11204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            return type;
11304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        }
11404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        if (segment.isHorizontal()) {
11504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            return kHorizontalLine_Segment;
11604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        }
11704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        if (segment.isVertical()) {
11804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt            return kVerticalLine_Segment;
11904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt        }
120c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt        return kLine_Segment;
12161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    }
12261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
12361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    bool startAfter(const SkIntersectionHelper& after) {
12461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        fIndex = after.fIndex;
12561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        return advance();
12661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    }
12761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
12861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    SkScalar top() const {
12961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt        return bounds().fTop;
13061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    }
13161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
13261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt    SkPath::Verb verb() const {
1331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt        return fContour->segments()[fIndex].verb();
1341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt    }
1351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt    SkScalar x() const {
1371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt        return bounds().fLeft;
1381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt    }
1391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt    bool xFlipped() const {
1411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt        return x() != pts()[0].fX;
1421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt    }
1431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt    SkScalar y() const {
14568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt        return bounds().fTop;
14668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt    }
14768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
14868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt    bool yFlipped() const {
14968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt        return y() != pts()[0].fY;
1501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt    }
151c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt
152c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt#ifdef SK_DEBUG
153c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt    void dump() {
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        SkDPoint::dump(pts()[0]);
15534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt        SkDPoint::dump(pts()[1]);
15634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt        if (verb() >= SkPath::kQuad_Verb) {
15734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt            SkDPoint::dump(pts()[2]);
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        if (verb() >= SkPath::kCubic_Verb) {
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt            SkDPoint::dump(pts()[3]);
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt        }
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    }
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtprivate:
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    SkOpContour* fContour;
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    int fIndex;
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    int fLast;
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt