376 lines
7.5 KiB
C++
376 lines
7.5 KiB
C++
//------------------------------------------------------------------------------
|
|
// Copyright (c) 2001-2002, Haiku, Inc.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
// copy of this software and associated documentation files (the "Software"),
|
|
// to deal in the Software without restriction, including without limitation
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
// and/or sell copies of the Software, and to permit persons to whom the
|
|
// Software is furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
// DEALINGS IN THE SOFTWARE.
|
|
//
|
|
// File Name: Angle.cpp
|
|
// Author: DarkWyrm <bpmagic@columbus.rr.com>
|
|
// Description: Angle class for speeding up trig functions
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
#include "Angle.h"
|
|
#include <math.h>
|
|
|
|
#ifndef ANGLE_PI
|
|
#define ANGLE_PI 3.14159265358979323846
|
|
#endif
|
|
|
|
static bool sTablesInitialized = false;
|
|
static float sSinTable[360];
|
|
static float sCosTable[360];
|
|
static float sTanTable[360];
|
|
|
|
/*!
|
|
\brief Constructor
|
|
\param angle Value in degrees
|
|
*/
|
|
Angle::Angle(float angle)
|
|
: fAngleValue(angle)
|
|
{
|
|
_InitTrigTables();
|
|
}
|
|
|
|
//! Constructor
|
|
Angle::Angle()
|
|
: fAngleValue(0)
|
|
{
|
|
_InitTrigTables();
|
|
}
|
|
|
|
//! Empty destructor
|
|
Angle::~Angle()
|
|
{
|
|
}
|
|
|
|
//! Constrains angle to 0 <= angle <= 360
|
|
void
|
|
Angle::Normalize()
|
|
{
|
|
// if the value of the angle is >=360 or <0, make it so that it is
|
|
// within those bounds
|
|
fAngleValue = fmodf(fAngleValue, 360);
|
|
if (fAngleValue < 0)
|
|
fAngleValue += 360;
|
|
}
|
|
|
|
/*!
|
|
\brief Obtains the sine of the angle
|
|
\return The sine of the angle
|
|
*/
|
|
float
|
|
Angle::Sine()
|
|
{
|
|
return sSinTable[(int)fAngleValue];
|
|
}
|
|
|
|
/*!
|
|
\brief Calculates an angle given a float value
|
|
\param value Number between 0 and 1 inclusive
|
|
\return The angle obtained or 0 if value passed was invalid
|
|
*/
|
|
Angle
|
|
Angle::InvSine(float value)
|
|
{
|
|
// Returns the inverse sine of a value in the range 0 <= value <= 1 via
|
|
// reverse-lookup any value out of range causes the function to return 0
|
|
|
|
// Filter out bad values
|
|
value = fabs(value);
|
|
|
|
if (value > 1)
|
|
return Angle(0);
|
|
|
|
uint16 i = 90;
|
|
while (value < sSinTable[i])
|
|
i--;
|
|
|
|
// current sSinTable[i] is less than value. Pick the degree value which is closer
|
|
// to the passed value
|
|
if ((value - sSinTable[i]) > (sSinTable[i + 1] - value))
|
|
return Angle(i + 1);
|
|
|
|
return Angle(i); // value is closer to previous
|
|
}
|
|
|
|
|
|
/*!
|
|
\brief Obtains the cosine of the angle
|
|
\return The cosine of the angle
|
|
*/
|
|
float
|
|
Angle::Cosine(void)
|
|
{
|
|
return sCosTable[(int)fAngleValue];
|
|
}
|
|
|
|
/*!
|
|
\brief Calculates an angle given a float value
|
|
\param value Number between 0 and 1 inclusive
|
|
\return The angle obtained or 0 if value passed was invalid
|
|
*/
|
|
Angle
|
|
Angle::InvCosine(float value)
|
|
{
|
|
// Returns the inverse cosine of a value in the range 0 <= value <= 1 via
|
|
// reverse-lookup any value out of range causes the function to return 0
|
|
|
|
// Filter out bad values
|
|
value = fabs(value);
|
|
|
|
if (value > 1)
|
|
return 0;
|
|
|
|
uint16 i = 90;
|
|
while (value > sCosTable[i])
|
|
i--;
|
|
|
|
// current sCosTable[i] is less than value. Pick the degree value which is closer
|
|
// to the passed value
|
|
if ((value - sCosTable[i]) < (sCosTable[i + 1] - value))
|
|
return Angle(i + 1);
|
|
|
|
return Angle(i); // value is closer to previous
|
|
}
|
|
|
|
/*!
|
|
\brief Obtains the tangent of the angle
|
|
\return The tangent of the angle
|
|
*/
|
|
float
|
|
Angle::Tangent(int *status)
|
|
{
|
|
if (fAngleValue == 90 || fAngleValue == 270) {
|
|
if (status)
|
|
*status = 0;
|
|
return 0.0;
|
|
}
|
|
|
|
return sTanTable[(int)fAngleValue];
|
|
}
|
|
|
|
/*!
|
|
\brief Returns the inverse tangent of a value given
|
|
\param value Number between 0 and 1 inclusive
|
|
\return The angle found or 0 if value was invalid
|
|
*/
|
|
Angle
|
|
Angle::InvTangent(float value)
|
|
{
|
|
// Filter out bad values
|
|
value = fabs(value);
|
|
|
|
if (value > 1)
|
|
return Angle(0);
|
|
|
|
uint16 i = 90;
|
|
while (value > sTanTable[i])
|
|
i--;
|
|
|
|
if ((value - sTanTable[i]) < (sTanTable[i+1] - value))
|
|
return Angle(i+1);
|
|
|
|
return Angle(i); // value is closer to previous
|
|
}
|
|
|
|
/*!
|
|
\brief Returns a value based on what quadrant the angle is in
|
|
\return
|
|
- \c 1: 0 <= angle <90
|
|
- \c 2: 90 <= angle < 180
|
|
- \c 3: 180 <= angle < 270
|
|
- \c 4: 270 <= angle < 360
|
|
*/
|
|
uint8
|
|
Angle::Quadrant()
|
|
{
|
|
// We can get away with not doing extra value checks because of the order in
|
|
// which the checks are done.
|
|
if (fAngleValue < 90)
|
|
return 1;
|
|
|
|
if (fAngleValue < 180)
|
|
return 2;
|
|
|
|
if (fAngleValue < 270)
|
|
return 3;
|
|
|
|
return 4;
|
|
}
|
|
|
|
/*!
|
|
\brief Obtains the angle constrained to between 0 and 180 inclusive
|
|
\return The constrained value
|
|
*/
|
|
Angle
|
|
Angle::Constrain180()
|
|
{
|
|
// Constrains angle to 0 <= angle < 180
|
|
if (fAngleValue < 180)
|
|
return Angle(fAngleValue);
|
|
|
|
float value = fmodf(fAngleValue, 180);;
|
|
if (value < 0)
|
|
value += 180;
|
|
return Angle(value);
|
|
}
|
|
|
|
/*!
|
|
\brief Obtains the angle constrained to between 0 and 90 inclusive
|
|
\return The constrained value
|
|
*/
|
|
Angle
|
|
Angle::Constrain90()
|
|
{
|
|
// Constrains angle to 0 <= angle < 90
|
|
if (fAngleValue < 90)
|
|
return Angle(fAngleValue);
|
|
|
|
float value = fmodf(fAngleValue, 90);;
|
|
if (value < 0)
|
|
value += 90;
|
|
return Angle(value);
|
|
}
|
|
|
|
/*!
|
|
\brief Sets the angle's value and normalizes the value
|
|
\param angle Value in degrees
|
|
*/
|
|
void
|
|
Angle::SetValue(float angle)
|
|
{
|
|
fAngleValue = angle;
|
|
Normalize();
|
|
}
|
|
|
|
|
|
float
|
|
Angle::Value() const
|
|
{
|
|
return fAngleValue;
|
|
}
|
|
|
|
//! Initializes the global trig tables
|
|
void
|
|
Angle::_InitTrigTables()
|
|
{
|
|
if (sTablesInitialized)
|
|
return;
|
|
sTablesInitialized = true;
|
|
|
|
for(int32 i = 0; i < 90; i++) {
|
|
double currentRadian = (i * ANGLE_PI) / 180.0;
|
|
|
|
// Get these so that we can do some superfast assignments
|
|
double sinValue = sin(currentRadian);
|
|
double cosValue = cos(currentRadian);
|
|
|
|
// Do 4 assignments, taking advantage of sin/cos symmetry
|
|
sSinTable[i] = sinValue;
|
|
sSinTable[i + 90] = cosValue;
|
|
sSinTable[i + 180] = sinValue * -1;
|
|
sSinTable[i + 270] = cosValue * -1;
|
|
|
|
sCosTable[i] = cosValue;
|
|
sCosTable[i + 90] = sinValue * -1;
|
|
sCosTable[i + 180] = cosValue * -1;
|
|
sCosTable[i + 270] = sinValue;
|
|
|
|
double tanValue = sinValue / cosValue;
|
|
|
|
sTanTable[i] = tanValue;
|
|
sTanTable[i + 90] = tanValue;
|
|
sTanTable[i + 180] = tanValue;
|
|
sTanTable[i + 270] = tanValue;
|
|
}
|
|
}
|
|
|
|
|
|
Angle&
|
|
Angle::operator=(const Angle &from)
|
|
{
|
|
fAngleValue = from.fAngleValue;
|
|
return *this;
|
|
}
|
|
|
|
|
|
Angle&
|
|
Angle::operator=(const float &from)
|
|
{
|
|
fAngleValue = from;
|
|
return *this;
|
|
}
|
|
|
|
|
|
Angle&
|
|
Angle::operator=(const long &from)
|
|
{
|
|
fAngleValue = (float)from;
|
|
return *this;
|
|
}
|
|
|
|
|
|
Angle&
|
|
Angle::operator=(const int &from)
|
|
{
|
|
fAngleValue = (float)from;
|
|
return *this;
|
|
}
|
|
|
|
|
|
bool
|
|
Angle::operator==(const Angle &from)
|
|
{
|
|
return (fAngleValue == from.fAngleValue);
|
|
}
|
|
|
|
|
|
bool
|
|
Angle::operator!=(const Angle &from)
|
|
{
|
|
return (fAngleValue != from.fAngleValue);
|
|
}
|
|
|
|
|
|
bool
|
|
Angle::operator>(const Angle &from)
|
|
{
|
|
return (fAngleValue > from.fAngleValue);
|
|
}
|
|
|
|
|
|
bool
|
|
Angle::operator<(const Angle &from)
|
|
{
|
|
return (fAngleValue < from.fAngleValue);
|
|
}
|
|
|
|
|
|
bool
|
|
Angle::operator>=(const Angle &from)
|
|
{
|
|
return (fAngleValue >= from.fAngleValue);
|
|
}
|
|
|
|
|
|
bool
|
|
Angle::operator<=(const Angle &from)
|
|
{
|
|
return (fAngleValue <= from.fAngleValue);
|
|
}
|