1 /**************************************************************************** 2 * 3 * fttrigon.c 4 * 5 * FreeType trigonometric functions (body). 6 * 7 * Copyright (C) 2001-2020 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_LONG64 57 58 /* multiply a given value by the CORDIC shrink factor */ 59 static FT_Fixed ft_trig_downscale(FT_Fixed val)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_LONG64 */ 80 81 /* multiply a given value by the CORDIC shrink factor */ 82 static FT_Fixed ft_trig_downscale(FT_Fixed val)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_LONG64 */ 129 130 131 /* undefined and never called for zero vector */ 132 static FT_Int ft_trig_prenorm(FT_Vector * vec)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 ft_trig_pseudo_rotate(FT_Vector * vec,FT_Angle theta)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 ft_trig_pseudo_polarize(FT_Vector * vec)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 ) FT_Cos(FT_Angle angle)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 ) FT_Sin(FT_Angle angle)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 ) FT_Tan(FT_Angle angle)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 ) FT_Atan2(FT_Fixed dx,FT_Fixed dy)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 ) FT_Vector_Unit(FT_Vector * vec,FT_Angle angle)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 ) FT_Vector_Rotate(FT_Vector * vec,FT_Angle angle)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 ) FT_Vector_Length(FT_Vector * vec)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 ) FT_Vector_Polarize(FT_Vector * vec,FT_Fixed * length,FT_Angle * angle)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 ) FT_Vector_From_Polar(FT_Vector * vec,FT_Fixed length,FT_Angle angle)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 ) FT_Angle_Diff(FT_Angle angle1,FT_Angle angle2)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 */ 518