fttrigon.c

Go to the documentation of this file.
00001 /***************************************************************************/
00002 /*                                                                         */
00003 /*  fttrigon.c                                                             */
00004 /*                                                                         */
00005 /*    FreeType trigonometric functions (body).                             */
00006 /*                                                                         */
00007 /*  Copyright 2001, 2002, 2003, 2004, 2005 by                              */
00008 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
00009 /*                                                                         */
00010 /*  This file is part of the FreeType project, and may only be used,       */
00011 /*  modified, and distributed under the terms of the FreeType project      */
00012 /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
00013 /*  this file you indicate that you have read the license and              */
00014 /*  understand and accept it fully.                                        */
00015 /*                                                                         */
00016 /***************************************************************************/
00017 
00018 
00019 #include <ft2build.h>
00020 #include FT_INTERNAL_OBJECTS_H
00021 #include FT_TRIGONOMETRY_H
00022 
00023 
00024   /* the following is 0.2715717684432231 * 2^30 */
00025 #define FT_TRIG_COSCALE  0x11616E8EUL
00026 
00027   /* this table was generated for FT_PI = 180L << 16, i.e. degrees */
00028 #define FT_TRIG_MAX_ITERS  23
00029 
00030   static const FT_Fixed
00031   ft_trig_arctan_table[24] =
00032   {
00033     4157273L, 2949120L, 1740967L, 919879L, 466945L, 234379L, 117304L,
00034     58666L, 29335L, 14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L,
00035     57L, 29L, 14L, 7L, 4L, 2L, 1L
00036   };
00037 
00038   /* the Cordic shrink factor, multiplied by 2^32 */
00039 #define FT_TRIG_SCALE    1166391785UL  /* 0x4585BA38UL */
00040 
00041 
00042 #ifdef FT_CONFIG_HAS_INT64
00043 
00044   /* multiply a given value by the CORDIC shrink factor */
00045   static FT_Fixed
00046   ft_trig_downscale( FT_Fixed  val )
00047   {
00048     FT_Fixed  s;
00049     FT_Int64  v;
00050 
00051 
00052     s   = val;
00053     val = ( val >= 0 ) ? val : -val;
00054 
00055     v   = ( val * (FT_Int64)FT_TRIG_SCALE ) + 0x100000000UL;
00056     val = (FT_Fixed)( v >> 32 );
00057 
00058     return ( s >= 0 ) ? val : -val;
00059   }
00060 
00061 #else /* !FT_CONFIG_HAS_INT64 */
00062 
00063   /* multiply a given value by the CORDIC shrink factor */
00064   static FT_Fixed
00065   ft_trig_downscale( FT_Fixed  val )
00066   {
00067     FT_Fixed   s;
00068     FT_UInt32  v1, v2, k1, k2, hi, lo1, lo2, lo3;
00069 
00070 
00071     s   = val;
00072     val = ( val >= 0 ) ? val : -val;
00073 
00074     v1 = (FT_UInt32)val >> 16;
00075     v2 = (FT_UInt32)(val & 0xFFFFL);
00076 
00077     k1 = (FT_UInt32)FT_TRIG_SCALE >> 16;       /* constant */
00078     k2 = (FT_UInt32)(FT_TRIG_SCALE & 0xFFFFL);   /* constant */
00079 
00080     hi   = k1 * v1;
00081     lo1  = k1 * v2 + k2 * v1;       /* can't overflow */
00082 
00083     lo2  = ( k2 * v2 ) >> 16;
00084     lo3  = ( lo1 >= lo2 ) ? lo1 : lo2;
00085     lo1 += lo2;
00086 
00087     hi  += lo1 >> 16;
00088     if ( lo1 < lo3 )
00089       hi += (FT_UInt32)0x10000UL;
00090 
00091     val  = (FT_Fixed)hi;
00092 
00093     return ( s >= 0 ) ? val : -val;
00094   }
00095 
00096 #endif /* !FT_CONFIG_HAS_INT64 */
00097 
00098 
00099   static FT_Int
00100   ft_trig_prenorm( FT_Vector*  vec )
00101   {
00102     FT_Fixed  x, y, z;
00103     FT_Int    shift;
00104 
00105 
00106     x = vec->x;
00107     y = vec->y;
00108 
00109     z     = ( ( x >= 0 ) ? x : - x ) | ( (y >= 0) ? y : -y );
00110     shift = 0;
00111 
00112 #if 1
00113     /* determine msb bit index in `shift' */
00114     if ( z >= ( 1L << 16 ) )
00115     {
00116       z     >>= 16;
00117       shift  += 16;
00118     }
00119     if ( z >= ( 1L << 8 ) )
00120     {
00121       z     >>= 8;
00122       shift  += 8;
00123     }
00124     if ( z >= ( 1L << 4 ) )
00125     {
00126       z     >>= 4;
00127       shift  += 4;
00128     }
00129     if ( z >= ( 1L << 2 ) )
00130     {
00131       z     >>= 2;
00132       shift  += 2;
00133     }
00134     if ( z >= ( 1L << 1 ) )
00135     {
00136       z    >>= 1;
00137       shift += 1;
00138     }
00139 
00140     if ( shift <= 27 )
00141     {
00142       shift  = 27 - shift;
00143       vec->x = x << shift;
00144       vec->y = y << shift;
00145     }
00146     else
00147     {
00148       shift -= 27;
00149       vec->x = x >> shift;
00150       vec->y = y >> shift;
00151       shift  = -shift;
00152     }
00153 
00154 #else /* 0 */
00155 
00156     if ( z < ( 1L << 27 ) )
00157     {
00158       do
00159       {
00160         shift++;
00161         z <<= 1;
00162       } while ( z < ( 1L << 27 ) );
00163       vec->x = x << shift;
00164       vec->y = y << shift;
00165     }
00166     else if ( z > ( 1L << 28 ) )
00167     {
00168       do
00169       {
00170         shift++;
00171         z >>= 1;
00172       } while ( z > ( 1L << 28 ) );
00173 
00174       vec->x = x >> shift;
00175       vec->y = y >> shift;
00176       shift  = -shift;
00177     }
00178 
00179 #endif /* 0 */
00180 
00181     return shift;
00182   }
00183 
00184 
00185   static void
00186   ft_trig_pseudo_rotate( FT_Vector*  vec,
00187                          FT_Angle    theta )
00188   {
00189     FT_Int           i;
00190     FT_Fixed         x, y, xtemp;
00191     const FT_Fixed  *arctanptr;
00192 
00193 
00194     x = vec->x;
00195     y = vec->y;
00196 
00197     /* Get angle between -90 and 90 degrees */
00198     while ( theta <= -FT_ANGLE_PI2 )
00199     {
00200       x = -x;
00201       y = -y;
00202       theta += FT_ANGLE_PI;
00203     }
00204 
00205     while ( theta > FT_ANGLE_PI2 )
00206     {
00207       x = -x;
00208       y = -y;
00209       theta -= FT_ANGLE_PI;
00210     }
00211 
00212     /* Initial pseudorotation, with left shift */
00213     arctanptr = ft_trig_arctan_table;
00214 
00215     if ( theta < 0 )
00216     {
00217       xtemp  = x + ( y << 1 );
00218       y      = y - ( x << 1 );
00219       x      = xtemp;
00220       theta += *arctanptr++;
00221     }
00222     else
00223     {
00224       xtemp  = x - ( y << 1 );
00225       y      = y + ( x << 1 );
00226       x      = xtemp;
00227       theta -= *arctanptr++;
00228     }
00229 
00230     /* Subsequent pseudorotations, with right shifts */
00231     i = 0;
00232     do
00233     {
00234       if ( theta < 0 )
00235       {
00236         xtemp  = x + ( y >> i );
00237         y      = y - ( x >> i );
00238         x      = xtemp;
00239         theta += *arctanptr++;
00240       }
00241       else
00242       {
00243         xtemp  = x - ( y >> i );
00244         y      = y + ( x >> i );
00245         x      = xtemp;
00246         theta -= *arctanptr++;
00247       }
00248     } while ( ++i < FT_TRIG_MAX_ITERS );
00249 
00250     vec->x = x;
00251     vec->y = y;
00252   }
00253 
00254 
00255   static void
00256   ft_trig_pseudo_polarize( FT_Vector*  vec )
00257   {
00258     FT_Fixed         theta;
00259     FT_Fixed         yi, i;
00260     FT_Fixed         x, y;
00261     const FT_Fixed  *arctanptr;
00262 
00263 
00264     x = vec->x;
00265     y = vec->y;
00266 
00267     /* Get the vector into the right half plane */
00268     theta = 0;
00269     if ( x < 0 )
00270     {
00271       x = -x;
00272       y = -y;
00273       theta = 2 * FT_ANGLE_PI2;
00274     }
00275 
00276     if ( y > 0 )
00277       theta = - theta;
00278 
00279     arctanptr = ft_trig_arctan_table;
00280 
00281     if ( y < 0 )
00282     {
00283       /* Rotate positive */
00284       yi     = y + ( x << 1 );
00285       x      = x - ( y << 1 );
00286       y      = yi;
00287       theta -= *arctanptr++;  /* Subtract angle */
00288     }
00289     else
00290     {
00291       /* Rotate negative */
00292       yi     = y - ( x << 1 );
00293       x      = x + ( y << 1 );
00294       y      = yi;
00295       theta += *arctanptr++;  /* Add angle */
00296     }
00297 
00298     i = 0;
00299     do
00300     {
00301       if ( y < 0 )
00302       {
00303         /* Rotate positive */
00304         yi     = y + ( x >> i );
00305         x      = x - ( y >> i );
00306         y      = yi;
00307         theta -= *arctanptr++;
00308       }
00309       else
00310       {
00311         /* Rotate negative */
00312         yi     = y - ( x >> i );
00313         x      = x + ( y >> i );
00314         y      = yi;
00315         theta += *arctanptr++;
00316       }
00317     } while ( ++i < FT_TRIG_MAX_ITERS );
00318 
00319     /* round theta */
00320     if ( theta >= 0 )
00321       theta = FT_PAD_ROUND( theta, 32 );
00322     else
00323       theta = -FT_PAD_ROUND( -theta, 32 );
00324 
00325     vec->x = x;
00326     vec->y = theta;
00327   }
00328 
00329 
00330   /* documentation is in fttrigon.h */
00331 
00332   FT_EXPORT_DEF( FT_Fixed )
00333   FT_Cos( FT_Angle  angle )
00334   {
00335     FT_Vector  v;
00336 
00337 
00338     v.x = FT_TRIG_COSCALE >> 2;
00339     v.y = 0;
00340     ft_trig_pseudo_rotate( &v, angle );
00341 
00342     return v.x / ( 1 << 12 );
00343   }
00344 
00345 
00346   /* documentation is in fttrigon.h */
00347 
00348   FT_EXPORT_DEF( FT_Fixed )
00349   FT_Sin( FT_Angle  angle )
00350   {
00351     return FT_Cos( FT_ANGLE_PI2 - angle );
00352   }
00353 
00354 
00355   /* documentation is in fttrigon.h */
00356 
00357   FT_EXPORT_DEF( FT_Fixed )
00358   FT_Tan( FT_Angle  angle )
00359   {
00360     FT_Vector  v;
00361 
00362 
00363     v.x = FT_TRIG_COSCALE >> 2;
00364     v.y = 0;
00365     ft_trig_pseudo_rotate( &v, angle );
00366 
00367     return FT_DivFix( v.y, v.x );
00368   }
00369 
00370 
00371   /* documentation is in fttrigon.h */
00372 
00373   FT_EXPORT_DEF( FT_Angle )
00374   FT_Atan2( FT_Fixed  dx,
00375             FT_Fixed  dy )
00376   {
00377     FT_Vector  v;
00378 
00379 
00380     if ( dx == 0 && dy == 0 )
00381       return 0;
00382 
00383     v.x = dx;
00384     v.y = dy;
00385     ft_trig_prenorm( &v );
00386     ft_trig_pseudo_polarize( &v );
00387 
00388     return v.y;
00389   }
00390 
00391 
00392   /* documentation is in fttrigon.h */
00393 
00394   FT_EXPORT_DEF( void )
00395   FT_Vector_Unit( FT_Vector*  vec,
00396                   FT_Angle    angle )
00397   {
00398     vec->x = FT_TRIG_COSCALE >> 2;
00399     vec->y = 0;
00400     ft_trig_pseudo_rotate( vec, angle );
00401     vec->x >>= 12;
00402     vec->y >>= 12;
00403   }
00404 
00405 
00406   /* these macros return 0 for positive numbers,
00407      and -1 for negative ones */
00408 #define FT_SIGN_LONG( x )   ( (x) >> ( FT_SIZEOF_LONG * 8 - 1 ) )
00409 #define FT_SIGN_INT( x )    ( (x) >> ( FT_SIZEOF_INT * 8 - 1 ) )
00410 #define FT_SIGN_INT32( x )  ( (x) >> 31 )
00411 #define FT_SIGN_INT16( x )  ( (x) >> 15 )
00412 
00413 
00414   /* documentation is in fttrigon.h */
00415 
00416   FT_EXPORT_DEF( void )
00417   FT_Vector_Rotate( FT_Vector*  vec,
00418                     FT_Angle    angle )
00419   {
00420     FT_Int     shift;
00421     FT_Vector  v;
00422 
00423 
00424     v.x   = vec->x;
00425     v.y   = vec->y;
00426 
00427     if ( angle && ( v.x != 0 || v.y != 0 ) )
00428     {
00429       shift = ft_trig_prenorm( &v );
00430       ft_trig_pseudo_rotate( &v, angle );
00431       v.x = ft_trig_downscale( v.x );
00432       v.y = ft_trig_downscale( v.y );
00433 
00434       if ( shift > 0 )
00435       {
00436         FT_Int32  half = (FT_Int32)1L << ( shift - 1 );
00437 
00438 
00439         vec->x = ( v.x + half + FT_SIGN_LONG( v.x ) ) >> shift;
00440         vec->y = ( v.y + half + FT_SIGN_LONG( v.y ) ) >> shift;
00441       }
00442       else
00443       {
00444         shift  = -shift;
00445         vec->x = v.x << shift;
00446         vec->y = v.y << shift;
00447       }
00448     }
00449   }
00450 
00451 
00452   /* documentation is in fttrigon.h */
00453 
00454   FT_EXPORT_DEF( FT_Fixed )
00455   FT_Vector_Length( FT_Vector*  vec )
00456   {
00457     FT_Int     shift;
00458     FT_Vector  v;
00459 
00460 
00461     v = *vec;
00462 
00463     /* handle trivial cases */
00464     if ( v.x == 0 )
00465     {
00466       return ( v.y >= 0 ) ? v.y : -v.y;
00467     }
00468     else if ( v.y == 0 )
00469     {
00470       return ( v.x >= 0 ) ? v.x : -v.x;
00471     }
00472 
00473     /* general case */
00474     shift = ft_trig_prenorm( &v );
00475     ft_trig_pseudo_polarize( &v );
00476 
00477     v.x = ft_trig_downscale( v.x );
00478 
00479     if ( shift > 0 )
00480       return ( v.x + ( 1 << ( shift - 1 ) ) ) >> shift;
00481 
00482     return v.x << -shift;
00483   }
00484 
00485 
00486   /* documentation is in fttrigon.h */
00487 
00488   FT_EXPORT_DEF( void )
00489   FT_Vector_Polarize( FT_Vector*  vec,
00490                       FT_Fixed   *length,
00491                       FT_Angle   *angle )
00492   {
00493     FT_Int     shift;
00494     FT_Vector  v;
00495 
00496 
00497     v = *vec;
00498 
00499     if ( v.x == 0 && v.y == 0 )
00500       return;
00501 
00502     shift = ft_trig_prenorm( &v );
00503     ft_trig_pseudo_polarize( &v );
00504 
00505     v.x = ft_trig_downscale( v.x );
00506 
00507     *length = ( shift >= 0 ) ? ( v.x >> shift ) : ( v.x << -shift );
00508     *angle  = v.y;
00509   }
00510 
00511 
00512   /* documentation is in fttrigon.h */
00513 
00514   FT_EXPORT_DEF( void )
00515   FT_Vector_From_Polar( FT_Vector*  vec,
00516                         FT_Fixed    length,
00517                         FT_Angle    angle )
00518   {
00519     vec->x = length;
00520     vec->y = 0;
00521 
00522     FT_Vector_Rotate( vec, angle );
00523   }
00524 
00525 
00526   /* documentation is in fttrigon.h */
00527 
00528   FT_EXPORT_DEF( FT_Angle )
00529   FT_Angle_Diff( FT_Angle  angle1,
00530                  FT_Angle  angle2 )
00531   {
00532     FT_Angle  delta = angle2 - angle1;
00533 
00534 
00535     delta %= FT_ANGLE_2PI;
00536     if ( delta < 0 )
00537       delta += FT_ANGLE_2PI;
00538 
00539     if ( delta > FT_ANGLE_PI )
00540       delta -= FT_ANGLE_2PI;
00541 
00542     return delta;
00543   }
00544 
00545 
00546 /* END */

Generated on Tue Jul 5 14:13:42 2011 for ROOT_528-00b_version by  doxygen 1.5.1