使用Cubic Spline通过一组2D点绘制平滑曲线
原文Draw a smooth curve through a set of 2D points with Cubic Spline
I would like to provide you with the code to draw a smooth curve through a set of 2D points with cubic spline. If we have some tabulated function yi=f(xi) it's easy to get its cubic spline interpolant with some library code. For example, you could use the code from "Numerical Recipes in C, 2-nd Edition" book - proved source of a lot of math algorithms. Cubic spline gives an excellent interpolation in the most cases.
Cubic spline is comprised from a sequence of cubic polynomials, so to draw the curve we have to approximate each partial cubic polynomial with the polyline.
Let we have a cubic polynomial defined at [x1, x2] interval.
To approximate it with polyline we should do the following:
- Get the deviation polynomial, i.e. the difference between the initial cubic polynomial and the straight line passing through its left and right bound points. This polynomial is either identically equal to zero or has one or two extremum(s) at [x1, x2].
- Evaluate the values of deviation polynomial at extremum points. It its absolute values are lower than the tolerance then the initial cubic polynomial can be approximated with a straight line passing through points (x1, y1) and (x2, y2). Otherwise
- Split the initial interval [x1, x2] on two or three subintervals (depending on extremum count) and repeat the procedure recursively from (1) for each of subintervals.
///
/// Approximating Cubic Polynomial with PolyLine.
///
public static class CubicPolynomialPolylineApproximation
{
///
/// Gets the approximation of the polynomial with polyline.
///
/// The polynomial.
/// The abscissas start.
/// The abscissas stop.
/// The tolerance is the maximum distance from the cubic
/// polynomial to the approximating polyline.
///
public static Collection Approximate(Polynomial polynomial, double x1, double x2, double tolerance)
{
Debug.Assert(x1 <= x2, "x1 <= x2");
Debug.Assert(polynomial.Order == 3, "polynomial.Order == 3");
Collection points = new Collection();
// Get difference between given polynomial and the straight line passing its node points.
Polynomial deviation = DeviationPolynomial(polynomial, x1, x2);
Debug.Assert(deviation.Order == 3, "diff.Order == 3");
if (deviation[0] == 0 && deviation[1] == 0 && deviation[2] == 0 && deviation[3] == 0)
{
points.Add(new Point(x1, polynomial.GetValue(x1)));
points.Add(new Point(x2, polynomial.GetValue(x2)));
return points;
}
// Get previouse polynomial first derivative
Polynomial firstDerivative = new Polynomial(new double[] { deviation[1], 2 * deviation[2], 3 * deviation[3] });
// Difference polinomial extremums.
// Fing first derivative roots.
Complex[] complexRoots = firstDerivative.Solve();
// Get real roots in [x1, x2].
List roots = new List();
foreach (Complex complexRoot in complexRoots)
{
if (complexRoot.Imaginary == 0)
{
double r = complexRoot.Real;
if (r > x1 && r < x2)
roots.Add(r);
}
}
Debug.Assert(roots.Count > 0, "roots.Count > 0");
Debug.Assert(roots.Count <= 2, "roots.Count <= 2");
// Check difference polynomial extremal values.
bool approximates = true;
foreach (double x in roots)
{
if (Math.Abs(deviation.GetValue(x)) > tolerance)
{
approximates = false;
break;
}
}
if (approximates)
{// Approximation is good enough.
points.Add(new Point(x1, polynomial.GetValue(x1)));
points.Add(new Point(x2, polynomial.GetValue(x2)));
return points;
}
if (roots.Count == 2)
{
if (roots[0] == roots[1])
roots.RemoveAt(1);
else if (roots[0] > roots[1])
{// Sort the roots
// Swap roots
double x = roots[0];
roots[0] = roots[1];
roots[1] = x;
}
}
// Add the end abscissas.
roots.Add(x2);
// First subinterval.
Collection pts = Approximate(polynomial, x1, roots[0], tolerance);
// Copy all points.
foreach (Point pt in pts)
{
points.Add(pt);
}
// The remnant of subintervals.
for (int i = 0; i < roots.Count - 1; ++i)
{
pts = Approximate(polynomial, roots[i], roots[i + 1], tolerance);
// Copy all points but the first one.
for (int j = 1; j < pts.Count; ++j)
{
points.Add(pts[j]);
}
}
return points;
}
///
/// Gets the difference between given polynomial and the straight line passing through its node points.
///
/// The polynomial.
/// The abscissas start.
/// The abscissas stop.
///
static Polynomial DeviationPolynomial(Polynomial polynomial, double x1, double x2)
{
double y1 = polynomial.GetValue(x1);
double y2 = polynomial.GetValue(x2);
double a = (y2 - y1) / (x2 - x1);
double b = y1 - a * x1;
if (a != 0)
return polynomial.Subtract(new Polynomial(new double[] { b, a }));
else if (b != 0)
return polynomial.Subtract(new Polynomial(new double[] { b }));
else
return polynomial;
}
}
In the code above I'm using the helper class Polynomial encapsulating operations on polynomials including addition, subtraction, dividing, root finding, etc. It's ported from "Numerical Recipes in C, 2-nd Edition" book with some additions and bug fixes.
The sample supplied with this article is Visual Studio 2008 solution targeted to .NET 3.5. It contains WPF Windows Application project designed to demonstrate some curves drawn with cubic spline. You can select one of the curves from Combo Box at the top of the Window, experiment with point counts, tolerance and set appropriate XY Scales. You can even add you own curve, but this requires coding as follows:
- Add your curve name to CurveNames enum.
- Add your curve implementation to Curves region.
Add call to your curve to OnRender override. - In the sample I use Path elements on the custom Canvas to render the curve but in real application you would probably use some more effective approach like visual layer rendering.
使用Cubic Spline通过一组2D点绘制平滑曲线的更多相关文章
- 平滑算法:三次样条插值(Cubic Spline Interpolation)
https://blog.csdn.net/left_la/article/details/6347373 感谢强大的google翻译. 我从中认识到了航位推算dead reckoning,立方体样条 ...
- iOS开发——图层OC篇&Quartz 2D各种绘制实例
Quartz 2D各种绘制实例 首先说一下,本篇文章只是介绍怎么使用Quartz 2D绘制一些常用的图像效果,关于Quartz和其他相关技术请查看笔者之前写的完整版(Quartz 2D详解) 一:画线 ...
- emwin之2D图形绘制问题
@2018-09-03 [问题] 在 WM_PAINT 消息分支里绘制2D图形可以正常显示,而在外部函数或按钮按下事件的响应消息分支下等处,绘制2D图形则不显示. [解决] 在除消息WM_PAINT分 ...
- Opencv 三次样条曲线(Cubic Spline)插值
本系列文章由 @YhL_Leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/47707679 1.样条曲线简介 样条曲 ...
- 【js类库Raphaël】使用raphael.js根据点坐标绘制平滑曲线
一.可供参考的文档资料. raphaeljs官网:http://raphaeljs.com/ w3c关于path的介绍:http://www.w3.org/TR/2003/REC-SVG11-200 ...
- Qt 绘制平滑曲线
本文介绍在 Qt 中绘制平滑曲线的实现,调用下面的函数 SmoothCurveGenerator::generateSmoothCurve(points) 即可.默认曲线的 2 个顶点之间被分割为 1 ...
- Direct3D 2D文本绘制
现在学习下Direct3D在窗口中绘制一些文本信息,ID3DXFont接口负责创建字体和绘制二维的文本.我们介绍下ID3DXFont的用法. 1.创建LPD3DXFONT接口 LPD3DXFONT g ...
- iOS - Quartz 2D 画板绘制
1.绘制画板 1.1 绘制简单画板 PaintBoardView.h @interface PaintBoardView : UIView @end PaintBoardView.m @interfa ...
- QT5之2D绘图-绘制路径
在绘制一个复杂的图形的时候,如果你需要重复绘制一个这样的图形,就可以使用到QPainterPath类,然后使用QPainter::drawPath()来进行绘制. QPainterPath类为绘制操作 ...
随机推荐
- php实现求二进制中1的个数(右移、&、int32位)(n = n & (n - 1);)
php实现求二进制中1的个数(右移.&.int32位)(n = n & (n - 1);) 一.总结 1.PHP中的位运算符和java和c++一样 2.位移运算符看箭头方向,箭头向左就 ...
- js获取浏览器尺寸
Javascript: alert(document.body.clientWidth); //网页可见区域宽(body) alert(document.body.clientHeigh ...
- JVM性能调优实践——JVM篇
前言 在遇到实际性能问题时,除了关注系统性能指标.还要结合应用程序的系统的日志.堆栈信息.GClog.threaddump等数据进行问题分析和定位.关于性能指标分析可以参考前一篇JVM性能调优实践-- ...
- 自绘实现半透明水晶按钮(继承CButton,设置BS_OWNERDRAW风格,覆盖DrawItem函数绘制按钮,把父窗口的背景复制到按钮上,实现视觉上的透明,最后通过AlphaBlend实现半透明)
运行效果 实现方法 1.给按钮加上BS_OWNERDRAW样式2.重载DrawItem函数,在这里绘制按钮3.关键之处就是把父窗口的背景复制到按钮上,实现视觉上的透明4.最后通过AlphaBlend实 ...
- Linux硬件信息查询命令
系统 uname -a # 查看内核/操作系统/CPU信息 Linux hostname 2.6.18-128.el5 #1 SMP Wed Dec 17 11:41:38 ...
- 分布式服务网关(Web Api)
分布式服务网关(Web Api) kmp算法又称“看毛片”算法,是一个效率非常高的字符串匹配算法.不过由于其难以理解,所以在很长的一段时间内一直没有搞懂.虽然网上有很多资料,但是鲜见好的博客能简单明了 ...
- linux的开机启动过程:
简单视图 按下电源开关 开机自检(BIOS)弹笔记本logo的时候,检查cpu 硬盘 这些硬件问题 MBR引导 一般是通过硬盘启动系统 GRUB的菜单 黑底白字有个倒数计时 可以选择内核 yum命令可 ...
- 关于Vuex可直接修改state问题
下面的代码证明不通过mutation,而直接修改state修改确实生效了.这样子多人协作岂不是很容易出问题.对于这个问题,在创建 store 的时候传入 strict: true, 开启严格模式,那么 ...
- VS版本 与 .NET版本以及C#版本之间的关系
版本 .NET Framework版本 Visual Studio版本 发布日期 特性 C# 1.0 .NET Framework 1.0 Visual Studio .NET 2002 2002.1 ...
- 利用jQuery传送json格式的字符串,后端用ashx文件来接收
在Default.aspx里面,我们会透过javascript建立两个物件,分别有Name和Age的属性,再透过Array的方式,将这两个物件塞到Array里面去.使用Ajax内建的$.ajax AP ...