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 > pointsList = new List >(); List pensList = new List(); 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(new PointF(x, y), pensList.Count - 1)); t += t_step; } } PointF prevPoint = new PointF(); foreach (Tuple 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); } } }