blob: 94a84862b796919a7334ee525e9dd445e77ed1ed [file] [log] [blame]
Werner Lembergf13516c2005-03-03 17:09:08 +00001/***************************************************************************/
2/* */
3/* afangles.c */
4/* */
5/* Routines used to compute vector angles with limited accuracy */
6/* and very high speed. It also contains sorting routines (body). */
7/* */
8/* Copyright 2003, 2004, 2005 by */
9/* David Turner, Robert Wilhelm, and Werner Lemberg. */
10/* */
11/* This file is part of the FreeType project, and may only be used, */
12/* modified, and distributed under the terms of the FreeType project */
13/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
14/* this file you indicate that you have read the license and */
15/* understand and accept it fully. */
16/* */
17/***************************************************************************/
18
19
David Turnerd25ad562003-10-02 21:07:10 +000020#include "aftypes.h"
21
Werner Lembergf13516c2005-03-03 17:09:08 +000022
David Turner03ee7c82005-09-23 14:14:15 +000023#if 1
24
25 /* the following table has been automatically generated with */
26 /* the `mather.py' Python script */
27
Werner Lemberg7c259462005-09-28 07:34:45 +000028#define AF_ATAN_BITS 8
David Turner03ee7c82005-09-23 14:14:15 +000029
30 static const FT_Byte af_arctan[1L << AF_ATAN_BITS] =
31 {
32 0, 0, 1, 1, 1, 2, 2, 2,
33 3, 3, 3, 3, 4, 4, 4, 5,
34 5, 5, 6, 6, 6, 7, 7, 7,
35 8, 8, 8, 9, 9, 9, 10, 10,
36 10, 10, 11, 11, 11, 12, 12, 12,
37 13, 13, 13, 14, 14, 14, 14, 15,
38 15, 15, 16, 16, 16, 17, 17, 17,
39 18, 18, 18, 18, 19, 19, 19, 20,
40 20, 20, 21, 21, 21, 21, 22, 22,
41 22, 23, 23, 23, 24, 24, 24, 24,
42 25, 25, 25, 26, 26, 26, 26, 27,
43 27, 27, 28, 28, 28, 28, 29, 29,
44 29, 30, 30, 30, 30, 31, 31, 31,
45 31, 32, 32, 32, 33, 33, 33, 33,
46 34, 34, 34, 34, 35, 35, 35, 35,
47 36, 36, 36, 36, 37, 37, 37, 38,
48 38, 38, 38, 39, 39, 39, 39, 40,
49 40, 40, 40, 41, 41, 41, 41, 42,
50 42, 42, 42, 42, 43, 43, 43, 43,
51 44, 44, 44, 44, 45, 45, 45, 45,
52 46, 46, 46, 46, 46, 47, 47, 47,
53 47, 48, 48, 48, 48, 48, 49, 49,
54 49, 49, 50, 50, 50, 50, 50, 51,
55 51, 51, 51, 51, 52, 52, 52, 52,
56 52, 53, 53, 53, 53, 53, 54, 54,
57 54, 54, 54, 55, 55, 55, 55, 55,
58 56, 56, 56, 56, 56, 57, 57, 57,
59 57, 57, 57, 58, 58, 58, 58, 58,
60 59, 59, 59, 59, 59, 59, 60, 60,
61 60, 60, 60, 61, 61, 61, 61, 61,
62 61, 62, 62, 62, 62, 62, 62, 63,
63 63, 63, 63, 63, 63, 64, 64, 64
64 };
65
66
67 FT_LOCAL_DEF( AF_Angle )
68 af_angle_atan( FT_Fixed dx,
69 FT_Fixed dy )
70 {
71 AF_Angle angle;
72
73
74 /* check trivial cases */
75 if ( dy == 0 )
76 {
77 angle = 0;
78 if ( dx < 0 )
79 angle = AF_ANGLE_PI;
80 return angle;
81 }
82 else if ( dx == 0 )
83 {
84 angle = AF_ANGLE_PI2;
85 if ( dy < 0 )
86 angle = -AF_ANGLE_PI2;
87 return angle;
88 }
89
90 angle = 0;
91 if ( dx < 0 )
92 {
93 dx = -dx;
94 dy = -dy;
95 angle = AF_ANGLE_PI;
96 }
97
98 if ( dy < 0 )
99 {
100 FT_Pos tmp;
101
102
103 tmp = dx;
104 dx = -dy;
105 dy = tmp;
106 angle -= AF_ANGLE_PI2;
107 }
108
109 if ( dx == 0 && dy == 0 )
110 return 0;
111
112 if ( dx == dy )
113 angle += AF_ANGLE_PI4;
114 else if ( dx > dy )
115 angle += af_arctan[FT_DivFix( dy, dx ) >> ( 16 - AF_ATAN_BITS )];
116 else
117 angle += AF_ANGLE_PI2 -
118 af_arctan[FT_DivFix( dx, dy ) >> ( 16 - AF_ATAN_BITS )];
119
120 if ( angle > AF_ANGLE_PI )
121 angle -= AF_ANGLE_2PI;
122
123 return angle;
124 }
125
126
127#else /* 0 */
Werner Lemberg7c259462005-09-28 07:34:45 +0000128
David Turnere664efa2004-06-04 17:41:59 +0000129/*
130 * a python script used to generate the following table
131 *
132
133import sys, math
134
Werner Lembergf13516c2005-03-03 17:09:08 +0000135units = 256
136scale = units/math.pi
137comma = ""
David Turnere664efa2004-06-04 17:41:59 +0000138
139print ""
Werner Lembergf13516c2005-03-03 17:09:08 +0000140print "table of arctan( 1/2^n ) for PI = " + repr( units / 65536.0 ) + " units"
David Turnere664efa2004-06-04 17:41:59 +0000141
Werner Lembergf13516c2005-03-03 17:09:08 +0000142r = [-1] + range( 32 )
David Turnere664efa2004-06-04 17:41:59 +0000143
144for n in r:
David Turnere664efa2004-06-04 17:41:59 +0000145 if n >= 0:
Werner Lembergf13516c2005-03-03 17:09:08 +0000146 x = 1.0 / ( 2.0 ** n ) # tangent value
David Turnere664efa2004-06-04 17:41:59 +0000147 else:
Werner Lembergf13516c2005-03-03 17:09:08 +0000148 x = 2.0 ** ( -n )
David Turnere664efa2004-06-04 17:41:59 +0000149
Werner Lembergf13516c2005-03-03 17:09:08 +0000150 angle = math.atan( x ) # arctangent
151 angle2 = angle * scale # arctangent in FT_Angle units
David Turnere664efa2004-06-04 17:41:59 +0000152
153 # determine which integer value for angle gives the best tangent
Werner Lembergf13516c2005-03-03 17:09:08 +0000154 lo = int( angle2 )
David Turnere664efa2004-06-04 17:41:59 +0000155 hi = lo + 1
Werner Lembergf13516c2005-03-03 17:09:08 +0000156 tlo = math.tan( lo / scale )
157 thi = math.tan( hi / scale )
David Turnere664efa2004-06-04 17:41:59 +0000158
159 errlo = abs( tlo - x )
160 errhi = abs( thi - x )
161
162 angle2 = hi
163 if errlo < errhi:
164 angle2 = lo
165
166 if angle2 <= 0:
167 break
168
Werner Lembergf13516c2005-03-03 17:09:08 +0000169 sys.stdout.write( comma + repr( int( angle2 ) ) )
David Turnere664efa2004-06-04 17:41:59 +0000170 comma = ", "
171
172*
173* end of python script
174*/
175
176
David Turnerd25ad562003-10-02 21:07:10 +0000177 /* this table was generated for AF_ANGLE_PI = 256 */
178#define AF_ANGLE_MAX_ITERS 8
David Turnere664efa2004-06-04 17:41:59 +0000179#define AF_TRIG_MAX_ITERS 8
David Turnerd25ad562003-10-02 21:07:10 +0000180
181 static const FT_Fixed
182 af_angle_arctan_table[9] =
183 {
David Turner87c0d302003-12-24 01:10:46 +0000184 90, 64, 38, 20, 10, 5, 3, 1, 1
David Turnerd25ad562003-10-02 21:07:10 +0000185 };
186
David Turnerff9d2412003-11-23 21:39:51 +0000187
David Turnerd25ad562003-10-02 21:07:10 +0000188 static FT_Int
189 af_angle_prenorm( FT_Vector* vec )
190 {
191 FT_Fixed x, y, z;
192 FT_Int shift;
193
194
195 x = vec->x;
196 y = vec->y;
197
198 z = ( ( x >= 0 ) ? x : - x ) | ( (y >= 0) ? y : -y );
199 shift = 0;
200
201 if ( z < ( 1L << 27 ) )
202 {
203 do
204 {
205 shift++;
206 z <<= 1;
207 } while ( z < ( 1L << 27 ) );
208
209 vec->x = x << shift;
210 vec->y = y << shift;
211 }
212 else if ( z > ( 1L << 28 ) )
213 {
214 do
215 {
216 shift++;
217 z >>= 1;
218 } while ( z > ( 1L << 28 ) );
219
220 vec->x = x >> shift;
221 vec->y = y >> shift;
222 shift = -shift;
223 }
224 return shift;
225 }
226
227
228 static void
229 af_angle_pseudo_polarize( FT_Vector* vec )
230 {
231 FT_Fixed theta;
232 FT_Fixed yi, i;
233 FT_Fixed x, y;
234 const FT_Fixed *arctanptr;
235
236
237 x = vec->x;
238 y = vec->y;
239
240 /* Get the vector into the right half plane */
241 theta = 0;
242 if ( x < 0 )
243 {
244 x = -x;
245 y = -y;
David Turnere664efa2004-06-04 17:41:59 +0000246 theta = AF_ANGLE_PI;
David Turnerd25ad562003-10-02 21:07:10 +0000247 }
248
249 if ( y > 0 )
Werner Lembergf13516c2005-03-03 17:09:08 +0000250 theta = -theta;
David Turnerd25ad562003-10-02 21:07:10 +0000251
252 arctanptr = af_angle_arctan_table;
253
254 if ( y < 0 )
255 {
256 /* Rotate positive */
257 yi = y + ( x << 1 );
258 x = x - ( y << 1 );
259 y = yi;
260 theta -= *arctanptr++; /* Subtract angle */
261 }
262 else
263 {
264 /* Rotate negative */
265 yi = y - ( x << 1 );
266 x = x + ( y << 1 );
267 y = yi;
268 theta += *arctanptr++; /* Add angle */
269 }
270
271 i = 0;
272 do
273 {
274 if ( y < 0 )
275 {
276 /* Rotate positive */
277 yi = y + ( x >> i );
278 x = x - ( y >> i );
279 y = yi;
280 theta -= *arctanptr++;
281 }
282 else
283 {
284 /* Rotate negative */
285 yi = y - ( x >> i );
286 x = x + ( y >> i );
287 y = yi;
288 theta += *arctanptr++;
289 }
290 } while ( ++i < AF_TRIG_MAX_ITERS );
291
David Turnere664efa2004-06-04 17:41:59 +0000292#if 0
David Turnerd25ad562003-10-02 21:07:10 +0000293 /* round theta */
294 if ( theta >= 0 )
Werner Lembergf13516c2005-03-03 17:09:08 +0000295 theta = FT_PAD_ROUND( theta, 2 );
David Turnerd25ad562003-10-02 21:07:10 +0000296 else
Werner Lembergf13516c2005-03-03 17:09:08 +0000297 theta = -FT_PAD_ROUND( -theta, 2 );
David Turnere664efa2004-06-04 17:41:59 +0000298#endif
David Turnerd25ad562003-10-02 21:07:10 +0000299
300 vec->x = x;
301 vec->y = theta;
302 }
303
304
Werner Lembergf13516c2005-03-03 17:09:08 +0000305 /* cf. documentation in fttrigon.h */
David Turnerd25ad562003-10-02 21:07:10 +0000306
307 FT_LOCAL_DEF( AF_Angle )
308 af_angle_atan( FT_Fixed dx,
309 FT_Fixed dy )
310 {
311 FT_Vector v;
312
313
314 if ( dx == 0 && dy == 0 )
315 return 0;
316
317 v.x = dx;
318 v.y = dy;
319 af_angle_prenorm( &v );
320 af_angle_pseudo_polarize( &v );
321
322 return v.y;
323 }
324
Werner Lemberg7c259462005-09-28 07:34:45 +0000325
David Turnerd25ad562003-10-02 21:07:10 +0000326 FT_LOCAL_DEF( AF_Angle )
327 af_angle_diff( AF_Angle angle1,
328 AF_Angle angle2 )
329 {
330 AF_Angle delta = angle2 - angle1;
David Turner87c0d302003-12-24 01:10:46 +0000331
Werner Lembergf13516c2005-03-03 17:09:08 +0000332
David Turnerd25ad562003-10-02 21:07:10 +0000333 delta %= AF_ANGLE_2PI;
334 if ( delta < 0 )
335 delta += AF_ANGLE_2PI;
David Turner87c0d302003-12-24 01:10:46 +0000336
David Turnerd25ad562003-10-02 21:07:10 +0000337 if ( delta > AF_ANGLE_PI )
338 delta -= AF_ANGLE_2PI;
David Turnerd25ad562003-10-02 21:07:10 +0000339
David Turner87c0d302003-12-24 01:10:46 +0000340 return delta;
341 }
342
Werner Lemberg4309edc2005-11-11 15:49:14 +0000343#endif /* 0 */
344
David Turner87c0d302003-12-24 01:10:46 +0000345
David Turnerff9d2412003-11-23 21:39:51 +0000346 FT_LOCAL_DEF( void )
Werner Lembergf13516c2005-03-03 17:09:08 +0000347 af_sort_pos( FT_UInt count,
348 FT_Pos* table )
David Turnerff9d2412003-11-23 21:39:51 +0000349 {
David Turnercf2c49c2003-12-24 18:42:04 +0000350 FT_UInt i, j;
351 FT_Pos swap;
David Turnerff9d2412003-11-23 21:39:51 +0000352
353
354 for ( i = 1; i < count; i++ )
355 {
356 for ( j = i; j > 0; j-- )
357 {
358 if ( table[j] > table[j - 1] )
359 break;
360
361 swap = table[j];
362 table[j] = table[j - 1];
363 table[j - 1] = swap;
364 }
365 }
David Turner87c0d302003-12-24 01:10:46 +0000366 }
David Turnercf2c49c2003-12-24 18:42:04 +0000367
368
369 FT_LOCAL_DEF( void )
370 af_sort_widths( FT_UInt count,
371 AF_Width table )
372 {
373 FT_UInt i, j;
374 AF_WidthRec swap;
375
376
377 for ( i = 1; i < count; i++ )
378 {
379 for ( j = i; j > 0; j-- )
380 {
381 if ( table[j].org > table[j - 1].org )
382 break;
383
384 swap = table[j];
385 table[j] = table[j - 1];
386 table[j - 1] = swap;
387 }
388 }
389 }
David Turnere664efa2004-06-04 17:41:59 +0000390
391
392#ifdef TEST
Werner Lembergf13516c2005-03-03 17:09:08 +0000393
David Turnere664efa2004-06-04 17:41:59 +0000394#include <stdio.h>
395#include <math.h>
396
397int main( void )
398{
399 int angle;
400 int dist;
401
Werner Lembergf13516c2005-03-03 17:09:08 +0000402
David Turnere664efa2004-06-04 17:41:59 +0000403 for ( dist = 100; dist < 1000; dist++ )
404 {
Werner Lembergf13516c2005-03-03 17:09:08 +0000405 for ( angle = AF_ANGLE_PI; angle < AF_ANGLE_2PI * 4; angle++ )
David Turnere664efa2004-06-04 17:41:59 +0000406 {
Werner Lembergf13516c2005-03-03 17:09:08 +0000407 double a = ( angle * 3.1415926535 ) / ( 1.0 * AF_ANGLE_PI );
408 int dx, dy, angle1, angle2, delta;
David Turnere664efa2004-06-04 17:41:59 +0000409
David Turnere664efa2004-06-04 17:41:59 +0000410
Werner Lembergf13516c2005-03-03 17:09:08 +0000411 dx = dist * cos( a );
412 dy = dist * sin( a );
413
414 angle1 = ( ( atan2( dy, dx ) * AF_ANGLE_PI ) / 3.1415926535 );
415 angle2 = af_angle_atan( dx, dy );
416 delta = ( angle2 - angle1 ) % AF_ANGLE_2PI;
David Turnere664efa2004-06-04 17:41:59 +0000417 if ( delta < 0 )
418 delta = -delta;
419
420 if ( delta >= 2 )
421 {
422 printf( "dist:%4d angle:%4d => (%4d,%4d) angle1:%4d angle2:%4d\n",
423 dist, angle, dx, dy, angle1, angle2 );
424 }
425 }
426 }
427 return 0;
428}
Werner Lembergf13516c2005-03-03 17:09:08 +0000429
430#endif /* TEST */
431
432
433/* END */