Line data Source code
1 : /*
2 : * Copyright 2008 The Android Open Source Project
3 : *
4 : * Use of this source code is governed by a BSD-style license that can be
5 : * found in the LICENSE file.
6 : */
7 :
8 :
9 : #include "SkMathPriv.h"
10 : #include "SkPoint.h"
11 :
12 0 : void SkIPoint::rotateCW(SkIPoint* dst) const {
13 0 : SkASSERT(dst);
14 :
15 : // use a tmp in case this == dst
16 0 : int32_t tmp = fX;
17 0 : dst->fX = -fY;
18 0 : dst->fY = tmp;
19 0 : }
20 :
21 0 : void SkIPoint::rotateCCW(SkIPoint* dst) const {
22 0 : SkASSERT(dst);
23 :
24 : // use a tmp in case this == dst
25 0 : int32_t tmp = fX;
26 0 : dst->fX = fY;
27 0 : dst->fY = -tmp;
28 0 : }
29 :
30 : ///////////////////////////////////////////////////////////////////////////////
31 :
32 0 : void SkPoint::setIRectFan(int l, int t, int r, int b, size_t stride) {
33 0 : SkASSERT(stride >= sizeof(SkPoint));
34 :
35 0 : ((SkPoint*)((intptr_t)this + 0 * stride))->set(SkIntToScalar(l),
36 0 : SkIntToScalar(t));
37 0 : ((SkPoint*)((intptr_t)this + 1 * stride))->set(SkIntToScalar(l),
38 0 : SkIntToScalar(b));
39 0 : ((SkPoint*)((intptr_t)this + 2 * stride))->set(SkIntToScalar(r),
40 0 : SkIntToScalar(b));
41 0 : ((SkPoint*)((intptr_t)this + 3 * stride))->set(SkIntToScalar(r),
42 0 : SkIntToScalar(t));
43 0 : }
44 :
45 0 : void SkPoint::rotateCW(SkPoint* dst) const {
46 0 : SkASSERT(dst);
47 :
48 : // use a tmp in case this == dst
49 0 : SkScalar tmp = fX;
50 0 : dst->fX = -fY;
51 0 : dst->fY = tmp;
52 0 : }
53 :
54 37 : void SkPoint::rotateCCW(SkPoint* dst) const {
55 37 : SkASSERT(dst);
56 :
57 : // use a tmp in case this == dst
58 37 : SkScalar tmp = fX;
59 37 : dst->fX = fY;
60 37 : dst->fY = -tmp;
61 37 : }
62 :
63 62 : void SkPoint::scale(SkScalar scale, SkPoint* dst) const {
64 62 : SkASSERT(dst);
65 62 : dst->set(fX * scale, fY * scale);
66 62 : }
67 :
68 0 : bool SkPoint::normalize() {
69 0 : return this->setLength(fX, fY, SK_Scalar1);
70 : }
71 :
72 37 : bool SkPoint::setNormalize(SkScalar x, SkScalar y) {
73 37 : return this->setLength(x, y, SK_Scalar1);
74 : }
75 :
76 64 : bool SkPoint::setLength(SkScalar length) {
77 64 : return this->setLength(fX, fY, length);
78 : }
79 :
80 : // Returns the square of the Euclidian distance to (dx,dy).
81 101 : static inline float getLengthSquared(float dx, float dy) {
82 101 : return dx * dx + dy * dy;
83 : }
84 :
85 : // Calculates the square of the Euclidian distance to (dx,dy) and stores it in
86 : // *lengthSquared. Returns true if the distance is judged to be "nearly zero".
87 : //
88 : // This logic is encapsulated in a helper method to make it explicit that we
89 : // always perform this check in the same manner, to avoid inconsistencies
90 : // (see http://code.google.com/p/skia/issues/detail?id=560 ).
91 101 : static inline bool is_length_nearly_zero(float dx, float dy,
92 : float *lengthSquared) {
93 101 : *lengthSquared = getLengthSquared(dx, dy);
94 101 : return *lengthSquared <= (SK_ScalarNearlyZero * SK_ScalarNearlyZero);
95 : }
96 :
97 0 : SkScalar SkPoint::Normalize(SkPoint* pt) {
98 0 : float x = pt->fX;
99 0 : float y = pt->fY;
100 : float mag2;
101 0 : if (is_length_nearly_zero(x, y, &mag2)) {
102 0 : pt->set(0, 0);
103 0 : return 0;
104 : }
105 :
106 : float mag, scale;
107 0 : if (SkScalarIsFinite(mag2)) {
108 0 : mag = sk_float_sqrt(mag2);
109 0 : scale = 1 / mag;
110 : } else {
111 : // our mag2 step overflowed to infinity, so use doubles instead.
112 : // much slower, but needed when x or y are very large, other wise we
113 : // divide by inf. and return (0,0) vector.
114 0 : double xx = x;
115 0 : double yy = y;
116 0 : double magmag = sqrt(xx * xx + yy * yy);
117 0 : mag = (float)magmag;
118 : // we perform the divide with the double magmag, to stay exactly the
119 : // same as setLength. It would be faster to perform the divide with
120 : // mag, but it is possible that mag has overflowed to inf. but still
121 : // have a non-zero value for scale (thanks to denormalized numbers).
122 0 : scale = (float)(1 / magmag);
123 : }
124 0 : pt->set(x * scale, y * scale);
125 0 : return mag;
126 : }
127 :
128 80 : SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) {
129 80 : float mag2 = dx * dx + dy * dy;
130 80 : if (SkScalarIsFinite(mag2)) {
131 80 : return sk_float_sqrt(mag2);
132 : } else {
133 0 : double xx = dx;
134 0 : double yy = dy;
135 0 : return (float)sqrt(xx * xx + yy * yy);
136 : }
137 : }
138 :
139 : /*
140 : * We have to worry about 2 tricky conditions:
141 : * 1. underflow of mag2 (compared against nearlyzero^2)
142 : * 2. overflow of mag2 (compared w/ isfinite)
143 : *
144 : * If we underflow, we return false. If we overflow, we compute again using
145 : * doubles, which is much slower (3x in a desktop test) but will not overflow.
146 : */
147 101 : bool SkPoint::setLength(float x, float y, float length) {
148 : float mag2;
149 101 : if (is_length_nearly_zero(x, y, &mag2)) {
150 0 : this->set(0, 0);
151 0 : return false;
152 : }
153 :
154 : float scale;
155 101 : if (SkScalarIsFinite(mag2)) {
156 101 : scale = length / sk_float_sqrt(mag2);
157 : } else {
158 : // our mag2 step overflowed to infinity, so use doubles instead.
159 : // much slower, but needed when x or y are very large, other wise we
160 : // divide by inf. and return (0,0) vector.
161 0 : double xx = x;
162 0 : double yy = y;
163 : #ifdef SK_CPU_FLUSH_TO_ZERO
164 : // The iOS ARM processor discards small denormalized numbers to go faster.
165 : // Casting this to a float would cause the scale to go to zero. Keeping it
166 : // as a double for the multiply keeps the scale non-zero.
167 : double dscale = length / sqrt(xx * xx + yy * yy);
168 : fX = x * dscale;
169 : fY = y * dscale;
170 : return true;
171 : #else
172 0 : scale = (float)(length / sqrt(xx * xx + yy * yy));
173 : #endif
174 : }
175 101 : fX = x * scale;
176 101 : fY = y * scale;
177 101 : return true;
178 : }
179 :
180 0 : bool SkPoint::setLengthFast(float length) {
181 0 : return this->setLengthFast(fX, fY, length);
182 : }
183 :
184 0 : bool SkPoint::setLengthFast(float x, float y, float length) {
185 : float mag2;
186 0 : if (is_length_nearly_zero(x, y, &mag2)) {
187 0 : this->set(0, 0);
188 0 : return false;
189 : }
190 :
191 : float scale;
192 0 : if (SkScalarIsFinite(mag2)) {
193 0 : scale = length * sk_float_rsqrt(mag2); // <--- this is the difference
194 : } else {
195 : // our mag2 step overflowed to infinity, so use doubles instead.
196 : // much slower, but needed when x or y are very large, other wise we
197 : // divide by inf. and return (0,0) vector.
198 0 : double xx = x;
199 0 : double yy = y;
200 0 : scale = (float)(length / sqrt(xx * xx + yy * yy));
201 : }
202 0 : fX = x * scale;
203 0 : fY = y * scale;
204 0 : return true;
205 : }
206 :
207 :
208 : ///////////////////////////////////////////////////////////////////////////////
209 :
210 0 : SkScalar SkPoint::distanceToLineBetweenSqd(const SkPoint& a,
211 : const SkPoint& b,
212 : Side* side) const {
213 :
214 0 : SkVector u = b - a;
215 0 : SkVector v = *this - a;
216 :
217 0 : SkScalar uLengthSqd = u.lengthSqd();
218 0 : SkScalar det = u.cross(v);
219 0 : if (side) {
220 : SkASSERT(-1 == SkPoint::kLeft_Side &&
221 : 0 == SkPoint::kOn_Side &&
222 : 1 == kRight_Side);
223 0 : *side = (Side) SkScalarSignAsInt(det);
224 : }
225 0 : SkScalar temp = det / uLengthSqd;
226 0 : temp *= det;
227 0 : return temp;
228 : }
229 :
230 0 : SkScalar SkPoint::distanceToLineSegmentBetweenSqd(const SkPoint& a,
231 : const SkPoint& b) const {
232 : // See comments to distanceToLineBetweenSqd. If the projection of c onto
233 : // u is between a and b then this returns the same result as that
234 : // function. Otherwise, it returns the distance to the closer of a and
235 : // b. Let the projection of v onto u be v'. There are three cases:
236 : // 1. v' points opposite to u. c is not between a and b and is closer
237 : // to a than b.
238 : // 2. v' points along u and has magnitude less than y. c is between
239 : // a and b and the distance to the segment is the same as distance
240 : // to the line ab.
241 : // 3. v' points along u and has greater magnitude than u. c is not
242 : // not between a and b and is closer to b than a.
243 : // v' = (u dot v) * u / |u|. So if (u dot v)/|u| is less than zero we're
244 : // in case 1. If (u dot v)/|u| is > |u| we are in case 3. Otherwise
245 : // we're in case 2. We actually compare (u dot v) to 0 and |u|^2 to
246 : // avoid a sqrt to compute |u|.
247 :
248 0 : SkVector u = b - a;
249 0 : SkVector v = *this - a;
250 :
251 0 : SkScalar uLengthSqd = u.lengthSqd();
252 0 : SkScalar uDotV = SkPoint::DotProduct(u, v);
253 :
254 0 : if (uDotV <= 0) {
255 0 : return v.lengthSqd();
256 0 : } else if (uDotV > uLengthSqd) {
257 0 : return b.distanceToSqd(*this);
258 : } else {
259 0 : SkScalar det = u.cross(v);
260 0 : SkScalar temp = det / uLengthSqd;
261 0 : temp *= det;
262 0 : return temp;
263 : }
264 : }
|