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 |