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 34static bool sTablesInitialized = false; 35static float sSinTable[360]; 36static float sCosTable[360]; 37static float sTanTable[360]; 38 39/*! 40 \brief Constructor 41 \param angle Value in degrees 42*/ 43Angle::Angle(float angle) 44 : fAngleValue(angle) 45{ 46 _InitTrigTables(); 47} 48 49//! Constructor 50Angle::Angle() 51 : fAngleValue(0) 52{ 53 _InitTrigTables(); 54} 55 56//! Empty destructor 57Angle::~Angle() 58{ 59} 60 61//! Constrains angle to 0 <= angle <= 360 62void 63Angle::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*/ 76float 77Angle::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*/ 87Angle 88Angle::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*/ 116float 117Angle::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*/ 127Angle 128Angle::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*/ 155float 156Angle::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*/ 172Angle 173Angle::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*/ 199uint8 200Angle::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*/ 220Angle 221Angle::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*/ 237Angle 238Angle::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*/ 254void 255Angle::SetValue(float angle) 256{ 257 fAngleValue = angle; 258 Normalize(); 259} 260 261 262float 263Angle::Value() const 264{ 265 return fAngleValue; 266} 267 268//! Initializes the global trig tables 269void 270Angle::_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 304Angle& 305Angle::operator=(const Angle &from) 306{ 307 fAngleValue = from.fAngleValue; 308 return *this; 309} 310 311 312Angle& 313Angle::operator=(const float &from) 314{ 315 fAngleValue = from; 316 return *this; 317} 318 319 320Angle& 321Angle::operator=(const long &from) 322{ 323 fAngleValue = (float)from; 324 return *this; 325} 326 327 328Angle& 329Angle::operator=(const int &from) 330{ 331 fAngleValue = (float)from; 332 return *this; 333} 334 335 336bool 337Angle::operator==(const Angle &from) 338{ 339 return (fAngleValue == from.fAngleValue); 340} 341 342 343bool 344Angle::operator!=(const Angle &from) 345{ 346 return (fAngleValue != from.fAngleValue); 347} 348 349 350bool 351Angle::operator>(const Angle &from) 352{ 353 return (fAngleValue > from.fAngleValue); 354} 355 356 357bool 358Angle::operator<(const Angle &from) 359{ 360 return (fAngleValue < from.fAngleValue); 361} 362 363 364bool 365Angle::operator>=(const Angle &from) 366{ 367 return (fAngleValue >= from.fAngleValue); 368} 369 370 371bool 372Angle::operator<=(const Angle &from) 373{ 374 return (fAngleValue <= from.fAngleValue); 375} 376