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