00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #ifndef EIGEN_SPLINE_H
00011 #define EIGEN_SPLINE_H
00012
00013 #include "SplineFwd.h"
00014
00015 namespace Eigen
00016 {
00034 template <typename _Scalar, int _Dim, int _Degree>
00035 class Spline
00036 {
00037 public:
00038 typedef _Scalar Scalar;
00039 enum { Dimension = _Dim };
00040 enum { Degree = _Degree };
00041
00043 typedef typename SplineTraits<Spline>::PointType PointType;
00044
00046 typedef typename SplineTraits<Spline>::KnotVectorType KnotVectorType;
00047
00049 typedef typename SplineTraits<Spline>::BasisVectorType BasisVectorType;
00050
00052 typedef typename SplineTraits<Spline>::ControlPointVectorType ControlPointVectorType;
00053
00058 Spline()
00059 : m_knots(1, (Degree==Dynamic ? 2 : 2*Degree+2))
00060 , m_ctrls(ControlPointVectorType::Zero(2,(Degree==Dynamic ? 1 : Degree+1)))
00061 {
00062
00063
00064 enum { MinDegree = (Degree==Dynamic ? 0 : Degree) };
00065 m_knots.template segment<MinDegree+1>(0) = Array<Scalar,1,MinDegree+1>::Zero();
00066 m_knots.template segment<MinDegree+1>(MinDegree+1) = Array<Scalar,1,MinDegree+1>::Ones();
00067 }
00068
00074 template <typename OtherVectorType, typename OtherArrayType>
00075 Spline(const OtherVectorType& knots, const OtherArrayType& ctrls) : m_knots(knots), m_ctrls(ctrls) {}
00076
00081 template <int OtherDegree>
00082 Spline(const Spline<Scalar, Dimension, OtherDegree>& spline) :
00083 m_knots(spline.knots()), m_ctrls(spline.ctrls()) {}
00084
00088 const KnotVectorType& knots() const { return m_knots; }
00089
00093 const ControlPointVectorType& ctrls() const { return m_ctrls; }
00094
00106 PointType operator()(Scalar u) const;
00107
00120 typename SplineTraits<Spline>::DerivativeType
00121 derivatives(Scalar u, DenseIndex order) const;
00122
00128 template <int DerivativeOrder>
00129 typename SplineTraits<Spline,DerivativeOrder>::DerivativeType
00130 derivatives(Scalar u, DenseIndex order = DerivativeOrder) const;
00131
00148 typename SplineTraits<Spline>::BasisVectorType
00149 basisFunctions(Scalar u) const;
00150
00164 typename SplineTraits<Spline>::BasisDerivativeType
00165 basisFunctionDerivatives(Scalar u, DenseIndex order) const;
00166
00172 template <int DerivativeOrder>
00173 typename SplineTraits<Spline,DerivativeOrder>::BasisDerivativeType
00174 basisFunctionDerivatives(Scalar u, DenseIndex order = DerivativeOrder) const;
00175
00179 DenseIndex degree() const;
00180
00185 DenseIndex span(Scalar u) const;
00186
00190 static DenseIndex Span(typename SplineTraits<Spline>::Scalar u, DenseIndex degree, const typename SplineTraits<Spline>::KnotVectorType& knots);
00191
00204 static BasisVectorType BasisFunctions(Scalar u, DenseIndex degree, const KnotVectorType& knots);
00205
00206
00207 private:
00208 KnotVectorType m_knots;
00209 ControlPointVectorType m_ctrls;
00210 };
00211
00212 template <typename _Scalar, int _Dim, int _Degree>
00213 DenseIndex Spline<_Scalar, _Dim, _Degree>::Span(
00214 typename SplineTraits< Spline<_Scalar, _Dim, _Degree> >::Scalar u,
00215 DenseIndex degree,
00216 const typename SplineTraits< Spline<_Scalar, _Dim, _Degree> >::KnotVectorType& knots)
00217 {
00218
00219 if (u <= knots(0)) return degree;
00220 const Scalar* pos = std::upper_bound(knots.data()+degree-1, knots.data()+knots.size()-degree-1, u);
00221 return static_cast<DenseIndex>( std::distance(knots.data(), pos) - 1 );
00222 }
00223
00224 template <typename _Scalar, int _Dim, int _Degree>
00225 typename Spline<_Scalar, _Dim, _Degree>::BasisVectorType
00226 Spline<_Scalar, _Dim, _Degree>::BasisFunctions(
00227 typename Spline<_Scalar, _Dim, _Degree>::Scalar u,
00228 DenseIndex degree,
00229 const typename Spline<_Scalar, _Dim, _Degree>::KnotVectorType& knots)
00230 {
00231 typedef typename Spline<_Scalar, _Dim, _Degree>::BasisVectorType BasisVectorType;
00232
00233 const DenseIndex p = degree;
00234 const DenseIndex i = Spline::Span(u, degree, knots);
00235
00236 const KnotVectorType& U = knots;
00237
00238 BasisVectorType left(p+1); left(0) = Scalar(0);
00239 BasisVectorType right(p+1); right(0) = Scalar(0);
00240
00241 VectorBlock<BasisVectorType,Degree>(left,1,p) = u - VectorBlock<const KnotVectorType,Degree>(U,i+1-p,p).reverse();
00242 VectorBlock<BasisVectorType,Degree>(right,1,p) = VectorBlock<const KnotVectorType,Degree>(U,i+1,p) - u;
00243
00244 BasisVectorType N(1,p+1);
00245 N(0) = Scalar(1);
00246 for (DenseIndex j=1; j<=p; ++j)
00247 {
00248 Scalar saved = Scalar(0);
00249 for (DenseIndex r=0; r<j; r++)
00250 {
00251 const Scalar tmp = N(r)/(right(r+1)+left(j-r));
00252 N[r] = saved + right(r+1)*tmp;
00253 saved = left(j-r)*tmp;
00254 }
00255 N(j) = saved;
00256 }
00257 return N;
00258 }
00259
00260 template <typename _Scalar, int _Dim, int _Degree>
00261 DenseIndex Spline<_Scalar, _Dim, _Degree>::degree() const
00262 {
00263 if (_Degree == Dynamic)
00264 return m_knots.size() - m_ctrls.cols() - 1;
00265 else
00266 return _Degree;
00267 }
00268
00269 template <typename _Scalar, int _Dim, int _Degree>
00270 DenseIndex Spline<_Scalar, _Dim, _Degree>::span(Scalar u) const
00271 {
00272 return Spline::Span(u, degree(), knots());
00273 }
00274
00275 template <typename _Scalar, int _Dim, int _Degree>
00276 typename Spline<_Scalar, _Dim, _Degree>::PointType Spline<_Scalar, _Dim, _Degree>::operator()(Scalar u) const
00277 {
00278 enum { Order = SplineTraits<Spline>::OrderAtCompileTime };
00279
00280 const DenseIndex span = this->span(u);
00281 const DenseIndex p = degree();
00282 const BasisVectorType basis_funcs = basisFunctions(u);
00283
00284 const Replicate<BasisVectorType,Dimension,1> ctrl_weights(basis_funcs);
00285 const Block<const ControlPointVectorType,Dimension,Order> ctrl_pts(ctrls(),0,span-p,Dimension,p+1);
00286 return (ctrl_weights * ctrl_pts).rowwise().sum();
00287 }
00288
00289
00290
00291 template <typename SplineType, typename DerivativeType>
00292 void derivativesImpl(const SplineType& spline, typename SplineType::Scalar u, DenseIndex order, DerivativeType& der)
00293 {
00294 enum { Dimension = SplineTraits<SplineType>::Dimension };
00295 enum { Order = SplineTraits<SplineType>::OrderAtCompileTime };
00296 enum { DerivativeOrder = DerivativeType::ColsAtCompileTime };
00297
00298 typedef typename SplineTraits<SplineType>::ControlPointVectorType ControlPointVectorType;
00299 typedef typename SplineTraits<SplineType,DerivativeOrder>::BasisDerivativeType BasisDerivativeType;
00300 typedef typename BasisDerivativeType::ConstRowXpr BasisDerivativeRowXpr;
00301
00302 const DenseIndex p = spline.degree();
00303 const DenseIndex span = spline.span(u);
00304
00305 const DenseIndex n = (std::min)(p, order);
00306
00307 der.resize(Dimension,n+1);
00308
00309
00310 const BasisDerivativeType basis_func_ders = spline.template basisFunctionDerivatives<DerivativeOrder>(u, n+1);
00311
00312
00313 for (DenseIndex der_order=0; der_order<n+1; ++der_order)
00314 {
00315 const Replicate<BasisDerivativeRowXpr,Dimension,1> ctrl_weights( basis_func_ders.row(der_order) );
00316 const Block<const ControlPointVectorType,Dimension,Order> ctrl_pts(spline.ctrls(),0,span-p,Dimension,p+1);
00317 der.col(der_order) = (ctrl_weights * ctrl_pts).rowwise().sum();
00318 }
00319 }
00320
00321 template <typename _Scalar, int _Dim, int _Degree>
00322 typename SplineTraits< Spline<_Scalar, _Dim, _Degree> >::DerivativeType
00323 Spline<_Scalar, _Dim, _Degree>::derivatives(Scalar u, DenseIndex order) const
00324 {
00325 typename SplineTraits< Spline >::DerivativeType res;
00326 derivativesImpl(*this, u, order, res);
00327 return res;
00328 }
00329
00330 template <typename _Scalar, int _Dim, int _Degree>
00331 template <int DerivativeOrder>
00332 typename SplineTraits< Spline<_Scalar, _Dim, _Degree>, DerivativeOrder >::DerivativeType
00333 Spline<_Scalar, _Dim, _Degree>::derivatives(Scalar u, DenseIndex order) const
00334 {
00335 typename SplineTraits< Spline, DerivativeOrder >::DerivativeType res;
00336 derivativesImpl(*this, u, order, res);
00337 return res;
00338 }
00339
00340 template <typename _Scalar, int _Dim, int _Degree>
00341 typename SplineTraits< Spline<_Scalar, _Dim, _Degree> >::BasisVectorType
00342 Spline<_Scalar, _Dim, _Degree>::basisFunctions(Scalar u) const
00343 {
00344 return Spline::BasisFunctions(u, degree(), knots());
00345 }
00346
00347
00348
00349 template <typename SplineType, typename DerivativeType>
00350 void basisFunctionDerivativesImpl(const SplineType& spline, typename SplineType::Scalar u, DenseIndex order, DerivativeType& N_)
00351 {
00352 enum { Order = SplineTraits<SplineType>::OrderAtCompileTime };
00353
00354 typedef typename SplineTraits<SplineType>::Scalar Scalar;
00355 typedef typename SplineTraits<SplineType>::BasisVectorType BasisVectorType;
00356 typedef typename SplineTraits<SplineType>::KnotVectorType KnotVectorType;
00357
00358 const KnotVectorType& U = spline.knots();
00359
00360 const DenseIndex p = spline.degree();
00361 const DenseIndex span = spline.span(u);
00362
00363 const DenseIndex n = (std::min)(p, order);
00364
00365 N_.resize(n+1, p+1);
00366
00367 BasisVectorType left = BasisVectorType::Zero(p+1);
00368 BasisVectorType right = BasisVectorType::Zero(p+1);
00369
00370 Matrix<Scalar,Order,Order> ndu(p+1,p+1);
00371
00372 double saved, temp;
00373
00374 ndu(0,0) = 1.0;
00375
00376 DenseIndex j;
00377 for (j=1; j<=p; ++j)
00378 {
00379 left[j] = u-U[span+1-j];
00380 right[j] = U[span+j]-u;
00381 saved = 0.0;
00382
00383 for (DenseIndex r=0; r<j; ++r)
00384 {
00385
00386 ndu(j,r) = right[r+1]+left[j-r];
00387 temp = ndu(r,j-1)/ndu(j,r);
00388
00389 ndu(r,j) = static_cast<Scalar>(saved+right[r+1] * temp);
00390 saved = left[j-r] * temp;
00391 }
00392
00393 ndu(j,j) = static_cast<Scalar>(saved);
00394 }
00395
00396 for (j = p; j>=0; --j)
00397 N_(0,j) = ndu(j,p);
00398
00399
00400 DerivativeType a(n+1,p+1);
00401 DenseIndex r=0;
00402 for (; r<=p; ++r)
00403 {
00404 DenseIndex s1,s2;
00405 s1 = 0; s2 = 1;
00406 a(0,0) = 1.0;
00407
00408
00409 for (DenseIndex k=1; k<=static_cast<DenseIndex>(n); ++k)
00410 {
00411 double d = 0.0;
00412 DenseIndex rk,pk,j1,j2;
00413 rk = r-k; pk = p-k;
00414
00415 if (r>=k)
00416 {
00417 a(s2,0) = a(s1,0)/ndu(pk+1,rk);
00418 d = a(s2,0)*ndu(rk,pk);
00419 }
00420
00421 if (rk>=-1) j1 = 1;
00422 else j1 = -rk;
00423
00424 if (r-1 <= pk) j2 = k-1;
00425 else j2 = p-r;
00426
00427 for (j=j1; j<=j2; ++j)
00428 {
00429 a(s2,j) = (a(s1,j)-a(s1,j-1))/ndu(pk+1,rk+j);
00430 d += a(s2,j)*ndu(rk+j,pk);
00431 }
00432
00433 if (r<=pk)
00434 {
00435 a(s2,k) = -a(s1,k-1)/ndu(pk+1,r);
00436 d += a(s2,k)*ndu(r,pk);
00437 }
00438
00439 N_(k,r) = static_cast<Scalar>(d);
00440 j = s1; s1 = s2; s2 = j;
00441 }
00442 }
00443
00444
00445
00446 r = p;
00447 for (DenseIndex k=1; k<=static_cast<DenseIndex>(n); ++k)
00448 {
00449 for (DenseIndex j=p; j>=0; --j) N_(k,j) *= r;
00450 r *= p-k;
00451 }
00452 }
00453
00454 template <typename _Scalar, int _Dim, int _Degree>
00455 typename SplineTraits< Spline<_Scalar, _Dim, _Degree> >::BasisDerivativeType
00456 Spline<_Scalar, _Dim, _Degree>::basisFunctionDerivatives(Scalar u, DenseIndex order) const
00457 {
00458 typename SplineTraits< Spline >::BasisDerivativeType der;
00459 basisFunctionDerivativesImpl(*this, u, order, der);
00460 return der;
00461 }
00462
00463 template <typename _Scalar, int _Dim, int _Degree>
00464 template <int DerivativeOrder>
00465 typename SplineTraits< Spline<_Scalar, _Dim, _Degree>, DerivativeOrder >::BasisDerivativeType
00466 Spline<_Scalar, _Dim, _Degree>::basisFunctionDerivatives(Scalar u, DenseIndex order) const
00467 {
00468 typename SplineTraits< Spline, DerivativeOrder >::BasisDerivativeType der;
00469 basisFunctionDerivativesImpl(*this, u, order, der);
00470 return der;
00471 }
00472 }
00473
00474 #endif // EIGEN_SPLINE_H