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

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

Issue 2237503003: Revert of Refactor SkCurveMeasure to use existing eval code (Closed) Base URL: https://skia.googlesource.com/skia.git@curvemeasure_rework
Patch Set: 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
« no previous file with comments | « 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"
10 9
11 // for abs 10 // for abs
12 #include <cmath> 11 #include <cmath>
13 12
14 #define UNIMPLEMENTED SkDEBUGF(("%s:%d unimplemented\n", __FILE__, __LINE__))
15
16 /// Used inside SkCurveMeasure::getTime's Newton's iteration
17 static inline SkPoint evaluate(const SkPoint pts[4], SkSegType segType,
18 SkScalar t) {
19 SkPoint pos;
20 switch (segType) {
21 case kQuad_SegType:
22 pos = SkEvalQuadAt(pts, t);
23 break;
24 case kLine_SegType:
25 pos = SkPoint::Make(SkScalarInterp(pts[0].x(), pts[1].x(), t),
26 SkScalarInterp(pts[0].y(), pts[1].y(), t));
27 break;
28 case kCubic_SegType:
29 SkEvalCubicAt(pts, t, &pos, nullptr, nullptr);
30 break;
31 case kConic_SegType: {
32 SkConic conic(pts, pts[3].x());
33 conic.evalAt(t, &pos);
34 }
35 break;
36 default:
37 UNIMPLEMENTED;
38 }
39
40 return pos;
41 }
42
43 /// Used inside SkCurveMeasure::getTime's Newton's iteration
44 static inline SkVector evaluateDerivative(const SkPoint pts[4],
45 SkSegType segType, SkScalar t) {
46 SkVector tan;
47 switch (segType) {
48 case kQuad_SegType:
49 tan = SkEvalQuadTangentAt(pts, t);
50 break;
51 case kLine_SegType:
52 tan = pts[1] - pts[0];
53 break;
54 case kCubic_SegType:
55 SkEvalCubicAt(pts, t, nullptr, &tan, nullptr);
56 break;
57 case kConic_SegType: {
58 SkConic conic(pts, pts[3].x());
59 conic.evalAt(t, nullptr, &tan);
60 }
61 break;
62 default:
63 UNIMPLEMENTED;
64 }
65
66 return tan;
67 }
68 /// Used in ArcLengthIntegrator::computeLength
69 static inline Sk8f evaluateDerivativeLength(const Sk8f& ts, 13 static inline Sk8f evaluateDerivativeLength(const Sk8f& ts,
70 const Sk8f (&xCoeff)[3], 14 const Sk8f (&xCoeff)[3],
71 const Sk8f (&yCoeff)[3], 15 const Sk8f (&yCoeff)[3],
72 const SkSegType segType) { 16 const SkSegType segType) {
73 Sk8f x; 17 Sk8f x;
74 Sk8f y; 18 Sk8f y;
75 switch (segType) { 19 switch (segType) {
76 case kQuad_SegType: 20 case kQuad_SegType:
77 x = xCoeff[0]*ts + xCoeff[1]; 21 x = xCoeff[0]*ts + xCoeff[1];
78 y = yCoeff[0]*ts + yCoeff[1]; 22 y = yCoeff[0]*ts + yCoeff[1];
79 break; 23 break;
80 case kLine_SegType: 24 case kLine_SegType:
81 // length of line derivative is constant 25 SkDebugf("Unimplemented");
82 // and we precompute it in the constructor 26 break;
83 return xCoeff[0];
84 case kCubic_SegType: 27 case kCubic_SegType:
85 x = (xCoeff[0]*ts + xCoeff[1])*ts + xCoeff[2]; 28 x = (xCoeff[0]*ts + xCoeff[1])*ts + xCoeff[2];
86 y = (yCoeff[0]*ts + yCoeff[1])*ts + yCoeff[2]; 29 y = (yCoeff[0]*ts + yCoeff[1])*ts + yCoeff[2];
87 break; 30 break;
88 case kConic_SegType: 31 case kConic_SegType:
89 UNIMPLEMENTED; 32 SkDebugf("Unimplemented");
90 break; 33 break;
91 default: 34 default:
92 UNIMPLEMENTED; 35 SkDebugf("Unimplemented");
93 } 36 }
94 37
95 x = x * x; 38 x = x * x;
96 y = y * y; 39 y = y * y;
97 40
98 return (x + y).sqrt(); 41 return (x + y).sqrt();
99 } 42 }
100
101 ArcLengthIntegrator::ArcLengthIntegrator(const SkPoint* pts, SkSegType segType) 43 ArcLengthIntegrator::ArcLengthIntegrator(const SkPoint* pts, SkSegType segType)
102 : fSegType(segType) { 44 : fSegType(segType) {
103 switch (fSegType) { 45 switch (fSegType) {
104 case kQuad_SegType: { 46 case kQuad_SegType: {
105 float Ax = pts[0].x(); 47 float Ax = pts[0].x();
106 float Bx = pts[1].x(); 48 float Bx = pts[1].x();
107 float Cx = pts[2].x(); 49 float Cx = pts[2].x();
108 float Ay = pts[0].y(); 50 float Ay = pts[0].y();
109 float By = pts[1].y(); 51 float By = pts[1].y();
110 float Cy = pts[2].y(); 52 float Cy = pts[2].y();
111 53
112 // precompute coefficients for derivative 54 // precompute coefficients for derivative
113 xCoeff[0] = Sk8f(2.0f*(Ax - 2*Bx + Cx)); 55 xCoeff[0] = Sk8f(2.0f*(Ax - 2*Bx + Cx));
114 xCoeff[1] = Sk8f(2.0f*(Bx - Ax)); 56 xCoeff[1] = Sk8f(2.0f*(Bx - Ax));
115 57
116 yCoeff[0] = Sk8f(2.0f*(Ay - 2*By + Cy)); 58 yCoeff[0] = Sk8f(2.0f*(Ay - 2*By + Cy));
117 yCoeff[1] = Sk8f(2.0f*(By - Ay)); 59 yCoeff[1] = Sk8f(2.0f*(By - Ay));
118 } 60 }
119 break; 61 break;
120 case kLine_SegType: { 62 case kLine_SegType:
121 // the length of the derivative of a line is constant 63 SkDEBUGF(("Unimplemented"));
122 // we put in in both coeff arrays for consistency's sake
123 SkScalar length = (pts[1] - pts[0]).length();
124 xCoeff[0] = Sk8f(length);
125 yCoeff[0] = Sk8f(length);
126 }
127 break; 64 break;
128 case kCubic_SegType: 65 case kCubic_SegType:
129 { 66 {
130 float Ax = pts[0].x(); 67 float Ax = pts[0].x();
131 float Bx = pts[1].x(); 68 float Bx = pts[1].x();
132 float Cx = pts[2].x(); 69 float Cx = pts[2].x();
133 float Dx = pts[3].x(); 70 float Dx = pts[3].x();
134 float Ay = pts[0].y(); 71 float Ay = pts[0].y();
135 float By = pts[1].y(); 72 float By = pts[1].y();
136 float Cy = pts[2].y(); 73 float Cy = pts[2].y();
137 float Dy = pts[3].y(); 74 float Dy = pts[3].y();
138 75
139 // precompute coefficients for derivative
140 xCoeff[0] = Sk8f(3.0f*(-Ax + 3.0f*(Bx - Cx) + Dx)); 76 xCoeff[0] = Sk8f(3.0f*(-Ax + 3.0f*(Bx - Cx) + Dx));
141 xCoeff[1] = Sk8f(3.0f*(2.0f*(Ax - 2.0f*Bx + Cx))); 77 xCoeff[1] = Sk8f(3.0f*(2.0f*(Ax - 2.0f*Bx + Cx)));
142 xCoeff[2] = Sk8f(3.0f*(-Ax + Bx)); 78 xCoeff[2] = Sk8f(3.0f*(-Ax + Bx));
143 79
144 yCoeff[0] = Sk8f(3.0f*(-Ay + 3.0f*(By - Cy) + Dy)); 80 yCoeff[0] = Sk8f(3.0f*(-Ay + 3.0f*(By - Cy) + Dy));
145 yCoeff[1] = Sk8f(3.0f * -Ay + By + 2.0f*(Ay - 2.0f*By + Cy)); 81 yCoeff[1] = Sk8f(3.0f * -Ay + By + 2.0f*(Ay - 2.0f*By + Cy));
146 yCoeff[2] = Sk8f(3.0f*(-Ay + By)); 82 yCoeff[2] = Sk8f(3.0f*(-Ay + By));
147 } 83 }
148 break; 84 break;
149 case kConic_SegType: 85 case kConic_SegType:
150 UNIMPLEMENTED; 86 SkDEBUGF(("Unimplemented"));
151 break; 87 break;
152 default: 88 default:
153 UNIMPLEMENTED; 89 SkDEBUGF(("Unimplemented"));
154 } 90 }
155 } 91 }
156 92
157 // We use Gaussian quadrature 93 // We use Gaussian quadrature
158 // (https://en.wikipedia.org/wiki/Gaussian_quadrature) 94 // (https://en.wikipedia.org/wiki/Gaussian_quadrature)
159 // to approximate the arc length integral here, because it is amenable to SIMD. 95 // to approximate the arc length integral here, because it is amenable to SIMD.
160 SkScalar ArcLengthIntegrator::computeLength(SkScalar t) { 96 SkScalar ArcLengthIntegrator::computeLength(SkScalar t) {
161 SkScalar length = 0.0f; 97 SkScalar length = 0.0f;
162 98
163 Sk8f lengths = evaluateDerivativeLength(absc*t, xCoeff, yCoeff, fSegType); 99 Sk8f lengths = evaluateDerivativeLength(absc*t, xCoeff, yCoeff, fSegType);
(...skipping 10 matching lines...) Expand all
174 110
175 SkCurveMeasure::SkCurveMeasure(const SkPoint* pts, SkSegType segType) 111 SkCurveMeasure::SkCurveMeasure(const SkPoint* pts, SkSegType segType)
176 : fSegType(segType) { 112 : fSegType(segType) {
177 switch (fSegType) { 113 switch (fSegType) {
178 case SkSegType::kQuad_SegType: 114 case SkSegType::kQuad_SegType:
179 for (size_t i = 0; i < 3; i++) { 115 for (size_t i = 0; i < 3; i++) {
180 fPts[i] = pts[i]; 116 fPts[i] = pts[i];
181 } 117 }
182 break; 118 break;
183 case SkSegType::kLine_SegType: 119 case SkSegType::kLine_SegType:
184 fPts[0] = pts[0]; 120 SkDebugf("Unimplemented");
185 fPts[1] = pts[1];
186 break; 121 break;
187 case SkSegType::kCubic_SegType: 122 case SkSegType::kCubic_SegType:
188 for (size_t i = 0; i < 4; i++) { 123 for (size_t i = 0; i < 4; i++) {
189 fPts[i] = pts[i]; 124 fPts[i] = pts[i];
190 } 125 }
191 break; 126 break;
192 case SkSegType::kConic_SegType: 127 case SkSegType::kConic_SegType:
193 for (size_t i = 0; i < 4; i++) { 128 SkDebugf("Unimplemented");
194 fPts[i] = pts[i];
195 }
196 break; 129 break;
197 default: 130 default:
198 UNIMPLEMENTED; 131 SkDEBUGF(("Unimplemented"));
199 break; 132 break;
200 } 133 }
201 fIntegrator = ArcLengthIntegrator(fPts, fSegType); 134 fIntegrator = ArcLengthIntegrator(fPts, fSegType);
202 } 135 }
203 136
204 SkScalar SkCurveMeasure::getLength() { 137 SkScalar SkCurveMeasure::getLength() {
205 if (-1.0f == fLength) { 138 if (-1.0f == fLength) {
206 fLength = fIntegrator.computeLength(1.0f); 139 fLength = fIntegrator.computeLength(1.0f);
207 } 140 }
208 return fLength; 141 return fLength;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 // on the t value 192 // on the t value
260 // because we may not have enough precision in the t to get close enough 193 // because we may not have enough precision in the t to get close enough
261 // in the length. 194 // in the length.
262 if ((std::abs(lengthDiff) < kTolerance) || 195 if ((std::abs(lengthDiff) < kTolerance) ||
263 (std::abs(prevT - currentT) < kTolerance)) { 196 (std::abs(prevT - currentT) < kTolerance)) {
264 break; 197 break;
265 } 198 }
266 199
267 prevT = currentT; 200 prevT = currentT;
268 if (iterations < kNewtonIters) { 201 if (iterations < kNewtonIters) {
202 // TODO(hstern) switch here on curve type.
269 // This is just newton's formula. 203 // This is just newton's formula.
270 SkScalar dt = evaluateDerivative(fPts, fSegType, currentT).length(); 204 SkScalar dt = evaluateQuadDerivative(currentT).length();
271 newT = currentT - (lengthDiff / dt); 205 newT = currentT - (lengthDiff / dt);
272 206
273 // If newT is out of bounds, bisect inside newton. 207 // If newT is out of bounds, bisect inside newton.
274 if ((newT < 0.0f) || (newT > 1.0f)) { 208 if ((newT < 0.0f) || (newT > 1.0f)) {
275 newT = (minT + maxT) * 0.5f; 209 newT = (minT + maxT) * 0.5f;
276 } 210 }
277 } else if (iterations < kNewtonIters + kBisectIters) { 211 } else if (iterations < kNewtonIters + kBisectIters) {
278 if (lengthDiff > 0.0f) { 212 if (lengthDiff > 0.0f) {
279 maxT = currentT; 213 maxT = currentT;
280 } else { 214 } else {
281 minT = currentT; 215 minT = currentT;
282 } 216 }
283 // TODO(hstern) do a lerp here instead of a bisection 217 // TODO(hstern) do a lerp here instead of a bisection
284 newT = (minT + maxT) * 0.5f; 218 newT = (minT + maxT) * 0.5f;
285 } else { 219 } else {
286 SkDEBUGF(("%.7f %.7f didn't get close enough after bisection.\n", 220 SkDEBUGF(("%.7f %.7f didn't get close enough after bisection.\n",
287 currentT, currentLength)); 221 currentT, currentLength));
288 break; 222 break;
289 } 223 }
290 currentT = newT; 224 currentT = newT;
291 225
292 SkASSERT(minT <= maxT); 226 SkASSERT(minT <= maxT);
293 227
294 iterations++; 228 iterations++;
295 } 229 }
296 230
297 // debug. is there an SKDEBUG or something for ifdefs? 231 // debug. is there an SKDEBUG or something for ifdefs?
298 fIters = iterations; 232 fIters = iterations;
299 233
300 return currentT; 234 return currentT;
301 } 235 }
302 236
303 void SkCurveMeasure::getPosTanTime(SkScalar targetLength, SkPoint* pos, 237 void SkCurveMeasure::getPosTanTime(SkScalar targetLength, SkPoint* pos,
304 SkVector* tan, SkScalar* time) { 238 SkVector* tan, SkScalar* time) {
305 SkScalar t = getTime(targetLength); 239 SkScalar t = getTime(targetLength);
306 240
307 if (time) { 241 if (time) {
308 *time = t; 242 *time = t;
309 } 243 }
310 if (pos) { 244 if (pos) {
311 *pos = evaluate(fPts, fSegType, t); 245 // TODO(hstern) switch here on curve type.
246 *pos = evaluateQuad(t);
312 } 247 }
313 if (tan) { 248 if (tan) {
314 *tan = evaluateDerivative(fPts, fSegType, t); 249 // TODO(hstern) switch here on curve type.
250 *tan = evaluateQuadDerivative(t);
315 } 251 }
316 } 252 }
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
« no previous file with comments | « src/utils/SkCurveMeasure.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698