| 428 | } |
| 429 | |
| 430 | std::vector<double> BSpline::Builder::knotVectorEquidistant(const std::vector<double> &values, |
| 431 | unsigned int degree, |
| 432 | unsigned int numBasisFunctions = 0) const |
| 433 | { |
| 434 | // Sort and remove duplicates |
| 435 | std::vector<double> unique = extractUniqueSorted(values); |
| 436 | |
| 437 | // Compute sizes |
| 438 | unsigned int n = unique.size(); |
| 439 | if (numBasisFunctions > 0) |
| 440 | n = numBasisFunctions; |
| 441 | unsigned int k = degree-1; // knots to remove |
| 442 | |
| 443 | // The minimum number of samples from which a free knot vector can be created |
| 444 | if (n < degree+1) |
| 445 | { |
| 446 | std::ostringstream e; |
| 447 | e << "knotVectorMovingAverage: Only " << n |
| 448 | << " unique interpolation points are given. A minimum of degree+1 = " << degree+1 |
| 449 | << " unique points are required to build a B-spline basis of degree " << degree << "."; |
| 450 | throw Exception(e.str()); |
| 451 | } |
| 452 | |
| 453 | // Compute (n-k-2) equidistant interior knots |
| 454 | unsigned int numIntKnots = std::max(n-k-2, (unsigned int)0); |
| 455 | numIntKnots = std::min((unsigned int)10, numIntKnots); |
| 456 | std::vector<double> knots = linspace(unique.front(), unique.back(), numIntKnots); |
| 457 | |
| 458 | // Repeat first knot p + 1 times (for interpolation of start point) |
| 459 | for (unsigned int i = 0; i < degree; ++i) |
| 460 | knots.insert(knots.begin(), unique.front()); |
| 461 | |
| 462 | // Repeat last knot p + 1 times (for interpolation of end point) |
| 463 | for (unsigned int i = 0; i < degree; ++i) |
| 464 | knots.insert(knots.end(), unique.back()); |
| 465 | |
| 466 | // Number of knots in a (p+1)-regular knot vector |
| 467 | //assert(knots.size() == uniqueX.size() + degree + 1); |
| 468 | |
| 469 | return knots; |
| 470 | } |
| 471 | |
| 472 | std::vector<double> BSpline::Builder::knotVectorBuckets(const std::vector<double> &values, unsigned int degree, unsigned int maxSegments) const |
| 473 | { |