Exemplo n.º 1
0
// 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;
}