107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com/*
207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com * Copyright 2012 Google Inc.
307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com *
407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com * Use of this source code is governed by a BSD-style license that can be
507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com * found in the LICENSE file.
607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com */
707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#include "SkOpContour.h"
807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com#include "SkPath.h"
907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
10d998bec91855b8830b01db2d2caf155ab077b91brobertphillips@google.com#ifdef SK_DEBUG
11a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com#include "SkPathOpsPoint.h"
12a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com#endif
13a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com
1407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comclass SkIntersectionHelper {
1507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.compublic:
1607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    enum SegmentType {
1707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        kHorizontalLine_Segment = -1,
1807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        kVerticalLine_Segment = 0,
1907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        kLine_Segment = SkPath::kLine_Verb,
2007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        kQuad_Segment = SkPath::kQuad_Verb,
2107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        kCubic_Segment = SkPath::kCubic_Verb,
2207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    };
2307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
247eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    bool addCoincident(SkIntersectionHelper& other, const SkIntersections& ts, bool swap) {
257eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        return fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap);
2607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
2707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
2807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // FIXME: does it make sense to write otherIndex now if we're going to
2907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // fix it up later?
3007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    void addOtherT(int index, double otherT, int otherIndex) {
3107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        fContour->addOtherT(fIndex, index, otherT, otherIndex);
3207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
3307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
347eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com    bool addPartialCoincident(SkIntersectionHelper& other, const SkIntersections& ts, int index,
35570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com            bool swap) {
367eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com        return fContour->addPartialCoincident(fIndex, other.fContour, other.fIndex, ts, index,
377eaa53d8f7e48fd17d02b5e3bd91f90e9c1899efcaryclark@google.com                swap);
38570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com    }
39570863f2e22b8ea7d7c504bd15e4f766af097df2caryclark@google.com
4007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // Avoid collapsing t values that are close to the same since
4107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // we walk ts to describe consecutive intersections. Since a pair of ts can
4207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // be nearly equal, any problems caused by this should be taken care
4307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // of later.
4407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    // On the edge or out of range values are negative; add 2 to get end
45866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org    int addT(const SkIntersectionHelper& other, const SkPoint& pt, double newT) {
46866f4e34a943c115ac372c22123a1520aa5f9b06commit-bot@chromium.org        return fContour->addT(fIndex, other.fContour, other.fIndex, pt, newT);
4707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
4807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
494431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    int addSelfT(const SkPoint& pt, double newT) {
504431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org        return fContour->addSelfT(fIndex, pt, newT);
5107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
5207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
5307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    bool advance() {
5407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return ++fIndex < fLast;
5507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
5607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
57dac1d17027dcaa5596885a9f333979418b35001ccaryclark    void alignTPt(SkIntersectionHelper& other, bool swap, int index,
58dac1d17027dcaa5596885a9f333979418b35001ccaryclark            SkIntersections* ts, SkPoint* point) {
59dac1d17027dcaa5596885a9f333979418b35001ccaryclark        fContour->alignTPt(fIndex, other.fContour, other.fIndex, swap, index, ts, point);
60dac1d17027dcaa5596885a9f333979418b35001ccaryclark    }
61dac1d17027dcaa5596885a9f333979418b35001ccaryclark
6207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkScalar bottom() const {
6307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return bounds().fBottom;
6407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
6507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
6607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    const SkPathOpsBounds& bounds() const {
6707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return fContour->segments()[fIndex].bounds();
6807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
6907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
7007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    void init(SkOpContour* contour) {
7107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        fContour = contour;
7207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        fIndex = 0;
7307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        fLast = contour->segments().count();
7407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
7507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
7607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    bool isAdjacent(const SkIntersectionHelper& next) {
7707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return fContour == next.fContour && fIndex + 1 == next.fIndex;
7807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
7907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
8007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    bool isFirstLast(const SkIntersectionHelper& next) {
8107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return fContour == next.fContour && fIndex == 0
8207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com                && next.fIndex == fLast - 1;
8307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
8407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
85a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    bool isPartial(double t1, double t2, const SkDPoint& pt1, const SkDPoint& pt2) const {
86a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        const SkOpSegment& segment = fContour->segments()[fIndex];
87a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        double mid = (t1 + t2) / 2;
88a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        SkDPoint midPtByT = segment.dPtAtT(mid);
89a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        SkDPoint midPtByAvg = SkDPoint::Mid(pt1, pt2);
90a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com        return midPtByT.approximatelyPEqual(midPtByAvg);
91a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com    }
92a2bbc6e19d5332e81784e582c290cc060f40c4c7caryclark@google.com
9307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkScalar left() const {
9407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return bounds().fLeft;
9507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
9607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
9707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    const SkPoint* pts() const {
9807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return fContour->segments()[fIndex].pts();
9907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
10007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
10107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkScalar right() const {
10207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return bounds().fRight;
10307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
10407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
10507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SegmentType segmentType() const {
10607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        const SkOpSegment& segment = fContour->segments()[fIndex];
10707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        SegmentType type = (SegmentType) segment.verb();
10807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (type != kLine_Segment) {
10907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            return type;
11007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
11107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (segment.isHorizontal()) {
11207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            return kHorizontalLine_Segment;
11307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
11407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        if (segment.isVertical()) {
11507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com            return kVerticalLine_Segment;
11607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        }
11707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return kLine_Segment;
11807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
11907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
12007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    bool startAfter(const SkIntersectionHelper& after) {
12107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        fIndex = after.fIndex;
12207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return advance();
12307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
12407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
12507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkScalar top() const {
12607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return bounds().fTop;
12707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
12807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
12907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkPath::Verb verb() const {
13007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return fContour->segments()[fIndex].verb();
13107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
13207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
13307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkScalar x() const {
13407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return bounds().fLeft;
13507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
13607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
13707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    bool xFlipped() const {
13807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return x() != pts()[0].fX;
13907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
14007393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
14107393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkScalar y() const {
14207393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return bounds().fTop;
14307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
14407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
14507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    bool yFlipped() const {
14607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com        return y() != pts()[0].fY;
14707393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    }
14807393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com
14907393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.comprivate:
1504431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    // utility callable by the user from the debugger when the implementation code is linked in
1514431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org    void dump() const;
1524431e7757cfcb8cfa99535eed0e9f156dabf95c2commit-bot@chromium.org
15307393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    SkOpContour* fContour;
15407393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int fIndex;
15507393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com    int fLast;
15607393cab57ce74a4aae89a31fae9aaa9780fc19dcaryclark@google.com};
157