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

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: Add comment about fixed precision of quadrature used 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 w484 = 4 - 8*w + 4*w*w;
129 Sk8f denom = ts*(-4 + 4*w + ts*(8 - 12*w + 4*w*w + ts*(-2*w484
130 + ts*(w484)))) + 1;
caryclark 2016/08/19 11:48:29 More factoring is possible here, e.g. -(-4 + 4*w)
Harry Stern 2016/08/19 16:31:28 Oh clever, I didn't think of that. Done.
131
132 x = xnum / denom;
133 y = ynum / denom;
134 }
86 break; 135 break;
87 default: 136 default:
88 UNIMPLEMENTED; 137 UNIMPLEMENTED;
89 } 138 }
90 139
91 x = x * x; 140 x = x * x;
92 y = y * y; 141 y = y * y;
93 142
94 return (x + y).sqrt(); 143 return (x + y).sqrt();
95 } 144 }
96 145
97 ArcLengthIntegrator::ArcLengthIntegrator(const SkPoint* pts, SkSegType segType) 146 ArcLengthIntegrator::ArcLengthIntegrator(const SkPoint* pts, SkSegType segType)
98 : fSegType(segType) { 147 : fSegType(segType) {
99 switch (fSegType) { 148 switch (fSegType) {
100 case kQuad_SegType: { 149 case kQuad_SegType: {
101 float Ax = pts[0].x(); 150 float Ax = pts[0].x();
102 float Bx = pts[1].x(); 151 float Bx = pts[1].x();
103 float Cx = pts[2].x(); 152 float Cx = pts[2].x();
104 float Ay = pts[0].y(); 153 float Ay = pts[0].y();
105 float By = pts[1].y(); 154 float By = pts[1].y();
106 float Cy = pts[2].y(); 155 float Cy = pts[2].y();
107 156
108 // precompute coefficients for derivative 157 // precompute coefficients for derivative
109 xCoeff[0] = Sk8f(2*(Ax - 2*Bx + Cx)); 158 fXCoeff[0] = Sk8f(2*(Ax - 2*Bx + Cx));
110 xCoeff[1] = Sk8f(2*(Bx - Ax)); 159 fXCoeff[1] = Sk8f(2*(Bx - Ax));
111 160
112 yCoeff[0] = Sk8f(2*(Ay - 2*By + Cy)); 161 fYCoeff[0] = Sk8f(2*(Ay - 2*By + Cy));
113 yCoeff[1] = Sk8f(2*(By - Ay)); 162 fYCoeff[1] = Sk8f(2*(By - Ay));
114 } 163 }
115 break; 164 break;
116 case kCubic_SegType: 165 case kCubic_SegType:
117 { 166 {
118 float Ax = pts[0].x(); 167 float Ax = pts[0].x();
119 float Bx = pts[1].x(); 168 float Bx = pts[1].x();
120 float Cx = pts[2].x(); 169 float Cx = pts[2].x();
121 float Dx = pts[3].x(); 170 float Dx = pts[3].x();
122 float Ay = pts[0].y(); 171 float Ay = pts[0].y();
123 float By = pts[1].y(); 172 float By = pts[1].y();
124 float Cy = pts[2].y(); 173 float Cy = pts[2].y();
125 float Dy = pts[3].y(); 174 float Dy = pts[3].y();
126 175
127 // precompute coefficients for derivative 176 // precompute coefficients for derivative
128 xCoeff[0] = Sk8f(3*(-Ax + 3*(Bx - Cx) + Dx)); 177 fXCoeff[0] = Sk8f(3*(-Ax + 3*(Bx - Cx) + Dx));
129 xCoeff[1] = Sk8f(6*(Ax - 2*Bx + Cx)); 178 fXCoeff[1] = Sk8f(6*(Ax - 2*Bx + Cx));
130 xCoeff[2] = Sk8f(3*(-Ax + Bx)); 179 fXCoeff[2] = Sk8f(3*(-Ax + Bx));
131 180
132 yCoeff[0] = Sk8f(3*(-Ay + 3*(By - Cy) + Dy)); 181 fYCoeff[0] = Sk8f(3*(-Ay + 3*(By - Cy) + Dy));
133 yCoeff[1] = Sk8f(6*(Ay - 2*By + Cy)); 182 fYCoeff[1] = Sk8f(6*(Ay - 2*By + Cy));
134 yCoeff[2] = Sk8f(3*(-Ay + By)); 183 fYCoeff[2] = Sk8f(3*(-Ay + By));
135 } 184 }
136 break; 185 break;
137 case kConic_SegType: 186 case kConic_SegType: {
138 UNIMPLEMENTED; 187 float Ax = pts[0].x();
188 float Bx = pts[1].x();
189 float Cx = pts[2].x();
190 float Ay = pts[0].y();
191 float By = pts[1].y();
192 float Cy = pts[2].y();
193
194 fConicW = pts[3].x();
195
196 SkScalar w = fConicW;
197
198 // precompute coefficients for derivative
199 fXCoeff[0] = Sk8f(2*(Ax - Cx - Ax*w + Cx*w));
200 fXCoeff[1] = Sk8f(-2*(Ax - Cx - 2*(Ax*w - Bx*w)));
201 fXCoeff[2] = Sk8f(-2*(Ax*w - Bx*w));
202
203 fYCoeff[0] = Sk8f(2*(Ay - Cy - Ay*w + Cy*w));
204 fYCoeff[1] = Sk8f(-2*(Ay - Cy - 2*(Ay*w - By*w)));
205 fYCoeff[2] = Sk8f(-2*(Ay*w - By*w));
caryclark 2016/08/19 11:48:29 Can come elements, e.g. -2*(Ax*w - Bx*w) be factor
Harry Stern 2016/08/19 16:31:28 Sure. The only reason I didn't do it initially is
206 }
139 break; 207 break;
140 default: 208 default:
141 UNIMPLEMENTED; 209 UNIMPLEMENTED;
142 } 210 }
143 } 211 }
144 212
145 // We use Gaussian quadrature 213 // We use Gaussian quadrature
146 // (https://en.wikipedia.org/wiki/Gaussian_quadrature) 214 // (https://en.wikipedia.org/wiki/Gaussian_quadrature)
147 // to approximate the arc length integral here, because it is amenable to SIMD. 215 // to approximate the arc length integral here, because it is amenable to SIMD.
148 SkScalar ArcLengthIntegrator::computeLength(SkScalar t) { 216 SkScalar ArcLengthIntegrator::computeLength(SkScalar t) {
149 SkScalar length = 0.0f; 217 SkScalar length = 0.0f;
150 218
151 Sk8f lengths = evaluateDerivativeLength(absc*t, xCoeff, yCoeff, fSegType); 219 Sk8f lengths =
152 lengths = weights*lengths; 220 evaluateDerivativeLength(absc * t, fXCoeff, fYCoeff, fConicW, fSegType);
221 lengths = weights * lengths;
153 // is it faster or more accurate to sum and then multiply or vice versa? 222 // is it faster or more accurate to sum and then multiply or vice versa?
154 lengths = lengths*(t*0.5f); 223 lengths = lengths*(t*0.5f);
caryclark 2016/08/19 11:48:30 Thanks for adding spaces around the 'weight * leng
Harry Stern 2016/08/19 16:31:28 In a previous review mtklein basically said not to
155 224
156 // Why does SkNx index with ints? does negative index mean something? 225 // Why does SkNx index with ints? does negative index mean something?
157 for (int i = 0; i < 8; i++) { 226 for (int i = 0; i < 8; i++) {
158 length += lengths[i]; 227 length += lengths[i];
159 } 228 }
160 return length; 229 return length;
161 } 230 }
162 231
163 SkCurveMeasure::SkCurveMeasure(const SkPoint* pts, SkSegType segType) 232 SkCurveMeasure::SkCurveMeasure(const SkPoint* pts, SkSegType segType)
164 : fSegType(segType) { 233 : fSegType(segType) {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 // at each step, and computing the derivative of the arc length integral, 277 // 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). 278 // which is equal to the length of the tangent (so we have to do a sqrt).
210 279
211 SkScalar SkCurveMeasure::getTime(SkScalar targetLength) { 280 SkScalar SkCurveMeasure::getTime(SkScalar targetLength) {
212 if (targetLength <= 0.0f) { 281 if (targetLength <= 0.0f) {
213 return 0.0f; 282 return 0.0f;
214 } 283 }
215 284
216 SkScalar currentLength = getLength(); 285 SkScalar currentLength = getLength();
217 286
218 if (targetLength > currentLength || (SkScalarNearlyEqual(targetLength, curre ntLength))) { 287 if (targetLength > currentLength ||
288 (SkScalarNearlyEqual(targetLength, currentLength))) {
caryclark 2016/08/19 11:48:29 parens unneeded targetLength - some_epsilon >= cu
Harry Stern 2016/08/19 16:31:28 Per discussion we're going to leave it like it is.
219 return 1.0f; 289 return 1.0f;
220 } 290 }
221 if (kLine_SegType == fSegType) { 291 if (kLine_SegType == fSegType) {
222 return targetLength / currentLength; 292 return targetLength / currentLength;
223 } 293 }
224 294
225 // initial estimate of t is percentage of total length 295 // initial estimate of t is percentage of total length
226 SkScalar currentT = targetLength / currentLength; 296 SkScalar currentT = targetLength / currentLength;
227 SkScalar prevT = -1.0f; 297 SkScalar prevT = -1.0f;
228 SkScalar newT; 298 SkScalar newT;
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
301 if (time) { 371 if (time) {
302 *time = t; 372 *time = t;
303 } 373 }
304 if (pos) { 374 if (pos) {
305 *pos = evaluate(fPts, fSegType, t); 375 *pos = evaluate(fPts, fSegType, t);
306 } 376 }
307 if (tan) { 377 if (tan) {
308 *tan = evaluateDerivative(fPts, fSegType, t); 378 *tan = evaluateDerivative(fPts, fSegType, t);
309 } 379 }
310 } 380 }
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