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

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

Issue 24810002: Yet another attempt to fix quadratic circle approximation (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Added GMs to ignore file Created 7 years, 2 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 | Annotate | Revision Log
« no previous file with comments | « expectations/gm/ignored-tests.txt ('k') | src/core/SkPath.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 /* 2 /*
3 * Copyright 2006 The Android Open Source Project 3 * Copyright 2006 The Android Open Source Project
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 9
10 #include "SkGeometry.h" 10 #include "SkGeometry.h"
(...skipping 1187 matching lines...) Expand 10 before | Expand all | Expand 10 after
1198 SkScalar C = a - d; 1198 SkScalar C = a - d;
1199 1199
1200 SkScalar roots[2]; 1200 SkScalar roots[2];
1201 int count = SkFindUnitQuadRoots(A, B, C, roots); 1201 int count = SkFindUnitQuadRoots(A, B, C, roots);
1202 1202
1203 SkASSERT(count <= 1); 1203 SkASSERT(count <= 1);
1204 return count == 1 ? roots[0] : 0; 1204 return count == 1 ? roots[0] : 0;
1205 } 1205 }
1206 1206
1207 /* given a quad-curve and a point (x,y), chop the quad at that point and place 1207 /* given a quad-curve and a point (x,y), chop the quad at that point and place
1208 the new off-curve point and endpoint into 'dest'. The new end point is used 1208 the new off-curve point and endpoint into 'dest'.
1209 (rather than (x,y)) to compensate for numerical inaccuracies.
1210 Should only return false if the computed pos is the start of the curve 1209 Should only return false if the computed pos is the start of the curve
1211 (i.e. root == 0) 1210 (i.e. root == 0)
1212 */ 1211 */
1213 static bool truncate_last_curve(const SkPoint quad[3], SkScalar x, SkScalar y, S kPoint* dest) 1212 static bool truncate_last_curve(const SkPoint quad[3], SkScalar x, SkScalar y, S kPoint* dest)
1214 { 1213 {
1215 const SkScalar* base; 1214 const SkScalar* base;
1216 SkScalar value; 1215 SkScalar value;
1217 1216
1218 if (SkScalarAbs(x) < SkScalarAbs(y)) { 1217 if (SkScalarAbs(x) < SkScalarAbs(y)) {
1219 base = &quad[0].fX; 1218 base = &quad[0].fX;
1220 value = x; 1219 value = x;
1221 } else { 1220 } else {
1222 base = &quad[0].fY; 1221 base = &quad[0].fY;
1223 value = y; 1222 value = y;
1224 } 1223 }
1225 1224
1226 // note: this returns 0 if it thinks value is out of range, meaning the 1225 // note: this returns 0 if it thinks value is out of range, meaning the
1227 // root might return something outside of [0, 1) 1226 // root might return something outside of [0, 1)
1228 SkScalar t = quad_solve(base[0], base[2], base[4], value); 1227 SkScalar t = quad_solve(base[0], base[2], base[4], value);
1229 1228
1230 if (t > 0) 1229 if (t > 0)
1231 { 1230 {
1232 SkPoint tmp[5]; 1231 SkPoint tmp[5];
1233 SkChopQuadAt(quad, tmp, t); 1232 SkChopQuadAt(quad, tmp, t);
1234 dest[0] = tmp[1]; 1233 dest[0] = tmp[1];
1235 dest[1] = tmp[2]; 1234 dest[1].set(x, y);
1236 return true; 1235 return true;
1237 } else { 1236 } else {
1238 /* t == 0 means either the value triggered a root outside of [0, 1) 1237 /* t == 0 means either the value triggered a root outside of [0, 1)
1239 For our purposes, we can ignore the <= 0 roots, but we want to 1238 For our purposes, we can ignore the <= 0 roots, but we want to
1240 catch the >= 1 roots (which given our caller, will basically mean 1239 catch the >= 1 roots (which given our caller, will basically mean
1241 a root of 1, give-or-take numerical instability). If we are in the 1240 a root of 1, give-or-take numerical instability). If we are in the
1242 >= 1 case, return the existing offCurve point. 1241 >= 1 case, return the existing offCurve point.
1243 1242
1244 The test below checks to see if we are close to the "end" of the 1243 The test below checks to see if we are close to the "end" of the
1245 curve (near base[4]). Rather than specifying a tolerance, I just 1244 curve (near base[4]). Rather than specifying a tolerance, I just
1246 check to see if value is on to the right/left of the middle point 1245 check to see if value is on to the right/left of the middle point
1247 (depending on the direction/sign of the end points). 1246 (depending on the direction/sign of the end points).
1248 */ 1247 */
1249 if ((base[0] < base[4] && value > base[2]) || 1248 if ((base[0] < base[4] && value > base[2]) ||
1250 (base[0] > base[4] && value < base[2])) // should root have been 1 1249 (base[0] > base[4] && value < base[2])) // should root have been 1
1251 { 1250 {
1252 dest[0] = quad[1]; 1251 dest[0] = quad[1];
1253 dest[1].set(x, y); 1252 dest[1].set(x, y);
1254 return true; 1253 return true;
1255 } 1254 }
1256 } 1255 }
1257 return false; 1256 return false;
1258 } 1257 }
1259 1258
1260 #ifdef SK_SCALAR_IS_FLOAT 1259 #ifdef SK_SCALAR_IS_FLOAT
1261 1260
1262 // Due to floating point issues (i.e., 1.0f - SK_ScalarRoot2Over2 != 1261 // Due to floating point issues (i.e., 1.0f - SK_ScalarRoot2Over2 !=
1263 // SK_ScalarRoot2Over2 - SK_ScalarTanPIOver8) a cruder root2over2 1262 // SK_ScalarRoot2Over2 - SK_ScalarTanPIOver8), the "correct" off curve
1264 // approximation is required to make the quad circle points convex. The 1263 // control points cause the quadratic circle approximation to be concave.
1265 // root of the problem is that with the root2over2 value in SkScalar.h 1264 // SK_OffEps is used to pull in the off-curve control points a bit
1266 // the arcs really are ever so slightly concave. Some alternative fixes 1265 // to make the quadratic approximation convex.
1267 // to this problem (besides just arbitrarily pushing out the mid-point as 1266 // Pulling the off-curve controls points in is preferable to pushing some
1268 // is done here) are: 1267 // of the on-curve points off.
1269 // Adjust all the points (not just the middle) to both better approximate 1268 #define SK_OffEps 0.0001f
1270 // the curve and remain convex
1271 // Switch over to using cubics rather then quads
1272 // Use a different method to create the mid-point (e.g., compute
1273 // the two side points, average them, then move it out as needed
1274 #define SK_ScalarRoot2Over2_QuadCircle 0.7072f
1275
1276 #else 1269 #else
1277 #define SK_ScalarRoot2Over2_QuadCircle SK_FixedRoot2Over2 1270 #define SK_OffEps 0
1278 #endif 1271 #endif
1279 1272
1280 1273
1281 static const SkPoint gQuadCirclePts[kSkBuildQuadArcStorage] = { 1274 static const SkPoint gQuadCirclePts[kSkBuildQuadArcStorage] = {
1282 { SK_Scalar1, 0 }, 1275 { SK_Scalar1, 0 },
1283 { SK_Scalar1, SK_ScalarTanPIOver8 }, 1276 { SK_Scalar1 - SK_OffEps, SK_ScalarTanPIOver8 - SK_OffEps },
1284 { SK_ScalarRoot2Over2_QuadCircle, SK_ScalarRoot2Over2_QuadCircle }, 1277 { SK_ScalarRoot2Over2, SK_ScalarRoot2Over2 },
1285 { SK_ScalarTanPIOver8, SK_Scalar1 }, 1278 { SK_ScalarTanPIOver8 - SK_OffEps, SK_Scalar1 - SK_OffEps },
1286 1279
1287 { 0, SK_Scalar1 }, 1280 { 0, SK_Scalar1 },
1288 { -SK_ScalarTanPIOver8, SK_Scalar1 }, 1281 { -SK_ScalarTanPIOver8 + SK_OffEps,SK_Scalar1 - SK_OffEps },
1289 { -SK_ScalarRoot2Over2_QuadCircle, SK_ScalarRoot2Over2_QuadCircle }, 1282 { -SK_ScalarRoot2Over2, SK_ScalarRoot2Over2 },
1290 { -SK_Scalar1, SK_ScalarTanPIOver8 }, 1283 { -SK_Scalar1 + SK_OffEps, SK_ScalarTanPIOver8 - SK_OffEps },
1291 1284
1292 { -SK_Scalar1, 0 }, 1285 { -SK_Scalar1, 0 },
1293 { -SK_Scalar1, -SK_ScalarTanPIOver8 }, 1286 { -SK_Scalar1 + SK_OffEps, -SK_ScalarTanPIOver8 + SK_OffEps },
1294 { -SK_ScalarRoot2Over2_QuadCircle, -SK_ScalarRoot2Over2_QuadCircle }, 1287 { -SK_ScalarRoot2Over2, -SK_ScalarRoot2Over2 },
1295 { -SK_ScalarTanPIOver8, -SK_Scalar1 }, 1288 { -SK_ScalarTanPIOver8 + SK_OffEps,-SK_Scalar1 + SK_OffEps },
1296 1289
1297 { 0, -SK_Scalar1 }, 1290 { 0, -SK_Scalar1 },
1298 { SK_ScalarTanPIOver8, -SK_Scalar1 }, 1291 { SK_ScalarTanPIOver8 - SK_OffEps, -SK_Scalar1 + SK_OffEps },
1299 { SK_ScalarRoot2Over2_QuadCircle, -SK_ScalarRoot2Over2_QuadCircle }, 1292 { SK_ScalarRoot2Over2, -SK_ScalarRoot2Over2 },
1300 { SK_Scalar1, -SK_ScalarTanPIOver8 }, 1293 { SK_Scalar1 - SK_OffEps, -SK_ScalarTanPIOver8 + SK_OffEps },
1301 1294
1302 { SK_Scalar1, 0 } 1295 { SK_Scalar1, 0 }
1303 }; 1296 };
1304 1297
1305 int SkBuildQuadArc(const SkVector& uStart, const SkVector& uStop, 1298 int SkBuildQuadArc(const SkVector& uStart, const SkVector& uStop,
1306 SkRotationDirection dir, const SkMatrix* userMatrix, 1299 SkRotationDirection dir, const SkMatrix* userMatrix,
1307 SkPoint quadPoints[]) 1300 SkPoint quadPoints[])
1308 { 1301 {
1309 // rotate by x,y so that uStart is (1.0) 1302 // rotate by x,y so that uStart is (1.0)
1310 SkScalar x = SkPoint::DotProduct(uStart, uStop); 1303 SkScalar x = SkPoint::DotProduct(uStart, uStop);
(...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after
1657 } 1650 }
1658 if (this->findYExtrema(&t)) { 1651 if (this->findYExtrema(&t)) {
1659 this->evalAt(t, &pts[count++]); 1652 this->evalAt(t, &pts[count++]);
1660 } 1653 }
1661 bounds->set(pts, count); 1654 bounds->set(pts, count);
1662 } 1655 }
1663 1656
1664 void SkConic::computeFastBounds(SkRect* bounds) const { 1657 void SkConic::computeFastBounds(SkRect* bounds) const {
1665 bounds->set(fPts, 3); 1658 bounds->set(fPts, 3);
1666 } 1659 }
OLDNEW
« no previous file with comments | « expectations/gm/ignored-tests.txt ('k') | src/core/SkPath.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698