Search code examples
algorithmmathangle

Lerp rotation angles clock or counter-clockwise


I'm trying to find an implementation of angle lerp (linear interpolation) that allows you to specify direction (clock or counter-clockwise). Most implementations I found rely on the shortest path possible, for example:

https://gist.github.com/shaunlebron/8832585

I'd like to have a function like:

// from        = angle where to start
// to          = target angle
// direction   = wether to reach "to" clock or counter clock wise
// progress    = 0-1 progress range 0 = from value 1 = to value.

function angle_lerp(from, to, direction, progress) {}

Here are a couple of examples to further clarify the expected behavior of the function. All examples are based on a 0-360 degree range:

# clockwise (short path)
angle_lerp(from=350, to=10, direction=clockwise, progress=0) = 350
angle_lerp(from=350, to=10, direction=clockwise, progress=0.5) = 0
angle_lerp(from=350, to=10, direction=clockwise, progress=1) = 10

# counter-clockwise (long path)
angle_lerp(from=350, to=10, direction=counter, progress=0) = 350
angle_lerp(from=350, to=10, direction=counter, progress=0.5) = 180
angle_lerp(from=350, to=10, direction=counter, progress=1) = 10
# clockwise (short path)
angle_lerp(from=90, to=180, direction=clockwise, progress=0.33333) = 119.7
angle_lerp(from=90, to=180, direction=clockwise, progress=0.5) = 135
angle_lerp(from=90, to=180, direction=clockwise, progress=0.8) = 162 

# counter (long path)
angle_lerp(from=90, to=180, direction=counter, progress=0.33333) = 0
angle_lerp(from=90, to=180, direction=counter, progress=0.66666) = 270

example where from is "ahead" of to:

# clockwise (long path)
angle_lerp(from=45, to=0, direction=clockwise, progress=0.1) = 76.5
angle_lerp(from=45, to=0, direction=clockwise, progress=0.5) = 202.5
angle_lerp(from=45, to=0, direction=clockwise, progress=0.95) = 344.25

# counter (short route)
angle_lerp(from=45, to=0, direction=counter, progress=0.1) = 40.5
angle_lerp(from=45, to=0, direction=counter, progress=0.5) = 22.5
angle_lerp(from=45, to=0, direction=counter, progress=0.95) = 2.25

Solution

  • Assuming the usual convention (angles increase in the counter-clockwise direction), here is a PHP solution.

    $from and $to are normalized angles (between 0 and 360).
    $cw is a boolean (true for clockwise, false for counter-clockwise).
    $progress is between 0 and 1.

    function angle_lerp($from, $to, $cw, $progress)
    {
        if($cw)
        {
            // Clockwise
            if($from < $to)
                $to -= 360;
        }
        else
        {
            // Counter-clockwise
            if($from > $to)
                $to += 360;
        }
        return $from + ($to-$from)*$progress;
    }
    

    Examples:

    echo angle_lerp(350, 10, true, 0.5); // 180
    echo angle_lerp(350, 10, false, 0.5); // 360