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 | 10 |
10 // for abs | 11 // for abs |
11 #include <cmath> | 12 #include <cmath> |
12 | 13 |
14 | |
15 /// Used inside SkCurveMeasure::getTime's Newton's iteration | |
16 static inline SkPoint evaluate(const SkPoint pts[4], SkSegType segType, | |
17 SkScalar t) { | |
18 SkPoint pos; | |
19 switch (segType) { | |
20 case kQuad_SegType: | |
21 pos = SkEvalQuadAt(pts, t); | |
22 break; | |
23 case kLine_SegType: | |
24 pos = pts[0]*t + pts[1]*(1-t); | |
25 break; | |
26 case kCubic_SegType: | |
27 SkEvalCubicAt(pts, t, &pos, nullptr, nullptr); | |
28 break; | |
29 case kConic_SegType: { | |
30 SkConic conic(pts, pts[3].x()); | |
31 conic.evalAt(t, &pos); | |
32 } | |
33 break; | |
34 default: | |
35 SkDebugf("Unimplemented"); | |
36 } | |
37 | |
38 return pos; | |
39 } | |
40 | |
41 /// Used inside SkCurveMeasure::getTime's Newton's iteration | |
42 static inline SkVector evaluateDerivative(const SkPoint pts[4], | |
43 SkSegType segType, SkScalar t) { | |
44 SkVector tan; | |
45 switch (segType) { | |
46 case kQuad_SegType: | |
47 tan = SkEvalQuadTangentAt(pts, t); | |
48 break; | |
49 case kLine_SegType: | |
50 tan = pts[1] - pts[0]; | |
51 break; | |
52 case kCubic_SegType: | |
53 SkEvalCubicAt(pts, t, nullptr, &tan, nullptr); | |
54 break; | |
55 case kConic_SegType: { | |
56 SkConic conic(pts, pts[3].x()); | |
57 conic.evalAt(t, nullptr, &tan); | |
58 } | |
59 break; | |
60 default: | |
61 SkDebugf("Unimplemented"); | |
62 } | |
63 | |
64 return tan; | |
65 } | |
66 /// Used in ArcLengthIntegrator::computeLength | |
13 static inline Sk8f evaluateDerivativeLength(const Sk8f& ts, | 67 static inline Sk8f evaluateDerivativeLength(const Sk8f& ts, |
14 const Sk8f (&xCoeff)[3], | 68 const Sk8f (&xCoeff)[3], |
15 const Sk8f (&yCoeff)[3], | 69 const Sk8f (&yCoeff)[3], |
16 const SkSegType segType) { | 70 const SkSegType segType) { |
17 Sk8f x; | 71 Sk8f x; |
18 Sk8f y; | 72 Sk8f y; |
19 switch (segType) { | 73 switch (segType) { |
20 case kQuad_SegType: | 74 case kQuad_SegType: |
21 x = xCoeff[0]*ts + xCoeff[1]; | 75 x = xCoeff[0]*ts + xCoeff[1]; |
22 y = yCoeff[0]*ts + yCoeff[1]; | 76 y = yCoeff[0]*ts + yCoeff[1]; |
23 break; | 77 break; |
24 case kLine_SegType: | 78 case kLine_SegType: |
25 SkDebugf("Unimplemented"); | 79 // length of line derivative is constant |
80 // and we precompute it in the constructor | |
81 return xCoeff[0]; | |
26 break; | 82 break; |
reed1
2016/08/10 12:08:07
nit: don't need the break;
Harry Stern
2016/08/10 17:55:58
Done.
| |
27 case kCubic_SegType: | 83 case kCubic_SegType: |
28 x = (xCoeff[0]*ts + xCoeff[1])*ts + xCoeff[2]; | 84 x = (xCoeff[0]*ts + xCoeff[1])*ts + xCoeff[2]; |
29 y = (yCoeff[0]*ts + yCoeff[1])*ts + yCoeff[2]; | 85 y = (yCoeff[0]*ts + yCoeff[1])*ts + yCoeff[2]; |
30 break; | 86 break; |
31 case kConic_SegType: | 87 case kConic_SegType: |
32 SkDebugf("Unimplemented"); | 88 SkDebugf("Unimplemented"); |
33 break; | 89 break; |
34 default: | 90 default: |
35 SkDebugf("Unimplemented"); | 91 SkDebugf("Unimplemented"); |
36 } | 92 } |
37 | 93 |
38 x = x * x; | 94 x = x * x; |
39 y = y * y; | 95 y = y * y; |
40 | 96 |
41 return (x + y).sqrt(); | 97 return (x + y).sqrt(); |
42 } | 98 } |
99 | |
43 ArcLengthIntegrator::ArcLengthIntegrator(const SkPoint* pts, SkSegType segType) | 100 ArcLengthIntegrator::ArcLengthIntegrator(const SkPoint* pts, SkSegType segType) |
44 : fSegType(segType) { | 101 : fSegType(segType) { |
45 switch (fSegType) { | 102 switch (fSegType) { |
46 case kQuad_SegType: { | 103 case kQuad_SegType: { |
47 float Ax = pts[0].x(); | 104 float Ax = pts[0].x(); |
48 float Bx = pts[1].x(); | 105 float Bx = pts[1].x(); |
49 float Cx = pts[2].x(); | 106 float Cx = pts[2].x(); |
50 float Ay = pts[0].y(); | 107 float Ay = pts[0].y(); |
51 float By = pts[1].y(); | 108 float By = pts[1].y(); |
52 float Cy = pts[2].y(); | 109 float Cy = pts[2].y(); |
53 | 110 |
54 // precompute coefficients for derivative | 111 // precompute coefficients for derivative |
55 xCoeff[0] = Sk8f(2.0f*(Ax - 2*Bx + Cx)); | 112 xCoeff[0] = Sk8f(2.0f*(Ax - 2*Bx + Cx)); |
56 xCoeff[1] = Sk8f(2.0f*(Bx - Ax)); | 113 xCoeff[1] = Sk8f(2.0f*(Bx - Ax)); |
57 | 114 |
58 yCoeff[0] = Sk8f(2.0f*(Ay - 2*By + Cy)); | 115 yCoeff[0] = Sk8f(2.0f*(Ay - 2*By + Cy)); |
59 yCoeff[1] = Sk8f(2.0f*(By - Ay)); | 116 yCoeff[1] = Sk8f(2.0f*(By - Ay)); |
60 } | 117 } |
61 break; | 118 break; |
62 case kLine_SegType: | 119 case kLine_SegType: { |
63 SkDEBUGF(("Unimplemented")); | 120 // the length of the derivative of a line is constant |
121 // we put in in both coeff arrays for consistency's sake | |
122 SkScalar length = (pts[1] - pts[0]).length(); | |
123 xCoeff[0] = Sk8f(length); | |
124 yCoeff[0] = Sk8f(length); | |
125 } | |
64 break; | 126 break; |
65 case kCubic_SegType: | 127 case kCubic_SegType: |
66 { | 128 { |
67 float Ax = pts[0].x(); | 129 float Ax = pts[0].x(); |
68 float Bx = pts[1].x(); | 130 float Bx = pts[1].x(); |
69 float Cx = pts[2].x(); | 131 float Cx = pts[2].x(); |
70 float Dx = pts[3].x(); | 132 float Dx = pts[3].x(); |
71 float Ay = pts[0].y(); | 133 float Ay = pts[0].y(); |
72 float By = pts[1].y(); | 134 float By = pts[1].y(); |
73 float Cy = pts[2].y(); | 135 float Cy = pts[2].y(); |
74 float Dy = pts[3].y(); | 136 float Dy = pts[3].y(); |
75 | 137 |
138 // precompute coefficients for derivative | |
76 xCoeff[0] = Sk8f(3.0f*(-Ax + 3.0f*(Bx - Cx) + Dx)); | 139 xCoeff[0] = Sk8f(3.0f*(-Ax + 3.0f*(Bx - Cx) + Dx)); |
77 xCoeff[1] = Sk8f(3.0f*(2.0f*(Ax - 2.0f*Bx + Cx))); | 140 xCoeff[1] = Sk8f(3.0f*(2.0f*(Ax - 2.0f*Bx + Cx))); |
78 xCoeff[2] = Sk8f(3.0f*(-Ax + Bx)); | 141 xCoeff[2] = Sk8f(3.0f*(-Ax + Bx)); |
79 | 142 |
80 yCoeff[0] = Sk8f(3.0f*(-Ay + 3.0f*(By - Cy) + Dy)); | 143 yCoeff[0] = Sk8f(3.0f*(-Ay + 3.0f*(By - Cy) + Dy)); |
81 yCoeff[1] = Sk8f(3.0f * -Ay + By + 2.0f*(Ay - 2.0f*By + Cy)); | 144 yCoeff[1] = Sk8f(3.0f * -Ay + By + 2.0f*(Ay - 2.0f*By + Cy)); |
82 yCoeff[2] = Sk8f(3.0f*(-Ay + By)); | 145 yCoeff[2] = Sk8f(3.0f*(-Ay + By)); |
83 } | 146 } |
84 break; | 147 break; |
85 case kConic_SegType: | 148 case kConic_SegType: |
(...skipping 24 matching lines...) Expand all Loading... | |
110 | 173 |
111 SkCurveMeasure::SkCurveMeasure(const SkPoint* pts, SkSegType segType) | 174 SkCurveMeasure::SkCurveMeasure(const SkPoint* pts, SkSegType segType) |
112 : fSegType(segType) { | 175 : fSegType(segType) { |
113 switch (fSegType) { | 176 switch (fSegType) { |
114 case SkSegType::kQuad_SegType: | 177 case SkSegType::kQuad_SegType: |
115 for (size_t i = 0; i < 3; i++) { | 178 for (size_t i = 0; i < 3; i++) { |
116 fPts[i] = pts[i]; | 179 fPts[i] = pts[i]; |
117 } | 180 } |
118 break; | 181 break; |
119 case SkSegType::kLine_SegType: | 182 case SkSegType::kLine_SegType: |
120 SkDebugf("Unimplemented"); | 183 fPts[0] = pts[0]; |
184 fPts[1] = pts[1]; | |
121 break; | 185 break; |
122 case SkSegType::kCubic_SegType: | 186 case SkSegType::kCubic_SegType: |
123 for (size_t i = 0; i < 4; i++) { | 187 for (size_t i = 0; i < 4; i++) { |
124 fPts[i] = pts[i]; | 188 fPts[i] = pts[i]; |
125 } | 189 } |
126 break; | 190 break; |
127 case SkSegType::kConic_SegType: | 191 case SkSegType::kConic_SegType: |
128 SkDebugf("Unimplemented"); | 192 for (size_t i = 0; i < 4; i++) { |
193 fPts[i] = pts[i]; | |
194 } | |
129 break; | 195 break; |
130 default: | 196 default: |
131 SkDEBUGF(("Unimplemented")); | 197 SkDEBUGF(("Unimplemented")); |
132 break; | 198 break; |
133 } | 199 } |
134 fIntegrator = ArcLengthIntegrator(fPts, fSegType); | 200 fIntegrator = ArcLengthIntegrator(fPts, fSegType); |
135 } | 201 } |
136 | 202 |
137 SkScalar SkCurveMeasure::getLength() { | 203 SkScalar SkCurveMeasure::getLength() { |
138 if (-1.0f == fLength) { | 204 if (-1.0f == fLength) { |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
192 // on the t value | 258 // on the t value |
193 // because we may not have enough precision in the t to get close enough | 259 // because we may not have enough precision in the t to get close enough |
194 // in the length. | 260 // in the length. |
195 if ((std::abs(lengthDiff) < kTolerance) || | 261 if ((std::abs(lengthDiff) < kTolerance) || |
196 (std::abs(prevT - currentT) < kTolerance)) { | 262 (std::abs(prevT - currentT) < kTolerance)) { |
197 break; | 263 break; |
198 } | 264 } |
199 | 265 |
200 prevT = currentT; | 266 prevT = currentT; |
201 if (iterations < kNewtonIters) { | 267 if (iterations < kNewtonIters) { |
202 // TODO(hstern) switch here on curve type. | |
203 // This is just newton's formula. | 268 // This is just newton's formula. |
204 SkScalar dt = evaluateQuadDerivative(currentT).length(); | 269 SkScalar dt = evaluateDerivative(fPts, fSegType, currentT).length(); |
205 newT = currentT - (lengthDiff / dt); | 270 newT = currentT - (lengthDiff / dt); |
206 | 271 |
207 // If newT is out of bounds, bisect inside newton. | 272 // If newT is out of bounds, bisect inside newton. |
208 if ((newT < 0.0f) || (newT > 1.0f)) { | 273 if ((newT < 0.0f) || (newT > 1.0f)) { |
209 newT = (minT + maxT) * 0.5f; | 274 newT = (minT + maxT) * 0.5f; |
210 } | 275 } |
211 } else if (iterations < kNewtonIters + kBisectIters) { | 276 } else if (iterations < kNewtonIters + kBisectIters) { |
212 if (lengthDiff > 0.0f) { | 277 if (lengthDiff > 0.0f) { |
213 maxT = currentT; | 278 maxT = currentT; |
214 } else { | 279 } else { |
(...skipping 13 matching lines...) Expand all Loading... | |
228 iterations++; | 293 iterations++; |
229 } | 294 } |
230 | 295 |
231 // debug. is there an SKDEBUG or something for ifdefs? | 296 // debug. is there an SKDEBUG or something for ifdefs? |
232 fIters = iterations; | 297 fIters = iterations; |
233 | 298 |
234 return currentT; | 299 return currentT; |
235 } | 300 } |
236 | 301 |
237 void SkCurveMeasure::getPosTanTime(SkScalar targetLength, SkPoint* pos, | 302 void SkCurveMeasure::getPosTanTime(SkScalar targetLength, SkPoint* pos, |
238 SkVector* tan, SkScalar* time) { | 303 SkVector* tan, SkScalar* time) { |
239 SkScalar t = getTime(targetLength); | 304 SkScalar t = getTime(targetLength); |
240 | 305 |
241 if (time) { | 306 if (time) { |
242 *time = t; | 307 *time = t; |
243 } | 308 } |
244 if (pos) { | 309 if (pos) { |
245 // TODO(hstern) switch here on curve type. | 310 *pos = evaluate(fPts, fSegType, t); |
246 *pos = evaluateQuad(t); | |
247 } | 311 } |
248 if (tan) { | 312 if (tan) { |
249 // TODO(hstern) switch here on curve type. | 313 *tan = evaluateDerivative(fPts, fSegType, t); |
250 *tan = evaluateQuadDerivative(t); | |
251 } | 314 } |
252 } | 315 } |
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 } | |
OLD | NEW |