Новые точки на прямой выше образуются следующим образом:
L = P2 - P1, где L - длина прямой, P1 и P2 - оригинальные точки
P3 = P1 + L * 0.25, где 0.25 описанные выше 25%
P4 = P1 + L * 0.75, где 0.75 описанные выше 75%
Перед тем как перейти к реализации алгоритма Чайкина необходимо реализовать код, который будет использоваться для рисования кривой, он может выглядеть следующим образом:
// Функция рисует линию по указанным точка. function drawCurve(points) { const context = canvas.getContext("2d"); context.lineWidth = 10; context.strokeStyle = "#4663C9" context.beginPath(); context.moveTo(points[0].x, points[0].y); for (let index = 1; index < points.length; index++) { context.lineTo(points[index].x, points[index].y); } context.stroke(); }
Код выше принимает в качестве аргумента массив точек и затем рисует прямые между ними. Для тестирования нашей реализации возьмем следующую кривую:
Используя функцию drawCurve рисование кривой будет выглядеть следующим образом:
const points = [ { x: 100, y: 100 }, { x: 200, y: 100 }, { x: 200, y: 200 }, { x: 300, y: 200 }, { x: 300, y: 100 }, { x: 400, y: 100 } ] drawCurve(points)
Используя формулу из предыдущего раздела реализуем функцию smoothing, которая создает две новые точки на каждую прямую образованную между оригинальными точками переданными в качестве аргумента функции smoothing:
// Функция создает новые точки используя алгоритм Чайкина. function smoothing(points) { const result = [points[0]] let index = 0 const last_index = points.length - 1 while (index < last_index) { const first = points[index] const second = points[index + 1] // Определение длины отрезка const dx = second.x - first.x const dy = second.y - first.y // 25% и 75% относительно длины полученного отрезка result.push({x: first.x + dx * 0.25, y: first.y + dy * 0.25}) result.push({x: first.x + dx * 0.75, y: first.y + dy * 0.75}) index++ } result.push(points[last_index]) return result }
Доработаем функцию drawCurve, таким образом чтобы перед рисованием она вызывала smoothing для сглаживания кривой.
// Функция рисует линию по указанным точка. function drawCurve(points) { // Создание новых точек для сглаживания кривой points = smoothing(points) const context = canvas.getContext("2d"); context.lineWidth = 10; context.strokeStyle = "#4663C9" context.beginPath(); context.moveTo(points[0].x, points[0].y); for (let index = 1; index < points.length; index++) { context.lineTo(points[index].x, points[index].y); } context.stroke(); }
Новая версия функции drawCurve рисует следующую кривую:
На изображении выше кривая стала более плавной, но выглядит все еще ломанной. Для того, чтобы избавиться от резких углов на нашей кривой достаточно повторить алгоритм несколько раз увеличив количество точек для рисования кривой. Доработаем функцию drawCurve еще раз.
// Функция рисует линию по указанным точка. function drawCurve(points, smooth) { // Создание новых точек для сглаживания кривой for (let i = 0; i < smooth; i++) { points = smoothing(points) } const context = canvas.getContext("2d"); context.lineWidth = 10; context.strokeStyle = "#4663C9" context.beginPath(); context.moveTo(points[0].x, points[0].y); for (let index = 1; index < points.length; index++) { context.lineTo(points[index].x, points[index].y); } context.stroke(); }
Новый аргумент smooth управляет количеством итераций сглаживания, для получения плавной кривой 3 итерация будет достаточно.
const points = [ { x: 100, y: 100 }, { x: 200, y: 100 }, { x: 200, y: 200 }, { x: 300, y: 200 }, { x: 300, y: 100 }, { x: 400, y: 100 } ] drawCurve(points, 3)
Результатом работы кода выше является следующая кривая:
Алгоритм Чайкина прост в реализации, но на практике его редко используют для рисования кривых, так как есть более эффективные алгоритмы, например кривые Безье.
Весь исходный код примеров к данной статье вы можете найти на GitHub.