michael@0: /* michael@0: * Copyright 2012 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: #include "SkOpContour.h" michael@0: #include "SkPath.h" michael@0: michael@0: #ifdef SK_DEBUG michael@0: #include "SkPathOpsPoint.h" michael@0: #endif michael@0: michael@0: class SkIntersectionHelper { michael@0: public: michael@0: enum SegmentType { michael@0: kHorizontalLine_Segment = -1, michael@0: kVerticalLine_Segment = 0, michael@0: kLine_Segment = SkPath::kLine_Verb, michael@0: kQuad_Segment = SkPath::kQuad_Verb, michael@0: kCubic_Segment = SkPath::kCubic_Verb, michael@0: }; michael@0: michael@0: bool addCoincident(SkIntersectionHelper& other, const SkIntersections& ts, bool swap) { michael@0: return fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap); michael@0: } michael@0: michael@0: // FIXME: does it make sense to write otherIndex now if we're going to michael@0: // fix it up later? michael@0: void addOtherT(int index, double otherT, int otherIndex) { michael@0: fContour->addOtherT(fIndex, index, otherT, otherIndex); michael@0: } michael@0: michael@0: bool addPartialCoincident(SkIntersectionHelper& other, const SkIntersections& ts, int index, michael@0: bool swap) { michael@0: return fContour->addPartialCoincident(fIndex, other.fContour, other.fIndex, ts, index, michael@0: swap); michael@0: } michael@0: michael@0: // Avoid collapsing t values that are close to the same since michael@0: // we walk ts to describe consecutive intersections. Since a pair of ts can michael@0: // be nearly equal, any problems caused by this should be taken care michael@0: // of later. michael@0: // On the edge or out of range values are negative; add 2 to get end michael@0: int addT(const SkIntersectionHelper& other, const SkPoint& pt, double newT) { michael@0: return fContour->addT(fIndex, other.fContour, other.fIndex, pt, newT); michael@0: } michael@0: michael@0: int addSelfT(const SkIntersectionHelper& other, const SkPoint& pt, double newT) { michael@0: return fContour->addSelfT(fIndex, other.fContour, other.fIndex, pt, newT); michael@0: } michael@0: michael@0: bool advance() { michael@0: return ++fIndex < fLast; michael@0: } michael@0: michael@0: SkScalar bottom() const { michael@0: return bounds().fBottom; michael@0: } michael@0: michael@0: const SkPathOpsBounds& bounds() const { michael@0: return fContour->segments()[fIndex].bounds(); michael@0: } michael@0: michael@0: void init(SkOpContour* contour) { michael@0: fContour = contour; michael@0: fIndex = 0; michael@0: fLast = contour->segments().count(); michael@0: } michael@0: michael@0: bool isAdjacent(const SkIntersectionHelper& next) { michael@0: return fContour == next.fContour && fIndex + 1 == next.fIndex; michael@0: } michael@0: michael@0: bool isFirstLast(const SkIntersectionHelper& next) { michael@0: return fContour == next.fContour && fIndex == 0 michael@0: && next.fIndex == fLast - 1; michael@0: } michael@0: michael@0: bool isPartial(double t1, double t2, const SkDPoint& pt1, const SkDPoint& pt2) const { michael@0: const SkOpSegment& segment = fContour->segments()[fIndex]; michael@0: double mid = (t1 + t2) / 2; michael@0: SkDPoint midPtByT = segment.dPtAtT(mid); michael@0: SkDPoint midPtByAvg = SkDPoint::Mid(pt1, pt2); michael@0: return midPtByT.approximatelyPEqual(midPtByAvg); michael@0: } michael@0: michael@0: SkScalar left() const { michael@0: return bounds().fLeft; michael@0: } michael@0: michael@0: const SkPoint* pts() const { michael@0: return fContour->segments()[fIndex].pts(); michael@0: } michael@0: michael@0: SkScalar right() const { michael@0: return bounds().fRight; michael@0: } michael@0: michael@0: SegmentType segmentType() const { michael@0: const SkOpSegment& segment = fContour->segments()[fIndex]; michael@0: SegmentType type = (SegmentType) segment.verb(); michael@0: if (type != kLine_Segment) { michael@0: return type; michael@0: } michael@0: if (segment.isHorizontal()) { michael@0: return kHorizontalLine_Segment; michael@0: } michael@0: if (segment.isVertical()) { michael@0: return kVerticalLine_Segment; michael@0: } michael@0: return kLine_Segment; michael@0: } michael@0: michael@0: bool startAfter(const SkIntersectionHelper& after) { michael@0: fIndex = after.fIndex; michael@0: return advance(); michael@0: } michael@0: michael@0: SkScalar top() const { michael@0: return bounds().fTop; michael@0: } michael@0: michael@0: SkPath::Verb verb() const { michael@0: return fContour->segments()[fIndex].verb(); michael@0: } michael@0: michael@0: SkScalar x() const { michael@0: return bounds().fLeft; michael@0: } michael@0: michael@0: bool xFlipped() const { michael@0: return x() != pts()[0].fX; michael@0: } michael@0: michael@0: SkScalar y() const { michael@0: return bounds().fTop; michael@0: } michael@0: michael@0: bool yFlipped() const { michael@0: return y() != pts()[0].fY; michael@0: } michael@0: michael@0: #ifdef SK_DEBUG michael@0: void dump() { michael@0: SkDPoint::dump(pts()[0]); michael@0: SkDPoint::dump(pts()[1]); michael@0: if (verb() >= SkPath::kQuad_Verb) { michael@0: SkDPoint::dump(pts()[2]); michael@0: } michael@0: if (verb() >= SkPath::kCubic_Verb) { michael@0: SkDPoint::dump(pts()[3]); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: private: michael@0: SkOpContour* fContour; michael@0: int fIndex; michael@0: int fLast; michael@0: };