| Index: src/pathops/SkAddIntersections.cpp
|
| ===================================================================
|
| --- src/pathops/SkAddIntersections.cpp (revision 0)
|
| +++ src/pathops/SkAddIntersections.cpp (revision 0)
|
| @@ -0,0 +1,433 @@
|
| +/*
|
| + * 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 "SkAddIntersections.h"
|
| +#include "SkPathOpsBounds.h"
|
| +
|
| +#if DEBUG_ADD_INTERSECTING_TS
|
| +
|
| +static void debugShowLineIntersection(int pts, const SkIntersectionHelper& wt,
|
| + const SkIntersectionHelper& wn, const SkIntersections& i) {
|
| + SkASSERT(i.used() == pts);
|
| + if (!pts) {
|
| + SkDebugf("%s no intersect " LINE_DEBUG_STR " " LINE_DEBUG_STR "\n",
|
| + __FUNCTION__, LINE_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
|
| + return;
|
| + }
|
| + SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " LINE_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
|
| + i[0][0], LINE_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
|
| + if (pts == 2) {
|
| + SkDebugf(" " T_DEBUG_STR(wtTs, 1) " " PT_DEBUG_STR, i[0][1], PT_DEBUG_DATA(i, 1));
|
| + }
|
| + SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i[1][0], LINE_DEBUG_DATA(wn.pts()));
|
| + if (pts == 2) {
|
| + SkDebugf(" " T_DEBUG_STR(wnTs, 1), i[1][1]);
|
| + }
|
| + SkDebugf("\n");
|
| +}
|
| +
|
| +static void debugShowQuadLineIntersection(int pts, const SkIntersectionHelper& wt,
|
| + const SkIntersectionHelper& wn,
|
| + const SkIntersections& i) {
|
| + SkASSERT(i.used() == pts);
|
| + if (!pts) {
|
| + SkDebugf("%s no intersect " QUAD_DEBUG_STR " " LINE_DEBUG_STR "\n",
|
| + __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
|
| + return;
|
| + }
|
| + SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
|
| + i[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
|
| + for (int n = 1; n < pts; ++n) {
|
| + SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n));
|
| + }
|
| + SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i[1][0], LINE_DEBUG_DATA(wn.pts()));
|
| + for (int n = 1; n < pts; ++n) {
|
| + SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]);
|
| + }
|
| + SkDebugf("\n");
|
| +}
|
| +
|
| +static void debugShowQuadIntersection(int pts, const SkIntersectionHelper& wt,
|
| + const SkIntersectionHelper& wn, const SkIntersections& i) {
|
| + SkASSERT(i.used() == pts);
|
| + if (!pts) {
|
| + SkDebugf("%s no intersect " QUAD_DEBUG_STR " " QUAD_DEBUG_STR "\n",
|
| + __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts()));
|
| + return;
|
| + }
|
| + SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
|
| + i[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
|
| + for (int n = 1; n < pts; ++n) {
|
| + SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n));
|
| + }
|
| + SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i[1][0], QUAD_DEBUG_DATA(wn.pts()));
|
| + for (int n = 1; n < pts; ++n) {
|
| + SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]);
|
| + }
|
| + SkDebugf("\n");
|
| +}
|
| +
|
| +static void debugShowCubicLineIntersection(int pts, const SkIntersectionHelper& wt,
|
| + const SkIntersectionHelper& wn, const SkIntersections& i) {
|
| + SkASSERT(i.used() == pts);
|
| + if (!pts) {
|
| + SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " LINE_DEBUG_STR "\n",
|
| + __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts()));
|
| + return;
|
| + }
|
| + SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
|
| + i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
|
| + for (int n = 1; n < pts; ++n) {
|
| + SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n));
|
| + }
|
| + SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i[1][0], LINE_DEBUG_DATA(wn.pts()));
|
| + for (int n = 1; n < pts; ++n) {
|
| + SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]);
|
| + }
|
| + SkDebugf("\n");
|
| +}
|
| +
|
| +static void debugShowCubicQuadIntersection(int pts, const SkIntersectionHelper& wt,
|
| + const SkIntersectionHelper& wn, const SkIntersections& i) {
|
| + SkASSERT(i.used() == pts);
|
| + if (!pts) {
|
| + SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " QUAD_DEBUG_STR "\n",
|
| + __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts()));
|
| + return;
|
| + }
|
| + SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
|
| + i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
|
| + for (int n = 1; n < pts; ++n) {
|
| + SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n));
|
| + }
|
| + SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i[1][0], QUAD_DEBUG_DATA(wn.pts()));
|
| + for (int n = 1; n < pts; ++n) {
|
| + SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]);
|
| + }
|
| + SkDebugf("\n");
|
| +}
|
| +
|
| +static void debugShowCubicIntersection(int pts, const SkIntersectionHelper& wt,
|
| + const SkIntersectionHelper& wn, const SkIntersections& i) {
|
| + SkASSERT(i.used() == pts);
|
| + if (!pts) {
|
| + SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " CUBIC_DEBUG_STR "\n",
|
| + __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), CUBIC_DEBUG_DATA(wn.pts()));
|
| + return;
|
| + }
|
| + SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
|
| + i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
|
| + for (int n = 1; n < pts; ++n) {
|
| + SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_DATA(i, n));
|
| + }
|
| + SkDebugf(" wnTs[0]=%g " CUBIC_DEBUG_STR, i[1][0], CUBIC_DEBUG_DATA(wn.pts()));
|
| + for (int n = 1; n < pts; ++n) {
|
| + SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]);
|
| + }
|
| + SkDebugf("\n");
|
| +}
|
| +
|
| +static void debugShowCubicIntersection(int pts, const SkIntersectionHelper& wt, const SkIntersections& i) {
|
| + SkASSERT(i.used() == pts);
|
| + if (!pts) {
|
| + SkDebugf("%s no self intersect " CUBIC_DEBUG_STR "\n", __FUNCTION__,
|
| + CUBIC_DEBUG_DATA(wt.pts()));
|
| + return;
|
| + }
|
| + SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__,
|
| + i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0));
|
| + SkDebugf(" " T_DEBUG_STR(wtTs, 1), i[1][0]);
|
| + SkDebugf("\n");
|
| +}
|
| +
|
| +#else
|
| +static void debugShowLineIntersection(int , const SkIntersectionHelper& , const SkIntersectionHelper& , const SkIntersections& ) {
|
| +}
|
| +
|
| +static void debugShowQuadLineIntersection(int , const SkIntersectionHelper& , const SkIntersectionHelper& , const SkIntersections& ) {
|
| +}
|
| +
|
| +static void debugShowQuadIntersection(int , const SkIntersectionHelper& , const SkIntersectionHelper& , const SkIntersections& ) {
|
| +}
|
| +
|
| +static void debugShowCubicLineIntersection(int , const SkIntersectionHelper& , const SkIntersectionHelper& ,
|
| + const SkIntersections& ) {
|
| +}
|
| +
|
| +static void debugShowCubicQuadIntersection(int , const SkIntersectionHelper& , const SkIntersectionHelper& ,
|
| + const SkIntersections& ) {
|
| +}
|
| +
|
| +static void debugShowCubicIntersection(int , const SkIntersectionHelper& , const SkIntersectionHelper& , const SkIntersections& ) {
|
| +}
|
| +
|
| +static void debugShowCubicIntersection(int , const SkIntersectionHelper& , const SkIntersections& ) {
|
| +}
|
| +#endif
|
| +
|
| +bool AddIntersectTs(SkOpContour* test, SkOpContour* next) {
|
| +
|
| + if (test != next) {
|
| + if (test->bounds().fBottom < next->bounds().fTop) {
|
| + return false;
|
| + }
|
| + if (!SkPathOpsBounds::Intersects(test->bounds(), next->bounds())) {
|
| + return true;
|
| + }
|
| + }
|
| + SkIntersectionHelper wt;
|
| + wt.init(test);
|
| + bool foundCommonContour = test == next;
|
| + do {
|
| + SkIntersectionHelper wn;
|
| + wn.init(next);
|
| + if (test == next && !wn.startAfter(wt)) {
|
| + continue;
|
| + }
|
| + do {
|
| + if (!SkPathOpsBounds::Intersects(wt.bounds(), wn.bounds())) {
|
| + continue;
|
| + }
|
| + int pts;
|
| + SkIntersections ts;
|
| + bool swap = false;
|
| + switch (wt.segmentType()) {
|
| + case SkIntersectionHelper::kHorizontalLine_Segment:
|
| + swap = true;
|
| + switch (wn.segmentType()) {
|
| + case SkIntersectionHelper::kHorizontalLine_Segment:
|
| + case SkIntersectionHelper::kVerticalLine_Segment:
|
| + case SkIntersectionHelper::kLine_Segment: {
|
| + pts = ts.lineHorizontal(wn.pts(), wt.left(),
|
| + wt.right(), wt.y(), wt.xFlipped());
|
| + debugShowLineIntersection(pts, wt, wn, ts);
|
| + break;
|
| + }
|
| + case SkIntersectionHelper::kQuad_Segment: {
|
| + pts = ts.quadHorizontal(wn.pts(), wt.left(),
|
| + wt.right(), wt.y(), wt.xFlipped());
|
| + debugShowQuadLineIntersection(pts, wn, wt, ts);
|
| + break;
|
| + }
|
| + case SkIntersectionHelper::kCubic_Segment: {
|
| + pts = ts.cubicHorizontal(wn.pts(), wt.left(),
|
| + wt.right(), wt.y(), wt.xFlipped());
|
| + debugShowCubicLineIntersection(pts, wn, wt, ts);
|
| + break;
|
| + }
|
| + default:
|
| + SkASSERT(0);
|
| + }
|
| + break;
|
| + case SkIntersectionHelper::kVerticalLine_Segment:
|
| + swap = true;
|
| + switch (wn.segmentType()) {
|
| + case SkIntersectionHelper::kHorizontalLine_Segment:
|
| + case SkIntersectionHelper::kVerticalLine_Segment:
|
| + case SkIntersectionHelper::kLine_Segment: {
|
| + pts = ts.lineVertical(wn.pts(), wt.top(),
|
| + wt.bottom(), wt.x(), wt.yFlipped());
|
| + debugShowLineIntersection(pts, wt, wn, ts);
|
| + break;
|
| + }
|
| + case SkIntersectionHelper::kQuad_Segment: {
|
| + pts = ts.quadVertical(wn.pts(), wt.top(),
|
| + wt.bottom(), wt.x(), wt.yFlipped());
|
| + debugShowQuadLineIntersection(pts, wn, wt, ts);
|
| + break;
|
| + }
|
| + case SkIntersectionHelper::kCubic_Segment: {
|
| + pts = ts.cubicVertical(wn.pts(), wt.top(),
|
| + wt.bottom(), wt.x(), wt.yFlipped());
|
| + debugShowCubicLineIntersection(pts, wn, wt, ts);
|
| + break;
|
| + }
|
| + default:
|
| + SkASSERT(0);
|
| + }
|
| + break;
|
| + case SkIntersectionHelper::kLine_Segment:
|
| + switch (wn.segmentType()) {
|
| + case SkIntersectionHelper::kHorizontalLine_Segment:
|
| + pts = ts.lineHorizontal(wt.pts(), wn.left(),
|
| + wn.right(), wn.y(), wn.xFlipped());
|
| + debugShowLineIntersection(pts, wt, wn, ts);
|
| + break;
|
| + case SkIntersectionHelper::kVerticalLine_Segment:
|
| + pts = ts.lineVertical(wt.pts(), wn.top(),
|
| + wn.bottom(), wn.x(), wn.yFlipped());
|
| + debugShowLineIntersection(pts, wt, wn, ts);
|
| + break;
|
| + case SkIntersectionHelper::kLine_Segment: {
|
| + pts = ts.lineLine(wt.pts(), wn.pts());
|
| + debugShowLineIntersection(pts, wt, wn, ts);
|
| + break;
|
| + }
|
| + case SkIntersectionHelper::kQuad_Segment: {
|
| + swap = true;
|
| + pts = ts.quadLine(wn.pts(), wt.pts());
|
| + debugShowQuadLineIntersection(pts, wn, wt, ts);
|
| + break;
|
| + }
|
| + case SkIntersectionHelper::kCubic_Segment: {
|
| + swap = true;
|
| + pts = ts.cubicLine(wn.pts(), wt.pts());
|
| + debugShowCubicLineIntersection(pts, wn, wt, ts);
|
| + break;
|
| + }
|
| + default:
|
| + SkASSERT(0);
|
| + }
|
| + break;
|
| + case SkIntersectionHelper::kQuad_Segment:
|
| + switch (wn.segmentType()) {
|
| + case SkIntersectionHelper::kHorizontalLine_Segment:
|
| + pts = ts.quadHorizontal(wt.pts(), wn.left(),
|
| + wn.right(), wn.y(), wn.xFlipped());
|
| + debugShowQuadLineIntersection(pts, wt, wn, ts);
|
| + break;
|
| + case SkIntersectionHelper::kVerticalLine_Segment:
|
| + pts = ts.quadVertical(wt.pts(), wn.top(),
|
| + wn.bottom(), wn.x(), wn.yFlipped());
|
| + debugShowQuadLineIntersection(pts, wt, wn, ts);
|
| + break;
|
| + case SkIntersectionHelper::kLine_Segment: {
|
| + pts = ts.quadLine(wt.pts(), wn.pts());
|
| + debugShowQuadLineIntersection(pts, wt, wn, ts);
|
| + break;
|
| + }
|
| + case SkIntersectionHelper::kQuad_Segment: {
|
| + pts = ts.quadQuad(wt.pts(), wn.pts());
|
| + debugShowQuadIntersection(pts, wt, wn, ts);
|
| + break;
|
| + }
|
| + case SkIntersectionHelper::kCubic_Segment: {
|
| + swap = true;
|
| + pts = ts.cubicQuad(wn.pts(), wt.pts());
|
| + debugShowCubicQuadIntersection(pts, wn, wt, ts);
|
| + break;
|
| + }
|
| + default:
|
| + SkASSERT(0);
|
| + }
|
| + break;
|
| + case SkIntersectionHelper::kCubic_Segment:
|
| + switch (wn.segmentType()) {
|
| + case SkIntersectionHelper::kHorizontalLine_Segment:
|
| + pts = ts.cubicHorizontal(wt.pts(), wn.left(),
|
| + wn.right(), wn.y(), wn.xFlipped());
|
| + debugShowCubicLineIntersection(pts, wt, wn, ts);
|
| + break;
|
| + case SkIntersectionHelper::kVerticalLine_Segment:
|
| + pts = ts.cubicVertical(wt.pts(), wn.top(),
|
| + wn.bottom(), wn.x(), wn.yFlipped());
|
| + debugShowCubicLineIntersection(pts, wt, wn, ts);
|
| + break;
|
| + case SkIntersectionHelper::kLine_Segment: {
|
| + pts = ts.cubicLine(wt.pts(), wn.pts());
|
| + debugShowCubicLineIntersection(pts, wt, wn, ts);
|
| + break;
|
| + }
|
| + case SkIntersectionHelper::kQuad_Segment: {
|
| + pts = ts.cubicQuad(wt.pts(), wn.pts());
|
| + debugShowCubicQuadIntersection(pts, wt, wn, ts);
|
| + break;
|
| + }
|
| + case SkIntersectionHelper::kCubic_Segment: {
|
| + pts = ts.cubicCubic(wt.pts(), wn.pts());
|
| + debugShowCubicIntersection(pts, wt, wn, ts);
|
| + break;
|
| + }
|
| + default:
|
| + SkASSERT(0);
|
| + }
|
| + break;
|
| + default:
|
| + SkASSERT(0);
|
| + }
|
| + if (!foundCommonContour && pts > 0) {
|
| + test->addCross(next);
|
| + next->addCross(test);
|
| + foundCommonContour = true;
|
| + }
|
| + // in addition to recording T values, record matching segment
|
| + if (pts == 2) {
|
| + if (wn.segmentType() <= SkIntersectionHelper::kLine_Segment
|
| + && wt.segmentType() <= SkIntersectionHelper::kLine_Segment) {
|
| + wt.addCoincident(wn, ts, swap);
|
| + continue;
|
| + }
|
| + if (wn.segmentType() >= SkIntersectionHelper::kQuad_Segment
|
| + && wt.segmentType() >= SkIntersectionHelper::kQuad_Segment
|
| + && ts.isCoincident(0)) {
|
| + SkASSERT(ts.coincidentUsed() == 2);
|
| + wt.addCoincident(wn, ts, swap);
|
| + continue;
|
| + }
|
| +
|
| + }
|
| + for (int pt = 0; pt < pts; ++pt) {
|
| + SkASSERT(ts[0][pt] >= 0 && ts[0][pt] <= 1);
|
| + SkASSERT(ts[1][pt] >= 0 && ts[1][pt] <= 1);
|
| + SkPoint point = ts.pt(pt).asSkPoint();
|
| + int testTAt = wt.addT(wn, point, ts[swap][pt]);
|
| + int nextTAt = wn.addT(wt, point, ts[!swap][pt]);
|
| + wt.addOtherT(testTAt, ts[!swap][pt], nextTAt);
|
| + wn.addOtherT(nextTAt, ts[swap][pt], testTAt);
|
| + }
|
| + } while (wn.advance());
|
| + } while (wt.advance());
|
| + return true;
|
| +}
|
| +
|
| +void AddSelfIntersectTs(SkOpContour* test) {
|
| + SkIntersectionHelper wt;
|
| + wt.init(test);
|
| + do {
|
| + if (wt.segmentType() != SkIntersectionHelper::kCubic_Segment) {
|
| + continue;
|
| + }
|
| + SkIntersections ts;
|
| + int pts = ts.cubic(wt.pts());
|
| + debugShowCubicIntersection(pts, wt, ts);
|
| + if (!pts) {
|
| + continue;
|
| + }
|
| + SkASSERT(pts == 1);
|
| + SkASSERT(ts[0][0] >= 0 && ts[0][0] <= 1);
|
| + SkASSERT(ts[1][0] >= 0 && ts[1][0] <= 1);
|
| + SkPoint point = ts.pt(0).asSkPoint();
|
| + int testTAt = wt.addSelfT(wt, point, ts[0][0]);
|
| + int nextTAt = wt.addT(wt, point, ts[1][0]);
|
| + wt.addOtherT(testTAt, ts[1][0], nextTAt);
|
| + wt.addOtherT(nextTAt, ts[0][0], testTAt);
|
| + } while (wt.advance());
|
| +}
|
| +
|
| +// resolve any coincident pairs found while intersecting, and
|
| +// see if coincidence is formed by clipping non-concident segments
|
| +void CoincidenceCheck(SkTDArray<SkOpContour*>& contourList, int total) {
|
| + int contourCount = contourList.count();
|
| +#if ONE_PASS_COINCIDENCE_CHECK
|
| + for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
|
| + SkOpContour* contour = contourList[cIndex];
|
| + contour->resolveCoincidence(contourList);
|
| + }
|
| +#else
|
| + for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
|
| + SkOpContour* contour = contourList[cIndex];
|
| + contour->addCoincidentPoints();
|
| + }
|
| + for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
|
| + SkOpContour* contour = contourList[cIndex];
|
| + contour->calcCoincidentWinding();
|
| + }
|
| +#endif
|
| + for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
|
| + SkOpContour* contour = contourList[cIndex];
|
| + contour->findTooCloseToCall();
|
| + }
|
| +}
|
|
|