OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |