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