// Insert knots and compute knot insertion matrix (to update control points) SparseMatrix BSplineBasis1D::insertKnots(double tau, unsigned int multiplicity) { if (!insideSupport(tau)) throw Exception("BSplineBasis1D::insertKnots: Cannot insert knot outside domain!"); if (knotMultiplicity(tau) + multiplicity > degree + 1) throw Exception("BSplineBasis1D::insertKnots: Knot multiplicity is too high!"); // New knot vector int index = indexHalfopenInterval(tau); std::vector<double> extKnots = knots; for (unsigned int i = 0; i < multiplicity; i++) extKnots.insert(extKnots.begin()+index+1, tau); if (!isKnotVectorRegular(extKnots)) throw Exception("BSplineBasis1D::insertKnots: New knot vector is not regular!"); // Return knot insertion matrix SparseMatrix A = buildKnotInsertionMatrix(extKnots); // Update knots knots = extKnots; return A; }
SparseVector BSplineBasis1D::evaluateDerivative(double x, int r) const { // Evaluate rth derivative of basis functions at x // Returns vector [D^(r)B_(u-p,p)(x) ... D^(r)B_(u,p)(x)] // where u is the knot index and p is the degree int p = degree; // Continuity requirement //assert(p >= r+1); if(!(p >= r+1)) { // Return zero-gradient SparseVector DB(numBasisFunctions()); return DB; } // Check for knot multiplicity here! supportHack(x); int knotIndex = indexHalfopenInterval(x); // Algorithm 3.18 from Lyche and Moerken 2011 SparseMatrix B(1,1); B.insert(0,0) = 1; for(int i = 1; i <= p-r; i++) { SparseMatrix R = buildBasisMatrix(x, knotIndex, i); B = B*R; } for(int i = p-r+1; i <= p; i++) { SparseMatrix DR = buildBasisMatrix(x, knotIndex, i, true); B = B*DR; } double factorial = std::tgamma(p+1)/std::tgamma(p-r+1); B = B*factorial; assert(B.cols() == p+1); // From row vector to extended column vector SparseVector DB(numBasisFunctions()); DB.reserve(p+1); int i = knotIndex-p; // First insertion index for(int k = 0; k < B.outerSize(); ++k) for(SparseMatrix::InnerIterator it(B,k); it; ++it) { DB.insert(i+it.col()) = it.value(); } return DB; }
bool BSplineBasis1D::buildKnotInsertionMatrix(SparseMatrix &A, const std::vector<double> &refinedKnots) const { if (!isRefinement(refinedKnots)) { throw Exception("BSplineBasis1D::buildKnotInsertionMatrix: New knot vector is not a proper refinement of the old!"); } std::vector<double> knotsAug = refinedKnots; unsigned int n = knots.size() - degree - 1; unsigned int m = knotsAug.size() - degree - 1; //SparseMatrix A(m,n); A.resize(m,n); A.reserve(Eigen::VectorXi::Constant(n,degree+1)); // Build A row-by-row for(unsigned int i = 0; i < m; i++) { int u = indexHalfopenInterval(knotsAug.at(i)); // Assuming that p > 0 SparseMatrix R(1,1); R.insert(0,0) = 1; for(unsigned int j = 1; j <= degree; j++) { SparseMatrix Ri = buildBasisMatrix(knotsAug.at(i+j), u, j); R = R*Ri; } // Size check if(R.rows() != 1 || R.cols() != degree+1) { throw Exception("BSplineBasis1D::buildKnotInsertionMatrix: Incorrect matrix dimensions!"); } // Insert row values int j = u-degree; // First insertion index for(int k = 0; k < R.outerSize(); ++k) for(SparseMatrix::InnerIterator it(R,k); it; ++it) { A.insert(i,j+it.col()) = it.value(); } } A.makeCompressed(); return true; }
// Return indices of supporting basis functions at x std::vector<int> BSplineBasis1D::indexSupportedBasisfunctions(double x) const { std::vector<int> ret; if(insideSupport(x)) { int last = indexHalfopenInterval(x); if(last < 0) { last = knots.size() - 1 - (degree + 1); } int first = std::max((int)(last - degree), 0); for(int i = first; i <= last; i++) { ret.push_back(i); } } return ret; }
// Insert knots and compute knot insertion matrix (to update control points) bool BSplineBasis1D::insertKnots(SparseMatrix &A, double tau, unsigned int multiplicity) { if(!insideSupport(tau) || knotMultiplicity(tau) + multiplicity > degree + 1) return false; // New knot vector int index = indexHalfopenInterval(tau); std::vector<double> extKnots = knots; for(unsigned int i = 0; i < multiplicity; i++) extKnots.insert(extKnots.begin()+index+1, tau); assert(isKnotVectorRegular(extKnots)); // Return knot insertion matrix if(!buildKnotInsertionMatrix(A, extKnots)) return false; // Update knots knots = extKnots; return true; }