Some CLERP (circular linear interpolation) functions

I think these work. I trip over this every time I try to do it; this is my most recent code and I think a lot of stuff for me wouldn't work if these were wrong but... I think these work.

```#ifndef UTIL_CLERP_H
#define UTIL_CLERP_H

// circular linear interpolation; note: these are all default mod 1.0, not M_2PI

float clerp_direction (float H0, float H1, float Domain);
float clerp_fmod (float H, float Mod);
float clerp_dist (float H0, float H1, float Domain = 1.0);
float clerp_do (float H0, float H1, float Alpha, float Domain = 1.0);
float clerp_closest (float HSrc, float HDst0, float HDst1, float Alpha);
float clerp_max_do (float H0, float H1, float Max, float Domain);

// integer version

int clerp_mod (int H, int Mod);

// modulo x along a circular domain, so that -1 -> Radix - 1

inline int zmod (int X, int Radix) {

if (X < 0) return Radix - ((-X - 1) % Radix) - 1;
}

#endif // CLERP_H
```
```#include "clerp.h"

#include <math.h>

#include <algorithm>

using namespace std;

float clerp_fmod (float H, float Mod) {

if (H >= 0) return fmod( H, Mod );
return Mod - fmod (-H, Mod);
};

int clerp_mod (int H, int Mod) {

int HM = H % Mod;
if (HM < 0) HM = Mod + HM;
return HM;
}

float clerp_direction (float H0, float H1, float Domain) {

H0 = fmod (H0, Domain);
H1 = fmod (H1, Domain);

float Factor = 1.0f;
if (H0 > H1) {

float Temp = H1;
H1 = H0;
H0 = Temp;
Factor = Factor * -1.0f;
}

float D1 = fabs (H1 - H0);
float D2 = fabs (H0 + Domain - H1);
if (D1 > D2) {

Factor = Factor * -1.0f;
}

return Factor;
}

float clerp_dist (float H0, float H1, float Domain) {

// we can either rotate H0 to the left, or to the right
H0 = clerp_fmod (H0, Domain);
H1 = clerp_fmod (H1, Domain);

float Dist = 0.0;
if (H0 < H1) {

float LeftDist = H0 + (Domain - H1);
float RightDist = H1 - H0;
Dist = min (LeftDist, RightDist);
}
else {

float LeftDist = H1 + (Domain - H0);
float RightDist = H0 - H1;
Dist = min (LeftDist, RightDist);
}

return Dist;
}

float clerp_do (float H0, float H1, float Alpha, float Domain) {

// which is the closest direction to rotate towards? if it's the other way, then bump it
H0 = clerp_fmod (H0, Domain);
H1 = clerp_fmod (H1, Domain);
if (fabs(H0 - H1) > fabs(H0 + Domain - H1)) {

H0 += Domain;
}
else if (fabs (H1 - H0) > fabs (H1 + Domain - H0)) {

H1 += Domain;
}

float HOut = H0 * (1.0 - Alpha) + H1 * Alpha;
clerp_fmod (HOut, Domain);

return HOut;
};

float clerp_closest (float HSrc, float HDst0, float HDst1, float Alpha) {

if( clerp_dist( HSrc, HDst0 ) < clerp_dist( HSrc, HDst1 ) ) {

return clerp_do( HSrc, HDst0, Alpha );
}
else {

return clerp_do( HSrc, HDst1, Alpha );
}
};

//
// move H0 to H1 up to Max amount, on Domain
//
float clerp_max_do (float H0, float H1, float Max, float Domain) {

// which is the closest direction to rotate towards? if it's the other way, then bump it
H0 = clerp_fmod (H0, Domain);
H1 = clerp_fmod (H1, Domain);
if (fabs (H0 - H1) > fabs (H0 + Domain - H1)) {

H0 = H0 + Domain;
}
else if (fabs (H1 - H0) > fabs (H1 + Domain - H0)) {

H1 = H1 + Domain;
}

float Delta = H1 - H0;
if (Delta > Max) Delta = Max;
else if (Delta < (Max * -1.0f)) Delta = Max * -1.0f;

float HOut = H0 + Delta;
HOut = clerp_fmod (HOut, Domain);

return HOut;
}

```

CLERP, January 28 2019
1572 views

◀ Back