From cfd54b859d477cdec37d0e5a17568b99b30b58ce Mon Sep 17 00:00:00 2001 From: Lynix Date: Mon, 8 Oct 2012 14:45:29 +0200 Subject: [PATCH] Added linear interpolation (Lerp) to math module Former-commit-id: 5920e21f25d42701a1895734eca492fdf5351669 --- include/Nazara/Math/Basic.hpp | 1 + include/Nazara/Math/Basic.inl | 14 ++++++ include/Nazara/Math/Cube.hpp | 16 +++--- include/Nazara/Math/Cube.inl | 78 +++++++++++++++++++----------- include/Nazara/Math/Quaternion.hpp | 3 +- include/Nazara/Math/Quaternion.inl | 42 +++++++++++----- include/Nazara/Math/Rect.hpp | 2 + include/Nazara/Math/Rect.inl | 20 ++++++++ include/Nazara/Math/Vector2.hpp | 1 + include/Nazara/Math/Vector2.inl | 6 +++ include/Nazara/Math/Vector3.hpp | 1 + include/Nazara/Math/Vector3.inl | 6 +++ 12 files changed, 141 insertions(+), 49 deletions(-) diff --git a/include/Nazara/Math/Basic.hpp b/include/Nazara/Math/Basic.hpp index 47d344c7b..c1d98ca10 100644 --- a/include/Nazara/Math/Basic.hpp +++ b/include/Nazara/Math/Basic.hpp @@ -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 T NzLerp(T from, T to, F interpolation); template T NzNormalizeAngle(T angle); template bool NzNumberEquals(T a, T b); inline NzString NzNumberToString(long long number, nzUInt8 radix = 10); diff --git a/include/Nazara/Math/Basic.inl b/include/Nazara/Math/Basic.inl index 457920a5a..57afcd2c0 100644 --- a/include/Nazara/Math/Basic.inl +++ b/include/Nazara/Math/Basic.inl @@ -132,6 +132,20 @@ unsigned int NzGetNumberLength(long double number, nzUInt8 precision) return NzGetNumberLength(static_cast(number)) + precision + 1; // Plus un pour le point } +template +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 T NzNormalizeAngle(T angle) { diff --git a/include/Nazara/Math/Cube.hpp b/include/Nazara/Math/Cube.hpp index 8fa678d38..8930831aa 100644 --- a/include/Nazara/Math/Cube.hpp +++ b/include/Nazara/Math/Cube.hpp @@ -20,28 +20,28 @@ class NzCube NzCube(const T cube[6]); NzCube(const NzRect& rect); NzCube(const NzVector3& vec1, const NzVector3& vec2); - template explicit NzCube(const NzCube& rect); - NzCube(const NzCube& rect) = default; + template explicit NzCube(const NzCube& cube); + NzCube(const NzCube& cube) = default; ~NzCube() = default; bool Contains(T X, T Y, T Z) const; bool Contains(const NzVector3& point) const; - bool Contains(const NzCube& rect) const; + bool Contains(const NzCube& cube) const; void ExtendTo(const NzVector3& point); - void ExtendTo(const NzCube& rect); + void ExtendTo(const NzCube& cube); NzVector3 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& rect); void Set(const NzVector3& vec1, const NzVector3& vec2); - template void Set(const NzCube& rect); + template void Set(const NzCube& 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; }; diff --git a/include/Nazara/Math/Cube.inl b/include/Nazara/Math/Cube.inl index d96c2cfcd..4ea4b07c1 100644 --- a/include/Nazara/Math/Cube.inl +++ b/include/Nazara/Math/Cube.inl @@ -39,9 +39,9 @@ NzCube::NzCube(const NzVector3& vec1, const NzVector3& vec2) template template -NzCube::NzCube(const NzCube& rect) +NzCube::NzCube(const NzCube& cube) { - Set(rect); + Set(cube); } template @@ -59,10 +59,10 @@ bool NzCube::Contains(const NzVector3& point) const } template -bool NzCube::Contains(const NzCube& rect) const +bool NzCube::Contains(const NzCube& 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 @@ -77,14 +77,14 @@ void NzCube::ExtendTo(const NzVector3& point) } template -void NzCube::ExtendTo(const NzCube& rect) +void NzCube::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 @@ -94,14 +94,14 @@ NzVector3 NzCube::GetCenter() const } template -bool NzCube::Intersect(const NzCube& rect, NzCube* intersection) const +bool NzCube::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::Set(T X, T Y, T Z, T Width, T Height, T Depth) } template -void NzCube::Set(const T rect[6]) +void NzCube::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 @@ -230,9 +230,31 @@ T NzCube::operator[](unsigned int i) const } template -std::ostream& operator<<(std::ostream& out, const NzCube& rect) +NzCube NzCube::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 +std::ostream& operator<<(std::ostream& out, const NzCube& cube) +{ + return out << cube.ToString(); } #undef F diff --git a/include/Nazara/Math/Quaternion.hpp b/include/Nazara/Math/Quaternion.hpp index bed9d5277..7e9addfc9 100644 --- a/include/Nazara/Math/Quaternion.hpp +++ b/include/Nazara/Math/Quaternion.hpp @@ -77,7 +77,8 @@ template 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; diff --git a/include/Nazara/Math/Quaternion.inl b/include/Nazara/Math/Quaternion.inl index d86f66ea9..6969aa3f4 100644 --- a/include/Nazara/Math/Quaternion.inl +++ b/include/Nazara/Math/Quaternion.inl @@ -365,32 +365,48 @@ NzQuaternion NzQuaternion::Identity() } template -NzQuaternion NzQuaternion::Slerp(const NzQuaternion& quatA, const NzQuaternion& quatB, T interp) +NzQuaternion NzQuaternion::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 +NzQuaternion NzQuaternion::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 NzQuaternion::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; } diff --git a/include/Nazara/Math/Rect.hpp b/include/Nazara/Math/Rect.hpp index 938e9e1ea..d7a6162dd 100644 --- a/include/Nazara/Math/Rect.hpp +++ b/include/Nazara/Math/Rect.hpp @@ -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; }; diff --git a/include/Nazara/Math/Rect.inl b/include/Nazara/Math/Rect.inl index 3984593c0..4d4e73e7b 100644 --- a/include/Nazara/Math/Rect.inl +++ b/include/Nazara/Math/Rect.inl @@ -195,6 +195,26 @@ T NzRect::operator[](unsigned int i) const return *(&x+i); } +template +NzRect NzRect::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 std::ostream& operator<<(std::ostream& out, const NzRect& rect) { diff --git a/include/Nazara/Math/Vector2.hpp b/include/Nazara/Math/Vector2.hpp index 1cbf1a65a..c60f1950f 100644 --- a/include/Nazara/Math/Vector2.hpp +++ b/include/Nazara/Math/Vector2.hpp @@ -83,6 +83,7 @@ template 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(); diff --git a/include/Nazara/Math/Vector2.inl b/include/Nazara/Math/Vector2.inl index 4ea664b61..7e8ebaeab 100644 --- a/include/Nazara/Math/Vector2.inl +++ b/include/Nazara/Math/Vector2.inl @@ -428,6 +428,12 @@ bool NzVector2::operator>=(const NzVector2& vec) const return !operator<(vec); } +template +NzVector2 NzVector2::Lerp(const NzVector2& from, const NzVector2& to, T interpolation) +{ + return NzLerp(from, to, interpolation); +} + template NzVector2 NzVector2::UnitX() { diff --git a/include/Nazara/Math/Vector3.hpp b/include/Nazara/Math/Vector3.hpp index 2750c6b7b..8353af6fd 100644 --- a/include/Nazara/Math/Vector3.hpp +++ b/include/Nazara/Math/Vector3.hpp @@ -96,6 +96,7 @@ template 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(); diff --git a/include/Nazara/Math/Vector3.inl b/include/Nazara/Math/Vector3.inl index d0c72b984..3725d5900 100644 --- a/include/Nazara/Math/Vector3.inl +++ b/include/Nazara/Math/Vector3.inl @@ -515,6 +515,12 @@ NzVector3 NzVector3::Left() return vector; } +template +NzVector3 NzVector3::Lerp(const NzVector3& from, const NzVector3& to, T interpolation) +{ + return NzLerp(from, to, interpolation); +} + template NzVector3 NzVector3::Normalize(const NzVector3& vec) {