Как получить кривую B-сплайна для соединения с конечной контрольной точкой?

У меня есть набор контрольных точек, и я пытаюсь нарисовать кубический B-сплайн (степень 3) на основе этих контрольных точек. Проблема, с которой я сталкиваюсь, заключается в том, что моя кривая не соединяется с конечной контрольной точкой, а вместо этого рисует кривую в какой-то другой точке, которая находится в другой области вместе. Кривые точки приближаются (0, 0) через определенное время.

Изображение только контрольных точек

Изображение кривой и контрольных точек. Обратите внимание, что кривая правильно начинается в первой контрольной точке, но не заканчивается в последней контрольной точке.

Код, с которым я работаю:

float Stroke::calculate_N(float t, int i, int j, vector<float> knots){
float t_1 = knots[i];
float t_2 = knots[(i + j)];
float t_3 = knots[(i + 1)];
float t_4 = knots[(i + j + 1)];

// Base case of basis function
if (j == 0){
if (t_1 <= t && t < t_3) return 1;
else return 0;
}

float temp1 = (t_2 - t_1 == 0) ? 0 : ((t - t_1) / (t_2 - t_1)) * calculate_N(t, i, j-1, knots);
float temp2 = (t_4 - t_3 == 0) ? 0 : ((t_4 - t) / (t_4 - t_3)) * calculate_N(t, i+1, j-1, knots);

return temp1 + temp2;
}

vector<float> make_knot_vector(int m, int p, int n){
vector<float> knots;
for (int i = 0; i <= p; i++){
knots.push_back(0.0);
}
for (int i = 1; i <= n - p; i++){
knots.push_back((float)i/(float)(n-p+1));
}
for (int i = 0; i <= p; i++){
knots.push_back(1.0);
}
return knots;
}

int main(){
// Init control points
s = Spline();
s.add_control_point(100,100);
s.add_control_point(232,71);
s.add_control_point(148,294);
s.add_control_point(310,115);
s.add_control_point(375,280);

// Get the number of knots based on the number of control points and degree
int num_ctrl_pts = s.get_control_points().size();
float NUM_KNOTS = (float)(num_ctrl_pts + 3 + 1);

// Draw each control point in red
for (auto pt : s.get_control_points()){
int x = pt->get_x();
int y = pt->get_y();
int r = s.get_radius();

vector<vector<float>> circle_points = calc_circ(y, x, r);
int si = circle_points.size();
for (auto circ_point : circle_points){
c->setColor(circ_point[0], circ_point[1], Color(1.0, 0.0, 0.0));
}
}

// Draw the curve
vector<float> knots = make_knot_vector(NUM_KNOTS, 3, num_ctrl_pts);
for (float t = 0.0; t < 1.0; t+= 1.0/1000.0){
Vector sum = Vector(0.0, 0.0);

for (int i = 0;i < num_ctrl_pts; i++){
Vector next = *(s.get_control_points()[i]);
float n = s.calculate_N(t, i, 3, knots);
next = next * n;
sum = sum + next;
}

cout<<"("<<(int)sum.get_x()<<", "<<(int)sum.get_y()<<")"<<endl;

// Draw the curve point in green
vector<vector<float>> circle_points = calc_circ((int)sum.get_y(), (int)sum.get_x(), s.get_radius());
for (auto circ_point : circle_points){
c->setColor(circ_point[0], circ_point[1], Color(0.0, 1.0, 0.0));
}
}

c->writeImage(path + "spline.ppm");

// delete canvas;
return 0;
}

0

Решение

Кубический B-сплайн состоит из начальной точки (узел), 2 контрольных точек и конечной точки (узел). Кривая не проходит через контрольные точки, только через узлы.

При объединении нескольких кубических B-сплайнов в форму конечная точка одного сплайна обычно является начальной точкой следующего, чтобы избежать пропусков. Чтобы кривая выглядела гладкой, этот узел и соседние контрольные точки должны быть коллинеарными (все три на одной линии).

Вы должны проверить, является ли Spline класс проводит различие между контрольными точками и узлами. Если нет, скорее всего, он просто ожидает, что каждая третья точка (начиная с первой, а затем пропуская две) будет сучком. В этом случае обязательно добавьте не менее 4 баллов, или 7, или 10, и т. Д.

Если Spline принимает только узлы (в этом случае вы должны переименовать add_control_point() функция-член add_knot()), он может рассчитать свои контрольные точки автоматически. Обычный способ сделать это путем построения Catmull-Rom сплайн. Сплайн пройдет через точки 2, 3, 4 … n-1. Чтобы добавить первый (от 1 до 2) и последний сегмент (от n-1 до n), вы обычно добавляете первую и последнюю точки дважды.

// Pseudo code:
auto spline = CatmullRom( { p1, p1, p2, p3, p4, p5, p5 } );

Лучшее решение — отразить 2-ю точку вокруг 1-й:

auto p0 = 2 * p1 - p2;
auto p6 = 2 * p5 - p4;
auto spline = CatmullRom( { p0, p1, p2, p3, p4, p5, p6 } );

0

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector