sunLoadingImage
whowedImag
decoration left 1
decoration left 2
transhome
transprojects
transgallery
transarticles
decoration rigth
English
Українська
Show/Hide search bar
black cat logo variable logo
[24 Січ 2013]

Використання та візуалізація кривих та сплайнів Без'є

Крива Без'є складається з котрольних точок. Крива проходить тільки через першу і останню контрольну точку. Вибірка позиції відбувається з допомогою параметричного значення t в інтервалі [0,1], крайні значення якого є початком і кінцем кривої. Формула для розрахунку точки кривої:
Formula for calculation of point on Bezier Curve
де:

n - кількість котрольних точок у кривій - 1

t - параметричне значення для вказання необхідної точки

Pi - i-та котрольна точка

R - розрахована точка на кривій, відповідно до t

(n,i) - біноміальний коефіцієнт

Потрібно в циклі пройтися по усім точкам кривої, та врахувати їх вплив на остаточну позицію. Біноміальний коефіцієнт розраховується як (n,i) = n!/(k!(n-k)!) і може бути попередньо прорахований і збережений в двовимірний масив. Для роботи з кривою, яка має три точки треба прорахувати біноміальні коефіцієнти для n=2, для кривої з чотирьох точок - n=3, і тп. Наприклад, для кривої з трьох точок: // n = numControlPointsInCurve-1 = 3-1 = 2
// binoms[n][i] = (n,i) = n!/(i!(n-i)!)
   binoms[2][0] = 1;   // 2!/(0!(2-0)!)
   binoms[2][1] = 2;   // 2!/(1!(2-1)!)
   binoms[2][2] = 1;   // 2!/(2!(2-2)!)
Аналогічно можна прорахувати для усіх інших n, які будуть використовуватися. Наприклад, n=1 - крива(пряма) з двох точок, n=3 - кубічна крива Без'є.
Код для розрахунку проміжних точок кривої Без'є: vec2 bezierPos(QVector<vec2> controlPoints,int numPointsPerCurve,float t){
    float ti=1.0-t;
    vec3 res=vec2(0);
    for(int i=0; i<numPointsPerCurve; i++){
        float binom = binoms[numPointsPerCurve][i];
        float level = pow(t,i) * pow(ti,numPointsPerCurve-1-i);
        res+=controlPoints[i+partOffset] * binom * level;
    }
    return res;
}
І відповідний виклик для розрахунку точки в t=0.15: numPointsPerCurve = 3; // points per curve
controlPoints = { vec2(0,0), vec2(1,1), vec2(2,0) }; // array of points
t = 0.15; // any value in [0,1]

vec2 P = bezierPos(controlPoints,numPointsPerCurve,t);
Для сплайна Без'є функцію доведеться трошки змінити. Сплайн Без'є це з'єднані криві Без'є. Кінець однієї кривої Без'є, є початком іншої. У місці зєднання похідні(дотичні) суміжних кривих мають бути рівні. Тобто три контрольні точки на стику двох кривих повинні утворювати пряму:
Bezier spline - connected Bezier curves
Наприклад, сплайн складається з numCurves кривих. Тоді для розрахунку позиції можна звертатися через t=[0...1*numCurves]. Ціле значення t буде вказувати підкриву сплайна, а дробова частина - позицію на цій підкривій. Вершини сплайна можна розмістити в одному масиві. Наприклад, сплайн з двох кривих, кожна з яких має три контрольні точки можна записати як: numPointsPerCurve = 3;
controlPoints = {vec2(0,0),vec2(1,1),vec2(2,0),vec2(3,-1),vec2(4,0)};
t = 1.15; // any value in [0,2], calculate position on 2nd curve at t=0.15
де точка vec2(2,0) є спільна для двох кривих, і лежить з суміжними точками на одній прямій.
Для розрахунку точки сплайну потрібно знайти першу вершину поточної підкривої в масиві(зсув partOffset), і звести значення t до iнтервалу [0,1].
Код для розрахунку точки сплайну Без'є: vec3 bezierPos(QVector<vec3>controlPoints,int numPointsPerCurve,float t){
    int partOffset= int(t) * (numPointsPerCurve-1);
    t = t - int(t);
    float ti=1.0-t;
    vec3 res=vec3(0,0,0);
    for(int i=0; i<numPointsPerCurve; i++){
        float binom = binoms[numPointsPerCurve][i];
        float level = pow(t,i) * pow(ti,numPointsPerCurve-1-i);
        res+=controlPoints[i+partOffset] * binom * level;
    }
    return res;
}
Візуалізацію кривої чи сплайну можна провести з допомогою їх дискретизації на скінченну кількість прямих. Наприклад розбивши на 10 прямих: float step = 1.0/10;
for(short i=0;i<9;i++){
    float t1 = step*(i);
    float t2 = step*(i+1);
    vec2 A = bezierPos(controlPoints,numPointsPerCurve,t1);
    vec2 B = bezierPos(controlPoints,numPointsPerCurve,t2);
    drawLine(A,B);
}



Sun and Black Cat- Ігор Дихта (igor dykhta email) © 2007-2014