Added linear interpolation (Lerp) to math module

Former-commit-id: 5920e21f25d42701a1895734eca492fdf5351669
This commit is contained in:
Lynix 2012-10-08 14:45:29 +02:00
parent 737f2a70bd
commit cfd54b859d
12 changed files with 141 additions and 49 deletions

View File

@ -31,6 +31,7 @@ inline unsigned int NzGetNumberLength(unsigned long long number);
inline unsigned int NzGetNumberLength(float number, nzUInt8 precision = NAZARA_CORE_REAL_PRECISION);
inline unsigned int NzGetNumberLength(double number, nzUInt8 precision = NAZARA_CORE_REAL_PRECISION);
inline unsigned int NzGetNumberLength(long double number, nzUInt8 precision = NAZARA_CORE_REAL_PRECISION);
template<typename T, typename F> T NzLerp(T from, T to, F interpolation);
template<typename T> T NzNormalizeAngle(T angle);
template<typename T> bool NzNumberEquals(T a, T b);
inline NzString NzNumberToString(long long number, nzUInt8 radix = 10);

View File

@ -132,6 +132,20 @@ unsigned int NzGetNumberLength(long double number, nzUInt8 precision)
return NzGetNumberLength(static_cast<long long>(number)) + precision + 1; // Plus un pour le point
}
template<typename T, typename F>
T NzLerp(T from, T to, F interpolation)
{
#ifdef NAZARA_DEBUG
if (interpolation < F(0.0) || interpolation > F(1.0))
{
NazaraError("Interpolation must be in range [0..1] (Got " + NzString::Number(interpolation) + ')');
return Zero();
}
#endif
return from + interpolation*(to-from);
}
template<typename T>
T NzNormalizeAngle(T angle)
{

View File

@ -20,28 +20,28 @@ class NzCube
NzCube(const T cube[6]);
NzCube(const NzRect<T>& rect);
NzCube(const NzVector3<T>& vec1, const NzVector3<T>& vec2);
template<typename U> explicit NzCube(const NzCube<U>& rect);
NzCube(const NzCube& rect) = default;
template<typename U> explicit NzCube(const NzCube<U>& cube);
NzCube(const NzCube& cube) = default;
~NzCube() = default;
bool Contains(T X, T Y, T Z) const;
bool Contains(const NzVector3<T>& point) const;
bool Contains(const NzCube& rect) const;
bool Contains(const NzCube& cube) const;
void ExtendTo(const NzVector3<T>& point);
void ExtendTo(const NzCube& rect);
void ExtendTo(const NzCube& cube);
NzVector3<T> GetCenter() const;
bool Intersect(const NzCube& rect, NzCube* intersection = nullptr) const;
bool Intersect(const NzCube& cube, NzCube* intersection = nullptr) const;
bool IsValid() const;
void Set(T X, T Y, T Z, T Width, T Height, T Depth);
void Set(const T rect[6]);
void Set(const T cube[6]);
void Set(const NzRect<T>& rect);
void Set(const NzVector3<T>& vec1, const NzVector3<T>& vec2);
template<typename U> void Set(const NzCube<U>& rect);
template<typename U> void Set(const NzCube<U>& cube);
NzString ToString() const;
@ -50,6 +50,8 @@ class NzCube
T& operator[](unsigned int i);
T operator[](unsigned int i) const;
static NzCube Lerp(const NzCube& from, const NzCube& to, T interpolation);
T x, y, z, width, height, depth;
};

View File

@ -39,9 +39,9 @@ NzCube<T>::NzCube(const NzVector3<T>& vec1, const NzVector3<T>& vec2)
template<typename T>
template<typename U>
NzCube<T>::NzCube(const NzCube<U>& rect)
NzCube<T>::NzCube(const NzCube<U>& cube)
{
Set(rect);
Set(cube);
}
template<typename T>
@ -59,10 +59,10 @@ bool NzCube<T>::Contains(const NzVector3<T>& point) const
}
template<typename T>
bool NzCube<T>::Contains(const NzCube<T>& rect) const
bool NzCube<T>::Contains(const NzCube<T>& cube) const
{
return Contains(rect.x, rect.y, rect.z) &&
Contains(rect.x + rect.width, rect.y + rect.height, rect.z + rect.depth);
return Contains(cube.x, cube.y, cube.z) &&
Contains(cube.x + cube.width, cube.y + cube.height, cube.z + cube.depth);
}
template<typename T>
@ -77,14 +77,14 @@ void NzCube<T>::ExtendTo(const NzVector3<T>& point)
}
template<typename T>
void NzCube<T>::ExtendTo(const NzCube& rect)
void NzCube<T>::ExtendTo(const NzCube& cube)
{
x = std::min(x, rect.x);
y = std::min(y, rect.y);
z = std::min(y, rect.z);
width = std::max(x+width, rect.x+rect.width)-x;
height = std::max(x+height, rect.y+rect.height)-y;
depth = std::max(x+depth, rect.z+rect.depth)-z;
x = std::min(x, cube.x);
y = std::min(y, cube.y);
z = std::min(y, cube.z);
width = std::max(x+width, cube.x+cube.width)-x;
height = std::max(x+height, cube.y+cube.height)-y;
depth = std::max(x+depth, cube.z+cube.depth)-z;
}
template<typename T>
@ -94,14 +94,14 @@ NzVector3<T> NzCube<T>::GetCenter() const
}
template<typename T>
bool NzCube<T>::Intersect(const NzCube& rect, NzCube* intersection) const
bool NzCube<T>::Intersect(const NzCube& cube, NzCube* intersection) const
{
T left = std::max(x, rect.x);
T right = std::min(x+width, rect.x+rect.width);
T top = std::max(y, rect.y);
T bottom = std::min(y+height, rect.y+rect.height);
T up = std::max(z, rect.z);
T down = std::min(z+depth, rect.z+rect.depth);
T left = std::max(x, cube.x);
T right = std::min(x+width, cube.x+cube.width);
T top = std::max(y, cube.y);
T bottom = std::min(y+height, cube.y+cube.height);
T up = std::max(z, cube.z);
T down = std::min(z+depth, cube.z+cube.depth);
if (left < right && top < bottom && up < down)
{
@ -139,14 +139,14 @@ void NzCube<T>::Set(T X, T Y, T Z, T Width, T Height, T Depth)
}
template<typename T>
void NzCube<T>::Set(const T rect[6])
void NzCube<T>::Set(const T cube[6])
{
x = rect[0];
y = rect[1];
z = rect[2];
width = rect[3];
height = rect[4];
depth = rect[5];
x = cube[0];
y = cube[1];
z = cube[2];
width = cube[3];
height = cube[4];
depth = cube[5];
}
template<typename T>
@ -230,9 +230,31 @@ T NzCube<T>::operator[](unsigned int i) const
}
template<typename T>
std::ostream& operator<<(std::ostream& out, const NzCube<T>& rect)
NzCube<T> NzCube<T>::Lerp(const NzCube& from, const NzCube& to, T interpolation)
{
return out << rect.ToString();
#ifdef NAZARA_DEBUG
if (interpolation < F(0.0) || interpolation > F(1.0))
{
NazaraError("Interpolation must be in range [0..1] (Got " + NzString::Number(interpolation) + ')');
return Zero();
}
#endif
NzCube cube;
cube.x = NzLerp(from.x, to.x, interpolation);
cube.y = NzLerp(from.y, to.y, interpolation);
cube.z = NzLerp(from.z, to.z, interpolation);
cube.width = NzLerp(from.width, to.width, interpolation);
cube.height = NzLerp(from.height, to.height, interpolation);
cube.depth = NzLerp(from.depth, to.depth, interpolation);
return cube;
}
template<typename T>
std::ostream& operator<<(std::ostream& out, const NzCube<T>& cube)
{
return out << cube.ToString();
}
#undef F

View File

@ -77,7 +77,8 @@ template<typename T> class NzQuaternion
bool operator>=(const NzQuaternion& quat) const;
static NzQuaternion Identity();
static NzQuaternion Slerp(const NzQuaternion& quatA, const NzQuaternion& quatB, T interp);
static NzQuaternion Lerp(const NzQuaternion& from, const NzQuaternion& to, T interpolation);
static NzQuaternion Slerp(const NzQuaternion& from, const NzQuaternion& to, T interpolation);
static NzQuaternion Zero();
T w, x, y, z;

View File

@ -365,32 +365,48 @@ NzQuaternion<T> NzQuaternion<T>::Identity()
}
template<typename T>
NzQuaternion<T> NzQuaternion<T>::Slerp(const NzQuaternion& quatA, const NzQuaternion& quatB, T interp)
NzQuaternion<T> NzQuaternion<T>::Lerp(const NzQuaternion& from, const NzQuaternion& to, T interpolation)
{
if (interp <= F(0.0))
return quatA;
#ifdef NAZARA_DEBUG
if (interpolation < F(0.0) || interpolation > F(1.0))
{
NazaraError("Interpolation must be in range [0..1] (Got " + NzString::Number(interpolation) + ')');
return Zero();
}
#endif
if (interp >= F(1.0))
return quatB;
return from + interpolation*(to-from);
}
template<typename T>
NzQuaternion<T> NzQuaternion<T>::Slerp(const NzQuaternion& from, const NzQuaternion& to, T interpolation)
{
#ifdef NAZARA_DEBUG
if (interpolation < F(0.0) || interpolation > F(1.0))
{
NazaraError("Interpolation must be in range [0..1] (Got " + NzString::Number(interpolation) + ')');
return Zero();
}
#endif
NzQuaternion q;
T cosOmega = quatA.DotProduct(quatB);
T cosOmega = from.DotProduct(to);
if (cosOmega < F(0.0))
{
// On inverse tout
q.Set(-quatB.w, -quatB.x, -quatB.y, -quatB.z);
q.Set(-to.w, -to.x, -to.y, -to.z);
cosOmega = -cosOmega;
}
else
q.Set(quatB);
q.Set(to);
T k0, k1;
if (cosOmega > F(0.9999))
{
// Interpolation linéaire pour éviter une division par zéro
k0 = F(1.0) - interp;
k1 = interp;
k0 = F(1.0) - interpolation;
k1 = interpolation;
}
else
{
@ -400,11 +416,11 @@ NzQuaternion<T> NzQuaternion<T>::Slerp(const NzQuaternion& quatA, const NzQuater
// Pour éviter deux divisions
sinOmega = F(1.0)/sinOmega;
k0 = std::sin((F(1.0) - interp) * omega) * sinOmega;
k1 = std::sin(interp*omega) * sinOmega;
k0 = std::sin((F(1.0) - interpolation) * omega) * sinOmega;
k1 = std::sin(interpolation*omega) * sinOmega;
}
NzQuaternion result(k0 * quatA.w, k0 * quatA.x, k0 * quatA.y, k0 * quatA.z);
NzQuaternion result(k0 * from.w, k0 * from.x, k0 * from.y, k0 * from.z);
return result += q*k1;
}

View File

@ -47,6 +47,8 @@ class NzRect
T& operator[](unsigned int i);
T operator[](unsigned int i) const;
static NzRect Lerp(const NzRect& from, const NzRect& to, T interpolation);
T x, y, width, height;
};

View File

@ -195,6 +195,26 @@ T NzRect<T>::operator[](unsigned int i) const
return *(&x+i);
}
template<typename T>
NzRect<T> NzRect<T>::Lerp(const NzRect& from, const NzRect& to, T interpolation)
{
#ifdef NAZARA_DEBUG
if (interpolation < F(0.0) || interpolation > F(1.0))
{
NazaraError("Interpolation must be in range [0..1] (Got " + NzString::Number(interpolation) + ')');
return Zero();
}
#endif
NzRect rect;
rect.x = NzLerp(from.x, to.x, interpolation);
rect.y = NzLerp(from.y, to.y, interpolation);
rect.width = NzLerp(from.width, to.width, interpolation);
rect.height = NzLerp(from.height, to.height, interpolation);
return rect;
}
template<typename T>
std::ostream& operator<<(std::ostream& out, const NzRect<T>& rect)
{

View File

@ -83,6 +83,7 @@ template<typename T> class NzVector2
bool operator>(const NzVector2& vec) const;
bool operator>=(const NzVector2& vec) const;
static NzVector2 Lerp(const NzVector2& from, const NzVector2& to, T interpolation);
static NzVector2 UnitX();
static NzVector2 UnitY();
static NzVector2 Zero();

View File

@ -428,6 +428,12 @@ bool NzVector2<T>::operator>=(const NzVector2& vec) const
return !operator<(vec);
}
template<typename T>
NzVector2<T> NzVector2<T>::Lerp(const NzVector2& from, const NzVector2& to, T interpolation)
{
return NzLerp(from, to, interpolation);
}
template<typename T>
NzVector2<T> NzVector2<T>::UnitX()
{

View File

@ -96,6 +96,7 @@ template<typename T> class NzVector3
static T DotProduct(const NzVector3& vec1, const NzVector3& vec2);
static NzVector3 Forward();
static NzVector3 Left();
static NzVector3 Lerp(const NzVector3& from, const NzVector3& to, T interpolation);
static NzVector3 Normalize(const NzVector3& vec);
static NzVector3 UnitX();
static NzVector3 UnitY();

View File

@ -515,6 +515,12 @@ NzVector3<T> NzVector3<T>::Left()
return vector;
}
template<typename T>
NzVector3<T> NzVector3<T>::Lerp(const NzVector3& from, const NzVector3& to, T interpolation)
{
return NzLerp(from, to, interpolation);
}
template<typename T>
NzVector3<T> NzVector3<T>::Normalize(const NzVector3& vec)
{