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