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