| OLD | NEW |
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2008 The Android Open Source Project | 3 * Copyright 2008 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 "SkPathMeasure.h" | 10 #include "SkPathMeasure.h" |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 66 // diff = -a/4 + b/2 - c/4 | 66 // diff = -a/4 + b/2 - c/4 |
| 67 SkScalar dx = SkScalarHalf(pts[1].fX) - | 67 SkScalar dx = SkScalarHalf(pts[1].fX) - |
| 68 SkScalarHalf(SkScalarHalf(pts[0].fX + pts[2].fX)); | 68 SkScalarHalf(SkScalarHalf(pts[0].fX + pts[2].fX)); |
| 69 SkScalar dy = SkScalarHalf(pts[1].fY) - | 69 SkScalar dy = SkScalarHalf(pts[1].fY) - |
| 70 SkScalarHalf(SkScalarHalf(pts[0].fY + pts[2].fY)); | 70 SkScalarHalf(SkScalarHalf(pts[0].fY + pts[2].fY)); |
| 71 | 71 |
| 72 SkScalar dist = SkMaxScalar(SkScalarAbs(dx), SkScalarAbs(dy)); | 72 SkScalar dist = SkMaxScalar(SkScalarAbs(dx), SkScalarAbs(dy)); |
| 73 return dist > CHEAP_DIST_LIMIT; | 73 return dist > CHEAP_DIST_LIMIT; |
| 74 } | 74 } |
| 75 | 75 |
| 76 static bool conic_too_curvy(const SkPoint& firstPt, const SkPoint& midTPt, |
| 77 const SkPoint& lastPt) { |
| 78 SkPoint midEnds = firstPt + lastPt; |
| 79 midEnds *= 0.5f; |
| 80 SkVector dxy = midTPt - midEnds; |
| 81 SkScalar dist = SkMaxScalar(SkScalarAbs(dxy.fX), SkScalarAbs(dxy.fY)); |
| 82 return dist > CHEAP_DIST_LIMIT; |
| 83 } |
| 84 |
| 76 static bool cheap_dist_exceeds_limit(const SkPoint& pt, | 85 static bool cheap_dist_exceeds_limit(const SkPoint& pt, |
| 77 SkScalar x, SkScalar y) { | 86 SkScalar x, SkScalar y) { |
| 78 SkScalar dist = SkMaxScalar(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY)); | 87 SkScalar dist = SkMaxScalar(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY)); |
| 79 // just made up the 1/2 | 88 // just made up the 1/2 |
| 80 return dist > CHEAP_DIST_LIMIT; | 89 return dist > CHEAP_DIST_LIMIT; |
| 81 } | 90 } |
| 82 | 91 |
| 83 static bool cubic_too_curvy(const SkPoint pts[4]) { | 92 static bool cubic_too_curvy(const SkPoint pts[4]) { |
| 84 return cheap_dist_exceeds_limit(pts[1], | 93 return cheap_dist_exceeds_limit(pts[1], |
| 85 SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1/3), | 94 SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1/3), |
| 86 SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1/3)) | 95 SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1/3)) |
| 87 || | 96 || |
| 88 cheap_dist_exceeds_limit(pts[2], | 97 cheap_dist_exceeds_limit(pts[2], |
| 89 SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1*2/3), | 98 SkScalarInterp(pts[0].fX, pts[3].fX, SK_Scalar1*2/3), |
| 90 SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1*2/3)); | 99 SkScalarInterp(pts[0].fY, pts[3].fY, SK_Scalar1*2/3)); |
| 91 } | 100 } |
| 92 | 101 |
| 93 /* from http://www.malczak.linuxpl.com/blog/quadratic-bezier-curve-length/ */ | 102 static SkScalar quad_folded_len(const SkPoint pts[3]) { |
| 94 static SkScalar compute_quad_len(const SkPoint pts[3]) { | 103 SkScalar t = SkFindQuadMaxCurvature(pts); |
| 95 SkPoint a,b; | 104 SkPoint pt = SkEvalQuadAt(pts, t); |
| 96 a.fX = pts[0].fX - 2 * pts[1].fX + pts[2].fX; | 105 SkVector a = pts[2] - pt; |
| 97 a.fY = pts[0].fY - 2 * pts[1].fY + pts[2].fY; | 106 SkScalar result = a.length(); |
| 98 b.fX = 2 * (pts[1].fX - pts[0].fX); | 107 if (0 != t) { |
| 99 b.fY = 2 * (pts[1].fY - pts[0].fY); | 108 SkVector b = pts[0] - pt; |
| 100 SkScalar A = 4 * (a.fX * a.fX + a.fY * a.fY); | 109 result += b.length(); |
| 101 SkScalar B = 4 * (a.fX * b.fX + a.fY * b.fY); | 110 } |
| 102 SkScalar C = b.fX * b.fX + b.fY * b.fY; | 111 SkASSERT(SkScalarIsFinite(result)); |
| 103 | 112 return result; |
| 104 SkScalar Sabc = 2 * SkScalarSqrt(A + B + C); | |
| 105 SkScalar A_2 = SkScalarSqrt(A); | |
| 106 SkScalar A_32 = 2 * A * A_2; | |
| 107 SkScalar C_2 = 2 * SkScalarSqrt(C); | |
| 108 SkScalar BA = B / A_2; | |
| 109 | |
| 110 return (A_32 * Sabc + A_2 * B * (Sabc - C_2) + | |
| 111 (4 * C * A - B * B) * SkScalarLog((2 * A_2 + BA + Sabc) / (BA + C_2)
)) / (4 * A_32); | |
| 112 } | 113 } |
| 113 | 114 |
| 115 /* from http://www.malczak.linuxpl.com/blog/quadratic-bezier-curve-length/ */ |
| 116 /* This works -- more needs to be done to see if it is performant on all platfor
ms. |
| 117 To use this to measure parts of quads requires recomputing everything -- perh
aps |
| 118 a chop-like interface can start from a larger measurement and get two new mea
surements |
| 119 with one call here. |
| 120 */ |
| 121 static SkScalar compute_quad_len(const SkPoint pts[3]) { |
| 122 SkPoint a,b; |
| 123 a.fX = pts[0].fX - 2 * pts[1].fX + pts[2].fX; |
| 124 a.fY = pts[0].fY - 2 * pts[1].fY + pts[2].fY; |
| 125 SkScalar A = 4 * (a.fX * a.fX + a.fY * a.fY); |
| 126 if (0 == A) { |
| 127 a = pts[2] - pts[0]; |
| 128 return a.length(); |
| 129 } |
| 130 b.fX = 2 * (pts[1].fX - pts[0].fX); |
| 131 b.fY = 2 * (pts[1].fY - pts[0].fY); |
| 132 SkScalar B = 4 * (a.fX * b.fX + a.fY * b.fY); |
| 133 SkScalar C = b.fX * b.fX + b.fY * b.fY; |
| 134 SkScalar Sabc = 2 * SkScalarSqrt(A + B + C); |
| 135 SkScalar A_2 = SkScalarSqrt(A); |
| 136 SkScalar A_32 = 2 * A * A_2; |
| 137 SkScalar C_2 = 2 * SkScalarSqrt(C); |
| 138 SkScalar BA = B / A_2; |
| 139 if (0 == BA + C_2) { |
| 140 return quad_folded_len(pts); |
| 141 } |
| 142 SkScalar J = A_32 * Sabc + A_2 * B * (Sabc - C_2); |
| 143 SkScalar K = 4 * C * A - B * B; |
| 144 SkScalar L = (2 * A_2 + BA + Sabc) / (BA + C_2); |
| 145 if (L <= 0) { |
| 146 return quad_folded_len(pts); |
| 147 } |
| 148 SkScalar M = SkScalarLog(L); |
| 149 SkScalar result = (J + K * M) / (4 * A_32); |
| 150 SkASSERT(SkScalarIsFinite(result)); |
| 151 return result; |
| 152 } |
| 114 | 153 |
| 115 SkScalar SkPathMeasure::compute_quad_segs(const SkPoint pts[3], | 154 SkScalar SkPathMeasure::compute_quad_segs(const SkPoint pts[3], |
| 116 SkScalar distance, int mint, int maxt, int ptIndex) { | 155 SkScalar distance, int mint, int maxt, int ptIndex) { |
| 117 if (tspan_big_enough(maxt - mint) && quad_too_curvy(pts)) { | 156 if (tspan_big_enough(maxt - mint) && quad_too_curvy(pts)) { |
| 118 SkPoint tmp[5]; | 157 SkPoint tmp[5]; |
| 119 int halft = (mint + maxt) >> 1; | 158 int halft = (mint + maxt) >> 1; |
| 120 | 159 |
| 121 SkChopQuadAtHalf(pts, tmp); | 160 SkChopQuadAtHalf(pts, tmp); |
| 122 distance = this->compute_quad_segs(tmp, distance, mint, halft, ptIndex); | 161 distance = this->compute_quad_segs(tmp, distance, mint, halft, ptIndex); |
| 123 distance = this->compute_quad_segs(&tmp[2], distance, halft, maxt, ptInd
ex); | 162 distance = this->compute_quad_segs(&tmp[2], distance, halft, maxt, ptInd
ex); |
| 124 } else { | 163 } else { |
| 125 SkScalar d = SkPoint::Distance(pts[0], pts[2]); | 164 SkScalar d = SkPoint::Distance(pts[0], pts[2]); |
| 126 SkScalar prevD = distance; | 165 SkScalar prevD = distance; |
| 127 distance += d; | 166 distance += d; |
| 128 if (distance > prevD) { | 167 if (distance > prevD) { |
| 129 Segment* seg = fSegments.append(); | 168 Segment* seg = fSegments.append(); |
| 130 seg->fDistance = distance; | 169 seg->fDistance = distance; |
| 131 seg->fPtIndex = ptIndex; | 170 seg->fPtIndex = ptIndex; |
| 132 seg->fType = kQuad_SegType; | 171 seg->fType = kQuad_SegType; |
| 133 seg->fTValue = maxt; | 172 seg->fTValue = maxt; |
| 134 } | 173 } |
| 135 } | 174 } |
| 136 return distance; | 175 return distance; |
| 137 } | 176 } |
| 138 | 177 |
| 178 #ifdef SK_SUPPORT_LEGACY_CONIC_MEASURE |
| 139 SkScalar SkPathMeasure::compute_conic_segs(const SkConic& conic, | 179 SkScalar SkPathMeasure::compute_conic_segs(const SkConic& conic, |
| 140 SkScalar distance, int mint, int maxt
, int ptIndex) { | 180 SkScalar distance, int mint, int maxt
, int ptIndex) { |
| 141 if (tspan_big_enough(maxt - mint) && quad_too_curvy(conic.fPts)) { | 181 if (tspan_big_enough(maxt - mint) && quad_too_curvy(conic.fPts)) { |
| 142 SkConic tmp[2]; | 182 SkConic tmp[2]; |
| 143 conic.chop(tmp); | 183 conic.chop(tmp); |
| 144 | 184 |
| 145 int halft = (mint + maxt) >> 1; | 185 int halft = (mint + maxt) >> 1; |
| 146 distance = this->compute_conic_segs(tmp[0], distance, mint, halft, ptInd
ex); | 186 distance = this->compute_conic_segs(tmp[0], distance, mint, halft, ptInd
ex); |
| 147 distance = this->compute_conic_segs(tmp[1], distance, halft, maxt, ptInd
ex); | 187 distance = this->compute_conic_segs(tmp[1], distance, halft, maxt, ptInd
ex); |
| 148 } else { | 188 } else { |
| 149 SkScalar d = SkPoint::Distance(conic.fPts[0], conic.fPts[2]); | 189 SkScalar d = SkPoint::Distance(conic.fPts[0], conic.fPts[2]); |
| 150 SkScalar prevD = distance; | 190 SkScalar prevD = distance; |
| 151 distance += d; | 191 distance += d; |
| 152 if (distance > prevD) { | 192 if (distance > prevD) { |
| 153 Segment* seg = fSegments.append(); | 193 Segment* seg = fSegments.append(); |
| 154 seg->fDistance = distance; | 194 seg->fDistance = distance; |
| 155 seg->fPtIndex = ptIndex; | 195 seg->fPtIndex = ptIndex; |
| 156 seg->fType = kConic_SegType; | 196 seg->fType = kConic_SegType; |
| 157 seg->fTValue = maxt; | 197 seg->fTValue = maxt; |
| 158 } | 198 } |
| 159 } | 199 } |
| 160 return distance; | 200 return distance; |
| 161 } | 201 } |
| 202 #else |
| 203 SkScalar SkPathMeasure::compute_conic_segs(const SkConic& conic, SkScalar distan
ce, |
| 204 int mint, const SkPoint& minPt, |
| 205 int maxt, const SkPoint& maxPt, int p
tIndex) { |
| 206 int halft = (mint + maxt) >> 1; |
| 207 SkPoint halfPt = conic.evalAt(tValue2Scalar(halft)); |
| 208 if (tspan_big_enough(maxt - mint) && conic_too_curvy(minPt, halfPt, maxPt))
{ |
| 209 distance = this->compute_conic_segs(conic, distance, mint, minPt, halft,
halfPt, ptIndex); |
| 210 distance = this->compute_conic_segs(conic, distance, halft, halfPt, maxt
, maxPt, ptIndex); |
| 211 } else { |
| 212 SkScalar d = SkPoint::Distance(minPt, maxPt); |
| 213 SkScalar prevD = distance; |
| 214 distance += d; |
| 215 if (distance > prevD) { |
| 216 Segment* seg = fSegments.append(); |
| 217 seg->fDistance = distance; |
| 218 seg->fPtIndex = ptIndex; |
| 219 seg->fType = kConic_SegType; |
| 220 seg->fTValue = maxt; |
| 221 } |
| 222 } |
| 223 return distance; |
| 224 } |
| 225 #endif |
| 162 | 226 |
| 163 SkScalar SkPathMeasure::compute_cubic_segs(const SkPoint pts[4], | 227 SkScalar SkPathMeasure::compute_cubic_segs(const SkPoint pts[4], |
| 164 SkScalar distance, int mint, int maxt, int ptIndex) { | 228 SkScalar distance, int mint, int maxt, int ptIndex) { |
| 165 if (tspan_big_enough(maxt - mint) && cubic_too_curvy(pts)) { | 229 if (tspan_big_enough(maxt - mint) && cubic_too_curvy(pts)) { |
| 166 SkPoint tmp[7]; | 230 SkPoint tmp[7]; |
| 167 int halft = (mint + maxt) >> 1; | 231 int halft = (mint + maxt) >> 1; |
| 168 | 232 |
| 169 SkChopCubicAtHalf(pts, tmp); | 233 SkChopCubicAtHalf(pts, tmp); |
| 170 distance = this->compute_cubic_segs(tmp, distance, mint, halft, ptIndex)
; | 234 distance = this->compute_cubic_segs(tmp, distance, mint, halft, ptIndex)
; |
| 171 distance = this->compute_cubic_segs(&tmp[3], distance, halft, maxt, ptIn
dex); | 235 distance = this->compute_cubic_segs(&tmp[3], distance, halft, maxt, ptIn
dex); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 246 } | 310 } |
| 247 if (distance > prevD) { | 311 if (distance > prevD) { |
| 248 fPts.append(2, pts + 1); | 312 fPts.append(2, pts + 1); |
| 249 ptIndex += 2; | 313 ptIndex += 2; |
| 250 } | 314 } |
| 251 } break; | 315 } break; |
| 252 | 316 |
| 253 case SkPath::kConic_Verb: { | 317 case SkPath::kConic_Verb: { |
| 254 const SkConic conic(pts, fIter.conicWeight()); | 318 const SkConic conic(pts, fIter.conicWeight()); |
| 255 SkScalar prevD = distance; | 319 SkScalar prevD = distance; |
| 320 #ifdef SK_SUPPORT_LEGACY_CONIC_MEASURE |
| 256 distance = this->compute_conic_segs(conic, distance, 0, kMaxTVal
ue, ptIndex); | 321 distance = this->compute_conic_segs(conic, distance, 0, kMaxTVal
ue, ptIndex); |
| 322 #else |
| 323 distance = this->compute_conic_segs(conic, distance, 0, conic.fP
ts[0], |
| 324 kMaxTValue, conic.fPts[2], p
tIndex); |
| 325 #endif |
| 257 if (distance > prevD) { | 326 if (distance > prevD) { |
| 258 // we store the conic weight in our next point, followed by
the last 2 pts | 327 // we store the conic weight in our next point, followed by
the last 2 pts |
| 259 // thus to reconstitue a conic, you'd need to say | 328 // thus to reconstitue a conic, you'd need to say |
| 260 // SkConic(pts[0], pts[2], pts[3], weight = pts[1].fX) | 329 // SkConic(pts[0], pts[2], pts[3], weight = pts[1].fX) |
| 261 fPts.append()->set(conic.fW, 0); | 330 fPts.append()->set(conic.fW, 0); |
| 262 fPts.append(2, pts + 1); | 331 fPts.append(2, pts + 1); |
| 263 ptIndex += 3; | 332 ptIndex += 3; |
| 264 } | 333 } |
| 265 } break; | 334 } break; |
| 266 | 335 |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 399 | 468 |
| 400 if (0 == startT) { | 469 if (0 == startT) { |
| 401 if (SK_Scalar1 == stopT) { | 470 if (SK_Scalar1 == stopT) { |
| 402 dst->conicTo(conic.fPts[1], conic.fPts[2], conic.fW); | 471 dst->conicTo(conic.fPts[1], conic.fPts[2], conic.fW); |
| 403 } else { | 472 } else { |
| 404 SkConic tmp[2]; | 473 SkConic tmp[2]; |
| 405 conic.chopAt(stopT, tmp); | 474 conic.chopAt(stopT, tmp); |
| 406 dst->conicTo(tmp[0].fPts[1], tmp[0].fPts[2], tmp[0].fW); | 475 dst->conicTo(tmp[0].fPts[1], tmp[0].fPts[2], tmp[0].fW); |
| 407 } | 476 } |
| 408 } else { | 477 } else { |
| 409 SkConic tmp1[2]; | 478 #ifdef SK_SUPPORT_LEGACY_CONIC_MEASURE |
| 479 SkConic tmp1[2];» |
| 410 conic.chopAt(startT, tmp1); | 480 conic.chopAt(startT, tmp1); |
| 411 if (SK_Scalar1 == stopT) { | 481 if (SK_Scalar1 == stopT) { |
| 412 dst->conicTo(tmp1[1].fPts[1], tmp1[1].fPts[2], tmp1[1].fW); | 482 dst->conicTo(tmp1[1].fPts[1], tmp1[1].fPts[2], tmp1[1].fW); |
| 413 } else { | 483 } else { |
| 414 SkConic tmp2[2]; | 484 SkConic tmp2[2]; |
| 415 tmp1[1].chopAt((stopT - startT) / (SK_Scalar1 - startT), tmp
2); | 485 tmp1[1].chopAt((stopT - startT) / (SK_Scalar1 - startT), tmp
2); |
| 416 dst->conicTo(tmp2[0].fPts[1], tmp2[0].fPts[2], tmp2[0].fW); | 486 dst->conicTo(tmp2[0].fPts[1], tmp2[0].fPts[2], tmp2[0].fW); |
| 417 } | 487 } |
| 488 #else |
| 489 if (SK_Scalar1 == stopT) { |
| 490 SkConic tmp1[2]; |
| 491 conic.chopAt(startT, tmp1); |
| 492 dst->conicTo(tmp1[1].fPts[1], tmp1[1].fPts[2], tmp1[1].fW); |
| 493 } else { |
| 494 SkConic tmp; |
| 495 conic.chopAt(startT, stopT, &tmp); |
| 496 dst->conicTo(tmp.fPts[1], tmp.fPts[2], tmp.fW); |
| 497 } |
| 498 #endif |
| 418 } | 499 } |
| 419 } break; | 500 } break; |
| 420 case kCubic_SegType: | 501 case kCubic_SegType: |
| 421 if (0 == startT) { | 502 if (0 == startT) { |
| 422 if (SK_Scalar1 == stopT) { | 503 if (SK_Scalar1 == stopT) { |
| 423 dst->cubicTo(pts[1], pts[2], pts[3]); | 504 dst->cubicTo(pts[1], pts[2], pts[3]); |
| 424 } else { | 505 } else { |
| 425 SkChopCubicAt(pts, tmp0, stopT); | 506 SkChopCubicAt(pts, tmp0, stopT); |
| 426 dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]); | 507 dst->cubicTo(tmp0[1], tmp0[2], tmp0[3]); |
| 427 } | 508 } |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 667 | 748 |
| 668 for (int i = 0; i < fSegments.count(); i++) { | 749 for (int i = 0; i < fSegments.count(); i++) { |
| 669 const Segment* seg = &fSegments[i]; | 750 const Segment* seg = &fSegments[i]; |
| 670 SkDebugf("pathmeas: seg[%d] distance=%g, point=%d, t=%g, type=%d\n", | 751 SkDebugf("pathmeas: seg[%d] distance=%g, point=%d, t=%g, type=%d\n", |
| 671 i, seg->fDistance, seg->fPtIndex, seg->getScalarT(), | 752 i, seg->fDistance, seg->fPtIndex, seg->getScalarT(), |
| 672 seg->fType); | 753 seg->fType); |
| 673 } | 754 } |
| 674 } | 755 } |
| 675 | 756 |
| 676 #endif | 757 #endif |
| OLD | NEW |