1
2 /*
3 * Copyright 2008 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10 #include "SkPoint.h"
11
rotateCW(SkIPoint * dst) const12 void SkIPoint::rotateCW(SkIPoint* dst) const {
13 SkASSERT(dst);
14
15 // use a tmp in case this == dst
16 int32_t tmp = fX;
17 dst->fX = -fY;
18 dst->fY = tmp;
19 }
20
rotateCCW(SkIPoint * dst) const21 void SkIPoint::rotateCCW(SkIPoint* dst) const {
22 SkASSERT(dst);
23
24 // use a tmp in case this == dst
25 int32_t tmp = fX;
26 dst->fX = fY;
27 dst->fY = -tmp;
28 }
29
30 ///////////////////////////////////////////////////////////////////////////////
31
setIRectFan(int l,int t,int r,int b,size_t stride)32 void SkPoint::setIRectFan(int l, int t, int r, int b, size_t stride) {
33 SkASSERT(stride >= sizeof(SkPoint));
34
35 ((SkPoint*)((intptr_t)this + 0 * stride))->set(SkIntToScalar(l),
36 SkIntToScalar(t));
37 ((SkPoint*)((intptr_t)this + 1 * stride))->set(SkIntToScalar(l),
38 SkIntToScalar(b));
39 ((SkPoint*)((intptr_t)this + 2 * stride))->set(SkIntToScalar(r),
40 SkIntToScalar(b));
41 ((SkPoint*)((intptr_t)this + 3 * stride))->set(SkIntToScalar(r),
42 SkIntToScalar(t));
43 }
44
setRectFan(SkScalar l,SkScalar t,SkScalar r,SkScalar b,size_t stride)45 void SkPoint::setRectFan(SkScalar l, SkScalar t, SkScalar r, SkScalar b,
46 size_t stride) {
47 SkASSERT(stride >= sizeof(SkPoint));
48
49 ((SkPoint*)((intptr_t)this + 0 * stride))->set(l, t);
50 ((SkPoint*)((intptr_t)this + 1 * stride))->set(l, b);
51 ((SkPoint*)((intptr_t)this + 2 * stride))->set(r, b);
52 ((SkPoint*)((intptr_t)this + 3 * stride))->set(r, t);
53 }
54
rotateCW(SkPoint * dst) const55 void SkPoint::rotateCW(SkPoint* dst) const {
56 SkASSERT(dst);
57
58 // use a tmp in case this == dst
59 SkScalar tmp = fX;
60 dst->fX = -fY;
61 dst->fY = tmp;
62 }
63
rotateCCW(SkPoint * dst) const64 void SkPoint::rotateCCW(SkPoint* dst) const {
65 SkASSERT(dst);
66
67 // use a tmp in case this == dst
68 SkScalar tmp = fX;
69 dst->fX = fY;
70 dst->fY = -tmp;
71 }
72
scale(SkScalar scale,SkPoint * dst) const73 void SkPoint::scale(SkScalar scale, SkPoint* dst) const {
74 SkASSERT(dst);
75 dst->set(SkScalarMul(fX, scale), SkScalarMul(fY, scale));
76 }
77
normalize()78 bool SkPoint::normalize() {
79 return this->setLength(fX, fY, SK_Scalar1);
80 }
81
setNormalize(SkScalar x,SkScalar y)82 bool SkPoint::setNormalize(SkScalar x, SkScalar y) {
83 return this->setLength(x, y, SK_Scalar1);
84 }
85
setLength(SkScalar length)86 bool SkPoint::setLength(SkScalar length) {
87 return this->setLength(fX, fY, length);
88 }
89
Normalize(SkPoint * pt)90 SkScalar SkPoint::Normalize(SkPoint* pt) {
91 SkScalar mag = SkPoint::Length(pt->fX, pt->fY);
92 if (mag > SK_ScalarNearlyZero) {
93 SkScalar scale = SkScalarInvert(mag);
94 pt->fX = SkScalarMul(pt->fX, scale);
95 pt->fY = SkScalarMul(pt->fY, scale);
96 return mag;
97 }
98 return 0;
99 }
100
101 #ifdef SK_SCALAR_IS_FLOAT
102
CanNormalize(SkScalar dx,SkScalar dy)103 bool SkPoint::CanNormalize(SkScalar dx, SkScalar dy) {
104 float mag2 = dx * dx + dy * dy;
105 return mag2 > SK_ScalarNearlyZero * SK_ScalarNearlyZero;
106 }
107
Length(SkScalar dx,SkScalar dy)108 SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) {
109 return sk_float_sqrt(dx * dx + dy * dy);
110 }
111
setLength(float x,float y,float length)112 bool SkPoint::setLength(float x, float y, float length) {
113 float mag2 = x * x + y * y;
114 if (mag2 > SK_ScalarNearlyZero * SK_ScalarNearlyZero) {
115 float scale = length / sk_float_sqrt(mag2);
116 fX = x * scale;
117 fY = y * scale;
118 return true;
119 }
120 return false;
121 }
122
123 #else
124
125 #include "Sk64.h"
126
CanNormalize(SkScalar dx,SkScalar dy)127 bool SkPoint::CanNormalize(SkScalar dx, SkScalar dy) {
128 Sk64 tmp1, tmp2, tolSqr;
129
130 tmp1.setMul(dx, dx);
131 tmp2.setMul(dy, dy);
132 tmp1.add(tmp2);
133
134 // we want nearlyzero^2, but to compute it fast we want to just do a
135 // 32bit multiply, so we require that it not exceed 31bits. That is true
136 // if nearlyzero is <= 0xB504, which should be trivial, since usually
137 // nearlyzero is a very small fixed-point value.
138 SkASSERT(SK_ScalarNearlyZero <= 0xB504);
139
140 tolSqr.set(0, SK_ScalarNearlyZero * SK_ScalarNearlyZero);
141 return tmp1 > tolSqr;
142 }
143
Length(SkScalar dx,SkScalar dy)144 SkScalar SkPoint::Length(SkScalar dx, SkScalar dy) {
145 Sk64 tmp1, tmp2;
146
147 tmp1.setMul(dx, dx);
148 tmp2.setMul(dy, dy);
149 tmp1.add(tmp2);
150
151 return tmp1.getSqrt();
152 }
153
154 #ifdef SK_DEBUGx
fixlen(SkFixed x,SkFixed y)155 static SkFixed fixlen(SkFixed x, SkFixed y) {
156 float fx = (float)x;
157 float fy = (float)y;
158
159 return (int)floorf(sqrtf(fx*fx + fy*fy) + 0.5f);
160 }
161 #endif
162
squarefixed(unsigned x)163 static inline uint32_t squarefixed(unsigned x) {
164 x >>= 16;
165 return x*x;
166 }
167
168 #if 1 // Newton iter for setLength
169
invsqrt_iter(unsigned V,unsigned U)170 static inline unsigned invsqrt_iter(unsigned V, unsigned U) {
171 unsigned x = V * U >> 14;
172 x = x * U >> 14;
173 x = (3 << 14) - x;
174 x = (U >> 1) * x >> 14;
175 return x;
176 }
177
178 static const uint16_t gInvSqrt14GuessTable[] = {
179 0x4000, 0x3c57, 0x393e, 0x3695, 0x3441, 0x3235, 0x3061,
180 0x2ebd, 0x2d41, 0x2be7, 0x2aaa, 0x2987, 0x287a, 0x2780,
181 0x2698, 0x25be, 0x24f3, 0x2434, 0x2380, 0x22d6, 0x2235,
182 0x219d, 0x210c, 0x2083, 0x2000, 0x1f82, 0x1f0b, 0x1e99,
183 0x1e2b, 0x1dc2, 0x1d5d, 0x1cfc, 0x1c9f, 0x1c45, 0x1bee,
184 0x1b9b, 0x1b4a, 0x1afc, 0x1ab0, 0x1a67, 0x1a20, 0x19dc,
185 0x1999, 0x1959, 0x191a, 0x18dd, 0x18a2, 0x1868, 0x1830,
186 0x17fa, 0x17c4, 0x1791, 0x175e, 0x172d, 0x16fd, 0x16ce
187 };
188
189 #define BUILD_INVSQRT_TABLEx
190 #ifdef BUILD_INVSQRT_TABLE
build_invsqrt14_guess_table()191 static void build_invsqrt14_guess_table() {
192 for (int i = 8; i <= 63; i++) {
193 unsigned x = SkToU16((1 << 28) / SkSqrt32(i << 25));
194 printf("0x%x, ", x);
195 }
196 printf("\n");
197 }
198 #endif
199
fast_invsqrt(uint32_t x)200 static unsigned fast_invsqrt(uint32_t x) {
201 #ifdef BUILD_INVSQRT_TABLE
202 unsigned top2 = x >> 25;
203 SkASSERT(top2 >= 8 && top2 <= 63);
204
205 static bool gOnce;
206 if (!gOnce) {
207 build_invsqrt14_guess_table();
208 gOnce = true;
209 }
210 #endif
211
212 unsigned V = x >> 14; // make V .14
213
214 unsigned top = x >> 25;
215 SkASSERT(top >= 8 && top <= 63);
216 SkASSERT(top - 8 < SK_ARRAY_COUNT(gInvSqrt14GuessTable));
217 unsigned U = gInvSqrt14GuessTable[top - 8];
218
219 U = invsqrt_iter(V, U);
220 return invsqrt_iter(V, U);
221 }
222
223 /* We "normalize" x,y to be .14 values (so we can square them and stay 32bits.
224 Then we Newton-iterate this in .14 space to compute the invser-sqrt, and
225 scale by it at the end. The .14 space means we can execute our iterations
226 and stay in 32bits as well, making the multiplies much cheaper than calling
227 SkFixedMul.
228 */
setLength(SkFixed ox,SkFixed oy,SkFixed length)229 bool SkPoint::setLength(SkFixed ox, SkFixed oy, SkFixed length) {
230 if (ox == 0) {
231 if (oy == 0) {
232 return false;
233 }
234 this->set(0, SkApplySign(length, SkExtractSign(oy)));
235 return true;
236 }
237 if (oy == 0) {
238 this->set(SkApplySign(length, SkExtractSign(ox)), 0);
239 return true;
240 }
241
242 unsigned x = SkAbs32(ox);
243 unsigned y = SkAbs32(oy);
244 int zeros = SkCLZ(x | y);
245
246 // make x,y 1.14 values so our fast sqr won't overflow
247 if (zeros > 17) {
248 x <<= zeros - 17;
249 y <<= zeros - 17;
250 } else {
251 x >>= 17 - zeros;
252 y >>= 17 - zeros;
253 }
254 SkASSERT((x | y) <= 0x7FFF);
255
256 unsigned invrt = fast_invsqrt(x*x + y*y);
257
258 x = x * invrt >> 12;
259 y = y * invrt >> 12;
260
261 if (length != SK_Fixed1) {
262 x = SkFixedMul(x, length);
263 y = SkFixedMul(y, length);
264 }
265 this->set(SkApplySign(x, SkExtractSign(ox)),
266 SkApplySign(y, SkExtractSign(oy)));
267 return true;
268 }
269 #else
270 /*
271 Normalize x,y, and then scale them by length.
272
273 The obvious way to do this would be the following:
274 S64 tmp1, tmp2;
275 tmp1.setMul(x,x);
276 tmp2.setMul(y,y);
277 tmp1.add(tmp2);
278 len = tmp1.getSqrt();
279 x' = SkFixedDiv(x, len);
280 y' = SkFixedDiv(y, len);
281 This is fine, but slower than what we do below.
282
283 The present technique does not compute the starting length, but
284 rather fiddles with x,y iteratively, all the while checking its
285 magnitude^2 (avoiding a sqrt).
286
287 We normalize by first shifting x,y so that at least one of them
288 has bit 31 set (after taking the abs of them).
289 Then we loop, refining x,y by squaring them and comparing
290 against a very large 1.0 (1 << 28), and then adding or subtracting
291 a delta (which itself is reduced by half each time through the loop).
292 For speed we want the squaring to be with a simple integer mul. To keep
293 that from overflowing we shift our coordinates down until we are dealing
294 with at most 15 bits (2^15-1)^2 * 2 says withing 32 bits)
295 When our square is close to 1.0, we shift x,y down into fixed range.
296 */
setLength(SkFixed ox,SkFixed oy,SkFixed length)297 bool SkPoint::setLength(SkFixed ox, SkFixed oy, SkFixed length) {
298 if (ox == 0) {
299 if (oy == 0)
300 return false;
301 this->set(0, SkApplySign(length, SkExtractSign(oy)));
302 return true;
303 }
304 if (oy == 0) {
305 this->set(SkApplySign(length, SkExtractSign(ox)), 0);
306 return true;
307 }
308
309 SkFixed x = SkAbs32(ox);
310 SkFixed y = SkAbs32(oy);
311
312 // shift x,y so that the greater of them is 15bits (1.14 fixed point)
313 {
314 int shift = SkCLZ(x | y);
315 // make them .30
316 x <<= shift - 1;
317 y <<= shift - 1;
318 }
319
320 SkFixed dx = x;
321 SkFixed dy = y;
322
323 for (int i = 0; i < 17; i++) {
324 dx >>= 1;
325 dy >>= 1;
326
327 U32 len2 = squarefixed(x) + squarefixed(y);
328 if (len2 >> 28) {
329 x -= dx;
330 y -= dy;
331 } else {
332 x += dx;
333 y += dy;
334 }
335 }
336 x >>= 14;
337 y >>= 14;
338
339 #ifdef SK_DEBUGx // measure how far we are from unit-length
340 {
341 static int gMaxError;
342 static int gMaxDiff;
343
344 SkFixed len = fixlen(x, y);
345 int err = len - SK_Fixed1;
346 err = SkAbs32(err);
347
348 if (err > gMaxError) {
349 gMaxError = err;
350 SkDebugf("gMaxError %d\n", err);
351 }
352
353 float fx = SkAbs32(ox)/65536.0f;
354 float fy = SkAbs32(oy)/65536.0f;
355 float mag = sqrtf(fx*fx + fy*fy);
356 fx /= mag;
357 fy /= mag;
358 SkFixed xx = (int)floorf(fx * 65536 + 0.5f);
359 SkFixed yy = (int)floorf(fy * 65536 + 0.5f);
360 err = SkMax32(SkAbs32(xx-x), SkAbs32(yy-y));
361 if (err > gMaxDiff) {
362 gMaxDiff = err;
363 SkDebugf("gMaxDiff %d\n", err);
364 }
365 }
366 #endif
367
368 x = SkApplySign(x, SkExtractSign(ox));
369 y = SkApplySign(y, SkExtractSign(oy));
370 if (length != SK_Fixed1) {
371 x = SkFixedMul(x, length);
372 y = SkFixedMul(y, length);
373 }
374
375 this->set(x, y);
376 return true;
377 }
378 #endif
379
380 #endif
381
382 ///////////////////////////////////////////////////////////////////////////////
383
distanceToLineBetweenSqd(const SkPoint & a,const SkPoint & b,Side * side) const384 SkScalar SkPoint::distanceToLineBetweenSqd(const SkPoint& a,
385 const SkPoint& b,
386 Side* side) const {
387
388 SkVector u = b - a;
389 SkVector v = *this - a;
390
391 SkScalar uLengthSqd = u.lengthSqd();
392 SkScalar det = u.cross(v);
393 if (NULL != side) {
394 SkASSERT(-1 == SkPoint::kLeft_Side &&
395 0 == SkPoint::kOn_Side &&
396 1 == kRight_Side);
397 *side = (Side) SkScalarSignAsInt(det);
398 }
399 return SkScalarMulDiv(det, det, uLengthSqd);
400 }
401
distanceToLineSegmentBetweenSqd(const SkPoint & a,const SkPoint & b) const402 SkScalar SkPoint::distanceToLineSegmentBetweenSqd(const SkPoint& a,
403 const SkPoint& b) const {
404 // See comments to distanceToLineBetweenSqd. If the projection of c onto
405 // u is between a and b then this returns the same result as that
406 // function. Otherwise, it returns the distance to the closer of a and
407 // b. Let the projection of v onto u be v'. There are three cases:
408 // 1. v' points opposite to u. c is not between a and b and is closer
409 // to a than b.
410 // 2. v' points along u and has magnitude less than y. c is between
411 // a and b and the distance to the segment is the same as distance
412 // to the line ab.
413 // 3. v' points along u and has greater magnitude than u. c is not
414 // not between a and b and is closer to b than a.
415 // v' = (u dot v) * u / |u|. So if (u dot v)/|u| is less than zero we're
416 // in case 1. If (u dot v)/|u| is > |u| we are in case 3. Otherwise
417 // we're in case 2. We actually compare (u dot v) to 0 and |u|^2 to
418 // avoid a sqrt to compute |u|.
419
420 SkVector u = b - a;
421 SkVector v = *this - a;
422
423 SkScalar uLengthSqd = u.lengthSqd();
424 SkScalar uDotV = SkPoint::DotProduct(u, v);
425
426 if (uDotV <= 0) {
427 return v.lengthSqd();
428 } else if (uDotV > uLengthSqd) {
429 return b.distanceToSqd(*this);
430 } else {
431 SkScalar det = u.cross(v);
432 return SkScalarMulDiv(det, det, uLengthSqd);
433 }
434 }
435