Форум программистов, компьютерный форум, киберфорум
Численные методы
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
0 / 0 / 0
Регистрация: 17.09.2023
Сообщений: 7

Преобразование кубического сплайна в кривую Безье

01.01.2026, 18:04. Показов 796. Ответов 5
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Столкнулся тут с тем что для SVG нет возможности отобразить сплайн, есть только кривая Безье.
Есть у меня кубический B-сплайн задан узловыми точками и массивом knots.

Необходимо сплайн преобразовать в кубическую кривую Безье. Т.е. вместо узловых точек и массива knots получить на каждый узел 3 комплекта точек с координатами (сам узел и 2 контрольные точки).

Есть у кого возможность помочь с алгоритмом? Можно за вознаграждение.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
01.01.2026, 18:04
Ответы с готовыми решениями:

Каким образом определять касательные кубического сплайна?
Здравствуйте. На основе формулы можно построить сегмент кривой через две точки и касательные....

Обеспечить совпадение на четырех точках кубического сплайна и полинома Ньютона
Здравствуйте. Подскажите, как можно обеспечить совпадение на четырех точках кубического сплайна и...

Кривая Безье в сплайн Безье
Здравствуйте. Я по специальности программист и мне нужно генерировать замкнутую кривую не...

5
2903 / 1937 / 210
Регистрация: 05.06.2011
Сообщений: 5,716
02.01.2026, 05:47
Не проще ли побить исходные отрезки на тучу маленьких, да представить кубический B-сплайн ломаной? Исходная задача-то, если и решаема, то явно нетривиальная.

Добавлено через 3 минуты
Впрочем, посмотрите вот тут. Не уверен, но что-то похожее рассматривается.
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6229 / 2930 / 1047
Регистрация: 01.06.2021
Сообщений: 10,884
02.01.2026, 14:46
Laotin, в SVG кривая Безье выглядит так

M x0 y0 C x1 y1 x2 y2 x y

M означает move to, то есть устанавливаем координату начала - x0 y0.
C означает кубическую кривую Безье, иногда используется квадратичная Q
Далее, x1 y1 x2 y2 это координаты контрольных точек для каждой из двух точек
x y это координата конечного узла

B-Spline же состоит из сегментов. Сплайны удобны во всяких интерполяциях, поэтому, полагаю, что вы получили сплайн в ходе каких-то математических вычислений и теперь хотите вывести результат в SVG.

Но судя по условию, вы и сами все это знаете.

Так вот, любой B-Spline точно можно преобразовать в кривую Безье, но если быть точнее, то не в одну, а несколько кривых Безье. По крайней мере, в общем случае B-сплайн с несколькими сегментами нельзя точно представить одной кривой Безье той же степени (требуется аппроксимация или повышение степени). Но аппроксимация означает потерю точности, а повышение степени кривой Безье для нас не вариант, поскольку SVG поддерживает только кубические и квадратичные кривые Безье. Так что, лучше просто B-Spline преобразовать в несколько кубических кривых Безье, тем более в SVG есть команда S, которая удобно "склеивает" кривые.

Цитата Сообщение от Laotin Посмотреть сообщение
Есть у кого возможность помочь с алгоритмом?
Алгоритмы давно существуют, равно как и библиотеки для конвертирования. Самый популярный алгоритм это Boehm's algorithm, который лучше, чем Oslo algorithm.
Про эти алгоритмы написано много в интернете, например, https://web.mit.edu/hyperbook/... ode18.html
Или см. документ во вложении.
Однако, я бы вместо того, чтобы читать всё это и пытаться написать код, искал бы уже готовые функции в библиотеках с открытым кодом. Просто у меня в прошлом уже был негативный опыт с чтением подобных документов, когда ты пытаешься реализовать в коде то, что написано, но не получается из-за того, что оказывается где-то в формулах была опечатка.
Лучше брать уже рабочий код откуда-то.
Кстати, есть такие B-Spline, сегменты которых уже эквиваленты кривым Безье и делать даже ничего не нужно...

Я бы на вашем месте, если нет цели досконально изучить эти алгоритмы (например, если вам лишь разок конвертировать и все), пользовался бы готовыми библиотеками. Например, я вот нашел библиотеку на языке С, называется tinyspline. Если копаться в сорцах, то можно увидеть там функцию
C
1
2
3
tsError ts_bspline_to_beziers(const tsBSpline *spline,
                      tsBSpline *beziers,
                      tsStatus *status)
которая преобразует сплайн в кривые Безье. Даже если вам нужен код не на языке С, вы все равно можете заглянуть туда и просто исследовать функции в качестве псевдокода. Преимущество данной библиотеки в том, что она маленькая, как и говорит ее название, и можно легко разобрать код.

Похожие функции для конвертирования есть и в других библиотеках, например, Open CASCADE, но думаю копаться в сорцах большой библиотеки будет сложнее.
Вложения
Тип файла: pdf bs.pdf (147.8 Кб, 20 просмотров)
1
0 / 0 / 0
Регистрация: 17.09.2023
Сообщений: 7
02.01.2026, 18:00  [ТС]
Цитата Сообщение от Royal_X Посмотреть сообщение
Я бы на вашем месте, если нет цели досконально изучить эти алгоритмы (например, если вам лишь разок конвертировать и все), пользовался бы готовыми библиотеками
К сожалению это не мой случай. Мне нужно не просто разок конвертировать, мне нужно понимать процесс, хотя бы в частном виде именно для такого случая.
То что вы добавили во вложении я тоже уже нашел и пытаюсь разобраться.
Мне бы не просто сырой код, который работает. А с пояснениями что именно происходит. Т.к. нужно сделать собственную реализацию алгоритма, в котором понимаешь весь процесс расчета.

Добавлено через 1 минуту
Цитата Сообщение от Royal_X Посмотреть сообщение
в SVG кривая Безье выглядит так
M x0 y0 C x1 y1 x2 y2 x y
M означает move to, то есть устанавливаем координату начала - x0 y0.
C означает кубическую кривую Безье, иногда используется квадратичная Q
Далее, x1 y1 x2 y2 это координаты контрольных точек для каждой из двух точек
x y это координата конечного узла
С этим все понятно. Просто не понимаю процесс преобразования knots сплайна в координаты контрольных точек.

У меня в целом ключевая проблема - как вообще контрольная точка сплайна и knots связаны с узлом и контрольными точками кривой Безье. Что то я недопонимаю, на сколько я понял в knots ключевой смысл не в его значении, а в отношении значений между соседними knots. Где то я даже прочитал что если все knots одновременно увеличить на одно и тоже значение то сам сплайн не изменится. И вот тут я не понимаю как эти knots используются для расчета контрольных точек.

Если я правильно понял в сплайне между двумя узлами с помощью knots можно вычислить кривую безье. Но дальше мне не хватает понимания процесса.
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6229 / 2930 / 1047
Регистрация: 01.06.2021
Сообщений: 10,884
02.01.2026, 23:17
Цитата Сообщение от Laotin
У меня в целом ключевая проблема - как вообще контрольная точка сплайна и knots связаны с узлом и контрольными точками кривой Безье.
Достаточно задать этот вопрос нейросети, как она все объяснит. Цитировать ее ответ не хочу, вы сами можете это сделать. Нейросеть в общих чертах неплохо объясняет, хотя и не в состоянии написать рабочий код для конвертирования.

Цитата Сообщение от Laotin Посмотреть сообщение
Т.к. нужно сделать собственную реализацию алгоритма

Laotin, я вот проверил библиотеку tinyspline, все работает правильно. Так что, неплохо бы заглянуть в реализацию данной библиотеки, если собираетесь написать нечто похожее. Снова повторюсь, что библиотека довольно маленькая и исходники очень легко воспринимаются. Одно дело изучить теорию с помощью книжек, но написание кода это совсем другое. И тут уже готовая библиотека со всеми функциями. Вы можете просто посмотреть на реализацию этих функций.
Вы даже можете брать оттуда куски кода и написать свою библиотеку для преобразования b-spline в beziers. Типа урезать ненужные функции из той библиотеки и сделать свою лёгкую библиотеку.

Вот подробности тестирования этой библиотеки:

Для входного BSpline я взял:
6 точек: { 0, 0, 1, 2, 3, 3, 4, 0, 5, -1, 6, 2 }
и вот такие knots { 0, 0, 0, 0, 1, 2, 3, 3, 3, 3 }

Написал код на С++ для получения точек кривой Безье, используя данную библиотеку:

Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <vector>
#include "tinysplinecxx.h"
 
using namespace tinyspline;
 
int main()
{
    BSpline spline(6, 2, 3); // 6 points, dimension = 2d, degree = 3
 
    
    std::vector<double> points{ 0, 0, 1, 2, 3, 3, 4, 0, 5, -1, 6, 2 };
    spline.setControlPoints(points);
 
    
    std::vector<double> knots{ 0, 0, 0, 0, 1, 2, 3, 3, 3, 3 };
    spline.setKnots(knots);
 
    std::cout << "*** Input BSpline *** \n\n";
 
    std::cout << "Number of points: " << spline.numControlPoints() << std::endl;
    std::cout << "Degree: " << spline.degree() << std::endl;
    std::cout << "Dimension: " << spline.dimension() << std::endl;
    
    std::cout << "\n*** Output Beziers *** \n\n";
 
    BSpline beziers = spline.toBeziers();
    std::cout << "Number of points: " << beziers.numControlPoints() << std::endl;
    std::cout << "Degree: " << beziers.degree() << std::endl;
    std::cout << "Dimension: " << beziers.dimension() << std::endl;
    std::cout << "Points: ";
    for (const auto& i : beziers.controlPoints())
        std::cout << i << ' ';
}


Вывод данной программы:
Кликните здесь для просмотра всего текста
Code
1
2
3
4
5
6
7
8
9
10
11
12
*** Input BSpline ***
 
Number of points: 6
Degree: 3
Dimension: 2
 
*** Output Beziers ***
 
Number of points: 12
Degree: 3
Dimension: 2
Points: 0 0 1 2 2 2.5 2.66667 2.25 2.66667 2.25 3.33333 2 3.66667 1 4.08333 0.25 4.08333 0.25 4.5 -0.5 5 -1 6 2


Теперь визуализируем в Wolfram Mathematica, чтобы убедиться, что программа нам дала правильный результат.

Этот код рисует наш оригинальный BSpline, используя функцию BSplineCurve

Haskell
1
2
3
4
5
6
7
8
p = {{0, 0}, {1, 2}, {3, 3}, {4, 0}, {5, -1}, {6, 2}};
u = {0, 0, 0, 0, 1, 2, 3, 3, 3, 3};
Graphics[{Thickness[0.005], Blue, 
  BSplineCurve[p, SplineKnots -> u, SplineDegree -> 3], 
  Thickness[0.003], Green, Line[p], Red, PointSize[0.015], Point[p]}, 
 GridLines -> {Range[-1, 7, 1], Range[-2, 4, 1]}, 
 GridLinesStyle -> Directive[Gray, Dashed], Axes -> True, 
 PlotRange -> {{-1, 7}, {-2, 4}}, AspectRatio -> Automatic]
А вот этот код рисует кривые Безье функцией BezierCurve по точкам, полученным с помощью tinyspline

Haskell
1
2
3
4
5
6
7
p = {{0, 0}, {1, 2}, {2, 2.5}, {2.66667, 2.25}, {3.33333, 
    2}, {3.66667, 1}, {4.08333, 0.25}, {4.5, -0.5}, {5, -1}, {6, 2}};
Graphics[{Thickness[0.005], Blue, BezierCurve[p, SplineDegree -> 3], 
  Thickness[0.003], Red, PointSize[0.015], Point[p]}, 
 GridLines -> {Range[-1, 7, 1], Range[-2, 4, 1]}, 
 GridLinesStyle -> Directive[Gray, Dashed], Axes -> True, 
 PlotRange -> {{-1, 7}, {-2, 4}}, AspectRatio -> Automatic]
Сравниваем картинки (на первой это исходный BSpline с 6 точками, на второй - полученные кривые Безье - всего 12 точек. Т.е. итого из сплайна мы получили три кривые Безье)



Кривые идентичны, что подтверждает правильную работу библиотеки tinyspline.
2
0 / 0 / 0
Регистрация: 17.09.2023
Сообщений: 7
07.02.2026, 15:32  [ТС]
Большое спасибо за наводку.
Реальной пользы от tinyspline не оказалось, но т.к. у меня задача не любую NURB кривую преобразовать. А конкретно B-сплайн то все оказалось до безобразия просто и одновременно сложно.
Оказалось что ключевая задача - вставка узлов в сплайн, принцип расчета количества необходимых узлов для вставки и место их вставки.
Как только это стало понятным ИИ легко подсказал код для алгоритма, кривой и нерабочий, но суть уже просматривалась, еще немного теории + отладчик и 2 простеньких процедуры выдают такой же результат как и у вас на примере.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
07.02.2026, 15:32
Помогаю со студенческими работами здесь

Получить кривую Безье заданной длины
Здравствуйте. Я программист. В процессе разработки появилась такая задача: есть два отрезка АВ...

В чем преимущество сплайна дефекта 1 над сплайном дефекта 2 ?
Помогите разобраться с вопросом,чем сплайн дефекта один превосходит сплайн дефекта 2 ? Я...

Как вычислить значение сплайна в произвольной точке
Составив трехдиагональную матрицу - я получил коеффициенты сплайна, далее я нашел еще 3...

Разработать алгоритм нахождения функции y=f(x), которая выражается либо таблицей, либо формулой сплайна
Всем привет! Подскажите, пожалуйста, в какую сторону копать. Есть задача по разработке алгоритма...

Сплайны Безье и В-сплайны
Вопрос: как построить сплайн Безье (или В-сплайн) через N точек, соединяя каждую точку кубической...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Новые блоги и статьи
Программный отбор элементов справочника Номенклатура по группе 1С
Maks 22.03.2026
Установка программного отбора элементов справочника "Номенклатура" из модуля формы документа. В качестве фильтра для отбора справочника служит группа номенклатуры. Отбор под наименованию группы (на. . .
Как я обхитрил таблицу Word
Alexander-7 21.03.2026
Когда мигает курсор у внешнего края таблицы, и нам надо перейти на новую строку, а при нажатии Enter создается новый ряд таблицы с ячейками, то мы вместо нервных нажатий Энтеров мы пишем любые буквы. . .
Krabik - рыболовный бот для WoW 3.3.5a
AmbA 21.03.2026
без регистрации и смс. Это не торговля, приложение не содержит рекламы. Выполняет свою непосредственную задачу - автоматизацию рыбалки в WoW - и ничего более. Однако если админы будут против -. . .
Программный отбор элементов справочника Сотрудники по перечислениям 1С
Maks 21.03.2026
Установка программного отбора элементов справочника "Сотрудники" из модуля формы документа. В качестве фильтра для отбора служит предопределенное значение перечислений. Процедура. . .
Переходник USB-CAN-GPIO
Eddy_Em 20.03.2026
Достаточно давно на работе возникла необходимость в переходнике CAN-USB с гальваноразвязкой, оный и был разработан. Однако, все меня терзала совесть, что аж 48-ногий МК используется так тупо: просто. . .
Оттенки серого
Argus19 18.03.2026
Оттенки серого Нашёл в интернете 3 прекрасных модуля: Модуль класса открытия диалога открытия/ сохранения файла на Win32 API; Модуль класса быстрого перекодирования цветного изображения в оттенки. . .
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-rectangles-sdl3-c. zip finish-rectangles-sdl3-cpp. zip
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая ссылка» (hard link),. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru