using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
Graphics g;
Random rnd1 = new Random(11);
float[,] ctrlArray;
double[] knots;
double t_step = 0.01;
int n, k;
PointF startCoordOffset;
public Form1()
{
InitializeComponent();
g = pictureBox1.CreateGraphics();
startCoordOffset = new PointF(pictureBox1.Width / 2, pictureBox1.Height / 2);
g.TranslateTransform(startCoordOffset.X, startCoordOffset.Y);
t_step = (double)trackBar3.Value / 1000;
}
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void buildToolStripMenuItem_Click(object sender, EventArgs e)
{
n = trackBar1.Value;
k = trackBar2.Value;
generateCtrlArray(n);
drawBSpline(n, k);
}
private void drawBSpline(int n, int k) // n - кол-во точек, k - порядок
{
g.Clear(Color.White);
g.DrawString("n = " + n.ToString() + "; k = " + k.ToString(), new Font("Arial", 14), Brushes.Black,
-startCoordOffset.X + 10,
-startCoordOffset.Y + 10
);
knots = getKnots(n, k);
double t, t_max;
List<Tuple<PointF, int> > pointsList = new List<Tuple<PointF, int> >();
List<Pen> pensList = new List<Pen>();
for (int index = 1; index < knots.Length; ++index)
{
t = knots[index - 1];
t_max = knots[index];
Pen tempPen = new Pen(new SolidBrush(Color.FromArgb(190, rnd1.Next() % 256, rnd1.Next() % 256, rnd1.Next() % 256)), 3);
bool penAdded = false;
while (t < t_max) {
float x = 0, y = 0;
for (int i = 0; i < n; ++i)
{
float curN = (float)getNik(t, i, k);
x += ctrlArray[i, 0] * curN;
y += ctrlArray[i, 1] * curN;
}
if (!penAdded) {
pensList.Add(tempPen);
penAdded = true;
}
pointsList.Add(new Tuple<PointF, int>(new PointF(x, y), pensList.Count - 1));
t += t_step;
}
}
PointF prevPoint = new PointF();
foreach (Tuple<PointF, int> point in pointsList) {
double dist = 0,
limit = trackBar3.Value + 1;
if (prevPoint != null) {
dist = Math.Sqrt((prevPoint.X - point.Item1.X) * (prevPoint.X - point.Item1.X)
+ (prevPoint.Y - point.Item1.Y) * (prevPoint.Y - point.Item1.Y));
}
if (dist < limit) {
g.DrawEllipse(pensList[point.Item2], point.Item1.X, point.Item1.Y, 2, 2);
}
prevPoint = point.Item1;
}
}
private double getNik(double t, int i, int k)
{
double[,] Niks = new double[k, i + k];
for (int kk = 1; kk <= k; ++kk)
{
for (int ii = i; ii < k + i - kk + 1; ++ii)
{
double NikPrev1, NikPrev2;
if (kk == 1) {
if (isEqualNull(Math.Abs(knots[ii] - t)) || (knots[ii] < t && t < knots[ii + 1])) {
NikPrev1 = 1;
} else {
NikPrev1 = 0;
}
Niks[kk - 1, ii] = NikPrev1;
continue;
} else {
NikPrev1 = Niks[kk - 2, ii];
NikPrev2 = Niks[kk - 2, ii + 1];
}
double numerator1 = (t - knots[ii]) * NikPrev1,
znam1 = knots[ii + kk - 1] - knots[ii];
double numerator2 = (knots[ii + kk] - t) * NikPrev2,
znam2 = knots[ii + kk] - knots[ii + 1];
double proportion1, proportion2;
if (isEqualNull(numerator1) || isEqualNull(znam1)) {
proportion1 = 0;
} else {
proportion1 = numerator1 / znam1;
}
if (isEqualNull(numerator2) || isEqualNull(znam2)) {
proportion2 = 0;
} else {
proportion2 = numerator2 / znam2;
}
double curN = proportion1 + proportion2;
Niks[kk - 1, ii] = curN;
}
}
return Niks[k - 1, i];
}
private double getNikRecursion(double t, int i, int k)
{
if (k == 1) {
if (isEqualNull(Math.Abs(knots[i] - t)) || (knots[i] < t && t < knots[i + 1])) {
return 1;
} else {
return 0;
}
}
double numerator1 = (t - knots[i]) * getNikRecursion(t, i, k - 1),
znam1 = knots[i + k - 1] - knots[i];
double numerator2 = (knots[i + k] - t) * getNikRecursion(t, i + 1, k - 1),
znam2 = knots[i + k] - knots[i + 1];
double proportion1, proportion2;
if (isEqualNull(numerator1) || isEqualNull(znam1)) {
proportion1 = 0;
} else {
proportion1 = numerator1 / znam1;
}
if (isEqualNull(numerator2) || isEqualNull(znam2)) {
proportion2 = 0;
} else {
proportion2 = numerator2 / znam2;
}
double curN = proportion1 + proportion2;
return curN;
}
public double[] getKnots(int n, int k)
{
int size = n + k;
double[] knots = new double[size];
int temp = 0;
for (int i = 0; i < size; ++i) {
if (i >= k && size - i >= k) {
++temp;
}
knots[i] = temp;
}
return knots;
}
private bool isEqualNull(double num)
{
return Math.Abs(num) <= 1e-8;
}
private void generateCtrlArray(int n)
{
float layerWidth = pictureBox1.Width,
layerHeight = pictureBox1.Height;
float spaceBetweenPoints = layerWidth / n;
float x = spaceBetweenPoints / 2 - startCoordOffset.X, y = (checkBox1.Checked ? 1 : -1) * 150;
ctrlArray = new float[n, 2];
for (int i = 0; i < n; ++i) {
ctrlArray[i, 0] = x;
ctrlArray[i, 1] = y;
x += spaceBetweenPoints;
y *= -1;
}
}
private void trackBar1_Scroll(object sender, EventArgs e)
{
n = trackBar1.Value;
k = trackBar2.Value;
if (k > n) {
trackBar2.Value = n;
k = n;
}
generateCtrlArray(n);
drawBSpline(n, k);
}
private void trackBar2_Scroll(object sender, EventArgs e)
{
n = trackBar1.Value;
k = trackBar2.Value;
if (k > n) {
trackBar2.Value = n;
k = n;
}
generateCtrlArray(n);
drawBSpline(n, k);
}
private void trackBar3_Scroll(object sender, EventArgs e)
{
t_step = (double)trackBar3.Value / 1000;
n = trackBar1.Value;
k = trackBar2.Value;
generateCtrlArray(n);
drawBSpline(n, k);
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
generateCtrlArray(n);
drawBSpline(n, k);
}
}
}