Spline.h
Go to the documentation of this file.
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 20010-2011 Hauke Heibel <hauke.heibel@gmail.com>
5 //
6 // This Source Code Form is subject to the terms of the Mozilla
7 // Public License v. 2.0. If a copy of the MPL was not distributed
8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 
10 #ifndef EIGEN_SPLINE_H
11 #define EIGEN_SPLINE_H
12 
13 // IWYU pragma: private
14 #include "./InternalHeaderCheck.h"
15 
16 #include "SplineFwd.h"
17 
18 namespace Eigen {
36 template <typename Scalar_, int Dim_, int Degree_>
37 class Spline {
38  public:
39  typedef Scalar_ Scalar;
40  enum { Dimension = Dim_ };
41  enum { Degree = Degree_ };
42 
45 
48 
51 
54 
57 
60 
66  : m_knots(1, (Degree == Dynamic ? 2 : 2 * Degree + 2)),
68  // in theory this code can go to the initializer list but it will get pretty
69  // much unreadable ...
70  enum { MinDegree = (Degree == Dynamic ? 0 : Degree) };
71  m_knots.template segment<MinDegree + 1>(0) = Array<Scalar, 1, MinDegree + 1>::Zero();
72  m_knots.template segment<MinDegree + 1>(MinDegree + 1) = Array<Scalar, 1, MinDegree + 1>::Ones();
73  }
74 
80  template <typename OtherVectorType, typename OtherArrayType>
81  Spline(const OtherVectorType& knots, const OtherArrayType& ctrls) : m_knots(knots), m_ctrls(ctrls) {}
82 
87  template <int OtherDegree>
88  Spline(const Spline<Scalar, Dimension, OtherDegree>& spline) : m_knots(spline.knots()), m_ctrls(spline.ctrls()) {}
89 
93  const KnotVectorType& knots() const { return m_knots; }
94 
98  const ControlPointVectorType& ctrls() const { return m_ctrls; }
99 
111  PointType operator()(Scalar u) const;
112 
126 
132  template <int DerivativeOrder>
134  DenseIndex order = DerivativeOrder) const;
135 
153 
168 
174  template <int DerivativeOrder>
176  Scalar u, DenseIndex order = DerivativeOrder) const;
177 
181  DenseIndex degree() const;
182 
187  DenseIndex span(Scalar u) const;
188 
194 
208 
215  const KnotVectorType& knots);
216 
217  private:
221  template <typename DerivativeType>
223  const DenseIndex order, const DenseIndex p,
225  DerivativeType& N_);
226 };
227 
228 template <typename Scalar_, int Dim_, int Degree_>
232  // Piegl & Tiller, "The NURBS Book", A2.1 (p. 68)
233  if (u <= knots(0)) return degree;
234  const Scalar* pos = std::upper_bound(knots.data() + degree - 1, knots.data() + knots.size() - degree - 1, u);
235  return static_cast<DenseIndex>(std::distance(knots.data(), pos) - 1);
236 }
237 
238 template <typename Scalar_, int Dim_, int Degree_>
241  const typename Spline<Scalar_, Dim_, Degree_>::KnotVectorType& knots) {
242  const DenseIndex p = degree;
243  const DenseIndex i = Spline::Span(u, degree, knots);
244 
245  const KnotVectorType& U = knots;
246 
247  BasisVectorType left(p + 1);
248  left(0) = Scalar(0);
249  BasisVectorType right(p + 1);
250  right(0) = Scalar(0);
251 
253  u - VectorBlock<const KnotVectorType, Degree>(U, i + 1 - p, p).reverse();
255 
256  BasisVectorType N(1, p + 1);
257  N(0) = Scalar(1);
258  for (DenseIndex j = 1; j <= p; ++j) {
259  Scalar saved = Scalar(0);
260  for (DenseIndex r = 0; r < j; r++) {
261  const Scalar tmp = N(r) / (right(r + 1) + left(j - r));
262  N[r] = saved + right(r + 1) * tmp;
263  saved = left(j - r) * tmp;
264  }
265  N(j) = saved;
266  }
267  return N;
268 }
269 
270 template <typename Scalar_, int Dim_, int Degree_>
272  if (Degree_ == Dynamic)
273  return m_knots.size() - m_ctrls.cols() - 1;
274  else
275  return Degree_;
276 }
277 
278 template <typename Scalar_, int Dim_, int Degree_>
280  return Spline::Span(u, degree(), knots());
281 }
282 
283 template <typename Scalar_, int Dim_, int Degree_>
286 
287  const DenseIndex span = this->span(u);
288  const DenseIndex p = degree();
289  const BasisVectorType basis_funcs = basisFunctions(u);
290 
291  const Replicate<BasisVectorType, Dimension, 1> ctrl_weights(basis_funcs);
292  const Block<const ControlPointVectorType, Dimension, Order> ctrl_pts(ctrls(), 0, span - p, Dimension, p + 1);
293  return (ctrl_weights * ctrl_pts).rowwise().sum();
294 }
295 
296 /* --------------------------------------------------------------------------------------------- */
297 
298 template <typename SplineType, typename DerivativeType>
299 void derivativesImpl(const SplineType& spline, typename SplineType::Scalar u, DenseIndex order, DerivativeType& der) {
300  enum { Dimension = SplineTraits<SplineType>::Dimension };
302  enum { DerivativeOrder = DerivativeType::ColsAtCompileTime };
303 
304  typedef typename SplineTraits<SplineType>::ControlPointVectorType ControlPointVectorType;
305  typedef typename SplineTraits<SplineType, DerivativeOrder>::BasisDerivativeType BasisDerivativeType;
306  typedef typename BasisDerivativeType::ConstRowXpr BasisDerivativeRowXpr;
307 
308  const DenseIndex p = spline.degree();
309  const DenseIndex span = spline.span(u);
310 
311  const DenseIndex n = (std::min)(p, order);
312 
313  der.resize(Dimension, n + 1);
314 
315  // Retrieve the basis function derivatives up to the desired order...
316  const BasisDerivativeType basis_func_ders = spline.template basisFunctionDerivatives<DerivativeOrder>(u, n + 1);
317 
318  // ... and perform the linear combinations of the control points.
319  for (DenseIndex der_order = 0; der_order < n + 1; ++der_order) {
320  const Replicate<BasisDerivativeRowXpr, Dimension, 1> ctrl_weights(basis_func_ders.row(der_order));
321  const Block<const ControlPointVectorType, Dimension, Order> ctrl_pts(spline.ctrls(), 0, span - p, Dimension, p + 1);
322  der.col(der_order) = (ctrl_weights * ctrl_pts).rowwise().sum();
323  }
324 }
325 
326 template <typename Scalar_, int Dim_, int Degree_>
328  Scalar u, DenseIndex order) const {
330  derivativesImpl(*this, u, order, res);
331  return res;
332 }
333 
334 template <typename Scalar_, int Dim_, int Degree_>
335 template <int DerivativeOrder>
336 typename SplineTraits<Spline<Scalar_, Dim_, Degree_>, DerivativeOrder>::DerivativeType
339  derivativesImpl(*this, u, order, res);
340  return res;
341 }
342 
343 template <typename Scalar_, int Dim_, int Degree_>
345  Scalar u) const {
346  return Spline::BasisFunctions(u, degree(), knots());
347 }
348 
349 /* --------------------------------------------------------------------------------------------- */
350 
351 template <typename Scalar_, int Dim_, int Degree_>
352 template <typename DerivativeType>
354  const typename Spline<Scalar_, Dim_, Degree_>::Scalar u, const DenseIndex order, const DenseIndex p,
355  const typename Spline<Scalar_, Dim_, Degree_>::KnotVectorType& U, DerivativeType& N_) {
356  typedef Spline<Scalar_, Dim_, Degree_> SplineType;
358 
359  const DenseIndex span = SplineType::Span(u, p, U);
360 
361  const DenseIndex n = (std::min)(p, order);
362 
363  N_.resize(n + 1, p + 1);
364 
367 
368  Matrix<Scalar, Order, Order> ndu(p + 1, p + 1);
369 
370  Scalar saved, temp; // FIXME These were double instead of Scalar. Was there a reason for that?
371 
372  ndu(0, 0) = 1.0;
373 
374  DenseIndex j;
375  for (j = 1; j <= p; ++j) {
376  left[j] = u - U[span + 1 - j];
377  right[j] = U[span + j] - u;
378  saved = 0.0;
379 
380  for (DenseIndex r = 0; r < j; ++r) {
381  /* Lower triangle */
382  ndu(j, r) = right[r + 1] + left[j - r];
383  temp = ndu(r, j - 1) / ndu(j, r);
384  /* Upper triangle */
385  ndu(r, j) = static_cast<Scalar>(saved + right[r + 1] * temp);
386  saved = left[j - r] * temp;
387  }
388 
389  ndu(j, j) = static_cast<Scalar>(saved);
390  }
391 
392  for (j = p; j >= 0; --j) N_(0, j) = ndu(j, p);
393 
394  // Compute the derivatives
395  DerivativeType a(n + 1, p + 1);
396  DenseIndex r = 0;
397  for (; r <= p; ++r) {
398  DenseIndex s1, s2;
399  s1 = 0;
400  s2 = 1; // alternate rows in array a
401  a(0, 0) = 1.0;
402 
403  // Compute the k-th derivative
404  for (DenseIndex k = 1; k <= static_cast<DenseIndex>(n); ++k) {
405  Scalar d = 0.0;
406  DenseIndex rk, pk, j1, j2;
407  rk = r - k;
408  pk = p - k;
409 
410  if (r >= k) {
411  a(s2, 0) = a(s1, 0) / ndu(pk + 1, rk);
412  d = a(s2, 0) * ndu(rk, pk);
413  }
414 
415  if (rk >= -1)
416  j1 = 1;
417  else
418  j1 = -rk;
419 
420  if (r - 1 <= pk)
421  j2 = k - 1;
422  else
423  j2 = p - r;
424 
425  for (j = j1; j <= j2; ++j) {
426  a(s2, j) = (a(s1, j) - a(s1, j - 1)) / ndu(pk + 1, rk + j);
427  d += a(s2, j) * ndu(rk + j, pk);
428  }
429 
430  if (r <= pk) {
431  a(s2, k) = -a(s1, k - 1) / ndu(pk + 1, r);
432  d += a(s2, k) * ndu(r, pk);
433  }
434 
435  N_(k, r) = static_cast<Scalar>(d);
436  j = s1;
437  s1 = s2;
438  s2 = j; // Switch rows
439  }
440  }
441 
442  /* Multiply through by the correct factors */
443  /* (Eq. [2.9]) */
444  r = p;
445  for (DenseIndex k = 1; k <= static_cast<DenseIndex>(n); ++k) {
446  for (j = p; j >= 0; --j) N_(k, j) *= r;
447  r *= p - k;
448  }
449 }
450 
451 template <typename Scalar_, int Dim_, int Degree_>
452 typename SplineTraits<Spline<Scalar_, Dim_, Degree_> >::BasisDerivativeType
455  BasisFunctionDerivativesImpl(u, order, degree(), knots(), der);
456  return der;
457 }
458 
459 template <typename Scalar_, int Dim_, int Degree_>
460 template <int DerivativeOrder>
461 typename SplineTraits<Spline<Scalar_, Dim_, Degree_>, DerivativeOrder>::BasisDerivativeType
463  typename SplineTraits<Spline<Scalar_, Dim_, Degree_>, DerivativeOrder>::BasisDerivativeType der;
464  BasisFunctionDerivativesImpl(u, order, degree(), knots(), der);
465  return der;
466 }
467 
468 template <typename Scalar_, int Dim_, int Degree_>
469 typename SplineTraits<Spline<Scalar_, Dim_, Degree_> >::BasisDerivativeType
471  const typename Spline<Scalar_, Dim_, Degree_>::Scalar u, const DenseIndex order, const DenseIndex degree,
472  const typename Spline<Scalar_, Dim_, Degree_>::KnotVectorType& knots) {
474  BasisFunctionDerivativesImpl(u, order, degree, knots, der);
475  return der;
476 }
477 } // namespace Eigen
478 
479 #endif // EIGEN_SPLINE_H
int i
Definition: BiCGSTAB_step_by_step.cpp:9
const unsigned n
Definition: CG3DPackingUnitTest.cpp:11
cout<< "Here is the matrix m:"<< endl<< m<< endl;Matrix< ptrdiff_t, 3, 1 > res
Definition: PartialRedux_count.cpp:3
float * p
Definition: Tutorial_Map_using.cpp:9
SCALAR Scalar
Definition: bench_gemm.cpp:45
General-purpose arrays with easy API for coefficient-wise operations.
Definition: Array.h:48
Expression of a fixed-size or dynamic-size block.
Definition: Block.h:110
The matrix class, also used for vectors and row-vectors.
Definition: Eigen/Eigen/src/Core/Matrix.h:186
Expression of the multiple replication of a matrix or vector.
Definition: Replicate.h:64
A class representing multi-dimensional spline curves.
Definition: Spline.h:37
Spline(const OtherVectorType &knots, const OtherArrayType &ctrls)
Creates a spline from a knot vector and control points.
Definition: Spline.h:81
@ Degree
Definition: Spline.h:41
DenseIndex degree() const
Returns the spline degree.
Definition: Spline.h:271
SplineTraits< Spline >::DerivativeType derivatives(Scalar u, DenseIndex order) const
Evaluation of spline derivatives of up-to given order.
Definition: Spline.h:327
PointType operator()(Scalar u) const
Returns the spline value at a given site .
Definition: Spline.h:284
SplineTraits< Spline, DerivativeOrder >::DerivativeType derivatives(Scalar u, DenseIndex order=DerivativeOrder) const
Evaluation of spline derivatives of up-to given order.
KnotVectorType m_knots
Definition: Spline.h:218
static void BasisFunctionDerivativesImpl(const typename Spline< Scalar_, Dim_, Degree_ >::Scalar u, const DenseIndex order, const DenseIndex p, const typename Spline< Scalar_, Dim_, Degree_ >::KnotVectorType &U, DerivativeType &N_)
Definition: Spline.h:353
SplineTraits< Spline >::ParameterVectorType ParameterVectorType
The data type used to store parameter vectors.
Definition: Spline.h:50
SplineTraits< Spline >::BasisDerivativeType basisFunctionDerivatives(Scalar u, DenseIndex order) const
Computes the non-zero spline basis function derivatives up to given order.
Definition: Spline.h:453
const ControlPointVectorType & ctrls() const
Returns the ctrls of the underlying spline.
Definition: Spline.h:98
Spline(const Spline< Scalar, Dimension, OtherDegree > &spline)
Copy constructor for splines.
Definition: Spline.h:88
static DenseIndex Span(typename SplineTraits< Spline >::Scalar u, DenseIndex degree, const typename SplineTraits< Spline >::KnotVectorType &knots)
Computes the span within the provided knot vector in which u is falling.
Definition: Spline.h:229
SplineTraits< Spline >::KnotVectorType KnotVectorType
The data type used to store knot vectors.
Definition: Spline.h:47
SplineTraits< Spline >::ControlPointVectorType ControlPointVectorType
The data type representing the spline's control points.
Definition: Spline.h:59
@ Dimension
Definition: Spline.h:40
SplineTraits< Spline, DerivativeOrder >::BasisDerivativeType basisFunctionDerivatives(Scalar u, DenseIndex order=DerivativeOrder) const
Computes the non-zero spline basis function derivatives up to given order.
DenseIndex span(Scalar u) const
Returns the span within the knot vector in which u is falling.
Definition: Spline.h:279
Spline()
Creates a (constant) zero spline. For Splines with dynamic degree, the resulting degree will be 0.
Definition: Spline.h:65
SplineTraits< Spline >::PointType PointType
The point type the spline is representing.
Definition: Spline.h:44
SplineTraits< Spline >::BasisVectorType BasisVectorType
The data type used to store non-zero basis functions.
Definition: Spline.h:53
SplineTraits< Spline >::BasisDerivativeType BasisDerivativeType
The data type used to store the values of the basis function derivatives.
Definition: Spline.h:56
static BasisDerivativeType BasisFunctionDerivatives(const Scalar u, const DenseIndex order, const DenseIndex degree, const KnotVectorType &knots)
Computes the non-zero spline basis function derivatives up to given order.
Definition: Spline.h:470
static BasisVectorType BasisFunctions(Scalar u, DenseIndex degree, const KnotVectorType &knots)
Returns the spline's non-zero basis functions.
Definition: Spline.h:239
Scalar_ Scalar
Definition: Spline.h:39
const KnotVectorType & knots() const
Returns the knots of the underlying spline.
Definition: Spline.h:93
ControlPointVectorType m_ctrls
Definition: Spline.h:219
SplineTraits< Spline >::BasisVectorType basisFunctions(Scalar u) const
Computes the non-zero basis functions at the given site.
Definition: Spline.h:344
Expression of a fixed-size or dynamic-size sub-vector.
Definition: VectorBlock.h:58
@ N
Definition: constructor.cpp:22
#define min(a, b)
Definition: datatypes.h:22
const Scalar * a
Definition: level2_cplx_impl.h:32
char char char int int * k
Definition: level2_impl.h:374
Eigen::Matrix< Scalar, Dynamic, Dynamic, ColMajor > tmp
Definition: level3_impl.h:365
Namespace containing all symbols from the Eigen library.
Definition: bench_norm.cpp:70
EIGEN_DEFAULT_DENSE_INDEX_TYPE DenseIndex
Definition: Meta.h:75
const int Dynamic
Definition: Constants.h:25
void derivativesImpl(const SplineType &spline, typename SplineType::Scalar u, DenseIndex order, DerivativeType &der)
Definition: Spline.h:299
double U
Swimming speed.
Definition: two_d_variable_diff_adapt.cc:53
r
Definition: UniformPSDSelfTest.py:20
const Mdouble degree
Definition: ExtendedMath.h:32
double Zero
Definition: pseudosolid_node_update_elements.cc:35
Definition: SplineFwd.h:22
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2