Last active
April 7, 2018 04:04
-
-
Save Const-me/46f90ce7fc2bc65dc12a41442ed51f73 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _USE_MATH_DEFINES | |
#include <math.h> | |
struct Point | |
{ | |
double x, y; | |
}; | |
// A class that contains a 2D angle as a pair of sine + cosine values. | |
// Sometimes, this approach saves substantial CPU time that would be wasted running these trigonometry functions. | |
// While reasonably efficient, one downside of this approach is it's hard to implement multiplication by a scalar value, i.e. linear interpolation. If that's your case, use quaternions instead, they work fine for 2D. | |
class Angle | |
{ | |
double x; // = cos(angle) | |
double y; // = sin(angle) | |
// Private constructor from raw values. Parameters must be normalized already. | |
Angle( double _x, double _y ) : x( _x ), y( _y ) {} | |
public: | |
// Construct from radians | |
Angle( double rad ) | |
{ | |
x = cos( rad ); | |
y = sin( rad ); | |
} | |
// Construct from a radius vector, by normalizing | |
Angle( const Point &pt ) | |
{ | |
double mul = 1.0 / sqrt( pt.x * pt.x + pt.y * pt.y ); | |
x = pt.x * mul; | |
y = pt.y * mul; | |
} | |
Angle( const Angle& that ) = default; | |
Angle& operator=( const Angle& that ) = default; | |
// Divide the angle by 2. The input angle is assumed to be between -Pi and +Pi. To inperpret the angle to be between 0 and 2*Pi, flip the result when y < 0 | |
Angle half() const | |
{ | |
// We do that by adding { 1, 0 } vector, and normalizing the result back onto the unit circle. This way it's a single square root, compared to 2 roots when using classical formulae. | |
const double x2 = x + 1.0; | |
const double len = sqrt( x2*x2 + y*y ); | |
if( isnormal( len ) ) | |
{ | |
const double mul = 1.0 / len; | |
return Angle{ x2 * mul, y * mul }; | |
} | |
// The length of the result is a de-normalized float, i.e. very close to 0. This means the angle is very close to Pi. Therefore, the result is very close to pi/2 | |
// All 3 exact zeros, -0.0, 0, and +0.0, are not normal numbers according to isnormal API, which is exactly what we want in this case. | |
return Angle{ 0, ( y >= 0 ) ? 1.0 : -1.0 }; | |
} | |
// Flip the angle, it's the same as adding Pi to it. | |
Angle operator-() const | |
{ | |
return Angle{ -x, -y }; | |
} | |
// Multiply the angle by 2 | |
Angle dbl() const | |
{ | |
return Angle{ x*x - y*y, 2 * x*y }; | |
} | |
// Add angles | |
Angle operator+( const Angle &that ) const | |
{ | |
return Angle{ x*that.x - y*that.y, y*that.x + x*that.y }; | |
} | |
// Subtract angles | |
Angle operator-( const Angle &that ) const | |
{ | |
return Angle{ x*that.x + y*that.y, y*that.x - x*that.y }; | |
} | |
// A point on circle with specified radius | |
Point radius( double r ) const | |
{ | |
return Point{ x*r, y*r }; | |
} | |
// A point on circle with specified radius and circle center | |
Point radius( const Point ¢er, double r ) const | |
{ | |
return Point{ center.x + x*r, center.y + y*r }; | |
} | |
static Angle zero() { return Angle{ 1, 0 }; } | |
static Angle pi() { return Angle{ -1, 0 }; } | |
static Angle halfPi() { return Angle{ 0, 1 }; } | |
}; | |
int main() | |
{ | |
Angle x( 7 * M_PI / 8 ); | |
Angle y = x.half(); | |
Angle y2( 7 * M_PI / 16 ); | |
Angle x2 = y + y; | |
Angle x3 = y.dbl(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment