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 | 10 |
11 bool SkXRayCrossesLine(const SkXRay& pt, const SkPoint pts[2], bool* ambiguous)
{ | 11 bool SkXRayCrossesLine(const SkXRay& pt, |
| 12 const SkPoint pts[2], |
| 13 bool* ambiguous) { |
12 if (ambiguous) { | 14 if (ambiguous) { |
13 *ambiguous = false; | 15 *ambiguous = false; |
14 } | 16 } |
15 // Determine quick discards. | 17 // Determine quick discards. |
16 // Consider query line going exactly through point 0 to not | 18 // Consider query line going exactly through point 0 to not |
17 // intersect, for symmetry with SkXRayCrossesMonotonicCubic. | 19 // intersect, for symmetry with SkXRayCrossesMonotonicCubic. |
18 if (pt.fY == pts[0].fY) { | 20 if (pt.fY == pts[0].fY) { |
19 if (ambiguous) { | 21 if (ambiguous) { |
20 *ambiguous = true; | 22 *ambiguous = true; |
21 } | 23 } |
(...skipping 545 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
567 dst[4].set(x123, y123); | 569 dst[4].set(x123, y123); |
568 dst[5].set(x23, y23); | 570 dst[5].set(x23, y23); |
569 dst[6] = src[3]; | 571 dst[6] = src[3]; |
570 } | 572 } |
571 | 573 |
572 static void flatten_double_cubic_extrema(SkScalar coords[14]) { | 574 static void flatten_double_cubic_extrema(SkScalar coords[14]) { |
573 coords[4] = coords[8] = coords[6]; | 575 coords[4] = coords[8] = coords[6]; |
574 } | 576 } |
575 | 577 |
576 /** Given 4 points on a cubic bezier, chop it into 1, 2, 3 beziers such that | 578 /** Given 4 points on a cubic bezier, chop it into 1, 2, 3 beziers such that |
577 the resulting beziers are monotonic in Y. This is called by the scan convert
er. | 579 the resulting beziers are monotonic in Y. This is called by the scan |
578 Depending on what is returned, dst[] is treated as follows | 580 converter. Depending on what is returned, dst[] is treated as follows: |
579 0 dst[0..3] is the original cubic | 581 0 dst[0..3] is the original cubic |
580 1 dst[0..3] and dst[3..6] are the two new cubics | 582 1 dst[0..3] and dst[3..6] are the two new cubics |
581 2 dst[0..3], dst[3..6], dst[6..9] are the three new cubics | 583 2 dst[0..3], dst[3..6], dst[6..9] are the three new cubics |
582 If dst == null, it is ignored and only the count is returned. | 584 If dst == null, it is ignored and only the count is returned. |
583 */ | 585 */ |
584 int SkChopCubicAtYExtrema(const SkPoint src[4], SkPoint dst[10]) { | 586 int SkChopCubicAtYExtrema(const SkPoint src[4], SkPoint dst[10]) { |
585 SkScalar tValues[2]; | 587 SkScalar tValues[2]; |
586 int roots = SkFindCubicExtrema(src[0].fY, src[1].fY, src[2].fY, | 588 int roots = SkFindCubicExtrema(src[0].fY, src[1].fY, src[2].fY, |
587 src[3].fY, tValues); | 589 src[3].fY, tValues); |
588 | 590 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
625 (BxCy - ByCx)t^2 + (AxCy - AyCx)t + AxBy - AyBx == 0 | 627 (BxCy - ByCx)t^2 + (AxCy - AyCx)t + AxBy - AyBx == 0 |
626 */ | 628 */ |
627 int SkFindCubicInflections(const SkPoint src[4], SkScalar tValues[]) { | 629 int SkFindCubicInflections(const SkPoint src[4], SkScalar tValues[]) { |
628 SkScalar Ax = src[1].fX - src[0].fX; | 630 SkScalar Ax = src[1].fX - src[0].fX; |
629 SkScalar Ay = src[1].fY - src[0].fY; | 631 SkScalar Ay = src[1].fY - src[0].fY; |
630 SkScalar Bx = src[2].fX - 2 * src[1].fX + src[0].fX; | 632 SkScalar Bx = src[2].fX - 2 * src[1].fX + src[0].fX; |
631 SkScalar By = src[2].fY - 2 * src[1].fY + src[0].fY; | 633 SkScalar By = src[2].fY - 2 * src[1].fY + src[0].fY; |
632 SkScalar Cx = src[3].fX + 3 * (src[1].fX - src[2].fX) - src[0].fX; | 634 SkScalar Cx = src[3].fX + 3 * (src[1].fX - src[2].fX) - src[0].fX; |
633 SkScalar Cy = src[3].fY + 3 * (src[1].fY - src[2].fY) - src[0].fY; | 635 SkScalar Cy = src[3].fY + 3 * (src[1].fY - src[2].fY) - src[0].fY; |
634 | 636 |
635 return SkFindUnitQuadRoots(Bx*Cy - By*Cx, Ax*Cy - Ay*Cx, Ax*By - Ay*Bx, tVal
ues); | 637 return SkFindUnitQuadRoots(Bx*Cy - By*Cx, |
| 638 Ax*Cy - Ay*Cx, |
| 639 Ax*By - Ay*Bx, |
| 640 tValues); |
636 } | 641 } |
637 | 642 |
638 int SkChopCubicAtInflections(const SkPoint src[], SkPoint dst[10]) { | 643 int SkChopCubicAtInflections(const SkPoint src[], SkPoint dst[10]) { |
639 SkScalar tValues[2]; | 644 SkScalar tValues[2]; |
640 int count = SkFindCubicInflections(src, tValues); | 645 int count = SkFindCubicInflections(src, tValues); |
641 | 646 |
642 if (dst) { | 647 if (dst) { |
643 if (count == 0) { | 648 if (count == 0) { |
644 memcpy(dst, src, 4 * sizeof(SkPoint)); | 649 memcpy(dst, src, 4 * sizeof(SkPoint)); |
645 } else { | 650 } else { |
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
956 && !SkScalarNearlyZero(eval.fY - pt.fY)); | 961 && !SkScalarNearlyZero(eval.fY - pt.fY)); |
957 if (pt.fX <= eval.fX) { | 962 if (pt.fX <= eval.fX) { |
958 if (ambiguous) { | 963 if (ambiguous) { |
959 *ambiguous = pt_at_extremum; | 964 *ambiguous = pt_at_extremum; |
960 } | 965 } |
961 return true; | 966 return true; |
962 } | 967 } |
963 return false; | 968 return false; |
964 } | 969 } |
965 | 970 |
966 int SkNumXRayCrossingsForCubic(const SkXRay& pt, const SkPoint cubic[4], bool* a
mbiguous) { | 971 int SkNumXRayCrossingsForCubic(const SkXRay& pt, |
| 972 const SkPoint cubic[4], |
| 973 bool* ambiguous) { |
967 int num_crossings = 0; | 974 int num_crossings = 0; |
968 SkPoint monotonic_cubics[10]; | 975 SkPoint monotonic_cubics[10]; |
969 int num_monotonic_cubics = SkChopCubicAtYExtrema(cubic, monotonic_cubics); | 976 int num_monotonic_cubics = SkChopCubicAtYExtrema(cubic, monotonic_cubics); |
970 if (ambiguous) { | 977 if (ambiguous) { |
971 *ambiguous = false; | 978 *ambiguous = false; |
972 } | 979 } |
973 bool locally_ambiguous; | 980 bool locally_ambiguous; |
974 if (SkXRayCrossesMonotonicCubic(pt, &monotonic_cubics[0], &locally_ambiguous
)) | 981 if (SkXRayCrossesMonotonicCubic(pt, |
| 982 &monotonic_cubics[0], |
| 983 &locally_ambiguous)) |
975 ++num_crossings; | 984 ++num_crossings; |
976 if (ambiguous) { | 985 if (ambiguous) { |
977 *ambiguous |= locally_ambiguous; | 986 *ambiguous |= locally_ambiguous; |
978 } | 987 } |
979 if (num_monotonic_cubics > 0) | 988 if (num_monotonic_cubics > 0) |
980 if (SkXRayCrossesMonotonicCubic(pt, &monotonic_cubics[3], &locally_ambig
uous)) | 989 if (SkXRayCrossesMonotonicCubic(pt, |
| 990 &monotonic_cubics[3], |
| 991 &locally_ambiguous)) |
981 ++num_crossings; | 992 ++num_crossings; |
982 if (ambiguous) { | 993 if (ambiguous) { |
983 *ambiguous |= locally_ambiguous; | 994 *ambiguous |= locally_ambiguous; |
984 } | 995 } |
985 if (num_monotonic_cubics > 1) | 996 if (num_monotonic_cubics > 1) |
986 if (SkXRayCrossesMonotonicCubic(pt, &monotonic_cubics[6], &locally_ambig
uous)) | 997 if (SkXRayCrossesMonotonicCubic(pt, |
| 998 &monotonic_cubics[6], |
| 999 &locally_ambiguous)) |
987 ++num_crossings; | 1000 ++num_crossings; |
988 if (ambiguous) { | 1001 if (ambiguous) { |
989 *ambiguous |= locally_ambiguous; | 1002 *ambiguous |= locally_ambiguous; |
990 } | 1003 } |
991 return num_crossings; | 1004 return num_crossings; |
992 } | 1005 } |
993 | 1006 |
994 /////////////////////////////////////////////////////////////////////////////// | 1007 /////////////////////////////////////////////////////////////////////////////// |
995 | 1008 |
996 /* Find t value for quadratic [a, b, c] = d. | 1009 /* Find t value for quadratic [a, b, c] = d. |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1056 dest[1].set(x, y); | 1069 dest[1].set(x, y); |
1057 return true; | 1070 return true; |
1058 } | 1071 } |
1059 } | 1072 } |
1060 return false; | 1073 return false; |
1061 } | 1074 } |
1062 | 1075 |
1063 static const SkPoint gQuadCirclePts[kSkBuildQuadArcStorage] = { | 1076 static const SkPoint gQuadCirclePts[kSkBuildQuadArcStorage] = { |
1064 // The mid point of the quadratic arc approximation is half way between the two | 1077 // The mid point of the quadratic arc approximation is half way between the two |
1065 // control points. The float epsilon adjustment moves the on curve point out by | 1078 // control points. The float epsilon adjustment moves the on curve point out by |
1066 // two bits, distributing the convex test error between the round rect approxima
tion | 1079 // two bits, distributing the convex test error between the round rect |
1067 // and the convex cross product sign equality test. | 1080 // approximation and the convex cross product sign equality test. |
1068 #define SK_MID_RRECT_OFFSET (SK_Scalar1 + SK_ScalarTanPIOver8 + FLT_EPSILON * 4)
/ 2 | 1081 #define SK_MID_RRECT_OFFSET \ |
| 1082 (SK_Scalar1 + SK_ScalarTanPIOver8 + FLT_EPSILON * 4) / 2 |
1069 { SK_Scalar1, 0 }, | 1083 { SK_Scalar1, 0 }, |
1070 { SK_Scalar1, SK_ScalarTanPIOver8 }, | 1084 { SK_Scalar1, SK_ScalarTanPIOver8 }, |
1071 { SK_MID_RRECT_OFFSET, SK_MID_RRECT_OFFSET }, | 1085 { SK_MID_RRECT_OFFSET, SK_MID_RRECT_OFFSET }, |
1072 { SK_ScalarTanPIOver8, SK_Scalar1 }, | 1086 { SK_ScalarTanPIOver8, SK_Scalar1 }, |
1073 | 1087 |
1074 { 0, SK_Scalar1 }, | 1088 { 0, SK_Scalar1 }, |
1075 { -SK_ScalarTanPIOver8, SK_Scalar1 }, | 1089 { -SK_ScalarTanPIOver8, SK_Scalar1 }, |
1076 { -SK_MID_RRECT_OFFSET, SK_MID_RRECT_OFFSET }, | 1090 { -SK_MID_RRECT_OFFSET, SK_MID_RRECT_OFFSET }, |
1077 { -SK_Scalar1, SK_ScalarTanPIOver8 }, | 1091 { -SK_Scalar1, SK_ScalarTanPIOver8 }, |
1078 | 1092 |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1155 if (dir == kCCW_SkRotationDirection) { | 1169 if (dir == kCCW_SkRotationDirection) { |
1156 matrix.preScale(SK_Scalar1, -SK_Scalar1); | 1170 matrix.preScale(SK_Scalar1, -SK_Scalar1); |
1157 } | 1171 } |
1158 if (userMatrix) { | 1172 if (userMatrix) { |
1159 matrix.postConcat(*userMatrix); | 1173 matrix.postConcat(*userMatrix); |
1160 } | 1174 } |
1161 matrix.mapPoints(quadPoints, pointCount); | 1175 matrix.mapPoints(quadPoints, pointCount); |
1162 return pointCount; | 1176 return pointCount; |
1163 } | 1177 } |
1164 | 1178 |
| 1179 |
1165 /////////////////////////////////////////////////////////////////////////////// | 1180 /////////////////////////////////////////////////////////////////////////////// |
1166 | 1181 // |
| 1182 // NURB representation for conics. Helpful explanations at: |
| 1183 // |
| 1184 // http://citeseerx.ist.psu.edu/viewdoc/ |
| 1185 // download?doi=10.1.1.44.5740&rep=rep1&type=ps |
| 1186 // and |
| 1187 // http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/NURBS/RB-conics.html |
| 1188 // |
1167 // F = (A (1 - t)^2 + C t^2 + 2 B (1 - t) t w) | 1189 // F = (A (1 - t)^2 + C t^2 + 2 B (1 - t) t w) |
1168 // ------------------------------------------ | 1190 // ------------------------------------------ |
1169 // ((1 - t)^2 + t^2 + 2 (1 - t) t w) | 1191 // ((1 - t)^2 + t^2 + 2 (1 - t) t w) |
1170 // | 1192 // |
1171 // = {t^2 (P0 + P2 - 2 P1 w), t (-2 P0 + 2 P1 w), P0} | 1193 // = {t^2 (P0 + P2 - 2 P1 w), t (-2 P0 + 2 P1 w), P0} |
1172 // ------------------------------------------------ | 1194 // ------------------------------------------------ |
1173 // {t^2 (2 - 2 w), t (-2 + 2 w), 1} | 1195 // {t^2 (2 - 2 w), t (-2 + 2 w), 1} |
1174 // | 1196 // |
1175 | 1197 |
1176 // Take the parametric specification for the conic (either X or Y) and return | |
1177 // in coeff[] the coefficients for the simple quadratic polynomial | |
1178 // coeff[0] for t^2 | |
1179 // coeff[1] for t | |
1180 // coeff[2] for constant term | |
1181 // | |
1182 static SkScalar conic_eval_pos(const SkScalar src[], SkScalar w, SkScalar t) { | 1198 static SkScalar conic_eval_pos(const SkScalar src[], SkScalar w, SkScalar t) { |
1183 SkASSERT(src); | 1199 SkASSERT(src); |
1184 SkASSERT(t >= 0 && t <= SK_Scalar1); | 1200 SkASSERT(t >= 0 && t <= SK_Scalar1); |
1185 | 1201 |
1186 SkScalar src2w = SkScalarMul(src[2], w); | 1202 SkScalar src2w = SkScalarMul(src[2], w); |
1187 SkScalar C = src[0]; | 1203 SkScalar C = src[0]; |
1188 SkScalar A = src[4] - 2 * src2w + C; | 1204 SkScalar A = src[4] - 2 * src2w + C; |
1189 SkScalar B = 2 * (src2w - C); | 1205 SkScalar B = 2 * (src2w - C); |
1190 SkScalar numer = SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C); | 1206 SkScalar numer = SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C); |
1191 | 1207 |
(...skipping 11 matching lines...) Expand all Loading... |
1203 // t^1 : (-2 P0 + 2 P2 + 4 P0 w - 4 P1 w) | 1219 // t^1 : (-2 P0 + 2 P2 + 4 P0 w - 4 P1 w) |
1204 // t^0 : -2 P0 w + 2 P1 w | 1220 // t^0 : -2 P0 w + 2 P1 w |
1205 // | 1221 // |
1206 // We disregard magnitude, so we can freely ignore the denominator of F', and | 1222 // We disregard magnitude, so we can freely ignore the denominator of F', and |
1207 // divide the numerator by 2 | 1223 // divide the numerator by 2 |
1208 // | 1224 // |
1209 // coeff[0] for t^2 | 1225 // coeff[0] for t^2 |
1210 // coeff[1] for t^1 | 1226 // coeff[1] for t^1 |
1211 // coeff[2] for t^0 | 1227 // coeff[2] for t^0 |
1212 // | 1228 // |
1213 static void conic_deriv_coeff(const SkScalar src[], SkScalar w, SkScalar coeff[3
]) { | 1229 static void conic_deriv_coeff(const SkScalar src[], |
| 1230 SkScalar w, |
| 1231 SkScalar coeff[3]) { |
1214 const SkScalar P20 = src[4] - src[0]; | 1232 const SkScalar P20 = src[4] - src[0]; |
1215 const SkScalar P10 = src[2] - src[0]; | 1233 const SkScalar P10 = src[2] - src[0]; |
1216 const SkScalar wP10 = w * P10; | 1234 const SkScalar wP10 = w * P10; |
1217 coeff[0] = w * P20 - P20; | 1235 coeff[0] = w * P20 - P20; |
1218 coeff[1] = P20 - 2 * wP10; | 1236 coeff[1] = P20 - 2 * wP10; |
1219 coeff[2] = wP10; | 1237 coeff[2] = wP10; |
1220 } | 1238 } |
1221 | 1239 |
1222 static SkScalar conic_eval_tan(const SkScalar coord[], SkScalar w, SkScalar t) { | 1240 static SkScalar conic_eval_tan(const SkScalar coord[], SkScalar w, SkScalar t) { |
1223 SkScalar coeff[3]; | 1241 SkScalar coeff[3]; |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1293 tmp2[0].projectDown(&dst[0].fPts[1]); | 1311 tmp2[0].projectDown(&dst[0].fPts[1]); |
1294 tmp2[1].projectDown(&dst[0].fPts[2]); dst[1].fPts[0] = dst[0].fPts[2]; | 1312 tmp2[1].projectDown(&dst[0].fPts[2]); dst[1].fPts[0] = dst[0].fPts[2]; |
1295 tmp2[2].projectDown(&dst[1].fPts[1]); | 1313 tmp2[2].projectDown(&dst[1].fPts[1]); |
1296 dst[1].fPts[2] = fPts[2]; | 1314 dst[1].fPts[2] = fPts[2]; |
1297 | 1315 |
1298 // to put in "standard form", where w0 and w2 are both 1, we compute the | 1316 // to put in "standard form", where w0 and w2 are both 1, we compute the |
1299 // new w1 as sqrt(w1*w1/w0*w2) | 1317 // new w1 as sqrt(w1*w1/w0*w2) |
1300 // or | 1318 // or |
1301 // w1 /= sqrt(w0*w2) | 1319 // w1 /= sqrt(w0*w2) |
1302 // | 1320 // |
1303 // However, in our case, we know that for dst[0], w0 == 1, and for dst[1], w
2 == 1 | 1321 // However, in our case, we know that for dst[0]: |
| 1322 // w0 == 1, and for dst[1], w2 == 1 |
1304 // | 1323 // |
1305 SkScalar root = SkScalarSqrt(tmp2[1].fZ); | 1324 SkScalar root = SkScalarSqrt(tmp2[1].fZ); |
1306 dst[0].fW = tmp2[0].fZ / root; | 1325 dst[0].fW = tmp2[0].fZ / root; |
1307 dst[1].fW = tmp2[2].fZ / root; | 1326 dst[1].fW = tmp2[2].fZ / root; |
1308 } | 1327 } |
1309 | 1328 |
1310 static SkScalar subdivide_w_value(SkScalar w) { | 1329 static SkScalar subdivide_w_value(SkScalar w) { |
1311 return SkScalarSqrt(SK_ScalarHalf + w * SK_ScalarHalf); | 1330 return SkScalarSqrt(SK_ScalarHalf + w * SK_ScalarHalf); |
1312 } | 1331 } |
1313 | 1332 |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1435 } | 1454 } |
1436 if (this->findYExtrema(&t)) { | 1455 if (this->findYExtrema(&t)) { |
1437 this->evalAt(t, &pts[count++]); | 1456 this->evalAt(t, &pts[count++]); |
1438 } | 1457 } |
1439 bounds->set(pts, count); | 1458 bounds->set(pts, count); |
1440 } | 1459 } |
1441 | 1460 |
1442 void SkConic::computeFastBounds(SkRect* bounds) const { | 1461 void SkConic::computeFastBounds(SkRect* bounds) const { |
1443 bounds->set(fPts, 3); | 1462 bounds->set(fPts, 3); |
1444 } | 1463 } |
| 1464 |
| 1465 bool SkConic::findMaxCurvature(SkScalar* t) const { |
| 1466 // TODO: Implement me |
| 1467 return false; |
| 1468 } |
OLD | NEW |