您的位置:首页 > 其它

Graphics.DrawCurve的算法

2013-11-13 17:50 239 查看


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(Vec2v) {
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
+(Vec2v1, Vec2v2) { 
return
new
Vec2(v1.X + v2.X, v1.Y + v2.Y); }


public
static
Vec2
operator
-(Vec2v1, Vec2v2) { 
return
new
Vec2(v1.X - v2.X, v1.Y - v2.Y); }


public
static
Vec2
operator
*(Vec2v, 
float
f) {
return
new
Vec2(v.X * f, v.Y * f); }


public
static
Vec2
operator
/(Vec2v, 
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;


Vec2u = ((Vec2)p2 - (Vec2)p0) * (tension / 3) + p1;


Vec2v = ((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));


}


}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: