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