OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
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 "SkGeometry.h" | 8 #include "SkGeometry.h" |
9 #include "SkMatrix.h" | 9 #include "SkMatrix.h" |
10 #include "Sk2x.h" | 10 #include "Sk2x.h" |
11 | 11 |
| 12 static Sk2s from_point(const SkPoint& point) { |
| 13 return Sk2s::Load(&point.fX); |
| 14 } |
| 15 |
| 16 static SkPoint to_point(const Sk2s& x) { |
| 17 SkPoint point; |
| 18 x.store(&point.fX); |
| 19 return point; |
| 20 } |
| 21 |
| 22 static SkVector to_vector(const Sk2s& x) { |
| 23 SkVector vector; |
| 24 x.store(&vector.fX); |
| 25 return vector; |
| 26 } |
| 27 |
| 28 #if 0 |
| 29 static Sk2s divide(const Sk2s& numer, const Sk2s& denom) { |
| 30 SkScalar numerStorage[2], denomStorage[2]; |
| 31 numer.store(numerStorage); |
| 32 denom.store(denomStorage); |
| 33 numerStorage[0] /= denomStorage[0]; |
| 34 numerStorage[1] /= denomStorage[1]; |
| 35 return Sk2s::Load(numerStorage); |
| 36 } |
| 37 #endif |
| 38 |
12 /** If defined, this makes eval_quad and eval_cubic do more setup (sometimes | 39 /** If defined, this makes eval_quad and eval_cubic do more setup (sometimes |
13 involving integer multiplies by 2 or 3, but fewer calls to SkScalarMul. | 40 involving integer multiplies by 2 or 3, but fewer calls to SkScalarMul. |
14 May also introduce overflow of fixed when we compute our setup. | 41 May also introduce overflow of fixed when we compute our setup. |
15 */ | 42 */ |
16 // #define DIRECT_EVAL_OF_POLYNOMIALS | 43 // #define DIRECT_EVAL_OF_POLYNOMIALS |
17 | 44 |
18 //////////////////////////////////////////////////////////////////////// | 45 //////////////////////////////////////////////////////////////////////// |
19 | 46 |
20 static int is_not_monotonic(SkScalar a, SkScalar b, SkScalar c) { | 47 static int is_not_monotonic(SkScalar a, SkScalar b, SkScalar c) { |
21 SkScalar ab = a - b; | 48 SkScalar ab = a - b; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 SkTSwap<SkScalar>(roots[0], roots[1]); | 112 SkTSwap<SkScalar>(roots[0], roots[1]); |
86 else if (roots[0] == roots[1]) // nearly-equal? | 113 else if (roots[0] == roots[1]) // nearly-equal? |
87 r -= 1; // skip the double root | 114 r -= 1; // skip the double root |
88 } | 115 } |
89 return (int)(r - roots); | 116 return (int)(r - roots); |
90 } | 117 } |
91 | 118 |
92 /////////////////////////////////////////////////////////////////////////////// | 119 /////////////////////////////////////////////////////////////////////////////// |
93 /////////////////////////////////////////////////////////////////////////////// | 120 /////////////////////////////////////////////////////////////////////////////// |
94 | 121 |
| 122 static Sk2s quad_poly_eval(const Sk2s& A, const Sk2s& B, const Sk2s& C, const Sk
2s& t) { |
| 123 return (A * t + B) * t + C; |
| 124 } |
| 125 |
95 static SkScalar eval_quad(const SkScalar src[], SkScalar t) { | 126 static SkScalar eval_quad(const SkScalar src[], SkScalar t) { |
96 SkASSERT(src); | 127 SkASSERT(src); |
97 SkASSERT(t >= 0 && t <= SK_Scalar1); | 128 SkASSERT(t >= 0 && t <= SK_Scalar1); |
98 | 129 |
99 #ifdef DIRECT_EVAL_OF_POLYNOMIALS | 130 #ifdef DIRECT_EVAL_OF_POLYNOMIALS |
100 SkScalar C = src[0]; | 131 SkScalar C = src[0]; |
101 SkScalar A = src[4] - 2 * src[2] + C; | 132 SkScalar A = src[4] - 2 * src[2] + C; |
102 SkScalar B = 2 * (src[2] - C); | 133 SkScalar B = 2 * (src[2] - C); |
103 return SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C); | 134 return SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C); |
104 #else | 135 #else |
(...skipping 20 matching lines...) Expand all Loading... |
125 if (tangent) { | 156 if (tangent) { |
126 tangent->set(eval_quad_derivative(&src[0].fX, t), | 157 tangent->set(eval_quad_derivative(&src[0].fX, t), |
127 eval_quad_derivative(&src[0].fY, t)); | 158 eval_quad_derivative(&src[0].fY, t)); |
128 } | 159 } |
129 } | 160 } |
130 | 161 |
131 SkPoint SkEvalQuadAt(const SkPoint src[3], SkScalar t) { | 162 SkPoint SkEvalQuadAt(const SkPoint src[3], SkScalar t) { |
132 SkASSERT(src); | 163 SkASSERT(src); |
133 SkASSERT(t >= 0 && t <= SK_Scalar1); | 164 SkASSERT(t >= 0 && t <= SK_Scalar1); |
134 | 165 |
135 const Sk2f t2(t); | 166 const Sk2s t2(t); |
136 | 167 |
137 Sk2f P0 = Sk2f::Load(&src[0].fX); | 168 Sk2s P0 = from_point(src[0]); |
138 Sk2f P1 = Sk2f::Load(&src[1].fX); | 169 Sk2s P1 = from_point(src[1]); |
139 Sk2f P2 = Sk2f::Load(&src[2].fX); | 170 Sk2s P2 = from_point(src[2]); |
140 | 171 |
141 Sk2f B = P1 - P0; | 172 Sk2s B = P1 - P0; |
142 Sk2f A = P2 - P1 - B; | 173 Sk2s A = P2 - P1 - B; |
143 | 174 |
144 SkPoint result; | 175 return to_point((A * t2 + B+B) * t2 + P0); |
145 ((A * t2 + B+B) * t2 + P0).store(&result.fX); | |
146 return result; | |
147 } | 176 } |
148 | 177 |
149 SkVector SkEvalQuadTangentAt(const SkPoint src[3], SkScalar t) { | 178 SkVector SkEvalQuadTangentAt(const SkPoint src[3], SkScalar t) { |
150 SkASSERT(src); | 179 SkASSERT(src); |
151 SkASSERT(t >= 0 && t <= SK_Scalar1); | 180 SkASSERT(t >= 0 && t <= SK_Scalar1); |
152 | 181 |
153 Sk2f P0 = Sk2f::Load(&src[0].fX); | 182 Sk2s P0 = from_point(src[0]); |
154 Sk2f P1 = Sk2f::Load(&src[1].fX); | 183 Sk2s P1 = from_point(src[1]); |
155 Sk2f P2 = Sk2f::Load(&src[2].fX); | 184 Sk2s P2 = from_point(src[2]); |
156 | 185 |
157 Sk2f B = P1 - P0; | 186 Sk2s B = P1 - P0; |
158 Sk2f A = P2 - P1 - B; | 187 Sk2s A = P2 - P1 - B; |
159 Sk2f T = A * Sk2f(t) + B; | 188 Sk2s T = A * Sk2s(t) + B; |
160 | 189 |
161 SkVector result; | 190 return to_vector(T + T); |
162 (T + T).store(&result.fX); | |
163 return result; | |
164 } | 191 } |
165 | 192 |
166 static void interp_quad_coords(const SkScalar* src, SkScalar* dst, SkScalar t) { | 193 static void interp_quad_coords(const SkScalar* src, SkScalar* dst, SkScalar t) { |
167 SkScalar ab = SkScalarInterp(src[0], src[2], t); | 194 SkScalar ab = SkScalarInterp(src[0], src[2], t); |
168 SkScalar bc = SkScalarInterp(src[2], src[4], t); | 195 SkScalar bc = SkScalarInterp(src[2], src[4], t); |
169 | 196 |
170 dst[0] = src[0]; | 197 dst[0] = src[0]; |
171 dst[2] = ab; | 198 dst[2] = ab; |
172 dst[4] = SkScalarInterp(ab, bc, t); | 199 dst[4] = SkScalarInterp(ab, bc, t); |
173 dst[6] = bc; | 200 dst[6] = bc; |
174 dst[8] = src[4]; | 201 dst[8] = src[4]; |
175 } | 202 } |
176 | 203 |
177 void SkChopQuadAt(const SkPoint src[3], SkPoint dst[5], SkScalar t) { | 204 void SkChopQuadAt(const SkPoint src[3], SkPoint dst[5], SkScalar t) { |
178 SkASSERT(t > 0 && t < SK_Scalar1); | 205 SkASSERT(t > 0 && t < SK_Scalar1); |
179 | 206 |
180 interp_quad_coords(&src[0].fX, &dst[0].fX, t); | 207 interp_quad_coords(&src[0].fX, &dst[0].fX, t); |
181 interp_quad_coords(&src[0].fY, &dst[0].fY, t); | 208 interp_quad_coords(&src[0].fY, &dst[0].fY, t); |
182 } | 209 } |
183 | 210 |
184 static inline Sk2s interp(const Sk2s& v0, const Sk2s& v1, const Sk2s& t) { | 211 static inline Sk2s interp(const Sk2s& v0, const Sk2s& v1, const Sk2s& t) { |
185 return v0 + (v1 - v0) * t; | 212 return v0 + (v1 - v0) * t; |
186 } | 213 } |
187 | 214 |
188 void SkChopQuadAt2(const SkPoint src[3], SkPoint dst[5], SkScalar t) { | 215 void SkChopQuadAt2(const SkPoint src[3], SkPoint dst[5], SkScalar t) { |
189 SkASSERT(t > 0 && t < SK_Scalar1); | 216 SkASSERT(t > 0 && t < SK_Scalar1); |
190 | 217 |
191 Sk2s p0 = Sk2f::Load(&src[0].fX); | 218 Sk2s p0 = from_point(src[0]); |
192 Sk2s p1 = Sk2f::Load(&src[1].fX); | 219 Sk2s p1 = from_point(src[1]); |
193 Sk2s p2 = Sk2f::Load(&src[2].fX); | 220 Sk2s p2 = from_point(src[2]); |
194 Sk2s tt = Sk2s(t); | 221 Sk2s tt = Sk2s(t); |
195 | 222 |
196 Sk2s p01 = interp(p0, p1, tt); | 223 Sk2s p01 = interp(p0, p1, tt); |
197 Sk2s p12 = interp(p1, p2, tt); | 224 Sk2s p12 = interp(p1, p2, tt); |
198 | 225 |
199 p0.store(&dst[0].fX); | 226 dst[0] = to_point(p0); |
200 p01.store(&dst[1].fX); | 227 dst[1] = to_point(p01); |
201 interp(p01, p12, tt).store(&dst[2].fX); | 228 dst[2] = to_point(interp(p01, p12, tt)); |
202 p12.store(&dst[3].fX); | 229 dst[3] = to_point(p12); |
203 p2.store(&dst[4].fX); | 230 dst[4] = to_point(p2); |
204 } | 231 } |
205 | 232 |
206 void SkChopQuadAtHalf(const SkPoint src[3], SkPoint dst[5]) { | 233 void SkChopQuadAtHalf(const SkPoint src[3], SkPoint dst[5]) { |
207 SkScalar x01 = SkScalarAve(src[0].fX, src[1].fX); | 234 SkScalar x01 = SkScalarAve(src[0].fX, src[1].fX); |
208 SkScalar y01 = SkScalarAve(src[0].fY, src[1].fY); | 235 SkScalar y01 = SkScalarAve(src[0].fY, src[1].fY); |
209 SkScalar x12 = SkScalarAve(src[1].fX, src[2].fX); | 236 SkScalar x12 = SkScalarAve(src[1].fX, src[2].fX); |
210 SkScalar y12 = SkScalarAve(src[1].fY, src[2].fY); | 237 SkScalar y12 = SkScalarAve(src[1].fY, src[2].fY); |
211 | 238 |
212 dst[0] = src[0]; | 239 dst[0] = src[0]; |
213 dst[1].set(x01, y01); | 240 dst[1].set(x01, y01); |
(...skipping 1030 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1244 // w1 /= sqrt(w0*w2) | 1271 // w1 /= sqrt(w0*w2) |
1245 // | 1272 // |
1246 // However, in our case, we know that for dst[0]: | 1273 // However, in our case, we know that for dst[0]: |
1247 // w0 == 1, and for dst[1], w2 == 1 | 1274 // w0 == 1, and for dst[1], w2 == 1 |
1248 // | 1275 // |
1249 SkScalar root = SkScalarSqrt(tmp2[1].fZ); | 1276 SkScalar root = SkScalarSqrt(tmp2[1].fZ); |
1250 dst[0].fW = tmp2[0].fZ / root; | 1277 dst[0].fW = tmp2[0].fZ / root; |
1251 dst[1].fW = tmp2[2].fZ / root; | 1278 dst[1].fW = tmp2[2].fZ / root; |
1252 } | 1279 } |
1253 | 1280 |
| 1281 static Sk2s times_2(const Sk2s& value) { |
| 1282 return value + value; |
| 1283 } |
| 1284 |
| 1285 SkPoint SkConic::evalAt(SkScalar t) const { |
| 1286 Sk2s p0 = from_point(fPts[0]); |
| 1287 Sk2s p1 = from_point(fPts[1]); |
| 1288 Sk2s p2 = from_point(fPts[2]); |
| 1289 Sk2s tt = Sk2s(t); |
| 1290 Sk2s ww = Sk2s(fW); |
| 1291 Sk2s one = Sk2s(1); |
| 1292 |
| 1293 Sk2s p1w = p1 * ww; |
| 1294 Sk2s C = p0; |
| 1295 Sk2s A = p2 - times_2(p1w) + p0; |
| 1296 Sk2s B = times_2(p1w - C); |
| 1297 Sk2s numer = quad_poly_eval(A, B, C, tt); |
| 1298 |
| 1299 B = times_2(ww - one); |
| 1300 A = -B; |
| 1301 Sk2s denom = quad_poly_eval(A, B, one, tt); |
| 1302 |
| 1303 return to_point(numer / denom); |
| 1304 } |
| 1305 |
| 1306 SkVector SkConic::evalTangentAt(SkScalar t) const { |
| 1307 Sk2s p0 = from_point(fPts[0]); |
| 1308 Sk2s p1 = from_point(fPts[1]); |
| 1309 Sk2s p2 = from_point(fPts[2]); |
| 1310 Sk2s ww = Sk2s(fW); |
| 1311 |
| 1312 Sk2s p20 = p2 - p0; |
| 1313 Sk2s p10 = p1 - p0; |
| 1314 |
| 1315 Sk2s C = ww * p10; |
| 1316 Sk2s A = ww * p20 - p20; |
| 1317 Sk2s B = p20 - C - C; |
| 1318 |
| 1319 return to_vector(quad_poly_eval(A, B, C, Sk2s(t))); |
| 1320 #if 0 |
| 1321 static void conic_deriv_coeff(const SkScalar src[], |
| 1322 SkScalar w, |
| 1323 SkScalar coeff[3]) { |
| 1324 const SkScalar P20 = src[4] - src[0]; |
| 1325 const SkScalar P10 = src[2] - src[0]; |
| 1326 const SkScalar wP10 = w * P10; |
| 1327 coeff[0] = w * P20 - P20; |
| 1328 coeff[1] = P20 - 2 * wP10; |
| 1329 coeff[2] = wP10; |
| 1330 } |
| 1331 |
| 1332 static SkScalar conic_eval_tan(const SkScalar coord[], SkScalar w, SkScalar
t) { |
| 1333 SkScalar coeff[3]; |
| 1334 conic_deriv_coeff(coord, w, coeff); |
| 1335 return t * (t * coeff[0] + coeff[1]) + coeff[2]; |
| 1336 } |
| 1337 #endif |
| 1338 } |
| 1339 |
1254 static SkScalar subdivide_w_value(SkScalar w) { | 1340 static SkScalar subdivide_w_value(SkScalar w) { |
1255 return SkScalarSqrt(SK_ScalarHalf + w * SK_ScalarHalf); | 1341 return SkScalarSqrt(SK_ScalarHalf + w * SK_ScalarHalf); |
1256 } | 1342 } |
1257 | 1343 |
1258 void SkConic::chop(SkConic dst[2]) const { | 1344 void SkConic::chop(SkConic dst[2]) const { |
1259 SkScalar scale = SkScalarInvert(SK_Scalar1 + fW); | 1345 SkScalar scale = SkScalarInvert(SK_Scalar1 + fW); |
1260 SkScalar p1x = fW * fPts[1].fX; | 1346 SkScalar p1x = fW * fPts[1].fX; |
1261 SkScalar p1y = fW * fPts[1].fY; | 1347 SkScalar p1y = fW * fPts[1].fY; |
1262 SkScalar mx = (fPts[0].fX + 2 * p1x + fPts[2].fX) * scale * SK_ScalarHalf; | 1348 SkScalar mx = (fPts[0].fX + 2 * p1x + fPts[2].fX) * scale * SK_ScalarHalf; |
1263 SkScalar my = (fPts[0].fY + 2 * p1y + fPts[2].fY) * scale * SK_ScalarHalf; | 1349 SkScalar my = (fPts[0].fY + 2 * p1y + fPts[2].fY) * scale * SK_ScalarHalf; |
1264 | 1350 |
1265 dst[0].fPts[0] = fPts[0]; | 1351 dst[0].fPts[0] = fPts[0]; |
1266 dst[0].fPts[1].set((fPts[0].fX + p1x) * scale, | 1352 dst[0].fPts[1].set((fPts[0].fX + p1x) * scale, |
1267 (fPts[0].fY + p1y) * scale); | 1353 (fPts[0].fY + p1y) * scale); |
1268 dst[0].fPts[2].set(mx, my); | 1354 dst[0].fPts[2].set(mx, my); |
1269 | 1355 |
1270 dst[1].fPts[0].set(mx, my); | 1356 dst[1].fPts[0].set(mx, my); |
1271 dst[1].fPts[1].set((p1x + fPts[2].fX) * scale, | 1357 dst[1].fPts[1].set((p1x + fPts[2].fX) * scale, |
1272 (p1y + fPts[2].fY) * scale); | 1358 (p1y + fPts[2].fY) * scale); |
1273 dst[1].fPts[2] = fPts[2]; | 1359 dst[1].fPts[2] = fPts[2]; |
1274 | 1360 |
1275 dst[0].fW = dst[1].fW = subdivide_w_value(fW); | 1361 dst[0].fW = dst[1].fW = subdivide_w_value(fW); |
1276 } | 1362 } |
1277 | 1363 |
| 1364 void SkConic::chop2(SkConic * SK_RESTRICT dst) const { |
| 1365 Sk2s scale(SkScalarInvert(SK_Scalar1 + fW)); |
| 1366 // Sk2s scale = Sk2s(SK_Scalar1 + fW).invert(); |
| 1367 SkScalar newW = subdivide_w_value(fW); |
| 1368 |
| 1369 Sk2s p0 = from_point(fPts[0]); |
| 1370 Sk2s p1 = from_point(fPts[1]); |
| 1371 Sk2s p2 = from_point(fPts[2]); |
| 1372 Sk2s ww = Sk2s(fW); |
| 1373 Sk2s half = Sk2s(0.5f); |
| 1374 |
| 1375 Sk2s wp1 = ww * p1; |
| 1376 Sk2s m = ((p0 + wp1 + wp1 + p2) * half) * scale; |
| 1377 |
| 1378 dst[0].fPts[0] = fPts[0]; |
| 1379 dst[0].fPts[1] = to_point((p0 + wp1) * scale); |
| 1380 dst[0].fPts[2] = dst[1].fPts[0] = to_point(m); |
| 1381 dst[1].fPts[1] = to_point((wp1 + p2) * scale); |
| 1382 dst[1].fPts[2] = fPts[2]; |
| 1383 |
| 1384 dst[0].fW = dst[1].fW = newW; |
| 1385 } |
| 1386 |
1278 /* | 1387 /* |
1279 * "High order approximation of conic sections by quadratic splines" | 1388 * "High order approximation of conic sections by quadratic splines" |
1280 * by Michael Floater, 1993 | 1389 * by Michael Floater, 1993 |
1281 */ | 1390 */ |
1282 #define AS_QUAD_ERROR_SETUP \ | 1391 #define AS_QUAD_ERROR_SETUP \ |
1283 SkScalar a = fW - 1; \ | 1392 SkScalar a = fW - 1; \ |
1284 SkScalar k = a / (4 * (2 + a)); \ | 1393 SkScalar k = a / (4 * (2 + a)); \ |
1285 SkScalar x = k * (fPts[0].fX - 2 * fPts[1].fX + fPts[2].fX); \ | 1394 SkScalar x = k * (fPts[0].fX - 2 * fPts[1].fX + fPts[2].fX); \ |
1286 SkScalar y = k * (fPts[0].fY - 2 * fPts[1].fY + fPts[2].fY); | 1395 SkScalar y = k * (fPts[0].fY - 2 * fPts[1].fY + fPts[2].fY); |
1287 | 1396 |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1517 matrix.preScale(SK_Scalar1, -SK_Scalar1); | 1626 matrix.preScale(SK_Scalar1, -SK_Scalar1); |
1518 } | 1627 } |
1519 if (userMatrix) { | 1628 if (userMatrix) { |
1520 matrix.postConcat(*userMatrix); | 1629 matrix.postConcat(*userMatrix); |
1521 } | 1630 } |
1522 for (int i = 0; i < conicCount; ++i) { | 1631 for (int i = 0; i < conicCount; ++i) { |
1523 matrix.mapPoints(dst[i].fPts, 3); | 1632 matrix.mapPoints(dst[i].fPts, 3); |
1524 } | 1633 } |
1525 return conicCount; | 1634 return conicCount; |
1526 } | 1635 } |
OLD | NEW |