fdf433ab866aa73dd89fbaa47c6c2cd98e0206f0
[framework/graphics/freetype.git] / src / base / fttrigon.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  fttrigon.c                                                             */
4 /*                                                                         */
5 /*    FreeType trigonometric functions (body).                             */
6 /*                                                                         */
7 /*  Copyright 2001, 2002, 2003, 2004, 2005 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 #include <ft2build.h>
20 #include FT_INTERNAL_OBJECTS_H
21 #include FT_TRIGONOMETRY_H
22
23
24   /* the following is 0.2715717684432231 * 2^30 */
25 #define FT_TRIG_COSCALE  0x11616E8EUL
26
27   /* this table was generated for FT_PI = 180L << 16, i.e. degrees */
28 #define FT_TRIG_MAX_ITERS  23
29
30   static const FT_Fixed
31   ft_trig_arctan_table[24] =
32   {
33     4157273L, 2949120L, 1740967L, 919879L, 466945L, 234379L, 117304L,
34     58666L, 29335L, 14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L,
35     57L, 29L, 14L, 7L, 4L, 2L, 1L
36   };
37
38   /* the Cordic shrink factor, multiplied by 2^32 */
39 #define FT_TRIG_SCALE    1166391785UL  /* 0x4585BA38UL */
40
41
42 #ifdef FT_CONFIG_HAS_INT64
43
44   /* multiply a given value by the CORDIC shrink factor */
45   static FT_Fixed
46   ft_trig_downscale( FT_Fixed  val )
47   {
48     FT_Fixed  s;
49     FT_Int64  v;
50
51
52     s   = val;
53     val = ( val >= 0 ) ? val : -val;
54
55     v   = ( val * (FT_Int64)FT_TRIG_SCALE ) + 0x100000000UL;
56     val = (FT_Fixed)( v >> 32 );
57
58     return ( s >= 0 ) ? val : -val;
59   }
60
61 #else /* !FT_CONFIG_HAS_INT64 */
62
63   /* multiply a given value by the CORDIC shrink factor */
64   static FT_Fixed
65   ft_trig_downscale( FT_Fixed  val )
66   {
67     FT_Fixed   s;
68     FT_UInt32  v1, v2, k1, k2, hi, lo1, lo2, lo3;
69
70
71     s   = val;
72     val = ( val >= 0 ) ? val : -val;
73
74     v1 = (FT_UInt32)val >> 16;
75     v2 = (FT_UInt32)(val & 0xFFFFL);
76
77     k1 = (FT_UInt32)FT_TRIG_SCALE >> 16;       /* constant */
78     k2 = (FT_UInt32)(FT_TRIG_SCALE & 0xFFFFL);   /* constant */
79
80     hi   = k1 * v1;
81     lo1  = k1 * v2 + k2 * v1;       /* can't overflow */
82
83     lo2  = ( k2 * v2 ) >> 16;
84     lo3  = ( lo1 >= lo2 ) ? lo1 : lo2;
85     lo1 += lo2;
86
87     hi  += lo1 >> 16;
88     if ( lo1 < lo3 )
89       hi += (FT_UInt32)0x10000UL;
90
91     val  = (FT_Fixed)hi;
92
93     return ( s >= 0 ) ? val : -val;
94   }
95
96 #endif /* !FT_CONFIG_HAS_INT64 */
97
98
99   static FT_Int
100   ft_trig_prenorm( FT_Vector*  vec )
101   {
102     FT_Fixed  x, y, z;
103     FT_Int    shift;
104
105
106     x = vec->x;
107     y = vec->y;
108
109     z     = ( ( x >= 0 ) ? x : - x ) | ( (y >= 0) ? y : -y );
110     shift = 0;
111
112 #if 1
113     /* determine msb bit index in `shift' */
114     if ( z >= ( 1L << 16 ) )
115     {
116       z     >>= 16;
117       shift  += 16;
118     }
119     if ( z >= ( 1L << 8 ) )
120     {
121       z     >>= 8;
122       shift  += 8;
123     }
124     if ( z >= ( 1L << 4 ) )
125     {
126       z     >>= 4;
127       shift  += 4;
128     }
129     if ( z >= ( 1L << 2 ) )
130     {
131       z     >>= 2;
132       shift  += 2;
133     }
134     if ( z >= ( 1L << 1 ) )
135     {
136       z    >>= 1;
137       shift += 1;
138     }
139
140     if ( shift <= 27 )
141     {
142       shift  = 27 - shift;
143       vec->x = x << shift;
144       vec->y = y << shift;
145     }
146     else
147     {
148       shift -= 27;
149       vec->x = x >> shift;
150       vec->y = y >> shift;
151       shift  = -shift;
152     }
153
154 #else /* 0 */
155
156     if ( z < ( 1L << 27 ) )
157     {
158       do
159       {
160         shift++;
161         z <<= 1;
162       } while ( z < ( 1L << 27 ) );
163       vec->x = x << shift;
164       vec->y = y << shift;
165     }
166     else if ( z > ( 1L << 28 ) )
167     {
168       do
169       {
170         shift++;
171         z >>= 1;
172       } while ( z > ( 1L << 28 ) );
173
174       vec->x = x >> shift;
175       vec->y = y >> shift;
176       shift  = -shift;
177     }
178
179 #endif /* 0 */
180
181     return shift;
182   }
183
184
185   static void
186   ft_trig_pseudo_rotate( FT_Vector*  vec,
187                          FT_Angle    theta )
188   {
189     FT_Int           i;
190     FT_Fixed         x, y, xtemp;
191     const FT_Fixed  *arctanptr;
192
193
194     x = vec->x;
195     y = vec->y;
196
197     /* Get angle between -90 and 90 degrees */
198     while ( theta <= -FT_ANGLE_PI2 )
199     {
200       x = -x;
201       y = -y;
202       theta += FT_ANGLE_PI;
203     }
204
205     while ( theta > FT_ANGLE_PI2 )
206     {
207       x = -x;
208       y = -y;
209       theta -= FT_ANGLE_PI;
210     }
211
212     /* Initial pseudorotation, with left shift */
213     arctanptr = ft_trig_arctan_table;
214
215     if ( theta < 0 )
216     {
217       xtemp  = x + ( y << 1 );
218       y      = y - ( x << 1 );
219       x      = xtemp;
220       theta += *arctanptr++;
221     }
222     else
223     {
224       xtemp  = x - ( y << 1 );
225       y      = y + ( x << 1 );
226       x      = xtemp;
227       theta -= *arctanptr++;
228     }
229
230     /* Subsequent pseudorotations, with right shifts */
231     i = 0;
232     do
233     {
234       if ( theta < 0 )
235       {
236         xtemp  = x + ( y >> i );
237         y      = y - ( x >> i );
238         x      = xtemp;
239         theta += *arctanptr++;
240       }
241       else
242       {
243         xtemp  = x - ( y >> i );
244         y      = y + ( x >> i );
245         x      = xtemp;
246         theta -= *arctanptr++;
247       }
248     } while ( ++i < FT_TRIG_MAX_ITERS );
249
250     vec->x = x;
251     vec->y = y;
252   }
253
254
255   static void
256   ft_trig_pseudo_polarize( FT_Vector*  vec )
257   {
258     FT_Fixed         theta;
259     FT_Fixed         yi, i;
260     FT_Fixed         x, y;
261     const FT_Fixed  *arctanptr;
262
263
264     x = vec->x;
265     y = vec->y;
266
267     /* Get the vector into the right half plane */
268     theta = 0;
269     if ( x < 0 )
270     {
271       x = -x;
272       y = -y;
273       theta = 2 * FT_ANGLE_PI2;
274     }
275
276     if ( y > 0 )
277       theta = - theta;
278
279     arctanptr = ft_trig_arctan_table;
280
281     if ( y < 0 )
282     {
283       /* Rotate positive */
284       yi     = y + ( x << 1 );
285       x      = x - ( y << 1 );
286       y      = yi;
287       theta -= *arctanptr++;  /* Subtract angle */
288     }
289     else
290     {
291       /* Rotate negative */
292       yi     = y - ( x << 1 );
293       x      = x + ( y << 1 );
294       y      = yi;
295       theta += *arctanptr++;  /* Add angle */
296     }
297
298     i = 0;
299     do
300     {
301       if ( y < 0 )
302       {
303         /* Rotate positive */
304         yi     = y + ( x >> i );
305         x      = x - ( y >> i );
306         y      = yi;
307         theta -= *arctanptr++;
308       }
309       else
310       {
311         /* Rotate negative */
312         yi     = y - ( x >> i );
313         x      = x + ( y >> i );
314         y      = yi;
315         theta += *arctanptr++;
316       }
317     } while ( ++i < FT_TRIG_MAX_ITERS );
318
319     /* round theta */
320     if ( theta >= 0 )
321       theta = FT_PAD_ROUND( theta, 32 );
322     else
323       theta = -FT_PAD_ROUND( -theta, 32 );
324
325     vec->x = x;
326     vec->y = theta;
327   }
328
329
330   /* documentation is in fttrigon.h */
331
332   FT_EXPORT_DEF( FT_Fixed )
333   FT_Cos( FT_Angle  angle )
334   {
335     FT_Vector  v;
336
337
338     v.x = FT_TRIG_COSCALE >> 2;
339     v.y = 0;
340     ft_trig_pseudo_rotate( &v, angle );
341
342     return v.x / ( 1 << 12 );
343   }
344
345
346   /* documentation is in fttrigon.h */
347
348   FT_EXPORT_DEF( FT_Fixed )
349   FT_Sin( FT_Angle  angle )
350   {
351     return FT_Cos( FT_ANGLE_PI2 - angle );
352   }
353
354
355   /* documentation is in fttrigon.h */
356
357   FT_EXPORT_DEF( FT_Fixed )
358   FT_Tan( FT_Angle  angle )
359   {
360     FT_Vector  v;
361
362
363     v.x = FT_TRIG_COSCALE >> 2;
364     v.y = 0;
365     ft_trig_pseudo_rotate( &v, angle );
366
367     return FT_DivFix( v.y, v.x );
368   }
369
370
371   /* documentation is in fttrigon.h */
372
373   FT_EXPORT_DEF( FT_Angle )
374   FT_Atan2( FT_Fixed  dx,
375             FT_Fixed  dy )
376   {
377     FT_Vector  v;
378
379
380     if ( dx == 0 && dy == 0 )
381       return 0;
382
383     v.x = dx;
384     v.y = dy;
385     ft_trig_prenorm( &v );
386     ft_trig_pseudo_polarize( &v );
387
388     return v.y;
389   }
390
391
392   /* documentation is in fttrigon.h */
393
394   FT_EXPORT_DEF( void )
395   FT_Vector_Unit( FT_Vector*  vec,
396                   FT_Angle    angle )
397   {
398     vec->x = FT_TRIG_COSCALE >> 2;
399     vec->y = 0;
400     ft_trig_pseudo_rotate( vec, angle );
401     vec->x >>= 12;
402     vec->y >>= 12;
403   }
404
405
406   /* these macros return 0 for positive numbers,
407      and -1 for negative ones */
408 #define FT_SIGN_LONG( x )   ( (x) >> ( FT_SIZEOF_LONG * 8 - 1 ) )
409 #define FT_SIGN_INT( x )    ( (x) >> ( FT_SIZEOF_INT * 8 - 1 ) )
410 #define FT_SIGN_INT32( x )  ( (x) >> 31 )
411 #define FT_SIGN_INT16( x )  ( (x) >> 15 )
412
413
414   /* documentation is in fttrigon.h */
415
416   FT_EXPORT_DEF( void )
417   FT_Vector_Rotate( FT_Vector*  vec,
418                     FT_Angle    angle )
419   {
420     FT_Int     shift;
421     FT_Vector  v;
422
423
424     v.x   = vec->x;
425     v.y   = vec->y;
426
427     if ( angle && ( v.x != 0 || v.y != 0 ) )
428     {
429       shift = ft_trig_prenorm( &v );
430       ft_trig_pseudo_rotate( &v, angle );
431       v.x = ft_trig_downscale( v.x );
432       v.y = ft_trig_downscale( v.y );
433
434       if ( shift > 0 )
435       {
436         FT_Int32  half = (FT_Int32)1L << ( shift - 1 );
437
438
439         vec->x = ( v.x + half + FT_SIGN_LONG( v.x ) ) >> shift;
440         vec->y = ( v.y + half + FT_SIGN_LONG( v.y ) ) >> shift;
441       }
442       else
443       {
444         shift  = -shift;
445         vec->x = v.x << shift;
446         vec->y = v.y << shift;
447       }
448     }
449   }
450
451
452   /* documentation is in fttrigon.h */
453
454   FT_EXPORT_DEF( FT_Fixed )
455   FT_Vector_Length( FT_Vector*  vec )
456   {
457     FT_Int     shift;
458     FT_Vector  v;
459
460
461     v = *vec;
462
463     /* handle trivial cases */
464     if ( v.x == 0 )
465     {
466       return ( v.y >= 0 ) ? v.y : -v.y;
467     }
468     else if ( v.y == 0 )
469     {
470       return ( v.x >= 0 ) ? v.x : -v.x;
471     }
472
473     /* general case */
474     shift = ft_trig_prenorm( &v );
475     ft_trig_pseudo_polarize( &v );
476
477     v.x = ft_trig_downscale( v.x );
478
479     if ( shift > 0 )
480       return ( v.x + ( 1 << ( shift - 1 ) ) ) >> shift;
481
482     return v.x << -shift;
483   }
484
485
486   /* documentation is in fttrigon.h */
487
488   FT_EXPORT_DEF( void )
489   FT_Vector_Polarize( FT_Vector*  vec,
490                       FT_Fixed   *length,
491                       FT_Angle   *angle )
492   {
493     FT_Int     shift;
494     FT_Vector  v;
495
496
497     v = *vec;
498
499     if ( v.x == 0 && v.y == 0 )
500       return;
501
502     shift = ft_trig_prenorm( &v );
503     ft_trig_pseudo_polarize( &v );
504
505     v.x = ft_trig_downscale( v.x );
506
507     *length = ( shift >= 0 ) ? ( v.x >> shift ) : ( v.x << -shift );
508     *angle  = v.y;
509   }
510
511
512   /* documentation is in fttrigon.h */
513
514   FT_EXPORT_DEF( void )
515   FT_Vector_From_Polar( FT_Vector*  vec,
516                         FT_Fixed    length,
517                         FT_Angle    angle )
518   {
519     vec->x = length;
520     vec->y = 0;
521
522     FT_Vector_Rotate( vec, angle );
523   }
524
525
526   /* documentation is in fttrigon.h */
527
528   FT_EXPORT_DEF( FT_Angle )
529   FT_Angle_Diff( FT_Angle  angle1,
530                  FT_Angle  angle2 )
531   {
532     FT_Angle  delta = angle2 - angle1;
533
534
535     delta %= FT_ANGLE_2PI;
536     if ( delta < 0 )
537       delta += FT_ANGLE_2PI;
538
539     if ( delta > FT_ANGLE_PI )
540       delta -= FT_ANGLE_2PI;
541
542     return delta;
543   }
544
545
546 /* END */