1 | /**************************************************************************** |
2 | * |
3 | * fttrigon.c |
4 | * |
5 | * FreeType trigonometric functions (body). |
6 | * |
7 | * Copyright (C) 2001-2019 by |
8 | * David Turner, Robert Wilhelm, and Werner Lemberg. |
9 | * |
10 | * This file is part of the FreeType project, and may only be used, |
11 | * modified, and distributed under the terms of the FreeType project |
12 | * license, LICENSE.TXT. By continuing to use, modify, or distribute |
13 | * this file you indicate that you have read the license and |
14 | * understand and accept it fully. |
15 | * |
16 | */ |
17 | |
18 | /************************************************************************** |
19 | * |
20 | * This is a fixed-point CORDIC implementation of trigonometric |
21 | * functions as well as transformations between Cartesian and polar |
22 | * coordinates. The angles are represented as 16.16 fixed-point values |
23 | * in degrees, i.e., the angular resolution is 2^-16 degrees. Note that |
24 | * only vectors longer than 2^16*180/pi (or at least 22 bits) on a |
25 | * discrete Cartesian grid can have the same or better angular |
26 | * resolution. Therefore, to maintain this precision, some functions |
27 | * require an interim upscaling of the vectors, whereas others operate |
28 | * with 24-bit long vectors directly. |
29 | * |
30 | */ |
31 | |
32 | #include <ft2build.h> |
33 | #include FT_INTERNAL_OBJECTS_H |
34 | #include FT_INTERNAL_CALC_H |
35 | #include FT_TRIGONOMETRY_H |
36 | |
37 | |
38 | /* the Cordic shrink factor 0.858785336480436 * 2^32 */ |
39 | #define FT_TRIG_SCALE 0xDBD95B16UL |
40 | |
41 | /* the highest bit in overflow-safe vector components, */ |
42 | /* MSB of 0.858785336480436 * sqrt(0.5) * 2^30 */ |
43 | #define FT_TRIG_SAFE_MSB 29 |
44 | |
45 | /* this table was generated for FT_PI = 180L << 16, i.e. degrees */ |
46 | #define FT_TRIG_MAX_ITERS 23 |
47 | |
48 | static const FT_Angle |
49 | ft_trig_arctan_table[] = |
50 | { |
51 | 1740967L, 919879L, 466945L, 234379L, 117304L, 58666L, 29335L, |
52 | 14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L, |
53 | 57L, 29L, 14L, 7L, 4L, 2L, 1L |
54 | }; |
55 | |
56 | |
57 | #ifdef FT_LONG64 |
58 | |
59 | /* multiply a given value by the CORDIC shrink factor */ |
60 | static FT_Fixed |
61 | ft_trig_downscale( FT_Fixed val ) |
62 | { |
63 | FT_Int s = 1; |
64 | |
65 | |
66 | if ( val < 0 ) |
67 | { |
68 | val = -val; |
69 | s = -1; |
70 | } |
71 | |
72 | /* 0x40000000 comes from regression analysis between true */ |
73 | /* and CORDIC hypotenuse, so it minimizes the error */ |
74 | val = (FT_Fixed)( |
75 | ( (FT_UInt64)val * FT_TRIG_SCALE + 0x40000000UL ) >> 32 ); |
76 | |
77 | return s < 0 ? -val : val; |
78 | } |
79 | |
80 | #else /* !FT_LONG64 */ |
81 | |
82 | /* multiply a given value by the CORDIC shrink factor */ |
83 | static FT_Fixed |
84 | ft_trig_downscale( FT_Fixed val ) |
85 | { |
86 | FT_Int s = 1; |
87 | FT_UInt32 lo1, hi1, lo2, hi2, lo, hi, i1, i2; |
88 | |
89 | |
90 | if ( val < 0 ) |
91 | { |
92 | val = -val; |
93 | s = -1; |
94 | } |
95 | |
96 | lo1 = (FT_UInt32)val & 0x0000FFFFU; |
97 | hi1 = (FT_UInt32)val >> 16; |
98 | lo2 = FT_TRIG_SCALE & 0x0000FFFFU; |
99 | hi2 = FT_TRIG_SCALE >> 16; |
100 | |
101 | lo = lo1 * lo2; |
102 | i1 = lo1 * hi2; |
103 | i2 = lo2 * hi1; |
104 | hi = hi1 * hi2; |
105 | |
106 | /* Check carry overflow of i1 + i2 */ |
107 | i1 += i2; |
108 | hi += (FT_UInt32)( i1 < i2 ) << 16; |
109 | |
110 | hi += i1 >> 16; |
111 | i1 = i1 << 16; |
112 | |
113 | /* Check carry overflow of i1 + lo */ |
114 | lo += i1; |
115 | hi += ( lo < i1 ); |
116 | |
117 | /* 0x40000000 comes from regression analysis between true */ |
118 | /* and CORDIC hypotenuse, so it minimizes the error */ |
119 | |
120 | /* Check carry overflow of lo + 0x40000000 */ |
121 | lo += 0x40000000UL; |
122 | hi += ( lo < 0x40000000UL ); |
123 | |
124 | val = (FT_Fixed)hi; |
125 | |
126 | return s < 0 ? -val : val; |
127 | } |
128 | |
129 | #endif /* !FT_LONG64 */ |
130 | |
131 | |
132 | /* undefined and never called for zero vector */ |
133 | static FT_Int |
134 | ft_trig_prenorm( FT_Vector* vec ) |
135 | { |
136 | FT_Pos x, y; |
137 | FT_Int shift; |
138 | |
139 | |
140 | x = vec->x; |
141 | y = vec->y; |
142 | |
143 | shift = FT_MSB( (FT_UInt32)( FT_ABS( x ) | FT_ABS( y ) ) ); |
144 | |
145 | if ( shift <= FT_TRIG_SAFE_MSB ) |
146 | { |
147 | shift = FT_TRIG_SAFE_MSB - shift; |
148 | vec->x = (FT_Pos)( (FT_ULong)x << shift ); |
149 | vec->y = (FT_Pos)( (FT_ULong)y << shift ); |
150 | } |
151 | else |
152 | { |
153 | shift -= FT_TRIG_SAFE_MSB; |
154 | vec->x = x >> shift; |
155 | vec->y = y >> shift; |
156 | shift = -shift; |
157 | } |
158 | |
159 | return shift; |
160 | } |
161 | |
162 | |
163 | static void |
164 | ft_trig_pseudo_rotate( FT_Vector* vec, |
165 | FT_Angle theta ) |
166 | { |
167 | FT_Int i; |
168 | FT_Fixed x, y, xtemp, b; |
169 | const FT_Angle *arctanptr; |
170 | |
171 | |
172 | x = vec->x; |
173 | y = vec->y; |
174 | |
175 | /* Rotate inside [-PI/4,PI/4] sector */ |
176 | while ( theta < -FT_ANGLE_PI4 ) |
177 | { |
178 | xtemp = y; |
179 | y = -x; |
180 | x = xtemp; |
181 | theta += FT_ANGLE_PI2; |
182 | } |
183 | |
184 | while ( theta > FT_ANGLE_PI4 ) |
185 | { |
186 | xtemp = -y; |
187 | y = x; |
188 | x = xtemp; |
189 | theta -= FT_ANGLE_PI2; |
190 | } |
191 | |
192 | arctanptr = ft_trig_arctan_table; |
193 | |
194 | /* Pseudorotations, with right shifts */ |
195 | for ( i = 1, b = 1; i < FT_TRIG_MAX_ITERS; b <<= 1, i++ ) |
196 | { |
197 | if ( theta < 0 ) |
198 | { |
199 | xtemp = x + ( ( y + b ) >> i ); |
200 | y = y - ( ( x + b ) >> i ); |
201 | x = xtemp; |
202 | theta += *arctanptr++; |
203 | } |
204 | else |
205 | { |
206 | xtemp = x - ( ( y + b ) >> i ); |
207 | y = y + ( ( x + b ) >> i ); |
208 | x = xtemp; |
209 | theta -= *arctanptr++; |
210 | } |
211 | } |
212 | |
213 | vec->x = x; |
214 | vec->y = y; |
215 | } |
216 | |
217 | |
218 | static void |
219 | ft_trig_pseudo_polarize( FT_Vector* vec ) |
220 | { |
221 | FT_Angle theta; |
222 | FT_Int i; |
223 | FT_Fixed x, y, xtemp, b; |
224 | const FT_Angle *arctanptr; |
225 | |
226 | |
227 | x = vec->x; |
228 | y = vec->y; |
229 | |
230 | /* Get the vector into [-PI/4,PI/4] sector */ |
231 | if ( y > x ) |
232 | { |
233 | if ( y > -x ) |
234 | { |
235 | theta = FT_ANGLE_PI2; |
236 | xtemp = y; |
237 | y = -x; |
238 | x = xtemp; |
239 | } |
240 | else |
241 | { |
242 | theta = y > 0 ? FT_ANGLE_PI : -FT_ANGLE_PI; |
243 | x = -x; |
244 | y = -y; |
245 | } |
246 | } |
247 | else |
248 | { |
249 | if ( y < -x ) |
250 | { |
251 | theta = -FT_ANGLE_PI2; |
252 | xtemp = -y; |
253 | y = x; |
254 | x = xtemp; |
255 | } |
256 | else |
257 | { |
258 | theta = 0; |
259 | } |
260 | } |
261 | |
262 | arctanptr = ft_trig_arctan_table; |
263 | |
264 | /* Pseudorotations, with right shifts */ |
265 | for ( i = 1, b = 1; i < FT_TRIG_MAX_ITERS; b <<= 1, i++ ) |
266 | { |
267 | if ( y > 0 ) |
268 | { |
269 | xtemp = x + ( ( y + b ) >> i ); |
270 | y = y - ( ( x + b ) >> i ); |
271 | x = xtemp; |
272 | theta += *arctanptr++; |
273 | } |
274 | else |
275 | { |
276 | xtemp = x - ( ( y + b ) >> i ); |
277 | y = y + ( ( x + b ) >> i ); |
278 | x = xtemp; |
279 | theta -= *arctanptr++; |
280 | } |
281 | } |
282 | |
283 | /* round theta to acknowledge its error that mostly comes */ |
284 | /* from accumulated rounding errors in the arctan table */ |
285 | if ( theta >= 0 ) |
286 | theta = FT_PAD_ROUND( theta, 16 ); |
287 | else |
288 | theta = -FT_PAD_ROUND( -theta, 16 ); |
289 | |
290 | vec->x = x; |
291 | vec->y = theta; |
292 | } |
293 | |
294 | |
295 | /* documentation is in fttrigon.h */ |
296 | |
297 | FT_EXPORT_DEF( FT_Fixed ) |
298 | FT_Cos( FT_Angle angle ) |
299 | { |
300 | FT_Vector v; |
301 | |
302 | |
303 | FT_Vector_Unit( &v, angle ); |
304 | |
305 | return v.x; |
306 | } |
307 | |
308 | |
309 | /* documentation is in fttrigon.h */ |
310 | |
311 | FT_EXPORT_DEF( FT_Fixed ) |
312 | FT_Sin( FT_Angle angle ) |
313 | { |
314 | FT_Vector v; |
315 | |
316 | |
317 | FT_Vector_Unit( &v, angle ); |
318 | |
319 | return v.y; |
320 | } |
321 | |
322 | |
323 | /* documentation is in fttrigon.h */ |
324 | |
325 | FT_EXPORT_DEF( FT_Fixed ) |
326 | FT_Tan( FT_Angle angle ) |
327 | { |
328 | FT_Vector v = { 1 << 24, 0 }; |
329 | |
330 | |
331 | ft_trig_pseudo_rotate( &v, angle ); |
332 | |
333 | return FT_DivFix( v.y, v.x ); |
334 | } |
335 | |
336 | |
337 | /* documentation is in fttrigon.h */ |
338 | |
339 | FT_EXPORT_DEF( FT_Angle ) |
340 | FT_Atan2( FT_Fixed dx, |
341 | FT_Fixed dy ) |
342 | { |
343 | FT_Vector v; |
344 | |
345 | |
346 | if ( dx == 0 && dy == 0 ) |
347 | return 0; |
348 | |
349 | v.x = dx; |
350 | v.y = dy; |
351 | ft_trig_prenorm( &v ); |
352 | ft_trig_pseudo_polarize( &v ); |
353 | |
354 | return v.y; |
355 | } |
356 | |
357 | |
358 | /* documentation is in fttrigon.h */ |
359 | |
360 | FT_EXPORT_DEF( void ) |
361 | FT_Vector_Unit( FT_Vector* vec, |
362 | FT_Angle angle ) |
363 | { |
364 | if ( !vec ) |
365 | return; |
366 | |
367 | vec->x = FT_TRIG_SCALE >> 8; |
368 | vec->y = 0; |
369 | ft_trig_pseudo_rotate( vec, angle ); |
370 | vec->x = ( vec->x + 0x80L ) >> 8; |
371 | vec->y = ( vec->y + 0x80L ) >> 8; |
372 | } |
373 | |
374 | |
375 | /* documentation is in fttrigon.h */ |
376 | |
377 | FT_EXPORT_DEF( void ) |
378 | FT_Vector_Rotate( FT_Vector* vec, |
379 | FT_Angle angle ) |
380 | { |
381 | FT_Int shift; |
382 | FT_Vector v; |
383 | |
384 | |
385 | if ( !vec || !angle ) |
386 | return; |
387 | |
388 | v = *vec; |
389 | |
390 | if ( v.x == 0 && v.y == 0 ) |
391 | return; |
392 | |
393 | shift = ft_trig_prenorm( &v ); |
394 | ft_trig_pseudo_rotate( &v, angle ); |
395 | v.x = ft_trig_downscale( v.x ); |
396 | v.y = ft_trig_downscale( v.y ); |
397 | |
398 | if ( shift > 0 ) |
399 | { |
400 | FT_Int32 half = (FT_Int32)1L << ( shift - 1 ); |
401 | |
402 | |
403 | vec->x = ( v.x + half - ( v.x < 0 ) ) >> shift; |
404 | vec->y = ( v.y + half - ( v.y < 0 ) ) >> shift; |
405 | } |
406 | else |
407 | { |
408 | shift = -shift; |
409 | vec->x = (FT_Pos)( (FT_ULong)v.x << shift ); |
410 | vec->y = (FT_Pos)( (FT_ULong)v.y << shift ); |
411 | } |
412 | } |
413 | |
414 | |
415 | /* documentation is in fttrigon.h */ |
416 | |
417 | FT_EXPORT_DEF( FT_Fixed ) |
418 | FT_Vector_Length( FT_Vector* vec ) |
419 | { |
420 | FT_Int shift; |
421 | FT_Vector v; |
422 | |
423 | |
424 | if ( !vec ) |
425 | return 0; |
426 | |
427 | v = *vec; |
428 | |
429 | /* handle trivial cases */ |
430 | if ( v.x == 0 ) |
431 | { |
432 | return FT_ABS( v.y ); |
433 | } |
434 | else if ( v.y == 0 ) |
435 | { |
436 | return FT_ABS( v.x ); |
437 | } |
438 | |
439 | /* general case */ |
440 | shift = ft_trig_prenorm( &v ); |
441 | ft_trig_pseudo_polarize( &v ); |
442 | |
443 | v.x = ft_trig_downscale( v.x ); |
444 | |
445 | if ( shift > 0 ) |
446 | return ( v.x + ( 1L << ( shift - 1 ) ) ) >> shift; |
447 | |
448 | return (FT_Fixed)( (FT_UInt32)v.x << -shift ); |
449 | } |
450 | |
451 | |
452 | /* documentation is in fttrigon.h */ |
453 | |
454 | FT_EXPORT_DEF( void ) |
455 | FT_Vector_Polarize( FT_Vector* vec, |
456 | FT_Fixed *length, |
457 | FT_Angle *angle ) |
458 | { |
459 | FT_Int shift; |
460 | FT_Vector v; |
461 | |
462 | |
463 | if ( !vec || !length || !angle ) |
464 | return; |
465 | |
466 | v = *vec; |
467 | |
468 | if ( v.x == 0 && v.y == 0 ) |
469 | return; |
470 | |
471 | shift = ft_trig_prenorm( &v ); |
472 | ft_trig_pseudo_polarize( &v ); |
473 | |
474 | v.x = ft_trig_downscale( v.x ); |
475 | |
476 | *length = shift >= 0 ? ( v.x >> shift ) |
477 | : (FT_Fixed)( (FT_UInt32)v.x << -shift ); |
478 | *angle = v.y; |
479 | } |
480 | |
481 | |
482 | /* documentation is in fttrigon.h */ |
483 | |
484 | FT_EXPORT_DEF( void ) |
485 | FT_Vector_From_Polar( FT_Vector* vec, |
486 | FT_Fixed length, |
487 | FT_Angle angle ) |
488 | { |
489 | if ( !vec ) |
490 | return; |
491 | |
492 | vec->x = length; |
493 | vec->y = 0; |
494 | |
495 | FT_Vector_Rotate( vec, angle ); |
496 | } |
497 | |
498 | |
499 | /* documentation is in fttrigon.h */ |
500 | |
501 | FT_EXPORT_DEF( FT_Angle ) |
502 | FT_Angle_Diff( FT_Angle angle1, |
503 | FT_Angle angle2 ) |
504 | { |
505 | FT_Angle delta = angle2 - angle1; |
506 | |
507 | |
508 | while ( delta <= -FT_ANGLE_PI ) |
509 | delta += FT_ANGLE_2PI; |
510 | |
511 | while ( delta > FT_ANGLE_PI ) |
512 | delta -= FT_ANGLE_2PI; |
513 | |
514 | return delta; |
515 | } |
516 | |
517 | |
518 | /* END */ |
519 | |