Skip to content

Instantly share code, notes, and snippets.

@shaunlebron
Created February 5, 2014 20:41
Show Gist options
  • Save shaunlebron/8832585 to your computer and use it in GitHub Desktop.
Save shaunlebron/8832585 to your computer and use it in GitHub Desktop.
The best way to interpolate 2D angles
/*
2D Angle Interpolation (shortest distance)
Parameters:
a0 = start angle
a1 = end angle
t = interpolation factor (0.0=start, 1.0=end)
Benefits:
1. Angles do NOT need to be normalized.
2. Implementation is portable, regardless of how the modulo "%" operator outputs sign (i.e. Python, Ruby, Javascript)
3. Very easy to remember.
Thanks to Trey Wilson for the closed-form solution for shortAngleDist!
*/
function shortAngleDist(a0,a1) {
var max = Math.PI*2;
var da = (a1 - a0) % max;
return 2*da % max - da;
}
function angleLerp(a0,a1,t) {
return a0 + shortAngleDist(a0,a1)*t;
}
@Lecrapouille
Copy link

My quick implementation in C++ using https://github.com/nholthaus/units:

#include "units.h"

using namespace units::literals;
using Radian = units::angle::radian_t;
using Degree = units::angle::degree_t;

template<typename T, typename U>
inline T lerp(T const from, T const to, U const weight)
{
   return from + (to - from) * weight;
}

template<typename T>
inline T constrain(T const value, T const lower, T const upper)
{
    if (value < lower) { return lower; }
    if (value > upper) { return upper; }
    return value;
}

inline Degree lerp_angle(Degree const from, Degree const to, double weight)
{
   auto repeat = [](Degree const t, Degree const m) -> Degree
   {
      return constrain(t - units::math::floor(t / m) * m, 0.0_deg, m);
   };
   const Degree dt = repeat(to - from, 360.0_deg);
   return lerp(from, from + (dt > 180.0_deg ? dt - 360.0_deg : dt), weight);
}

@Lecrapouille
Copy link

@codergautam nice !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment