Как реализовать кривую Безье в C++?
Я хотел бы реализовать кривой Безье. Я делал это на C# раньше, но я совершенно не знаком с библиотеками c++. Как мне создать квадратичную кривую?
void printQuadCurve(float delta, Vector2f p0, Vector2f p1, Vector2f p2);
очевидно, что нам нужно использовать линейную интерполяцию, но существует ли это в стандартной математической библиотеке? Если нет, то где я могу его найти?
обновление 1:
Извините, я забыл упомянуть, что использую Linux.
5 ответов
вы использовали библиотеку C# ранее?
в C++ стандартная библиотечная функция для кривых Безье недоступна (пока). Вы можете, конечно, свернуть свой собственный (CodeProject пример) или найдите математическую библиотеку.
этой blogpost объясняет идею красиво, но в Actionscript. Перевод не должен быть большой проблемой.
недавно я столкнулся с тем же вопросом и хотел реализовать его самостоятельно. Это изображение из Википедии помогло мне:
следующий код написан на 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 на изображении. Просто чтобы показать основную идею...
для тех, кто просит кубический Безье, он просто работает аналоговый (также от Википедия):
этой ответ содержит код для него.
вот общая реализация для кривой с любым количеством точек.
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);
}
у вас есть выбор между методом де Кастельжау, который заключается в рекурсивном разделении пути управления до тех пор, пока вы не прибудете в точку с помощью линейной интерполяции, как описано выше, или методом Безье, который заключается в смешивании контрольных точек.
метод Безье
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, etc управление точки. Кривая проходит через две конечные точки, но обычно не через другие точки.
Если вы просто хотите, чтобы отобразить кривую Безье, вы можете использовать что-то вроде PolyBezier для Windows.
Если вы хотите реализовать процедуру самостоятельно, вы можете найти код линейной интерполяции по всему Интарнетцу.
Я считаю библиотеки Boost иметь поддержку для этого. Линейная интерполяция, а не конкретно Безье. Не цитируй меня., однако.