Рисование кривой через набор из N точек, где N> 2 - PullRequest
6 голосов
/ 23 июля 2011

Мне нужно нарисовать кривую плавно через N точек с N> 2 с помощью Javascript. В настоящее время я использую bezierCurveTo () в объекте html5 canvas. Я потратил много времени, пытаясь найти лучший метод для достижения этой цели, и хотя Catmull-Rom Splines кажутся многообещающими, я не знаю, как нарисовать их в виде линий. Поэтому у меня остались кривые Полилинии Безье, и мне нужно найти все промежуточные контрольные точки.

Мне потребовалось много математики, но у меня есть частично работающий пример здесь . Временами линия не особенно гладкая, и есть проблема с отключением контрольных точек для определенных векторов. Здесь - это мой первоначальный вопрос по математике , который я попросил получить основную часть математики для контрольных точек.

Я также был бы открыт для сплайнов Кэтмулла-Рома, но мне потребовалась бы некоторая помощь в том, как я могу преобразовать их в линии на холсте. Я нашел этот ресурс, но снова теряюсь в применении его для моих нужд.

Вот изображение, созданное по моей примерной ссылке выше, иллюстрирующее, как копировать плохие контрольные точки:

enter image description here

Большое спасибо за любую помощь заранее!

1 Ответ

4 голосов
/ 23 июля 2011

Оригинальный код:

var a = new Array(points[p-1].x,points[p-1].y);
var b = new Array(points[p].x,points[p].y);
var c = new Array(points[p+1].x,points[p+1].y);

var delta_a = subtract_v(a, b);
var delta_c = subtract_v(c, b);

// Get vector (m) perpendicular bisector
var m = normalize_v( add_v( normalize_v(delta_a),normalize_v(delta_c) ) );

// Get ma and mc
var ma = normalize_v( subtract_v(delta_a,multiply_v(multiply_v(delta_a,m),m) ) );
var mc = normalize_v( subtract_v(delta_c,multiply_v(multiply_v(delta_c,m),m) ) );

// Get the coordinates
points[p].c2x = resolution( b[0] + ( (Math.sqrt( sqr(delta_a[0]) + sqr(delta_a[1]) ) / tightness) * ma[0] ) );
points[p].c2y = resolution( b[1] + ( (Math.sqrt( sqr(delta_a[0]) + sqr(delta_a[1]) ) / tightness) * ma[1] ) );
points[p+1].c1x = resolution( b[0] + ( (Math.sqrt( sqr(delta_c[0]) + sqr(delta_c[1]) ) / tightness) * mc[0] ) );
points[p+1].c1y = resolution( b[1] + ( (Math.sqrt( sqr(delta_c[0]) + sqr(delta_c[1]) ) / tightness) * mc[1] ) );

Я понятия не имею, что "Get ma and mc" должен делать здесь. Вам нужен вектор, ортогональный к биссектрисе угла (m), и его отрицательный.

Sorry for the horrible drawing

Так что это должно быть хорошо:

var delta_a = subtract_v(b, a); // note that we're calculating AB instead of BA
var delta_c = subtract_v(c, b);

// Get an orthogonal to the angle bisector
var m = normalize_v( add_v( normalize_v(delta_a),normalize_v(delta_c) ) );

var ma = [-m[0],-m[1]];
var mc = m;

Также обязательно удалите resolution() для ваших контрольных точек.

Edit:
Вы также должны добавить запасной вариант для крайних случаев (например, A==B или A==C, в этом случае ваш скрипт выдаст исключение, пытаясь нормализовать вектор 0)

...