Graphics.DrawCurve的算法

Graphics.DrawCurve的算法为Cardinal Spline,中文可能叫做'基数样条'。
它计算并不复杂,如下代码:

C# code?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public  static  class  Spline
{
     [System.Diagnostics.DebuggerDisplay( "({X},{Y})" )]
     public  partial  struct  Vec2
     {
         public  float  X, Y;
         public  Vec2( float  x,  float  y) { this .X = x;  this .Y = y;}
         public  static  implicit  operator  PointF(Vec2 v) {  return  new  PointF(v.X, v.Y); }
         public  static  implicit  operator  Vec2(PointF p) {  return  new  Vec2(p.X, p.Y); }
         public  static  Vec2  operator  +(Vec2 v1, Vec2 v2) {  return  new  Vec2(v1.X + v2.X, v1.Y + v2.Y); }
         public  static  Vec2  operator  -(Vec2 v1, Vec2 v2) {  return  new  Vec2(v1.X - v2.X, v1.Y - v2.Y); }
         public  static  Vec2  operator  *(Vec2 v,  float  f) {  return  new  Vec2(v.X * f, v.Y * f); }
         public  static  Vec2  operator  /(Vec2 v,  float  f) {  return  new  Vec2(v.X / f, v.Y / f); }
     }
 
     /// <summary>
     /// '贝塞尔'内插。结果不包括头尾点
     /// </summary>
     public  static  PointF[] InterpolateBezier(PointF p0, PointF p1, PointF p2, PointF p3,  int  samples)
     {
         PointF[] result =  new  PointF[samples];
         for  ( int  i = 0; i < samples; i++)
         {
             float  t = (i + 1) / (samples + 1.0f);
             result[i] =
                 (Vec2)p0 * (1 - t) * (1 - t) * (1 - t) +
                 (Vec2)p1 * (3 * (1 - t) * (1 - t) * t) +
                 (Vec2)p2 * (3 * (1 - t) * t * t) +
                 (Vec2)p3 * (t * t * t);
         }
         return  result;
     }
 
     public  static  PointF[] InterpolateCardinalSpline(PointF p0, PointF p1, PointF p2, PointF p3,  int  samples)
     {
         const  float  tension = 0.5f;
         Vec2 u = ((Vec2)p2 - (Vec2)p0) * (tension / 3) + p1;
         Vec2 v = ((Vec2)p1 - (Vec2)p3) * (tension / 3) + p2;
         return  InterpolateBezier(p1, u, v, p2, samples);
     }
 
     /// <summary>
     /// '基数样条'内插法。 points为通过点,samplesInSegment为两个样本点之间的内插数量。
     /// </summary>
     public  static  PointF[] CardinalSpline(PointF[] points,  int  samplesInSegment)
     {
         List<PointF> result =  new  List<PointF>();
         for  ( int  i = 0; i < points.Length - 1; i++)
         {
             result.Add(points[i]);
             result.AddRange( InterpolateCardinalSpline(
                 points[Math.Max(i-1, 0)],
                 points[i],
                 points[i+1],
                 points[Math.Min(i+2, points.Length-1)],
                 samplesInSegment
                 ));
         }
         result.Add(points[points.Length - 1]);
         return  result.ToArray();
     }
}


验证:
C# code ?
1
2
3
4
5
6
7
8
9
10
11
12
13
public  partial  class  Form1 : Form
{
     protected  override  void  OnPaint(PaintEventArgs e)
     {
         PointF[] ps = { new  PointF(50,50),  new  PointF(100, 80),  new  PointF(120, 10),  new  PointF(200,100)};
 
         // 系统的Graphics.DrawCurve,桃色
         e.Graphics.DrawCurve( new  Pen(Brushes.PeachPuff, 5), ps);
 
         // 自己取样,蓝色
         e.Graphics.DrawLines(Pens.Blue, Spline.CardinalSpline(ps, 10));
     }
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值