| Index: src/utils/SkCurveMeasure.cpp
|
| diff --git a/src/utils/SkCurveMeasure.cpp b/src/utils/SkCurveMeasure.cpp
|
| index fc2aa84faa119558d5dce1c30f6bdd826c3eb890..60fbf34ff24be9d78085f7333e4a74db0ae2b07b 100644
|
| --- a/src/utils/SkCurveMeasure.cpp
|
| +++ b/src/utils/SkCurveMeasure.cpp
|
| @@ -6,10 +6,66 @@
|
| */
|
|
|
| #include "SkCurveMeasure.h"
|
| +#include "SkGeometry.h"
|
|
|
| // for abs
|
| #include <cmath>
|
|
|
| +#define UNIMPLEMENTED SkDEBUGF(("%s:%d unimplemented\n", __FILE__, __LINE__))
|
| +
|
| +/// 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 = SkPoint::Make(SkScalarInterp(pts[0].x(), pts[1].x(), t),
|
| + SkScalarInterp(pts[0].y(), pts[1].y(), 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:
|
| + 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:
|
| + UNIMPLEMENTED;
|
| + }
|
| +
|
| + return tan;
|
| +}
|
| +/// Used in ArcLengthIntegrator::computeLength
|
| static inline Sk8f evaluateDerivativeLength(const Sk8f& ts,
|
| const Sk8f (&xCoeff)[3],
|
| const Sk8f (&yCoeff)[3],
|
| @@ -21,18 +77,15 @@ static inline Sk8f evaluateDerivativeLength(const Sk8f& ts,
|
| x = xCoeff[0]*ts + xCoeff[1];
|
| y = yCoeff[0]*ts + yCoeff[1];
|
| break;
|
| - case kLine_SegType:
|
| - SkDebugf("Unimplemented");
|
| - break;
|
| case kCubic_SegType:
|
| x = (xCoeff[0]*ts + xCoeff[1])*ts + xCoeff[2];
|
| y = (yCoeff[0]*ts + yCoeff[1])*ts + yCoeff[2];
|
| break;
|
| case kConic_SegType:
|
| - SkDebugf("Unimplemented");
|
| + UNIMPLEMENTED;
|
| break;
|
| default:
|
| - SkDebugf("Unimplemented");
|
| + UNIMPLEMENTED;
|
| }
|
|
|
| x = x * x;
|
| @@ -40,6 +93,7 @@ static inline Sk8f evaluateDerivativeLength(const Sk8f& ts,
|
|
|
| return (x + y).sqrt();
|
| }
|
| +
|
| ArcLengthIntegrator::ArcLengthIntegrator(const SkPoint* pts, SkSegType segType)
|
| : fSegType(segType) {
|
| switch (fSegType) {
|
| @@ -59,9 +113,6 @@ ArcLengthIntegrator::ArcLengthIntegrator(const SkPoint* pts, SkSegType segType)
|
| yCoeff[1] = Sk8f(2.0f*(By - Ay));
|
| }
|
| break;
|
| - case kLine_SegType:
|
| - SkDEBUGF(("Unimplemented"));
|
| - break;
|
| case kCubic_SegType:
|
| {
|
| float Ax = pts[0].x();
|
| @@ -73,6 +124,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));
|
| @@ -83,10 +135,10 @@ ArcLengthIntegrator::ArcLengthIntegrator(const SkPoint* pts, SkSegType segType)
|
| }
|
| break;
|
| case kConic_SegType:
|
| - SkDEBUGF(("Unimplemented"));
|
| + UNIMPLEMENTED;
|
| break;
|
| default:
|
| - SkDEBUGF(("Unimplemented"));
|
| + UNIMPLEMENTED;
|
| }
|
| }
|
|
|
| @@ -117,7 +169,9 @@ SkCurveMeasure::SkCurveMeasure(const SkPoint* pts, SkSegType segType)
|
| }
|
| break;
|
| case SkSegType::kLine_SegType:
|
| - SkDebugf("Unimplemented");
|
| + fPts[0] = pts[0];
|
| + fPts[1] = pts[1];
|
| + fLength = (fPts[1] - fPts[0]).length();
|
| break;
|
| case SkSegType::kCubic_SegType:
|
| for (size_t i = 0; i < 4; i++) {
|
| @@ -125,13 +179,17 @@ 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"));
|
| + UNIMPLEMENTED;
|
| break;
|
| }
|
| - fIntegrator = ArcLengthIntegrator(fPts, fSegType);
|
| + if (kLine_SegType != segType) {
|
| + fIntegrator = ArcLengthIntegrator(fPts, fSegType);
|
| + }
|
| }
|
|
|
| SkScalar SkCurveMeasure::getLength() {
|
| @@ -151,15 +209,18 @@ SkScalar SkCurveMeasure::getLength() {
|
| // which is equal to the length of the tangent (so we have to do a sqrt).
|
|
|
| SkScalar SkCurveMeasure::getTime(SkScalar targetLength) {
|
| - if (targetLength == 0.0f) {
|
| + if (targetLength <= 0.0f) {
|
| return 0.0f;
|
| }
|
|
|
| SkScalar currentLength = getLength();
|
|
|
| - if (SkScalarNearlyEqual(targetLength, currentLength)) {
|
| + if (targetLength > currentLength || (SkScalarNearlyEqual(targetLength, currentLength))) {
|
| return 1.0f;
|
| }
|
| + if (kLine_SegType == fSegType) {
|
| + return targetLength / currentLength;
|
| + }
|
|
|
| // initial estimate of t is percentage of total length
|
| SkScalar currentT = targetLength / currentLength;
|
| @@ -199,9 +260,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.
|
| @@ -218,7 +278,7 @@ SkScalar SkCurveMeasure::getTime(SkScalar targetLength) {
|
| newT = (minT + maxT) * 0.5f;
|
| } else {
|
| SkDEBUGF(("%.7f %.7f didn't get close enough after bisection.\n",
|
| - currentT, currentLength));
|
| + currentT, currentLength));
|
| break;
|
| }
|
| currentT = newT;
|
| @@ -235,52 +295,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);
|
| -}
|
|
|