Подтвердить что ты не робот

Как реализовать кривую Безье в С++?

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

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

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

Этот ответ дает код для него.

Ответ 3

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

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);
}

Ответ 4

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

Метод Безье

 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 и т.д. - контрольные точки. Кривая проходит через две конечные точки, но обычно не проходит через другие точки.

Ответ 5

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

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

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