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

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

Issue 175193003: Stub for conic section max curvature (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Nits and a bunch of 80 col fixes Created 6 years, 10 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
« include/core/SkGeometry.h ('K') | « include/core/SkGeometry.h ('k') | no next file » | 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 * 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
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
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
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
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
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
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
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
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 }
OLDNEW
« include/core/SkGeometry.h ('K') | « include/core/SkGeometry.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698