Ticket #2109: Atan2.patch

File Atan2.patch, 4.0 KB (added by Thanduel, 11 years ago)

patch for fixed.h and fixed.cpp with cordic version of atan2_approx

  • source/maths/Fixed.cpp

     
     1
    12/* Copyright (C) 2010 Wildfire Games.
    23 * This file is part of 0 A.D.
    34 *
     
    143144    return r.str();
    144145}
    145146
    146 // Based on http://www.dspguru.com/dsp/tricks/fixed-point-atan2-with-self-normalization
     147//angles: 45, 26.565, 14.036, 7.125, 3.576, 1.790, 0.895, 0.448
     148static const CFixed_15_16 tan_angle_table_rad[8] = {CFixed_15_16(51472), CFixed_15_16(30386), CFixed_15_16(16055), CFixed_15_16(8150), CFixed_15_16(4091), CFixed_15_16(2047), CFixed_15_16(1042), CFixed_15_16(512) };
     149//angles 90 and 180
     150static const CFixed_15_16 angle_0_5_pi = CFixed_15_16(102944);
     151static const CFixed_15_16 angle_1_0_pi = CFixed_15_16(205887);
     152static const CFixed_15_16 zero = CFixed_15_16();
     153
    147154CFixed_15_16 atan2_approx(CFixed_15_16 y, CFixed_15_16 x)
    148155{
    149     CFixed_15_16 zero;
     156    CFixed_15_16 angle;
     157    i32 loop_var;
     158    i32 previous_x_val;
     159    i32 new_x_val;
    150160
    151     // Special case to avoid division-by-zero
    152     if (x.IsZero() && y.IsZero())
    153         return zero;
     161    //quadrant 2
     162    if(x < zero && y > zero)
     163    {
     164        angle += angle_0_5_pi;
     165        x.SetInternalValue(x.GetInternalValue()* -1);
     166    }
    154167
    155     CFixed_15_16 c1;
    156     c1.SetInternalValue(51472); // pi/4 << 16
     168    //quadrant 4
     169    else if(x > zero && y < zero)
     170    {
     171        angle -= angle_0_5_pi;
     172        y.SetInternalValue(y.GetInternalValue()* -1);
     173    }
    157174
    158     CFixed_15_16 c2;
    159     c2.SetInternalValue(154415); // 3*pi/4 << 16
     175    //quadrant 3
     176    else if(x < zero && y < zero)
     177    {
     178        angle -= angle_1_0_pi;
     179        x.SetInternalValue(x.GetInternalValue()* -1);
     180        y.SetInternalValue(y.GetInternalValue()* -1);
     181    }
    160182
    161     CFixed_15_16 abs_y = y.Absolute();
     183    for(loop_var = 0; loop_var < 5; ++loop_var)
     184    {
     185        i32 factor;
     186        //these divisions should be optimised by the compiler to shifts because the operations are always division by a power of two
     187        //this makes the cost of each division 1 cycle.
     188        if( y.GetInternalValue() < 0 )
     189        {
     190            factor = (1 << loop_var);
     191            previous_x_val = x.GetInternalValue();
     192            x -= (y/factor);
     193            new_x_val = x.GetInternalValue();
     194            x.SetInternalValue(previous_x_val);
     195            y += (x/factor);
     196            x.SetInternalValue(new_x_val);
    162197
    163     CFixed_15_16 angle;
    164     if (x >= zero)
    165     {
    166         CFixed_15_16 r = (x - abs_y) / (x + abs_y);
    167         angle = c1 - c1.Multiply(r);
    168     }
    169     else
    170     {
    171         CFixed_15_16 r = (x + abs_y) / (abs_y - x);
    172         angle = c2 - c1.Multiply(r);
    173     }
     198            angle -= tan_angle_table_rad[loop_var];
     199        }
     200        else
     201        {
     202            factor = (1 << loop_var);
     203            previous_x_val = x.GetInternalValue();
     204            x += (y/factor);
     205            new_x_val = x.GetInternalValue();
     206            x.SetInternalValue(previous_x_val);
     207            y -= (x/factor);
     208            x.SetInternalValue(new_x_val);
    174209
    175     if (y < zero)
    176         return -angle;
    177     else
    178         return angle;
     210            angle += tan_angle_table_rad[loop_var];
     211        }
     212    }
     213
     214    return angle;
    179215}
    180216
    181217template<>
  • source/maths/Fixed.h

     
     1
    12/* Copyright (C) 2010 Wildfire Games.
    23 * This file is part of 0 A.D.
    34 *
     
    109110private:
    110111    T value;
    111112
    112     explicit CFixed(T v) : value(v) { }
    113113
    114114public:
    115115    enum { fract_bits = fract_bits_ };
    116116
    117117    CFixed() : value(0) { }
     118    explicit CFixed(T v) : value(v) { }
    118119
    119120    static CFixed Zero() { return CFixed(0); }
    120121    static CFixed Epsilon() { return CFixed(1); }
     
    348349
    349350/**
    350351 * Inaccurate approximation of atan2 over fixed-point numbers.
    351  * Maximum error is almost 0.08 radians (4.5 degrees).
     352 * Maximum error is dependent on the number of iterations for 5 iterations the maximum error is about 0.062rad (3.57deg).
    352353 */
    353354CFixed_15_16 atan2_approx(CFixed_15_16 y, CFixed_15_16 x);
    354355