一、样条

样条(Spline)函数是由舍恩伯格于1946年提出的。样条是富有弹性的细木条或有机玻璃条,它的作用相当于“万能”曲线板。早期船舶、汽车、飞机放样时用铅压铁压住样条,使其通过一系列型值点,调整压铁达到设计要求后绘制其曲线,称为样条曲线。这样设计曲线的方法在20世纪六七十年代得到了广泛应用。

二、几何连续性

2.1 连续性条件

通常单一的曲线段或曲面片难以表达复杂的形状,必须将一些曲线段拼接成组合曲线,或将一些曲面片拼接成组合曲面,才能表达复杂的形状。为了保证在结合点处光滑过渡,需要满足连续性条件。连续性条件有两种:参数连续性(Parametric Continuity)与几何连续性(Geometric Continuity)。

2.2 参数连续性

  • 零阶参数连续性,记为C0,指相邻两段曲线在结合点处具有相同的坐标。

  • 一阶参数连续性,记为C1,指相邻两段曲线在结合点处具有相同的一阶导数

  • 二阶参数连续性,记为C2,指相邻两段曲线在结合点处具有相同的一阶导数和二阶导数。

2.3 几何连续性

与参数连续性不同的是,几何连续性只要求参数成比例而非相等。

  • 零阶几何连续性,记为G0,与零阶参数连续性相同,即相邻两段曲线在结合点处有相同的坐标。
  • 一阶几何连续性,记为G1,指相邻两段曲线在结合点处的一阶导数成比例,但大小不一定相等。
  • 二阶几何连续性,记为G2,指相邻两段曲线在结合点处的一阶导数和二阶导数成比例,即曲率一致,但大小不一定相等。

三、三次样条曲线

  • 三次样条曲线是组合曲线,它在相邻的两型值点之间,使用三次函数进行插值。如果把n段三次曲线连接起来,使两相邻曲线在连接点(称为节点)的斜率和曲率相等,就获得n段三次函数组合成的曲线,即三次样条曲线。
  • 三次样条曲线是插值曲线,它通过所有型值点。
  • 样条函数的理论和运用是从三次样条函数发展起来的。
  • 在计算几何中,应用得最早、研究得最详细的也是三次样条函数,因为 三次样条函数在节点处具有C2连续性,而二阶连续性是大多数工程问题所需要的。
  • 样条函数也是放样工艺中绘制曲线用的细木条的数学模型的线性近似,符合传统的光顺要求。

3.1 三次样条函数的定义

已知n个型值点Pi(xi, yi), i = 1, 2,…, n且a = x1 < x2 <…< xn = b。若 y=s(x)满足下列条件:
(1)型值点Pi在函数 y=s(x) 上。
(2) s(x) 在整个区间[a, b]上二阶连续可导。
(3)在每个子区间[xi, xi+1], i = 1, 2,…, n-1上,分段函数 都是参数x的三次多项式。则称函数 是过型值点的三次样条函数,由三次样条函数构成的曲线称为三次样条曲线。

3.2 三次样条函数的表达式

第i段的 si(x) 表示为:

式中,ai,bi,ci,di为待定系数,i=1,2 … ,n-1。

第i段曲线的首端通过Pi(xi,yi),末端通过Pi+1(xi+1,yi+1)
Pi处的二阶导数为Mi。
其中各型值点的弯矩Mi的力学解释如下:


子区间示意图如下:

用型值点处的二阶导数Mi表示的三次B样条函数为:

3.3 求解思路

3.4 函数推导

3.5 边界条件

3.5 推导过程

见个人资源:三次样条插值函数求解过程.pdf

四、算法实现

4.1 思路

(1)读入n个型值点且满足其x坐标递增。
(2)根据实际情况确定三次样条曲线的边界条件。
(3)计算曲线的系数,将其表达为型值点二阶导数的函数。
(4)用追赶法求解三弯矩方程。
(5)将求解出的参数代入三次样条函数的表达式中,构造三次样条曲线。
(6)循环访问每个节点。在每个子区间内,按照精度要求,使用直线段连接各段内的若干等分点,即可绘制出三次样条曲线。

4.2 代码

4.2.1 读取型值点

首先定义数据结构p2.cpp与头文件(主要如下):

CP2::CP2(double x, double y)
{this->x = x;this->y = y;
}

之后在主函数中定义读取函数:

// CGeometricfiguretestViewmessage handlers
void CGeometricfiguretestView::ReadPoint()
{P[1].x = -340, P[1].y = -200;P[2].x = -150, P[2].y =  0;P[3].x =  0,   P[3].y =  -50;P[4].x =  100, P[4].y =  -100;P[5].x =  250, P[5].y =  -100;P[6].x =  350, P[6].y =  -50;
}

4.2.2 绘制型值点

void CGeometricfiguretestView::DrawDataPoint(CDC* pDC)//绘制型值点
{CBrush NewBrush, *pOldBrush;NewBrush.CreateSolidBrush(RGB(0, 0, 0));pOldBrush = pDC->SelectObject(&NewBrush);for( int i = 1; i < 7; i++)pDC->Ellipse(ROUND(P[i].x - 5), ROUND(P[i].y - 5), ROUND(P[i].x + 5), ROUND(P[i].y + 5));pDC->SelectObject(pOldBrush);
}

4.2.3 三次样条曲线绘制

具体过程见注释:

void CGeometricfiguretestView::DrawCubicSpline(CDC* pDC)//三次样条曲线
{int n = 6;const int dim = 7;//二维数组维数double b1 = 10, bn = 10;//边界条件:"夹持端",给出起点和终点的一阶导数double h[dim], lambda[dim], mu[dim], D[dim];double l[dim], m[dim], u[dim]; double M[dim], K[dim];double a[dim], b[dim], c[dim], d[dim];for(int i = 1; i < n; i++)//计算hi=xi+1-xih[i] = P[i+1].x - P[i].x;for(int i = 2; i < n; i++){lambda[i] = h[i-1]/(h[i-1]+h[i]);//计算λmu[i] = h[i]/(h[i-1]+h[i]);//计算μD[i] = 6/(h[i-1]+h[i])*((P[i+1].y-P[i].y)/h[i]-(P[i].y-P[i-1].y)/h[i-1]);//计算D}D[1]=6*((P[2].y-P[1].y)/h[1]-b1)/h[1];//夹持端的D[1]D[n]=6*(bn-(P[n].y-P[n-1].y)/h[n-1])/h[n-1];//夹持端的D[n]mu[1]=1;//夹持端的μ[1],lambda[n]=1;//夹持端的λ[n]//追赶法求解三弯矩方程l[1]=2;u[1]=mu[1]/l[1];for(int i=2; i <= n; i++){m[i]=lambda[i];l[i]=2-m[i]*u[i-1];u[i]=mu[i]/l[i];}K[1] = D[1]/l[1];//解LK=Dfor(int i = 2; i <= n;i++){K[i]=(D[i]-m[i]*K[i-1])/l[i];}M[n] = K[n];//解UM=Kfor(int i = n-1; i >= 1;i--){M[i]=K[i]-u[i]*M[i+1];}//计算三次样条函数的系数for(int i = 1; i < n; i++){a[i] = P[i].y;b[i] = (P[i+1].y-P[i].y)/h[i] - h[i]*(M[i]/3+M[i+1]/6);c[i] = M[i]/2;d[i] = (M[i+1]-M[i])/(6*h[i]);}pDC->MoveTo(ROUND(P[1].x), ROUND(P[1].y));double xStep = 0.5;//x的步长double x, y;//当前点for(int i = 1; i < n; i++)//循环访问每个节点{for(x = P[i].x; x < P[i+1].x; x += xStep)//循环访问每个节点{y=a[i]+b[i]*(x-P[i].x)+c[i]*(x-P[i].x)*(x-P[i].x)+d[i]*(x-P[i].x)*(x-P[i].x)*(x-P[i].x);pDC->LineTo(ROUND(x), ROUND(y));//绘制样条曲线}}
}

4.2.4 主函数调用

void CGeometricfiguretestView::OnDraw(CDC* pDC)
{CTestDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);if (!pDoc)return;// TODO: add draw code for native data hereCRect rect;//定义客户区矩形GetClientRect(&rect);//获得客户区矩形的信息pDC->SetMapMode(MM_ANISOTROPIC);//自定义二维坐标系pDC->SetWindowExt(rect.Width(), rect.Height());//设置窗口范围pDC->SetViewportExt(rect.Width(), -rect.Height());//设置视区范围,且x轴水平向右为正,y轴垂直向上为正pDC->SetViewportOrg(rect.Width() / 2, rect.Height() / 2);//设置客户区中心为二维坐标系原点rect.OffsetRect(-rect.Width() / 2, -rect.Height() / 2);//rect矩形与客户区重合ReadPoint();DrawDataPoint(pDC);DrawCubicSpline(pDC);
}

编译运行,可见如下:

我们也可以改变其中一个边界约束条件:

double b1 = 10, bn = -5;//边界条件:"夹持端",给出起点和终点的一阶导数

运行可以看到如下:

计算几何02_三次样条曲线相关推荐

  1. MATLAB---构造一个插值三次样条曲线

    function InterpCubicSplineCurv() %本程序的功能是构造一个插值三次样条曲线N = 12; SamplPs = CollectSPFergusonCi2(N);%采集型值 ...

  2. 机械臂规划----三次样条曲线

    机械臂规划----三次样条曲线 原理讲解 源代码 三次样条曲线将稀疏点变成稠密点,是常用的一种规划方法. 原理讲解 源代码 #!/usr/bin/env python #-*-coding:utf-8 ...

  3. java三次样条函数求导_利用java语言对三次样条曲线的实现

    Java语言中关于曲线问题的高级应用开发在jdk尚未支援2D图形之前,只可以画出直的.相同粗细的线条.现在可以通过2DAPI绘出不同粗细的线条及圆滑的曲线.通过系统java.awt.geom包中提供了 ...

  4. matlab导数曲线怎样画,matlab三次样条曲线的绘制(spline和csape函数详解)

    matlab三次样条函数的绘制(spline和csape函数详解) 样条函数是工程中常用的插值函数.早期工程师制图时,把富有弹性的细长木条(所谓样条)用压铁固定在样点上,在其他地方让它自由弯曲,然后沿 ...

  5. 三次样条曲线 python实现

    reference:https://blog.csdn.net/deramer1/article/details/79034201 import numpy as np import matplotl ...

  6. 三次样条曲线CubicSpline

    本文参考老张在上海轨迹规划 之 三次样条曲线(概念+性质) - 知乎 (zhihu.com) 什么是三次样条曲线 之 三次 样条是一种数据插值的方式,在多项式插值中,多项式是给出的单一公式来尽可能满足 ...

  7. 三次样条曲线插值的基本原理及其C#实现

    声明:本人空间的所有文章,若无特别声明,皆为本人原创,可自由转载,但要注明原作者和原始出处,不可作为商业用途. 下面的内容是直接从Word文档复制粘贴出来的,有很多内容丢失,完整的PDF版本可到百度网 ...

  8. 三次样条曲线插值(cubic spline)实例应用

    目标 工作需要,需要达成这样得一个需求,给一系列得三维点,三维点按照顺序连接,形成一条折线.需要依照这条折线,进行曲线1m等距离插值.具体如下图 其中,红色圆圈点为原始点集OrigPoints(原始点 ...

  9. matlab三次样条曲线的绘制(spline和csape函数详解)

    matlab三次样条函数的绘制(spline和csape函数详解) 前言 1.spline函数详解 1.一维非节点边界 2.第二边界条件 3.高维无约束 4.高维第二边界 5.利用第二边界条件绘制圆 ...

  10. matlab 拖动曲线,Matlab屏幕交互取点并作三次样条曲线matlab GUI:屏幕取点+三次样条曲线+屏幕拖动 | 学步园...

    函数实现屏幕拖动: function figure1_WindowButtonDownFcn(hObject, eventdata, handles) set(gcf,'Pointer','fleur ...

最新文章

  1. 编写wordcount程序
  2. HttpSessionListener监听Session的创建和失效
  3. 编程软件python中的if用法-给Python初学者的一些编程技巧
  4. JSP+JavaBean+Servlet工作原理实例…
  5. linux传输文件无密码,Linux下scp无密码上传 下载 文件 目录
  6. apple tv 开发_如何防止Apple TV进入睡眠状态
  7. 【HDU - 5886】Tower Defence(树的直径,思维,dp)
  8. 370万开发者,14万家企业!飞桨中国行落地深圳 激发AI软硬件创新发展新动能...
  9. cocos2d-x+lua开发模式下编辑器的选择
  10. DB2单表排序查询报错分析及解决办法
  11. 将你的数据导入到json格式
  12. 字符设备与块设备的区别
  13. 讲解【分布式事务】的一篇良心之作!
  14. Animated之基础篇-概述
  15. android CMWAP CMNET
  16. 旋转体体积和平行截面的面积求体积
  17. Redis-Sentinel(哨兵模式),看这篇就够了哦
  18. nodejs京东接口分析系列-实现京东自动化功能 之 扫码登陆,需要puppeteer
  19. 恭贺2022年下半年NPDP产品经理认证班成功举行
  20. matlab小波变换程序,matlab 二维小波变换程序

热门文章

  1. Excel校验银行卡号是否正确
  2. ​SQL注入非常详细总结
  3. stm8单片机程序加密方法 id加密技巧
  4. html静态网页实例一(附完整代码)
  5. 超市管理系统(JavaWeb版)
  6. matlab colorbar 颜色范围,Matlab对数范围colorbar imagesc
  7. 工程实践线切割3B代码参考
  8. 证明不是哈密顿图的几种方法归纳总结
  9. vue 电子签名插件
  10. 购物中心节假日如何统计客流量分析客流量数据?