Алгоритм автоматического сглаживания узлов Inkscape - PullRequest
1 голос
/ 02 мая 2020

Я генерирую плавные кривые путем интерполяции (много) точек. Я хочу иметь локальную поддержку (т. Е. Только несколько точек определяют локальную гладкую кривую), поэтому я не хочу использовать классический сплайн интерполяции. Кривые Безье для меня были бы естественным решением, и автоматически сглаживающие узлы Inkscape (http://tavmjong.free.fr/INKSCAPE/MANUAL/html/Paths-Editing.html#Paths -Node-AutoSmooth ) довольно хорошо справляются со своими задачами. Но у меня проблемы с поиском реализации в источнике или какой-либо ссылкой на базовый алгоритм.

Кто-нибудь здесь знает об алгоритме или достаточно знаком с источником Inkscape, чтобы они могли указать мне правильное направление?

Для контекста: я вычисляю плавный путь для перьевого плоттера, но не могу дождаться, когда будут доступны все опорные точки.

1 Ответ

1 голос
/ 02 мая 2020

Комментарий @ Фанга ниже. Лучше использовать вместо этого интерполирующий сплайн Catmull-Rom, который одновременно интерполирует и имеет свойство локального управления. Подробнее здесь

Для склеивания кубических кривых Безье c, которые интерполируются (больше похоже на натуральные кубические c сплайны), см. Ниже оригинальный ответ.

=============================================== ====================

Ниже приведен javascript -подобный псевдокод, который вычисляет серию (до) кубов c Кривые Безье, которые вместе объединяются в , достигают одного плавного прохода кривой через заданные точки . Примечание bezier в приведенном ниже коде предполагается функцией, которая вычисляет (полиномиальную форму) куби c по заданным контрольным точкам (что уже является известным алгоритмом). Примечание2 приведенный ниже алгоритм предназначен для 1d кривых, его легко настроить для 2d кривых (ie вычислить координаты x и y)

function bezierThrough( knots )
{
    var i, points, segments;
    computePoints = function computePoints( knots ) {
        var i, p1, p2, a, b, c, r, m, n = knots.length-1;
        p1 = new Array(n);
        p2 = new Array(n);

        /*rhs vector*/
        a = new Array(n);
        b = new Array(n);
        c = new Array(n);
        r = new Array(n);

        /*left most segment*/
        a[0] = 0;
        b[0] = 2;
        c[0] = 1;
        r[0] = knots[0] + 2*knots[1];

        /*internal segments*/
        for(i=1; i<n-1; i++)
        {
            a[i] = 1;
            b[i] = 4;
            c[i] = 1;
            r[i] = 4*knots[i] + 2*knots[i+1];
        }

        /*right segment*/
        a[n-1] = 2;
        b[n-1] = 7;
        c[n-1] = 0;
        r[n-1] = 8*knots[n-1] + knots[n];

        /*solves Ax=b with the Thomas algorithm (from Wikipedia)*/
        for(i=1; i<n; i++)
        {
            m = a[i] / b[i-1];
            b[i] = b[i] - m*c[i - 1];
            r[i] = r[i] - m*r[i-1];
        }

        p1[n-1] = r[n-1] / b[n-1];
        for(i=n-2; i>=0; --i)
            p1[i] = (r[i]-c[i]*p1[i+1]) / b[i];

        /*we have p1, now compute p2*/
        for (i=0;i<n-1;i++)
            p2[i] = 2*knots[i+1] - p1[i+1];
        p2[n-1] = (knots[n]+p1[n-1])/2;

        return [p1, p2];
    };
    if ( 1 === knots.length )
    {
        segments = [knots[0]];
    }
    else if ( 2 === knots.length )
    {
        segments = [bezier([knots[0], knots[1]])];
    }
    else
    {
        segments = [];
        points = computePoints(knots);
        for(i=0; i<knots.length-1; i++)
            segments.push(bezier([knots[i], points[0][i], points[1][i], knots[i+1]]));
    }
    return segments;
}

см. Также соответствующий пост

Адаптированный код от здесь

...