# 采用Cardinal法构造插枝分段三次样条曲线 : 代码篇

 版权声明：   本文由timewolf完成，首发于CSDN，作者保留版权。未经许可，不得使用于任何商业用途。欢迎转载，但请保持文章及版权声明完整。如需联络请发邮件：karla9(AT)eyou(dot)com

using System;
using System.Collections;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace CardinalTest
{
/// <summary>
/// the declaration of the Spline, each spline contains 4 control points
/// </summary>
public class Spline
{
// it's the "Pk-1" point
private Point3D m_startControlPoint;
// it's the "Pk" point
private Point3D m_startPoint;
// it's the "Pk+1" point
private Point3D m_endPoint;
// it's the "Pk+2" point
private Point3D m_endControlPoint;
// that means we'll generate 20 sample points between Pk & Pk+1, so "u" will start from 0.00F
// and the increase step is 0.05F
private static readonly int m_sampleCount = 20;
// the "t" in Cardinal altorithm
private static readonly float m_tension = 0.0F;
// store the result sample points
private Point3D[] m_ctrlPoints;
// indicate whether this spline is the first, if it is,
//the m_startControlPoint & m_startPoint will be the same
// because the 4 points can just determine the spline between Pk & Pk+1, so we add a point ahead
// of the Pk-1 manually, so that we can draw the spline between Pk-1 & Pk+1
// similarly, the last Spline's "Pk+2" will be the same as its "Pk+1"
// so that we can draw the spline between Pk+1 & Pk+2
private bool m_isFirst = false;

#region Associated Property Block
public Point3D StartControlPoint
{
get
{
return this.m_startControlPoint;
}
set
{
this.m_startControlPoint = value;
}
}

public Point3D StartPoint
{
get
{
return this.m_startPoint;
}
set
{
this.m_startPoint = value;
}
}

public Point3D EndPoint
{
get
{
return this.m_endPoint;
}
set
{
this.m_endPoint = value;
}
}

public Point3D EndControlPoint
{
get
{
return this.m_endControlPoint;
}
set
{
this.m_endControlPoint = value;
}
}

public Point3D[] CtrlPoints
{
get
{
return this.m_ctrlPoints;
}
}

public bool IsFirst
{
get
{
return this.m_isFirst;
}
set
{
this.m_isFirst = value;
}
}
#endregion

public Spline()
{
m_startControlPoint = new Point3D();
m_startPoint = new Point3D();
m_endPoint = new Point3D();
m_endControlPoint = new Point3D();
m_ctrlPoints = new Point3D[m_sampleCount + 1];
for(int i = 0; i < m_ctrlPoints.Length; i++)
{
m_ctrlPoints[i] = new Point3D();
}
}

/// <summary>
/// A new control point added to the control points, so the previous splines should be updated
/// </summary>
public void AddJoint(Spline prevSpline, Point3D currentPoint)
{
// the previous spline is null, so there's just one point in the control point list;
// so the 4 control points are all the same
// while the 2nd & later points added into the list, the 1st spline's Pk+1 & Pk+2
// will be updated
if (null == prevSpline)
{
this.m_startControlPoint = currentPoint;
this.m_startPoint = currentPoint;
this.m_endPoint = currentPoint;
this.m_endControlPoint = currentPoint;
this.m_isFirst = true;
}
// the previous spline is not null, so update the previous spline's control points
// and update this Spline's points
else
{
// the previous spline is the 1st spline, update its Pk+1 & Pk+2
if (true == prevSpline.m_isFirst)
{
this.m_startControlPoint = prevSpline.StartControlPoint;
this.m_startPoint = prevSpline.StartPoint;
this.m_endPoint = currentPoint;
this.m_endControlPoint = currentPoint;
GenerateSamplePoint();
return;
}
// the previous spline is not the 1st, just update its Pk+2
else
{
prevSpline.EndControlPoint = currentPoint;
prevSpline.GenerateSamplePoint();

// simulate the sample points of current Spline
this.m_startControlPoint = prevSpline.m_startPoint;
this.m_startPoint = prevSpline.m_endPoint;
this.m_endPoint = currentPoint;
this.m_endControlPoint = currentPoint;
GenerateSamplePoint();

}
}
}

/// <summary>
/// use Cardinal altorithm to generate the sample points
/// </summary>
public void GenerateSamplePoint()
{
Point3D startControlPoint = this.StartControlPoint;
Point3D startPoint = this.StartPoint;
Point3D endPoint = this.EndPoint;
Point3D endControlPoint = this.EndControlPoint;
float step = 1.0F / (float)m_sampleCount;
float uValue = 0.00F;

for (int i = 0; i < m_sampleCount; i++)
{
Point3D pointNew = Cardinal(uValue, startControlPoint, startPoint, endPoint, endControlPoint);
this.CtrlPoints[i] = new Point3D(pointNew);
uValue += step;
}
this.CtrlPoints[m_ctrlPoints.Length - 1] = endPoint;
}

public void Draw()
{
for (int i = 0; i < m_ctrlPoints.Length - 1; i++ )
{
Point3D lastP3D = m_ctrlPoints[i];
Point3D nextP3D = m_ctrlPoints[i + 1];
DrawLine(lastP3D, nextP3D, dexStart + i);
}
}

#region Cardinal algorithm
/// <summary>
/// Get a point on the result curve, this point is between startPoint & endPoint
/// </summary>
/// <param name="u">
/// the variable between 0 & 1, the input parameter
/// </param>
/// <param name="startControlPoint">
/// the control point in front of start point, help to determine the appearance of the result curve
/// </param>
/// <param name="startPoint">
/// the start point of the result curve, when u == 0, the returned result is startPoint
/// </param>
/// <param name="endPoint">
/// the end point of the result curve, when u == 1, the returned result is endPoint
/// </param>
/// <param name="endControlPoint">
/// the control point after start point, help to determine the appearance of the result curve
/// </param>
/// <returns>
/// the result point between startPoint & endPoint
/// </returns>
private Point3D Cardinal(float u, Point3D startControlPoint,
Point3D startPoint, Point3D endPoint, Point3D endControlPoint)
{
float s = (1 - m_tension) / 2;
Point3D resultPoint = new Point3D();
resultPoint.X = GetResult(startControlPoint.X, startPoint.X, endPoint.X, endControlPoint.X, s, u);
resultPoint.Y = GetResult(startControlPoint.Y, startPoint.Y, endPoint.Y, endControlPoint.Y, s, u);
resultPoint.Z = GetResult(startControlPoint.Z, startPoint.Z, endPoint.Z, endControlPoint.Z, s, u);
return resultPoint;
}

private float GetResult(float a, float b, float c, float d, float s, float u)
{
float result = 0.0F;
result = a*(2*s*u*u - s*u*u*u - s*u) + b*((2-s)*u*u*u + (s-3)*u*u + 1) +
c*((s-2)*u*u*u + (3-2*s)*u*u + s*u) + d*(s*u*u*u - s*u*u);
return result;
}
#endregion
}
}

namespace CardinalTest
{
/// <summary>
/// Summary description for Point3D.
/// </summary>
public class Point3D
{
private float m_x;
private float m_y;
private float m_z;
public float sizeModulus;

#region Associated Property Declaration
public float X
{
get
{
return m_x;
}
set
{
m_x = value;
}
}

public float Y
{
get
{
return m_y;
}
set
{
m_y = value;
}
}

public float Z
{
get
{
return m_z;
}
set
{
m_z = value;
}
}
#endregion

public Point3D()
{
m_x = 0.0F;
m_y = 0.0F;
m_z = 0.0F;
}

public Point3D(Point3D sourcePoint)
{
m_x = sourcePoint.X;
m_y = sourcePoint.Y;
m_z = sourcePoint.Z;
}

public Point3D(float x, float y, float z)
{
m_x = x;
m_y = y;
m_z = z;
}

public Point3D(double x, double y, double z)
{
m_x = (float)x;
m_y = (float)y;
m_z = (float)z;
}

}
}

/// <summary>
/// Add joint to the path
/// </summary>
/// <param name="nowP3D"></param>
{
if (null == m_currentSplines || 0 == m_currentSplines.Count)
{
Spline splineNew = new Spline();
}
else
{
Spline splineNew = new Spline();
Spline lastNew = m_currentSplines[m_currentSplines.Count - 1] as Spline;
}
}

/// <summary>
/// Redraw the path and joints
/// </summary>
/// <returns></returns>
public void Draw()
{

int count = m_currentSplines.Count;
for (int i = 0; i < count; i++)
{
Spline spline = m_currentSplines[i] as Spline;
if (true == spline.IsFirst)
{
continue;
}
spline.Draw();
}
}

• 本文已收录于以下专栏：

## 采用Cardinal法构造插枝分段三次样条曲线 : 代码篇

• timewolf
• 2006年05月30日 10:29
• 2867

## 三次样条插值

• skyworth0103
• 2017年01月09日 20:22
• 729

## 采用Cardinal法构造插枝分段三次样条曲线 : 原理篇

Cardinal样条是插值分段三次曲线,并且每条曲线段的终点位置均指定切线.不过Cardinal样条不用给出终点的切线值.在Cardinal样条中,一个控制点的斜率可以由两个相邻控制点的...
• timewolf
• 2006年05月29日 17:11
• 3941

## 采用Cardinal法构造插枝分段三次样条曲线 : 实战篇

版权声明：   本文由timewolf完成，首发于CSDN...
• timewolf
• 2006年05月30日 10:39
• 2393

## 样条曲线概述

1 背景 参考资料 [1]计算机图形学(第三版)，电子工业出版社 [2]计算方法(第2版)，电子工业出版社...
• Q1302182594
• 2016年01月20日 22:43
• 3449

## 三次样条曲线

• guggy
• 2016年05月27日 10:47
• 1311

## cocos2d-x 基本样条动作

• Liar0606
• 2014年01月15日 23:22
• 1001

## Opencv 三次样条曲线(Cubic Spline)插值

• YhL_Leo
• 2015年08月16日 22:03
• 10837

## [计算机动画] 路径曲线与运动物体控制（Cardinal样条曲线）

•路径曲线与运动物体控制 •掌握Cardinal样条曲线的表示和算法，了解控制参数对曲线形状的影响。 •对照Cardinal样条曲线的数学表示和程序代码的对应关系。 •在路径曲线上放置一小汽车，使其在...
• ZJU_fish1996
• 2016年10月05日 00:58
• 3166

## 3次B样条曲线

void B3_Line(CDC *pDC,CPoint p1,CPoint p2,CPoint p3,CPoint p4) { int x0=p1.x,y0=p1.y; int x1=p2...
• a527606652
• 2013年06月24日 13:35
• 1631

举报原因： 您举报文章：采用Cardinal法构造插枝分段三次样条曲线 : 代码篇 色情 政治 抄袭 广告 招聘 骂人 其他 (最多只允许输入30个字)