• C#绘制带控制点的Bezier曲线,用于点阵图像及矢量图形


    【摘要】不借助第三方, 使用c# + GDI+进行SVG等绘图,绘制带控制点的Bezier曲线。可用于点阵图像及矢量图形(如SVG)绘图。
    
    先看效果:
    (不知为何,已两次上传图片,无法显示,求助csdn)
    
    图注:使用方法二绘制。
    
    
    方法一:
    /// <summary>
    /// Bezier样条曲线
    /// </summary>
    public static class BezierSpline
    {
    	/// <summary>
    	/// Get open-ended Bezier Spline Control Points.
    	/// </summary>
    	/// <param name="knots">Input Knot Bezier spline points.</param>
    	/// <param name="firstControlPoints">Output First Control points
    	/// array of knots.Length - 1 length.</param>
    	/// <param name="secondControlPoints">Output Second Control points
    	/// array of knots.Length - 1 length.</param>
    	/// <exception cref="ArgumentNullException"><paramref name="knots"/>
    	/// parameter must be not null.</exception>
    	/// <exception cref="ArgumentException"><paramref name="knots"/>
    	/// array must contain at least two points.</exception>
    	public static void GetCurveControlPoints(Point[] knots,
    		out Point[] firstControlPoints, out Point[] secondControlPoints)
    	{
    		if (knots == null)
    			throw new ArgumentNullException("knots");
    		int n = knots.Length - 1;
    		if (n < 1)
    			throw new ArgumentException
    			("At least two knot points required", "knots");
    		if (n == 1)
    		{ // Special case: Bezier curve should be a straight line.
    			firstControlPoints = new Point[1];
    			// 3P1 = 2P0 + P3
    			firstControlPoints[0].X = (2 * knots[0].X + knots[1].X) / 3;
    			firstControlPoints[0].Y = (2 * knots[0].Y + knots[1].Y) / 3;
    
    			secondControlPoints = new Point[1];
    			// P2 = 2P1 – P0
    			secondControlPoints[0].X = 2 *
    				firstControlPoints[0].X - knots[0].X;
    			secondControlPoints[0].Y = 2 *
    				firstControlPoints[0].Y - knots[0].Y;
    			return;
    		}
    
    		// Calculate first Bezier control points
    		// Right hand side vector
    		double[] rhs = new double[n];
    
    		// Set right hand side X values
    		for (int i = 1; i < n - 1; ++i)
    			rhs[i] = 4 * knots[i].X + 2 * knots[i + 1].X;
    		rhs[0] = knots[0].X + 2 * knots[1].X;
    		rhs[n - 1] = (8 * knots[n - 1].X + knots[n].X) / 2.0;
    		// Get first control points X-values
    		double[] x = GetFirstControlPoints(rhs);
    
    		// Set right hand side Y values
    		for (int i = 1; i < n - 1; ++i)
    			rhs[i] = 4 * knots[i].Y + 2 * knots[i + 1].Y;
    		rhs[0] = knots[0].Y + 2 * knots[1].Y;
    		rhs[n - 1] = (8 * knots[n - 1].Y + knots[n].Y) / 2.0;
    		// Get first control points Y-values
    		double[] y = GetFirstControlPoints(rhs);
    
    		// Fill output arrays.
    		firstControlPoints = new Point[n];
    		secondControlPoints = new Point[n];
    		for (int i = 0; i < n; ++i)
    		{
    			// First control point
    			firstControlPoints[i] = new Point(x[i], y[i]);
    			// Second control point
    			if (i < n - 1)
    				secondControlPoints[i] = new Point(2 * knots
    					[i + 1].X - x[i + 1], 2 *
    					knots[i + 1].Y - y[i + 1]);
    			else
    				secondControlPoints[i] = new Point((knots
    					[n].X + x[n - 1]) / 2,
    					(knots[n].Y + y[n - 1]) / 2);
    		}
    	}
    
    	/// <summary>
    	/// Solves a tridiagonal system for one of coordinates (x or y)
    	/// of first Bezier control points.
    	/// </summary>
    	/// <param name="rhs">Right hand side vector.</param>
    	/// <returns>Solution vector.</returns>
    	private static double[] GetFirstControlPoints(double[] rhs)
    	{
    		int n = rhs.Length;
    		double[] x = new double[n]; // Solution vector.
    		double[] tmp = new double[n]; // Temp workspace.
    
    		double b = 2.0;
    		x[0] = rhs[0] / b;
    		for (int i = 1; i < n; i++) // Decomposition and forward substitution.
    		{
    			tmp[i] = 1 / b;
    			b = (i < n - 1 ? 4.0 : 3.5) - tmp[i];
    			x[i] = (rhs[i] - x[i - 1]) / b;
    		}
    		for (int i = 1; i < n; i++)
    			x[n - i - 1] -= tmp[n - i] * x[n - i]; // Backsubstitution.
    
    		return x;
    	}
    }
    

    方法二:


            private void DrawCurve(Graphics g, PointF[] points, float tension)
            {
                int n=points.Length;
                Pen rPen = new Pen(Color.Red, 2f);
                Pen blPen= new Pen(Color.Blue, 1f);
                Pen bzPen = new Pen(Color.DarkGoldenrod, 2f);
                for (int i = 0; i < n; ++i)
                {
                    // draw segment points[i] - points[(i + 1) % n]
                    var pPrev1 = points[(i - 1 + n) % n];
                    var p1 = points[i];
                    var p2 = points[(i + 1) % n];
                    var pAfter2 = points[(i + 2) % n];

                    // tangents 切线控制点
                    var t1 = new PointF(tension * (p2.X - pPrev1.X), tension * (p2.Y - pPrev1.Y));
                    var t2 = new PointF(tension * (pAfter2.X - p1.X), tension * (pAfter2.Y - p1.Y));

                    // interior Bezier control points
                    var c1 = new PointF(p1.X + t1.X / 3.0f, p1.Y + t1.Y / 3.0f);
                    var c2 = new PointF(p2.X - t2.X / 3.0f, p2.Y - t2.Y / 3.0f);
                    
                    //画贝塞尔曲线
                    g.DrawBezier(bzPen, p1, c1, c2, p2);
                    
                    //画关键点到切线控制点的直线
                    g.DrawLine(blPen, p1, c1);
                    g.DrawEllipse(rPen, p1.X - 2, p1.Y - 2, 4, 4);
                    g.DrawEllipse(rPen, c1.X - 2, c1.Y - 2, 4, 4);

                    g.DrawLine(blPen, p2, c2);
                    g.DrawEllipse(rPen, p2.X - 2, p2.Y - 2, 4, 4);
                    g.DrawEllipse(rPen, c2.X - 2, c2.Y - 2, 4, 4);

                    g.FillEllipse(new SolidBrush(Color.Green), new RectangleF(p1.X-2, p1.Y-2, 4, 4));

                }
            }

    方法二的调用方法:

    //这里使用的是Panel上绘图,其他控件(如PictureBox)道理一样。

                Graphics g = pnlWorkArea.CreateGraphics();
                g.Clear(Color.White);
                g.CompositingQuality = CompositingQuality.HighQuality;
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                g.SmoothingMode = SmoothingMode.HighQuality;
                g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
                PointF[] points = { new PointF(568,200),new PointF(168,110),new PointF(60,186),new PointF(300,191),new PointF(600,300),new PointF(800,431),new PointF(300,650), new PointF(568, 200) };
                float tension=0.68f;
                DrawCurve(g, points, tension);

    这里有一个不错的链接: 

    C# GraphicsPath AddBeziers(params System.Drawing.Point[] points)

    C# GraphicsPath AddBeziers(System.Drawing.PointF[] points)

    源码也可以在此下载:C#带控制点的贝塞尔Bezier曲线算法(源码)-C#文档类资源-CSDN下载 

  • 相关阅读:
    【人工智能与机器学习】——K近邻(KNN)与模型选择(学习笔记)
    第十六章 品质保证:发布覆盖率测试报告
    JAVA学习笔记
    【技术积累】Mysql中的SQL语言【技术篇】【三】
    网络工程师的网络安全之路:应对威胁与保障数据
    MySQL EXPLAIN查看执行计划
    Mybatis之if标签判断boolean值
    51单片机 LCD1602
    算法模板(5):数学(1):数学知识(2)combination
    MySQL产生死锁原因
  • 原文地址:https://blog.csdn.net/johnsuna/article/details/125446942