Browse Source

Animation: support for spline interpolation.

pull/267/head
Vladimír Vondruš 8 years ago
parent
commit
b1b663fa65
  1. 23
      src/Magnum/Animation/Interpolation.cpp
  2. 31
      src/Magnum/Animation/Interpolation.h
  3. 93
      src/Magnum/Animation/Test/InterpolationTest.cpp
  4. 7
      src/Magnum/Animation/Track.h

23
src/Magnum/Animation/Interpolation.cpp

@ -25,7 +25,7 @@
#include "Interpolation.h"
#include "Magnum/Math/Complex.h"
#include "Magnum/Math/CubicHermite.h"
#include "Magnum/Math/DualQuaternion.h"
namespace Magnum { namespace Animation {
@ -37,6 +37,7 @@ Debug& operator<<(Debug& debug, const Interpolation value) {
#define _c(value) case Interpolation::value: return debug << "Animation::Interpolation::" #value;
_c(Constant)
_c(Linear)
_c(Spline)
_c(Custom)
#undef _c
/* LCOV_EXCL_STOP */
@ -67,6 +68,7 @@ template<class T> auto TypeTraits<Math::Complex<T>, Math::Complex<T>>::interpola
case Interpolation::Constant: return Math::select;
case Interpolation::Linear: return Math::slerp;
case Interpolation::Spline:
case Interpolation::Custom: ; /* nope */
}
@ -78,6 +80,7 @@ template<class T> auto TypeTraits<Math::Quaternion<T>, Math::Quaternion<T>>::int
case Interpolation::Constant: return Math::select;
case Interpolation::Linear: return Math::slerp;
case Interpolation::Spline:
case Interpolation::Custom: ; /* nope */
}
@ -89,6 +92,19 @@ template<class T> auto TypeTraits<Math::DualQuaternion<T>, Math::DualQuaternion<
case Interpolation::Constant: return Math::select;
case Interpolation::Linear: return Math::sclerp;
case Interpolation::Spline:
case Interpolation::Custom: ; /* nope */
}
CORRADE_ASSERT(false, "Animation::interpolatorFor(): can't deduce interpolator function for" << interpolation, {});
}
template<class T> auto TypeTraits<Math::CubicHermite<T>, T>::interpolator(Interpolation interpolation) -> Interpolator {
switch(interpolation) {
case Interpolation::Constant: return Math::select;
case Interpolation::Linear: return Math::lerp;
case Interpolation::Spline: return Math::splerp;
case Interpolation::Custom: ; /* nope */
}
@ -98,6 +114,11 @@ template<class T> auto TypeTraits<Math::DualQuaternion<T>, Math::DualQuaternion<
template struct MAGNUM_EXPORT TypeTraits<Math::Complex<Float>, Math::Complex<Float>>;
template struct MAGNUM_EXPORT TypeTraits<Math::Quaternion<Float>, Math::Quaternion<Float>>;
template struct MAGNUM_EXPORT TypeTraits<Math::DualQuaternion<Float>, Math::DualQuaternion<Float>>;
template struct MAGNUM_EXPORT TypeTraits<Math::CubicHermite<Float>, Float>;
template struct MAGNUM_EXPORT TypeTraits<Math::CubicHermite<Math::Vector2<Float>>, Math::Vector2<Float>>;
template struct MAGNUM_EXPORT TypeTraits<Math::CubicHermite<Math::Vector3<Float>>, Math::Vector3<Float>>;
template struct MAGNUM_EXPORT TypeTraits<Math::CubicHermite<Math::Complex<Float>>, Math::Complex<Float>>;
template struct MAGNUM_EXPORT TypeTraits<Math::CubicHermite<Math::Quaternion<Float>>, Math::Quaternion<Float>>;
}

31
src/Magnum/Animation/Interpolation.h

@ -60,6 +60,13 @@ enum class Interpolation: UnsignedByte {
*/
Linear,
/**
* Spline interpolation.
*
* @see @ref Math::splerp()
*/
Spline,
/**
* Custom interpolation. An user-supplied interpolation function should be
* used.
@ -74,8 +81,9 @@ MAGNUM_EXPORT Debug& operator<<(Debug& debug, Interpolation value);
@brief Animation result type for given value type
Result of interpolating two `V` values (for example interpolating two
@ref Color3 values gives back a @ref Color3 again, but interpolating a spline
does not result in a spline).
@ref Color3 values gives back a @ref Color3 again, but interpolating a
@ref Magnum::CubicHermite2D "CubicHermite2D" spline results in
@ref Magnum::Vector2 "Vector2").
@experimental
*/
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
@ -96,6 +104,7 @@ faster but less precise results.
Interpolation type | Value type | Result type | Interpolator
------------------- | ----------------- | ------------- | ------------
@ref Interpolation::Constant | any `V` | `V` | @ref Math::select()
@ref Interpolation::Constant | @ref Math::CubicHermite "Math::CubicHermite<T>" | `T` | @ref Math::select(const CubicHermite<T>&, const CubicHermite<T>&, U) "Math::select()"
@ref Interpolation::Linear | @cpp bool @ce <b></b> | @cpp bool @ce <b></b> | @ref Math::select()
@ref Interpolation::Linear | @ref Math::BoolVector | @ref Math::BoolVector | @ref Math::select()
@ref Interpolation::Linear | any scalar `V` | `V` | @ref Math::lerp()
@ -103,6 +112,12 @@ Interpolation type | Value type | Result type | Interpolator
@ref Interpolation::Linear | @ref Math::Complex | @ref Math::Complex | @ref Math::slerp(const Complex<T>&, const Complex<T>&, T) "Math::slerp()"
@ref Interpolation::Linear | @ref Math::Quaternion | @ref Math::Quaternion | @ref Math::slerp(const Quaternion<T>&, const Quaternion<T>&, T) "Math::slerp()"
@ref Interpolation::Linear | @ref Math::DualQuaternion | @ref Math::DualQuaternion | @ref Math::sclerp(const DualQuaternion<T>&, const DualQuaternion<T>&, T) "Math::sclerp()"
@ref Interpolation::Linear | @ref Math::CubicHermite "Math::CubicHermite<T>" | `T` | @ref Math::lerp(const CubicHermite<T>&, const CubicHermite<T>&, U) "Math::lerp()"
@ref Interpolation::Linear | @ref Math::CubicHermiteComplex | @ref Math::Complex | @ref Math::lerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T) "Math::lerp()"
@ref Interpolation::Linear | @ref Math::CubicHermiteQuaternion | @ref Math::Quaternion | @ref Math::lerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T) "Math::lerp()"
@ref Interpolation::Spline | @ref Math::CubicHermite "Math::CubicHermite<T>" | `T` | @ref Math::splerp(const CubicHermite<T>&, const CubicHermite<T>&, U) "Math::splerp()"
@ref Interpolation::Spline | @ref Math::CubicHermiteComplex | @ref Math::Complex | @ref Math::splerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T) "Math::splerp()"
@ref Interpolation::Spline | @ref Math::CubicHermiteQuaternion | @ref Math::Quaternion | @ref Math::splerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T) "Math::splerp()"
@see @ref interpolate(), @ref interpolateStrict()
@experimental
@ -213,6 +228,9 @@ namespace Implementation {
template<class V> struct ResultTraits {
typedef V Type;
};
template<class T> struct ResultTraits<Math::CubicHermite<T>> {
typedef T Type;
};
template<class V> struct TypeTraits<V, V> {
typedef V(*Interpolator)(const V&, const V&, Float);
@ -223,6 +241,7 @@ template<class V> auto TypeTraits<V, V>::interpolator(Interpolation interpolatio
case Interpolation::Constant: return Math::select;
case Interpolation::Linear: return Math::lerp;
case Interpolation::Spline:
case Interpolation::Custom: ; /* nope */
}
@ -240,6 +259,7 @@ template<class T> auto TypeTraitsBool<T>::interpolator(Interpolation interpolati
case Interpolation::Constant:
case Interpolation::Linear: return Math::select;
case Interpolation::Spline:
case Interpolation::Custom: ; /* nope */
}
@ -267,6 +287,13 @@ template<class T> struct MAGNUM_EXPORT TypeTraits<Math::DualQuaternion<T>, Math:
static Interpolator interpolator(Interpolation interpolation);
};
/* Cubic Hermite spline point has a different result type */
template<class T> struct MAGNUM_EXPORT TypeTraits<Math::CubicHermite<T>, T> {
typedef T(*Interpolator)(const Math::CubicHermite<T>&, const Math::CubicHermite<T>&, Float);
static Interpolator interpolator(Interpolation interpolation);
};
}
/* Needs to be defined later so it can pick up the TypeTraits definitions */

93
src/Magnum/Animation/Test/InterpolationTest.cpp

@ -28,6 +28,7 @@
#include "Magnum/Animation/Interpolation.h"
#include "Magnum/Math/Complex.h"
#include "Magnum/Math/CubicHermite.h"
#include "Magnum/Math/DualQuaternion.h"
#include "Magnum/Math/Half.h"
@ -42,6 +43,10 @@ struct InterpolationTest: TestSuite::Tester {
void interpolatorForComplex();
void interpolatorForQuaternion();
void interpolatorForDualQuaternion();
void interpolatorForCubicHermiteScalar();
void interpolatorForCubicHermiteVector();
void interpolatorForCubicHermiteComplex();
void interpolatorForCubicHermiteQuaternion();
void interpolate();
void interpolateStrict();
@ -142,7 +147,11 @@ InterpolationTest::InterpolationTest() {
&InterpolationTest::interpolatorForBoolVector,
&InterpolationTest::interpolatorForComplex,
&InterpolationTest::interpolatorForQuaternion,
&InterpolationTest::interpolatorForDualQuaternion});
&InterpolationTest::interpolatorForDualQuaternion,
&InterpolationTest::interpolatorForCubicHermiteScalar,
&InterpolationTest::interpolatorForCubicHermiteVector,
&InterpolationTest::interpolatorForCubicHermiteComplex,
&InterpolationTest::interpolatorForCubicHermiteQuaternion});
addInstancedTests({&InterpolationTest::interpolate,
&InterpolationTest::interpolateStrict},
@ -178,11 +187,11 @@ void InterpolationTest::interpolatorFor() {
std::ostringstream out;
Error redirectError{&out};
Animation::interpolatorFor<Float>(Interpolation::Custom);
Animation::interpolatorFor<Float>(Interpolation::Spline);
Animation::interpolatorFor<Float>(Interpolation(0xde));
CORRADE_COMPARE(out.str(),
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation::Custom\n"
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation::Spline\n"
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation(0xde)\n");
}
@ -250,11 +259,11 @@ void InterpolationTest::interpolatorForQuaternion() {
std::ostringstream out;
Error redirectError{&out};
Animation::interpolatorFor<Quaternion>(Interpolation::Custom);
Animation::interpolatorFor<Quaternion>(Interpolation::Spline);
Animation::interpolatorFor<Quaternion>(Interpolation(0xde));
CORRADE_COMPARE(out.str(),
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation::Custom\n"
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation::Spline\n"
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation(0xde)\n");
}
@ -278,6 +287,80 @@ void InterpolationTest::interpolatorForDualQuaternion() {
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation(0xde)\n");
}
void InterpolationTest::interpolatorForCubicHermiteScalar() {
CubicHermite1D a{2.0f, 3.0f, -1.0f};
CubicHermite1D b{5.0f, -2.0f, 1.5f};
CORRADE_COMPARE(Animation::interpolatorFor<CubicHermite1D>(Interpolation::Constant)(a, b, 0.8f), 3.0f);
CORRADE_COMPARE(Animation::interpolatorFor<CubicHermite1D>(Interpolation::Linear)(a, b, 0.8f), -1.0f);
CORRADE_COMPARE(Animation::interpolatorFor<CubicHermite1D>(Interpolation::Spline)(a, b, 0.8f), -2.152f);
std::ostringstream out;
Error redirectError{&out};
Animation::interpolatorFor<CubicHermite1D>(Interpolation::Custom);
Animation::interpolatorFor<CubicHermite1D>(Interpolation(0xde));
CORRADE_COMPARE(out.str(),
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation::Custom\n"
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation(0xde)\n");
}
void InterpolationTest::interpolatorForCubicHermiteVector() {
CubicHermite2D a{{2.0f, 1.5f}, {3.0f, 0.1f}, {-1.0f, 0.0f}};
CubicHermite2D b{{5.0f, 0.3f}, {-2.0f, 1.1f}, {1.5f, 0.3f}};
CORRADE_COMPARE(Animation::interpolatorFor<CubicHermite2D>(Interpolation::Constant)(a, b, 0.8f), (Vector2{3.0f, 0.1f}));
CORRADE_COMPARE(Animation::interpolatorFor<CubicHermite2D>(Interpolation::Linear)(a, b, 0.8f), (Vector2{-1.0f, 0.9f}));
CORRADE_COMPARE(Animation::interpolatorFor<CubicHermite2D>(Interpolation::Spline)(a, b, 0.8f), (Vector2{-2.152f, 0.9576f}));
std::ostringstream out;
Error redirectError{&out};
Animation::interpolatorFor<CubicHermite2D>(Interpolation::Custom);
Animation::interpolatorFor<CubicHermite2D>(Interpolation(0xde));
CORRADE_COMPARE(out.str(),
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation::Custom\n"
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation(0xde)\n");
}
void InterpolationTest::interpolatorForCubicHermiteComplex() {
CubicHermiteComplex a{{2.0f, 1.5f}, {0.999445f, 0.0333148f}, {-1.0f, 0.0f}};
CubicHermiteComplex b{{5.0f, 0.3f}, {-0.876216f, 0.481919f}, {1.5f, 0.3f}};
CORRADE_COMPARE(Animation::interpolatorFor<CubicHermiteComplex>(Interpolation::Constant)(a, b, 0.8f), (Complex{0.999445f, 0.0333148f}));
CORRADE_COMPARE(Animation::interpolatorFor<CubicHermiteComplex>(Interpolation::Linear)(a, b, 0.8f), (Complex{-0.78747f, 0.616353f}));
CORRADE_COMPARE(Animation::interpolatorFor<CubicHermiteComplex>(Interpolation::Spline)(a, b, 0.8f), (Complex{-0.95958f, 0.281435f}));
std::ostringstream out;
Error redirectError{&out};
Animation::interpolatorFor<CubicHermiteComplex>(Interpolation::Custom);
Animation::interpolatorFor<CubicHermiteComplex>(Interpolation(0xde));
CORRADE_COMPARE(out.str(),
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation::Custom\n"
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation(0xde)\n");
}
void InterpolationTest::interpolatorForCubicHermiteQuaternion() {
CubicHermiteQuaternion a{
{{2.0f, 1.5f, 0.3f}, 1.1f},
{{0.780076f, 0.0260025f, 0.598059f}, 0.182018f},
{{-1.0f, 0.0f, 0.3f}, 0.4f}};
CubicHermiteQuaternion b{
{{5.0f, 0.3f, 1.1f}, 0.5f},
{{-0.711568f, 0.391362f, 0.355784f}, 0.462519f},
{{1.5f, 0.3f, 17.0f}, -7.0f}};
CORRADE_COMPARE(Animation::interpolatorFor<CubicHermiteQuaternion>(Interpolation::Constant)(a, b, 0.8f), (Quaternion{{0.780076f, 0.0260025f, 0.598059f}, 0.182018f}));
CORRADE_COMPARE(Animation::interpolatorFor<CubicHermiteQuaternion>(Interpolation::Linear)(a, b, 0.8f), (Quaternion{{-0.533196f, 0.410685f, 0.521583f}, 0.524396f}));
CORRADE_COMPARE(Animation::interpolatorFor<CubicHermiteQuaternion>(Interpolation::Spline)(a, b, 0.8f), (Quaternion{{-0.911408f, 0.23368f, 0.185318f}, 0.283524f}));
std::ostringstream out;
Error redirectError{&out};
Animation::interpolatorFor<CubicHermiteQuaternion>(Interpolation::Custom);
Animation::interpolatorFor<CubicHermiteQuaternion>(Interpolation(0xde));
CORRADE_COMPARE(out.str(),
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation::Custom\n"
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation(0xde)\n");
}
namespace {
constexpr Float Keys[]{0.0f, 2.0f, 4.0f, 5.0f};
constexpr Float Values[]{3.0f, 1.0f, 2.5f, 0.5f};

7
src/Magnum/Animation/Track.h

@ -63,15 +63,22 @@ are common combinations:
Interpolation type | Value type | Result type | Interpolator
------------------- | ----------------- | ------------- | ------------
Constant | any `V` | `V` | @ref Math::select()
Constant | @ref Math::CubicHermite "Math::CubicHermite<T>" | `T` | @ref Math::select(const CubicHermite<T>&, const CubicHermite<T>&, U) "Math::select()"
Linear | @cpp bool @ce <b></b> | @cpp bool @ce <b></b> | @ref Math::select()
Linear | @ref Math::BoolVector | @ref Math::BoolVector | @ref Math::select()
Linear | any scalar `V` | `V` | @ref Math::lerp()
Linear | any vector `V` | `V` | @ref Math::lerp()
Linear | @ref Math::Complex | @ref Math::Complex | @ref Math::lerp(const Complex<T>&, const Complex<T>&, T) "Math::lerp()"
Linear | @ref Math::Quaternion | @ref Math::Quaternion | @ref Math::lerp(const Quaternion<T>&, const Quaternion<T>&, T) "Math::lerp()"
Linear | @ref Math::CubicHermite "Math::CubicHermite<T>" | `T` | @ref Math::lerp(const CubicHermite<T>&, const CubicHermite<T>&, U) "Math::lerp()"
Linear | @ref Math::CubicHermiteComplex | @ref Math::Complex | @ref Math::lerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T) "Math::lerp()"
Linear | @ref Math::CubicHermiteQuaternion | @ref Math::Quaternion | @ref Math::lerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T) "Math::lerp()"
Spherical linear | @ref Math::Complex | @ref Math::Complex | @ref Math::slerp(const Complex<T>&, const Complex<T>&, T) "Math::slerp()"
Spherical linear | @ref Math::Quaternion | @ref Math::Quaternion | @ref Math::slerp(const Quaternion<T>&, const Quaternion<T>&, T) "Math::slerp()"
Screw linear | @ref Math::DualQuaternion | @ref Math::DualQuaternion | @ref Math::sclerp(const DualQuaternion<T>&, const DualQuaternion<T>&, T) "Math::sclerp()"
Spline | @ref Math::CubicHermite "Math::CubicHermite<T>" | `T` | @ref Math::splerp(const CubicHermite<T>&, const CubicHermite<T>&, U) "Math::splerp()"
Spline | @ref Math::CubicHermiteComplex | @ref Math::Complex | @ref Math::splerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T) "Math::splerp()"
Spline | @ref Math::CubicHermiteQuaternion | @ref Math::Quaternion | @ref Math::splerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T) "Math::splerp()"
It's also possible to supply a generic interpolation behavior by passing the
@ref Interpolation enum to the constructor. In case the interpolator function

Loading…
Cancel
Save