Ticket #2109: Atan2.2.patch
File Atan2.2.patch, 4.0 KB (added by , 11 years ago) |
---|
-
source/maths/Fixed.cpp
1 1 2 /* Copyright (C) 2010 Wildfire Games. 2 3 * This file is part of 0 A.D. 3 4 * … … 143 144 return r.str(); 144 145 } 145 146 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 148 static 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 150 static const CFixed_15_16 angle_0_5_pi = CFixed_15_16(102944); 151 static const CFixed_15_16 angle_1_0_pi = CFixed_15_16(205887); 152 static const CFixed_15_16 zero = CFixed_15_16(); 153 147 154 CFixed_15_16 atan2_approx(CFixed_15_16 y, CFixed_15_16 x) 148 155 { 149 CFixed_15_16 zero; 156 CFixed_15_16 angle; 157 i32 loop_var; 158 i32 previous_x_val; 159 i32 new_x_val; 150 160 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 } 154 167 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 } 157 174 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 } 160 182 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 < zero ) 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); 162 197 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); 174 209 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; 179 215 } 180 216 181 217 template<> -
source/maths/Fixed.h
1 1 2 /* Copyright (C) 2010 Wildfire Games. 2 3 * This file is part of 0 A.D. 3 4 * … … 109 110 private: 110 111 T value; 111 112 112 explicit CFixed(T v) : value(v) { }113 113 114 114 public: 115 115 enum { fract_bits = fract_bits_ }; 116 116 117 117 CFixed() : value(0) { } 118 explicit CFixed(T v) : value(v) { } 118 119 119 120 static CFixed Zero() { return CFixed(0); } 120 121 static CFixed Epsilon() { return CFixed(1); } … … 348 349 349 350 /** 350 351 * 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). 352 353 */ 353 354 CFixed_15_16 atan2_approx(CFixed_15_16 y, CFixed_15_16 x); 354 355