Как мне реализовать кривую Безье в C ++? - PullRequest
14 голосов
/ 24 апреля 2009

Я бы хотел реализовать кривую Безье . Я делал это раньше в C #, но я совершенно незнаком с библиотеками C ++. Как мне создать квадратную кривую?

void printQuadCurve(float delta, Vector2f p0, Vector2f p1, Vector2f p2);

Очевидно, что нам нужно использовать линейную интерполяцию, но существует ли она в стандартной математической библиотеке? Если нет, где я могу его найти?

Обновление 1:

Извините, я забыл упомянуть, что использую Linux.

Ответы [ 5 ]

102 голосов
/ 11 июля 2012

Недавно я столкнулся с тем же вопросом и хотел реализовать его самостоятельно. Это изображение из Википедии помогло мне:

http://upload.wikimedia.org/wikipedia/commons/3/35/Bezier_quadratic_anim.gif

Следующий код написан на C ++ и показывает, как вычислить квадратичный Безье.

int getPt( int n1 , int n2 , float perc )
{
    int diff = n2 - n1;

    return n1 + ( diff * perc );
}    

for( float i = 0 ; i < 1 ; i += 0.01 )
{
    // The Green Line
    xa = getPt( x1 , x2 , i );
    ya = getPt( y1 , y2 , i );
    xb = getPt( x2 , x3 , i );
    yb = getPt( y2 , y3 , i );

    // The Black Dot
    x = getPt( xa , xb , i );
    y = getPt( ya , yb , i );

    drawPixel( x , y , COLOR_RED );
}

С (x1 | y1), (x2 | y2) и (x3 | y3) являются P0, P1 и P2 на изображении. Просто для того, чтобы показать основную идею ...

Для тех, кто просит кубический Безье, просто работает аналог (также из Википедии):

http://upload.wikimedia.org/wikipedia/commons/a/a3/Bezier_cubic_anim.gif

Этот ответ содержит код для него.

11 голосов
/ 08 февраля 2014

Вот общая реализация кривой с любым количеством точек.

vec2 getBezierPoint( vec2* points, int numPoints, float t ) {
    vec2* tmp = new vec2[numPoints];
    memcpy(tmp, points, numPoints * sizeof(vec2));
    int i = numPoints - 1;
    while (i > 0) {
        for (int k = 0; k < i; k++)
            tmp[k] = tmp[k] + t * ( tmp[k+1] - tmp[k] );
        i--;
    }
    vec2 answer = tmp[0];
    delete[] tmp;
    return answer;
}

Обратите внимание, что он использует кучу памяти для временного массива, который не так эффективен. Если вам нужно иметь дело только с фиксированным числом точек, вы можете жестко закодировать значение numPoints и использовать вместо этого стековую память.

Конечно, вышеизложенное предполагает, что у вас есть структура vec2 и операторы для нее:

struct vec2 {
    float x, y;
    vec2(float x, float y) : x(x), y(y) {}
};

vec2 operator + (vec2 a, vec2 b) {
    return vec2(a.x + b.x, a.y + b.y);
}

vec2 operator - (vec2 a, vec2 b) {
    return vec2(a.x - b.x, a.y - b.y);
}

vec2 operator * (float s, vec2 a) {
    return vec2(s * a.x, s * a.y);
}
7 голосов
/ 28 марта 2017

У вас есть выбор между методом де Кастельжау, который заключается в рекурсивном разделении контрольного пути, пока вы не достигнете точки с использованием линейной интерполяции, как описано выше, или методом Безье, который заключается в смешивании контрольных точек.

Метод Безье

 p = (1-t)^3 *P0 + 3*t*(1-t)^2*P1 + 3*t^2*(1-t)*P2 + t^3*P3 

для кубиков и

 p = (1-t)^2 *P0 + 2*(1-t)*t*P1 + t*t*P2

для квадратиков.

t обычно на 0-1, но это не существенно - фактически кривые простираются до бесконечности. P0, P1 и т. Д. Являются контрольными точками. Кривая проходит через две конечные точки, но обычно не проходит через другие точки.

7 голосов
/ 24 апреля 2009

Вы использовали библиотеку C # ранее?

В C ++ нет стандартной библиотеки функций для кривых Безье (пока). Конечно, вы можете свернуть свои собственные (CodeProject sample ) или поискать математическую библиотеку.

Этот пост в блоге объясняет идею хорошо, но в Actionscript. Перевод не должен быть большой проблемой.

1 голос
/ 24 апреля 2009
  • Если вы просто хотите отобразить кривую Безье, вы можете использовать что-то вроде PolyBezier для Windows.

  • Если вы хотите реализовать процедуру самостоятельно, вы можете найти код линейной интерполяции по всему Intarnetz.

  • Я полагаю, что библиотеки Boost поддерживают это. Линейная интерполяция, а не Безье. Однако не цитируйте меня по этому поводу.

...