Подсчет длины кривой Безье
Как посчитать длину кубической Безье с 4 точками? Нашел подсчет для квадратичной Безье
var v = {};
var w = {};
v.x = 2*(p2.x - p1.x);
v.y = 2*(p2.y - p1.y);
w.x = p3.x - 2*p2.x + p1.x;
w.y = p3.y - 2*p2.y + p1.y;
var uu = 4*(Math.pow(w.x, 2) + Math.pow(w.y, 2));
if(uu < 0.00001)
{
console.log(Math.sqrt(Math.pow(p3.x - p1.x, 2) + Math.pow(p3.y - p1.y, 2)));
}
else
{
var vv = 4*(v.x*w.x + v.y*w.y);
var ww = v.x*v.x + v.y*v.y;
var t1 = (2*Math.sqrt(uu*(uu + vv + ww)));
var t2 = 2*uu+vv;
var t3 = vv*vv - 4*uu*ww;
var t4 = (2*Math.sqrt(uu*ww));
console.log(((t1*t2 - t3*Math.log(t2+t1) -(vv*t4 - t3*Math.log(vv+t4))) / (8*Math.pow(uu, 1.5))));
}
Может как-то можно сделать и для кубической?
Ответы (2 шт):
Для длины кубической кривой Безье не существует замкнутой формулы, т.к. эта длина выражается через т.н. эллиптические интегралы.
Можно делить кривую на кусочки пополам рекурсивно, пока они не станут достаточно плоскими - это стандартный процесс Bezier subdivision, и на последнем уровне вычислять длины отрезков (можно также оценивать длину дуги по хорде и апофеме). Возможно, у вас есть какой-то готовый метод типа Flatten (представить кривую как набор прямых отрезков), иначе это вполне реально сделать вручную.
Альтернатива - выполнить численное интегрирование. Например, в квадратурах Гаусса - опять же, придётся делить кривую на куски, пока не будет достигнута нужная точность.
Можно довериться браузуру, передать путь кубической Безье в SVG в качества атрибута d элемента path и взять длину кривой с помощью path.getTotalLength().
SVG скрыт, но для наглядность кривая отрисовывается на холсте (canvas).
Четыре точки кубической Безье в данном случае: [10 100] - начало, [30,40] - первая контрольная точка, [180,20] - вторая контрольная точка, [300,100] - конец кривой.
В виде строки можно сформировать так:
`M ${begin.x} ${begin.y} C ${control1.x} ${control1.y} ${control2.x} ${control2.y} ${end.x} ${end.y}`
const curve = "M 10 100 C 30 40 180 20 300 100";
document.getElementById('canvas').getContext('2d').stroke(new Path2D(curve));
const path = document.querySelector('path');
path.setAttribute('d', curve);
document.querySelector('p').textContent = path.getTotalLength();
<canvas id="canvas"></canvas>
<p id="curve-length" style="position:fixed;top:0;right:0"></p>
<svg id="svg" style="display:none"><path></path></svg>