Helpful vector / radians / angle snippets

edited April 2013 in General discussions
I was looking for a good way to "normalize" an angle in radians. By normalize I mean making sure the value is between 0 and 2 * pi (i.e. tau). I came across several implementations that simply didn't work right, so I made my own. These are pretty basic, but have been very useful.
/*
 * Common.h
 *
 *  Created on: Apr 12, 2013
 *      Author: epoulsen
 */

#ifndef COMMON_H_
#define COMMON_H_
#define _USE_MATH_DEFINES
#include <math.h>
#include "orx.h"

#define M_TAU 6.283185307
//
//  Python prototype
//
//   def normalizeradians(rad):
//    if rad < 0:
//        rad += math.ceil(abs(rad) / math.tau) * math.tau
//    else:
//        return rad % math.tau
//    return rad

inline float normalizeRadians(float rad) {
	if (rad < 0)
		rad += M_TAU * ceil(fabs(rad) / M_TAU); 	else
		rad = fmod(rad, M_TAU);
	return rad;
}

inline float rad2deg(float rad) {
	return rad * (180 / M_PI);
}

inline float vec2rad(orxVECTOR & vec) {
	return normalizeRadians(atan2(vec.fY, vec.fX));
}

inline void rad2vec(orxVECTOR & out, float rad) {
	out.fX = cos(rad);
	out.fY = sin(rad);
}

#endif /* COMMON_H_ */

Comments

  • edited April 2013
    Thanks for sharing that code snippet.

    As fmod is famous to be a (relatively) expensive function, here's an alternative that should work just as well, without any conditional branching (which is an added bonus! :)):
    float normalizeRadians(float rad)
    {
      float result;
    
      // Scale the input by 1/Tau (ie. normalize)
      result = rad * (1.0f / M_TAU);
    
      // Apply a circular clamp to domain [0, 1[
      result -= (float)((int)result - (int)(result < 0.0f));
    
      // Scale back to original domain
      result *= M_TAU;
    
      // Done!
      return result;
    }
    
    Also, if you use orx, the whole vec2rad/rad2vec conversion already exists as part of the cartesian<->spherical translations:
    // vec2rad
    orxFLOAT fRad = orxVector_FromCartesianToSpherical(&MyVector, &MyVector)->fTheta;
    
    // rad2vec
    MyVector.fRho   = orxFLOAT_1; // Rho is the norm of the vector
    MyVector.fTheta = fRad; // Theta the angle on the horizontal plan
    MyVector.fPhi   = orxMATH_KF_PI_BY_2; // Phi is the angle on the vertical plan, in XY 2D it's always Pi by 2
    orxVector_FromSphericalToCartesian(&MyVector, &MyVector);
    
  • edited April 2013
    Cool, I've [strike]copied[/strike] implemented your normalizer =)

    I'm not that up on coordinate spaces; I didn't realize that those vector functions did what I wanted.
Sign In or Register to comment.