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 |