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

Side by Side Diff: src/core/SkGeometry.cpp

Issue 1311273002: fix zero-length tangent (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: remove duplicate code; add unit tests Created 5 years, 3 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 | « gm/strokes.cpp ('k') | tests/GeometryTest.cpp » ('j') | 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 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 "SkNx.h" 10 #include "SkNx.h"
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 SkScalar A = src[4] - 2 * src[2] + C; 123 SkScalar A = src[4] - 2 * src[2] + C;
124 SkScalar B = 2 * (src[2] - C); 124 SkScalar B = 2 * (src[2] - C);
125 return SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C); 125 return SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C);
126 #else 126 #else
127 SkScalar ab = SkScalarInterp(src[0], src[2], t); 127 SkScalar ab = SkScalarInterp(src[0], src[2], t);
128 SkScalar bc = SkScalarInterp(src[2], src[4], t); 128 SkScalar bc = SkScalarInterp(src[2], src[4], t);
129 return SkScalarInterp(ab, bc, t); 129 return SkScalarInterp(ab, bc, t);
130 #endif 130 #endif
131 } 131 }
132 132
133 static SkScalar eval_quad_derivative(const SkScalar src[], SkScalar t) {
134 SkScalar A = src[4] - 2 * src[2] + src[0];
135 SkScalar B = src[2] - src[0];
136
137 return 2 * SkScalarMulAdd(A, t, B);
138 }
139
140 void SkQuadToCoeff(const SkPoint pts[3], SkPoint coeff[3]) { 133 void SkQuadToCoeff(const SkPoint pts[3], SkPoint coeff[3]) {
141 Sk2s p0 = from_point(pts[0]); 134 Sk2s p0 = from_point(pts[0]);
142 Sk2s p1 = from_point(pts[1]); 135 Sk2s p1 = from_point(pts[1]);
143 Sk2s p2 = from_point(pts[2]); 136 Sk2s p2 = from_point(pts[2]);
144 137
145 Sk2s p1minus2 = p1 - p0; 138 Sk2s p1minus2 = p1 - p0;
146 139
147 coeff[0] = to_point(p2 - p1 - p1 + p0); // A * t^2 140 coeff[0] = to_point(p2 - p1 - p1 + p0); // A * t^2
148 coeff[1] = to_point(p1minus2 + p1minus2); // B * t 141 coeff[1] = to_point(p1minus2 + p1minus2); // B * t
149 coeff[2] = pts[0]; // C 142 coeff[2] = pts[0]; // C
150 } 143 }
151 144
152 void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint* pt, SkVector* tange nt) { 145 void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint* pt, SkVector* tange nt) {
153 SkASSERT(src); 146 SkASSERT(src);
154 SkASSERT(t >= 0 && t <= SK_Scalar1); 147 SkASSERT(t >= 0 && t <= SK_Scalar1);
155 148
156 if (pt) { 149 if (pt) {
157 pt->set(eval_quad(&src[0].fX, t), eval_quad(&src[0].fY, t)); 150 pt->set(eval_quad(&src[0].fX, t), eval_quad(&src[0].fY, t));
158 } 151 }
159 if (tangent) { 152 if (tangent) {
160 tangent->set(eval_quad_derivative(&src[0].fX, t), 153 *tangent = SkEvalQuadTangentAt(src, t);
161 eval_quad_derivative(&src[0].fY, t));
162 } 154 }
163 } 155 }
164 156
165 SkPoint SkEvalQuadAt(const SkPoint src[3], SkScalar t) { 157 SkPoint SkEvalQuadAt(const SkPoint src[3], SkScalar t) {
166 SkASSERT(src); 158 SkASSERT(src);
167 SkASSERT(t >= 0 && t <= SK_Scalar1); 159 SkASSERT(t >= 0 && t <= SK_Scalar1);
168 160
169 const Sk2s t2(t); 161 const Sk2s t2(t);
170 162
171 Sk2s P0 = from_point(src[0]); 163 Sk2s P0 = from_point(src[0]);
172 Sk2s P1 = from_point(src[1]); 164 Sk2s P1 = from_point(src[1]);
173 Sk2s P2 = from_point(src[2]); 165 Sk2s P2 = from_point(src[2]);
174 166
175 Sk2s B = P1 - P0; 167 Sk2s B = P1 - P0;
176 Sk2s A = P2 - P1 - B; 168 Sk2s A = P2 - P1 - B;
177 169
178 return to_point((A * t2 + B+B) * t2 + P0); 170 return to_point((A * t2 + B+B) * t2 + P0);
179 } 171 }
180 172
181 SkVector SkEvalQuadTangentAt(const SkPoint src[3], SkScalar t) { 173 SkVector SkEvalQuadTangentAt(const SkPoint src[3], SkScalar t) {
174 // The derivative equation is 2(b - a +(a - 2b +c)t). This returns a
175 // zero tangent vector when t is 0 or 1, and the control point is equal
176 // to the end point. In this case, use the quad end points to compute the ta ngent.
177 if ((t == 0 && src[0] == src[1]) || (t == 1 && src[1] == src[2])) {
178 return src[2] - src[0];
179 }
182 SkASSERT(src); 180 SkASSERT(src);
183 SkASSERT(t >= 0 && t <= SK_Scalar1); 181 SkASSERT(t >= 0 && t <= SK_Scalar1);
184 182
185 Sk2s P0 = from_point(src[0]); 183 Sk2s P0 = from_point(src[0]);
186 Sk2s P1 = from_point(src[1]); 184 Sk2s P1 = from_point(src[1]);
187 Sk2s P2 = from_point(src[2]); 185 Sk2s P2 = from_point(src[2]);
188 186
189 Sk2s B = P1 - P0; 187 Sk2s B = P1 - P0;
190 Sk2s A = P2 - P1 - B; 188 Sk2s A = P2 - P1 - B;
191 Sk2s T = A * Sk2s(t) + B; 189 Sk2s T = A * Sk2s(t) + B;
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 389
392 void SkEvalCubicAt(const SkPoint src[4], SkScalar t, SkPoint* loc, 390 void SkEvalCubicAt(const SkPoint src[4], SkScalar t, SkPoint* loc,
393 SkVector* tangent, SkVector* curvature) { 391 SkVector* tangent, SkVector* curvature) {
394 SkASSERT(src); 392 SkASSERT(src);
395 SkASSERT(t >= 0 && t <= SK_Scalar1); 393 SkASSERT(t >= 0 && t <= SK_Scalar1);
396 394
397 if (loc) { 395 if (loc) {
398 loc->set(eval_cubic(&src[0].fX, t), eval_cubic(&src[0].fY, t)); 396 loc->set(eval_cubic(&src[0].fX, t), eval_cubic(&src[0].fY, t));
399 } 397 }
400 if (tangent) { 398 if (tangent) {
401 tangent->set(eval_cubic_derivative(&src[0].fX, t), 399 // The derivative equation returns a zero tangent vector when t is 0 or 1, and the
402 eval_cubic_derivative(&src[0].fY, t)); 400 // adjacent control point is equal to the end point. In this case, use t he
401 // next control point or the end points to compute the tangent.
402 if ((t == 0 && src[0] == src[1]) || (t == 1 && src[2] == src[3])) {
403 if (t == 0) {
404 *tangent = src[2] - src[0];
405 } else {
406 *tangent = src[3] - src[1];
407 }
408 if (!tangent->fX && !tangent->fY) {
409 *tangent = src[3] - src[0];
410 }
411 } else {
412 tangent->set(eval_cubic_derivative(&src[0].fX, t),
413 eval_cubic_derivative(&src[0].fY, t));
414 }
403 } 415 }
404 if (curvature) { 416 if (curvature) {
405 curvature->set(eval_cubic_2ndDerivative(&src[0].fX, t), 417 curvature->set(eval_cubic_2ndDerivative(&src[0].fX, t),
406 eval_cubic_2ndDerivative(&src[0].fY, t)); 418 eval_cubic_2ndDerivative(&src[0].fY, t));
407 } 419 }
408 } 420 }
409 421
410 /** Cubic'(t) = At^2 + Bt + C, where 422 /** Cubic'(t) = At^2 + Bt + C, where
411 A = 3(-a + 3(b - c) + d) 423 A = 3(-a + 3(b - c) + d)
412 B = 6(a - 2b + c) 424 B = 6(a - 2b + c)
(...skipping 756 matching lines...) Expand 10 before | Expand all | Expand 10 after
1169 SkScalar w, 1181 SkScalar w,
1170 SkScalar coeff[3]) { 1182 SkScalar coeff[3]) {
1171 const SkScalar P20 = src[4] - src[0]; 1183 const SkScalar P20 = src[4] - src[0];
1172 const SkScalar P10 = src[2] - src[0]; 1184 const SkScalar P10 = src[2] - src[0];
1173 const SkScalar wP10 = w * P10; 1185 const SkScalar wP10 = w * P10;
1174 coeff[0] = w * P20 - P20; 1186 coeff[0] = w * P20 - P20;
1175 coeff[1] = P20 - 2 * wP10; 1187 coeff[1] = P20 - 2 * wP10;
1176 coeff[2] = wP10; 1188 coeff[2] = wP10;
1177 } 1189 }
1178 1190
1179 static SkScalar conic_eval_tan(const SkScalar coord[], SkScalar w, SkScalar t) {
1180 SkScalar coeff[3];
1181 conic_deriv_coeff(coord, w, coeff);
1182 return t * (t * coeff[0] + coeff[1]) + coeff[2];
1183 }
1184
1185 static bool conic_find_extrema(const SkScalar src[], SkScalar w, SkScalar* t) { 1191 static bool conic_find_extrema(const SkScalar src[], SkScalar w, SkScalar* t) {
1186 SkScalar coeff[3]; 1192 SkScalar coeff[3];
1187 conic_deriv_coeff(src, w, coeff); 1193 conic_deriv_coeff(src, w, coeff);
1188 1194
1189 SkScalar tValues[2]; 1195 SkScalar tValues[2];
1190 int roots = SkFindUnitQuadRoots(coeff[0], coeff[1], coeff[2], tValues); 1196 int roots = SkFindUnitQuadRoots(coeff[0], coeff[1], coeff[2], tValues);
1191 SkASSERT(0 == roots || 1 == roots); 1197 SkASSERT(0 == roots || 1 == roots);
1192 1198
1193 if (1 == roots) { 1199 if (1 == roots) {
1194 *t = tValues[0]; 1200 *t = tValues[0];
(...skipping 30 matching lines...) Expand all
1225 } 1231 }
1226 1232
1227 void SkConic::evalAt(SkScalar t, SkPoint* pt, SkVector* tangent) const { 1233 void SkConic::evalAt(SkScalar t, SkPoint* pt, SkVector* tangent) const {
1228 SkASSERT(t >= 0 && t <= SK_Scalar1); 1234 SkASSERT(t >= 0 && t <= SK_Scalar1);
1229 1235
1230 if (pt) { 1236 if (pt) {
1231 pt->set(conic_eval_pos(&fPts[0].fX, fW, t), 1237 pt->set(conic_eval_pos(&fPts[0].fX, fW, t),
1232 conic_eval_pos(&fPts[0].fY, fW, t)); 1238 conic_eval_pos(&fPts[0].fY, fW, t));
1233 } 1239 }
1234 if (tangent) { 1240 if (tangent) {
1235 tangent->set(conic_eval_tan(&fPts[0].fX, fW, t), 1241 *tangent = evalTangentAt(t);
1236 conic_eval_tan(&fPts[0].fY, fW, t));
1237 } 1242 }
1238 } 1243 }
1239 1244
1240 void SkConic::chopAt(SkScalar t, SkConic dst[2]) const { 1245 void SkConic::chopAt(SkScalar t, SkConic dst[2]) const {
1241 SkP3D tmp[3], tmp2[3]; 1246 SkP3D tmp[3], tmp2[3];
1242 1247
1243 ratquad_mapTo3D(fPts, fW, tmp); 1248 ratquad_mapTo3D(fPts, fW, tmp);
1244 1249
1245 p3d_interp(&tmp[0].fX, &tmp2[0].fX, t); 1250 p3d_interp(&tmp[0].fX, &tmp2[0].fX, t);
1246 p3d_interp(&tmp[0].fY, &tmp2[0].fY, t); 1251 p3d_interp(&tmp[0].fY, &tmp2[0].fY, t);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1284 Sk2s numer = quad_poly_eval(A, B, C, tt); 1289 Sk2s numer = quad_poly_eval(A, B, C, tt);
1285 1290
1286 B = times_2(ww - one); 1291 B = times_2(ww - one);
1287 A = Sk2s(0)-B; 1292 A = Sk2s(0)-B;
1288 Sk2s denom = quad_poly_eval(A, B, one, tt); 1293 Sk2s denom = quad_poly_eval(A, B, one, tt);
1289 1294
1290 return to_point(numer / denom); 1295 return to_point(numer / denom);
1291 } 1296 }
1292 1297
1293 SkVector SkConic::evalTangentAt(SkScalar t) const { 1298 SkVector SkConic::evalTangentAt(SkScalar t) const {
1299 // The derivative equation returns a zero tangent vector when t is 0 or 1,
1300 // and the control point is equal to the end point.
1301 // In this case, use the conic endpoints to compute the tangent.
1302 if ((t == 0 && fPts[0] == fPts[1]) || (t == 1 && fPts[1] == fPts[2])) {
1303 return fPts[2] - fPts[0];
1304 }
1294 Sk2s p0 = from_point(fPts[0]); 1305 Sk2s p0 = from_point(fPts[0]);
1295 Sk2s p1 = from_point(fPts[1]); 1306 Sk2s p1 = from_point(fPts[1]);
1296 Sk2s p2 = from_point(fPts[2]); 1307 Sk2s p2 = from_point(fPts[2]);
1297 Sk2s ww(fW); 1308 Sk2s ww(fW);
1298 1309
1299 Sk2s p20 = p2 - p0; 1310 Sk2s p20 = p2 - p0;
1300 Sk2s p10 = p1 - p0; 1311 Sk2s p10 = p1 - p0;
1301 1312
1302 Sk2s C = ww * p10; 1313 Sk2s C = ww * p10;
1303 Sk2s A = ww * p20 - p20; 1314 Sk2s A = ww * p20 - p20;
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after
1579 matrix.preScale(SK_Scalar1, -SK_Scalar1); 1590 matrix.preScale(SK_Scalar1, -SK_Scalar1);
1580 } 1591 }
1581 if (userMatrix) { 1592 if (userMatrix) {
1582 matrix.postConcat(*userMatrix); 1593 matrix.postConcat(*userMatrix);
1583 } 1594 }
1584 for (int i = 0; i < conicCount; ++i) { 1595 for (int i = 0; i < conicCount; ++i) {
1585 matrix.mapPoints(dst[i].fPts, 3); 1596 matrix.mapPoints(dst[i].fPts, 3);
1586 } 1597 }
1587 return conicCount; 1598 return conicCount;
1588 } 1599 }
OLDNEW
« no previous file with comments | « gm/strokes.cpp ('k') | tests/GeometryTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698