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

В-сплайновые кривые

10.05.2016, 12:59. Показов 4320. Ответов 17
Метки нет (Все метки)

дана формула
https://www.cyberforum.ru/cgi-bin/latex.cgi?r(t)=\sum_{k=0}^{n} N_{k}^{q}(t)*P_k

где
https://www.cyberforum.ru/cgi-bin/latex.cgi?t_{min} \leq t \leq t_{max}
https://www.cyberforum.ru/cgi-bin/latex.cgi?1 \leq q \leq n+1

https://www.cyberforum.ru/cgi-bin/latex.cgi?N_{k}^1(t)=\left\{\begin{1} [if]  t_{min} \leq t \leq t_{0} \\ 0 [if] 1 \leq q \leq n+1\right.

https://www.cyberforum.ru/cgi-bin/latex.cgi?N_{k}^q(t)=\frac{t-t_k}{t_{k+q-1}-t_k}*N_{k}^{q-1}(t)+\frac{t_{k+q}-t}{t_{k+q}-t_{k+1}}*N_{k+1}^{q-1}(t)

Напишите мне на с++ функцию, которая считает https://www.cyberforum.ru/cgi-bin/latex.cgi?N_{k}^q(t) и возвращает значение.
Я над кривой Безье очень долго думал, а тут вообще темный лес. Нужно только эту функцию, я просто не могу понять нижнюю формулу, что есть что
0

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
10.05.2016, 12:59
Ответы с готовыми решениями:

Кривые на С++
Добрый день. Есть такая задача: имеются 4 точки на плоскости, их координаты известны. При условии,...

Кривые Серпинского
Мучаюсь третий день! Не могу сделать так, чтобы порядок нужно было вводить с клавиатуры, не...

Кривые Серпинсого
На рисунке изображены кривые Серпинского 1 и 2-го порядков. Составить программу построения кривых...

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

17
случайный прохожий
1509 / 1007 / 373
Регистрация: 20.07.2013
Сообщений: 2,928
10.05.2016, 19:51 2
Это вся имеющаяся информация?
Откуда формулы взяты?

Замечания:
В предпоследней формуле второе условие выполняется всегда. Зачем тогда первое условие? И верно ли оно (как выглядит в общем случае)?
На сколько частей разбит интервал изменения параметра t?
Как N зависит от k в предпоследней формуле?
Что такое https://www.cyberforum.ru/cgi-bin/latex.cgi?{P}_{k}? Точки?
0
7 / 3 / 3
Регистрация: 07.11.2014
Сообщений: 218
Записей в блоге: 1
10.05.2016, 19:58  [ТС] 3
gunslinger, формулы взял из лекций мгту https://www.google.ru/url?sa=t... 1273,d.bGg

P_k я так понимаю, что опорные точки ломаной
0
gunslinger
10.05.2016, 20:06
  #4

Не по теме:

Гляну на досуге. Но обещать результат пока не буду.

0
случайный прохожий
1509 / 1007 / 373
Регистрация: 20.07.2013
Сообщений: 2,928
12.05.2016, 02:00 5
Лучший ответ Сообщение было отмечено Gubila_2000 как решение

Решение

Выкладываю, что получилось, а получилось не очень.
Насколько понимаю, нужно еще выбирать значения узлов t (тут внимательней надо теорию просматривать).
В любом случае, может часть кода тебе пригодится, а я на данный момент пас.
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
 
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
const count = 4;
TPoint point[count];
double tmin = 0., tmax = 200.;
double step = count-1. + count + 1;
 
double N(UINT q, UINT k, double t)
{
  if (q == 1)
  {
    if (t >= tmin + step * k && t <= tmin + step * (k + 1))
      return 1;
    else
      return 0;
  }
  else
    return (t - tmin - step * k) / (tmin + step * (k + q + 1) - tmin - step * k) * N(q-1, k, t) +
           (tmin + step * (k + q) - t) / (tmin + step * (k + q) - tmin - step * (k + 1)) * N(q-1, k+1, t);
}
//---------------------------------------------------------------------------
TPoint R(UINT q, double t)
{
  TPoint b = TPoint(0, 0);
  double temp;
  for (UINT i = 0; i <= count; i++)
  {
    temp = N(q, i, 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-1, offset = 500, r = 3;
  TPoint a;
  TColor color = clRed;
  TColor color2 = clBlack;
  double step = 0.001;
  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 = tmin + step; t <= tmax; t += step)
  {
    a = R(n, t);
    if (fabs(a.x) > 10 && fabs(a.y) > 10)
      Canvas->LineTo(a.x, a.y);
  }
 
//  Canvas->MoveTo(point[0].x, point[0].y);
//  Canvas->Pen->Color = clBlue;
//  Canvas->PolyBezier(point, n-1);
}
//---------------------------------------------------------------------------
2
Миниатюры
В-сплайновые кривые  
случайный прохожий
1509 / 1007 / 373
Регистрация: 20.07.2013
Сообщений: 2,928
14.05.2016, 14:11 6
Подправил немного (но до "истины" еще далеко):
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
//---------------------------------------------------------------------------
 
#include <vcl.h>
#pragma hdrstop
 
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
const count = 4;
TPoint point[count];
double tmin = 0., tmax = 6.;
double step = (tmax-tmin) / (count-1 + count-1);
 
double N(UINT q, UINT k, double t)
{
  if (q == 1)
  {
    if (t >= tmin + step * k && t <= tmin + step * (k + 1))
      return 1;
    else
      return 0;
  }
  else
    return (t - tmin - step * k) / (tmin + step * (k + q + 1) - tmin - step * k) * N(q-1, k, t) +
           (tmin + step * (k + q) - t) / (tmin + step * (k + q) - tmin - step * (k + 1)) * N(q-1, k+1, t);
}
//---------------------------------------------------------------------------
TPoint R(UINT q, double t)
{
  TPoint b = TPoint(0, 0);
  double temp;
  for (UINT i = 0; i < count; i++)
  {
    temp = N(q, i, 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-1, q = n, offset = 500, r = 3;
  TPoint a;
  TColor color = clRed;
  TColor color2 = clBlack;
  double st = 0.00001*1;
  randomize();
  for (UINT i = 0; i < count; 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->Pen->Color = color;
  for(double t = tmin + 0*step; t <= tmax - 0*step; t += st)
  {
    a = R(q, t);
    if (t <= tmin + 2*step || t > tmax - 2*step)
    {
      Canvas->MoveTo(a.x, a.y);
//    Canvas->Pen->Color = color2;
    }
    else
    {
      Canvas->LineTo(a.x, a.y);
//    Canvas->Pen->Color = color;
    }
  }
}
//---------------------------------------------------------------------------
Замечание по коду: если st выбирать равным step, то получим следующее
В-сплайновые кривые


если же уменьшать st, то
В-сплайновые кривые


Я почти что уверен, что проблема по крайней мере в выборе точек https://www.cyberforum.ru/cgi-bin/latex.cgi?{t}_{k}.
Возможно, они должны быть не равномерно распределены в диапазоне от https://www.cyberforum.ru/cgi-bin/latex.cgi?{t}_{min} до https://www.cyberforum.ru/cgi-bin/latex.cgi?{t}_{max}, а выбраны исходя из соображений на стр. 14 документа из поста №3 (либо см. вложение).
1
Миниатюры
В-сплайновые кривые  
7 / 3 / 3
Регистрация: 07.11.2014
Сообщений: 218
Записей в блоге: 1
14.05.2016, 14:13  [ТС] 7
gunslinger,

В первоначальном виде все работает нормално, но стоило мне просто добавить свой ввод, как програма стала вылетать с ошибкой деления на ноль. Из-за чего это может быть?
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
TForm3 *Form3;
//---------------------------------------------------------------------------
__fastcall TForm3::TForm3(TComponent* Owner)
    : TForm(Owner)
{
#define ic Image1->Canvas
}
int count, flag=0;
TPoint point[100];
double tmin = 0., tmax = 200.;
double step = count-1. + count + 1;
 
double N(UINT q, UINT k, double t)
{
  if (q == 1)
  {
    if (t >= tmin + step * k && t <= tmin + step * (k + 1))
      return 1;
    else
      return 0;
  }
  else
    return (t - tmin - step * k) / (tmin + step * (k + q + 1) - tmin - step * k) * N(q-1, k, t) +
           (tmin + step * (k + q) - t) / (tmin + step * (k + q) - tmin - step * (k + 1)) * N(q-1, k+1, t);
}
//---------------------------------------------------------------------------
TPoint R(UINT q, double t)
{
  TPoint b = TPoint(0, 0);
  double temp;
  for (UINT i = 0; i < count; i++)
  {
    temp = N(q, i, t);
    b.x += point[i].x * temp;
    b.y += point[i].y * temp;
  }
  return b;
}
//---------------------------------------------------------------------------
void __fastcall TForm3::Button1Click(TObject *Sender)
{
 
    if (flag) {
    Refresh();
    UINT n = count-1;
    TPoint a;
 
    double step = 0.001;
 
     for(double t = tmin + step; t <= tmax; t += step)
    {
        a = R(n, t);
        if (a.x > 10 && a.y > 10)
          ic->LineTo(a.x, a.y);
     }
     flag=0;
} else count = 0;
flag=1;
}
//---------------------------------------------------------------------------
void __fastcall TForm3::Image1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift,
          int X, int Y)
{
ic->Pen->Width=10;
ic->Pen->Color=clBlack;
point[count]= TPoint(X,Y);
ic->MoveTo(X,Y);
ic->LineTo(X,Y);
if (count) {
   ic->Pen->Width=3;
   ic->Pen->Color=clSilver;
   ic->MoveTo(point[count-1].X, point[count-1].Y);
   ic->LineTo(X,Y);
}
count++;
}
0
случайный прохожий
1509 / 1007 / 373
Регистрация: 20.07.2013
Сообщений: 2,928
14.05.2016, 14:21 8
В документе (стр. 4, внизу) написано по этому поводу - если знаменатель равняется 0, то нужно считать выражение (дробь), содержащее этот знаменатель, равным нулю.
Смотри функцию N().
P.S.: в твоем коде строке №53 не обязательна, я использовал ее для теста.
Можно убрать либо заменить 10 на 0. Лучше первый вариант.
0
7 / 3 / 3
Регистрация: 07.11.2014
Сообщений: 218
Записей в блоге: 1
14.05.2016, 14:25  [ТС] 9
gunslinger, просто странно, что в расчетах я вообще ничего не менял, даже ставил 4 точки, все равно выбивает с ошибкой, а когда count была константой этой ошибки небыло
0
случайный прохожий
1509 / 1007 / 373
Регистрация: 20.07.2013
Сообщений: 2,928
14.05.2016, 14:34 10
И step у меня изначально считался неправильно.
P.S.: значит, ты что-то поменял, что влияет.
Нужно смотреть.

Добавлено через 6 минут
Я сейчас глянуть не могу, только если позже.
0
7 / 3 / 3
Регистрация: 07.11.2014
Сообщений: 218
Записей в блоге: 1
14.05.2016, 19:05  [ТС] 11
gunslinger, нет проблем. Если сам разберусь, то отпишусь

Добавлено через 3 часа 30 минут
Понятия не имею что я изменил, но программа перестала ругаться на деление на ноль и стала рисовать, однако программа стала капризничать и не выполнять некоторые команды. Например не хочет менять цвет и толщину линии, несмотря на то, что я эти команды поместил в тело основной функции. Во время отрисовки сплайна все настройки сбрасывается и рисуется черная линия толщиной 1. И рисовать начинает из левого верхнего угла (1,1).

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
TForm3 *Form3;
//---------------------------------------------------------------------------
__fastcall TForm3::TForm3(TComponent* Owner)
    : TForm(Owner)
{
#define ic Image1->Canvas
}
int  flag=0, nc=0;
int count=4;
TPoint point[100];
double tmin = 0., tmax = 6.;
double step = (tmax-tmin) / (count-1 + count-1);
 
double N(UINT q, UINT k, double t)
{
  if (q == 1)
  {
    if (t >= tmin + step * k && t <= tmin + step * (k + 1))
      return 1;
    else
      return 0;
  }
  else
    return (t - tmin - step * k) / (tmin + step * (k + q + 1) - tmin - step * k) * N(q-1, k, t) +
           (tmin + step * (k + q) - t) / (tmin + step * (k + q) - tmin - step * (k + 1)) * N(q-1, k+1, t);
}
//---------------------------------------------------------------------------
TPoint R(UINT q, double t)
{
  TPoint b = TPoint(0, 0);
  double temp;
  for (UINT i = 0; i < count; i++)
  {
    temp = N(q, i, t);
    b.x += point[i].x * temp;
    b.y += point[i].y * temp;
  }
  return b;
}
//---------------------------------------------------------------------------
void __fastcall TForm3::Button1Click(TObject *Sender)
{
 
    if (flag)
     {
        Refresh();
        UINT n = count-1;
        TPoint a;
        double st = 0.0001;
        double step = 0.001;
        ic->MoveTo(point[0].x,point[0].y);
        ic->Pen->Color=clRed;
        ic->Pen->Width=3;
        for(double t = tmin + step*0; t <= tmax - step*0; t += st)
        {
 
            a = R(n, t);
           /*   if (t <= tmin + 0*step || t > tmax - 0*step)
            {
                 Canvas->MoveTo(a.x, a.y);
 
            }
            else
            { */
                Canvas->LineTo(a.x, a.y);
 
            //}
        }
        flag=0;
     } else {count = 0; flag=1; ic->MoveTo(1,1);}
 
}
//---------------------------------------------------------------------------
void __fastcall TForm3::Image1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift,
          int X, int Y)
{
ic->Pen->Width=10;
ic->Pen->Color=clBlack;
point[count]= TPoint(X,Y);
ic->MoveTo(X,Y);
ic->LineTo(X,Y);
if (count) {
   ic->Pen->Width=3;
   ic->Pen->Color=clSilver;
   ic->MoveTo(point[count-1].X, point[count-1].Y);
   ic->LineTo(X,Y);
}
 
count++;
}
Но даже если не смотреть на это кривая выглядит чересчур страшной)

Добавлено через 47 минут
Вот на шарпе готовая программа, но тут много лишнего
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
 
namespace b_spline
{
    public partial class Form1 : Form
    {
        public struct mypanel // создаём структуру, содержащую 
        {
            //панель, на которой расположены
            public Panel pan;
            //два поля для ввода координат
            public TextBox tbxx;
            public TextBox tbxy;
            //  и надписи X и Y.
            public Label lx;
            public Label ly;
        }
        public mypanel temp; //с помощью этой переменной будем инициализировать новые панели
        private List<mypanel> pnls;// список панелей, в котором будут храниться все наши панели
        public int pnls_num;// количество элементов в списке
        public PointF[] coords; // массив точек, в который будем загружать записанные в текстбоксы данные из списка панелей
        private float[] a = new float[4];// массив для рассчёта коэффициентов а
        private float[] b = new float[4];// для рассчёта коэффициентов b
        public Graphics graph;// поверхность для рисования
        public Bitmap btmp;// рисунок
        public Pen axis_pen = new Pen(Color.Black, 1);//  для рисования осей
        public Pen spline_pen = new Pen(Color.Blue, 1); //  для рисования сплайна
        public SolidBrush points_brush= new SolidBrush(Color.Red); // для рисования опорных точек
        public Form1()
        {
            this.InitializeComponent();
        }
        private void load_Form(object sender, EventArgs e)
        {
            load();
        }// обработка события " загрузка формы"
        public void load()
        {
            temp = new mypanel();// создаем новый объект типа mypanel, из которого будем передавать данные в список
            // инициализируем уже  существующими элементами (для удобства построения
            temp.pan = panel12;
            temp.tbxx = TextBox23;
            temp.tbxy = TextBox24;
            temp.lx = label23;
            temp.ly = label24;
            pnls = new List<mypanel>(4);// инициализируем список панелей (минимум 4 точки)
            pnls.Add(temp);// добавляем существующую панель в список
            for (int i = 1; i < 4; i++)
                pnls.Add(new_Panel(pnls[i - 1])); //создаём еще 3 панели 
            pnls_num = 4;// устанавливаем счётчик
        }
        public void Add_to_control(mypanel panel)
        {
            // добавляем родителей каждому элементу структуры. Это необходимо для отображения на экране
            flowLayoutPanel1.Controls.Add(panel.pan);
            panel.pan.Controls.Add(panel.tbxx);
            panel.pan.Controls.Add(panel.tbxy);
            panel.pan.Controls.Add(panel.lx);
            panel.pan.Controls.Add(panel.ly);
        }
        public mypanel new_Panel(mypanel sender)
        {
            //инициализируем объект mypanel и объекты, которые к нему подсоединим
            temp = new mypanel();
            temp.pan = new Panel();// панель, содержащая боксы и надписи
            temp.lx = new Label();
            temp.ly = new Label();
            temp.tbxx = new TextBox();// бокс для ввода x
            temp.tbxy = new TextBox();// бокс для ввода y
            temp.pan.Location = new Point(3, 28*sender.pan.Location.Y + 3);// каждую новую панель сдвигаем на 28 пикселов вниз
            temp.pan.Name = "panel" + temp.pan.Location.Y;// имя
            temp.pan.Size = new Size(152, 25);// размер
            temp.lx.Font = temp.ly.Font = new Font("Times New Roman", 6.75F, FontStyle.Bold, GraphicsUnit.Point, 204);//параметры шрифта
            temp.lx.Margin = temp.ly.Margin = new Padding(0);//внешняя граница не видна
            temp.lx.Size = temp.ly.Size = new Size(14, 11);// размер
            temp.lx.Text = "X:";// текст в label'ах
            temp.ly.Text = "Y:";
            //координаты label lx и ly
            temp.lx.Location = new Point(1, 7);//координаты
            temp.ly.Location = new Point(75, 6);
            temp.lx.Name = "temp.lx" + temp.pan.Location.Y;// имена
            temp.ly.Name = "temp.ly" + temp.pan.Location.Y;
            temp.tbxx.Size = temp.tbxy.Size = new Size(60, 20);
            temp.tbxx.KeyPress += (this.key_press);// добавляем функцию обработки ввода
            temp.tbxy.KeyPress += (this.key_press);
            temp.tbxx.Location = new Point(15, 2);//координаты
            temp.tbxy.Location = new Point(89, 2);
            temp.tbxx.Name = "temp.tbxx" + temp.pan.Location.Y;//имена
            temp.tbxy.Name = "temp.tbxy" + temp.pan.Location.Y;
            temp.tbxx.TabIndex = 1;//очерёдность переключения с помощью Tab
            temp.tbxy.TabIndex = 2;
            Add_to_control(temp);// добавляем к родителям
            return temp;// возвращаем готовый элемент списка
        }
        private int is_not_empty(TextBox tbx)// проверка заполненности поля ввода координат (возвращает содержимое)
        {
            int res;// создаем результат типа int (можно вводить только целые значения)
            if (!Int32.TryParse(tbx.Text, out res))// проверяем введено ли значение
                res = Int32.MaxValue;// если нет, то присваиваем результату 2^32 (не самый лучший способ, но размеры экрана всё-таки намного меньше)
            return res;// возвращаем полученнное значение
         }
        private void key_press(object s, KeyPressEventArgs e)// проверка ввода
        {
            TextBox sender = (TextBox) s;// знаем, что событие создает TextBox, поэтому производим приведение типов
 
            if (e.KeyChar != 22)// если не производится вставка
                // Handled- это свойство KeyPressEventArgs, которое показывает, обработано ли нажатие клавиши
                // проверяем ввод Разрешено вводить "-" первым символом, цифру и нажимать Backspace
                if (!Char.IsDigit(e.KeyChar) && e.KeyChar != (char) Keys.Back &&
                    (e.KeyChar != '-' || (sender).SelectionStart != 0 ||
                     ((sender).Text.Contains("-") && !(sender).SelectedText.Contains("-"))))
                    e.Handled = true;
        }
        private void Add_field(object sender, EventArgs e)// если нажали кнопку "Добавить", появляется новая панель
        {
            pnls.Add(new_Panel(pnls[pnls.Count - 1]));
            pnls_num++;
        }
        private void Delete_field(object sender, EventArgs e)// по нажатию кнопки "Удалить" удаляется панель, если их количество больше 4
        {
            if (pnls_num > 4)
            {
                pnls[pnls.Count - 1].pan.Dispose();
                pnls.RemoveAt(pnls.Count - 1);
                pnls_num--;
            }
        }
        public void Calculate(object sender, EventArgs e)
        {
            //в функции производится считывание данных из TextBox'ов
            //проверка корректности и вызов функции рассчёта и отображения точек и сплайна
            bool correct_input = true; // флаг правильного ввода
            coords = new PointF[pnls_num + 2];// создаём массив точек, в которые помещаем данные из текстбоксов
            for (int i = 0; i < pnls_num; i++)// считываем данные из всех текстбоксов
            {
                if ((coords[i + 1].X = is_not_empty(pnls[i].tbxx)) == Int32.MaxValue ||// проверяем правильный ввод
                    (coords[i + 1].Y = is_not_empty(pnls[i].tbxy)) == Int32.MaxValue)
                {
                    correct_input = false;// если неправильный, то выходим из цикла
                    break;
                }
            }
            if (correct_input == false)// ошибка
                MessageBox.Show("Рассчёт не может быть произведён.\r\nНеверно (неполностью) заполнены поля ввода.");
            else
            {
                btmp = new Bitmap(pictureBox1.Width , pictureBox1.Height);// инициализируем битмап
                // для правильного отображения сплайна необходимо дважды добавить первую и последнюю точку
                coords[0] = coords[1];
                coords[pnls_num + 1] = coords[pnls_num];
                pictureBox1.Refresh();// обновляем pictureBox(стираем старое)
                graph = Graphics.FromImage(btmp);// инициализируем поверхность для рисования
                graph.TranslateTransform(pictureBox1.Width/2, pictureBox1.Height/2);// переносим начало координат в центр
                graph.ScaleTransform(1, -1);// меняем направление оси Y
                //рисуем координатные оси
                graph.DrawLine(axis_pen, 0, -pictureBox1.Height / 2, 0, pictureBox1.Height / 2);
                graph.DrawLine(axis_pen, -pictureBox1.Width / 2, 0,pictureBox1.Width / 2 , 0);
                Draw_spline();// рисуем сплайн
                Draw(null, null);// рисуем опорные точки
            }
        }
        public void Draw(object sender, PaintEventArgs e)
        {
            for (int i = 1; i < pnls_num+1; i++)
                graph.FillRectangle(points_brush, coords[i].X - 1, coords[i].Y - 1, 3, 3);// точки рисуются прямоугольниками
            pictureBox1.BackgroundImage = btmp;// переносим на битмап
        }
        public void Draw_spline()
        {
            for (int i = 1; i < pnls_num; i++)// в цикле по всем четвёркам точек
            {
                Coefficient(i);// считаем коэффициенты
                PointF[] points=new PointF[100];// создаём массив промежуточных точек
                for(int j=0;j<100;j++)
                {
                    float t = (float)((float)j/100);// шаг интерполяции
                    // передаём массиву точек значения по методу beta-spline
                    points[j].X = (a[0] + t * (a[1] + t * (a[2] + t * a[3])));
                    points[j].Y = (b[0] + t * (b[1] + t * (b[2] + t * b[3])));
                }
                graph.DrawCurve(spline_pen, points,0.1f);// рисуем кривую по полученным точкам
            }
        }
        public void Coefficient(int i)// в функции рассчитываются коэффициенты a0-a3, b0-b3
        {
            a[3] = (-coords[i - 1].X + 3*coords[i].X - 3*coords[i + 1].X + coords[i + 2].X)/6;
            a[2] = (coords[i - 1].X - 2*coords[i].X + coords[i + 1].X)/2;
            a[1] = (-coords[i - 1].X + coords[i + 1].X)/2;
            a[0] = (coords[i - 1].X + 4*coords[i].X + coords[i + 1].X)/6;
            b[3] = (-coords[i - 1].Y + 3*coords[i].Y - 3*coords[i + 1].Y + coords[i + 2].Y)/6;
            b[2] = (coords[i - 1].Y - 2*coords[i].Y + coords[i + 1].Y)/2;
            b[1] = (-coords[i - 1].Y + coords[i + 1].Y)/2;
            b[0] = (coords[i - 1].Y + 4*coords[i].Y + coords[i + 1].Y)/6;
        }
    }
}
http://grafika.me/node/408

Добавлено через 6 минут
0
случайный прохожий
1509 / 1007 / 373
Регистрация: 20.07.2013
Сообщений: 2,928
15.05.2016, 03:41 12
Лучший ответ Сообщение было отмечено BRcr как решение

Решение

Нашел хорошее описание алгоритма (коротко и ясно): http://mathworld.wolfram.com/B-Spline.html

Код на его основе:
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
const count = 7, m = 9;
TPoint point[count];
double tmin = 0, tmax = 1, t[m+1] = {tmin, 0, 0, 0.2, 0.4, 0.6, 0.8, 1, 1, tmax};
int n = count - 1, p = m - n - 1;
 
double N(UINT i, UINT j, double T)
{
  if (j == 0)
  {
    if (T >= t[i] && T < t[i+1])  // && t[i+1] > t[i])
      return 1;
    else
      return 0;
  }
  else
  {
    double memb1 = (t[i+j] - t[i]) ? (T - t[i]) / (t[i+j] - t[i]) : 0,
           memb2 = (t[i+j+1] - t[i+1]) ? (t[i+j+1] - T) / (t[i+j+1] - t[i+1]) : 0;
    return memb1 * N(i, j-1, T) + memb2 * N(i+1, j-1, T);
  }
}
//---------------------------------------------------------------------------
TPoint C(UINT p, double T)
{
  TPoint b = TPoint(0, 0);
  double temp;
  for (int i = 0; i <= n; i++)
  {
    temp = N(i, p, T);
    b.x += point[i].x * temp;
    b.y += point[i].y * temp;
  }
  return b;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ButtonClick(TObject *Sender)
{
  Refresh();
  UINT offset = 500, r = 3;
  double step = 0.0001;
  TPoint a;
  TColor color = clRed;
  TColor color2 = clBlack;
  randomize();
  for (int 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 (int 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);
  }
 
  for(double T = tmin; T <= tmax; T += step)
  {
    a = C(p, T);
    Canvas->Pixels[a.x][a.y] = color;
  }
}
В-сплайновые кривые


Замечание: при некоторых значениях параметра p (обычно когда он > 2), сплайн проходит через левый верхний угол.
Причину пока выяснить не удалось.
Формулу (p = m - n - 1) менять не стоит, можешь изменять count и/или m, а также точки t. Но учти, что они (точки) должны быть неубывающей последовательностью.

В-сплайновые кривые
2
случайный прохожий
1509 / 1007 / 373
Регистрация: 20.07.2013
Сообщений: 2,928
16.05.2016, 05:50 13
Лучший ответ Сообщение было отмечено Gubila_2000 как решение

Решение

Выяснил причину. Нужно было соответствующим образом выбирать узловые точки https://www.cyberforum.ru/cgi-bin/latex.cgi?{t}_{i}.
Теперь можно строить сплайны вплоть до степени p = 4. Хотя третьей степени вроде достаточно.
Можешь поэкспериментировать.
ехе для случая p = 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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
const count = 7, m = 10;
TPoint point[count];
double tmin = 0, tmax = 1, t[m+1] = {tmin, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, tmax};
int n = count - 1, p = m - count;  // p = m - n - 1;
 
double N(UINT i, UINT j, double T)
{
  if (j == 0)
  {
    if (T >= t[i] && T < t[i+1])  // && t[i+1] > t[i])
      return 1;
    else
      return 0;
  }
  else
  {
    double memb1 = (t[i+j] - t[i]) ? (T - t[i]) / (t[i+j] - t[i]) : 0,
           memb2 = (t[i+j+1] - t[i+1]) ? (t[i+j+1] - T) / (t[i+j+1] - t[i+1]) : 0;
    return memb1 * N(i, j-1, T) + memb2 * N(i+1, j-1, T);
  }
}
//---------------------------------------------------------------------------
TPoint C(UINT p, double T)
{
  TPoint b = TPoint(0, 0);
  double temp;
  for (int i = 0; i <= n; i++)
  {
    temp = N(i, p, T);
    b.x += point[i].x * temp;
    b.y += point[i].y * temp;
  }
  return b;
}
//---------------------------------------------------------------------------
void init()
{
  for (int i = 1; i <= p; i++)
  {
    t[i] = tmin;
    t[m-i] = tmax;
  }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ButtonClick(TObject *Sender)
{
  Refresh();
  init();
  UINT offset = 25, range = 500 - 2 * offset, r = 3;
  double step = 1e-5;
  TPoint a;
  TColor color = clRed;
  TColor color2 = clGray;
  randomize();
  for (int i = 0; i <= n; i++)
    point[i] = TPoint(offset + random(range), offset + random(range));
 
  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 (int 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);
  }
 
  if (p * 2 <= m - 1)
    for(double T = tmin; T <= tmax; T += step)
    {
      a = C(p, T);
      Canvas->Pixels[a.x][a.y] = color;
    }
  else
    MessageBox(Application->Handle, String("Должно выполняться условие\n\nm-1 >= 2p\n\nПри m=" + String(m) + ", p=" + String(p) + " оно не соблюдается.").c_str(), L"Ошибка", 0);
}
1
Миниатюры
В-сплайновые кривые  
Вложения
Тип файла: zip bspline.zip (1.36 Мб, 58 просмотров)
7 / 3 / 3
Регистрация: 07.11.2014
Сообщений: 218
Записей в блоге: 1
16.05.2016, 17:37  [ТС] 14
gunslinger, Насколько я понял в ходе подбора, если count не константа, а изменяется, то m изменяется по правилу m=count*2-1;
0
случайный прохожий
1509 / 1007 / 373
Регистрация: 20.07.2013
Сообщений: 2,928
16.05.2016, 18:01 15
m никак не зависит от count.
m+1 - количество узловых точек.
count - количество контрольных точек.
n = count - 1, p = m - count.

В-сплайновые кривые


Функция init() дублирует точки для правильного построения сплайна.

Можно условие
C++
1
if (p * 2 <= m - 1)
заменить на
C++
1
if (p < 5 && p > 0)
Тут добавлено условие, что p должно быть положительным числом.

Тогда строка
C++
1
MessageBox(Application->Handle, String("Должно выполняться условие\n\nm-1 >= 2p\n\nПри m=" + String(m) + ", p=" + String(p) + " оно не соблюдается.").c_str(), L"Ошибка", 0);
меняется на
C++
1
MessageBox(Application->Handle, String("Должно выполняться условие\n\np > 0 и p < 5\n\nПри p=" + String(p) + " оно не соблюдается.").c_str(), L"Ошибка", 0);
0
Изображения
 
случайный прохожий
1509 / 1007 / 373
Регистрация: 20.07.2013
Сообщений: 2,928
16.05.2016, 18:18 16
Что касается твоего утверждения, то ты не до конца понял - просто должно выполняться условие
m <= count*2-1 (или m < count*2).
Плюс m > count (или m >= count+1).
Либо двойное условие для p постом выше (p < 5 && p > 0).
Повторю еще раз, зависимости между m и count в любом случае никакой нет.
0
случайный прохожий
1509 / 1007 / 373
Регистрация: 20.07.2013
Сообщений: 2,928
16.05.2016, 21:57 17
Сделал на основе вышеприведенного кода программу-заставку.
Для больных эпилепсией просьба использовать на свой страх и риск, так как смена фона может быть достаточно резкой, хоть и происходит не с большой частотой.
0
Миниатюры
В-сплайновые кривые  
Вложения
Тип файла: zip bspline_scr.zip (1.38 Мб, 13 просмотров)
случайный прохожий
1509 / 1007 / 373
Регистрация: 20.07.2013
Сообщений: 2,928
16.05.2016, 22:20 18
Немного подправил смену цвета.
0
Вложения
Тип файла: zip bspline_scr.zip (1.38 Мб, 27 просмотров)
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
16.05.2016, 22:20

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Кривые Безье
Добрый вечер! Помогите, пожалуйста! Никак не могу разобраться с кривыми Безье :cry: Мне нужно...

Эллиптические кривые
Не подскажете, что можно почитать про эллиптические кривые на средне-популярном уровне? Скажем, на...

Эллиптические кривые
Доброго времени суток! Нуждаюсь в помощи людей, которые разбираются в этом хоть чуточку лучше меня....

полиномиальные кривые
Здравствуйте! Задание: Z-функции (zmf), PI-функции (pimf) и S-функции (smf). Функция zmf...

Кривые Безье
Имеется задание: С помощью кубических кривых Безье нарисовать первую букву своего имени(Русский или...

кривые зеркала
Есть сайтик. все было норм. 10 стр в индексе, их и есть 10. сегодня смотрю - 14 добавило 4...


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

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.