| 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 |