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, | |
12 const SkPoint pts[2], | |
13 bool* ambiguous) { | |
14 if (ambiguous) { | |
15 *ambiguous = false; | |
16 } | |
17 // Determine quick discards. | |
18 // Consider query line going exactly through point 0 to not | |
19 // intersect, for symmetry with SkXRayCrossesMonotonicCubic. | |
20 if (pt.fY == pts[0].fY) { | |
21 if (ambiguous) { | |
22 *ambiguous = true; | |
23 } | |
24 return false; | |
25 } | |
26 if (pt.fY < pts[0].fY && pt.fY < pts[1].fY) | |
27 return false; | |
28 if (pt.fY > pts[0].fY && pt.fY > pts[1].fY) | |
29 return false; | |
30 if (pt.fX > pts[0].fX && pt.fX > pts[1].fX) | |
31 return false; | |
32 // Determine degenerate cases | |
33 if (SkScalarNearlyZero(pts[0].fY - pts[1].fY)) | |
34 return false; | |
35 if (SkScalarNearlyZero(pts[0].fX - pts[1].fX)) { | |
36 // We've already determined the query point lies within the | |
37 // vertical range of the line segment. | |
38 if (pt.fX <= pts[0].fX) { | |
39 if (ambiguous) { | |
40 *ambiguous = (pt.fY == pts[1].fY); | |
41 } | |
42 return true; | |
43 } | |
44 return false; | |
45 } | |
46 // Ambiguity check | |
47 if (pt.fY == pts[1].fY) { | |
48 if (pt.fX <= pts[1].fX) { | |
49 if (ambiguous) { | |
50 *ambiguous = true; | |
51 } | |
52 return true; | |
53 } | |
54 return false; | |
55 } | |
56 // Full line segment evaluation | |
57 SkScalar delta_y = pts[1].fY - pts[0].fY; | |
58 SkScalar delta_x = pts[1].fX - pts[0].fX; | |
59 SkScalar slope = SkScalarDiv(delta_y, delta_x); | |
60 SkScalar b = pts[0].fY - SkScalarMul(slope, pts[0].fX); | |
61 // Solve for x coordinate at y = pt.fY | |
62 SkScalar x = SkScalarDiv(pt.fY - b, slope); | |
63 return pt.fX <= x; | |
64 } | |
65 | |
66 /** If defined, this makes eval_quad and eval_cubic do more setup (sometimes | 11 /** If defined, this makes eval_quad and eval_cubic do more setup (sometimes |
67 involving integer multiplies by 2 or 3, but fewer calls to SkScalarMul. | 12 involving integer multiplies by 2 or 3, but fewer calls to SkScalarMul. |
68 May also introduce overflow of fixed when we compute our setup. | 13 May also introduce overflow of fixed when we compute our setup. |
69 */ | 14 */ |
70 // #define DIRECT_EVAL_OF_POLYNOMIALS | 15 // #define DIRECT_EVAL_OF_POLYNOMIALS |
71 | 16 |
72 //////////////////////////////////////////////////////////////////////// | 17 //////////////////////////////////////////////////////////////////////// |
73 | 18 |
74 static int is_not_monotonic(SkScalar a, SkScalar b, SkScalar c) { | 19 static int is_not_monotonic(SkScalar a, SkScalar b, SkScalar c) { |
75 SkScalar ab = a - b; | 20 SkScalar ab = a - b; |
(...skipping 866 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
942 if (dst) { | 887 if (dst) { |
943 if (count == 0) { | 888 if (count == 0) { |
944 memcpy(dst, src, 4 * sizeof(SkPoint)); | 889 memcpy(dst, src, 4 * sizeof(SkPoint)); |
945 } else { | 890 } else { |
946 SkChopCubicAt(src, dst, tValues, count); | 891 SkChopCubicAt(src, dst, tValues, count); |
947 } | 892 } |
948 } | 893 } |
949 return count + 1; | 894 return count + 1; |
950 } | 895 } |
951 | 896 |
952 bool SkXRayCrossesMonotonicCubic(const SkXRay& pt, const SkPoint cubic[4], | |
953 bool* ambiguous) { | |
954 if (ambiguous) { | |
955 *ambiguous = false; | |
956 } | |
957 | |
958 // Find the minimum and maximum y of the extrema, which are the | |
959 // first and last points since this cubic is monotonic | |
960 SkScalar min_y = SkMinScalar(cubic[0].fY, cubic[3].fY); | |
961 SkScalar max_y = SkMaxScalar(cubic[0].fY, cubic[3].fY); | |
962 | |
963 if (pt.fY == cubic[0].fY | |
964 || pt.fY < min_y | |
965 || pt.fY > max_y) { | |
966 // The query line definitely does not cross the curve | |
967 if (ambiguous) { | |
968 *ambiguous = (pt.fY == cubic[0].fY); | |
969 } | |
970 return false; | |
971 } | |
972 | |
973 bool pt_at_extremum = (pt.fY == cubic[3].fY); | |
974 | |
975 SkScalar min_x = | |
976 SkMinScalar( | |
977 SkMinScalar( | |
978 SkMinScalar(cubic[0].fX, cubic[1].fX), | |
979 cubic[2].fX), | |
980 cubic[3].fX); | |
981 if (pt.fX < min_x) { | |
982 // The query line definitely crosses the curve | |
983 if (ambiguous) { | |
984 *ambiguous = pt_at_extremum; | |
985 } | |
986 return true; | |
987 } | |
988 | |
989 SkScalar max_x = | |
990 SkMaxScalar( | |
991 SkMaxScalar( | |
992 SkMaxScalar(cubic[0].fX, cubic[1].fX), | |
993 cubic[2].fX), | |
994 cubic[3].fX); | |
995 if (pt.fX > max_x) { | |
996 // The query line definitely does not cross the curve | |
997 return false; | |
998 } | |
999 | |
1000 // Do a binary search to find the parameter value which makes y as | |
1001 // close as possible to the query point. See whether the query | |
1002 // line's origin is to the left of the associated x coordinate. | |
1003 | |
1004 // kMaxIter is chosen as the number of mantissa bits for a float, | |
1005 // since there's no way we are going to get more precision by | |
1006 // iterating more times than that. | |
1007 const int kMaxIter = 23; | |
1008 SkPoint eval; | |
1009 int iter = 0; | |
1010 SkScalar upper_t; | |
1011 SkScalar lower_t; | |
1012 // Need to invert direction of t parameter if cubic goes up | |
1013 // instead of down | |
1014 if (cubic[3].fY > cubic[0].fY) { | |
1015 upper_t = SK_Scalar1; | |
1016 lower_t = 0; | |
1017 } else { | |
1018 upper_t = 0; | |
1019 lower_t = SK_Scalar1; | |
1020 } | |
1021 do { | |
1022 SkScalar t = SkScalarAve(upper_t, lower_t); | |
1023 SkEvalCubicAt(cubic, t, &eval, NULL, NULL); | |
1024 if (pt.fY > eval.fY) { | |
1025 lower_t = t; | |
1026 } else { | |
1027 upper_t = t; | |
1028 } | |
1029 } while (++iter < kMaxIter | |
1030 && !SkScalarNearlyZero(eval.fY - pt.fY)); | |
1031 if (pt.fX <= eval.fX) { | |
1032 if (ambiguous) { | |
1033 *ambiguous = pt_at_extremum; | |
1034 } | |
1035 return true; | |
1036 } | |
1037 return false; | |
1038 } | |
1039 | |
1040 int SkNumXRayCrossingsForCubic(const SkXRay& pt, | |
1041 const SkPoint cubic[4], | |
1042 bool* ambiguous) { | |
1043 int num_crossings = 0; | |
1044 SkPoint monotonic_cubics[10]; | |
1045 int num_monotonic_cubics = SkChopCubicAtYExtrema(cubic, monotonic_cubics); | |
1046 if (ambiguous) { | |
1047 *ambiguous = false; | |
1048 } | |
1049 bool locally_ambiguous; | |
1050 if (SkXRayCrossesMonotonicCubic(pt, | |
1051 &monotonic_cubics[0], | |
1052 &locally_ambiguous)) | |
1053 ++num_crossings; | |
1054 if (ambiguous) { | |
1055 *ambiguous |= locally_ambiguous; | |
1056 } | |
1057 if (num_monotonic_cubics > 0) | |
1058 if (SkXRayCrossesMonotonicCubic(pt, | |
1059 &monotonic_cubics[3], | |
1060 &locally_ambiguous)) | |
1061 ++num_crossings; | |
1062 if (ambiguous) { | |
1063 *ambiguous |= locally_ambiguous; | |
1064 } | |
1065 if (num_monotonic_cubics > 1) | |
1066 if (SkXRayCrossesMonotonicCubic(pt, | |
1067 &monotonic_cubics[6], | |
1068 &locally_ambiguous)) | |
1069 ++num_crossings; | |
1070 if (ambiguous) { | |
1071 *ambiguous |= locally_ambiguous; | |
1072 } | |
1073 return num_crossings; | |
1074 } | |
1075 | |
1076 /////////////////////////////////////////////////////////////////////////////// | 897 /////////////////////////////////////////////////////////////////////////////// |
1077 | 898 |
1078 /* Find t value for quadratic [a, b, c] = d. | 899 /* Find t value for quadratic [a, b, c] = d. |
1079 Return 0 if there is no solution within [0, 1) | 900 Return 0 if there is no solution within [0, 1) |
1080 */ | 901 */ |
1081 static SkScalar quad_solve(SkScalar a, SkScalar b, SkScalar c, SkScalar d) { | 902 static SkScalar quad_solve(SkScalar a, SkScalar b, SkScalar c, SkScalar d) { |
1082 // At^2 + Bt + C = d | 903 // At^2 + Bt + C = d |
1083 SkScalar A = a - 2 * b + c; | 904 SkScalar A = a - 2 * b + c; |
1084 SkScalar B = 2 * (b - a); | 905 SkScalar B = 2 * (b - a); |
1085 SkScalar C = a - d; | 906 SkScalar C = a - d; |
(...skipping 575 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1661 matrix.preScale(SK_Scalar1, -SK_Scalar1); | 1482 matrix.preScale(SK_Scalar1, -SK_Scalar1); |
1662 } | 1483 } |
1663 if (userMatrix) { | 1484 if (userMatrix) { |
1664 matrix.postConcat(*userMatrix); | 1485 matrix.postConcat(*userMatrix); |
1665 } | 1486 } |
1666 for (int i = 0; i < conicCount; ++i) { | 1487 for (int i = 0; i < conicCount; ++i) { |
1667 matrix.mapPoints(dst[i].fPts, 3); | 1488 matrix.mapPoints(dst[i].fPts, 3); |
1668 } | 1489 } |
1669 return conicCount; | 1490 return conicCount; |
1670 } | 1491 } |
OLD | NEW |