Home | History | Annotate | Download | only in base
      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 */
    547