Browse Source

Math: use the leaf Vector2/3/4 types in Bezier.

Same as what Range does, so accessing them doesn't lead to weird
surprises with e.g. `.x()` missing.

Which means I can also HOPEFULLY remove that old MSVC ICE workaround
from the tests.
pull/168/merge
Vladimír Vondruš 2 years ago
parent
commit
86e7dd51f3
  1. 48
      src/Magnum/Math/Bezier.h
  2. 10
      src/Magnum/Math/Test/BezierTest.cpp

48
src/Magnum/Math/Bezier.h

@ -44,6 +44,18 @@
namespace Magnum { namespace Math {
namespace Implementation {
/* Compared to traits in Range.h it handles also arbitrary other dimension
count */
template<UnsignedInt dimensions, class T> struct BezierTraits {
typedef T Type;
};
template<class T> struct BezierTraits<2, T> {
typedef Vector2<T> Type;
};
template<class T> struct BezierTraits<3, T> {
typedef Vector3<T> Type;
};
template<UnsignedInt, UnsignedInt, class, class> struct BezierConverter;
}
@ -70,6 +82,15 @@ template<UnsignedInt order, UnsignedInt dimensions, class T> class Bezier {
public:
typedef T Type; /**< @brief Underlying data type */
/**
* @brief Underlying vector type
* @m_since_latest
*
* @cpp T @ce in 1D, @ref Math::Vector2 "Vector2<T>" in 2D,
* @ref Math::Vector3 "Vector3<T>" in 3D.
*/
typedef typename Implementation::BezierTraits<dimensions, T>::Type VectorType;
enum: UnsignedInt {
Order = order, /**< Order of Bézier curve */
Dimensions = dimensions /**< Dimensions of control points */
@ -96,11 +117,10 @@ template<UnsignedInt order, UnsignedInt dimensions, class T> class Bezier {
* underlying types. See @ref CubicHermite::fromBezier() for the
* inverse operation.
*/
template<class VectorType> static
#ifndef DOXYGEN_GENERATING_OUTPUT
typename std::enable_if<std::is_base_of<Vector<dimensions, T>, VectorType>::value && order == 3, Bezier<order, dimensions, T>>::type
template<UnsignedInt order_ = order> static typename std::enable_if<order_ == 3, Bezier<order, dimensions, T>>::type
#else
Bezier<order, dimensions, T>
static Bezier<order, dimensions, T>
#endif
fromCubicHermite(const CubicHermite<VectorType>& a, const CubicHermite<VectorType>& b) {
return {a.point(), a.outTangent()/T(3) - a.point(), b.point() - b.inTangent()/T(3), b.point()};
@ -124,7 +144,7 @@ template<UnsignedInt order, UnsignedInt dimensions, class T> class Bezier {
explicit Bezier(Magnum::NoInitT) noexcept: Bezier<order, dimensions, T>{typename Containers::Implementation::GenerateSequence<order + 1>::Type{}, Magnum::NoInit} {}
/** @brief Construct a Bézier curve with given array of control points */
template<typename... U> constexpr /*implicit*/ Bezier(const Vector<dimensions, T>& first, U... next) noexcept: _data{first, next...} {
template<typename... U> constexpr /*implicit*/ Bezier(const VectorType& first, U... next) noexcept: _data{first, next...} {
static_assert(sizeof...(U) + 1 == order + 1, "Wrong number of arguments");
}
@ -155,11 +175,11 @@ template<UnsignedInt order, UnsignedInt dimensions, class T> class Bezier {
* post-processing step (https://github.com/mosra/m.css/issues/56)
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<dimensions, T>* data();
constexpr const Vector<dimensions, T>* data() const; /**< @overload */
VectorType* data();
constexpr const VectorType* data() const; /**< @overload */
#else
auto data() -> Vector<dimensions, T>(&)[order + 1] { return _data; }
constexpr auto data() const -> const Vector<dimensions, T>(&)[order + 1] { return _data; }
auto data() -> VectorType(&)[order + 1] { return _data; }
constexpr auto data() const -> const VectorType(&)[order + 1] { return _data; }
#endif
/** @brief Equality comparison */
@ -179,9 +199,9 @@ template<UnsignedInt order, UnsignedInt dimensions, class T> class Bezier {
*
* @p i should not be larger than @ref Order.
*/
Vector<dimensions, T>& operator[](std::size_t i) { return _data[i]; }
VectorType& operator[](std::size_t i) { return _data[i]; }
/* returns const& so [][] operations are also constexpr */
constexpr const Vector<dimensions, T>& operator[](std::size_t i) const { return _data[i]; } /**< @overload */
constexpr const VectorType& operator[](std::size_t i) const { return _data[i]; } /**< @overload */
/**
* @brief Interpolate the curve at given position
@ -190,7 +210,7 @@ template<UnsignedInt order, UnsignedInt dimensions, class T> class Bezier {
* the [De Casteljau's algorithm](https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm).
* @see @ref subdivide()
*/
Vector<dimensions, T> value(T t) const {
VectorType value(T t) const {
Bezier<order, dimensions, T> iPoints[order + 1];
calculateIntermediatePoints(iPoints, t);
return iPoints[0][order];
@ -216,11 +236,11 @@ template<UnsignedInt order, UnsignedInt dimensions, class T> class Bezier {
private:
/* Implementation for Bezier<order, dimensions, T>::Bezier(const Bezier<order, dimensions, U>&) */
template<class U, std::size_t ...sequence> constexpr explicit Bezier(Containers::Implementation::Sequence<sequence...>, const Bezier<order, dimensions, U>& other) noexcept: _data{Vector<dimensions, T>(other._data[sequence])...} {}
template<class U, std::size_t ...sequence> constexpr explicit Bezier(Containers::Implementation::Sequence<sequence...>, const Bezier<order, dimensions, U>& other) noexcept: _data{VectorType(other._data[sequence])...} {}
/* Implementation for Bezier<order, dimensions, T>::Bezier(ZeroInitT) and Bezier<order, dimensions, T>::Bezier(NoInitT) */
/* MSVC 2015 can't handle {} here */
template<class U, std::size_t ...sequence> constexpr explicit Bezier(Containers::Implementation::Sequence<sequence...>, U): _data{Vector<dimensions, T>((static_cast<void>(sequence), U{typename U::Init{}}))...} {}
template<class U, std::size_t ...sequence> constexpr explicit Bezier(Containers::Implementation::Sequence<sequence...>, U): _data{VectorType{U{(static_cast<void>(sequence), typename U::Init{})}}...} {}
/* Calculates and returns all intermediate points generated when using De Casteljau's algorithm */
void calculateIntermediatePoints(Bezier<order, dimensions, T>(&iPoints)[order + 1], T t) const {
@ -234,7 +254,7 @@ template<UnsignedInt order, UnsignedInt dimensions, class T> class Bezier {
}
}
Vector<dimensions, T> _data[order + 1];
VectorType _data[order + 1];
};
/**

10
src/Magnum/Math/Test/BezierTest.cpp

@ -157,12 +157,7 @@ void BezierTest::constructNoInit() {
}
void BezierTest::constructConversion() {
#ifndef CORRADE_MSVC2017_COMPATIBILITY
constexpr QuadraticBezier2Dd a{Vector2d{0.5, 1.0}, Vector2d{1.1, 0.3}, Vector2d{0.1, 1.2}};
#else
/* https://developercommunity.visualstudio.com/content/problem/259204/1572-regression-ice-in-constexpr-code-involving-de.html */
constexpr QuadraticBezier2Dd a{Vector<2, Double>{0.5, 1.0}, Vector<2, Double>{1.1, 0.3}, Vector<2, Double>{0.1, 1.2}};
#endif
constexpr QuadraticBezier2D b{a};
CORRADE_COMPARE(b, (QuadraticBezier2D{Vector2{0.5f, 1.0f}, Vector2{1.1f, 0.3f}, Vector2{0.1f, 1.2f}}));
@ -198,12 +193,7 @@ void BezierTest::constructCopy() {
void BezierTest::convert() {
constexpr QBezier2D a{0.5f, 1.1f, 0.1f, 1.0f, 0.3f, 1.2f};
#ifndef CORRADE_MSVC2017_COMPATIBILITY
constexpr QuadraticBezier2D b{Vector2{0.5f, 1.0f}, Vector2{1.1f, 0.3f}, Vector2{0.1f, 1.2f}};
#else
/* https://developercommunity.visualstudio.com/content/problem/259204/1572-regression-ice-in-constexpr-code-involving-de.html */
constexpr QuadraticBezier2D b{Vector<2, Float>{0.5f, 1.0f}, Vector<2, Float>{1.1f, 0.3f}, Vector<2, Float>{0.1f, 1.2f}};
#endif
constexpr QuadraticBezier2D c{a};
CORRADE_COMPARE(c, b);

Loading…
Cancel
Save