|
|
|
|
#ifndef Magnum_Math_CubicHermiteSpline_h
|
|
|
|
|
#define Magnum_Math_CubicHermiteSpline_h
|
|
|
|
|
/*
|
|
|
|
|
This file is part of Magnum.
|
|
|
|
|
|
|
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
|
|
|
|
|
Vladimír Vondruš <mosra@centrum.cz>
|
|
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
to deal in the Software without restriction, including without limitation
|
|
|
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included
|
|
|
|
|
in all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
|
DEALINGS IN THE SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/** @file
|
|
|
|
|
* @brief Class @ref Magnum::Math::CubicHermite, alias @ref Magnum::Math::CubicHermite2D, @ref Magnum::Math::CubicHermite3D, function @ref Magnum::Math::select(), @ref Magnum::Math::lerp(), @ref Magnum::Math::splerp()
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "Magnum/Math/Complex.h"
|
|
|
|
|
#include "Magnum/Math/Quaternion.h"
|
|
|
|
|
|
|
|
|
|
namespace Magnum { namespace Math {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@brief Cubic Hermite spline point
|
|
|
|
|
|
|
|
|
|
Represents a point on a [cubic Hermite spline](https://en.wikipedia.org/wiki/Cubic_Hermite_spline).
|
|
|
|
|
|
|
|
|
|
Unlike @ref Bezier, which describes a curve segment, this structure describes
|
|
|
|
|
a spline point @f$ \boldsymbol{p} @f$, with in-tangent @f$ \boldsymbol{m} @f$
|
|
|
|
|
and out-tangent @f$ \boldsymbol{n} @f$. This form is more suitable for
|
|
|
|
|
animation keyframe representation. The structure assumes the in/out tangents
|
|
|
|
|
to be in their final form, i.e. already normalized by length of their adjacent
|
|
|
|
|
segments.
|
|
|
|
|
|
|
|
|
|
Cubic Hermite splines are fully interchangeable with cubic Bézier curves, use
|
|
|
|
|
@ref fromBezier() and @ref Bezier::fromCubicHermite() for the conversion.
|
|
|
|
|
|
|
|
|
|
@see @ref CubicHermite2D, @ref CubicHermite3D,
|
|
|
|
|
@ref Magnum::CubicHermite2D, @ref Magnum::CubicHermite2Dd,
|
|
|
|
|
@ref Magnum::CubicHermite3D, @ref Magnum::CubicHermite3Dd,
|
|
|
|
|
@ref CubicBezier
|
|
|
|
|
@experimental
|
|
|
|
|
*/
|
|
|
|
|
template<class T> class CubicHermite {
|
|
|
|
|
public:
|
|
|
|
|
typedef T Type; /**< @brief Underlying data type */
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Create cubic Hermite spline point from adjacent Bézier curve segments
|
|
|
|
|
*
|
|
|
|
|
* Given two adjacent cubic Bézier curve segments defined by points
|
|
|
|
|
* @f$ \boldsymbol{a}_i @f$ and @f$ \boldsymbol{b}_i @f$,
|
|
|
|
|
* @f$ i \in \{ 0, 1, 2, 3 \} @f$, the corresponding cubic Hermite
|
|
|
|
|
* spline point @f$ \boldsymbol{p} @f$, in-tangent @f$ \boldsymbol{m} @f$
|
|
|
|
|
* and out-tangent @f$ \boldsymbol{n} @f$ is defined as: @f[
|
|
|
|
|
* \begin{array}{rcl}
|
|
|
|
|
* \boldsymbol{m} & = & 3 (\boldsymbol{a}_3 - \boldsymbol{a}_2)
|
|
|
|
|
* = 3 (\boldsymbol{b}_0 - \boldsymbol{a}_2) \\
|
|
|
|
|
* \boldsymbol{p} & = & \boldsymbol{a}_3 = \boldsymbol{b}_0 \\
|
|
|
|
|
* \boldsymbol{n} & = & 3 (\boldsymbol{b}_1 - \boldsymbol{a}_3)
|
|
|
|
|
* = 3 (\boldsymbol{b}_1 - \boldsymbol{b}_0)
|
|
|
|
|
* \end{array}
|
|
|
|
|
* @f]
|
|
|
|
|
*
|
|
|
|
|
* Expects that the two segments are adjacent (i.e., the endpoint of
|
|
|
|
|
* first segment is the start point of the second). If you need to
|
|
|
|
|
* create a cubic Hermite spline point that's at the beginning or at
|
|
|
|
|
* the end of a curve, simply pass a dummy Bézier segment that
|
|
|
|
|
* satisfies this constraint as the other parameter:
|
|
|
|
|
*
|
|
|
|
|
* @snippet MagnumMath.cpp CubicHermite-fromBezier
|
|
|
|
|
*
|
|
|
|
|
* Enabled only on vector underlying types. See
|
|
|
|
|
* @ref Bezier::fromCubicHermite() for the inverse operation.
|
|
|
|
|
*/
|
|
|
|
|
template<UnsignedInt dimensions, class U> static
|
|
|
|
|
#ifdef DOXYGEN_GENERATING_OUTPUT
|
|
|
|
|
CubicHermite<T>
|
|
|
|
|
#else
|
|
|
|
|
typename std::enable_if<std::is_base_of<Vector<dimensions, U>, T>::value, CubicHermite<T>>::type
|
|
|
|
|
#endif
|
|
|
|
|
fromBezier(const CubicBezier<dimensions, U>& a, const CubicBezier<dimensions, U>& b) {
|
|
|
|
|
return CORRADE_CONSTEXPR_ASSERT(a[3] == b[0],
|
|
|
|
|
"Math::CubicHermite::fromBezier(): segments are not adjacent"),
|
|
|
|
|
CubicHermite<T>{3*(a[3] - a[2]), a[3], 3*(b[1] - a[3])};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Default constructor
|
|
|
|
|
*
|
|
|
|
|
* Equivalent to @ref CubicHermite(ZeroInitT) for vector types and to
|
|
|
|
|
* @ref CubicHermite(IdentityInitT) for complex and quaternion types.
|
|
|
|
|
*/
|
|
|
|
|
constexpr /*implicit*/ CubicHermite() noexcept: CubicHermite{typename std::conditional<std::is_constructible<T, IdentityInitT>::value, IdentityInitT, ZeroInitT>::type{typename std::conditional<std::is_constructible<T, IdentityInitT>::value, IdentityInitT, ZeroInitT>::type::Init{}}} {}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Default constructor
|
|
|
|
|
*
|
|
|
|
|
* Construct cubic Hermite spline point with all control points being
|
|
|
|
|
* zero.
|
|
|
|
|
*/
|
|
|
|
|
constexpr explicit CubicHermite(ZeroInitT) noexcept: CubicHermite{ZeroInit, typename std::conditional<std::is_constructible<T, ZeroInitT>::value, ZeroInitT*, void*>::type{}} {}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Identity constructor
|
|
|
|
|
*
|
|
|
|
|
* The @ref point() is constructed as identity in order to have
|
|
|
|
|
* interpolation working correctly; @ref inTangent() and
|
|
|
|
|
* @ref outTangent() is constructed as zero. Enabled only for complex
|
|
|
|
|
* and quaternion types.
|
|
|
|
|
*/
|
|
|
|
|
template<class U = T, class = typename std::enable_if<std::is_constructible<U, IdentityInitT>::value>::type> constexpr explicit CubicHermite(IdentityInitT) noexcept: _inTangent{ZeroInit}, _point{IdentityInit}, _outTangent{ZeroInit} {}
|
|
|
|
|
|
|
|
|
|
/** @brief Construct cubic Hermite spline point without initializing its contents */
|
|
|
|
|
explicit CubicHermite(NoInitT) noexcept: CubicHermite{NoInit, typename std::conditional<std::is_constructible<T, NoInitT>::value, NoInitT*, void*>::type{}} {}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Construct cubic Hermite spline point with given control points
|
|
|
|
|
* @param inTangent In-tangent @f$ \boldsymbol{m} @f$
|
|
|
|
|
* @param point Point @f$ \boldsymbol{p} @f$
|
|
|
|
|
* @param outTangent Out-tangent @f$ \boldsymbol{n} @f$
|
|
|
|
|
*/
|
|
|
|
|
constexpr /*implicit*/ CubicHermite(const T& inTangent, const T& point, const T& outTangent) noexcept: _inTangent{inTangent}, _point{point}, _outTangent{outTangent} {}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Construct subic Hermite spline point from another of different type
|
|
|
|
|
*
|
|
|
|
|
* Performs only default casting on the values, no rounding or
|
|
|
|
|
* anything else.
|
|
|
|
|
*/
|
|
|
|
|
template<class U> constexpr explicit CubicHermite(const CubicHermite<U>& other) noexcept: _inTangent{T(other._inTangent)}, _point{T(other._point)}, _outTangent{T(other._outTangent)} {}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Raw data
|
|
|
|
|
* @return One-dimensional array of three elements
|
|
|
|
|
*
|
|
|
|
|
* @see @ref inTangent(), @ref point(), @ref outTangent()
|
|
|
|
|
*/
|
|
|
|
|
T* data() { return &_inTangent; }
|
|
|
|
|
constexpr const T* data() const { return &_inTangent; } /**< @overload */
|
|
|
|
|
|
|
|
|
|
/** @brief Equality comparison */
|
|
|
|
|
bool operator==(const CubicHermite<T>& other) const;
|
|
|
|
|
|
|
|
|
|
/** @brief Non-equality comparison */
|
|
|
|
|
bool operator!=(const CubicHermite<T>& other) const {
|
|
|
|
|
return !operator==(other);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @brief In-tangent @f$ \boldsymbol{m} @f$ */
|
|
|
|
|
T& inTangent() { return _inTangent; }
|
|
|
|
|
/* returns const& so [] operations are also constexpr */
|
|
|
|
|
constexpr const T& inTangent() const { return _inTangent; } /**< @overload */
|
|
|
|
|
|
|
|
|
|
/** @brief Point @f$ \boldsymbol{p} @f$ */
|
|
|
|
|
T& point() { return _point; }
|
|
|
|
|
/* returns const& so [] operations are also constexpr */
|
|
|
|
|
constexpr const T& point() const { return _point; } /**< @overload */
|
|
|
|
|
|
|
|
|
|
/** @brief Out-tangent @f$ \boldsymbol{n} @f$ */
|
|
|
|
|
T& outTangent() { return _outTangent; }
|
|
|
|
|
/* returns const& so [] operations are also constexpr */
|
|
|
|
|
constexpr const T& outTangent() const { return _outTangent; } /**< @overload */
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
template<class> friend class CubicHermite;
|
|
|
|
|
|
|
|
|
|
/* Called from CubicHermite(ZeroInit), either using the ZeroInit
|
|
|
|
|
constructor (if available) or passing zero directly (for scalar
|
|
|
|
|
types) */
|
|
|
|
|
constexpr explicit CubicHermite(ZeroInitT, ZeroInitT*) noexcept: _inTangent{ZeroInit}, _point{ZeroInit}, _outTangent{ZeroInit} {}
|
|
|
|
|
constexpr explicit CubicHermite(ZeroInitT, void*) noexcept: _inTangent{T(0)}, _point{T(0)}, _outTangent{T(0)} {}
|
|
|
|
|
|
|
|
|
|
/* Called from CubicHermite(NoInit), either using the NoInit
|
|
|
|
|
constructor (if available) or not doing anything */
|
|
|
|
|
explicit CubicHermite(NoInitT, NoInitT*) noexcept: _inTangent{NoInit}, _point{NoInit}, _outTangent{NoInit} {}
|
|
|
|
|
explicit CubicHermite(NoInitT, void*) noexcept {}
|
|
|
|
|
|
|
|
|
|
T _inTangent;
|
|
|
|
|
T _point;
|
|
|
|
|
T _outTangent;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@brief Scalar cubic Hermite spline point
|
|
|
|
|
|
|
|
|
|
Convenience alternative to @cpp CubicHermite<T> @ce. See @ref CubicHermite for
|
|
|
|
|
more information.
|
|
|
|
|
@see @ref CubicHermite2D, @ref CubicHermite3D, @ref CubicHermiteComplex,
|
|
|
|
|
@ref CubicHermiteQuaternion, @ref Magnum::CubicHermite1D,
|
|
|
|
|
@ref Magnum::CubicHermite1Dd
|
|
|
|
|
*/
|
|
|
|
|
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
|
|
|
|
|
template<class T> using CubicHermite1D = CubicHermite<T>;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@brief Two-dimensional cubic Hermite spline point
|
|
|
|
|
|
|
|
|
|
Convenience alternative to @cpp CubicHermite<Vector2<T>> @ce. See
|
|
|
|
|
@ref CubicHermite for more information.
|
|
|
|
|
@see @ref CubicHermite1D, @ref CubicHermite3D, @ref CubicHermiteComplex,
|
|
|
|
|
@ref CubicHermiteQuaternion, @ref Magnum::CubicHermite2D,
|
|
|
|
|
@ref Magnum::CubicHermite2Dd
|
|
|
|
|
*/
|
|
|
|
|
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
|
|
|
|
|
template<class T> using CubicHermite2D = CubicHermite<Vector2<T>>;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@brief Three-dimensional cubic Hermite spline point
|
|
|
|
|
|
|
|
|
|
Convenience alternative to @cpp CubicHermite<Vector2<T>> @ce. See
|
|
|
|
|
@ref CubicHermite for more information.
|
|
|
|
|
@see @ref CubicHermite1D, @ref CubicHermite2D, @ref CubicHermiteComplex,
|
|
|
|
|
@ref CubicHermiteQuaternion, @ref Magnum::CubicHermite3D,
|
|
|
|
|
@ref Magnum::CubicHermite3Dd
|
|
|
|
|
*/
|
|
|
|
|
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
|
|
|
|
|
template<class T> using CubicHermite3D = CubicHermite<Vector3<T>>;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@brief Cubic Hermite spline complex number
|
|
|
|
|
|
|
|
|
|
Convenience alternative to @cpp CubicHermite<Complex<T>> @ce. See
|
|
|
|
|
@ref CubicHermite for more information.
|
|
|
|
|
@see @ref CubicHermite1D, @ref CubicHermite2D, @ref CubicHermite3D,
|
|
|
|
|
@ref CubicHermiteQuaternion, @ref Magnum::CubicHermiteComplex,
|
|
|
|
|
@ref Magnum::CubicHermiteComplexd
|
|
|
|
|
*/
|
|
|
|
|
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
|
|
|
|
|
template<class T> using CubicHermiteComplex = CubicHermite<Complex<T>>;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@brief Cubic Hermite spline quaternion
|
|
|
|
|
|
|
|
|
|
Convenience alternative to @cpp CubicHermite<Quaternion<T>> @ce. See
|
|
|
|
|
@ref CubicHermite for more information.
|
|
|
|
|
@see @ref CubicHermite1D, @ref CubicHermite2D, @ref CubicHermite3D,
|
|
|
|
|
@ref CubicHermiteComplex, @ref Magnum::CubicHermiteQuaternion,
|
|
|
|
|
@ref Magnum::CubicHermiteQuaterniond
|
|
|
|
|
*/
|
|
|
|
|
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
|
|
|
|
|
template<class T> using CubicHermiteQuaternion = CubicHermite<Quaternion<T>>;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/** @debugoperator{CubicHermite} */
|
|
|
|
|
template<class T> Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug& debug, const CubicHermite<T>& value) {
|
|
|
|
|
return debug << "CubicHermite(" << Corrade::Utility::Debug::nospace
|
|
|
|
|
<< value.inTangent() << Corrade::Utility::Debug::nospace << ","
|
|
|
|
|
<< value.point() << Corrade::Utility::Debug::nospace << ","
|
|
|
|
|
<< value.outTangent() << Corrade::Utility::Debug::nospace << ")";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Explicit instantiation for commonly used types */
|
|
|
|
|
#ifndef DOXYGEN_GENERATING_OUTPUT
|
|
|
|
|
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Float>&);
|
|
|
|
|
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Double>&);
|
|
|
|
|
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Vector2<Float>>&);
|
|
|
|
|
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Vector3<Float>>&);
|
|
|
|
|
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Vector4<Float>>&);
|
|
|
|
|
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Vector2<Double>>&);
|
|
|
|
|
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Vector3<Double>>&);
|
|
|
|
|
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Vector4<Double>>&);
|
|
|
|
|
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Complex<Float>>&);
|
|
|
|
|
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Complex<Double>>&);
|
|
|
|
|
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Quaternion<Float>>&);
|
|
|
|
|
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Quaternion<Double>>&);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/** @relatesalso CubicHermite
|
|
|
|
|
@brief Constant interpolation of two cubic Hermite spline points
|
|
|
|
|
@param a First spline point
|
|
|
|
|
@param b Second spline point
|
|
|
|
|
@param t Interpolation phase (from range @f$ [0; 1] @f$)
|
|
|
|
|
|
|
|
|
|
Given segment points @f$ \boldsymbol{p}_i @f$, in-tangents @f$ \boldsymbol{m}_i @f$
|
|
|
|
|
and out-tangents @f$ \boldsymbol{n}_i @f$, the interpolated value @f$ \boldsymbol{p} @f$
|
|
|
|
|
at phase @f$ t @f$ is: @f[
|
|
|
|
|
\boldsymbol{p}(t) = \begin{cases}
|
|
|
|
|
\boldsymbol{p}_a, & t < 1 \\
|
|
|
|
|
\boldsymbol{p}_b, & t \ge 1
|
|
|
|
|
\end{cases}
|
|
|
|
|
@f]
|
|
|
|
|
|
|
|
|
|
Equivalent to calling @ref select(const T&, const T&, U) on
|
|
|
|
|
@ref CubicHermite::point() extracted from both @p a and @p b.
|
|
|
|
|
@see @ref lerp(const CubicHermite<T>&, const CubicHermite<T>&, U),
|
|
|
|
|
@ref splerp(const CubicHermite<T>&, const CubicHermite<T>&, U)
|
|
|
|
|
*/
|
|
|
|
|
template<class T, class U> T select(const CubicHermite<T>& a, const CubicHermite<T>& b, U t) {
|
|
|
|
|
/* Not using select() from Functions.h to avoid the header dependency */
|
|
|
|
|
return t < U(1) ? a.point() : b.point();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @relatesalso CubicHermite
|
|
|
|
|
@brief Linear interpolation of two cubic Hermite points
|
|
|
|
|
@param a First spline point
|
|
|
|
|
@param b Second spline point
|
|
|
|
|
@param t Interpolation phase (from range @f$ [0; 1] @f$)
|
|
|
|
|
|
|
|
|
|
Given segment points @f$ \boldsymbol{p}_i @f$, in-tangents @f$ \boldsymbol{m}_i @f$
|
|
|
|
|
and out-tangents @f$ \boldsymbol{n}_i @f$, the interpolated value @f$ \boldsymbol{p} @f$
|
|
|
|
|
at phase @f$ t @f$ is: @f[
|
|
|
|
|
\boldsymbol{p}(t) = (1 - t) \boldsymbol{p}_a + t \boldsymbol{p}_b
|
|
|
|
|
@f]
|
|
|
|
|
|
|
|
|
|
Equivalent to calling @ref lerp(const T&, const T&, U) on
|
|
|
|
|
@ref CubicHermite::point() extracted from both @p a and @p b.
|
|
|
|
|
@see @ref lerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T),
|
|
|
|
|
@ref lerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T),
|
|
|
|
|
@ref lerpShortestPath(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T),
|
|
|
|
|
@ref slerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T),
|
|
|
|
|
@ref slerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T),
|
|
|
|
|
@ref slerpShortestPath(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T),
|
|
|
|
|
@ref select(const CubicHermite<T>&, const CubicHermite<T>&, U),
|
|
|
|
|
@ref splerp(const CubicHermite<T>&, const CubicHermite<T>&, U),
|
|
|
|
|
@ref splerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T),
|
|
|
|
|
@ref splerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T)
|
|
|
|
|
*/
|
|
|
|
|
template<class T, class U> T lerp(const CubicHermite<T>& a, const CubicHermite<T>& b, U t) {
|
|
|
|
|
/* To avoid dependency on Functions.h */
|
|
|
|
|
return Implementation::lerp(a.point(), b.point(), t);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @relatesalso CubicHermite
|
|
|
|
|
@brief Linear interpolation of two cubic Hermite complex numbers
|
|
|
|
|
|
|
|
|
|
Equivalent to calling @ref lerp(const Complex<T>&, const Complex<T>&, T) on
|
|
|
|
|
@ref CubicHermite::point() extracted from @p a and @p b. Compared to
|
|
|
|
|
@ref lerp(const CubicHermite<T>&, const CubicHermite<T>&, U) this adds a
|
|
|
|
|
normalization step after. Expects that @ref CubicHermite::point() is a
|
|
|
|
|
normalized complex number in both @p a and @p b.
|
|
|
|
|
@see @ref Complex::isNormalized(),
|
|
|
|
|
@ref lerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T),
|
|
|
|
|
@ref select(const CubicHermite<T>&, const CubicHermite<T>&, U),
|
|
|
|
|
@ref slerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T),
|
|
|
|
|
@ref splerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T)
|
|
|
|
|
*/
|
|
|
|
|
template<class T> Complex<T> lerp(const CubicHermiteComplex<T>& a, const CubicHermiteComplex<T>& b, T t) {
|
|
|
|
|
return lerp(a.point(), b.point(), t);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @relatesalso CubicHermite
|
|
|
|
|
@brief Linear interpolation of two cubic Hermite quaternions
|
|
|
|
|
|
|
|
|
|
Equivalent to calling @ref lerp(const Quaternion<T>&, const Quaternion<T>&, T)
|
|
|
|
|
on @ref CubicHermite::point() extracted from @p a and @p b. Compared to
|
|
|
|
|
@ref lerp(const CubicHermite<T>&, const CubicHermite<T>&, U) this adds a
|
|
|
|
|
normalization step after. Expects that @ref CubicHermite::point() is a
|
|
|
|
|
normalized quaternion in both @p a and @p b.
|
|
|
|
|
@see @ref Quaternion::isNormalized(),
|
|
|
|
|
@ref lerpShortestPath(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T),
|
|
|
|
|
@ref lerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T),
|
|
|
|
|
@ref select(const CubicHermite<T>&, const CubicHermite<T>&, U),
|
|
|
|
|
@ref slerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T),
|
|
|
|
|
@ref splerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T)
|
|
|
|
|
*/
|
|
|
|
|
template<class T> Quaternion<T> lerp(const CubicHermiteQuaternion<T>& a, const CubicHermiteQuaternion<T>& b, T t) {
|
|
|
|
|
return lerp(a.point(), b.point(), t);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @relatesalso CubicHermite
|
|
|
|
|
@brief Linear shortest-path interpolation of two cubic Hermite quaternions
|
|
|
|
|
|
|
|
|
|
Equivalent to calling @ref lerpShortestPath(const Quaternion<T>&, const Quaternion<T>&, T)
|
|
|
|
|
on @ref CubicHermite::point() extracted from @p a and @p b. Expects that
|
|
|
|
|
@ref CubicHermite::point() is a normalized quaternion in both @p a and @p b.
|
|
|
|
|
|
|
|
|
|
Note that rotations interpolated with this function may go along a completely
|
|
|
|
|
different path compared to @ref splerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T).
|
|
|
|
|
Use @ref lerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T)
|
|
|
|
|
for behavior that is consistent with spline interpolation.
|
|
|
|
|
@see @ref Quaternion::isNormalized(),
|
|
|
|
|
@ref slerpShortestPath(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T)
|
|
|
|
|
*/
|
|
|
|
|
template<class T> Quaternion<T> lerpShortestPath(const CubicHermiteQuaternion<T>& a, const CubicHermiteQuaternion<T>& b, T t) {
|
|
|
|
|
return lerpShortestPath(a.point(), b.point(), t);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @relatesalso CubicHermite
|
|
|
|
|
@brief Spherical linear interpolation of two cubic Hermite complex numbers
|
|
|
|
|
|
|
|
|
|
Equivalent to calling @ref slerp(const Complex<T>&, const Complex<T>&, T) on
|
|
|
|
|
@ref CubicHermite::point() extracted from @p a and @p b. Expects that
|
|
|
|
|
@ref CubicHermite::point() is a normalized complex number in both @p a and @p b.
|
|
|
|
|
@see @ref Complex::isNormalized(),
|
|
|
|
|
@ref slerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T),
|
|
|
|
|
@ref select(const CubicHermite<T>&, const CubicHermite<T>&, U),
|
|
|
|
|
@ref lerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T),
|
|
|
|
|
@ref splerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T)
|
|
|
|
|
*/
|
|
|
|
|
template<class T> inline Complex<T> slerp(const CubicHermiteComplex<T>& a, const CubicHermiteComplex<T>& b, T t) {
|
|
|
|
|
return slerp(a.point(), b.point(), t);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @relatesalso CubicHermite
|
|
|
|
|
@brief Spherical linear interpolation of two cubic Hermite quaternions
|
|
|
|
|
|
|
|
|
|
Equivalent to calling @ref slerp(const Quaternion<T>&, const Quaternion<T>&, T)
|
|
|
|
|
on @ref CubicHermite::point() extracted from @p a and @p b. Expects that
|
|
|
|
|
@ref CubicHermite::point() is a normalized complex number in both @p a and @p b.
|
|
|
|
|
@see @ref Quaternion::isNormalized(),
|
|
|
|
|
@ref slerpShortestPath(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T),
|
|
|
|
|
@ref slerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T),
|
|
|
|
|
@ref select(const CubicHermite<T>&, const CubicHermite<T>&, U),
|
|
|
|
|
@ref lerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T),
|
|
|
|
|
@ref splerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T)
|
|
|
|
|
*/
|
|
|
|
|
template<class T> inline Quaternion<T> slerp(const CubicHermiteQuaternion<T>& a, const CubicHermiteQuaternion<T>& b, T t) {
|
|
|
|
|
return slerp(a.point(), b.point(), t);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @relatesalso CubicHermite
|
|
|
|
|
@brief Spherical linear shortest-path interpolation of two cubic Hermite quaternions
|
|
|
|
|
|
|
|
|
|
Equivalent to calling @ref slerpShortestPath(const Quaternion<T>&, const Quaternion<T>&, T)
|
|
|
|
|
on @ref CubicHermite::point() extracted from @p a and @p b. Expects that
|
|
|
|
|
@ref CubicHermite::point() is a normalized quaternion in both @p a and @p b.
|
|
|
|
|
|
|
|
|
|
Note that rotations interpolated with this function may go along a completely
|
|
|
|
|
different path compared to @ref splerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T).
|
|
|
|
|
Use @ref slerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T)
|
|
|
|
|
for spherical linear interpolation with behavior that is consistent with spline
|
|
|
|
|
interpolation.
|
|
|
|
|
@see @ref Quaternion::isNormalized(),
|
|
|
|
|
@ref lerpShortestPath(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T)
|
|
|
|
|
*/
|
|
|
|
|
template<class T> Quaternion<T> slerpShortestPath(const CubicHermiteQuaternion<T>& a, const CubicHermiteQuaternion<T>& b, T t) {
|
|
|
|
|
return slerpShortestPath(a.point(), b.point(), t);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @relatesalso CubicHermite
|
|
|
|
|
@brief Spline interpolation of two cubic Hermite points
|
|
|
|
|
@param a First spline point
|
|
|
|
|
@param b Second spline point
|
|
|
|
|
@param t Interpolation phase
|
|
|
|
|
|
|
|
|
|
Given segment points @f$ \boldsymbol{p}_i @f$, in-tangents @f$ \boldsymbol{m}_i @f$
|
|
|
|
|
and out-tangents @f$ \boldsymbol{n}_i @f$, the interpolated value @f$ \boldsymbol{p} @f$
|
|
|
|
|
at phase @f$ t @f$ is: @f[
|
|
|
|
|
\boldsymbol{p}(t) = (2 t^3 - 3 t^2 + 1) \boldsymbol{p}_a + (t^3 - 2 t^2 + t) \boldsymbol{n}_a + (-2 t^3 + 3 t^2) \boldsymbol{p}_b + (t^3 - t^2)\boldsymbol{m}_b
|
|
|
|
|
@f]
|
|
|
|
|
|
|
|
|
|
@see @ref splerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T),
|
|
|
|
|
@ref splerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T),
|
|
|
|
|
@ref select(const CubicHermite<T>&, const CubicHermite<T>&, U),
|
|
|
|
|
@ref lerp(const CubicHermite<T>&, const CubicHermite<T>&, U)
|
|
|
|
|
*/
|
|
|
|
|
template<class T, class U> T splerp(const CubicHermite<T>& a, const CubicHermite<T>& b, U t) {
|
|
|
|
|
return (U(2)*t*t*t - U(3)*t*t + U(1))*a.point() +
|
|
|
|
|
(t*t*t - U(2)*t*t + t)*a.outTangent() +
|
|
|
|
|
(U(-2)*t*t*t + U(3)*t*t)*b.point() +
|
|
|
|
|
(t*t*t - t*t)*b.inTangent();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @relatesalso CubicHermite
|
|
|
|
|
@brief Spline interpolation of two cubic Hermite complex numbers
|
|
|
|
|
|
|
|
|
|
Unlike @ref splerp(const CubicHermite<T>&, const CubicHermite<T>&, U) this adds
|
|
|
|
|
a normalization step after. Given segment points @f$ \boldsymbol{p}_i @f$,
|
|
|
|
|
in-tangents @f$ \boldsymbol{m}_i @f$ and out-tangents @f$ \boldsymbol{n}_i @f$,
|
|
|
|
|
the interpolated value @f$ \boldsymbol{p} @f$ at phase @f$ t @f$ is: @f[
|
|
|
|
|
\begin{array}{rcl}
|
|
|
|
|
\boldsymbol{p'}(t) & = & (2 t^3 - 3 t^2 + 1) \boldsymbol{p}_a + (t^3 - 2 t^2 + t) \boldsymbol{n}_a + (-2 t^3 + 3 t^2) \boldsymbol{p}_b + (t^3 - t^2)\boldsymbol{m}_b \\
|
|
|
|
|
\boldsymbol{p}(t) & = & \cfrac{\boldsymbol{p'}(t)}{|\boldsymbol{p'}(t)|}
|
|
|
|
|
\end{array}
|
|
|
|
|
@f]
|
|
|
|
|
|
|
|
|
|
Expects that @ref CubicHermite::point() is a normalized complex number in both
|
|
|
|
|
@p a and @p b.
|
|
|
|
|
@see @ref Complex::isNormalized(),
|
|
|
|
|
@ref splerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T),
|
|
|
|
|
@ref select(const CubicHermite<T>&, const CubicHermite<T>&, U),
|
|
|
|
|
@ref lerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T),
|
|
|
|
|
@ref slerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T)
|
|
|
|
|
*/
|
|
|
|
|
template<class T> Complex<T> splerp(const CubicHermiteComplex<T>& a, const CubicHermiteComplex<T>& b, T t) {
|
|
|
|
|
CORRADE_ASSERT(a.point().isNormalized() && b.point().isNormalized(),
|
|
|
|
|
"Math::splerp(): complex spline points" << a.point() << "and" << b.point() << "are not normalized", {});
|
|
|
|
|
return ((T(2)*t*t*t - T(3)*t*t + T(1))*a.point() +
|
|
|
|
|
(t*t*t - T(2)*t*t + t)*a.outTangent() +
|
|
|
|
|
(T(-2)*t*t*t + T(3)*t*t)*b.point() +
|
|
|
|
|
(t*t*t - t*t)*b.inTangent()).normalized();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @relatesalso CubicHermite
|
|
|
|
|
@brief Spline interpolation of two cubic Hermite quaternions
|
|
|
|
|
|
|
|
|
|
Unlike @ref splerp(const CubicHermite<T>&, const CubicHermite<T>&, U) this adds
|
|
|
|
|
a normalization step after. Given segment points @f$ \boldsymbol{p}_i @f$,
|
|
|
|
|
in-tangents @f$ \boldsymbol{m}_i @f$ and out-tangents @f$ \boldsymbol{n}_i @f$,
|
|
|
|
|
the interpolated value @f$ \boldsymbol{p} @f$ at phase @f$ t @f$ is: @f[
|
|
|
|
|
\begin{array}{rcl}
|
|
|
|
|
\boldsymbol{p'}(t) & = & (2 t^3 - 3 t^2 + 1) \boldsymbol{p}_a + (t^3 - 2 t^2 + t) \boldsymbol{n}_a + (-2 t^3 + 3 t^2) \boldsymbol{p}_b + (t^3 - t^2)\boldsymbol{m}_b \\
|
|
|
|
|
\boldsymbol{p}(t) & = & \cfrac{\boldsymbol{p'}(t)}{|\boldsymbol{p'}(t)|}
|
|
|
|
|
\end{array}
|
|
|
|
|
@f]
|
|
|
|
|
|
|
|
|
|
Expects that @ref CubicHermite::point() is a normalized quaternion in both @p a
|
|
|
|
|
and @p b.
|
|
|
|
|
@see @ref Quaternion::isNormalized(),
|
|
|
|
|
@ref splerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T),
|
|
|
|
|
@ref select(const CubicHermite<T>&, const CubicHermite<T>&, U),
|
|
|
|
|
@ref lerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T),
|
|
|
|
|
@ref slerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T)
|
|
|
|
|
*/
|
|
|
|
|
template<class T> Quaternion<T> splerp(const CubicHermiteQuaternion<T>& a, const CubicHermiteQuaternion<T>& b, T t) {
|
|
|
|
|
CORRADE_ASSERT(a.point().isNormalized() && b.point().isNormalized(),
|
|
|
|
|
"Math::splerp(): quaternion spline points" << a.point() << "and" << b.point() << "are not normalized", {});
|
|
|
|
|
return ((T(2)*t*t*t - T(3)*t*t + T(1))*a.point() +
|
|
|
|
|
(t*t*t - T(2)*t*t + t)*a.outTangent() +
|
|
|
|
|
(T(-2)*t*t*t + T(3)*t*t)*b.point() +
|
|
|
|
|
(t*t*t - t*t)*b.inTangent()).normalized();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class T> inline bool CubicHermite<T>::operator==(const CubicHermite<T>& other) const {
|
|
|
|
|
/* For non-scalar types default implementation of TypeTraits would be used,
|
|
|
|
|
which is just operator== */
|
|
|
|
|
return TypeTraits<T>::equals(_inTangent, other._inTangent) &&
|
|
|
|
|
TypeTraits<T>::equals(_point, other._point) &&
|
|
|
|
|
TypeTraits<T>::equals(_outTangent, other._outTangent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace Implementation {
|
|
|
|
|
|
|
|
|
|
template<class T> struct StrictWeakOrdering<CubicHermite<T>> {
|
|
|
|
|
bool operator()(const CubicHermite<T>& a, const CubicHermite<T>& b) const {
|
|
|
|
|
StrictWeakOrdering<T> o;
|
|
|
|
|
if(o(a.inTangent(), b.inTangent()))
|
|
|
|
|
return true;
|
|
|
|
|
if(o(b.inTangent(), a.inTangent()))
|
|
|
|
|
return false;
|
|
|
|
|
if(o(a.point(), b.point()))
|
|
|
|
|
return true;
|
|
|
|
|
if(o(b.point(), a.point()))
|
|
|
|
|
return false;
|
|
|
|
|
return o(a.outTangent(), b.outTangent());
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
#endif
|