diff options
author | 2015-04-29 08:28:30 -0700 | |
---|---|---|
committer | 2015-04-29 08:28:30 -0700 | |
commit | aec251012542e971100e218bf463adbfb5d21d20 (patch) | |
tree | 16c2e84c2d59d94b75d7d2bc50fec53c0e38a898 /src/pathops/SkPathOpsCurve.cpp | |
parent | 97fdea6c4393cf0102d7eee5790782509fb4f57b (diff) |
minor fixes to cubics code and overall alignment of how bounds and tops are computed for all curve types
All but 17 extended tests work.
A helper function is privately added to SkPath.h to permit a test to modify a given point in a path.
BUG=skia:3588
Review URL: https://codereview.chromium.org/1107353004
Diffstat (limited to 'src/pathops/SkPathOpsCurve.cpp')
-rw-r--r-- | src/pathops/SkPathOpsCurve.cpp | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/src/pathops/SkPathOpsCurve.cpp b/src/pathops/SkPathOpsCurve.cpp new file mode 100644 index 0000000000..651e64a908 --- /dev/null +++ b/src/pathops/SkPathOpsCurve.cpp @@ -0,0 +1,146 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "SkPathOpsBounds.h" +#include "SkPathOpsRect.h" +#include "SkPathOpsCurve.h" + +SkDPoint SkDCurve::conicTop(const SkPoint curve[3], SkScalar curveWeight, + double startT, double endT, double* topT) { + SkDPoint topPt = fConic[0]; + *topT = startT; + if (topPt.fY > fConic[2].fY || (topPt.fY == fConic[2].fY && topPt.fX > fConic[2].fX)) { + *topT = endT; + topPt = fConic[2]; + } + if (!fConic.monotonicInY()) { + double extremeT; + if (SkDConic::FindExtrema(&fConic.fPts.fPts[0].fY, fConic.fWeight, &extremeT)) { + SkDConic dCurve; + dCurve.set(curve, curveWeight); + extremeT = startT + (endT - startT) * extremeT; + SkDPoint test = dCurve.ptAtT(extremeT); + if (topPt.fY > test.fY || (topPt.fY == test.fY && topPt.fX > test.fX)) { + *topT = extremeT; + topPt = test; + } + } + } + return topPt; +} + +SkDPoint SkDCurve::cubicTop(const SkPoint curve[4], SkScalar , + double startT, double endT, double* topT) { + SkDPoint topPt = fCubic[0]; + *topT = startT; + if (topPt.fY > fCubic[3].fY || (topPt.fY == fCubic[3].fY && topPt.fX > fCubic[3].fX)) { + *topT = endT; + topPt = fCubic[3]; + } + double extremeTs[2]; + if (!fCubic.monotonicInY()) { + int roots = SkDCubic::FindExtrema(&fCubic.fPts[0].fY, extremeTs); + SkDCubic dCurve; + dCurve.set(curve); + for (int index = 0; index < roots; ++index) { + double t = startT + (endT - startT) * extremeTs[index]; + SkDPoint mid = dCurve.ptAtT(t); + if (topPt.fY > mid.fY || (topPt.fY == mid.fY && topPt.fX > mid.fX)) { + *topT = t; + topPt = mid; + } + } + } + return topPt; +} + +SkDPoint SkDCurve::lineTop(const SkPoint[2], SkScalar , double startT, double endT, double* topT) { + SkDPoint topPt = fLine[0]; + *topT = startT; + if (topPt.fY > fLine[1].fY || (topPt.fY == fLine[1].fY && topPt.fX > fLine[1].fX)) { + *topT = endT; + topPt = fLine[1]; + } + return topPt; +} + +SkDPoint SkDCurve::quadTop(const SkPoint curve[3], SkScalar , + double startT, double endT, double* topT) { + SkDPoint topPt = fQuad[0]; + *topT = startT; + if (topPt.fY > fQuad[2].fY || (topPt.fY == fQuad[2].fY && topPt.fX > fQuad[2].fX)) { + *topT = endT; + topPt = fQuad[2]; + } + if (!fQuad.monotonicInY()) { + double extremeT; + if (SkDQuad::FindExtrema(&fQuad.fPts[0].fY, &extremeT)) { + SkDQuad dCurve; + dCurve.set(curve); + extremeT = startT + (endT - startT) * extremeT; + SkDPoint test = dCurve.ptAtT(extremeT); + if (topPt.fY > test.fY || (topPt.fY == test.fY && topPt.fX > test.fX)) { + *topT = extremeT; + topPt = test; + } + } + } + return topPt; +} + +SkDPoint (SkDCurve::* const Top[])(const SkPoint curve[], SkScalar curveWeight, + double tStart, double tEnd, double* topT) = { + NULL, + &SkDCurve::lineTop, + &SkDCurve::quadTop, + &SkDCurve::conicTop, + &SkDCurve::cubicTop +}; + +void SkDCurve::setConicBounds(const SkPoint curve[3], SkScalar curveWeight, + double tStart, double tEnd, SkPathOpsBounds* bounds) { + SkDConic dCurve; + dCurve.set(curve, curveWeight); + SkDRect dRect; + dRect.setBounds(dCurve, fConic, tStart, tEnd); + bounds->set(SkDoubleToScalar(dRect.fLeft), SkDoubleToScalar(dRect.fTop), + SkDoubleToScalar(dRect.fRight), SkDoubleToScalar(dRect.fBottom)); +} + +void SkDCurve::setCubicBounds(const SkPoint curve[4], SkScalar , + double tStart, double tEnd, SkPathOpsBounds* bounds) { + SkDCubic dCurve; + dCurve.set(curve); + SkDRect dRect; + dRect.setBounds(dCurve, fCubic, tStart, tEnd); + bounds->set(SkDoubleToScalar(dRect.fLeft), SkDoubleToScalar(dRect.fTop), + SkDoubleToScalar(dRect.fRight), SkDoubleToScalar(dRect.fBottom)); +} + +void SkDCurve::setLineBounds(const SkPoint[2], SkScalar , + double , double , SkPathOpsBounds* bounds) { + bounds->setPointBounds(fLine[0]); + bounds->add(fLine[1]); +} + +void SkDCurve::setQuadBounds(const SkPoint curve[3], SkScalar , + double tStart, double tEnd, SkPathOpsBounds* bounds) { + SkDQuad dCurve; + dCurve.set(curve); + SkDRect dRect; + dRect.setBounds(dCurve, fQuad, tStart, tEnd); + bounds->set(SkDoubleToScalar(dRect.fLeft), SkDoubleToScalar(dRect.fTop), + SkDoubleToScalar(dRect.fRight), SkDoubleToScalar(dRect.fBottom)); +} + +void (SkDCurve::* const SetBounds[])(const SkPoint curve[], SkScalar curveWeight, + double tStart, double tEnd, SkPathOpsBounds* bounds) = { + NULL, + &SkDCurve::setLineBounds, + &SkDCurve::setQuadBounds, + &SkDCurve::setConicBounds, + &SkDCurve::setCubicBounds +}; |