Eigen-Contrib  5.0.1
 
Loading...
Searching...
No Matches
Spline.h
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// SPDX-License-Identifier: MPL-2.0
10
11#ifndef EIGEN_SPLINE_H
12#define EIGEN_SPLINE_H
13
14// IWYU pragma: private
15#include "./InternalHeaderCheck.h"
16
17#include "SplineFwd.h"
18
19namespace Eigen {
43template <typename Scalar_, int Dim_, int Degree_>
44class Spline {
45 public:
46 typedef Scalar_ Scalar;
47 enum { Dimension = Dim_ };
48 enum { Degree = Degree_ };
49
51 typedef typename SplineTraits<Spline>::PointType PointType;
52
54 typedef typename SplineTraits<Spline>::KnotVectorType KnotVectorType;
55
57 typedef typename SplineTraits<Spline>::ParameterVectorType ParameterVectorType;
58
60 typedef typename SplineTraits<Spline>::BasisVectorType BasisVectorType;
61
63 typedef typename SplineTraits<Spline>::BasisDerivativeType BasisDerivativeType;
64
66 typedef typename SplineTraits<Spline>::ControlPointVectorType ControlPointVectorType;
67
73 : m_knots(1, (Degree == Dynamic ? 2 : 2 * Degree + 2)),
74 m_ctrls(ControlPointVectorType::Zero(Dimension, (Degree == Dynamic ? 1 : Degree + 1))) {
75 // in theory this code can go to the initializer list but it will get pretty
76 // much unreadable ...
77 enum { MinDegree = (Degree == Dynamic ? 0 : Degree) };
78 m_knots.template segment<MinDegree + 1>(0) = Array<Scalar, 1, MinDegree + 1>::Zero();
79 m_knots.template segment<MinDegree + 1>(MinDegree + 1) = Array<Scalar, 1, MinDegree + 1>::Ones();
80 }
81
87 template <typename OtherVectorType, typename OtherArrayType>
88 Spline(const OtherVectorType& knots, const OtherArrayType& ctrls) : m_knots(knots), m_ctrls(ctrls) {}
89
94 template <int OtherDegree>
95 Spline(const Spline<Scalar, Dimension, OtherDegree>& spline) : m_knots(spline.knots()), m_ctrls(spline.ctrls()) {}
96
100 const KnotVectorType& knots() const { return m_knots; }
101
105 const ControlPointVectorType& ctrls() const { return m_ctrls; }
106
119
132 typename SplineTraits<Spline>::DerivativeType derivatives(Scalar u, DenseIndex order) const;
133
139 template <int DerivativeOrder>
140 typename SplineTraits<Spline, DerivativeOrder>::DerivativeType derivatives(Scalar u,
141 DenseIndex order = DerivativeOrder) const;
142
159 typename SplineTraits<Spline>::BasisVectorType basisFunctions(Scalar u) const;
160
174 typename SplineTraits<Spline>::BasisDerivativeType basisFunctionDerivatives(Scalar u, DenseIndex order) const;
175
181 template <int DerivativeOrder>
182 typename SplineTraits<Spline, DerivativeOrder>::BasisDerivativeType basisFunctionDerivatives(
183 Scalar u, DenseIndex order = DerivativeOrder) const;
184
188 DenseIndex degree() const;
189
194 DenseIndex span(Scalar u) const;
195
199 static DenseIndex Span(typename SplineTraits<Spline>::Scalar u, DenseIndex degree,
200 const typename SplineTraits<Spline>::KnotVectorType& knots);
201
215
221 static BasisDerivativeType BasisFunctionDerivatives(const Scalar u, const DenseIndex order, const DenseIndex degree,
222 const KnotVectorType& knots);
223
224 private:
225 KnotVectorType m_knots;
226 ControlPointVectorType m_ctrls;
227
228 template <typename DerivativeType>
229 static void BasisFunctionDerivativesImpl(const typename Spline<Scalar_, Dim_, Degree_>::Scalar u,
230 const DenseIndex order, const DenseIndex p,
232 DerivativeType& N_);
233};
234
235template <typename Scalar_, int Dim_, int Degree_>
237 typename SplineTraits<Spline<Scalar_, Dim_, Degree_> >::Scalar u, DenseIndex degree,
238 const typename SplineTraits<Spline<Scalar_, Dim_, Degree_> >::KnotVectorType& knots) {
239 // Piegl & Tiller, "The NURBS Book", A2.1 (p. 68)
240 if (u <= knots(0)) return degree;
241 const Scalar* pos = std::upper_bound(knots.data() + degree - 1, knots.data() + knots.size() - degree - 1, u);
242 return static_cast<DenseIndex>(std::distance(knots.data(), pos) - 1);
243}
244
245template <typename Scalar_, int Dim_, int Degree_>
247 typename Spline<Scalar_, Dim_, Degree_>::Scalar u, DenseIndex degree,
249 const DenseIndex p = degree;
250 const DenseIndex i = Spline::Span(u, degree, knots);
251
252 const KnotVectorType& U = knots;
253
254 BasisVectorType left(p + 1);
255 left(0) = Scalar(0);
256 BasisVectorType right(p + 1);
257 right(0) = Scalar(0);
258
260 u - VectorBlock<const KnotVectorType, Degree>(U, i + 1 - p, p).reverse();
262
263 BasisVectorType N(1, p + 1);
264 N(0) = Scalar(1);
265 for (DenseIndex j = 1; j <= p; ++j) {
266 Scalar saved = Scalar(0);
267 for (DenseIndex r = 0; r < j; r++) {
268 const Scalar tmp = N(r) / (right(r + 1) + left(j - r));
269 N[r] = saved + right(r + 1) * tmp;
270 saved = left(j - r) * tmp;
271 }
272 N(j) = saved;
273 }
274 return N;
275}
276
277template <typename Scalar_, int Dim_, int Degree_>
279 EIGEN_IF_CONSTEXPR (Degree_ == Dynamic)
280 return m_knots.size() - m_ctrls.cols() - 1;
281 else
282 return Degree_;
283}
284
285template <typename Scalar_, int Dim_, int Degree_>
287 return Spline::Span(u, degree(), knots());
288}
289
290template <typename Scalar_, int Dim_, int Degree_>
292 enum { Order = SplineTraits<Spline>::OrderAtCompileTime };
293
294 const DenseIndex span = this->span(u);
295 const DenseIndex p = degree();
296 const BasisVectorType basis_funcs = basisFunctions(u);
297
298 const Replicate<BasisVectorType, Dimension, 1> ctrl_weights(basis_funcs);
300 return (ctrl_weights * ctrl_pts).rowwise().sum();
301}
302
303/* --------------------------------------------------------------------------------------------- */
304
305template <typename SplineType, typename DerivativeType>
306void derivativesImpl(const SplineType& spline, typename SplineType::Scalar u, DenseIndex order, DerivativeType& der) {
307 enum { Dimension = SplineTraits<SplineType>::Dimension };
308 enum { Order = SplineTraits<SplineType>::OrderAtCompileTime };
309 enum { DerivativeOrder = DerivativeType::ColsAtCompileTime };
310
311 typedef typename SplineTraits<SplineType>::ControlPointVectorType ControlPointVectorType;
312 typedef typename SplineTraits<SplineType, DerivativeOrder>::BasisDerivativeType BasisDerivativeType;
313 typedef typename BasisDerivativeType::ConstRowXpr BasisDerivativeRowXpr;
314
315 const DenseIndex p = spline.degree();
316 const DenseIndex span = spline.span(u);
317
318 const DenseIndex n = (std::min)(p, order);
319
320 der.resize(Dimension, n + 1);
321
322 // Retrieve the basis function derivatives up to the desired order...
323 const BasisDerivativeType basis_func_ders = spline.template basisFunctionDerivatives<DerivativeOrder>(u, n + 1);
324
325 // ... and perform the linear combinations of the control points.
326 for (DenseIndex der_order = 0; der_order < n + 1; ++der_order) {
327 const Replicate<BasisDerivativeRowXpr, Dimension, 1> ctrl_weights(basis_func_ders.row(der_order));
328 const Block<const ControlPointVectorType, Dimension, Order> ctrl_pts(spline.ctrls(), 0, span - p, Dimension, p + 1);
329 der.col(der_order) = (ctrl_weights * ctrl_pts).rowwise().sum();
330 }
331}
332
333template <typename Scalar_, int Dim_, int Degree_>
334typename SplineTraits<Spline<Scalar_, Dim_, Degree_> >::DerivativeType Spline<Scalar_, Dim_, Degree_>::derivatives(
335 Scalar u, DenseIndex order) const {
336 typename SplineTraits<Spline>::DerivativeType res;
337 derivativesImpl(*this, u, order, res);
338 return res;
339}
340
341template <typename Scalar_, int Dim_, int Degree_>
342template <int DerivativeOrder>
343typename SplineTraits<Spline<Scalar_, Dim_, Degree_>, DerivativeOrder>::DerivativeType
345 typename SplineTraits<Spline, DerivativeOrder>::DerivativeType res;
346 derivativesImpl(*this, u, order, res);
347 return res;
348}
349
350template <typename Scalar_, int Dim_, int Degree_>
351typename SplineTraits<Spline<Scalar_, Dim_, Degree_> >::BasisVectorType Spline<Scalar_, Dim_, Degree_>::basisFunctions(
352 Scalar u) const {
353 return Spline::BasisFunctions(u, degree(), knots());
354}
355
356/* --------------------------------------------------------------------------------------------- */
357
358template <typename Scalar_, int Dim_, int Degree_>
359template <typename DerivativeType>
360void Spline<Scalar_, Dim_, Degree_>::BasisFunctionDerivativesImpl(
361 const typename Spline<Scalar_, Dim_, Degree_>::Scalar u, const DenseIndex order, const DenseIndex p,
362 const typename Spline<Scalar_, Dim_, Degree_>::KnotVectorType& U, DerivativeType& N_) {
363 typedef Spline<Scalar_, Dim_, Degree_> SplineType;
364 enum { Order = SplineTraits<SplineType>::OrderAtCompileTime };
365
366 const DenseIndex span = SplineType::Span(u, p, U);
367
368 const DenseIndex n = (std::min)(p, order);
369
370 N_.resize(n + 1, p + 1);
371
372 BasisVectorType left = BasisVectorType::Zero(p + 1);
373 BasisVectorType right = BasisVectorType::Zero(p + 1);
374
375 Matrix<Scalar, Order, Order> ndu(p + 1, p + 1);
376
377 Scalar saved, temp; // FIXME: These were double instead of Scalar. Was there a reason for that?
378
379 ndu(0, 0) = 1.0;
380
381 DenseIndex j;
382 for (j = 1; j <= p; ++j) {
383 left[j] = u - U[span + 1 - j];
384 right[j] = U[span + j] - u;
385 saved = 0.0;
386
387 for (DenseIndex r = 0; r < j; ++r) {
388 /* Lower triangle */
389 ndu(j, r) = right[r + 1] + left[j - r];
390 temp = ndu(r, j - 1) / ndu(j, r);
391 /* Upper triangle */
392 ndu(r, j) = static_cast<Scalar>(saved + right[r + 1] * temp);
393 saved = left[j - r] * temp;
394 }
395
396 ndu(j, j) = static_cast<Scalar>(saved);
397 }
398
399 for (j = p; j >= 0; --j) N_(0, j) = ndu(j, p);
400
401 // Compute the derivatives
402 DerivativeType a(n + 1, p + 1);
403 DenseIndex r = 0;
404 for (; r <= p; ++r) {
405 DenseIndex s1, s2;
406 s1 = 0;
407 s2 = 1; // alternate rows in array a
408 a(0, 0) = 1.0;
409
410 // Compute the k-th derivative
411 for (DenseIndex k = 1; k <= static_cast<DenseIndex>(n); ++k) {
412 Scalar d = 0.0;
413 DenseIndex rk, pk, j1, j2;
414 rk = r - k;
415 pk = p - k;
416
417 if (r >= k) {
418 a(s2, 0) = a(s1, 0) / ndu(pk + 1, rk);
419 d = a(s2, 0) * ndu(rk, pk);
420 }
421
422 if (rk >= -1)
423 j1 = 1;
424 else
425 j1 = -rk;
426
427 if (r - 1 <= pk)
428 j2 = k - 1;
429 else
430 j2 = p - r;
431
432 for (j = j1; j <= j2; ++j) {
433 a(s2, j) = (a(s1, j) - a(s1, j - 1)) / ndu(pk + 1, rk + j);
434 d += a(s2, j) * ndu(rk + j, pk);
435 }
436
437 if (r <= pk) {
438 a(s2, k) = -a(s1, k - 1) / ndu(pk + 1, r);
439 d += a(s2, k) * ndu(r, pk);
440 }
441
442 N_(k, r) = static_cast<Scalar>(d);
443 j = s1;
444 s1 = s2;
445 s2 = j; // Switch rows
446 }
447 }
448
449 /* Multiply through by the correct factors */
450 /* (Eq. [2.9]) */
451 r = p;
452 for (DenseIndex k = 1; k <= static_cast<DenseIndex>(n); ++k) {
453 for (j = p; j >= 0; --j) N_(k, j) *= r;
454 r *= p - k;
455 }
456}
457
458template <typename Scalar_, int Dim_, int Degree_>
459typename SplineTraits<Spline<Scalar_, Dim_, Degree_> >::BasisDerivativeType
461 typename SplineTraits<Spline<Scalar_, Dim_, Degree_> >::BasisDerivativeType der;
462 BasisFunctionDerivativesImpl(u, order, degree(), knots(), der);
463 return der;
464}
465
466template <typename Scalar_, int Dim_, int Degree_>
467template <int DerivativeOrder>
468typename SplineTraits<Spline<Scalar_, Dim_, Degree_>, DerivativeOrder>::BasisDerivativeType
470 typename SplineTraits<Spline<Scalar_, Dim_, Degree_>, DerivativeOrder>::BasisDerivativeType der;
471 BasisFunctionDerivativesImpl(u, order, degree(), knots(), der);
472 return der;
473}
474
475template <typename Scalar_, int Dim_, int Degree_>
476typename SplineTraits<Spline<Scalar_, Dim_, Degree_> >::BasisDerivativeType
478 const typename Spline<Scalar_, Dim_, Degree_>::Scalar u, const DenseIndex order, const DenseIndex degree,
480 typename SplineTraits<Spline>::BasisDerivativeType der;
481 BasisFunctionDerivativesImpl(u, order, degree, knots, der);
482 return der;
483}
484} // namespace Eigen
485
486#endif // EIGEN_SPLINE_H
A class representing multi-dimensional spline curves.
Definition Spline.h:44
Spline(const OtherVectorType &knots, const OtherArrayType &ctrls)
Creates a spline from a knot vector and control points.
Definition Spline.h:88
DenseIndex degree() const
Returns the spline degree.
Definition Spline.h:278
PointType operator()(Scalar u) const
Returns the spline value at a given site .
Definition Spline.h:291
@ Degree
Definition Spline.h:48
const KnotVectorType & knots() const
Definition Spline.h:100
SplineTraits< Spline >::ParameterVectorType ParameterVectorType
The data type used to store parameter vectors.
Definition Spline.h:57
SplineTraits< Spline >::BasisDerivativeType basisFunctionDerivatives(Scalar u, DenseIndex order) const
Computes the non-zero spline basis function derivatives up to given order.
Definition Spline.h:460
Spline(const Spline< Scalar, Dimension, OtherDegree > &spline)
Copy constructor for splines.
Definition Spline.h:95
SplineTraits< Spline, DerivativeOrder >::DerivativeType derivatives(Scalar u, DenseIndex order=DerivativeOrder) const
Evaluation of spline derivatives of up-to given order.
Definition Spline.h:344
SplineTraits< Spline, DerivativeOrder >::BasisDerivativeType basisFunctionDerivatives(Scalar u, DenseIndex order=DerivativeOrder) const
Computes the non-zero spline basis function derivatives up to given order.
Definition Spline.h:469
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:236
SplineTraits< Spline >::KnotVectorType KnotVectorType
The data type used to store knot vectors.
Definition Spline.h:54
SplineTraits< Spline >::ControlPointVectorType ControlPointVectorType
The data type representing the spline's control points.
Definition Spline.h:66
@ Dimension
Definition Spline.h:47
DenseIndex span(Scalar u) const
Returns the span within the knot vector in which u is falling.
Definition Spline.h:286
Spline()
Creates a (constant) zero spline. For Splines with dynamic degree, the resulting degree will be 0.
Definition Spline.h:72
SplineTraits< Spline >::PointType PointType
The point type the spline is representing.
Definition Spline.h:51
SplineTraits< Spline >::BasisVectorType BasisVectorType
The data type used to store non-zero basis functions.
Definition Spline.h:60
SplineTraits< Spline >::BasisDerivativeType BasisDerivativeType
The data type used to store the values of the basis function derivatives.
Definition Spline.h:63
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:477
static BasisVectorType BasisFunctions(Scalar u, DenseIndex degree, const KnotVectorType &knots)
Returns the spline's non-zero basis functions.
Definition Spline.h:246
Scalar_ Scalar
Definition Spline.h:46
SplineTraits< Spline >::DerivativeType derivatives(Scalar u, DenseIndex order) const
Evaluation of spline derivatives of up-to given order.
Definition Spline.h:334
SplineTraits< Spline >::BasisVectorType basisFunctions(Scalar u) const
Computes the non-zero basis functions at the given site.
Definition Spline.h:351
const ControlPointVectorType & ctrls() const
Definition Spline.h:105
Namespace containing all symbols from the Eigen library.