Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(272)

Side by Side Diff: src/utils/SkCurveMeasure.cpp

Issue 2226973004: Refactor SkCurveMeasure to use existing eval code (Closed) Base URL: https://skia.googlesource.com/skia.git@curvemeasure_rework
Patch Set: Remove incomplete line fragment mistakenly included Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« src/utils/SkCurveMeasure.h ('K') | « src/utils/SkCurveMeasure.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2016 Google Inc. 2 * Copyright 2016 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkCurveMeasure.h" 8 #include "SkCurveMeasure.h"
9 #include "SkGeometry.h"
9 10
10 // for abs 11 // for abs
11 #include <cmath> 12 #include <cmath>
12 13
14
15 /// Used inside SkCurveMeasure::getTime's Newton's iteration
16 static inline SkPoint evaluate(const SkPoint pts[4], SkSegType segType,
17 SkScalar t) {
18 SkPoint pos;
19 switch (segType) {
20 case kQuad_SegType:
21 pos = SkEvalQuadAt(pts, t);
22 break;
23 case kLine_SegType:
24 pos = pts[0]*t + pts[1]*(1-t);
25 break;
26 case kCubic_SegType:
27 SkEvalCubicAt(pts, t, &pos, nullptr, nullptr);
28 break;
29 case kConic_SegType: {
30 SkConic conic(pts, pts[3].x());
31 conic.evalAt(t, &pos);
32 }
33 break;
34 default:
35 SkDebugf("Unimplemented");
36 }
37
38 return pos;
39 }
40
41 /// Used inside SkCurveMeasure::getTime's Newton's iteration
42 static inline SkVector evaluateDerivative(const SkPoint pts[4],
43 SkSegType segType, SkScalar t) {
44 SkVector tan;
45 switch (segType) {
46 case kQuad_SegType:
47 tan = SkEvalQuadTangentAt(pts, t);
48 break;
49 case kLine_SegType:
50 tan = pts[1] - pts[0];
51 break;
52 case kCubic_SegType:
53 SkEvalCubicAt(pts, t, nullptr, &tan, nullptr);
54 break;
55 case kConic_SegType: {
56 SkConic conic(pts, pts[3].x());
57 conic.evalAt(t, nullptr, &tan);
58 }
59 break;
60 default:
61 SkDebugf("Unimplemented");
62 }
63
64 return tan;
65 }
66 /// Used in ArcLengthIntegrator::computeLength
13 static inline Sk8f evaluateDerivativeLength(const Sk8f& ts, 67 static inline Sk8f evaluateDerivativeLength(const Sk8f& ts,
14 const Sk8f (&xCoeff)[3], 68 const Sk8f (&xCoeff)[3],
15 const Sk8f (&yCoeff)[3], 69 const Sk8f (&yCoeff)[3],
16 const SkSegType segType) { 70 const SkSegType segType) {
17 Sk8f x; 71 Sk8f x;
18 Sk8f y; 72 Sk8f y;
19 switch (segType) { 73 switch (segType) {
20 case kQuad_SegType: 74 case kQuad_SegType:
21 x = xCoeff[0]*ts + xCoeff[1]; 75 x = xCoeff[0]*ts + xCoeff[1];
22 y = yCoeff[0]*ts + yCoeff[1]; 76 y = yCoeff[0]*ts + yCoeff[1];
23 break; 77 break;
24 case kLine_SegType: 78 case kLine_SegType:
25 SkDebugf("Unimplemented"); 79 // length of line derivative is constant
80 // and we precompute it in the constructor
81 return xCoeff[0];
26 break; 82 break;
reed1 2016/08/10 12:08:07 nit: don't need the break;
Harry Stern 2016/08/10 17:55:58 Done.
27 case kCubic_SegType: 83 case kCubic_SegType:
28 x = (xCoeff[0]*ts + xCoeff[1])*ts + xCoeff[2]; 84 x = (xCoeff[0]*ts + xCoeff[1])*ts + xCoeff[2];
29 y = (yCoeff[0]*ts + yCoeff[1])*ts + yCoeff[2]; 85 y = (yCoeff[0]*ts + yCoeff[1])*ts + yCoeff[2];
30 break; 86 break;
31 case kConic_SegType: 87 case kConic_SegType:
32 SkDebugf("Unimplemented"); 88 SkDebugf("Unimplemented");
33 break; 89 break;
34 default: 90 default:
35 SkDebugf("Unimplemented"); 91 SkDebugf("Unimplemented");
36 } 92 }
37 93
38 x = x * x; 94 x = x * x;
39 y = y * y; 95 y = y * y;
40 96
41 return (x + y).sqrt(); 97 return (x + y).sqrt();
42 } 98 }
99
43 ArcLengthIntegrator::ArcLengthIntegrator(const SkPoint* pts, SkSegType segType) 100 ArcLengthIntegrator::ArcLengthIntegrator(const SkPoint* pts, SkSegType segType)
44 : fSegType(segType) { 101 : fSegType(segType) {
45 switch (fSegType) { 102 switch (fSegType) {
46 case kQuad_SegType: { 103 case kQuad_SegType: {
47 float Ax = pts[0].x(); 104 float Ax = pts[0].x();
48 float Bx = pts[1].x(); 105 float Bx = pts[1].x();
49 float Cx = pts[2].x(); 106 float Cx = pts[2].x();
50 float Ay = pts[0].y(); 107 float Ay = pts[0].y();
51 float By = pts[1].y(); 108 float By = pts[1].y();
52 float Cy = pts[2].y(); 109 float Cy = pts[2].y();
53 110
54 // precompute coefficients for derivative 111 // precompute coefficients for derivative
55 xCoeff[0] = Sk8f(2.0f*(Ax - 2*Bx + Cx)); 112 xCoeff[0] = Sk8f(2.0f*(Ax - 2*Bx + Cx));
56 xCoeff[1] = Sk8f(2.0f*(Bx - Ax)); 113 xCoeff[1] = Sk8f(2.0f*(Bx - Ax));
57 114
58 yCoeff[0] = Sk8f(2.0f*(Ay - 2*By + Cy)); 115 yCoeff[0] = Sk8f(2.0f*(Ay - 2*By + Cy));
59 yCoeff[1] = Sk8f(2.0f*(By - Ay)); 116 yCoeff[1] = Sk8f(2.0f*(By - Ay));
60 } 117 }
61 break; 118 break;
62 case kLine_SegType: 119 case kLine_SegType: {
63 SkDEBUGF(("Unimplemented")); 120 // the length of the derivative of a line is constant
121 // we put in in both coeff arrays for consistency's sake
122 SkScalar length = (pts[1] - pts[0]).length();
123 xCoeff[0] = Sk8f(length);
124 yCoeff[0] = Sk8f(length);
125 }
64 break; 126 break;
65 case kCubic_SegType: 127 case kCubic_SegType:
66 { 128 {
67 float Ax = pts[0].x(); 129 float Ax = pts[0].x();
68 float Bx = pts[1].x(); 130 float Bx = pts[1].x();
69 float Cx = pts[2].x(); 131 float Cx = pts[2].x();
70 float Dx = pts[3].x(); 132 float Dx = pts[3].x();
71 float Ay = pts[0].y(); 133 float Ay = pts[0].y();
72 float By = pts[1].y(); 134 float By = pts[1].y();
73 float Cy = pts[2].y(); 135 float Cy = pts[2].y();
74 float Dy = pts[3].y(); 136 float Dy = pts[3].y();
75 137
138 // precompute coefficients for derivative
76 xCoeff[0] = Sk8f(3.0f*(-Ax + 3.0f*(Bx - Cx) + Dx)); 139 xCoeff[0] = Sk8f(3.0f*(-Ax + 3.0f*(Bx - Cx) + Dx));
77 xCoeff[1] = Sk8f(3.0f*(2.0f*(Ax - 2.0f*Bx + Cx))); 140 xCoeff[1] = Sk8f(3.0f*(2.0f*(Ax - 2.0f*Bx + Cx)));
78 xCoeff[2] = Sk8f(3.0f*(-Ax + Bx)); 141 xCoeff[2] = Sk8f(3.0f*(-Ax + Bx));
79 142
80 yCoeff[0] = Sk8f(3.0f*(-Ay + 3.0f*(By - Cy) + Dy)); 143 yCoeff[0] = Sk8f(3.0f*(-Ay + 3.0f*(By - Cy) + Dy));
81 yCoeff[1] = Sk8f(3.0f * -Ay + By + 2.0f*(Ay - 2.0f*By + Cy)); 144 yCoeff[1] = Sk8f(3.0f * -Ay + By + 2.0f*(Ay - 2.0f*By + Cy));
82 yCoeff[2] = Sk8f(3.0f*(-Ay + By)); 145 yCoeff[2] = Sk8f(3.0f*(-Ay + By));
83 } 146 }
84 break; 147 break;
85 case kConic_SegType: 148 case kConic_SegType:
(...skipping 24 matching lines...) Expand all
110 173
111 SkCurveMeasure::SkCurveMeasure(const SkPoint* pts, SkSegType segType) 174 SkCurveMeasure::SkCurveMeasure(const SkPoint* pts, SkSegType segType)
112 : fSegType(segType) { 175 : fSegType(segType) {
113 switch (fSegType) { 176 switch (fSegType) {
114 case SkSegType::kQuad_SegType: 177 case SkSegType::kQuad_SegType:
115 for (size_t i = 0; i < 3; i++) { 178 for (size_t i = 0; i < 3; i++) {
116 fPts[i] = pts[i]; 179 fPts[i] = pts[i];
117 } 180 }
118 break; 181 break;
119 case SkSegType::kLine_SegType: 182 case SkSegType::kLine_SegType:
120 SkDebugf("Unimplemented"); 183 fPts[0] = pts[0];
184 fPts[1] = pts[1];
121 break; 185 break;
122 case SkSegType::kCubic_SegType: 186 case SkSegType::kCubic_SegType:
123 for (size_t i = 0; i < 4; i++) { 187 for (size_t i = 0; i < 4; i++) {
124 fPts[i] = pts[i]; 188 fPts[i] = pts[i];
125 } 189 }
126 break; 190 break;
127 case SkSegType::kConic_SegType: 191 case SkSegType::kConic_SegType:
128 SkDebugf("Unimplemented"); 192 for (size_t i = 0; i < 4; i++) {
193 fPts[i] = pts[i];
194 }
129 break; 195 break;
130 default: 196 default:
131 SkDEBUGF(("Unimplemented")); 197 SkDEBUGF(("Unimplemented"));
132 break; 198 break;
133 } 199 }
134 fIntegrator = ArcLengthIntegrator(fPts, fSegType); 200 fIntegrator = ArcLengthIntegrator(fPts, fSegType);
135 } 201 }
136 202
137 SkScalar SkCurveMeasure::getLength() { 203 SkScalar SkCurveMeasure::getLength() {
138 if (-1.0f == fLength) { 204 if (-1.0f == fLength) {
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 // on the t value 258 // on the t value
193 // because we may not have enough precision in the t to get close enough 259 // because we may not have enough precision in the t to get close enough
194 // in the length. 260 // in the length.
195 if ((std::abs(lengthDiff) < kTolerance) || 261 if ((std::abs(lengthDiff) < kTolerance) ||
196 (std::abs(prevT - currentT) < kTolerance)) { 262 (std::abs(prevT - currentT) < kTolerance)) {
197 break; 263 break;
198 } 264 }
199 265
200 prevT = currentT; 266 prevT = currentT;
201 if (iterations < kNewtonIters) { 267 if (iterations < kNewtonIters) {
202 // TODO(hstern) switch here on curve type.
203 // This is just newton's formula. 268 // This is just newton's formula.
204 SkScalar dt = evaluateQuadDerivative(currentT).length(); 269 SkScalar dt = evaluateDerivative(fPts, fSegType, currentT).length();
205 newT = currentT - (lengthDiff / dt); 270 newT = currentT - (lengthDiff / dt);
206 271
207 // If newT is out of bounds, bisect inside newton. 272 // If newT is out of bounds, bisect inside newton.
208 if ((newT < 0.0f) || (newT > 1.0f)) { 273 if ((newT < 0.0f) || (newT > 1.0f)) {
209 newT = (minT + maxT) * 0.5f; 274 newT = (minT + maxT) * 0.5f;
210 } 275 }
211 } else if (iterations < kNewtonIters + kBisectIters) { 276 } else if (iterations < kNewtonIters + kBisectIters) {
212 if (lengthDiff > 0.0f) { 277 if (lengthDiff > 0.0f) {
213 maxT = currentT; 278 maxT = currentT;
214 } else { 279 } else {
(...skipping 13 matching lines...) Expand all
228 iterations++; 293 iterations++;
229 } 294 }
230 295
231 // debug. is there an SKDEBUG or something for ifdefs? 296 // debug. is there an SKDEBUG or something for ifdefs?
232 fIters = iterations; 297 fIters = iterations;
233 298
234 return currentT; 299 return currentT;
235 } 300 }
236 301
237 void SkCurveMeasure::getPosTanTime(SkScalar targetLength, SkPoint* pos, 302 void SkCurveMeasure::getPosTanTime(SkScalar targetLength, SkPoint* pos,
238 SkVector* tan, SkScalar* time) { 303 SkVector* tan, SkScalar* time) {
239 SkScalar t = getTime(targetLength); 304 SkScalar t = getTime(targetLength);
240 305
241 if (time) { 306 if (time) {
242 *time = t; 307 *time = t;
243 } 308 }
244 if (pos) { 309 if (pos) {
245 // TODO(hstern) switch here on curve type. 310 *pos = evaluate(fPts, fSegType, t);
246 *pos = evaluateQuad(t);
247 } 311 }
248 if (tan) { 312 if (tan) {
249 // TODO(hstern) switch here on curve type. 313 *tan = evaluateDerivative(fPts, fSegType, t);
250 *tan = evaluateQuadDerivative(t);
251 } 314 }
252 } 315 }
253
254 // this is why I feel that the ArcLengthIntegrator should be combined
255 // with some sort of evaluator that caches the constants computed from the
256 // control points. this is basically the same code in ArcLengthIntegrator
257 SkPoint SkCurveMeasure::evaluateQuad(SkScalar t) {
258 SkScalar ti = 1.0f - t;
259
260 SkScalar Ax = fPts[0].x();
261 SkScalar Bx = fPts[1].x();
262 SkScalar Cx = fPts[2].x();
263 SkScalar Ay = fPts[0].y();
264 SkScalar By = fPts[1].y();
265 SkScalar Cy = fPts[2].y();
266
267 SkScalar x = Ax*ti*ti + 2.0f*Bx*t*ti + Cx*t*t;
268 SkScalar y = Ay*ti*ti + 2.0f*By*t*ti + Cy*t*t;
269 return SkPoint::Make(x, y);
270 }
271
272 SkVector SkCurveMeasure::evaluateQuadDerivative(SkScalar t) {
273 SkScalar Ax = fPts[0].x();
274 SkScalar Bx = fPts[1].x();
275 SkScalar Cx = fPts[2].x();
276 SkScalar Ay = fPts[0].y();
277 SkScalar By = fPts[1].y();
278 SkScalar Cy = fPts[2].y();
279
280 SkScalar A2BCx = 2.0f*(Ax - 2*Bx + Cx);
281 SkScalar A2BCy = 2.0f*(Ay - 2*By + Cy);
282 SkScalar ABx = 2.0f*(Bx - Ax);
283 SkScalar ABy = 2.0f*(By - Ay);
284
285 return SkPoint::Make(A2BCx*t + ABx, A2BCy*t + ABy);
286 }
OLDNEW
« src/utils/SkCurveMeasure.h ('K') | « src/utils/SkCurveMeasure.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698