B样条(B-Spline)是常用的曲线拟合与插值算法之一。
这里给出在 Form 的 图像 Picturebox 组件上,按鼠标点击点绘制 (三次)B样条曲线的代码。
2022-12-05 修改了代码。
using System;
using System.Data;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Legalsoft.Truffer.Algorithm;
{
? ? public partial class Form1 : Form
? ? {
? ? ? ? public double[] splinex = new double[1001];
? ? ? ? public double[] spliney = new double[1001];
? ? ? ? public point[] pt = new point[6];
? ? ? ? public int no_of_points = 0;
? ? ? ? /// <summary>
? ? ? ? /// Prints a dot at the place whrere the mouseup event occurs
? ? ? ? /// </summary>
? ? ? ? /// <param name="sender"></param>
? ? ? ? /// <param name="e"></param>
? ? ? ? private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
? ? ? ? {
? ? ? ? ? ? Graphics g = pictureBox1.CreateGraphics();
? ? ? ? ? ? Color cl = Color.DarkBlue;
? ? ? ? ? ? g.DrawLine(new Pen(cl, 2), e.X-3, e.Y, e.X + 3, e.Y);
? ? ? ? ? ? g.DrawLine(new Pen(cl, 2), e.X, e.Y-3, e.X, e.Y + 3);
? ? ? ? ? ? g.DrawString(no_of_points+"", new Font("宋体",12), new SolidBrush(Color.Red), e.X, e.Y);
? ? ? ? }
? ? ? ? /// <summary>
? ? ? ? /// At each mousedown event the the no of points is calculated
? ? ? ? /// if the value is more than 3 then the curve is drawn
? ? ? ? /// </summary>
? ? ? ? /// <param name="sender"></param>
? ? ? ? /// <param name="e"></param>
? ? ? ? private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
? ? ? ? {
? ? ? ? ? ?if (no_of_points > 3)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? pt[0] = pt[1];
? ? ? ? ? ? ? ? pt[1] = pt[2];
? ? ? ? ? ? ? ? pt[2] = pt[3];
? ? ? ? ? ? ? ? pt[3].X = e.X;
? ? ? ? ? ? ? ? pt[3].Y = e.Y;
? ? ? ? ? ? ? ? double temp = Math.Sqrt(Math.Pow(pt[2].X - pt[1].X, 2F) + Math.Pow(pt[2].Y - pt[1].Y, 2F));
? ? ? ? ? ? ? ? int interpol = System.Convert.ToInt32(temp);
? ? ? ? ? ? ? ? bspline(pt[0], pt[1], pt[2], pt[3], interpol);
? ? ? ? ? ? ? ? int width = 2;
? ? ? ? ? ? ? ? Graphics g = pictureBox1.CreateGraphics();
? ? ? ? ? ? ? ? Color cl = Color.Blue;
? ? ? ? ? ? ? ? int x, y;
? ? ? ? ? ? ? ? for (int i = 0; i <= interpol - 1; i++)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? x = System.Convert.ToInt32(splinex[i]);
? ? ? ? ? ? ? ? ? ? y = System.Convert.ToInt32(spliney[i]);
? ? ? ? ? ? ? ? ? ? g.DrawLine(new Pen(cl, width), x - 1, y, x + 1, y);
? ? ? ? ? ? ? ? ? ? g.DrawLine(new Pen(cl, width), x, y - 1, x, y + 1);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? else
? ? ? ? ? ? {
? ? ? ? ? ? ? ? pt[no_of_points].X = e.X;
? ? ? ? ? ? ? ? pt[no_of_points].Y = e.Y;
? ? ? ? ? ? }
? ? ? ? ? ? no_of_points++;
? ? ? ? }
? ? ? ? /// <summary>
? ? ? ? /// calculating the values using the algorithm?
? ? ? ? /// </summary>
? ? ? ? /// <param name="p1"></param>
? ? ? ? /// <param name="p2"></param>
? ? ? ? /// <param name="p3"></param>
? ? ? ? /// <param name="p4"></param>
? ? ? ? /// <param name="divisions"></param>
? ? ? ? public void bspline(point p1, point p2, point p3, point p4, int divisions)
? ? ? ? {
? ? ? ? ? ? double[] a = new double[5];
? ? ? ? ? ? double[] b = new double[5];
? ? ? ? ? ? a[0] = (-p1.X + 3 * p2.X - 3 * p3.X + p4.X) / 6.0;
? ? ? ? ? ? a[1] = (3 * p1.X - 6 * p2.X + 3 * p3.X) / 6.0;
? ? ? ? ? ? a[2] = (-3 * p1.X + 3 * p3.X) / 6.0;
? ? ? ? ? ? a[3] = (p1.X + 4 * p2.X + p3.X) / 6.0;
? ? ? ? ? ? b[0] = (-p1.Y + 3 * p2.Y - 3 * p3.Y + p4.Y) / 6.0;
? ? ? ? ? ? b[1] = (3 * p1.Y - 6 * p2.Y + 3 * p3.Y) / 6.0;
? ? ? ? ? ? b[2] = (-3 * p1.Y + 3 * p3.Y) / 6.0;
? ? ? ? ? ? b[3] = (p1.Y + 4 * p2.Y + p3.Y) / 6.0;
? ? ? ? ? ? splinex[0] = a[3];
? ? ? ? ? ? spliney[0] = b[3];
? ? ? ? ? ? for (int i = 1; i <= divisions - 1; i++)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? double t = System.Convert.ToSingle(i) / System.Convert.ToSingle(divisions);
? ? ? ? ? ? ? ? splinex[i] = (a[2] + t * (a[1] + t * a[0])) * t + a[3];
? ? ? ? ? ? ? ? spliney[i] = (b[2] + t * (b[1] + t * b[0])) * t + b[3];
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
?
using System;
using System.Data;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Legalsoft.Truffer.Algorithm;
{
? ? public partial class Form1 : Form
? ? {
? ? ? ? public double[] splinex = new double[1001];
? ? ? ? public double[] spliney = new double[1001];
? ? ? ? public point[] pt = new point[6];
? ? ? ? public int no_of_points = 0;
? ? ? ? /// <summary>
? ? ? ? /// Prints a dot at the place whrere the mouseup event occurs
? ? ? ? /// </summary>
? ? ? ? /// <param name="sender"></param>
? ? ? ? /// <param name="e"></param>
? ? ? ? private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
? ? ? ? {
? ? ? ? ? ? Graphics g = pictureBox1.CreateGraphics();
? ? ? ? ? ? Color cl = Color.DarkBlue;
? ? ? ? ? ? g.DrawLine(new Pen(cl, 2), e.X-3, e.Y, e.X + 3, e.Y);
? ? ? ? ? ? g.DrawLine(new Pen(cl, 2), e.X, e.Y-3, e.X, e.Y + 3);
? ? ? ? ? ? g.DrawString(no_of_points+"", new Font("宋体",12), new SolidBrush(Color.Red), e.X, e.Y);
? ? ? ? }
? ? ? ? /// <summary>
? ? ? ? /// At each mousedown event the the no of points is calculated
? ? ? ? /// if the value is more than 3 then the curve is drawn
? ? ? ? /// </summary>
? ? ? ? /// <param name="sender"></param>
? ? ? ? /// <param name="e"></param>
? ? ? ? private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
? ? ? ? {
? ? ? ? ? ?if (no_of_points > 3)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? pt[0] = pt[1];
? ? ? ? ? ? ? ? pt[1] = pt[2];
? ? ? ? ? ? ? ? pt[2] = pt[3];
? ? ? ? ? ? ? ? pt[3].X = e.X;
? ? ? ? ? ? ? ? pt[3].Y = e.Y;
? ? ? ? ? ? ? ? double temp = Math.Sqrt(Math.Pow(pt[2].X - pt[1].X, 2F) + Math.Pow(pt[2].Y - pt[1].Y, 2F));
? ? ? ? ? ? ? ? int interpol = System.Convert.ToInt32(temp);
? ? ? ? ? ? ? ? bspline(pt[0], pt[1], pt[2], pt[3], interpol);
? ? ? ? ? ? ? ? int width = 2;
? ? ? ? ? ? ? ? Graphics g = pictureBox1.CreateGraphics();
? ? ? ? ? ? ? ? Color cl = Color.Blue;
? ? ? ? ? ? ? ? int x, y;
? ? ? ? ? ? ? ? for (int i = 0; i <= interpol - 1; i++)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? x = System.Convert.ToInt32(splinex[i]);
? ? ? ? ? ? ? ? ? ? y = System.Convert.ToInt32(spliney[i]);
? ? ? ? ? ? ? ? ? ? g.DrawLine(new Pen(cl, width), x - 1, y, x + 1, y);
? ? ? ? ? ? ? ? ? ? g.DrawLine(new Pen(cl, width), x, y - 1, x, y + 1);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? else
? ? ? ? ? ? {
? ? ? ? ? ? ? ? pt[no_of_points].X = e.X;
? ? ? ? ? ? ? ? pt[no_of_points].Y = e.Y;
? ? ? ? ? ? }
? ? ? ? ? ? no_of_points++;
? ? ? ? }
? ? ? ? /// <summary>
? ? ? ? /// calculating the values using the algorithm?
? ? ? ? /// </summary>
? ? ? ? /// <param name="p1"></param>
? ? ? ? /// <param name="p2"></param>
? ? ? ? /// <param name="p3"></param>
? ? ? ? /// <param name="p4"></param>
? ? ? ? /// <param name="divisions"></param>
? ? ? ? public void bspline(point p1, point p2, point p3, point p4, int divisions)
? ? ? ? {
? ? ? ? ? ? double[] a = new double[5];
? ? ? ? ? ? double[] b = new double[5];
? ? ? ? ? ? a[0] = (-p1.X + 3 * p2.X - 3 * p3.X + p4.X) / 6.0;
? ? ? ? ? ? a[1] = (3 * p1.X - 6 * p2.X + 3 * p3.X) / 6.0;
? ? ? ? ? ? a[2] = (-3 * p1.X + 3 * p3.X) / 6.0;
? ? ? ? ? ? a[3] = (p1.X + 4 * p2.X + p3.X) / 6.0;
? ? ? ? ? ? b[0] = (-p1.Y + 3 * p2.Y - 3 * p3.Y + p4.Y) / 6.0;
? ? ? ? ? ? b[1] = (3 * p1.Y - 6 * p2.Y + 3 * p3.Y) / 6.0;
? ? ? ? ? ? b[2] = (-3 * p1.Y + 3 * p3.Y) / 6.0;
? ? ? ? ? ? b[3] = (p1.Y + 4 * p2.Y + p3.Y) / 6.0;
? ? ? ? ? ? splinex[0] = a[3];
? ? ? ? ? ? spliney[0] = b[3];
? ? ? ? ? ? for (int i = 1; i <= divisions - 1; i++)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? double t = System.Convert.ToSingle(i) / System.Convert.ToSingle(divisions);
? ? ? ? ? ? ? ? splinex[i] = (a[2] + t * (a[1] + t * a[0])) * t + a[3];
? ? ? ? ? ? ? ? spliney[i] = (b[2] + t * (b[1] + t * b[0])) * t + b[3];
? ? ? ? ? ? }
? ? ? ? }
? ? }
}