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(float number, nzUInt8 precision = NAZARA_CORE_REAL_PRECISION);
inline unsigned int NzGetNumberLength(double 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); 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> T NzNormalizeAngle(T angle);
template<typename T> bool NzNumberEquals(T a, T b); template<typename T> bool NzNumberEquals(T a, T b);
inline NzString NzNumberToString(long long number, nzUInt8 radix = 10); 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 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> template<typename T>
T NzNormalizeAngle(T angle) T NzNormalizeAngle(T angle)
{ {

View File

@ -20,28 +20,28 @@ class NzCube
NzCube(const T cube[6]); NzCube(const T cube[6]);
NzCube(const NzRect<T>& rect); NzCube(const NzRect<T>& rect);
NzCube(const NzVector3<T>& vec1, const NzVector3<T>& vec2); NzCube(const NzVector3<T>& vec1, const NzVector3<T>& vec2);
template<typename U> explicit NzCube(const NzCube<U>& rect); template<typename U> explicit NzCube(const NzCube<U>& cube);
NzCube(const NzCube& rect) = default; NzCube(const NzCube& cube) = default;
~NzCube() = default; ~NzCube() = default;
bool Contains(T X, T Y, T Z) const; bool Contains(T X, T Y, T Z) const;
bool Contains(const NzVector3<T>& point) 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 NzVector3<T>& point);
void ExtendTo(const NzCube& rect); void ExtendTo(const NzCube& cube);
NzVector3<T> GetCenter() const; 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; bool IsValid() const;
void Set(T X, T Y, T Z, T Width, T Height, T Depth); 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 NzRect<T>& rect);
void Set(const NzVector3<T>& vec1, const NzVector3<T>& vec2); 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; NzString ToString() const;
@ -50,6 +50,8 @@ class NzCube
T& operator[](unsigned int i); T& operator[](unsigned int i);
T operator[](unsigned int i) const; T operator[](unsigned int i) const;
static NzCube Lerp(const NzCube& from, const NzCube& to, T interpolation);
T x, y, z, width, height, depth; 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 T>
template<typename U> template<typename U>
NzCube<T>::NzCube(const NzCube<U>& rect) NzCube<T>::NzCube(const NzCube<U>& cube)
{ {
Set(rect); Set(cube);
} }
template<typename T> template<typename T>
@ -59,10 +59,10 @@ bool NzCube<T>::Contains(const NzVector3<T>& point) const
} }
template<typename T> 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) && return Contains(cube.x, cube.y, cube.z) &&
Contains(rect.x + rect.width, rect.y + rect.height, rect.z + rect.depth); Contains(cube.x + cube.width, cube.y + cube.height, cube.z + cube.depth);
} }
template<typename T> template<typename T>
@ -77,14 +77,14 @@ void NzCube<T>::ExtendTo(const NzVector3<T>& point)
} }
template<typename T> template<typename T>
void NzCube<T>::ExtendTo(const NzCube& rect) void NzCube<T>::ExtendTo(const NzCube& cube)
{ {
x = std::min(x, rect.x); x = std::min(x, cube.x);
y = std::min(y, rect.y); y = std::min(y, cube.y);
z = std::min(y, rect.z); z = std::min(y, cube.z);
width = std::max(x+width, rect.x+rect.width)-x; width = std::max(x+width, cube.x+cube.width)-x;
height = std::max(x+height, rect.y+rect.height)-y; height = std::max(x+height, cube.y+cube.height)-y;
depth = std::max(x+depth, rect.z+rect.depth)-z; depth = std::max(x+depth, cube.z+cube.depth)-z;
} }
template<typename T> template<typename T>
@ -94,14 +94,14 @@ NzVector3<T> NzCube<T>::GetCenter() const
} }
template<typename T> 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 left = std::max(x, cube.x);
T right = std::min(x+width, rect.x+rect.width); T right = std::min(x+width, cube.x+cube.width);
T top = std::max(y, rect.y); T top = std::max(y, cube.y);
T bottom = std::min(y+height, rect.y+rect.height); T bottom = std::min(y+height, cube.y+cube.height);
T up = std::max(z, rect.z); T up = std::max(z, cube.z);
T down = std::min(z+depth, rect.z+rect.depth); T down = std::min(z+depth, cube.z+cube.depth);
if (left < right && top < bottom && up < down) 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> template<typename T>
void NzCube<T>::Set(const T rect[6]) void NzCube<T>::Set(const T cube[6])
{ {
x = rect[0]; x = cube[0];
y = rect[1]; y = cube[1];
z = rect[2]; z = cube[2];
width = rect[3]; width = cube[3];
height = rect[4]; height = cube[4];
depth = rect[5]; depth = cube[5];
} }
template<typename T> template<typename T>
@ -230,9 +230,31 @@ T NzCube<T>::operator[](unsigned int i) const
} }
template<typename T> 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 #undef F

View File

@ -77,7 +77,8 @@ template<typename T> class NzQuaternion
bool operator>=(const NzQuaternion& quat) const; bool operator>=(const NzQuaternion& quat) const;
static NzQuaternion Identity(); 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(); static NzQuaternion Zero();
T w, x, y, z; T w, x, y, z;

View File

@ -365,32 +365,48 @@ NzQuaternion<T> NzQuaternion<T>::Identity()
} }
template<typename T> 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)) #ifdef NAZARA_DEBUG
return quatA; 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 from + interpolation*(to-from);
return quatB; }
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; NzQuaternion q;
T cosOmega = quatA.DotProduct(quatB); T cosOmega = from.DotProduct(to);
if (cosOmega < F(0.0)) if (cosOmega < F(0.0))
{ {
// On inverse tout // 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; cosOmega = -cosOmega;
} }
else else
q.Set(quatB); q.Set(to);
T k0, k1; T k0, k1;
if (cosOmega > F(0.9999)) if (cosOmega > F(0.9999))
{ {
// Interpolation linéaire pour éviter une division par zéro // Interpolation linéaire pour éviter une division par zéro
k0 = F(1.0) - interp; k0 = F(1.0) - interpolation;
k1 = interp; k1 = interpolation;
} }
else else
{ {
@ -400,11 +416,11 @@ NzQuaternion<T> NzQuaternion<T>::Slerp(const NzQuaternion& quatA, const NzQuater
// Pour éviter deux divisions // Pour éviter deux divisions
sinOmega = F(1.0)/sinOmega; sinOmega = F(1.0)/sinOmega;
k0 = std::sin((F(1.0) - interp) * omega) * sinOmega; k0 = std::sin((F(1.0) - interpolation) * omega) * sinOmega;
k1 = std::sin(interp*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; return result += q*k1;
} }

View File

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

View File

@ -195,6 +195,26 @@ T NzRect<T>::operator[](unsigned int i) const
return *(&x+i); 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> template<typename T>
std::ostream& operator<<(std::ostream& out, const NzRect<T>& rect) 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;
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 UnitX();
static NzVector2 UnitY(); static NzVector2 UnitY();
static NzVector2 Zero(); static NzVector2 Zero();

View File

@ -428,6 +428,12 @@ bool NzVector2<T>::operator>=(const NzVector2& vec) const
return !operator<(vec); 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> template<typename T>
NzVector2<T> NzVector2<T>::UnitX() 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 T DotProduct(const NzVector3& vec1, const NzVector3& vec2);
static NzVector3 Forward(); static NzVector3 Forward();
static NzVector3 Left(); static NzVector3 Left();
static NzVector3 Lerp(const NzVector3& from, const NzVector3& to, T interpolation);
static NzVector3 Normalize(const NzVector3& vec); static NzVector3 Normalize(const NzVector3& vec);
static NzVector3 UnitX(); static NzVector3 UnitX();
static NzVector3 UnitY(); static NzVector3 UnitY();

View File

@ -515,6 +515,12 @@ NzVector3<T> NzVector3<T>::Left()
return vector; 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> template<typename T>
NzVector3<T> NzVector3<T>::Normalize(const NzVector3& vec) NzVector3<T> NzVector3<T>::Normalize(const NzVector3& vec)
{ {