26BSpline::BSpline(
unsigned int numVariables)
27 : Function(numVariables)
33BSpline::BSpline(std::vector<std::vector<double>> knotVectors,
34 std::vector<unsigned int> basisDegrees)
35 : Function(knotVectors.size()),
36 basis(BSplineBasis(knotVectors, basisDegrees)),
37 coefficients(DenseVector::Zero(1)),
38 knotaverages(computeKnotAverages())
41 setCoefficients(DenseVector::Ones(basis.getNumBasisFunctions()));
45BSpline::BSpline(std::vector<double> coefficients,
46 std::vector<std::vector<double>> knotVectors,
47 std::vector<unsigned int> basisDegrees)
52BSpline::BSpline(DenseVector coefficients,
53 std::vector<std::vector<double>> knotVectors,
54 std::vector<unsigned int> basisDegrees)
55 : Function(knotVectors.size()),
56 basis(BSplineBasis(knotVectors, basisDegrees)),
57 coefficients(coefficients),
58 knotaverages(computeKnotAverages())
60 setCoefficients(coefficients);
67BSpline::BSpline(
const char* fileName)
68 : BSpline(std::string(fileName))
72BSpline::BSpline(
const std::string& fileName)
81double BSpline::eval(DenseVector x)
const
85 DenseVector res = coefficients.transpose() * evalBasis(x);
92DenseMatrix BSpline::evalJacobian(DenseVector x)
const
95 return coefficients.transpose() * evalBasisJacobian(x);
103DenseMatrix BSpline::evalHessian(DenseVector x)
const
108 if (!pointInDomain(x))
110 throw Exception(
"BSpline::evalHessian: Evaluation at point outside domain.");
116 DenseMatrix identity = DenseMatrix::Identity(numVariables, numVariables);
117 DenseMatrix caug = kroneckerProduct(identity, coefficients.transpose());
118 DenseMatrix DB = basis.evalBasisHessian(x);
122 for (
size_t i = 0;
i < numVariables; ++
i)
123 for (
size_t j =
i + 1; j < numVariables; ++j)
132SparseVector BSpline::evalBasis(DenseVector x)
const
136 if (!pointInDomain(x))
138 throw Exception(
"BSpline::evalBasis: Evaluation at point outside domain.");
142 return basis.eval(x);
145SparseMatrix BSpline::evalBasisJacobian(DenseVector x)
const
149 if (!pointInDomain(x))
151 throw Exception(
"BSpline::evalBasisJacobian: Evaluation at point outside domain.");
157 DenseMatrix Bi = basis.evalBasisJacobianOld(x);
158 return Bi.sparseView();
161std::vector<unsigned int> BSpline::getNumBasisFunctionsPerVariable()
const
163 std::vector<unsigned int> ret;
165 for (
unsigned int i = 0;
i < numVariables;
i++)
167 ret.push_back(basis.getNumBasisFunctions(
i));
173std::vector< std::vector<double>> BSpline::getKnotVectors()
const
175 return basis.getKnotVectors();
178std::vector<unsigned int> BSpline::getBasisDegrees()
const
180 return basis.getBasisDegrees();
183std::vector<double> BSpline::getDomainUpperBound()
const
185 return basis.getSupportUpperBound();
188std::vector<double> BSpline::getDomainLowerBound()
const
190 return basis.getSupportLowerBound();
193DenseMatrix BSpline::getControlPoints()
const
195 int nc = coefficients.size();
196 DenseMatrix controlPoints(nc, numVariables + 1);
197 controlPoints.block(0, 0, nc, numVariables) = knotaverages;
198 controlPoints.block(0, numVariables, nc, 1) = coefficients;
199 return controlPoints;
202void BSpline::setCoefficients(
const DenseVector& coefficients)
204 if (coefficients.size() != getNumBasisFunctions())
206 throw Exception(
"BSpline::setControlPoints: Incompatible size of coefficient vector.");
209 this->coefficients = coefficients;
210 checkControlPoints();
213void BSpline::setControlPoints(
const DenseMatrix& controlPoints)
215 if (controlPoints.cols() != numVariables + 1)
217 throw Exception(
"BSpline::setControlPoints: Incompatible size of control point matrix.");
220 int nc = controlPoints.rows();
221 knotaverages = controlPoints.block(0, 0, nc, numVariables);
222 coefficients = controlPoints.block(0, numVariables, nc, 1);
223 checkControlPoints();
226void BSpline::updateControlPoints(
const DenseMatrix&
A)
228 if (
A.cols() != coefficients.rows() ||
A.cols() != knotaverages.rows())
230 throw Exception(
"BSpline::updateControlPoints: Incompatible size of linear transformation matrix.");
233 coefficients =
A * coefficients;
234 knotaverages =
A * knotaverages;
237void BSpline::checkControlPoints()
const
239 if (coefficients.rows() != knotaverages.rows())
241 throw Exception(
"BSpline::checkControlPoints: Inconsistent size of coefficients and knot averages matrices.");
244 if (knotaverages.cols() != numVariables)
246 throw Exception(
"BSpline::checkControlPoints: Inconsistent size of knot averages matrix.");
250bool BSpline::pointInDomain(DenseVector x)
const
252 return basis.insideSupport(x);
255void BSpline::reduceSupport(std::vector<double> lb, std::vector<double> ub,
256 bool doRegularizeKnotVectors)
258 if (lb.size() != numVariables || ub.size() != numVariables)
260 throw Exception(
"BSpline::reduceSupport: Inconsistent vector sizes!");
263 std::vector<double> sl = basis.getSupportLowerBound();
264 std::vector<double> su = basis.getSupportUpperBound();
266 for (
unsigned int dim = 0; dim < numVariables; dim++)
269 if (ub.at(dim) <= lb.at(dim) || lb.at(dim) >= su.at(dim)
270 || ub.at(dim) <= sl.at(dim))
272 throw Exception(
"BSpline::reduceSupport: Cannot reduce B-spline domain to empty set!");
276 if (su.at(dim) < ub.at(dim) || sl.at(dim) > lb.at(dim))
278 throw Exception(
"BSpline::reduceSupport: Cannot expand B-spline domain!");
282 sl.at(dim) = lb.at(dim);
283 su.at(dim) = ub.at(dim);
286 if (doRegularizeKnotVectors)
288 regularizeKnotVectors(sl, su);
292 if (!removeUnsupportedBasisFunctions(sl, su))
294 throw Exception(
"BSpline::reduceSupport: Failed to remove unsupported basis functions!");
298void BSpline::globalKnotRefinement()
301 SparseMatrix
A = basis.refineKnots();
303 updateControlPoints(
A);
306void BSpline::localKnotRefinement(DenseVector x)
309 SparseMatrix
A = basis.refineKnotsLocally(x);
311 updateControlPoints(
A);
314void BSpline::decomposeToBezierForm()
317 SparseMatrix
A = basis.decomposeToBezierForm();
319 updateControlPoints(
A);
323DenseMatrix BSpline::computeKnotAverages()
const
326 std::vector<DenseVector> mu_vectors;
328 for (
unsigned int i = 0;
i < numVariables;
i++)
330 std::vector<double> knots = basis.getKnotVector(
i);
331 DenseVector mu = DenseVector::Zero(basis.getNumBasisFunctions(
i));
333 for (
unsigned int j = 0; j < basis.getNumBasisFunctions(
i); j++)
337 for (
unsigned int k = j + 1; k <= j + basis.getBasisDegree(
i); k++)
339 knotAvg += knots.at(k);
342 mu(j) = knotAvg / basis.getBasisDegree(
i);
345 mu_vectors.push_back(mu);
349 std::vector<DenseVector> knotOnes;
351 for (
unsigned int i = 0;
i < numVariables;
i++)
353 knotOnes.push_back(DenseVector::Ones(mu_vectors.at(
i).rows()));
357 DenseMatrix knot_averages = DenseMatrix::Zero(basis.getNumBasisFunctions(),
360 for (
unsigned int i = 0;
i < numVariables;
i++)
362 DenseMatrix mu_ext(1, 1);
365 for (
unsigned int j = 0; j < numVariables; j++)
367 DenseMatrix temp = mu_ext;
371 mu_ext = Eigen::kroneckerProduct(temp, mu_vectors.at(j));
375 mu_ext = Eigen::kroneckerProduct(temp, knotOnes.at(j));
379 if (mu_ext.rows() != basis.getNumBasisFunctions())
381 throw Exception(
"BSpline::computeKnotAverages: Incompatible size of knot average matrix.");
384 knot_averages.block(0,
i, basis.getNumBasisFunctions(), 1) = mu_ext;
387 return knot_averages;
390void BSpline::insertKnots(
double tau,
unsigned int dim,
391 unsigned int multiplicity)
394 SparseMatrix
A = basis.insertKnots(
tau, dim, multiplicity);
396 updateControlPoints(
A);
399void BSpline::regularizeKnotVectors(std::vector<double>& lb,
400 std::vector<double>& ub)
403 if (!(lb.size() == numVariables && ub.size() == numVariables))
405 throw Exception(
"BSpline::regularizeKnotVectors: Inconsistent vector sizes.");
408 for (
unsigned int dim = 0; dim < numVariables; dim++)
410 unsigned int multiplicityTarget = basis.getBasisDegree(dim) + 1;
417 int numKnotsLB = multiplicityTarget - basis.getKnotMultiplicity(dim,
422 insertKnots(lb.at(dim), dim, numKnotsLB);
425 int numKnotsUB = multiplicityTarget - basis.getKnotMultiplicity(dim,
430 insertKnots(ub.at(dim), dim, numKnotsUB);
435bool BSpline::removeUnsupportedBasisFunctions(std::vector<double>& lb,
436 std::vector<double>& ub)
438 if (lb.size() != numVariables || ub.size() != numVariables)
440 throw Exception(
"BSpline::removeUnsupportedBasisFunctions: Incompatible dimension of domain bounds.");
443 SparseMatrix
A = basis.reduceSupport(lb, ub);
445 if (coefficients.size() !=
A.rows())
451 updateControlPoints(
A.transpose());
455void BSpline::save(
const std::string& fileName)
const
459 s.saveToFile(fileName);
462void BSpline::load(
const std::string& fileName)
464 Serializer s(fileName);
465 s.deserialize(*
this);
468std::string BSpline::getDescription()
const
470 std::string description(
"BSpline of degree");
471 auto degrees = getBasisDegrees();
475 for (
size_t i = 1;
i < degrees.size(); ++
i)
477 equal = equal && (degrees.at(
i) == degrees.at(
i - 1));
482 description.append(
" ");
483 description.append(std::to_string(degrees.at(0)));
487 description.append(
"s (");
489 for (
size_t i = 0;
i < degrees.size(); ++
i)
491 description.append(std::to_string(degrees.at(
i)));
493 if (
i + 1 < degrees.size())
495 description.append(
", ");
499 description.append(
")");