C#的绘图函数中有一个绘制样条曲线的函数DrawCurve,当只传入Pen和Point数组时,采用的是基数样条曲线绘制。如果只是绘制样条曲线,那这个函数已经满足了。但是项目中要求不但要绘制曲线,还要将曲线以方格的形式模拟来实现。为此,就必须知道样条曲线是如何绘制的,才有办法知道都有哪些点,然后再用格子来模拟。
起初,使用了很粗暴的方法,即使用DrawCurve在内存中绘制到Image中,然后从Image中取出黑白点,然后形成黑白点的矩阵,进而利用这些矩阵点对应到像素点来绘制方格。做了简单的实现,但效果不理想。原因有几个。
1.不断使用内存绘制到Image中需要消耗大量的内存。
2.利用像素点来采集矩阵的点时,难以确定一个采集的范围。
3.至少需要对像素进行X和Y的双重循环遍历才能达成,这样时间复杂度会随着X、Y的增加而不断加大。
后面找到了一份模拟实现,经过改造,初步达成了目的。来看看模拟实现的和DrawCurve的拟合效果图,见下图。
注:图中黑色部分使用DrawCurve来绘制,黑色线中间的白色部分采用的是模拟绘制。从测试的结果来看,符合程度比较理想。下面是实现的代码。
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
namespace SplineTest
{
/// <summary>
/// 样条曲线。每根样条曲线包含4个控制点
/// </summary>
public class Spline
{
/// <summary>
/// 样点数。在点Pk和Pk+1之间,将会生成若干个样点。所以"u"将会从0.00F增长到0.05F.
/// </summary>
private static readonly int _samplePointCount = 20;
/// <summary>
/// 在基数算法中的t
/// </summary>
private static readonly float _tension = 0.0F;
#region 属性
private PointF _startControlPoint;
/// <summary>
/// "Pk-1"点(起始控制点)
/// </summary>
public PointF StartControlPoint
{
get
{
return this._startControlPoint;
}
set
{
this._startControlPoint = value;
}
}
private PointF _startPoint;
/// <summary>
/// "Pk"点(起始点)
/// </summary>
public PointF StartPoint
{
get
{
return this._startPoint;
}
set
{
this._startPoint = value;
}
}
private PointF _endPoint;
/// <summary>
/// "Pk+1"点(结束点)
/// </summary>
public PointF EndPoint
{
get
{
return this._endPoint;
}
set
{
this._endPoint = value;
}
}
private PointF _endControlPoint;
/// <summary>
/// "Pk+2"点(结束控制点)
/// </summary>
public PointF EndControlPoint
{