Chromium Code Reviews| Index: src/utils/SkCurveMeasure.cpp |
| diff --git a/src/utils/SkCurveMeasure.cpp b/src/utils/SkCurveMeasure.cpp |
| index fc2aa84faa119558d5dce1c30f6bdd826c3eb890..a199bc722e5f3d5ac6b06f22b82d86c9aa511232 100644 |
| --- a/src/utils/SkCurveMeasure.cpp |
| +++ b/src/utils/SkCurveMeasure.cpp |
| @@ -6,10 +6,64 @@ |
| */ |
| #include "SkCurveMeasure.h" |
| +#include "SkGeometry.h" |
| // for abs |
| #include <cmath> |
| + |
| +/// Used inside SkCurveMeasure::getTime's Newton's iteration |
| +static inline SkPoint evaluate(const SkPoint pts[4], SkSegType segType, |
| + SkScalar t) { |
| + SkPoint pos; |
| + switch (segType) { |
| + case kQuad_SegType: |
| + pos = SkEvalQuadAt(pts, t); |
| + break; |
| + case kLine_SegType: |
| + pos = pts[0]*t + pts[1]*(1-t); |
| + break; |
| + case kCubic_SegType: |
| + SkEvalCubicAt(pts, t, &pos, nullptr, nullptr); |
| + break; |
| + case kConic_SegType: { |
| + SkConic conic(pts, pts[3].x()); |
| + conic.evalAt(t, &pos); |
| + } |
| + break; |
| + default: |
| + SkDebugf("Unimplemented"); |
| + } |
| + |
| + return pos; |
| +} |
| + |
| +/// Used inside SkCurveMeasure::getTime's Newton's iteration |
| +static inline SkVector evaluateDerivative(const SkPoint pts[4], |
| + SkSegType segType, SkScalar t) { |
| + SkVector tan; |
| + switch (segType) { |
| + case kQuad_SegType: |
| + tan = SkEvalQuadTangentAt(pts, t); |
| + break; |
| + case kLine_SegType: |
| + tan = pts[1] - pts[0]; |
| + break; |
| + case kCubic_SegType: |
| + SkEvalCubicAt(pts, t, nullptr, &tan, nullptr); |
| + break; |
| + case kConic_SegType: { |
| + SkConic conic(pts, pts[3].x()); |
| + conic.evalAt(t, nullptr, &tan); |
| + } |
| + break; |
| + default: |
| + SkDebugf("Unimplemented"); |
| + } |
| + |
| + return tan; |
| +} |
| +/// Used in ArcLengthIntegrator::computeLength |
| static inline Sk8f evaluateDerivativeLength(const Sk8f& ts, |
| const Sk8f (&xCoeff)[3], |
| const Sk8f (&yCoeff)[3], |
| @@ -22,7 +76,9 @@ static inline Sk8f evaluateDerivativeLength(const Sk8f& ts, |
| y = yCoeff[0]*ts + yCoeff[1]; |
| break; |
| case kLine_SegType: |
| - SkDebugf("Unimplemented"); |
| + // length of line derivative is constant |
| + // and we precompute it in the constructor |
| + return xCoeff[0]; |
| break; |
|
reed1
2016/08/10 12:08:07
nit: don't need the break;
Harry Stern
2016/08/10 17:55:58
Done.
|
| case kCubic_SegType: |
| x = (xCoeff[0]*ts + xCoeff[1])*ts + xCoeff[2]; |
| @@ -40,6 +96,7 @@ static inline Sk8f evaluateDerivativeLength(const Sk8f& ts, |
| return (x + y).sqrt(); |
| } |
| + |
| ArcLengthIntegrator::ArcLengthIntegrator(const SkPoint* pts, SkSegType segType) |
| : fSegType(segType) { |
| switch (fSegType) { |
| @@ -59,8 +116,13 @@ ArcLengthIntegrator::ArcLengthIntegrator(const SkPoint* pts, SkSegType segType) |
| yCoeff[1] = Sk8f(2.0f*(By - Ay)); |
| } |
| break; |
| - case kLine_SegType: |
| - SkDEBUGF(("Unimplemented")); |
| + case kLine_SegType: { |
| + // the length of the derivative of a line is constant |
| + // we put in in both coeff arrays for consistency's sake |
| + SkScalar length = (pts[1] - pts[0]).length(); |
| + xCoeff[0] = Sk8f(length); |
| + yCoeff[0] = Sk8f(length); |
| + } |
| break; |
| case kCubic_SegType: |
| { |
| @@ -73,6 +135,7 @@ ArcLengthIntegrator::ArcLengthIntegrator(const SkPoint* pts, SkSegType segType) |
| float Cy = pts[2].y(); |
| float Dy = pts[3].y(); |
| + // precompute coefficients for derivative |
| xCoeff[0] = Sk8f(3.0f*(-Ax + 3.0f*(Bx - Cx) + Dx)); |
| xCoeff[1] = Sk8f(3.0f*(2.0f*(Ax - 2.0f*Bx + Cx))); |
| xCoeff[2] = Sk8f(3.0f*(-Ax + Bx)); |
| @@ -117,7 +180,8 @@ SkCurveMeasure::SkCurveMeasure(const SkPoint* pts, SkSegType segType) |
| } |
| break; |
| case SkSegType::kLine_SegType: |
| - SkDebugf("Unimplemented"); |
| + fPts[0] = pts[0]; |
| + fPts[1] = pts[1]; |
| break; |
| case SkSegType::kCubic_SegType: |
| for (size_t i = 0; i < 4; i++) { |
| @@ -125,7 +189,9 @@ SkCurveMeasure::SkCurveMeasure(const SkPoint* pts, SkSegType segType) |
| } |
| break; |
| case SkSegType::kConic_SegType: |
| - SkDebugf("Unimplemented"); |
| + for (size_t i = 0; i < 4; i++) { |
| + fPts[i] = pts[i]; |
| + } |
| break; |
| default: |
| SkDEBUGF(("Unimplemented")); |
| @@ -199,9 +265,8 @@ SkScalar SkCurveMeasure::getTime(SkScalar targetLength) { |
| prevT = currentT; |
| if (iterations < kNewtonIters) { |
| - // TODO(hstern) switch here on curve type. |
| // This is just newton's formula. |
| - SkScalar dt = evaluateQuadDerivative(currentT).length(); |
| + SkScalar dt = evaluateDerivative(fPts, fSegType, currentT).length(); |
| newT = currentT - (lengthDiff / dt); |
| // If newT is out of bounds, bisect inside newton. |
| @@ -235,52 +300,16 @@ SkScalar SkCurveMeasure::getTime(SkScalar targetLength) { |
| } |
| void SkCurveMeasure::getPosTanTime(SkScalar targetLength, SkPoint* pos, |
| - SkVector* tan, SkScalar* time) { |
| + SkVector* tan, SkScalar* time) { |
| SkScalar t = getTime(targetLength); |
| if (time) { |
| *time = t; |
| } |
| if (pos) { |
| - // TODO(hstern) switch here on curve type. |
| - *pos = evaluateQuad(t); |
| + *pos = evaluate(fPts, fSegType, t); |
| } |
| if (tan) { |
| - // TODO(hstern) switch here on curve type. |
| - *tan = evaluateQuadDerivative(t); |
| + *tan = evaluateDerivative(fPts, fSegType, t); |
| } |
| } |
| - |
| -// this is why I feel that the ArcLengthIntegrator should be combined |
| -// with some sort of evaluator that caches the constants computed from the |
| -// control points. this is basically the same code in ArcLengthIntegrator |
| -SkPoint SkCurveMeasure::evaluateQuad(SkScalar t) { |
| - SkScalar ti = 1.0f - t; |
| - |
| - SkScalar Ax = fPts[0].x(); |
| - SkScalar Bx = fPts[1].x(); |
| - SkScalar Cx = fPts[2].x(); |
| - SkScalar Ay = fPts[0].y(); |
| - SkScalar By = fPts[1].y(); |
| - SkScalar Cy = fPts[2].y(); |
| - |
| - SkScalar x = Ax*ti*ti + 2.0f*Bx*t*ti + Cx*t*t; |
| - SkScalar y = Ay*ti*ti + 2.0f*By*t*ti + Cy*t*t; |
| - return SkPoint::Make(x, y); |
| -} |
| - |
| -SkVector SkCurveMeasure::evaluateQuadDerivative(SkScalar t) { |
| - SkScalar Ax = fPts[0].x(); |
| - SkScalar Bx = fPts[1].x(); |
| - SkScalar Cx = fPts[2].x(); |
| - SkScalar Ay = fPts[0].y(); |
| - SkScalar By = fPts[1].y(); |
| - SkScalar Cy = fPts[2].y(); |
| - |
| - SkScalar A2BCx = 2.0f*(Ax - 2*Bx + Cx); |
| - SkScalar A2BCy = 2.0f*(Ay - 2*By + Cy); |
| - SkScalar ABx = 2.0f*(Bx - Ax); |
| - SkScalar ABy = 2.0f*(By - Ay); |
| - |
| - return SkPoint::Make(A2BCx*t + ABx, A2BCy*t + ABy); |
| -} |