Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.81/103: Рейтинг темы: голосов - 103, средняя оценка - 4.81
 Аватар для Gubila_2000
7 / 3 / 3
Регистрация: 07.11.2014
Сообщений: 218
Записей в блоге: 1

Кривая Безье

07.05.2016, 17:10. Показов 21382. Ответов 20
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Вооружился статейкой на википедии https://ru.wikipedia.org/wiki/... 1%8C%D0%B5 и использовал формулу, описаную там, в своей программе, и нифига не работает.

Вот функция факториала
C++
1
2
3
4
5
6
7
8
static long Fact (int n)  // факториал
{
    long r=1;
    for (int i = 1; i <=n; i++) {
        r*=i;
    }
    return r;
}
Вот функция базиса
C++
1
2
3
4
5
float getBasis(int i, float t)
{
 
   return (Fact(n)/(Fact(i)*Fact(n-i)))*pow(t,i)*pow(1-t,n-i);
}
Вот главная функция рисования, где p[i][1] = x и p[i][2] = y i-й точки
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void Bezier ()
{
    float step=0.01;
    int x,y;
    float gb;
    //int **res = new int*[n];
    x=p[0][1];
    y=p[0][2];
   for (int i=0; i < n; i++)
   {
 
    for (float t = 0.01; t < 1; t+=step)
        {
           gb=getBasis(i+1, t);//if (t>1)t=1;
           x+=p[i][1]*gb;
           y+=p[i][2]*gb;
           im->LineTo(x,y);
 
        }
    }
}
На выходе получается что чертится линия от первой точки вниз экрана. Возможно я не правильно понял формулу. Подскажите где ошибся.
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
07.05.2016, 17:10
Ответы с готовыми решениями:

Кривая Безье
Добрый день, подскажите пожалуйста, как реализовать отрисовку Кривых Безье. Нашел кучу теории, но не понять, как же его рисовать. По...

Кривая Безье по 4 точкам
Доброго времени суток. В общем зада стоит написать програмку где будет рисоваться кривая Безье, но меня уже берет поплава по этому поводу....

Кривая Безье на основе N точек
Доброго времени суток! Вопрос такой, существует n(допустим 500) точек, по ней нужно построить кривую Безье для сглаживания точек я...

20
Практикантроп
 Аватар для nick42
4841 / 2726 / 534
Регистрация: 23.09.2011
Сообщений: 5,798
07.05.2016, 17:34
Так не подскажешь; здесь не все ясновидящие. Попробуйте значения x и y сохранять ещё и в StringList и по окончании цикла сохраните его в файл. Станет понятно, какие там величины фигурируют.
0
place status here
 Аватар для gunslinger
3186 / 2220 / 640
Регистрация: 20.07.2013
Сообщений: 6,008
07.05.2016, 17:47
Кривая Безье по 4 точкам
Кривая Безье
1
 Аватар для Gubila_2000
7 / 3 / 3
Регистрация: 07.11.2014
Сообщений: 218
Записей в блоге: 1
08.05.2016, 12:14  [ТС]
nick42, да величины должны быть нормальные, так как я пробовал в лоб по полиному для 4-х точек и там все нормально рисуется. А вот с этой универсальной формулой с факториалами ничего не получается. К тому же все значения можно в отладчике посмотреть. Тут главный вопрос в том, что правильно ли я понял алгоритм

Добавлено через 3 минуты
gunslinger, как ни странно, я не находил этих тем, несмотря на то, что даже в гугле вбивал запрос

Добавлено через 17 часов 15 минут
Не хотите вы думать. Попрыгал с бубном около часа и наконец выстроил такую последовательность команд, которая нужна. Ошибки были в главной функции, вот рабочая:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void Bezier ()
{
    float step=0.01;
    int x,y;
    for (float t = 0.01; t <= 1; t+=step)
        {
        x=0;
        y=0;
            for (int i=0; i < n; i++)
            {
 
            x+=p[i][1]*getBasis(i, t);
            y+=p[i][2]*getBasis(i, t);
            }
            im->LineTo(x,y);
        }
}
И да, внутри getBasis нужно использовать n-1, а не n. В остальных случаях не меняется
0
place status here
 Аватар для gunslinger
3186 / 2220 / 640
Регистрация: 20.07.2013
Сообщений: 6,008
08.05.2016, 23:09
Можно так сделать (немного переделал):
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
35
36
37
38
39
40
41
42
43
44
45
const count = 10;
TPoint point[count];
//---------------------------------------------------------------------------
unsigned __int64 factor(UINT n)
{
  unsigned __int64 result = 1;
  for (UINT i = 1; i <= n; i++)
    result *= i;
  return result;
}
//---------------------------------------------------------------------------
double basis(UINT i, UINT n, double t)
{
  return factor(n-1) / factor(i) / factor(n-1-i) * pow(t, i) * pow(1-t, n-1-i);
}
//---------------------------------------------------------------------------
TPoint bezier(UINT n, double t)
{
  TPoint b = TPoint(0, 0);
  double temp;
  for (UINT i = 0; i < n; i++)
  {
    temp = basis(i, n, t);
    b.x += point[i].x * temp;
    b.y += point[i].y * temp;
  }
  return b;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ButtonClick(TObject *Sender)
{
  Refresh();
  UINT n = count, delta = 500;
  TPoint a;
  double step = 0.0001;
  randomize();
  for (UINT i = 0; i < n; i++)
    point[i] = TPoint(random(delta), random(delta));
  Canvas->MoveTo(point[0].x, point[0].y);
  for(double t = step; t <= 1; t += step)
  {
    a = bezier(n, t);
    Canvas->LineTo(a.x, a.y);
  }
}
Миниатюры
Кривая Безье  
2
place status here
 Аватар для gunslinger
3186 / 2220 / 640
Регистрация: 20.07.2013
Сообщений: 6,008
09.05.2016, 21:54
Лучший ответ Сообщение было отмечено BRcr как решение

Решение

Дополнительная "визуализация":
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
35
void __fastcall TForm1::ButtonClick(TObject *Sender)
{
  Refresh();
  UINT n = count, offset = 500, r = 3;
  TPoint a;
  TColor color = clRed;
  TColor color2 = clBlack;
  double step = 0.0001;
  randomize();
  for (UINT i = 0; i < n; i++)
    point[i] = TPoint(random(offset), random(offset));
 
  Canvas->Pen->Color = color2;
  Canvas->TextOutW(point[0].x, point[0].y, 1);
  Canvas->Ellipse(point[0].x - r, point[0].y - r, point[0].x + r, point[0].y + r);
  for (UINT i = 1; i < n; i++)
  {
    Canvas->TextOutW(point[i].x, point[i].y, i+1);
    Canvas->MoveTo(point[i-1].x, point[i-1].y);
    Canvas->LineTo(point[i].x, point[i].y);
    Canvas->Ellipse(point[i].x - r, point[i].y - r, point[i].x + r, point[i].y + r);
  }
 
  Canvas->MoveTo(point[0].x, point[0].y);
  Canvas->Pen->Color = color;
  for(double t = step; t <= 1; t += step)
  {
    a = bezier(n, t);
    Canvas->LineTo(a.x, a.y);
  }
 
//  Canvas->MoveTo(point[0].x, point[0].y);
//  Canvas->Pen->Color = clBlue;
//  Canvas->PolyBezier(point, n-1);
}
Миниатюры
Кривая Безье   Кривая Безье   Кривая Безье  

Кривая Безье   Кривая Безье   Кривая Безье  

2
394 / 194 / 48
Регистрация: 11.07.2013
Сообщений: 1,210
16.05.2017, 17:12
Повторил ваш код. Всё прекрасно получилось. Спасибо.
Однако кривая Безье, если внимательно присмотреться, получается не ровной, создаётся эффект "смазанности", хотя в

Автокаде, например, такое не наблюдается.

У вас, если присмотреться, то же самое. Как можно это исправить?
0
394 / 194 / 48
Регистрация: 11.07.2013
Сообщений: 1,210
16.05.2017, 18:39
Решение проблемы найдено.
Пришлось немного изменить функцию TPoint bezier(UINT n, double t). Выполнял на Лазарусе, поэтому, если кому интересно, можете посмотреть код здесь: Как при построении кривой Безье уменьшить разброс точек?
1
place status here
 Аватар для gunslinger
3186 / 2220 / 640
Регистрация: 20.07.2013
Сообщений: 6,008
16.05.2017, 19:05
Насколько помню, проблему решить не особо удалось.
Пробовал уменьшать шаг step, рисовать не линиями, а точками.
Хотя, если увеличить рисунок, вроде немного плавнее получается.
Вот пример общего случая (для которого кривые Безье являются частным случаем): В-сплайновые кривые
Может нужен другой подход при рисовании (для лучшего сглаживания), хотя математически в самом построении кривых вроде все верно.
Миниатюры
Кривая Безье  
0
place status here
 Аватар для gunslinger
3186 / 2220 / 640
Регистрация: 20.07.2013
Сообщений: 6,008
16.05.2017, 19:46
Долго я сообщение писал... Спасибо за решение.

Добавлено через 26 минут
В принципе можно обойтись без итогового округления.
0
394 / 194 / 48
Регистрация: 11.07.2013
Сообщений: 1,210
16.05.2017, 19:57
А есть ли какой-нибудь математический аппарат, позволяющий разбить кривую Безье (или элипс) на кокие-то элементарные фигуры (линии, дуги и пр.)? Суть такая: надо взять Автокадовский DXF-файл и при помощи его управлять положением режущего инструмента станка, при этом как можно ближе к истине отображать на экране положение инструмента. Если отправить сразу координаты узловых точек той же линии Безье, то теряется возможность отслеживать положение инструмента, если отправлять из цикла for(double t = step; t <= 1; t += step)... и одновременно отрисовывать на экране, то слабым местом будет пропускная способность линии связи.
С окружностью и прямыми всё просто: разбивается фигура на отдельные дуги или линии (от 5 до 20 мм), приращения которых передеются в исполнительное устройство. А вот с кривой Безье не всё так просто...
0
place status here
 Аватар для gunslinger
3186 / 2220 / 640
Регистрация: 20.07.2013
Сообщений: 6,008
16.05.2017, 22:16
Если я правильно понимаю, что требуется, то при (для) предварительной примерной оценки положения инструмента можно увеличить шаг step, и, если все устраивает, вернуть исходное значение шага и отрисовывать в "обычном" режиме.
0
394 / 194 / 48
Регистрация: 11.07.2013
Сообщений: 1,210
16.05.2017, 22:58
По идее всё почти так, но не совсем. Шаговые двигатели работают на скорости 20 000 микрошагов в секунду. Интерфейс связи со скоростью 19200 бит/сек. Поэтому, чтобы не останавливались двигатели (это создаст вибрацию) приходится использовать буфер упреждения, глубиной в несколько перемещений. Т.е. из буфера считываются координаты очередного перемещения, двигатели его отрабатывают, компьютер получает уведомление, отрисовывает на экране и отправляет очередные координаты в буфер. Каждая новая точка должна отличаться от предыдущей хотя бы на расстояние, на которое способны переместить двигатели режущий инструмент за время сеанса связи. Вот отсюда, собственно, и вопрос.
Нашёл учебник: Роджерс "Математические основы машинной графики" 2001 г, раздел 5-12 "Разбиение В-сплайнов", но, вероятно, поспешил, т.к. в DXF-файле очень интересная кодировка сплайнов (SPLINE). Нарисовал в AutoCAD-е,
Вложение 833391
а у себя получил
Вложение 833392
(имею ввиду не симметрию по Y, это из-за разных точек начала отсчёта, а несоответствие формы).
0
394 / 194 / 48
Регистрация: 11.07.2013
Сообщений: 1,210
16.05.2017, 23:01
Автокад:

Мой результат:
0
394 / 194 / 48
Регистрация: 11.07.2013
Сообщений: 1,210
16.05.2017, 23:51
Нашёл интересную статью на тему кривых Безье: Кривые Безье для ваших игр.rar
0
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
16.05.2017, 23:52
Цитата Сообщение от shyub Посмотреть сообщение
позволяющий разбить кривую Безье (или элипс) на кокие-то элементарные фигуры (линии, дуги и пр.)?
Дуга вообще-то совсем не элементарная, просто в станках её практически всегда реализовывают на нижнем уровне. А разбить на окружности, в принципе, можно (хотя это не будет аппроксимацией, т.к. деление как и на "точки" будет через равные промежутки расстояния). Смысл примерно следующий - берём пару соседних точек кривой, получаем одну касательную к кривой, далее - берём ещё следующую пару точек, получаем касательную к ней, далее по перпендикулярам получаем центр окружности, и её передаём. Математику мож позже напишу, но нужно чтоб оно перед получением радиуса проверяло, не параллельны ли касательные или близки к параллельным (иначе деление на 0 при получении радиуса окружности)
Миниатюры
Кривая Безье  
1
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
16.05.2017, 23:55
в этом случае вместо дуг передавать линии линии
0
394 / 194 / 48
Регистрация: 11.07.2013
Сообщений: 1,210
17.05.2017, 00:52
Спасибо. Очень понравилась ваша идея.
В последней задаче у меня были прямые и окружности. Их я разбивал на отрезки, координаты очередной точки, куда должен "приехать" рабочий инструмент (а в случае дуги - центр и угол сектора) передавал в станок. В станке использовал ARM-контроллер, который преобразовывал координаты в шаги методом Брезенхема (в случае наклонных и дуг), ну и по мере ответов станка отрисовывал их на экране.

Не по теме. Лет 10 назад увидил рекламу "буржуйского станка": кладут на станину приклад от охотничьего ружъя. Он его просканировал. Затем кладут заготовку, из которой он повторил копию. Вот, в принципе, в чём вся идея. Просканировать, правда, пока ещё не могу, поэтому первоначально использовал CorelDraw и PLT-формат, теперь хочу освоить DXF, а затем, если получится, то и сканирование. Сложности, правда, не в программировании и электронике, а в "доставании железяк" для станка.

Добавлено через 18 минут
Цитата Сообщение от TRam_ Посмотреть сообщение
через равные промежутки расстояния
Не могу оспорить (вернее хочу, но не могу доказать). А если кривая резко на этом промежутке изменяет своё направление... Вот представьте, что станок фрезерует нос Буратино. Одна точка была перед носом, а другая после. Буратино (Пинокио) будет без носа...?
0
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
17.05.2017, 01:53
Цитата Сообщение от shyub Посмотреть сообщение
А если кривая резко на этом промежутке изменяет своё направление...
тут вопрос не в резком изменении направления, а в том, как точки этой кривой обходятся (т.е. какой шаг между точками). Называется это параметризацией кривой. То что вы описываете - когда "нос" Буратино всего из 3х точек, то естественно предложенный алгоритм её не построит. А вот если точки там будут через примерно равные расстояния, то точки на нос обязательно попадут, в некотором количестве. Нос получится, возможно, менее длинным чем в оригинале, но он таки будет. Если нужно, чтоб "если делаем нос Буратино, то чтоб получился точно, даже в ущерб вибрации инструмента" - то это уже задача аппроксимации, тут шаг по кривой будет переменный, подбирать когда значение аппроксимации будет минимальным, и т.д.

Кое-что в тему - http://dxdy.ru/topic8371.html
По аппроксимации (для случая когда "для кучи точек выбираем максимально близко через них проходящую окружность") - http://prografix.narod.ru/rus_cirap.html, можно например для контроля точности разбиения применить.

И то, что разбиение с автоматически подбирающимся шагом до нас уже делали - http://www.caduser.ru/forum/in... &TID=29238

Добавлено через 9 минут
Да, и в точке "носа" будет меняться направления обхода окружности (с "по часовой" на "против часовой"). Уже и подзабыл, как это в G-кодах...
0
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
17.05.2017, 03:25
Подумал-подумал, и нашёл ошибку. В общем случае через такие 2 пары точек можно построить только дугу + прямую. Зато считать, наверно, проще - радиус берётся как расстояние от пересечения касательных до ближайшей точки, помноженное на котангенс половины угла между касательными.
Миниатюры
Кривая Безье  
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
17.05.2017, 03:25
Помогаю со студенческими работами здесь

кривой Безье
написать проектную процедуру создания кривой Безье, Желательно в С++ Добавлено через 17 часов 16 минут помогайте срочно надо(( я не...

Кривая в C++ Builder
Ребята как по задным иксам и игрекам построить кривую x1=4,y1=-4,x2=5.18,y2=2, x3=6,y3=5; x4=6.33,y4=5,8; И нужно что бы математические...

Кривая Эрмита
Доброго времени суток =) Не мог бы кто нибудь помочь с написание программы для построение &quot; кривой Эрмита &quot;. Либо скинуть...

Кривая сортировка пузырьком StringGrid
Есть код сортировки писал сам может что не учел но не могу понять кода жму на кнопку пропадает значения в 1 строке и сортирует другие...

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


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru