SparseMatrix BSplineBasis1D::reduceSupport(double lb, double ub) { // Check bounds if (lb < knots.front() || ub > knots.back()) throw Exception("BSplineBasis1D::reduceSupport: Cannot increase support!"); unsigned int k = degree + 1; int index_lower = indexSupportedBasisfunctions(lb).front(); int index_upper = indexSupportedBasisfunctions(ub).back(); // Check lower bound index if (k != knotMultiplicity(knots.at(index_lower))) { int suggested_index = index_lower - 1; if (0 <= suggested_index) { index_lower = suggested_index; } else { throw Exception("BSplineBasis1D::reduceSupport: Suggested index is negative!"); } } // Check upper bound index if (knotMultiplicity(ub) == k && knots.at(index_upper) == ub) { index_upper -= k; } // New knot vector std::vector<double> si; si.insert(si.begin(), knots.begin()+index_lower, knots.begin()+index_upper+k+1); // Construct selection matrix A int numOld = knots.size()-k; // Current number of basis functions int numNew = si.size()-k; // Number of basis functions after update if (numOld < numNew) throw Exception("BSplineBasis1D::reduceSupport: Number of basis functions is increased instead of reduced!"); DenseMatrix Ad = DenseMatrix::Zero(numOld, numNew); Ad.block(index_lower, 0, numNew, numNew) = DenseMatrix::Identity(numNew, numNew); SparseMatrix A = Ad.sparseView(); // Update knots knots = si; return A; }
SparseMatrix BSplineBasis1D::decomposeToBezierForm() { // Build refine knot vector std::vector<double> refinedKnots = knots; // Start at first knot and add knots until all knots have multiplicity degree + 1 std::vector<double>::iterator knoti = refinedKnots.begin(); while (knoti != refinedKnots.end()) { // Insert new knots int mult = degree + 1 - knotMultiplicity(*knoti); if (mult > 0) { std::vector<double> newKnots(mult, *knoti); refinedKnots.insert(knoti, newKnots.begin(), newKnots.end()); } // Advance to next knot knoti = std::upper_bound(refinedKnots.begin(), refinedKnots.end(), *knoti); } if (!isKnotVectorRegular(refinedKnots) || !isRefinement(refinedKnots)) throw Exception("BSplineBasis1D::refineKnots: New knot vector is not a proper refinement!"); // Return knot insertion matrix SparseMatrix A = buildKnotInsertionMatrix(refinedKnots); // Update knots knots = refinedKnots; return A; }
// 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; }
SparseMatrix BSplineBasis1D::refineKnotsLocally(double x) { if (!insideSupport(x)) throw Exception("BSplineBasis1D::refineKnotsLocally: Cannot refine outside support!"); if (getNumBasisFunctions() >= getNumBasisFunctionsTarget() || assertNear(knots.front(), knots.back())) { unsigned int n = getNumBasisFunctions(); DenseMatrix A = DenseMatrix::Identity(n,n); return A.sparseView(); } // Refined knot vector std::vector<double> refinedKnots = knots; auto upper = std::lower_bound(refinedKnots.begin(), refinedKnots.end(), x); // Check left boundary if (upper == refinedKnots.begin()) std::advance(upper, degree+1); // Get previous iterator auto lower = std::prev(upper); // Do not insert if upper and lower bounding knot are close if (assertNear(*upper, *lower)) { unsigned int n = getNumBasisFunctions(); DenseMatrix A = DenseMatrix::Identity(n,n); return A.sparseView(); } // Insert knot at x double insertVal = x; // Adjust x if it is on or close to a knot if (knotMultiplicity(x) > 0 || assertNear(*upper, x, 1e-6, 1e-6) || assertNear(*lower, x, 1e-6, 1e-6)) { insertVal = (*upper + *lower)/2.0; } // Insert new knot refinedKnots.insert(upper, insertVal); if (!isKnotVectorRegular(refinedKnots) || !isRefinement(refinedKnots)) throw Exception("BSplineBasis1D::refineKnotsLocally: New knot vector is not a proper refinement!"); // Build knot insertion matrix SparseMatrix A = buildKnotInsertionMatrix(refinedKnots); // Update knots knots = refinedKnots; return A; }
// 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; }
bool BSplineBasis1D::reduceSupport(double lb, double ub, SparseMatrix &A) { // Check bounds if(lb < knots.front() || ub > knots.back()) { return false; } unsigned int k = degree + 1; int index_lower = indexSupportedBasisfunctions(lb).front(); int index_upper = indexSupportedBasisfunctions(ub).back(); // Check lower bound index unsigned int count = knotMultiplicity(knots.at(index_lower)); bool is_p_regular = (k == count); if(!is_p_regular) { int suggested_index = index_lower - 1; if(0 <= suggested_index) { index_lower = suggested_index; } else { #ifndef NDEBUG std::cout << "\n\n----------------adjust_index_for_domain_reduction-----------------" << std::endl; std::cout << "Error: not enough knots to guarantee controlpoint convergence" << std::endl; std::cout << "----------------adjust_index_for_domain_reduction-----------------\n\n" << std::endl; #endif // NDEBUG return false; } } // Check upper bound index if(knotMultiplicity(ub) == k && knots.at(index_upper) == ub) { index_upper -= k; } // New knot vector std::vector<double> si; si.insert(si.begin(), knots.begin()+index_lower, knots.begin()+index_upper+k+1); // Construct selection matrix A int n_old = knots.size()-k; // Current number of basis functions int n_new = si.size()-k; // Number of basis functions after update if (n_old < n_new) return false; DenseMatrix Ad = DenseMatrix::Zero(n_old, n_new); Ad.block(index_lower, 0, n_new, n_new) = DenseMatrix::Identity(n_new, n_new); A = Ad.sparseView(); // Update knots knots = si; return true; }