1 //------------------------------------------------------------------------------ 2 // Copyright (c) 2001-2002, Haiku, Inc. 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a 5 // copy of this software and associated documentation files (the "Software"), 6 // to deal in the Software without restriction, including without limitation 7 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 // and/or sell copies of the Software, and to permit persons to whom the 9 // Software is furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 // DEALINGS IN THE SOFTWARE. 21 // 22 // File Name: Angle.cpp 23 // Author: DarkWyrm <bpmagic@columbus.rr.com> 24 // Description: Angle class for speeding up trig functions 25 // 26 //------------------------------------------------------------------------------ 27 #include "Angle.h" 28 #include <math.h> 29 30 #ifndef ANGLE_PI 31 #define ANGLE_PI 3.14159265358979323846 32 #endif 33 34 static bool sTablesInitialized = false; 35 static float sSinTable[360]; 36 static float sCosTable[360]; 37 static float sTanTable[360]; 38 39 /*! 40 \brief Constructor 41 \param angle Value in degrees 42 */ 43 Angle::Angle(float angle) 44 : fAngleValue(angle) 45 { 46 _InitTrigTables(); 47 } 48 49 //! Constructor 50 Angle::Angle() 51 : fAngleValue(0) 52 { 53 _InitTrigTables(); 54 } 55 56 //! Empty destructor 57 Angle::~Angle() 58 { 59 } 60 61 //! Constrains angle to 0 <= angle <= 360 62 void 63 Angle::Normalize() 64 { 65 // if the value of the angle is >=360 or <0, make it so that it is 66 // within those bounds 67 fAngleValue = fmodf(fAngleValue, 360); 68 if (fAngleValue < 0) 69 fAngleValue += 360; 70 } 71 72 /*! 73 \brief Obtains the sine of the angle 74 \return The sine of the angle 75 */ 76 float 77 Angle::Sine() 78 { 79 return sSinTable[(int)fAngleValue]; 80 } 81 82 /*! 83 \brief Calculates an angle given a float value 84 \param value Number between 0 and 1 inclusive 85 \return The angle obtained or 0 if value passed was invalid 86 */ 87 Angle 88 Angle::InvSine(float value) 89 { 90 // Returns the inverse sine of a value in the range 0 <= value <= 1 via 91 // reverse-lookup any value out of range causes the function to return 0 92 93 // Filter out bad values 94 value = fabs(value); 95 96 if (value > 1) 97 return Angle(0); 98 99 uint16 i = 90; 100 while (value < sSinTable[i]) 101 i--; 102 103 // current sSinTable[i] is less than value. Pick the degree value which is closer 104 // to the passed value 105 if ((value - sSinTable[i]) > (sSinTable[i + 1] - value)) 106 return Angle(i + 1); 107 108 return Angle(i); // value is closer to previous 109 } 110 111 112 /*! 113 \brief Obtains the cosine of the angle 114 \return The cosine of the angle 115 */ 116 float 117 Angle::Cosine(void) 118 { 119 return sCosTable[(int)fAngleValue]; 120 } 121 122 /*! 123 \brief Calculates an angle given a float value 124 \param value Number between 0 and 1 inclusive 125 \return The angle obtained or 0 if value passed was invalid 126 */ 127 Angle 128 Angle::InvCosine(float value) 129 { 130 // Returns the inverse cosine of a value in the range 0 <= value <= 1 via 131 // reverse-lookup any value out of range causes the function to return 0 132 133 // Filter out bad values 134 value = fabs(value); 135 136 if (value > 1) 137 return 0; 138 139 uint16 i = 90; 140 while (value > sCosTable[i]) 141 i--; 142 143 // current sCosTable[i] is less than value. Pick the degree value which is closer 144 // to the passed value 145 if ((value - sCosTable[i]) < (sCosTable[i + 1] - value)) 146 return Angle(i + 1); 147 148 return Angle(i); // value is closer to previous 149 } 150 151 /*! 152 \brief Obtains the tangent of the angle 153 \return The tangent of the angle 154 */ 155 float 156 Angle::Tangent(int *status) 157 { 158 if (fAngleValue == 90 || fAngleValue == 270) { 159 if (status) 160 *status = 0; 161 return 0.0; 162 } 163 164 return sTanTable[(int)fAngleValue]; 165 } 166 167 /*! 168 \brief Returns the inverse tangent of a value given 169 \param value Number between 0 and 1 inclusive 170 \return The angle found or 0 if value was invalid 171 */ 172 Angle 173 Angle::InvTangent(float value) 174 { 175 // Filter out bad values 176 value = fabs(value); 177 178 if (value > 1) 179 return Angle(0); 180 181 uint16 i = 90; 182 while (value > sTanTable[i]) 183 i--; 184 185 if( (value - sTanTable[i]) < (sTanTable[i+1] - value) ) 186 return Angle(i+1); 187 188 return Angle(i); // value is closer to previous 189 } 190 191 /*! 192 \brief Returns a value based on what quadrant the angle is in 193 \return 194 - \c 1: 0 <= angle <90 195 - \c 2: 90 <= angle < 180 196 - \c 3: 180 <= angle < 270 197 - \c 4: 270 <= angle < 360 198 */ 199 uint8 200 Angle::Quadrant() 201 { 202 // We can get away with not doing extra value checks because of the order in 203 // which the checks are done. 204 if (fAngleValue < 90) 205 return 1; 206 207 if (fAngleValue < 180) 208 return 2; 209 210 if (fAngleValue < 270) 211 return 3; 212 213 return 4; 214 } 215 216 /*! 217 \brief Obtains the angle constrained to between 0 and 180 inclusive 218 \return The constrained value 219 */ 220 Angle 221 Angle::Constrain180() 222 { 223 // Constrains angle to 0 <= angle < 180 224 if (fAngleValue < 180) 225 return Angle(fAngleValue); 226 227 float value = fmodf(fAngleValue, 180);; 228 if (value < 0) 229 value += 180; 230 return Angle(value); 231 } 232 233 /*! 234 \brief Obtains the angle constrained to between 0 and 90 inclusive 235 \return The constrained value 236 */ 237 Angle 238 Angle::Constrain90() 239 { 240 // Constrains angle to 0 <= angle < 90 241 if (fAngleValue < 90) 242 return Angle(fAngleValue); 243 244 float value = fmodf(fAngleValue, 90);; 245 if (value < 0) 246 value += 90; 247 return Angle(value); 248 } 249 250 /*! 251 \brief Sets the angle's value and normalizes the value 252 \param angle Value in degrees 253 */ 254 void 255 Angle::SetValue(float angle) 256 { 257 fAngleValue = angle; 258 Normalize(); 259 } 260 261 262 float 263 Angle::Value() const 264 { 265 return fAngleValue; 266 } 267 268 //! Initializes the global trig tables 269 void 270 Angle::_InitTrigTables() 271 { 272 if (sTablesInitialized) 273 return; 274 sTablesInitialized = true; 275 276 for(int32 i = 0; i < 90; i++) { 277 double currentRadian = (i * ANGLE_PI) / 180.0; 278 279 // Get these so that we can do some superfast assignments 280 double sinValue = sin(currentRadian); 281 double cosValue = cos(currentRadian); 282 283 // Do 4 assignments, taking advantage of sin/cos symmetry 284 sSinTable[i] = sinValue; 285 sSinTable[i + 90] = cosValue; 286 sSinTable[i + 180] = sinValue * -1; 287 sSinTable[i + 270] = cosValue * -1; 288 289 sCosTable[i] = cosValue; 290 sCosTable[i + 90] = sinValue * -1; 291 sCosTable[i + 180] = cosValue * -1; 292 sCosTable[i + 270] = sinValue; 293 294 double tanValue = sinValue / cosValue; 295 296 sTanTable[i] = tanValue; 297 sTanTable[i + 90] = tanValue; 298 sTanTable[i + 180] = tanValue; 299 sTanTable[i + 270] = tanValue; 300 } 301 } 302 303 304 Angle& 305 Angle::operator=(const Angle &from) 306 { 307 fAngleValue = from.fAngleValue; 308 return *this; 309 } 310 311 312 Angle& 313 Angle::operator=(const float &from) 314 { 315 fAngleValue = from; 316 return *this; 317 } 318 319 320 Angle& 321 Angle::operator=(const long &from) 322 { 323 fAngleValue = (float)from; 324 return *this; 325 } 326 327 328 Angle& 329 Angle::operator=(const int &from) 330 { 331 fAngleValue = (float)from; 332 return *this; 333 } 334 335 336 bool 337 Angle::operator==(const Angle &from) 338 { 339 return (fAngleValue == from.fAngleValue); 340 } 341 342 343 bool 344 Angle::operator!=(const Angle &from) 345 { 346 return (fAngleValue != from.fAngleValue); 347 } 348 349 350 bool 351 Angle::operator>(const Angle &from) 352 { 353 return (fAngleValue > from.fAngleValue); 354 } 355 356 357 bool 358 Angle::operator<(const Angle &from) 359 { 360 return (fAngleValue < from.fAngleValue); 361 } 362 363 364 bool 365 Angle::operator>=(const Angle &from) 366 { 367 return (fAngleValue >= from.fAngleValue); 368 } 369 370 371 bool 372 Angle::operator<=(const Angle &from) 373 { 374 return (fAngleValue <= from.fAngleValue); 375 } 376