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

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

Issue 2243313002: Implement Conics in SkCurveMeasure (Closed) Base URL: https://skia.googlesource.com/skia.git@cubic_fix
Patch Set: Refactor coefficients and minor fixups 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" 9 #include "SkGeometry.h"
10 10
11 // for abs 11 // for abs
12 #include <cmath> 12 #include <cmath>
13 13
14 #define UNIMPLEMENTED SkDEBUGF(("%s:%d unimplemented\n", __FILE__, __LINE__)) 14 #define UNIMPLEMENTED SkDEBUGFAILF("%s:%d unimplemented\n", __FILE__, __LINE__)
15 15
16 /// Used inside SkCurveMeasure::getTime's Newton's iteration 16 /// Used inside SkCurveMeasure::getTime's Newton's iteration
17 static inline SkPoint evaluate(const SkPoint pts[4], SkSegType segType, 17 static inline SkPoint evaluate(const SkPoint pts[4], SkSegType segType,
18 SkScalar t) { 18 SkScalar t) {
19 SkPoint pos; 19 SkPoint pos;
20 switch (segType) { 20 switch (segType) {
21 case kQuad_SegType: 21 case kQuad_SegType:
22 pos = SkEvalQuadAt(pts, t); 22 pos = SkEvalQuadAt(pts, t);
23 break; 23 break;
24 case kLine_SegType: 24 case kLine_SegType:
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
58 SkConic conic(pts, pts[3].x()); 58 SkConic conic(pts, pts[3].x());
59 conic.evalAt(t, nullptr, &tan); 59 conic.evalAt(t, nullptr, &tan);
60 } 60 }
61 break; 61 break;
62 default: 62 default:
63 UNIMPLEMENTED; 63 UNIMPLEMENTED;
64 } 64 }
65 65
66 return tan; 66 return tan;
67 } 67 }
68
69 /*
70 * Derivation of conic formulae based on parameterization from
71 * http://citeseerx.ist.psu.edu/viewdoc/
72 * download?doi=10.1.1.44.5740&rep=rep1&type=ps
73 * referenced in SkGeometry.cpp
74 *
75 * Usage: below and in the constructor for ArcLengthIntegrator
76 *
77 * Mathematica:
78 *
79 * conic[t_] := (A*(1 - t)^2 + 2*w*B*(1 - t)*t + C*t^2)/
80 * (1 - 2*(1 - w)*t + 2*(1 - w)*t^2)
81 *
82 * conic[0]
83 *
84 * >>> A
85 *
86 * conic[1]
87 *
88 * >>> C
89 *
90 * Simplify[Derivative[1][conic][t]]
91 *
92 * >>> (2*(C*t*(1 + t*(-1 + w)) - A*(-1 + t)*(t*(-1 + w) - w) + B*(1 - 2*t)*w))/
93 * (1 + 2*t*(-1 + w) - 2*t^2*(-1 + w))^2
94 *
95 * HornerForm[Numerator[Simplify[Derivative[1][conic][t]]], t]
96 *
97 * >>> -2*A*w + 2*B*w + t*(-2*A + 2*C + 4*A*w - 4*B*w +
98 * t*(2*A - 2*C - 2*A*w + 2*C*w))
99 *
100 * HornerForm[Denominator[Simplify[Derivative[1][conic][t]]], t]
101 *
102 * >>> 1 + t*(-4 + 4*w + t*(8 - 12*w + 4*w^2 +
103 * t*(-8 + 16*w - 8*w^2 + t*(4 - 8*w + 4*w^2))))
104 *
105 */
106
68 /// Used in ArcLengthIntegrator::computeLength 107 /// Used in ArcLengthIntegrator::computeLength
69 static inline Sk8f evaluateDerivativeLength(const Sk8f& ts, 108 static inline Sk8f evaluateDerivativeLength(const Sk8f& ts,
70 const Sk8f (&xCoeff)[3], 109 const Sk8f (&fXCoeff)[3],
71 const Sk8f (&yCoeff)[3], 110 const Sk8f (&fYCoeff)[3],
111 const SkScalar w,
72 const SkSegType segType) { 112 const SkSegType segType) {
73 Sk8f x; 113 Sk8f x;
74 Sk8f y; 114 Sk8f y;
75 switch (segType) { 115 switch (segType) {
76 case kQuad_SegType: 116 case kQuad_SegType:
77 x = xCoeff[0]*ts + xCoeff[1]; 117 x = fXCoeff[0]*ts + fXCoeff[1];
78 y = yCoeff[0]*ts + yCoeff[1]; 118 y = fYCoeff[0]*ts + fYCoeff[1];
79 break; 119 break;
80 case kCubic_SegType: 120 case kCubic_SegType:
81 x = (xCoeff[0]*ts + xCoeff[1])*ts + xCoeff[2]; 121 x = (fXCoeff[0]*ts + fXCoeff[1])*ts + fXCoeff[2];
82 y = (yCoeff[0]*ts + yCoeff[1])*ts + yCoeff[2]; 122 y = (fYCoeff[0]*ts + fYCoeff[1])*ts + fYCoeff[2];
83 break; 123 break;
84 case kConic_SegType: 124 case kConic_SegType: {
85 UNIMPLEMENTED; 125 Sk8f xnum = (fXCoeff[0]*ts + fXCoeff[1])*ts + fXCoeff[2];
126 Sk8f ynum = (fYCoeff[0]*ts + fYCoeff[1])*ts + fYCoeff[2];
127
128 SkScalar w44 = 4 + 4*w;
129 SkScalar w484 = 4 - 8*w + 4*w*w;
130 Sk8f denom = ts*(-8 + w44 + ts*(8 + -w44 + w484 + ts*(-2*w484
131 + ts*(w484)))) + 1;
132
133 x = xnum / denom;
134 y = ynum / denom;
135 }
86 break; 136 break;
87 default: 137 default:
88 UNIMPLEMENTED; 138 UNIMPLEMENTED;
89 } 139 }
90 140
91 x = x * x; 141 x = x * x;
92 y = y * y; 142 y = y * y;
93 143
94 return (x + y).sqrt(); 144 return (x + y).sqrt();
95 } 145 }
96 146
97 ArcLengthIntegrator::ArcLengthIntegrator(const SkPoint* pts, SkSegType segType) 147 ArcLengthIntegrator::ArcLengthIntegrator(const SkPoint* pts, SkSegType segType)
98 : fSegType(segType) { 148 : fSegType(segType) {
99 switch (fSegType) { 149 switch (fSegType) {
100 case kQuad_SegType: { 150 case kQuad_SegType: {
101 float Ax = pts[0].x(); 151 float Ax = pts[0].x();
102 float Bx = pts[1].x(); 152 float Bx = pts[1].x();
103 float Cx = pts[2].x(); 153 float Cx = pts[2].x();
104 float Ay = pts[0].y(); 154 float Ay = pts[0].y();
105 float By = pts[1].y(); 155 float By = pts[1].y();
106 float Cy = pts[2].y(); 156 float Cy = pts[2].y();
107 157
108 // precompute coefficients for derivative 158 // precompute coefficients for derivative
109 xCoeff[0] = Sk8f(2*(Ax - 2*Bx + Cx)); 159 fXCoeff[0] = Sk8f(2*(Ax - 2*Bx + Cx));
110 xCoeff[1] = Sk8f(2*(Bx - Ax)); 160 fXCoeff[1] = Sk8f(2*(Bx - Ax));
111 161
112 yCoeff[0] = Sk8f(2*(Ay - 2*By + Cy)); 162 fYCoeff[0] = Sk8f(2*(Ay - 2*By + Cy));
113 yCoeff[1] = Sk8f(2*(By - Ay)); 163 fYCoeff[1] = Sk8f(2*(By - Ay));
114 } 164 }
115 break; 165 break;
116 case kCubic_SegType: 166 case kCubic_SegType:
117 { 167 {
118 float Ax = pts[0].x(); 168 float Ax = pts[0].x();
119 float Bx = pts[1].x(); 169 float Bx = pts[1].x();
120 float Cx = pts[2].x(); 170 float Cx = pts[2].x();
121 float Dx = pts[3].x(); 171 float Dx = pts[3].x();
122 float Ay = pts[0].y(); 172 float Ay = pts[0].y();
123 float By = pts[1].y(); 173 float By = pts[1].y();
124 float Cy = pts[2].y(); 174 float Cy = pts[2].y();
125 float Dy = pts[3].y(); 175 float Dy = pts[3].y();
126 176
127 // precompute coefficients for derivative 177 // precompute coefficients for derivative
128 xCoeff[0] = Sk8f(3*(-Ax + 3*(Bx - Cx) + Dx)); 178 fXCoeff[0] = Sk8f(3*(-Ax + 3*(Bx - Cx) + Dx));
129 xCoeff[1] = Sk8f(6*(Ax - 2*Bx + Cx)); 179 fXCoeff[1] = Sk8f(6*(Ax - 2*Bx + Cx));
130 xCoeff[2] = Sk8f(3*(-Ax + Bx)); 180 fXCoeff[2] = Sk8f(3*(-Ax + Bx));
131 181
132 yCoeff[0] = Sk8f(3*(-Ay + 3*(By - Cy) + Dy)); 182 fYCoeff[0] = Sk8f(3*(-Ay + 3*(By - Cy) + Dy));
133 yCoeff[1] = Sk8f(6*(Ay - 2*By + Cy)); 183 fYCoeff[1] = Sk8f(6*(Ay - 2*By + Cy));
134 yCoeff[2] = Sk8f(3*(-Ay + By)); 184 fYCoeff[2] = Sk8f(3*(-Ay + By));
135 } 185 }
136 break; 186 break;
137 case kConic_SegType: 187 case kConic_SegType: {
138 UNIMPLEMENTED; 188 float Ax = pts[0].x();
189 float Bx = pts[1].x();
190 float Cx = pts[2].x();
191 float Ay = pts[0].y();
192 float By = pts[1].y();
193 float Cy = pts[2].y();
194
195 fConicW = pts[3].x();
196
197 SkScalar w = fConicW;
198
199 // precompute coefficients for derivative
200 SkScalar AwBwx = -2*(Ax*w - Bx*w);
201 SkScalar AxCx = Ax - Cx;
202 fXCoeff[0] = Sk8f(2*(AxCx - Ax*w + Cx*w));
203 fXCoeff[1] = Sk8f(-2*(AxCx + AwBwx));
204 fXCoeff[2] = Sk8f(AwBwx);
205
206 SkScalar AwBwy = -2*(Ay*w - By*w);
207 SkScalar AyCy = Ay - Cy;
208 fYCoeff[0] = Sk8f(2*(AyCy - Ay*w + Cy*w));
209 fYCoeff[1] = Sk8f(-2*(AyCy + AwBwy));
210 fYCoeff[2] = Sk8f(AwBwy);
211 }
139 break; 212 break;
140 default: 213 default:
141 UNIMPLEMENTED; 214 UNIMPLEMENTED;
142 } 215 }
143 } 216 }
144 217
145 // We use Gaussian quadrature 218 // We use Gaussian quadrature
146 // (https://en.wikipedia.org/wiki/Gaussian_quadrature) 219 // (https://en.wikipedia.org/wiki/Gaussian_quadrature)
147 // to approximate the arc length integral here, because it is amenable to SIMD. 220 // to approximate the arc length integral here, because it is amenable to SIMD.
148 SkScalar ArcLengthIntegrator::computeLength(SkScalar t) { 221 SkScalar ArcLengthIntegrator::computeLength(SkScalar t) {
149 SkScalar length = 0.0f; 222 SkScalar length = 0.0f;
150 223
151 Sk8f lengths = evaluateDerivativeLength(absc*t, xCoeff, yCoeff, fSegType); 224 Sk8f lengths =
152 lengths = weights*lengths; 225 evaluateDerivativeLength(absc * t, fXCoeff, fYCoeff, fConicW, fSegType);
226 lengths = weights * lengths;
153 // is it faster or more accurate to sum and then multiply or vice versa? 227 // is it faster or more accurate to sum and then multiply or vice versa?
154 lengths = lengths*(t*0.5f); 228 lengths = lengths*(t*0.5f);
155 229
156 // Why does SkNx index with ints? does negative index mean something? 230 // Why does SkNx index with ints? does negative index mean something?
157 for (int i = 0; i < 8; i++) { 231 for (int i = 0; i < 8; i++) {
158 length += lengths[i]; 232 length += lengths[i];
159 } 233 }
160 return length; 234 return length;
161 } 235 }
162 236
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 // The computationally expensive parts are the integral approximation 281 // The computationally expensive parts are the integral approximation
208 // at each step, and computing the derivative of the arc length integral, 282 // at each step, and computing the derivative of the arc length integral,
209 // which is equal to the length of the tangent (so we have to do a sqrt). 283 // which is equal to the length of the tangent (so we have to do a sqrt).
210 284
211 SkScalar SkCurveMeasure::getTime(SkScalar targetLength) { 285 SkScalar SkCurveMeasure::getTime(SkScalar targetLength) {
212 if (targetLength <= 0.0f) { 286 if (targetLength <= 0.0f) {
213 return 0.0f; 287 return 0.0f;
214 } 288 }
215 289
216 SkScalar currentLength = getLength(); 290 SkScalar currentLength = getLength();
217 291 if (targetLength > currentLength ||
218 if (targetLength > currentLength || (SkScalarNearlyEqual(targetLength, curre ntLength))) { 292 (SkScalarNearlyEqual(targetLength, currentLength))) {
219 return 1.0f; 293 return 1.0f;
220 } 294 }
221 if (kLine_SegType == fSegType) { 295 if (kLine_SegType == fSegType) {
222 return targetLength / currentLength; 296 return targetLength / currentLength;
223 } 297 }
224 298
225 // initial estimate of t is percentage of total length 299 // initial estimate of t is percentage of total length
226 SkScalar currentT = targetLength / currentLength; 300 SkScalar currentT = targetLength / currentLength;
227 SkScalar prevT = -1.0f; 301 SkScalar prevT = -1.0f;
228 SkScalar newT; 302 SkScalar newT;
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
301 if (time) { 375 if (time) {
302 *time = t; 376 *time = t;
303 } 377 }
304 if (pos) { 378 if (pos) {
305 *pos = evaluate(fPts, fSegType, t); 379 *pos = evaluate(fPts, fSegType, t);
306 } 380 }
307 if (tan) { 381 if (tan) {
308 *tan = evaluateDerivative(fPts, fSegType, t); 382 *tan = evaluateDerivative(fPts, fSegType, t);
309 } 383 }
310 } 384 }
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