Chromium Code Reviews| 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 "SkPoint.h" | 10 #include "SkPoint.h" |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 100 // This logic is encapsulated in a helper method to make it explicit that we | 100 // This logic is encapsulated in a helper method to make it explicit that we |
| 101 // always perform this check in the same manner, to avoid inconsistencies | 101 // always perform this check in the same manner, to avoid inconsistencies |
| 102 // (see http://code.google.com/p/skia/issues/detail?id=560 ). | 102 // (see http://code.google.com/p/skia/issues/detail?id=560 ). |
| 103 static inline bool isLengthNearlyZero(float dx, float dy, | 103 static inline bool isLengthNearlyZero(float dx, float dy, |
| 104 float *lengthSquared) { | 104 float *lengthSquared) { |
| 105 *lengthSquared = getLengthSquared(dx, dy); | 105 *lengthSquared = getLengthSquared(dx, dy); |
| 106 return *lengthSquared <= (SK_ScalarNearlyZero * SK_ScalarNearlyZero); | 106 return *lengthSquared <= (SK_ScalarNearlyZero * SK_ScalarNearlyZero); |
| 107 } | 107 } |
| 108 | 108 |
| 109 SkScalar SkPoint::Normalize(SkPoint* pt) { | 109 SkScalar SkPoint::Normalize(SkPoint* pt) { |
| 110 float x = pt->fX; | |
| 111 float y = pt->fY; | |
| 110 float mag2; | 112 float mag2; |
| 111 if (!isLengthNearlyZero(pt->fX, pt->fY, &mag2)) { | 113 if (isLengthNearlyZero(x, y, &mag2)) { |
| 112 float mag = sk_float_sqrt(mag2); | 114 return false; |
|
caryclark
2013/05/03 15:41:51
return 0?
| |
| 113 float scale = 1.0f / mag; | |
| 114 pt->fX = pt->fX * scale; | |
| 115 pt->fY = pt->fY * scale; | |
| 116 return mag; | |
| 117 } | 115 } |
| 118 return 0; | 116 |
| 117 float mag, scale; | |
| 118 if (SkScalarIsFinite(mag2)) { | |
| 119 mag = sk_float_sqrt(mag2); | |
| 120 scale = 1 / mag; | |
| 121 } else { | |
| 122 // our mag2 step overflowed to infinity, so use doubles instead. | |
| 123 // much slower, but needed when x or y are very large, other wise we | |
| 124 // divide by inf. and return (0,0) vector. | |
| 125 double xx = x; | |
| 126 double yy = y; | |
| 127 double magmag = sqrt(xx * xx + yy * yy); | |
| 128 mag = (float)magmag; | |
| 129 // we perform the divide with the double magmag, to stay exactly the | |
| 130 // same as setLength. It would be faster to perform the divide with | |
| 131 // mag, but it is possible that mag has overflowed to inf. but still | |
| 132 // have a non-zero value for scale (thanks to denormalized numbers). | |
| 133 scale = (float)(1 / magmag); | |
| 134 } | |
| 135 pt->set(x * scale, y * scale); | |
| 136 return mag; | |
| 119 } | 137 } |
| 120 | 138 |
| 121 SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) { | 139 SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) { |
| 122 return sk_float_sqrt(getLengthSquared(dx, dy)); | 140 float mag2 = dx * dx + dy * dy; |
| 141 if (SkScalarIsFinite(mag2)) { | |
| 142 return sk_float_sqrt(mag2); | |
| 143 } else { | |
|
caryclark
2013/05/03 15:41:51
don't need else?
| |
| 144 double xx = dx; | |
| 145 double yy = dy; | |
| 146 return (float)sqrt(xx * xx + yy * yy); | |
| 147 } | |
| 123 } | 148 } |
| 124 | 149 |
| 150 /* | |
| 151 * We have to worry about 2 tricky conditions: | |
| 152 * 1. underflow of mag2 (compared against nearlyzero^2) | |
| 153 * 2. overflow of mag2 (compared w/ isfinite) | |
| 154 * | |
| 155 * If we underflow, we return false. If we overflow, we compute again using | |
| 156 * doubles, which is much slower (3x in a desktop test) but will not overflow. | |
| 157 */ | |
| 125 bool SkPoint::setLength(float x, float y, float length) { | 158 bool SkPoint::setLength(float x, float y, float length) { |
| 126 float mag2; | 159 float mag2; |
| 127 if (!isLengthNearlyZero(x, y, &mag2)) { | 160 if (isLengthNearlyZero(x, y, &mag2)) { |
| 128 float scale = length / sk_float_sqrt(mag2); | 161 return false; |
| 129 fX = x * scale; | |
| 130 fY = y * scale; | |
| 131 return true; | |
| 132 } | 162 } |
| 133 return false; | 163 |
| 164 float scale; | |
| 165 if (SkScalarIsFinite(mag2)) { | |
| 166 scale = length / sk_float_sqrt(mag2); | |
| 167 } else { | |
| 168 // our mag2 step overflowed to infinity, so use doubles instead. | |
| 169 // much slower, but needed when x or y are very large, other wise we | |
| 170 // divide by inf. and return (0,0) vector. | |
| 171 double xx = x; | |
| 172 double yy = y; | |
| 173 scale = (float)(length / sqrt(xx * xx + yy * yy)); | |
| 174 } | |
| 175 fX = x * scale; | |
| 176 fY = y * scale; | |
| 177 return true; | |
| 134 } | 178 } |
| 135 | 179 |
| 136 #else | 180 #else |
| 137 | 181 |
| 138 #include "Sk64.h" | 182 #include "Sk64.h" |
| 139 | 183 |
| 140 // Returns the square of the Euclidian distance to (dx,dy) in *result. | 184 // Returns the square of the Euclidian distance to (dx,dy) in *result. |
| 141 static inline void getLengthSquared(SkScalar dx, SkScalar dy, Sk64 *result) { | 185 static inline void getLengthSquared(SkScalar dx, SkScalar dy, Sk64 *result) { |
| 142 Sk64 dySqr; | 186 Sk64 dySqr; |
| 143 | 187 |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 464 | 508 |
| 465 if (uDotV <= 0) { | 509 if (uDotV <= 0) { |
| 466 return v.lengthSqd(); | 510 return v.lengthSqd(); |
| 467 } else if (uDotV > uLengthSqd) { | 511 } else if (uDotV > uLengthSqd) { |
| 468 return b.distanceToSqd(*this); | 512 return b.distanceToSqd(*this); |
| 469 } else { | 513 } else { |
| 470 SkScalar det = u.cross(v); | 514 SkScalar det = u.cross(v); |
| 471 return SkScalarMulDiv(det, det, uLengthSqd); | 515 return SkScalarMulDiv(det, det, uLengthSqd); |
| 472 } | 516 } |
| 473 } | 517 } |
| OLD | NEW |