Криві Безьє-де Кастельжо. HTML5 Canvas

image

Передмова

У вільний час вирішив зайнятися цікавою справою. В голову прийшла ідея написати невеликий фреймворк для canvas (хоч і велосипед, але теж цікаво). Справа дійшла до кривих Безьє.

Вирішив якось прикрасити вбудоване рішення, але у нього є один недолік. Проблема в тому, що функції квадратичної та кубічної кривої видають вже готовий результат, який не підлягає редагуванню. Мені ж потрібно описувати криву поступово або змалювати тільки частина кривої, не кажучи вже про те, що хотілося описувати криві більшого порядку, ніж 2-3 ступеня.

Почав гуглити. Знайшов цікаву статті на Хабре. Але мої знання математики так і не дозволили перетворити її до своїх потреб, до того ж там використовуються таймери, з-за яких зупинити анімацію вчасно не вийде.

Починаю писати з нуля.

Все виявилося не так вже й страшно. Суть алгоритму де Костельжо сама по собі проста, дак навіщо ж використовувати таку мудровану формулу? Ось я і не буду.

Коротко розповім алгоритм, а потім приклад коду.

Функція, що розраховує криву, повертає тільки точку по зсуву (тобто за відстанню від початку кривої у відсотках). Поступово збільшуючи зміщення отримуємо все нові і нові точки. Коли захочете можна і зупинити алгоритм, краса! І не потрібна купа таймерів, всього один setInteval який поступово запросить і окреслить точки.

Функція getPointOnCurve рекурсивно обчислює відрізки з переданих їй точок.
Обчисливши, по зсуву знаходить нові точки на цих відрізках, які передає далі самій собі. Продовжуючи до тих пір, поки не буде знайдена точка на кривій, яку вона поверне.

//всі потрібні функції зберігаються в об'єкті formula

formula.getPointOnCurve = function(shift,points){
if(points.length == 2){
return this.getPointOnLine(shift,points);
}
var pointsPP = [];
for(var i = 1;i < points.length;i++){

//функція getPointOnLine обчислює точку на відрізку, по зсуву. вона розглянута нижче

pointsPP.push(this.getPointOnLine(shift,[
points[i - 1],
points[i]
]));
}
return this.getPointOnCurve(shift,pointsPP);
};

Допоміжна функція getPointOnLine:

formula.getPointOnLine = function(shift,points){

//мається на увазі, що в points переданий масив виду: [[x0,y0],[x1,y1]]

return [
(points[1][0] - points[0][0]) * (shift / 100) + points[0][0],
(points[1][1] - points[0][1]) * (shift / 100) + points[0][1]
];
};

А ось і сама побудова:

//створюємо масив з контрольними точками
var points = [
[10,50],
[40,-40],
[190,180],
[40,-60],
[80,130],
[10,50]
];//так виглядає пелюстка

var shift = 0;
var step = 1;//змінна shift буде змінюватися з кроком step

var timer = setInterval(function(){
context.beginPath();

context.moveTo(points[0][0],points[0][1]);

if(shift > 101){
shift = 101;
}

for(var i = 0;i <= shift;i += step){
var coord = formula.getPointOnCurve(i,points);
context.lineTo(coord[0],coord[1]);
}

context.closePath();

if(shift <= 100){
shift += step;
}
},fps)


Ну і, звичайно ж, приклад.

Сподіваюся, кому-небудь допоміг, так як сам довго не міг розібратися.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.