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 bool tables_initialized=false; 35 float sintable[360], costable[360], tantable[360]; 36 37 /*! 38 \brief Constructor 39 \param angle Value in degrees 40 */ 41 Angle::Angle(float angle) 42 { 43 fAngleValue=angle; 44 if(tables_initialized==false) 45 { 46 InitTrigTables(); 47 tables_initialized=true; 48 } 49 } 50 51 //! Constructor 52 Angle::Angle() 53 { 54 fAngleValue=0; 55 if(tables_initialized==false) 56 { 57 InitTrigTables(); 58 tables_initialized=true; 59 } 60 } 61 62 //! Empty destructor 63 Angle::~Angle() 64 { 65 } 66 67 //! Constrains angle to 0 <= angle <= 360 68 void Angle::Normalize(void) 69 { 70 // if the value of the angle is >=360 or <0, make it so that it is 71 // within those bounds 72 73 if(fAngleValue>359) 74 { 75 while(fAngleValue>359) 76 fAngleValue-=360; 77 return; 78 } 79 if(fAngleValue<0) 80 { 81 while(fAngleValue<0) 82 fAngleValue+=360; 83 } 84 } 85 86 /*! 87 \brief Obtains the sine of the angle 88 \return The sine of the angle 89 */ 90 float Angle::Sine(void) 91 { 92 return sintable[(int)fAngleValue]; 93 } 94 95 /*! 96 \brief Calculates an angle given a float value 97 \param value Number between 0 and 1 inclusive 98 \return The angle obtained or 0 if value passed was invalid 99 */ 100 Angle Angle::InvSine(float value) 101 { 102 // Returns the inverse sine of a value in the range 0 <= value <= 1 via 103 // reverse-lookup any value out of range causes the function to return 0 104 uint16 i=90; 105 106 // Filter out bad values 107 if(value<0) 108 value*=-1; 109 110 if(value > 1) 111 return Angle(0); 112 113 while(value < sintable[i]) 114 i--; 115 116 // current sintable[i] is less than value. Pick the degree value which is closer 117 // to the passed value 118 if( (value - sintable[i]) > (sintable[i+1] - value) ) 119 return Angle(i+1); 120 121 return Angle(i); // value is closer to previous 122 } 123 124 125 /*! 126 \brief Obtains the cosine of the angle 127 \return The cosine of the angle 128 */ 129 float Angle::Cosine(void) 130 { 131 return costable[(int)fAngleValue]; 132 } 133 134 /*! 135 \brief Calculates an angle given a float value 136 \param value Number between 0 and 1 inclusive 137 \return The angle obtained or 0 if value passed was invalid 138 */ 139 Angle Angle::InvCosine(float value) 140 { 141 // Returns the inverse cosine of a value in the range 0 <= value <= 1 via 142 // reverse-lookup any value out of range causes the function to return 0 143 uint16 i=90; 144 145 // Filter out bad values 146 if(value<0) 147 value*=-1; 148 149 if(value > 1) 150 return 0; 151 152 while(value > costable[i]) 153 i--; 154 155 // current costable[i] is less than value. Pick the degree value which is closer 156 // to the passed value 157 if( (value - costable[i]) < (costable[i+1] - value) ) 158 return Angle(i+1); 159 160 return Angle(i); // value is closer to previous 161 } 162 163 /*! 164 \brief Obtains the tangent of the angle 165 \return The tangent of the angle 166 */ 167 float Angle::Tangent(int *status) 168 { 169 if(fAngleValue==90 || fAngleValue==270) 170 { 171 if(status) 172 *status=0; 173 return 0.0; 174 } 175 176 return tantable[(int)fAngleValue]; 177 } 178 179 /*! 180 \brief Returns the inverse tangent of a value given 181 \param value Number between 0 and 1 inclusive 182 \return The angle found or 0 if value was invalid 183 */ 184 Angle Angle::InvTangent(float value) 185 { 186 uint16 i=90; 187 188 // Filter out bad values 189 if(value<0) 190 value*=-1; 191 192 if(value > 1) 193 return Angle(0); 194 195 while(value > tantable[i]) 196 i--; 197 198 if( (value - tantable[i]) < (tantable[i+1] - value) ) 199 return Angle(i+1); 200 201 return Angle(i); // value is closer to previous 202 } 203 204 /*! 205 \brief Returns a value based on what quadrant the angle is in 206 \return 207 - \c 1: 0 <= angle <90 208 - \c 2: 90 <= angle < 180 209 - \c 3: 180 <= angle < 270 210 - \c 4: 270 <= angle < 360 211 */ 212 uint8 Angle::Quadrant(void) 213 { 214 // We can get away with not doing extra value checks because of the order in 215 // which the checks are done. 216 if(fAngleValue < 90) 217 return 1; 218 219 if(fAngleValue < 180) 220 return 2; 221 222 if(fAngleValue < 270) 223 return 3; 224 225 return 4; 226 } 227 228 /*! 229 \brief Obtains the angle constrained to between 0 and 180 inclusive 230 \return The constrained value 231 */ 232 Angle Angle::Constrain180(void) 233 { 234 // Constrains angle to 0 <= angle < 180 235 float val=fAngleValue; 236 237 if(fAngleValue<180) 238 return Angle(fAngleValue); 239 240 while(!(val<180)) 241 val-=90; 242 return Angle(val); 243 } 244 245 /*! 246 \brief Obtains the angle constrained to between 0 and 90 inclusive 247 \return The constrained value 248 */ 249 Angle Angle::Constrain90(void) 250 { 251 // Constrains angle to 0 <= angle < 90 252 float val=fAngleValue; 253 254 if(fAngleValue<90) 255 return Angle(fAngleValue); 256 257 while(!(val<90)) 258 val-=90; 259 return Angle(val); 260 } 261 262 /*! 263 \brief Sets the angle's value and normalizes the value 264 \param angle Value in degrees 265 */ 266 void Angle::SetValue(float angle) 267 { 268 fAngleValue=angle; 269 Normalize(); 270 } 271 272 /*! 273 \brief Returns the value of the angle 274 \return The angle's value in degrees 275 */ 276 float Angle::Value(void) const 277 { 278 return fAngleValue; 279 } 280 281 //! Initializes the global trig tables 282 void Angle::InitTrigTables(void) 283 { 284 int8 i; 285 double sval,cval,tval,current_radian; 286 287 for(i=0;i<90; i++) 288 { 289 current_radian=(i * ANGLE_PI)/180.0; 290 291 // Get these so that we can do some superfast assignments 292 sval=(float)sin(current_radian); 293 cval=(float)cos(current_radian); 294 295 // Do 4 assignments, taking advantage of sin/cos symmetry 296 sintable[i]=sval; 297 sintable[i+90]=cval; 298 sintable[i+180]=sval * -1; 299 sintable[i+270]=cval * -1; 300 301 costable[i]=cval; 302 costable[i+90]=sval * -1; 303 costable[i+180]=cval * -1; 304 costable[i+270]=sval; 305 306 tval=sval/cval; 307 308 tantable[i]=tval; 309 tantable[i+90]=tval; 310 tantable[i+180]=tval; 311 tantable[i+270]=tval; 312 } 313 } 314 315 /*! 316 \brief Overloaded assignment operator 317 \param from Angle to copy the value from 318 \return The angle's new value 319 */ 320 Angle & Angle::operator=(const Angle &from) 321 { 322 fAngleValue=from.fAngleValue; 323 return *this; 324 } 325 326 /*! 327 \brief Overloaded assignment operator 328 \param from New value of the angle 329 \return The angle's new value 330 */ 331 Angle & Angle::operator=(const float &from) 332 { 333 fAngleValue=from; 334 return *this; 335 } 336 337 /*! 338 \brief Overloaded assignment operator 339 \param from New value of the angle 340 \return The angle's new value 341 */ 342 Angle & Angle::operator=(const long &from) 343 { 344 fAngleValue=(float)from; 345 return *this; 346 } 347 348 /*! 349 \brief Overloaded assignment operator 350 \param from New value of the angle 351 \return The angle's new value 352 */ 353 Angle & Angle::operator=(const int &from) 354 { 355 fAngleValue=(float)from; 356 return *this; 357 } 358 359 /*! 360 \brief Overloaded equivalence operator 361 \param The angle to compare to 362 \return True if equal, false if not 363 */ 364 bool Angle::operator==(const Angle &from) 365 { 366 return (fAngleValue==from.fAngleValue)?true:false; 367 } 368 369 /*! 370 \brief Overloaded inequality operator 371 \param The angle to compare to 372 \return True if not equal, false if not 373 */ 374 bool Angle::operator!=(const Angle &from) 375 { 376 return (fAngleValue!=from.fAngleValue)?true:false; 377 } 378 379 /*! 380 \brief Overloaded greater than operator 381 \param The angle to compare to 382 \return True if greater, false if not 383 */ 384 bool Angle::operator>(const Angle &from) 385 { 386 return (fAngleValue>from.fAngleValue)?true:false; 387 } 388 389 /*! 390 \brief Overloaded less than operator 391 \param The angle to compare to 392 \return True if less than, false if not 393 */ 394 bool Angle::operator<(const Angle &from) 395 { 396 return (fAngleValue<from.fAngleValue)?true:false; 397 } 398 399 /*! 400 \brief Overloaded greater than or equal to operator 401 \param The angle to compare to 402 \return True if greater than or equal to, false if not 403 */ 404 bool Angle::operator>=(const Angle &from) 405 { 406 return (fAngleValue>=from.fAngleValue)?true:false; 407 } 408 409 /*! 410 \brief Overloaded less than or equal to operator 411 \param The angle to compare to 412 \return True if less than or equal to, false if not 413 */ 414 bool Angle::operator<=(const Angle &from) 415 { 416 return (fAngleValue<=from.fAngleValue)?true:false; 417 } 418